云
昨天 d80fa460742ddf052844746482801de355e85528
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
@@ -12,9 +12,11 @@
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedReturnQualitySubmitReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
import cn.iocoder.yudao.module.mes.framework.qrcode.MesTraceCodeUtils;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesDO;
@@ -78,8 +80,10 @@
    private static final int QC_LINE_PROCESS = 1, QC_LINE_SALES = 2;
    /** 业务类型:1 生产入库质检;2 经销商退货质检 */
    private static final int BIZ_TYPE_PRODUCTION = 1, BIZ_TYPE_RETURN = 2;
    /** 本线领导审批流程定义标识 */
    /** 加工部领导审批流程定义标识 */
    private static final String LINE_PROCESS_KEY = "mes_seed_quality_line_approve";
    /** 销售部领导审批流程定义标识 */
    private static final String SALES_LINE_PROCESS_KEY = "mes_seed_quality_sales_line_approve";
    /** 公司质检审批流程定义标识 */
    private static final String COMPANY_PROCESS_KEY = "mes_seed_quality_company_approve";
    /** 经销商退货质检审批流程定义标识 */
@@ -194,7 +198,7 @@
    @Override
    public Map<String, Object> resolveScan(String code) {
        MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(code);
        MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(MesTraceCodeUtils.extractCode(code));
        if (bag == null) throw new IllegalArgumentException("未解析到有效袋码,请扫描袋码");
        Map<String, Object> result = new HashMap<>();
        result.put("code", bag.getCode());
@@ -227,28 +231,66 @@
        return result;
    }
    private record Scope(String code, String businessCode, String batchCode, boolean canceled, List<MesProBagCodeDO> bags) { }
    private record Scope(String type, String code, String businessCode, String batchCode, boolean canceled, List<MesProBagCodeDO> bags) { }
    /** 扫码类型:由码值自动识别袋码 / 托盘码 / 生产批次码 */
    private static final String SCAN_TYPE_AUTO = "AUTO";
    private Scope scope(String code, String type, boolean lock) {
        // 标签二维码内容可能是整段追溯链接,先拆解为纯码值再匹配
        code = MesTraceCodeUtils.extractCode(code);
        if (StrUtil.isBlank(type) || SCAN_TYPE_AUTO.equalsIgnoreCase(type)) {
            return autoScope(code, lock);
        }
        if ("BAG".equals(type)) {
            MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(code);
            if (bag == null) throw invalidParamException("未找到袋码,请核对扫码类型和码值");
            return new Scope(bag.getCode(), bag.getBusinessCode(), bag.getBatchCode(), Integer.valueOf(30).equals(bag.getStatus()), List.of(bag));
            return bagScope(bag);
        }
        if ("PALLET".equals(type)) {
            var pallet = lock ? palletMapper.selectByScanCodeForUpdate(code) : palletMapper.selectByScanCode(code);
            if (pallet == null) throw invalidParamException("未找到托盘码,请核对扫码类型和码值");
            if (pallet.getBatchId() == null) throw invalidParamException("托盘尚未绑定生产批次,无法质检");
            return new Scope(StrUtil.blankToDefault(pallet.getCode(), pallet.getTempCode()), pallet.getBusinessCode(), pallet.getBatchCode(),
                    Integer.valueOf(20).equals(pallet.getStatus()), lock ? bagCodeMapper.selectListByPalletIdForUpdate(pallet.getId()) : bagCodeMapper.selectListByPalletId(pallet.getId()));
            return palletScope(pallet, lock);
        }
        if ("BATCH".equals(type)) {
            var batch = lock ? batchMapper.selectByScanCodeForUpdate(code) : batchMapper.selectByScanCode(code);
            if (batch == null) throw invalidParamException("未找到生产批次码,请核对扫码类型和码值");
            return new Scope(StrUtil.blankToDefault(batch.getCode(), batch.getTempCode()), batch.getBusinessCode(), batch.getCode(),
                    Integer.valueOf(40).equals(batch.getStatus()), lock ? bagCodeMapper.selectListByBatchIdForUpdate(batch.getId()) : bagCodeMapper.selectListByBatchId(batch.getId()));
            return batchScope(batch, lock);
        }
        throw invalidParamException("不支持的质检扫码类型");
    }
    /** 与扫码绑定托盘一致:按码值自动识别类型,依次尝试袋码、托盘码、生产批次码 */
    private Scope autoScope(String code, boolean lock) {
        MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(code);
        if (bag != null) {
            return bagScope(bag);
        }
        var pallet = lock ? palletMapper.selectByScanCodeForUpdate(code) : palletMapper.selectByScanCode(code);
        if (pallet != null) {
            return palletScope(pallet, lock);
        }
        var batch = lock ? batchMapper.selectByScanCodeForUpdate(code) : batchMapper.selectByScanCode(code);
        if (batch != null) {
            return batchScope(batch, lock);
        }
        throw invalidParamException("未找到对应的袋码、托盘码或生产批次码,请核对码值");
    }
    private Scope bagScope(MesProBagCodeDO bag) {
        return new Scope("BAG", bag.getCode(), bag.getBusinessCode(), bag.getBatchCode(),
                Integer.valueOf(30).equals(bag.getStatus()), List.of(bag));
    }
    private Scope palletScope(MesProPalletDO pallet, boolean lock) {
        if (pallet.getBatchId() == null) throw invalidParamException("托盘尚未绑定生产批次,无法质检");
        return new Scope("PALLET", StrUtil.blankToDefault(pallet.getCode(), pallet.getTempCode()), pallet.getBusinessCode(), pallet.getBatchCode(),
                Integer.valueOf(20).equals(pallet.getStatus()), lock ? bagCodeMapper.selectListByPalletIdForUpdate(pallet.getId()) : bagCodeMapper.selectListByPalletId(pallet.getId()));
    }
    private Scope batchScope(MesProBatchDO batch, boolean lock) {
        return new Scope("BATCH", StrUtil.blankToDefault(batch.getCode(), batch.getTempCode()), batch.getBusinessCode(), batch.getCode(),
                Integer.valueOf(40).equals(batch.getStatus()), lock ? bagCodeMapper.selectListByBatchIdForUpdate(batch.getId()) : bagCodeMapper.selectListByBatchId(batch.getId()));
    }
    @Override
