自动化立体仓库 - WMS系统
src/main/java/com/zy/asrs/task/handler/WorkErpReportHandler.java
@@ -16,12 +16,14 @@
import com.zy.asrs.task.core.ReturnT;
import com.zy.common.entity.Parameter;
import com.zy.common.utils.HttpHandler;
import com.zy.integration.iot.biz.IotInstructionService;
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.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@@ -36,6 +38,7 @@
    public static final String ERP_REPORT_PENDING_FLAG = "P";
    public static final String ERP_REPORT_SUCCESS_FLAG = "Y";
    public static final String ERP_REPORT_FAIL_FLAG = "F";
    public static final String ERP_REPORT_SKIPPED_FLAG = "S";
    private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
@@ -47,6 +50,8 @@
    private WaitPakinService waitPakinService;
    @Autowired
    private ApiLogService apiLogService;
    @Autowired
    private IotInstructionService iotInstructionService;
    @Value("${erp.switch.ErpReportOld}")
    private boolean erpReportOld;
@@ -64,6 +69,13 @@
            return SUCCESS;
        }
        // 历史/运行中数据可能已经在完工时被置为 ERP 待上报。
        // 调度器执行前再做一次来源判断,确保 MQTT 来源任务即使已进入待上报状态,也会被改回完成态并跳过 ERP HTTP 调用。
        if (iotInstructionService.isMqttOriginWork(wrkMast)) {
            skipReport(wrkMast);
            return SUCCESS;
        }
        if (!isErpReportEnabled()) {
            finishReport(wrkMast, false, getRetryTimes(wrkMast), "ERP reporting is disabled", false);
            return FAIL.setMsg("ERP reporting is disabled");
@@ -77,6 +89,22 @@
        WaitPakin waitPakin = findWaitPakin(wrkMast.getBarcode());
        ErpPakinReportParam param = buildParam(wrkMast, wrkDetls, waitPakin);
        // 庫位轉換
        String locId = param.getLocId();
        String row = locId.substring(0, 2);
        String col = locId.substring(2, 5);
        String lev =  locId.substring(5, 7);
        if(Integer.parseInt(row) >= 37) {
            row = "C" + row;
        } else if(Integer.parseInt(row) >= 13) {
            row = "B" + row;
        } else {
            row = "A" + row;
        }
        String newLocId = row + "-" + col + "-" + lev;
        param.setLocId(newLocId);
        String request = JSON.toJSONString(param);
        String response = "";
        boolean success = false;
@@ -141,13 +169,25 @@
        param.setPalletId(resolvePalletId(wrkMast, wrkDetls));
        param.setAnfme(sumAnfme(wrkDetls));
        param.setLocId(wrkMast.getLocNo());
        param.setWeight(sumWeight(wrkDetls));
//        param.setWeight(sumWeight(wrkDetls));
        param.setWeight(adjustErpReportWeight(wrkMast.getScWeight()));
        param.setCreateTime(formatDate(resolveCreateTime(wrkMast)));
        param.setBizNo(resolveBizNo(wrkDetls, waitPakin));
        param.setStartTime(formatDate(resolveStartTime(wrkMast, waitPakin)));
        param.setPhotos(wrkDetls.get(0).getPic());
        return param;
    }
    /** 上报 ERP 重量:≤20 传 0,>20 减 10 */
    private static BigDecimal adjustErpReportWeight(BigDecimal scWeight) {
        BigDecimal base = scWeight == null ? BigDecimal.ZERO : scWeight;
        if (base.compareTo(new BigDecimal("20")) <= 0) {
            return BigDecimal.ZERO;
        }
        return base.subtract(new BigDecimal("20.8"));
        // BigDecimal v = base.subtract(new BigDecimal("10"));
        // return v.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : v;
    }
    private String resolvePalletId(WrkMast wrkMast, List<WrkDetl> wrkDetls) {
        if (!Cools.isEmpty(wrkMast.getBarcode())) {
            return wrkMast.getBarcode();
@@ -170,22 +210,19 @@
        return total;
    }
    private Double sumWeight(List<WrkDetl> wrkDetls) {
        double total = 0D;
        for (WrkDetl wrkDetl : wrkDetls) {
            if (Cools.isEmpty(wrkDetl.getWeight())) {
                continue;
            }
            double qty = Cools.isEmpty(wrkDetl.getAnfme()) ? 1D : wrkDetl.getAnfme();
            total += wrkDetl.getWeight() * qty;
        }
        return total;
    }
//    private Double sumWeight(List<WrkDetl> wrkDetls) {
//        double total = 0D;
//        for (WrkDetl wrkDetl : wrkDetls) {
//            if (Cools.isEmpty(wrkDetl.getWeight())) {
//                continue;
//            }
//            double qty = Cools.isEmpty(wrkDetl.getAnfme()) ? 1D : wrkDetl.getAnfme();
//            total += wrkDetl.getWeight() * qty;
//        }
//        return total;
//    }
    private Date resolveCreateTime(WrkMast wrkMast) {
        if (!Cools.isEmpty(wrkMast.getCrnEndTime())) {
            return wrkMast.getCrnEndTime();
        }
        if (!Cools.isEmpty(wrkMast.getModiTime())) {
            return wrkMast.getModiTime();
        }
@@ -309,6 +346,21 @@
        }
    }
    private void skipReport(WrkMast wrkMast) {
        Date now = new Date();
        wrkMast.setWrkSts(ERP_REPORT_FINISHED_WRK_STS);
        wrkMast.setLogMk(ERP_REPORT_SKIPPED_FLAG);
        wrkMast.setExpTime(0D);
        wrkMast.setLogErrMemo(null);
        wrkMast.setLogErrTime(null);
        wrkMast.setModiTime(now);
        if (!wrkMastService.updateById(wrkMast)) {
            throw new IllegalStateException("skip inbound erp report failed, workNo=" + wrkMast.getWrkNo());
        }
        // 兼容已进入 ERP 待上报的旧任务:跳过 ERP 后补一次 MQTT 完工入队,已有记录时 queueWorkCompletion 会直接返回。
        iotInstructionService.queueWorkCompletion(wrkMast);
    }
    private String truncate(String message, int maxLength) {
        if (message == null || message.length() <= maxLength) {
            return message;