From deb6cac081fd2e6b2ad459e5b3050b5fa4042144 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 30 Mar 2026 12:54:12 +0800 Subject: [PATCH] ✨ feat(mes): 增强产品入库单功能,新增数量校验和明细检查 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productreceipt/vo/detail/MesWmProductReceiptDetailSaveReqVO.java | 2 ++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 1 + yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptDetailServiceImpl.java | 36 +++++++++++++++++++++++------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptLineServiceImpl.java | 33 +++++++++++++++++++++++++-------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java | 50 ++++++++++++++++++++++++++++---------------------- 5 files changed, 79 insertions(+), 43 deletions(-) diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productreceipt/vo/detail/MesWmProductReceiptDetailSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productreceipt/vo/detail/MesWmProductReceiptDetailSaveReqVO.java index dedda4b..5b645f4 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productreceipt/vo/detail/MesWmProductReceiptDetailSaveReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productreceipt/vo/detail/MesWmProductReceiptDetailSaveReqVO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.controller.admin.wm.productreceipt.vo.detail import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; import lombok.Data; import java.math.BigDecimal; @@ -27,6 +28,7 @@ public class MesWmProductReceiptDetailSaveReqVO { @Schema(description = "上架数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") @NotNull(message = "上架数量不能为空") + @Positive(message = "上架数量必须大于 0") private BigDecimal quantity; @Schema(description = "批次编号", example = "1") 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 5261196..904e208 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 @@ -491,6 +491,7 @@ public interface ErrorCodeConstants { ErrorCode WM_PRODUCT_RECPT_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_712_004, "明细上架总数与行收货数量不匹配"); ErrorCode WM_PRODUCT_RECPT_STATUS_ERROR = new ErrorCode(1_040_712_005, "收货单状态不正确"); ErrorCode WM_PRODUCT_RECPT_CANCEL_NOT_ALLOWED = new ErrorCode(1_040_712_006, "已完成或已取消的收货单不允许取消"); + ErrorCode WM_PRODUCT_RECPT_NO_DETAIL = new ErrorCode(1_040_712_007, "收货单没有上架明细,无法执行入库"); ErrorCode WM_PRODUCT_RECPT_LINE_NOT_EXISTS = new ErrorCode(1_040_712_100, "产品收货单行不存在"); ErrorCode WM_PRODUCT_RECPT_DETAIL_NOT_EXISTS = new ErrorCode(1_040_712_200, "产品收货明细不存在"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptDetailServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptDetailServiceImpl.java index 26038c2..06c3596 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptDetailServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptDetailServiceImpl.java @@ -34,12 +34,10 @@ public class MesWmProductReceiptDetailServiceImpl implements MesWmProductReceipt @Override public Long createProductReceiptDetail(MesWmProductReceiptDetailSaveReqVO createReqVO) { - // 校验父单据存在且为可编辑状态 - productReceiptService.validateProductReceiptEditable(createReqVO.getReceiptId()); - // 校验库区关系 - warehouseAreaService.validateWarehouseAreaExists( - createReqVO.getWarehouseId(), createReqVO.getLocationId(), createReqVO.getAreaId()); + // 1. 校验关联数据 + validateProductReceiptDetailSaveData(createReqVO); + // 2. 新增 MesWmProductReceiptDetailDO detail = BeanUtils.toBean(createReqVO, MesWmProductReceiptDetailDO.class); productReceiptDetailMapper.insert(detail); return detail.getId(); @@ -47,15 +45,13 @@ public class MesWmProductReceiptDetailServiceImpl implements MesWmProductReceipt @Override public void updateProductReceiptDetail(MesWmProductReceiptDetailSaveReqVO updateReqVO) { - // 校验存在 + // 1.1 校验存在 MesWmProductReceiptDetailDO detail = validateProductReceiptDetailExists(updateReqVO.getId()); - // 校验父单据存在且为可编辑状态 - productReceiptService.validateProductReceiptEditable(detail.getReceiptId()); - // 校验库区关系 - warehouseAreaService.validateWarehouseAreaExists( - updateReqVO.getWarehouseId(), updateReqVO.getLocationId(), updateReqVO.getAreaId()); + // 1.2 校验关联数据 + updateReqVO.setReceiptId(detail.getReceiptId()); + validateProductReceiptDetailSaveData(updateReqVO); - // 更新 + // 2. 更新 MesWmProductReceiptDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductReceiptDetailDO.class); productReceiptDetailMapper.updateById(updateObj); } @@ -63,7 +59,10 @@ public class MesWmProductReceiptDetailServiceImpl implements MesWmProductReceipt @Override public void deleteProductReceiptDetail(Long id) { // 校验存在 - validateProductReceiptDetailExists(id); + MesWmProductReceiptDetailDO detail = validateProductReceiptDetailExists(id); + // 校验父单据存在且为可编辑状态 + productReceiptService.validateProductReceiptEditable(detail.getReceiptId()); + // 删除 productReceiptDetailMapper.deleteById(id); } @@ -101,4 +100,15 @@ public class MesWmProductReceiptDetailServiceImpl implements MesWmProductReceipt return detail; } + /** + * 校验明细保存时的关联数据 + */ + private void validateProductReceiptDetailSaveData(MesWmProductReceiptDetailSaveReqVO reqVO) { + // 校验父单据存在且为可编辑状态 + productReceiptService.validateProductReceiptEditable(reqVO.getReceiptId()); + // 校验仓库层级关系 + warehouseAreaService.validateWarehouseAreaExists( + reqVO.getWarehouseId(), reqVO.getLocationId(), reqVO.getAreaId()); + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptLineServiceImpl.java index 02248fc..4582437 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptLineServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptLineServiceImpl.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.productreceipt.vo.line.Me import cn.iocoder.yudao.module.mes.controller.admin.wm.productreceipt.vo.line.MesWmProductReceiptLineSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productreceipt.MesWmProductReceiptLineDO; import cn.iocoder.yudao.module.mes.dal.mysql.wm.productreceipt.MesWmProductReceiptLineMapper; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -34,12 +35,15 @@ public class MesWmProductReceiptLineServiceImpl implements MesWmProductReceiptLi @Resource private MesWmProductReceiptDetailService productReceiptDetailService; + @Resource + private MesMdItemService itemService; + @Override public Long createProductReceiptLine(MesWmProductReceiptLineSaveReqVO createReqVO) { - // 校验父单据存在且为可编辑状态 - productReceiptService.validateProductReceiptEditable(createReqVO.getReceiptId()); + // 1. 校验关联数据 + validateProductReceiptLineSaveData(createReqVO); - // 新增 + // 2. 新增 MesWmProductReceiptLineDO line = BeanUtils.toBean(createReqVO, MesWmProductReceiptLineDO.class); productReceiptLineMapper.insert(line); return line.getId(); @@ -47,12 +51,13 @@ public class MesWmProductReceiptLineServiceImpl implements MesWmProductReceiptLi @Override public void updateProductReceiptLine(MesWmProductReceiptLineSaveReqVO updateReqVO) { - // 校验存在 + // 1.1 校验存在 MesWmProductReceiptLineDO line = validateProductReceiptLineExists(updateReqVO.getId()); - // 校验父单据存在且为可编辑状态 - productReceiptService.validateProductReceiptEditable(line.getReceiptId()); + // 1.2 校验关联数据 + updateReqVO.setReceiptId(line.getReceiptId()); + validateProductReceiptLineSaveData(updateReqVO); - // 更新 + // 2. 更新 MesWmProductReceiptLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductReceiptLineDO.class); productReceiptLineMapper.updateById(updateObj); } @@ -61,7 +66,9 @@ public class MesWmProductReceiptLineServiceImpl implements MesWmProductReceiptLi @Transactional(rollbackFor = Exception.class) public void deleteProductReceiptLine(Long id) { // 校验存在 - validateProductReceiptLineExists(id); + MesWmProductReceiptLineDO line = validateProductReceiptLineExists(id); + // 校验父单据存在且为可编辑状态 + productReceiptService.validateProductReceiptEditable(line.getReceiptId()); // 级联删除明细 productReceiptDetailService.deleteProductReceiptDetailByLineId(id); @@ -97,4 +104,14 @@ public class MesWmProductReceiptLineServiceImpl implements MesWmProductReceiptLi return line; } + /** + * 校验行保存时的关联数据 + */ + private void validateProductReceiptLineSaveData(MesWmProductReceiptLineSaveReqVO reqVO) { + // 校验父单据存在且为可编辑状态 + productReceiptService.validateProductReceiptEditable(reqVO.getReceiptId()); + // 校验物料存在 + itemService.validateItemExists(reqVO.getItemId()); + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java index a5e5443..7e9689c 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java @@ -12,15 +12,14 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderD import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productreceipt.MesWmProductReceiptDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productreceipt.MesWmProductReceiptDetailDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productreceipt.MesWmProductReceiptLineDO; -import cn.iocoder.yudao.module.mes.dal.mysql.wm.productreceipt.MesWmProductReceiptMapper; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; -import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductReceiptStatusEnum; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.productreceipt.MesWmProductReceiptMapper; import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; +import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductReceiptStatusEnum; import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum; import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; -import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService; import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; @@ -54,9 +53,6 @@ public class MesWmProductReceiptServiceImpl implements MesWmProductReceiptServic private MesWmProductReceiptDetailService productReceiptDetailService; @Resource - private MesWmMaterialStockService materialStockService; - - @Resource private MesWmTransactionService wmTransactionService; @Resource @@ -70,13 +66,10 @@ public class MesWmProductReceiptServiceImpl implements MesWmProductReceiptServic @Override public Long createProductReceipt(MesWmProductReceiptSaveReqVO createReqVO) { - // 校验编码唯一 - validateCodeUnique(null, createReqVO.getCode()); - // 校验工单存在并设置 itemId - MesProWorkOrderDO workOrder = createReqVO.getWorkOrderId() != null ? - workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId()) : null; + // 1. 校验关联数据 + MesProWorkOrderDO workOrder = validateProductReceiptSaveData(createReqVO); - // 插入 + // 2. 插入 MesWmProductReceiptDO receipt = BeanUtils.toBean(createReqVO, MesWmProductReceiptDO.class); if (workOrder != null) { receipt.setItemId(workOrder.getProductId()); @@ -88,15 +81,12 @@ public class MesWmProductReceiptServiceImpl implements MesWmProductReceiptServic @Override public void updateProductReceipt(MesWmProductReceiptSaveReqVO updateReqVO) { - // 校验存在 + 草稿状态 + // 1.1 校验存在 + 草稿状态 validateProductReceiptExistsAndDraft(updateReqVO.getId()); - // 校验编码唯一 - validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); - // 校验工单存在 - MesProWorkOrderDO workOrder = updateReqVO.getWorkOrderId() != null ? - workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId()) : null; + // 1.2 校验关联数据 + MesProWorkOrderDO workOrder = validateProductReceiptSaveData(updateReqVO); - // 更新 + // 2. 更新 MesWmProductReceiptDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductReceiptDO.class); if (workOrder != null) { updateObj.setItemId(workOrder.getProductId()); @@ -179,23 +169,27 @@ public class MesWmProductReceiptServiceImpl implements MesWmProductReceiptServic if (ObjUtil.notEqual(MesWmProductReceiptStatusEnum.APPROVED.getStatus(), receipt.getStatus())) { throw exception(WM_PRODUCT_RECPT_STATUS_ERROR); } + // 校验明细非空 + List details = productReceiptDetailService.getProductReceiptDetailListByRecptId(id); + if (CollUtil.isEmpty(details)) { + throw exception(WM_PRODUCT_RECPT_NO_DETAIL); + } // 创建库存事务 - createTransactionList(receipt); + createTransactionList(receipt, details); // 更新收货单状态 productReceiptMapper.updateById(new MesWmProductReceiptDO() .setId(id).setStatus(MesWmProductReceiptStatusEnum.FINISHED.getStatus())); } - private void createTransactionList(MesWmProductReceiptDO receipt) { + private void createTransactionList(MesWmProductReceiptDO receipt, List details) { // 1. 查询虚拟线边库 MesWmWarehouseDO virtualWarehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE); MesWmWarehouseLocationDO virtualLocation = locationService.getWarehouseLocationByCode(MesWmWarehouseLocationDO.WIP_VIRTUAL_LOCATION); MesWmWarehouseAreaDO virtualArea = areaService.getWarehouseAreaByCode(MesWmWarehouseAreaDO.WIP_VIRTUAL_AREA); // 2. 遍历明细,每条明细产生 OUT(虚拟线边库扣减)+ IN(实际仓库增加) - List details = productReceiptDetailService.getProductReceiptDetailListByRecptId(receipt.getId()); for (MesWmProductReceiptDetailDO detail : details) { // 2.1 先从虚拟线边库出库(库存减少) Long outTransactionId = wmTransactionService.createTransaction(new MesWmTransactionSaveReqDTO() @@ -263,6 +257,18 @@ public class MesWmProductReceiptServiceImpl implements MesWmProductReceiptServic } return receipt; } + /** + * 校验保存时的关联数据 + * + * @return 工单对象(可能为 null) + */ + private MesProWorkOrderDO validateProductReceiptSaveData(MesWmProductReceiptSaveReqVO reqVO) { + // 校验编码唯一 + validateCodeUnique(reqVO.getId(), reqVO.getCode()); + // 校验工单存在 + return reqVO.getWorkOrderId() != null ? + workOrderService.validateWorkOrderExists(reqVO.getWorkOrderId()) : null; + } private void validateCodeUnique(Long id, String code) { MesWmProductReceiptDO receipt = productReceiptMapper.selectByCode(code); -- libgit2 0.21.4