Commit ff8aea9dd3610085d64203500046125254666100

Authored by YunaiV
1 parent c9dedd68

✨ feat(mes): 添加物料编码、名称及规格字段,更新状态管理

yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/MesWmTransferDetailController.java
1 1 package cn.iocoder.yudao.module.mes.controller.admin.wm.transfer;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
4 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 7 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.detail.MesWmTransferDetailRespVO;
6 8 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.detail.MesWmTransferDetailSaveReqVO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
7 11 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDetailDO;
  12 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
  14 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
  15 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  16 +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
8 17 import cn.iocoder.yudao.module.mes.service.wm.transfer.MesWmTransferDetailService;
  18 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
  19 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
  20 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
9 21 import io.swagger.v3.oas.annotations.Operation;
10 22 import io.swagger.v3.oas.annotations.Parameter;
11 23 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -15,9 +27,12 @@ import org.springframework.security.access.prepost.PreAuthorize;
15 27 import org.springframework.validation.annotation.Validated;
16 28 import org.springframework.web.bind.annotation.*;
17 29  
  30 +import java.util.Collections;
18 31 import java.util.List;
  32 +import java.util.Map;
19 33  
20 34 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
21 36  
22 37 @Tag(name = "管理后台 - MES 调拨明细")
23 38 @RestController
... ... @@ -28,6 +43,21 @@ public class MesWmTransferDetailController {
28 43 @Resource
29 44 private MesWmTransferDetailService transferDetailService;
30 45  
  46 + @Resource
  47 + private MesMdItemService itemService;
  48 +
  49 + @Resource
  50 + private MesMdUnitMeasureService unitMeasureService;
  51 +
  52 + @Resource
  53 + private MesWmWarehouseService warehouseService;
  54 +
  55 + @Resource
  56 + private MesWmWarehouseLocationService locationService;
  57 +
  58 + @Resource
  59 + private MesWmWarehouseAreaService areaService;
  60 +
31 61 @PostMapping("/create")
32 62 @Operation(summary = "创建调拨明细")
33 63 @PreAuthorize("@ss.hasPermission('mes:wm-transfer:create')")
... ... @@ -58,7 +88,10 @@ public class MesWmTransferDetailController {
58 88 @PreAuthorize("@ss.hasPermission('mes:wm-transfer:query')")
59 89 public CommonResult<MesWmTransferDetailRespVO> getTransferDetail(@RequestParam("id") Long id) {
60 90 MesWmTransferDetailDO detail = transferDetailService.getTransferDetail(id);
61   - return success(BeanUtils.toBean(detail, MesWmTransferDetailRespVO.class));
  91 + if (detail == null) {
  92 + return success(null);
  93 + }
  94 + return success(buildRespVOList(Collections.singletonList(detail)).get(0));
62 95 }
63 96  
64 97 @GetMapping("/list-by-line")
... ... @@ -68,7 +101,39 @@ public class MesWmTransferDetailController {
68 101 public CommonResult<List<MesWmTransferDetailRespVO>> getTransferDetailListByLineId(
69 102 @RequestParam("lineId") Long lineId) {
70 103 List<MesWmTransferDetailDO> list = transferDetailService.getTransferDetailListByLineId(lineId);
71   - return success(BeanUtils.toBean(list, MesWmTransferDetailRespVO.class));
  104 + return success(buildRespVOList(list));
  105 + }
  106 +
  107 + // ==================== 拼接 VO ====================
  108 +
  109 + private List<MesWmTransferDetailRespVO> buildRespVOList(List<MesWmTransferDetailDO> list) {
  110 + if (CollUtil.isEmpty(list)) {
  111 + return Collections.emptyList();
  112 + }
  113 + // 查询相关数据
  114 + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(convertSet(list, MesWmTransferDetailDO::getItemId));
  115 + Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
  116 + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId));
  117 + Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
  118 + convertSet(list, MesWmTransferDetailDO::getToWarehouseId));
  119 + Map<Long, MesWmWarehouseLocationDO> locationMap = locationService.getWarehouseLocationMap(
  120 + convertSet(list, MesWmTransferDetailDO::getToLocationId));
  121 + Map<Long, MesWmWarehouseAreaDO> areaMap = areaService.getWarehouseAreaMap(
  122 + convertSet(list, MesWmTransferDetailDO::getToAreaId));
  123 + // 拼接数据
  124 + return BeanUtils.toBean(list, MesWmTransferDetailRespVO.class, vo -> {
  125 + MapUtils.findAndThen(itemMap, vo.getItemId(), item -> {
  126 + vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification());
  127 + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(),
  128 + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName()));
  129 + });
  130 + MapUtils.findAndThen(warehouseMap, vo.getToWarehouseId(),
  131 + warehouse -> vo.setToWarehouseName(warehouse.getName()));
  132 + MapUtils.findAndThen(locationMap, vo.getToLocationId(),
  133 + location -> vo.setToLocationName(location.getName()));
  134 + MapUtils.findAndThen(areaMap, vo.getToAreaId(),
  135 + area -> vo.setToAreaName(area.getName()));
  136 + });
