fix: ACI POD 배송중 추적 및 배송완료 전환 보정

This commit is contained in:
이주일
2026-07-09 21:59:11 +09:00
parent a75cfef5ba
commit c13bbd7e2d
3 changed files with 111 additions and 56 deletions

View File

@@ -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<AciDlivyOrderVO> goodsExportList = AciDlivyMapper.selectGoodsExportList(DLIVY_STTUS_CD);
// 대상 주문 목록 조회 (DLIVY_STTUS_CD IN ('55', '65'))
List<AciDlivyOrderVO> goodsExportList = AciDlivyMapper.selectGoodsExportList();
log.info("[AciPodBatch] 대상 출고 건수: {}", goodsExportList.size());
if (goodsExportList.isEmpty()) {
@@ -87,28 +89,39 @@ public class AciPodTasklet implements Tasklet {
try {
// 건별 ACI 출고자료 API 호출
List<DataMap> 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");
processDeliveryPod(boDlivyUpdtVO);
}
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++;
}
}
} catch (Exception e) {
log.error("[AciPodBatch] 배송처리 실패 - DLIVY_INNB={}, 오류={}",
@@ -188,7 +201,7 @@ public class AciPodTasklet implements Tasklet {
HttpEntity<Map<String, Object>> apiRequest =
new HttpEntity<>(body, headers);
log.info("[AciPodBatch] API 응답: {}", apiRequest.toString());
log.info("[AciPodBatch] API 요청: {}", apiRequest.toString());
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> 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<DataMap> 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<DataMap> volumeList = new ArrayList<>();
for(JsonNode volumeItem : podInfoItem.get("VOLUME")) {
JsonNode volumeNode = podInfoItem.get("VOLUME");
if (volumeNode != null && volumeNode.isArray()) {
for(JsonNode volumeItem : volumeNode) {
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());
volume.put("width", getText(volumeItem, "WIDTH"));
volume.put("length", getText(volumeItem, "LENGTH"));
volume.put("height", getText(volumeItem, "HEIGHT"));
volumeList.add(volume);
}
}
PODInfo.put("volume", volumeList);
List<List> customsList = new ArrayList<>();
for(JsonNode customsItem : podInfoItem.get("CUSTOMS")) {
JsonNode customsNode = podInfoItem.get("CUSTOMS");
if (customsNode != null && customsNode.isArray()) {
for(JsonNode customsItem : customsNode) {
List<DataMap> 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());
Custom.put("dateEvent", getText(customItem, "DATE_EVENT"));
Custom.put("traceStatus", getText(customItem, "TRACE_STATUS"));
customDetail.add(Custom);
}
customsList.add(customDetail);
}
}
PODInfo.put("customs", customsList);
List<DataMap> localPodList = new ArrayList<>();
for(JsonNode localPodItem : podInfoItem.get("LOCAL_POD")) {
JsonNode localPodNode = podInfoItem.get("LOCAL_POD");
if (localPodNode != null && localPodNode.isArray()) {
for(JsonNode localPodItem : localPodNode) {
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());
localPod.put("traceStatus", getText(localPodItem, "TRACE_STATUS"));
localPod.put("dateEvent", getText(localPodItem, "DATE_EVENT"));
localPod.put("position", getText(localPodItem, "POSITION"));
localPodList.add(localPod);
}
}
PODInfo.put("localPod", localPodList);
podInfoList.add(PODInfo);
}
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();
}
}

View File

@@ -57,8 +57,8 @@ public interface AciDlivyMapper {
/** GC_ORDER_LOG INSERT */
int insertOrderLog(DataMap logMap);
/** 배송처리 대상 주문 목록 조회 (gc_goods_export.DLIVY_STTUS_CD = '55') */
List<AciDlivyOrderVO> selectGoodsExportList(String dlivySttusCd);
/** 배송처리 대상 주문 목록 조회 (gc_goods_export.DLIVY_STTUS_CD IN ('55', '65')) */
List<AciDlivyOrderVO> selectGoodsExportList();
/** 출고 상태 일괄 변경 다건 */
public Integer updateBODlivySttusGetbackUpdtArr(BODlivyUpdtVO dlivyVO);

View File

@@ -367,18 +367,18 @@
]]>
</insert>
<!-- 배송처리 대상 주문 목록 조회 (DLIVY_STTUS_CD = '55' 출고완료) -->
<select id="selectGoodsExportList" parameterType="java.lang.String"
resultType="com.wb.domainserver.acidlivy.vo.AciDlivyOrderVO">
<!-- 배송처리 대상 주문 목록 조회 (DLIVY_STTUS_CD IN ('55', '65')) -->
<select id="selectGoodsExportList" resultType="com.wb.domainserver.acidlivy.vo.AciDlivyOrderVO">
<![CDATA[
SELECT
DLIVY_INNB,
ORDR_INNB,
ORDR_DLVY_INNB,
SOPMAL_CD,
INVCNB
INVCNB,
DLIVY_STTUS_CD
FROM GC_GOODS_EXPORT
WHERE DLIVY_STTUS_CD = #{param}
WHERE DLIVY_STTUS_CD IN ('55', '65')
ORDER BY DLIVY_INNB ASC
]]>
</select>