liu
昨天 4ca4444ad33a2a1a51f5c06e78ee9365dfb1eed6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
@@ -6,6 +6,7 @@
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO;
import cn.iocoder.yudao.module.mes.controller.pub.trace.vo.MesProTracePublicConfigRespVO;
import cn.iocoder.yudao.module.mes.controller.pub.trace.vo.MesProTracePublicRespVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
@@ -18,6 +19,9 @@
import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeStatusEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchWorkerTypeEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum;
import cn.iocoder.yudao.module.mes.enums.trace.MesTraceCodeStatusEnum;
import cn.iocoder.yudao.module.mes.framework.qrcode.MesProQrLabelBuilder;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.pro.bagcode.MesProBagCodeService;
import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService;
@@ -112,8 +116,8 @@
            if (entry.batchId == null && entry.bagItemId == null) {
                throw exception(MES_TRACE_CODE_NOT_FOUND);
            }
            // 2. 聚合全程信息
            MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry.sourceType, entry.batchId, entry.bagItemId);
            // 2. 聚合全程信息(作废码仍正常返回并记录扫码:作废码被扫是重要的防伪信号,不应记为查询失败)
            MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry);
            recordConsumerScan(rawCode, traceCode, entry.sourceType, entry.batchId, true);
            return result;
        } catch (RuntimeException ex) {
@@ -121,6 +125,15 @@
                    entry == null ? null : entry.batchId, false);
            throw ex;
        }
    }
    @Override
    public MesProTracePublicConfigRespVO getPublicConfig() {
        MesProTracePublicConfigRespVO respVO = new MesProTracePublicConfigRespVO();
        respVO.setOperatorName(MesProQrLabelBuilder.resolveOperatorName());
        respVO.setTraceUrl(MesProQrLabelBuilder.resolveTraceUrl());
        respVO.setImported(MesProQrLabelBuilder.isImported());
        return respVO;
    }
    /**
@@ -173,7 +186,13 @@
        // ① 袋码
        MesProBagCodeDO bag = bagCodeService.getBagCodeByCode(traceCode);
        if (bag != null) {
            return new TraceEntry("BAG", bag.getBatchId(), bag.getItemId());
            // 已作废的袋码(破损替换后作废)必须对外失效:国标要求二维码不得重复使用,
            // 若作废码仍返回有效溯源信息,作废码即可被冒用销售
            if (MesProBagCodeStatusEnum.CANCELED.getStatus().equals(bag.getStatus())) {
                return new TraceEntry("BAG", bag.getBatchId(), bag.getItemId(),
                        MesTraceCodeStatusEnum.CANCELED.getStatus());
            }
            return TraceEntry.valid("BAG", bag.getBatchId(), bag.getItemId());
        }
        // ② 托盘码
        MesProPalletDO pallet = palletService.getPalletByCode(traceCode);
@@ -181,19 +200,30 @@
            // 未录入批次的托盘取托盘内任一袋码品种,保证仍能展示品种信息
            Long itemId = pallet.getBatchId() == null
                    ? firstItemId(bagCodeService.getBagCodeListByPalletId(pallet.getId())) : null;
            return new TraceEntry("PALLET", pallet.getBatchId(), itemId);
            if (MesProPalletStatusEnum.CANCELED.getStatus().equals(pallet.getStatus())) {
                return new TraceEntry("PALLET", pallet.getBatchId(), itemId,
                        MesTraceCodeStatusEnum.CANCELED.getStatus());
            }
            return TraceEntry.valid("PALLET", pallet.getBatchId(), itemId);
        }
        // ③ 批次码(含临时批次码,getBatchByCode 内部兼容)
        MesProBatchDO batch = batchService.getBatchByCode(traceCode);
        if (batch != null) {
            return new TraceEntry("BATCH", batch.getId(), null);
            if (MesProBatchStatusEnum.CANCELED.getStatus().equals(batch.getStatus())) {
                return new TraceEntry("BATCH", batch.getId(), null,
                        MesTraceCodeStatusEnum.CANCELED.getStatus());
        }
        return new TraceEntry("", null, null);
            return TraceEntry.valid("BATCH", batch.getId(), null);
        }
        return new TraceEntry("", null, null, MesTraceCodeStatusEnum.VALID.getStatus());
    }
    // ==================== 聚合构建 ====================
    private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, String sourceType, Long batchId, Long bagItemId) {
    private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, TraceEntry entry) {
        String sourceType = entry.sourceType();
        Long batchId = entry.batchId();
        Long bagItemId = entry.bagItemId();
        MesProBatchDO batch = batchId == null ? null : batchService.getBatch(batchId);
        if (batchId != null && batch == null) {
            throw exception(MES_TRACE_CODE_NOT_FOUND);
@@ -201,6 +231,10 @@
        MesProTracePublicRespVO resp = new MesProTracePublicRespVO();
        resp.setSourceType(sourceType);
        resp.setRequestCode(requestCode);
        // 追溯码有效性 + 标签四要素中的生产经营者与追溯网址,保证与标签印刷内容一致
        resp.setCodeStatus(entry.codeStatus());
        resp.setOperatorName(MesProQrLabelBuilder.resolveOperatorName());
        resp.setTraceUrl(MesProQrLabelBuilder.resolveTraceUrl());
        // 品种区块
        fillItem(resp, batch, bagItemId);
        if (batch == null) {
@@ -505,7 +539,20 @@
        };
    }
    private record TraceEntry(String sourceType, Long batchId, Long bagItemId) {
    /**
     * 追溯入口解析结果
     *
     * @param sourceType 入口类型:BAG / PALLET / BATCH,未匹配到时为空串
     * @param batchId    生产批次编号
     * @param bagItemId  袋码绑定的品种编号(未录批次时用于展示品种)
     * @param codeStatus 追溯码有效性:{@link MesTraceCodeStatusEnum#VALID} / {@link MesTraceCodeStatusEnum#CANCELED}
     */
    private record TraceEntry(String sourceType, Long batchId, Long bagItemId, String codeStatus) {
        static TraceEntry valid(String sourceType, Long batchId, Long bagItemId) {
            return new TraceEntry(sourceType, batchId, bagItemId, MesTraceCodeStatusEnum.VALID.getStatus());
        }
    }
}