From 51ab84aea3358b1a6b30c07f5a79440e317fd68f Mon Sep 17 00:00:00 2001 From: rjy1537 Date: Fri, 8 Nov 2024 20:08:52 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B0=80=EA=B2=A9=20=EB=8F=99=EA=B8=B0?= =?UTF-8?q?=ED=99=94=20=EB=B0=B0=EC=B9=98=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qcast/batch/JobLauncherController.java | 32 +++- .../batch/master/PriceJobConfiguration.java | 157 ++++++++++++++++++ .../biz/displayItem/DisplayItemMapper.java | 14 +- .../biz/displayItem/DisplayItemService.java | 20 ++- .../dto/PriceItemSyncResponse.java | 21 +++ .../biz/displayItem/dto/PriceSyncRequest.java | 11 ++ .../displayItem/dto/PriceSyncResponse.java | 17 ++ src/main/resources/config/application-dev.yml | 1 + .../resources/config/application-local.yml | 1 + src/main/resources/config/application-prd.yml | 1 + .../mappers/displayItem/displayItemMapper.xml | 29 ++++ 11 files changed, 295 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/interplug/qcast/batch/master/PriceJobConfiguration.java create mode 100644 src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceItemSyncResponse.java create mode 100644 src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceSyncRequest.java create mode 100644 src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceSyncResponse.java diff --git a/src/main/java/com/interplug/qcast/batch/JobLauncherController.java b/src/main/java/com/interplug/qcast/batch/JobLauncherController.java index d9569296..678d0626 100644 --- a/src/main/java/com/interplug/qcast/batch/JobLauncherController.java +++ b/src/main/java/com/interplug/qcast/batch/JobLauncherController.java @@ -219,7 +219,7 @@ public class JobLauncherController { * @throws JobRestartException */ @Scheduled(cron = "0 0 0 * * *") - public String adminUserStep() + public String adminUserJob() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, @@ -238,4 +238,34 @@ public class JobLauncherController { return "OK"; } + + /** + * 가격 동기화 배치 + * + * @return + * @throws JobInstanceAlreadyCompleteException + * @throws JobExecutionAlreadyRunningException + * @throws JobParametersInvalidException + * @throws JobRestartException + */ + @Scheduled(cron = "0 0 0 * * *") + public String priceJob() + throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, + JobParametersInvalidException, + JobRestartException { + + String jobName = "priceJob"; + 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"; + } } diff --git a/src/main/java/com/interplug/qcast/batch/master/PriceJobConfiguration.java b/src/main/java/com/interplug/qcast/batch/master/PriceJobConfiguration.java new file mode 100644 index 00000000..46e0a145 --- /dev/null +++ b/src/main/java/com/interplug/qcast/batch/master/PriceJobConfiguration.java @@ -0,0 +1,157 @@ +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.PriceSyncRequest; +import com.interplug.qcast.biz.displayItem.dto.PriceSyncResponse; +import com.interplug.qcast.util.InterfaceQsp; +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 { + PriceSyncRequest priceSyncRequest = new PriceSyncRequest(); + priceSyncRequest.setAllYn("Y"); + + this.priceSyncResponse = + interfaceQsp.callApiData( + HttpMethod.GET, qspInterfaceUrl, priceSyncRequest, 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 Step buildStep( + String stepName, + JobRepository jobRepository, + PlatformTransactionManager transactionManager, + ItemReader reader, + ItemWriter writer) { + return new StepBuilder(stepName, jobRepository) + .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 ListItemReader createReader(List items, String readerName) { + log.info("{}Reader 호출됨...", readerName); + return new ListItemReader<>(items != null ? items : Collections.emptyList()); + } + + @Bean + @StepScope + public ListItemReader modulePriceListReader() { + return createReader( + priceSyncResponse != null ? priceSyncResponse.getModulePriceList() : null, "store"); + } + + @Bean + @StepScope + public ListItemReader bosPriceListReader() { + return createReader( + priceSyncResponse != null ? priceSyncResponse.getBosPriceList() : null, "user"); + } + + private ItemWriter createWriter(Consumer> processor, String writerName) { + return items -> { + try { + List itemList = (List) items.getItems(); + processor.accept(itemList); + log.info("{}Writer: {} items 처리 완료", writerName, items.size()); + } catch (Exception e) { + log.error("{}Writer 오류: {}", writerName, e.getMessage()); + throw e; + } + }; + } +} diff --git a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemMapper.java b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemMapper.java index f750db67..bac6f917 100644 --- a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemMapper.java +++ b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemMapper.java @@ -1,9 +1,6 @@ package com.interplug.qcast.biz.displayItem; -import com.interplug.qcast.biz.displayItem.dto.BomSyncResponse; -import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; -import com.interplug.qcast.biz.displayItem.dto.ItemResponse; -import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse; +import com.interplug.qcast.biz.displayItem.dto.*; import java.util.List; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -43,4 +40,13 @@ public interface DisplayItemMapper { * @throws Exception */ int setBomSyncSave(BomSyncResponse bomInfoSync); + + /** + * 아이템 가격 정보 동기화 + * + * @param priceItemSyncResponse 아이템 가격 정보 + * @return + * @throws Exception + */ + int setPriceItemSyncSave(PriceItemSyncResponse priceItemSyncResponse); } diff --git a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemService.java b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemService.java index 2cbc67f0..3cd4110d 100644 --- a/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemService.java +++ b/src/main/java/com/interplug/qcast/biz/displayItem/DisplayItemService.java @@ -1,9 +1,6 @@ package com.interplug.qcast.biz.displayItem; -import com.interplug.qcast.biz.displayItem.dto.BomSyncResponse; -import com.interplug.qcast.biz.displayItem.dto.DisplayItemRequest; -import com.interplug.qcast.biz.displayItem.dto.ItemResponse; -import com.interplug.qcast.biz.displayItem.dto.ItemSyncResponse; +import com.interplug.qcast.biz.displayItem.dto.*; import com.interplug.qcast.biz.estimate.EstimateMapper; import com.interplug.qcast.biz.estimate.dto.NoteRequest; import com.interplug.qcast.biz.estimate.dto.NoteResponse; @@ -108,4 +105,19 @@ public class DisplayItemService { } return cnt; } + + /** + * 아이템 가격 정보 동기화 + * + * @param priceItemSyncList 가격 목록 + * @return + * @throws Exception + */ + public int setPriceSyncSave(List priceItemSyncList) throws Exception { + int cnt = 0; + for (PriceItemSyncResponse priceItemSyncResponse : priceItemSyncList) { + cnt += displayItemMapper.setPriceItemSyncSave(priceItemSyncResponse); + } + return cnt; + } } diff --git a/src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceItemSyncResponse.java b/src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceItemSyncResponse.java new file mode 100644 index 00000000..8160d17c --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceItemSyncResponse.java @@ -0,0 +1,21 @@ +package com.interplug.qcast.biz.displayItem.dto; + +import com.interplug.qcast.util.DefaultResponse; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** 아이템 동기화 Response */ +@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; +} diff --git a/src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceSyncRequest.java b/src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceSyncRequest.java new file mode 100644 index 00000000..7c5dae63 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceSyncRequest.java @@ -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; +} diff --git a/src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceSyncResponse.java b/src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceSyncResponse.java new file mode 100644 index 00000000..4dc07ee5 --- /dev/null +++ b/src/main/java/com/interplug/qcast/biz/displayItem/dto/PriceSyncResponse.java @@ -0,0 +1,17 @@ +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; + +/** 가격 동기화 Response */ +@Data +public class PriceSyncResponse extends DefaultResponse { + + @Schema(description = "Module Price") + private List modulePriceList; + + @Schema(description = "Bos Price") + private List bosPriceList; +} diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index 84e21406..c6016240 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -43,6 +43,7 @@ qsp: master-bom-batch-url: /api/master/bomList master-business-charger-batch-url: /api/user/businessChargerList master-admin-user-batch-url: /api/admin/userList + master-price-batch-url: /api/master/priceList simulation-guide-info-url: /api/simulation/guideInfo aes256.key: jpqcellQ123456!! auto.login.aes256.key: _autoL!! diff --git a/src/main/resources/config/application-local.yml b/src/main/resources/config/application-local.yml index af61a309..691fd4f7 100644 --- a/src/main/resources/config/application-local.yml +++ b/src/main/resources/config/application-local.yml @@ -43,6 +43,7 @@ qsp: master-bom-batch-url: /api/master/bomList master-business-charger-batch-url: /api/user/businessChargerList master-admin-user-batch-url: /api/admin/userList + master-price-batch-url: /api/master/priceList simulation-guide-info-url: /api/simulation/guideInfo aes256.key: jpqcellQ123456!! auto.login.aes256.key: _autoL!! diff --git a/src/main/resources/config/application-prd.yml b/src/main/resources/config/application-prd.yml index 1294b4a9..60232ba2 100644 --- a/src/main/resources/config/application-prd.yml +++ b/src/main/resources/config/application-prd.yml @@ -43,6 +43,7 @@ qsp: master-bom-batch-url: /api/master/bomList master-business-charger-batch-url: /api/user/businessChargerList master-admin-user-batch-url: /api/admin/userList + master-price-batch-url: /api/master/priceList simulation-guide-info-url: /api/simulation/guideInfo aes256.key: jpqcellQ123456!! auto.login.aes256.key: _autoL!! diff --git a/src/main/resources/mappers/displayItem/displayItemMapper.xml b/src/main/resources/mappers/displayItem/displayItemMapper.xml index bbaa65ce..bd772924 100644 --- a/src/main/resources/mappers/displayItem/displayItemMapper.xml +++ b/src/main/resources/mappers/displayItem/displayItemMapper.xml @@ -278,4 +278,33 @@ , GETDATE() ); + + + /* sqlid : com.interplug.qcast.displayItem.setPriceItemSyncSave */ + MERGE M_PRICE_PATTERN_MONEY AS A + USING + ( SELECT #{pricePattern} AS PRICE_PATTERN + , #{itemId} AS ITEM_ID + ) AS D + ON ( + A.PRICE_PATTERN = D.PRICE_PATTERN + AND A.ITEM_ID = D.ITEM_ID + ) + WHEN MATCHED THEN + UPDATE SET + SALE_PRICE = #{salePrice} + , COST_PRICE = #{costPrice} + WHEN NOT MATCHED THEN + INSERT ( + PRICE_PATTERN + , ITEM_ID + , SALE_PRICE + , COST_PRICE + ) VALUES ( + #{pricePattern} + , #{itemId} + , #{salePrice} + , #{costPrice} + ); +