72 137 }
73 138  
74 139 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/MesWmTransferLineController.java
1 1 package cn.iocoder.yudao.module.mes.controller.admin.wm.transfer;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
4 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 7 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.line.MesWmTransferLineRespVO;
6 8 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.line.MesWmTransferLineSaveReqVO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
7 11 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferLineDO;
  12 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
  14 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
  15 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  16 +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
8 17 import cn.iocoder.yudao.module.mes.service.wm.transfer.MesWmTransferLineService;
  18 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
  19 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
  20 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
9 21 import io.swagger.v3.oas.annotations.Operation;
10 22 import io.swagger.v3.oas.annotations.Parameter;
11 23 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -15,9 +27,12 @@ import org.springframework.security.access.prepost.PreAuthorize;
15 27 import org.springframework.validation.annotation.Validated;
16 28 import org.springframework.web.bind.annotation.*;
17 29  
  30 +import java.util.Collections;
18 31 import java.util.List;
  32 +import java.util.Map;
19 33  
20 34 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
21 36  
22 37 @Tag(name = "管理后台 - MES 转移单行")
23 38 @RestController
... ... @@ -28,6 +43,21 @@ public class MesWmTransferLineController {
28 43 @Resource
29 44 private MesWmTransferLineService transferLineService;
30 45  
  46 + @Resource
  47 + private MesMdItemService itemService;
  48 +
  49 + @Resource
  50 + private MesMdUnitMeasureService unitMeasureService;
  51 +
  52 + @Resource
  53 + private MesWmWarehouseService warehouseService;
  54 +
  55 + @Resource
  56 + private MesWmWarehouseLocationService locationService;
  57 +
  58 + @Resource
  59 + private MesWmWarehouseAreaService areaService;
  60 +
31 61 @PostMapping("/create")
32 62 @Operation(summary = "创建转移单行")
33 63 @PreAuthorize("@ss.hasPermission('mes:wm-transfer:create')")
... ... @@ -58,7 +88,10 @@ public class MesWmTransferLineController {
58 88 @PreAuthorize("@ss.hasPermission('mes:wm-transfer:query')")
59 89 public CommonResult<MesWmTransferLineRespVO> getTransferLine(@RequestParam("id") Long id) {
60 90 MesWmTransferLineDO line = transferLineService.getTransferLine(id);
61   - return success(BeanUtils.toBean(line, MesWmTransferLineRespVO.class));
  91 + if (line == null) {
  92 + return success(null);
  93 + }
  94 + return success(buildRespVOList(Collections.singletonList(line)).get(0));
62 95 }
63 96  
64 97 @GetMapping("/list")
... ... @@ -67,7 +100,39 @@ public class MesWmTransferLineController {
67 100 @PreAuthorize("@ss.hasPermission('mes:wm-transfer:query')")
68 101 public CommonResult<List<MesWmTransferLineRespVO>> getTransferLineList(@RequestParam("transferId") Long transferId) {
69 102 List<MesWmTransferLineDO> list = transferLineService.getTransferLineListByTransferId(transferId);
70   - return success(BeanUtils.toBean(list, MesWmTransferLineRespVO.class));
  103 + return success(buildRespVOList(list));
  104 + }
  105 +
  106 + // ==================== 拼接 VO ====================
  107 +
  108 + private List<MesWmTransferLineRespVO> buildRespVOList(List<MesWmTransferLineDO> list) {
  109 + if (CollUtil.isEmpty(list)) {
  110 + return Collections.emptyList();
  111 + }
  112 + // 查询相关数据
  113 + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(convertSet(list, MesWmTransferLineDO::getItemId));
  114 + Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
  115 + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId));
  116 + Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
  117 + convertSet(list, MesWmTransferLineDO::getFromWarehouseId));
  118 + Map<Long, MesWmWarehouseLocationDO> locationMap = locationService.getWarehouseLocationMap(
  119 + convertSet(list, MesWmTransferLineDO::getFromLocationId));
  120 + Map<Long, MesWmWarehouseAreaDO> areaMap = areaService.getWarehouseAreaMap(
  121 + convertSet(list, MesWmTransferLineDO::getFromAreaId));
  122 + // 拼接数据
  123 + return BeanUtils.toBean(list, MesWmTransferLineRespVO.class, vo -> {
  124 + MapUtils.findAndThen(itemMap, vo.getItemId(), item -> {
  125 + vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification());
  126 + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(),
  127 + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName()));
  128 + });
  129 + MapUtils.findAndThen(warehouseMap, vo.getFromWarehouseId(),
  130 + warehouse -> vo.setFromWarehouseName(warehouse.getName()));
  131 + MapUtils.findAndThen(locationMap, vo.getFromLocationId(),
  132 + location -> vo.setFromLocationName(location.getName()));
  133 + MapUtils.findAndThen(areaMap, vo.getFromAreaId(),
  134 + area -> vo.setFromAreaName(area.getName()));
  135 + });
