package com.aps.core.service.impl;
|
|
import java.math.BigDecimal;
|
import java.util.*;
|
|
import cn.hutool.core.date.DateUtil;
|
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<ApsPlateStandardRequire> 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<ApsPlateStandardRequire> selectPlateSupplyGapList(ApsPlateStandardRequire apsPlateStandardRequire) {
|
return apsPlateStandardRequireMapper.selectPlateSupplyGapList(apsPlateStandardRequire);
|
}
|
|
@Transactional
|
public void generatorPlan(){
|
|
/*初始化数据*/
|
requireBatchService.initRequireBatch();
|
/*定义工厂为南通 */
|
String plantCode="FORTUNA";
|
/*定义主单类型为钣金主单*/
|
String mainOrderType = "钣金主件";
|
/*生成新批次号*/
|
String batchNum= requireBatchService.getNewBatchNumber();
|
/*获取钣金主单信息*/
|
List<ApsPlatePlan> mainPlans = platePlanMapper.selectPlatePlanByPlantMajor(plantCode,mainOrderType);
|
for (ApsPlatePlan mainPlan : mainPlans) {
|
String itemNumber = mainPlan.getItemNumber();
|
/*根据料号 获取BOM Header */
|
/*当前Bom节点处理完成后,处理下级BOM*/
|
List<ApsBom> bomLineList = bomLineService.selectApsBomLineList(plantCode, itemNumber);
|
List<ApsPlateStandardRequire> requiresList=new ArrayList<>();
|
if(!bomLineList.isEmpty()){
|
bomLineList.forEach(line -> {
|
getBomRequires(plantCode, line, 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<ApsPlateStandardRequire> batch = requiresList.subList(i, end);
|
apsPlateStandardRequireMapper.batchInsert(batch);
|
}
|
}
|
}
|
}
|
|
/**
|
* 构建需求信息
|
* */
|
private void getBomRequires(String plant, ApsBom bomLine, String batchNum, Date upLevelStartDate, ApsPlatePlan plan, List<ApsPlateStandardRequire> allRequires, Long level) {
|
|
String itemNumber = bomLine.getItemCode();
|
/*构建需求信息*/
|
ApsPlateStandardRequire require = new ApsPlateStandardRequire();
|
require.setId(IdUtil.getSnowflakeNextId());
|
require.setRequireId(plan.getId());
|
require.setBatchNumber(batchNum);
|
require.setDocNum(plan.getDocumentNumber());
|
require.setOrgCode(plant);
|
require.setBomLineCode(itemNumber);
|
require.setBomLineLevel(level);
|
require.setBomUseAmount(bomLine.getNum());
|
require.setCreateTime(DateUtils.getNowDate());
|
require.setCreateBy(SecurityUtils.getUsername());
|
/*计算需求数量*/
|
if (level == 0) {
|
require.setBomUseAmount(BigDecimal.ONE);
|
require.setCompleteDate(plan.getPlanEndDay());
|
require.setDemandDate(plan.getPlanEndDay());
|
} else {
|
require.setBomUseAmount(bomLine.getNum().multiply(plan.getProductionQuantity()));
|
}
|
/*查找库存,计算净需求,保存剩余库存,保存库存扣减明细*/
|
BigDecimal remainderStock = BigDecimal.ZERO;
|
/*默认净需求为BOM用量*/
|
require.setNetRequirement(require.getBomUseAmount());
|
Optional<ApsMaterialStorageManagement> itemStorage = getItemStorage(plant, itemNumber);
|
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, bomLine, batchNum, deductionAmount, afterStockAmount,require.getId().toString());
|
}
|
}
|
|
/*工艺路线总需求*/
|
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("无风险");
|
Date dateZero = getDateZero(DateUtils.getNowDate());
|
if (startDay.before(dateZero)) {
|
require.setHasDelayRisk("有风险");
|
}
|
|
/*生产基地*/
|
require.setProductionBase(plan.getProductionBase());
|
|
require.setMatchState("已匹配");
|
require.setMatchMode("库存匹配");
|
if (require.getNetRequirement().compareTo(BigDecimal.ZERO) > 0) {
|
require.setMatchState("待匹配");
|
require.setMatchMode("工单匹配");
|
}
|
/*使用子件工单进行需求匹配*/
|
matchRequireAndSubPlan(require);
|
|
allRequires.add(require);
|
/*当前Bom节点处理完成后,处理下级BOM*/
|
List<ApsBom> bomLineList = bomLineService.selectApsBomLineList(plant, itemNumber);
|
if (!bomLineList.isEmpty()) {
|
bomLineList.forEach(line -> {
|
getBomRequires(plant, line, batchNum, require.getStartDate(), plan, allRequires, level + 1);
|
});
|
}
|
}
|
/**
|
* 获取物料库存信息
|
* */
|
private Optional<ApsMaterialStorageManagement> 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<SysDictData> 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();
|
if (netRequirement.compareTo(BigDecimal.ZERO) > 0) {
|
ApsPlatePlan platePlan = apsPlatePlanMapper.selectUnMatchPlateSubPlan(require.getOrgCode());
|
/*子件工单的未匹配数量 作为当前的库存*/
|
while (platePlan != null && netRequirement.compareTo(BigDecimal.ZERO) > 0) {
|
BigDecimal stock = platePlan.getUnmatchedQuantity();
|
if (netRequirement.compareTo(stock) < 0) {
|
/* 库存数量 大于 净需求数量*/
|
/* 净需求数量=0 ,子件工单未匹配数量= 库存-净需求*/
|
netRequirement = BigDecimal.ZERO;
|
require.setNetRequirement(netRequirement);
|
BigDecimal subtract = stock.subtract(netRequirement);
|
bomOrderDetailService.savePlastPlanAndBomOrderDetail(require, platePlan, subtract, stock, netRequirement);
|
/*净需求已经被满足,不需要继续匹配*/
|
|
} else if (netRequirement.compareTo(stock) == 0) {
|
/*净需求数量 == 库存数量*/
|
netRequirement = BigDecimal.ZERO;
|
require.setNetRequirement(netRequirement);
|
BigDecimal subtract = BigDecimal.ZERO;
|
bomOrderDetailService.savePlastPlanAndBomOrderDetail(require, platePlan, subtract, stock, netRequirement);
|
/*净需求已经被满足,不需要继续匹配*/
|
}
|
if (netRequirement.compareTo(stock) > 0) {
|
/*需求大于库存*/
|
/*净需求 被部分满足 */
|
BigDecimal rest = netRequirement.subtract(stock);
|
require.setNetRequirement(rest);
|
require.setMatchState("匹配中");
|
/*工单 未匹配数量为0 全部用于匹配需求*/
|
bomOrderDetailService.savePlastPlanAndBomOrderDetail(require, platePlan, BigDecimal.ZERO, stock, netRequirement);
|
/*净需求未被满足,需要继续匹配*/
|
platePlan = apsPlatePlanMapper.selectUnMatchPlateSubPlan(require.getOrgCode());
|
netRequirement = rest;
|
}
|
}
|
}
|
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();
|
}
|
|
}
|