package com.zy.asrs.task.handler; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.core.common.Cools; import com.zy.asrs.entity.WrkDetl; import com.zy.asrs.entity.WrkMast; import com.zy.asrs.entity.param.ErpOutTaskLockReportParam; import com.zy.asrs.service.ApiLogService; import com.zy.asrs.service.WrkDetlService; import com.zy.asrs.service.WrkMastService; import com.zy.asrs.task.AbstractHandler; import com.zy.asrs.task.core.ReturnT; import com.zy.common.entity.Parameter; import com.zy.common.utils.HttpHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; @Slf4j @Service public class WorkOutLockErpReportHandler extends AbstractHandler { public static final long ERP_LOCK_REPORT_PENDING_WRK_STS = 13L; public static final long ERP_LOCK_REPORT_SUCCESS_WRK_STS = 21L; public static final long ERP_LOCK_REPORT_FAIL_WRK_STS = 22L; public static final int ERP_LOCK_REPORT_MAX_RETRY_TIMES = 3; public static final String ERP_LOCK_REPORT_PENDING_FLAG = "P"; public static final String ERP_LOCK_REPORT_SUCCESS_FLAG = "Y"; public static final String ERP_LOCK_REPORT_FAIL_FLAG = "F"; private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; @Autowired private WrkMastService wrkMastService; @Autowired private WrkDetlService wrkDetlService; @Autowired private ApiLogService apiLogService; @Value("${erp.switch.ErpReportOld}") private boolean erpReportOld; @Value("${erp.address.URL:}") private String erpUrl; @Value("${erp.address.OutLockaddress:}") private String erpOutLockAddress; /** * 7.12 出库任务锁定。 * WCS 出库任务开始后,WMS 向 ERP 上报 palletId、orderId;失败最多重试三次。 */ @Transactional(rollbackFor = Exception.class) public ReturnT start(WrkMast source) { WrkMast wrkMast = wrkMastService.selectById(source.getWrkNo()); if (wrkMast == null || !Long.valueOf(ERP_LOCK_REPORT_PENDING_WRK_STS).equals(wrkMast.getWrkSts())) { return SUCCESS; } if (!isErpReportEnabled()) { finishReport(wrkMast, false, getRetryTimes(wrkMast), "ERP reporting is disabled", false); return FAIL.setMsg("ERP reporting is disabled"); } if (Cools.isEmpty(erpOutLockAddress)) { return failWithoutCallingErp(wrkMast, "ERP出库任务锁定上报地址未配置"); } List wrkDetls = wrkDetlService.selectByWrkNo(wrkMast.getWrkNo()); ErpOutTaskLockReportParam param = buildParam(wrkMast, wrkDetls); String validateMsg = validateParam(param); if (!Cools.isEmpty(validateMsg)) { return failWithoutCallingErp(wrkMast, validateMsg); } String request = JSON.toJSONString(param); String response = ""; boolean success = false; String errorMsg = null; String requestUrl = buildRequestUrl(); try { response = new HttpHandler.Builder() .setUri(erpUrl) .setPath(erpOutLockAddress) .setJson(request) .build() .doPost(); success = isErpReportSuccess(response); if (!success) { errorMsg = extractErrorMsg(response); } finishReport(wrkMast, success, getRetryTimes(wrkMast), errorMsg, true); } catch (Exception e) { errorMsg = e.getMessage(); finishReport(wrkMast, false, getRetryTimes(wrkMast), errorMsg, true); } finally { try { apiLogService.save( "Outbound ERP Lock Report", requestUrl, null, "127.0.0.1", request, response, success, "workNo=" + wrkMast.getWrkNo() ); } catch (Exception logEx) { log.error("save outbound erp lock api log failed", logEx); } } if (success) { return SUCCESS; } return FAIL.setMsg(errorMsg); } private ReturnT failWithoutCallingErp(WrkMast wrkMast, String errorMsg) { finishReport(wrkMast, false, getRetryTimes(wrkMast), errorMsg, true); return FAIL.setMsg(errorMsg); } private boolean isErpReportEnabled() { if (!erpReportOld) { return false; } String erpReport = Parameter.get().getErpReport(); return Cools.isEmpty(erpReport) || "true".equalsIgnoreCase(erpReport); } private ErpOutTaskLockReportParam buildParam(WrkMast wrkMast, List wrkDetls) { ErpOutTaskLockReportParam param = new ErpOutTaskLockReportParam(); param.setPalletId(resolvePalletId(wrkMast, wrkDetls)); param.setOrderId(resolveOrderId(wrkMast, wrkDetls)); param.setStartTime(formatDate(new Date())); return param; } private String formatDate(Date date) { if (date == null) { return null; } return new SimpleDateFormat(DATE_TIME_PATTERN).format(date); } private String resolvePalletId(WrkMast wrkMast, List wrkDetls) { if (!Cools.isEmpty(wrkMast.getBarcode())) { return wrkMast.getBarcode(); } if (wrkDetls == null) { return null; } for (WrkDetl wrkDetl : wrkDetls) { if (!Cools.isEmpty(wrkDetl.getZpallet())) { return wrkDetl.getZpallet(); } } return null; } private String resolveOrderId(WrkMast wrkMast, List wrkDetls) { if (wrkDetls != null) { for (WrkDetl wrkDetl : wrkDetls) { if (!Cools.isEmpty(wrkDetl.getOrderNo())) { return wrkDetl.getOrderNo(); } } } return wrkMast.getUserNo(); } private String validateParam(ErpOutTaskLockReportParam param) { if (param == null || Cools.isEmpty(param.getPalletId())) { return "ERP出库任务锁定上报失败:palletId为空"; } if (Cools.isEmpty(param.getOrderId())) { return "ERP出库任务锁定上报失败:orderId为空"; } return null; } private boolean isErpReportSuccess(String response) { if (Cools.isEmpty(response)) { return false; } try { JSONObject jsonObject = JSON.parseObject(response); if (jsonObject == null) { return false; } Boolean success = jsonObject.getBoolean("success"); if (success != null) { return success; } Integer code = jsonObject.getInteger("code"); if (code != null) { return code == 200 || code == 0; } Integer status = jsonObject.getInteger("status"); if (status != null) { return status == 200 || status == 0; } String result = jsonObject.getString("result"); if (!Cools.isEmpty(result)) { return "success".equalsIgnoreCase(result) || "ok".equalsIgnoreCase(result) || "true".equalsIgnoreCase(result); } } catch (Exception ignore) { return response.toLowerCase().contains("success") && response.toLowerCase().contains("true"); } return false; } private String extractErrorMsg(String response) { if (Cools.isEmpty(response)) { return "empty erp response"; } try { JSONObject jsonObject = JSON.parseObject(response); if (jsonObject == null) { return response; } String[] keys = new String[]{"msg", "message", "error", "errMsg"}; for (String key : keys) { String value = jsonObject.getString(key); if (!Cools.isEmpty(value)) { return value; } } } catch (Exception ignore) { } return response; } private int getRetryTimes(WrkMast wrkMast) { if (wrkMast.getExpTime() == null) { return 0; } return wrkMast.getExpTime().intValue(); } private void finishReport(WrkMast wrkMast, boolean success, int currentRetryTimes, String errorMsg, boolean countCurrentAttempt) { int retryTimes = currentRetryTimes + (countCurrentAttempt ? 1 : 0); Date now = new Date(); wrkMast.setExpTime((double) retryTimes); wrkMast.setModiTime(now); if (success) { wrkMast.setWrkSts(ERP_LOCK_REPORT_SUCCESS_WRK_STS); wrkMast.setLogMk(ERP_LOCK_REPORT_SUCCESS_FLAG); wrkMast.setLogErrMemo(null); wrkMast.setLogErrTime(null); } else { wrkMast.setLogErrMemo(truncate(errorMsg, 500)); wrkMast.setLogErrTime(now); if (retryTimes >= ERP_LOCK_REPORT_MAX_RETRY_TIMES || !countCurrentAttempt) { wrkMast.setWrkSts(ERP_LOCK_REPORT_FAIL_WRK_STS); wrkMast.setLogMk(ERP_LOCK_REPORT_FAIL_FLAG); } else { wrkMast.setWrkSts(ERP_LOCK_REPORT_PENDING_WRK_STS); wrkMast.setLogMk(ERP_LOCK_REPORT_PENDING_FLAG); } } if (!wrkMastService.updateById(wrkMast)) { throw new IllegalStateException("update outbound erp lock report status failed, workNo=" + wrkMast.getWrkNo()); } } private String truncate(String message, int maxLength) { if (message == null || message.length() <= maxLength) { return message; } return message.substring(0, maxLength); } private String buildRequestUrl() { if (Cools.isEmpty(erpUrl)) { return erpOutLockAddress; } if (erpOutLockAddress == null) { return erpUrl; } if (erpUrl.endsWith("/") && erpOutLockAddress.startsWith("/")) { return erpUrl + erpOutLockAddress.substring(1); } if (!erpUrl.endsWith("/") && !erpOutLockAddress.startsWith("/")) { return erpUrl + "/" + erpOutLockAddress; } return erpUrl + erpOutLockAddress; } }