From 40f33b79747686f408847acc3293b24ec368d698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=EC=9D=BC?= Date: Thu, 9 Jul 2026 21:59:11 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20ACI=20POD=20=EB=B0=B0=EC=86=A1=EC=A4=91?= =?UTF-8?q?=20=EC=B6=94=EC=A0=81=20=EB=B0=8F=20=EB=B0=B0=EC=86=A1=EC=99=84?= =?UTF-8?q?=EB=A3=8C=20=EC=A0=84=ED=99=98=20=EB=B3=B4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../acidlivy/tasklet/AciPodTasklet.java | 153 ++++++++++++------ .../mapper/gcone/AciDlivyMapper.java | 4 +- .../xml/mapper/acidlivy/AciDlivyMapper.xml | 10 +- 3 files changed, 111 insertions(+), 56 deletions(-) diff --git a/src/main/java/com/wb/domainserver/acidlivy/tasklet/AciPodTasklet.java b/src/main/java/com/wb/domainserver/acidlivy/tasklet/AciPodTasklet.java index d967a33..640fdb3 100644 --- a/src/main/java/com/wb/domainserver/acidlivy/tasklet/AciPodTasklet.java +++ b/src/main/java/com/wb/domainserver/acidlivy/tasklet/AciPodTasklet.java @@ -30,7 +30,7 @@ import java.math.BigInteger; import java.util.*; // ACI 배송자료 조회 및 배송처리 배치 Tasklet -// 흐름: gc_order_shipping(DLIVY_STTUS_CD=55) 조회 → 토큰 발급 → ACI API 호출 → BLNO 추출 → 배송처리 +// 흐름: gc_goods_export(DLIVY_STTUS_CD=55,65) 조회 -> 토큰 발급 -> ACI API 호출 -> BLNO 검증 -> 배송처리 @Slf4j @Component @RequiredArgsConstructor @@ -57,7 +57,9 @@ public class AciPodTasklet implements Tasklet { @Value("${acikey.apikey}") private String apiKey; - private static final String DLIVY_STTUS_CD = "55"; // 출고완료 코드 + private static final String DLIVY_STTUS_CD_EXPORT_COMPLETE = "55"; // 출고완료 코드 + private static final String DLIVY_STTUS_CD_DELIVERY_IN_PROGRESS = "65"; // 배송중 코드 + private static final String DLIVY_STTUS_CD_DELIVERY_COMPLETE = "75"; // 배송완료 코드 @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { @@ -66,8 +68,8 @@ public class AciPodTasklet implements Tasklet { // 토큰 발급 (yaml 고정 apikey → ACIKey 토큰 발급, 메모리에만 유지) String aciKeyToken = issueAciKeyToken(); - // 대상 주문 목록 조회 (DLIVY_STTUS_CD = '55') - List goodsExportList = AciDlivyMapper.selectGoodsExportList(DLIVY_STTUS_CD); + // 대상 주문 목록 조회 (DLIVY_STTUS_CD IN ('55', '65')) + List goodsExportList = AciDlivyMapper.selectGoodsExportList(); log.info("[AciPodBatch] 대상 출고 건수: {}", goodsExportList.size()); if (goodsExportList.isEmpty()) { @@ -87,28 +89,39 @@ public class AciPodTasklet implements Tasklet { try { // 건별 ACI 출고자료 API 호출 List podInfoList = callAciPodApi(dlivyOrderVO, aciKeyToken); - if (podInfoList.isEmpty()) { + if (CollectionUtils.isEmpty(podInfoList)) { skipCnt++; } else { boolean dlvyInPrg = podInfoList.stream() .anyMatch(podInfo -> !isBlank(podInfo, "dateLocalwhin")); boolean dlvyCompt = podInfoList.stream() - .allMatch(podInfo -> !isBlank(podInfo, "dateDelivery")); + .anyMatch(podInfo -> !isBlank(podInfo, "dateDelivery")); // 건별 배송처리 BODlivyUpdtVO boDlivyUpdtVO = new BODlivyUpdtVO(); boDlivyUpdtVO.setDlivyInnb(dlivyOrderVO.getDlivyInnb()); boDlivyUpdtVO.setDlivySttusCd(dlivyOrderVO.getDlivySttusCd()); boDlivyUpdtVO.setSopmalCd(dlivyOrderVO.getSopmalCd()); - if(dlvyInPrg) { - boDlivyUpdtVO.setDlivySttusCd("65"); + + String currentDlivySttusCd = dlivyOrderVO.getDlivySttusCd(); + if (dlvyCompt) { + boDlivyUpdtVO.setDlivySttusCd(DLIVY_STTUS_CD_DELIVERY_COMPLETE); processDeliveryPod(boDlivyUpdtVO); - } - if(dlvyCompt) { - boDlivyUpdtVO.setDlivySttusCd("75"); + successCnt++; + } else if (dlvyInPrg && DLIVY_STTUS_CD_EXPORT_COMPLETE.equals(currentDlivySttusCd)) { + boDlivyUpdtVO.setDlivySttusCd(DLIVY_STTUS_CD_DELIVERY_IN_PROGRESS); processDeliveryPod(boDlivyUpdtVO); + successCnt++; + } else { + if (dlvyInPrg && DLIVY_STTUS_CD_DELIVERY_IN_PROGRESS.equals(currentDlivySttusCd)) { + log.info("[AciPodBatch] 스킵 - 이미 배송중 상태 유지 - DLIVY_INNB={}, INVCNB={}", + dlivyOrderVO.getDlivyInnb(), dlivyOrderVO.getInvcnb()); + } else { + log.info("[AciPodBatch] 스킵 - ACI 배송상태 판단 불가 - DLIVY_INNB={}, INVCNB={}", + dlivyOrderVO.getDlivyInnb(), dlivyOrderVO.getInvcnb()); + } + skipCnt++; } - successCnt++; } } catch (Exception e) { log.error("[AciPodBatch] 배송처리 실패 - DLIVY_INNB={}, 오류={}", @@ -188,7 +201,7 @@ public class AciPodTasklet implements Tasklet { HttpEntity> apiRequest = new HttpEntity<>(body, headers); - log.info("[AciPodBatch] API 응답: {}", apiRequest.toString()); + log.info("[AciPodBatch] API 요청: {}", apiRequest.toString()); RestTemplate restTemplate = new RestTemplate(); ResponseEntity response = restTemplate.exchange( @@ -201,70 +214,100 @@ public class AciPodTasklet implements Tasklet { ObjectMapper objectMapper = new ObjectMapper(); JsonNode jsonNode = objectMapper.readTree(response.getBody()); - log.info("[AciPodBatch] API 응답 Status: {}", jsonNode.get("Status").asText()); - log.info("[AciPodBatch] API 응답 RstMsg: {}", jsonNode.get("RstMsg").asText()); + String status = getText(jsonNode, "Status"); + log.info("[AciPodBatch] API 응답 Status: {}", status); + log.info("[AciPodBatch] API 응답 RstMsg: {}", getText(jsonNode, "RstMsg")); + + if (!"success".equals(status)) { + log.info("[AciPodBatch] 스킵 - ACI 응답 Status 실패 - DLIVY_INNB={}, Status={}, ErrMsg={}", + orderVO.getDlivyInnb(), status, getText(jsonNode, "ErrMsg")); + return Collections.emptyList(); + } + JsonNode podInfoNode = jsonNode.get("PODInfo"); - if(!podInfoNode.isNull()) { + if(podInfoNode != null && podInfoNode.isArray() && podInfoNode.size() > 0) { List podInfoList = new ArrayList<>(); for(JsonNode podInfoItem : podInfoNode) { + String blno = getText(podInfoItem, "BLNO"); + if (!Objects.equals(trimToEmpty(orderVO.getInvcnb()), trimToEmpty(blno))) { + log.info("[AciPodBatch] 스킵 - 요청 송장번호와 ACI 응답 BLNO 불일치 - DLIVY_INNB={}, INVCNB={}, BLNO={}", + orderVO.getDlivyInnb(), orderVO.getInvcnb(), blno); + continue; + } + DataMap PODInfo = new DataMap(); - PODInfo.put("blno", podInfoItem.get("BLNO").asText()); - PODInfo.put("dateLocalwhin", podInfoItem.get("DATE_LOCALWHIN").asText()); - PODInfo.put("dateLocaldeparture", podInfoItem.get("DATE_LOCALDEPARTURE").asText()); - PODInfo.put("dateIcnarrival", podInfoItem.get("DATE_ICNARRIVAL").asText()); - PODInfo.put("dateCustomes", podInfoItem.get("DATE_CUSTOMES").asText()); - PODInfo.put("dateDelivery", podInfoItem.get("DATE_DELIVERY").asText()); - PODInfo.put("recipient", podInfoItem.get("RECIPIENT").asText()); - PODInfo.put("wta", podInfoItem.get("WTA").asText()); - PODInfo.put("wtdan", podInfoItem.get("WTDAN").asText()); + PODInfo.put("blno", blno); + PODInfo.put("dateLocalwhin", getText(podInfoItem, "DATE_LOCALWHIN")); + PODInfo.put("dateLocaldeparture", getText(podInfoItem, "DATE_LOCALDEPARTURE")); + PODInfo.put("dateIcnarrival", getText(podInfoItem, "DATE_ICNARRIVAL")); + PODInfo.put("dateCustomes", getText(podInfoItem, "DATE_CUSTOMES")); + PODInfo.put("dateDelivery", getText(podInfoItem, "DATE_DELIVERY")); + PODInfo.put("recipient", getText(podInfoItem, "RECIPIENT")); + PODInfo.put("wta", getText(podInfoItem, "WTA")); + PODInfo.put("wtdan", getText(podInfoItem, "WTDAN")); List volumeList = new ArrayList<>(); - for(JsonNode volumeItem : podInfoItem.get("VOLUME")) { - DataMap volume = new DataMap(); - volume.put("width", volumeItem.get("WIDTH").asText()); - volume.put("length", volumeItem.get("LENGTH").asText()); - volume.put("height", volumeItem.get("HEIGHT").asText()); + JsonNode volumeNode = podInfoItem.get("VOLUME"); + if (volumeNode != null && volumeNode.isArray()) { + for(JsonNode volumeItem : volumeNode) { + DataMap volume = new DataMap(); + volume.put("width", getText(volumeItem, "WIDTH")); + volume.put("length", getText(volumeItem, "LENGTH")); + volume.put("height", getText(volumeItem, "HEIGHT")); - volumeList.add(volume); + volumeList.add(volume); + } } PODInfo.put("volume", volumeList); List customsList = new ArrayList<>(); - for(JsonNode customsItem : podInfoItem.get("CUSTOMS")) { - List customDetail = new ArrayList<>(); - for(JsonNode customItem : customsItem) { - DataMap Custom = new DataMap(); - Custom.put("dateEvent", customItem.get("DATE_EVENT").asText()); - Custom.put("traceStatus", customItem.get("TRACE_STATUS").asText()); + JsonNode customsNode = podInfoItem.get("CUSTOMS"); + if (customsNode != null && customsNode.isArray()) { + for(JsonNode customsItem : customsNode) { + List customDetail = new ArrayList<>(); + for(JsonNode customItem : customsItem) { + DataMap Custom = new DataMap(); + Custom.put("dateEvent", getText(customItem, "DATE_EVENT")); + Custom.put("traceStatus", getText(customItem, "TRACE_STATUS")); - customDetail.add(Custom); + customDetail.add(Custom); + } + customsList.add(customDetail); } - customsList.add(customDetail); } PODInfo.put("customs", customsList); List localPodList = new ArrayList<>(); - for(JsonNode localPodItem : podInfoItem.get("LOCAL_POD")) { - DataMap localPod = new DataMap(); - localPod.put("traceStatus", localPodItem.get("TRACE_STATUS").asText()); - localPod.put("dateEvent", localPodItem.get("DATE_EVENT").asText()); - localPod.put("position", localPodItem.get("POSITION").asText()); + JsonNode localPodNode = podInfoItem.get("LOCAL_POD"); + if (localPodNode != null && localPodNode.isArray()) { + for(JsonNode localPodItem : localPodNode) { + DataMap localPod = new DataMap(); + localPod.put("traceStatus", getText(localPodItem, "TRACE_STATUS")); + localPod.put("dateEvent", getText(localPodItem, "DATE_EVENT")); + localPod.put("position", getText(localPodItem, "POSITION")); - localPodList.add(localPod); + localPodList.add(localPod); + } } PODInfo.put("localPod", localPodList); podInfoList.add(PODInfo); } - log.info("[AciPodBatch] API 응답 PODInfo: {}", podInfoList); + if (podInfoList.isEmpty()) { + log.info("[AciPodBatch] 스킵 - 요청 송장번호와 일치하는 ACI PODInfo 없음 - DLIVY_INNB={}, INVCNB={}", + orderVO.getDlivyInnb(), orderVO.getInvcnb()); + } else { + log.info("[AciPodBatch] API 응답 PODInfo: {}", podInfoList); + } return podInfoList; } else { - log.info("[AciPodBatch] API 응답 ErrMsg: {}", jsonNode.get("ErrMsg").asText()); - return null; + log.info("[AciPodBatch] 스킵 - ACI PODInfo 없음 - DLIVY_INNB={}, ErrMsg={}", + orderVO.getDlivyInnb(), getText(jsonNode, "ErrMsg")); + return Collections.emptyList(); } } catch (Exception e) { log.error("[AciPodBatch] API 호출 오류 - DLIVY_INNB={}, 오류={}", orderVO.getDlivyInnb(), e.getMessage(), e); - return null; + return Collections.emptyList(); } } @@ -435,4 +478,16 @@ public class AciPodTasklet implements Tasklet { return podInfo.get(key) == null || podInfo.get(key).toString().trim().isEmpty(); } + + private String getText(JsonNode jsonNode, String key) { + JsonNode valueNode = jsonNode.get(key); + if (valueNode == null || valueNode.isNull()) { + return ""; + } + return valueNode.asText(); + } + + private String trimToEmpty(String value) { + return value == null ? "" : value.trim(); + } } diff --git a/src/main/java/com/wb/domainserver/mapper/gcone/AciDlivyMapper.java b/src/main/java/com/wb/domainserver/mapper/gcone/AciDlivyMapper.java index 35d614b..38a920e 100644 --- a/src/main/java/com/wb/domainserver/mapper/gcone/AciDlivyMapper.java +++ b/src/main/java/com/wb/domainserver/mapper/gcone/AciDlivyMapper.java @@ -57,8 +57,8 @@ public interface AciDlivyMapper { /** GC_ORDER_LOG INSERT */ int insertOrderLog(DataMap logMap); - /** 배송처리 대상 주문 목록 조회 (gc_goods_export.DLIVY_STTUS_CD = '55') */ - List selectGoodsExportList(String dlivySttusCd); + /** 배송처리 대상 주문 목록 조회 (gc_goods_export.DLIVY_STTUS_CD IN ('55', '65')) */ + List selectGoodsExportList(); /** 출고 상태 일괄 변경 다건 */ public Integer updateBODlivySttusGetbackUpdtArr(BODlivyUpdtVO dlivyVO); diff --git a/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml b/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml index 2192f5d..6181fea 100644 --- a/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml +++ b/src/main/resources/mybatis/xml/mapper/acidlivy/AciDlivyMapper.xml @@ -367,18 +367,18 @@ ]]> - -