| | |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPageReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemBatchConfigDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.batch.MesWmBatchMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService; |
| | | import cn.iocoder.yudao.module.mdm.api.item.MdmItemBatchConfigApi; |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemBatchConfigRespDTO; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | private MesWmBatchMapper batchMapper; |
| | | |
| | | @Resource |
| | | private MesMdItemService itemService; |
| | | private MesMdmItemService mdmItemService; |
| | | @Resource |
| | | private MesMdItemBatchConfigService itemBatchConfigService; |
| | | private MdmItemBatchConfigApi itemBatchConfigApi; |
| | | @Resource |
| | | private MesMdAutoCodeRecordService autoCodeRecordService; |
| | | @Resource |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MesWmBatchDO getOrGenerateBatchCode(MesWmBatchGenerateReqVO reqVO) { |
| | | // 1.1 查询物料信息,检查是否启用批次管理 |
| | | MesMdItemDO item = itemService.validateItemExists(reqVO.getItemId()); |
| | | if (Boolean.FALSE.equals(item.getBatchFlag())) { |
| | | MesMdmItemDO item = mdmItemService.validateItemExists(reqVO.getItemId()); |
| | | if (Boolean.FALSE.equals(item.getIsBatchManaged())) { |
| | | // 未启用批次管理,返回 null |
| | | return null; |
| | | } |
| | | // 1.2 查询物料批次配置 |
| | | MesMdItemBatchConfigDO config = itemBatchConfigService.validateItemBatchConfigExists(reqVO.getItemId()); |
| | | |
| | | // 调试日志:打印接收到的日期 |
| | | log.info("[getOrGenerateBatchCode] 收到请求, itemId={}, batchCode={}, produceDate={}", |
| | | reqVO.getItemId(), reqVO.getBatchCode(), reqVO.getProduceDate()); |
| | | |
| | | // 1.2 查询物料批次配置(从 MDM 获取,不存在则使用默认配置) |
| | | MdmItemBatchConfigRespDTO config = itemBatchConfigApi.getItemBatchConfig(reqVO.getItemId()); |
| | | |
| | | // 2. 根据配置校验必填参数并清空不需要的参数 |
| | | MesWmBatchDO batch = MesWmBatchDO.builder().itemId(reqVO.getItemId()).build(); |
| | | // 生产日期 |
| | | if (Boolean.TRUE.equals(config.getProduceDateFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getProduceDate())) { |
| | | throw exception(WM_BATCH_PRODUCE_DATE_REQUIRED); |
| | | if (config != null) { |
| | | // 生产日期 |
| | | if (Boolean.TRUE.equals(config.getProduceDateFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getProduceDate())) { |
| | | throw exception(WM_BATCH_PRODUCE_DATE_REQUIRED); |
| | | } |
| | | batch.setProduceDate(reqVO.getProduceDate()); |
| | | } |
| | | batch.setProduceDate(reqVO.getProduceDate()); |
| | | // 入库日期 |
| | | if (Boolean.TRUE.equals(config.getReceiptDateFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getReceiptDate())) { |
| | | throw exception(WM_BATCH_RECEIPT_DATE_REQUIRED); |
| | | } |
| | | batch.setReceiptDate(reqVO.getReceiptDate()); |
| | | } |
| | | // 有效期 |
| | | if (Boolean.TRUE.equals(config.getExpireDateFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getExpireDate())) { |
| | | throw exception(WM_BATCH_EXPIRE_DATE_REQUIRED); |
| | | } |
| | | batch.setExpireDate(reqVO.getExpireDate()); |
| | | } |
| | | // 供应商 |
| | | if (Boolean.TRUE.equals(config.getVendorFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getVendorId())) { |
| | | throw exception(WM_BATCH_VENDOR_REQUIRED); |
| | | } |
| | | batch.setVendorId(reqVO.getVendorId()); |
| | | } |
| | | // 客户 |
| | | if (Boolean.TRUE.equals(config.getClientFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getClientId())) { |
| | | throw exception(WM_BATCH_CLIENT_REQUIRED); |
| | | } |
| | | batch.setClientId(reqVO.getClientId()); |
| | | } |
| | | // 采购订单编号 |
| | | if (Boolean.TRUE.equals(config.getPurchaseOrderCodeFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getPurchaseOrderCode())) { |
| | | throw exception(WM_BATCH_PURCHASE_ORDER_CODE_REQUIRED); |
| | | } |
| | | batch.setPurchaseOrderCode(reqVO.getPurchaseOrderCode()); |
| | | } |
| | | // 销售订单编号 |
| | | if (Boolean.TRUE.equals(config.getSalesOrderCodeFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getSalesOrderCode())) { |
| | | throw exception(WM_BATCH_CUSTOMER_ORDER_CODE_REQUIRED); |
| | | } |
| | | batch.setSalesOrderCode(reqVO.getSalesOrderCode()); |
| | | } |
| | | // 生产工单 |
| | | if (Boolean.TRUE.equals(config.getWorkOrderFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getWorkOrderId())) { |
| | | throw exception(WM_BATCH_WORK_ORDER_REQUIRED); |
| | | } |
| | | batch.setWorkOrderId(reqVO.getWorkOrderId()); |
| | | } |
| | | // 生产任务 |
| | | if (Boolean.TRUE.equals(config.getTaskFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getTaskId())) { |
| | | throw exception(WM_BATCH_TASK_REQUIRED); |
| | | } |
| | | batch.setTaskId(reqVO.getTaskId()); |
| | | } |
| | | // 工作站 |
| | | if (Boolean.TRUE.equals(config.getWorkstationFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getWorkstationId())) { |
| | | throw exception(WM_BATCH_WORKSTATION_REQUIRED); |
| | | } |
| | | batch.setWorkstationId(reqVO.getWorkstationId()); |
| | | } |
| | | // 工具 |
| | | if (Boolean.TRUE.equals(config.getToolFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getToolId())) { |
| | | throw exception(WM_BATCH_TOOL_REQUIRED); |
| | | } |
| | | batch.setToolId(reqVO.getToolId()); |
| | | } |
| | | // 模具 |
| | | if (Boolean.TRUE.equals(config.getMoldFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getMoldId())) { |
| | | throw exception(WM_BATCH_MOLD_REQUIRED); |
| | | } |
| | | batch.setMoldId(reqVO.getMoldId()); |
| | | } |
| | | // 生产批号 |
| | | if (Boolean.TRUE.equals(config.getLotNumberFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getLotNumber())) { |
| | | throw exception(WM_BATCH_LOT_NUMBER_REQUIRED); |
| | | } |
| | | batch.setLotNumber(reqVO.getLotNumber()); |
| | | } |
| | | // 质量状态 |
| | | if (Boolean.TRUE.equals(config.getQualityStatusFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getQualityStatus())) { |
| | | throw exception(WM_BATCH_QUALITY_STATUS_REQUIRED); |
| | | } |
| | | batch.setQualityStatus(reqVO.getQualityStatus()); |
| | | } |
| | | } |
| | | // 入库日期 |
| | | if (Boolean.TRUE.equals(config.getReceiptDateFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getReceiptDate())) { |
| | | throw exception(WM_BATCH_RECEIPT_DATE_REQUIRED); |
| | | // 无批次配置时,使用传入的参数(宽松模式,适用于自定义入库等场景) |
| | | else { |
| | | if (reqVO.getProduceDate() != null) { |
| | | batch.setProduceDate(reqVO.getProduceDate()); |
| | | } |
| | | batch.setReceiptDate(reqVO.getReceiptDate()); |
| | | } |
| | | // 有效期 |
| | | if (Boolean.TRUE.equals(config.getExpireDateFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getExpireDate())) { |
| | | throw exception(WM_BATCH_EXPIRE_DATE_REQUIRED); |
| | | if (reqVO.getReceiptDate() != null) { |
| | | batch.setReceiptDate(reqVO.getReceiptDate()); |
| | | } |
| | | batch.setExpireDate(reqVO.getExpireDate()); |
| | | } |
| | | // 供应商 |
| | | if (Boolean.TRUE.equals(config.getVendorFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getVendorId())) { |
| | | throw exception(WM_BATCH_VENDOR_REQUIRED); |
| | | if (reqVO.getExpireDate() != null) { |
| | | batch.setExpireDate(reqVO.getExpireDate()); |
| | | } |
| | | batch.setVendorId(reqVO.getVendorId()); |
| | | } |
| | | // 客户 |
| | | if (Boolean.TRUE.equals(config.getClientFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getClientId())) { |
| | | throw exception(WM_BATCH_CLIENT_REQUIRED); |
| | | if (reqVO.getVendorId() != null) { |
| | | batch.setVendorId(reqVO.getVendorId()); |
| | | } |
| | | batch.setClientId(reqVO.getClientId()); |
| | | } |
| | | // 采购订单编号 |
| | | if (Boolean.TRUE.equals(config.getPurchaseOrderCodeFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getPurchaseOrderCode())) { |
| | | throw exception(WM_BATCH_PURCHASE_ORDER_CODE_REQUIRED); |
| | | if (reqVO.getClientId() != null) { |
| | | batch.setClientId(reqVO.getClientId()); |
| | | } |
| | | batch.setPurchaseOrderCode(reqVO.getPurchaseOrderCode()); |
| | | } |
| | | // 销售订单编号 |
| | | if (Boolean.TRUE.equals(config.getSalesOrderCodeFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getSalesOrderCode())) { |
| | | throw exception(WM_BATCH_CUSTOMER_ORDER_CODE_REQUIRED); |
| | | } |
| | | batch.setSalesOrderCode(reqVO.getSalesOrderCode()); |
| | | } |
| | | // 生产工单 |
| | | if (Boolean.TRUE.equals(config.getWorkOrderFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getWorkOrderId())) { |
| | | throw exception(WM_BATCH_WORK_ORDER_REQUIRED); |
| | | } |
| | | batch.setWorkOrderId(reqVO.getWorkOrderId()); |
| | | } |
| | | // 生产任务 |
| | | if (Boolean.TRUE.equals(config.getTaskFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getTaskId())) { |
| | | throw exception(WM_BATCH_TASK_REQUIRED); |
| | | } |
| | | batch.setTaskId(reqVO.getTaskId()); |
| | | } |
| | | // 工作站 |
| | | if (Boolean.TRUE.equals(config.getWorkstationFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getWorkstationId())) { |
| | | throw exception(WM_BATCH_WORKSTATION_REQUIRED); |
| | | } |
| | | batch.setWorkstationId(reqVO.getWorkstationId()); |
| | | } |
| | | // 工具 |
| | | if (Boolean.TRUE.equals(config.getToolFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getToolId())) { |
| | | throw exception(WM_BATCH_TOOL_REQUIRED); |
| | | } |
| | | batch.setToolId(reqVO.getToolId()); |
| | | } |
| | | // 模具 |
| | | if (Boolean.TRUE.equals(config.getMoldFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getMoldId())) { |
| | | throw exception(WM_BATCH_MOLD_REQUIRED); |
| | | } |
| | | batch.setMoldId(reqVO.getMoldId()); |
| | | } |
| | | // 生产批号 |
| | | if (Boolean.TRUE.equals(config.getLotNumberFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getLotNumber())) { |
| | | throw exception(WM_BATCH_LOT_NUMBER_REQUIRED); |
| | | } |
| | | batch.setLotNumber(reqVO.getLotNumber()); |
| | | } |
| | | // 质量状态 |
| | | if (Boolean.TRUE.equals(config.getQualityStatusFlag())) { |
| | | if (ObjUtil.isNull(reqVO.getQualityStatus())) { |
| | | throw exception(WM_BATCH_QUALITY_STATUS_REQUIRED); |
| | | } |
| | | batch.setQualityStatus(reqVO.getQualityStatus()); |
| | | } |
| | | |
| | | // 3.1 情况一:查询是否存在匹配的批次 |
| | | MesWmBatchDO existingBatch = batchMapper.selectFirst(batch); |
| | | if (existingBatch != null) { |
| | | return existingBatch; |
| | | // 3.1 情况一:传入了 batchCode,查询是否存在该批次号 |
| | | if (StrUtil.isNotBlank(reqVO.getBatchCode())) { |
| | | MesWmBatchDO existingBatch = batchMapper.selectByCode(reqVO.getBatchCode()); |
| | | if (existingBatch != null) { |
| | | // 校验物料是否匹配 |
| | | if (!existingBatch.getItemId().equals(reqVO.getItemId())) { |
| | | throw exception(WM_BATCH_ITEM_MISMATCH); |
| | | } |
| | | // 更新批次属性(仅更新传入的非空值) |
| | | updateBatchProperties(existingBatch, batch); |
| | | return existingBatch; |
| | | } |
| | | // 不存在则使用传入的 batchCode 创建新批次 |
| | | batch.setCode(reqVO.getBatchCode()); |
| | | } else { |
| | | // 3.2 情况二:查询是否存在匹配的批次(根据属性匹配) |
| | | MesWmBatchDO existingBatch = batchMapper.selectFirst(batch); |
| | | if (existingBatch != null) { |
| | | return existingBatch; |
| | | } |
| | | // 3.3 情况三:自动生成新批次号 |
| | | String batchCode = autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.WM_BATCH_CODE.getCode()); |
| | | batch.setCode(batchCode); |
| | | } |
| | | |
| | | // 3.2 情况二:生成新批次 |
| | | String batchCode = autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.WM_BATCH_CODE.getCode()); |
| | | batch.setCode(batchCode); |
| | | batchMapper.insert(batch); |
| | | |
| | | // 4. 生成条码 |
| | |
| | | return batch; |
| | | } |
| | | |
| | | /** |
| | | * 更新已有批次的属性(仅更新传入的非空值) |
| | | * |
| | | * @param existingBatch 已有批次 |
| | | * @param newBatch 新批次属性 |
| | | */ |
| | | private void updateBatchProperties(MesWmBatchDO existingBatch, MesWmBatchDO newBatch) { |
| | | boolean needUpdate = false; |
| | | if (newBatch.getProduceDate() != null && !newBatch.getProduceDate().equals(existingBatch.getProduceDate())) { |
| | | existingBatch.setProduceDate(newBatch.getProduceDate()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getExpireDate() != null && !newBatch.getExpireDate().equals(existingBatch.getExpireDate())) { |
| | | existingBatch.setExpireDate(newBatch.getExpireDate()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getReceiptDate() != null && !newBatch.getReceiptDate().equals(existingBatch.getReceiptDate())) { |
| | | existingBatch.setReceiptDate(newBatch.getReceiptDate()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getVendorId() != null && !newBatch.getVendorId().equals(existingBatch.getVendorId())) { |
| | | existingBatch.setVendorId(newBatch.getVendorId()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getClientId() != null && !newBatch.getClientId().equals(existingBatch.getClientId())) { |
| | | existingBatch.setClientId(newBatch.getClientId()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getSalesOrderCode() != null && !newBatch.getSalesOrderCode().equals(existingBatch.getSalesOrderCode())) { |
| | | existingBatch.setSalesOrderCode(newBatch.getSalesOrderCode()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getPurchaseOrderCode() != null && !newBatch.getPurchaseOrderCode().equals(existingBatch.getPurchaseOrderCode())) { |
| | | existingBatch.setPurchaseOrderCode(newBatch.getPurchaseOrderCode()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getWorkOrderId() != null && !newBatch.getWorkOrderId().equals(existingBatch.getWorkOrderId())) { |
| | | existingBatch.setWorkOrderId(newBatch.getWorkOrderId()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getTaskId() != null && !newBatch.getTaskId().equals(existingBatch.getTaskId())) { |
| | | existingBatch.setTaskId(newBatch.getTaskId()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getWorkstationId() != null && !newBatch.getWorkstationId().equals(existingBatch.getWorkstationId())) { |
| | | existingBatch.setWorkstationId(newBatch.getWorkstationId()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getToolId() != null && !newBatch.getToolId().equals(existingBatch.getToolId())) { |
| | | existingBatch.setToolId(newBatch.getToolId()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getMoldId() != null && !newBatch.getMoldId().equals(existingBatch.getMoldId())) { |
| | | existingBatch.setMoldId(newBatch.getMoldId()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getLotNumber() != null && !newBatch.getLotNumber().equals(existingBatch.getLotNumber())) { |
| | | existingBatch.setLotNumber(newBatch.getLotNumber()); |
| | | needUpdate = true; |
| | | } |
| | | if (newBatch.getQualityStatus() != null && !newBatch.getQualityStatus().equals(existingBatch.getQualityStatus())) { |
| | | existingBatch.setQualityStatus(newBatch.getQualityStatus()); |
| | | needUpdate = true; |
| | | } |
| | | if (needUpdate) { |
| | | batchMapper.updateById(existingBatch); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public List<MesWmBatchDO> getForwardBatchList(String code) { |
| | | return getForwardBatchList(code, new HashSet<>(), 0); |