feature/jp-0331 #526

Open
jungpyo2001 wants to merge 998 commits from feature/jp-0331 into main
12805 changed files with 1498780 additions and 3087 deletions

10
.gitignore vendored
View File

@ -33,3 +33,13 @@ build/
### VS Code ### ### VS Code ###
.vscode/ .vscode/
### logs ###
qcast3/
src/test
logs/
### Claude Code ###
# 2026-05-08: .claude 전체 및 docs/ 디렉터리는 로컬 전용으로 git 제외
.claude/
docs/

45
pom.xml
View File

@ -15,6 +15,7 @@
<description>qcast</description> <description>qcast</description>
<properties> <properties>
<java.version>17</java.version> <java.version>17</java.version>
<spring-cloud.version>2023.0.2</spring-cloud.version>
</properties> </properties>
<dependencies> <dependencies>
<!-- Spring Boot Start --> <!-- Spring Boot Start -->
@ -26,6 +27,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId> <artifactId>spring-boot-starter-batch</artifactId>
@ -103,7 +108,7 @@
<dependency> <dependency>
<groupId>org.springdoc</groupId> <groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.6.0</version> <version>2.3.0</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
@ -160,9 +165,47 @@
<version>1.0.9</version> <version>1.0.9</version>
</dependency> </dependency>
<!--pdf-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>4.0.3</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>7.2.5</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>7.2.5</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>io</artifactId>
<version>7.2.5</version>
</dependency>
</dependencies> </dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>

View File

@ -0,0 +1,108 @@
package com.interplug.qcast.batch;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.*;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.web.bind.annotation.*;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
@RestController
@RequiredArgsConstructor
@Slf4j
public class BatchMonitorController {
private final JobExplorer jobExplorer;
private final JobOperator jobOperator;
@GetMapping("/batch/status")
public Map<String, Object> getBatchStatus() {
Map<String, Object> status = new HashMap<>();
String[] jobNames = {"storeAdditionalJob", "priceJob", "materialJob", "bomJob",
"businessChargerJob", "adminUserJob", "commonCodeJob",
"specialNoteDispItemAdditionalJob", "planConfirmJob", "estimateSyncJob"};
for (String jobName : jobNames) {
status.put(jobName, getJobStatus(jobName));
}
return status;
}
private Map<String, Object> getJobStatus(String jobName) {
Map<String, Object> jobStatus = new HashMap<>();
try {
List<JobInstance> jobInstances = jobExplorer.findJobInstancesByJobName(jobName, 0, 1);
if (jobInstances.isEmpty()) {
jobStatus.put("status", "NEVER_EXECUTED");
return jobStatus;
}
JobInstance latestJobInstance = jobInstances.get(0);
List<JobExecution> jobExecutions = jobExplorer.getJobExecutions(latestJobInstance);
if (!jobExecutions.isEmpty()) {
JobExecution latestExecution = jobExecutions.get(0);
jobStatus.put("status", latestExecution.getStatus().toString());
jobStatus.put("startTime", latestExecution.getStartTime());
jobStatus.put("endTime", latestExecution.getEndTime());
// Duration 계산 (LocalDateTime용)
if (latestExecution.getEndTime() != null && latestExecution.getStartTime() != null) {
Duration duration = Duration.between(latestExecution.getStartTime(), latestExecution.getEndTime());
jobStatus.put("durationSeconds", duration.getSeconds());
jobStatus.put("durationMinutes", duration.toMinutes());
} else if (latestExecution.getStartTime() != null) {
// 실행 중인 경우 현재까지의 경과 시간
Duration duration = Duration.between(latestExecution.getStartTime(), LocalDateTime.now());
jobStatus.put("runningDurationSeconds", duration.getSeconds());
jobStatus.put("runningDurationMinutes", duration.toMinutes());
}
}
} catch (Exception e) {
jobStatus.put("status", "ERROR");
jobStatus.put("error", e.getMessage());
}
return jobStatus;
}
/**
* 강제 Job 중지
*/
@PostMapping("/batch/stop/{jobName}")
public Map<String, Object> stopJob(@PathVariable String jobName) {
Map<String, Object> result = new HashMap<>();
try {
Set<Long> runningExecutions = jobOperator.getRunningExecutions(jobName);
if (runningExecutions.isEmpty()) {
result.put("code", "NO_RUNNING_JOBS");
result.put("message", "No running executions found for job: " + jobName);
return result;
}
List<String> stopResults = new ArrayList<>();
for (Long executionId : runningExecutions) {
boolean stopped = jobOperator.stop(executionId);
stopResults.add("Execution " + executionId + ": " + (stopped ? "STOPPED" : "FAILED_TO_STOP"));
}
result.put("code", "SUCCESS");
result.put("message", "Stop commands sent");
result.put("results", stopResults);
} catch (Exception e) {
result.put("code", "ERROR");
result.put("message", "Error stopping job: " + e.getMessage());
}
return result;
}
}

View File

@ -1,27 +1,69 @@
package com.interplug.qcast.batch; package com.interplug.qcast.batch;
import java.util.Date; import java.time.Duration;
import java.util.Map; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job; import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.*;
import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException; import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.context.event.EventListener;
import java.time.LocalDateTime;
import java.sql.SQLException;
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j
public class JobLauncherController { public class JobLauncherController {
private final Map<String, Job> jobs; // 여러 Job을 주입받도록 변경 private final Map<String, Job> jobs; // 여러 Job을 주입받도록 변경
private final JobLauncher jobLauncher; private final JobLauncher jobLauncher;
private final JobExplorer jobExplorer;
private final JobRepository jobRepository; // 생성자 주입을 위해 필드 추가
@Value("${qsp.master-admin-user-batch-url}")
private String qspInterfaceUrl;
@Value("${spring.profiles.scheduler}")
private String scheduler;
@Value("${server.port:8080}")
private int serverPort;
@Value("${batch.scheduler-port:8080}")
private int schedulerPort;
/**
* 서버 시작 실행 (STARTED) 상태로 남은 Job들을 FAILED 처리
*/
@EventListener(ApplicationReadyEvent.class)
public void resetFailedJobs() {
log.info("Checking for 'STARTED' jobs to reset after reboot...");
for (String jobName : jobs.keySet()) {
Set<JobExecution> runningExecutions = jobExplorer.findRunningJobExecutions(jobName);
for (JobExecution execution : runningExecutions) {
execution.setStatus(BatchStatus.FAILED);
execution.setExitStatus(ExitStatus.FAILED.addExitDescription("Reset on application startup"));
execution.setEndTime(LocalDateTime.now()); // new Date() 대신 LocalDateTime.now() 사용
jobRepository.update(execution);
log.info("Reset job execution {} for job {}", execution.getId(), jobName);
}
}
}
/** /**
* 특정 Job을 매핑으로 실행하는 메소드 * 특정 Job을 매핑으로 실행하는 메소드
@ -34,118 +76,401 @@ public class JobLauncherController {
* @throws JobRestartException * @throws JobRestartException
*/ */
@GetMapping("/batch/job/{jobName}") // Path Variable로 jobName을 받음 @GetMapping("/batch/job/{jobName}") // Path Variable로 jobName을 받음
public String launchJob(@PathVariable String jobName) public Map<String, Object> launchJob(@PathVariable String jobName)
throws JobInstanceAlreadyCompleteException, throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException,
JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
JobParametersInvalidException,
JobRestartException {
log.info("Manual launch requested for job: {}", jobName);
Job job = jobs.get(jobName); Job job = jobs.get(jobName);
Map<String, Object> resultMap = new HashMap<String, Object>();
if (job == null) { if (job == null) {
return "Job " + jobName + " not found"; // return "Job " + jobName + " not found";
resultMap.put("code", "FAILED");
resultMap.put("message", "Job" + jobName + " not found");
return resultMap;
} }
JobParameters jobParameters = // 실행 중인 Job 확인 (데이터베이스 기반)
new JobParametersBuilder() if (isJobRunning(jobName)) {
.addString("jobName", jobName) log.warn("Job {} is already running, skipping execution", jobName);
.addDate("time", new Date()) resultMap.put("code", "FAILED");
.toJobParameters(); resultMap.put("message", "Job "+ jobName +" is already running, skipping execution");
return resultMap;
jobLauncher.run(job, jobParameters);
return "Job " + jobName + " started";
}
/**
* 스케줄러로 Job을 실행하는 메소드
*
* @return
* @throws JobInstanceAlreadyCompleteException
* @throws JobExecutionAlreadyRunningException
* @throws JobParametersInvalidException
* @throws JobRestartException
*/
@Scheduled(cron = "0 55 23 * * *")
public String scheduleJobLauncher()
throws JobInstanceAlreadyCompleteException,
JobExecutionAlreadyRunningException,
JobParametersInvalidException,
JobRestartException {
String jobName = "sampleOtherJob";
Job job = jobs.get(jobName);
if (job == null) {
return "Job " + jobName + " not found";
} }
JobParameters jobParameters = try {
new JobParametersBuilder() log.info("Starting job: {}", jobName);
.addString("jobName", jobName)
.addDate("time", new Date())
.toJobParameters();
jobLauncher.run(job, jobParameters); JobParameters jobParameters = new JobParametersBuilder().addString("jobName", jobName)
.addDate("time", new Date()).toJobParameters();
return "Job " + jobName + " started"; JobExecution jobExecution = jobLauncher.run(job, jobParameters);
log.info("Job {} started with execution id {}", jobName, jobExecution.getId());
BatchStatus status = jobExecution.getStatus();
ExitStatus exitStatus = jobExecution.getExitStatus();
resultMap.put("code", status.toString());
resultMap.put("message", exitStatus.getExitDescription());
// return "Job " + jobName + " started";
return resultMap;
} catch (JobExecutionAlreadyRunningException e) {
log.warn("Job {} 이 다른 인스턴스에서 이미 실행 중입니다.", jobName);
resultMap.put("code", "ALREADY_RUNNING");
resultMap.put("message", "Job " + jobName + " is already running on another instance.");
return resultMap;
} catch (Exception e) {
logExceptionDetails("Manual launch failed", jobName, e);
if (isDeadlockException(e)) {
logDeadlockDetails(jobName, e);
resultMap.put("code", "DEADLOCK");
resultMap.put("message", "Deadlock detected while executing job " + jobName + ". Please retry.");
return resultMap;
}
resultMap.put("code", "FAILED");
resultMap.put("message", e.getMessage());
return resultMap;
}
} }
/** /**
* Q.CAST 판매점 / 사용자 / 즐겨찾기 / 노출 아이템 동기화 배치 * Q.CAST 판매점 / 사용자 / 즐겨찾기 / 노출 아이템 동기화 배치
* *
* @return
* @throws JobInstanceAlreadyCompleteException
* @throws JobExecutionAlreadyRunningException
* @throws JobParametersInvalidException
* @throws JobRestartException
*/ */
// @Scheduled(cron = "*/5 * * * * *") // @Scheduled(cron = "*/5 * * * * *")
@Scheduled(cron = "0 55 23 * * *") @Scheduled(cron = "0 50 23 * * *")
public String storeAdditionalInfoJob() public String storeAdditionalJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
throws JobInstanceAlreadyCompleteException,
JobExecutionAlreadyRunningException,
JobParametersInvalidException,
JobRestartException {
String jobName = "storeAdditionalJob"; return executeScheduledJob("storeAdditionalJob");
Job job = jobs.get(jobName);
if (job == null) {
return "Job " + jobName + " not found";
}
JobParameters jobParameters =
new JobParametersBuilder().addDate("time", new Date()).toJobParameters();
jobLauncher.run(job, jobParameters);
return "OK";
} }
/** /**
* 아이템 동기화 배치 * 아이템 동기화 배치
* *
* @return
* @throws JobInstanceAlreadyCompleteException
* @throws JobExecutionAlreadyRunningException
* @throws JobParametersInvalidException
* @throws JobRestartException
*/
@Scheduled(cron = "0 0 0 * * *")
public String materialJob()
throws JobInstanceAlreadyCompleteException,
JobExecutionAlreadyRunningException,
JobParametersInvalidException,
JobRestartException {
String jobName = "materialJob"; */
@Scheduled(cron = "0 50 04 * * *")
public String materialJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
return executeScheduledJob("materialJob");
}
/**
* BOM 아이템 동기화 배치
*
* [2026-05-13] 04:20 으로 이동 (estimateSyncJob 시간 스왑).
* 사유: estimateSyncJob 만성 timeout 으로 길어질 있어, 새벽 마지막 슬롯(05:20)으로 옮김.
* BOM GET 단일 호출(0.7초 수준)이라 슬롯 영향 .
*/
@Scheduled(cron = "0 20 04 * * *")
public String bomJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
return executeScheduledJob("bomJob");
}
/**
* 영업사원 동기화 배치
*
*/
@Scheduled(cron = "0 40 03 * * *")
public String businessChargerJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
return executeScheduledJob("businessChargerJob");
}
/**
* 관리자 유저 동기화 배치
*
*/
@Scheduled(cron = "0 30 01 * * *")
public String adminUserJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
return executeScheduledJob("adminUserJob");
}
/**
* 가격 동기화 배치
*
*/
@Scheduled(cron = "0 20 00 * * *")
public String priceJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
return executeScheduledJob("priceJob");
}
/**
* 공통코드 M_COMM_H, M_COMM_L 동기화 배치
*
*/
@Scheduled(cron = "0 10 03 * * *")
public String commonCodeJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
return executeScheduledJob("commonCodeJob");
}
/**
* Q.CAST 견적특이사항 / 아이템 표시, 미표시 동기화 배치
*
*/
@Scheduled(cron = "0 30 23 * * *")
public String specialNoteDispItemAdditionalInfoJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
return executeScheduledJob("specialNoteDispItemAdditionalJob");
}
/**
* Plan Confrim 동기화 배치
*
*/
@Scheduled(cron = "0 05 04 * * *")
public String planConfirmJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
return executeScheduledJob("planConfirmJob");
}
/**
* 견적서 전송 동기화 배치
*
* [2026-05-13] 05:20 으로 이동 (bomJob 시간 스왑).
* 사유: 만성 QSP timeout 으로 chunk 분할 송신해도 길어질 있어, 새벽 마지막 슬롯에 배치.
* 다음 스케줄(23:50 storeAdditionalJob)까지 18시간 버퍼 확보 후속 job 침범 위험 제거.
* chunk 분할 로직은 EstimateSyncConfiguration 참고.
*/
@Scheduled(cron = "0 20 05 * * *")
public String estimateSyncJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
return executeScheduledJob("estimateSyncJob");
}
/**
* 공통 스케줄러 실행 메소드
*/
private String executeScheduledJob(String jobName) throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
// 스케줄러 전용 포트 인스턴스에서만 실행 (멀티 인스턴스 데드락 방지)
if (serverPort != schedulerPort) {
log.debug("스케줄러는 {} 포트 인스턴스에서만 실행됩니다. 현재 포트: {}, Job: {} 스킵", schedulerPort, serverPort, jobName);
return "Scheduler runs only on port " + schedulerPort + ". Current port: " + serverPort;
}
Job job = jobs.get(jobName); Job job = jobs.get(jobName);
if (job == null) { if (job == null) {
log.error("Job {} not found", jobName);
return "Job " + jobName + " not found"; return "Job " + jobName + " not found";
} }
JobParameters jobParameters = // if (!"Y".equals(scheduler) &&
new JobParametersBuilder().addDate("time", new Date()).toJobParameters(); // !"materialJob".equals(jobName) &&
// !"commonCodeJob".equals(jobName) &&
// !"specialNoteDispItemAdditionalJob".equals(jobName) &&
// !"planConfirmJob".equals(jobName) &&
// !"estimateSyncJob".equals(jobName) &&
// !"bomJob".equals(jobName)){
// log.info("Scheduler disabled, skipping job {}", jobName);
// return "Scheduler disabled";
// }
jobLauncher.run(job, jobParameters); // 허용된 작업 목록 정의
Set<String> allowedJobs = new HashSet<>(Arrays.asList(
"materialJob",
"commonCodeJob",
"specialNoteDispItemAdditionalJob",
"planConfirmJob",
"estimateSyncJob",
"bomJob",
"storeAdditionalJob",
"businessChargerJob",
"adminUserJob"
));
return "OK"; // 스케줄러가 비활성화되어 있고, 허용된 작업이 아닌 경우
if (!"Y".equals(scheduler) && !allowedJobs.contains(jobName)) {
log.info("스케줄러가 비활성화되어 작업을 건너뜁니다: {}", jobName);
return "Scheduler disabled";
}
// 실행 중인 Job 확인 (데이터베이스 기반)
if (isJobRunning(jobName)) {
log.warn("Job {} is already running, skipping execution", jobName);
return "Job already running";
}
// JobParameters jobParameters =
// new JobParametersBuilder().addDate("time", new Date()).toJobParameters();
//
// jobLauncher.run(job, jobParameters);
//
// return jobName+ " executed successfully";
JobParameters jobParameters = new JobParametersBuilder()
.addString("jobName", jobName)
.addDate("time", new Date())
.toJobParameters();
try {
log.info("Job {} 실행 시작", jobName);
JobExecution jobExecution = jobLauncher.run(job, jobParameters);
log.info("Job {} completed with execution id {} and status {}",
jobName, jobExecution.getId(), jobExecution.getExitStatus().getExitCode());
return jobName + " executed successfully";
} catch (JobExecutionAlreadyRunningException e) {
log.warn("Job {} 이 다른 인스턴스에서 이미 실행 중입니다. 스킵합니다.", jobName);
return "Job " + jobName + " is already running on another instance. Skipped.";
} catch (Exception e) {
logExceptionDetails("Scheduled launch failed", jobName, e);
if (isDeadlockException(e)) {
logDeadlockDetails(jobName, e);
return "Deadlock detected while executing job " + jobName + ". Manual retry required.";
}
log.error("Job {} 실행 실패", jobName, e);
return "Error executing job " + jobName + ": " + e.getMessage();
}
}
/**
* Job 실행 상태 확인
*/
private boolean isJobRunning(String jobName) {
try {
log.debug("Checking running executions for job: {}", jobName);
Set<JobExecution> runningExecutions = jobExplorer.findRunningJobExecutions(jobName);
if (runningExecutions.isEmpty()) {
return false;
}
boolean isActuallyBlocked = false;
for (JobExecution execution : runningExecutions) {
LocalDateTime startTime = execution.getStartTime();
if (startTime == null) continue;
// 현재 시간과 시작 시간의 차이 계산
Duration duration = Duration.between(startTime, LocalDateTime.now());
long hours = duration.toHours();
if (hours >= 1) {
// 1시간 이상 경과한 경우 로그 출력 DB 강제 업데이트
log.warn("Job {} (Execution ID: {}) 가 실행된 지 {}시간이 지났습니다. 상태를 FAILED로 초기화하고 재실행을 시도합니다.",
jobName, execution.getId(), hours);
execution.setStatus(BatchStatus.FAILED);
execution.setExitStatus(ExitStatus.FAILED.addExitDescription("Forcefully reset: Running for more than 1 hour"));
execution.setEndTime(LocalDateTime.now());
jobRepository.update(execution);
log.info("Job {} 의 이전 실행 상태가 성공적으로 초기화되었습니다.", jobName);
} else {
// 1시간 미만으로 실행 중인 잡이 있다면 진짜 실행 중인 것으로 간주
log.info("Job {} 가 현재 실행 중입니다. (시작 시간: {}, 경과 시간: {}분)",
jobName, startTime, duration.toMinutes());
isActuallyBlocked = true;
}
}
return isActuallyBlocked;
} catch (Exception e) {
log.error("Job 상태 확인 중 오류 발생: {}", e.getMessage());
return false;
}
}
private void logExceptionDetails(String context, String jobName, Exception e) {
Throwable root = e;
while (root.getCause() != null) {
root = root.getCause();
}
if (root instanceof SQLException) {
SQLException sqlEx = (SQLException) root;
log.error("{} for job {}: SQLState={}, errorCode={}, message={}, sqlChain={}",
context, jobName, sqlEx.getSQLState(), sqlEx.getErrorCode(), sqlEx.getMessage(),
buildSqlExceptionChain(sqlEx), e);
} else {
log.error("{} for job {}: {}", context, jobName, root.getMessage(), e);
}
}
private void logDeadlockDetails(String jobName, Exception e) {
log.error("===== [DEADLOCK] Job: {} 데드락 상세 정보 =====", jobName);
Throwable current = e;
int depth = 0;
while (current != null && depth < 10) {
log.error("[DEADLOCK] Exception chain [{}]: {} - {}",
depth, current.getClass().getName(), current.getMessage());
if (current instanceof SQLException) {
SQLException sqlEx = (SQLException) current;
log.error("[DEADLOCK] SQLState: {}, ErrorCode: {}, Message: {}",
sqlEx.getSQLState(), sqlEx.getErrorCode(), sqlEx.getMessage());
// SQLException 체인의 next exception도 확인
SQLException nextEx = sqlEx.getNextException();
int sqlDepth = 0;
while (nextEx != null && sqlDepth < 10) {
log.error("[DEADLOCK] SQL NextException [{}]: SQLState={}, ErrorCode={}, Message={}",
sqlDepth, nextEx.getSQLState(), nextEx.getErrorCode(), nextEx.getMessage());
nextEx = nextEx.getNextException();
sqlDepth++;
}
}
current = current.getCause();
depth++;
}
log.error("[DEADLOCK] Full stack trace:", e);
log.error("===== [DEADLOCK] Job: {} 데드락 상세 정보 끝 =====", jobName);
}
private boolean isDeadlockException(Throwable throwable) {
Throwable root = throwable;
while (root.getCause() != null) {
root = root.getCause();
}
if (root instanceof SQLException) {
SQLException sqlEx = (SQLException) root;
if ("40001".equals(sqlEx.getSQLState()) || sqlEx.getErrorCode() == 1205) {
return true;
}
}
String message = root.getMessage();
if (message == null) return false;
String lowerMessage = message.toLowerCase();
return lowerMessage.contains("deadlock")
|| message.contains("デッドロック")
|| message.contains("교착 상태");
}
private String buildSqlExceptionChain(SQLException sqlEx) {
StringBuilder sb = new StringBuilder();
SQLException current = sqlEx;
int depth = 0;
while (current != null && depth < 10) {
if (depth > 0) {
sb.append(" | ");
}
sb.append("[").append(current.getClass().getSimpleName())
.append(" sqlState=").append(current.getSQLState())
.append(" errorCode=").append(current.getErrorCode())
.append(" message=").append(current.getMessage()).append("]");
current = current.getNextException();
depth++;
}
return sb.toString();
} }
} }

View File

@ -0,0 +1,174 @@
package com.interplug.qcast.batch.estimate;
import com.interplug.qcast.biz.estimate.EstimateService;
import com.interplug.qcast.biz.estimate.dto.EstimateSendRequest;
import com.interplug.qcast.biz.estimate.dto.EstimateSendResponse;
import com.interplug.qcast.biz.estimate.dto.EstimateSyncResponse;
import com.interplug.qcast.biz.estimate.dto.PlanSyncResponse;
import com.interplug.qcast.util.InterfaceQsp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;
/** Plan 확정 Item 마스터 동기화 배치 */
@Slf4j
@Configuration
public class EstimateSyncConfiguration implements JobExecutionListener {
private final EstimateService estimateService;
private final InterfaceQsp interfaceQsp;
@Value("${qsp.estimate-sync-batch-url}")
private String qspInterfaceUrl;
// [2026-05-13] QSP 견적 동기화 chunk 크기 만성 120s timeout 회피 위해 분할 송신
@Value("${qsp.estimate-sync-chunk-size:50}")
private int estimateSyncChunkSize;
// [2026-05-13] 송신 시간 상한 (밀리초). 초과 남은 chunk 중단하여 다음 스케줄 job (04:50 materialJob) 침범 방지.
@Value("${qsp.estimate-sync-total-timeout-ms:1500000}")
private long estimateSyncTotalTimeoutMs;
public EstimateSyncConfiguration(EstimateService estimateService, InterfaceQsp interfaceQsp) {
this.estimateService = estimateService;
this.interfaceQsp = interfaceQsp;
}
@Bean
public Job estimateSyncJob(JobRepository jobRepository, Step estimateSyncStep) {
return new JobBuilder("estimateSyncJob", jobRepository).start(estimateSyncStep).build();
}
@Bean
public Step estimateSyncStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception {
return new StepBuilder("estimateSyncStep", jobRepository)
.<PlanSyncResponse, PlanSyncResponse>chunk(100, transactionManager)
.reader(estimateSyncReader())
.processor(estimateSyncProcessor())
.writer(estimateSyncWriter())
.build();
}
@Bean
@StepScope
public ListItemReader<PlanSyncResponse> estimateSyncReader() throws Exception {
// [2026-05-13] 만성 timeout 회피: 전체 fail list 번에 POST 하지 않고 chunk 단위로 분할 송신.
// chunk try/catch 일부 chunk 실패해도 다음 chunk 진행.
// 모든 chunk 실패 시에만 throw 하여 Step FAILED.
// elapsed 상한 초과 남은 chunk 중단 (다음 스케줄 job 침범 방지).
EstimateSendRequest fullRequest = estimateService.selectEstimateSyncFailList();
List<EstimateSendResponse> quoteList =
(fullRequest != null) ? fullRequest.getQuoteList() : null;
if (quoteList == null || quoteList.isEmpty()) {
log.info("QSP 견적 동기화: 송신할 fail list 없음");
return new ListItemReader<>(Collections.emptyList());
}
int chunkSize = Math.max(1, estimateSyncChunkSize);
int totalChunks = (quoteList.size() + chunkSize - 1) / chunkSize;
List<PlanSyncResponse> mergedSuccessList = new ArrayList<>();
int successChunks = 0;
int abortedChunks = 0;
long startAt = System.currentTimeMillis();
log.info(
"QSP 견적 동기화 분할 송신 시작: totalItems={}, chunkSize={}, totalChunks={}",
quoteList.size(),
chunkSize,
totalChunks);
for (int i = 0; i < quoteList.size(); i += chunkSize) {
long elapsed = System.currentTimeMillis() - startAt;
if (elapsed > estimateSyncTotalTimeoutMs) {
abortedChunks = totalChunks - (i / chunkSize);
log.warn(
"QSP 견적 동기화 총 elapsed 상한 초과 — 남은 chunk 중단: elapsedMs={}, limitMs={}, abortedChunks={}",
elapsed,
estimateSyncTotalTimeoutMs,
abortedChunks);
break;
}
int end = Math.min(i + chunkSize, quoteList.size());
int chunkIndex = i / chunkSize;
List<EstimateSendResponse> sub = new ArrayList<>(quoteList.subList(i, end));
EstimateSendRequest subRequest = new EstimateSendRequest();
subRequest.setQuoteList(sub);
try {
EstimateSyncResponse chunkResponse =
interfaceQsp.callApiData(
HttpMethod.POST, qspInterfaceUrl, subRequest, EstimateSyncResponse.class);
if (chunkResponse != null && chunkResponse.getSuccessList() != null) {
mergedSuccessList.addAll(chunkResponse.getSuccessList());
}
successChunks++;
log.info(
"QSP 견적 동기화 chunk 성공: chunkIndex={}/{}, range=[{},{}), accumulatedSuccess={}",
chunkIndex,
totalChunks,
i,
end,
mergedSuccessList.size());
} catch (Exception e) {
log.error(
"QSP 견적 동기화 chunk 실패 — 다음 chunk 계속: chunkIndex={}/{}, range=[{},{})",
chunkIndex,
totalChunks,
i,
end,
e);
}
}
long totalElapsed = System.currentTimeMillis() - startAt;
log.info(
"QSP 견적 동기화 분할 송신 완료: totalChunks={}, successChunks={}, abortedChunks={}, mergedSuccess={}, totalElapsedMs={}",
totalChunks,
successChunks,
abortedChunks,
mergedSuccessList.size(),
totalElapsed);
if (successChunks == 0) {
throw new IllegalStateException(
"QSP 견적 동기화 모든 chunk 실패: totalChunks="
+ totalChunks
+ ", quoteSize="
+ quoteList.size());
}
return new ListItemReader<>(mergedSuccessList);
}
@Bean
public ItemProcessor<PlanSyncResponse, PlanSyncResponse> estimateSyncProcessor() {
return item -> item;
}
@Bean
public ItemWriter<PlanSyncResponse> estimateSyncWriter() {
return items -> {
List<PlanSyncResponse> planList = new ArrayList<>(items.getItems());
estimateService.setEstimateSyncSave(planList);
};
}
}

View File

