From eb566426396a052423527b418079cc22b8acb924 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 13 Mar 2026 23:55:24 +0800 Subject: [PATCH] ✨ feat(mes): 添加批次管理功能,支持批次生成与获取 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchGenerateReqVO.java | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/MesWmItemReceiptSaveReqVO.java | 2 +- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/line/MesWmItemReceiptLineRespVO.java | 3 +++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdItemBatchConfigDO.java | 2 +- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptLineDO.java | 9 ++++++++- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 16 ++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java | 3 ++- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigService.java | 8 ++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigServiceImpl.java | 10 ++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java | 2 +- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java | 23 +++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptLineServiceImpl.java | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- 15 files changed, 617 insertions(+), 18 deletions(-) create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchGenerateReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchGenerateReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchGenerateReqVO.java new file mode 100644 index 0000000..072050f --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchGenerateReqVO.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo; + +import lombok.Data; + +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; + +/** + * 批次生成请求 VO + * + * @author 芋道源码 + */ +@Data +public class MesWmBatchGenerateReqVO { + + /** + * 物料ID + */ + @NotNull(message = "物料 ID 不能为空") + private Long itemId; + + /** + * 生产日期 + */ + private LocalDateTime produceDate; + /** + * 有效期 + */ + private LocalDateTime expireDate; + /** + * 入库日期 + */ + private LocalDateTime receiptDate; + + /** + * 供应商 ID + */ + private Long vendorId; + /** + * 客户 ID + */ + private Long clientId; + + /** + * 采购订单编号 + */ + private String purchaseOrderCode; + /** + * 销售订单编号 + */ + private String salesOrderCode; + + /** + * 生产工单 ID + */ + private Long workOrderId; + /** + * 生产任务 ID + */ + private Long taskId; + /** + * 工作站 ID + */ + private Long workstationId; + /** + * 工具 ID + */ + private Long toolId; + /** + * 模具 ID + */ + private Long moldId; + + /** + * 生产批号 + */ + private String lotNumber; + /** + * 质量状态 + */ + private String qualityStatus; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/MesWmItemReceiptSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/MesWmItemReceiptSaveReqVO.java index 91415b5..a85aee9 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/MesWmItemReceiptSaveReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/MesWmItemReceiptSaveReqVO.java @@ -39,4 +39,4 @@ public class MesWmItemReceiptSaveReqVO { @Schema(description = "备注", example = "备注") private String remark; - } +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/line/MesWmItemReceiptLineRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/line/MesWmItemReceiptLineRespVO.java index 13bad17..38c2ccf 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/line/MesWmItemReceiptLineRespVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/line/MesWmItemReceiptLineRespVO.java @@ -40,6 +40,9 @@ public class MesWmItemReceiptLineRespVO { @Schema(description = "批次编号", example = "1") private Long batchId; + @Schema(description = "批次编码", example = "BATCH20260110") + private String batchCode; + @Schema(description = "生产日期") private LocalDateTime productionDate; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdItemBatchConfigDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdItemBatchConfigDO.java index 4ee9b0c..1096883 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdItemBatchConfigDO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdItemBatchConfigDO.java @@ -63,7 +63,7 @@ public class MesMdItemBatchConfigDO extends BaseDO { /** * 批次属性-生产工单 */ - private Boolean workorderFlag; + private Boolean workOrderFlag; /** * 批次属性-生产任务 */ diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java new file mode 100644 index 0000000..9fe973d --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java @@ -0,0 +1,122 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 批次管理 DO + * + * @author 芋道源码 + */ +@TableName("mes_wm_batch") +@KeySequence("mes_wm_batch_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesWmBatchDO extends BaseDO { + + /** + * 批次ID + */ + @TableId + private Long id; + /** + * 批次编码 + */ + private String code; + /** + * 物料ID + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long itemId; + /** + * 生产日期 + */ + private LocalDateTime produceDate; + /** + * 有效期 + */ + private LocalDateTime expireDate; + /** + * 入库日期 + */ + private LocalDateTime receiptDate; + /** + * 供应商ID + * + * 关联 {@link MesMdVendorDO#getId()} + */ + private Long vendorId; + /** + * 客户ID + * + * 关联 {@link MesMdClientDO#getId()} + */ + private Long clientId; + + /** + * 销售订单编号 + */ + private String salesOrderCode; + /** + * 采购订单编号 + */ + private String purchaseOrderCode; + /** + * 生产工单ID + * + * 关联 {@link MesProWorkOrderDO#getId()} + */ + private Long workOrderId; + /** + * 生产任务ID + * + * 关联 {@link MesProTaskDO#getId()} + */ + private Long taskId; + /** + * 工作站ID + * + * 关联 {@link MesMdWorkstationDO#getId()} + */ + private Long workstationId; + /** + * 工具ID + * + * 关联 {@link MesTmToolDO#getId()} + */ + private Long toolId; + /** + * 模具 ID + */ + private Long moldId; + /** + * 生产批号 + */ + private String lotNumber; + /** + * 质量状态 + */ + private String qualityStatus; + /** + * 备注 + */ + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptLineDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptLineDO.java index a29b9c7..1003432 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptLineDO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptLineDO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeLineDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -54,10 +55,16 @@ public class MesWmItemReceiptLineDO extends BaseDO { /** * 批次编号 * - * TODO DONE @芋艿:保留。待 mes_wm_batch 模块迁移后补充 @link 关联 + * 关联 {@link MesWmBatchDO#getId()} */ private Long batchId; /** + * 批次编码 + * + * 关联 {@link MesWmBatchDO#getCode()} + */ + private String batchCode; + /** * 生产日期 */ private LocalDateTime productionDate; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java new file mode 100644 index 0000000..d6a0cce --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.wm.batch; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; +import cn.hutool.core.util.ObjUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 批次管理 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesWmBatchMapper extends BaseMapperX { + + /** + * 根据参数查询匹配的第一条批次记录 + *

+ * 使用 NULL 值精确匹配,返回 ID 最小的批次 + * + * @param batch 批次参数 + * @return 匹配的批次记录 + */ + default MesWmBatchDO selectFirst(MesWmBatchDO batch) { + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(MesWmBatchDO::getItemId, batch.getItemId()); + if (ObjUtil.isNull(batch.getVendorId())) { + query.isNull(MesWmBatchDO::getVendorId); + } else { + query.eq(MesWmBatchDO::getVendorId, batch.getVendorId()); + } + if (ObjUtil.isNull(batch.getClientId())) { + query.isNull(MesWmBatchDO::getClientId); + } else { + query.eq(MesWmBatchDO::getClientId, batch.getClientId()); + } + if (ObjUtil.isNull(batch.getSalesOrderCode())) { + query.isNull(MesWmBatchDO::getSalesOrderCode); + } else { + query.eq(MesWmBatchDO::getSalesOrderCode, batch.getSalesOrderCode()); + } + if (ObjUtil.isNull(batch.getPurchaseOrderCode())) { + query.isNull(MesWmBatchDO::getPurchaseOrderCode); + } else { + query.eq(MesWmBatchDO::getPurchaseOrderCode, batch.getPurchaseOrderCode()); + } + if (ObjUtil.isNull(batch.getWorkOrderId())) { + query.isNull(MesWmBatchDO::getWorkOrderId); + } else { + query.eq(MesWmBatchDO::getWorkOrderId, batch.getWorkOrderId()); + } + if (ObjUtil.isNull(batch.getTaskId())) { + query.isNull(MesWmBatchDO::getTaskId); + } else { + query.eq(MesWmBatchDO::getTaskId, batch.getTaskId()); + } + if (ObjUtil.isNull(batch.getWorkstationId())) { + query.isNull(MesWmBatchDO::getWorkstationId); + } else { + query.eq(MesWmBatchDO::getWorkstationId, batch.getWorkstationId()); + } + if (ObjUtil.isNull(batch.getToolId())) { + query.isNull(MesWmBatchDO::getToolId); + } else { + query.eq(MesWmBatchDO::getToolId, batch.getToolId()); + } + if (ObjUtil.isNull(batch.getMoldId())) { + query.isNull(MesWmBatchDO::getMoldId); + } else { + query.eq(MesWmBatchDO::getMoldId, batch.getMoldId()); + } + if (ObjUtil.isNull(batch.getLotNumber())) { + query.isNull(MesWmBatchDO::getLotNumber); + } else { + query.eq(MesWmBatchDO::getLotNumber, batch.getLotNumber()); + } + if (ObjUtil.isNull(batch.getQualityStatus())) { + query.isNull(MesWmBatchDO::getQualityStatus); + } else { + query.eq(MesWmBatchDO::getQualityStatus, batch.getQualityStatus()); + } + if (ObjUtil.isNull(batch.getProduceDate())) { + query.isNull(MesWmBatchDO::getProduceDate); + } else { + query.eq(MesWmBatchDO::getProduceDate, batch.getProduceDate()); + } + if (ObjUtil.isNull(batch.getExpireDate())) { + query.isNull(MesWmBatchDO::getExpireDate); + } else { + query.eq(MesWmBatchDO::getExpireDate, batch.getExpireDate()); + } + if (ObjUtil.isNull(batch.getReceiptDate())) { + query.isNull(MesWmBatchDO::getReceiptDate); + } else { + query.eq(MesWmBatchDO::getReceiptDate, batch.getReceiptDate()); + } + + // 返回 ID 最小的批次 + query.orderByAsc(MesWmBatchDO::getId); + List list = selectList(query); + return CollUtil.getFirst(list); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index f3bbb74..2ad21be 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -35,6 +35,22 @@ public interface ErrorCodeConstants { ErrorCode MD_ITEM_BATCH_CONFIG_NOT_EXISTS = new ErrorCode(1_040_102_100, "物料批次属性配置不存在"); ErrorCode MD_ITEM_BATCH_CONFIG_AT_LEAST_ONE_FLAG = new ErrorCode(1_040_102_101, "批次管理已启用,至少需要配置一个批次属性"); + // ========== MES 仓库管理-批次管理(1-040-717-000) ========== + ErrorCode WM_BATCH_PRODUCE_DATE_REQUIRED = new ErrorCode(1_040_717_000, "批次配置要求生产日期不能为空"); + ErrorCode WM_BATCH_RECEIPT_DATE_REQUIRED = new ErrorCode(1_040_717_001, "批次配置要求入库日期不能为空"); + ErrorCode WM_BATCH_EXPIRE_DATE_REQUIRED = new ErrorCode(1_040_717_002, "批次配置要求有效期不能为空"); + ErrorCode WM_BATCH_VENDOR_REQUIRED = new ErrorCode(1_040_717_003, "批次配置要求供应商不能为空"); + ErrorCode WM_BATCH_CLIENT_REQUIRED = new ErrorCode(1_040_717_004, "批次配置要求客户不能为空"); + ErrorCode WM_BATCH_PURCHASE_ORDER_CODE_REQUIRED = new ErrorCode(1_040_717_005, "批次配置要求采购订单编号不能为空"); + ErrorCode WM_BATCH_CUSTOMER_ORDER_CODE_REQUIRED = new ErrorCode(1_040_717_006, "批次配置要求销售订单编号不能为空"); + ErrorCode WM_BATCH_WORK_ORDER_REQUIRED = new ErrorCode(1_040_717_007, "批次配置要求生产工单不能为空"); + ErrorCode WM_BATCH_TASK_REQUIRED = new ErrorCode(1_040_717_008, "批次配置要求生产任务不能为空"); + ErrorCode WM_BATCH_WORKSTATION_REQUIRED = new ErrorCode(1_040_717_009, "批次配置要求工作站不能为空"); + ErrorCode WM_BATCH_TOOL_REQUIRED = new ErrorCode(1_040_717_010, "批次配置要求工具不能为空"); + ErrorCode WM_BATCH_MOLD_REQUIRED = new ErrorCode(1_040_717_011, "批次配置要求模具不能为空"); + ErrorCode WM_BATCH_LOT_NUMBER_REQUIRED = new ErrorCode(1_040_717_012, "批次配置要求生产批号不能为空"); + ErrorCode WM_BATCH_QUALITY_STATUS_REQUIRED = new ErrorCode(1_040_717_013, "批次配置要求质量状态不能为空"); + // ========== MES 基础数据-客户(1-040-103-000) ========== ErrorCode MD_CLIENT_NOT_EXISTS = new ErrorCode(1_040_103_000, "客户不存在"); ErrorCode MD_CLIENT_CODE_DUPLICATE = new ErrorCode(1_040_103_001, "客户编码已存在"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java index bda17a7..c1bb864 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java @@ -13,7 +13,8 @@ import lombok.Getter; public enum MesMdAutoCodeRuleCodeEnum { SN_CODE("SN_CODE", "SN 码"), - PACKAGE_CODE("PACKAGE_CODE", "装箱单编码"); + PACKAGE_CODE("PACKAGE_CODE", "装箱单编码"), + BATCH_CODE("BATCH_CODE", "批次编码"); /** * 规则代码 diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigService.java index bf64742..39651f0 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigService.java @@ -20,6 +20,14 @@ public interface MesMdItemBatchConfigService { MesMdItemBatchConfigDO getItemBatchConfigByItemId(Long itemId); /** + * 校验物料批次配置存在 + * + * @param itemId 物料 ID + * @return 物料批次配置 + */ + MesMdItemBatchConfigDO validateItemBatchConfigExists(Long itemId); + + /** * 保存批次属性配置(新增或更新) * * @param saveReqVO 保存信息 diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigServiceImpl.java index e01d162..84010c6 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigServiceImpl.java @@ -10,6 +10,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_BATCH_CONFIG_NOT_EXISTS; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_NOT_EXISTS; /** @@ -34,6 +35,15 @@ public class MesMdItemBatchConfigServiceImpl implements MesMdItemBatchConfigServ } @Override + public MesMdItemBatchConfigDO validateItemBatchConfigExists(Long itemId) { + MesMdItemBatchConfigDO config = getItemBatchConfigByItemId(itemId); + if (config == null) { + throw exception(MD_ITEM_BATCH_CONFIG_NOT_EXISTS); + } + return config; + } + + @Override public Long saveItemBatchConfig(MesMdItemBatchConfigSaveReqVO saveReqVO) { // 1. 校验物料存在 if (itemService.getItem(saveReqVO.getItemId()) == null) { diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java index 77e9280..f0b0126 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java @@ -198,7 +198,7 @@ public class MesMdItemServiceImpl implements MesMdItemService { || Boolean.TRUE.equals(config.getClientFlag()) || Boolean.TRUE.equals(config.getSalesOrderCodeFlag()) || Boolean.TRUE.equals(config.getPurchaseOrderCodeFlag()) - || Boolean.TRUE.equals(config.getWorkorderFlag()) + || Boolean.TRUE.equals(config.getWorkOrderFlag()) || Boolean.TRUE.equals(config.getTaskFlag()) || Boolean.TRUE.equals(config.getWorkstationFlag()) || Boolean.TRUE.equals(config.getToolFlag()) diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java new file mode 100644 index 0000000..29da386 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.mes.service.wm.batch; + +import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; + +/** + * 批次管理 Service 接口 + * + * @author 芋道源码 + */ +public interface MesWmBatchService { + + /** + * 获取或生成批次编码 + *

+ * 根据物料批次配置,查询或生成批次记录 + * + * @param reqVO 批次参数(包含 itemId 及其他可选属性) + * @return 批次记录(如果物料未启用批次管理则返回 null) + */ + MesWmBatchDO getOrGenerateBatchCode(MesWmBatchGenerateReqVO reqVO); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java new file mode 100644 index 0000000..efbb90e --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java @@ -0,0 +1,174 @@ +package cn.iocoder.yudao.module.mes.service.wm.batch; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; +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.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.wm.barcode.MesWmBarcodeService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; + +/** + * 批次管理 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class MesWmBatchServiceImpl implements MesWmBatchService { + + @Resource + private MesWmBatchMapper batchMapper; + @Resource + private MesMdItemService itemService; + @Resource + private MesMdItemBatchConfigService itemBatchConfigService; + @Resource + private MesMdAutoCodeRecordService autoCodeRecordService; + @Resource + private MesWmBarcodeService barcodeService; + + @Override + @Transactional(rollbackFor = Exception.class) + public MesWmBatchDO getOrGenerateBatchCode(MesWmBatchGenerateReqVO reqVO) { + // 1.1 查询物料信息,检查是否启用批次管理 + MesMdItemDO item = itemService.validateItemExists(reqVO.getItemId()); + if (Boolean.FALSE.equals(item.getBatchFlag())) { + // 未启用批次管理,返回 null + return null; + } + // 1.2 查询物料批次配置 + MesMdItemBatchConfigDO config = itemBatchConfigService.validateItemBatchConfigExists(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); + } + 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()); + } + + // 3.1 情况一:查询是否存在匹配的批次 + MesWmBatchDO existingBatch = batchMapper.selectFirst(batch); + if (existingBatch != null) { + return existingBatch; + } + + // 3.2 情况二:生成新批次 + String batchCode = autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.BATCH_CODE.getCode()); + batch.setCode(batchCode); + batchMapper.insert(batch); + + // 4. 生成条码 + barcodeService.autoGenerateBarcode(MesBizTypeConstants.WM_BATCH, batch.getId(), batch.getCode(), item.getName()); + return batch; + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptLineServiceImpl.java index c290fc4..a7889d4 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptLineServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptLineServiceImpl.java @@ -2,12 +2,17 @@ package cn.iocoder.yudao.module.mes.service.wm.itemreceipt; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.line.MesWmItemReceiptLinePageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.line.MesWmItemReceiptLineSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptLineDO; import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemreceipt.MesWmItemReceiptLineMapper; import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeLineService; +import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeService; +import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -32,43 +37,55 @@ public class MesWmItemReceiptLineServiceImpl implements MesWmItemReceiptLineServ @Resource @Lazy private MesWmItemReceiptService itemReceiptService; - @Resource private MesWmItemReceiptDetailService itemReceiptDetailService; - @Resource @Lazy private MesWmArrivalNoticeLineService arrivalNoticeLineService; + @Resource + @Lazy + private MesWmArrivalNoticeService arrivalNoticeService; + @Resource + private MesWmBatchService batchService; @Override public Long createItemReceiptLine(MesWmItemReceiptLineSaveReqVO createReqVO) { - // 校验父单据存在且为可编辑状态 + // 1.1 校验父单据存在且为可编辑状态 MesWmItemReceiptDO receipt = itemReceiptService.validateItemReceiptEditable(createReqVO.getReceiptId()); - // 校验关联到货通知单行存在 + // 1.2 校验关联到货通知单行存在 validateArrivalNoticeLine(receipt, createReqVO.getArrivalNoticeLineId()); - // 新增 + // 2.1 创建入库单行 MesWmItemReceiptLineDO line = BeanUtils.toBean(createReqVO, MesWmItemReceiptLineDO.class); + // 2.2 生成或获取批次 + MesWmBatchDO batch = generateOrGetBatch(receipt, createReqVO); + if (batch != null) { + line.setBatchId(batch.getId()); + line.setBatchCode(batch.getCode()); + } + // 2.3 插入数据库 itemReceiptLineMapper.insert(line); - - // TODO @芋艿:【暂时不处理】wmBatchService 需要生成下;基于 batchCode return line.getId(); } @Override public void updateItemReceiptLine(MesWmItemReceiptLineSaveReqVO updateReqVO) { - // 校验存在 + // 1.1 校验存在 MesWmItemReceiptLineDO line = validateItemReceiptLineExists(updateReqVO.getId()); - // 校验父单据存在且为可编辑状态 + // 1.2 校验父单据存在且为可编辑状态 MesWmItemReceiptDO receipt = itemReceiptService.validateItemReceiptEditable(line.getReceiptId()); - // 校验关联到货通知单行存在 + // 1.3 校验关联到货通知单行存在 validateArrivalNoticeLine(receipt, updateReqVO.getArrivalNoticeLineId()); - // 更新 + // 2.1 更新 MesWmItemReceiptLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmItemReceiptLineDO.class); + // 2.2 生成或获取批次 + MesWmBatchDO batch = generateOrGetBatch(receipt, updateReqVO); + if (batch != null) { + updateObj.setBatchId(batch.getId()).setBatchCode(batch.getCode()); + } + // 2.3 更新数据库 itemReceiptLineMapper.updateById(updateObj); - - // TODO @芋艿:【暂时不处理】wmBatchService 需要生成下;基于 batchCode } @Override @@ -134,4 +151,31 @@ public class MesWmItemReceiptLineServiceImpl implements MesWmItemReceiptLineServ return line; } + /** + * 生成或获取批次 + * + * @param receipt 入库单 + * @param reqVO 入库单行请求VO + * @return 批次记录(如果物料未启用批次管理则返回 null) + */ + private MesWmBatchDO generateOrGetBatch(MesWmItemReceiptDO receipt, MesWmItemReceiptLineSaveReqVO reqVO) { + // 构建批次参数 VO + MesWmBatchGenerateReqVO batchReqVO = new MesWmBatchGenerateReqVO(); + // 从入库单行获取 + batchReqVO.setItemId(reqVO.getItemId()).setProduceDate(reqVO.getProductionDate()) + .setExpireDate(reqVO.getExpireDate()).setLotNumber(reqVO.getProductionBatchNumber()); + // 从父单据获取 + batchReqVO.setVendorId(receipt.getVendorId()).setReceiptDate(receipt.getReceiptDate()); + // 从到货通知单获取采购订单号(如果关联了到货通知单) + if (receipt.getNoticeId() != null) { + MesWmArrivalNoticeDO notice = arrivalNoticeService.getArrivalNotice(receipt.getNoticeId()); + if (notice != null) { + batchReqVO.setPurchaseOrderCode(notice.getPurchaseOrderCode()); + } + } + + // 生成或获取批次 + return batchService.getOrGenerateBatchCode(batchReqVO); + } + } -- libgit2 0.21.4