Commit 4ec13fac38725dd2993439d220365f4ed0ee5345

Authored by YunaiV
1 parent 911ddc37

✨ feat(mes): 更新杂项类型为整数并添加明细服务

将杂项类型字段从字符串更改为整数,以支持新的枚举类型。同时,新增杂项出库明细的服务接口和实现,提供对明细的增删改查功能,提升系统的灵活性和可维护性。
Showing 26 changed files with 816 additions and 62 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscissue/vo/MesWmMiscIssuePageReqVO.java
... ... @@ -21,8 +21,8 @@ public class MesWmMiscIssuePageReqVO extends PageParam {
21 21 @Schema(description = "出库单名称", example = "库存调整出库")
22 22 private String name;
23 23  
24   - @Schema(description = "杂项类型", example = "STOCK_ADJUSTMENT")
25   - private String type;
  24 + @Schema(description = "杂项类型", example = "1")
  25 + private Integer type;
26 26  
27 27 @Schema(description = "状态", example = "0")
28 28 private Integer status;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscissue/vo/MesWmMiscIssueRespVO.java
... ... @@ -18,8 +18,8 @@ public class MesWmMiscIssueRespVO {
18 18 @Schema(description = "出库单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "库存调整出库")
19 19 private String name;
20 20  
21   - @Schema(description = "杂项类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "STOCK_ADJUSTMENT")
22   - private String type;
  21 + @Schema(description = "杂项类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  22 + private Integer type;
23 23  
24 24 @Schema(description = "来源单据ID", example = "1")
25 25 private Long sourceDocId;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscissue/vo/MesWmMiscIssueSaveReqVO.java
... ... @@ -22,9 +22,9 @@ public class MesWmMiscIssueSaveReqVO {
22 22 @NotBlank(message = "出库单名称不能为空")
23 23 private String name;
24 24  
25   - @Schema(description = "杂项类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "STOCK_ADJUSTMENT")
26   - @NotBlank(message = "杂项类型不能为空")
27   - private String type;
  25 + @Schema(description = "杂项类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  26 + @NotNull(message = "杂项类型不能为空")
  27 + private Integer type;
28 28  
29 29 @Schema(description = "来源单据ID", example = "1")
30 30 private Long sourceDocId;
... ... @@ -35,8 +35,7 @@ public class MesWmMiscIssueSaveReqVO {
35 35 @Schema(description = "来源单据类型", example = "PURCHASE_ORDER")
36 36 private String sourceDocType;
37 37  
38   - @Schema(description = "出库日期", requiredMode = Schema.RequiredMode.REQUIRED)
39   - @NotNull(message = "出库日期不能为空")
  38 + @Schema(description = "出库日期")
40 39 private LocalDateTime issueDate;
41 40  
42 41 @Schema(description = "备注", example = "备注")
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/vo/MesWmMiscReceiptPageReqVO.java
... ... @@ -23,8 +23,8 @@ public class MesWmMiscReceiptPageReqVO extends PageParam {
23 23 @Schema(description = "入库单名称", example = "退料入库单")
24 24 private String name;
25 25  
26   - @Schema(description = "杂项类型", example = "RETURN")
27   - private String type;
  26 + @Schema(description = "杂项类型", example = "1")
  27 + private Integer type;
28 28  
29 29 @Schema(description = "状态", example = "0")
30 30 private Integer status;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/vo/MesWmMiscReceiptRespVO.java
... ... @@ -18,8 +18,8 @@ public class MesWmMiscReceiptRespVO {
18 18 @Schema(description = "入库单名称", example = "退料入库单")
19 19 private String name;
20 20  
21   - @Schema(description = "杂项类型", example = "RETURN")
22   - private String type;
  21 + @Schema(description = "杂项类型", example = "1")
  22 + private Integer type;
23 23  
24 24 @Schema(description = "来源单据 ID", example = "1")
25 25 private Long sourceDocId;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/vo/MesWmMiscReceiptSaveReqVO.java
... ... @@ -23,9 +23,9 @@ public class MesWmMiscReceiptSaveReqVO {
23 23 @NotEmpty(message = "入库单名称不能为空")
24 24 private String name;
25 25  
26   - @Schema(description = "杂项类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "RETURN")
27   - @NotEmpty(message = "杂项类型不能为空")
28   - private String type;
  26 + @Schema(description = "杂项类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  27 + @NotNull(message = "杂项类型不能为空")
  28 + private Integer type;
29 29  
30 30 @Schema(description = "来源单据 ID", example = "1")
31 31 private Long sourceDocId;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/vo/line/MesWmMiscReceiptLineSaveReqVO.java
... ... @@ -24,6 +24,7 @@ public class MesWmMiscReceiptLineSaveReqVO {
24 24  
25 25 @Schema(description = "入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
26 26 @NotNull(message = "入库数量不能为空")
  27 + // TODO @AI:最小是 0.01
27 28 private BigDecimal quantity;
28 29  
29 30 @Schema(description = "批次号", example = "BATCH20260301")
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/miscissue/MesWmMiscIssueDO.java
... ... @@ -38,9 +38,9 @@ public class MesWmMiscIssueDO extends BaseDO {
38 38 /**
39 39 * 杂项类型
40 40 *
41   - * 枚举 {@link cn.iocoder.yudao.module.mes.enums.DictTypeConstants#MES_WM_MISC_ISSUE_TYPE}
  41 + * 枚举 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmMiscIssueTypeEnum}
42 42 */
43   - private String type;
  43 + private Integer type;
44 44 // TODO @芋艿:这里还没定,关联哪些;
45 45 /**
46 46 * 来源单据ID
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/miscissue/MesWmMiscIssueDetailDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscissue;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
  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 +import com.baomidou.mybatisplus.annotation.KeySequence;
  10 +import com.baomidou.mybatisplus.annotation.TableId;
  11 +import com.baomidou.mybatisplus.annotation.TableName;
  12 +import lombok.*;
  13 +
  14 +import java.math.BigDecimal;
  15 +
  16 +/**
  17 + * MES 杂项出库明细 DO
  18 + */
  19 +@TableName("mes_wm_misc_issue_detail")
  20 +@KeySequence("mes_wm_misc_issue_detail_seq")
  21 +@Data
  22 +@EqualsAndHashCode(callSuper = true)
  23 +@ToString(callSuper = true)
  24 +@Builder
  25 +@NoArgsConstructor
  26 +@AllArgsConstructor
  27 +public class MesWmMiscIssueDetailDO extends BaseDO {
  28 +
  29 + /**
  30 + * 编号
  31 + */
  32 + @TableId
  33 + private Long id;
  34 + /**
  35 + * 出库单ID
  36 + *
  37 + * 关联 {@link MesWmMiscIssueDO#getId()}
  38 + */
  39 + private Long issueId;
  40 + /**
  41 + * 行ID
  42 + *
  43 + * 关联 {@link MesWmMiscIssueLineDO#getId()}
  44 + */
  45 + private Long lineId;
  46 + /**
  47 + * 库存记录ID
  48 + *
  49 + * 关联 {@link MesWmMaterialStockDO#getId()}
  50 + */
  51 + private Long materialStockId;
  52 + /**
  53 + * 物料ID
  54 + *
  55 + * 关联 {@link MesMdItemDO#getId()}
  56 + */
  57 + private Long itemId;
  58 + /**
  59 + * 出库数量
  60 + */
  61 + private BigDecimal quantity;
  62 + /**
  63 + * 批次ID
  64 + */
  65 + private Long batchId;
  66 + /**
  67 + * 批次号
  68 + */
  69 + private String batchCode;
  70 + /**
  71 + * 仓库ID
  72 + *
  73 + * 关联 {@link MesWmWarehouseDO#getId()}
  74 + */
  75 + private Long warehouseId;
  76 + /**
  77 + * 库区ID
  78 + *
  79 + * 关联 {@link MesWmWarehouseLocationDO#getId()}
  80 + */
  81 + private Long locationId;
  82 + /**
  83 + * 库位ID
  84 + *
  85 + * 关联 {@link MesWmWarehouseAreaDO#getId()}
  86 + */
  87 + private Long areaId;
  88 + /**
  89 + * 备注
  90 + */
  91 + private String remark;
  92 +
  93 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/miscreceipt/MesWmMiscReceiptDO.java
... ... @@ -43,7 +43,7 @@ public class MesWmMiscReceiptDO extends BaseDO {
43 43 *
44 44 * 枚举 {@link MesWmMiscReceiptTypeEnum}
45 45 */
46   - private String type;
  46 + private Integer type;
47 47 // TODO @芋艿:后续看看怎么跟进;
48 48 /**
49 49 * 来源单据 ID
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/miscissue/MesWmMiscIssueDetailMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.wm.miscissue;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscissue.MesWmMiscIssueDetailDO;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * MES 杂项出库明细 Mapper
  11 + */
  12 +@Mapper
  13 +public interface MesWmMiscIssueDetailMapper extends BaseMapperX<MesWmMiscIssueDetailDO> {
  14 +
  15 + default List<MesWmMiscIssueDetailDO> selectListByLineId(Long lineId) {
  16 + return selectList(MesWmMiscIssueDetailDO::getLineId, lineId);
  17 + }
  18 +
  19 + default List<MesWmMiscIssueDetailDO> selectListByIssueId(Long issueId) {
  20 + return selectList(MesWmMiscIssueDetailDO::getIssueId, issueId);
  21 + }
  22 +
  23 + default void deleteByIssueId(Long issueId) {
  24 + delete(MesWmMiscIssueDetailDO::getIssueId, issueId);
  25 + }
  26 +
  27 + default void deleteByLineId(Long lineId) {
  28 + delete(MesWmMiscIssueDetailDO::getLineId, lineId);
  29 + }
  30 +
  31 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMiscIssueTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.enums.wm;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +@Getter
  10 +@AllArgsConstructor
  11 +public enum MesWmMiscIssueTypeEnum implements ArrayValuable<Integer> {
  12 +
  13 + ADJUST(1, "库存调整"),
  14 + SCRAP(2, "报废出库");
  15 +
  16 + private final Integer type;
  17 + private final String name;
  18 +
  19 + @Override
  20 + public Integer[] array() {
  21 + return Arrays.stream(values()).map(MesWmMiscIssueTypeEnum::getType).toArray(Integer[]::new);
  22 + }
  23 +
  24 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMiscReceiptTypeEnum.java
... ... @@ -8,31 +8,26 @@ import java.util.Arrays;
8 8  
9 9 /**
10 10 * MES 杂项入库类型枚举
11   - *
12   - * @author 芋道源码
13 11 */
14 12 @Getter
15 13 @AllArgsConstructor
16   -public enum MesWmMiscReceiptTypeEnum implements ArrayValuable<String> {
  14 +public enum MesWmMiscReceiptTypeEnum implements ArrayValuable<Integer> {
17 15  
18   - RETURN("RETURN", "退料入库"),
19   - ADJUST("ADJUST", "调整入库"),
20   - TRANSFER("TRANSFER", "调拨入库"),
21   - OTHER("OTHER", "其他入库");
  16 + ADJUST(1, "库存调整");
22 17  
23   - public static final String[] ARRAYS = Arrays.stream(values()).map(MesWmMiscReceiptTypeEnum::getType).toArray(String[]::new);
  18 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmMiscReceiptTypeEnum::getType).toArray(Integer[]::new);
24 19  
25 20 /**
26 21 * 类型值
27 22 */
28   - private final String type;
  23 + private final Integer type;
29 24 /**
30 25 * 类型名
31 26 */
32 27 private final String name;
33 28  
34 29 @Override
35   - public String[] array() {
  30 + public Integer[] array() {
36 31 return ARRAYS;
37 32 }
38 33  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueDetailService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.miscissue;
  2 +
  3 +import cn.iocoder.yudao.module.mes.controller.admin.wm.miscissue.vo.line.MesWmMiscIssueLineSaveReqVO;
  4 +
  5 +/**
  6 + * MES 杂项出库明细 Service 接口
  7 + */
  8 +public interface MesWmMiscIssueDetailService {
  9 +
  10 + /**
  11 + * 创建杂项出库明细
  12 + *
  13 + * @param createReqVO 创建信息
  14 + * @return 编号
  15 + */
  16 + Long createMiscIssueDetail(MesWmMiscIssueLineSaveReqVO createReqVO);
  17 +
  18 + /**
  19 + * 更新杂项出库明细
  20 + *
  21 + * @param updateReqVO 更新信息
  22 + */
  23 + void updateMiscIssueDetail(MesWmMiscIssueLineSaveReqVO updateReqVO);
  24 +
  25 + /**
  26 + * 删除杂项出库明细(根据出库单ID)
  27 + *
  28 + * @param issueId 出库单ID
  29 + */
  30 + void deleteMiscIssueDetailByIssueId(Long issueId);
  31 +
  32 + /**
  33 + * 删除杂项出库明细(根据行ID)
  34 + *
  35 + * @param lineId 行ID
  36 + */
  37 + void deleteMiscIssueDetailByLineId(Long lineId);
  38 +
  39 + /**
  40 + * 校验杂项出库明细是否存在
  41 + *
  42 + * @param id 编号
  43 + */
  44 + void validateMiscIssueDetailExists(Long id);
  45 +
  46 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueDetailServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.miscissue;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.wm.miscissue.vo.line.MesWmMiscIssueLineSaveReqVO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscissue.MesWmMiscIssueDetailDO;
  7 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.miscissue.MesWmMiscIssueDetailMapper;
  8 +import jakarta.annotation.Resource;
  9 +import org.springframework.stereotype.Service;
  10 +import org.springframework.validation.annotation.Validated;
  11 +
  12 +import java.util.List;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  15 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_MISC_ISSUE_DETAIL_NOT_EXISTS;
  16 +
  17 +/**
  18 + * MES 杂项出库明细 Service 实现类
  19 + */
  20 +@Service
  21 +@Validated
  22 +public class MesWmMiscIssueDetailServiceImpl implements MesWmMiscIssueDetailService {
  23 +
  24 + @Resource
  25 + private MesWmMiscIssueDetailMapper issueDetailMapper;
  26 +
  27 + @Override
  28 + public Long createMiscIssueDetail(MesWmMiscIssueLineSaveReqVO createReqVO) {
  29 + MesWmMiscIssueDetailDO detail = BeanUtils.toBean(createReqVO, MesWmMiscIssueDetailDO.class);
  30 + detail.setId(null); // 清空 id,让数据库自动生成
  31 + detail.setLineId(createReqVO.getId()); // VO 的 id 就是 lineId
  32 + issueDetailMapper.insert(detail);
  33 + return detail.getId();
  34 + }
  35 +
  36 + @Override
  37 + public void updateMiscIssueDetail(MesWmMiscIssueLineSaveReqVO updateReqVO) {
  38 + // 基于 lineId 查询唯一的 detail 记录(VO 的 id 字段是 lineId)
  39 + List<MesWmMiscIssueDetailDO> details = issueDetailMapper.selectListByLineId(updateReqVO.getId());
  40 + if (CollUtil.isEmpty(details)) {
  41 + return;
  42 + }
  43 +
  44 + // 更新 detail(应该只有一条记录)
  45 + MesWmMiscIssueDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmMiscIssueDetailDO.class);
  46 + updateObj.setId(details.get(0).getId()); // 使用查询到的 detail id
  47 + updateObj.setLineId(updateReqVO.getId()); // VO 的 id 就是 lineId
  48 + issueDetailMapper.updateById(updateObj);
  49 + }
  50 +
  51 + @Override
  52 + public void deleteMiscIssueDetailByIssueId(Long issueId) {
  53 + issueDetailMapper.deleteByIssueId(issueId);
  54 + }
  55 +
  56 + @Override
  57 + public void deleteMiscIssueDetailByLineId(Long lineId) {
  58 + issueDetailMapper.deleteByLineId(lineId);
  59 + }
  60 +
  61 + @Override
  62 + public void validateMiscIssueDetailExists(Long id) {
  63 + if (issueDetailMapper.selectById(id) == null) {
  64 + throw exception(WM_MISC_ISSUE_DETAIL_NOT_EXISTS);
  65 + }
  66 + }
  67 +
  68 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueLineService.java
... ... @@ -66,4 +66,11 @@ public interface MesWmMiscIssueLineService {
66 66 */
67 67 void deleteMiscIssueLineByIssueId(Long issueId);
68 68  
  69 + /**
  70 + * 校验杂项出库单行是否存在
  71 + *
  72 + * @param id 编号
  73 + */
  74 + void validateMiscIssueLineExists(Long id);
  75 +
69 76 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueLineServiceImpl.java
... ... @@ -17,7 +17,7 @@ import org.springframework.validation.annotation.Validated;
17 17 import java.util.List;
18 18  
19 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
20   -import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
  20 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_MISC_ISSUE_LINE_NOT_EXISTS;
21 21  
22 22 /**
23 23 * MES 杂项出库单行 Service 实现类
... ... @@ -34,52 +34,67 @@ public class MesWmMiscIssueLineServiceImpl implements MesWmMiscIssueLineService
34 34 private MesWmMiscIssueService miscIssueService;
35 35  
36 36 @Resource
  37 + @Lazy
  38 + private MesWmMiscIssueDetailService miscIssueDetailService;
  39 +
  40 + @Resource
37 41 private MesMdItemService itemService;
38 42  
39 43 @Resource
40 44 private MesWmWarehouseAreaService warehouseAreaService;
41 45  
42 46 @Override
  47 + @Transactional(rollbackFor = Exception.class)
43 48 public Long createMiscIssueLine(MesWmMiscIssueLineSaveReqVO createReqVO) {
44   - // 校验父单据存在且为可编辑状态
  49 + // 1.1 校验父单据存在且为可编辑状态
45 50 miscIssueService.validateMiscIssueEditable(createReqVO.getIssueId());
46   - // 校验物料存在
  51 + // 1.2 校验物料存在
47 52 itemService.validateItemExists(createReqVO.getItemId());
48   - // 校验仓库、库区、库位的父子关系
  53 + // 1.3 校验仓库、库区、库位的父子关系
49 54 warehouseAreaService.validateWarehouseAreaExists(createReqVO.getWarehouseId(),
50 55 createReqVO.getLocationId(), createReqVO.getAreaId());
51 56  
52   - // 新增
  57 + // 2. 新增行
53 58 MesWmMiscIssueLineDO line = BeanUtils.toBean(createReqVO, MesWmMiscIssueLineDO.class);
54 59 miscIssueLineMapper.insert(line);
  60 +
  61 + // 3.自动创建明细
  62 + createReqVO.setId(line.getId());
  63 + miscIssueDetailService.createMiscIssueDetail(createReqVO);
55 64 return line.getId();
56 65 }
57 66  
58 67 @Override
  68 + @Transactional(rollbackFor = Exception.class)
59 69 public void updateMiscIssueLine(MesWmMiscIssueLineSaveReqVO updateReqVO) {
60   - // 校验存在
61   - MesWmMiscIssueLineDO line = validateMiscIssueLineExists(updateReqVO.getId());
62   - // 校验父单据存在且为可编辑状态
  70 + // 1.1 校验存在
  71 + MesWmMiscIssueLineDO line = validateAndGetMiscIssueLine(updateReqVO.getId());
  72 + // 1.2 校验父单据存在且为可编辑状态
63 73 miscIssueService.validateMiscIssueEditable(line.getIssueId());
64   - // 校验物料存在
  74 + // 1.3 校验物料存在
65 75 itemService.validateItemExists(updateReqVO.getItemId());
66   - // 校验仓库、库区、库位的父子关系
  76 + // 1.4 校验仓库、库区、库位的父子关系
67 77 warehouseAreaService.validateWarehouseAreaExists(updateReqVO.getWarehouseId(),
68 78 updateReqVO.getLocationId(), updateReqVO.getAreaId());
69 79  
70   - // 更新
  80 + // 2. 更新行
71 81 MesWmMiscIssueLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmMiscIssueLineDO.class);
72 82 miscIssueLineMapper.updateById(updateObj);
  83 +
  84 + // 3. 更新明细(基于行信息)
  85 + miscIssueDetailService.updateMiscIssueDetail(updateReqVO);
73 86 }
74 87  
75 88 @Override
76 89 @Transactional(rollbackFor = Exception.class)
77 90 public void deleteMiscIssueLine(Long id) {
78 91 // 校验存在
79   - validateMiscIssueLineExists(id);
  92 + validateAndGetMiscIssueLine(id);
80 93  
81   - // 删除
  94 + // 删除行
82 95 miscIssueLineMapper.deleteById(id);
  96 + // 删除明细
  97 + miscIssueDetailService.deleteMiscIssueDetailByLineId(id);
83 98 }
84 99  
85 100 @Override
... ... @@ -98,11 +113,22 @@ public class MesWmMiscIssueLineServiceImpl implements MesWmMiscIssueLineService
98 113 }
99 114  
100 115 @Override
  116 + @Transactional(rollbackFor = Exception.class)
101 117 public void deleteMiscIssueLineByIssueId(Long issueId) {
  118 + // 删除明细
  119 + miscIssueDetailService.deleteMiscIssueDetailByIssueId(issueId);
  120 + // 删除行
102 121 miscIssueLineMapper.deleteByIssueId(issueId);
103 122 }
104 123  
105   - private MesWmMiscIssueLineDO validateMiscIssueLineExists(Long id) {
  124 + @Override
  125 + public void validateMiscIssueLineExists(Long id) {
  126 + if (miscIssueLineMapper.selectById(id) == null) {
  127 + throw exception(WM_MISC_ISSUE_LINE_NOT_EXISTS);
  128 + }
  129 + }
  130 +
  131 + private MesWmMiscIssueLineDO validateAndGetMiscIssueLine(Long id) {
106 132 MesWmMiscIssueLineDO line = miscIssueLineMapper.selectById(id);
107 133 if (line == null) {
108 134 throw exception(WM_MISC_ISSUE_LINE_NOT_EXISTS);
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueServiceImpl.java
... ... @@ -39,9 +39,6 @@ public class MesWmMiscIssueServiceImpl implements MesWmMiscIssueService {
39 39 @Resource
40 40 private MesWmMiscIssueLineService miscIssueLineService;
41 41  
42   - @Resource
43   - private MesWmMaterialStockService materialStockService;
44   -
45 42 @Override
46 43 public Long createMiscIssue(MesWmMiscIssueSaveReqVO createReqVO) {
47 44 // 校验编码唯一
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscreceipt/MesWmMiscReceiptLineServiceImpl.java
... ... @@ -25,9 +25,12 @@ public class MesWmMiscReceiptLineServiceImpl implements MesWmMiscReceiptLineServ
25 25  
26 26 @Override
27 27 public Long createMiscReceiptLine(MesWmMiscReceiptLineSaveReqVO createReqVO) {
  28 + // TODO @AI:物料存在;lineId 可编辑;
  29 +
28 30 // 插入
29 31 MesWmMiscReceiptLineDO line = BeanUtils.toBean(createReqVO, MesWmMiscReceiptLineDO.class);
30 32 miscReceiptLineMapper.insert(line);
  33 + // TODO @AI:还是需要新增一个 detail 表;类似别的 line + detail 的设计;1)create 时,新增;2)update 时,更新;3)delete 时,删除;
31 34 return line.getId();
32 35 }
33 36  
... ... @@ -35,6 +38,7 @@ public class MesWmMiscReceiptLineServiceImpl implements MesWmMiscReceiptLineServ
35 38 public void updateMiscReceiptLine(MesWmMiscReceiptLineSaveReqVO updateReqVO) {
36 39 // 校验存在
37 40 validateMiscReceiptLineExists(updateReqVO.getId());
  41 + // TODO @AI:物料存在;lineId 可编辑;
38 42  
39 43 // 更新
40 44 MesWmMiscReceiptLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmMiscReceiptLineDO.class);
... ... @@ -43,6 +47,7 @@ public class MesWmMiscReceiptLineServiceImpl implements MesWmMiscReceiptLineServ
43 47  
44 48 @Override
45 49 public void deleteMiscReceiptLine(Long id) {
  50 + // TODO @AI:lineId 存在 + 可编辑;
46 51 // 校验存在
47 52 validateMiscReceiptLineExists(id);
48 53  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscreceipt/MesWmMiscReceiptServiceImpl.java
... ... @@ -18,7 +18,6 @@ import org.springframework.stereotype.Service;
18 18 import org.springframework.transaction.annotation.Transactional;
19 19 import org.springframework.validation.annotation.Validated;
20 20  
21   -import java.math.BigDecimal;
22 21 import java.util.List;
23 22  
24 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -98,17 +97,6 @@ public class MesWmMiscReceiptServiceImpl implements MesWmMiscReceiptService {
98 97 throw exception(WM_MISC_RECEIPT_NO_LINE);
99 98 }
100 99  
101   - // 校验行数据完整性
102   - // TODO @AI:不用做这块的校验;
103   - for (MesWmMiscReceiptLineDO line : lines) {
104   - if (line.getWarehouseId() == null) {
105   - throw exception(WM_MISC_RECEIPT_WAREHOUSE_REQUIRED);
106   - }
107   - if (line.getQuantity() == null || line.getQuantity().compareTo(BigDecimal.ZERO) <= 0) {
108   - throw exception(WM_MISC_RECEIPT_QUANTITY_INVALID);
109   - }
110   - }
111   -
112 100 // 提交审批(草稿 → 已审批)
113 101 miscReceiptMapper.updateById(new MesWmMiscReceiptDO()
114 102 .setId(id).setStatus(MesWmMiscReceiptStatusEnum.APPROVED.getStatus()));
... ... @@ -124,8 +112,6 @@ public class MesWmMiscReceiptServiceImpl implements MesWmMiscReceiptService {
124 112 }
125 113  
126 114 // 遍历所有行,更新库存台账
127   - // TODO @芋艿:后续对齐下;
128   - // TODO @AI:这里有编译报错;
129 115 List<MesWmMiscReceiptLineDO> lines = miscReceiptLineMapper.selectListByReceiptId(id);
130 116 for (MesWmMiscReceiptLineDO line : lines) {
131 117 materialStockService.increaseStock(
... ... @@ -133,9 +119,11 @@ public class MesWmMiscReceiptServiceImpl implements MesWmMiscReceiptService {
133 119 line.getWarehouseId(),
134 120 line.getLocationId(),
135 121 line.getAreaId(),
136   - line.getBatchCode(),
  122 + null, // batchId 传 null(杂项入库使用 batchCode)
  123 + line.getQuantity(),
137 124 null, // vendorId 传 null(杂项入库无供应商)
138   - line.getQuantity()
  125 + line.getProductionDate(),
  126 + line.getExpireDate()
139 127 );
140 128 }
141 129  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourcereceipt/MesWmOutsourceReceiptDetailService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.outsourcereceipt;
  2 +
  3 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.outsourcereceipt.MesWmOutsourceReceiptDetailDO;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * MES 委外收货明细 Service 接口
  9 + */
  10 +public interface MesWmOutsourceReceiptDetailService {
  11 +
  12 + /**
  13 + * 获得委外收货明细列表(根据收货单编号)
  14 + *
  15 + * @param receiptId 收货单编号
  16 + * @return 委外收货明细列表
  17 + */
  18 + List<MesWmOutsourceReceiptDetailDO> getOutsourceReceiptDetailListByReceiptId(Long receiptId);
  19 +
  20 + /**
  21 + * 获得委外收货明细列表(根据行编号)
  22 + *
  23 + * @param lineId 行编号
  24 + * @return 委外收货明细列表
  25 + */
  26 + List<MesWmOutsourceReceiptDetailDO> getOutsourceReceiptDetailListByLineId(Long lineId);
  27 +
  28 + /**
  29 + * 删除委外收货明细(根据收货单编号)
  30 + *
  31 + * @param receiptId 收货单编号
  32 + */
  33 + void deleteOutsourceReceiptDetailByReceiptId(Long receiptId);
  34 +
  35 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourcereceipt/MesWmOutsourceReceiptDetailServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.outsourcereceipt;
  2 +
  3 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.outsourcereceipt.MesWmOutsourceReceiptDetailDO;
  4 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.outsourcereceipt.MesWmOutsourceReceiptDetailMapper;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.stereotype.Service;
  7 +import org.springframework.validation.annotation.Validated;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * MES 委外收货明细 Service 实现类
  13 + */
  14 +@Service
  15 +@Validated
  16 +public class MesWmOutsourceReceiptDetailServiceImpl implements MesWmOutsourceReceiptDetailService {
  17 +
  18 + @Resource
  19 + private MesWmOutsourceReceiptDetailMapper detailMapper;
  20 +
  21 + @Override
  22 + public List<MesWmOutsourceReceiptDetailDO> getOutsourceReceiptDetailListByReceiptId(Long receiptId) {
  23 + return detailMapper.selectListByReceiptId(receiptId);
  24 + }
  25 +
  26 + @Override
  27 + public List<MesWmOutsourceReceiptDetailDO> getOutsourceReceiptDetailListByLineId(Long lineId) {
  28 + return detailMapper.selectListByLineId(lineId);
  29 + }
  30 +
  31 + @Override
  32 + public void deleteOutsourceReceiptDetailByReceiptId(Long receiptId) {
  33 + detailMapper.deleteByReceiptId(receiptId);
  34 + }
  35 +
  36 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourcereceipt/MesWmOutsourceReceiptLineService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.outsourcereceipt;
  2 +
  3 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.outsourcereceipt.MesWmOutsourceReceiptLineDO;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * MES 委外收货单行 Service 接口
  9 + */
  10 +public interface MesWmOutsourceReceiptLineService {
  11 +
  12 + /**
  13 + * 获得委外收货单行列表
  14 + *
  15 + * @param receiptId 收货单编号
  16 + * @return 委外收货单行列表
  17 + */
  18 + List<MesWmOutsourceReceiptLineDO> getOutsourceReceiptLineListByReceiptId(Long receiptId);
  19 +
  20 + /**
  21 + * 删除委外收货单行(根据收货单编号)
  22 + *
  23 + * @param receiptId 收货单编号
  24 + */
  25 + void deleteOutsourceReceiptLineByReceiptId(Long receiptId);
  26 +
  27 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourcereceipt/MesWmOutsourceReceiptLineServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.outsourcereceipt;
  2 +
  3 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.outsourcereceipt.MesWmOutsourceReceiptLineDO;
  4 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.outsourcereceipt.MesWmOutsourceReceiptLineMapper;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.stereotype.Service;
  7 +import org.springframework.validation.annotation.Validated;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * MES 委外收货单行 Service 实现类
  13 + */
  14 +@Service
  15 +@Validated
  16 +public class MesWmOutsourceReceiptLineServiceImpl implements MesWmOutsourceReceiptLineService {
  17 +
  18 + @Resource
  19 + private MesWmOutsourceReceiptLineMapper lineMapper;
  20 +
  21 + // TODO @AI:新增、修改缺少;
  22 +
  23 + @Override
  24 + public List<MesWmOutsourceReceiptLineDO> getOutsourceReceiptLineListByReceiptId(Long receiptId) {
  25 + return lineMapper.selectListByReceiptId(receiptId);
  26 + }
  27 +
  28 + @Override
  29 + public void deleteOutsourceReceiptLineByReceiptId(Long receiptId) {
  30 + lineMapper.deleteByReceiptId(receiptId);
  31 + }
  32 +
  33 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourcereceipt/MesWmOutsourceReceiptService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.outsourcereceipt;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.wm.outsourcereceipt.vo.MesWmOutsourceReceiptPageReqVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.wm.outsourcereceipt.vo.MesWmOutsourceReceiptSaveReqVO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.outsourcereceipt.MesWmOutsourceReceiptDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +/**
  10 + * MES 外协入库单 Service 接口
  11 + */
  12 +public interface MesWmOutsourceReceiptService {
  13 +
  14 + /**
  15 + * 创建外协入库单
  16 + *
  17 + * @param createReqVO 创建信息
  18 + * @return 编号
  19 + */
  20 + Long createOutsourceReceipt(@Valid MesWmOutsourceReceiptSaveReqVO createReqVO);
  21 +
  22 + /**
  23 + * 修改外协入库单
  24 + *
  25 + * @param updateReqVO 修改信息
  26 + */
  27 + void updateOutsourceReceipt(@Valid MesWmOutsourceReceiptSaveReqVO updateReqVO);
  28 +
  29 + /**
  30 + * 删除外协入库单(级联删除行+明细)
  31 + *
  32 + * @param id 编号
  33 + */
  34 + void deleteOutsourceReceipt(Long id);
  35 +
  36 + /**
  37 + * 获得外协入库单
  38 + *
  39 + * @param id 编号
  40 + * @return 外协入库单
  41 + */
  42 + MesWmOutsourceReceiptDO getOutsourceReceipt(Long id);
  43 +
  44 + /**
  45 + * 获得外协入库单分页
  46 + *
  47 + * @param pageReqVO 分页参数
  48 + * @return 外协入库单分页
  49 + */
  50 + PageResult<MesWmOutsourceReceiptDO> getOutsourceReceiptPage(MesWmOutsourceReceiptPageReqVO pageReqVO);
  51 +
  52 + /**
  53 + * 提交外协入库单(草稿 → 审批中)
  54 + *
  55 + * @param id 编号
  56 + */
  57 + void submitOutsourceReceipt(Long id);
  58 +
  59 + /**
  60 + * 执行上架(审批中 → 已审批)
  61 + *
  62 + * @param id 编号
  63 + */
  64 + void stockOutsourceReceipt(Long id);
  65 +
  66 + /**
  67 + * 完成入库(已审批 → 已完成),更新库存台账
  68 + *
  69 + * @param id 编号
  70 + */
  71 + void finishOutsourceReceipt(Long id);
  72 +
  73 + /**
  74 + * 取消外协入库单(任意非已完成/已取消状态 → 已取消)
  75 + *
  76 + * @param id 编号
  77 + */
  78 + void cancelOutsourceReceipt(Long id);
  79 +
  80 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourcereceipt/MesWmOutsourceReceiptServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.outsourcereceipt;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  7 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  9 +import cn.iocoder.yudao.module.mes.controller.admin.wm.outsourcereceipt.vo.MesWmOutsourceReceiptPageReqVO;
  10 +import cn.iocoder.yudao.module.mes.controller.admin.wm.outsourcereceipt.vo.MesWmOutsourceReceiptSaveReqVO;
  11 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.outsourcereceipt.MesWmOutsourceReceiptDO;
  12 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.outsourcereceipt.MesWmOutsourceReceiptDetailDO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.outsourcereceipt.MesWmOutsourceReceiptLineDO;
  14 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.outsourcereceipt.MesWmOutsourceReceiptDetailMapper;
  15 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.outsourcereceipt.MesWmOutsourceReceiptLineMapper;
  16 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.outsourcereceipt.MesWmOutsourceReceiptMapper;
  17 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmOutsourceReceiptStatusEnum;
  18 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  19 +import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService;
  20 +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
  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 +import jakarta.annotation.Resource;
  25 +import org.springframework.stereotype.Service;
  26 +import org.springframework.transaction.annotation.Transactional;
  27 +import org.springframework.validation.annotation.Validated;
  28 +
  29 +import java.math.BigDecimal;
  30 +import java.util.List;
  31 +
  32 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  33 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
  34 +
  35 +/**
  36 + * MES 外协入库单 Service 实现类
  37 + */
  38 +@Service
  39 +@Validated
  40 +public class MesWmOutsourceReceiptServiceImpl implements MesWmOutsourceReceiptService {
  41 +
  42 + @Resource
  43 + private MesWmOutsourceReceiptMapper outsourceReceiptMapper;
  44 +
  45 + @Resource
  46 + private MesWmOutsourceReceiptLineMapper outsourceReceiptLineMapper;
  47 +
  48 + @Resource
  49 + private MesWmOutsourceReceiptDetailMapper outsourceReceiptDetailMapper;
  50 +
  51 + @Resource
  52 + private MesWmMaterialStockService materialStockService;
  53 +
  54 + @Resource
  55 + private MesMdVendorService vendorService;
  56 +
  57 + @Resource
  58 + private MesMdItemService itemService;
  59 +
  60 + @Resource
  61 + private MesWmWarehouseService warehouseService;
  62 +
  63 + @Resource
  64 + private MesWmWarehouseLocationService warehouseLocationService;
  65 +
  66 + @Resource
  67 + private MesWmWarehouseAreaService warehouseAreaService;
  68 +
  69 + @Override
  70 + public Long createOutsourceReceipt(MesWmOutsourceReceiptSaveReqVO createReqVO) {
  71 + // 校验编码唯一
  72 + validateCodeUnique(null, createReqVO.getCode());
  73 + // 校验供应商存在
  74 + vendorService.validateVendorExists(createReqVO.getVendorId());
  75 +
  76 + // 插入
  77 + MesWmOutsourceReceiptDO receipt = BeanUtils.toBean(createReqVO, MesWmOutsourceReceiptDO.class);
  78 + receipt.setStatus(MesWmOutsourceReceiptStatusEnum.PREPARE.getStatus());
  79 + outsourceReceiptMapper.insert(receipt);
  80 + return receipt.getId();
  81 + }
  82 +
  83 + @Override
  84 + public void updateOutsourceReceipt(MesWmOutsourceReceiptSaveReqVO updateReqVO) {
  85 + // 校验存在 + 草稿状态
  86 + validateOutsourceReceiptExistsAndDraft(updateReqVO.getId());
  87 + // 校验编码唯一
  88 + validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
  89 + // 校验供应商存在
  90 + vendorService.validateVendorExists(updateReqVO.getVendorId());
  91 +
  92 + // 更新
  93 + MesWmOutsourceReceiptDO updateObj = BeanUtils.toBean(updateReqVO, MesWmOutsourceReceiptDO.class);
  94 + outsourceReceiptMapper.updateById(updateObj);
  95 + }
  96 +
  97 + @Override
  98 + @Transactional(rollbackFor = Exception.class)
  99 + public void deleteOutsourceReceipt(Long id) {
  100 + // 校验存在 + 草稿状态
  101 + validateOutsourceReceiptExistsAndDraft(id);
  102 +
  103 + // 级联删除明细和行
  104 + outsourceReceiptDetailMapper.deleteByReceiptId(id);
  105 + outsourceReceiptLineMapper.deleteByReceiptId(id);
  106 + // 删除
  107 + outsourceReceiptMapper.deleteById(id);
  108 + }
  109 +
  110 + @Override
  111 + public MesWmOutsourceReceiptDO getOutsourceReceipt(Long id) {
  112 + return outsourceReceiptMapper.selectById(id);
  113 + }
  114 +
  115 + @Override
  116 + public PageResult<MesWmOutsourceReceiptDO> getOutsourceReceiptPage(MesWmOutsourceReceiptPageReqVO pageReqVO) {
  117 + return outsourceReceiptMapper.selectPage(pageReqVO);
  118 + }
  119 +
  120 + @Override
  121 + @Transactional(rollbackFor = Exception.class)
  122 + public void submitOutsourceReceipt(Long id) {
  123 + // 校验存在 + 草稿状态
  124 + validateOutsourceReceiptExistsAndDraft(id);
  125 + // 校验至少有一条行
  126 + List<MesWmOutsourceReceiptLineDO> lines = outsourceReceiptLineMapper.selectListByReceiptId(id);
  127 + if (CollUtil.isEmpty(lines)) {
  128 + throw exception(WM_OUTSOURCE_RECEIPT_NO_LINE);
  129 + }
  130 + // 校验物料存在
  131 + for (MesWmOutsourceReceiptLineDO line : lines) {
  132 + itemService.validateItemExists(line.getItemId());
  133 + }
  134 +
  135 + // 提交(草稿 → 审批中)
  136 + outsourceReceiptMapper.updateById(new MesWmOutsourceReceiptDO()
  137 + .setId(id).setStatus(MesWmOutsourceReceiptStatusEnum.APPROVING.getStatus()));
  138 + }
  139 +
  140 + @Override
  141 + @Transactional(rollbackFor = Exception.class)
  142 + public void stockOutsourceReceipt(Long id) {
  143 + // 校验存在
  144 + MesWmOutsourceReceiptDO receipt = validateOutsourceReceiptExists(id);
  145 + if (ObjUtil.notEqual(MesWmOutsourceReceiptStatusEnum.APPROVING.getStatus(), receipt.getStatus())) {
  146 + throw exception(WM_OUTSOURCE_RECEIPT_STATUS_ERROR);
  147 + }
  148 + // 校验每行明细数量之和是否等于行入库数量
  149 + // TODO @AI:这个校验,不需要了;
  150 + List<MesWmOutsourceReceiptLineDO> lines = outsourceReceiptLineMapper.selectListByReceiptId(id);
  151 + for (MesWmOutsourceReceiptLineDO line : lines) {
  152 + // 校验物料存在
  153 + itemService.validateItemExists(line.getItemId());
  154 +
  155 + List<MesWmOutsourceReceiptDetailDO> details = outsourceReceiptDetailMapper.selectListByLineId(line.getId());
  156 + BigDecimal totalDetailQty = CollectionUtils.getSumValue(details,
  157 + MesWmOutsourceReceiptDetailDO::getQuantity, BigDecimal::add, BigDecimal.ZERO);
  158 + if (line.getQuantity() != null && totalDetailQty.compareTo(line.getQuantity()) != 0) {
  159 + throw exception(WM_OUTSOURCE_RECEIPT_DETAIL_QUANTITY_MISMATCH);
  160 + }
  161 +
  162 + // 校验明细中的仓库、库区、库位存在
  163 + for (MesWmOutsourceReceiptDetailDO detail : details) {
  164 + itemService.validateItemExists(detail.getItemId());
  165 + if (detail.getWarehouseId() != null) {
  166 + warehouseService.validateWarehouseExists(detail.getWarehouseId());
  167 + }
  168 + if (detail.getLocationId() != null) {
  169 + warehouseLocationService.validateWarehouseLocationExists(detail.getLocationId());
  170 + }
  171 + if (detail.getAreaId() != null) {
  172 + warehouseAreaService.validateWarehouseAreaExists(detail.getAreaId());
  173 + }
  174 + }
  175 + }
  176 +
  177 + // 审批(审批中 → 已审批)
  178 + outsourceReceiptMapper.updateById(new MesWmOutsourceReceiptDO()
  179 + .setId(id).setStatus(MesWmOutsourceReceiptStatusEnum.APPROVED.getStatus()));
  180 + }
  181 +
  182 + @Override
  183 + @Transactional(rollbackFor = Exception.class)
  184 + public void finishOutsourceReceipt(Long id) {
  185 + // 校验存在
  186 + MesWmOutsourceReceiptDO receipt = validateOutsourceReceiptExists(id);
  187 + if (ObjUtil.notEqual(MesWmOutsourceReceiptStatusEnum.APPROVED.getStatus(), receipt.getStatus())) {
  188 + throw exception(WM_OUTSOURCE_RECEIPT_STATUS_ERROR);
  189 + }
  190 +
  191 + // 遍历所有明细,校验并更新库存台账
  192 + // TODO @AI:芋艿【暂时不处理】;后续在观察;
  193 + List<MesWmOutsourceReceiptDetailDO> details = outsourceReceiptDetailMapper.selectListByReceiptId(id);
  194 + for (MesWmOutsourceReceiptDetailDO detail : details) {
  195 + // 校验物料、仓库、库区、库位存在
  196 + // TODO @AI:warehouseAreaService 有个公用的校验;
  197 + itemService.validateItemExists(detail.getItemId());
  198 + if (detail.getWarehouseId() != null) {
  199 + warehouseService.validateWarehouseExists(detail.getWarehouseId());
  200 + }
  201 + if (detail.getLocationId() != null) {
  202 + warehouseLocationService.validateWarehouseLocationExists(detail.getLocationId());
  203 + }
  204 + if (detail.getAreaId() != null) {
  205 + warehouseAreaService.validateWarehouseAreaExists(detail.getAreaId());
  206 + }
  207 +
  208 + materialStockService.increaseStock(
  209 + detail.getItemId(), detail.getWarehouseId(), detail.getLocationId(), detail.getAreaId(),
  210 + detail.getBatchId(), detail.getQuantity(), receipt.getVendorId(), null, null);
  211 + }
  212 +
  213 + // 更新入库单状态
  214 + outsourceReceiptMapper.updateById(new MesWmOutsourceReceiptDO()
  215 + .setId(id).setStatus(MesWmOutsourceReceiptStatusEnum.FINISHED.getStatus()));
  216 + }
  217 +
  218 + @Override
  219 + @Transactional(rollbackFor = Exception.class)
  220 + public void cancelOutsourceReceipt(Long id) {
  221 + // 校验存在
  222 + MesWmOutsourceReceiptDO receipt = validateOutsourceReceiptExists(id);
  223 + // 已完成和已取消不允许取消
  224 + if (ObjectUtils.equalsAny(receipt.getStatus(),
  225 + MesWmOutsourceReceiptStatusEnum.FINISHED.getStatus(),
  226 + MesWmOutsourceReceiptStatusEnum.CANCELED.getStatus())) {
  227 + throw exception(WM_OUTSOURCE_RECEIPT_CANCEL_NOT_ALLOWED);
  228 + }
  229 + // 取消
  230 + outsourceReceiptMapper.updateById(new MesWmOutsourceReceiptDO()
  231 + .setId(id).setStatus(MesWmOutsourceReceiptStatusEnum.CANCELED.getStatus()));
  232 + }
  233 +
  234 + private MesWmOutsourceReceiptDO validateOutsourceReceiptExists(Long id) {
  235 + MesWmOutsourceReceiptDO receipt = outsourceReceiptMapper.selectById(id);
  236 + if (receipt == null) {
  237 + throw exception(WM_OUTSOURCE_RECEIPT_NOT_EXISTS);
  238 + }
  239 + return receipt;
  240 + }
  241 +
  242 + /**
  243 + * 校验外协入库单存在且为草稿状态
  244 + */
  245 + private MesWmOutsourceReceiptDO validateOutsourceReceiptExistsAndDraft(Long id) {
  246 + MesWmOutsourceReceiptDO receipt = validateOutsourceReceiptExists(id);
  247 + if (ObjUtil.notEqual(MesWmOutsourceReceiptStatusEnum.PREPARE.getStatus(), receipt.getStatus())) {
  248 + throw exception(WM_OUTSOURCE_RECEIPT_STATUS_NOT_PREPARE);
  249 + }
  250 + return receipt;
  251 + }
  252 +
  253 + private void validateCodeUnique(Long id, String code) {
  254 + MesWmOutsourceReceiptDO receipt = outsourceReceiptMapper.selectByCode(code);
  255 + if (receipt == null) {
  256 + return;
  257 + }
  258 + if (ObjUtil.notEqual(id, receipt.getId())) {
  259 + throw exception(WM_OUTSOURCE_RECEIPT_CODE_DUPLICATE);
  260 + }
  261 + }
  262 +
  263 +}
... ...