@ -0,0 +1,81 @@
package com.interplug.qcast.batch.estimate;
import com.fasterxml.jackson.core.type.TypeReference;
import com.interplug.qcast.biz.estimate.EstimateService;
import com.interplug.qcast.biz.estimate.dto.PlanSyncResponse;
import com.interplug.qcast.util.InterfaceQsp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;
/** Plan 확정 Item 마스터 동기화 배치 */
@Configuration
public class PlanConfrimConfiguration implements JobExecutionListener {
private final EstimateService estimateService;
private final InterfaceQsp interfaceQsp;
List<PlanSyncResponse> planSyncList;
@Value("${qsp.estimate-plan-confirm-batch-url}")
private String qspInterfaceUrl;
public PlanConfrimConfiguration(EstimateService estimateService, InterfaceQsp interfaceQsp) {
this.estimateService = estimateService;
this.interfaceQsp = interfaceQsp;
}
@Bean
public Job planConfirmJob(JobRepository jobRepository, Step planConfirmStep) {
return new JobBuilder("planConfirmJob", jobRepository).start(planConfirmStep).build();
}
@Bean
public Step planConfirmStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception {
return new StepBuilder("planConfirmStep", jobRepository)
.<PlanSyncResponse, PlanSyncResponse>chunk(100, transactionManager)
.reader(planConfirmReader())
.processor(planConfirmProcessor())
.writer(planConfirmWriter())
.build();
}
@Bean
@StepScope
public ListItemReader<PlanSyncResponse> planConfirmReader() throws Exception {
this.planSyncList =
interfaceQsp.callApiData(
HttpMethod.GET, qspInterfaceUrl, null, new TypeReference<List<PlanSyncResponse>>() {});
return (planSyncList != null)
? new ListItemReader<>(planSyncList)
: new ListItemReader<>(Collections.emptyList());
}
@Bean
public ItemProcessor<PlanSyncResponse, PlanSyncResponse> planConfirmProcessor() {
return item -> item;
}
@Bean
public ItemWriter<PlanSyncResponse> planConfirmWriter() {
return items -> {
estimateService.setPlanConfirmSyncSave(new ArrayList<>(items.getItems()));
};
}
}

View File

@ -0,0 +1,89 @@
package com.interplug.qcast.batch.master;
import com.fasterxml.jackson.core.type.TypeReference;
import com.interplug.qcast.biz.displayItem.DisplayItemService;
import com.interplug.qcast.biz.displayItem.dto.BomSyncResponse;
import com.interplug.qcast.util.InterfaceQsp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;
/** Bom Item 마스터 동기화 배치 */
@Configuration
public class BomConfiguration implements JobExecutionListener {
private final DisplayItemService displayItemService;
private final InterfaceQsp interfaceQsp;
List<BomSyncResponse> bomSyncList;
@Value("${qsp.master-bom-batch-url}")
private String qspInterfaceUrl;
public BomConfiguration(DisplayItemService displayItemService, InterfaceQsp interfaceQsp) {
this.displayItemService = displayItemService;
this.interfaceQsp = interfaceQsp;
}
@Bean
public Job bomJob(JobRepository jobRepository, Step bomStep) {
return new JobBuilder("bomJob", jobRepository).start(bomStep).build();
}
@Bean
public Step bomStep(JobRepository jobRepository, PlatformTransactionManager transactionManager)
throws Exception {
return new StepBuilder("bomStep", jobRepository)
.<BomSyncResponse, BomSyncResponse>chunk(100, transactionManager)
.reader(bomReader())
.processor(bomProcessor())
.writer(bomWriter())
.build();
}
@Bean
@StepScope
public ListItemReader<BomSyncResponse> bomReader() throws Exception {
this.bomSyncList =
interfaceQsp.callApiData(
HttpMethod.GET, qspInterfaceUrl, null, new TypeReference<List<BomSyncResponse>>() {});
if (bomSyncList == null) {
return new ListItemReader<>(Collections.emptyList());
}
// 2026-05-20 청크 경계에서 같은 A/D 분리되어 A 먼저 MERGE
// 다음 청크의 D 그것을 삭제해버리는 리스크를 차단하기 위해,
// 전체 리스트를 statCd='D' 우선으로 정렬한다. (Spring Batch 청크를 순차 처리하므로
// 모든 D 청크가 끝난 뒤에 A/U 청크가 시작되어 전역적으로 'A 이김' 보장됨)
bomSyncList.sort(
Comparator.comparingInt((BomSyncResponse b) -> "D".equals(b.getStatCd()) ? 0 : 1));
return new ListItemReader<>(bomSyncList);
}
@Bean
public ItemProcessor<BomSyncResponse, BomSyncResponse> bomProcessor() {
return item -> item;
}
@Bean
public ItemWriter<BomSyncResponse> bomWriter() {
return items -> {
displayItemService.setBomSyncSave(new ArrayList<>(items.getItems()));
};
}
}

View File

