From 81193982eea08877a04cd55c942643a8a2fcbe65 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 1 Mar 2026 13:16:39 +0800 Subject: [PATCH] ✨ feat(mes): 添加产品收货单明细数量校验功能 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/MesWmProductRecptController.java | 8 ++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptPageReqVO.java | 12 ------------ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptSaveReqVO.java | 9 +-------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/line/MesWmProductRecptLineSaveReqVO.java | 2 ++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productrecpt/MesWmProductRecptMapper.java | 2 -- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductRecptStatusEnum.java | 15 +++++++++++++-- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptService.java | 8 ++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptServiceImpl.java | 34 ++++++++++++++++++++++++++++------ 8 files changed, 60 insertions(+), 30 deletions(-) diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/MesWmProductRecptController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/MesWmProductRecptController.java index 9b4106e..9915e2e 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/MesWmProductRecptController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/MesWmProductRecptController.java @@ -149,6 +149,14 @@ public class MesWmProductRecptController { return success(true); } + @GetMapping("/check-quantity") + @Operation(summary = "校验产品收货单明细数量") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:wm-product-recpt:query')") + public CommonResult checkProductRecptQuantity(@RequestParam("id") Long id) { + return success(productRecptService.checkProductRecptQuantity(id)); + } + // ==================== 拼接 VO ==================== private List buildRespVOList(List list) { diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptPageReqVO.java index d063260..3a973a2 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptPageReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptPageReqVO.java @@ -5,11 +5,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @Schema(description = "管理后台 - MES 产品收货单分页 Request VO") @Data @@ -29,11 +24,4 @@ public class MesWmProductRecptPageReqVO extends PageParam { @Schema(description = "产品物料编号", example = "1") private Long itemId; - @Schema(description = "状态", example = "0") - private Integer status; - - @Schema(description = "收货日期") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] receiptDate; - } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptSaveReqVO.java index d96f64f..904b98e 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptSaveReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/MesWmProductRecptSaveReqVO.java @@ -22,16 +22,9 @@ public class MesWmProductRecptSaveReqVO { @NotEmpty(message = "收货单名称不能为空") private String name; - @Schema(description = "生产工单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - // TODO @AI:workOrderId 必须要非必传 - @NotNull(message = "生产工单不能为空") + @Schema(description = "生产工单编号", example = "1") private Long workOrderId; - @Schema(description = "产品物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "产品物料不能为空") - // TODO @AI:workOrderId 必须要非必传 - private Long itemId; - @Schema(description = "收货日期", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "收货日期不能为空") private LocalDateTime receiptDate; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/line/MesWmProductRecptLineSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/line/MesWmProductRecptLineSaveReqVO.java index 7806589..2605814 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/line/MesWmProductRecptLineSaveReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productrecpt/vo/line/MesWmProductRecptLineSaveReqVO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.controller.admin.wm.productrecpt.vo.line; 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; @@ -23,6 +24,7 @@ public class MesWmProductRecptLineSaveReqVO { @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/dal/mysql/wm/productrecpt/MesWmProductRecptMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productrecpt/MesWmProductRecptMapper.java index c3f560b..3e2ae75 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productrecpt/MesWmProductRecptMapper.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productrecpt/MesWmProductRecptMapper.java @@ -19,8 +19,6 @@ public interface MesWmProductRecptMapper extends BaseMapperX { - // TODO @AI:对应的方法;参考别的 MesWmProductionIssueStatusEnum /** * 草稿 + * + * 对应方法:{@link MesWmProductRecptService#createProductRecpt(MesWmProductRecptSaveReqVO)} */ PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), /** * 待上架 + * + * 对应方法:{@link MesWmProductRecptService#submitProductRecpt(Long)} */ APPROVING(MesOrderStatusConstants.APPROVING, "待上架"), /** * 待执行入库 + * + * 对应方法:{@link MesWmProductRecptService#stockProductRecpt(Long)} */ APPROVED(MesOrderStatusConstants.APPROVED, "待执行入库"), /** * 已完成 + * + * 对应方法:{@link MesWmProductRecptService#executeProductRecpt(Long)} */ FINISHED(MesOrderStatusConstants.FINISHED, "已完成"), /** * 已取消 + * + * 对应方法:{@link MesWmProductRecptService#cancelProductRecpt(Long)} */ CANCELED(MesOrderStatusConstants.CANCELLED, "已取消"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptService.java index db42864..0e069d8 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptService.java @@ -85,4 +85,12 @@ public interface MesWmProductRecptService { */ MesWmProductRecptDO validateProductRecptEditable(Long id); + /** + * 校验产品收货单明细数量(每行明细数量之和是否等于行收货数量) + * + * @param id 编号 + * @return 是否匹配 + */ + Boolean checkProductRecptQuantity(Long id); + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptServiceImpl.java index f37400f..72adc3c 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productrecpt/MesWmProductRecptServiceImpl.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.mes.controller.admin.wm.productrecpt.vo.MesWmProductRecptPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productrecpt.vo.MesWmProductRecptSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productrecpt.MesWmProductRecptDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productrecpt.MesWmProductRecptDetailDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productrecpt.MesWmProductRecptLineDO; @@ -44,13 +45,22 @@ public class MesWmProductRecptServiceImpl implements MesWmProductRecptService { @Resource private MesWmMaterialStockService materialStockService; + @Resource + private cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService workOrderService; + @Override public Long createProductRecpt(MesWmProductRecptSaveReqVO createReqVO) { // 校验编码唯一 validateCodeUnique(null, createReqVO.getCode()); + // 校验工单存在并设置 itemId + MesProWorkOrderDO workOrder = createReqVO.getWorkOrderId() != null ? + workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId()) : null; // 插入 MesWmProductRecptDO recpt = BeanUtils.toBean(createReqVO, MesWmProductRecptDO.class); + if (workOrder != null) { + recpt.setItemId(workOrder.getProductId()); + } recpt.setStatus(MesWmProductRecptStatusEnum.PREPARE.getStatus()); productRecptMapper.insert(recpt); return recpt.getId(); @@ -62,9 +72,15 @@ public class MesWmProductRecptServiceImpl implements MesWmProductRecptService { validateProductRecptExistsAndDraft(updateReqVO.getId()); // 校验编码唯一 validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); + // 校验工单存在 + MesProWorkOrderDO workOrder = updateReqVO.getWorkOrderId() != null ? + workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId()) : null; // 更新 MesWmProductRecptDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductRecptDO.class); + if (workOrder != null) { + updateObj.setItemId(workOrder.getProductId()); + } productRecptMapper.updateById(updateObj); } @@ -115,20 +131,24 @@ public class MesWmProductRecptServiceImpl implements MesWmProductRecptService { if (ObjUtil.notEqual(MesWmProductRecptStatusEnum.APPROVING.getStatus(), recpt.getStatus())) { throw exception(WM_PRODUCT_RECPT_STATUS_ERROR); } - // 校验每行明细数量之和是否等于行收货数量 + + // 执行上架(待上架 → 待入库) + productRecptMapper.updateById(new MesWmProductRecptDO() + .setId(id).setStatus(MesWmProductRecptStatusEnum.APPROVED.getStatus())); + } + + @Override + public Boolean checkProductRecptQuantity(Long id) { List lines = productRecptLineService.getProductRecptLineListByRecptId(id); for (MesWmProductRecptLineDO line : lines) { List details = productRecptDetailService.getProductRecptDetailListByLineId(line.getId()); BigDecimal totalDetailQty = CollectionUtils.getSumValue(details, MesWmProductRecptDetailDO::getQuantity, BigDecimal::add, BigDecimal.ZERO); if (line.getQuantity() != null && totalDetailQty.compareTo(line.getQuantity()) != 0) { - throw exception(WM_PRODUCT_RECPT_DETAIL_QUANTITY_MISMATCH); + return false; } } - - // 执行上架(待上架 → 待入库) - productRecptMapper.updateById(new MesWmProductRecptDO() - .setId(id).setStatus(MesWmProductRecptStatusEnum.APPROVED.getStatus())); + return true; } @Override @@ -141,6 +161,7 @@ public class MesWmProductRecptServiceImpl implements MesWmProductRecptService { } // 遍历所有明细,更新库存台账 + // TODO @芋艿:【后面优化】 List details = productRecptDetailService.getProductRecptDetailListByRecptId(id); for (MesWmProductRecptDetailDO detail : details) { materialStockService.increaseStock( @@ -164,6 +185,7 @@ public class MesWmProductRecptServiceImpl implements MesWmProductRecptService { MesWmProductRecptStatusEnum.CANCELED.getStatus())) { throw exception(WM_PRODUCT_RECPT_CANCEL_NOT_ALLOWED); } + // 取消 productRecptMapper.updateById(new MesWmProductRecptDO() .setId(id).setStatus(MesWmProductRecptStatusEnum.CANCELED.getStatus())); -- libgit2 0.21.4