Commit eb566426396a052423527b418079cc22b8acb924
1 parent
b1f836ab
✨ feat(mes): 添加批次管理功能,支持批次生成与获取
新增批次生成请求 VO 和批次管理服务接口,支持根据物料批次配置生成或获取批次记录。更新相关数据对象和服务实现,确保批次管理功能的完整性和可用性。
Showing
15 changed files
with
617 additions
and
18 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchGenerateReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +import jakarta.validation.constraints.NotNull; | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 批次生成请求 VO | |
| 10 | + * | |
| 11 | + * @author 芋道源码 | |
| 12 | + */ | |
| 13 | +@Data | |
| 14 | +public class MesWmBatchGenerateReqVO { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 物料ID | |
| 18 | + */ | |
| 19 | + @NotNull(message = "物料 ID 不能为空") | |
| 20 | + private Long itemId; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 生产日期 | |
| 24 | + */ | |
| 25 | + private LocalDateTime produceDate; | |
| 26 | + /** | |
| 27 | + * 有效期 | |
| 28 | + */ | |
| 29 | + private LocalDateTime expireDate; | |
| 30 | + /** | |
| 31 | + * 入库日期 | |
| 32 | + */ | |
| 33 | + private LocalDateTime receiptDate; | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * 供应商 ID | |
| 37 | + */ | |
| 38 | + private Long vendorId; | |
| 39 | + /** | |
| 40 | + * 客户 ID | |
| 41 | + */ | |
| 42 | + private Long clientId; | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * 采购订单编号 | |
| 46 | + */ | |
| 47 | + private String purchaseOrderCode; | |
| 48 | + /** | |
| 49 | + * 销售订单编号 | |
| 50 | + */ | |
| 51 | + private String salesOrderCode; | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 生产工单 ID | |
| 55 | + */ | |
| 56 | + private Long workOrderId; | |
| 57 | + /** | |
| 58 | + * 生产任务 ID | |
| 59 | + */ | |
| 60 | + private Long taskId; | |
| 61 | + /** | |
| 62 | + * 工作站 ID | |
| 63 | + */ | |
| 64 | + private Long workstationId; | |
| 65 | + /** | |
| 66 | + * 工具 ID | |
| 67 | + */ | |
| 68 | + private Long toolId; | |
| 69 | + /** | |
| 70 | + * 模具 ID | |
| 71 | + */ | |
| 72 | + private Long moldId; | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * 生产批号 | |
| 76 | + */ | |
| 77 | + private String lotNumber; | |
| 78 | + /** | |
| 79 | + * 质量状态 | |
| 80 | + */ | |
| 81 | + private String qualityStatus; | |
| 82 | + | |
| 83 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/MesWmItemReceiptSaveReqVO.java
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 { |
| 40 | 40 | @Schema(description = "批次编号", example = "1") |
| 41 | 41 | private Long batchId; |
| 42 | 42 | |
| 43 | + @Schema(description = "批次编码", example = "BATCH20260110") | |
| 44 | + private String batchCode; | |
| 45 | + | |
| 43 | 46 | @Schema(description = "生产日期") |
| 44 | 47 | private LocalDateTime productionDate; |
| 45 | 48 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdItemBatchConfigDO.java
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 4 | +import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO; | |
| 5 | +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; | |
| 6 | +import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; | |
| 7 | +import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; | |
| 8 | +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; | |
| 9 | +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; | |
| 10 | +import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO; | |
| 11 | +import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 12 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 13 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 14 | +import lombok.*; | |
| 15 | + | |
| 16 | +import java.time.LocalDateTime; | |
| 17 | + | |
| 18 | +/** | |
| 19 | + * 批次管理 DO | |
| 20 | + * | |
| 21 | + * @author 芋道源码 | |
| 22 | + */ | |
| 23 | +@TableName("mes_wm_batch") | |
| 24 | +@KeySequence("mes_wm_batch_seq") | |
| 25 | +@Data | |
| 26 | +@EqualsAndHashCode(callSuper = true) | |
| 27 | +@ToString(callSuper = true) | |
| 28 | +@Builder | |
| 29 | +@NoArgsConstructor | |
| 30 | +@AllArgsConstructor | |
| 31 | +public class MesWmBatchDO extends BaseDO { | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 批次ID | |
| 35 | + */ | |
| 36 | + @TableId | |
| 37 | + private Long id; | |
| 38 | + /** | |
| 39 | + * 批次编码 | |
| 40 | + */ | |
| 41 | + private String code; | |
| 42 | + /** | |
| 43 | + * 物料ID | |
| 44 | + * | |
| 45 | + * 关联 {@link MesMdItemDO#getId()} | |
| 46 | + */ | |
| 47 | + private Long itemId; | |
| 48 | + /** | |
| 49 | + * 生产日期 | |
| 50 | + */ | |
| 51 | + private LocalDateTime produceDate; | |
| 52 | + /** | |
| 53 | + * 有效期 | |
| 54 | + */ | |
| 55 | + private LocalDateTime expireDate; | |
| 56 | + /** | |
| 57 | + * 入库日期 | |
| 58 | + */ | |
| 59 | + private LocalDateTime receiptDate; | |
| 60 | + /** | |
| 61 | + * 供应商ID | |
| 62 | + * | |
| 63 | + * 关联 {@link MesMdVendorDO#getId()} | |
| 64 | + */ | |
| 65 | + private Long vendorId; | |
| 66 | + /** | |
| 67 | + * 客户ID | |
| 68 | + * | |
| 69 | + * 关联 {@link MesMdClientDO#getId()} | |
| 70 | + */ | |
| 71 | + private Long clientId; | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * 销售订单编号 | |
| 75 | + */ | |
| 76 | + private String salesOrderCode; | |
| 77 | + /** | |
| 78 | + * 采购订单编号 | |
| 79 | + */ | |
| 80 | + private String purchaseOrderCode; | |
| 81 | + /** | |
| 82 | + * 生产工单ID | |
| 83 | + * | |
| 84 | + * 关联 {@link MesProWorkOrderDO#getId()} | |
| 85 | + */ | |
| 86 | + private Long workOrderId; | |
| 87 | + /** | |
| 88 | + * 生产任务ID | |
| 89 | + * | |
| 90 | + * 关联 {@link MesProTaskDO#getId()} | |
| 91 | + */ | |
| 92 | + private Long taskId; | |
| 93 | + /** | |
| 94 | + * 工作站ID | |
| 95 | + * | |
| 96 | + * 关联 {@link MesMdWorkstationDO#getId()} | |
| 97 | + */ | |
| 98 | + private Long workstationId; | |
| 99 | + /** | |
| 100 | + * 工具ID | |
| 101 | + * | |
| 102 | + * 关联 {@link MesTmToolDO#getId()} | |
| 103 | + */ | |
| 104 | + private Long toolId; | |
| 105 | + /** | |
| 106 | + * 模具 ID | |
| 107 | + */ | |
| 108 | + private Long moldId; | |
| 109 | + /** | |
| 110 | + * 生产批号 | |
| 111 | + */ | |
| 112 | + private String lotNumber; | |
| 113 | + /** | |
| 114 | + * 质量状态 | |
| 115 | + */ | |
| 116 | + private String qualityStatus; | |
| 117 | + /** | |
| 118 | + * 备注 | |
| 119 | + */ | |
| 120 | + private String remark; | |
| 121 | + | |
| 122 | +} | ... | ... |
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; |
| 3 | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | 4 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| 5 | 5 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeLineDO; |
| 6 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; | |
| 6 | 7 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 7 | 8 | import com.baomidou.mybatisplus.annotation.TableId; |
| 8 | 9 | import com.baomidou.mybatisplus.annotation.TableName; |
| ... | ... | @@ -54,10 +55,16 @@ public class MesWmItemReceiptLineDO extends BaseDO { |
| 54 | 55 | /** |
| 55 | 56 | * 批次编号 |
| 56 | 57 | * |
| 57 | - * TODO DONE @芋艿:保留。待 mes_wm_batch 模块迁移后补充 @link 关联 | |
| 58 | + * 关联 {@link MesWmBatchDO#getId()} | |
| 58 | 59 | */ |
| 59 | 60 | private Long batchId; |
| 60 | 61 | /** |
| 62 | + * 批次编码 | |
| 63 | + * | |
| 64 | + * 关联 {@link MesWmBatchDO#getCode()} | |
| 65 | + */ | |
| 66 | + private String batchCode; | |
| 67 | + /** | |
| 61 | 68 | * 生产日期 |
| 62 | 69 | */ |
| 63 | 70 | private LocalDateTime productionDate; | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.dal.mysql.wm.batch; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 5 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; | |
| 6 | +import cn.hutool.core.util.ObjUtil; | |
| 7 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |
| 8 | +import org.apache.ibatis.annotations.Mapper; | |
| 9 | + | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 批次管理 Mapper | |
| 14 | + * | |
| 15 | + * @author 芋道源码 | |
| 16 | + */ | |
| 17 | +@Mapper | |
| 18 | +public interface MesWmBatchMapper extends BaseMapperX<MesWmBatchDO> { | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * 根据参数查询匹配的第一条批次记录 | |
| 22 | + * <p> | |
| 23 | + * 使用 NULL 值精确匹配,返回 ID 最小的批次 | |
| 24 | + * | |
| 25 | + * @param batch 批次参数 | |
| 26 | + * @return 匹配的批次记录 | |
| 27 | + */ | |
| 28 | + default MesWmBatchDO selectFirst(MesWmBatchDO batch) { | |
| 29 | + LambdaQueryWrapper<MesWmBatchDO> query = new LambdaQueryWrapper<>(); | |
| 30 | + query.eq(MesWmBatchDO::getItemId, batch.getItemId()); | |
| 31 | + if (ObjUtil.isNull(batch.getVendorId())) { | |
| 32 | + query.isNull(MesWmBatchDO::getVendorId); | |
| 33 | + } else { | |
| 34 | + query.eq(MesWmBatchDO::getVendorId, batch.getVendorId()); | |
| 35 | + } | |
| 36 | + if (ObjUtil.isNull(batch.getClientId())) { | |
| 37 | + query.isNull(MesWmBatchDO::getClientId); | |
| 38 | + } else { | |
| 39 | + query.eq(MesWmBatchDO::getClientId, batch.getClientId()); | |
| 40 | + } | |
| 41 | + if (ObjUtil.isNull(batch.getSalesOrderCode())) { | |
| 42 | + query.isNull(MesWmBatchDO::getSalesOrderCode); | |
| 43 | + } else { | |
| 44 | + query.eq(MesWmBatchDO::getSalesOrderCode, batch.getSalesOrderCode()); | |
| 45 | + } | |
| 46 | + if (ObjUtil.isNull(batch.getPurchaseOrderCode())) { | |
| 47 | + query.isNull(MesWmBatchDO::getPurchaseOrderCode); | |
| 48 | + } else { | |
| 49 | + query.eq(MesWmBatchDO::getPurchaseOrderCode, batch.getPurchaseOrderCode()); | |
| 50 | + } | |
| 51 | + if (ObjUtil.isNull(batch.getWorkOrderId())) { | |
| 52 | + query.isNull(MesWmBatchDO::getWorkOrderId); | |
| 53 | + } else { | |
| 54 | + query.eq(MesWmBatchDO::getWorkOrderId, batch.getWorkOrderId()); | |
| 55 | + } | |
| 56 | + if (ObjUtil.isNull(batch.getTaskId())) { | |
| 57 | + query.isNull(MesWmBatchDO::getTaskId); | |
| 58 | + } else { | |
| 59 | + query.eq(MesWmBatchDO::getTaskId, batch.getTaskId()); | |
| 60 | + } | |
| 61 | + if (ObjUtil.isNull(batch.getWorkstationId())) { | |
| 62 | + query.isNull(MesWmBatchDO::getWorkstationId); | |
| 63 | + } else { | |
| 64 | + query.eq(MesWmBatchDO::getWorkstationId, batch.getWorkstationId()); | |
| 65 | + } | |
| 66 | + if (ObjUtil.isNull(batch.getToolId())) { | |
| 67 | + query.isNull(MesWmBatchDO::getToolId); | |
| 68 | + } else { | |
| 69 | + query.eq(MesWmBatchDO::getToolId, batch.getToolId()); | |
| 70 | + } | |
| 71 | + if (ObjUtil.isNull(batch.getMoldId())) { | |
| 72 | + query.isNull(MesWmBatchDO::getMoldId); | |
| 73 | + } else { | |
| 74 | + query.eq(MesWmBatchDO::getMoldId, batch.getMoldId()); | |
| 75 | + } | |
| 76 | + if (ObjUtil.isNull(batch.getLotNumber())) { | |
| 77 | + query.isNull(MesWmBatchDO::getLotNumber); | |
| 78 | + } else { | |
| 79 | + query.eq(MesWmBatchDO::getLotNumber, batch.getLotNumber()); | |
| 80 | + } | |
| 81 | + if (ObjUtil.isNull(batch.getQualityStatus())) { | |
| 82 | + query.isNull(MesWmBatchDO::getQualityStatus); | |
| 83 | + } else { | |
| 84 | + query.eq(MesWmBatchDO::getQualityStatus, batch.getQualityStatus()); | |
| 85 | + } | |
| 86 | + if (ObjUtil.isNull(batch.getProduceDate())) { | |
| 87 | + query.isNull(MesWmBatchDO::getProduceDate); | |
| 88 | + } else { | |
| 89 | + query.eq(MesWmBatchDO::getProduceDate, batch.getProduceDate()); | |
| 90 | + } | |
| 91 | + if (ObjUtil.isNull(batch.getExpireDate())) { | |
| 92 | + query.isNull(MesWmBatchDO::getExpireDate); | |
| 93 | + } else { | |
| 94 | + query.eq(MesWmBatchDO::getExpireDate, batch.getExpireDate()); | |
| 95 | + } | |
| 96 | + if (ObjUtil.isNull(batch.getReceiptDate())) { | |
| 97 | + query.isNull(MesWmBatchDO::getReceiptDate); | |
| 98 | + } else { | |
| 99 | + query.eq(MesWmBatchDO::getReceiptDate, batch.getReceiptDate()); | |
| 100 | + } | |
| 101 | + | |
| 102 | + // 返回 ID 最小的批次 | |
| 103 | + query.orderByAsc(MesWmBatchDO::getId); | |
| 104 | + List<MesWmBatchDO> list = selectList(query); | |
| 105 | + return CollUtil.getFirst(list); | |
| 106 | + } | |
| 107 | + | |
| 108 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
| ... | ... | @@ -35,6 +35,22 @@ public interface ErrorCodeConstants { |
| 35 | 35 | ErrorCode MD_ITEM_BATCH_CONFIG_NOT_EXISTS = new ErrorCode(1_040_102_100, "物料批次属性配置不存在"); |
| 36 | 36 | ErrorCode MD_ITEM_BATCH_CONFIG_AT_LEAST_ONE_FLAG = new ErrorCode(1_040_102_101, "批次管理已启用,至少需要配置一个批次属性"); |
| 37 | 37 | |
| 38 | + // ========== MES 仓库管理-批次管理(1-040-717-000) ========== | |
| 39 | + ErrorCode WM_BATCH_PRODUCE_DATE_REQUIRED = new ErrorCode(1_040_717_000, "批次配置要求生产日期不能为空"); | |
| 40 | + ErrorCode WM_BATCH_RECEIPT_DATE_REQUIRED = new ErrorCode(1_040_717_001, "批次配置要求入库日期不能为空"); | |
| 41 | + ErrorCode WM_BATCH_EXPIRE_DATE_REQUIRED = new ErrorCode(1_040_717_002, "批次配置要求有效期不能为空"); | |
| 42 | + ErrorCode WM_BATCH_VENDOR_REQUIRED = new ErrorCode(1_040_717_003, "批次配置要求供应商不能为空"); | |
| 43 | + ErrorCode WM_BATCH_CLIENT_REQUIRED = new ErrorCode(1_040_717_004, "批次配置要求客户不能为空"); | |
| 44 | + ErrorCode WM_BATCH_PURCHASE_ORDER_CODE_REQUIRED = new ErrorCode(1_040_717_005, "批次配置要求采购订单编号不能为空"); | |
| 45 | + ErrorCode WM_BATCH_CUSTOMER_ORDER_CODE_REQUIRED = new ErrorCode(1_040_717_006, "批次配置要求销售订单编号不能为空"); | |
| 46 | + ErrorCode WM_BATCH_WORK_ORDER_REQUIRED = new ErrorCode(1_040_717_007, "批次配置要求生产工单不能为空"); | |
| 47 | + ErrorCode WM_BATCH_TASK_REQUIRED = new ErrorCode(1_040_717_008, "批次配置要求生产任务不能为空"); | |
| 48 | + ErrorCode WM_BATCH_WORKSTATION_REQUIRED = new ErrorCode(1_040_717_009, "批次配置要求工作站不能为空"); | |
| 49 | + ErrorCode WM_BATCH_TOOL_REQUIRED = new ErrorCode(1_040_717_010, "批次配置要求工具不能为空"); | |
| 50 | + ErrorCode WM_BATCH_MOLD_REQUIRED = new ErrorCode(1_040_717_011, "批次配置要求模具不能为空"); | |
| 51 | + ErrorCode WM_BATCH_LOT_NUMBER_REQUIRED = new ErrorCode(1_040_717_012, "批次配置要求生产批号不能为空"); | |
| 52 | + ErrorCode WM_BATCH_QUALITY_STATUS_REQUIRED = new ErrorCode(1_040_717_013, "批次配置要求质量状态不能为空"); | |
| 53 | + | |
| 38 | 54 | // ========== MES 基础数据-客户(1-040-103-000) ========== |
| 39 | 55 | ErrorCode MD_CLIENT_NOT_EXISTS = new ErrorCode(1_040_103_000, "客户不存在"); |
| 40 | 56 | ErrorCode MD_CLIENT_CODE_DUPLICATE = new ErrorCode(1_040_103_001, "客户编码已存在"); | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemBatchConfigService.java
| ... | ... | @@ -20,6 +20,14 @@ public interface MesMdItemBatchConfigService { |
| 20 | 20 | MesMdItemBatchConfigDO getItemBatchConfigByItemId(Long itemId); |
| 21 | 21 | |
| 22 | 22 | /** |
| 23 | + * 校验物料批次配置存在 | |
| 24 | + * | |
| 25 | + * @param itemId 物料 ID | |
| 26 | + * @return 物料批次配置 | |
| 27 | + */ | |
| 28 | + MesMdItemBatchConfigDO validateItemBatchConfigExists(Long itemId); | |
| 29 | + | |
| 30 | + /** | |
| 23 | 31 | * 保存批次属性配置(新增或更新) |
| 24 | 32 | * |
| 25 | 33 | * @param saveReqVO 保存信息 | ... | ... |
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; |
| 10 | 10 | import org.springframework.validation.annotation.Validated; |
| 11 | 11 | |
| 12 | 12 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 13 | +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_BATCH_CONFIG_NOT_EXISTS; | |
| 13 | 14 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_NOT_EXISTS; |
| 14 | 15 | |
| 15 | 16 | /** |
| ... | ... | @@ -34,6 +35,15 @@ public class MesMdItemBatchConfigServiceImpl implements MesMdItemBatchConfigServ |
| 34 | 35 | } |
| 35 | 36 | |
| 36 | 37 | @Override |
| 38 | + public MesMdItemBatchConfigDO validateItemBatchConfigExists(Long itemId) { | |
| 39 | + MesMdItemBatchConfigDO config = getItemBatchConfigByItemId(itemId); | |
| 40 | + if (config == null) { | |
| 41 | + throw exception(MD_ITEM_BATCH_CONFIG_NOT_EXISTS); | |
| 42 | + } | |
| 43 | + return config; | |
| 44 | + } | |
| 45 | + | |
| 46 | + @Override | |
| 37 | 47 | public Long saveItemBatchConfig(MesMdItemBatchConfigSaveReqVO saveReqVO) { |
| 38 | 48 | // 1. 校验物料存在 |
| 39 | 49 | if (itemService.getItem(saveReqVO.getItemId()) == null) { | ... | ... |
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 { |
| 198 | 198 | || Boolean.TRUE.equals(config.getClientFlag()) |
| 199 | 199 | || Boolean.TRUE.equals(config.getSalesOrderCodeFlag()) |
| 200 | 200 | || Boolean.TRUE.equals(config.getPurchaseOrderCodeFlag()) |
| 201 | - || Boolean.TRUE.equals(config.getWorkorderFlag()) | |
| 201 | + || Boolean.TRUE.equals(config.getWorkOrderFlag()) | |
| 202 | 202 | || Boolean.TRUE.equals(config.getTaskFlag()) |
| 203 | 203 | || Boolean.TRUE.equals(config.getWorkstationFlag()) |
| 204 | 204 | || Boolean.TRUE.equals(config.getToolFlag()) | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.service.wm.batch; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; | |
| 4 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 批次管理 Service 接口 | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +public interface MesWmBatchService { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * 获取或生成批次编码 | |
| 15 | + * <p> | |
| 16 | + * 根据物料批次配置,查询或生成批次记录 | |
| 17 | + * | |
| 18 | + * @param reqVO 批次参数(包含 itemId 及其他可选属性) | |
| 19 | + * @return 批次记录(如果物料未启用批次管理则返回 null) | |
| 20 | + */ | |
| 21 | + MesWmBatchDO getOrGenerateBatchCode(MesWmBatchGenerateReqVO reqVO); | |
| 22 | + | |
| 23 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.service.wm.batch; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.ObjUtil; | |
| 4 | +import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemBatchConfigDO; | |
| 6 | +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; | |
| 7 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; | |
| 8 | +import cn.iocoder.yudao.module.mes.dal.mysql.wm.batch.MesWmBatchMapper; | |
| 9 | +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; | |
| 10 | +import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum; | |
| 11 | +import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService; | |
| 12 | +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService; | |
| 13 | +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; | |
| 14 | +import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService; | |
| 15 | +import jakarta.annotation.Resource; | |
| 16 | +import lombok.extern.slf4j.Slf4j; | |
| 17 | +import org.springframework.stereotype.Service; | |
| 18 | +import org.springframework.transaction.annotation.Transactional; | |
| 19 | +import org.springframework.validation.annotation.Validated; | |
| 20 | + | |
| 21 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 22 | +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * 批次管理 Service 实现类 | |
| 26 | + * | |
| 27 | + * @author 芋道源码 | |
| 28 | + */ | |
| 29 | +@Service | |
| 30 | +@Validated | |
| 31 | +@Slf4j | |
| 32 | +public class MesWmBatchServiceImpl implements MesWmBatchService { | |
| 33 | + | |
| 34 | + @Resource | |
| 35 | + private MesWmBatchMapper batchMapper; | |
| 36 | + @Resource | |
| 37 | + private MesMdItemService itemService; | |
| 38 | + @Resource | |
| 39 | + private MesMdItemBatchConfigService itemBatchConfigService; | |
| 40 | + @Resource | |
| 41 | + private MesMdAutoCodeRecordService autoCodeRecordService; | |
| 42 | + @Resource | |
| 43 | + private MesWmBarcodeService barcodeService; | |
| 44 | + | |
| 45 | + @Override | |
| 46 | + @Transactional(rollbackFor = Exception.class) | |
| 47 | + public MesWmBatchDO getOrGenerateBatchCode(MesWmBatchGenerateReqVO reqVO) { | |
| 48 | + // 1.1 查询物料信息,检查是否启用批次管理 | |
| 49 | + MesMdItemDO item = itemService.validateItemExists(reqVO.getItemId()); | |
| 50 | + if (Boolean.FALSE.equals(item.getBatchFlag())) { | |
| 51 | + // 未启用批次管理,返回 null | |
| 52 | + return null; | |
| 53 | + } | |
| 54 | + // 1.2 查询物料批次配置 | |
| 55 | + MesMdItemBatchConfigDO config = itemBatchConfigService.validateItemBatchConfigExists(reqVO.getItemId()); | |
| 56 | + | |
| 57 | + // 2. 根据配置校验必填参数并清空不需要的参数 | |
| 58 | + MesWmBatchDO batch = MesWmBatchDO.builder().itemId(reqVO.getItemId()).build(); | |
| 59 | + // 生产日期 | |
| 60 | + if (Boolean.TRUE.equals(config.getProduceDateFlag())) { | |
| 61 | + if (ObjUtil.isNull(reqVO.getProduceDate())) { | |
| 62 | + throw exception(WM_BATCH_PRODUCE_DATE_REQUIRED); | |
| 63 | + } | |
| 64 | + batch.setProduceDate(reqVO.getProduceDate()); | |
| 65 | + } | |
| 66 | + // 入库日期 | |
| 67 | + if (Boolean.TRUE.equals(config.getReceiptDateFlag())) { | |
| 68 | + if (ObjUtil.isNull(reqVO.getReceiptDate())) { | |
| 69 | + throw exception(WM_BATCH_RECEIPT_DATE_REQUIRED); | |
| 70 | + } | |
| 71 | + batch.setReceiptDate(reqVO.getReceiptDate()); | |
| 72 | + } | |
| 73 | + // 有效期 | |
| 74 | + if (Boolean.TRUE.equals(config.getExpireDateFlag())) { | |
| 75 | + if (ObjUtil.isNull(reqVO.getExpireDate())) { | |
| 76 | + throw exception(WM_BATCH_EXPIRE_DATE_REQUIRED); | |
| 77 | + } | |
| 78 | + batch.setExpireDate(reqVO.getExpireDate()); | |
| 79 | + } | |
| 80 | + // 供应商 | |
| 81 | + if (Boolean.TRUE.equals(config.getVendorFlag())) { | |
| 82 | + if (ObjUtil.isNull(reqVO.getVendorId())) { | |
| 83 | + throw exception(WM_BATCH_VENDOR_REQUIRED); | |
| 84 | + } | |
| 85 | + batch.setVendorId(reqVO.getVendorId()); | |
| 86 | + } | |
| 87 | + // 客户 | |
| 88 | + if (Boolean.TRUE.equals(config.getClientFlag())) { | |
| 89 | + if (ObjUtil.isNull(reqVO.getClientId())) { | |
| 90 | + throw exception(WM_BATCH_CLIENT_REQUIRED); | |
| 91 | + } | |
| 92 | + batch.setClientId(reqVO.getClientId()); | |
| 93 | + } | |
| 94 | + // 采购订单编号 | |
| 95 | + if (Boolean.TRUE.equals(config.getPurchaseOrderCodeFlag())) { | |
| 96 | + if (ObjUtil.isNull(reqVO.getPurchaseOrderCode())) { | |
| 97 | + throw exception(WM_BATCH_PURCHASE_ORDER_CODE_REQUIRED); | |
| 98 | + } | |
| 99 | + batch.setPurchaseOrderCode(reqVO.getPurchaseOrderCode()); | |
| 100 | + } | |
| 101 | + // 销售订单编号 | |
| 102 | + if (Boolean.TRUE.equals(config.getSalesOrderCodeFlag())) { | |
| 103 | + if (ObjUtil.isNull(reqVO.getSalesOrderCode())) { | |
| 104 | + throw exception(WM_BATCH_CUSTOMER_ORDER_CODE_REQUIRED); | |
| 105 | + } | |
| 106 | + batch.setSalesOrderCode(reqVO.getSalesOrderCode()); | |
| 107 | + } | |
| 108 | + // 生产工单 | |
| 109 | + if (Boolean.TRUE.equals(config.getWorkOrderFlag())) { | |
| 110 | + if (ObjUtil.isNull(reqVO.getWorkOrderId())) { | |
| 111 | + throw exception(WM_BATCH_WORK_ORDER_REQUIRED); | |
| 112 | + } | |
| 113 | + batch.setWorkOrderId(reqVO.getWorkOrderId()); | |
| 114 | + } | |
| 115 | + // 生产任务 | |
| 116 | + if (Boolean.TRUE.equals(config.getTaskFlag())) { | |
| 117 | + if (ObjUtil.isNull(reqVO.getTaskId())) { | |
| 118 | + throw exception(WM_BATCH_TASK_REQUIRED); | |
| 119 | + } | |
| 120 | + batch.setTaskId(reqVO.getTaskId()); | |
| 121 | + } | |
| 122 | + // 工作站 | |
| 123 | + if (Boolean.TRUE.equals(config.getWorkstationFlag())) { | |
| 124 | + if (ObjUtil.isNull(reqVO.getWorkstationId())) { | |
| 125 | + throw exception(WM_BATCH_WORKSTATION_REQUIRED); | |
| 126 | + } | |
| 127 | + batch.setWorkstationId(reqVO.getWorkstationId()); | |
| 128 | + } | |
| 129 | + // 工具 | |
| 130 | + if (Boolean.TRUE.equals(config.getToolFlag())) { | |
| 131 | + if (ObjUtil.isNull(reqVO.getToolId())) { | |
| 132 | + throw exception(WM_BATCH_TOOL_REQUIRED); | |
| 133 | + } | |
| 134 | + batch.setToolId(reqVO.getToolId()); | |
| 135 | + } | |
| 136 | + // 模具 | |
| 137 | + if (Boolean.TRUE.equals(config.getMoldFlag())) { | |
| 138 | + if (ObjUtil.isNull(reqVO.getMoldId())) { | |
| 139 | + throw exception(WM_BATCH_MOLD_REQUIRED); | |
| 140 | + } | |
| 141 | + batch.setMoldId(reqVO.getMoldId()); | |
| 142 | + } | |
| 143 | + // 生产批号 | |
| 144 | + if (Boolean.TRUE.equals(config.getLotNumberFlag())) { | |
| 145 | + if (ObjUtil.isNull(reqVO.getLotNumber())) { | |
| 146 | + throw exception(WM_BATCH_LOT_NUMBER_REQUIRED); | |
| 147 | + } | |
| 148 | + batch.setLotNumber(reqVO.getLotNumber()); | |
| 149 | + } | |
| 150 | + // 质量状态 | |
| 151 | + if (Boolean.TRUE.equals(config.getQualityStatusFlag())) { | |
| 152 | + if (ObjUtil.isNull(reqVO.getQualityStatus())) { | |
| 153 | + throw exception(WM_BATCH_QUALITY_STATUS_REQUIRED); | |
| 154 | + } | |
| 155 | + batch.setQualityStatus(reqVO.getQualityStatus()); | |
| 156 | + } | |
| 157 | + | |
| 158 | + // 3.1 情况一:查询是否存在匹配的批次 | |
| 159 | + MesWmBatchDO existingBatch = batchMapper.selectFirst(batch); | |
| 160 | + if (existingBatch != null) { | |
| 161 | + return existingBatch; | |
| 162 | + } | |
| 163 | + | |
| 164 | + // 3.2 情况二:生成新批次 | |
| 165 | + String batchCode = autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.BATCH_CODE.getCode()); | |
| 166 | + batch.setCode(batchCode); | |
| 167 | + batchMapper.insert(batch); | |
| 168 | + | |
| 169 | + // 4. 生成条码 | |
| 170 | + barcodeService.autoGenerateBarcode(MesBizTypeConstants.WM_BATCH, batch.getId(), batch.getCode(), item.getName()); | |
| 171 | + return batch; | |
| 172 | + } | |
| 173 | + | |
| 174 | +} | ... | ... |
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; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | +import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; | |
| 5 | 6 | import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.line.MesWmItemReceiptLinePageReqVO; |
| 6 | 7 | import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.line.MesWmItemReceiptLineSaveReqVO; |
| 8 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeDO; | |
| 9 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; | |
| 7 | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptDO; |
| 8 | 11 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptLineDO; |
| 9 | 12 | import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemreceipt.MesWmItemReceiptLineMapper; |
| 10 | 13 | import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeLineService; |
| 14 | +import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeService; | |
| 15 | +import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; | |
| 11 | 16 | import jakarta.annotation.Resource; |
| 12 | 17 | import org.springframework.context.annotation.Lazy; |
| 13 | 18 | import org.springframework.stereotype.Service; |
| ... | ... | @@ -32,43 +37,55 @@ public class MesWmItemReceiptLineServiceImpl implements MesWmItemReceiptLineServ |
| 32 | 37 | @Resource |
| 33 | 38 | @Lazy |
| 34 | 39 | private MesWmItemReceiptService itemReceiptService; |
| 35 | - | |
| 36 | 40 | @Resource |
| 37 | 41 | private MesWmItemReceiptDetailService itemReceiptDetailService; |
| 38 | - | |
| 39 | 42 | @Resource |
| 40 | 43 | @Lazy |
| 41 | 44 | private MesWmArrivalNoticeLineService arrivalNoticeLineService; |
| 45 | + @Resource | |
| 46 | + @Lazy | |
| 47 | + private MesWmArrivalNoticeService arrivalNoticeService; | |
| 48 | + @Resource | |
| 49 | + private MesWmBatchService batchService; | |
| 42 | 50 | |
| 43 | 51 | @Override |
| 44 | 52 | public Long createItemReceiptLine(MesWmItemReceiptLineSaveReqVO createReqVO) { |
| 45 | - // 校验父单据存在且为可编辑状态 | |
| 53 | + // 1.1 校验父单据存在且为可编辑状态 | |
| 46 | 54 | MesWmItemReceiptDO receipt = itemReceiptService.validateItemReceiptEditable(createReqVO.getReceiptId()); |
| 47 | - // 校验关联到货通知单行存在 | |
| 55 | + // 1.2 校验关联到货通知单行存在 | |
| 48 | 56 | validateArrivalNoticeLine(receipt, createReqVO.getArrivalNoticeLineId()); |
| 49 | 57 | |
| 50 | - // 新增 | |
| 58 | + // 2.1 创建入库单行 | |
| 51 | 59 | MesWmItemReceiptLineDO line = BeanUtils.toBean(createReqVO, MesWmItemReceiptLineDO.class); |
| 60 | + // 2.2 生成或获取批次 | |
| 61 | + MesWmBatchDO batch = generateOrGetBatch(receipt, createReqVO); | |
| 62 | + if (batch != null) { | |
| 63 | + line.setBatchId(batch.getId()); | |
| 64 | + line.setBatchCode(batch.getCode()); | |
| 65 | + } | |
| 66 | + // 2.3 插入数据库 | |
| 52 | 67 | itemReceiptLineMapper.insert(line); |
| 53 | - | |
| 54 | - // TODO @芋艿:【暂时不处理】wmBatchService 需要生成下;基于 batchCode | |
| 55 | 68 | return line.getId(); |
| 56 | 69 | } |
| 57 | 70 | |
| 58 | 71 | @Override |
| 59 | 72 | public void updateItemReceiptLine(MesWmItemReceiptLineSaveReqVO updateReqVO) { |
| 60 | - // 校验存在 | |
| 73 | + // 1.1 校验存在 | |
| 61 | 74 | MesWmItemReceiptLineDO line = validateItemReceiptLineExists(updateReqVO.getId()); |
| 62 | - // 校验父单据存在且为可编辑状态 | |
| 75 | + // 1.2 校验父单据存在且为可编辑状态 | |
| 63 | 76 | MesWmItemReceiptDO receipt = itemReceiptService.validateItemReceiptEditable(line.getReceiptId()); |
| 64 | - // 校验关联到货通知单行存在 | |
| 77 | + // 1.3 校验关联到货通知单行存在 | |
| 65 | 78 | validateArrivalNoticeLine(receipt, updateReqVO.getArrivalNoticeLineId()); |
| 66 | 79 | |
| 67 | - // 更新 | |
| 80 | + // 2.1 更新 | |
| 68 | 81 | MesWmItemReceiptLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmItemReceiptLineDO.class); |
| 82 | + // 2.2 生成或获取批次 | |
| 83 | + MesWmBatchDO batch = generateOrGetBatch(receipt, updateReqVO); | |
| 84 | + if (batch != null) { | |
| 85 | + updateObj.setBatchId(batch.getId()).setBatchCode(batch.getCode()); | |
| 86 | + } | |
| 87 | + // 2.3 更新数据库 | |
| 69 | 88 | itemReceiptLineMapper.updateById(updateObj); |
| 70 | - | |
| 71 | - // TODO @芋艿:【暂时不处理】wmBatchService 需要生成下;基于 batchCode | |
| 72 | 89 | } |
| 73 | 90 | |
| 74 | 91 | @Override |
| ... | ... | @@ -134,4 +151,31 @@ public class MesWmItemReceiptLineServiceImpl implements MesWmItemReceiptLineServ |
| 134 | 151 | return line; |
| 135 | 152 | } |
| 136 | 153 | |
| 154 | + /** | |
| 155 | + * 生成或获取批次 | |
| 156 | + * | |
| 157 | + * @param receipt 入库单 | |
| 158 | + * @param reqVO 入库单行请求VO | |
| 159 | + * @return 批次记录(如果物料未启用批次管理则返回 null) | |
| 160 | + */ | |
| 161 | + private MesWmBatchDO generateOrGetBatch(MesWmItemReceiptDO receipt, MesWmItemReceiptLineSaveReqVO reqVO) { | |
| 162 | + // 构建批次参数 VO | |
| 163 | + MesWmBatchGenerateReqVO batchReqVO = new MesWmBatchGenerateReqVO(); | |
| 164 | + // 从入库单行获取 | |
| 165 | + batchReqVO.setItemId(reqVO.getItemId()).setProduceDate(reqVO.getProductionDate()) | |
| 166 | + .setExpireDate(reqVO.getExpireDate()).setLotNumber(reqVO.getProductionBatchNumber()); | |
| 167 | + // 从父单据获取 | |
| 168 | + batchReqVO.setVendorId(receipt.getVendorId()).setReceiptDate(receipt.getReceiptDate()); | |
| 169 | + // 从到货通知单获取采购订单号(如果关联了到货通知单) | |
| 170 | + if (receipt.getNoticeId() != null) { | |
| 171 | + MesWmArrivalNoticeDO notice = arrivalNoticeService.getArrivalNotice(receipt.getNoticeId()); | |
| 172 | + if (notice != null) { | |
| 173 | + batchReqVO.setPurchaseOrderCode(notice.getPurchaseOrderCode()); | |
| 174 | + } | |
| 175 | + } | |
| 176 | + | |
| 177 | + // 生成或获取批次 | |
| 178 | + return batchService.getOrGenerateBatchCode(batchReqVO); | |
| 179 | + } | |
| 180 | + | |
| 137 | 181 | } | ... | ... |