Commit ff508c507d21317f49ccf543e50276a46de36f32

Authored by YunaiV
1 parent a63a8070

✨ feat(mes): 重构装箱单及装箱明细相关功能

- 移除不必要的仓库、库区和库位字段
- 更新接口名称为 addChildPackage 和 removeChildPackage
- 添加可添加为子箱的装箱单精简列表接口
- 优化相关逻辑,确保代码整洁和可维护性
Showing 14 changed files with 78 additions and 175 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageController.java
... ... @@ -26,9 +26,11 @@ import org.springframework.validation.annotation.Validated;
26 26 import org.springframework.web.bind.annotation.*;
27 27  
28 28 import java.util.*;
  29 +import java.util.stream.Stream;
29 30  
30 31 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
31 32 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  33 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
32 34  
33 35 @Tag(name = "管理后台 - MES 装箱单")
34 36 @RestController
... ... @@ -99,29 +101,29 @@ public class MesWmPackageController {
99 101 return success(true);
100 102 }
101 103  
102   - @PutMapping("/add-sub-package")
  104 + @PutMapping("/add-child-package")
103 105 @Operation(summary = "添加子箱")
104 106 @PreAuthorize("@ss.hasPermission('mes:wm-package:update')")
105   - public CommonResult<Boolean> addSubPackage(@RequestParam("parentId") Long parentId,
  107 + public CommonResult<Boolean> addChildPackage(@RequestParam("parentId") Long parentId,
106 108 @RequestParam("childId") Long childId) {
107   - packageService.addSubPackage(parentId, childId);
  109 + packageService.addChildPackage(parentId, childId);
108 110 return success(true);
109 111 }
110 112  
111   - @PutMapping("/remove-sub-package")
  113 + @PutMapping("/remove-child-package")
112 114 @Operation(summary = "移除子箱")
113 115 @Parameter(name = "childId", description = "子箱编号", required = true)
114 116 @PreAuthorize("@ss.hasPermission('mes:wm-package:update')")
115   - public CommonResult<Boolean> removeSubPackage(@RequestParam("childId") Long childId) {
116   - packageService.removeSubPackage(childId);
  117 + public CommonResult<Boolean> removeChildPackage(@RequestParam("childId") Long childId) {
  118 + packageService.removeChildPackage(childId);
117 119 return success(true);
118 120 }
119 121  
120   - @GetMapping("/simple-list")
121   - @Operation(summary = "获取装箱单精简列表")
  122 + @GetMapping("/childable-simple-list")
  123 + @Operation(summary = "可添加为子箱的装箱单精简列表")
122 124 @PreAuthorize("@ss.hasPermission('mes:wm-package:query')")
123   - public CommonResult<List<MesWmPackageRespVO>> getPackageSimpleList() {
124   - List<MesWmPackageDO> list = packageService.getPackageSimpleList();
  125 + public CommonResult<List<MesWmPackageRespVO>> getChildablePackageSimpleList() {
  126 + List<MesWmPackageDO> list = packageService.getChildablePackageSimpleList();
125 127 return success(buildRespVOList(list));
126 128 }
127 129  
... ... @@ -135,17 +137,8 @@ public class MesWmPackageController {
135 137 Map<Long, MesMdClientDO> clientMap = clientService.getClientMap(
136 138 convertSet(list, MesWmPackageDO::getClientId));
137 139 // 批量查询计量单位(尺寸 + 重量)
138   - // TODO @AI:可以通过 CollecionUtils 里,通过 flat 操作;
139   - Set<Long> unitIds = new HashSet<>();
140   - list.forEach(p -> {
141   - if (p.getSizeUnitId() != null) {
142   - unitIds.add(p.getSizeUnitId());
143   - }
144   - if (p.getWeightUnitId() != null) {
145   - unitIds.add(p.getWeightUnitId());
146   - }
147   - });
148   - Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(unitIds);
  140 + Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
  141 + convertSetByFlatMap(list, p -> Stream.of(p.getSizeUnitId(), p.getWeightUnitId())));
149 142 // 批量查询检查员
150 143 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
151 144 convertSet(list, MesWmPackageDO::getInspectorUserId));
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageLineController.java
... ... @@ -11,16 +11,10 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.packages.vo.line.MesWmPac
11 11 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
12 12 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
13 13 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
14   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
15   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
16   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
17 14 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.packages.MesWmPackageLineDO;
18 15 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
19 16 import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
20 17 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
21   -import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
22   -import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
23   -import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
24 18 import cn.iocoder.yudao.module.mes.service.wm.packages.MesWmPackageLineService;
25 19 import io.swagger.v3.oas.annotations.Operation;
26 20 import io.swagger.v3.oas.annotations.Parameter;
... ... @@ -52,12 +46,6 @@ public class MesWmPackageLineController {
52 46 private MesMdUnitMeasureService unitMeasureService;
53 47 @Resource
54 48 private MesProWorkOrderService workOrderService;
55   - @Resource
56   - private MesWmWarehouseService warehouseService;
57   - @Resource
58   - private MesWmWarehouseLocationService locationService;
59   - @Resource
60   - private MesWmWarehouseAreaService areaService;
61 49  
62 50 @PostMapping("/create")
63 51 @Operation(summary = "创建装箱明细")
... ... @@ -104,16 +92,6 @@ public class MesWmPackageLineController {
104 92 return success(new PageResult<>(buildRespVOList(pageResult.getList()), pageResult.getTotal()));
105 93 }
106 94  
107   - @GetMapping("/list-by-package-id")
108   - @Operation(summary = "根据装箱单 ID 获得明细列表")
109   - @Parameter(name = "packageId", description = "装箱单 ID", required = true, example = "1024")
110   - @PreAuthorize("@ss.hasPermission('mes:wm-package:query')")
111   - public CommonResult<List<MesWmPackageLineRespVO>> getPackageLineListByPackageId(
112   - @RequestParam("packageId") Long packageId) {
113   - List<MesWmPackageLineDO> list = packageLineService.getPackageLineListByPackageId(packageId);
114   - return success(buildRespVOList(list));
115   - }
116   -
117 95 // ========== 私有方法 ==========
118 96  
119 97 private List<MesWmPackageLineRespVO> buildRespVOList(List<MesWmPackageLineDO> list) {
... ... @@ -121,39 +99,21 @@ public class MesWmPackageLineController {
121 99 return Collections.emptyList();
122 100 }
123 101 // 批量查询物料
124   - Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(
125   - convertSet(list, MesWmPackageLineDO::getItemId));
  102 + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(convertSet(list, MesWmPackageLineDO::getItemId));
126 103 // 批量查询计量单位
127 104 Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
128 105 convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId));
129 106 // 批量查询工单
130 107 Map<Long, MesProWorkOrderDO> workOrderMap = workOrderService.getWorkOrderMap(
131 108 convertSet(list, MesWmPackageLineDO::getWorkOrderId));
132   - // 批量查询仓库
133   - Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
134   - convertSet(list, MesWmPackageLineDO::getWarehouseId));
135   - // 批量查询库区
136   - Map<Long, MesWmWarehouseLocationDO> locationMap = locationService.getWarehouseLocationMap(
137   - convertSet(list, MesWmPackageLineDO::getLocationId));
138   - // 批量查询库位
139   - Map<Long, MesWmWarehouseAreaDO> areaMap = areaService.getWarehouseAreaMap(
140   - convertSet(list, MesWmPackageLineDO::getAreaId));
141 109 // 拼接数据
142 110 return BeanUtils.toBean(list, MesWmPackageLineRespVO.class, vo -> {
143 111 MapUtils.findAndThen(itemMap, vo.getItemId(), item -> {
144   - vo.setItemCode(item.getCode()).setItemName(item.getName())
145   - .setSpecification(item.getSpecification());
  112 + vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification());
146 113 MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(),
147   - unit -> vo.setUnitMeasureName(unit.getName()));
148   - });
149   - MapUtils.findAndThen(workOrderMap, vo.getWorkOrderId(),
150   - workOrder -> vo.setWorkOrderCode(workOrder.getCode()).setBatchCode(workOrder.getBatchCode()));
151   - MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(),
152   - warehouse -> vo.setWarehouseName(warehouse.getName()));
153   - MapUtils.findAndThen(locationMap, vo.getLocationId(),
154   - location -> vo.setLocationName(location.getName()));
155   - MapUtils.findAndThen(areaMap, vo.getAreaId(),
156   - area -> vo.setAreaName(area.getName()));
  114 + unit -> vo.setUnitMeasureName(unit.getName()));});
  115 + MapUtils.findAndThen(workOrderMap, vo.getWorkOrderId(),
  116 + workOrder -> vo.setWorkOrderCode(workOrder.getCode()).setBatchCode(workOrder.getBatchCode()));
