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.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.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: 工单报工
|
* @Author: jeecg-boot
|
* @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;
|
|
@Override
|
public List<MesWorkReporting> queryWorkReportingByWorkOrderId(String workOrderId) {
|
return baseMapper.queryWorkReportingByWorkOrderId(workOrderId);
|
}
|
|
@Override
|
public List<MesWorkReporting> queryWorkReportingByOrderId(String orderId) {
|
return baseMapper.queryWorkReportingByOrderId(orderId);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void 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)
|
.setWarehouseId(lineSideWarehouse.getId())
|
.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);
|
//拼接成品报工托号
|
String palletNumber4 = sysBusinessCodeRuleService.generateBusinessCodeSeq("WorkReportingPalletNumber4");
|
String finishedPalletNumber = material.getMaterialNumber() + date + palletNumber4;
|
mesWorkReporting.setPalletNumber(finishedPalletNumber);
|
//todo 打印成品托标签、检验标识卡、移库单、完工检验工单
|
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);
|
break;
|
}
|
//新增报工记录
|
save(mesWorkReporting);
|
//更新排产工单
|
MesProductionWorkOrder productionWorkUpdateOrder = new MesProductionWorkOrder()
|
.setId(workOrder.getId())
|
.setActualQuantity(workOrder.getActualQuantity().add(mesWorkReporting.getQuantity()))
|
.setFinishedPallets(workOrder.getFinishedPallets() + 1);
|
mesProductionWorkOrderService.updateById(productionWorkUpdateOrder);
|
}
|
|
//半成品(内法兰、外法兰)、成品报工
|
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 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;
|
}
|
}
|