@@ -266,7 +308,8 @@
                .filter(q -> !isReturnQuality(q))
                .map(MesQcSeedQualityDO::getCode).collect(java.util.stream.Collectors.toSet());
        Map<String, Object> result = new HashMap<>();
        result.put("scanType", scanType); result.put("code", scope.code()); result.put("businessCode", scope.businessCode());
        // 自动识别时回传实际码类型,前端据此展示对象类型并用于提交
        result.put("scanType", scope.type()); result.put("code", scope.code()); result.put("businessCode", scope.businessCode());
        result.put("batchCode", scope.batchCode()); result.put("canceled", scope.canceled());
        result.put("totalCount", effective.size());
        result.put("inbound", !effective.isEmpty() && effective.stream().allMatch(b -> b.getInboundEventId() != null));
@@ -278,7 +321,7 @@
        result.put("itemCode", item == null ? null : item.getCode());
        result.put("itemName", item == null ? null : item.getName());
        result.put("indicators", toRangePayload(itemId));
        if ("BAG".equals(scanType)) {
        if ("BAG".equals(scope.type())) {
            List<MesQcSeedQualityDO> qualities = qualityMapper.selectListByCode(scope.code());
            MesQcSeedQualityDO quality = qualities.stream()
                    .filter(q -> !isReturnQuality(q)).findFirst().orElse(null);
@@ -1076,9 +1119,11 @@
        Map<String, Object> variables = new HashMap<>();
        variables.put("qcLine", qcLine);
        variables.put("batchCode", batchCode);
        String processDefinitionKey = Objects.equals(qcLine, QC_LINE_SALES)
                ? SALES_LINE_PROCESS_KEY : LINE_PROCESS_KEY;
        String processInstanceId = processInstanceApi.createProcessInstance(operatorId,
                new BpmProcessInstanceCreateReqDTO()
                        .setProcessDefinitionKey(LINE_PROCESS_KEY)
                        .setProcessDefinitionKey(processDefinitionKey)
                        .setBusinessKey(qcLine + "#" + batchCode)
                        .setVariables(variables));
        for (MesQcSeedQualityDO quality : pending) {