aps-modules/aps-core/src/main/java/com/aps/core/domain/ApsPlateStandardRequire.java
@@ -28,6 +28,8 @@ /** 需求追溯ID */ @Excel(name = "需求追溯ID") private String requireId; /**单号*/ private String docNum; /** bom_line_id */ // @Excel(name = "bom_line_id") @@ -91,21 +93,15 @@ /** 未匹配需求数量 */ @Excel(name = "未匹配需求数量") private String unmatchedDemandAmount; private BigDecimal unmatchedDemandAmount; /** 建议完成日期 */ // @Excel(name = "建议完成日期") private String suggestedCompletionDate; private Date suggestedCompletionDate; /** 延迟风险标识 */ // @Excel(name = "延迟风险标识") private String hasDelayRisk; /** $column.columnComment */ private String batchNumber; /** $column.columnComment */ private String delFlag; } aps-modules/aps-core/src/main/java/com/aps/core/domain/ApsPlateStandardRequireError.java
@@ -3,6 +3,7 @@ import com.aps.common.core.annotation.Excel; import com.aps.common.core.web.domain.BaseEntity; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; @@ -17,6 +18,7 @@ @EqualsAndHashCode(callSuper = true) @Data @Schema(description = "钣金标准需求异常信息实体类") @Builder public class ApsPlateStandardRequireError extends BaseEntity { @Serial aps-modules/aps-core/src/main/java/com/aps/core/mapper/ApsPlateStandardRequireMapper.java
@@ -69,4 +69,6 @@ * @return */ public List<ApsPlateStandardRequire> selectPlateSupplyGapList(ApsPlateStandardRequire apsPlateStandardRequire); int batchInsert(List<ApsPlateStandardRequire> requireList); } aps-modules/aps-core/src/main/java/com/aps/core/service/IApsStandardProcessRouteLineService.java
@@ -1,6 +1,9 @@ package com.aps.core.service; import java.math.BigDecimal; import java.util.List; import com.aps.core.domain.ApsPlateStandardRequire; import com.aps.core.domain.ApsStandardProcessRouteLine; /** @@ -58,4 +61,6 @@ * @return 结果 */ public int deleteApsStandardProcessRouteLineById(Long id); ApsStandardProcessRouteLine getRouteLineTotalTime(ApsPlateStandardRequire require); } aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsPlateStandardRequireServiceImpl.java
@@ -1,25 +1,20 @@ package com.aps.core.service.impl; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Optional; 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.IApsBomService; import com.aps.core.service.IApsPlateStandardRequireBomOrderDetailService; import com.aps.core.service.IApsPlateStandardRequireBomStockDetailService; 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 com.aps.core.service.IApsPlateStandardRequireService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.aps.core.service.IApsPlateStandardRequireService; @@ -72,6 +67,8 @@ @Resource IApsPlateStandardRequireBomOrderDetailService bomOrderDetailService; @Resource IApsStandardProcessRouteLineService routeLineService; /** * 查询钣金工单标准需求 @@ -169,29 +166,44 @@ String batchNum=getBatch(); /*获取钣金主单信息*/ List<ApsPlatePlan> mainPlans = platePlanMapper.selectPlatePlanByPlantMajor(plantCode,mainOrderType); List<ApsPlateStandardRequire> requiresList=new ArrayList<>(); 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(); String productivityModel_combined_batch="合批"; String productivityModel_monopolize="独占"; Optional<ApsStandardProcessRouteHeader> firstProcessRoute = standardProcessRouteHeaderMapper.queryStandardProcessRouteHeaderByPlantAndItemCode(plant, itemNumber).stream().findFirst(); if (firstProcessRoute.isPresent()) { /*获取工艺路线Header信息*/ ApsStandardProcessRouteHeader routeHeader = firstProcessRoute.get(); /*构建需求信息*/ 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); @@ -233,12 +245,16 @@ bomStockDetailService.saveStorageAndDetail(storage, plan, bomLine, batchNum, deductionAmount, afterStockAmount); } } /*净需求*/ BigDecimal netRequirement = require.getNetRequirement(); /*工艺路线总需求*/ BigDecimal totalRouteTime = getRouteLineTotalTime(routeHeader, productivityModel_monopolize, netRequirement); 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(); /*预留天数*/ @@ -250,11 +266,22 @@ } /*设置完成日期*/ require.setCompleteDate(completeDate); require.setDemandDate(require.getCompleteDate()); 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){ @@ -262,6 +289,8 @@ require.setMatchMode("工单匹配"); } require.setHasDelayRisk("无风险"); /*使用子件工单进行需求匹配*/ matchRequireAndSubPlan(require); allRequires.add(require); /*当前Bom节点处理完成后,处理下级BOM*/ @@ -270,10 +299,6 @@ bomLineList.forEach(line -> { getBomRequires(plant, line, batchNum, require.getStartDate(), plan, allRequires, level+1); }); } } else { throw new RuntimeException("未找到标准工艺路线"); } } @@ -315,10 +340,8 @@ ApsMaterialStorageManagement storageParam = new ApsMaterialStorageManagement(); storageParam.setItemNumber(itemNumber); storageParam.setApplicableFactories(plant); Optional<ApsMaterialStorageManagement> firstStorage = itemStorageMapper.selectApsMaterialStorageManagementList(storageParam).stream() return itemStorageMapper.selectApsMaterialStorageManagementList(storageParam).stream() .findFirst(); return firstStorage; } /** @@ -336,11 +359,13 @@ /** * 使用子件工单匹配需求中的净需求 * */ 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) { /* 库存数量 大于 净需求数量*/ @@ -360,7 +385,6 @@ /*净需求已经被满足,不需要继续匹配*/ } if (netRequirement.compareTo(stock) > 0) { while (platePlan != null && netRequirement.compareTo(BigDecimal.ZERO) > 0) { /*需求大于库存*/ /*净需求 被部分满足 */ BigDecimal rest = netRequirement.subtract(stock); @@ -373,10 +397,23 @@ 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(); } } aps-modules/aps-core/src/main/java/com/aps/core/service/impl/ApsStandardProcessRouteLineServiceImpl.java
@@ -1,7 +1,18 @@ package com.aps.core.service.impl; import java.math.BigDecimal; import java.util.Hashtable; import java.util.List; import java.util.Optional; import com.aps.common.core.utils.DateUtils; import com.aps.common.security.utils.SecurityUtils; import com.aps.core.domain.ApsPlateStandardRequire; import com.aps.core.domain.ApsPlateStandardRequireError; import com.aps.core.domain.ApsStandardProcessRouteHeader; import com.aps.core.mapper.ApsPlateStandardRequireErrorMapper; import com.aps.core.mapper.ApsStandardProcessRouteHeaderMapper; import jakarta.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.aps.core.mapper.ApsStandardProcessRouteLineMapper; @@ -19,7 +30,10 @@ { @Autowired private ApsStandardProcessRouteLineMapper apsStandardProcessRouteLineMapper; @Resource ApsStandardProcessRouteHeaderMapper standardProcessRouteHeaderMapper; @Resource ApsPlateStandardRequireErrorMapper requireErrorMapper; /** * 查询标准工艺路线Line * @@ -93,4 +107,74 @@ { return apsStandardProcessRouteLineMapper.deleteApsStandardProcessRouteLineById(id); } /** * 根据料号 查询工艺路线 及其下的工序,计算工艺路线总工时 * @param require 需求信息 * @return 工艺路线总工时 */ @Override public ApsStandardProcessRouteLine getRouteLineTotalTime(ApsPlateStandardRequire require) { // 定义独占生产模式常量 String productivityModel_monopolize = "独占"; // 初始化总工时为0 BigDecimal totalRouteTime = BigDecimal.ZERO; //工厂 String plant=require.getOrgCode(); // 物料号 String itemNumber=require.getBomLineCode(); long routId=0L; ApsStandardProcessRouteLine ret=ApsStandardProcessRouteLine.builder() .routeId(String.valueOf(routId)) .routeTime(BigDecimal.ZERO) .build(); // 查询标准工艺路线头部信息 Optional<ApsStandardProcessRouteHeader> firstProcessRoute = standardProcessRouteHeaderMapper.queryStandardProcessRouteHeaderByPlantAndItemCode(plant, itemNumber).stream().findFirst(); if (firstProcessRoute.isPresent()) { ApsStandardProcessRouteHeader routeHeader = firstProcessRoute.get(); // 构建工艺路线行参数对象 ApsStandardProcessRouteLine routeLineParam = ApsStandardProcessRouteLine.builder() .routeId(routeHeader.getRouteId()) .build(); // 查询标准工艺路线行信息 List<ApsStandardProcessRouteLine> apsStandardProcessRouteLines = apsStandardProcessRouteLineMapper.selectApsStandardProcessRouteLineList(routeLineParam); /*工艺路线Line 总工时*/ if(apsStandardProcessRouteLines.isEmpty()){ saveRequireError(require,"工序不存在"); }else { // 遍历每个工艺路线行 apsStandardProcessRouteLines.forEach(line -> { // 默认将设计产能设置为路线时间 line.setRouteTime(line.getDesignCapacity()); // 如果生产模式为独占,则路线时间为设计产能乘以净需求量 if (line.getProductivityModel().equals(productivityModel_monopolize)) { line.setRouteTime(line.getDesignCapacity().multiply(require.getNetRequirement())); } // 累加路线时间到总工时中 totalRouteTime.add(line.getRouteTime()); }); } ret.setRouteTime(totalRouteTime); ret.setRouteId(routeHeader.getRouteId()); }else { saveRequireError(require,"标准工艺路线不存在"); } // 返回总工时 return ret; } private void saveRequireError(ApsPlateStandardRequire require,String message) { ApsPlateStandardRequireError data = ApsPlateStandardRequireError.builder() .requireId(require.getRequireId()) .batchNumber(require.getBatchNumber()) .docNum(require.getDocNum()) .itemNum(require.getBomLineCode()) .orgCode(require.getOrgCode()) .message(message) .delFlag("0") .build(); data.setCreateBy(SecurityUtils.getUsername()); data.setCreateTime(DateUtils.getNowDate()); requireErrorMapper.insertApsPlateStandardRequireError(data); } } aps-modules/aps-core/src/main/resources/mapper/core/ApsPlateStandardRequireMapper.xml
@@ -177,4 +177,43 @@ <if test="requireId != null and requireId != ''"> and require_id like '%' || #{requireId} || '%'</if> <if test="bomLineCode != null and bomLineCode != ''"> and bom_line_code like '%' || #{bomLineCode} || '%'</if> </select> <insert id="batchInsert" parameterType="java.util.List"> insert into aps_plate_standard_require (id, require_id,doc_num,batch_number, org_code, bom_line_id, bom_line_code, bom_line_level, bom_use_amount, process_route_id, process_route_hours, require_amount, net_requirement, start_date, complete_date, demand_date, production_base, match_state, match_mode, unmatched_demand_amount, suggested_completion_date, has_delay_risk, batch_number, del_flag, create_time, create_by) values <foreach collection="list" item="item" separator=","> ( #{item.Id}, #{item.requireId}, #{item.docNum}, #{item.batchNumber}, #{item.orgCode}, #{item.bomLineId}, #{item.bomLineCode}, #{item.bomLineLevel}, #{item.bomUseAmount}, #{item.processRouteId}, #{item.processRouteHours}, #{item.requireAmount}, #{item.netRequirement}, #{item.startDate}, #{item.completeDate}, #{item.demandDate}, #{item.productionBase}, #{item.matchState}, #{item.matchMode}, #{item.unmatchedDemandAmount}, #{item.suggestedCompletionDate}, #{item.hasDelayRisk}, #{item.batchNumber}, #{item.delFlag}, #{item.createTime}, #{item.createBy} ) </foreach> </insert> </mapper>