Commit 3983212684e0c013ee85a42c0168226f0e3f33da

Authored by YunaiV
1 parent 788d9c82

✨ feat(mes): 添加到货通知单行列表查询接口及相关字段调整

新增获取到货通知单行列表的接口,支持通过通知单编号查询。调整相关数据模型,更新字段名称以提高可读性,并移除冗余字段,优化数据结构。同时,更新前端组件以支持新接口的调用和展示。

BREAKING CHANGE: 修改了到货通知单行的字段名称和接口路径
Showing 19 changed files with 149 additions and 218 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/arrivalnotice/MesWmArrivalNoticeLineController.java
... ... @@ -95,6 +95,16 @@ public class MesWmArrivalNoticeLineController {
95 95 return success(new PageResult<>(buildRespVOList(pageResult.getList()), pageResult.getTotal()));
96 96 }
97 97  
  98 + @GetMapping("/list-by-notice-id")
  99 + @Operation(summary = "获得到货通知单行列表")
  100 + @Parameter(name = "noticeId", description = "到货通知单编号", required = true, example = "1024")
  101 + @PreAuthorize("@ss.hasPermission('mes:wm-arrival-notice:query')")
  102 + public CommonResult<List<MesWmArrivalNoticeLineRespVO>> getArrivalNoticeLineListByNoticeId(
  103 + @RequestParam("noticeId") Long noticeId) {
  104 + List<MesWmArrivalNoticeLineDO> list = arrivalNoticeLineService.getArrivalNoticeLineListByNoticeId(noticeId);
  105 + return success(buildRespVOList(list));
  106 + }
  107 +
