diff --git a/src/main/java/com/interplug/qcast/batch/JobLauncherController.java b/src/main/java/com/interplug/qcast/batch/JobLauncherController.java index 6783f14e..0e97a73f 100644 --- a/src/main/java/com/interplug/qcast/batch/JobLauncherController.java +++ b/src/main/java/com/interplug/qcast/batch/JobLauncherController.java @@ -2,6 +2,7 @@ package com.interplug.qcast.batch; import java.util.Date; import java.util.Map; +import lombok.RequiredArgsConstructor; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; @@ -15,7 +16,6 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import lombok.RequiredArgsConstructor; @RestController @RequiredArgsConstructor @@ -38,16 +38,22 @@ public class JobLauncherController { * @throws JobRestartException */ @GetMapping("/batch/job/{jobName}") // Path Variable로 jobName을 받음 - public String launchJob(@PathVariable String jobName) throws JobInstanceAlreadyCompleteException, - JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + public String launchJob(@PathVariable String jobName) + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { Job job = jobs.get(jobName); if (job == null) { return "Job " + jobName + " not found"; } - JobParameters jobParameters = new JobParametersBuilder().addString("jobName", jobName) - .addDate("time", new Date()).toJobParameters(); + JobParameters jobParameters = + new JobParametersBuilder() + .addString("jobName", jobName) + .addDate("time", new Date()) + .toJobParameters(); jobLauncher.run(job, jobParameters); @@ -65,8 +71,11 @@ public class JobLauncherController { */ // @Scheduled(cron = "*/5 * * * * *") @Scheduled(cron = "0 55 23 * * *") - public String storeAdditionalInfoJob() throws JobInstanceAlreadyCompleteException, - JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + public String storeAdditionalInfoJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { String jobName = "storeAdditionalJob"; Job job = jobs.get(jobName); @@ -92,8 +101,11 @@ public class JobLauncherController { * @throws JobRestartException */ @Scheduled(cron = "0 30 02 * * *") - public String materialJob() throws JobInstanceAlreadyCompleteException, - JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + public String materialJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { String jobName = "materialJob"; Job job = jobs.get(jobName); @@ -120,8 +132,11 @@ public class JobLauncherController { * @throws JobRestartException */ @Scheduled(cron = "0 40 02 * * *") - public String bomJob() throws JobInstanceAlreadyCompleteException, - JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + public String bomJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { String jobName = "bomJob"; Job job = jobs.get(jobName); @@ -149,8 +164,11 @@ public class JobLauncherController { * @throws JobRestartException */ @Scheduled(cron = "0 40 03 * * *") - public String businessChargerJob() throws JobInstanceAlreadyCompleteException, - JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + public String businessChargerJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { String jobName = "businessChargerJob"; Job job = jobs.get(jobName); @@ -178,8 +196,11 @@ public class JobLauncherController { * @throws JobRestartException */ @Scheduled(cron = "0 0 01 * * *") - public String adminUserJob() throws JobInstanceAlreadyCompleteException, - JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + public String adminUserJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { String jobName = "adminUserJob"; Job job = jobs.get(jobName); @@ -207,8 +228,11 @@ public class JobLauncherController { * @throws JobRestartException */ @Scheduled(cron = "0 0 0 * * *") - public String priceJob() throws JobInstanceAlreadyCompleteException, - JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + public String priceJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { String jobName = "priceJob"; Job job = jobs.get(jobName); @@ -236,8 +260,11 @@ public class JobLauncherController { * @throws JobRestartException */ @Scheduled(cron = "0 10 03 * * *") - public String commonCodeJob() throws JobInstanceAlreadyCompleteException, - JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + public String commonCodeJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { String jobName = "commonCodeJob"; Job job = jobs.get(jobName); @@ -264,8 +291,11 @@ public class JobLauncherController { * @throws JobRestartException */ @Scheduled(cron = "0 30 23 * * *") - public String specialNoteDispItemAdditionalInfoJob() throws JobInstanceAlreadyCompleteException, - JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + public String specialNoteDispItemAdditionalInfoJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { String jobName = "specialNoteDispItemAdditionalJob"; Job job = jobs.get(jobName); if (job == null) { @@ -282,4 +312,67 @@ public class JobLauncherController { return "OK"; } + /** + * Plan Confrim 동기화 배치 + * + * @return + * @throws JobInstanceAlreadyCompleteException + * @throws JobExecutionAlreadyRunningException + * @throws JobParametersInvalidException + * @throws JobRestartException + */ + @Scheduled(cron = "1 0 0 * * *") + public String planConfirmJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { + + String jobName = "planConfirmJob"; + Job job = jobs.get(jobName); + if (job == null) { + return "Job " + jobName + " not found"; + } + + if ("Y".equals(System.getProperty("spring.profiles.scheduler"))) { + 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 = "1 20 0 * * *") + public String estimateSyncJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { + + String jobName = "estimateSyncJob"; + Job job = jobs.get(jobName); + if (job == null) { + return "Job " + jobName + " not found"; + } + + if ("Y".equals(System.getProperty("spring.profiles.scheduler"))) { + JobParameters jobParameters = + new JobParametersBuilder().addDate("time", new Date()).toJobParameters(); + + jobLauncher.run(job, jobParameters); + } + + return "OK"; + } } diff --git a/src/main/java/com/interplug/qcast/batch/estimate/EstimateSyncConfiguration.java b/src/main/java/com/interplug/qcast/batch/estimate/EstimateSyncConfiguration.java new file mode 100644 index 00000000..e6a340c6 --- /dev/null +++ b/src/main/java/com/interplug/qcast/batch/estimate/EstimateSyncConfiguration.java @@ -0,0 +1,83 @@ +package com.interplug.qcast.batch.estimate; + +import com.interplug.qcast.biz.estimate.EstimateService; +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.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 EstimateSyncConfiguration implements JobExecutionListener { + private final EstimateService estimateService; + + private final InterfaceQsp interfaceQsp; + + EstimateSyncResponse estimateSyncResponse; + + @Value("${qsp.estimate-sync-batch-url}") + private String qspInterfaceUrl; + + 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) + .chunk(100, transactionManager) + .reader(estimateSyncReader()) + .processor(estimateSyncProcessor()) + .writer(estimateSyncWriter()) + .build(); + } + + @Bean + @StepScope + public ListItemReader estimateSyncReader() throws Exception { + this.estimateSyncResponse = + interfaceQsp.callApiData( + HttpMethod.POST, + qspInterfaceUrl, + estimateService.selectEstimateSyncFailList(), + EstimateSyncResponse.class); + return (estimateSyncResponse != null) + ? new ListItemReader<>(estimateSyncResponse.getSuccessList()) + : new ListItemReader<>(Collections.emptyList()); + } + + @Bean + public ItemProcessor estimateSyncProcessor() { + return item -> item; + } + + @Bean + public ItemWriter estimateSyncWriter() { + return items -> { + estimateService.setEstimateSyncSave((List) items.getItems()); + }; + } +} diff --git a/src/main/java/com/interplug/qcast/batch/estimate/PlanConfrimConfiguration.java b/src/main/java/com/interplug/qcast/batch/estimate/PlanConfrimConfiguration.java new file mode 100644 index 00000000..36afa1fb --- /dev/null +++ b/src/main/java/com/interplug/qcast/batch/estimate/PlanConfrimConfiguration.java @@ -0,0 +1,80 @@ +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.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 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) + .chunk(100, transactionManager) + .reader(planConfirmReader()) + .processor(planConfirmProcessor()) + .writer(planConfirmWriter()) + .build(); + } + + @Bean + @StepScope + public ListItemReader planConfirmReader() throws Exception { + this.planSyncList = + interfaceQsp.callApiData( + HttpMethod.GET, qspInterfaceUrl, null, new TypeReference>() {}); + return (planSyncList != null) + ? new ListItemReader<>(planSyncList) + : new ListItemReader<>(Collections.emptyList()); + } + + @Bean + public ItemProcessor planConfirmProcessor() { + return item -> item; + } + + @Bean + public ItemWriter planConfirmWriter() { + return items -> { + estimateService.setPlanConfirmSyncSave((List) items.getItems()); + }; + } +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/EstimateMapper.java b/src/main/java/com/interplug/qcast/biz/estimate/EstimateMapper.java index 5e287c47..31d879a9 100644 --- a/src/main/java/com/interplug/qcast/biz/estimate/EstimateMapper.java +++ b/src/main/java/com/interplug/qcast/biz/estimate/EstimateMapper.java @@ -15,6 +15,9 @@ public interface EstimateMapper { // 견적서 API 상세 확인 public EstimateSendResponse selectEstimateApiDetail(EstimateRequest estimateRequest); + // 견적서 API 실패 목록 조회 + public List selectEstimateApiFailList(); + // 견적서 아이템 목록 조회 public List selectEstimateItemList(EstimateRequest estimateRequest); @@ -80,4 +83,7 @@ public interface EstimateMapper { // 견적서 복사 public int insertEstimateCopy(EstimateCopyRequest estimateCopyRequest); + + // Plan 확정 동기화 + public int updatePlanConfirmSync(PlanSyncResponse planSyncData); } diff --git a/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java b/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java index b24a5557..1483b246 100644 --- a/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java +++ b/src/main/java/com/interplug/qcast/biz/estimate/EstimateService.java @@ -778,6 +778,7 @@ public class EstimateService { estimateRequest.setPlanNo(result.getPlanNo()); estimateRequest.setDocNo(result.getDocNo()); estimateRequest.setSyncFlg(result.getSyncFlg()); + estimateRequest.setUserId(estimateCopyRequest.getUserId()); estimateMapper.updateEstimateApi(estimateRequest); } @@ -1125,8 +1126,8 @@ public class EstimateService { estimateSendResponse.setSaveType("3"); estimateSendResponse.setSyncFlg("0"); estimateSendResponse.setConstructSpecification( - !StringUtils.isEmpty(estimateRequest.getConstructSpecification()) - ? estimateRequest.getConstructSpecification().split("、")[0] + !StringUtils.isEmpty(estimateSendResponse.getConstructSpecification()) + ? estimateSendResponse.getConstructSpecification().split("、")[0] : ""); estimateSendResponse.setDelFlg("1".equals(estimateSendResponse.getDelFlg()) ? "Y" : "N"); @@ -1152,7 +1153,7 @@ public class EstimateService { /* [1]. QSP API CALL -> Response */ String strResponse = interfaceQsp.callApi( - HttpMethod.POST, QSP_API_URL + "/api/master/qcastQuotationSave", estimateSendRequest); + HttpMethod.POST, QSP_API_URL + "/api/order/qcastQuotationSave", estimateSendRequest); if (!"".equals(strResponse)) { com.fasterxml.jackson.databind.ObjectMapper om = @@ -1581,4 +1582,92 @@ public class EstimateService { } return resultList; } + + /** + * Plan 확정 정보 동기화 + * + * @param planSyncList Plan 목록 + * @return + * @throws Exception + */ + public int setPlanConfirmSyncSave(List planSyncList) throws Exception { + int cnt = 0; + for (PlanSyncResponse planSyncData : planSyncList) { + // Plan 확정 처리 + cnt += estimateMapper.updatePlanConfirmSync(planSyncData); + } + return cnt; + } + + /** + * QSP Q.CAST 견적서 동기화 실패 목록 + * + * @return EstimateSendRequest 견적서 실패 목록 + * @throws Exception + */ + public EstimateSendRequest selectEstimateSyncFailList() throws Exception { + EstimateSendRequest estimateSendRequest = new EstimateSendRequest(); + List quoteList = new ArrayList(); + String docNo = ""; + + // 견적서 동기화 실패 목록 조회 + List estimateSendListResponse = + estimateMapper.selectEstimateApiFailList(); + + for (EstimateSendResponse estimateSendResponse : estimateSendListResponse) { + EstimateRequest estimateRequest = new EstimateRequest(); + estimateRequest.setObjectNo(estimateSendResponse.getObjectNo()); + estimateRequest.setPlanNo(estimateSendResponse.getPlanNo()); + + estimateSendResponse.setSaveType("3"); + estimateSendResponse.setSyncFlg("0"); + estimateSendResponse.setConstructSpecification( + !StringUtils.isEmpty(estimateSendResponse.getConstructSpecification()) + ? estimateSendResponse.getConstructSpecification().split("、")[0] + : ""); + estimateSendResponse.setDelFlg("1".equals(estimateSendResponse.getDelFlg()) ? "Y" : "N"); + + // 아이템 목록 조회 + estimateRequest.setSchBomNotExist("1"); + List estimateItemList = estimateMapper.selectEstimateItemList(estimateRequest); + estimateSendResponse.setItemList(estimateItemList); + + // 첨부파일 목록 조회 + FileRequest fileDeleteReq = new FileRequest(); + fileDeleteReq.setObjectNo(estimateRequest.getObjectNo()); + fileDeleteReq.setPlanNo(estimateRequest.getPlanNo()); + fileDeleteReq.setCategory("10"); + + List fileList = fileMapper.selectFileList(fileDeleteReq); + estimateSendResponse.setFileList(fileList); + + quoteList.add(estimateSendResponse); + estimateSendRequest.setQuoteList(quoteList); + } + + return estimateSendRequest; + } + + /** + * 견적서 정보 QSP 동기화 + * + * @param planSyncList Plan 목록 + * @return + * @throws Exception + */ + public int setEstimateSyncSave(List planSyncList) throws Exception { + int cnt = 0; + for (PlanSyncResponse planSyncData : planSyncList) { + EstimateRequest estimateRequest = new EstimateRequest(); + estimateRequest.setObjectNo(planSyncData.getObjectNo()); + estimateRequest.setPlanNo(planSyncData.getPlanNo()); + estimateRequest.setDocNo(planSyncData.getDocNo()); + estimateRequest.setSyncFlg(planSyncData.getSyncFlg()); + estimateRequest.setUserId("system"); + + // 견적서 동기화 여부 처리 + cnt += estimateMapper.updateEstimateApi(estimateRequest); + } + return cnt; + } } diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/EstimateSyncResponse.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/EstimateSyncResponse.java new file mode 100644 index 00000000..b1ddf18e --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/EstimateSyncResponse.java @@ -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 failList; + + @Schema(description = "성공목록") + private List successList; +} diff --git a/src/main/java/com/interplug/qcast/biz/estimate/dto/PlanSyncResponse.java b/src/main/java/com/interplug/qcast/biz/estimate/dto/PlanSyncResponse.java new file mode 100644 index 00000000..71ff1652 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/estimate/dto/PlanSyncResponse.java @@ -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; +} diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index 8542fa29..a40b715d 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -51,6 +51,8 @@ qsp: auto.login.aes256.key: _autoL!! system-commonCode-batch-url: /api/system/commonCodeListData master-special-note-disp-item-batch-url: /api/master/quotationDispItemInfo + estimate-plan-confirm-batch-url: /api/order/planConfirmListData + estimate-sync-batch-url: /api/order/qcastQuotationSave #File file: root.path: C:\\ diff --git a/src/main/resources/config/application-local.yml b/src/main/resources/config/application-local.yml index 7ed6345e..d8500c4c 100644 --- a/src/main/resources/config/application-local.yml +++ b/src/main/resources/config/application-local.yml @@ -39,7 +39,7 @@ spring: #QSP qsp: - url: http://1.248.227.176:8120 + url: http://localhost:8120 master-store-batch-url: /api/master/storeAdditionalInfo master-material-batch-url: /api/master/materialList master-bom-batch-url: /api/master/bomList @@ -51,6 +51,8 @@ qsp: auto.login.aes256.key: _autoL!! system-commonCode-batch-url: /api/system/commonCodeListData master-special-note-disp-item-batch-url: /api/master/quotationDispItemInfo + estimate-plan-confirm-batch-url: /api/order/planConfirmListData + estimate-sync-batch-url: /api/order/qcastQuotationSave #File file: root.path: C:\\ diff --git a/src/main/resources/config/application-prd.yml b/src/main/resources/config/application-prd.yml index c620bc40..351d2dd3 100644 --- a/src/main/resources/config/application-prd.yml +++ b/src/main/resources/config/application-prd.yml @@ -51,6 +51,8 @@ qsp: auto.login.aes256.key: _autoL!! system-commonCode-batch-url: /api/system/commonCodeListData master-special-note-disp-item-batch-url: /api/master/quotationDispItemInfo + estimate-plan-confirm-batch-url: /api/order/planConfirmListData + estimate-sync-batch-url: /api/order/qcastQuotationSave #File file: root.path: C:\\ diff --git a/src/main/resources/mappers/estimate/estimateMapper.xml b/src/main/resources/mappers/estimate/estimateMapper.xml index 49e45638..a64823f8 100644 --- a/src/main/resources/mappers/estimate/estimateMapper.xml +++ b/src/main/resources/mappers/estimate/estimateMapper.xml @@ -119,6 +119,49 @@ ON T.CREATE_SALE_STORE_ID = SS2.SALE_STORE_ID + +