| | |
| | | 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; |
| | |
| | | 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"; |
| | | /** 经销商退货质检审批流程定义标识 */ |
| | |
| | | |
| | | @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()); |
| | |
| | | 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 |
| | |
| | | .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)); |
| | |
| | | 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); |
| | |
| | | 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) { |