Commit 5c9cbe75edf9040f0d877744d4d121a81443f8cc
1 parent
c5728f11
✨ feat(mes): 添加外协发料单状态管理功能
新增提交到待拣货、执行拣货和完成外协发料出库的功能,优化了状态管理逻辑,确保发料单在不同状态下的操作流程更加清晰和安全。
Showing
10 changed files
with
120 additions
and
59 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueController.java
| ... | ... | @@ -109,12 +109,30 @@ public class MesWmOutsourceIssueController { |
| 109 | 109 | BeanUtils.toBean(pageResult.getList(), MesWmOutsourceIssueExcelVO.class)); |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | + @PutMapping("/submit") | |
| 113 | + @Operation(summary = "提交到待拣货") | |
| 114 | + @Parameter(name = "id", description = "编号", required = true) | |
| 115 | + @PreAuthorize("@ss.hasPermission('mes:wm-outsource-issue:update')") | |
| 116 | + public CommonResult<Boolean> submitOutsourceIssue(@RequestParam("id") Long id) { | |
| 117 | + outsourceIssueService.submitOutsourceIssue(id); | |
| 118 | + return success(true); | |
| 119 | + } | |
| 120 | + | |
| 121 | + @PutMapping("/stock") | |
| 122 | + @Operation(summary = "执行拣货") | |
| 123 | + @Parameter(name = "id", description = "编号", required = true) | |
| 124 | + @PreAuthorize("@ss.hasPermission('mes:wm-outsource-issue:update')") | |
| 125 | + public CommonResult<Boolean> stockOutsourceIssue(@RequestParam("id") Long id) { | |
| 126 | + outsourceIssueService.stockOutsourceIssue(id); | |
| 127 | + return success(true); | |
| 128 | + } | |
| 129 | + | |
| 112 | 130 | @PutMapping("/finish") |
| 113 | 131 | @Operation(summary = "完成外协发料出库") |
| 114 | 132 | @Parameter(name = "id", description = "编号", required = true) |
| 115 | 133 | @PreAuthorize("@ss.hasPermission('mes:wm-outsource-issue:finish')") |
| 116 | 134 | public CommonResult<Boolean> finishOutsourceIssue(@RequestParam("id") Long id) { |
| 117 | - outsourceIssueService.executeOutsourceIssue(id); | |
| 135 | + outsourceIssueService.finishOutsourceIssue(id); | |
| 118 | 136 | return success(true); |
| 119 | 137 | } |
| 120 | 138 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/vo/MesWmOutsourceIssueExcelVO.java
| ... | ... | @@ -7,6 +7,7 @@ import lombok.Data; |
| 7 | 7 | |
| 8 | 8 | import java.time.LocalDateTime; |
| 9 | 9 | |
| 10 | +// TODO @AI:删除掉,融合到 MesWmOutsourceIssueRespVO 中,保持一个 VO 就好 | |
| 10 | 11 | @Schema(description = "管理后台 - MES 外协发料单 Excel VO") |
| 11 | 12 | @Data |
| 12 | 13 | @ExcelIgnoreUnannotated |
| ... | ... | @@ -28,10 +29,10 @@ public class MesWmOutsourceIssueExcelVO { |
| 28 | 29 | private String vendorName; |
| 29 | 30 | |
| 30 | 31 | @ExcelProperty("生产工单编码") |
| 31 | - private String workorderCode; | |
| 32 | + private String workOrderCode; | |
| 32 | 33 | |
| 33 | 34 | @ExcelProperty("生产工单名称") |
| 34 | - private String workorderName; | |
| 35 | + private String workOrderName; | |
| 35 | 36 | |
| 36 | 37 | @ExcelProperty("发料日期") |
| 37 | 38 | private LocalDateTime issueDate; | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/vo/MesWmOutsourceIssuePageReqVO.java
| ... | ... | @@ -27,15 +27,17 @@ public class MesWmOutsourceIssuePageReqVO extends PageParam { |
| 27 | 27 | private Long vendorId; |
| 28 | 28 | |
| 29 | 29 | @Schema(description = "生产工单ID", example = "1") |
| 30 | - private Long workorderId; | |
| 30 | + private Long workOrderId; | |
| 31 | 31 | |
| 32 | + // TODO @AI:这个字段,去掉筛选 | |
| 32 | 33 | @Schema(description = "生产工单编码", example = "WO202603020001") |
| 33 | - private String workorderCode; | |
| 34 | + private String workOrderCode; | |
| 34 | 35 | |
| 35 | 36 | @Schema(description = "发料日期") |
| 36 | 37 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 37 | 38 | private LocalDateTime[] issueDate; |
| 38 | 39 | |
| 40 | + // TODO @AI:这个字段,去掉筛选 | |
| 39 | 41 | @Schema(description = "单据状态", example = "0") |
| 40 | 42 | private Integer status; |
| 41 | 43 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/vo/MesWmOutsourceIssueRespVO.java
| ... | ... | @@ -36,15 +36,15 @@ public class MesWmOutsourceIssueRespVO { |
| 36 | 36 | private String vendorName; |
| 37 | 37 | |
| 38 | 38 | @Schema(description = "生产工单ID", example = "1") |
| 39 | - private Long workorderId; | |
| 39 | + private Long workOrderId; | |
| 40 | 40 | |
| 41 | 41 | @Schema(description = "生产工单编码", example = "WO202603020001") |
| 42 | 42 | @ExcelProperty("生产工单编码") |
| 43 | - private String workorderCode; | |
| 43 | + private String workOrderCode; | |
| 44 | 44 | |
| 45 | 45 | @Schema(description = "生产工单名称", example = "生产工单001") |
| 46 | 46 | @ExcelProperty("生产工单名称") |
| 47 | - private String workorderName; | |
| 47 | + private String workOrderName; | |
| 48 | 48 | |
| 49 | 49 | @Schema(description = "发料日期", requiredMode = Schema.RequiredMode.REQUIRED) |
| 50 | 50 | @ExcelProperty("发料日期") | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/vo/MesWmOutsourceIssueSaveReqVO.java
| ... | ... | @@ -22,27 +22,14 @@ public class MesWmOutsourceIssueSaveReqVO { |
| 22 | 22 | @NotEmpty(message = "发料单名称不能为空") |
| 23 | 23 | private String name; |
| 24 | 24 | |
| 25 | - @Schema(description = "供应商ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 26 | - @NotNull(message = "供应商ID不能为空") | |
| 25 | + @Schema(description = "供应商ID", example = "1") | |
| 27 | 26 | private Long vendorId; |
| 28 | 27 | |
| 29 | - @Schema(description = "供应商编码", example = "V001") | |
| 30 | - private String vendorCode; | |
| 28 | + @Schema(description = "生产工单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 29 | + @NotNull(message = "生产工单ID不能为空") | |
| 30 | + private Long workOrderId; | |
| 31 | 31 | |
| 32 | - @Schema(description = "供应商名称", example = "供应商A") | |
| 33 | - private String vendorName; | |
| 34 | - | |
| 35 | - @Schema(description = "生产工单ID", example = "1") | |
| 36 | - private Long workorderId; | |
| 37 | - | |
| 38 | - @Schema(description = "生产工单编码", example = "WO202603020001") | |
| 39 | - private String workorderCode; | |
| 40 | - | |
| 41 | - @Schema(description = "生产工单名称", example = "生产工单001") | |
| 42 | - private String workorderName; | |
| 43 | - | |
| 44 | - @Schema(description = "发料日期", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 45 | - @NotNull(message = "发料日期不能为空") | |
| 32 | + @Schema(description = "发料日期") | |
| 46 | 33 | private LocalDateTime issueDate; |
| 47 | 34 | |
| 48 | 35 | @Schema(description = "备注", example = "备注") | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/outsourceissue/MesWmOutsourceIssueDO.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.outsourceissue; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | 4 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; |
| 5 | +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; | |
| 5 | 6 | import cn.iocoder.yudao.module.mes.enums.wm.MesWmOutsourceIssueStatusEnum; |
| 6 | 7 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 7 | 8 | import com.baomidou.mybatisplus.annotation.TableId; |
| ... | ... | @@ -44,29 +45,12 @@ public class MesWmOutsourceIssueDO extends BaseDO { |
| 44 | 45 | * 关联 {@link MesMdVendorDO#getId()} |
| 45 | 46 | */ |
| 46 | 47 | private Long vendorId; |
| 47 | - // TODO @AI:去掉冗余的 vendorCode、vendorName 字段 | |
| 48 | - /** | |
| 49 | - * 供应商编码 | |
| 50 | - */ | |
| 51 | - private String vendorCode; | |
| 52 | - /** | |
| 53 | - * 供应商名称 | |
| 54 | - */ | |
| 55 | - private String vendorName; | |
| 56 | - // TODO @AI:去掉冗余的 workorderCode、workorderName 字段 | |
| 57 | - // TODO @AI:拼写不对;应该是 workOrderId; | |
| 58 | 48 | /** |
| 59 | 49 | * 生产工单ID |
| 50 | + * | |
| 51 | + * 关联 {@link MesProWorkOrderDO#getId()} | |
| 60 | 52 | */ |
| 61 | - private Long workorderId; | |
| 62 | - /** | |
| 63 | - * 生产工单编码 | |
| 64 | - */ | |
| 65 | - private String workorderCode; | |
| 66 | - /** | |
| 67 | - * 生产工单名称 | |
| 68 | - */ | |
| 69 | - private String workorderName; | |
| 53 | + private Long workOrderId; | |
| 70 | 54 | /** |
| 71 | 55 | * 发料日期 |
| 72 | 56 | */ | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
| ... | ... | @@ -358,6 +358,8 @@ public interface ErrorCodeConstants { |
| 358 | 358 | ErrorCode WM_OUTSOURCE_ISSUE_STATUS_NOT_PREPARE = new ErrorCode(1_040_707_002, "只有草稿状态才允许此操作"); |
| 359 | 359 | ErrorCode WM_OUTSOURCE_ISSUE_NO_LINE = new ErrorCode(1_040_707_003, "至少需要一条发料行"); |
| 360 | 360 | ErrorCode WM_OUTSOURCE_ISSUE_QUANTITY_MISMATCH = new ErrorCode(1_040_707_004, "发料单行数量与明细数量不一致"); |
| 361 | + ErrorCode WM_OUTSOURCE_ISSUE_STATUS_NOT_APPROVING = new ErrorCode(1_040_707_005, "只有待拣货状态才允许此操作"); | |
| 362 | + ErrorCode WM_OUTSOURCE_ISSUE_STATUS_NOT_APPROVED = new ErrorCode(1_040_707_006, "只有待执行出库状态才允许此操作"); | |
| 361 | 363 | ErrorCode WM_OUTSOURCE_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_707_100, "外协发料单行不存在"); |
| 362 | 364 | ErrorCode WM_OUTSOURCE_ISSUE_DETAIL_NOT_EXISTS = new ErrorCode(1_040_707_200, "外协发料单明细不存在"); |
| 363 | 365 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmOutsourceIssueStatusEnum.java
| 1 | 1 | package cn.iocoder.yudao.module.mes.enums.wm; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.core.ArrayValuable; |
| 4 | +import cn.iocoder.yudao.module.mes.controller.admin.wm.outsourceissue.vo.MesWmOutsourceIssueSaveReqVO; | |
| 4 | 5 | import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants; |
| 6 | +import cn.iocoder.yudao.module.mes.service.wm.outsourceissue.MesWmOutsourceIssueService; | |
| 5 | 7 | import lombok.AllArgsConstructor; |
| 6 | 8 | import lombok.Getter; |
| 7 | 9 | |
| ... | ... | @@ -10,6 +12,8 @@ import java.util.Arrays; |
| 10 | 12 | /** |
| 11 | 13 | * MES 外协发料单状态枚举 |
| 12 | 14 | * |
| 15 | + * 对应字典 mes_wm_outsource_issue_status | |
| 16 | + * | |
| 13 | 17 | * @author 芋道源码 |
| 14 | 18 | */ |
| 15 | 19 | @Getter |
| ... | ... | @@ -18,13 +22,34 @@ public enum MesWmOutsourceIssueStatusEnum implements ArrayValuable<Integer> { |
| 18 | 22 | |
| 19 | 23 | /** |
| 20 | 24 | * 草稿 |
| 25 | + * | |
| 26 | + * 对应方法:{@link MesWmOutsourceIssueService#createOutsourceIssue(MesWmOutsourceIssueSaveReqVO)} | |
| 21 | 27 | */ |
| 22 | 28 | PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), |
| 23 | - // TODO @AI:状态缺失了; | |
| 29 | + /** | |
| 30 | + * 待拣货 | |
| 31 | + * | |
| 32 | + * 对应方法:TODO 待实现 | |
| 33 | + */ | |
| 34 | + APPROVING(MesOrderStatusConstants.APPROVING, "待拣货"), | |
| 35 | + /** | |
| 36 | + * 待执行出库 | |
| 37 | + * | |
| 38 | + * 对应方法:TODO 待实现 | |
| 39 | + */ | |
| 40 | + APPROVED(MesOrderStatusConstants.APPROVED, "待执行出库"), | |
| 24 | 41 | /** |
| 25 | 42 | * 已完成 |
| 43 | + * | |
| 44 | + * 对应方法:{@link MesWmOutsourceIssueService#executeOutsourceIssue(Long)} | |
| 45 | + */ | |
| 46 | + FINISHED(MesOrderStatusConstants.FINISHED, "已完成"), | |
| 47 | + /** | |
| 48 | + * 已取消 | |
| 49 | + * | |
| 50 | + * 对应方法:TODO 待实现 | |
| 26 | 51 | */ |
| 27 | - FINISHED(MesOrderStatusConstants.FINISHED, "已完成"); | |
| 52 | + CANCELLED(MesOrderStatusConstants.CANCELLED, "已取消"); | |
| 28 | 53 | |
| 29 | 54 | public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmOutsourceIssueStatusEnum::getStatus).toArray(Integer[]::new); |
| 30 | 55 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourceissue/MesWmOutsourceIssueService.java
| ... | ... | @@ -52,10 +52,24 @@ public interface MesWmOutsourceIssueService { |
| 52 | 52 | PageResult<MesWmOutsourceIssueDO> getOutsourceIssuePage(MesWmOutsourceIssuePageReqVO pageReqVO); |
| 53 | 53 | |
| 54 | 54 | /** |
| 55 | - * 执行外协发料出库(草稿 → 已完成,扣减库存) | |
| 55 | + * 提交到待拣货(草稿 → 待拣货) | |
| 56 | 56 | * |
| 57 | 57 | * @param id 编号 |
| 58 | 58 | */ |
| 59 | - void executeOutsourceIssue(Long id); | |
| 59 | + void submitOutsourceIssue(Long id); | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * 执行拣货(待拣货 → 待执行出库) | |
| 63 | + * | |
| 64 | + * @param id 编号 | |
| 65 | + */ | |
| 66 | + void stockOutsourceIssue(Long id); | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * 完成外协发料出库(待执行出库 → 已完成,扣减库存) | |
| 70 | + * | |
| 71 | + * @param id 编号 | |
| 72 | + */ | |
| 73 | + void finishOutsourceIssue(Long id); | |
| 60 | 74 | |
| 61 | 75 | } | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourceissue/MesWmOutsourceIssueServiceImpl.java
| ... | ... | @@ -97,29 +97,56 @@ public class MesWmOutsourceIssueServiceImpl implements MesWmOutsourceIssueServic |
| 97 | 97 | |
| 98 | 98 | @Override |
| 99 | 99 | @Transactional(rollbackFor = Exception.class) |
| 100 | - public void executeOutsourceIssue(Long id) { | |
| 101 | - // 1. 校验存在 + 草稿状态 | |
| 102 | - MesWmOutsourceIssueDO issue = validateOutsourceIssueExistsAndDraft(id); | |
| 103 | - | |
| 104 | - // 2. 检查是否有发料行 | |
| 100 | + public void submitOutsourceIssue(Long id) { | |
| 101 | + // 1.1 校验存在 + 草稿状态 | |
| 102 | + validateOutsourceIssueExistsAndDraft(id); | |
| 103 | + // 1.2 检查是否有发料行 | |
| 105 | 104 | List<MesWmOutsourceIssueLineDO> lines = outsourceIssueLineService.getOutsourceIssueLineListByIssueId(id); |
| 106 | 105 | if (CollUtil.isEmpty(lines)) { |
| 107 | 106 | throw exception(WM_OUTSOURCE_ISSUE_NO_LINE); |
| 108 | 107 | } |
| 109 | 108 | |
| 110 | - // 3. 校验数量一致性(行数量 = 明细数量之和) | |
| 109 | + // 2. 更新单据状态为待拣货 | |
| 110 | + outsourceIssueMapper.updateById(new MesWmOutsourceIssueDO() | |
| 111 | + .setId(id).setStatus(MesWmOutsourceIssueStatusEnum.APPROVING.getStatus())); | |
| 112 | + } | |
| 113 | + | |
| 114 | + @Override | |
| 115 | + @Transactional(rollbackFor = Exception.class) | |
| 116 | + public void stockOutsourceIssue(Long id) { | |
| 117 | + // 1.1 校验存在 + 待拣货状态 | |
| 118 | + MesWmOutsourceIssueDO issue = validateOutsourceIssueExists(id); | |
| 119 | + if (ObjUtil.notEqual(MesWmOutsourceIssueStatusEnum.APPROVING.getStatus(), issue.getStatus())) { | |
| 120 | + throw exception(WM_OUTSOURCE_ISSUE_STATUS_NOT_APPROVING); | |
| 121 | + } | |
| 122 | + // 1.2 校验数量一致性(行数量 = 明细数量之和) | |
| 123 | + List<MesWmOutsourceIssueLineDO> lines = outsourceIssueLineService.getOutsourceIssueLineListByIssueId(id); | |
| 111 | 124 | validateQuantityMatch(id, lines); |
| 112 | 125 | |
| 113 | - // 4. 扣减库存(遍历明细表,逐条扣减) | |
| 126 | + // 2. 更新单据状态为待执行出库 | |
| 127 | + outsourceIssueMapper.updateById(new MesWmOutsourceIssueDO() | |
| 128 | + .setId(id).setStatus(MesWmOutsourceIssueStatusEnum.APPROVED.getStatus())); | |
| 129 | + } | |
| 130 | + | |
| 131 | + @Override | |
| 132 | + @Transactional(rollbackFor = Exception.class) | |
| 133 | + public void finishOutsourceIssue(Long id) { | |
| 134 | + // 1. 校验存在 + 待执行出库状态 | |
| 135 | + MesWmOutsourceIssueDO issue = validateOutsourceIssueExists(id); | |
| 136 | + if (ObjUtil.notEqual(MesWmOutsourceIssueStatusEnum.APPROVED.getStatus(), issue.getStatus())) { | |
| 137 | + throw exception(WM_OUTSOURCE_ISSUE_STATUS_NOT_APPROVED); | |
| 138 | + } | |
| 139 | + | |
| 140 | + // 2. 扣减库存(遍历明细表,逐条扣减) | |
| 114 | 141 | List<MesWmOutsourceIssueDetailDO> details = outsourceIssueDetailService.getOutsourceIssueDetailListByIssueId(id); |
| 115 | 142 | for (MesWmOutsourceIssueDetailDO detail : details) { |
| 116 | 143 | // TODO: 调用库存服务扣减库存 |
| 117 | 144 | // materialStockService.decreaseStock(detail.getMaterialStockId(), detail.getQuantity()); |
| 118 | - log.info("[executeOutsourceIssue][发料单({}) 扣减库存 - 库存ID: {}, 数量: {}]", | |
| 145 | + log.info("[finishOutsourceIssue][发料单({}) 扣减库存 - 库存ID: {}, 数量: {}]", | |
| 119 | 146 | id, detail.getMaterialStockId(), detail.getQuantity()); |
| 120 | 147 | } |
| 121 | 148 | |
| 122 | - // 5. 更新单据状态为已完成 | |
| 149 | + // 3. 更新单据状态为已完成 | |
| 123 | 150 | outsourceIssueMapper.updateById(new MesWmOutsourceIssueDO() |
| 124 | 151 | .setId(id).setStatus(MesWmOutsourceIssueStatusEnum.FINISHED.getStatus())); |
| 125 | 152 | } |
| ... | ... | @@ -162,6 +189,7 @@ public class MesWmOutsourceIssueServiceImpl implements MesWmOutsourceIssueServic |
| 162 | 189 | /** |
| 163 | 190 | * 校验数量一致性(行数量 = 明细数量之和) |
| 164 | 191 | */ |
| 192 | + // TODO @AI:参考别的模块,不要抽成小方法; | |
| 165 | 193 | private void validateQuantityMatch(Long issueId, List<MesWmOutsourceIssueLineDO> lines) { |
| 166 | 194 | // 获取所有明细 |
| 167 | 195 | List<MesWmOutsourceIssueDetailDO> details = outsourceIssueDetailService.getOutsourceIssueDetailListByIssueId(issueId); | ... | ... |