package com.aps.core.service.impl; import java.math.BigDecimal; import java.util.*; import cn.hutool.core.util.IdUtil; import com.aps.common.core.utils.DateUtils; import com.aps.common.security.utils.DictUtils; import com.aps.common.security.utils.SecurityUtils; import com.aps.core.domain.*; import com.aps.core.mapper.*; import com.aps.core.service.*; import com.aps.system.api.domain.SysDictData; import jakarta.annotation.Resource; import com.aps.core.domain.ApsPlateStandardRequire; import com.aps.core.mapper.ApsPlateStandardRequireMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.aps.core.service.IApsPlateStandardRequireService; import org.springframework.transaction.annotation.Transactional; import java.util.List; /** * 钣金工单标准需求Service业务层处理 * * @author zhl * @date 2025-05-06 */ @Service public class ApsPlateStandardRequireServiceImpl implements IApsPlateStandardRequireService { @Autowired private ApsPlateStandardRequireMapper apsPlateStandardRequireMapper; @Resource private ApsPlateStandardRequireBatchMapper requireBatchMapper; @Resource ApsPlatePlanMapper platePlanMapper; @Resource ApsBomHeaderMapper bomHeaderMapper; @Resource IApsBomService bomLineService; @Resource ApsMaterialStorageManagementMapper itemStorageMapper; @Resource ApsPlateStandardRequireBomStockDetailMapper plateBomStockDetailMapper; @Resource IApsPlateStandardRequireBomStockDetailService bomStockDetailService; @Resource ApsStandardProcessRouteHeaderMapper standardProcessRouteHeaderMapper; @Resource ApsStandardProcessRouteLineMapper ApsStandardProcessRouteLineMapper; @Resource ApsPlateStandardRequireBomOrderDetailMapper plateBomOrderDetailMapper; @Autowired private ApsPlatePlanMapper apsPlatePlanMapper; @Resource IApsPlateStandardRequireBomOrderDetailService bomOrderDetailService; @Resource IApsStandardProcessRouteLineService routeLineService; @Resource IApsPlateStandardRequireBatchService requireBatchService; /** * 查询钣金工单标准需求 * * @param id 钣金工单标准需求主键 * @return 钣金工单标准需求 */ @Override public ApsPlateStandardRequire selectApsPlateStandardRequireById(Long id) { return apsPlateStandardRequireMapper.selectApsPlateStandardRequireById(id); } /** * 查询钣金工单标准需求列表 * * @param apsPlateStandardRequire 钣金工单标准需求 * @return 钣金工单标准需求 */ @Override public List selectApsPlateStandardRequireList(ApsPlateStandardRequire apsPlateStandardRequire) { return apsPlateStandardRequireMapper.selectApsPlateStandardRequireList(apsPlateStandardRequire); } /** * 新增钣金工单标准需求 * * @param apsPlateStandardRequire 钣金工单标准需求 * @return 结果 */ @Override public int insertApsPlateStandardRequire(ApsPlateStandardRequire apsPlateStandardRequire) { apsPlateStandardRequire.setCreateTime(DateUtils.getNowDate()); return apsPlateStandardRequireMapper.insertApsPlateStandardRequire(apsPlateStandardRequire); } /** * 修改钣金工单标准需求 * * @param apsPlateStandardRequire 钣金工单标准需求 * @return 结果 */ @Override public int updateApsPlateStandardRequire(ApsPlateStandardRequire apsPlateStandardRequire) { apsPlateStandardRequire.setUpdateTime(DateUtils.getNowDate()); return apsPlateStandardRequireMapper.updateApsPlateStandardRequire(apsPlateStandardRequire); } /** * 批量删除钣金工单标准需求 * * @param ids 需要删除的钣金工单标准需求主键 * @return 结果 */ @Override public int deleteApsPlateStandardRequireByIds(Long[] ids) { return apsPlateStandardRequireMapper.deleteApsPlateStandardRequireByIds(ids); } /** * 删除钣金工单标准需求信息 * * @param id 钣金工单标准需求主键 * @return 结果 */ @Override public int deleteApsPlateStandardRequireById(Long id) { return apsPlateStandardRequireMapper.deleteApsPlateStandardRequireById(id); } /** * 钣金供应缺口报表 * @param apsPlateStandardRequire * @return */ @Override public List selectPlateSupplyGapList(ApsPlateStandardRequire apsPlateStandardRequire) { return apsPlateStandardRequireMapper.selectPlateSupplyGapList(apsPlateStandardRequire); } @Transactional @Override public void generatorPlan(){ /*初始化数据*/ requireBatchService.initRequireBatch(); /*定义工厂为南通 */ String plantCode="FORTUNA"; /*定义主单类型为钣金主单*/ String mainOrderType = "0"; /*生成新批次号*/ String batchNum= requireBatchService.getNewBatchNumber(); /*获取钣金主单信息*/ List mainPlans = platePlanMapper.selectPlatePlanByPlantMajor(plantCode,mainOrderType); for (ApsPlatePlan mainPlan : mainPlans) { String itemNumber = mainPlan.getItemNumber(); /*根据料号 获取BOM Header */ /*当前Bom节点处理完成后,处理下级BOM*/ List requiresList=new ArrayList<>(); getBomRequires(plantCode, "0","0",itemNumber,BigDecimal.ONE, batchNum, null, mainPlan, requiresList, 0L); // 批量插入以提高性能 if (!requiresList.isEmpty()) { int batchSize = 1000; for (int i = 0; i < requiresList.size(); i += batchSize) { int end = Math.min(i + batchSize, requiresList.size()); List batch = requiresList.subList(i, end); apsPlateStandardRequireMapper.batchInsert(batch); } } } } /** * 构建需求信息 * * @param plant 工厂代码 * @param bomHeaderCode BOM上级物料编码 * @param bomLineId BOM行ID * @param itemCode 物料代码 * @param itemNum 物料数量 * @param batchNum 批次号 * @param upLevelStartDate 上级工序的开始日期 * @param plan 计划对象 * @param allRequires 所有需求的列表 * @param level 层级 */ private void getBomRequires(String plant, String bomHeaderCode, String bomLineId,String itemCode,BigDecimal itemNum, String batchNum, Date upLevelStartDate, ApsPlatePlan plan, List allRequires, Long level) { /*构建需求信息*/ ApsPlateStandardRequire require = new ApsPlateStandardRequire(); require.setId(IdUtil.getSnowflakeNextId()); require.setRequireTrackId(plan.getId() + ""); require.setBatchNumber(batchNum); require.setDocNum(plan.getDocumentNumber()); require.setOrgCode(plant); require.setBomHeaderCode(bomHeaderCode); require.setBomLineId(bomLineId); require.setBomLineCode(itemCode); require.setBomLineLevel(level); require.setBomUseAmount(itemNum); require.setCreateTime(DateUtils.getNowDate()); require.setCreateBy(SecurityUtils.getUsername()); require.setDelFlag("0"); require.setProductionBase(plan.getProductionBase()); /*计算需求数量*/ if (level == 0) { require.setBomUseAmount(BigDecimal.ONE); require.setCompleteDate(plan.getPlanEndDay()); require.setDemandDate(plan.getPlanEndDay()); } else { require.setBomUseAmount(itemNum.multiply(plan.getProductionQuantity())); } /*查找库存,计算净需求,保存剩余库存,保存库存扣减明细*/ BigDecimal remainderStock = BigDecimal.ZERO; /*默认净需求为BOM用量*/ require.setNetRequirement(require.getBomUseAmount()); Optional itemStorage = getItemStorage(plant, itemCode); if (itemStorage.isPresent()) { ApsMaterialStorageManagement storage = itemStorage.get(); /*剩余库存*/ remainderStock = storage.getRemainderStock(); /*计算净需求 默认=需求数量*/ if (remainderStock.compareTo(BigDecimal.ZERO) == 0) { require.setNetRequirement(require.getBomUseAmount()); } if (remainderStock.compareTo(BigDecimal.ZERO) > 0) { BigDecimal subtract = require.getBomUseAmount().subtract(remainderStock); BigDecimal deductionAmount = BigDecimal.ZERO; BigDecimal afterStockAmount = BigDecimal.ZERO; if (subtract.compareTo(BigDecimal.ZERO) >= 0) { deductionAmount = remainderStock; afterStockAmount = BigDecimal.ZERO; require.setNetRequirement(subtract); } else { deductionAmount = require.getBomUseAmount(); afterStockAmount = remainderStock.subtract(deductionAmount); require.setNetRequirement(BigDecimal.ZERO); } /*记录库存剩余数量,记录库存使用记录*/ bomStockDetailService.saveStorageAndDetail(storage, plan, bomLineId,itemCode, batchNum, deductionAmount, afterStockAmount,require.getId()); } } /*未匹配数量,默认为净需求*/ require.setUnmatchedDemandAmount(require.getNetRequirement()); /*工艺路线总需求*/ ApsStandardProcessRouteLine routeHeader = routeLineService.getRouteLineTotalTime(require); String routeId = routeHeader.getRouteId(); BigDecimal totalRouteTime = routeHeader.getRouteTime(); long millisecond = 60 * 60 * 1000L; long totalRouteMillisecond = totalRouteTime.multiply(BigDecimal.valueOf(millisecond)).longValue(); require.setProcessRouteId(routeId); require.setProcessRouteHours(String.valueOf(totalRouteTime)); /*完成时间,level=0 时默认为工单的计划完成日期*/ Date completeDate = plan.getPlanEndDay(); /*预留天数*/ Long reservedDay = getReservedDays(); if (level > 0) { /* 当前需求完成日期为上阶层需求的开始时间 - 预留天数(转换为毫秒)*/ long reservedMillisecond = reservedDay * 24 * millisecond; completeDate.setTime(upLevelStartDate.getTime() - reservedMillisecond); } /*设置完成日期*/ require.setCompleteDate(completeDate); require.setDemandDate(completeDate); /*设置开始时间*/ Date startDay = new Date(); startDay.setTime(completeDate.getTime() - totalRouteMillisecond); require.setStartDate(startDay); /*计算是否有风险*/ require.setHasDelayRisk("0"); Date dateZero = getDateZero(DateUtils.getNowDate()); if (startDay.before(dateZero)) { require.setHasDelayRisk("1"); } /*生产基地*/ require.setProductionBase(plan.getProductionBase()); require.setMatchState("已匹配"); require.setMatchMode("库存匹配"); if (require.getNetRequirement().compareTo(BigDecimal.ZERO) > 0) { require.setMatchState("待匹配"); require.setMatchMode("工单匹配"); /*使用子件工单进行需求匹配*/ matchRequireAndSubPlan(require); } allRequires.add(require); if (require.getNetRequirement().compareTo(BigDecimal.ZERO) > 0) { /*当前Bom节点处理完成后,处理下级BOM*/ long nextLevel=level+1; List bomLineList = bomLineService.selectApsBomLineList(plant, itemCode); if (!bomLineList.isEmpty()) { bomLineList.forEach(line -> { getBomRequires(plant, itemCode, line.getBomLineId(),line.getItemCode() ,line.getNum() , batchNum, require.getStartDate(), plan, allRequires, nextLevel); }); } } } /** * 获取物料库存信息 * */ private Optional getItemStorage(String plant, String itemNumber) { ApsMaterialStorageManagement storageParam = new ApsMaterialStorageManagement(); storageParam.setItemNumber(itemNumber); storageParam.setApplicableFactories(plant); return itemStorageMapper.selectApsMaterialStorageManagementList(storageParam).stream() .findFirst(); } /** * 获取钣金计划 预留天数 * */ private Long getReservedDays(){ Long days=0L; List dictDataList = DictUtils.getDictCache("aps_is_suspended"); if (dictDataList != null) { Long.getLong(dictDataList.get(0).getDictValue()); } return days; } /** * 使用子件工单匹配需求中的净需求 * */ private void matchRequireAndSubPlan(ApsPlateStandardRequire require) { BigDecimal netRequirement = require.getNetRequirement(); require.setMatchMode("工单匹配"); if (netRequirement.compareTo(BigDecimal.ZERO) > 0) { ApsPlatePlan platePlan = apsPlatePlanMapper.selectUnMatchPlateSubPlan(require.getOrgCode(), require.getBomLineCode()); /*子件工单的未匹配数量 作为当前的库存*/ while (platePlan != null && netRequirement.compareTo(BigDecimal.ZERO) > 0) { BigDecimal stock = platePlan.getUnmatchedQuantity(); if (netRequirement.compareTo(stock) < 0) { /* 库存数量 大于 净需求数量*/ /* 净需求数量=0 ,子件工单未匹配数量= 库存-净需求*/ BigDecimal subtract = stock.subtract(netRequirement); bomOrderDetailService.savePlastPlanAndBomOrderDetail(require, platePlan, subtract, stock, netRequirement); netRequirement = BigDecimal.ZERO; require.setMatchState("已匹配"); require.setUnmatchedDemandAmount(netRequirement); /*净需求已经被满足,不需要继续匹配*/ } else if (netRequirement.compareTo(stock) == 0) { /*净需求数量 == 库存数量*/ BigDecimal subtract = BigDecimal.ZERO; bomOrderDetailService.savePlastPlanAndBomOrderDetail(require, platePlan, subtract, stock, netRequirement); netRequirement = BigDecimal.ZERO; require.setMatchState("已匹配"); require.setUnmatchedDemandAmount(netRequirement); /*净需求已经被满足,不需要继续匹配*/ } if (netRequirement.compareTo(stock) > 0) { /*需求大于库存*/ /*净需求 被部分满足 */ BigDecimal rest = netRequirement.subtract(stock); require.setMatchState("匹配中"); /*工单 未匹配数量为0 全部用于匹配需求*/ bomOrderDetailService.savePlastPlanAndBomOrderDetail(require, platePlan, BigDecimal.ZERO, stock, netRequirement); /*净需求未被满足,需要继续匹配*/ platePlan = apsPlatePlanMapper.selectUnMatchPlateSubPlan(require.getOrgCode(), require.getBomLineCode()); /*剩余净需求*/ netRequirement = rest; require.setUnmatchedDemandAmount(netRequirement); } } } require.setUnmatchedDemandAmount(require.getNetRequirement()); } /** * 获取日期零点 * */ private Date getDateZero(Date date){ Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); return calendar.getTime(); } }