71 136 }
72 137  
73 138 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/detail/MesWmTransferDetailRespVO.java
... ... @@ -20,21 +20,37 @@ public class MesWmTransferDetailRespVO {
20 20  
21 21 @Schema(description = "物料编号", example = "1")
22 22 private Long itemId;
  23 + @Schema(description = "物料编码")
  24 + private String itemCode;
  25 + @Schema(description = "物料名称")
  26 + private String itemName;
  27 + @Schema(description = "规格型号")
  28 + private String specification;
  29 + @Schema(description = "单位名称")
  30 + private String unitMeasureName;
23 31  
24 32 @Schema(description = "上架数量", example = "100")
25 33 private BigDecimal quantity;
26 34  
27 35 @Schema(description = "批次编号", example = "1")
28 36 private Long batchId;
  37 + @Schema(description = "批次号")
  38 + private String batchCode;
29 39  
30 40 @Schema(description = "移入仓库编号", example = "1")
31 41 private Long toWarehouseId;
  42 + @Schema(description = "移入仓库名称")
  43 + private String toWarehouseName;
32 44  
33 45 @Schema(description = "移入库区编号", example = "1")
34 46 private Long toLocationId;
  47 + @Schema(description = "移入库区名称")
  48 + private String toLocationName;
35 49  
36 50 @Schema(description = "移入库位编号", example = "1")
37 51 private Long toAreaId;
  52 + @Schema(description = "移入库位名称")
  53 + private String toAreaName;
38 54  
39 55 @Schema(description = "备注", example = "备注信息")
40 56 private String remark;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/detail/MesWmTransferDetailSaveReqVO.java
1 1 package cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.detail;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.DecimalMin;
  5 +import jakarta.validation.constraints.NotNull;
4 6 import lombok.Data;
5 7  
6 8 import java.math.BigDecimal;
... ... @@ -12,28 +14,36 @@ public class MesWmTransferDetailSaveReqVO {
12 14 @Schema(description = "编号", example = "1")
13 15 private Long id;
14 16  
15   - @Schema(description = "转移单行编号", example = "1")
  17 + @Schema(description = "转移单行编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + @NotNull(message = "转移单行编号不能为空")
16 19 private Long lineId;
17 20  
18   - @Schema(description = "转移单编号", example = "1")
  21 + @Schema(description = "转移单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  22 + @NotNull(message = "转移单编号不能为空")
19 23 private Long transferId;
20 24  
21   - @Schema(description = "物料编号", example = "1")
  25 + @Schema(description = "物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  26 + @NotNull(message = "物料编号不能为空")
22 27 private Long itemId;
23 28  
24   - @Schema(description = "上架数量", example = "100")
  29 + @Schema(description = "上架数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  30 + @NotNull(message = "上架数量不能为空")
  31 + @DecimalMin(value = "0.01", message = "上架数量必须大于 0")
25 32 private BigDecimal quantity;
26 33  
27 34 @Schema(description = "批次编号", example = "1")
28 35 private Long batchId;
29 36  
30   - @Schema(description = "移入仓库编号", example = "1")
  37 + @Schema(description = "移入仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  38 + @NotNull(message = "移入仓库编号不能为空")
31 39 private Long toWarehouseId;
32 40  
33   - @Schema(description = "移入库区编号", example = "1")
  41 + @Schema(description = "移入库区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  42 + @NotNull(message = "移入库区编号不能为空")
34 43 private Long toLocationId;
35 44  
36   - @Schema(description = "移入库位编号", example = "1")
  45 + @Schema(description = "移入库位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  46 + @NotNull(message = "移入库位编号不能为空")
37 47 private Long toAreaId;
38 48  
39 49 @Schema(description = "备注", example = "备注信息")
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/line/MesWmTransferLineRespVO.java
... ... @@ -20,21 +20,37 @@ public class MesWmTransferLineRespVO {
20 20  
21 21 @Schema(description = "物料编号", example = "1")
22 22 private Long itemId;
  23 + @Schema(description = "物料编码")
  24 + private String itemCode;
  25 + @Schema(description = "物料名称")
  26 + private String itemName;
  27 + @Schema(description = "规格型号")
  28 + private String specification;
  29 + @Schema(description = "单位名称")
  30 + private String unitMeasureName;
23 31  
24 32 @Schema(description = "转移数量", example = "100")
25 33 private BigDecimal quantity;
26 34  
27 35 @Schema(description = "批次编号", example = "1")
28 36 private Long batchId;
  37 + @Schema(description = "批次号")
  38 + private String batchCode;
29 39  
30 40 @Schema(description = "移出仓库编号", example = "1")
31 41 private Long fromWarehouseId;
  42 + @Schema(description = "移出仓库名称")
  43 + private String fromWarehouseName;
32 44  
33 45 @Schema(description = "移出库区编号", example = "1")
34 46 private Long fromLocationId;
  47 + @Schema(description = "移出库区名称")
  48 + private String fromLocationName;
35 49  
36 50 @Schema(description = "移出库位编号", example = "1")
37 51 private Long fromAreaId;
  52 + @Schema(description = "移出库位名称")
  53 + private String fromAreaName;
38 54  
39 55 @Schema(description = "备注", example = "备注信息")
40 56 private String remark;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/line/MesWmTransferLineSaveReqVO.java
1 1 package cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.line;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.DecimalMin;
  5 +import jakarta.validation.constraints.NotNull;
4 6 import lombok.Data;
5 7  
6 8 import java.math.BigDecimal;
... ... @@ -12,34 +14,35 @@ public class MesWmTransferLineSaveReqVO {
12 14 @Schema(description = "编号", example = "1")
13 15 private Long id;
14 16  
15   - @Schema(description = "转移单编号", example = "1")
16   - // TODO @AI:不能为空
  17 + @Schema(description = "转移单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + @NotNull(message = "转移单编号不能为空")
17 19 private Long transferId;
18 20  
19 21 @Schema(description = "库存记录编号", example = "1")
20 22 private Long materialStockId;
21 23  
22   - @Schema(description = "物料编号", example = "1")
23   - // TODO @AI:不能为空
  24 + @Schema(description = "物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  25 + @NotNull(message = "物料编号不能为空")
24 26 private Long itemId;
25 27  
26   - @Schema(description = "转移数量", example = "100")
27   - // TODO @AI:数量不能为空,且要大于 0
  28 + @Schema(description = "转移数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  29 + @NotNull(message = "转移数量不能为空")
  30 + @DecimalMin(value = "0.01", message = "转移数量必须大于 0")
28 31 private BigDecimal quantity;
29 32  
30 33 @Schema(description = "批次编号", example = "1")
31 34 private Long batchId;
32 35  
33   - @Schema(description = "移出仓库编号", example = "1")
34   - // TODO @AI:不能为空
  36 + @Schema(description = "移出仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  37 + @NotNull(message = "移出仓库编号不能为空")
35 38 private Long fromWarehouseId;
36 39  
37   - @Schema(description = "移出库区编号", example = "1")
38   - // TODO @AI:不能为空
  40 + @Schema(description = "移出库区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  41 + @NotNull(message = "移出库区编号不能为空")
39 42 private Long fromLocationId;
40 43  
41   - @Schema(description = "移出库位编号", example = "1")
42   - // TODO @AI:不能为空
  44 + @Schema(description = "移出库位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  45 + @NotNull(message = "移出库位编号不能为空")
43 46 private Long fromAreaId;
44 47  
45 48 @Schema(description = "备注", example = "备注信息")
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -401,13 +401,14 @@ public interface ErrorCodeConstants {
401 401 ErrorCode WM_TRANSFER_CODE_DUPLICATE = new ErrorCode(1_040_710_002, "转移单编号已存在");
402 402 ErrorCode WM_TRANSFER_NOT_DRAFT = new ErrorCode(1_040_710_003, "只有草稿状态的转移单才可操作");
403 403 ErrorCode WM_TRANSFER_NOT_CONFIRMED = new ErrorCode(1_040_710_004, "只有待确认状态的转移单才可执行确认");
404   - ErrorCode WM_TRANSFER_NOT_UNSTOCK = new ErrorCode(1_040_710_005, "只有待上架状态的转移单才可执行上架");
405   - ErrorCode WM_TRANSFER_NOT_UNEXECUTE = new ErrorCode(1_040_710_006, "只有待执行状态的转移单才可完成");
  404 + ErrorCode WM_TRANSFER_NOT_APPROVING = new ErrorCode(1_040_710_005, "只有待上架状态的转移单才可执行上架");
  405 + ErrorCode WM_TRANSFER_NOT_APPROVED = new ErrorCode(1_040_710_006, "只有待执行状态的转移单才可完成");
406 406 ErrorCode WM_TRANSFER_ALREADY_FINISHED = new ErrorCode(1_040_710_007, "转移单已完成或已取消,无法继续操作");
407 407 ErrorCode WM_TRANSFER_NO_LINE = new ErrorCode(1_040_710_008, "转移单至少需要一条行数据");
408 408 ErrorCode WM_TRANSFER_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_710_009, "转移单行数量与明细数量不一致");
409 409 ErrorCode WM_TRANSFER_LINE_NOT_EXISTS = new ErrorCode(1_040_710_100, "转移单行不存在");
410 410 ErrorCode WM_TRANSFER_DETAIL_NOT_EXISTS = new ErrorCode(1_040_710_200, "调拨明细不存在");
  411 + ErrorCode WM_TRANSFER_DETAIL_QUANTITY_EXCEED = new ErrorCode(1_040_710_201, "调拨明细总数量不能超过调拨单行数量");
411 412  
412 413 // ========== MES 仓库管理-生产退料单(1-040-711-000) ==========
413 414 ErrorCode WM_RETURN_ISSUE_NOT_EXISTS = new ErrorCode(1_040_710_000, "生产退料单不存在");
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmTransferStatusEnum.java
... ... @@ -30,20 +30,18 @@ public enum MesWmTransferStatusEnum implements ArrayValuable&lt;Integer&gt; {
30 30 * 对应方法:{@link MesWmTransferService#submitTransfer(Long)}
31 31 */
32 32 UNCONFIRMED(MesOrderStatusConstants.CONFIRMED, "待确认"),
33   - // TODO @AI:前后端,要不都改成 APPROVING
34 33 /**
35 34 * 待上架
36 35 *
37 36 * 对应方法:{@link MesWmTransferService#submitTransfer(Long)}、{@link MesWmTransferService#confirmTransfer(Long)}
38 37 */
39   - UNSTOCK(MesOrderStatusConstants.APPROVING, "待上架"),
40   - // TODO @AI:前后端,要不都改成 APPROVED
  38 + APPROVING(MesOrderStatusConstants.APPROVING, "待上架"),
41 39 /**
42 40 * 待执行
43 41 *
44 42 * 对应方法:{@link MesWmTransferService#stockTransfer(Long)}
45 43 */
46   - UNEXECUTE(MesOrderStatusConstants.APPROVED, "待执行"),
  44 + APPROVED(MesOrderStatusConstants.APPROVED, "待执行"),
47 45 /**
48 46 * 已完成
49 47 *
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferDetailServiceImpl.java
1 1 package cn.iocoder.yudao.module.mes.service.wm.transfer;
2 2  
  3 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
3 4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 5 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.detail.MesWmTransferDetailSaveReqVO;
5 6 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDetailDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferLineDO;
6 8 import cn.iocoder.yudao.module.mes.dal.mysql.wm.transfer.MesWmTransferDetailMapper;
  9 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
7 10 import jakarta.annotation.Resource;
8 11 import org.springframework.context.annotation.Lazy;
9 12 import org.springframework.stereotype.Service;
10 13 import org.springframework.validation.annotation.Validated;
11 14  
  15 +import java.math.BigDecimal;
12 16 import java.util.List;
13 17  
14 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
15 19 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_DETAIL_NOT_EXISTS;
  20 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_DETAIL_QUANTITY_EXCEED;
16 21  
17 22 /**
18 23 * MES 调拨明细 Service 实现类
... ... @@ -28,12 +33,21 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
28 33 @Lazy
29 34 private MesWmTransferLineService transferLineService;
30 35  
  36 + @Resource
  37 + private MesWmWarehouseAreaService warehouseAreaService;
  38 +
31 39 @Override
32 40 public Long createTransferDetail(MesWmTransferDetailSaveReqVO createReqVO) {
33   - transferLineService.validateTransferLineExists(createReqVO.getLineId());
34   - // DONE @AI:当前先保留行存在校验,其他关联校验需结合上架业务与库位规则统一设计,暂不在本轮 TODO 修复中扩展
35   - // TODO @AI:位置相关的几个校验;
36   -
  41 + // 校验父数据存在
  42 + MesWmTransferLineDO line = transferLineService.validateTransferLineExists(createReqVO.getLineId());
  43 + // 校验仓库、库区、库位的关联关系
  44 + warehouseAreaService.validateWarehouseAreaExists(
  45 + createReqVO.getToWarehouseId(), createReqVO.getToLocationId(), createReqVO.getToAreaId());
  46 + // 校验明细总数量不超过行数量
  47 + validateDetailQuantityNotExceed(createReqVO.getLineId(), createReqVO.getQuantity(), null, line);
  48 + // TODO @芋艿:不能混货
  49 +
  50 + // 插入
37 51 MesWmTransferDetailDO detail = BeanUtils.toBean(createReqVO, MesWmTransferDetailDO.class);
38 52 transferDetailMapper.insert(detail);
39 53 return detail.getId();
... ... @@ -41,19 +55,27 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
41 55  
42 56 @Override
43 57 public void updateTransferDetail(MesWmTransferDetailSaveReqVO updateReqVO) {
  58 + // 校验存在
44 59 validateTransferDetailExists(updateReqVO.getId());
45   - transferLineService.validateTransferLineExists(updateReqVO.getLineId());
46   - // DONE @AI:当前先保留行存在校验,其他关联校验需结合上架业务与库位规则统一设计,暂不在本轮 TODO 修复中扩展
47   - // TODO @AI:位置相关的几个校验;
48   -
  60 + // 校验父数据存在
  61 + MesWmTransferLineDO line = transferLineService.validateTransferLineExists(updateReqVO.getLineId());
  62 + // 校验仓库、库区、库位的关联关系
  63 + warehouseAreaService.validateWarehouseAreaExists(
  64 + updateReqVO.getToWarehouseId(), updateReqVO.getToLocationId(), updateReqVO.getToAreaId());
  65 + // 校验明细总数量不超过行数量(排除自身)
  66 + validateDetailQuantityNotExceed(updateReqVO.getLineId(), updateReqVO.getQuantity(), updateReqVO.getId(), line);
  67 + // TODO @芋艿:不能混货
  68 +
  69 + // 更新
49 70 MesWmTransferDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmTransferDetailDO.class);
50 71 transferDetailMapper.updateById(updateObj);
51 72 }
52 73  
53 74 @Override
54 75 public void deleteTransferDetail(Long id) {
55   - // DONE @AI:当前先保留行存在校验,其他关联校验需结合上架业务与库位规则统一设计,暂不在本轮 TODO 修复中扩展
  76 + // 校验存在
56 77 validateTransferDetailExists(id);
  78 + // 删除
57 79 transferDetailMapper.deleteById(id);
58 80 }
59 81  
... ... @@ -84,4 +106,26 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
84 106 }
85 107 }
86 108  
  109 + /**
  110 + * 校验明细总数量不超过行数量
  111 + *
  112 + * @param lineId 行 ID
  113 + * @param newQuantity 本次新增/修改的数量
  114 + * @param excludeDetailId 排除的明细 ID(更新时排除自身,新增时传 null)
  115 + * @param line 调拨单行
  116 + */
  117 + private void validateDetailQuantityNotExceed(Long lineId, BigDecimal newQuantity,
  118 + Long excludeDetailId, MesWmTransferLineDO line) {
  119 + // 计算已有明细总数量(排除自身)
  120 + List<MesWmTransferDetailDO> details = transferDetailMapper.selectListByLineId(lineId);
  121 + BigDecimal existingTotal = CollectionUtils.getSumValue(details,
  122 + detail -> excludeDetailId != null && excludeDetailId.equals(detail.getId())
  123 + ? BigDecimal.ZERO : detail.getQuantity(),
  124 + BigDecimal::add, BigDecimal.ZERO);
  125 + // 校验:已有 + 本次 <= 行数量
  126 + if (existingTotal.add(newQuantity).compareTo(line.getQuantity()) > 0) {
  127 + throw exception(WM_TRANSFER_DETAIL_QUANTITY_EXCEED);
  128 + }
  129 + }
  130 +
87 131 }
... ...