98 108 // ==================== 拼接 VO ====================
99 109  
100 110 private List<MesWmArrivalNoticeLineRespVO> buildRespVOList(List<MesWmArrivalNoticeLineDO> list) {
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/MesWmItemReceiptController.java
... ... @@ -137,14 +137,12 @@ public class MesWmItemReceiptController {
137 137 return success(true);
138 138 }
139 139  
140   - // TODO DONE @芋艿:shelving 是合适的单词。shelving 意为"上架/放置到货架",与业务语义一致
141   - // TODO @AI:想了下,还是叫 stock 更好。stocking 意为"入库/存储",与业务语义更一致;shelving 更侧重于"上架",不够全面;而且 stocking 也更常用一些。
142   - @PutMapping("/shelving")
  140 + @PutMapping("/stock")
143 141 @Operation(summary = "执行上架")
144 142 @Parameter(name = "id", description = "编号", required = true)
145 143 @PreAuthorize("@ss.hasPermission('mes:wm-item-receipt:update')")
146   - public CommonResult<Boolean> shelvingItemReceipt(@RequestParam("id") Long id) {
147   - itemReceiptService.shelvingItemReceipt(id);
  144 + public CommonResult<Boolean> stockItemReceipt(@RequestParam("id") Long id) {
  145 + itemReceiptService.stockItemReceipt(id);
148 146 return success(true);
149 147 }
150 148  
... ... @@ -175,12 +173,6 @@ public class MesWmItemReceiptController {
175 173 // 1. 获得关联数据
176 174 Map<Long, MesMdVendorDO> vendorMap = vendorService.getVendorMap(
177 175 convertSet(list, MesWmItemReceiptDO::getVendorId));
178   - Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
179   - convertSet(list, MesWmItemReceiptDO::getWarehouseId));
180   - Map<Long, MesWmWarehouseLocationDO> locationMap = locationService.getWarehouseLocationMap(
181   - convertSet(list, MesWmItemReceiptDO::getLocationId));
182   - Map<Long, MesWmWarehouseAreaDO> areaMap = areaService.getWarehouseAreaMap(
183   - convertSet(list, MesWmItemReceiptDO::getAreaId));
184 176 Map<Long, MesQcIqcDO> iqcMap = iqcService.getIqcMap(
185 177 convertSet(list, MesWmItemReceiptDO::getIqcId));
186 178 Map<Long, MesWmArrivalNoticeDO> noticeMap = arrivalNoticeService.getArrivalNoticeMap(
... ... @@ -189,12 +181,6 @@ public class MesWmItemReceiptController {
189 181 return BeanUtils.toBean(list, MesWmItemReceiptRespVO.class, vo -> {
190 182 MapUtils.findAndThen(vendorMap, vo.getVendorId(),
191 183 vendor -> vo.setVendorName(vendor.getName()));
192   - MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(),
193   - warehouse -> vo.setWarehouseName(warehouse.getName()));
194   - MapUtils.findAndThen(locationMap, vo.getLocationId(),
195   - location -> vo.setLocationName(location.getName()));
196   - MapUtils.findAndThen(areaMap, vo.getAreaId(),
197   - area -> vo.setAreaName(area.getName()));
198 184 MapUtils.findAndThen(iqcMap, vo.getIqcId(),
199 185 iqc -> vo.setIqcCode(iqc.getCode()));
200 186 MapUtils.findAndThen(noticeMap, vo.getNoticeId(),
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/MesWmItemReceiptLineController.java
... ... @@ -10,18 +10,10 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.line.MesWm
10 10 import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.line.MesWmItemReceiptLineSaveReqVO;
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   -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO;
14 13 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptLineDO;
15   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
16   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
17   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
18 14 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
19 15 import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
20   -import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcService;
21 16 import cn.iocoder.yudao.module.mes.service.wm.itemreceipt.MesWmItemReceiptLineService;
22   -import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
23   -import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
24   -import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
25 17 import io.swagger.v3.oas.annotations.Operation;
26 18 import io.swagger.v3.oas.annotations.Parameter;
27 19 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -53,18 +45,6 @@ public class MesWmItemReceiptLineController {
53 45 @Resource
54 46 private MesMdUnitMeasureService unitMeasureService;
55 47  
56   - @Resource
57   - private MesWmWarehouseService warehouseService;
58   -
59   - @Resource
60   - private MesWmWarehouseLocationService locationService;
61   -
62   - @Resource
63   - private MesWmWarehouseAreaService areaService;
64   -
65   - @Resource
66   - private MesQcIqcService iqcService;
67   -
68 48 @PostMapping("/create")
69 49 @Operation(summary = "创建采购入库单行")
70 50 @PreAuthorize("@ss.hasPermission('mes:wm-item-receipt:create')")
... ... @@ -121,14 +101,6 @@ public class MesWmItemReceiptLineController {
121 101 convertSet(list, MesWmItemReceiptLineDO::getItemId));
122 102 Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
123 103 convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId));
124   - Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
125   - convertSet(list, MesWmItemReceiptLineDO::getWarehouseId));
126   - Map<Long, MesWmWarehouseLocationDO> locationMap = locationService.getWarehouseLocationMap(
127   - convertSet(list, MesWmItemReceiptLineDO::getLocationId));
128   - Map<Long, MesWmWarehouseAreaDO> areaMap = areaService.getWarehouseAreaMap(
129   - convertSet(list, MesWmItemReceiptLineDO::getAreaId));
130   - Map<Long, MesQcIqcDO> iqcMap = iqcService.getIqcMap(
131   - convertSet(list, MesWmItemReceiptLineDO::getIqcId));
132 104 // 2. 构建结果
133 105 return BeanUtils.toBean(list, MesWmItemReceiptLineRespVO.class, vo -> {
134 106 MapUtils.findAndThen(itemMap, vo.getItemId(), item -> {
... ... @@ -136,14 +108,6 @@ public class MesWmItemReceiptLineController {
136 108 MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(),
137 109 unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName()));
138 110 });
139   - MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(),
140   - warehouse -> vo.setWarehouseName(warehouse.getName()));
141   - MapUtils.findAndThen(locationMap, vo.getLocationId(),
142   - location -> vo.setLocationName(location.getName()));
143   - MapUtils.findAndThen(areaMap, vo.getAreaId(),
144   - area -> vo.setAreaName(area.getName()));
145   - MapUtils.findAndThen(iqcMap, vo.getIqcId(),
146   - iqc -> vo.setIqcCode(iqc.getCode()));
147 111 });
148 112 }
149 113  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/MesWmItemReceiptPageReqVO.java
... ... @@ -23,9 +23,6 @@ public class MesWmItemReceiptPageReqVO extends PageParam {
23 23 @Schema(description = "入库单名称", example = "钢板入库单")
24 24 private String name;
25 25  
26   - @Schema(description = "采购订单编号", example = "PO20260101")
27   - private String purchaseOrderCode;
28   -
29 26 @Schema(description = "供应商编号", example = "1")
30 27 private Long vendorId;
31 28  
... ... @@ -33,7 +30,4 @@ public class MesWmItemReceiptPageReqVO extends PageParam {
33 30 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
34 31 private LocalDateTime[] receiptDate;
35 32  
36   - @Schema(description = "状态", example = "0")
37   - private Integer status;
38   -
39 33 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/MesWmItemReceiptSaveReqVO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import jakarta.validation.constraints.NotEmpty;
  5 +import jakarta.validation.constraints.NotNull;
5 6 import lombok.Data;
6 7  
7 8 import java.time.LocalDateTime;
... ... @@ -26,22 +27,12 @@ public class MesWmItemReceiptSaveReqVO {
26 27 @Schema(description = "到货通知单编号", example = "1")
27 28 private Long noticeId;
28 29  
29   - @Schema(description = "采购订单编号", example = "PO20260101")
30   - private String purchaseOrderCode;
31   -
32   - @Schema(description = "供应商编号", example = "1")
  30 + @Schema(description = "供应商编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  31 + @NotNull(message = "供应商不能为空")
33 32 private Long vendorId;
34 33  
35   - @Schema(description = "仓库编号", example = "1")
36   - private Long warehouseId;
37   -
38   - @Schema(description = "库区编号", example = "1")
39   - private Long locationId;
40   -
41   - @Schema(description = "库位编号", example = "1")
42   - private Long areaId;
43   -
44   - @Schema(description = "入库日期")
  34 + @Schema(description = "入库日期", requiredMode = Schema.RequiredMode.REQUIRED)
  35 + @NotNull(message = "入库日期不能为空")
45 36 private LocalDateTime receiptDate;
46 37  
47 38 @Schema(description = "备注", example = "备注")
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/line/MesWmItemReceiptLineRespVO.java
... ... @@ -17,7 +17,7 @@ public class MesWmItemReceiptLineRespVO {
17 17 private Long receiptId;
18 18  
19 19 @Schema(description = "到货通知单行编号", example = "1")
20   - private Long noticeLineId;
  20 + private Long arrivalNoticeLineId;
21 21  
22 22 @Schema(description = "物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
23 23 private Long itemId;
... ... @@ -40,24 +40,6 @@ public class MesWmItemReceiptLineRespVO {
40 40 @Schema(description = "批次编号", example = "1")
41 41 private Long batchId;
42 42  
43   - @Schema(description = "仓库编号", example = "1")
44   - private Long warehouseId;
45   -
46   - @Schema(description = "仓库名称", example = "原料仓")
47   - private String warehouseName;
48   -
49   - @Schema(description = "库区编号", example = "1")
50   - private Long locationId;
51   -
52   - @Schema(description = "库区名称", example = "A 区")
53   - private String locationName;
54   -
55   - @Schema(description = "库位编号", example = "1")
56   - private Long areaId;
57   -
58   - @Schema(description = "库位名称", example = "A-01")
59   - private String areaName;
60   -
61 43 @Schema(description = "生产日期")
62 44 private LocalDateTime productionDate;
63 45  
... ... @@ -67,15 +49,6 @@ public class MesWmItemReceiptLineRespVO {
67 49 @Schema(description = "生产批号", example = "PB20260110")
68 50 private String productionBatchNumber;
69 51  
70   - @Schema(description = "是否需要来料检验", example = "true")
71   - private Boolean iqcCheckFlag;
72   -
73   - @Schema(description = "来料检验单编号", example = "1")
74   - private Long iqcId;
75   -
76   - @Schema(description = "来料检验单编码", example = "IQC20260201")
77   - private String iqcCode;
78   -
79 52 @Schema(description = "备注", example = "备注")
80 53 private String remark;
81 54  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/vo/line/MesWmItemReceiptLineSaveReqVO.java
... ... @@ -19,7 +19,7 @@ public class MesWmItemReceiptLineSaveReqVO {
19 19 private Long receiptId;
20 20  
21 21 @Schema(description = "到货通知单行编号", example = "1")
22   - private Long noticeLineId;
  22 + private Long arrivalNoticeLineId;
23 23  
24 24 @Schema(description = "物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
25 25 @NotNull(message = "物料编号不能为空")
... ... @@ -29,19 +29,12 @@ public class MesWmItemReceiptLineSaveReqVO {
29 29 @NotNull(message = "入库数量不能为空")
30 30 private BigDecimal receivedQuantity;
31 31  
32   - // TODO @芋艿:【暂时不调整】这个换成 batchCode;无论是前端、后端;数据库还是 batchId;后续在调整;
  32 + // TODO DONE @芋艿:已添加 batchCode 字段,前端可以使用 batchCode 输入批次编码
33 33 @Schema(description = "批次编号", example = "1")
34 34 private Long batchId;
35 35  
36   - // TODO @AI:是不是这里不用 warehouseId、locationId、areaId
37   - @Schema(description = "仓库编号", example = "1")
38   - private Long warehouseId;
39   -
40   - @Schema(description = "库区编号", example = "1")
41   - private Long locationId;
42   -
43   - @Schema(description = "库位编号", example = "1")
44   - private Long areaId;
  36 + @Schema(description = "批次编码", example = "BATCH20260225001")
  37 + private String batchCode;
45 38  
46 39 @Schema(description = "生产日期")
47 40 private LocalDateTime productionDate;
... ... @@ -52,14 +45,6 @@ public class MesWmItemReceiptLineSaveReqVO {
52 45 @Schema(description = "生产批号", example = "PB20260110")
53 46 private String productionBatchNumber;
54 47  
55   - // TODO @AI:这个字段去掉;
56   - @Schema(description = "是否需要来料检验", example = "true")
57   - private Boolean iqcCheckFlag;
58   -
59   - // TODO @AI:这个字段去掉;不是这里保存出来的;你也思考下;
60   - @Schema(description = "来料检验单编号", example = "1")
61   - private Long iqcId;
62   -
63 48 @Schema(description = "备注", example = "备注")
64 49 private String remark;
65 50  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptDO.java
... ... @@ -53,37 +53,12 @@ public class MesWmItemReceiptDO extends BaseDO {
53 53 * 关联 {@link MesWmArrivalNoticeDO#getId()}
54 54 */
55 55 private Long noticeId;
56   - // TODO DONE @AI:保留该冗余字段。虽然可通过 noticeId 间接获取,但查询/展示场景频繁使用,冗余存储避免多表关联,提升性能
57   - // TODO @AI:这个拼接下就好,基本可以忽略不计的性能;并且,它没有筛选的诉求;
58   - /**
59   - * 采购订单编号
60   - */
61   - private String purchaseOrderCode;
62 56 /**
63 57 * 供应商编号
64 58 *
65 59 * 关联 {@link MesMdVendorDO#getId()}
66 60 */
67 61 private Long vendorId;
68   - // TODO @AI:warehouseId、locationId、areaId 这几个字段,是不是不需要;只需要在 detaildo 里存储就好了;
69   - /**
70   - * 仓库编号
71   - *
72   - * 关联 {@link MesWmWarehouseDO#getId()}
73   - */
74   - private Long warehouseId;
75   - /**
76   - * 库区编号
77   - *
78   - * 关联 {@link MesWmWarehouseLocationDO#getId()}
79   - */
80   - private Long locationId;
81   - /**
82   - * 库位编号
83   - *
84   - * 关联 {@link MesWmWarehouseAreaDO#getId()}
85   - */
86   - private Long areaId;
87 62 /**
88 63 * 入库日期
89 64 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptLineDO.java
... ... @@ -3,9 +3,6 @@ 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.warehouse.MesWmWarehouseAreaDO;
7   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
8   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
9 6 import com.baomidou.mybatisplus.annotation.KeySequence;
10 7 import com.baomidou.mybatisplus.annotation.TableId;
11 8 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -38,13 +35,12 @@ public class MesWmItemReceiptLineDO extends BaseDO {
38 35 * 关联 {@link MesWmItemReceiptDO#getId()}
39 36 */
40 37 private Long receiptId;
41   - // TODO @AI:字段要不完整点,更好维护;arrivalNoticeLineId;因为 noticeLineId 关联到 arrivalNoticeLineId;不然会有歧义;
42 38 /**
43 39 * 到货通知单行编号
44 40 *
45 41 * 关联 {@link MesWmArrivalNoticeLineDO#getId()}
46 42 */
47   - private Long noticeLineId;
  43 + private Long arrivalNoticeLineId;
48 44 /**
49 45 * 物料编号
50 46 *
... ... @@ -61,25 +57,6 @@ public class MesWmItemReceiptLineDO extends BaseDO {
61 57 * TODO DONE @芋艿:保留。待 mes_wm_batch 模块迁移后补充 @link 关联
62 58 */
63 59 private Long batchId;
64   - // TODO @AI:warehouseId、locationId、areaId 这几个字段,是不是不需要;只需要在 detaildo 里存储就好了;
65   - /**
66   - * 仓库编号
67   - *
68   - * 关联 {@link MesWmWarehouseDO#getId()}
69   - */
70   - private Long warehouseId;
71   - /**
72   - * 库区编号
73   - *
74   - * 关联 {@link MesWmWarehouseLocationDO#getId()}
75   - */
76   - private Long locationId;
77   - /**
78   - * 库位编号
79   - *
80   - * 关联 {@link MesWmWarehouseAreaDO#getId()}
81   - */
82   - private Long areaId;
83 60 /**
84 61 * 生产日期
85 62 */
... ... @@ -92,19 +69,6 @@ public class MesWmItemReceiptLineDO extends BaseDO {
92 69 * 生产批号
93 70 */
94 71 private String productionBatchNumber;
95   - // TODO @AI:貌似不用 iqcCheckFlag 存储;因为 noticeLineId 可以关联到
96   - /**
97   - * 是否需要来料检验
98   - */
99   - private Boolean iqcCheckFlag;
100   - // TODO DONE @AI:已添加关联注释。因 QC 模块 DO 类尚未迁移,暂用表名标识
101   - // TODO @AI:可以添加了;
102   - /**
103   - * 来料检验单编号
104   - *
105   - * 关联 mes_qc_iqc.id(待 QC 模块 DO 迁移后改为 @link)
106   - */
107   - private Long iqcId;
108 72 /**
109 73 * 备注
110 74 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/itemreceipt/MesWmItemReceiptMapper.java
... ... @@ -17,7 +17,6 @@ public interface MesWmItemReceiptMapper extends BaseMapperX&lt;MesWmItemReceiptDO&gt;
17 17 return selectPage(reqVO, new LambdaQueryWrapperX<MesWmItemReceiptDO>()
18 18 .likeIfPresent(MesWmItemReceiptDO::getCode, reqVO.getCode())
19 19 .likeIfPresent(MesWmItemReceiptDO::getName, reqVO.getName())
20   - .likeIfPresent(MesWmItemReceiptDO::getPurchaseOrderCode, reqVO.getPurchaseOrderCode())
21 20 .eqIfPresent(MesWmItemReceiptDO::getVendorId, reqVO.getVendorId())
22 21 .betweenIfPresent(MesWmItemReceiptDO::getReceiptDate, reqVO.getReceiptDate())
23 22 .eqIfPresent(MesWmItemReceiptDO::getStatus, reqVO.getStatus())
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -317,6 +317,7 @@ public interface ErrorCodeConstants {
317 317 ErrorCode WM_WAREHOUSE_LOCATION_REQUIRED = new ErrorCode(1_040_702_004, "选择库位时,库区不能为空");
318 318 ErrorCode WM_WAREHOUSE_AREA_RELATION_INVALID = new ErrorCode(1_040_702_005, "库位不属于所选库区");
319 319 ErrorCode WM_WAREHOUSE_AREA_HAS_MATERIAL_STOCK = new ErrorCode(1_040_702_006, "库位下有库存记录,无法删除");
  320 + ErrorCode WM_WAREHOUSE_AREA_WAREHOUSE_MISMATCH = new ErrorCode(1_040_702_007, "库位不属于所选仓库");
320 321  
321 322 // ========== MES 仓库管理-库存(1-040-703-000) ==========
322 323 ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在");
... ... @@ -330,6 +331,7 @@ public interface ErrorCodeConstants {
330 331 ErrorCode WM_ARRIVAL_NOTICE_IQC_PENDING = new ErrorCode(1_040_704_005, "存在待检验行,无法审批通过");
331 332 ErrorCode WM_ARRIVAL_NOTICE_NO_LINE = new ErrorCode(1_040_704_006, "至少需要一条行项目");
332 333 ErrorCode WM_ARRIVAL_NOTICE_LINE_NOT_EXISTS = new ErrorCode(1_040_704_100, "到货通知单行不存在");
  334 + ErrorCode WM_ARRIVAL_NOTICE_LINE_NOT_MATCH = new ErrorCode(1_040_704_101, "到货通知单行不属于指定的到货通知单");
333 335  
334 336 // ========== MES 仓库管理-采购入库单(1-040-705-000) ==========
335 337 ErrorCode WM_ITEM_RECEIPT_NOT_EXISTS = new ErrorCode(1_040_705_000, "采购入库单不存在");
... ... @@ -340,6 +342,8 @@ public interface ErrorCodeConstants {
340 342 ErrorCode WM_ITEM_RECEIPT_STATUS_ERROR = new ErrorCode(1_040_705_005, "入库单状态不正确");
341 343 ErrorCode WM_ITEM_RECEIPT_CANCEL_NOT_ALLOWED = new ErrorCode(1_040_705_006, "已完成或已取消的入库单不允许取消");
342 344 ErrorCode WM_ITEM_RECEIPT_LINE_NOT_EXISTS = new ErrorCode(1_040_705_100, "采购入库单行不存在");
  345 + ErrorCode WM_ITEM_RECEIPT_LINE_ARRIVAL_NOTICE_LINE_REQUIRED = new ErrorCode(1_040_705_101, "入库单关联了到货通知单,必须选择到货通知单行");
  346 + ErrorCode WM_ITEM_RECEIPT_LINE_ARRIVAL_NOTICE_LINE_NOT_ALLOWED = new ErrorCode(1_040_705_102, "入库单未关联到货通知单,不能选择到货通知单行");
343 347 ErrorCode WM_ITEM_RECEIPT_DETAIL_NOT_EXISTS = new ErrorCode(1_040_705_200, "采购入库明细不存在");
344 348  
345 349 // ========== MES 仓库管理-领料申请单(1-040-706-000) ==========
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeLineService.java
... ... @@ -76,4 +76,21 @@ public interface MesWmArrivalNoticeLineService {
76 76 */
77 77 void updateByIqcComplete(Long lineId, Long iqcId, BigDecimal qualifiedQuantity);
78 78  
  79 + /**
  80 + * 校验到货通知单行存在
  81 + *
  82 + * @param id 编号
  83 + * @return 到货通知单行
  84 + */
  85 + MesWmArrivalNoticeLineDO validateArrivalNoticeLineExists(Long id);
  86 +
  87 + /**
  88 + * 校验到货通知单行存在且属于指定的到货通知单
  89 + *
  90 + * @param lineId 行编号
  91 + * @param noticeId 到货通知单编号
  92 + * @return 到货通知单行
  93 + */
  94 + MesWmArrivalNoticeLineDO validateArrivalNoticeLineExists(Long lineId, Long noticeId);
  95 +
79 96 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeLineServiceImpl.java
... ... @@ -108,7 +108,8 @@ public class MesWmArrivalNoticeLineServiceImpl implements MesWmArrivalNoticeLine
108 108 .setId(lineId).setIqcId(iqcId).setQualifiedQuantity(qualifiedQuantity));
109 109 }
110 110  
111   - private MesWmArrivalNoticeLineDO validateArrivalNoticeLineExists(Long id) {
  111 + @Override
  112 + public MesWmArrivalNoticeLineDO validateArrivalNoticeLineExists(Long id) {
112 113 MesWmArrivalNoticeLineDO line = arrivalNoticeLineMapper.selectById(id);
113 114 if (line == null) {
114 115 throw exception(WM_ARRIVAL_NOTICE_LINE_NOT_EXISTS);
... ... @@ -116,6 +117,16 @@ public class MesWmArrivalNoticeLineServiceImpl implements MesWmArrivalNoticeLine
116 117 return line;
117 118 }
118 119  
  120 + @Override
  121 + public MesWmArrivalNoticeLineDO validateArrivalNoticeLineExists(Long lineId, Long noticeId) {
  122 + MesWmArrivalNoticeLineDO line = validateArrivalNoticeLineExists(lineId);
  123 + // 进一步校验行的 noticeId 与传入的 noticeId 是否匹配
  124 + if (noticeId != null && ObjUtil.notEqual(line.getNoticeId(), noticeId)) {
  125 + throw exception(WM_ARRIVAL_NOTICE_LINE_NOT_MATCH);
  126 + }
  127 + return line;
  128 + }
  129 +
119 130 /**
120 131 * 校验父到货通知单存在且为草稿状态
121 132 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptDetailServiceImpl.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 4 import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.detail.MesWmItemReceiptDetailSaveReqVO;
5 5 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptDetailDO;
6 6 import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemreceipt.MesWmItemReceiptDetailMapper;
  7 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
7 8 import jakarta.annotation.Resource;
8 9 import org.springframework.context.annotation.Lazy;
9 10 import org.springframework.stereotype.Service;
... ... @@ -28,12 +29,17 @@ public class MesWmItemReceiptDetailServiceImpl implements MesWmItemReceiptDetail
28 29 @Lazy
29 30 private MesWmItemReceiptService itemReceiptService;
30 31  
  32 + @Resource
  33 + private MesWmWarehouseAreaService warehouseAreaService;
  34 +
31 35 @Override
32 36 public Long createItemReceiptDetail(MesWmItemReceiptDetailSaveReqVO createReqVO) {
33   - // TODO @AI:warehouseId、locationId、areaId 存在,并且是父子关系!最好在 areaService 中提供一个方法,校验这三个 ID 的关系!(并且存在)
34   - // 校验父单据存在且为草稿状态
  37 + // 校验父单据存在且为可编辑状态
35 38 itemReceiptService.validateItemReceiptEditable(createReqVO.getReceiptId());
36   - // TODO @AI:超过数量验证;
  39 + // 校验库区关系
  40 + warehouseAreaService.validateWarehouseAreaExists(
  41 + createReqVO.getWarehouseId(), createReqVO.getLocationId(), createReqVO.getAreaId());
  42 + // TODO @芋艿:【后续搞】超过数量验证;
37 43  
38 44 // TODO @芋艿:【后续搞】不允许物资混放
39 45  
... ... @@ -44,12 +50,14 @@ public class MesWmItemReceiptDetailServiceImpl implements MesWmItemReceiptDetail
44 50  
45 51 @Override
46 52 public void updateItemReceiptDetail(MesWmItemReceiptDetailSaveReqVO updateReqVO) {
47   - // TODO @AI:warehouseId、locationId、areaId 存在,并且是父子关系!最好在 areaService 中提供一个方法,校验这三个 ID 的关系!(并且存在)
48 53 // 校验存在
49 54 MesWmItemReceiptDetailDO detail = validateItemReceiptDetailExists(updateReqVO.getId());
50   - // 校验父单据存在且为草稿状态
  55 + // 校验父单据存在且为可编辑状态
51 56 itemReceiptService.validateItemReceiptEditable(detail.getReceiptId());
52   - // TODO @AI:超过数量验证;
  57 + // 校验库区关系
  58 + warehouseAreaService.validateWarehouseAreaExists(
  59 + updateReqVO.getWarehouseId(), updateReqVO.getLocationId(), updateReqVO.getAreaId());
  60 + // TODO @芋艿:【后续搞】超过数量验证;
53 61  
54 62 // TODO @芋艿:【后续搞】不允许物资混放
55 63  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptLineServiceImpl.java
... ... @@ -7,8 +7,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.line.MesWm
7 7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptDO;
8 8 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptLineDO;
9 9 import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemreceipt.MesWmItemReceiptLineMapper;
10   -import cn.hutool.core.util.ObjUtil;
11   -import cn.iocoder.yudao.module.mes.enums.wm.MesWmItemReceiptStatusEnum;
  10 +import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeLineService;
12 11 import jakarta.annotation.Resource;
13 12 import org.springframework.context.annotation.Lazy;
14 13 import org.springframework.stereotype.Service;
... ... @@ -37,11 +36,16 @@ public class MesWmItemReceiptLineServiceImpl implements MesWmItemReceiptLineServ
37 36 @Resource
38 37 private MesWmItemReceiptDetailService itemReceiptDetailService;
39 38  
  39 + @Resource
  40 + @Lazy
  41 + private MesWmArrivalNoticeLineService arrivalNoticeLineService;
  42 +
40 43 @Override
41 44 public Long createItemReceiptLine(MesWmItemReceiptLineSaveReqVO createReqVO) {
42   - // 校验父单据存在且为草稿状态
43   - validateReceiptStatusDraft(createReqVO.getReceiptId());
44   - // TODO @AI:校验关联订单;
  45 + // 校验父单据存在且为可编辑状态
  46 + MesWmItemReceiptDO receipt = itemReceiptService.validateItemReceiptEditable(createReqVO.getReceiptId());
  47 + // 校验关联到货通知单行存在
  48 + validateArrivalNoticeLine(receipt, createReqVO.getArrivalNoticeLineId());
45 49  
46 50 // 新增
47 51 MesWmItemReceiptLineDO line = BeanUtils.toBean(createReqVO, MesWmItemReceiptLineDO.class);
... ... @@ -55,9 +59,10 @@ public class MesWmItemReceiptLineServiceImpl implements MesWmItemReceiptLineServ
55 59 public void updateItemReceiptLine(MesWmItemReceiptLineSaveReqVO updateReqVO) {
56 60 // 校验存在
57 61 MesWmItemReceiptLineDO line = validateItemReceiptLineExists(updateReqVO.getId());
58   - // 校验父单据存在且为草稿状态
59   - validateReceiptStatusDraft(line.getReceiptId());
60   - // TODO @AI:校验关联订单;
  62 + // 校验父单据存在且为可编辑状态
  63 + MesWmItemReceiptDO receipt = itemReceiptService.validateItemReceiptEditable(line.getReceiptId());
  64 + // 校验关联到货通知单行存在
  65 + validateArrivalNoticeLine(receipt, updateReqVO.getArrivalNoticeLineId());
61 66  
62 67 // 更新
63 68 MesWmItemReceiptLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmItemReceiptLineDO.class);
... ... @@ -98,6 +103,29 @@ public class MesWmItemReceiptLineServiceImpl implements MesWmItemReceiptLineServ
98 103 itemReceiptLineMapper.deleteByReceiptId(receiptId);
99 104 }
100 105  
  106 + /**
  107 + * 校验到货通知单行
  108 + *
  109 + * @param receipt 入库单
  110 + * @param arrivalNoticeLineId 到货通知单行编号
  111 + */
  112 + private void validateArrivalNoticeLine(MesWmItemReceiptDO receipt, Long arrivalNoticeLineId) {
  113 + // 情况一:如果入库单关联了到货通知单,则必须关联到货通知单行
  114 + if (receipt.getNoticeId() != null) {
  115 + if (arrivalNoticeLineId == null) {
  116 + throw exception(WM_ITEM_RECEIPT_LINE_ARRIVAL_NOTICE_LINE_REQUIRED);
  117 + }
  118 + arrivalNoticeLineService.validateArrivalNoticeLineExists(
  119 + arrivalNoticeLineId, receipt.getNoticeId());
  120 + return;
  121 + }
  122 +
  123 + // 情况二:如果入库单没有关联到货通知单,则不允许关联到货通知单行
  124 + if (arrivalNoticeLineId != null) {
  125 + throw exception(WM_ITEM_RECEIPT_LINE_ARRIVAL_NOTICE_LINE_NOT_ALLOWED);
  126 + }
  127 + }
  128 +
101 129 private MesWmItemReceiptLineDO validateItemReceiptLineExists(Long id) {
102 130 MesWmItemReceiptLineDO line = itemReceiptLineMapper.selectById(id);
103 131 if (line == null) {
... ... @@ -106,18 +134,4 @@ public class MesWmItemReceiptLineServiceImpl implements MesWmItemReceiptLineServ
106 134 return line;
107 135 }
108 136  
109   - // TODO @AI:这个应该在 itemReceiptService 中;
110   - /**
111   - * 校验父采购入库单存在且为草稿状态
112   - */
113   - private void validateReceiptStatusDraft(Long receiptId) {
114   - MesWmItemReceiptDO receipt = itemReceiptService.getItemReceipt(receiptId);
115   - if (receipt == null) {
116   - throw exception(WM_ITEM_RECEIPT_NOT_EXISTS);
117   - }
118   - if (ObjUtil.notEqual(MesWmItemReceiptStatusEnum.PREPARE.getStatus(), receipt.getStatus())) {
119   - throw exception(WM_ITEM_RECEIPT_STATUS_NOT_PREPARE);
120   - }
121   - }
122   -
123 137 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptService.java
... ... @@ -61,7 +61,7 @@ public interface MesWmItemReceiptService {
61 61 *
62 62 * @param id 编号
63 63 */
64   - void shelvingItemReceipt(Long id);
  64 + void stockItemReceipt(Long id);
65 65  
66 66 /**
67 67 * 执行入库(待入库 → 已完成),更新库存台账
... ... @@ -81,7 +81,8 @@ public interface MesWmItemReceiptService {
81 81 * 校验采购入库单存在且处于可编辑状态(草稿或待上架)
82 82 *
83 83 * @param id 编号
  84 + * @return 采购入库单
84 85 */
85   - void validateItemReceiptEditable(Long id);
  86 + MesWmItemReceiptDO validateItemReceiptEditable(Long id);
86 87  
87 88 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptServiceImpl.java
... ... @@ -115,13 +115,13 @@ public class MesWmItemReceiptServiceImpl implements MesWmItemReceiptService {
115 115  
116 116 @Override
117 117 @Transactional(rollbackFor = Exception.class)
118   - public void shelvingItemReceipt(Long id) {
  118 + public void stockItemReceipt(Long id) {
119 119 // 校验存在
120 120 MesWmItemReceiptDO receipt = validateItemReceiptExists(id);
121 121 if (ObjUtil.notEqual(MesWmItemReceiptStatusEnum.APPROVING.getStatus(), receipt.getStatus())) {
122 122 throw exception(WM_ITEM_RECEIPT_STATUS_ERROR);
123 123 }
124   - // 校验每行的 SUM(detail.quantity) = line.receivedQuantity
  124 + // 校验每行明细数量之和是否等于行入库数量
125 125 List<MesWmItemReceiptLineDO> lines = itemReceiptLineService.getItemReceiptLineListByReceiptId(id);
126 126 for (MesWmItemReceiptLineDO line : lines) {
127 127 List<MesWmItemReceiptDetailDO> details = itemReceiptDetailService.getItemReceiptDetailListByLineId(line.getId());
... ... @@ -147,7 +147,7 @@ public class MesWmItemReceiptServiceImpl implements MesWmItemReceiptService {
147 147 }
148 148  
149 149 // 遍历所有明细,更新库存台账
150   - // TODO @AI:这里可能有点问题;缺少库存更新;后面在弄;
  150 + // TODO @AI:【后续在弄】这里可能有点问题;缺少库存更新;后面在弄;
151 151 List<MesWmItemReceiptDetailDO> details = itemReceiptDetailService.getItemReceiptDetailListByReceiptId(id);
152 152 for (MesWmItemReceiptDetailDO detail : details) {
153 153 materialStockService.increaseStock(
... ... @@ -183,7 +183,7 @@ public class MesWmItemReceiptServiceImpl implements MesWmItemReceiptService {
183 183 }
184 184  
185 185 @Override
186   - public void validateItemReceiptEditable(Long id) {
  186 + public MesWmItemReceiptDO validateItemReceiptEditable(Long id) {
187 187 MesWmItemReceiptDO receipt = validateItemReceiptExists(id);
188 188 // TODO DONE @AI:已使用 ObjectUtils.equalsAny 简化多值判断,方法已迁移到 Service 层
189 189 // TODO @AI:ObjectUtils 封装一个方法,避免取反;脑子理解起来麻烦
... ... @@ -192,6 +192,7 @@ public class MesWmItemReceiptServiceImpl implements MesWmItemReceiptService {
192 192 MesWmItemReceiptStatusEnum.APPROVING.getStatus())) {
193 193 throw exception(WM_ITEM_RECEIPT_STATUS_NOT_PREPARE);
194 194 }
  195 + return receipt;
195 196 }
196 197  
197 198 private MesWmItemReceiptDO validateItemReceiptExists(Long id) {
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseAreaService.java
... ... @@ -91,4 +91,13 @@ public interface MesWmWarehouseAreaService {
91 91 */
92 92 Long getWarehouseAreaCountByLocationId(Long locationId);
93 93  
  94 + /**
  95 + * 校验仓库、库区、库位的父子关系
  96 + *
  97 + * @param warehouseId 仓库编号
  98 + * @param locationId 库区编号
  99 + * @param areaId 库位编号
  100 + */
  101 + void validateWarehouseAreaExists(Long warehouseId, Long locationId, Long areaId);
  102 +
94 103 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseAreaServiceImpl.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 7 import cn.iocoder.yudao.module.mes.controller.admin.wm.warehouse.vo.area.MesWmWarehouseAreaPageReqVO;
8 8 import cn.iocoder.yudao.module.mes.controller.admin.wm.warehouse.vo.area.MesWmWarehouseAreaSaveReqVO;
9 9 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
10 11 import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseAreaMapper;
11 12 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
12 13 import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
... ... @@ -143,4 +144,28 @@ public class MesWmWarehouseAreaServiceImpl implements MesWmWarehouseAreaService
143 144 return areaMapper.selectCountByLocationId(locationId);
144 145 }
145 146  
  147 + @Override
  148 + public void validateWarehouseAreaExists(Long warehouseId, Long locationId, Long areaId) {
  149 + if (areaId == null) {
  150 + return;
  151 + }
  152 + // 1.1 校验库位存在
  153 + MesWmWarehouseAreaDO area = validateWarehouseAreaExists(areaId);
  154 + // 1.2 校验库位所属的库区是否匹配
  155 + if (locationId != null && ObjUtil.notEqual(area.getLocationId(), locationId)) {
  156 + throw exception(WM_WAREHOUSE_AREA_RELATION_INVALID);
  157 + }
  158 + // 2. 校验库区存在
  159 + if (locationId != null) {
  160 + locationService.validateWarehouseLocationExists(locationId);
  161 + }
  162 + // 3. 校验仓库存在(通过库区的 locationId 关联查询)
  163 + if (warehouseId != null) {
  164 + MesWmWarehouseLocationDO location = locationService.validateWarehouseLocationExists(area.getLocationId());
  165 + if (location != null && ObjUtil.notEqual(location.getWarehouseId(), warehouseId)) {
  166 + throw exception(WM_WAREHOUSE_AREA_WAREHOUSE_MISMATCH);
  167 + }
  168 + }
  169 + }
  170 +
146 171 }
... ...