package cn.iocoder.yudao.module.mes.service.pro.maintenanceplan; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.erp.api.purchase.ErpPurchasePlanApi; import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchasePlanCreateReqDTO; import cn.iocoder.yudao.module.mes.controller.admin.pro.maintenanceplan.vo.MesProMaintenancePlanPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.maintenanceplan.vo.MesProMaintenancePlanSaveReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.maintenanceplan.MesProMaintenancePlanDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.maintenanceplan.MesProMaintenancePlanItemDO; import cn.iocoder.yudao.module.mes.dal.mysql.pro.maintenanceplan.MesProMaintenancePlanItemMapper; import cn.iocoder.yudao.module.mes.dal.mysql.pro.maintenanceplan.MesProMaintenancePlanMapper; import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderSourceTypeEnum; import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderTypeEnum; import cn.iocoder.yudao.module.mes.service.cal.team.MesCalTeamService; import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; /** * MES 电力作业计划 Service 实现类 * * @author xiaoyi */ @Service @Validated @Slf4j public class MesProMaintenancePlanServiceImpl implements MesProMaintenancePlanService { /** * 状态:草稿 */ private static final Integer STATUS_DRAFT = 0; /** * 状态:已下发 */ private static final Integer STATUS_ISSUED = 10; /** * 状态:已完成 */ private static final Integer STATUS_FINISHED = 20; /** * 状态:已取消 */ private static final Integer STATUS_CANCELLED = 30; @Resource private MesProMaintenancePlanMapper planMapper; @Resource private MesProMaintenancePlanItemMapper planItemMapper; @Resource private MesCalTeamService teamService; @Resource private MesMdItemService itemService; @Resource private ErpPurchasePlanApi erpPurchasePlanApi; @Resource private MesProWorkOrderService workOrderService; @Override @Transactional(rollbackFor = Exception.class) public Long createPlan(MesProMaintenancePlanSaveReqVO createReqVO) { // 1. 生成计划编码 String code = generatePlanCode(); if (planMapper.selectByCode(code) != null) { throw exception(MD_ITEM_CODE_DUPLICATE); } // 2. 校验班组并回填 fillTeamInfo(createReqVO); // 3. 插入计划 MesProMaintenancePlanDO plan = BeanUtils.toBean(createReqVO, MesProMaintenancePlanDO.class, req -> req .setCode(code) .setStatus(STATUS_DRAFT)); planMapper.insert(plan); // 4. 插入明细 insertPlanItems(plan.getId(), createReqVO.getItems()); return plan.getId(); } @Override @Transactional(rollbackFor = Exception.class) public void updatePlan(MesProMaintenancePlanSaveReqVO updateReqVO) { // 1. 校验存在 + 草稿状态 MesProMaintenancePlanDO oldPlan = validatePlanCanModify(updateReqVO.getId()); fillTeamInfo(updateReqVO); // 2. 更新主表 MesProMaintenancePlanDO updateObj = BeanUtils.toBean(updateReqVO, MesProMaintenancePlanDO.class, req -> req .setCode(oldPlan.getCode()) .setStatus(oldPlan.getStatus())); planMapper.updateById(updateObj); // 3. 更新明细:先删后插 planItemMapper.deleteByPlanId(updateReqVO.getId()); insertPlanItems(updateReqVO.getId(), updateReqVO.getItems()); } @Override @Transactional(rollbackFor = Exception.class) public void deletePlan(Collection ids) { if (CollUtil.isEmpty(ids)) { return; } for (Long id : ids) { validatePlanCanModify(id); planItemMapper.deleteByPlanId(id); planMapper.deleteById(id); } } @Override public MesProMaintenancePlanDO getPlan(Long id) { return planMapper.selectById(id); } @Override public List getPlanItemListByPlanId(Long planId) { return planItemMapper.selectListByPlanId(planId); } @Override public List getPlanItemListByPlanIds(Collection planIds) { return planItemMapper.selectListByPlanIds(planIds); } @Override public PageResult getPlanPage(MesProMaintenancePlanPageReqVO pageReqVO) { return planMapper.selectPage(pageReqVO); } @Override @Transactional(rollbackFor = Exception.class) public void issuePlan(Long id) { MesProMaintenancePlanDO plan = validatePlanExists(id); if (!Objects.equals(plan.getStatus(), STATUS_DRAFT)) { throw exception(PRO_WORK_ORDER_NOT_PREPARE); } planMapper.updateById(new MesProMaintenancePlanDO().setId(id).setStatus(STATUS_ISSUED)); } @Override @Transactional(rollbackFor = Exception.class) public void finishPlan(Long id) { MesProMaintenancePlanDO plan = validatePlanExists(id); if (!Objects.equals(plan.getStatus(), STATUS_ISSUED)) { throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); } planMapper.updateById(new MesProMaintenancePlanDO().setId(id).setStatus(STATUS_FINISHED)); } @Override @Transactional(rollbackFor = Exception.class) public Long generatePurchasePlan(Long id) { // 1. 校验计划存在且已下发 MesProMaintenancePlanDO plan = validatePlanExists(id); if (!Objects.equals(plan.getStatus(), STATUS_ISSUED)) { throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); } // 2. 获取明细 List planItems = planItemMapper.selectListByPlanId(id); if (CollUtil.isEmpty(planItems)) { throw exception(PRO_WORK_ORDER_NOT_EXISTS); } // 3. 组装采购计划 DTO(MES 物料 -> MDM 物料) Map itemMap = itemService.getItemMap( planItems.stream().map(MesProMaintenancePlanItemDO::getItemId).collect(Collectors.toSet())); List items = planItems.stream().map(item -> { ErpPurchasePlanCreateReqDTO.Item dtoItem = new ErpPurchasePlanCreateReqDTO.Item(); MesMdItemDO mesItem = itemMap.get(item.getItemId()); dtoItem.setProductId(mesItem != null ? mesItem.getMdmItemId() : item.getItemId()); dtoItem.setProductUnitId(mesItem != null ? mesItem.getUnitMeasureId() : null); dtoItem.setCount(item.getQuantity()); dtoItem.setRemark(item.getRemark()); return dtoItem; }).collect(Collectors.toList()); // 4. 调用 ERP 生成采购计划 ErpPurchasePlanCreateReqDTO createReqDTO = new ErpPurchasePlanCreateReqDTO(); createReqDTO.setName("作业计划采购-" + plan.getName()); createReqDTO.setDemandSource(2); // 运维/生产计划 createReqDTO.setPlanDate(plan.getPlanDate()); createReqDTO.setRemark("来源计划: " + plan.getCode()); createReqDTO.setItems(items); return erpPurchasePlanApi.createPurchasePlan(createReqDTO); } @Override @Transactional(rollbackFor = Exception.class) public Long generateWorkOrder(Long id) { // 1. 校验计划存在且已下发 MesProMaintenancePlanDO plan = validatePlanExists(id); if (!Objects.equals(plan.getStatus(), STATUS_ISSUED)) { throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); } // 2. 已生成过工单则直接返回 if (plan.getWorkOrderId() != null) { return plan.getWorkOrderId(); } // 3. 组装工单 MesProWorkOrderSaveReqVO workOrderReq = new MesProWorkOrderSaveReqVO(); workOrderReq.setName(plan.getName()); workOrderReq.setType(convertPlanTypeToWorkOrderType(plan.getPlanType())); workOrderReq.setOrderSourceType(MesProWorkOrderSourceTypeEnum.MAINTENANCE_PLAN.getType()); workOrderReq.setOrderSourceCode(plan.getCode()); workOrderReq.setQuantity(BigDecimal.ONE); workOrderReq.setRequestDate(plan.getPlanDate() != null ? plan.getPlanDate() : java.time.LocalDateTime.now()); workOrderReq.setRemark("来自电力作业计划: " + plan.getCode()); Long workOrderId = workOrderService.createWorkOrder(workOrderReq); // 4. 回写计划 MesProMaintenancePlanDO updateObj = new MesProMaintenancePlanDO(); updateObj.setId(id); updateObj.setWorkOrderId(workOrderId); planMapper.updateById(updateObj); return workOrderId; } /** * 计划类型 -> 工单类型映射 */ private Integer convertPlanTypeToWorkOrderType(Integer planType) { return switch (planType) { case 1 -> MesProWorkOrderTypeEnum.POWER_OPERATION.getType(); // 电网运行 -> 电力运维 case 2 -> MesProWorkOrderTypeEnum.POWER_GENERATION.getType(); // 发电 case 3 -> MesProWorkOrderTypeEnum.POWER_OPERATION.getType(); // 变电运维 -> 电力运维 case 4 -> MesProWorkOrderTypeEnum.POWER_MAINTENANCE.getType(); // 线路检修 -> 检修 default -> MesProWorkOrderTypeEnum.POWER_OPERATION.getType(); }; } private void insertPlanItems(Long planId, List items) { if (CollUtil.isEmpty(items)) { return; } planItemMapper.insertBatch(items.stream().map(item -> BeanUtils.toBean(item, MesProMaintenancePlanItemDO.class).setPlanId(planId)) .collect(Collectors.toList())); } private void fillTeamInfo(MesProMaintenancePlanSaveReqVO reqVO) { if (reqVO.getTeamId() == null) { return; } MesCalTeamDO team = teamService.validateTeamExists(reqVO.getTeamId()); if (team != null) { reqVO.setTeamName(team.getName()); } } private String generatePlanCode() { return "MP" + DateUtil.format(java.time.LocalDateTime.now(), "yyyyMMddHHmmss") + String.format("%03d", (int) (Math.random() * 1000)); } private MesProMaintenancePlanDO validatePlanExists(Long id) { MesProMaintenancePlanDO plan = planMapper.selectById(id); if (plan == null) { throw exception(PRO_WORK_ORDER_NOT_EXISTS); } return plan; } private MesProMaintenancePlanDO validatePlanCanModify(Long id) { MesProMaintenancePlanDO plan = validatePlanExists(id); if (!Objects.equals(plan.getStatus(), STATUS_DRAFT)) { throw exception(PRO_WORK_ORDER_NOT_PREPARE); } return plan; } }