diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/MesWmProductionIssueController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/MesWmProductionIssueController.java index fa0c04d..73839a1 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/MesWmProductionIssueController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/MesWmProductionIssueController.java @@ -34,6 +34,9 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPOR import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +// TODO @AI:方法的排序,参考别的模块; +// TODO @AI:controller、service、包括其他的,都需要全。createProductitonIssue 这种;其它模块也是; +// TODO @AI:需要新增 line、detail 的 controller;参考 /Users/yunai/Java/yudao-all-in-one/ruoyi-vue-pro/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt @Tag(name = "管理后台 - MES 领料出库单") @RestController @RequestMapping("/mes/wm/production-issue") @@ -102,24 +105,6 @@ public class MesWmProductionIssueController { buildRespVOList(pageResult.getList())); } - @PutMapping("/approve") - @Operation(summary = "审批领料出库单") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mes:wm-production-issue:update-status')") - public CommonResult approveIssue(@RequestParam("id") Long id) { - issueService.approveIssue(id); - return success(true); - } - - @PutMapping("/unapprove") - @Operation(summary = "反审批领料出库单") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mes:wm-production-issue:update-status')") - public CommonResult unapproveIssue(@RequestParam("id") Long id) { - issueService.unapproveIssue(id); - return success(true); - } - @PutMapping("/finish") @Operation(summary = "完成领料出库单") @Parameter(name = "id", description = "编号", required = true) @@ -131,6 +116,7 @@ public class MesWmProductionIssueController { // ==================== 拼接 VO ==================== + // TODO @AI:这个方法的拼接,在优化下; private List buildRespVOList(List list) { if (CollUtil.isEmpty(list)) { return Collections.emptyList(); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/MesWmProductionIssueSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/MesWmProductionIssueSaveReqVO.java index 8a95441..d9453e1 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/MesWmProductionIssueSaveReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productionissue/vo/MesWmProductionIssueSaveReqVO.java @@ -13,28 +13,25 @@ public class MesWmProductionIssueSaveReqVO { @Schema(description = "编号", example = "1024") private Long id; + // TODO @AI:必须传递 @Schema(description = "领料单编号", example = "ISSUE20250226001") private String code; + // TODO @AI:必须传递 @Schema(description = "领料单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "生产领料") private String name; - @Schema(description = "工作站ID", example = "1") + // TODO @AI:必须传递 + // TODO @AI:service 需要校验存在 + @Schema(description = "工作站 ID", example = "1") private Long workstationId; - @Schema(description = "生产工单ID", example = "1") + @Schema(description = "生产工单 ID", example = "1") + // TODO @AI:service 需要校验存在 private Long workorderId; - @Schema(description = "生产任务ID", example = "1") - private Long taskId; - - @Schema(description = "客户ID", example = "1") - private Long clientId; - - @Schema(description = "领料日期") - private LocalDateTime issueDate; - @Schema(description = "需求时间") + // TODO @AI:必须传递 private LocalDateTime requiredTime; @Schema(description = "备注", example = "备注") @@ -52,6 +49,7 @@ public class MesWmProductionIssueSaveReqVO { @Schema(description = "预留字段4") private Integer attribute4; + // TODO @AI:应该单独接口,传递这个;参考别的模块; @Schema(description = "领料单行列表") private List lines; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index 83f189d..62e01d2 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -357,4 +357,17 @@ public interface ErrorCodeConstants { ErrorCode WM_OUTSOURCE_ISSUE_QUANTITY_MISMATCH = new ErrorCode(1_040_707_002, "出库单行数量与明细数量不一致"); ErrorCode WM_OUTSOURCE_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_707_100, "外协出库单行不存在"); + // ========== MES 仓库管理-生产领料出库单(1-040-708-000) ========== + ErrorCode WM_PRODUCTION_ISSUE_NOT_EXISTS = new ErrorCode(1_040_708_000, "生产领料出库单不存在"); + ErrorCode WM_PRODUCTION_ISSUE_STATUS_INVALID = new ErrorCode(1_040_708_001, "生产领料出库单状态不正确,无法执行该操作"); + // TODO @AI:不需要的错误码,需要处理下。 + ErrorCode WM_PRODUCTION_ISSUE_WAREHOUSE_NOT_EXISTS = new ErrorCode(1_040_708_002, "仓库不存在"); + ErrorCode WM_PRODUCTION_ISSUE_ITEM_NOT_EXISTS = new ErrorCode(1_040_708_003, "物料不存在"); + ErrorCode WM_PRODUCTION_ISSUE_WORKORDER_NOT_EXISTS = new ErrorCode(1_040_708_004, "生产工单不存在"); + ErrorCode WM_PRODUCTION_ISSUE_WORKSTATION_NOT_EXISTS = new ErrorCode(1_040_708_005, "工作站不存在"); + ErrorCode WM_PRODUCTION_ISSUE_NO_LINE = new ErrorCode(1_040_708_006, "至少需要一条行项目"); + ErrorCode WM_PRODUCTION_ISSUE_QUANTITY_MISMATCH = new ErrorCode(1_040_708_007, "领料单行数量与明细数量不一致"); + ErrorCode WM_PRODUCTION_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_708_100, "生产领料出库单行不存在"); + ErrorCode WM_PRODUCTION_ISSUE_DETAIL_NOT_EXISTS = new ErrorCode(1_040_708_200, "生产领料出库单明细不存在"); + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductionIssueStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductionIssueStatusEnum.java index 4717048..d55f8e1 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductionIssueStatusEnum.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductionIssueStatusEnum.java @@ -1,12 +1,12 @@ package cn.iocoder.yudao.module.mes.enums.wm; import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants; import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Arrays; -// TODO @AI:需要使用 status constants 去映射; /** * MES 领料出库单状态枚举 */ @@ -14,9 +14,8 @@ import java.util.Arrays; @AllArgsConstructor public enum MesWmProductionIssueStatusEnum implements ArrayValuable { - PREPARE(10, "准备中"), - APPROVED(20, "已审批"), - FINISHED(30, "已完成"); + PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), + FINISHED(MesOrderStatusConstants.FINISHED, "已完成"); public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmProductionIssueStatusEnum::getStatus).toArray(Integer[]::new); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueService.java index e135073..0c359b1 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueService.java @@ -53,21 +53,7 @@ public interface MesWmProductionIssueService { PageResult getIssuePage(MesWmProductionIssuePageReqVO pageReqVO); /** - * 审批领料出库单(准备中 → 已审批,扣减库存) - * - * @param id 编号 - */ - void approveIssue(Long id); - - /** - * 反审批领料出库单(已审批 → 准备中,恢复库存) - * - * @param id 编号 - */ - void unapproveIssue(Long id); - - /** - * 完成领料出库单(已审批 → 已完成) + * 完成领料出库单(草稿 → 已完成,执行出库) * * @param id 编号 */ diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueServiceImpl.java index cfb6c82..1f69042 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productionissue/MesWmProductionIssueServiceImpl.java @@ -4,14 +4,19 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueLineSaveReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssuePageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueSaveReqVO; -import cn.iocoder.yudao.module.mes.controller.admin.wm.productionissue.vo.MesWmProductionIssueLineSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productionissue.MesWmProductionIssueLineDO; -import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdItemMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkstationMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderMapper; import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueLineMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.productionissue.MesWmProductionIssueMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseMapper; import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductionIssueStatusEnum; +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -21,6 +26,11 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_NOT_EXISTS; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCTION_ISSUE_STATUS_INVALID; + +// TODO @AI:参考别的模块,拆分多个; /** * MES 领料出库单 Service 实现类 */ @@ -40,17 +50,33 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @Resource private MesWmProductionIssueDetailService issueDetailService; + @Resource + private MesWmWarehouseMapper warehouseMapper; + + @Resource + private MesMdItemMapper itemMapper; + + @Resource + private MesMdWorkstationMapper workstationMapper; + + @Resource + private MesProWorkOrderMapper workOrderMapper; + + @Resource + private MesWmMaterialStockService materialStockService; + @Override @Transactional(rollbackFor = Exception.class) public Long createIssue(MesWmProductionIssueSaveReqVO createReqVO) { - // TODO @AI:领料出库关联数据校验待完善(仓库、物料、工单、工位等基础数据校验) + // 1. 校验关联数据 + validateRelatedData(createReqVO); - // 1. 插入主表 + // 2. 插入主表 MesWmProductionIssueDO issueHeader = BeanUtils.toBean(createReqVO, MesWmProductionIssueDO.class); issueHeader.setStatus(MesWmProductionIssueStatusEnum.PREPARE.getStatus()); issueHeaderMapper.insert(issueHeader); - // 2. 插入行表 + // 3. 插入行表 if (CollUtil.isNotEmpty(createReqVO.getLines())) { for (MesWmProductionIssueLineSaveReqVO lineVO : createReqVO.getLines()) { MesWmProductionIssueLineDO line = BeanUtils.toBean(lineVO, MesWmProductionIssueLineDO.class); @@ -67,13 +93,15 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ public void updateIssue(MesWmProductionIssueSaveReqVO updateReqVO) { // 1. 校验存在 + 准备中状态 validateIssueExistsAndPrepare(updateReqVO.getId()); - // TODO @AI:领料出库关联数据校验待完善(仓库、物料、工单、工位等基础数据校验) - // 2. 更新主表 + // 2. 校验关联数据 + validateRelatedData(updateReqVO); + + // 3. 更新主表 MesWmProductionIssueDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductionIssueDO.class); issueHeaderMapper.updateById(updateObj); - // 3. 更新行表:先删除旧数据,再插入新数据 + // 4. 更新行表:先删除旧数据,再插入新数据 issueLineMapper.deleteByIssueId(updateReqVO.getId()); if (CollUtil.isNotEmpty(updateReqVO.getLines())) { for (MesWmProductionIssueLineSaveReqVO lineVO : updateReqVO.getLines()) { @@ -110,51 +138,33 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ @Override @Transactional(rollbackFor = Exception.class) - public void approveIssue(Long id) { + public void finishIssue(Long id) { // 1.1 校验存在 MesWmProductionIssueDO issueHeader = validateIssueExists(id); - // 1.2 校验状态:只有准备中才允许审批 + // 1.2 校验状态:只有草稿才允许完成 if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.PREPARE.getStatus(), issueHeader.getStatus())) { -// throw exception(WM_ISSUE_STATUS_INVALID); - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下; - } - - // 2. 准备中 → 已审批 - issueHeaderMapper.updateById(new MesWmProductionIssueDO() - .setId(id).setStatus(MesWmProductionIssueStatusEnum.APPROVED.getStatus())); - - // TODO @AI:扣减库存逻辑待完善(需要调用库存服务,根据 detail 表扣减库存) - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void unapproveIssue(Long id) { - // 1.1 校验存在 - MesWmProductionIssueDO issueHeader = validateIssueExists(id); - // 1.2 校验状态:只有已审批才允许反审批 - if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.APPROVED.getStatus(), issueHeader.getStatus())) { -// throw exception(WM_ISSUE_STATUS_INVALID); - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下; + throw exception(WM_PRODUCTION_ISSUE_STATUS_INVALID); } - // 2. 已审批 → 准备中 - issueHeaderMapper.updateById(new MesWmProductionIssueDO() - .setId(id).setStatus(MesWmProductionIssueStatusEnum.PREPARE.getStatus())); - - // TODO @AI:恢复库存逻辑待完善(需要调用库存服务,根据 detail 表恢复库存) - } - - @Override - public void finishIssue(Long id) { - // 1.1 校验存在 - MesWmProductionIssueDO issueHeader = validateIssueExists(id); - // 1.2 校验状态:只有已审批才允许完成 - if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.APPROVED.getStatus(), issueHeader.getStatus())) { -// throw exception(WM_ISSUE_STATUS_INVALID); - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下; + // 2. 扣减库存(根据 line 表) + List lines = issueLineMapper.selectByIssueId(id); + if (CollUtil.isNotEmpty(lines)) { + for (MesWmProductionIssueLineDO line : lines) { + materialStockService.increaseStock( + line.getItemId(), + issueHeader.getWarehouseId(), // 使用主表的仓库ID + null, // locationId + null, // areaId + line.getBatchId(), + line.getQuantityIssued().negate(), // 负数表示扣减 + null, // vendorId + null, // productionDate + null // expireDate + ); + } } - // 2. 已审批 → 已完成 + // 3. 草稿 → 已完成 issueHeaderMapper.updateById(new MesWmProductionIssueDO() .setId(id).setStatus(MesWmProductionIssueStatusEnum.FINISHED.getStatus())); } @@ -170,8 +180,7 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ private MesWmProductionIssueDO validateIssueExists(Long id) { MesWmProductionIssueDO issueHeader = issueHeaderMapper.selectById(id); if (issueHeader == null) { -// throw exception(WM_ISSUE_NOT_EXISTS); - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下; + throw exception(WM_PRODUCTION_ISSUE_NOT_EXISTS); } return issueHeader; } @@ -182,8 +191,7 @@ public class MesWmProductionIssueServiceImpl implements MesWmProductionIssueServ private MesWmProductionIssueDO validateIssueExistsAndPrepare(Long id) { MesWmProductionIssueDO issueHeader = validateIssueExists(id); if (ObjUtil.notEqual(MesWmProductionIssueStatusEnum.PREPARE.getStatus(), issueHeader.getStatus())) { -// throw exception(WM_ISSUE_STATUS_INVALID); - throw new IllegalArgumentException(); // TODO @芋艿:晚点优化下; + throw exception(WM_PRODUCTION_ISSUE_STATUS_INVALID); } return issueHeader; }