Commit f7b06a095267da7562c47c29a7dbbf84a0d85a27
1 parent
7098655a
fix(mes): 完善生产工单模块,优化 BOM 展开、工单状态校验及仓库删除保护
1. BomController:新增物料需求接口 /item-list-by-work-order-id, 采用逐层 IN 查询展开 BOM 到叶子物料(替代递归),使用 convertMultiMap 统一风格; 补充 BomRespVO 的 itemOrProduct 字段及 itemType 拼接 2. WorkOrderController:新增 confirmWorkOrder 确认接口, 调整 confirm/finish/cancel 端点顺序;parentMap 改用 getWorkOrderMap 3. WorkOrderService/ServiceImpl:新增 getWorkOrderList 空判断、getWorkOrderMap、 confirmWorkOrder 状态校验,finish/cancel 增加"已确认"状态前置校验, 新增 PRO_WORK_ORDER_NOT_CONFIRMED 错误码 4. ProductBomMapper/Service:新增 selectByItemIds 批量查询方法 5. 仓库/库区/库位删除:补充库存记录占用校验(WM_WAREHOUSE_HAS_MATERIAL_STOCK 等) 6. 移除工单 batchCode 字段(DO/SaveReqVO/RespVO)
Showing
13 changed files
with
228 additions
and
45 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderBomController.java
| ... | ... | @@ -5,13 +5,18 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.util.collection.MapUtils; |
| 7 | 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 8 | +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderItemRespVO; | |
| 8 | 9 | import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; |
| 9 | 10 | import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomRespVO; |
| 10 | 11 | import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; |
| 11 | 12 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| 13 | +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; | |
| 14 | +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; | |
| 12 | 15 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| 13 | 16 | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; |
| 14 | 17 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| 18 | +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; | |
| 19 | +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService; | |
| 15 | 20 | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; |
| 16 | 21 | import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderBomService; |
| 17 | 22 | import io.swagger.v3.oas.annotations.Operation; |
| ... | ... | @@ -23,11 +28,10 @@ import org.springframework.security.access.prepost.PreAuthorize; |
| 23 | 28 | import org.springframework.validation.annotation.Validated; |
| 24 | 29 | import org.springframework.web.bind.annotation.*; |
| 25 | 30 | |
| 26 | -import java.util.Collections; | |
| 27 | -import java.util.List; | |
| 28 | -import java.util.Map; | |
| 29 | - | |
| 31 | +import java.math.BigDecimal; | |
| 32 | +import java.util.*; | |
| 30 | 33 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 34 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; | |
| 31 | 35 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 32 | 36 | |
| 33 | 37 | @Tag(name = "管理后台 - MES 生产工单 BOM") |
| ... | ... | @@ -45,6 +49,12 @@ public class MesProWorkOrderBomController { |
| 45 | 49 | @Resource |
| 46 | 50 | private MesMdUnitMeasureService unitMeasureService; |
| 47 | 51 | |
| 52 | + @Resource | |
| 53 | + private MesMdItemTypeService itemTypeService; | |
| 54 | + | |
| 55 | + @Resource | |
| 56 | + private MesMdProductBomService productBomService; | |
| 57 | + | |
| 48 | 58 | @PostMapping("/create") |
| 49 | 59 | @Operation(summary = "创建工单 BOM") |
| 50 | 60 | @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") |
| ... | ... | @@ -89,6 +99,44 @@ public class MesProWorkOrderBomController { |
| 89 | 99 | return success(new PageResult<>(buildWorkOrderBomRespVOList(pageResult.getList()), pageResult.getTotal())); |
| 90 | 100 | } |
| 91 | 101 | |
| 102 | + @GetMapping("/item-list-by-work-order-id") | |
| 103 | + @Operation(summary = "获得工单物料需求列表") | |
| 104 | + @Parameter(name = "workOrderId", description = "工单编号", required = true) | |
| 105 | + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") | |
| 106 | + public CommonResult<List<MesProWorkOrderItemRespVO>> getWorkOrderBomItemListByWorkOrderId( | |
| 107 | + @RequestParam("workOrderId") Long workOrderId) { | |
| 108 | + // 1. 获取工单 BOM 行 | |
| 109 | + List<MesProWorkOrderBomDO> bomList = workOrderBomService.getWorkOrderBomListByWorkOrderId(workOrderId); | |
| 110 | + if (CollUtil.isEmpty(bomList)) { | |
| 111 | + return success(Collections.emptyList()); | |
| 112 | + } | |
| 113 | + | |
| 114 | + // 2. 逐层展开,得到叶子物料 itemId → quantity | |
| 115 | + Map<Long, BigDecimal> leafItems = buildWorkOrderItems(bomList); | |
| 116 | + if (leafItems.isEmpty()) { | |
| 117 | + return success(Collections.emptyList()); | |
| 118 | + } | |
| 119 | + | |
| 120 | + // 3. 拼接 VO 字段 | |
| 121 | + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(leafItems.keySet()); | |
| 122 | + Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap( | |
| 123 | + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); | |
| 124 | + List<MesProWorkOrderItemRespVO> result = new ArrayList<>(leafItems.size()); | |
| 125 | + for (Map.Entry<Long, BigDecimal> entry : leafItems.entrySet()) { | |
| 126 | + MesMdItemDO item = itemMap.get(entry.getKey()); | |
| 127 | + if (item == null) { | |
| 128 | + continue; | |
| 129 | + } | |
| 130 | + MesProWorkOrderItemRespVO vo = new MesProWorkOrderItemRespVO() | |
| 131 | + .setItemId(item.getId()).setQuantity(entry.getValue()) | |
| 132 | + .setItemCode(item.getCode()).setItemName(item.getName()).setItemSpec(item.getSpecification()); | |
| 133 | + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), | |
| 134 | + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); | |
| 135 | + result.add(vo); | |
| 136 | + } | |
| 137 | + return success(result); | |
| 138 | + } | |
| 139 | + | |
| 92 | 140 | // ==================== 拼接 VO ==================== |
| 93 | 141 | |
| 94 | 142 | private List<MesProWorkOrderBomRespVO> buildWorkOrderBomRespVOList(List<MesProWorkOrderBomDO> list) { |
| ... | ... | @@ -100,14 +148,62 @@ public class MesProWorkOrderBomController { |
| 100 | 148 | convertSet(list, MesProWorkOrderBomDO::getItemId)); |
| 101 | 149 | Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap( |
| 102 | 150 | convertSet(list, MesProWorkOrderBomDO::getUnitMeasureId)); |
| 151 | + Map<Long, MesMdItemTypeDO> itemTypeMap = itemTypeService.getItemTypeMap( | |
| 152 | + convertSet(itemMap.values(), MesMdItemDO::getItemTypeId)); | |
| 103 | 153 | // 2. 拼接 VO |
| 104 | 154 | return BeanUtils.toBean(list, MesProWorkOrderBomRespVO.class, vo -> { |
| 105 | - MapUtils.findAndThen(itemMap, vo.getItemId(), item -> | |
| 106 | - vo.setItemName(item.getName()).setItemCode(item.getCode()) | |
| 107 | - .setItemSpec(item.getSpecification())); | |
| 155 | + MapUtils.findAndThen(itemMap, vo.getItemId(), item -> { | |
| 156 | + vo.setItemName(item.getName()).setItemCode(item.getCode()) | |
| 157 | + .setItemSpec(item.getSpecification()); | |
| 158 | + MapUtils.findAndThen(itemTypeMap, item.getItemTypeId(), | |
| 159 | + itemType -> vo.setItemOrProduct(itemType.getItemOrProduct())); | |
| 160 | + }); | |
| 108 | 161 | MapUtils.findAndThen(unitMeasureMap, vo.getUnitMeasureId(), |
| 109 | 162 | unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); |
| 110 | 163 | }); |
| 111 | 164 | } |
| 112 | 165 | |
| 166 | + // ==================== 物料需求逐层展开 ==================== | |
| 167 | + | |
| 168 | + /** | |
| 169 | + * 逐层 IN 查询展开工单 BOM 到叶子物料,合并同物料的需求数量 | |
| 170 | + * | |
| 171 | + * @param bomList 工单 BOM 列表 | |
| 172 | + * @return 叶子物料 Map:itemId → 合并后的需求数量 | |
| 173 | + */ | |
| 174 | + private Map<Long, BigDecimal> buildWorkOrderItems(List<MesProWorkOrderBomDO> bomList) { | |
| 175 | + // 1. 初始化:收集第一层物料 ID 和对应数量 | |
| 176 | + Map<Long, BigDecimal> currentLayer = new LinkedHashMap<>(); | |
| 177 | + for (MesProWorkOrderBomDO bom : bomList) { | |
| 178 | + currentLayer.merge(bom.getItemId(), bom.getQuantity(), BigDecimal::add); | |
| 179 | + } | |
| 180 | + | |
| 181 | + // 2. 逐层 IN 查询展开 BOM | |
| 182 | + Map<Long, BigDecimal> leafItems = new LinkedHashMap<>(); | |
| 183 | + for (int i = 0; i < Byte.MAX_VALUE && CollUtil.isNotEmpty(currentLayer); i++) { | |
| 184 | + // 2.1 批量查询当前层所有物料的子 BOM | |
| 185 | + List<MesMdProductBomDO> subBomList = productBomService.getProductBomListByItemIds(currentLayer.keySet()); | |
| 186 | + // 2.2 按 itemId 分组 | |
| 187 | + Map<Long, List<MesMdProductBomDO>> subBomMap = convertMultiMap(subBomList, MesMdProductBomDO::getItemId); | |
| 188 | + // 2.3 区分叶子节点和非叶子节点 | |
| 189 | + Map<Long, BigDecimal> nextLayer = new LinkedHashMap<>(); | |
| 190 | + for (Map.Entry<Long, BigDecimal> entry : currentLayer.entrySet()) { | |
| 191 | + Long itemId = entry.getKey(); | |
| 192 | + BigDecimal quantity = entry.getValue(); | |
| 193 | + List<MesMdProductBomDO> children = subBomMap.get(itemId); | |
| 194 | + // 情况一:叶子节点,累加到结果 | |
| 195 | + if (CollUtil.isEmpty(children)) { | |
| 196 | + leafItems.merge(itemId, quantity, BigDecimal::add); | |
| 197 | + continue; | |
| 198 | + } | |
| 199 | + // 情况二:非叶子,子物料进入下一层 | |
| 200 | + for (MesMdProductBomDO child : children) { | |
| 201 | + nextLayer.merge(child.getBomItemId(), quantity.multiply(child.getQuantity()), BigDecimal::add); | |
| 202 | + } | |
| 203 | + } | |
| 204 | + currentLayer = nextLayer; | |
| 205 | + } | |
| 206 | + return leafItems; | |
| 207 | + } | |
| 208 | + | |
| 113 | 209 | } | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderController.java
| ... | ... | @@ -32,14 +32,10 @@ import org.springframework.validation.annotation.Validated; |
| 32 | 32 | import org.springframework.web.bind.annotation.*; |
| 33 | 33 | |
| 34 | 34 | import java.io.IOException; |
| 35 | -import java.util.Collections; | |
| 36 | -import java.util.List; | |
| 37 | -import java.util.Map; | |
| 38 | -import java.util.Set; | |
| 35 | +import java.util.*; | |
| 39 | 36 | |
| 40 | 37 | import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; |
| 41 | 38 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 42 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 43 | 39 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 44 | 40 | |
| 45 | 41 | @Tag(name = "管理后台 - MES 生产工单") |
| ... | ... | @@ -119,6 +115,15 @@ public class MesProWorkOrderController { |
| 119 | 115 | ExcelUtils.write(response, "生产工单.xls", "数据", MesProWorkOrderRespVO.class, voList); |
| 120 | 116 | } |
| 121 | 117 | |
| 118 | + @PutMapping("/confirm") | |
| 119 | + @Operation(summary = "确认工单") | |
| 120 | + @Parameter(name = "id", description = "编号", required = true) | |
| 121 | + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") | |
| 122 | + public CommonResult<Boolean> confirmWorkOrder(@RequestParam("id") Long id) { | |
| 123 | + workOrderService.confirmWorkOrder(id); | |
| 124 | + return success(true); | |
| 125 | + } | |
| 126 | + | |
| 122 | 127 | @PutMapping("/finish") |
| 123 | 128 | @Operation(summary = "完成工单") |
| 124 | 129 | @Parameter(name = "id", description = "编号", required = true) |
| ... | ... | @@ -152,11 +157,8 @@ public class MesProWorkOrderController { |
| 152 | 157 | convertSet(list, MesProWorkOrderDO::getVendorId)); |
| 153 | 158 | Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap( |
| 154 | 159 | convertSet(list, MesProWorkOrderDO::getUnitMeasureId)); |
| 155 | - // TODO @AI:直接 workOrderService.getWorkOrderMap,内部调用 workOrderService.getWorkOrderList | |
| 156 | - Set<Long> parentIds = convertSet(list, MesProWorkOrderDO::getParentId); | |
| 157 | - Map<Long, MesProWorkOrderDO> parentMap = CollUtil.isEmpty(parentIds) | |
| 158 | - ? Collections.emptyMap() | |
| 159 | - : convertMap(workOrderService.getWorkOrderList(parentIds), MesProWorkOrderDO::getId); | |
| 160 | + Map<Long, MesProWorkOrderDO> parentMap = workOrderService.getWorkOrderMap( | |
| 161 | + convertSet(list, MesProWorkOrderDO::getParentId)); | |
| 160 | 162 | // 2. 拼接 VO |
| 161 | 163 | return BeanUtils.toBean(list, MesProWorkOrderRespVO.class, vo -> { |
| 162 | 164 | MapUtils.findAndThen(itemMap, vo.getProductId(), item -> | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderItemRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.math.BigDecimal; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - MES 工单物料需求 Response VO") | |
| 9 | +@Data | |
| 10 | +public class MesProWorkOrderItemRespVO { | |
| 11 | + | |
| 12 | + @Schema(description = "物料编号", example = "100") | |
| 13 | + private Long itemId; | |
| 14 | + | |
| 15 | + @Schema(description = "物料编码", example = "M-001") | |
| 16 | + private String itemCode; | |
| 17 | + | |
| 18 | + @Schema(description = "物料名称", example = "电阻 10K") | |
| 19 | + private String itemName; | |
| 20 | + | |
| 21 | + @Schema(description = "规格型号", example = "0603") | |
| 22 | + private String itemSpec; | |
| 23 | + | |
| 24 | + @Schema(description = "单位名称", example = "个") | |
| 25 | + private String unitMeasureName; | |
| 26 | + | |
| 27 | + @Schema(description = "需求数量", example = "1000.00") | |
| 28 | + private BigDecimal quantity; | |
| 29 | + | |
| 30 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkorderRespVO.java
| ... | ... | @@ -98,10 +98,6 @@ public class MesProWorkOrderRespVO { |
| 98 | 98 | @ExcelProperty("供应商名称") |
| 99 | 99 | private String vendorName; |
| 100 | 100 | |
| 101 | - @Schema(description = "批次号", example = "BATCH-001") | |
| 102 | - @ExcelProperty("批次号") | |
| 103 | - private String batchCode; | |
| 104 | - | |
| 105 | 101 | @Schema(description = "需求日期") |
| 106 | 102 | @ExcelProperty("需求日期") |
| 107 | 103 | private LocalDateTime requestDate; | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkorderSaveReqVO.java
| ... | ... | @@ -61,9 +61,6 @@ public class MesProWorkOrderSaveReqVO { |
| 61 | 61 | @Schema(description = "供应商编号", example = "400") |
| 62 | 62 | private Long vendorId; |
| 63 | 63 | |
| 64 | - @Schema(description = "批次号", example = "BATCH-001") | |
| 65 | - private String batchCode; | |
| 66 | - | |
| 67 | 64 | @Schema(description = "需求日期", requiredMode = Schema.RequiredMode.REQUIRED) |
| 68 | 65 | @NotNull(message = "需求日期不能为空") |
| 69 | 66 | private LocalDateTime requestDate; | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomRespVO.java
| ... | ... | @@ -50,6 +50,9 @@ public class MesProWorkOrderBomRespVO { |
| 50 | 50 | @ExcelProperty("备注") |
| 51 | 51 | private String remark; |
| 52 | 52 | |
| 53 | + @Schema(description = "物料产品标识", example = "PRODUCT") | |
| 54 | + private String itemOrProduct; | |
| 55 | + | |
| 53 | 56 | @Schema(description = "预留字段1") |
| 54 | 57 | private String attribute1; |
| 55 | 58 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderDO.java
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductBomMapper.java
| ... | ... | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductB |
| 7 | 7 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; |
| 8 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 9 | |
| 10 | +import java.util.Collection; | |
| 10 | 11 | import java.util.List; |
| 11 | 12 | |
| 12 | 13 | /** |
| ... | ... | @@ -28,6 +29,10 @@ public interface MesMdProductBomMapper extends BaseMapperX<MesMdProductBomDO> { |
| 28 | 29 | return selectList(MesMdProductBomDO::getItemId, itemId); |
| 29 | 30 | } |
| 30 | 31 | |
| 32 | + default List<MesMdProductBomDO> selectByItemIds(Collection<Long> itemIds) { | |
| 33 | + return selectList(MesMdProductBomDO::getItemId, itemIds); | |
| 34 | + } | |
| 35 | + | |
| 31 | 36 | default List<MesMdProductBomDO> selectAll() { |
| 32 | 37 | return selectList(); |
| 33 | 38 | } | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
| ... | ... | @@ -167,6 +167,7 @@ public interface ErrorCodeConstants { |
| 167 | 167 | ErrorCode PRO_WORK_ORDER_NOT_EXISTS = new ErrorCode(1_040_502_000, "生产工单不存在"); |
| 168 | 168 | ErrorCode PRO_WORK_ORDER_CODE_DUPLICATE = new ErrorCode(1_040_502_001, "生产工单编码已存在"); |
| 169 | 169 | ErrorCode PRO_WORK_ORDER_NOT_PREPARE = new ErrorCode(1_040_502_002, "只能删除草稿状态的工单"); |
| 170 | + ErrorCode PRO_WORK_ORDER_NOT_CONFIRMED = new ErrorCode(1_040_502_003, "只有已确认状态的工单才能执行此操作"); | |
| 170 | 171 | ErrorCode PRO_WORK_ORDER_BOM_NOT_EXISTS = new ErrorCode(1_040_502_100, "生产工单BOM不存在"); |
| 171 | 172 | |
| 172 | 173 | // ========== MES 生产管理-生产任务(1-040-503-000) ========== | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomService.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductB |
| 6 | 6 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; |
| 7 | 7 | import jakarta.validation.Valid; |
| 8 | 8 | |
| 9 | +import java.util.Collection; | |
| 9 | 10 | import java.util.List; |
| 10 | 11 | |
| 11 | 12 | /** |
| ... | ... | @@ -62,6 +63,14 @@ public interface MesMdProductBomService { |
| 62 | 63 | List<MesMdProductBomDO> getProductBomListByItemId(Long itemId); |
| 63 | 64 | |
| 64 | 65 | /** |
| 66 | + * 根据物料产品编号批量获得产品BOM列表 | |
| 67 | + * | |
| 68 | + * @param itemIds 物料产品编号数组 | |
| 69 | + * @return 产品BOM列表 | |
| 70 | + */ | |
| 71 | + List<MesMdProductBomDO> getProductBomListByItemIds(Collection<Long> itemIds); | |
| 72 | + | |
| 73 | + /** | |
| 65 | 74 | * 根据物料产品编号删除产品BOM |
| 66 | 75 | * |
| 67 | 76 | * @param itemId 物料产品编号 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomServiceImpl.java
| ... | ... | @@ -133,6 +133,11 @@ public class MesMdProductBomServiceImpl implements MesMdProductBomService { |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | 135 | @Override |
| 136 | + public List<MesMdProductBomDO> getProductBomListByItemIds(Collection<Long> itemIds) { | |
| 137 | + return productBomMapper.selectByItemIds(itemIds); | |
| 138 | + } | |
| 139 | + | |
| 140 | + @Override | |
| 136 | 141 | public void deleteProductBomByItemId(Long itemId) { |
| 137 | 142 | productBomMapper.deleteByItemId(itemId); |
| 138 | 143 | } | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java
| ... | ... | @@ -8,6 +8,9 @@ import jakarta.validation.Valid; |
| 8 | 8 | |
| 9 | 9 | import java.util.Collection; |
| 10 | 10 | import java.util.List; |
| 11 | +import java.util.Map; | |
| 12 | + | |
| 13 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 11 | 14 | |
| 12 | 15 | /** |
| 13 | 16 | * MES 生产工单 Service 接口 |
| ... | ... | @@ -63,25 +66,42 @@ public interface MesProWorkOrderService { |
| 63 | 66 | PageResult<MesProWorkOrderDO> getWorkOrderPage(MesProWorkOrderPageReqVO pageReqVO); |
| 64 | 67 | |
| 65 | 68 | /** |
| 66 | - * 完成工单 | |
| 69 | + * 获得工单列表 | |
| 70 | + * | |
| 71 | + * @param ids 编号数组 | |
| 72 | + * @return 工单列表 | |
| 73 | + */ | |
| 74 | + List<MesProWorkOrderDO> getWorkOrderList(Collection<Long> ids); | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * 获得工单 Map | |
| 78 | + * | |
| 79 | + * @param ids 编号数组 | |
| 80 | + * @return 工单 Map | |
| 81 | + */ | |
| 82 | + default Map<Long, MesProWorkOrderDO> getWorkOrderMap(Collection<Long> ids) { | |
| 83 | + return convertMap(getWorkOrderList(ids), MesProWorkOrderDO::getId); | |
| 84 | + } | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * 确认工单(草稿 → 已确认) | |
| 67 | 88 | * |
| 68 | 89 | * @param id 编号 |
| 69 | 90 | */ |
| 70 | - void finishWorkOrder(Long id); | |
| 91 | + void confirmWorkOrder(Long id); | |
| 71 | 92 | |
| 72 | 93 | /** |
| 73 | - * 取消工单 | |
| 94 | + * 完成工单 | |
| 74 | 95 | * |
| 75 | 96 | * @param id 编号 |
| 76 | 97 | */ |
| 77 | - void cancelWorkOrder(Long id); | |
| 98 | + void finishWorkOrder(Long id); | |
| 78 | 99 | |
| 79 | 100 | /** |
| 80 | - * 获得工单列表 | |
| 101 | + * 取消工单 | |
| 81 | 102 | * |
| 82 | - * @param ids 编号数组 | |
| 83 | - * @return 工单列表 | |
| 103 | + * @param id 编号 | |
| 84 | 104 | */ |
| 85 | - List<MesProWorkOrderDO> getWorkOrderList(Collection<Long> ids); | |
| 105 | + void cancelWorkOrder(Long id); | |
| 86 | 106 | |
| 87 | 107 | } | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java
| ... | ... | @@ -25,6 +25,7 @@ import org.springframework.validation.annotation.Validated; |
| 25 | 25 | import java.math.BigDecimal; |
| 26 | 26 | import java.time.LocalDateTime; |
| 27 | 27 | import java.util.Collection; |
| 28 | +import java.util.Collections; | |
| 28 | 29 | import java.util.List; |
| 29 | 30 | |
| 30 | 31 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| ... | ... | @@ -139,9 +140,33 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { |
| 139 | 140 | } |
| 140 | 141 | |
| 141 | 142 | @Override |
| 142 | - public void finishWorkOrder(Long id) { | |
| 143 | + public List<MesProWorkOrderDO> getWorkOrderList(Collection<Long> ids) { | |
| 144 | + if (CollUtil.isEmpty(ids)) { | |
| 145 | + return Collections.emptyList(); | |
| 146 | + } | |
| 147 | + return workOrderMapper.selectByIds(ids); | |
| 148 | + } | |
| 149 | + | |
| 150 | + @Override | |
| 151 | + public void confirmWorkOrder(Long id) { | |
| 143 | 152 | // 1. 校验存在 |
| 144 | - validateWorkOrderExists(id); | |
| 153 | + MesProWorkOrderDO workOrder = validateWorkOrderExists(id); | |
| 154 | + // 2. 只有草稿状态才能确认 | |
| 155 | + if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) { | |
| 156 | + throw exception(PRO_WORK_ORDER_NOT_PREPARE); | |
| 157 | + } | |
| 158 | + // 3. 更新状态为已确认 | |
| 159 | + workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) | |
| 160 | + .setStatus(MesProWorkOrderStatusEnum.CONFIRMED.getStatus())); | |
| 161 | + } | |
| 162 | + | |
| 163 | + @Override | |
| 164 | + public void finishWorkOrder(Long id) { | |
| 165 | + // 1. 校验存在 + 只有已确认状态才能完成 | |
| 166 | + MesProWorkOrderDO workOrder = validateWorkOrderExists(id); | |
| 167 | + if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { | |
| 168 | + throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); | |
| 169 | + } | |
| 145 | 170 | |
| 146 | 171 | // 2. 更新状态为已完成 |
| 147 | 172 | workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) |
| ... | ... | @@ -152,8 +177,11 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { |
| 152 | 177 | |
| 153 | 178 | @Override |
| 154 | 179 | public void cancelWorkOrder(Long id) { |
| 155 | - // 1. 校验存在 | |
| 156 | - validateWorkOrderExists(id); | |
| 180 | + // 1. 校验存在 + 只有已确认状态才能取消 | |
| 181 | + MesProWorkOrderDO workOrder = validateWorkOrderExists(id); | |
| 182 | + if (!ObjUtil.equal(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { | |
| 183 | + throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); | |
| 184 | + } | |
| 157 | 185 | |
| 158 | 186 | // 2. 更新状态为已取消 |
| 159 | 187 | workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) |
| ... | ... | @@ -162,11 +190,6 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { |
| 162 | 190 | // TODO @芋艿:pro_task 未迁移,暂不级联更新任务状态 |
| 163 | 191 | } |
| 164 | 192 | |
| 165 | - @Override | |
| 166 | - public List<MesProWorkOrderDO> getWorkOrderList(Collection<Long> ids) { | |
| 167 | - return workOrderMapper.selectByIds(ids); | |
| 168 | - } | |
| 169 | - | |
| 170 | 193 | // ==================== 校验方法 ==================== |
| 171 | 194 | |
| 172 | 195 | private void validateWorkOrderCodeUnique(Long id, String code) { | ... | ... |