From 41e26623b4bae0488933676eeecfa9ee0eaa427f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 6 Apr 2026 19:35:19 +0800 Subject: [PATCH] feat(mes):修复 workorder 的路径问题 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderBomController.java | 209 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderController.java | 180 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomPageReqVO.java | 20 ++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomRespVO.java | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomSaveReqVO.java | 31 +++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomPageReqVO.java | 20 -------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomRespVO.java | 60 ------------------------------------------------------------ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomSaveReqVO.java | 31 ------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderBomDO.java | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderBomDO.java | 53 ----------------------------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderDO.java | 134 -------------------------------------------------------------------------------------------------------------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderBomMapper.java | 34 ++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderMapper.java | 43 +++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderBomMapper.java | 34 ---------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java | 43 ------------------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java | 39 +++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderTypeEnum.java | 38 ++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderStatusEnum.java | 39 --------------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderTypeEnum.java | 38 -------------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomService.java | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomServiceImpl.java | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomService.java | 83 ----------------------------------------------------------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomServiceImpl.java | 136 ---------------------------------------------------------------------------------------------------------------------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java | 132 ------------------------------------------------------------------------------------------------------------------------------------ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java | 248 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 30 files changed, 1440 insertions(+), 1440 deletions(-) create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderBomController.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderController.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomPageReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomRespVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomSaveReqVO.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomPageReqVO.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomRespVO.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomSaveReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderBomDO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderBomDO.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderDO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderBomMapper.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderMapper.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderBomMapper.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderTypeEnum.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderStatusEnum.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderTypeEnum.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomService.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomServiceImpl.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomService.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomServiceImpl.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java delete mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java new file mode 100644 index 0000000..464d54d --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java @@ -0,0 +1,209 @@ +package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderItemRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService; +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; +import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderBomService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; +import java.util.*; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - MES 生产工单 BOM") +@RestController +@RequestMapping("/mes/pro/work-order-bom") +@Validated +public class MesProWorkOrderBomController { + + @Resource + private MesProWorkOrderBomService workOrderBomService; + + @Resource + private MesMdItemService itemService; + + @Resource + private MesMdUnitMeasureService unitMeasureService; + + @Resource + private MesMdItemTypeService itemTypeService; + + @Resource + private MesMdProductBomService productBomService; + + @PostMapping("/create") + @Operation(summary = "创建工单 BOM") + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") + public CommonResult createWorkOrderBom(@Valid @RequestBody MesProWorkOrderBomSaveReqVO createReqVO) { + return success(workOrderBomService.createWorkOrderBom(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新工单 BOM") + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") + public CommonResult updateWorkOrderBom(@Valid @RequestBody MesProWorkOrderBomSaveReqVO updateReqVO) { + workOrderBomService.updateWorkOrderBom(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除工单 BOM") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") + public CommonResult deleteWorkOrderBom(@RequestParam("id") Long id) { + workOrderBomService.deleteWorkOrderBom(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得工单 BOM") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") + public CommonResult getWorkOrderBom(@RequestParam("id") Long id) { + MesProWorkOrderBomDO workOrderBom = workOrderBomService.getWorkOrderBom(id); + if (workOrderBom == null) { + return success(null); + } + return success(buildWorkOrderBomRespVOList(List.of(workOrderBom)).get(0)); + } + + @GetMapping("/page") + @Operation(summary = "获得工单 BOM 分页") + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") + public CommonResult> getWorkOrderBomPage(@Valid MesProWorkOrderBomPageReqVO pageReqVO) { + PageResult pageResult = workOrderBomService.getWorkOrderBomPage(pageReqVO); + return success(new PageResult<>(buildWorkOrderBomRespVOList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/item-list-by-work-order-id") + @Operation(summary = "获得工单物料需求列表") + @Parameter(name = "workOrderId", description = "工单编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") + public CommonResult> getWorkOrderBomItemListByWorkOrderId( + @RequestParam("workOrderId") Long workOrderId) { + // 1. 获取工单 BOM 行 + List bomList = workOrderBomService.getWorkOrderBomListByWorkOrderId(workOrderId); + if (CollUtil.isEmpty(bomList)) { + return success(Collections.emptyList()); + } + + // 2. 逐层展开,得到叶子物料 itemId → quantity + Map leafItems = buildWorkOrderItems(bomList); + if (CollUtil.isEmpty(leafItems)) { + return success(Collections.emptyList()); + } + + // 3. 拼接 VO 字段 + Map itemMap = itemService.getItemMap(leafItems.keySet()); + Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); + List result = new ArrayList<>(leafItems.size()); + for (Map.Entry entry : leafItems.entrySet()) { + MesMdItemDO item = itemMap.get(entry.getKey()); + if (item == null) { + continue; + } + MesProWorkOrderItemRespVO vo = new MesProWorkOrderItemRespVO() + .setItemId(item.getId()).setQuantity(entry.getValue()) + .setItemCode(item.getCode()).setItemName(item.getName()).setItemSpec(item.getSpecification()); + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); + result.add(vo); + } + return success(result); + } + + // ==================== 拼接 VO ==================== + + private List buildWorkOrderBomRespVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1. 批量获取关联数据 + Map itemMap = itemService.getItemMap( + convertSet(list, MesProWorkOrderBomDO::getItemId)); + Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); + Map itemTypeMap = itemTypeService.getItemTypeMap( + convertSet(itemMap.values(), MesMdItemDO::getItemTypeId)); + // 2. 拼接 VO + return BeanUtils.toBean(list, MesProWorkOrderBomRespVO.class, vo -> { + MapUtils.findAndThen(itemMap, vo.getItemId(), item -> { + vo.setItemName(item.getName()).setItemCode(item.getCode()) + .setItemSpec(item.getSpecification()); + MapUtils.findAndThen(itemTypeMap, item.getItemTypeId(), + itemType -> vo.setItemOrProduct(itemType.getItemOrProduct())); + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); + }); + }); + } + + // ==================== 物料需求逐层展开 ==================== + + /** + * 逐层 IN 查询展开工单 BOM 到叶子物料,合并同物料的需求数量 + * + * @param bomList 工单 BOM 列表 + * @return 叶子物料 Map:itemId → 合并后的需求数量 + */ + private Map buildWorkOrderItems(List bomList) { + // 1. 初始化:收集第一层物料 ID 和对应数量 + Map currentLayer = new LinkedHashMap<>(); + for (MesProWorkOrderBomDO bom : bomList) { + currentLayer.merge(bom.getItemId(), bom.getQuantity(), BigDecimal::add); + } + + // 2. 逐层 IN 查询展开 BOM + Map leafItems = new LinkedHashMap<>(); + for (int i = 0; i < Byte.MAX_VALUE && CollUtil.isNotEmpty(currentLayer); i++) { + // 2.1 批量查询当前层所有物料的子 BOM + List subBomList = productBomService.getProductBomListByItemIds(currentLayer.keySet()); + // 2.2 按 itemId 分组 + Map> subBomMap = convertMultiMap(subBomList, MesMdProductBomDO::getItemId); + // 2.3 区分叶子节点和非叶子节点 + Map nextLayer = new LinkedHashMap<>(); + for (Map.Entry entry : currentLayer.entrySet()) { + Long itemId = entry.getKey(); + BigDecimal quantity = entry.getValue(); + List children = subBomMap.get(itemId); + // 情况一:叶子节点,累加到结果 + if (CollUtil.isEmpty(children)) { + leafItems.merge(itemId, quantity, BigDecimal::add); + continue; + } + // 情况二:非叶子,子物料进入下一层 + for (MesMdProductBomDO child : children) { + nextLayer.merge(child.getBomItemId(), quantity.multiply(child.getQuantity()), BigDecimal::add); + } + } + currentLayer = nextLayer; + } + return leafItems; + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java new file mode 100644 index 0000000..7d7b678 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java @@ -0,0 +1,180 @@ +package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; +import cn.iocoder.yudao.module.mes.service.md.client.MesMdClientService; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; +import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService; +import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.*; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - MES 生产工单") +@RestController +@RequestMapping("/mes/pro/work-order") +@Validated +public class MesProWorkOrderController { + + @Resource + private MesProWorkOrderService workOrderService; + + @Resource + private MesMdItemService itemService; + + @Resource + private MesMdClientService clientService; + + @Resource + private MesMdVendorService vendorService; + + @Resource + private MesMdUnitMeasureService unitMeasureService; + + @PostMapping("/create") + @Operation(summary = "创建生产工单") + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:create')") + public CommonResult createWorkOrder(@Valid @RequestBody MesProWorkOrderSaveReqVO createReqVO) { + return success(workOrderService.createWorkOrder(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新生产工单") + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") + public CommonResult updateWorkOrder(@Valid @RequestBody MesProWorkOrderSaveReqVO updateReqVO) { + workOrderService.updateWorkOrder(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除生产工单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:delete')") + public CommonResult deleteWorkOrder(@RequestParam("id") Long id) { + workOrderService.deleteWorkOrder(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得生产工单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") + public CommonResult getWorkOrder(@RequestParam("id") Long id) { + MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(id); + if (workOrder == null) { + return success(null); + } + return success(buildWorkOrderRespVOList(List.of(workOrder)).get(0)); + } + + @GetMapping("/page") + @Operation(summary = "获得生产工单分页") + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") + public CommonResult> getWorkOrderPage(@Valid MesProWorkOrderPageReqVO pageReqVO) { + PageResult pageResult = workOrderService.getWorkOrderPage(pageReqVO); + return success(new PageResult<>(buildWorkOrderRespVOList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出生产工单 Excel") + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportWorkOrderExcel(@Valid MesProWorkOrderPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = workOrderService.getWorkOrderPage(pageReqVO).getList(); + List voList = buildWorkOrderRespVOList(list); + ExcelUtils.write(response, "生产工单.xls", "数据", MesProWorkOrderRespVO.class, voList); + } + + @PutMapping("/confirm") + @Operation(summary = "确认工单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") + public CommonResult confirmWorkOrder(@RequestParam("id") Long id) { + workOrderService.confirmWorkOrder(id); + return success(true); + } + + @PutMapping("/finish") + @Operation(summary = "完成工单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") + public CommonResult finishWorkOrder(@RequestParam("id") Long id) { + workOrderService.finishWorkOrder(id); + return success(true); + } + + @PutMapping("/cancel") + @Operation(summary = "取消工单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") + public CommonResult cancelWorkOrder(@RequestParam("id") Long id) { + workOrderService.cancelWorkOrder(id); + return success(true); + } + + // ==================== 拼接 VO ==================== + + private List buildWorkOrderRespVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1. 批量获取关联数据 + Map itemMap = itemService.getItemMap( + convertSet(list, MesProWorkOrderDO::getProductId)); + Map clientMap = clientService.getClientMap( + convertSet(list, MesProWorkOrderDO::getClientId)); + Map vendorMap = vendorService.getVendorMap( + convertSet(list, MesProWorkOrderDO::getVendorId)); + // 单位从产品关联的 item 获得 + Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); + Map parentMap = workOrderService.getWorkOrderMap( + convertSet(list, MesProWorkOrderDO::getParentId)); + // 2. 拼接 VO(单位名称从产品关联的 item 获得) + return BeanUtils.toBean(list, MesProWorkOrderRespVO.class, vo -> { + MapUtils.findAndThen(itemMap, vo.getProductId(), item -> { + vo.setProductName(item.getName()).setProductCode(item.getCode()) + .setProductSpec(item.getSpecification()); + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); + }); + MapUtils.findAndThen(clientMap, vo.getClientId(), + client -> vo.setClientName(client.getName()).setClientCode(client.getCode())); + MapUtils.findAndThen(vendorMap, vo.getVendorId(), + vendor -> vo.setVendorName(vendor.getName()).setVendorCode(vendor.getCode())); + MapUtils.findAndThen(parentMap, vo.getParentId(), + parent -> vo.setParentCode(parent.getCode())); + }); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderBomController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderBomController.java deleted file mode 100644 index 464d54d..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderBomController.java +++ /dev/null @@ -1,209 +0,0 @@ -package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderItemRespVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomRespVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; -import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; -import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; -import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService; -import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; -import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderBomService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.math.BigDecimal; -import java.util.*; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; - -@Tag(name = "管理后台 - MES 生产工单 BOM") -@RestController -@RequestMapping("/mes/pro/work-order-bom") -@Validated -public class MesProWorkOrderBomController { - - @Resource - private MesProWorkOrderBomService workOrderBomService; - - @Resource - private MesMdItemService itemService; - - @Resource - private MesMdUnitMeasureService unitMeasureService; - - @Resource - private MesMdItemTypeService itemTypeService; - - @Resource - private MesMdProductBomService productBomService; - - @PostMapping("/create") - @Operation(summary = "创建工单 BOM") - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") - public CommonResult createWorkOrderBom(@Valid @RequestBody MesProWorkOrderBomSaveReqVO createReqVO) { - return success(workOrderBomService.createWorkOrderBom(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新工单 BOM") - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") - public CommonResult updateWorkOrderBom(@Valid @RequestBody MesProWorkOrderBomSaveReqVO updateReqVO) { - workOrderBomService.updateWorkOrderBom(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除工单 BOM") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") - public CommonResult deleteWorkOrderBom(@RequestParam("id") Long id) { - workOrderBomService.deleteWorkOrderBom(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得工单 BOM") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") - public CommonResult getWorkOrderBom(@RequestParam("id") Long id) { - MesProWorkOrderBomDO workOrderBom = workOrderBomService.getWorkOrderBom(id); - if (workOrderBom == null) { - return success(null); - } - return success(buildWorkOrderBomRespVOList(List.of(workOrderBom)).get(0)); - } - - @GetMapping("/page") - @Operation(summary = "获得工单 BOM 分页") - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") - public CommonResult> getWorkOrderBomPage(@Valid MesProWorkOrderBomPageReqVO pageReqVO) { - PageResult pageResult = workOrderBomService.getWorkOrderBomPage(pageReqVO); - return success(new PageResult<>(buildWorkOrderBomRespVOList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/item-list-by-work-order-id") - @Operation(summary = "获得工单物料需求列表") - @Parameter(name = "workOrderId", description = "工单编号", required = true) - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") - public CommonResult> getWorkOrderBomItemListByWorkOrderId( - @RequestParam("workOrderId") Long workOrderId) { - // 1. 获取工单 BOM 行 - List bomList = workOrderBomService.getWorkOrderBomListByWorkOrderId(workOrderId); - if (CollUtil.isEmpty(bomList)) { - return success(Collections.emptyList()); - } - - // 2. 逐层展开,得到叶子物料 itemId → quantity - Map leafItems = buildWorkOrderItems(bomList); - if (CollUtil.isEmpty(leafItems)) { - return success(Collections.emptyList()); - } - - // 3. 拼接 VO 字段 - Map itemMap = itemService.getItemMap(leafItems.keySet()); - Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( - convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); - List result = new ArrayList<>(leafItems.size()); - for (Map.Entry entry : leafItems.entrySet()) { - MesMdItemDO item = itemMap.get(entry.getKey()); - if (item == null) { - continue; - } - MesProWorkOrderItemRespVO vo = new MesProWorkOrderItemRespVO() - .setItemId(item.getId()).setQuantity(entry.getValue()) - .setItemCode(item.getCode()).setItemName(item.getName()).setItemSpec(item.getSpecification()); - MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), - unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); - result.add(vo); - } - return success(result); - } - - // ==================== 拼接 VO ==================== - - private List buildWorkOrderBomRespVOList(List list) { - if (CollUtil.isEmpty(list)) { - return Collections.emptyList(); - } - // 1. 批量获取关联数据 - Map itemMap = itemService.getItemMap( - convertSet(list, MesProWorkOrderBomDO::getItemId)); - Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( - convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); - Map itemTypeMap = itemTypeService.getItemTypeMap( - convertSet(itemMap.values(), MesMdItemDO::getItemTypeId)); - // 2. 拼接 VO - return BeanUtils.toBean(list, MesProWorkOrderBomRespVO.class, vo -> { - MapUtils.findAndThen(itemMap, vo.getItemId(), item -> { - vo.setItemName(item.getName()).setItemCode(item.getCode()) - .setItemSpec(item.getSpecification()); - MapUtils.findAndThen(itemTypeMap, item.getItemTypeId(), - itemType -> vo.setItemOrProduct(itemType.getItemOrProduct())); - MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), - unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); - }); - }); - } - - // ==================== 物料需求逐层展开 ==================== - - /** - * 逐层 IN 查询展开工单 BOM 到叶子物料,合并同物料的需求数量 - * - * @param bomList 工单 BOM 列表 - * @return 叶子物料 Map:itemId → 合并后的需求数量 - */ - private Map buildWorkOrderItems(List bomList) { - // 1. 初始化:收集第一层物料 ID 和对应数量 - Map currentLayer = new LinkedHashMap<>(); - for (MesProWorkOrderBomDO bom : bomList) { - currentLayer.merge(bom.getItemId(), bom.getQuantity(), BigDecimal::add); - } - - // 2. 逐层 IN 查询展开 BOM - Map leafItems = new LinkedHashMap<>(); - for (int i = 0; i < Byte.MAX_VALUE && CollUtil.isNotEmpty(currentLayer); i++) { - // 2.1 批量查询当前层所有物料的子 BOM - List subBomList = productBomService.getProductBomListByItemIds(currentLayer.keySet()); - // 2.2 按 itemId 分组 - Map> subBomMap = convertMultiMap(subBomList, MesMdProductBomDO::getItemId); - // 2.3 区分叶子节点和非叶子节点 - Map nextLayer = new LinkedHashMap<>(); - for (Map.Entry entry : currentLayer.entrySet()) { - Long itemId = entry.getKey(); - BigDecimal quantity = entry.getValue(); - List children = subBomMap.get(itemId); - // 情况一:叶子节点,累加到结果 - if (CollUtil.isEmpty(children)) { - leafItems.merge(itemId, quantity, BigDecimal::add); - continue; - } - // 情况二:非叶子,子物料进入下一层 - for (MesMdProductBomDO child : children) { - nextLayer.merge(child.getBomItemId(), quantity.multiply(child.getQuantity()), BigDecimal::add); - } - } - currentLayer = nextLayer; - } - return leafItems; - } - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderController.java deleted file mode 100644 index 7d7b678..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkorderController.java +++ /dev/null @@ -1,180 +0,0 @@ -package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderRespVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; -import cn.iocoder.yudao.module.mes.service.md.client.MesMdClientService; -import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; -import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; -import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService; -import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.io.IOException; -import java.util.*; - -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; - -@Tag(name = "管理后台 - MES 生产工单") -@RestController -@RequestMapping("/mes/pro/work-order") -@Validated -public class MesProWorkOrderController { - - @Resource - private MesProWorkOrderService workOrderService; - - @Resource - private MesMdItemService itemService; - - @Resource - private MesMdClientService clientService; - - @Resource - private MesMdVendorService vendorService; - - @Resource - private MesMdUnitMeasureService unitMeasureService; - - @PostMapping("/create") - @Operation(summary = "创建生产工单") - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:create')") - public CommonResult createWorkOrder(@Valid @RequestBody MesProWorkOrderSaveReqVO createReqVO) { - return success(workOrderService.createWorkOrder(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新生产工单") - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") - public CommonResult updateWorkOrder(@Valid @RequestBody MesProWorkOrderSaveReqVO updateReqVO) { - workOrderService.updateWorkOrder(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除生产工单") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:delete')") - public CommonResult deleteWorkOrder(@RequestParam("id") Long id) { - workOrderService.deleteWorkOrder(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得生产工单") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") - public CommonResult getWorkOrder(@RequestParam("id") Long id) { - MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(id); - if (workOrder == null) { - return success(null); - } - return success(buildWorkOrderRespVOList(List.of(workOrder)).get(0)); - } - - @GetMapping("/page") - @Operation(summary = "获得生产工单分页") - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") - public CommonResult> getWorkOrderPage(@Valid MesProWorkOrderPageReqVO pageReqVO) { - PageResult pageResult = workOrderService.getWorkOrderPage(pageReqVO); - return success(new PageResult<>(buildWorkOrderRespVOList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出生产工单 Excel") - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportWorkOrderExcel(@Valid MesProWorkOrderPageReqVO pageReqVO, - HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = workOrderService.getWorkOrderPage(pageReqVO).getList(); - List voList = buildWorkOrderRespVOList(list); - ExcelUtils.write(response, "生产工单.xls", "数据", MesProWorkOrderRespVO.class, voList); - } - - @PutMapping("/confirm") - @Operation(summary = "确认工单") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") - public CommonResult confirmWorkOrder(@RequestParam("id") Long id) { - workOrderService.confirmWorkOrder(id); - return success(true); - } - - @PutMapping("/finish") - @Operation(summary = "完成工单") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") - public CommonResult finishWorkOrder(@RequestParam("id") Long id) { - workOrderService.finishWorkOrder(id); - return success(true); - } - - @PutMapping("/cancel") - @Operation(summary = "取消工单") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')") - public CommonResult cancelWorkOrder(@RequestParam("id") Long id) { - workOrderService.cancelWorkOrder(id); - return success(true); - } - - // ==================== 拼接 VO ==================== - - private List buildWorkOrderRespVOList(List list) { - if (CollUtil.isEmpty(list)) { - return Collections.emptyList(); - } - // 1. 批量获取关联数据 - Map itemMap = itemService.getItemMap( - convertSet(list, MesProWorkOrderDO::getProductId)); - Map clientMap = clientService.getClientMap( - convertSet(list, MesProWorkOrderDO::getClientId)); - Map vendorMap = vendorService.getVendorMap( - convertSet(list, MesProWorkOrderDO::getVendorId)); - // 单位从产品关联的 item 获得 - Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( - convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); - Map parentMap = workOrderService.getWorkOrderMap( - convertSet(list, MesProWorkOrderDO::getParentId)); - // 2. 拼接 VO(单位名称从产品关联的 item 获得) - return BeanUtils.toBean(list, MesProWorkOrderRespVO.class, vo -> { - MapUtils.findAndThen(itemMap, vo.getProductId(), item -> { - vo.setProductName(item.getName()).setProductCode(item.getCode()) - .setProductSpec(item.getSpecification()); - MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), - unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); - }); - MapUtils.findAndThen(clientMap, vo.getClientId(), - client -> vo.setClientName(client.getName()).setClientCode(client.getCode())); - MapUtils.findAndThen(vendorMap, vo.getVendorId(), - vendor -> vo.setVendorName(vendor.getName()).setVendorCode(vendor.getCode())); - MapUtils.findAndThen(parentMap, vo.getParentId(), - parent -> vo.setParentCode(parent.getCode())); - }); - } - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomPageReqVO.java new file mode 100644 index 0000000..40fa649 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomPageReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - MES 生产工单 BOM 分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesProWorkOrderBomPageReqVO extends PageParam { + + @Schema(description = "生产工单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "生产工单编号不能为空") + private Long workOrderId; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomRespVO.java new file mode 100644 index 0000000..ca4e31e --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomRespVO.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 生产工单 BOM Response VO") +@Data +@ExcelIgnoreUnannotated +public class MesProWorkOrderBomRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "生产工单编号", example = "100") + private Long workOrderId; + + @Schema(description = "BOM 物料编号", example = "200") + private Long itemId; + + @Schema(description = "物料名称", example = "电阻 R1") + @ExcelProperty("物料名称") + private String itemName; + + @Schema(description = "物料编码", example = "M-001") + @ExcelProperty("物料编码") + private String itemCode; + + @Schema(description = "规格型号", example = "10K 0603") + @ExcelProperty("规格型号") + private String itemSpec; + + @Schema(description = "单位编号", example = "300") + private Long unitMeasureId; + + @Schema(description = "单位名称", example = "个") + @ExcelProperty("单位") + private String unitMeasureName; + + @Schema(description = "预计使用量", example = "10.00") + @ExcelProperty("预计使用量") + private BigDecimal quantity; + + @Schema(description = "备注", example = "备注") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "物料产品标识", example = "PRODUCT") + private String itemOrProduct; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomSaveReqVO.java new file mode 100644 index 0000000..4194be2 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkOrderBomSaveReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - MES 生产工单 BOM 新增/修改 Request VO") +@Data +public class MesProWorkOrderBomSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "生产工单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "生产工单编号不能为空") + private Long workOrderId; + + @Schema(description = "BOM 物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") + @NotNull(message = "BOM 物料不能为空") + private Long itemId; + + @Schema(description = "预计使用量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10.00") + @NotNull(message = "预计使用量不能为空") + private BigDecimal quantity; + + @Schema(description = "备注", example = "备注") + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomPageReqVO.java deleted file mode 100644 index 40fa649..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomPageReqVO.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - MES 生产工单 BOM 分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class MesProWorkOrderBomPageReqVO extends PageParam { - - @Schema(description = "生产工单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - @NotNull(message = "生产工单编号不能为空") - private Long workOrderId; - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomRespVO.java deleted file mode 100644 index ca4e31e..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomRespVO.java +++ /dev/null @@ -1,60 +0,0 @@ -package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom; - -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; -import cn.idev.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - MES 生产工单 BOM Response VO") -@Data -@ExcelIgnoreUnannotated -public class MesProWorkOrderBomRespVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @ExcelProperty("编号") - private Long id; - - @Schema(description = "生产工单编号", example = "100") - private Long workOrderId; - - @Schema(description = "BOM 物料编号", example = "200") - private Long itemId; - - @Schema(description = "物料名称", example = "电阻 R1") - @ExcelProperty("物料名称") - private String itemName; - - @Schema(description = "物料编码", example = "M-001") - @ExcelProperty("物料编码") - private String itemCode; - - @Schema(description = "规格型号", example = "10K 0603") - @ExcelProperty("规格型号") - private String itemSpec; - - @Schema(description = "单位编号", example = "300") - private Long unitMeasureId; - - @Schema(description = "单位名称", example = "个") - @ExcelProperty("单位") - private String unitMeasureName; - - @Schema(description = "预计使用量", example = "10.00") - @ExcelProperty("预计使用量") - private BigDecimal quantity; - - @Schema(description = "备注", example = "备注") - @ExcelProperty("备注") - private String remark; - - @Schema(description = "物料产品标识", example = "PRODUCT") - private String itemOrProduct; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomSaveReqVO.java deleted file mode 100644 index 4194be2..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/bom/MesProWorkorderBomSaveReqVO.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -import java.math.BigDecimal; - -@Schema(description = "管理后台 - MES 生产工单 BOM 新增/修改 Request VO") -@Data -public class MesProWorkOrderBomSaveReqVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long id; - - @Schema(description = "生产工单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - @NotNull(message = "生产工单编号不能为空") - private Long workOrderId; - - @Schema(description = "BOM 物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") - @NotNull(message = "BOM 物料不能为空") - private Long itemId; - - @Schema(description = "预计使用量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10.00") - @NotNull(message = "预计使用量不能为空") - private BigDecimal quantity; - - @Schema(description = "备注", example = "备注") - private String remark; - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderBomDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderBomDO.java new file mode 100644 index 0000000..db63e65 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderBomDO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * MES 生产工单 BOM DO + * + * @author 芋道源码 + */ +@TableName("mes_pro_work_order_bom") +@KeySequence("mes_pro_work_order_bom_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesProWorkOrderBomDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 生产工单编号 + * + * 关联 {@link MesProWorkOrderDO#getId()} + */ + private Long workOrderId; + /** + * BOM 物料编号 + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long itemId; + /** + * 预计使用量 + */ + private BigDecimal quantity; + /** + * 备注 + */ + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java new file mode 100644 index 0000000..6ff101a --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java @@ -0,0 +1,134 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; +import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderSourceTypeEnum; +import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum; +import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * MES 生产工单 DO + * + * @author 芋道源码 + */ +@TableName("mes_pro_work_order") +@KeySequence("mes_pro_work_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesProWorkOrderDO extends BaseDO { + + /** + * 父工单编号,空值 + */ + public static final Long PARENT_ID_NULL = 0L; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 工单编码 + */ + private String code; + /** + * 工单名称 + */ + private String name; + /** + * 工单类型 + * + * 枚举 {@link MesProWorkOrderTypeEnum} + */ + private Integer type; + /** + * 来源类型 + * + * 枚举 {@link MesProWorkOrderSourceTypeEnum} + */ + private Integer orderSourceType; + /** + * 来源单据编号 + */ + private String orderSourceCode; + /** + * 产品编号 + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long productId; + /** + * 生产数量 + */ + private BigDecimal quantity; + /** + * 已生产数量 + */ + private BigDecimal quantityProduced; + /** + * 调整数量 + */ + private BigDecimal quantityChanged; + /** + * 已排产数量 + */ + private BigDecimal quantityScheduled; + /** + * 客户编号 + * + * 关联 {@link MesMdClientDO#getId()} + */ + private Long clientId; + /** + * 供应商编号 + * + * 关联 {@link MesMdVendorDO#getId()} + */ + private Long vendorId; + /** + * 批次号 + */ + private String batchCode; + /** + * 需求日期 + */ + private LocalDateTime requestDate; + /** + * 父工单编号 + * + * 关联 {@link MesProWorkOrderDO#getId()} + */ + private Long parentId; + /** + * 完成时间 + */ + private LocalDateTime finishDate; + /** + * 取消时间 + */ + private LocalDateTime cancelDate; + /** + * 工单状态 + * + * 枚举 {@link MesProWorkOrderStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderBomDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderBomDO.java deleted file mode 100644 index db63e65..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderBomDO.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.math.BigDecimal; - -/** - * MES 生产工单 BOM DO - * - * @author 芋道源码 - */ -@TableName("mes_pro_work_order_bom") -@KeySequence("mes_pro_work_order_bom_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class MesProWorkOrderBomDO extends BaseDO { - - /** - * 编号 - */ - @TableId - private Long id; - /** - * 生产工单编号 - * - * 关联 {@link MesProWorkOrderDO#getId()} - */ - private Long workOrderId; - /** - * BOM 物料编号 - * - * 关联 {@link MesMdItemDO#getId()} - */ - private Long itemId; - /** - * 预计使用量 - */ - private BigDecimal quantity; - /** - * 备注 - */ - private String remark; - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderDO.java deleted file mode 100644 index 6ff101a..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkorderDO.java +++ /dev/null @@ -1,134 +0,0 @@ -package cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; -import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderSourceTypeEnum; -import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum; -import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderTypeEnum; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * MES 生产工单 DO - * - * @author 芋道源码 - */ -@TableName("mes_pro_work_order") -@KeySequence("mes_pro_work_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class MesProWorkOrderDO extends BaseDO { - - /** - * 父工单编号,空值 - */ - public static final Long PARENT_ID_NULL = 0L; - - /** - * 编号 - */ - @TableId - private Long id; - /** - * 工单编码 - */ - private String code; - /** - * 工单名称 - */ - private String name; - /** - * 工单类型 - * - * 枚举 {@link MesProWorkOrderTypeEnum} - */ - private Integer type; - /** - * 来源类型 - * - * 枚举 {@link MesProWorkOrderSourceTypeEnum} - */ - private Integer orderSourceType; - /** - * 来源单据编号 - */ - private String orderSourceCode; - /** - * 产品编号 - * - * 关联 {@link MesMdItemDO#getId()} - */ - private Long productId; - /** - * 生产数量 - */ - private BigDecimal quantity; - /** - * 已生产数量 - */ - private BigDecimal quantityProduced; - /** - * 调整数量 - */ - private BigDecimal quantityChanged; - /** - * 已排产数量 - */ - private BigDecimal quantityScheduled; - /** - * 客户编号 - * - * 关联 {@link MesMdClientDO#getId()} - */ - private Long clientId; - /** - * 供应商编号 - * - * 关联 {@link MesMdVendorDO#getId()} - */ - private Long vendorId; - /** - * 批次号 - */ - private String batchCode; - /** - * 需求日期 - */ - private LocalDateTime requestDate; - /** - * 父工单编号 - * - * 关联 {@link MesProWorkOrderDO#getId()} - */ - private Long parentId; - /** - * 完成时间 - */ - private LocalDateTime finishDate; - /** - * 取消时间 - */ - private LocalDateTime cancelDate; - /** - * 工单状态 - * - * 枚举 {@link MesProWorkOrderStatusEnum} - */ - private Integer status; - /** - * 备注 - */ - private String remark; - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderBomMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderBomMapper.java new file mode 100644 index 0000000..28f6f60 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderBomMapper.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * MES 生产工单 BOM Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesProWorkOrderBomMapper extends BaseMapperX { + + default PageResult selectPage(MesProWorkOrderBomPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(MesProWorkOrderBomDO::getWorkOrderId, reqVO.getWorkOrderId()) + .orderByDesc(MesProWorkOrderBomDO::getId)); + } + + default List selectListByWorkOrderId(Long workOrderId) { + return selectList(MesProWorkOrderBomDO::getWorkOrderId, workOrderId); + } + + default void deleteByWorkOrderId(Long workOrderId) { + delete(MesProWorkOrderBomDO::getWorkOrderId, workOrderId); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderMapper.java new file mode 100644 index 0000000..b6f9b09 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkOrderMapper.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; + +/** + * MES 生产工单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesProWorkOrderMapper extends BaseMapperX { + + default PageResult selectPage(MesProWorkOrderPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(MesProWorkOrderDO::getCode, reqVO.getCode()) + .likeIfPresent(MesProWorkOrderDO::getName, reqVO.getName()) + .eqIfPresent(MesProWorkOrderDO::getType, reqVO.getType()) + .likeIfPresent(MesProWorkOrderDO::getOrderSourceCode, reqVO.getOrderSourceCode()) + .eqIfPresent(MesProWorkOrderDO::getProductId, reqVO.getProductId()) + .eqIfPresent(MesProWorkOrderDO::getClientId, reqVO.getClientId()) + .betweenIfPresent(MesProWorkOrderDO::getRequestDate, reqVO.getRequestDate()) + .orderByDesc(MesProWorkOrderDO::getId)); + } + + default MesProWorkOrderDO selectByCode(String code) { + return selectOne(MesProWorkOrderDO::getCode, code); + } + + default void updateProducedQuantity(Long id, BigDecimal incrQuantityProduced) { + update(null, new LambdaUpdateWrapper() + .eq(MesProWorkOrderDO::getId, id) + .setSql("quantity_produced = IFNULL(quantity_produced, 0) + " + incrQuantityProduced)); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderBomMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderBomMapper.java deleted file mode 100644 index 28f6f60..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderBomMapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * MES 生产工单 BOM Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface MesProWorkOrderBomMapper extends BaseMapperX { - - default PageResult selectPage(MesProWorkOrderBomPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(MesProWorkOrderBomDO::getWorkOrderId, reqVO.getWorkOrderId()) - .orderByDesc(MesProWorkOrderBomDO::getId)); - } - - default List selectListByWorkOrderId(Long workOrderId) { - return selectList(MesProWorkOrderBomDO::getWorkOrderId, workOrderId); - } - - default void deleteByWorkOrderId(Long workOrderId) { - delete(MesProWorkOrderBomDO::getWorkOrderId, workOrderId); - } - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java deleted file mode 100644 index b6f9b09..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO; -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import org.apache.ibatis.annotations.Mapper; - -import java.math.BigDecimal; - -/** - * MES 生产工单 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface MesProWorkOrderMapper extends BaseMapperX { - - default PageResult selectPage(MesProWorkOrderPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(MesProWorkOrderDO::getCode, reqVO.getCode()) - .likeIfPresent(MesProWorkOrderDO::getName, reqVO.getName()) - .eqIfPresent(MesProWorkOrderDO::getType, reqVO.getType()) - .likeIfPresent(MesProWorkOrderDO::getOrderSourceCode, reqVO.getOrderSourceCode()) - .eqIfPresent(MesProWorkOrderDO::getProductId, reqVO.getProductId()) - .eqIfPresent(MesProWorkOrderDO::getClientId, reqVO.getClientId()) - .betweenIfPresent(MesProWorkOrderDO::getRequestDate, reqVO.getRequestDate()) - .orderByDesc(MesProWorkOrderDO::getId)); - } - - default MesProWorkOrderDO selectByCode(String code) { - return selectOne(MesProWorkOrderDO::getCode, code); - } - - default void updateProducedQuantity(Long id, BigDecimal incrQuantityProduced) { - update(null, new LambdaUpdateWrapper() - .eq(MesProWorkOrderDO::getId, id) - .setSql("quantity_produced = IFNULL(quantity_produced, 0) + " + incrQuantityProduced)); - } - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java new file mode 100644 index 0000000..1bd2ffa --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.mes.enums.pro; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * MES 生产工单状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum MesProWorkOrderStatusEnum implements ArrayValuable { + + PREPARE(0, "草稿"), + CONFIRMED(1, "已确认"), + FINISHED(2, "已完成"), + CANCELED(3, "已取消"); + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProWorkOrderStatusEnum::getStatus).toArray(Integer[]::new); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderTypeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderTypeEnum.java new file mode 100644 index 0000000..3c7b150 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderTypeEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.mes.enums.pro; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * MES 工单类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum MesProWorkOrderTypeEnum implements ArrayValuable { + + SELF(1, "自行生产"), + OUTSOURCE(2, "代工"), + PURCHASE(3, "采购"); + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProWorkOrderTypeEnum::getType).toArray(Integer[]::new); + + /** + * 类型值 + */ + private final Integer type; + /** + * 类型名 + */ + private final String name; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderStatusEnum.java deleted file mode 100644 index 1bd2ffa..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderStatusEnum.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.mes.enums.pro; - -import cn.iocoder.yudao.framework.common.core.ArrayValuable; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Arrays; - -/** - * MES 生产工单状态枚举 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum MesProWorkOrderStatusEnum implements ArrayValuable { - - PREPARE(0, "草稿"), - CONFIRMED(1, "已确认"), - FINISHED(2, "已完成"), - CANCELED(3, "已取消"); - - public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProWorkOrderStatusEnum::getStatus).toArray(Integer[]::new); - - /** - * 状态值 - */ - private final Integer status; - /** - * 状态名 - */ - private final String name; - - @Override - public Integer[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderTypeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderTypeEnum.java deleted file mode 100644 index 3c7b150..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderTypeEnum.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.yudao.module.mes.enums.pro; - -import cn.iocoder.yudao.framework.common.core.ArrayValuable; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Arrays; - -/** - * MES 工单类型枚举 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum MesProWorkOrderTypeEnum implements ArrayValuable { - - SELF(1, "自行生产"), - OUTSOURCE(2, "代工"), - PURCHASE(3, "采购"); - - public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProWorkOrderTypeEnum::getType).toArray(Integer[]::new); - - /** - * 类型值 - */ - private final Integer type; - /** - * 类型名 - */ - private final String name; - - @Override - public Integer[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomService.java new file mode 100644 index 0000000..b6ec56a --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomService.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.mes.service.pro.workorder; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * MES 生产工单 BOM Service 接口 + * + * @author 芋道源码 + */ +public interface MesProWorkOrderBomService { + + /** + * 创建工单 BOM + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createWorkOrderBom(@Valid MesProWorkOrderBomSaveReqVO createReqVO); + + /** + * 更新工单 BOM + * + * @param updateReqVO 更新信息 + */ + void updateWorkOrderBom(@Valid MesProWorkOrderBomSaveReqVO updateReqVO); + + /** + * 删除工单 BOM + * + * @param id 编号 + */ + void deleteWorkOrderBom(Long id); + + /** + * 获得工单 BOM + * + * @param id 编号 + * @return 工单 BOM + */ + MesProWorkOrderBomDO getWorkOrderBom(Long id); + + /** + * 获得工单 BOM 分页 + * + * @param pageReqVO 分页查询 + * @return 工单 BOM 分页 + */ + PageResult getWorkOrderBomPage(MesProWorkOrderBomPageReqVO pageReqVO); + + /** + * 根据工单编号获得 BOM 列表 + * + * @param workOrderId 工单编号 + * @return BOM 列表 + */ + List getWorkOrderBomListByWorkOrderId(Long workOrderId); + + /** + * 根据工单编号删除 BOM + * + * @param workOrderId 工单编号 + */ + void deleteWorkOrderBomByWorkOrderId(Long workOrderId); + + /** + * 根据产品 BOM 自动生成工单 BOM 行 + *

+ * 如果 updated 为 true,会先清理旧的 BOM 数据再重新生成 + * + * @param workOrderId 工单编号 + * @param reqVO 工单创建/更新请求(取 productId、quantity) + * @param updated 是否为更新场景(true 时先删除旧 BOM) + */ + void generateWorkOrderBom(Long workOrderId, MesProWorkOrderSaveReqVO reqVO, boolean updated); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomServiceImpl.java new file mode 100644 index 0000000..f995cd0 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomServiceImpl.java @@ -0,0 +1,136 @@ +package cn.iocoder.yudao.module.mes.service.pro.workorder; + +import cn.hutool.core.collection.CollUtil; +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.pro.workorder.vo.MesProWorkOrderSaveReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; +import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderBomMapper; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_NOT_EXISTS; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_WORK_ORDER_BOM_NOT_EXISTS; + +/** + * MES 生产工单 BOM Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService { + + @Resource + private MesProWorkOrderBomMapper workOrderBomMapper; + + @Resource + @Lazy // 延迟加载,避免循环依赖 + private MesProWorkOrderService workOrderService; + @Resource + private MesMdItemService itemService; + @Resource + private MesMdProductBomService productBomService; + + @Override + public Long createWorkOrderBom(MesProWorkOrderBomSaveReqVO createReqVO) { + // 校验工单存在 + workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId()); + + // 插入数据 + MesProWorkOrderBomDO workOrderBom = BeanUtils.toBean(createReqVO, MesProWorkOrderBomDO.class); + workOrderBomMapper.insert(workOrderBom); + return workOrderBom.getId(); + } + + @Override + public void updateWorkOrderBom(MesProWorkOrderBomSaveReqVO updateReqVO) { + // 校验存在 + validateWorkOrderBomExists(updateReqVO.getId()); + + // 更新数据 + MesProWorkOrderBomDO updateObj = BeanUtils.toBean(updateReqVO, MesProWorkOrderBomDO.class); + workOrderBomMapper.updateById(updateObj); + } + + @Override + public void deleteWorkOrderBom(Long id) { + // 校验存在 + validateWorkOrderBomExists(id); + + // 删除 + workOrderBomMapper.deleteById(id); + } + + private void validateWorkOrderBomExists(Long id) { + if (workOrderBomMapper.selectById(id) == null) { + throw exception(PRO_WORK_ORDER_BOM_NOT_EXISTS); + } + } + + @Override + public MesProWorkOrderBomDO getWorkOrderBom(Long id) { + return workOrderBomMapper.selectById(id); + } + + @Override + public PageResult getWorkOrderBomPage(MesProWorkOrderBomPageReqVO pageReqVO) { + return workOrderBomMapper.selectPage(pageReqVO); + } + + @Override + public List getWorkOrderBomListByWorkOrderId(Long workOrderId) { + return workOrderBomMapper.selectListByWorkOrderId(workOrderId); + } + + @Override + public void deleteWorkOrderBomByWorkOrderId(Long workOrderId) { + workOrderBomMapper.deleteByWorkOrderId(workOrderId); + } + + @Override + public void generateWorkOrderBom(Long workOrderId, MesProWorkOrderSaveReqVO reqVO, boolean updated) { + // 1. 如果是更新场景,先清理旧的 BOM 数据 + if (updated) { + workOrderBomMapper.deleteByWorkOrderId(workOrderId); + } + + // 2.1 查询产品 BOM + List productBomList = productBomService.getProductBomListByItemId(reqVO.getProductId()); + if (CollUtil.isEmpty(productBomList)) { + return; + } + // 2.2 批量获取并校验 BOM 物料 + Set bomItemIds = convertSet(productBomList, MesMdProductBomDO::getBomItemId); + Map itemMap = itemService.getItemMap(bomItemIds); + bomItemIds.forEach(itemId -> { + if (itemMap.get(itemId) == null) { + throw exception(MD_ITEM_NOT_EXISTS); + } + }); + + // 3. 构建工单 BOM 列表并批量插入 + List bomList = new ArrayList<>(productBomList.size()); + for (MesMdProductBomDO productBom : productBomList) { + bomList.add(new MesProWorkOrderBomDO().setWorkOrderId(workOrderId).setItemId(productBom.getBomItemId()) + .setQuantity(reqVO.getQuantity().multiply(productBom.getQuantity()))); + } + workOrderBomMapper.insertBatch(bomList); + } + +} \ No newline at end of file diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java new file mode 100644 index 0000000..9aa713e --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java @@ -0,0 +1,132 @@ +package cn.iocoder.yudao.module.mes.service.pro.workorder; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; +import jakarta.validation.Valid; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * MES 生产工单 Service 接口 + * + * @author 芋道源码 + */ +public interface MesProWorkOrderService { + + /** + * 创建生产工单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createWorkOrder(@Valid MesProWorkOrderSaveReqVO createReqVO); + + /** + * 更新生产工单 + * + * @param updateReqVO 更新信息 + */ + void updateWorkOrder(@Valid MesProWorkOrderSaveReqVO updateReqVO); + + /** + * 删除生产工单 + * + * @param id 编号 + */ + void deleteWorkOrder(Long id); + + /** + * 校验生产工单存在 + * + * @param id 编号 + * @return 生产工单 + */ + MesProWorkOrderDO validateWorkOrderExists(Long id); + + /** + * 获得生产工单 + * + * @param id 编号 + * @return 生产工单 + */ + MesProWorkOrderDO getWorkOrder(Long id); + + /** + * 根据编码获得生产工单 + * + * @param code 编码 + * @return 生产工单 + */ + MesProWorkOrderDO getWorkOrder(String code); + + /** + * 获得生产工单分页 + * + * @param pageReqVO 分页查询 + * @return 生产工单分页 + */ + PageResult getWorkOrderPage(MesProWorkOrderPageReqVO pageReqVO); + + /** + * 获得工单列表 + * + * @param ids 编号数组 + * @return 工单列表 + */ + List getWorkOrderList(Collection ids); + + /** + * 获得工单 Map + * + * @param ids 编号数组 + * @return 工单 Map + */ + default Map getWorkOrderMap(Collection ids) { + return convertMap(getWorkOrderList(ids), MesProWorkOrderDO::getId); + } + + /** + * 校验工单已确认 + * + * @param id 编号 + * @return 工单 + */ + MesProWorkOrderDO validateWorkOrderConfirmed(Long id); + + /** + * 确认工单(草稿 → 已确认) + * + * @param id 编号 + */ + void confirmWorkOrder(Long id); + + /** + * 完成工单 + * + * @param id 编号 + */ + void finishWorkOrder(Long id); + + /** + * 取消工单 + * + * @param id 编号 + */ + void cancelWorkOrder(Long id); + + /** + * 累加工单的已生产数量 + * + * @param id 工单编号 + * @param incrQuantityProduced 本次已生产数量增量 + */ + void updateProducedQuantity(Long id, BigDecimal incrQuantityProduced); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java new file mode 100644 index 0000000..431b084 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java @@ -0,0 +1,248 @@ +package cn.iocoder.yudao.module.mes.service.pro.workorder; + +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.pro.workorder.vo.MesProWorkOrderPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemBatchConfigDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; +import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderMapper; +import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum; +import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService; +import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +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.*; + +/** + * MES 生产工单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { + + @Resource + private MesProWorkOrderMapper workOrderMapper; + + @Resource + private MesProWorkOrderBomService workOrderBomService; + @Resource + private MesMdItemService itemService; + @Resource + private MesMdItemBatchConfigService itemBatchConfigService; + @Resource + private MesWmBarcodeService barcodeService; + @Resource + private MesProTaskService taskService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createWorkOrder(MesProWorkOrderSaveReqVO createReqVO) { + // 1. 校验数据 + validateWorkOrderSaveData(null, createReqVO); + + // 2.1 设置默认值 + if (createReqVO.getParentId() == null) { + createReqVO.setParentId(MesProWorkOrderDO.PARENT_ID_NULL); + } + // 2.2 插入工单 + MesProWorkOrderDO workOrder = BeanUtils.toBean(createReqVO, MesProWorkOrderDO.class); + workOrder.setStatus(MesProWorkOrderStatusEnum.PREPARE.getStatus()); + workOrderMapper.insert(workOrder); + + // 3. 自动生成 BOM:根据产品 BOM 生成工单 BOM + workOrderBomService.generateWorkOrderBom(workOrder.getId(), createReqVO, false); + + // 4. 自动生成条码 + barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.WORKORDER.getValue(), + workOrder.getId(), workOrder.getCode(), workOrder.getName()); + return workOrder.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateWorkOrder(MesProWorkOrderSaveReqVO updateReqVO) { + // 1.1 校验存在 + 只有草稿状态才能编辑 + MesProWorkOrderDO oldWorkOrder = validateWorkOrderExists(updateReqVO.getId()); + if (ObjUtil.notEqual(oldWorkOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) { + throw exception(PRO_WORK_ORDER_NOT_PREPARE); + } + // 1.2 校验数据 + validateWorkOrderSaveData(updateReqVO.getId(), updateReqVO); + + // 2. 判断产品或数量是否变更,如果变更则重新生成 BOM(updated=true 会先清理旧数据) + boolean productChanged = ObjUtil.notEqual(oldWorkOrder.getProductId(), updateReqVO.getProductId()); + boolean quantityChanged = oldWorkOrder.getQuantity().compareTo(updateReqVO.getQuantity()) != 0; + if (productChanged || quantityChanged) { + workOrderBomService.generateWorkOrderBom(updateReqVO.getId(), updateReqVO, true); + } + + // 3. 更新 + MesProWorkOrderDO updateObj = BeanUtils.toBean(updateReqVO, MesProWorkOrderDO.class); + workOrderMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteWorkOrder(Long id) { + // 1.1 校验存在 + MesProWorkOrderDO workOrder = validateWorkOrderExists(id); + // 1.2 只能删除草稿状态的工单 + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) { + throw exception(PRO_WORK_ORDER_NOT_PREPARE); + } + // 1.3 校验是否有子工单 + Long childCount = workOrderMapper.selectCount(MesProWorkOrderDO::getParentId, id); + if (childCount > 0) { + throw exception(PRO_WORK_ORDER_HAS_CHILDREN); + } + + // 2. 删除工单 + BOM + workOrderMapper.deleteById(id); + workOrderBomService.deleteWorkOrderBomByWorkOrderId(id); + } + + @Override + public MesProWorkOrderDO validateWorkOrderExists(Long id) { + MesProWorkOrderDO workOrder = workOrderMapper.selectById(id); + if (workOrder == null) { + throw exception(PRO_WORK_ORDER_NOT_EXISTS); + } + return workOrder; + } + + @Override + public MesProWorkOrderDO getWorkOrder(Long id) { + return workOrderMapper.selectById(id); + } + + @Override + public MesProWorkOrderDO getWorkOrder(String code) { + return workOrderMapper.selectByCode(code); + } + + @Override + public PageResult getWorkOrderPage(MesProWorkOrderPageReqVO pageReqVO) { + return workOrderMapper.selectPage(pageReqVO); + } + + @Override + public List getWorkOrderList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return workOrderMapper.selectByIds(ids); + } + + @Override + public MesProWorkOrderDO validateWorkOrderConfirmed(Long id) { + MesProWorkOrderDO workOrder = validateWorkOrderExists(id); + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { + throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); + } + return workOrder; + } + + @Override + public void confirmWorkOrder(Long id) { + // 1.1 校验存在 + MesProWorkOrderDO workOrder = validateWorkOrderExists(id); + // 1.2 只有草稿状态才能确认 + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) { + throw exception(PRO_WORK_ORDER_NOT_PREPARE); + } + + // 2. 更新状态为已确认 + workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) + .setStatus(MesProWorkOrderStatusEnum.CONFIRMED.getStatus())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void finishWorkOrder(Long id) { + // 1. 校验存在 + 只有已确认状态才能完成 + MesProWorkOrderDO workOrder = validateWorkOrderExists(id); + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { + throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); + } + + // 2. 级联完成所有关联任务 + taskService.finishTaskByOrderId(id); + + // 3. 更新工单状态为已完成 + workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) + .setStatus(MesProWorkOrderStatusEnum.FINISHED.getStatus()) + .setFinishDate(LocalDateTime.now())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelWorkOrder(Long id) { + // 1. 校验存在 + 只有已确认状态才能取消 + MesProWorkOrderDO workOrder = validateWorkOrderExists(id); + if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { + throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); + } + + // 2. 级联取消所有关联任务 + taskService.cancelTaskByOrderId(id); + + // 3. 更新工单状态为已取消 + workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) + .setStatus(MesProWorkOrderStatusEnum.CANCELED.getStatus()) + .setCancelDate(LocalDateTime.now())); + } + + // ==================== 校验方法 ==================== + + private void validateWorkOrderSaveData(Long id, MesProWorkOrderSaveReqVO reqVO) { + // 1. 校验编码唯一 + validateWorkOrderCodeUnique(id, reqVO.getCode()); + // 2. 校验产品存在 + itemService.validateItemExists(reqVO.getProductId()); + // 3. 校验批次配置(如果产品有 clientFlag=true,则 clientId 必填) + MesMdItemBatchConfigDO batchConfig = itemBatchConfigService.getItemBatchConfigByItemId(reqVO.getProductId()); + if (batchConfig != null && Boolean.TRUE.equals(batchConfig.getClientFlag()) && reqVO.getClientId() == null) { + throw exception(MD_CLIENT_NOT_EXISTS); + } + } + + private void validateWorkOrderCodeUnique(Long id, String code) { + if (code == null) { + return; + } + MesProWorkOrderDO workOrder = workOrderMapper.selectByCode(code); + if (workOrder == null) { + return; + } + if (ObjUtil.notEqual(workOrder.getId(), id)) { + throw exception(PRO_WORK_ORDER_CODE_DUPLICATE); + } + } + + @Override + public void updateProducedQuantity(Long id, BigDecimal incrQuantityProduced) { + // 校验工单存在 + validateWorkOrderExists(id); + // 更新数量 + workOrderMapper.updateProducedQuantity(id, incrQuantityProduced); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomService.java deleted file mode 100644 index b6ec56a..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomService.java +++ /dev/null @@ -1,83 +0,0 @@ -package cn.iocoder.yudao.module.mes.service.pro.workorder; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; -import jakarta.validation.Valid; - -import java.util.List; - -/** - * MES 生产工单 BOM Service 接口 - * - * @author 芋道源码 - */ -public interface MesProWorkOrderBomService { - - /** - * 创建工单 BOM - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createWorkOrderBom(@Valid MesProWorkOrderBomSaveReqVO createReqVO); - - /** - * 更新工单 BOM - * - * @param updateReqVO 更新信息 - */ - void updateWorkOrderBom(@Valid MesProWorkOrderBomSaveReqVO updateReqVO); - - /** - * 删除工单 BOM - * - * @param id 编号 - */ - void deleteWorkOrderBom(Long id); - - /** - * 获得工单 BOM - * - * @param id 编号 - * @return 工单 BOM - */ - MesProWorkOrderBomDO getWorkOrderBom(Long id); - - /** - * 获得工单 BOM 分页 - * - * @param pageReqVO 分页查询 - * @return 工单 BOM 分页 - */ - PageResult getWorkOrderBomPage(MesProWorkOrderBomPageReqVO pageReqVO); - - /** - * 根据工单编号获得 BOM 列表 - * - * @param workOrderId 工单编号 - * @return BOM 列表 - */ - List getWorkOrderBomListByWorkOrderId(Long workOrderId); - - /** - * 根据工单编号删除 BOM - * - * @param workOrderId 工单编号 - */ - void deleteWorkOrderBomByWorkOrderId(Long workOrderId); - - /** - * 根据产品 BOM 自动生成工单 BOM 行 - *

- * 如果 updated 为 true,会先清理旧的 BOM 数据再重新生成 - * - * @param workOrderId 工单编号 - * @param reqVO 工单创建/更新请求(取 productId、quantity) - * @param updated 是否为更新场景(true 时先删除旧 BOM) - */ - void generateWorkOrderBom(Long workOrderId, MesProWorkOrderSaveReqVO reqVO, boolean updated); - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomServiceImpl.java deleted file mode 100644 index f995cd0..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderBomServiceImpl.java +++ /dev/null @@ -1,136 +0,0 @@ -package cn.iocoder.yudao.module.mes.service.pro.workorder; - -import cn.hutool.core.collection.CollUtil; -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.pro.workorder.vo.MesProWorkOrderSaveReqVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomPageReqVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO; -import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderBomMapper; -import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; -import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService; -import jakarta.annotation.Resource; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_NOT_EXISTS; -import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_WORK_ORDER_BOM_NOT_EXISTS; - -/** - * MES 生产工单 BOM Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class MesProWorkOrderBomServiceImpl implements MesProWorkOrderBomService { - - @Resource - private MesProWorkOrderBomMapper workOrderBomMapper; - - @Resource - @Lazy // 延迟加载,避免循环依赖 - private MesProWorkOrderService workOrderService; - @Resource - private MesMdItemService itemService; - @Resource - private MesMdProductBomService productBomService; - - @Override - public Long createWorkOrderBom(MesProWorkOrderBomSaveReqVO createReqVO) { - // 校验工单存在 - workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId()); - - // 插入数据 - MesProWorkOrderBomDO workOrderBom = BeanUtils.toBean(createReqVO, MesProWorkOrderBomDO.class); - workOrderBomMapper.insert(workOrderBom); - return workOrderBom.getId(); - } - - @Override - public void updateWorkOrderBom(MesProWorkOrderBomSaveReqVO updateReqVO) { - // 校验存在 - validateWorkOrderBomExists(updateReqVO.getId()); - - // 更新数据 - MesProWorkOrderBomDO updateObj = BeanUtils.toBean(updateReqVO, MesProWorkOrderBomDO.class); - workOrderBomMapper.updateById(updateObj); - } - - @Override - public void deleteWorkOrderBom(Long id) { - // 校验存在 - validateWorkOrderBomExists(id); - - // 删除 - workOrderBomMapper.deleteById(id); - } - - private void validateWorkOrderBomExists(Long id) { - if (workOrderBomMapper.selectById(id) == null) { - throw exception(PRO_WORK_ORDER_BOM_NOT_EXISTS); - } - } - - @Override - public MesProWorkOrderBomDO getWorkOrderBom(Long id) { - return workOrderBomMapper.selectById(id); - } - - @Override - public PageResult getWorkOrderBomPage(MesProWorkOrderBomPageReqVO pageReqVO) { - return workOrderBomMapper.selectPage(pageReqVO); - } - - @Override - public List getWorkOrderBomListByWorkOrderId(Long workOrderId) { - return workOrderBomMapper.selectListByWorkOrderId(workOrderId); - } - - @Override - public void deleteWorkOrderBomByWorkOrderId(Long workOrderId) { - workOrderBomMapper.deleteByWorkOrderId(workOrderId); - } - - @Override - public void generateWorkOrderBom(Long workOrderId, MesProWorkOrderSaveReqVO reqVO, boolean updated) { - // 1. 如果是更新场景,先清理旧的 BOM 数据 - if (updated) { - workOrderBomMapper.deleteByWorkOrderId(workOrderId); - } - - // 2.1 查询产品 BOM - List productBomList = productBomService.getProductBomListByItemId(reqVO.getProductId()); - if (CollUtil.isEmpty(productBomList)) { - return; - } - // 2.2 批量获取并校验 BOM 物料 - Set bomItemIds = convertSet(productBomList, MesMdProductBomDO::getBomItemId); - Map itemMap = itemService.getItemMap(bomItemIds); - bomItemIds.forEach(itemId -> { - if (itemMap.get(itemId) == null) { - throw exception(MD_ITEM_NOT_EXISTS); - } - }); - - // 3. 构建工单 BOM 列表并批量插入 - List bomList = new ArrayList<>(productBomList.size()); - for (MesMdProductBomDO productBom : productBomList) { - bomList.add(new MesProWorkOrderBomDO().setWorkOrderId(workOrderId).setItemId(productBom.getBomItemId()) - .setQuantity(reqVO.getQuantity().multiply(productBom.getQuantity()))); - } - workOrderBomMapper.insertBatch(bomList); - } - -} \ No newline at end of file diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java deleted file mode 100644 index 9aa713e..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java +++ /dev/null @@ -1,132 +0,0 @@ -package cn.iocoder.yudao.module.mes.service.pro.workorder; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; -import jakarta.validation.Valid; - -import java.math.BigDecimal; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * MES 生产工单 Service 接口 - * - * @author 芋道源码 - */ -public interface MesProWorkOrderService { - - /** - * 创建生产工单 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createWorkOrder(@Valid MesProWorkOrderSaveReqVO createReqVO); - - /** - * 更新生产工单 - * - * @param updateReqVO 更新信息 - */ - void updateWorkOrder(@Valid MesProWorkOrderSaveReqVO updateReqVO); - - /** - * 删除生产工单 - * - * @param id 编号 - */ - void deleteWorkOrder(Long id); - - /** - * 校验生产工单存在 - * - * @param id 编号 - * @return 生产工单 - */ - MesProWorkOrderDO validateWorkOrderExists(Long id); - - /** - * 获得生产工单 - * - * @param id 编号 - * @return 生产工单 - */ - MesProWorkOrderDO getWorkOrder(Long id); - - /** - * 根据编码获得生产工单 - * - * @param code 编码 - * @return 生产工单 - */ - MesProWorkOrderDO getWorkOrder(String code); - - /** - * 获得生产工单分页 - * - * @param pageReqVO 分页查询 - * @return 生产工单分页 - */ - PageResult getWorkOrderPage(MesProWorkOrderPageReqVO pageReqVO); - - /** - * 获得工单列表 - * - * @param ids 编号数组 - * @return 工单列表 - */ - List getWorkOrderList(Collection ids); - - /** - * 获得工单 Map - * - * @param ids 编号数组 - * @return 工单 Map - */ - default Map getWorkOrderMap(Collection ids) { - return convertMap(getWorkOrderList(ids), MesProWorkOrderDO::getId); - } - - /** - * 校验工单已确认 - * - * @param id 编号 - * @return 工单 - */ - MesProWorkOrderDO validateWorkOrderConfirmed(Long id); - - /** - * 确认工单(草稿 → 已确认) - * - * @param id 编号 - */ - void confirmWorkOrder(Long id); - - /** - * 完成工单 - * - * @param id 编号 - */ - void finishWorkOrder(Long id); - - /** - * 取消工单 - * - * @param id 编号 - */ - void cancelWorkOrder(Long id); - - /** - * 累加工单的已生产数量 - * - * @param id 工单编号 - * @param incrQuantityProduced 本次已生产数量增量 - */ - void updateProducedQuantity(Long id, BigDecimal incrQuantityProduced); - -} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java deleted file mode 100644 index 431b084..0000000 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java +++ /dev/null @@ -1,248 +0,0 @@ -package cn.iocoder.yudao.module.mes.service.pro.workorder; - -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.pro.workorder.vo.MesProWorkOrderPageReqVO; -import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; -import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemBatchConfigDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; -import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderMapper; -import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum; -import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum; -import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemBatchConfigService; -import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; -import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService; -import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import java.math.BigDecimal; -import java.time.LocalDateTime; -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.*; - -/** - * MES 生产工单 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { - - @Resource - private MesProWorkOrderMapper workOrderMapper; - - @Resource - private MesProWorkOrderBomService workOrderBomService; - @Resource - private MesMdItemService itemService; - @Resource - private MesMdItemBatchConfigService itemBatchConfigService; - @Resource - private MesWmBarcodeService barcodeService; - @Resource - private MesProTaskService taskService; - - @Override - @Transactional(rollbackFor = Exception.class) - public Long createWorkOrder(MesProWorkOrderSaveReqVO createReqVO) { - // 1. 校验数据 - validateWorkOrderSaveData(null, createReqVO); - - // 2.1 设置默认值 - if (createReqVO.getParentId() == null) { - createReqVO.setParentId(MesProWorkOrderDO.PARENT_ID_NULL); - } - // 2.2 插入工单 - MesProWorkOrderDO workOrder = BeanUtils.toBean(createReqVO, MesProWorkOrderDO.class); - workOrder.setStatus(MesProWorkOrderStatusEnum.PREPARE.getStatus()); - workOrderMapper.insert(workOrder); - - // 3. 自动生成 BOM:根据产品 BOM 生成工单 BOM - workOrderBomService.generateWorkOrderBom(workOrder.getId(), createReqVO, false); - - // 4. 自动生成条码 - barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.WORKORDER.getValue(), - workOrder.getId(), workOrder.getCode(), workOrder.getName()); - return workOrder.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updateWorkOrder(MesProWorkOrderSaveReqVO updateReqVO) { - // 1.1 校验存在 + 只有草稿状态才能编辑 - MesProWorkOrderDO oldWorkOrder = validateWorkOrderExists(updateReqVO.getId()); - if (ObjUtil.notEqual(oldWorkOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) { - throw exception(PRO_WORK_ORDER_NOT_PREPARE); - } - // 1.2 校验数据 - validateWorkOrderSaveData(updateReqVO.getId(), updateReqVO); - - // 2. 判断产品或数量是否变更,如果变更则重新生成 BOM(updated=true 会先清理旧数据) - boolean productChanged = ObjUtil.notEqual(oldWorkOrder.getProductId(), updateReqVO.getProductId()); - boolean quantityChanged = oldWorkOrder.getQuantity().compareTo(updateReqVO.getQuantity()) != 0; - if (productChanged || quantityChanged) { - workOrderBomService.generateWorkOrderBom(updateReqVO.getId(), updateReqVO, true); - } - - // 3. 更新 - MesProWorkOrderDO updateObj = BeanUtils.toBean(updateReqVO, MesProWorkOrderDO.class); - workOrderMapper.updateById(updateObj); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deleteWorkOrder(Long id) { - // 1.1 校验存在 - MesProWorkOrderDO workOrder = validateWorkOrderExists(id); - // 1.2 只能删除草稿状态的工单 - if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) { - throw exception(PRO_WORK_ORDER_NOT_PREPARE); - } - // 1.3 校验是否有子工单 - Long childCount = workOrderMapper.selectCount(MesProWorkOrderDO::getParentId, id); - if (childCount > 0) { - throw exception(PRO_WORK_ORDER_HAS_CHILDREN); - } - - // 2. 删除工单 + BOM - workOrderMapper.deleteById(id); - workOrderBomService.deleteWorkOrderBomByWorkOrderId(id); - } - - @Override - public MesProWorkOrderDO validateWorkOrderExists(Long id) { - MesProWorkOrderDO workOrder = workOrderMapper.selectById(id); - if (workOrder == null) { - throw exception(PRO_WORK_ORDER_NOT_EXISTS); - } - return workOrder; - } - - @Override - public MesProWorkOrderDO getWorkOrder(Long id) { - return workOrderMapper.selectById(id); - } - - @Override - public MesProWorkOrderDO getWorkOrder(String code) { - return workOrderMapper.selectByCode(code); - } - - @Override - public PageResult getWorkOrderPage(MesProWorkOrderPageReqVO pageReqVO) { - return workOrderMapper.selectPage(pageReqVO); - } - - @Override - public List getWorkOrderList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return Collections.emptyList(); - } - return workOrderMapper.selectByIds(ids); - } - - @Override - public MesProWorkOrderDO validateWorkOrderConfirmed(Long id) { - MesProWorkOrderDO workOrder = validateWorkOrderExists(id); - if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { - throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); - } - return workOrder; - } - - @Override - public void confirmWorkOrder(Long id) { - // 1.1 校验存在 - MesProWorkOrderDO workOrder = validateWorkOrderExists(id); - // 1.2 只有草稿状态才能确认 - if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) { - throw exception(PRO_WORK_ORDER_NOT_PREPARE); - } - - // 2. 更新状态为已确认 - workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) - .setStatus(MesProWorkOrderStatusEnum.CONFIRMED.getStatus())); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void finishWorkOrder(Long id) { - // 1. 校验存在 + 只有已确认状态才能完成 - MesProWorkOrderDO workOrder = validateWorkOrderExists(id); - if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { - throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); - } - - // 2. 级联完成所有关联任务 - taskService.finishTaskByOrderId(id); - - // 3. 更新工单状态为已完成 - workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) - .setStatus(MesProWorkOrderStatusEnum.FINISHED.getStatus()) - .setFinishDate(LocalDateTime.now())); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void cancelWorkOrder(Long id) { - // 1. 校验存在 + 只有已确认状态才能取消 - MesProWorkOrderDO workOrder = validateWorkOrderExists(id); - if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { - throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); - } - - // 2. 级联取消所有关联任务 - taskService.cancelTaskByOrderId(id); - - // 3. 更新工单状态为已取消 - workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) - .setStatus(MesProWorkOrderStatusEnum.CANCELED.getStatus()) - .setCancelDate(LocalDateTime.now())); - } - - // ==================== 校验方法 ==================== - - private void validateWorkOrderSaveData(Long id, MesProWorkOrderSaveReqVO reqVO) { - // 1. 校验编码唯一 - validateWorkOrderCodeUnique(id, reqVO.getCode()); - // 2. 校验产品存在 - itemService.validateItemExists(reqVO.getProductId()); - // 3. 校验批次配置(如果产品有 clientFlag=true,则 clientId 必填) - MesMdItemBatchConfigDO batchConfig = itemBatchConfigService.getItemBatchConfigByItemId(reqVO.getProductId()); - if (batchConfig != null && Boolean.TRUE.equals(batchConfig.getClientFlag()) && reqVO.getClientId() == null) { - throw exception(MD_CLIENT_NOT_EXISTS); - } - } - - private void validateWorkOrderCodeUnique(Long id, String code) { - if (code == null) { - return; - } - MesProWorkOrderDO workOrder = workOrderMapper.selectByCode(code); - if (workOrder == null) { - return; - } - if (ObjUtil.notEqual(workOrder.getId(), id)) { - throw exception(PRO_WORK_ORDER_CODE_DUPLICATE); - } - } - - @Override - public void updateProducedQuantity(Long id, BigDecimal incrQuantityProduced) { - // 校验工单存在 - validateWorkOrderExists(id); - // 更新数量 - workOrderMapper.updateProducedQuantity(id, incrQuantityProduced); - } - -} -- libgit2 0.21.4