| | |
| | | package org.jeecg.modules.mes.service.impl; |
| | | |
| | | import cn.hutool.core.collection.CollectionUtil; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.jeecg.common.constant.CommonConstant; |
| | | import org.jeecg.common.exception.JeecgBootException; |
| | | import org.jeecg.modules.base.entity.Factory; |
| | | import org.jeecg.modules.base.entity.LineSideWarehouse; |
| | | import org.jeecg.modules.base.entity.Shift; |
| | | import org.jeecg.modules.base.entity.ShiftGroup; |
| | | import org.jeecg.modules.base.service.IFactoryService; |
| | | import org.jeecg.modules.base.service.ILineSideWarehouseService; |
| | | import org.jeecg.modules.base.service.IShiftGroupService; |
| | | import org.jeecg.modules.base.service.IShiftService; |
| | | import org.jeecg.modules.lsw.entity.LswMaterial; |
| | | import org.jeecg.modules.lsw.entity.LswMaterialInbound; |
| | | import org.jeecg.modules.lsw.enums.MaterialCategoryEnum; |
| | | import org.jeecg.modules.lsw.service.ILswMaterialInboundService; |
| | | import org.jeecg.modules.lsw.service.ILswMaterialService; |
| | | import org.jeecg.modules.mes.entity.MesMaterialLoading; |
| | | import org.jeecg.modules.mes.entity.MesProductionOrder; |
| | | import org.jeecg.modules.mes.entity.MesProductionWorkOrder; |
| | | import org.jeecg.modules.mes.entity.MesWorkReporting; |
| | | import org.jeecg.modules.mes.mapper.MesWorkReportingMapper; |
| | | import org.jeecg.modules.mes.service.IMesMaterialLoadingService; |
| | | import org.jeecg.modules.mes.service.IMesProductionOrderService; |
| | | import org.jeecg.modules.mes.service.IMesProductionWorkOrderService; |
| | | import org.jeecg.modules.mes.service.IMesWorkReportingService; |
| | | import org.jeecg.modules.mes.utils.CommonUtils; |
| | | import org.jeecg.modules.pms.entity.PmsMaterialProcess; |
| | | import org.jeecg.modules.pms.service.IPmsMaterialProcessService; |
| | | import org.jeecg.modules.pms.service.IPmsProcessBillMaterialsService; |
| | | import org.jeecg.modules.pms.vo.ProcessBillMaterialsDetailVo; |
| | | import org.jeecg.modules.qms.entity.InspectionPlan; |
| | | import org.jeecg.modules.qms.entity.InspectionPlanItem; |
| | | import org.jeecg.modules.qms.enums.PlanCategoryEnum; |
| | | import org.jeecg.modules.qms.service.IInspectionPlanItemService; |
| | | import org.jeecg.modules.qms.service.IInspectionPlanService; |
| | | import org.jeecg.modules.sap.request.OrderLoadRequest; |
| | | import org.jeecg.modules.sap.request.OrderReportRequest; |
| | | import org.jeecg.modules.sap.service.OrderLoadService; |
| | | import org.jeecg.modules.sap.service.OrderReportService; |
| | | import org.jeecg.modules.system.service.ISysBusinessCodeRuleService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.List; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.temporal.ChronoField; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * @Description: 工单报工 |
| | |
| | | * @Date: 2025-07-04 |
| | | * @Version: V1.0 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class MesWorkReportingServiceImpl extends ServiceImpl<MesWorkReportingMapper, MesWorkReporting> implements IMesWorkReportingService { |
| | | |
| | | @Autowired |
| | | private IMesProductionWorkOrderService mesProductionWorkOrderService; |
| | | @Autowired |
| | | private IMesProductionOrderService mesProductionOrderService; |
| | | @Autowired |
| | | private ILswMaterialService lswMaterialService; |
| | | @Autowired |
| | | private IFactoryService factoryService; |
| | | @Autowired |
| | | private IShiftService shiftService; |
| | | @Autowired |
| | | private IShiftGroupService shiftGroupService; |
| | | @Autowired |
| | | private ILineSideWarehouseService lineSideWarehouseService; |
| | | @Autowired |
| | | private ILswMaterialInboundService lswMaterialInboundService; |
| | | @Autowired |
| | | private IMesMaterialLoadingService mesMaterialLoadingService; |
| | | @Autowired |
| | | private IPmsProcessBillMaterialsService pmsProcessBillMaterialsService; |
| | | @Autowired |
| | | private IPmsMaterialProcessService pmsMaterialProcessService; |
| | | @Autowired |
| | | private ISysBusinessCodeRuleService sysBusinessCodeRuleService; |
| | | @Autowired |
| | | private OrderReportService orderReportService; |
| | | @Autowired |
| | | private OrderLoadService orderLoadService; |
| | | @Autowired |
| | | private IInspectionPlanService inspectionPlanService; |
| | | @Autowired |
| | | private IInspectionPlanItemService inspectionPlanItemService; |
| | | |
| | | @Override |
| | | public List<MesWorkReporting> queryWorkReportingByWorkOrderId(String workOrderId) { |
| | |
| | | public List<MesWorkReporting> queryWorkReportingByOrderId(String orderId) { |
| | | return baseMapper.queryWorkReportingByOrderId(orderId); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MesWorkReporting addReporting(MesWorkReporting mesWorkReporting) { |
| | | MesProductionWorkOrder workOrder = mesProductionWorkOrderService.getById(mesWorkReporting.getWorkOrderId()); |
| | | if (workOrder == null) { |
| | | throw new JeecgBootException("工单不存在!"); |
| | | } |
| | | LswMaterial material = lswMaterialService.list(new LambdaQueryWrapper<LswMaterial>() |
| | | .eq(LswMaterial::getMaterialNumber, workOrder.getMaterialNumber()) |
| | | .eq(LswMaterial::getDelFlag, CommonConstant.DEL_FLAG_0)).stream() |
| | | .findAny().orElse(null); |
| | | if (material == null) { |
| | | throw new JeecgBootException("物料不存在!"); |
| | | } |
| | | MaterialCategoryEnum materialCategory = MaterialCategoryEnum.fromName(material.getMaterialCategory()); |
| | | if (materialCategory == null) { |
| | | throw new JeecgBootException("未知的物料类型!"); |
| | | } |
| | | |
| | | LineSideWarehouse lineSideWarehouse = lineSideWarehouseService.list(new LambdaQueryWrapper<LineSideWarehouse>() |
| | | .eq(LineSideWarehouse::getFactoryId, mesWorkReporting.getFactoryId()) |
| | | .eq(LineSideWarehouse::getDelFlag, CommonConstant.DEL_FLAG_0)) |
| | | .stream().findAny().orElse(null); |
| | | if (lineSideWarehouse == null) { |
| | | throw new JeecgBootException("线边仓库不存在!"); |
| | | } |
| | | |
| | | //生产批次号 |
| | | LocalDate today = LocalDate.now(); |
| | | String yearLastTwo = today.format(DateTimeFormatter.ofPattern("yy")); |
| | | String dayOfYearStr = today.format(DateTimeFormatter.ofPattern("DDD")); |
| | | ShiftGroup shiftGroup = shiftGroupService.getById(workOrder.getGroupId()); |
| | | int currentPallets = workOrder.getFinishedPallets() + 1; |
| | | String batchNumber = yearLastTwo + dayOfYearStr + shiftGroup.getGroupCode() + currentPallets; |
| | | mesWorkReporting.setBatchNumber(batchNumber) |
| | | .setWorkOrderCode(workOrder.getWorkOrderCode()) |
| | | .setWarehouseId(lineSideWarehouse.getId()) |
| | | .setWarehouseCode(lineSideWarehouse.getWarehouseCode()) |
| | | .setReporter(Objects.requireNonNull(CommonUtils.getCurrentUser()).getUsername()) |
| | | .setReportTime(new Date()); |
| | | String date = today.format(DateTimeFormatter.ofPattern("yyMMdd")); |
| | | Factory factory = factoryService.getById(mesWorkReporting.getFactoryId()); |
| | | workOrder.setFactoryCode(factory.getFactoryCode()); |
| | | switch (materialCategory) { |
| | | case FINISHED_PRODUCT: |
| | | //成品报工 |
| | | productReport(mesWorkReporting, workOrder, lineSideWarehouse); |
| | | //生成检验工单 |
| | | generateInspectionOrder(mesWorkReporting, workOrder); |
| | | //拼接成品报工托号 |
| | | String palletNumber4 = sysBusinessCodeRuleService.generateBusinessCodeSeq("WorkReportingPalletNumber4"); |
| | | String finishedPalletNumber = material.getMaterialNumber() + date + palletNumber4; |
| | | mesWorkReporting.setPalletNumber(finishedPalletNumber).setReportType("FINISHED"); |
| | | break; |
| | | case INNER_FLANGE: |
| | | case OUTER_FLANGE: |
| | | //半成品(内法兰、外法兰)报工 |
| | | productReport(mesWorkReporting, workOrder, lineSideWarehouse); |
| | | //拼接半成品报工托号 |
| | | Shift shift = shiftService.getById(workOrder.getShiftId()); |
| | | String palletNumber6 = sysBusinessCodeRuleService.generateBusinessCodeSeq("WorkReportingPalletNumber6"); |
| | | String halfPalletNumber = factory.getFactoryCode() + material.getMaterialNumber() + date + shift.getShiftCode() + palletNumber6; |
| | | mesWorkReporting.setPalletNumber(halfPalletNumber).setReportType("HALF"); |
| | | break; |
| | | } |
| | | //新增报工记录 |
| | | save(mesWorkReporting); |
| | | //更新排产工单 |
| | | MesProductionWorkOrder productionWorkUpdateOrder = new MesProductionWorkOrder() |
| | | .setId(workOrder.getId()) |
| | | .setActualQuantity(workOrder.getActualQuantity().add(mesWorkReporting.getQuantity())) |
| | | .setFinishedPallets(workOrder.getFinishedPallets() + 1); |
| | | mesProductionWorkOrderService.updateById(productionWorkUpdateOrder); |
| | | //返回报工记录,用于托标签打印 |
| | | return mesWorkReporting; |
| | | } |
| | | |
| | | //半成品(内法兰、外法兰)、成品报工 |
| | | private void productReport(MesWorkReporting mesWorkReporting, MesProductionWorkOrder workOrder, LineSideWarehouse lineSideWarehouse) { |
| | | //1、入库 半成品/成品 到对应线边库 |
| | | LswMaterialInbound materialInbound = new LswMaterialInbound() |
| | | .setFactoryId(workOrder.getFactoryId()) |
| | | .setWarehouseId(lineSideWarehouse.getId()) |
| | | .setMaterialNumber(workOrder.getMaterialNumber()) |
| | | .setMaterialName(workOrder.getMaterialName()) |
| | | .setBatchNumber(mesWorkReporting.getBatchNumber()) |
| | | .setQuantity(mesWorkReporting.getQuantity()); |
| | | lswMaterialInboundService.save(materialInbound); |
| | | //2、扣减使用毛坯库存(更新上料记录)或半成品物料库存(内法兰、外法兰、小内圈、配件等),按照 排产工单id、物料编码 查询上料记录,按照时间从早到晚排序,优先扣减早的上料记录(先进先出) |
| | | //先查询物料 BOM |
| | | Map<String, ProcessBillMaterialsDetailVo> processBillMaterialsDetailMap = pmsProcessBillMaterialsService |
| | | .queryMaterialsDetailByOrderIdAndMaterialNumber(mesWorkReporting.getOrderId(), workOrder.getMaterialNumber()).stream() |
| | | .collect(Collectors.toMap(ProcessBillMaterialsDetailVo::getMaterialNumber, v1 -> v1, (v1, v2) -> v1)); |
| | | //查询上料记录 |
| | | Map<String, List<MesMaterialLoading>> materialLoadingRecordMap = mesMaterialLoadingService.list(new LambdaQueryWrapper<MesMaterialLoading>() |
| | | .eq(MesMaterialLoading::getWorkOrderId, workOrder.getId()) |
| | | .in(MesMaterialLoading::getMaterialNumber, processBillMaterialsDetailMap.keySet()) |
| | | .gt(MesMaterialLoading::getRemainingQuantity, BigDecimal.ZERO)).stream() |
| | | .sorted(Comparator.comparing(MesMaterialLoading::getCreateTime)) |
| | | .collect(Collectors.groupingBy(MesMaterialLoading::getMaterialNumber)); |
| | | List<MesMaterialLoading> materialLoadingRecordUpdateList = CollectionUtil.newArrayList(); |
| | | for (String materialNumber : processBillMaterialsDetailMap.keySet()) { |
| | | List<MesMaterialLoading> materialLoadingRecordList = materialLoadingRecordMap.get(materialNumber); |
| | | if (materialLoadingRecordList.isEmpty()) { |
| | | throw new JeecgBootException("未查询到相应物料的上料记录!"); |
| | | } |
| | | //计算物料扣减数量 |
| | | ProcessBillMaterialsDetailVo processBillMaterialsDetailVo = processBillMaterialsDetailMap.get(materialNumber); |
| | | BigDecimal quantity = processBillMaterialsDetailVo.getPerQuantity().multiply(mesWorkReporting.getQuantity()); |
| | | List<MesMaterialLoading> updateList = deductQuantity(materialLoadingRecordList, quantity); |
| | | materialLoadingRecordUpdateList.addAll(updateList); |
| | | } |
| | | //更新上料记录 |
| | | mesMaterialLoadingService.updateBatchById(materialLoadingRecordUpdateList); |
| | | MesProductionOrder productionOrder = mesProductionOrderService.getById(mesWorkReporting.getOrderId()); |
| | | //3、调用SAP投料接口(消耗的物料) OrderLoadService |
| | | for (String materialNumber : processBillMaterialsDetailMap.keySet()) { |
| | | ProcessBillMaterialsDetailVo processBillMaterialsDetailVo = processBillMaterialsDetailMap.get(materialNumber); |
| | | OrderLoadRequest loadRequest = new OrderLoadRequest() |
| | | .setOrderCode(productionOrder.getOrderCode()) |
| | | .setFactoryCode(workOrder.getFactoryCode()) |
| | | .setMaterialNumber(materialNumber) |
| | | .setWarehouseCode(lineSideWarehouse.getWarehouseCode()) |
| | | .setQuantity(processBillMaterialsDetailVo.getPerQuantity().multiply(mesWorkReporting.getQuantity())) |
| | | .setBatchNumber(mesWorkReporting.getBatchNumber()) |
| | | .setProductionUnit(processBillMaterialsDetailVo.getProductionUnit()); |
| | | try { |
| | | orderLoadService.productionOrderLoad(loadRequest); |
| | | } catch (Exception e) { |
| | | log.error("SAP生产订单投料异常!", e); |
| | | } |
| | | } |
| | | //4、调用SAP工序报工(根据生产订单id查询对应的物料工序(半成品是多个工序,成品只有一个工序),按照工序号从小到大依次挨个报工;目前考虑异步执行) OrderReportService |
| | | List<PmsMaterialProcess> processList = pmsMaterialProcessService.list(new LambdaQueryWrapper<PmsMaterialProcess>() |
| | | .eq(PmsMaterialProcess::getOrderId, mesWorkReporting.getOrderId()) |
| | | .orderByAsc(PmsMaterialProcess::getProcessCode)); |
| | | for (PmsMaterialProcess process : processList) { |
| | | OrderReportRequest reportRequest = new OrderReportRequest() |
| | | .setOrderCode(productionOrder.getOrderCode()) |
| | | .setFactoryCode(workOrder.getFactoryCode()) |
| | | .setProcessCode(process.getProcessCode()) |
| | | .setQualifiedQuantity(mesWorkReporting.getQuantity()) |
| | | .setWarehouseCode(lineSideWarehouse.getWarehouseCode()) |
| | | .setBatchNumber(mesWorkReporting.getBatchNumber()); |
| | | try { |
| | | orderReportService.productionOrderReport(reportRequest); |
| | | } catch (Exception e) { |
| | | log.error("SAP工序报工异常!", e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | //根据检验方案生成检验工单 |
| | | private void generateInspectionOrder(MesWorkReporting mesWorkReporting, MesProductionWorkOrder workOrder) { |
| | | //1.根据物料编码查询检验方案 |
| | | InspectionPlan inspectionPlan = inspectionPlanService.list(new LambdaQueryWrapper<InspectionPlan>() |
| | | .eq(InspectionPlan::getMaterialNumber, workOrder.getMaterialNumber()) |
| | | .eq(InspectionPlan::getPlanCategory, PlanCategoryEnum.COMPLETION_INSPECTION.name()) |
| | | .eq(InspectionPlan::getPlanStatus, CommonConstant.STATUS_1) |
| | | .eq(InspectionPlan::getDelFlag, CommonConstant.DEL_FLAG_0)).stream().findFirst().orElse(null); |
| | | if (inspectionPlan == null) { |
| | | throw new JeecgBootException("未找到该物料的检验方案!"); |
| | | } |
| | | List<InspectionPlanItem> inspectionPlanItemList = inspectionPlanItemService.list(new LambdaQueryWrapper<InspectionPlanItem>() |
| | | .eq(InspectionPlanItem::getPlanId, inspectionPlan.getId()) |
| | | .orderByAsc(InspectionPlanItem::getSorter)); |
| | | if (inspectionPlanItemList.isEmpty()) { |
| | | throw new JeecgBootException("未找到该物料的检验方案检验项明细!"); |
| | | } |
| | | //2.生成检验工单 |
| | | //todo 检验工单目前还没有生成代码,没有功能 |
| | | } |
| | | |
| | | private List<MesMaterialLoading> deductQuantity(List<MesMaterialLoading> materialLoadingRecordList, BigDecimal quantity) { |
| | | for (MesMaterialLoading mesMaterialLoading : materialLoadingRecordList) { |
| | | if (mesMaterialLoading.getRemainingQuantity().compareTo(quantity) >= 0) { |
| | | mesMaterialLoading.setRemainingQuantity(mesMaterialLoading.getRemainingQuantity().subtract(quantity)); |
| | | break; |
| | | } else { |
| | | quantity = quantity.subtract(mesMaterialLoading.getRemainingQuantity()); |
| | | mesMaterialLoading.setRemainingQuantity(BigDecimal.ZERO); |
| | | } |
| | | } |
| | | return materialLoadingRecordList; |
| | | } |
| | | } |