@ -2,11 +2,13 @@ package com.interplug.qcast.batch.master;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.interplug.qcast.biz.displayItem.DisplayItemService; import com.interplug.qcast.biz.displayItem.DisplayItemService;
import com.interplug.qcast.biz.displayItem.dto.ItemSyncRequest;
import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse; import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse;
import com.interplug.qcast.util.InterfaceQsp; import com.interplug.qcast.util.InterfaceQsp;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.springframework.batch.core.Job; import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener; import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step; import org.springframework.batch.core.Step;
@ -15,7 +17,6 @@ import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader; import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -24,7 +25,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
/** chunk 방식의 Job을 생성하는 Configuration */ /** Item 마스터 동기화 배치 */
@Configuration @Configuration
public class MaterialConfiguration implements JobExecutionListener { public class MaterialConfiguration implements JobExecutionListener {
private final DisplayItemService displayItemService; private final DisplayItemService displayItemService;
@ -36,6 +37,9 @@ public class MaterialConfiguration implements JobExecutionListener {
@Value("${qsp.master-material-batch-url}") @Value("${qsp.master-material-batch-url}")
private String qspInterfaceUrl; private String qspInterfaceUrl;
@Value("${qsp.master-material-batch-page-size:1000}")
private int pageSize;
public MaterialConfiguration(DisplayItemService displayItemService, InterfaceQsp interfaceQsp) { public MaterialConfiguration(DisplayItemService displayItemService, InterfaceQsp interfaceQsp) {
this.displayItemService = displayItemService; this.displayItemService = displayItemService;
this.interfaceQsp = interfaceQsp; this.interfaceQsp = interfaceQsp;
@ -59,15 +63,33 @@ public class MaterialConfiguration implements JobExecutionListener {
@Bean @Bean
@StepScope @StepScope
public ItemReader<ItemSyncResponse> materialReader() throws Exception { public ListItemReader<ItemSyncResponse> materialReader() throws Exception {
ItemSyncRequest itemSyncRequest = new ItemSyncRequest(); List<ItemSyncResponse> aggregated = new ArrayList<>();
itemSyncRequest.setAllYn("N"); int page = 1;
this.itemSyncList = while (true) {
interfaceQsp.callApiData( Map<String, Object> params = new HashMap<>();
HttpMethod.GET, params.put("allYn", "N");
qspInterfaceUrl, params.put("page", page);
itemSyncRequest, params.put("size", pageSize);
new TypeReference<List<ItemSyncResponse>>() {});
List<ItemSyncResponse> pageItems =
interfaceQsp.callApiData(
HttpMethod.GET,
qspInterfaceUrl,
params,
new TypeReference<List<ItemSyncResponse>>() {});
if (pageItems == null || pageItems.isEmpty()) {
break;
}
aggregated.addAll(pageItems);
if (pageItems.size() < pageSize) {
break;
}
page++;
}
this.itemSyncList = aggregated;
return (itemSyncList != null) return (itemSyncList != null)
? new ListItemReader<>(itemSyncList) ? new ListItemReader<>(itemSyncList)
: new ListItemReader<>(Collections.emptyList()); : new ListItemReader<>(Collections.emptyList());
@ -81,7 +103,7 @@ public class MaterialConfiguration implements JobExecutionListener {
@Bean @Bean
public ItemWriter<ItemSyncResponse> materialWriter() { public ItemWriter<ItemSyncResponse> materialWriter() {
return items -> { return items -> {
displayItemService.setItemSyncSave((List<ItemSyncResponse>) items.getItems()); displayItemService.setItemSyncSave(new ArrayList<>(items.getItems()));
}; };
} }
} }

View File

@ -0,0 +1,154 @@
package com.interplug.qcast.batch.master;
import com.interplug.qcast.biz.displayItem.DisplayItemService;
import com.interplug.qcast.biz.displayItem.dto.PriceItemSyncResponse;
import com.interplug.qcast.biz.displayItem.dto.PriceSyncResponse;
import com.interplug.qcast.util.InterfaceQsp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;
/** Price 동기화 배치 */
@Configuration
@Slf4j
public class PriceJobConfiguration implements JobExecutionListener {
private final InterfaceQsp interfaceQsp;
private final DisplayItemService displayItemService;
@Value("${qsp.master-price-batch-url}")
private String qspInterfaceUrl;
private PriceSyncResponse priceSyncResponse;
public PriceJobConfiguration(InterfaceQsp interfaceQsp, DisplayItemService displayItemService) {
this.interfaceQsp = interfaceQsp;
this.displayItemService = displayItemService;
}
@Override
public void beforeJob(JobExecution jobExecution) {
log.info("Job 시작: 초기화 메서드 호출 중...");
try {
this.priceSyncResponse =
interfaceQsp.callApiData(
HttpMethod.GET, qspInterfaceUrl + "?allYn=N", null, PriceSyncResponse.class);
log.info("API 호출 완료, 항목 수: {}", this.priceSyncResponse.getModulePriceList().size());
} catch (Exception e) {
log.error("priceSyncResponse 갱신 중 오류: {}", e.getMessage());
}
}
@Bean
public Job priceJob(JobRepository jobRepository, Step modulePriceStep, Step bosPriceStep) {
return new JobBuilder("priceJob", jobRepository)
.start(modulePriceStep)
.next(bosPriceStep)
.listener(this)
.build();
}
private <T> Step buildStep(
String stepName,
JobRepository jobRepository,
PlatformTransactionManager transactionManager,
ItemReader<T> reader,
ItemWriter<T> writer) {
return new StepBuilder(stepName, jobRepository)
.<T, T>chunk(100, transactionManager)
.reader(reader)
.writer(writer)
.build();
}
@Bean
public Step modulePriceStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return buildStep(
"modulePriceStep",
jobRepository,
transactionManager,
modulePriceListReader(),
createWriter(
(items) -> {
try {
log.debug("Module Price batch processing {} items", items.size());
displayItemService.setPriceSyncSave(items);
log.debug("Successfully processed Module Price batch");
} catch (Exception e) {
log.error("Error processing Module Price batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process Module Price batch", e);
}
},
"module price"));
}
@Bean
public Step bosPriceStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return buildStep(
"bosPriceStep",
jobRepository,
transactionManager,
bosPriceListReader(),
createWriter(
(items) -> {
try {
log.debug("Bos Price batch processing {} items", items.size());
displayItemService.setPriceSyncSave(items);
log.debug("Successfully processed Bos Price batch");
} catch (Exception e) {
log.error("Error processing Bos Price batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process Bos Price batch", e);
}
},
"bos price"));
}
private <T> ListItemReader<T> createReader(List<T> items, String readerName) {
log.info("{}Reader 호출됨...", readerName);
return new ListItemReader<>(items != null ? items : Collections.emptyList());
}
@Bean
@StepScope
public ListItemReader<PriceItemSyncResponse> modulePriceListReader() {
return createReader(
priceSyncResponse != null ? priceSyncResponse.getModulePriceList() : null, "module");
}
@Bean
@StepScope
public ListItemReader<PriceItemSyncResponse> bosPriceListReader() {
return createReader(
priceSyncResponse != null ? priceSyncResponse.getBosPriceList() : null, "bos");
}
private <T> ItemWriter<T> createWriter(Consumer<List<T>> processor, String writerName) {
return items -> {
try {
List<T> itemList = new ArrayList<>(items.getItems());
processor.accept(itemList);
log.info("{}Writer: {} items 처리 완료", writerName, items.size());
} catch (Exception e) {
log.error("{}Writer 오류: {}", writerName, e.getMessage());
throw e;
}
};
}
}

View File

@ -0,0 +1,170 @@
package com.interplug.qcast.batch.master;
import com.interplug.qcast.biz.specialNote.SpecialNoteService;
import com.interplug.qcast.biz.specialNote.dto.SpecialNoteItemRequest;
import com.interplug.qcast.biz.specialNote.dto.SpecialNoteRequest;
import com.interplug.qcast.biz.specialNote.dto.SpecialNoteSyncResponse;
import com.interplug.qcast.util.InterfaceQsp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
@Slf4j
public class SpecialNoteDispItemJobConfiguration implements JobExecutionListener {
private final InterfaceQsp interfaceQsp;
private final SpecialNoteService specialNoteService;
@Value("${qsp.master-special-note-disp-item-batch-url}")
private String qspMasterSpecialNoteDispItemBatchUrl;
private SpecialNoteSyncResponse SpecialNoteDispItemSyncResponse;
public SpecialNoteDispItemJobConfiguration(
InterfaceQsp interfaceQsp, SpecialNoteService specialNoteService) {
this.interfaceQsp = interfaceQsp;
this.specialNoteService = specialNoteService;
}
@Override
public void beforeJob(JobExecution jobExecution) {
log.info("Job 시작: 초기화 메서드 호출 중...");
try {
this.SpecialNoteDispItemSyncResponse =
interfaceQsp.callApiData(
HttpMethod.GET,
qspMasterSpecialNoteDispItemBatchUrl,
null,
SpecialNoteSyncResponse.class);
log.info(
"API 호출 완료, 항목 수: {}", this.SpecialNoteDispItemSyncResponse.getSdOrderSpnList().size());
} catch (Exception e) {
log.error("specialNoteDispItemSyncResponse 갱신 중 오류: {}", e.getMessage());
}
}
@Bean
public Job specialNoteDispItemAdditionalJob(
JobRepository jobRepository, Step specialNoteStep, Step specialNoteItemStep) {
return new JobBuilder("specialNoteDispItemAdditionalJob", jobRepository)
.start(specialNoteStep)
.next(specialNoteItemStep)
.listener(this)
.build();
}
private <T> Step buildStep(
String stepName,
JobRepository jobRepository,
PlatformTransactionManager transactionManager,
ItemReader<T> reader,
ItemWriter<T> writer) {
return new StepBuilder(stepName, jobRepository)
.<T, T>chunk(10, transactionManager)
.reader(reader)
.writer(writer)
.build();
}
@Bean
public Step specialNoteStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return buildStep(
"specialNoteStep",
jobRepository,
transactionManager,
specialNoteListReader(),
createWriter(
(items) -> {
try {
log.debug("Special Note batch processing {} items", items.size());
specialNoteService.setSpecialNoteBatch(items);
log.debug("Successfully processed Special Note batch");
} catch (Exception e) {
log.error("Error processing Special Note batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process Special Note batch", e);
}
},
"specialNote"));
}
@Bean
public Step specialNoteItemStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return buildStep(
"specialNoteItemStep",
jobRepository,
transactionManager,
specialNoteItemListReader(),
createWriter(
(items) -> {
try {
log.debug("Special Note Item batch processing {} items", items.size());
specialNoteService.setSpecialNoteItemBatch(items);
log.debug("Successfully processed Special Note Item batch");
} catch (Exception e) {
log.error("Error processing Special Note Item batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process Special Note Item batch", e);
}
},
"specialNoteItem"));
}
private <T> ListItemReader<T> createReader(List<T> items, String readerName) {
log.info("{}Reader 호출됨...", readerName);
return new ListItemReader<>(items != null ? items : Collections.emptyList());
}
@Bean
@StepScope
public ListItemReader<SpecialNoteRequest> specialNoteListReader() {
return createReader(
SpecialNoteDispItemSyncResponse != null
? SpecialNoteDispItemSyncResponse.getSdOrderSpnList()
: null,
"specialNote");
}
@Bean
@StepScope
public ListItemReader<SpecialNoteItemRequest> specialNoteItemListReader() {
return createReader(
SpecialNoteDispItemSyncResponse != null
? SpecialNoteDispItemSyncResponse.getSdOrderSpnItemList()
: null,
"specialNoteItem");
}
private <T> ItemWriter<T> createWriter(Consumer<List<T>> processor, String writerName) {
return items -> {
try {
List<T> itemList = new ArrayList<>(items.getItems());
processor.accept(itemList);
log.info("{}Writer: {} items 처리 완료", writerName, items.size());
} catch (Exception e) {
log.error("{}Writer 오류: {}", writerName, e.getMessage());
throw e;
}
};
}
}

View File

@ -1,12 +1,16 @@
package com.interplug.qcast.batch.master; package com.interplug.qcast.batch.master;
import com.interplug.qcast.biz.displayItem.DisplayItemService;
import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest;
import com.interplug.qcast.biz.storeFavorite.StoreFavoriteService; import com.interplug.qcast.biz.storeFavorite.StoreFavoriteService;
import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteRequest; import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteRequest;
import com.interplug.qcast.biz.user.UserService; import com.interplug.qcast.biz.user.UserService;
import com.interplug.qcast.biz.user.dto.StoreRequest; import com.interplug.qcast.biz.user.dto.StoreRequest;
import com.interplug.qcast.biz.user.dto.StoreSyncResponse; import com.interplug.qcast.biz.user.dto.StoreSyncResponse;
import com.interplug.qcast.biz.user.dto.StoreSyncResquest;
import com.interplug.qcast.biz.user.dto.UserRequest; import com.interplug.qcast.biz.user.dto.UserRequest;
import com.interplug.qcast.util.InterfaceQsp; import com.interplug.qcast.util.InterfaceQsp;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -32,6 +36,7 @@ public class StoreJobConfiguration implements JobExecutionListener {
private final InterfaceQsp interfaceQsp; private final InterfaceQsp interfaceQsp;
private final UserService userService; private final UserService userService;
private final StoreFavoriteService storeFavService; private final StoreFavoriteService storeFavService;
private final DisplayItemService displayItemService;
@Value("${qsp.master-store-batch-url}") @Value("${qsp.master-store-batch-url}")
private String qspMasterStoreBatchUrl; private String qspMasterStoreBatchUrl;
@ -39,19 +44,26 @@ public class StoreJobConfiguration implements JobExecutionListener {
private StoreSyncResponse storeSyncResponse; private StoreSyncResponse storeSyncResponse;
public StoreJobConfiguration( public StoreJobConfiguration(
InterfaceQsp interfaceQsp, UserService userService, StoreFavoriteService storeFavService) { InterfaceQsp interfaceQsp,
UserService userService,
StoreFavoriteService storeFavService,
DisplayItemService displayItemService) {
this.interfaceQsp = interfaceQsp; this.interfaceQsp = interfaceQsp;
this.userService = userService; this.userService = userService;
this.storeFavService = storeFavService; this.storeFavService = storeFavService;
this.displayItemService = displayItemService;
} }
@Override @Override
public void beforeJob(JobExecution jobExecution) { public void beforeJob(JobExecution jobExecution) {
log.info("Job 시작: 초기화 메서드 호출 중..."); log.info("Job 시작: 초기화 메서드 호출 중...");
try { try {
StoreSyncResquest storeSyncResquest = new StoreSyncResquest();
storeSyncResquest.setAllYn("N"); // 전체가 아닌 날짜조건으로 조회
this.storeSyncResponse = this.storeSyncResponse =
interfaceQsp.callApiData( interfaceQsp.callApiData(
HttpMethod.GET, qspMasterStoreBatchUrl, null, StoreSyncResponse.class); HttpMethod.GET, qspMasterStoreBatchUrl, storeSyncResquest, StoreSyncResponse.class);
log.info("API 호출 완료, 항목 수: {}", this.storeSyncResponse.getStoreList().size()); log.info("API 호출 완료, 항목 수: {}", this.storeSyncResponse.getStoreList().size());
} catch (Exception e) { } catch (Exception e) {
log.error("storeSyncResponse 갱신 중 오류: {}", e.getMessage()); log.error("storeSyncResponse 갱신 중 오류: {}", e.getMessage());
@ -60,11 +72,16 @@ public class StoreJobConfiguration implements JobExecutionListener {
@Bean @Bean
public Job storeAdditionalJob( public Job storeAdditionalJob(
JobRepository jobRepository, Step storeStep, Step userStep, Step favoriteStep) { JobRepository jobRepository,
Step storeStep,
Step userStep,
Step favoriteStep,
Step storeDispItemStep) {
return new JobBuilder("storeAdditionalJob", jobRepository) return new JobBuilder("storeAdditionalJob", jobRepository)
.start(storeStep) .start(storeStep)
.next(userStep) .next(userStep)
.next(favoriteStep) .next(favoriteStep)
.next(storeDispItemStep)
.listener(this) .listener(this)
.build(); .build();
} }
@ -93,12 +110,9 @@ public class StoreJobConfiguration implements JobExecutionListener {
createWriter( createWriter(
(items) -> { (items) -> {
try { try {
log.debug("Store batch processing {} items", items.size());
userService.setStoreBatch(items); userService.setStoreBatch(items);
log.debug("Successfully processed store batch");
} catch (Exception e) { } catch (Exception e) {
log.error("Error processing store batch: {}", e.getMessage(), e); log.error("Error processing store batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process store batch", e);
} }
}, },
"store")); "store"));
@ -114,12 +128,9 @@ public class StoreJobConfiguration implements JobExecutionListener {
createWriter( createWriter(
(items) -> { (items) -> {
try { try {
log.debug("User batch processing {} items", items.size());
userService.setUserBatch(items); userService.setUserBatch(items);
log.debug("Successfully processed user batch");
} catch (Exception e) { } catch (Exception e) {
log.error("Error processing user batch: {}", e.getMessage(), e); log.error("Error processing user batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process user batch", e);
} }
}, },
"user")); "user"));
@ -136,17 +147,36 @@ public class StoreJobConfiguration implements JobExecutionListener {
createWriter( createWriter(
(items) -> { (items) -> {
try { try {
log.debug("Favorite batch processing {} items", items.size());
storeFavService.setStoreFavoriteBatch(items); storeFavService.setStoreFavoriteBatch(items);
log.debug("Successfully processed favorite batch");
} catch (Exception e) { } catch (Exception e) {
log.error("Error processing favorite batch: {}", e.getMessage(), e); log.error("Error processing favorite batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process favorite batch", e);
} }
}, },
"favorite")); "favorite"));
} }
@Bean
public Step storeDispItemStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return buildStep(
"storeDispItemStep",
jobRepository,
transactionManager,
storeDispItemListReader(),
createWriter(
(items) -> {
try {
log.debug("Store Disp Item batch processing {} items", items.size());
displayItemService.setStoreDispItemBatch(items);
log.debug("Successfully processed Store Disp Item batch");
} catch (Exception e) {
log.error("Error processing Store Disp Item batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process Store Disp Item batch", e);
}
},
"storeDispItem"));
}
private <T> ListItemReader<T> createReader(List<T> items, String readerName) { private <T> ListItemReader<T> createReader(List<T> items, String readerName) {
log.info("{}Reader 호출됨...", readerName); log.info("{}Reader 호출됨...", readerName);
return new ListItemReader<>(items != null ? items : Collections.emptyList()); return new ListItemReader<>(items != null ? items : Collections.emptyList());
@ -172,10 +202,18 @@ public class StoreJobConfiguration implements JobExecutionListener {
storeSyncResponse != null ? storeSyncResponse.getStoreFavList() : null, "storeFav"); storeSyncResponse != null ? storeSyncResponse.getStoreFavList() : null, "storeFav");
} }
@Bean
@StepScope
public ListItemReader<DisplayItemRequest> storeDispItemListReader() {
return createReader(
storeSyncResponse != null ? storeSyncResponse.getStoreDispItemList() : null,
"storeDispItem");
}
private <T> ItemWriter<T> createWriter(Consumer<List<T>> processor, String writerName) { private <T> ItemWriter<T> createWriter(Consumer<List<T>> processor, String writerName) {
return items -> { return items -> {
try { try {
List<T> itemList = (List<T>) items.getItems(); List<T> itemList = new ArrayList<>(items.getItems());
processor.accept(itemList); processor.accept(itemList);
log.info("{}Writer: {} items 처리 완료", writerName, items.size()); log.info("{}Writer: {} items 처리 완료", writerName, items.size());
} catch (Exception e) { } catch (Exception e) {

View File

@ -0,0 +1,89 @@
package com.interplug.qcast.batch.system;
import com.fasterxml.jackson.core.type.TypeReference;
import com.interplug.qcast.biz.user.UserService;
import com.interplug.qcast.biz.user.dto.AdminUserSyncResponse;
import com.interplug.qcast.util.InterfaceQsp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;
/** 관리자 유저 동기화 배치 */
@Configuration
public class AdminUserConfiguration implements JobExecutionListener {
private final UserService userService;
private final InterfaceQsp interfaceQsp;
List<AdminUserSyncResponse> adminUserSyncList;
@Value("${qsp.master-admin-user-batch-url}")
private String qspInterfaceUrl;
public AdminUserConfiguration(UserService userService, InterfaceQsp interfaceQsp) {
this.userService = userService;
this.interfaceQsp = interfaceQsp;
}
@Bean
public Job adminUserJob(JobRepository jobRepository, Step adminUserStep) {
return new JobBuilder("adminUserJob", jobRepository).start(adminUserStep).build();
}
@Bean
public Step adminUserStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception {
return new StepBuilder("adminUserStep", jobRepository)
.<AdminUserSyncResponse, AdminUserSyncResponse>chunk(100, transactionManager)
.reader(adminUserReader())
.processor(adminUserProcessor())
.writer(adminUserWriter())
.build();
}
@Bean
@StepScope
public ListItemReader<AdminUserSyncResponse> adminUserReader() throws Exception {
this.adminUserSyncList =
interfaceQsp.callApiData(
HttpMethod.GET,
qspInterfaceUrl,
null,
new TypeReference<List<AdminUserSyncResponse>>() {});
return (adminUserSyncList != null)
? new ListItemReader<>(adminUserSyncList)
: new ListItemReader<>(Collections.emptyList());
}
@Bean
public ItemProcessor<AdminUserSyncResponse, AdminUserSyncResponse> adminUserProcessor() {
return item -> {
if (item.getCategory() != null && item.getCategory().length() > 20) {
item.setCategory(item.getCategory().substring(0, 20));
}
return item;
};
}
@Bean
public ItemWriter<AdminUserSyncResponse> adminUserWriter() {
return items -> {
userService.setAdminUserSyncSave(new ArrayList<>(items.getItems()));
};
}
}

View File

@ -0,0 +1,85 @@
package com.interplug.qcast.batch.system;
import com.fasterxml.jackson.core.type.TypeReference;
import com.interplug.qcast.biz.user.UserService;
import com.interplug.qcast.biz.user.dto.BusinessChargerSyncResponse;
import com.interplug.qcast.util.InterfaceQsp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;
/** 영업사원 동기화 배치 */
@Configuration
public class BusinessChargerConfiguration implements JobExecutionListener {
private final UserService userService;
private final InterfaceQsp interfaceQsp;
List<BusinessChargerSyncResponse> businessChargerSyncList;
@Value("${qsp.master-business-charger-batch-url}")
private String qspInterfaceUrl;
public BusinessChargerConfiguration(UserService userService, InterfaceQsp interfaceQsp) {
this.userService = userService;
this.interfaceQsp = interfaceQsp;
}
@Bean
public Job businessChargerJob(JobRepository jobRepository, Step businessChargerStep) {
return new JobBuilder("businessChargerJob", jobRepository).start(businessChargerStep).build();
}
@Bean
public Step businessChargerStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) throws Exception {
return new StepBuilder("businessChargerStep", jobRepository)
.<BusinessChargerSyncResponse, BusinessChargerSyncResponse>chunk(100, transactionManager)
.reader(businessChargerReader())
.processor(businessChargerProcessor())
.writer(businessChargerWriter())
.build();
}
@Bean
@StepScope
public ListItemReader<BusinessChargerSyncResponse> businessChargerReader() throws Exception {
this.businessChargerSyncList =
interfaceQsp.callApiData(
HttpMethod.GET,
qspInterfaceUrl,
null,
new TypeReference<List<BusinessChargerSyncResponse>>() {});
return (businessChargerSyncList != null)
? new ListItemReader<>(businessChargerSyncList)
: new ListItemReader<>(Collections.emptyList());
}
@Bean
public ItemProcessor<BusinessChargerSyncResponse, BusinessChargerSyncResponse>
businessChargerProcessor() {
return item -> item;
}
@Bean
public ItemWriter<BusinessChargerSyncResponse> businessChargerWriter() {
return items -> {
userService.setBusinessChargerSyncSave(new ArrayList<>(items.getItems()));
};
}
}

View File

@ -0,0 +1,140 @@
package com.interplug.qcast.batch.system;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;
import com.interplug.qcast.biz.commCode.CommCodeService;
import com.interplug.qcast.biz.commCode.dto.CommonCodeSyncResponse;
import com.interplug.qcast.biz.commCode.dto.DetailCodeRequest;
import com.interplug.qcast.biz.commCode.dto.HeadCodeRequest;
import com.interplug.qcast.util.InterfaceQsp;
import lombok.extern.slf4j.Slf4j;
/** 공통코드 동기화 배치 */
@Configuration
@Slf4j
public class CommonCodeConfiguration implements JobExecutionListener {
private final InterfaceQsp interfaceQsp;
private final CommCodeService commCodeService;
@Value("${qsp.system-commonCode-batch-url}")
private String qspInterfaceUrl;
private CommonCodeSyncResponse commonCodeSyncResponse;
public CommonCodeConfiguration(InterfaceQsp interfaceQsp, CommCodeService commCodeService) {
this.interfaceQsp = interfaceQsp;
this.commCodeService = commCodeService;
}
@Override
public void beforeJob(JobExecution jobExecution) {
log.info("Job 시작: 초기화 메서드 호출 중...");
try {
this.commonCodeSyncResponse = interfaceQsp.callApiData(HttpMethod.GET, qspInterfaceUrl, null,
CommonCodeSyncResponse.class);
log.info("API 호출 완료, 항목 수: {}", this.commonCodeSyncResponse.getApiHeadCdList().size());
log.info("API 호출 완료, 항목 수: {}", this.commonCodeSyncResponse.getApiCommCdList().size());
} catch (Exception e) {
log.error("commonCodeSyncResponse 갱신 중 오류: {}", e.getMessage());
}
}
@Bean
public Job commonCodeJob(JobRepository jobRepository, Step headCodeStep, Step commonCodeStep) {
return new JobBuilder("commonCodeJob", jobRepository).start(headCodeStep).next(commonCodeStep)
.listener(this).build();
}
private <T> Step buildStep(String stepName, JobRepository jobRepository,
PlatformTransactionManager transactionManager, ItemReader<T> reader, ItemWriter<T> writer) {
return new StepBuilder(stepName, jobRepository).<T, T>chunk(10, transactionManager)
.reader(reader).writer(writer).build();
}
@Bean
public Step headCodeStep(JobRepository jobRepository,
PlatformTransactionManager transactionManager) {
return buildStep("headCodeStep", jobRepository, transactionManager, headCodeListReader(),
createWriter((items) -> {
try {
log.debug("HeadCode batch processing {} items", items.size());
commCodeService.setHeaderCodeSyncSave(items);
log.debug("Successfully processed headCommonCode batch");
} catch (Exception e) {
log.error("Error processing headCommonCode batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process headCommonCode batch", e);
}
}, "headCode"));
}
@Bean
public Step commonCodeStep(JobRepository jobRepository,
PlatformTransactionManager transactionManager) {
return buildStep("commonCodeStep", jobRepository, transactionManager, commonCodeListReader(),
createWriter((items) -> {
try {
log.debug("commonCodeStep batch processing {} items", items.size());
commCodeService.setCommonCodeSyncSave(items);
log.debug("Successfully processed commonCode batch");
} catch (Exception e) {
log.error("Error processing commonCode batch: {}", e.getMessage(), e);
throw new RuntimeException("Failed to process commonCode batch", e);
}
}, "commonCode"));
}
private <T> ListItemReader<T> createReader(List<T> items, String readerName) {
log.info("{}Reader 호출됨...", readerName);
return new ListItemReader<>(items != null ? items : Collections.emptyList());
}
@Bean
@StepScope
public ListItemReader<HeadCodeRequest> headCodeListReader() {
return createReader(
commonCodeSyncResponse != null ? commonCodeSyncResponse.getApiHeadCdList() : null,
"headCode");
}
@Bean
@StepScope
public ListItemReader<DetailCodeRequest> commonCodeListReader() {
return createReader(
commonCodeSyncResponse != null ? commonCodeSyncResponse.getApiCommCdList() : null,
"commonCode");
}
private <T> ItemWriter<T> createWriter(Consumer<List<T>> processor, String writerName) {
return items -> {
try {
List<T> itemList = new ArrayList<>(items.getItems());
processor.accept(itemList);
log.info("{}Writer: {} items 처리 완료", writerName, items.size());
} catch (Exception e) {
log.error("{}Writer 오류: {}", writerName, e.getMessage());
throw e;
}
};
}
}

View File

@ -3,6 +3,7 @@ package com.interplug.qcast.biz;
import com.interplug.qcast.config.message.Messages; import com.interplug.qcast.config.message.Messages;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -12,11 +13,33 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api/main") @RequestMapping("/api/main")
public class MainController { public class MainController {
@Autowired @Autowired Messages message;
Messages message;
@Value("${front.url}")
private String frontUrl;
@GetMapping @GetMapping
public String Main() { public MainTestResponse Main() {
return message.getMessage("example.msg.001"); MainTestResponse response =
new MainTestResponse(message.getMessage("example.msg.001"), frontUrl);
return response;
}
class MainTestResponse {
private String message;
private String frontUrl;
public MainTestResponse(String message, String frontUrl) {
this.message = message;
this.frontUrl = frontUrl;
}
public String getMessage() {
return message;
}
public String getFrontUrl() {
return frontUrl;
}
} }
} }

View File

@ -2,15 +2,14 @@ package com.interplug.qcast.biz.canvasBasicSetting;
import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingInfo; import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingInfo;
import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingResponse; import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingResponse;
import com.interplug.qcast.biz.canvasBasicSetting.dto.RoofAllocationSettingInfo;
import com.interplug.qcast.config.Exception.QcastException;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -21,24 +20,52 @@ import org.springframework.web.bind.annotation.*;
@Tag(name = "CanvasBasicSettingController", description = "Canvas Basic Setting 관련 API") @Tag(name = "CanvasBasicSettingController", description = "Canvas Basic Setting 관련 API")
public class CanvasBasicSettingController { public class CanvasBasicSettingController {
private final CanvasBasicSettingService canvasBasicSettingService; private final CanvasBasicSettingService canvasBasicSettingService;
@Operation(description = "Canvas Basic Setting 정보를 조회 한다.") @Operation(description = "Canvas Basic Setting 정보를 조회 한다.")
@GetMapping("/canvas-basic-settings/by-object/{objectNo}") @GetMapping("/canvas-basic-settings/by-object/{objectNo}/{planNo}")
public List<CanvasBasicSettingResponse> selectCanvasBasicSetting(@PathVariable String objectNo) { public List<CanvasBasicSettingResponse> selectCanvasBasicSetting(@PathVariable String objectNo, @PathVariable Integer planNo)
throws QcastException {
log.debug("Basic Setting 조회 ::::: " + objectNo); log.debug("Basic Setting 조회 ::::: " + objectNo + " : " + planNo);
return canvasBasicSettingService.selectCanvasBasicSetting(objectNo); return canvasBasicSettingService.selectCanvasBasicSetting(objectNo, planNo);
} }
@Operation(description = "Canvas Basic Setting 정보를 등록 한다.") @Operation(description = "Canvas Basic Setting 정보를 등록 한다.")
@PostMapping("/canvas-basic-settings") @PostMapping("/canvas-basic-settings")
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
public Map<String, String> insertCanvasBasicSetting(@RequestBody CanvasBasicSettingInfo csi) { public Map<String, String> insertCanvasBasicSetting(@RequestBody CanvasBasicSettingInfo csi) throws QcastException {
log.debug("Basic Setting 등록 ::::: " + csi.getObjectNo()); log.debug("Basic Setting 등록 ::::: " + csi.getObjectNo());
return canvasBasicSettingService.insertCanvasBasicSetting(csi); return canvasBasicSettingService.insertCanvasBasicSetting(csi);
} }
@Operation(description = "Canvas Basic Setting 정보를 삭제 한다.")
@DeleteMapping("/canvas-basic-settings/delete-basic-settings/{objectNo}/{planNo}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteCanvasBasicSetting(@PathVariable String objectNo, @PathVariable Integer planNo) throws QcastException {
log.debug("Basic Setting 삭제 ::::: " + objectNo + " : " + planNo);
canvasBasicSettingService.deleteCanvasBasicSetting(objectNo, planNo);
}
@Operation(description = "지붕면 할당 정보를 등록 한다.")
@PostMapping("/roof-allocation-settings")
@ResponseStatus(HttpStatus.CREATED)
public Map<String, String> insertRoofAllocSetting(@RequestBody RoofAllocationSettingInfo rasi) throws QcastException {
log.debug("지붕면 할당 등록 ::::: " + rasi.getObjectNo());
return canvasBasicSettingService.insertRoofAllocSetting(rasi);
}
@Operation(description = "Canvas 지붕재추가 Setting 정보를 삭제 한다.")
@DeleteMapping("/canvas-basic-settings/delete-RoofMaterials/{objectNo}/{planNo}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteRoofMaterialsAdd(@PathVariable String objectNo, @PathVariable Integer planNo) throws QcastException {
canvasBasicSettingService.deleteRoofMaterialsAdd(objectNo, planNo);
}
} }

View File

@ -6,21 +6,42 @@ import org.apache.ibatis.annotations.Mapper;
import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingInfo; import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingInfo;
import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingResponse; import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingResponse;
import com.interplug.qcast.biz.canvasBasicSetting.dto.RoofAllocationInfo;
import com.interplug.qcast.biz.canvasBasicSetting.dto.RoofMaterialsAddInfo; import com.interplug.qcast.biz.canvasBasicSetting.dto.RoofMaterialsAddInfo;
@Mapper @Mapper
public interface CanvasBasicSettingMapper { public interface CanvasBasicSettingMapper {
// Canvas Basic Setting 조회(objectNo) // Canvas Basic Setting 유무 조회
public List<CanvasBasicSettingResponse> selectCanvasBasicSetting(String objectNo); public CanvasBasicSettingInfo getCanvasBasicSettingCnt(String objectNo, Integer planNo);
// Canvas Basic Setting 등록
public void insertCanvasBasicSetting(CanvasBasicSettingInfo csi);
// Canvas 지붕재추가 Setting 등록
public void insertRoofMaterialsAdd(RoofMaterialsAddInfo rma);
// Canvas 지붕재추가 Setting 삭제 // Canvas Basic Setting 조회(objectNo)
public void deleteRoofMaterialsAdd(String objectNo); public List<CanvasBasicSettingResponse> selectCanvasBasicSetting(String objectNo, Integer planNo);
// Canvas Basic Setting 등록
public void insertCanvasBasicSetting(CanvasBasicSettingInfo csi);
// Canvas Basic Setting 수정
public void updateCanvasBasicSetting(CanvasBasicSettingInfo csi);
// Canvas Basic Setting 삭제
public void deleteCanvasBasicSetting(String objectNo, Integer planNo);
// Canvas 지붕재추가 Setting 유무 조회
public RoofMaterialsAddInfo getRoofMaterialsCnt(String objectNo, Integer planNo);
// Canvas 지붕재추가 Setting 등록
public void insertRoofMaterialsAdd(RoofMaterialsAddInfo rma);
// Canvas 지붕재추가 Setting 수정
public void updateRoofMaterialsAdd(RoofMaterialsAddInfo rma);
// 지붕면 할당 Setting 등록
public void insertRoofAllocation(RoofAllocationInfo rai);
// Canvas 지붕재추가 Setting 삭제
public void deleteRoofMaterialsAdd(String objectNo, Integer planNo);
// Canvas 하제비치 update
public void updateHajebichRoofMaterialsAdd(CanvasBasicSettingResponse canvasBasicSettingResponse);
} }

View File

@ -1,61 +1,150 @@
package com.interplug.qcast.biz.canvasBasicSetting; package com.interplug.qcast.biz.canvasBasicSetting;
import lombok.RequiredArgsConstructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingInfo; import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingInfo;
import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingResponse; import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingResponse;
import com.interplug.qcast.biz.canvasBasicSetting.dto.RoofAllocationInfo;
import com.interplug.qcast.biz.canvasBasicSetting.dto.RoofAllocationSettingInfo;
import com.interplug.qcast.biz.canvasBasicSetting.dto.RoofMaterialsAddInfo; import com.interplug.qcast.biz.canvasBasicSetting.dto.RoofMaterialsAddInfo;
import com.interplug.qcast.config.Exception.ErrorCode;
import com.interplug.qcast.config.Exception.QcastException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class CanvasBasicSettingService { public class CanvasBasicSettingService {
private final CanvasBasicSettingMapper canvasBasicSettingMapper; private final CanvasBasicSettingMapper canvasBasicSettingMapper;
// Canvas Basic Setting 조회(objectNo) //Canvas Basic Setting 조회(objectNo)
public List<CanvasBasicSettingResponse> selectCanvasBasicSetting(String objectNo) { public List<CanvasBasicSettingResponse> selectCanvasBasicSetting(String objectNo, Integer planNo) throws QcastException {
return canvasBasicSettingMapper.selectCanvasBasicSetting(objectNo); try {
return canvasBasicSettingMapper.selectCanvasBasicSetting(objectNo, planNo);
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
} }
// Canvas Basic Setting 등록 // Canvas Basic Setting 등록
public Map<String, String> insertCanvasBasicSetting(CanvasBasicSettingInfo csi) { public Map<String, String> insertCanvasBasicSetting(CanvasBasicSettingInfo csi) throws QcastException {
Map<String, String> response = new HashMap<>(); Map<String, String> response = new HashMap<>();
if (csi.getObjectNo() == null && csi.getPlanNo() == null) {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"올바르지 않은 입력값입니다.");
}
try { try {
// 도면/치수/각도 정보 insert/update // 먼저 데이터가 존재하는지 확인
canvasBasicSettingMapper.insertCanvasBasicSetting(csi); CanvasBasicSettingInfo cntData = canvasBasicSettingMapper.getCanvasBasicSettingCnt(csi.getObjectNo(), csi.getPlanNo());
log.debug("cntData ::::: " + cntData);
// 데이터가 존재하지 않으면 insert
if (cntData.getRoofCnt().intValue() < 1) {
// 도면/치수/각도 정보 insert
canvasBasicSettingMapper.insertCanvasBasicSetting(csi);
// for-each 루프를 사용하여 지붕재추가 Setting
for (RoofMaterialsAddInfo rma : csi.getRoofMaterialsAddList()) {
rma.setObjectNo(csi.getObjectNo());
rma.setPlanNo(csi.getPlanNo());
// 신규 지붕재추가 정보 insert
canvasBasicSettingMapper.insertRoofMaterialsAdd(rma);
}
response.put("objectNo", csi.getObjectNo());
response.put("returnMessage", "common.message.confirm.mark");
} else {
// 도면/치수/각도 정보 update
canvasBasicSettingMapper.updateCanvasBasicSetting(csi);
// for-each 루프를 사용하여 지붕재추가 Setting
for (RoofMaterialsAddInfo rma : csi.getRoofMaterialsAddList()) {
rma.setObjectNo(csi.getObjectNo());
rma.setPlanNo(csi.getPlanNo());
// 신규 지붕재추가 정보 insert
canvasBasicSettingMapper.updateRoofMaterialsAdd(rma);
}
response.put("objectNo", csi.getObjectNo());
response.put("returnMessage", "common.message.confirm.mark");
}
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
// 생성된 objectNo 반환
return response;
}
// Canvas Basic Setting 삭제
public void deleteCanvasBasicSetting(String objectNo, Integer planNo) throws QcastException {
if ((objectNo == null || objectNo.trim().isEmpty()) && (planNo == null)) {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"올바르지 않은 입력값입니다.");
}
try {
// Canvas Basic Setting 정보 삭제
canvasBasicSettingMapper.deleteCanvasBasicSetting(objectNo, planNo);
// 지붕재추가 정보 삭제
canvasBasicSettingMapper.deleteRoofMaterialsAdd(objectNo, planNo);
} catch (Exception e) {
if (e instanceof QcastException) throw e;
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
// 지붕면 할당 Setting 등록
public Map<String, String> insertRoofAllocSetting(RoofAllocationSettingInfo rasi) throws QcastException {
Map<String, String> response = new HashMap<>();
if (rasi.getObjectNo() == null && rasi.getPlanNo() == null) {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"올바르지 않은 입력값입니다.");
}
try {
// 기존 지붕재추가 정보 삭제 insert // 기존 지붕재추가 정보 삭제 insert
canvasBasicSettingMapper.deleteRoofMaterialsAdd(csi.getObjectNo()); canvasBasicSettingMapper.deleteRoofMaterialsAdd(rasi.getObjectNo(), rasi.getPlanNo());
int roofSeq = 1; // for-each 루프를 사용하여 지붕재추가 Setting
// for-each 루프를 사용하여 지붕재추가 Setting for (RoofAllocationInfo rai : rasi.getRoofAllocationList()) {
for (RoofMaterialsAddInfo rma : csi.getRoofMaterialsAddList()) { rai.setObjectNo(rasi.getObjectNo());
rai.setPlanNo(rasi.getPlanNo());
rma.setObjectNo(csi.getObjectNo()); canvasBasicSettingMapper.insertRoofAllocation(rai);
rma.setRoofSeq(roofSeq++); //roofSeq는 순차적으로 새로 생성하여 insert
// 신규 지붕재추가 정보 insert
canvasBasicSettingMapper.insertRoofMaterialsAdd(rma);
} }
response.put("objectNo", csi.getObjectNo()); response.put("objectNo", rasi.getObjectNo());
response.put("returnMessage", "common.message.confirm.mark"); response.put("returnMessage", "common.message.confirm.mark");
} catch (Exception e) { } catch (Exception e) {
response.put("objectNo", csi.getObjectNo()); throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
response.put("returnMessage", "common.message.save.error");
} }
// 생성된 objectNo 반환 // 생성된 objectNo 반환
return response; return response;
} }
// 지붕재추가 삭제
public void deleteRoofMaterialsAdd(String objectNo, Integer planNo) throws QcastException {
if ((objectNo == null || objectNo.trim().isEmpty()) && (planNo == null)) {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"올바르지 않은 입력값입니다.");
}
try {
canvasBasicSettingMapper.deleteRoofMaterialsAdd(objectNo, planNo);
} catch (Exception e) {
if (e instanceof QcastException) throw e;
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
} }

View File

@ -11,8 +11,10 @@ import lombok.Setter;
public class CanvasBasicSettingInfo { public class CanvasBasicSettingInfo {
private String objectNo; //견적서 번호 private String objectNo; //견적서 번호
private int roofSizeSet; //치수(복사도/실측값/육지붕) private Integer planNo; // plan 번호
private Integer roofSizeSet; //치수(복사도/실측값/육지붕)
private String roofAngleSet; //각도(경사/각도) private String roofAngleSet; //각도(경사/각도)
private Integer roofCnt; //존재여부
private Date registDatetime; //생성일시 private Date registDatetime; //생성일시
private Date lastEditDatetime; //수정일시 private Date lastEditDatetime; //수정일시

View File

@ -6,16 +6,19 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public class CanvasBasicSettingResponse { public class CanvasBasicSettingResponse {
private String objectNo; //견적서 번호 private String objectNo; // 견적서 번호
private int roofDrawingSet; //도면(치수) private Integer planNo; // plan 번호
private int roofSizeSet; //치수(복사도/실측값/육지붕) private Integer roofSizeSet; // 치수(복사도/실측값/육지붕)
private String roofAngleSet; //각도(경사/각도) private String roofAngleSet; // 각도(경사/각도)
private int roofSeq; //순번 SEQ private boolean roofApply; // 적용
private int roofType; //타입 private Integer roofSeq; // 순번 SEQ
private int roofWidth; //넓이 private String roofMatlCd; // 타입
private int roofHeight; //높이 private Integer roofWidth; // 넓이
private int roofGap; //간격 private Integer roofHeight; // 높이
private String roofLayout; //방식 private Integer roofHajebichi; // 하제비치
private String roofGap; // 간격
} private String roofLayout; // 방식
private Float roofPitch; // 경사도
private Float roofAngle; // 각도
}

View File

@ -0,0 +1,27 @@
package com.interplug.qcast.biz.canvasBasicSetting.dto;
import java.sql.Date;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class RoofAllocationInfo {
private String objectNo; // 견적서 번호
private Integer planNo; // plan 번호
private boolean roofApply; // 적용
private Integer roofSeq; // 순번 SEQ
private String roofMatlCd; // 타입
private Integer roofWidth; // 넓이
private Integer roofHeight; // 높이
private Integer roofHajebichi;// 하제비치
private String roofGap; // 간격
private String roofLayout; // 방식
private Float roofPitch; // 경사도
private Float roofAngle; // 각도
private Date registDatetime; // 생성일시
private Date lastEditDatetime;// 수정일시
private String returnMessage; // return message
}

View File

@ -0,0 +1,18 @@
package com.interplug.qcast.biz.canvasBasicSetting.dto;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class RoofAllocationSettingInfo {
private String objectNo; //견적서 번호
private Integer planNo; // plan 번호
private Integer roofSizeSet; //치수(복사도/실측값/육지붕)
private String roofAngleSet; //각도(경사/각도)
private List<RoofAllocationInfo> roofAllocationList;
}

View File

@ -8,17 +8,21 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public class RoofMaterialsAddInfo { public class RoofMaterialsAddInfo {
private String objectNo; //견적서 번호 private String objectNo; // 견적서 번호
private boolean roofApply; //적용 private Integer planNo; // plan 번호
private int roofSeq; //순번 SEQ private boolean roofApply; // 적용
private int roofType; //타입 private Integer roofSeq; // 순번 SEQ
private int roofWidth; //넓이 private String roofMatlCd; // 타입
private int roofHeight; //높이 private Integer roofWidth; // 넓이
private int roofHajebichi; //하제비치 private Integer roofHeight; // 높이
private int roofGap; //간격 private Integer roofHajebichi;// 하제비치
private String roofLayout; //방식 private String roofGap; // 간격
private Date registDatetime; //생성일시 private String roofLayout; // 방식
private Date lastEditDatetime; //수정일시 private Float roofPitch; // 경사도
private Float roofAngle; // 각도
private Integer roofCnt; // 존재여부
private Date registDatetime; // 생성일시
private Date lastEditDatetime;// 수정일시
private String returnMessage; // return message
} }

View File

@ -1,42 +0,0 @@
package com.interplug.qcast.biz.canvasGridSetting;
import com.interplug.qcast.biz.canvasGridSetting.dto.CanvasGridSettingInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
@RequestMapping("/api/canvas-management")
@RequiredArgsConstructor
@Tag(name = "CanvasGridSettingController", description = "Canvas Grid Setting 관련 API")
public class CanvasGridSettingController {
private final CanvasGridSettingService canvasGridSettingService;
@Operation(description = "Canvas Grid Setting 정보를 조회 한다.")
@GetMapping("/canvas-grid-settings/by-object/{objectNo}")
public CanvasGridSettingInfo selectCanvasGridSetting(@PathVariable String objectNo) {
log.debug("Grid Setting 조회 ::::: " + objectNo);
return canvasGridSettingService.selectCanvasGridSetting(objectNo);
}
@Operation(description = "Canvas Grid Setting 정보를 등록 한다.")
@PostMapping("/canvas-grid-settings")
@ResponseStatus(HttpStatus.CREATED)
public Map<String, String> insertCanvasGridStatus(@RequestBody CanvasGridSettingInfo csi) {
log.debug("Grid Setting 등록 ::::: " + csi.getObjectNo());
return canvasGridSettingService.insertCanvasGridSetting(csi);
}
}

View File

@ -1,16 +0,0 @@
package com.interplug.qcast.biz.canvasGridSetting;
import com.interplug.qcast.biz.canvasGridSetting.dto.CanvasGridSettingInfo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CanvasGridSettingMapper {
// Canvas Grid Setting 조회(objectNo)
public CanvasGridSettingInfo selectCanvasGridSetting(String objectNo);
// Canvas Grid Setting 등록
public void insertCanvasGridSetting(CanvasGridSettingInfo csi);
}

View File

@ -1,43 +0,0 @@
package com.interplug.qcast.biz.canvasGridSetting;
import com.interplug.qcast.biz.canvasGridSetting.dto.CanvasGridSettingInfo;
import lombok.RequiredArgsConstructor;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class CanvasGridSettingService {
private final CanvasGridSettingMapper canvasGridSettingMapper;
// Canvas Setting 조회(objectNo)
public CanvasGridSettingInfo selectCanvasGridSetting(String objectNo) {
return canvasGridSettingMapper.selectCanvasGridSetting(objectNo);
}
// Canvas Setting 등록
public Map<String, String> insertCanvasGridSetting(CanvasGridSettingInfo csi) {
Map<String, String> response = new HashMap<>();
try {
canvasGridSettingMapper.insertCanvasGridSetting(csi);
response.put("objectNo", csi.getObjectNo());
response.put("returnMessage", "common.message.confirm.mark");
} catch (Exception e) {
response.put("objectNo", csi.getObjectNo());
response.put("returnMessage", "common.message.save.error");
}
// 생성된 objectNo 반환
return response;
}
}

View File

@ -1,24 +0,0 @@
package com.interplug.qcast.biz.canvasGridSetting.dto;
import java.sql.Date;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CanvasGridSettingInfo {
private String objectNo; //견적서 번호
private boolean dotGridDisplay; // 그리드 표시
private boolean lineGridDisplay; // 그리드 표시
private Integer gridType; //그리드 설정 타입
private Integer gridHorizon; //가로 간격
private Integer gridVertical; //세로 간격
private Integer gridRatio; //비율 간격
private String gridDimen; //치수 간격
private Date registDatetime; //생성일시
private Date lastEditDatetime; //수정일시
private String returnMessage; //return message
}

View File

@ -1,14 +1,12 @@
package com.interplug.qcast.biz.canvasSetting; package com.interplug.qcast.biz.canvasSetting;
import com.interplug.qcast.biz.canvasSetting.dto.CanvasSettingInfo; import com.interplug.qcast.biz.canvasSetting.dto.CanvasSettingInfo;
import com.interplug.qcast.config.Exception.QcastException;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.Map;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -19,33 +17,34 @@ import org.springframework.web.bind.annotation.*;
@Tag(name = "CanvasSettingController", description = "Canvas Setting 관련 API") @Tag(name = "CanvasSettingController", description = "Canvas Setting 관련 API")
public class CanvasSettingController { public class CanvasSettingController {
private final CanvasSettingService canvasSettingService; private final CanvasSettingService canvasSettingService;
@Operation(description = "Canvas Setting 정보를 조회 한다.") @Operation(description = "Canvas Setting 정보를 조회 한다.")
@GetMapping("/canvas-settings/by-object/{objectNo}") @GetMapping("/canvas-settings/by-object/{objectNo}")
public CanvasSettingInfo selectCanvasSetting(@PathVariable String objectNo) { public CanvasSettingInfo selectCanvasSetting(@PathVariable String objectNo)
throws QcastException {
log.debug("Setting 조회 ::::: " + objectNo);
log.debug("Setting 조회 ::::: " + objectNo);
return canvasSettingService.selectCanvasSetting(objectNo);
return canvasSettingService.selectCanvasSetting(objectNo);
} }
@Operation(description = "Canvas Setting 정보를 등록 한다.") @Operation(description = "Canvas Setting 정보를 등록 한다.")
@PostMapping("/canvas-settings") @PostMapping("/canvas-settings")
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
public Map<String, String> insertCanvasSetting(@RequestBody CanvasSettingInfo csi) { public Map<String, String> insertCanvasSetting(@RequestBody CanvasSettingInfo csi)
throws QcastException {
log.debug("Setting 등록 ::::: " + csi.getObjectNo());
log.debug("Setting 등록 ::::: " + csi.getObjectNo());
return canvasSettingService.insertCanvasSetting(csi);
return canvasSettingService.insertCanvasSetting(csi);
} }
@Operation(description = "Canvas Setting 정보를 수정 한다.") @Operation(description = "Canvas Setting 정보를 수정 한다.")
@PutMapping("/canvas-settings") @PutMapping("/canvas-settings")
public void updateCanvasStatus(@RequestBody CanvasSettingInfo csi) { public void updateCanvasStatus(@RequestBody CanvasSettingInfo csi) throws QcastException {
log.debug("Setting 수정 ::::: " + csi.getObjectNo()); log.debug("Setting 수정 ::::: " + csi.getObjectNo());
canvasSettingService.updateCanvasSetting(csi); canvasSettingService.updateCanvasSetting(csi);
} }
} }

View File

@ -7,6 +7,9 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface CanvasSettingMapper { public interface CanvasSettingMapper {
// Canvas Setting 유무 조회
public CanvasSettingInfo getCanvasSettingCnt(String objectNo);
// Canvas Setting 조회(objectNo) // Canvas Setting 조회(objectNo)
public CanvasSettingInfo selectCanvasSetting(String objectNo); public CanvasSettingInfo selectCanvasSetting(String objectNo);

View File

@ -1,48 +1,63 @@
package com.interplug.qcast.biz.canvasSetting; package com.interplug.qcast.biz.canvasSetting;
import com.interplug.qcast.biz.canvasSetting.dto.CanvasSettingInfo; import com.interplug.qcast.biz.canvasSetting.dto.CanvasSettingInfo;
import com.interplug.qcast.config.Exception.ErrorCode;
import lombok.RequiredArgsConstructor; import com.interplug.qcast.config.Exception.QcastException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class CanvasSettingService { public class CanvasSettingService {
private final CanvasSettingMapper canvasSettingMapper; private final CanvasSettingMapper canvasSettingMapper;
// Canvas Setting 조회(objectNo) // Canvas Setting 조회(objectNo)
public CanvasSettingInfo selectCanvasSetting(String objectNo) { public CanvasSettingInfo selectCanvasSetting(String objectNo) throws QcastException {
return canvasSettingMapper.selectCanvasSetting(objectNo); try {
} return canvasSettingMapper.selectCanvasSetting(objectNo);
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
// Canvas Setting 등록 // Canvas Setting 등록
public Map<String, String> insertCanvasSetting(CanvasSettingInfo csi) { public Map<String, String> insertCanvasSetting(CanvasSettingInfo csi) throws QcastException {
Map<String, String> response = new HashMap<>();
try { Map<String, String> response = new HashMap<>();
canvasSettingMapper.insertCanvasSetting(csi);
response.put("objectNo", csi.getObjectNo());
response.put("returnMessage", "common.message.confirm.mark");
} catch (Exception e) {
response.put("objectNo", csi.getObjectNo());
response.put("returnMessage", "common.message.save.error");
}
// 생성된 objectNo 반환 if (csi.getObjectNo() == null) {
return response; throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, "올바르지 않은 입력값입니다.");
}
} try {
// Canvas Setting 수정 // 먼저 데이터가 존재하는지 확인
public void updateCanvasSetting(CanvasSettingInfo csi) { CanvasSettingInfo cntData = canvasSettingMapper.getCanvasSettingCnt(csi.getObjectNo());
canvasSettingMapper.updateCanvasSetting(csi);
}
// 데이터가 존재하지 않으면 insert
if (cntData.getCnt().intValue() < 1) {
canvasSettingMapper.insertCanvasSetting(csi);
} else {
canvasSettingMapper.updateCanvasSetting(csi);
}
response.put("objectNo", csi.getObjectNo());
response.put("returnMessage", "common.message.confirm.mark");
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
// 생성된 objectNo 반환
return response;
}
// Canvas Setting 수정
public void updateCanvasSetting(CanvasSettingInfo csi) throws QcastException {
try {
canvasSettingMapper.updateCanvasSetting(csi);
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
} }

View File

@ -31,8 +31,40 @@ public class CanvasSettingInfo {
private boolean adsorpRangeMedium; //흡착범위설정 private boolean adsorpRangeMedium; //흡착범위설정
private boolean adsorpRangeLarge; //흡착범위설정 private boolean adsorpRangeLarge; //흡착범위설정
private boolean adsorpPoint; //흡착점 ON OFF private boolean adsorpPoint; //흡착점 ON OFF
private boolean dotGridDisplay;
private boolean lineGridDisplay;
private Integer gridType;
private float gridHorizon;
private float gridVertical;
private float gridRatio;
private String gridDimen;
private String gridColor;
private String wordFont;
private String wordFontStyle;
private Integer wordFontSize;
private String wordFontColor;
private String flowFont;
private String flowFontStyle;
private Integer flowFontSize;
private String flowFontColor;
private String dimensioFont;
private String dimensioFontStyle;
private Integer dimensioFontSize;
private String dimensioFontColor;
private String circuitNumFont;
private String circuitNumFontStyle;
private Integer circuitNumFontSize;
private String circuitNumFontColor;
private String lengthFont;
private String lengthFontStyle;
private Integer lengthFontSize;
private String lengthFontColor;
private Integer originPixel;
private String originColor;
private Integer originHorizon;
private Integer originVertical;
private Date registDatetime; //생성일시 private Date registDatetime; //생성일시
private Date lastEditDatetime; //수정일시 private Date lastEditDatetime; //수정일시
private String returnMessage; //return message private String returnMessage; //return message
private Integer cnt; //견적서 유무
} }

View File

@ -17,43 +17,44 @@ import org.springframework.web.bind.annotation.*;
public class CanvasStatusController { public class CanvasStatusController {
private final CanvasStatusService canvasStatusService; private final CanvasStatusService canvasStatusService;
@Operation(description = "계정에 해당하는 전체 견적서를 조회 한다.") @Operation(description = "사용자(userId)에 해당하는 전체 캔버스를 조회 한다.")
@GetMapping("/canvas-statuses/{userId}") @GetMapping("/canvas-statuses/{userId}")
public List<CanvasStatusResponse> selectAllCanvasStatus(@PathVariable String userId) throws QcastException { public List<CanvasStatusResponse> selectAllCanvasStatus(@PathVariable String userId)
throws QcastException {
return canvasStatusService.selectAllCanvasStatus(userId); return canvasStatusService.selectAllCanvasStatus(userId);
} }
@Operation(description = "견적서를 조회 한다.") @Operation(description = "물건번호(objectNo)에 해당하는 캔버스를 조회 한다.")
@GetMapping("/canvas-statuses/by-object/{objectNo}/{userId}") @GetMapping("/canvas-statuses/by-object/{objectNo}")
public List<CanvasStatusResponse> selectObjectNoCanvasStatus(@PathVariable String objectNo, @PathVariable String userId) throws QcastException { public List<CanvasStatusResponse> selectObjectNoCanvasStatus(@PathVariable String objectNo)
return canvasStatusService.selectObjectNoCanvasStatus(objectNo, userId); throws QcastException {
return canvasStatusService.selectObjectNoCanvasStatus(objectNo);
} }
@Operation(description = "견적서를 등록 한다.") @Operation(description = "캔버스를 등록 한다.")
@PostMapping("/canvas-statuses") @PostMapping("/canvas-statuses")
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
public Integer insertCanvasStatus(@RequestBody CanvasStatus cs) throws QcastException { public Integer insertCanvasStatus(@RequestBody CanvasStatus cs) throws QcastException {
return canvasStatusService.insertCanvasStatus(cs); return canvasStatusService.insertCanvasStatus(cs);
} }
@Operation(description = "견적서를 수정 한다.") @Operation(description = "캔버스를 수정 한다.")
@PutMapping("/canvas-statuses") @PutMapping("/canvas-statuses")
public void updateCanvasStatus(@RequestBody CanvasStatus cs) throws QcastException { public void updateCanvasStatus(@RequestBody CanvasStatus cs) throws QcastException {
canvasStatusService.updateCanvasStatus(cs); canvasStatusService.updateCanvasStatus(cs);
} }
@Operation(description = "견적서를 삭제 한다.") @Operation(description = "물건번호(objectNo)에 해당하는캔버스를 삭제 한다.")
@DeleteMapping("/canvas-statuses/by-object/{objectNo}") @DeleteMapping("/canvas-statuses/by-object/{objectNo}")
@ResponseStatus(HttpStatus.NO_CONTENT) @ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteObjectNoCanvasStatus(@PathVariable String objectNo) throws QcastException { public void deleteObjectNoCanvasStatus(@PathVariable String objectNo) throws QcastException {
canvasStatusService.deleteObjectNoCanvasStatus(objectNo); canvasStatusService.deleteObjectNoCanvasStatus(objectNo);
} }
@Operation(description = "견적서의 이미지(템플릿)를 삭제 한다.") @Operation(description = "id에 해당하는 캔버스를 삭제 한다.")
@DeleteMapping("/canvas-statuses/by-id/{id}") @DeleteMapping("/canvas-statuses/by-id/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT) @ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteIdCanvasStatus(@PathVariable Integer id) throws QcastException { public void deleteIdCanvasStatus(@PathVariable Integer id) throws QcastException {
canvasStatusService.deleteIdCanvasStatus(id); canvasStatusService.deleteIdCanvasStatus(id);
} }
} }

View File

@ -1,47 +1,50 @@
package com.interplug.qcast.biz.canvasStatus; package com.interplug.qcast.biz.canvasStatus;
import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatus; import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatus;
import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatusCopyRequest;
import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatusResponse; import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatusResponse;
import java.util.List; import java.util.List;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface CanvasStatusMapper { public interface CanvasStatusMapper {
// objectNo 생성(미사용) // objectNo 생성(미사용)
public CanvasStatus getCanvasStatusNewObjectNo(String userId); public CanvasStatus getCanvasStatusNewObjectNo(String userId);
// imageName 생성(미사용)
public CanvasStatus getCanvasStatusImageAdd(String objectNo);
// 전체 견적서 조회
public List<CanvasStatusResponse> selectAllCanvasStatus(String userId);
// 견적서 조회(objectNo/userId)
public List<CanvasStatusResponse> selectObjectNoCanvasStatus(String objectNo, String userId);
// 견적서 조회(Max id)
public List<CanvasStatusResponse> getMaxIdCanvasStatus(String objectNo, String userId);
// 견적서 조회(id별)
public List<CanvasStatusResponse> getIdCanvasStatus(Integer id);
// 견적서 조회(objectNo)
public List<CanvasStatusResponse> getObjectNoCanvasStatus(String objectNo);
// 견적서 등록
public void insertCanvasStatus(CanvasStatus cs);
// 견적서 수정
public void updateCanvasStatus(CanvasStatus cs);
// 견적서 삭제
public void deleteObjectNoCanvasStatus(String objectNo);
// 이미지(템플릿) 삭제
public void deleteIdCanvasStatus(Integer id);
// imageName 생성(미사용)
} public CanvasStatus getCanvasStatusImageAdd(String objectNo);
// 전체 캔버스 조회 by 사용자(userId)
public List<CanvasStatusResponse> selectAllCanvasStatus(String userId);
// 캔버스 조회 by 물건번호(objectNo)
public List<CanvasStatusResponse> selectObjectNoCanvasStatus(String objectNo);
// 캔버스 조회 by Max(id)
public List<CanvasStatusResponse> getMaxIdCanvasStatus(String objectNo, String userId);
// 캔버스 조회 by id
public List<CanvasStatusResponse> getIdCanvasStatus(Integer id);
// 캔버스 조회 by 물건번호(objectNo)
public List<CanvasStatusResponse> getObjectNoCanvasStatus(String objectNo);
// 캔버스 등록
public void insertCanvasStatus(CanvasStatus cs);
// 캔버스 수정
public void updateCanvasStatus(CanvasStatus cs);
// 캔버스 삭제 by 물건번호(objectNo)
public void deleteObjectNoCanvasStatus(String objectNo);
// 캔버스 삭제 by id (미사용)
public void deleteIdCanvasStatus(Integer id);
// 캔버스 삭제플래그 변경 by id
public void updateDeletedCanvasStatus(Integer id);
// 캔버스 복사
public int copyCanvasStatus(CanvasStatusCopyRequest cs);
}

View File

@ -1,122 +1,209 @@
package com.interplug.qcast.biz.canvasStatus; package com.interplug.qcast.biz.canvasStatus;
import com.interplug.qcast.biz.canvasBasicSetting.CanvasBasicSettingMapper;
import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingInfo;
import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingResponse;
import com.interplug.qcast.biz.canvasBasicSetting.dto.RoofMaterialsAddInfo;
import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatus; import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatus;
import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatusCopyRequest;
import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatusResponse; import com.interplug.qcast.biz.canvasStatus.dto.CanvasStatusResponse;
import com.interplug.qcast.config.Exception.ErrorCode; import com.interplug.qcast.config.Exception.ErrorCode;
import com.interplug.qcast.config.Exception.QcastException; import com.interplug.qcast.config.Exception.QcastException;
import lombok.RequiredArgsConstructor;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class CanvasStatusService { public class CanvasStatusService {
private final CanvasStatusMapper canvasStatusMapper; private final CanvasStatusMapper canvasStatusMapper;
private final CanvasBasicSettingMapper canvasBasicSettingMapper;
// 전체 견적서 조회 // 사용자(userId) 해당하는 전체 캔버스 조회
public List<CanvasStatusResponse> selectAllCanvasStatus(String userId) throws QcastException { public List<CanvasStatusResponse> selectAllCanvasStatus(String userId) throws QcastException {
List<CanvasStatusResponse> result = null; List<CanvasStatusResponse> result = null;
if (userId != null && !userId.trim().isEmpty()) {
result = canvasStatusMapper.selectAllCanvasStatus(userId);
} else {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"올바르지 않은 입력값입니다.");
}
return result;
}
// 견적서 조회(objectNo) try {
public List<CanvasStatusResponse> selectObjectNoCanvasStatus(String objectNo, String userId) throws QcastException { if (userId != null && !userId.trim().isEmpty()) {
List<CanvasStatusResponse> result = null; result = canvasStatusMapper.selectAllCanvasStatus(userId);
} else {
if (objectNo != null && !objectNo.trim().isEmpty() && userId != null && !userId.trim().isEmpty()) { throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, "올바르지 않은 입력값입니다.");
result = canvasStatusMapper.selectObjectNoCanvasStatus(objectNo, userId); }
} else { } catch (Exception e) {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"올바르지 않은 입력값입니다."); if (e instanceof QcastException) throw e;
} throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
return result;
}
// 견적서 등록 return result;
public Integer insertCanvasStatus(CanvasStatus cs) throws QcastException { }
Integer id = 0;
// 데이터가 없으면 저장
try {
canvasStatusMapper.insertCanvasStatus(cs);
// 데이터 저장 Max id 확인
List<CanvasStatusResponse> maxId = canvasStatusMapper.getMaxIdCanvasStatus(cs.getObjectNo(), cs.getUserId());
id = maxId.get(0).getId();
} catch (Exception e) {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"견적서 등록 중 오류 발생");
}
// 생성된 id 반환
return id;
}
// 견적서 수정 // 물건번호(objectNo) 해당하는 캔버스 조회
public void updateCanvasStatus(CanvasStatus cs) throws QcastException { public List<CanvasStatusResponse> selectObjectNoCanvasStatus(String objectNo)
throws QcastException {
List<CanvasStatusResponse> result = null;
if (cs.getId() == null) { try {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"올바르지 않은 입력값입니다."); if (objectNo != null && !objectNo.trim().isEmpty()) {
} result = canvasStatusMapper.selectObjectNoCanvasStatus(objectNo);
} else {
// 먼저 데이터가 존재하는지 확인 throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, "올바르지 않은 입력값입니다.");
List<CanvasStatusResponse> existingStatus = canvasStatusMapper.getIdCanvasStatus(cs.getId()); }
} catch (Exception e) {
if (e instanceof QcastException) throw e;
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
// 데이터가 존재하지 않으면 수정하지 않고 예외를 던짐 return result;
if (existingStatus.size() > 0) { }
canvasStatusMapper.updateCanvasStatus(cs);
} else {
throw new QcastException (ErrorCode.NOT_FOUND ,"수정할 견적서가 존재하지 않습니다.");
}
}
// 전체 견적서 삭제 // 캔버스 등록
public void deleteObjectNoCanvasStatus(String objectNo) throws QcastException { public Integer insertCanvasStatus(CanvasStatus cs) throws QcastException {
if (objectNo == null || objectNo.trim().isEmpty()) {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"올바르지 않은 입력값입니다.");
}
// 먼저 데이터가 존재하는지 확인
List<CanvasStatusResponse> existingStatus = canvasStatusMapper.getObjectNoCanvasStatus(objectNo);
// 데이터가 존재하지 않으면 수정하지 않고 예외를 던짐
if (existingStatus.size() > 0) {
canvasStatusMapper.deleteObjectNoCanvasStatus(objectNo);
} else {
throw new QcastException (ErrorCode.NOT_FOUND ,"삭제할 견적서가 존재하지 않습니다.");
}
}
// 이미지(템플릿) 삭제 Integer id = 0;
public void deleteIdCanvasStatus(Integer id) throws QcastException {
if (id == null) {
throw new QcastException (ErrorCode.INVALID_INPUT_VALUE ,"올바르지 않은 입력값입니다.");
}
// 먼저 데이터가 존재하는지 확인
List<CanvasStatusResponse> existingStatus = canvasStatusMapper.getIdCanvasStatus(id);
// 데이터가 존재하지 않으면 수정하지 않고 예외를 던짐
if (existingStatus.size() > 0) {
canvasStatusMapper.deleteIdCanvasStatus(id);
} else {
throw new QcastException (ErrorCode.NOT_FOUND ,"삭제할 견적서가 존재하지 않습니다.");
}
}
// 데이터가 없으면 저장
try {
canvasStatusMapper.insertCanvasStatus(cs);
// 데이터 저장 Max id 확인
List<CanvasStatusResponse> maxId =
canvasStatusMapper.getMaxIdCanvasStatus(cs.getObjectNo(), cs.getUserId());
id = maxId.get(0).getId();
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
// 생성된 id 반환
return id;
}
// 캔버스 수정
public void updateCanvasStatus(CanvasStatus cs) throws QcastException {
if (cs.getId() == null) {
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, "올바르지 않은 입력값입니다.");
}
try {
// 먼저 데이터가 존재하는지 확인
List<CanvasStatusResponse> existingStatus = canvasStatusMapper.getIdCanvasStatus(cs.getId());
// 데이터가 존재하지 않으면 수정하지 않고 예외를 던짐
if (existingStatus.size() > 0) {
canvasStatusMapper.updateCanvasStatus(cs);
} else {
throw new QcastException(ErrorCode.NOT_FOUND, "수정할 캔버스가 존재하지 않습니다.");
}
} catch (Exception e) {
if (e instanceof QcastException) throw e;
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
// 물건번호(objectNo) 해당하는 캔버스 삭제
public void deleteObjectNoCanvasStatus(String objectNo) throws QcastException {
if (objectNo == null || objectNo.trim().isEmpty()) {
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, "올바르지 않은 입력값입니다.");
}
try {
// 먼저 데이터가 존재하는지 확인
List<CanvasStatusResponse> existingStatus =
canvasStatusMapper.getObjectNoCanvasStatus(objectNo);
// 데이터가 존재하지 않으면 수정하지 않고 예외를 던짐
if (existingStatus.size() > 0) {
canvasStatusMapper.deleteObjectNoCanvasStatus(objectNo);
} else {
throw new QcastException(ErrorCode.NOT_FOUND, "삭제할 캔버스가 존재하지 않습니다.");
}
} catch (Exception e) {
if (e instanceof QcastException) throw e;
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
// id에 해당하는 캔버스 삭제
public void deleteIdCanvasStatus(Integer id) throws QcastException {
if (id == null) {
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, "올바르지 않은 입력값입니다.");
}
try {
// 먼저 데이터가 존재하는지 확인
List<CanvasStatusResponse> existingStatus = canvasStatusMapper.getIdCanvasStatus(id);
// 데이터가 존재하지 않으면 처리하지 않고 예외를 던짐
if (existingStatus.size() > 0) {
// 데이터를 삭제하는 기존 방식에서 데이터를 삭제하지 않고 deleted 데이터를 바꾸는 방식으로 변경 (2025.02.11)
// canvasStatusMapper.deleteIdCanvasStatus(id);
canvasStatusMapper.updateDeletedCanvasStatus(id);
} else {
throw new QcastException(ErrorCode.NOT_FOUND, "삭제할 캔버스가 존재하지 않습니다.");
}
} catch (Exception e) {
if (e instanceof QcastException) throw e;
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
// 캔버스 복사 등록
@Transactional
public int copyCanvasStatus(CanvasStatusCopyRequest cs, Boolean flag) throws QcastException {
try {
if (flag) {
// 배치면 초기설정 정보 조회
List<CanvasBasicSettingResponse> selData =
canvasBasicSettingMapper.selectCanvasBasicSetting(
cs.getOriginObjectNo(), Integer.parseInt(cs.getOriginPlanNo()));
if (!selData.isEmpty()) {
// 번째 데이터만 CanvasBasicSettingInfo로 변환하여 insert 실행
CanvasBasicSettingResponse firstData = selData.get(0);
// CanvasBasicSettingResponse CanvasBasicSettingInfo 변환
CanvasBasicSettingInfo basicSettingInfo = new CanvasBasicSettingInfo();
basicSettingInfo.setObjectNo(cs.getObjectNo());
basicSettingInfo.setPlanNo(Integer.parseInt(cs.getPlanNo()));
basicSettingInfo.setRoofSizeSet(firstData.getRoofSizeSet());
basicSettingInfo.setRoofAngleSet(firstData.getRoofAngleSet());
// 도면/치수/각도 정보 insert ( 번만 실행)
canvasBasicSettingMapper.insertCanvasBasicSetting(basicSettingInfo);
// 나머지 RoofMaterialsAddInfo 처리
for (CanvasBasicSettingResponse data : selData) {
// CanvasBasicSettingResponse RoofMaterialsAddInfo 변환
RoofMaterialsAddInfo roofMaterials = new RoofMaterialsAddInfo();
roofMaterials.setObjectNo(cs.getObjectNo());
roofMaterials.setPlanNo(Integer.parseInt(cs.getPlanNo()));
roofMaterials.setRoofApply(data.isRoofApply());
roofMaterials.setRoofSeq(data.getRoofSeq());
roofMaterials.setRoofMatlCd(data.getRoofMatlCd());
roofMaterials.setRoofWidth(data.getRoofWidth());
roofMaterials.setRoofHeight(data.getRoofHeight());
roofMaterials.setRoofHajebichi(data.getRoofHajebichi());
roofMaterials.setRoofGap(data.getRoofGap());
roofMaterials.setRoofLayout(data.getRoofLayout());
roofMaterials.setRoofPitch(data.getRoofPitch());
roofMaterials.setRoofAngle(data.getRoofAngle());
// 지붕재 추가 Setting insert (여러 가능)
canvasBasicSettingMapper.insertRoofMaterialsAdd(roofMaterials);
}
}
}
canvasStatusMapper.copyCanvasStatus(cs);
return cs.getId();
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, "캔버스 복사 중 오류 발생");
}
}
} }

View File

@ -7,7 +7,7 @@ public class CanvasStatus {
private Integer id; // PK ID private Integer id; // PK ID
private String userId; // 사용자 ID private String userId; // 사용자 ID
private String objectNo; // 견적서 번호 private String objectNo; // 견적서 번호
private String imageName; // 이미지명 private String planNo; // 플랜 번호
private String canvasStatus; // 캠버스 상태 private String canvasStatus; // 캠버스 상태
private String bgImageName; // 배경 이미지명 private String bgImageName; // 배경 이미지명
private String mapPositionAddress; // 배경 CAD 파일명 private String mapPositionAddress; // 배경 CAD 파일명

View File

@ -0,0 +1,28 @@
package com.interplug.qcast.biz.canvasStatus.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Schema(description = "캔버스 복사 요청 객체")
public class CanvasStatusCopyRequest {
@Schema(description = "ID", hidden = true)
private Integer id;
@Schema(description = "원본 물건 번호")
private String originObjectNo;
@Schema(description = "원본 플랜 번호")
private String originPlanNo;
@Schema(description = "복사본 저장할 사용자 ID")
private String userId;
@Schema(description = "복사본 저장할 물건 번호")
private String objectNo;
@Schema(description = "복사본 저장할 플랜 번호")
private String planNo;
}

View File

@ -10,7 +10,7 @@ public class CanvasStatusResponse {
private Integer id; // PK ID private Integer id; // PK ID
private String userId; // 사용자 ID private String userId; // 사용자 ID
private String objectNo; // 견적서 번호 private String objectNo; // 견적서 번호
private String imageName; // 이미지명 private String planNo; // 플랜 번호
private String canvasStatus; // 캠버스 상태 private String canvasStatus; // 캠버스 상태
private Date registDatetime; // 생성일시 private Date registDatetime; // 생성일시
private Date lastEditDatetime; // 수정일시 private Date lastEditDatetime; // 수정일시

View File

@ -0,0 +1,79 @@
package com.interplug.qcast.biz.canvaspopupstatus;
import com.interplug.qcast.biz.canvaspopupstatus.dto.CanvasPopupStatus;
import com.interplug.qcast.config.Exception.ErrorCode;
import com.interplug.qcast.config.Exception.QcastException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/canvas-popup-status")
@RequiredArgsConstructor
@Tag(name = "CanvasPopupStatusController", description = "Canvas Popup Status 관련 API")
public class CanvasPopupStatusController {
private final CanvasPopupStatusService canvasPopupStatusService;
/**
* 캔버스 팝업 상태를 조회한다.
*
* @param objectNo 물건정보 번호
* @param planNo plan 번호
* @param popupType 캔버스 팝업 단계
* @return 조회된 CanvasPopupStatus 객체, 조회된 데이터가 없을 경우 객체 반환
*/
@Operation(description = "캔버스 팝업 상태를 조회한다.")
@GetMapping
public CanvasPopupStatus getCanvasPopupStatus(
@RequestParam @Schema(description = "물건정보 번호") String objectNo,
@RequestParam @Schema(description = "plan 번호") Integer planNo,
@RequestParam @Schema(description = "캔버스 팝업 단계") String popupType)
throws QcastException {
if (objectNo == null
|| objectNo.trim().isEmpty()
|| planNo == null
|| popupType == null
|| popupType.trim().isEmpty()) {
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE);
}
return canvasPopupStatusService.selectCanvasPopupStatus(objectNo, planNo, popupType);
}
/**
* 캔버스 팝업 상태를 저장 또는 수정한다.
*
* @param canvasPopupStatus 저장 또는 수정할 CanvasPopupStatus 객체
* @throws QcastException 저장 또는 수정 예외 발생
*/
@Operation(description = "캔버스 팝업 상태를 저장 또는 수정한다.")
@PostMapping
public void saveCanvasPopupStatus(@RequestBody CanvasPopupStatus canvasPopupStatus)
throws QcastException {
canvasPopupStatusService.saveCanvasPopupStatus(canvasPopupStatus);
}
/**
* 캔버스 팝업 상태를 삭제한다. (미사용)
*
* @param canvasPopupStatus 삭제할 CanvasPopupStatus 객체
* @throws QcastException 삭제 예외 발생
*/
@Operation(description = "캔버스 팝업 상태를 삭제한다. (미사용)")
@DeleteMapping
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteCanvasPopupStatus(@RequestBody CanvasPopupStatus canvasPopupStatus)
throws QcastException {
canvasPopupStatusService.deleteCanvasPopupStatus(canvasPopupStatus);
}
}

View File

@ -0,0 +1,37 @@
package com.interplug.qcast.biz.canvaspopupstatus;
import com.interplug.qcast.biz.canvaspopupstatus.dto.CanvasPopupStatus;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CanvasPopupStatusMapper {
/**
* Canvas Popup Status 조회
*
* @param canvasPopupStatus 조회할 CanvasPopupStatus 객체
* @return 조회된 CanvasPopupStatus 객체
*/
public CanvasPopupStatus selectCanvasPopupStatus(CanvasPopupStatus canvasPopupStatus);
/**
* Canvas Popup Status 생성
*
* @param canvasPopupStatus 생성할 CanvasPopupStatus 객체
*/
public void insertCanvasPopupStatus(CanvasPopupStatus canvasPopupStatus);
/**
* Canvas Popup Status 수정
*
* @param canvasPopupStatus 수정할 CanvasPopupStatus 객체
*/
public void updateCanvasPopupStatus(CanvasPopupStatus canvasPopupStatus);
/**
* Canvas Popup Status 삭제
*
* @param canvasPopupStatus 삭제할 CanvasPopupStatus 객체
*/
public void deleteCanvasPopupStatus(CanvasPopupStatus canvasPopupStatus);
}

View File

@ -0,0 +1,149 @@
package com.interplug.qcast.biz.canvaspopupstatus;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.interplug.qcast.biz.canvasBasicSetting.CanvasBasicSettingMapper;
import com.interplug.qcast.biz.canvasBasicSetting.dto.CanvasBasicSettingResponse;
import com.interplug.qcast.biz.canvaspopupstatus.dto.CanvasPopupStatus;
import com.interplug.qcast.biz.estimate.dto.EstimateApiResponse;
import com.interplug.qcast.config.Exception.ErrorCode;
import com.interplug.qcast.config.Exception.QcastException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class CanvasPopupStatusService {
private final CanvasPopupStatusMapper canvasPopupStatusMapper;
private final CanvasBasicSettingMapper canvasBasicSettingMapper;
/**
* Canvas Popup Status 조회
*
* @param objectNo 조회할 object 번호
* @param planNo 조회할 plan 번호
* @param popupType 조회할 popup 타입
* @return 조회된 CanvasPopupStatus 객체, 조회된 데이터가 없을 경우 객체 반환
*/
public CanvasPopupStatus selectCanvasPopupStatus(
String objectNo, Integer planNo, String popupType) throws QcastException {
CanvasPopupStatus request =
CanvasPopupStatus.builder().objectNo(objectNo).planNo(planNo).popupType(popupType).build();
CanvasPopupStatus cps = canvasPopupStatusMapper.selectCanvasPopupStatus(request);
return cps != null ? cps : CanvasPopupStatus.builder().build();
}
/**
* Canvas Popup Status 저장 - 이미 존재하는 데이터인 경우 수정, 없는 경우 생성
*
* @param cps 저장할 CanvasPopupStatus 객체
* @throws QcastException 저장 예외 발생
*/
@Transactional
public void saveCanvasPopupStatus(CanvasPopupStatus cps) throws QcastException {
CanvasPopupStatus chk = canvasPopupStatusMapper.selectCanvasPopupStatus(cps);
if (chk == null) {
createCanvasPopupStatus(cps);
} else {
updateCanvasPopupStatus(cps);
}
//기초정보 업데이트 (roofHajebichi)
String hajebichi = cps.getHajebichi();
if(hajebichi != null && !hajebichi.isEmpty()){
CanvasBasicSettingResponse canvasBasicSettingResponse = new CanvasBasicSettingResponse();
canvasBasicSettingResponse.setObjectNo(cps.getObjectNo());
canvasBasicSettingResponse.setPlanNo(cps.getPlanNo());
canvasBasicSettingResponse.setRoofHajebichi(Integer.valueOf(hajebichi));
canvasBasicSettingMapper.updateHajebichRoofMaterialsAdd(canvasBasicSettingResponse);
}
// String popupStatus = cps.getPopupStatus();
// List<Integer> hajebichiList = new ArrayList<>();//getHajebichiValues(popupStatus, 0, 1); // roofIndex=0, planNo=1인 hajebichi 값들 조회
//
// try {
// ObjectMapper mapper = new ObjectMapper();
// JsonNode rootNode = mapper.readTree(popupStatus);
// JsonNode roofConstructions = rootNode.get("roofConstructions");
// if (roofConstructions.isArray()) {
// for (JsonNode construction : roofConstructions) {
// JsonNode addRoof = construction.get("addRoof");
// if (addRoof != null
// && addRoof.get("roofIndex").asInt() == 0
// && addRoof.get("planNo").asInt() == cps.getPlanNo()) {
// hajebichiList.add(addRoof.get("hajebichi").asInt());
// }
// }
// }
//
// } catch (JsonProcessingException e) {
// throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, "JSON 파싱 오류");
// }
// if(!hajebichiList.isEmpty()){
// CanvasBasicSettingResponse canvasBasicSettingResponse = new CanvasBasicSettingResponse();
// canvasBasicSettingResponse.setObjectNo(cps.getObjectNo());
// canvasBasicSettingResponse.setPlanNo(cps.getPlanNo());
// canvasBasicSettingResponse.setRoofHajebichi(hajebichiList.get(0));
//
// if(canvasBasicSettingResponse.getRoofHajebichi() > 0){
// canvasBasicSettingMapper.updateHajebichRoofMaterialsAdd(canvasBasicSettingResponse);
// }
//
// }
}
/**
* Canvas Popup Status 생성
*
* @param cps 생성할 CanvasPopupStatus 객체
* @throws QcastException 생성 예외 발생
*/
@Transactional
public void createCanvasPopupStatus(CanvasPopupStatus cps) throws QcastException {
try {
canvasPopupStatusMapper.insertCanvasPopupStatus(cps);
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
/**
* Canvas Popup Status 수정
*
* @param cps 수정할 CanvasPopupStatus 객체
* @throws QcastException 수정 예외 발생
*/
public void updateCanvasPopupStatus(CanvasPopupStatus cps) throws QcastException {
try {
canvasPopupStatusMapper.updateCanvasPopupStatus(cps);
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
/**
* Canvas Popup Status 삭제
*
* @param cps 삭제할 CanvasPopupStatus 객체
* @throws QcastException 삭제 예외 발생
*/
public void deleteCanvasPopupStatus(CanvasPopupStatus cps) throws QcastException {
try {
canvasPopupStatusMapper.deleteCanvasPopupStatus(cps);
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
}

View File

@ -0,0 +1,32 @@
package com.interplug.qcast.biz.canvaspopupstatus.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
@Schema(description = "캔버스 팝업 상태")
public class CanvasPopupStatus {
// @Schema(description = "id")
// private Long id;
@Schema(description = "물건정보 번호")
private String objectNo;
@Schema(description = "plan 번호")
private Integer planNo;
@Schema(description = "캔버스 팝업 단계")
private String popupType;
@Schema(description = "캔버스 팝업 상태 데이터")
private String popupStatus;
@Schema(description = "하제비치")
private String hajebichi;
}

View File

@ -3,14 +3,54 @@ package com.interplug.qcast.biz.commCode;
import java.util.List; import java.util.List;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import com.interplug.qcast.biz.commCode.dto.CodeRes; import com.interplug.qcast.biz.commCode.dto.CodeRes;
import com.interplug.qcast.biz.commCode.dto.DetailCodeRequest;
import com.interplug.qcast.biz.commCode.dto.HeadCodeRequest;
@Mapper @Mapper
public interface CommCodeMapper { public interface CommCodeMapper {
/**
* Qcast 공통코드 저장시 실시간 동기화
*
* @param codeRes
* @return
*/
int setCommHUpdate(CodeRes codeRes); int setCommHUpdate(CodeRes codeRes);
/**
* Qcast 공통코드 저장시 실시간 동기화
*
* @param codeRes
* @return
*/
int setCommLUpdate(CodeRes codeRes); int setCommLUpdate(CodeRes codeRes);
/**
* QCast에서 사용하는 공통코드 조회
*
* @return
*/
List<CodeRes> selectQcastCommCode(); List<CodeRes> selectQcastCommCode();
/**
* 배치 공통코드 헤더 정보 동기화 저장
*
* @param headCodeReq
* @return
* @throws Exception
*/
int setHeadCodeSyncSave(HeadCodeRequest headCodeReq) throws Exception;
/**
* 배치 공통코드 상세 정보 동기화 저장
*
* @param detailCodeReq
* @return
* @throws Exception
*/
int setCommonCodeSyncSave(DetailCodeRequest detailCodeReq) throws Exception;
} }

View File

@ -1,13 +1,17 @@
package com.interplug.qcast.biz.commCode; package com.interplug.qcast.biz.commCode;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.interplug.qcast.biz.commCode.dto.CodeReq; import com.interplug.qcast.biz.commCode.dto.CodeReq;
import com.interplug.qcast.biz.commCode.dto.CodeRes; import com.interplug.qcast.biz.commCode.dto.CodeRes;
import com.interplug.qcast.biz.commCode.dto.CommCodeRes; import com.interplug.qcast.biz.commCode.dto.CommCodeRes;
import java.util.ArrayList; import com.interplug.qcast.biz.commCode.dto.DetailCodeRequest;
import java.util.List; import com.interplug.qcast.biz.commCode.dto.HeadCodeRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class CommCodeService { public class CommCodeService {
@ -49,17 +53,55 @@ public class CommCodeService {
public List<CommCodeRes> selectQcastCommCode() { public List<CommCodeRes> selectQcastCommCode() {
List<CodeRes> result = commCodeMapper.selectQcastCommCode(); List<CodeRes> result = commCodeMapper.selectQcastCommCode();
List<CommCodeRes> commCodeList = new ArrayList<>(); List<CommCodeRes> commCodeList = new ArrayList<>();
result.forEach( result.forEach(cr -> {
cr -> { commCodeList.add(CommCodeRes.builder().clHeadCd(cr.getClHeadCd()).clCode(cr.getClCode())
commCodeList.add( .clCodeNm(cr.getClCodeNm()).clCodeJp(cr.getClCodeJp()).clPriority(cr.getClPriority())
CommCodeRes.builder() .clRefChr1(cr.getClRefChr1()).clRefChr2(cr.getClRefChr2()).build());
.clHeadCd(cr.getClHeadCd()) });
.clCode(cr.getClCode())
.clCodeNm(cr.getClCodeNm())
.clCodeJp(cr.getClCodeJp())
.clPriority(cr.getClPriority())
.build());
});
return commCodeList; return commCodeList;
} }
/**
* 헤더코드 동기화
*
* @param headCodeList
* @throws Exception
*/
public void setHeaderCodeSyncSave(List<HeadCodeRequest> headCodeList) throws Exception {
// 헤더코드 동기화
for (HeadCodeRequest headCodeReq : headCodeList) {
try {
if ("Y".equals(headCodeReq.getQcCommYn()) && "N".equals(headCodeReq.getDelYn())) {
headCodeReq.setDelFlg(0);
} else {
headCodeReq.setDelFlg(1);
}
commCodeMapper.setHeadCodeSyncSave(headCodeReq);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
/**
* 상세코드 동기화
*
* @param detailCodeList
* @throws Exception
*/
public void setCommonCodeSyncSave(List<DetailCodeRequest> detailCodeList) throws Exception {
// 상세코드 동기화
for (DetailCodeRequest detailCodeReq : detailCodeList) {
try {
if ("A".equals(detailCodeReq.getStatCd()) && "N".equals(detailCodeReq.getDelYn())) {
detailCodeReq.setDelFlg(0);
} else {
detailCodeReq.setDelFlg(1);
}
commCodeMapper.setCommonCodeSyncSave(detailCodeReq);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
} }

View File

@ -11,4 +11,6 @@ public class CommCodeRes {
private String clCodeNm; private String clCodeNm;
private String clCodeJp; private String clCodeJp;
private Integer clPriority; private Integer clPriority;
private String clRefChr1;
private String clRefChr2;
} }

View File

@ -0,0 +1,17 @@
package com.interplug.qcast.biz.commCode.dto;
import java.util.List;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CommonCodeSyncResponse {
@Schema(description = "공통코드 H 목록")
private List<HeadCodeRequest> apiHeadCdList;
@Schema(description = "공통코드 L 목록")
private List<DetailCodeRequest> apiCommCdList;
}

View File

@ -0,0 +1,28 @@
package com.interplug.qcast.biz.commCode.dto;
import lombok.Data;
@Data
public class DetailCodeRequest {
private String headCd;
private String code;
private String readCd;
private String codeNm;
private String codeJp;
private String code4Th;
private String refChr1;
private String refChr2;
private String refChr3;
private String refChr4;
private String refChr5;
private Integer refNum1;
private Integer refNum2;
private Integer refNum3;
private Integer refNum4;
private Integer refNum5;
private Integer priority;
private String refCnt;
private String statCd;
private Integer delFlg;
private String delYn;
}

View File

@ -0,0 +1,26 @@
package com.interplug.qcast.biz.commCode.dto;
import lombok.Data;
@Data
public class HeadCodeRequest {
private String headCd;
private String headId;
private String headNm;
private String headJp;
private String head4Th;
private String refChr1;
private String refChr2;
private String refChr3;
private String refChr4;
private String refChr5;
private String refNum1;
private String refNum2;
private String refNum3;
private String refNum4;
private String refNum5;
private String remarks;
private Integer delFlg;
private String qcCommYn;
private String delYn;
}

View File

@ -1,19 +1,16 @@
package com.interplug.qcast.biz.community; package com.interplug.qcast.biz.community;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.interplug.qcast.biz.community.dto.BoardRequest; import com.interplug.qcast.biz.community.dto.BoardRequest;
import com.interplug.qcast.biz.community.dto.BoardResponse; import com.interplug.qcast.biz.community.dto.BoardResponse;
import com.interplug.qcast.biz.file.dto.FileRequest;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@Slf4j @Slf4j
@RestController @RestController
@ -38,12 +35,21 @@ public class BoardController {
return boardService.getBoardDetail(boardRequest); return boardService.getBoardDetail(boardRequest);
} }
@Operation(description = "문의를 저장한다.")
@PostMapping("/saveQna")
@ResponseStatus(HttpStatus.OK)
public BoardResponse getBoardQnaSave(BoardRequest boardRequest, HttpServletRequest request) throws Exception {
return boardService.getBoardQnaSave(boardRequest, request);
}
@Operation(description = "커뮤니티(공지사항, FAQ, 자료다운로드) 파일 다운로드를 진행한다.") @Operation(description = "커뮤니티(공지사항, FAQ, 자료다운로드) 파일 다운로드를 진행한다.")
@GetMapping("/file/download") @GetMapping("/file/download")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public void getFileDownload(HttpServletResponse response, public void getFileDownload(
@RequestParam(required = true) String encodeFileNo) throws Exception { HttpServletResponse response,
boardService.getFileDownload(response, encodeFileNo); @RequestParam(required = true) String keyNo,
@RequestParam String zipYn)
throws Exception {
boardService.getFileDownload(response, keyNo, zipYn);
} }
} }

View File

@ -1,28 +1,40 @@
package com.interplug.qcast.biz.community; package com.interplug.qcast.biz.community;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import org.springframework.web.util.UriComponentsBuilder;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.interplug.qcast.biz.community.dto.BoardRequest; import com.interplug.qcast.biz.community.dto.BoardRequest;
import com.interplug.qcast.biz.community.dto.BoardResponse; import com.interplug.qcast.biz.community.dto.BoardResponse;
import com.interplug.qcast.biz.estimate.dto.EstimateApiResponse;
import com.interplug.qcast.biz.file.dto.FileRequest;
import com.interplug.qcast.config.Exception.ErrorCode; import com.interplug.qcast.config.Exception.ErrorCode;
import com.interplug.qcast.config.Exception.QcastException; import com.interplug.qcast.config.Exception.QcastException;
import com.interplug.qcast.config.message.Messages; import com.interplug.qcast.config.message.Messages;
import com.interplug.qcast.util.InterfaceQsp; import com.interplug.qcast.util.InterfaceQsp;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.*;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.util.UriComponentsBuilder;
@Slf4j @Slf4j
@Service @Service
@ -30,8 +42,7 @@ import lombok.extern.slf4j.Slf4j;
public class BoardService { public class BoardService {
private final InterfaceQsp interfaceQsp; private final InterfaceQsp interfaceQsp;
@Autowired @Autowired Messages message;
Messages message;
@Value("${qsp.url}") @Value("${qsp.url}")
private String QSP_API_URL; private String QSP_API_URL;
@ -50,12 +61,14 @@ public class BoardService {
/* [0]. Validation Check */ /* [0]. Validation Check */
if ("".equals(boardRequest.getSchNoticeClsCd())) { if ("".equals(boardRequest.getSchNoticeClsCd())) {
// [msg] {0} is required input value. // [msg] {0} is required input value.
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Notice Cls Code")); message.getMessage("common.message.required.data", "Notice Cls Code"));
} }
if ("".equals(boardRequest.getSchNoticeTpCd())) { if ("".equals(boardRequest.getSchNoticeTpCd())) {
// [msg] {0} is required input value. // [msg] {0} is required input value.
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Notice Type Code")); message.getMessage("common.message.required.data", "Notice Type Code"));
} }
@ -65,13 +78,39 @@ public class BoardService {
encodedSchTitle = URLEncoder.encode(boardRequest.getSchTitle(), StandardCharsets.UTF_8); encodedSchTitle = URLEncoder.encode(boardRequest.getSchTitle(), StandardCharsets.UTF_8);
} }
String url = QSP_API_URL + "/api/board/list"; String url = null;
String apiUrl = UriComponentsBuilder.fromHttpUrl(url) String apiUrl = null;
.queryParam("noticeNo", boardRequest.getNoticeNo()).queryParam("schTitle", encodedSchTitle)
.queryParam("schNoticeTpCd", boardRequest.getSchNoticeTpCd()) if("QNA".equals(boardRequest.getSchNoticeClsCd())) {
.queryParam("schNoticeClsCd", boardRequest.getSchNoticeClsCd()) url = QSP_API_URL + "/api/qna/list";
.queryParam("startRow", boardRequest.getStartRow()) apiUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("endRow", boardRequest.getEndRow()).build().toUriString(); .queryParam("compCd", boardRequest.getCompCd())
.queryParam("storeId", boardRequest.getStoreId())
.queryParam("siteTpCd", boardRequest.getSiteTpCd())
.queryParam("schTitle", encodedSchTitle)
.queryParam("schRegId", boardRequest.getSchRegId())
.queryParam("schFromDt", boardRequest.getSchFromDt())
.queryParam("schToDt", boardRequest.getSchToDt())
.queryParam("startRow", boardRequest.getStartRow())
.queryParam("endRow", boardRequest.getEndRow())
.queryParam("loginId", boardRequest.getLoginId())
.queryParam("langCd", boardRequest.getLangCd())
.build()
.toUriString();
} else {
url = QSP_API_URL + "/api/board/list";
apiUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("noticeNo", boardRequest.getNoticeNo())
.queryParam("schTitle", encodedSchTitle)
.queryParam("schNoticeTpCd", boardRequest.getSchNoticeTpCd())
.queryParam("schNoticeClsCd", boardRequest.getSchNoticeClsCd())
.queryParam("startRow", boardRequest.getStartRow())
.queryParam("endRow", boardRequest.getEndRow())
.queryParam("schMainYn", boardRequest.getSchMainYn())
.build()
.toUriString();
}
/* [2]. QSP API CALL -> Response */ /* [2]. QSP API CALL -> Response */
String strResponse = interfaceQsp.callApi(HttpMethod.GET, apiUrl, null); String strResponse = interfaceQsp.callApi(HttpMethod.GET, apiUrl, null);
@ -103,15 +142,32 @@ public class BoardService {
/* [0]. Validation Check */ /* [0]. Validation Check */
if (boardRequest.getNoticeNo() == null) { if (boardRequest.getNoticeNo() == null) {
// [msg] {0} is required input value. // [msg] {0} is required input value.
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Notice No")); message.getMessage("common.message.required.data", "Notice No"));
} }
/* [1]. QSP API (url + param) Setting */ String url = null;
String url = QSP_API_URL + "/api/board/detail"; String apiUrl = null;
String apiUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("noticeNo", boardRequest.getNoticeNo()).build().toUriString();
if("QNA".equals(boardRequest.getSchNoticeClsCd())) {
url = QSP_API_URL + "/api/qna/detail";
apiUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("qnaNo", boardRequest.getQnaNo())
.queryParam("compCd", boardRequest.getCompCd())
.queryParam("loginId", boardRequest.getLoginId())
.queryParam("langCd", boardRequest.getLangCd())
.queryParam("siteTpCd", boardRequest.getSiteTpCd())
.build()
.toUriString();
} else {
/* [1]. QSP API (url + param) Setting */
url = QSP_API_URL + "/api/board/detail";
apiUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("noticeNo", boardRequest.getNoticeNo())
.build()
.toUriString();
}
/* [2]. QSP API CALL -> Response */ /* [2]. QSP API CALL -> Response */
String strResponse = interfaceQsp.callApi(HttpMethod.GET, apiUrl, null); String strResponse = interfaceQsp.callApi(HttpMethod.GET, apiUrl, null);
@ -128,6 +184,138 @@ public class BoardService {
return response; return response;
} }
/**
* 게시판 저장 QSP -> Q.CAST3
*
* @param boardRequest
* @return
* @throws Exception
*/
public BoardResponse getBoardQnaSave(BoardRequest boardRequest, HttpServletRequest request) throws Exception {
BoardResponse response = null;
/* [0]. Validation Check */
if (boardRequest.getCompCd() == null || boardRequest.getCompCd().isEmpty()) {
// [msg] {0} is required input value.
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Comp Cd"));
}
if (boardRequest.getSiteTpCd() == null || boardRequest.getSiteTpCd().isEmpty()) {
// [msg] {0} is required input value.
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Site Type Cd"));
}
if (boardRequest.getQnaClsLrgCd() == null || boardRequest.getQnaClsLrgCd().isEmpty()) {
// [msg] {0} is required input value.
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Qna Cls Large Cd"));
}
if (boardRequest.getQnaClsMidCd() == null || boardRequest.getQnaClsMidCd().isEmpty()) {
// [msg] {0} is required input value.
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Qna Cls Mid Cd"));
}
if (boardRequest.getTitle() == null || boardRequest.getTitle().isEmpty()) {
// [msg] {0} is required input value.
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "title"));
}
if (boardRequest.getContents() == null || boardRequest.getContents().isEmpty()) {
// [msg] {0} is required input value.
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "contents"));
}
if (boardRequest.getRegId() == null || boardRequest.getRegId().isEmpty()) {
// [msg] {0} is required input value.
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Reg Id"));
}
if (boardRequest.getRegUserNm() == null || boardRequest.getRegUserNm().isEmpty()) {
// [msg] {0} is required input value.
throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Reg User Nm"));
}
String url = null;
String apiUrl = null;
BoardResponse boardResponse = null;
if("QNA".equals(boardRequest.getSchNoticeClsCd())) {
url = QSP_API_URL + "/api/qna/save";
apiUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("siteTpCd", boardRequest.getSiteTpCd())
.queryParam("compCd", boardRequest.getCompCd())
.queryParam("regId", boardRequest.getRegId())
.queryParam("title", boardRequest.getTitle())
.queryParam("qnaClsLrgCd", boardRequest.getQnaClsLrgCd() )
.queryParam("qnaClsMidCd", boardRequest.getQnaClsMidCd())
.queryParam("qnaClsSmlCd", boardRequest.getQnaClsSmlCd())
.queryParam("contents", boardRequest.getContents())
.queryParam("storeId", boardRequest.getStoreId())
.queryParam("regUserNm", boardRequest.getRegUserNm())
.queryParam("regUserTelNo", boardRequest.getRegUserTelNo())
.queryParam("qstMail", boardRequest.getQstMail())
// .queryParam("files", multipartFileList)
.build()
.toUriString();
}
List<MultipartFile> multipartFileList = new ArrayList<>();
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, List<MultipartFile>> mapMultipart = multipartRequest.getMultiFileMap();
String strParamKey;
for (String s : mapMultipart.keySet()) {
strParamKey = s;
multipartFileList.addAll(mapMultipart.get(strParamKey));
}
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
RestTemplate restTemplate = new RestTemplate();
String responseStr;
HttpStatus httpStatus = HttpStatus.CREATED;
for (MultipartFile file : multipartFileList) {
if (!file.isEmpty()) {
map.add("file", new MultipartInputStreamFileResource(file.getInputStream(), file.getOriginalFilename()));
}
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);
String strResponse = restTemplate.postForObject(apiUrl, requestEntity, String.class);
//String strResponse = interfaceQsp.callApi(HttpMethod.POST, apiUrl, multipartFileList);
if (!"".equals(strResponse)) {
com.fasterxml.jackson.databind.ObjectMapper om =
new com.fasterxml.jackson.databind.ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
response = om.readValue(strResponse, BoardResponse.class);
} else {
// [msg] No data
throw new QcastException(ErrorCode.NOT_FOUND, message.getMessage("common.message.no.data"));
}
return response;
}
/** /**
* 게시판 파일 다운로드 QSP -> Q.CAST3 * 게시판 파일 다운로드 QSP -> Q.CAST3
* *
@ -135,17 +323,33 @@ public class BoardService {
* @param encodeFileNo * @param encodeFileNo
* @throws Exception * @throws Exception
*/ */
public void getFileDownload(HttpServletResponse response, String encodeFileNo) throws Exception { public void getFileDownload(HttpServletResponse response, String keyNo, String zipYn)
throws Exception {
/* [0]. Validation Check */ /* [0]. Validation Check */
if ("".equals(encodeFileNo)) { if ("".equals(keyNo)) {
// [msg] {0} is required input value. // [msg] {0} is required input value.
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, String arg = "Y".equals(zipYn) ? "Notice No" : "File No";
message.getMessage("common.message.required.data", "File No")); throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE, message.getMessage("common.message.required.data", arg));
} }
/* [1]. QSP API (url + fileNo) Setting */ /* [1]. QSP API (url + fileNo) Setting */
String url = QSP_API_URL + "/api/file/downloadFile" + "?encodeFileNo=" + encodeFileNo; String url = null;
if("NO".equals(zipYn)) {
url = QSP_API_URL + "/api/file/downloadFile2?encodeFileNo=" + keyNo;
}else{
url = QSP_API_URL + "/api/file/downloadFile";
if ("Y".equals(zipYn)) {
url += "?noticeNo=" + keyNo;
} else {
url += "?fileNo=" + keyNo;
}
}
/* [2]. QSP API CALL -> Response */ /* [2]. QSP API CALL -> Response */
Map<String, String> result = new HashMap<String, String>(); Map<String, String> result = new HashMap<String, String>();
@ -154,10 +358,13 @@ public class BoardService {
if (byteResponse != null && byteResponse.length > 0) { if (byteResponse != null && byteResponse.length > 0) {
try { try {
/* [3]. API 응답 파일 처리 */ /* [3]. API 응답 파일 처리 */
response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setContentType( response.setContentType(
!"".equals(result.get("type")) && result.get("type") != null ? result.get("type") !"".equals(result.get("type")) && result.get("type") != null
? result.get("type")
: "application/octet-stream"); : "application/octet-stream");
response.setHeader("Content-Disposition", response.setHeader(
"Content-Disposition",
!"".equals(result.get("disposition")) && result.get("disposition") != null !"".equals(result.get("disposition")) && result.get("disposition") != null
? result.get("disposition") ? result.get("disposition")
: "attachment;"); : "attachment;");
@ -170,14 +377,35 @@ public class BoardService {
} catch (Exception e) { } catch (Exception e) {
// [msg] File download error // [msg] File download error
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, throw new QcastException(
ErrorCode.INTERNAL_SERVER_ERROR,
message.getMessage("common.message.file.download.error")); message.getMessage("common.message.file.download.error"));
} }
} else { } else {
// [msg] File does not exist. // [msg] File does not exist.
throw new QcastException(ErrorCode.NOT_FOUND, throw new QcastException(
message.getMessage("common.message.file.download.exists")); ErrorCode.NOT_FOUND, message.getMessage("common.message.file.download.exists"));
} }
} }
} }
class MultipartInputStreamFileResource extends InputStreamResource {
private final String filename;
MultipartInputStreamFileResource(InputStream inputStream, String filename) {
super(inputStream);
this.filename = filename;
}
@Override
public String getFilename() {
return this.filename;
}
@Override
public long contentLength() throws IOException {
return -1; // we do not want to generally read the whole stream into memory ...
}
}

View File

@ -1,7 +1,13 @@
package com.interplug.qcast.biz.community.dto; package com.interplug.qcast.biz.community.dto;
import com.interplug.qcast.biz.file.dto.FileRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Getter @Getter
@Setter @Setter
@ -25,4 +31,40 @@ public class BoardRequest {
/** 종료 행 */ /** 종료 행 */
private int endRow; private int endRow;
/** 메인여부 */
private String schMainYn;
//Company Code
private String compCd;
private String storeId;
//Site Type Code
private String siteTpCd;
private String loginId;
//등록자 아이디
private String schRegId;
//검색 시작일시
private String schFromDt;
//검색 끝일시
private String schToDt;
private String qnaNo;
private String langCd;
private String qnaClsLrgCd;
private String qnaClsMidCd;
private String qnaClsSmlCd;
private String contents;
private String regId;
private String title;
private String regUserNm;
private String regUserTelNo;
private String qstMail;
@Schema(description = "첨부파일 목록")
List<MultipartFile> fileList;
} }

View File

@ -1,14 +1,23 @@
package com.interplug.qcast.biz.displayItem; package com.interplug.qcast.biz.displayItem;
import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest;
import com.interplug.qcast.biz.displayItem.dto.ItemDetailResponse;
import com.interplug.qcast.biz.displayItem.dto.ItemRequest;
import com.interplug.qcast.biz.displayItem.dto.ItemResponse; import com.interplug.qcast.biz.displayItem.dto.ItemResponse;
import com.interplug.qcast.config.Exception.QcastException;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@Slf4j @Slf4j
@RestController @RestController
@ -18,26 +27,46 @@ import org.springframework.web.bind.annotation.*;
public class DisplayItemController { public class DisplayItemController {
private final DisplayItemService displayItemService; private final DisplayItemService displayItemService;
/**
* 전시제품 정보 등록/수정
*
* @param displayItemRequest
* @throws QcastException
*/
@Operation(description = "전시제품 정보를 등록/수정한다. (동기화)") @Operation(description = "전시제품 정보를 등록/수정한다. (동기화)")
@PostMapping("/display-item-save") @PostMapping("/display-item-save")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public void setStoreDisplayItemSave(@RequestBody DisplayItemRequest displayItemRequest) public void setStoreDisplayItemSave(@RequestBody DisplayItemRequest displayItemRequest)
throws Exception { throws QcastException {
displayItemService.setStoreDisplayItemSave(displayItemRequest); displayItemService.setStoreDisplayItemSave(displayItemRequest);
} }
/**
* 제품 목록 조회
*
* @param itemRequest
* @return
* @throws QcastException
*/
@Operation(description = "제품 목록을 조회한다.") @Operation(description = "제품 목록을 조회한다.")
@GetMapping("/item-list") @PostMapping("/item-list")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public List<ItemResponse> getItemList(@RequestParam("saleStoreId") String saleStoreId) public List<ItemResponse> getItemList(@RequestBody ItemRequest itemRequest)
throws Exception { throws QcastException {
return displayItemService.getItemList(saleStoreId); return displayItemService.getItemList(itemRequest);
} }
/**
* 제품 상세 정보 조회
*
* @param itemId
* @return
* @throws QcastException
*/
@Operation(description = "제품 상세 정보를 조회한다.") @Operation(description = "제품 상세 정보를 조회한다.")
@GetMapping("/item-detail") @GetMapping("/item-detail")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public ItemResponse getItemDetail(@RequestParam("itemId") String itemId) throws Exception { public ItemDetailResponse getItemDetail(@RequestParam String itemId) throws QcastException {
return displayItemService.getItemDetail(itemId); return displayItemService.getItemDetail(itemId);
} }
} }

View File

@ -1,8 +1,6 @@
package com.interplug.qcast.biz.displayItem; package com.interplug.qcast.biz.displayItem;
import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; import com.interplug.qcast.biz.displayItem.dto.*;
import com.interplug.qcast.biz.displayItem.dto.ItemResponse;
import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse;
import java.util.List; import java.util.List;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
@ -12,9 +10,11 @@ public interface DisplayItemMapper {
void setStoreDisplayItemSave(DisplayItemRequest displayItemRequest) throws Exception; void setStoreDisplayItemSave(DisplayItemRequest displayItemRequest) throws Exception;
List<ItemResponse> getItemList(@Param("saleStoreId") String saleStoreId); List<ItemResponse> getItemList(ItemRequest itemRequest);
ItemResponse getItemDetail(@Param("itemId") String itemId); ItemDetailResponse getItemDetail(@Param("itemId") String itemId);
List<ItemResponse> selectItemBomList(@Param("itemId") String itemId);
/** /**
* 아이템 정보 동기화 * 아이템 정보 동기화
@ -24,4 +24,40 @@ public interface DisplayItemMapper {
* @throws Exception * @throws Exception
*/ */
int setItemSyncSave(ItemSyncResponse itemInfoSync); int setItemSyncSave(ItemSyncResponse itemInfoSync);
/**
* 아이템 추가 정보 동기화
*
* @param itemInfoSync 아이템 정보
* @return
* @throws Exception
*/
int setItemInfoSyncSave(ItemSyncResponse itemInfoSync);
/**
* BOM 아이템 정보 삭제
*
* @param bomInfoSync 아이템 정보
* @return
* @throws Exception
*/
int deleteBomSync(BomSyncResponse bomInfoSync);
/**
* BOM 아이템 정보 동기화
*
* @param bomInfoSync 아이템 정보
* @return
* @throws Exception
*/
int setBomSyncSave(BomSyncResponse bomInfoSync);
/**
* 아이템 가격 정보 동기화
*
* @param priceItemSyncResponse 아이템 가격 정보
* @return
* @throws Exception
*/
int setPriceItemSyncSave(PriceItemSyncResponse priceItemSyncResponse);
} }

View File

@ -1,11 +1,11 @@
package com.interplug.qcast.biz.displayItem; package com.interplug.qcast.biz.displayItem;
import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; import com.interplug.qcast.biz.displayItem.dto.*;
import com.interplug.qcast.biz.displayItem.dto.ItemResponse;
import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse;
import com.interplug.qcast.biz.estimate.EstimateMapper; import com.interplug.qcast.biz.estimate.EstimateMapper;
import com.interplug.qcast.biz.estimate.dto.NoteRequest; import com.interplug.qcast.biz.estimate.dto.NoteRequest;
import com.interplug.qcast.biz.estimate.dto.NoteResponse; import com.interplug.qcast.biz.estimate.dto.NoteResponse;
import com.interplug.qcast.config.Exception.ErrorCode;
import com.interplug.qcast.config.Exception.QcastException;
import io.micrometer.common.util.StringUtils; import io.micrometer.common.util.StringUtils;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -25,20 +25,29 @@ public class DisplayItemService {
* 판매점 노출 아이템 정보 저장 * 판매점 노출 아이템 정보 저장
* *
* @param displayItemRequest * @param displayItemRequest
* @throws Exception * @throws QcastException
*/ */
public void setStoreDisplayItemSave(DisplayItemRequest displayItemRequest) throws Exception { public void setStoreDisplayItemSave(DisplayItemRequest displayItemRequest) throws QcastException {
displayItemMapper.setStoreDisplayItemSave(displayItemRequest); try {
displayItemMapper.setStoreDisplayItemSave(displayItemRequest);
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
} }
/** /**
* 아이템 목록 조회 * 아이템 목록 조회
* *
* @param saleStoreId * @param itemRequest
* @return * @return
* @throws QcastException
*/ */
public List<ItemResponse> getItemList(String saleStoreId) { public List<ItemResponse> getItemList(ItemRequest itemRequest) throws QcastException {
return displayItemMapper.getItemList(saleStoreId); try {
return displayItemMapper.getItemList(itemRequest);
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
} }
/** /**
@ -47,29 +56,39 @@ public class DisplayItemService {
* @param itemId * @param itemId
* @return * @return
*/ */
public ItemResponse getItemDetail(String itemId) { public ItemDetailResponse getItemDetail(String itemId) throws QcastException {
try {
ItemDetailResponse itemDetailResponse = displayItemMapper.getItemDetail(itemId);
ItemResponse itemResponse = displayItemMapper.getItemDetail(itemId); if (itemDetailResponse != null) {
// BOM 헤더 아이템인 경우 BOM List를 내려준다.
if ("ERLA".equals(itemDetailResponse.getItemCtgGr())) {
List<ItemResponse> itemBomList = displayItemMapper.selectItemBomList(itemId);
if (itemResponse != null) { itemDetailResponse.setItemBomList(itemBomList);
// 견적특이사항 관련 데이터 셋팅 }
String[] arrItemId = {itemId};
NoteRequest noteRequest = new NoteRequest(); // 견적특이사항 관련 데이터 셋팅
noteRequest.setArrItemId(arrItemId); String[] arrItemId = {itemId};
noteRequest.setSchSpnTypeCd("PROD");
List<NoteResponse> noteItemList = estimateMapper.selectEstimateNoteItemList(noteRequest);
String spnAttrCds = ""; NoteRequest noteRequest = new NoteRequest();
for (NoteResponse noteResponse : noteItemList) { noteRequest.setArrItemId(arrItemId);
spnAttrCds += !StringUtils.isEmpty(spnAttrCds) ? "" : ""; noteRequest.setSchSpnTypeCd("PROD");
spnAttrCds += noteResponse.getCode(); List<NoteResponse> noteItemList = estimateMapper.selectEstimateNoteItemList(noteRequest);
String spnAttrCds = "";
for (NoteResponse noteResponse : noteItemList) {
spnAttrCds += !StringUtils.isEmpty(spnAttrCds) ? "" : "";
spnAttrCds += noteResponse.getCode();
}
itemDetailResponse.setSpnAttrCds(spnAttrCds);
} }
itemResponse.setSpnAttrCds(spnAttrCds); return itemDetailResponse;
} catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, e.getMessage());
} }
return itemResponse;
} }
/** /**
@ -82,8 +101,69 @@ public class DisplayItemService {
public int setItemSyncSave(List<ItemSyncResponse> itemSyncList) throws Exception { public int setItemSyncSave(List<ItemSyncResponse> itemSyncList) throws Exception {
int cnt = 0; int cnt = 0;
for (ItemSyncResponse itemSyncData : itemSyncList) { for (ItemSyncResponse itemSyncData : itemSyncList) {
displayItemMapper.setItemSyncSave(itemSyncData); cnt += displayItemMapper.setItemSyncSave(itemSyncData);
cnt += displayItemMapper.setItemInfoSyncSave(itemSyncData);
} }
return cnt; return cnt;
} }
/**
* 아이템 정보 동기화
*
* @param bomSyncList 아이템 목록
* @return
* @throws Exception
*/
public int setBomSyncSave(List<BomSyncResponse> bomSyncList) throws Exception {
int cnt = 0;
// 2026-05-12 같은 (PACKAGE_ITEM_ID, ITEM_ID) A/D 함께 오는 케이스 대비,
// 외부 응답 순서와 무관하게 결정적 결과(A 이김) 보장하기 위해 2단계로 처리.
// 1단계: D 먼저 전부 DELETE
for (BomSyncResponse bomSyncData : bomSyncList) {
if ("D".equals(bomSyncData.getStatCd())) {
// Bom 아이템 삭제 처리
cnt += displayItemMapper.deleteBomSync(bomSyncData);
}
}
// 2단계: D 전부 MERGE (upsert)
for (BomSyncResponse bomSyncData : bomSyncList) {
if (!"D".equals(bomSyncData.getStatCd())) {
// Bom 아이템 수정/등록 처리
cnt += displayItemMapper.setBomSyncSave(bomSyncData);
}
}
return cnt;
}
/**
* 아이템 가격 정보 동기화
*
* @param priceItemSyncList 가격 목록
* @return
* @throws Exception
*/
public int setPriceSyncSave(List<PriceItemSyncResponse> priceItemSyncList) throws Exception {
int cnt = 0;
for (PriceItemSyncResponse priceItemSyncResponse : priceItemSyncList) {
cnt += displayItemMapper.setPriceItemSyncSave(priceItemSyncResponse);
}
return cnt;
}
/**
* 노출 아이템 동기화 - Batch
*
* @param displayItemList
* @throws Exception
*/
public void setStoreDispItemBatch(List<DisplayItemRequest> displayItemList) throws Exception {
// 노출 아이템 동기화
for (DisplayItemRequest displayItemRequest : displayItemList) {
try {
displayItemMapper.setStoreDisplayItemSave(displayItemRequest);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
} }

View File

@ -0,0 +1,27 @@
package com.interplug.qcast.biz.displayItem.dto;
import com.interplug.qcast.util.DefaultResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/** Bom 아이템 동기화 Response */
@EqualsAndHashCode(callSuper = true)
@Data
public class BomSyncResponse extends DefaultResponse {
@Schema(description = "Material Number")
String packageItemId;
@Schema(description = "Bom Code")
String itemId;
@Schema(description = "Amount")
String amount;
@Schema(description = "Manual Flag")
String manualFlg;
@Schema(description = "Status Code(A, D)")
String statCd;
}

View File

@ -0,0 +1,57 @@
package com.interplug.qcast.biz.displayItem.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
@Data
public class ItemDetailResponse {
@Schema(description = "Itme Id")
private String itemId;
@Schema(description = "Item No")
private String itemNo;
@Schema(description = "Item Name")
private String itemName;
@Schema(description = "Goods No")
private String goodsNo;
@Schema(description = "Unit")
private String unit;
@Schema(description = "Specification")
private String specification;
@Schema(description = "pnow_w")
private String pnowW;
@Schema(description = "Item Group")
private String itemGroup;
@Schema(description = "Module Flag")
private String moduleFlg;
@Schema(description = "PKG Material Flag")
private String pkgMaterialFlg;
@Schema(description = "File Upload Flag")
private String fileUploadFlg;
@Schema(description = "오픈가 Flag")
private String openFlg;
@Schema(description = "Sale Price")
private String salePrice;
@Schema(description = "Item Ctg Group")
private String itemCtgGr;
@Schema(description = "견적 특이사항 코드")
private String spnAttrCds;
@Schema(description = "Bom 목록")
List<ItemResponse> itemBomList;
}

View File

@ -0,0 +1,17 @@
package com.interplug.qcast.biz.displayItem.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class ItemRequest {
@Schema(description = "Sale Store Id")
private String saleStoreId;
@Schema(description = "Cold Zone Flg")
private String coldZoneFlg;
@Schema(description = "Salt-affected Flg")
private String saltAffectedFlg;
}

View File

@ -9,6 +9,9 @@ public class ItemResponse {
@Schema(description = "Itme Id") @Schema(description = "Itme Id")
private String itemId; private String itemId;
@Schema(description = "Item No")
private String itemNo;
@Schema(description = "Item Name") @Schema(description = "Item Name")
private String itemName; private String itemName;
@ -39,6 +42,12 @@ public class ItemResponse {
@Schema(description = "Sale Price") @Schema(description = "Sale Price")
private String salePrice; private String salePrice;
@Schema(description = "Item Ctg Group")
private String itemCtgGr;
@Schema(description = "Bom Amount")
private String bomAmount;
@Schema(description = "견적 특이사항 코드") @Schema(description = "견적 특이사항 코드")
private String spnAttrCds; private String spnAttrCds;
} }

View File

@ -3,8 +3,10 @@ package com.interplug.qcast.biz.displayItem.dto;
import com.interplug.qcast.util.DefaultResponse; import com.interplug.qcast.util.DefaultResponse;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
/** 아이템 동기화 Response */ /** 아이템 동기화 Response */
@EqualsAndHashCode(callSuper = false)
@Data @Data
public class ItemSyncResponse extends DefaultResponse { public class ItemSyncResponse extends DefaultResponse {
@Schema(description = "Material Number") @Schema(description = "Material Number")
@ -34,6 +36,9 @@ public class ItemSyncResponse extends DefaultResponse {
@Schema(description = "Power Class") @Schema(description = "Power Class")
String pnowW; String pnowW;
@Schema(description = "Item Ctg Group")
String itemCtgGr;
@Schema(description = "Qcast Material Group Code") @Schema(description = "Qcast Material Group Code")
String itemGroup; String itemGroup;
@ -133,6 +138,18 @@ public class ItemSyncResponse extends DefaultResponse {
@Schema(description = "PKG Material Flg") @Schema(description = "PKG Material Flg")
String pkgMaterialFlg; String pkgMaterialFlg;
@Schema(description = "Temp Loss")
String tempLoss;
@Schema(description = "Temperature Coefficient")
String tempCoeff;
@Schema(description = "AMP")
String amp;
@Schema(description = "Conversion Efficiency")
String cnvEff;
@Schema(description = "Status Code(A, D)") @Schema(description = "Status Code(A, D)")
String statCd; String statCd;

View File

@ -0,0 +1,23 @@
package com.interplug.qcast.biz.displayItem.dto;
import com.interplug.qcast.util.DefaultResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/** 아이템 동기화 Response */
@EqualsAndHashCode(callSuper = false)
@Data
public class PriceItemSyncResponse extends DefaultResponse {
@Schema(description = "Price Pattern(정가 : 510,.A가격 : 513, C가격 : 514)")
String pricePattern;
@Schema(description = "Material Number")
String itemId;
@Schema(description = "Price Amount")
String salePrice;
@Schema(description = "Price Amount")
String costPrice;
}

View File

@ -0,0 +1,11 @@
package com.interplug.qcast.biz.displayItem.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/** 가격 동기화 Request */
@Data
public class PriceSyncRequest {
@Schema(description = "All Material Master Yn")
private String allYn;
}

View File

@ -0,0 +1,19 @@
package com.interplug.qcast.biz.displayItem.dto;
import com.interplug.qcast.util.DefaultResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
/** 가격 동기화 Response */
@EqualsAndHashCode(callSuper = false)
@Data
public class PriceSyncResponse extends DefaultResponse {
@Schema(description = "Module Price")
private List<PriceItemSyncResponse> modulePriceList;
@Schema(description = "Bos Price")
private List<PriceItemSyncResponse> bosPriceList;
}

View File

@ -1,6 +1,7 @@
package com.interplug.qcast.biz.estimate; package com.interplug.qcast.biz.estimate;
import com.interplug.qcast.biz.estimate.dto.*; import com.interplug.qcast.biz.estimate.dto.*;
import com.interplug.qcast.biz.object.dto.ObjectRequest;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@ -22,18 +23,25 @@ public class EstimateController {
@Operation(description = "1차점 가격 관리 목록을 조회한다.") @Operation(description = "1차점 가격 관리 목록을 조회한다.")
@GetMapping("/price/store-price-list") @GetMapping("/price/store-price-list")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public PriceResponse selectStorePriceList(PriceRequest priceRequest) throws Exception { public EstimateApiResponse selectStorePriceList(PriceRequest priceRequest) throws Exception {
return estimateService.selectStorePriceList(priceRequest); return estimateService.selectStorePriceList(priceRequest);
} }
@Operation(description = "아이템 가격 목록을 조회한다.") @Operation(description = "아이템 가격 목록을 조회한다.")
@PostMapping("/price/item-price-list") @PostMapping("/price/item-price-list")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public PriceResponse selectItemPriceList(@RequestBody PriceRequest priceRequest) public EstimateApiResponse selectItemPriceList(@RequestBody PriceRequest priceRequest)
throws Exception { throws Exception {
return estimateService.selectItemPriceList(priceRequest); return estimateService.selectItemPriceList(priceRequest);
} }
@Operation(description = "견적서 특이사항 타이틀 목록을 조회한다.")
@GetMapping("/special-note-title-list")
@ResponseStatus(HttpStatus.OK)
public List<NoteResponse> selectSpecialNoteTitleList(NoteRequest noteRequest) throws Exception {
return estimateService.selectSpecialNoteTitleList(noteRequest);
}
@Operation(description = "견적서 특이사항 목록을 조회한다.") @Operation(description = "견적서 특이사항 목록을 조회한다.")
@GetMapping("/special-note-list") @GetMapping("/special-note-list")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
@ -44,7 +52,7 @@ public class EstimateController {
@Operation(description = "견적서 상세를 조회한다.") @Operation(description = "견적서 상세를 조회한다.")
@GetMapping("/{objectNo}/{planNo}/detail") @GetMapping("/{objectNo}/{planNo}/detail")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public EstimateResponse selectObjectDetail( public EstimateResponse selectEstimateDetail(
@PathVariable String objectNo, @PathVariable String planNo) throws Exception { @PathVariable String objectNo, @PathVariable String planNo) throws Exception {
return estimateService.selectEstimateDetail(objectNo, planNo); return estimateService.selectEstimateDetail(objectNo, planNo);
} }
@ -59,9 +67,24 @@ public class EstimateController {
@Operation(description = "견적서를 복사한다.") @Operation(description = "견적서를 복사한다.")
@PostMapping("/save-estimate-copy") @PostMapping("/save-estimate-copy")
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
public EstimateResponse insertEstimateCopy(@RequestBody EstimateRequest estimateRequest) public EstimateResponse insertEstimateCopy(@RequestBody EstimateCopyRequest estimateCopyRequest)
throws Exception { throws Exception {
return estimateService.insertEstimateCopy(estimateRequest); return estimateService.insertEstimateCopy(estimateCopyRequest);
}
@Operation(description = "견적서를 초기화한다.")
@PostMapping("/reset-estimate")
@ResponseStatus(HttpStatus.CREATED)
public EstimateResponse updateEstimateReset(@RequestBody EstimateRequest estimateRequest)
throws Exception {
return estimateService.updateEstimateReset(estimateRequest);
}
@Operation(description = "견적서 잠금여부를 저장한다.")
@PostMapping("/save-estimate-lock")
@ResponseStatus(HttpStatus.CREATED)
public void updateEstimateLock(@RequestBody EstimateRequest estimateRequest) throws Exception {
estimateService.updateEstimateLock(estimateRequest);
} }
@Operation(description = "견적서를 엑셀로 다운로드한다.") @Operation(description = "견적서를 엑셀로 다운로드한다.")
@ -74,4 +97,32 @@ public class EstimateController {
throws Exception { throws Exception {
estimateService.excelDownload(request, response, estimateRequest); estimateService.excelDownload(request, response, estimateRequest);
} }
@Operation(description = "2차점 특가 있는 2nd Agency 목록을 조회한다.")
@GetMapping("/agency-cust-list")
@ResponseStatus(HttpStatus.OK)
public EstimateApiResponse selectAgencyCustList(PriceRequest priceRequest) throws Exception {
return estimateService.selectAgencyCustList(priceRequest);
}
@Operation(description = "견적서를 삭제한다.")
@PostMapping("/delete-estimate")
@ResponseStatus(HttpStatus.CREATED)
public void deleteEstimate(@RequestBody EstimateRequest estimateRequest) throws Exception {
estimateService.deleteEstimate(estimateRequest);
}
@Operation(description = "발전시뮬레이션 필요 데이터 목록을 조회한다.")
@GetMapping("/simulation-estimate-list")
@ResponseStatus(HttpStatus.OK)
public SimulationEstimateListResponse selectSimulationEstimateList(ObjectRequest objectRequest) throws Exception {
return estimateService.selectSimulationEstimateList(objectRequest);
}
@Operation(description = "발전시뮬레이션 필요 데이터 상세 정보를 조회한다.")
@GetMapping("/simulation-estimate-info")
@ResponseStatus(HttpStatus.OK)
public SimulationEstimateResponse selectSimulationEstimateInfo(EstimateRequest estimateRequest) throws Exception {
return estimateService.selectSimulationEstimateInfo(estimateRequest);
}
} }

View File

@ -1,8 +1,10 @@
package com.interplug.qcast.biz.estimate; package com.interplug.qcast.biz.estimate;
import com.interplug.qcast.biz.estimate.dto.*; import com.interplug.qcast.biz.estimate.dto.*;
import com.interplug.qcast.biz.object.dto.*;
import java.util.List; import java.util.List;
import com.interplug.qcast.biz.object.dto.ObjectRequest;
import com.interplug.qcast.biz.object.dto.ObjectResponse;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
@ -13,42 +15,156 @@ public interface EstimateMapper {
// 견적서 PDF 상세 확인 // 견적서 PDF 상세 확인
public EstimateResponse selectEstimatePdfDetail(EstimateRequest estimateRequest); public EstimateResponse selectEstimatePdfDetail(EstimateRequest estimateRequest);
// 견적서 API 상세 확인
public EstimateSendResponse selectEstimateApiDetail(EstimateRequest estimateRequest);
// 견적서 API 실패 목록 조회
public List<EstimateSendResponse> selectEstimateApiFailList();
// 견적서 도면 아이템 목록 조회
public List<ItemResponse> selectEstimateDrawingItemList(EstimateRequest estimateRequest);
// 견적서 아이템 목록 조회 // 견적서 아이템 목록 조회
public List<ItemResponse> selectEstimateItemList(EstimateRequest estimateRequest); public List<ItemResponse> selectEstimateItemList(EstimateRequest estimateRequest);
// 아이템 마스터 목록 조회 // 아이템 마스터 목록 조회
public List<ItemResponse> selectItemMasterList(EstimateRequest estimateRequest); public List<ItemResponse> selectItemMasterList(EstimateRequest estimateRequest);
// 아이템 마스터 목록 조회 // 아이템 마스터 BOM 목록 조회
public List<ItemResponse> selectItemMasterBomList(String itemId);
// 견적서 지붕재 인증용량 조회
public String selectEstimateRoofCertVolKw(EstimateRequest estimateRequest);
// 견적서 지붕재 목록 조회
public List<RoofResponse> selectEstimateRoofList(EstimateRequest estimateRequest);
// 견적서 지붕재 아이템 목록 조회
public List<RoofResponse> selectEstimateRoofItemList(EstimateRequest estimateRequest);
// 견적서 지붕재 PC 목록 조회
public List<ItemResponse> selectEstimateCircuitItemList(EstimateRequest estimateRequest);
// 견적서 지붕재 용량 목록 조회
public List<RoofResponse> selectEstimateRoofVolList(EstimateRequest estimateRequest);
// 견적서 특이사항 타이틀 목록 조회
public List<NoteResponse> selectEstimateNoteTitleList(NoteRequest noteRequest);
// 견적서 특이사항 목록 조회
public List<NoteResponse> selectEstimateNoteList(NoteRequest noteRequest); public List<NoteResponse> selectEstimateNoteList(NoteRequest noteRequest);
// 아이템 마스터 목록 조회 // 아이템 마스터 목록 조회
public List<NoteResponse> selectEstimateNoteItemList(NoteRequest noteRequest); public List<NoteResponse> selectEstimateNoteItemList(NoteRequest noteRequest);
// 아이템 히스토리 번호 조회
public String selectEstimateItemHisNo(EstimateRequest estimateRequest);
// 물건정보 수정 // 물건정보 수정
public int updateObject(EstimateRequest estimateRequest); public int updateObject(EstimateRequest estimateRequest);
// 물건정보 상세 수정
public int updateObjectInfo(EstimateRequest estimateRequest);
// 견적서 정보 수정 // 견적서 정보 수정
public int updateEstimate(EstimateRequest estimateRequest); public int updateEstimate(EstimateRequest estimateRequest);
// 견적서 지붕재 등록 // 견적서 상세 정보 수정
public int updateEstimateInfo(EstimateRequest estimateRequest);
// 견적서 정보 초기화
public int updateEstimateReset(EstimateRequest estimateRequest);
// 견적서 상세 정보 초기화
public int updateEstimateInfoReset(EstimateRequest estimateRequest);
// 견적서 잠금 수정
public int updateEstimateLock(EstimateRequest estimateRequest);
// 견적서 API 정보 수정
public int updateEstimateApi(EstimateRequest estimateRequest);
// 견적서 지붕면 등록
public int insertEstimateRoof(RoofRequest roofRequest); public int insertEstimateRoof(RoofRequest roofRequest);
// 견적서 지붕재 아이템 등록 // 견적서 지붕 아이템 등록
public int insertEstimateRoofItem(ItemRequest itemRequest); public int insertEstimateRoofItem(ItemRequest itemRequest);
// 견적서 지붕면 회로구성 아이템 등록
public int insertEstimateCircuitItem(ItemRequest itemRequest);
// 견적서 도면 아이템 등록
public int insertEstimateDrawingItem(ItemRequest itemRequest);
// 견적서 아이템 등록 // 견적서 아이템 등록
public int insertEstimateItem(ItemRequest itemRequest); public int insertEstimateItem(ItemRequest itemRequest);
// 견적서 아이템 상세 등록
public int insertEstimateInfoItem(ItemRequest itemRequest);
// 견적서 아이템 히스토리 등록
public int insertEstimateItemHis(ItemRequest itemRequest);
// 견적서 지붕재 목록 삭제(물리 삭제) // 견적서 지붕재 목록 삭제(물리 삭제)
public int deleteEstimateRoofList(EstimateRequest estimateRequest); public int deleteEstimateRoofList(EstimateRequest estimateRequest);
// 견적서 지붕재 아이템 목록 삭제(물리 삭제) // 견적서 지붕재 아이템 목록 삭제(물리 삭제)
public int deleteEstimateRoofItemList(EstimateRequest estimateRequest); public int deleteEstimateRoofItemList(EstimateRequest estimateRequest);
// 견적서 회로구성 아이템 목록 삭제(물리 삭제)
public int deleteEstimateCircuitItemList(EstimateRequest estimateRequest);
// 견적서 도면 아이템 목록 삭제(물리 삭제)
public int deleteEstimateDrawingItemList(EstimateRequest estimateRequest);
// 견적서 아이템 목록 삭제(물리 삭제) // 견적서 아이템 목록 삭제(물리 삭제)
public int deleteEstimateItemList(EstimateRequest estimateRequest); public int deleteEstimateItemList(EstimateRequest estimateRequest);
// 견적서 아이템 상세 목록 삭제(물리 삭제)
public int deleteEstimateInfoItemList(EstimateRequest estimateRequest);
// 견적서 복사 // 견적서 복사
public int insertEstimateCopy(EstimateRequest estimateRequest); public int insertEstimateCopy(EstimateCopyRequest estimateCopyRequest);
// 견적서 상세 복사
public int insertEstimateInfoCopy(EstimateCopyRequest estimateCopyRequest);
// 견적서 지붕면 복사
public int insertEstimateRoofCopy(EstimateCopyRequest estimateCopyRequest);
// 견적서 지붕면 아이템 복사
public int insertEstimateRoofItemCopy(EstimateCopyRequest estimateCopyRequest);
// 견적서 지붕면 회로구성 아이템 복사
public int insertEstimateCircuitItemCopy(EstimateCopyRequest estimateCopyRequest);
// 견적서 도면 아이템 복사
public int insertEstimateDrawingItemCopy(EstimateCopyRequest estimateCopyRequest);
// Plan 확정 동기화
public int updatePlanConfirmSync(PlanSyncResponse planSyncData);
// 견적서 Q.ORDER 연동 시공타입 조회
public String selectEstimateConstructSpecification(EstimateRequest estimateRequest);
// 견적서 수정일 변경
public int updateEstimateLastEditDate(EstimateRequest estimateRequest);
public int updateEstimateInit(EstimateRequest estimateRequest);
public int updateEstimateInfoInit(EstimateRequest estimateRequest);
public int insertCanvasPopupStatusCopy(EstimateCopyRequest estimateCopyRequest);
// 발전시뮬레이션 물건번호 목록 조회
public List<ObjectResponse> selectSimulationEstimateList(ObjectRequest objectRequest);
// 발전시뮬레이션 지붕재 목록 조회
public List<SimulationRoofResponse> selectSimulationEstimateRoofList(EstimateRequest estimateRequest);
// 발전시뮬레이션 지붕재 아이템 목록 조회
public List<SimulationItemResponse> selectSimulationEstimateRoofModuleList(EstimateRequest estimateRequest);
// 발전시뮬레이션 지붕재 아이템 목록 조회
public List<SimulationItemResponse> selectSimulationEstimateRoofPcsList(EstimateRequest estimateRequest);
} }

View File

@ -3,7 +3,7 @@ package com.interplug.qcast.biz.estimate.dto;
import lombok.Data; import lombok.Data;
@Data @Data
public class PriceResponse { public class EstimateApiResponse {
/** API response result */ /** API response result */
private Object result; private Object result;

View File

@ -0,0 +1,31 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class EstimateCopyRequest {
@Schema(description = "물건번호")
private String objectNo;
@Schema(description = "플랜번호")
private String planNo;
@Schema(description = "판매점ID")
private String saleStoreId;
@Schema(description = "복사 판매점 ID")
private String copySaleStoreId;
@Schema(description = "복사 물건번호")
private String copyObjectNo;
@Schema(description = "복사 플랜번호")
private String copyPlanNo;
@Schema(description = "복사 담당자명")
private String copyReceiveUser;
@Schema(description = "사용자아이디")
private String userId;
}

View File

@ -1,5 +1,6 @@
package com.interplug.qcast.biz.estimate.dto; package com.interplug.qcast.biz.estimate.dto;
import com.interplug.qcast.biz.file.dto.FileRequest;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List; import java.util.List;
import lombok.Data; import lombok.Data;
@ -21,6 +22,9 @@ public class EstimateRequest {
@Schema(description = "안건명") @Schema(description = "안건명")
private String objectName; private String objectName;
@Schema(description = "경칭")
private String objectNameOmit;
@Schema(description = "시공방법") @Schema(description = "시공방법")
private String constructSpecification; private String constructSpecification;
@ -150,32 +154,71 @@ public class EstimateRequest {
@Schema(description = "가격코드") @Schema(description = "가격코드")
private String priceCd; private String priceCd;
@Schema(description = "QSP 동기화 여부")
private String syncFlg;
@Schema(description = "잠금 여부")
private String lockFlg;
@Schema(description = "임시저장 여부")
private String tempFlg;
@Schema(description = "비고") @Schema(description = "비고")
private String remarks; private String remarks;
@Schema(description = "복사 플랜번호")
private String copyPlanNo;
@Schema(description = "아이템번호 목록") @Schema(description = "아이템번호 목록")
private String[] arrItemId; private String[] arrItemId;
// 다운로드 관련 조건 // 다운로드 관련 조건
@Schema(description = "다운로드 정가 표시여부") @Schema(description = "검색 - 다운로드 구분")
private String schDownload;
@Schema(description = "검색 - 다운로드 정가 표시여부")
private String schUnitPriceFlg; private String schUnitPriceFlg;
@Schema(description = "다운로드 표시여부") @Schema(description = "검색 - 다운로드 표시여부")
private String schDisplayFlg; private String schDisplayFlg;
@Schema(description = "가대중량표 포함 여부") @Schema(description = "검색 - 가대중량표 포함 여부")
private String schWeightFlg; private String schWeightFlg;
@Schema(description = "도면 포함 여부") @Schema(description = "검색 - 도면/시뮬레이션 포함 여부")
private String schDrawingFlg; private String schDrawingFlg;
@Schema(description = "검색 - 아이템 그룹")
private String schItemGroup;
@Schema(description = "검색 - 아이템 BOM 제외여부")
private String schBomNotExist;
// 데이터 목록 관련 정보 // 데이터 목록 관련 정보
@Schema(description = "지붕재 목록") @Schema(description = "지붕재 목록")
List<RoofRequest> roofList; List<RoofRequest> roofSurfaceList;
@Schema(description = "PC 회로구성도 목록")
List<ItemRequest> circuitItemList;
@Schema(description = "아이템 목록") @Schema(description = "아이템 목록")
List<ItemRequest> itemList; List<ItemRequest> itemList;
@Schema(description = "첨부파일 목록")
List<FileRequest> fileList;
@Schema(description = "삭제 첨부파일 목록")
List<FileRequest> deleteFileList;
@Schema(description = "다운로드 파일명")
private String fileName;
@Schema(description = "발전시뮬레이션 타입")
private String pwrGnrSimType;
@Schema(description = "2차 SAP 판매점코드")
private String secSapSalesStoreCd;
@Schema(description = "판매점레벨")
private String storeLvl;
@Schema(description = "견적서생성판매점코드")
private String createStoreId;
} }

View File

@ -1,8 +1,10 @@
package com.interplug.qcast.biz.estimate.dto; package com.interplug.qcast.biz.estimate.dto;
import com.interplug.qcast.biz.file.dto.FileResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List; import java.util.List;
import com.interplug.qcast.biz.file.dto.FileResponse;
import com.interplug.qcast.biz.pwrGnrSimulation.dto.PwrGnrSimResponse;
import com.interplug.qcast.biz.pwrGnrSimulation.dto.PwrGnrSimRoofResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@Data @Data
@ -79,6 +81,9 @@ public class EstimateResponse {
@Schema(description = "기준풍속ID") @Schema(description = "기준풍속ID")
private String standardWindSpeedId; private String standardWindSpeedId;
@Schema(description = "기준풍속명")
private String standardWindSpeedName;
@Schema(description = "가대 메이커명") @Schema(description = "가대 메이커명")
private String supportMeaker; private String supportMeaker;
@ -139,12 +144,24 @@ public class EstimateResponse {
@Schema(description = "가격코드") @Schema(description = "가격코드")
private String priceCd; private String priceCd;
@Schema(description = "잠금 여부")
private String lockFlg;
@Schema(description = "임시저장 여부")
private String tempFlg;
@Schema(description = "비고") @Schema(description = "비고")
private String remarks; private String remarks;
@Schema(description = "갱신일") @Schema(description = "갱신일")
private String lastEditDatetime; private String lastEditDatetime;
@Schema(description = "생성일")
private String createDatetime;
@Schema(description = "생성자 아이디")
private String createUser;
// 가격 관련 정보 // 가격 관련 정보
@Schema(description = "총 수량") @Schema(description = "총 수량")
private String totAmount; private String totAmount;
@ -174,6 +191,15 @@ public class EstimateResponse {
@Schema(description = "경칭") @Schema(description = "경칭")
private String objectNameOmit; private String objectNameOmit;
@Schema(description = "도도부현명")
private String prefName;
@Schema(description = "지역명")
private String areaName;
@Schema(description = "계약조건")
private String conType;
@Schema(description = "물건정보 비고") @Schema(description = "물건정보 비고")
private String objectRemarks; private String objectRemarks;
@ -192,6 +218,27 @@ public class EstimateResponse {
@Schema(description = "하위 판매점명") @Schema(description = "하위 판매점명")
private String agencySaleStoreName; private String agencySaleStoreName;
@Schema(description = "지역코드")
private String areaId;
@Schema(description = "한랭지 대책여부")
private String coldRegionFlg;
@Schema(description = "염해지역 아이템사용 여부")
private String saltAreaFlg;
@Schema(description = "도면이미지1 (셀범위용, 기존)")
private byte[] drawingImg1;
@Schema(description = "도면이미지2 (셀범위용, 기존)")
private byte[] drawingImg2;
@Schema(description = "도면이미지1 (풀사이즈, 여백없음)")
private byte[] drawingImg1Full;
@Schema(description = "도면이미지2 (풀사이즈, 여백없음)")
private byte[] drawingImg2Full;
// 판매점 정보 // 판매점 정보
@Schema(description = "고객 판매점명") @Schema(description = "고객 판매점명")
private String custSaleStoreName; private String custSaleStoreName;
@ -233,4 +280,47 @@ public class EstimateResponse {
@Schema(description = "첨부파일 목록") @Schema(description = "첨부파일 목록")
List<FileResponse> fileList; List<FileResponse> fileList;
@Schema(description = "지붕재 정보")
RoofInfoResponse roofInfo;
@Schema(description = "발전시뮬레이션 정보")
PwrGnrSimResponse pwrGnrSim;
@Schema(description = "SAP STORE ID")
private String sapSaleStoreId;
@Schema(description = "SAP STORE CD")
private String sapSalesStoreCd;
@Schema(description = "2차 SAP 판매점코드")
private String secSapSalesStoreCd;
@Schema(description = "견적서 아이템 목록 15개")
List<ItemResponse> estimateItemList15;
@Schema(description = "PC 회로구성도 목록 11개")
List<ItemResponse> circuitItemList11;
@Schema(description = "지붕 모듈 목록 8개")
private List<PwrGnrSimRoofResponse> roofModuleList8;
@Schema(description = "견적서 STAND 아이템 목록 15개")
List<ItemResponse> estimateItemListS15;
@Schema(description = "PCS 목록 3개")
List<PwrGnrSimRoofResponse> pcsList3;
@Schema(description = "영업점 주소")
private String salesOfficeAddr;
@Schema(description = "영업점 전화번호")
private String salesOfficeTel;
@Schema(description = "영업점 Fax번호")
private String salesOfficeFax;
@Schema(description = "작성자 판매점 ID")
private String createSaleStoreId;
} }

View File

@ -0,0 +1,11 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
@Data
public class EstimateSendRequest {
@Schema(description = "견적서 목록 정보")
List<EstimateSendResponse> quoteList;
}

View File

@ -0,0 +1,121 @@
package com.interplug.qcast.biz.estimate.dto;
import com.interplug.qcast.biz.file.dto.FileResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
@Data
public class EstimateSendResponse {
@Schema(description = "물건번호")
private String objectNo;
@Schema(description = "플랜번호")
private String planNo;
@Schema(description = "판매점 ID")
private String saleStoreId;
@Schema(description = "물건명")
private String objectName;
@Schema(description = "경칭코드")
private String objectNameOmitCd;
@Schema(description = "견적서 등록일")
private String estimateDetailCreateDate;
@Schema(description = "수취회사명")
private String receiveCompanyName;
@Schema(description = "수취자명")
private String receiveUser;
@Schema(description = "배송지 우편번호")
private String deliveryZipNo;
@Schema(description = "배송지 주소")
private String deliveryTarget;
@Schema(description = "배송지 연락처")
private String deliveryTel;
@Schema(description = "배송 희망일")
private String deliveryHopeDate;
@Schema(description = "사양확장일")
private String specificationConfirmDate;
@Schema(description = "결제기간일")
private String paymentTerms;
@Schema(description = "차종류 코드")
private String carKindCd;
@Schema(description = "Track 종류 코드")
private String trackKind;
@Schema(description = "Track 10톤 배송일")
private String track10tDelivery;
@Schema(description = "Track 무게 코드")
private String trackWeight;
@Schema(description = "Track 시간 지정")
private String trackTimeSpecify;
@Schema(description = "Track 시간")
private String trackTime;
@Schema(description = "포리프트 여부")
private String forklift;
@Schema(description = "전압여부 (주택:0, 저압:1)")
private String houseClassCd;
@Schema(description = "영업사원 코드")
private String businessChargerCd;
@Schema(description = "영업사원 그룹 코드")
private String businessGroupCd;
@Schema(description = "시공방법")
private String constructSpecification;
@Schema(description = "북면설치여부")
private String northArrangement;
@Schema(description = "견적서 타입 (YJSS, YJOD)")
private String estimateType;
@Schema(description = "주택패키지 단가")
private String pkgAsp;
@Schema(description = "삭제여부")
private String delFlg;
@Schema(description = "마지막 수정일")
private String lastEditDatetime;
@Schema(description = "마지막 수정자")
private String lastEditUser;
@Schema(description = "저장타입(3:Q.CAST III)")
private String saveType;
@Schema(description = "문서번호")
private String docNo;
@Schema(description = "동기화 처리여부")
private String syncFlg;
// 데이터 목록 관련 정보
@Schema(description = "아이템 목록")
List<ItemResponse> itemList;
@Schema(description = "첨부파일 목록")
List<FileResponse> fileList;
@Schema(description = "2차 SAP 판매점코드")
private String secSapSalesStoreCd;
}

View File

@ -0,0 +1,14 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
@Data
public class EstimateSyncResponse {
@Schema(description = "실패목록")
private List<PlanSyncResponse> failList;
@Schema(description = "성공목록")
private List<PlanSyncResponse> successList;
}

View File

@ -14,15 +14,21 @@ public class ItemRequest {
@Schema(description = "플랜번호") @Schema(description = "플랜번호")
private String planNo; private String planNo;
@Schema(description = "지붕재 아이템 번호")
private String roofItemNo;
@Schema(description = "지붕재 번호") @Schema(description = "지붕재 번호")
private String roofNo; private String roofSurfaceId;
@Schema(description = "아이템 ID") @Schema(description = "아이템 ID")
private String itemId; private String itemId;
@Schema(description = "정렬순서") @Schema(description = "정렬번호")
private String dispOrder; private String dispOrder;
@Schema(description = "부모 정렬번호")
private String paDispOrder;
@Schema(description = "아이템 번호") @Schema(description = "아이템 번호")
private String itemNo; private String itemNo;
@ -38,6 +44,9 @@ public class ItemRequest {
@Schema(description = "수량") @Schema(description = "수량")
private String amount; private String amount;
@Schema(description = "BOM 수량")
private String bomAmount;
@Schema(description = "변경수량") @Schema(description = "변경수량")
private String amountChange; private String amountChange;
@ -59,15 +68,54 @@ public class ItemRequest {
@Schema(description = "아이템 특이사항 코드") @Schema(description = "아이템 특이사항 코드")
private String specialNoteCd; private String specialNoteCd;
@Schema(description = "아이템 오픈가 여부")
private String openFlg;
@Schema(description = "아이템 변경 여부") @Schema(description = "아이템 변경 여부")
private String itemChangeFlg; private String itemChangeFlg;
@Schema(description = "대표 케이블 여부")
private String dispCableFlg;
@Schema(description = "PC 아이템 ID")
private String pcItemId;
@Schema(description = "회로번호")
private String circuitNo;
@Schema(description = "회로구성번호")
private String circuit;
@Schema(description = "회로구성도")
private String circuitCfg;
@Schema(description = "W") @Schema(description = "W")
private String pnowW; private String pnowW;
@Schema(description = "아이템 그룹코드") @Schema(description = "아이템 그룹코드")
private String itemGroup; private String itemGroup;
@Schema(description = "아이템 CTG 그룹코드")
private String itemCtgGr;
@Schema(description = "히스토리 번호")
private String hisNo;
@Schema(description = "삭제여부")
private String delFlg;
@Schema(description = "사용자아이디") @Schema(description = "사용자아이디")
private String userId; private String userId;
@Schema(description = "아이템 타입 코드")
public String itemTpCd;
@Schema(description = "unit price 아이템 오픈가 여부")
private String unitOpenFlg;
@Schema(description = "Q.CAST 고객 제품 ID")
public String qcastCustPrdId;
@Schema(description = "모듈의 북면지원여부")
public String northModuleYn;
} }

View File

@ -14,9 +14,12 @@ public class ItemResponse {
@Schema(description = "플랜번호") @Schema(description = "플랜번호")
private String planNo; private String planNo;
@Schema(description = "노출번호") @Schema(description = "정렬번호")
private String dispOrder; private String dispOrder;
@Schema(description = "부모 정렬번호")
private String paDispOrder;
@Schema(description = "번호") @Schema(description = "번호")
private String no; private String no;
@ -38,6 +41,9 @@ public class ItemResponse {
@Schema(description = "수량") @Schema(description = "수량")
private String amount; private String amount;
@Schema(description = "BOM 수량")
private String bomAmount;
@Schema(description = "단가") @Schema(description = "단가")
private String salePrice; private String salePrice;
@ -56,15 +62,42 @@ public class ItemResponse {
@Schema(description = "아이템 특이사항 코드") @Schema(description = "아이템 특이사항 코드")
private String specialNoteCd; private String specialNoteCd;
@Schema(description = "아이템 오픈가 여부")
private String openFlg;
@Schema(description = "아이템 변경 여부") @Schema(description = "아이템 변경 여부")
private String itemChangeFlg; private String itemChangeFlg;
@Schema(description = "대표 케이블 여부")
private String dispCableFlg;
@Schema(description = "W") @Schema(description = "W")
private String pnowW; private String pnowW;
@Schema(description = "아이템 그룹코드") @Schema(description = "아이템 그룹코드")
private String itemGroup; private String itemGroup;
@Schema(description = "아이템 CTG 그룹코드")
private String itemCtgGr;
@Schema(description = "모듈여부") @Schema(description = "모듈여부")
private String moduleFlg; private String moduleFlg;
@Schema(description = "회로구성도")
private String circuitCfg;
@Schema(description = "아이템 타입 코드")
public String itemTpCd;
@Schema(description = "unit price 아이템 오픈가 여부")
private String unitOpenFlg;
@Schema(description = "단위 중량")
public String grossWt;
@Schema(description = "Q.CAST 고객 제품 ID")
public String qcastCustPrdId;
@Schema(description = "모듈의 북면지원여부")
public String northModuleYn;
} }

View File

@ -16,4 +16,7 @@ public class NoteResponse {
@Schema(description = "견적특이사항") @Schema(description = "견적특이사항")
private String remarks; private String remarks;
@Schema(description = "특이사항 묶음 여부")
private String pkgYn;
} }

View File

@ -0,0 +1,22 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class PlanSyncResponse {
@Schema(description = "물건번호")
private String objectNo;
@Schema(description = "플랜번호")
private String planNo;
@Schema(description = "견적서번호")
private String docNo;
@Schema(description = "동기화여부")
private String syncFlg;
@Schema(description = "메시지")
private String message;
}

View File

@ -23,4 +23,7 @@ public class PriceRequest {
@Schema(description = "아이템번호 목록") @Schema(description = "아이템번호 목록")
private List<PriceItemRequest> itemIdList; private List<PriceItemRequest> itemIdList;
@Schema(description = "2차 SAP 판매점코드")
private String secSapSalesStoreCd;
} }

View File

@ -0,0 +1,36 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
// @Data
@Getter
@Setter
public class RoofInfoResponse {
@Schema(description = "인증용량")
private String certVolKw;
@Schema(description = "모듈 총 수")
private String moduleTotAmount;
@Schema(description = "모듈 총 용량")
private String moduleTotVolKw;
@Schema(description = "지붕면 목록")
private List<RoofResponse> roofList;
@Schema(description = "파워컨디셔너 목록")
private List<ItemResponse> circuitItemList;
@Schema(description = "지붕면 용량 목록")
private List<RoofResponse> roofVolList;
@Schema(description = "방위")
private String compasDeg;
@Schema(description = "방위이미지")
private byte[] compasDegImg;
}

View File

@ -15,8 +15,8 @@ public class RoofRequest {
@Schema(description = "플랜번호") @Schema(description = "플랜번호")
private String planNo; private String planNo;
@Schema(description = "지붕재 번호") @Schema(description = "지붕재 ID")
private String roofNo; private String roofSurfaceId;
@Schema(description = "지붕면") @Schema(description = "지붕면")
private String roofSurface; private String roofSurface;
@ -48,6 +48,9 @@ public class RoofRequest {
@Schema(description = "각도") @Schema(description = "각도")
private String angle; private String angle;
@Schema(description = "경사각 선택코드")
private String classType;
@Schema(description = "방위각") @Schema(description = "방위각")
private String azimuth; private String azimuth;
@ -55,5 +58,5 @@ public class RoofRequest {
private String userId; private String userId;
@Schema(description = "아이템 목록") @Schema(description = "아이템 목록")
List<ItemRequest> roofItemList; List<ItemRequest> moduleList;
} }

View File

@ -0,0 +1,97 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
// @Data
@Getter
@Setter
public class RoofResponse {
@Schema(description = "물건번호")
private String objectNo;
@Schema(description = "플랜번호")
private String planNo;
@Schema(description = "지붕면 ID")
private String roofSurfaceId;
@Schema(description = "지붕면")
private String roofSurface;
@Schema(description = "지붕재 아이템 ID")
private String roofMaterialId;
@Schema(description = "지붕재 아이템명")
private String roofMaterialName;
@Schema(description = "공법 ID")
private String supportMethodId;
@Schema(description = "공법명")
private String supportMethodName;
@Schema(description = "시공사양 ID")
private String constructSpecification;
@Schema(description = "시공사양명")
private String constructSpecificationName;
@Schema(description = "지붕재 아이템명")
private String roofMaterialIdMulti;
@Schema(description = "공법명")
private String supportMethodIdMulti;
@Schema(description = "시공방법명")
private String constructSpecificationMulti;
@Schema(description = "가대메이커명")
private String supportMeaker;
@Schema(description = "경사")
private String slope;
@Schema(description = "각도")
private String angle;
@Schema(description = "방위각")
private String azimuth;
@Schema(description = "경사각 선택코드")
private String classType;
@Schema(description = "경사각 선택명")
private String classTypeName;
@Schema(description = "면조도구분")
private String surfaceType;
@Schema(description = "설치높이")
private String setupHeight;
@Schema(description = "아이템 ID")
private String itemId;
@Schema(description = "아이템 번호")
private String itemNo;
@Schema(description = "아이템명")
private String itemName;
@Schema(description = "W")
private String specification;
@Schema(description = "매수")
private String amount;
@Schema(description = "용량")
private String volKw;
@Schema(description = "PC 아이템 ID")
private String pcItemId;
@Schema(description = "하세비치")
private Integer roofHajebichi;
}

View File

@ -0,0 +1,13 @@
package com.interplug.qcast.biz.estimate.dto;
import com.interplug.qcast.biz.object.dto.ObjectResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class SimulationEstimateListResponse {
@Schema(description = "물건정보 목록")
List<ObjectResponse> objectList;
}

View File

@ -0,0 +1,30 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class SimulationEstimateResponse {
@Schema(description = "물건번호")
private String objectNo;
@Schema(description = "안건명")
private String objectName;
@Schema(description = "플랜번호")
private String planNo;
@Schema(description = "지역코드")
private String areaId;
@Schema(description = "계약조건")
private String conType;
@Schema(description = "지붕면 정보 목록")
List<SimulationRoofResponse> roofList;
@Schema(description = "PCS 정보 목록")
List<SimulationItemResponse> pcsList;
}

View File

@ -0,0 +1,25 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
// @Data
@Getter
@Setter
public class SimulationItemResponse {
@Schema(description = "지붕면 ID")
private String roofSurfaceId;
@Schema(description = "아이템 아이디")
private String itemId;
@Schema(description = "아이템 번호")
private String itemNo;
@Schema(description = "아이템명")
private String itemName;
@Schema(description = "매수")
private String amount;
}

View File

@ -0,0 +1,30 @@
package com.interplug.qcast.biz.estimate.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
// @Data
@Getter
@Setter
public class SimulationRoofResponse {
@Schema(description = "지붕면 ID")
private String roofSurfaceId;
@Schema(description = "지붕면")
private String roofSurface;
@Schema(description = "경사")
private String slope;
@Schema(description = "각도")
private String angle;
@Schema(description = "방위각")
private String azimuth;
@Schema(description = "지붕면 모듈 정보 목록")
List<SimulationItemResponse> roofModuleList;
}

View File

@ -9,7 +9,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.interplug.qcast.biz.excelDown.dto.NtrCtsCmpRequest; import com.interplug.qcast.biz.excelDown.dto.NtrCtsCmpRequest;
import com.interplug.qcast.biz.excelDown.dto.NtrCtsCmpResponse; import com.interplug.qcast.biz.excelDown.dto.NtrCtsCmpResponse;
import com.interplug.qcast.biz.excelDown.dto.QuotItemResponse;
import com.interplug.qcast.biz.excelDown.dto.QuotPlanResponse; import com.interplug.qcast.biz.excelDown.dto.QuotPlanResponse;
import com.interplug.qcast.biz.excelDown.dto.QuotRequest; import com.interplug.qcast.biz.excelDown.dto.QuotRequest;
import com.interplug.qcast.biz.excelDown.dto.QuotResponse; import com.interplug.qcast.biz.excelDown.dto.QuotResponse;
@ -34,14 +33,17 @@ public class ExcelDownController {
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public QuotResponse quotExclDownData(@RequestBody QuotRequest quotRequest) throws Exception { public QuotResponse quotExclDownData(@RequestBody QuotRequest quotRequest) throws Exception {
List<QuotPlanResponse> quotPlanExclDownData =
excelDownService.selectQuotPlanExclDownData(quotRequest);
List<QuotItemResponse> quotItemExclDownData =
excelDownService.selectQuotItemExclDownData(quotRequest);
QuotResponse quotRes = new QuotResponse(); QuotResponse quotRes = new QuotResponse();
quotRes.setQuotPlanList(quotPlanExclDownData);
quotRes.setQuotItemList(quotItemExclDownData); if ("1".equals(quotRequest.getSch_selectType())) {
quotRes.setQuotPlanList(excelDownService.selectQuotPlanExclDownData(quotRequest));
quotRes.setQuotItemList(excelDownService.selectQuotItemExclDownData(quotRequest));
} else {
List<QuotPlanResponse> quotPlanExclDownData =
excelDownService.selectQuotPlanExclDownData2(quotRequest);
quotRes.setQuotPlanList(quotPlanExclDownData);
}
return quotRes; return quotRes;
} }
@ -74,5 +76,4 @@ public class ExcelDownController {
log.error(e.getMessage()); log.error(e.getMessage());
} }
} }
} }

View File

@ -10,6 +10,7 @@ import com.interplug.qcast.biz.excelDown.dto.WrntIsncCmplRequest;
import com.interplug.qcast.biz.excelDown.dto.WrntIsncCmplResponse; import com.interplug.qcast.biz.excelDown.dto.WrntIsncCmplResponse;
import java.util.List; import java.util.List;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper @Mapper
interface ExcelDownMapper { interface ExcelDownMapper {
@ -23,6 +24,15 @@ interface ExcelDownMapper {
*/ */
List<QuotPlanResponse> selectQuotPlanExclDownData(QuotRequest quotRequest) throws Exception; List<QuotPlanResponse> selectQuotPlanExclDownData(QuotRequest quotRequest) throws Exception;
/**
* 과거데이터_견적 엑셀다운로드 조회 - 심플모드
*
* @param quotRequest
* @return
* @throws Exception
*/
List<QuotPlanResponse> selectQuotPlanExclDownData2(QuotRequest quotRequest) throws Exception;
/** /**
* 과거데이터_견적 엑셀다운로드 조회(아이템) * 과거데이터_견적 엑셀다운로드 조회(아이템)
* *
@ -32,6 +42,7 @@ interface ExcelDownMapper {
*/ */
List<QuotItemResponse> selectQuotItemExclDownData(QuotRequest quotRequest) throws Exception; List<QuotItemResponse> selectQuotItemExclDownData(QuotRequest quotRequest) throws Exception;
/** /**
* 과거데이터_자연재해보상입력 엑셀다운로드 조회 * 과거데이터_자연재해보상입력 엑셀다운로드 조회
* *

View File

@ -5,9 +5,12 @@ import com.interplug.qcast.config.message.Messages;
import com.interplug.qcast.util.ZipFileManager; import com.interplug.qcast.util.ZipFileManager;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -38,6 +41,18 @@ public class ExcelDownService {
return excelDownMapper.selectQuotPlanExclDownData(quotRequest); return excelDownMapper.selectQuotPlanExclDownData(quotRequest);
} }
/**
* 과거데이터_견적 엑셀다운로드 조회
*
* @param quotRequest
* @return
* @throws Exception
*/
public List<QuotPlanResponse> selectQuotPlanExclDownData2(QuotRequest quotRequest)
throws Exception {
return excelDownMapper.selectQuotPlanExclDownData2(quotRequest);
}
/** /**
* 과거데이터_견적 엑셀다운로드 조회(아이템) * 과거데이터_견적 엑셀다운로드 조회(아이템)
* *

View File

@ -53,6 +53,8 @@ public class QuotPlanResponse {
private String saleStoreId; private String saleStoreId;
@Schema(description = "최종갱신자 最終更新者") @Schema(description = "최종갱신자 最終更新者")
private String lastEditUser; private String lastEditUser;
@Schema(description = "최종갱신자명 最終更新者名")
private String lastEditUserName;
@Schema(description = "지붕종류 屋根種類 ") @Schema(description = "지붕종류 屋根種類 ")
private String rofTyp; private String rofTyp;
@Schema(description = "지붕재 屋根材") @Schema(description = "지붕재 屋根材")
@ -117,5 +119,10 @@ public class QuotPlanResponse {
private String saleOther; private String saleOther;
@Schema(description = "가대판매가격 架台販売価格") @Schema(description = "가대판매가격 架台販売価格")
private String saleStand; private String saleStand;
@Schema(description = "플랜정보 등록일시 プラン情報登録日時")
private String createDatetime;
@Schema(description = "플랜정보 등록자 プラン情報登録者")
private String createUser;
@Schema(description = "플랜정보 등록자명 プラン情報登録者名")
private String createUserName;
} }

View File

@ -11,6 +11,8 @@ import lombok.Setter;
public class QuotRequest { public class QuotRequest {
@Schema(description = "Language Code") @Schema(description = "Language Code")
private String langCd; private String langCd;
@Schema(description = "조회타입")
private String sch_selectType;
@Schema(description = "시작일") @Schema(description = "시작일")
private String sch_startDt; private String sch_startDt;
@Schema(description = "종료일") @Schema(description = "종료일")
@ -19,4 +21,9 @@ public class QuotRequest {
private String sch_saleStoreId; private String sch_saleStoreId;
@Schema(description = "영업 담당자명") @Schema(description = "영업 담당자명")
private String sch_businessChargerCd; private String sch_businessChargerCd;
@Schema(description = "페이지 번호 (1부터 시작, null이면 전체 조회)")
private Integer pageNo;
@Schema(description = "페이지당 건수")
private Integer pageSize;
} }

View File

@ -48,12 +48,10 @@ public class FileController {
@Operation(description = "파일을 업로드 한다.") @Operation(description = "파일을 업로드 한다.")
@PostMapping("/fileUpload") @PostMapping("/fileUpload")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public Integer fileUpload( public List<FileRequest> fileUpload(
HttpServletRequest request, HttpServletResponse response, FileRequest fileRequest) HttpServletRequest request, HttpServletResponse response, FileRequest fileRequest)
throws Exception { throws Exception {
List<FileRequest> saveFileList = fileService.getUploadFileList(request, fileRequest); return fileService.fileUpload(request, fileRequest);
Integer resultCnt = fileService.setFile(saveFileList, null);
return resultCnt;
} }
@Operation(description = "파일을 삭제 한다.") @Operation(description = "파일을 삭제 한다.")

View File

@ -26,6 +26,15 @@ public interface FileMapper {
*/ */
Integer insertFile(FileRequest fileInsertReq) throws Exception; Integer insertFile(FileRequest fileInsertReq) throws Exception;
/**
* 파일 상세정보 등록
*
* @param fileInsertReq
* @return
* @throws Exception
*/
Integer insertFileInfo(FileRequest fileInsertReq) throws Exception;
/** /**
* 파일 1건 조회 * 파일 1건 조회
* *

View File

@ -102,6 +102,7 @@ public class FileService {
} }
String strSrcFileNm = multipartFile.getOriginalFilename(); String strSrcFileNm = multipartFile.getOriginalFilename();
strSrcFileNm = this.getUniqueFileName(strFileFolderPath, strSrcFileNm);
File file = new File(strFileFolderPath, strSrcFileNm); File file = new File(strFileFolderPath, strSrcFileNm);
multipartFile.transferTo(file); multipartFile.transferTo(file);
@ -199,6 +200,7 @@ public class FileService {
for (FileRequest fileInsertReq : saveFilelist) { for (FileRequest fileInsertReq : saveFilelist) {
if (!"".equals(fileInsertReq.getObjectNo()) && !"".equals(fileInsertReq.getCategory())) { if (!"".equals(fileInsertReq.getObjectNo()) && !"".equals(fileInsertReq.getCategory())) {
iResult += fileMapper.insertFile(fileInsertReq); iResult += fileMapper.insertFile(fileInsertReq);
fileMapper.insertFileInfo(fileInsertReq);
} }
} }
} }
@ -218,6 +220,8 @@ public class FileService {
HttpServletRequest request, HttpServletResponse response, FileRequest fileRequest) HttpServletRequest request, HttpServletResponse response, FileRequest fileRequest)
throws Exception { throws Exception {
System.out.println("fileRequest>>>" + fileRequest.toString());
// 필수값 체크 // 필수값 체크
if (fileRequest.getObjectNo() == null || fileRequest.getObjectNo().isEmpty()) { if (fileRequest.getObjectNo() == null || fileRequest.getObjectNo().isEmpty()) {
throw new QcastException( throw new QcastException(
@ -235,42 +239,46 @@ public class FileService {
ErrorCode.NOT_FOUND, message.getMessage(" common.message.file.download.exists")); ErrorCode.NOT_FOUND, message.getMessage(" common.message.file.download.exists"));
} }
// 첨부파일 물리적 경로 try {
String strSeparator = File.separator; // 첨부파일 물리적 경로
String filePath = baseDirPath + strSeparator + fileResponse.getObjectNo(); String strSeparator = File.separator;
if (fileResponse.getPlanNo() != null && !fileResponse.getPlanNo().isEmpty()) { String filePath = baseDirPath + strSeparator + fileResponse.getObjectNo();
filePath += strSeparator + fileResponse.getPlanNo(); if (fileResponse.getPlanNo() != null && !fileResponse.getPlanNo().isEmpty()) {
} filePath += strSeparator + fileResponse.getPlanNo();
filePath += strSeparator + fileResponse.getFaileName(); }
filePath += strSeparator + fileResponse.getFaileName();
File file = new File(filePath); File file = new File(filePath);
if (!file.exists()) { if (!file.exists()) {
log.error("### File not found: {}", filePath); log.error("### File not found: {}", filePath);
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR); throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR);
} }
String mimeType = URLConnection.guessContentTypeFromName(file.getName()); String mimeType = URLConnection.guessContentTypeFromName(file.getName());
if (mimeType == null) { if (mimeType == null) {
mimeType = "application/octet-stream"; mimeType = "application/octet-stream";
} }
String originalFileName = fileResponse.getFaileName(); String originalFileName = fileResponse.getFaileName();
String encodedFileName = String encodedFileName =
URLEncoder.encode(originalFileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20"); URLEncoder.encode(originalFileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
response.setHeader("Content-Transfer-Encoding", "binary;"); response.setHeader("Content-Transfer-Encoding", "binary;");
response.setHeader("Pragma", "no-cache;"); response.setHeader("Pragma", "no-cache;");
response.setHeader("Expires", "-1;"); response.setHeader("Expires", "-1;");
response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\""); response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
response.setContentType(mimeType); response.setContentType(mimeType);
response.setContentLength((int) file.length()); response.setContentLength((int) file.length());
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) { try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
FileCopyUtils.copy(inputStream, response.getOutputStream()); FileCopyUtils.copy(inputStream, response.getOutputStream());
} catch (IOException e) { } catch (IOException e) {
throw new QcastException( throw new QcastException(
ErrorCode.INTERNAL_SERVER_ERROR, ErrorCode.INTERNAL_SERVER_ERROR,
message.getMessage("common.message.file.download.error")); message.getMessage("common.message.file.download.error"));
}
} catch (Exception e) {
e.printStackTrace();
} }
} }
@ -339,4 +347,40 @@ public class FileService {
return iResult; return iResult;
} }
public List<FileRequest> fileUpload(HttpServletRequest request, FileRequest fileRequest)
throws Exception {
List<FileRequest> saveFileList = this.getUploadFileList(request, fileRequest);
// Integer resultCnt = this.setFile(saveFileList, null);
return saveFileList;
}
public String getUniqueFileName(String uploadDir, String fileName) {
File dir = new File(uploadDir);
if (!dir.exists()) {
dir.mkdirs(); // 디렉터리가 없으면 생성
}
String name = fileName;
String extension = "";
// 파일명과 확장자 분리
int dotIndex = fileName.lastIndexOf(".");
if (dotIndex >= 0) {
name = fileName.substring(0, dotIndex);
extension = fileName.substring(dotIndex);
}
File file = new File(uploadDir, fileName);
int counter = 1;
// 파일명이 중복될 경우 번호를 붙임
while (file.exists()) {
String newFileName = name + "_" + counter + extension;
file = new File(uploadDir, newFileName);
counter++;
}
return file.getName();
}
} }

View File

@ -30,6 +30,6 @@ public class FileRequest {
@Schema(description = "zip 파일 이름") @Schema(description = "zip 파일 이름")
private String zipFileName; private String zipFileName;
@Schema(description = "planNo null 체크 Flag (NULL=1, NOT NULL=0)", defaultValue = "1") @Schema(description = "planNo null 체크 Flag (NULL=1, NOT NULL=0)")
private String planNoNullChkFlg = "1"; private String planNoNullChkFlg;
} }

View File

@ -1,21 +1,5 @@
package com.interplug.qcast.biz.login; package com.interplug.qcast.biz.login;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.interplug.qcast.biz.login.dto.JoinUser; import com.interplug.qcast.biz.login.dto.JoinUser;
import com.interplug.qcast.biz.login.dto.LoginUser; import com.interplug.qcast.biz.login.dto.LoginUser;
import com.interplug.qcast.biz.login.dto.UserLoginResponse; import com.interplug.qcast.biz.login.dto.UserLoginResponse;
@ -26,8 +10,24 @@ import com.interplug.qcast.config.Exception.QcastException;
import com.interplug.qcast.config.message.Messages; import com.interplug.qcast.config.message.Messages;
import com.interplug.qcast.util.DefaultResponse; import com.interplug.qcast.util.DefaultResponse;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@Slf4j @Slf4j
@RestController @RestController
@ -37,8 +37,7 @@ public class LoginController {
// @Autowired private LoginService loginService; // @Autowired private LoginService loginService;
private final LoginService loginService; private final LoginService loginService;
@Autowired @Autowired Messages message;
Messages message;
@Value("${qsp.aes256.key}") @Value("${qsp.aes256.key}")
String loginPasswordAesKey; String loginPasswordAesKey;
@ -46,10 +45,9 @@ public class LoginController {
@Value("${qsp.auto.login.aes256.key}") @Value("${qsp.auto.login.aes256.key}")
String autoLoginAesKey; String autoLoginAesKey;
/** /**
* Q.CAST III에 로그인하여 사용자 정보를 획득한다. * Q.CAST III에 로그인하여 사용자 정보를 획득한다.
* *
* @param loginUser LoginUser * @param loginUser LoginUser
* @return UserLoginResponse * @return UserLoginResponse
* @throws Exception * @throws Exception
@ -61,6 +59,34 @@ public class LoginController {
return loginService.getLogin(loginUser); return loginService.getLogin(loginUser);
} }
/**
* Q.CAST III에 자동 로그인하여 사용자 정보를 획득한다.
*
* @param loginUser LoginUser
* @return UserLoginResponse
* @throws Exception
*/
@Operation(description = "Q.CAST III에 자동 로그인하여 사용자 정보를 획득한다.")
@PostMapping("/v1.0/autoLogin")
@ResponseStatus(HttpStatus.CREATED)
public UserLoginResponse autoLogin(@RequestBody LoginUser loginUser) throws Exception {
return loginService.getAutoLogin(loginUser);
}
/**
* Q.CAST III에서 로그아웃한다.
*
* @param loginUser LoginUser
* @return DefaultResponse
* @throws Exception
*/
@Operation(description = "Q.CAST III에서 로그아웃한다.")
@PostMapping("/v1.0/logout")
@ResponseStatus(HttpStatus.CREATED)
public DefaultResponse logout(@RequestBody LoginUser loginUser) throws Exception {
return loginService.getLogout(loginUser);
}
@PostMapping("/v1.0/user") @PostMapping("/v1.0/user")
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
public UserResponse getUser(@RequestBody LoginUser loginUser) { public UserResponse getUser(@RequestBody LoginUser loginUser) {
@ -69,7 +95,7 @@ public class LoginController {
/** /**
* 가입 신청 정보를 등록한다. * 가입 신청 정보를 등록한다.
* *
* @param joinUser JoinUser * @param joinUser JoinUser
* @return DefaultResponse * @return DefaultResponse
* @throws Exception * @throws Exception
@ -83,7 +109,7 @@ public class LoginController {
/** /**
* 비밀번호를 초기화한다. * 비밀번호를 초기화한다.
* *
* @param userPassword UserPassword * @param userPassword UserPassword
* @return DefaultResponse * @return DefaultResponse
* @throws Exception * @throws Exception
@ -96,7 +122,7 @@ public class LoginController {
/** /**
* 비밀번호를 변경한다. * 비밀번호를 변경한다.
* *
* @param userPassword UserPassword * @param userPassword UserPassword
* @return DefaultResponse * @return DefaultResponse
* @throws Exception * @throws Exception
@ -109,7 +135,7 @@ public class LoginController {
/** /**
* 자동 로그인에 사용하는 아이디를 암호화한다. * 자동 로그인에 사용하는 아이디를 암호화한다.
* *
* @param loginUser LoginUser * @param loginUser LoginUser
* @return String * @return String
* @throws Exception * @throws Exception
@ -121,7 +147,8 @@ public class LoginController {
String loginEncryptId = ""; String loginEncryptId = "";
if ("".equals(loginUser.getLoginId()) || loginUser.getLoginId() == null) { if ("".equals(loginUser.getLoginId()) || loginUser.getLoginId() == null) {
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "User Id")); message.getMessage("common.message.required.data", "User Id"));
} }
@ -136,16 +163,19 @@ public class LoginController {
byte[] keyData = loginPasswordAesKey.getBytes(); byte[] keyData = loginPasswordAesKey.getBytes();
SecretKey secureKey = new SecretKeySpec(keyData, "AES"); SecretKey secureKey = new SecretKeySpec(keyData, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, secureKey, c.init(
Cipher.ENCRYPT_MODE,
secureKey,
new IvParameterSpec(encryptKey.substring(0, 16).getBytes())); new IvParameterSpec(encryptKey.substring(0, 16).getBytes()));
byte[] encrypted = c.doFinal(loginUser.getLoginId().getBytes("UTF-8")); byte[] encrypted = c.doFinal(loginUser.getLoginId().getBytes("UTF-8"));
// [2]. 암호화 셋팅 // [2]. 암호화 셋팅
loginEncryptId = new String(Base64.getEncoder().encode(encrypted));; loginEncryptId = new String(Base64.getEncoder().encode(encrypted));
;
} catch (Exception e) { } catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, throw new QcastException(
message.getMessage("common.message.error")); ErrorCode.INTERNAL_SERVER_ERROR, message.getMessage("common.message.error"));
} }
return loginEncryptId; return loginEncryptId;
@ -153,7 +183,7 @@ public class LoginController {
/** /**
* 자동 로그인에 사용하는 아이디를 복호화한다. * 자동 로그인에 사용하는 아이디를 복호화한다.
* *
* @param loginUser LoginUser * @param loginUser LoginUser
* @return String * @return String
* @throws Exception * @throws Exception
@ -165,7 +195,8 @@ public class LoginController {
String loginDecryptId = ""; String loginDecryptId = "";
if ("".equals(loginUser.getLoginId()) || loginUser.getLoginId() == null) { if ("".equals(loginUser.getLoginId()) || loginUser.getLoginId() == null) {
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(
ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "User Id")); message.getMessage("common.message.required.data", "User Id"));
} }
@ -180,7 +211,9 @@ public class LoginController {
byte[] keyData = loginPasswordAesKey.getBytes(); byte[] keyData = loginPasswordAesKey.getBytes();
SecretKey secureKey = new SecretKeySpec(keyData, "AES"); SecretKey secureKey = new SecretKeySpec(keyData, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, secureKey, c.init(
Cipher.DECRYPT_MODE,
secureKey,
new IvParameterSpec(decryptKey.substring(0, 16).getBytes("UTF-8"))); new IvParameterSpec(decryptKey.substring(0, 16).getBytes("UTF-8")));
byte[] byteStr = Base64.getDecoder().decode(loginUser.getLoginId().getBytes()); byte[] byteStr = Base64.getDecoder().decode(loginUser.getLoginId().getBytes());
@ -189,11 +222,10 @@ public class LoginController {
loginDecryptId = new String(c.doFinal(byteStr), "UTF-8"); loginDecryptId = new String(c.doFinal(byteStr), "UTF-8");
} catch (Exception e) { } catch (Exception e) {
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR, throw new QcastException(
message.getMessage("common.message.error")); ErrorCode.INTERNAL_SERVER_ERROR, message.getMessage("common.message.error"));
} }
return loginDecryptId; return loginDecryptId;
} }
} }

View File

@ -16,6 +16,7 @@ import com.interplug.qcast.config.Exception.QcastException;
import com.interplug.qcast.config.message.Messages; import com.interplug.qcast.config.message.Messages;
import com.interplug.qcast.util.DefaultResponse; import com.interplug.qcast.util.DefaultResponse;
import com.interplug.qcast.util.InterfaceQsp; import com.interplug.qcast.util.InterfaceQsp;
import java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -35,7 +36,7 @@ public class LoginService {
/** /**
* 로그인 처리 * 로그인 처리
* *
* @param loginUser LoginUser * @param loginUser LoginUser
* @return UserLoginResponse * @return UserLoginResponse
* @throws Exception * @throws Exception
@ -49,6 +50,31 @@ public class LoginService {
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Password")); message.getMessage("common.message.required.data", "Password"));
return callLoginApi(loginUser, "LOGIN");
}
/**
* 자동 로그인 처리
*
* @param loginUser LoginUser
* @return UserLoginResponse
* @throws Exception
*/
public UserLoginResponse getAutoLogin(LoginUser loginUser) throws Exception {
if (loginUser.getLoginId() == null || "".equals(loginUser.getLoginId()))
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Login Id"));
return callLoginApi(loginUser, "AUTO_LOGIN");
}
private UserLoginResponse callLoginApi(LoginUser loginUser, String actLog) throws Exception {
loginUser.setAccsSiteCd("DESIGN");
loginUser.setActLog(actLog);
String sessionId = UUID.randomUUID().toString();
loginUser.setRequestId(sessionId);
UserLoginResponse userLoginResponse = null; UserLoginResponse userLoginResponse = null;
// QSP API Call.. // QSP API Call..
@ -63,16 +89,53 @@ public class LoginService {
userLoginResponse = om.readValue(strResponse, UserLoginResponse.class); userLoginResponse = om.readValue(strResponse, UserLoginResponse.class);
} }
if (userLoginResponse != null
&& userLoginResponse.getResult() != null
&& "S".equalsIgnoreCase(userLoginResponse.getResult().getResultCode())) {
userLoginResponse.setSessionId(sessionId);
}
return userLoginResponse; return userLoginResponse;
} }
/**
* 로그아웃 처리
*
* @param loginUser LoginUser
* @return DefaultResponse
* @throws Exception
*/
public DefaultResponse getLogout(LoginUser loginUser) throws Exception {
if (loginUser.getLoginId() == null || "".equals(loginUser.getLoginId()))
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Login Id"));
loginUser.setAccsSiteCd("DESIGN");
loginUser.setActLog("LOGOUT");
// QSP API Call..
// Q.CAST 로그아웃
// post
// /api/user/logout
DefaultResponse defaultResponse = null;
String strResponse =
interfaceQsp.callApi(HttpMethod.POST, qspUrl + "/api/user/logout", loginUser);
if (!"".equals(strResponse)) {
ObjectMapper om =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
defaultResponse = om.readValue(strResponse, DefaultResponse.class);
}
return defaultResponse;
}
public UserResponse getUser(LoginUser loginUser) { public UserResponse getUser(LoginUser loginUser) {
return loginMapper.getUser(loginUser); return loginMapper.getUser(loginUser);
} }
/** /**
* 가입 신청 등록 * 가입 신청 등록
* *
* @param joinUser JoinUser * @param joinUser JoinUser
* @return DefaultResponse * @return DefaultResponse
* @throws Exception * @throws Exception
@ -98,9 +161,13 @@ public class LoginService {
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Telephone")); message.getMessage("common.message.required.data", "Telephone"));
if (joinUser.getFax() == null || "".equals(joinUser.getFax())) if (joinUser.getBizNo() == null || "".equals(joinUser.getBizNo()))
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Fax")); message.getMessage("common.message.required.data", "Business Registration No"));
// if (joinUser.getFax() == null || "".equals(joinUser.getFax()))
// throw new QcastException(
// ErrorCode.INVALID_INPUT_VALUE, message.getMessage("common.message.required.data", "Fax"));
if (joinUser.getUserInfo().getUserId() == null || "".equals(joinUser.getUserInfo().getUserId())) if (joinUser.getUserInfo().getUserId() == null || "".equals(joinUser.getUserInfo().getUserId()))
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
@ -110,18 +177,18 @@ public class LoginService {
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Name")); message.getMessage("common.message.required.data", "Name"));
// if (joinUser.getUserInfo().getUserNmKana() == null if (joinUser.getUserInfo().getUserNmKana() == null
// || "".equals(joinUser.getUserInfo().getUserNmKana())) || "".equals(joinUser.getUserInfo().getUserNmKana()))
// throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
// message.getMessage("common.message.required.data", "Name Kana")); message.getMessage("common.message.required.data", "Name Kana"));
if (joinUser.getUserInfo().getTelNo() == null || "".equals(joinUser.getUserInfo().getTelNo())) if (joinUser.getUserInfo().getTelNo() == null || "".equals(joinUser.getUserInfo().getTelNo()))
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
message.getMessage("common.message.required.data", "Telephone")); message.getMessage("common.message.required.data", "Telephone"));
if (joinUser.getUserInfo().getFax() == null || "".equals(joinUser.getUserInfo().getFax())) // if (joinUser.getUserInfo().getFax() == null || "".equals(joinUser.getUserInfo().getFax()))
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, // throw new QcastException(
message.getMessage("common.message.required.data", "Fax")); // ErrorCode.INVALID_INPUT_VALUE, message.getMessage("common.message.required.data", "Fax"));
if (joinUser.getUserInfo().getEmail() == null || "".equals(joinUser.getUserInfo().getEmail())) if (joinUser.getUserInfo().getEmail() == null || "".equals(joinUser.getUserInfo().getEmail()))
throw new QcastException(ErrorCode.INVALID_INPUT_VALUE, throw new QcastException(ErrorCode.INVALID_INPUT_VALUE,
@ -145,7 +212,7 @@ public class LoginService {
/** /**
* 비밀번호 초기화 * 비밀번호 초기화
* *
* @param userPassword UserPassword * @param userPassword UserPassword
* @return DefaultResponse * @return DefaultResponse
* @throws Exception * @throws Exception
@ -177,7 +244,7 @@ public class LoginService {
/** /**
* 비밀번호 변경 * 비밀번호 변경
* *
* @param userPassword UserPassword * @param userPassword UserPassword
* @return DefaultResponse * @return DefaultResponse
* @throws Exception * @throws Exception

View File

@ -6,4 +6,7 @@ import lombok.Data;
public class LoginUser { public class LoginUser {
private String loginId; // Login Id private String loginId; // Login Id
private String pwd; // Password private String pwd; // Password
private String accsSiteCd; // Access Site Code (QSP, QORDER, QMUSUBI_DESIGN, QREAD, QWARRANTY, QPARTNERS)
private String actLog; // Action Log (LOGIN, AUTO_LOGIN, LOGOUT)
private String requestId; // Request ID <= Unique ID
} }

View File

@ -8,4 +8,5 @@ import lombok.Setter;
@Setter @Setter
public class UserLoginResponse extends DefaultResponse { public class UserLoginResponse extends DefaultResponse {
private UserResponse data; private UserResponse data;
private String sessionId;
} }

View File

@ -25,4 +25,9 @@ public class UserResponse {
private String storeLvl; // Store Level private String storeLvl; // Store Level
private String groupId; // groupId private String groupId; // groupId
private String custCd; // custCd private String custCd; // custCd
private String custNm;
//시공사 번호
private String builderNo;
private String builderNm; // Builder Name
private String builderId; // Builder Id
} }

View File

@ -21,9 +21,9 @@ public class MainPageController {
private final ObjectService objectService; private final ObjectService objectService;
@Operation(description = "메인 물건정보 목록을 조회한다.") @Operation(description = "메인 물건정보 목록을 조회한다.")
@GetMapping("/object/{saleStoreId}/list") @GetMapping("/object/{saleStoreId}/{userId}/{builderNo}/list")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public MainPageResponse selectObjectList(@PathVariable String saleStoreId) throws Exception { public MainPageResponse selectObjectList(@PathVariable String saleStoreId, @PathVariable String userId, @PathVariable String builderNo) throws Exception {
MainPageResponse mainPageResponse = new MainPageResponse(); MainPageResponse mainPageResponse = new MainPageResponse();
// 판매점명 조회 // 판매점명 조회
@ -39,10 +39,13 @@ public class MainPageController {
// 물건정보 목록 조회 // 물건정보 목록 조회
ObjectRequest objectRequest = new ObjectRequest(); ObjectRequest objectRequest = new ObjectRequest();
objectRequest.setSaleStoreId(saleStoreId); objectRequest.setSaleStoreId(saleStoreId);
objectRequest.setStartRow("1"); objectRequest.setUserId(userId);
objectRequest.setEndRow("3"); if(builderNo != null && !"null".equals(builderNo)) {
objectRequest.setBuilderNo(builderNo);
}
List<ObjectResponse> objectList = objectService.selectObjectList(objectRequest);
List<ObjectResponse> objectList = objectService.selectObjectMainList(objectRequest);
mainPageResponse.setObjectList(objectList); mainPageResponse.setObjectList(objectList);
return mainPageResponse; return mainPageResponse;

View File

@ -0,0 +1,130 @@
package com.interplug.qcast.biz.master;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Schema(description = "Api 시공법 목록 조회 요청 객체 빌더")
public class ApiConstructionBuilder {
@Schema(description = "모듈타입코드")
private String moduleTpCd;
@Schema(description = "지붕재코드")
private String roofMatlCd;
@Schema(description = "가대메이커코드")
private String trestleMkrCd;
@Schema(description = "공법코드")
private String constMthdCd;
@Schema(description = "지붕기초코드")
private String roofBaseCd;
@Schema(description = "면조도")
private String illuminationTp;
@Schema(description = "설치높이")
private String instHt;
@Schema(description = "풍속")
private String stdWindSpeed;
@Schema(description = "적설량")
private String stdSnowLd;
@Schema(description = "경사도코드")
private String inclCd;
@Schema(description = "서까래기초코드")
private String raftBaseCd;
@Schema(description = "하제(망둥어)피치")
private Integer roofPitch;
public ApiConstructionBuilder setModuleTpCd(String moduleTpCd){
this.moduleTpCd = moduleTpCd;
return this;
}
public ApiConstructionBuilder setRoofMatlCd(String roofMatlCd){
this.roofMatlCd = roofMatlCd;
return this;
}
public ApiConstructionBuilder setTrestleMkrCd(String trestleMkrCd){
this.trestleMkrCd = trestleMkrCd;
return this;
}
public ApiConstructionBuilder setConstMthdCd(String constMthdCd){
this.constMthdCd = constMthdCd;
return this;
}
public ApiConstructionBuilder setRoofBaseCd(String roofBaseCd){
this.roofBaseCd = roofBaseCd;
return this;
}
public ApiConstructionBuilder setIlluminationTp(String illuminationTp){
this.illuminationTp = illuminationTp;
return this;
}
public ApiConstructionBuilder setInstHt(String instHt){
this.instHt = instHt;
return this;
}
public ApiConstructionBuilder setStdWindSpeed(String stdWindSpeed){
this.stdWindSpeed = stdWindSpeed;
return this;
}
public ApiConstructionBuilder setStdSnowLd(String stdSnowLd){
this.stdSnowLd = stdSnowLd;
return this;
}
public ApiConstructionBuilder setInclCd(String inclCd){
this.inclCd = inclCd;
return this;
}
public ApiConstructionBuilder setRaftBaseCd(String raftBaseCd){
this.raftBaseCd = raftBaseCd;
return this;
}
public ApiConstructionBuilder setRoofPitch(Integer roofPitch){
this.roofPitch = roofPitch;
return this;
}
public ApiConstructionBuilder (String moduleTpCd, String roofMatlCd, String trestleMkrCd, String constMthdCd, String roofBaseCd, String illuminationTp,
String instHt, String stdWindSpeed, String stdSnowLd, String inclCd, String raftBaseCd, Integer roofPitch) {
this.moduleTpCd = moduleTpCd;
this.roofMatlCd = roofMatlCd;
this.trestleMkrCd = trestleMkrCd;
this.constMthdCd = constMthdCd;
this.roofBaseCd = roofBaseCd;
this.illuminationTp = illuminationTp;
this.instHt = instHt;
this.stdWindSpeed = stdWindSpeed;
this.stdSnowLd = stdSnowLd;
this.inclCd = inclCd;
this.raftBaseCd = raftBaseCd;
this.roofPitch = roofPitch;
}
public ApiConstructionBuilder build(){
return new ApiConstructionBuilder(moduleTpCd, roofMatlCd, trestleMkrCd, constMthdCd, roofBaseCd, illuminationTp,
instHt, stdWindSpeed, stdSnowLd, inclCd, raftBaseCd, roofPitch);
}
}

View File

@ -0,0 +1,74 @@
package com.interplug.qcast.biz.master;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Schema(description = "Api 가대 목록 조회 요청 객체 빌더")
public class ApiTrestleBuilder {
@Schema(description = "모듈타입코드")
private String moduleTpCd;
@Schema(description = "지붕재코드")
private String roofMatlCd;
@Schema(description = "서까래기초코드")
private String raftBaseCd;
@Schema(description = "가대메이커코드")
private String trestleMkrCd;
@Schema(description = "공법코드")
private String constMthdCd;
@Schema(description = "지붕기초코드")
private String roofBaseCd;
public ApiTrestleBuilder setModuleTpCd(String moduleTpCd){
this.moduleTpCd = moduleTpCd;
return this;
}
public ApiTrestleBuilder setRoofMatlCdCd(String roofMatlCd){
this.roofMatlCd = roofMatlCd;
return this;
}
public ApiTrestleBuilder setRaftBaseCd(String raftBaseCd){
this.raftBaseCd = raftBaseCd;
return this;
}
public ApiTrestleBuilder setTrestleMkrCd(String trestleMkrCd){
this.trestleMkrCd = trestleMkrCd;
return this;
}
public ApiTrestleBuilder setConstMthdCd(String constMthdCd){
this.constMthdCd = constMthdCd;
return this;
}
public ApiTrestleBuilder setRoofBaseCd(String roofBaseCd){
this.roofBaseCd = roofBaseCd;
return this;
}
public ApiTrestleBuilder (String moduleTpCd, String roofMatlCd, String raftBaseCd, String trestleMkrCd, String constMthdCd, String roofBaseCd) {
this.moduleTpCd = moduleTpCd;
this.roofMatlCd = roofMatlCd;
this.raftBaseCd = raftBaseCd;
this.trestleMkrCd = trestleMkrCd;
this.constMthdCd = constMthdCd;
this.roofBaseCd = roofBaseCd;
}
public ApiTrestleBuilder build(){
return new ApiTrestleBuilder(moduleTpCd, roofMatlCd, raftBaseCd, trestleMkrCd, constMthdCd, roofBaseCd);
}
}

Some files were not shown because too many files have changed in this diff Show More