| | |
| | | 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.mps.MesProMpsDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.mps.MesProMpsMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.qc.retentionsample.MesQcRetentionSampleMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProMpsStatusEnum; |
| | | 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.common.bpm.MesBpmProcessService; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderProgressRespVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO; |
| | |
| | | public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { |
| | | |
| | | @Resource |
| | | private MesBpmProcessService mesBpmProcessService; |
| | | |
| | | private static final String BPM_PROCESS_DEFINITION_CATEGORY_CODE = "mes_pro_feedback_audit"; |
| | | |
| | | @Resource |
| | | private MesProWorkOrderMapper workOrderMapper; |
| | | @Resource |
| | | private MesProMpsMapper mpsMapper; |
| | | @Resource |
| | | private MesQcRetentionSampleMapper retentionSampleMapper; |
| | | |
| | | @Resource |
| | | private MesProWorkOrderBomService workOrderBomService; |
| | |
| | | private MesMdWorkstationService workstationService; |
| | | @Resource |
| | | private CrmCustomerApi customerApi; |
| | | @Resource |
| | | private cn.iocoder.yudao.module.mes.service.pro.cost.MesProWorkOrderCostService workOrderCostService; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | |
| | | // 3. 自动生成 BOM:根据产品 BOM 生成工单 BOM |
| | | workOrderBomService.generateWorkOrderBom(workOrder.getId(), createReqVO, false); |
| | | // 3.1 计算标准物料成本 |
| | | workOrderCostService.recalculateWorkOrderCost(workOrder.getId()); |
| | | |
| | | // 4. 工序由前端选择产品后带入,不再自动生成 |
| | | |
| | |
| | | // 3. 更新 |
| | | MesProWorkOrderDO updateObj = BeanUtils.toBean(updateReqVO, MesProWorkOrderDO.class); |
| | | workOrderMapper.updateById(updateObj); |
| | | |
| | | // 4. 产品或数量变化后重算标准物料成本 |
| | | if (productChanged || quantityChanged) { |
| | | workOrderCostService.recalculateWorkOrderCost(updateReqVO.getId()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<Map<String, Object>> getWorkOrderApproveProcessDefinitionList() { |
| | | return mesBpmProcessService.getApproveProcessDefinitionList(BPM_PROCESS_DEFINITION_CATEGORY_CODE); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public MesProWorkOrderDO getWorkOrder(Long id) { |
| | | return workOrderMapper.selectById(id); |
| | | } |
| | |
| | | |
| | | @Override |
| | | public PageResult<MesProWorkOrderDO> getWorkOrderPage(MesProWorkOrderPageReqVO pageReqVO) { |
| | | // 获取用户有权限的客户 ID 列表 |
| | | List<Long> permittedClientIds = customerApi.getPermittedCustomerIds(); |
| | | return workOrderMapper.selectPage(pageReqVO, permittedClientIds); |
| | | return workOrderMapper.selectPage(pageReqVO, (List<Long>) null); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<MesProWorkOrderDO> getWorkOrderSchedulePage(MesProWorkOrderPageReqVO pageReqVO) { |
| | | // 获取用户有权限的客户 ID 列表 |
| | | List<Long> permittedClientIds = customerApi.getPermittedCustomerIds(); |
| | | return workOrderMapper.selectSchedulePage(pageReqVO, permittedClientIds); |
| | | return workOrderMapper.selectSchedulePage(pageReqVO, (List<Long>) null); |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.CONFIRMED.getStatus())) { |
| | | throw exception(PRO_WORK_ORDER_NOT_CONFIRMED); |
| | | } |
| | | // 2. 校验已生产数量必须大于 0(没有产出不允许完成) |
| | | BigDecimal quantityProduced = ObjUtil.defaultIfNull(workOrder.getQuantityProduced(), BigDecimal.ZERO); |
| | | if (quantityProduced.compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw exception(PRO_WORK_ORDER_NO_PRODUCED_QUANTITY, workOrder.getCode()); |
| | | } |
| | | // 3. 校验留样记录(所有工单完成前必须登记留样) |
| | | if (retentionSampleMapper.selectByWorkOrderId(id) == null) { |
| | | throw exception(PRO_WORK_ORDER_RETENTION_SAMPLE_REQUIRED, workOrder.getCode()); |
| | | } |
| | | |
| | | // 2. 级联完成所有关联任务 |
| | | // 4. 级联完成所有关联任务 |
| | | taskService.finishTaskByOrderId(id); |
| | | |
| | | // 3. 更新工单状态为已完成 |
| | | // 5. 更新工单状态为已完成 |
| | | workOrderMapper.updateById(new MesProWorkOrderDO().setId(id) |
| | | .setStatus(MesProWorkOrderStatusEnum.FINISHED.getStatus()) |
| | | .setFinishDate(LocalDateTime.now())); |
| | | |
| | | // 6. 同步关联 MPS 状态 |
| | | finishRelatedMps(workOrder, quantityProduced); |
| | | } |
| | | |
| | | /** |
| | | * 工单完成时同步 MPS:已下发 → 已完成,并回填完成时间。 |
| | | * 合并下发时一个工单对应多条 MPS,已生产数量由各 MPS 自身维护,这里不回填,避免重复累计。 |
| | | */ |
| | | private void finishRelatedMps(MesProWorkOrderDO workOrder, BigDecimal quantityProduced) { |
| | | List<MesProMpsDO> mpsList = mpsMapper.selectListByWorkOrderId(workOrder.getId()); |
| | | if (CollUtil.isEmpty(mpsList)) { |
| | | return; |
| | | } |
| | | boolean singleMps = mpsList.size() == 1; |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | for (MesProMpsDO mps : mpsList) { |
| | | // 已取消/已完成的 MPS 不做状态回写 |
| | | if (!ObjUtil.equal(mps.getStatus(), MesProMpsStatusEnum.ISSUED.getStatus())) { |
| | | continue; |
| | | } |
| | | MesProMpsDO updateObj = new MesProMpsDO().setId(mps.getId()) |
| | | .setStatus(MesProMpsStatusEnum.FINISHED.getStatus()) |
| | | .setFinishDate(now); |
| | | if (singleMps) { |
| | | BigDecimal currentProduced = ObjUtil.defaultIfNull(mps.getQuantityProduced(), BigDecimal.ZERO); |
| | | updateObj.setQuantityProduced(quantityProduced.max(currentProduced)); |
| | | } |
| | | mpsMapper.updateById(updateObj); |
| | | } |
| | | } |
| | | |
| | | @Override |