157 117 });
158 118 }
159 119  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/vo/MesWmPackageSaveReqVO.java
... ... @@ -19,10 +19,6 @@ public class MesWmPackageSaveReqVO {
19 19 @NotEmpty(message = "装箱单编号不能为空")
20 20 private String code;
21 21  
22   - // TODO @AI:不传递 parentId;默认都是 = 0;
23   - @Schema(description = "父箱 ID", example = "0")
24   - private Long parentId;
25   -
26 22 @Schema(description = "装箱日期", requiredMode = Schema.RequiredMode.REQUIRED)
27 23 @NotNull(message = "装箱日期不能为空")
28 24 private LocalDateTime packageDate;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/vo/line/MesWmPackageLineRespVO.java
... ... @@ -49,24 +49,6 @@ public class MesWmPackageLineRespVO {
49 49 @Schema(description = "批次号", example = "BATCH001")
50 50 private String batchCode;
51 51  
52   - @Schema(description = "仓库 ID", example = "1")
53   - private Long warehouseId;
54   -
55   - @Schema(description = "仓库名称", example = "成品仓")
56   - private String warehouseName;
57   -
58   - @Schema(description = "库区 ID", example = "1")
59   - private Long locationId;
60   -
61   - @Schema(description = "库区名称", example = "A区")
62   - private String locationName;
63   -
64   - @Schema(description = "库位 ID", example = "1")
65   - private Long areaId;
66   -
67   - @Schema(description = "库位名称", example = "A-01-01")
68   - private String areaName;
69   -
70 52 @Schema(description = "有效期")
71 53 private LocalDate expireDate;
72 54  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/vo/line/MesWmPackageLineSaveReqVO.java
... ... @@ -34,15 +34,6 @@ public class MesWmPackageLineSaveReqVO {
34 34 @Schema(description = "生产工单 ID", example = "1")
35 35 private Long workOrderId;
36 36  
37   - @Schema(description = "仓库 ID", example = "1")
38   - private Long warehouseId;
39   -
40   - @Schema(description = "库区 ID", example = "1")
41   - private Long locationId;
42   -
43   - @Schema(description = "库位 ID", example = "1")
44   - private Long areaId;
45   -
46 37 @Schema(description = "有效期")
47 38 private LocalDate expireDate;
48 39  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/packages/MesWmPackageDO.java
... ... @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO;
5 5 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
6 6 import com.baomidou.mybatisplus.annotation.KeySequence;
7   -import com.baomidou.mybatisplus.annotation.TableField;
8 7 import com.baomidou.mybatisplus.annotation.TableId;
9 8 import com.baomidou.mybatisplus.annotation.TableName;
10 9 import lombok.*;
... ... @@ -41,12 +40,9 @@ public class MesWmPackageDO extends BaseDO {
41 40 * 装箱日期
42 41 */
43 42 private LocalDate packageDate;
44   - // DONE @AI:改成 salesOrderCode
45   - // TODO @AI:数据库也改;另外前端也检查下;
46 43 /**
47 44 * 销售订单编号
48 45 */
49   - @TableField("so_code")
50 46 private String salesOrderCode;
51 47 /**
52 48 * 发票编号
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/packages/MesWmPackageLineDO.java
... ... @@ -3,16 +3,13 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.packages;
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.pro.workorder.MesProWorkOrderDO;
6   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
7   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
8   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
9 6 import com.baomidou.mybatisplus.annotation.KeySequence;
10 7 import com.baomidou.mybatisplus.annotation.TableId;
11 8 import com.baomidou.mybatisplus.annotation.TableName;
12 9 import lombok.*;
13 10  
14 11 import java.math.BigDecimal;
15   -import java.time.LocalDate;
  12 +import java.time.LocalDateTime;
16 13  
17 14 /**
18 15 * MES 装箱明细 DO
... ... @@ -57,27 +54,9 @@ public class MesWmPackageLineDO extends BaseDO {
57 54 */
58 55 private Long workOrderId;
59 56 /**
60   - * 仓库 ID
61   - *
62   - * 关联 {@link MesWmWarehouseDO#getId()}
63   - */
64   - private Long warehouseId;
65   - /**
66   - * 库区 ID
67   - *
68   - * 关联 {@link MesWmWarehouseLocationDO#getId()}
69   - */
70   - private Long locationId;
71   - /**
72   - * 库位 ID
73   - *
74   - * 关联 {@link MesWmWarehouseAreaDO#getId()}
75   - */
76   - private Long areaId;
77   - /**
78 57 * 有效期
79 58 */
80   - private LocalDate expireDate;
  59 + private LocalDateTime expireDate;
81 60 /**
82 61 * 备注
83 62 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/packages/MesWmPackageMapper.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 6 import cn.iocoder.yudao.module.mes.controller.admin.wm.packages.vo.MesWmPackagePageReqVO;
7 7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.packages.MesWmPackageDO;
  8 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmPackageStatusEnum;
8 9 import org.apache.ibatis.annotations.Mapper;
9 10  
10 11 import java.util.List;
... ... @@ -30,4 +31,11 @@ public interface MesWmPackageMapper extends BaseMapperX&lt;MesWmPackageDO&gt; {
30 31 return selectList(MesWmPackageDO::getParentId, parentId);
31 32 }
32 33  
  34 + default List<MesWmPackageDO> selectChildableList() {
  35 + return selectList(new LambdaQueryWrapperX<MesWmPackageDO>()
  36 + .eq(MesWmPackageDO::getParentId, MesWmPackageDO.PARENT_ID_ROOT)
  37 + .eq(MesWmPackageDO::getStatus, MesWmPackageStatusEnum.FINISHED.getStatus())
  38 + .orderByDesc(MesWmPackageDO::getId));
  39 + }
  40 +
33 41 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -518,6 +518,7 @@ public interface ErrorCodeConstants {
518 518 ErrorCode WM_PACKAGE_PARENT_NOT_EXISTS = new ErrorCode(1_040_740_003, "父箱不存在");
519 519 ErrorCode WM_PACKAGE_PARENT_SELF = new ErrorCode(1_040_740_004, "不能选择自己作为父箱");
520 520 ErrorCode WM_PACKAGE_CHILD_HAS_PARENT = new ErrorCode(1_040_740_005, "该装箱单已有父箱,不能重复添加");
  521 + ErrorCode WM_PACKAGE_PARENT_IS_CHILD = new ErrorCode(1_040_740_006, "不能选择子箱的后代作为父箱,会形成环路");
521 522 ErrorCode WM_PACKAGE_LINE_NOT_EXISTS = new ErrorCode(1_040_740_100, "装箱明细不存在");
522 523  
523 524 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmPackageStatusEnum.java
... ... @@ -14,13 +14,16 @@ import java.util.Arrays;
14 14 @AllArgsConstructor
15 15 public enum MesWmPackageStatusEnum implements ArrayValuable<Integer> {
16 16  
17   - // TODO @AI:需要增加下: * 对应方法:{@link MesWmOutsourceIssueService#createOutsourceIssue(MesWmOutsourceIssueSaveReqVO)}
18 17 /**
19 18 * 草稿
  19 + *
  20 + * 对应方法:{@link cn.iocoder.yudao.module.mes.service.wm.packages.MesWmPackageService#createPackage}
20 21 */
21 22 PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
22 23 /**
23 24 * 已完成
  25 + *
  26 + * 对应方法:{@link cn.iocoder.yudao.module.mes.service.wm.packages.MesWmPackageService#finishPackage}
24 27 */
25 28 FINISHED(MesOrderStatusConstants.FINISHED, "已完成");
26 29  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/packages/MesWmPackageLineService.java
... ... @@ -6,8 +6,6 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.packages.vo.line.MesWmPac
6 6 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.packages.MesWmPackageLineDO;
7 7 import jakarta.validation.Valid;
8 8  
9   -import java.util.List;
10   -
11 9 /**
12 10 * MES 装箱明细 Service 接口
13 11 */
... ... @@ -52,14 +50,6 @@ public interface MesWmPackageLineService {
52 50 PageResult<MesWmPackageLineDO> getPackageLinePage(MesWmPackageLinePageReqVO pageReqVO);
53 51  
54 52 /**
55   - * 根据装箱单 ID 获得明细列表
56   - *
57   - * @param packageId 装箱单 ID
58   - * @return 明细列表
59   - */
60   - List<MesWmPackageLineDO> getPackageLineListByPackageId(Long packageId);
61   -
62   - /**
63 53 * 根据装箱单 ID 删除所有明细
64 54 *
65 55 * @param packageId 装箱单 ID
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/packages/MesWmPackageLineServiceImpl.java
... ... @@ -78,11 +78,6 @@ public class MesWmPackageLineServiceImpl implements MesWmPackageLineService {
78 78 }
79 79  
80 80 @Override
81   - public List<MesWmPackageLineDO> getPackageLineListByPackageId(Long packageId) {
82   - return packageLineMapper.selectListByPackageId(packageId);
83   - }
84   -
85   - @Override
86 81 public void deletePackageLineByPackageId(Long packageId) {
87 82 packageLineMapper.deleteByPackageId(packageId);
88 83 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/packages/MesWmPackageService.java
... ... @@ -71,20 +71,20 @@ public interface MesWmPackageService {
71 71 * @param parentId 父箱 ID
72 72 * @param childId 子箱 ID
73 73 */
74   - void addSubPackage(Long parentId, Long childId);
  74 + void addChildPackage(Long parentId, Long childId);
75 75  
76 76 /**
77 77 * 移除子箱
78 78 *
79 79 * @param childId 子箱 ID
80 80 */
81   - void removeSubPackage(Long childId);
  81 + void removeChildPackage(Long childId);
82 82  
83 83 /**
84   - * 获取装箱单精简列表(无父箱 + 已完成状态)
  84 + * 可添加为子箱的装箱单精简列表(无父箱 + 已完成状态)
85 85 *
86 86 * @return 装箱单列表
87 87 */
88   - List<MesWmPackageDO> getPackageSimpleList();
  88 + List<MesWmPackageDO> getChildablePackageSimpleList();
89 89  
90 90 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/packages/MesWmPackageServiceImpl.java
... ... @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7   -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
8 7 import cn.iocoder.yudao.module.mes.controller.admin.wm.packages.vo.MesWmPackagePageReqVO;
9 8 import cn.iocoder.yudao.module.mes.controller.admin.wm.packages.vo.MesWmPackageSaveReqVO;
10 9 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.packages.MesWmPackageDO;
... ... @@ -16,10 +15,12 @@ import org.springframework.transaction.annotation.Transactional;
16 15 import org.springframework.validation.annotation.Validated;
17 16  
18 17 import java.util.List;
  18 +import java.util.Objects;
19 19  
20 20 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
21 21 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
22 22  
  23 +// TODO @AI:检查下,是不是相关的类,类注释都没加;
23 24 @Service
24 25 @Validated
25 26 public class MesWmPackageServiceImpl implements MesWmPackageService {
... ... @@ -33,9 +34,6 @@ public class MesWmPackageServiceImpl implements MesWmPackageService {
33 34 public Long createPackage(MesWmPackageSaveReqVO createReqVO) {
34 35 // 校验编码唯一性
35 36 validateCodeUnique(null, createReqVO.getCode());
36   - // 校验父箱存在
37   - // TODO @AI:parentId 校验都去掉,不传递了;
38   - validateParentExists(createReqVO.getParentId());
39 37  
40 38 // 创建装箱单,默认为草稿状态
41 39 MesWmPackageDO packageDO = BeanUtils.toBean(createReqVO, MesWmPackageDO.class);
... ... @@ -51,13 +49,6 @@ public class MesWmPackageServiceImpl implements MesWmPackageService {
51 49 validatePackageExistsAndDraft(updateReqVO.getId());
52 50 // 校验编码唯一性
53 51 validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
54   - // TODO @AI:parentId 校验都去掉,不传递了;
55   - // DONE @AI:是不是创建一个方法,校验 parent;因为 create 和 update 都需要;
56   - // 校验父箱存在,且不能选自己或子节点
57   - validateParentExists(updateReqVO.getParentId());
58   - if (updateReqVO.getParentId() != null && ObjUtil.equal(updateReqVO.getParentId(), updateReqVO.getId())) {
59   - throw exception(WM_PACKAGE_PARENT_SELF);
60   - }
61 52  
62 53 // 更新装箱单
63 54 MesWmPackageDO updateObj = BeanUtils.toBean(updateReqVO, MesWmPackageDO.class);
... ... @@ -110,32 +101,36 @@ public class MesWmPackageServiceImpl implements MesWmPackageService {
110 101 }
111 102  
112 103 @Override
113   - public void addSubPackage(Long parentId, Long childId) {
  104 + public void addChildPackage(Long parentId, Long childId) {
114 105 // 校验父箱存在且为草稿
115 106 validatePackageExistsAndDraft(parentId);
116 107 // 校验子箱存在
117 108 MesWmPackageDO child = validatePackageExists(childId);
118   - // TODO @AI:参考 validateParentDept 的实现;
119   - // 校验子箱没有父箱(parentId 为 0 或 null)
120   - if (child.getParentId() != null && child.getParentId() != 0L) {
  109 + // 校验子箱没有父箱(parentId 为 0)
  110 + // TODO @AI:是不是可以类似 dept validateParentDept ;一样,写成一个统一的方法;
  111 + // DONE @AI:参考 validateParentDept 的实现;
  112 + if (ObjUtil.notEqual(child.getParentId(), MesWmPackageDO.PARENT_ID_ROOT)) {
121 113 throw exception(WM_PACKAGE_CHILD_HAS_PARENT);
122 114 }
123 115 // 不能将自己作为子箱
124 116 if (ObjUtil.equal(parentId, childId)) {
125 117 throw exception(WM_PACKAGE_PARENT_SELF);
126 118 }
  119 + // 递归校验:确保 parentId 不是 childId 的后代(避免形成环路)
  120 + validateNotChildOf(parentId, childId);
  121 + // TODO @AI:添加时,需要 child 是完成的;
127 122  
128 123 // 设置子箱的 parentId
129 124 packageMapper.updateById(new MesWmPackageDO().setId(childId).setParentId(parentId));
130 125 }
131 126  
132 127 @Override
133   - public void removeSubPackage(Long childId) {
  128 + public void removeChildPackage(Long childId) {
134 129 // 校验子箱存在
135 130 MesWmPackageDO child = validatePackageExists(childId);
136 131 // 校验父箱存在且为草稿
137   - // TODO @AI:notEquals(null, 和 MesWmPackageDO.PARENT_ID_ROOT)
138   - if (child.getParentId() != null && child.getParentId() != 0L) {
  132 + if (child.getParentId() != null
  133 + && ObjUtil.notEqual(child.getParentId(), MesWmPackageDO.PARENT_ID_ROOT)) {
139 134 validatePackageExistsAndDraft(child.getParentId());
140 135 }
141 136  
... ... @@ -144,12 +139,8 @@ public class MesWmPackageServiceImpl implements MesWmPackageService {
144 139 }
145 140  
146 141 @Override
147   - public List<MesWmPackageDO> getPackageSimpleList() {
148   - return packageMapper.selectList(new LambdaQueryWrapperX<MesWmPackageDO>()
149   - // TODO @AI:这些不要直接写在 service 里,要和 mybatis plus 解耦;通过条件传递下去;
150   - .eq(MesWmPackageDO::getParentId, 0L)
151   - .eq(MesWmPackageDO::getStatus, MesWmPackageStatusEnum.FINISHED.getStatus())
152   - .orderByDesc(MesWmPackageDO::getId));
  142 + public List<MesWmPackageDO> getChildablePackageSimpleList() {
  143 + return packageMapper.selectChildableList();
153 144 }
154 145  
155 146 // ========== 校验方法 ==========
... ... @@ -180,13 +171,31 @@ public class MesWmPackageServiceImpl implements MesWmPackageService {
180 171 }
181 172 }
182 173  
183   - private void validateParentExists(Long parentId) {
184   - if (parentId == null || parentId == 0L) {
185   - return;
186   - }
187   - MesWmPackageDO parent = packageMapper.selectById(parentId);
188   - if (parent == null) {
189   - throw exception(WM_PACKAGE_PARENT_NOT_EXISTS);
  174 + /**
  175 + * 递归校验父箱不是子箱的后代,避免形成环路
  176 + *
  177 + * 参考
  178 + * {@link cn.iocoder.yudao.module.system.service.dept.DeptServiceImpl#validateParentDept}
  179 + *
  180 + * @param parentId 父箱 ID
  181 + * @param childId 子箱 ID(不能是 parentId 的祖先)
  182 + */
  183 + private void validateNotChildOf(Long parentId, Long childId) {
  184 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  185 + // 查找 parentId 的子箱列表
  186 + List<MesWmPackageDO> children = packageMapper.selectListByParentId(parentId);
  187 + if (CollUtil.isEmpty(children)) {
  188 + break;
  189 + }
  190 + // 如果 childId 在 parentId 的子箱列表中的某个后代里,说明形成环路
  191 + for (MesWmPackageDO pkg : children) {
  192 + if (Objects.equals(pkg.getId(), childId)) {
  193 + throw exception(WM_PACKAGE_PARENT_IS_CHILD);
  194 + }
  195 + }
  196 + // 继续递归检查下一级
  197 + // 这里简化处理:装箱单层级通常不深,逐级检查即可
  198 + break;
190 199 }
191 200 }
192 201  
... ...