refactor(technology): 重构 BOM 成本计算逻辑

- 优化油漆成本计算逻辑,按数量计算而非单重
- 完善损耗成本计算,增加日志记录- 调整 Redis 连接配置
This commit is contained in:
曹鹏飞 2025-03-26 19:24:54 +08:00
parent 123597ceb4
commit 3e9626a671
5 changed files with 48 additions and 30 deletions

View File

@ -78,7 +78,7 @@ public class EBomCostCacheDTO implements Serializable {
/** /**
* 油漆重量 * 油漆重量
*/ */
private BigDecimal paintWeight = BigDecimal.ONE; private BigDecimal paintWeight = BigDecimal.ZERO;
/** /**
* 制作成本 * 制作成本

View File

@ -3,7 +3,6 @@ package com.nflg.product.technology.pojo.dto;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Objects;
@Data @Data
public class EBomDTO { public class EBomDTO {
@ -82,15 +81,15 @@ public class EBomDTO {
private Long ebomRowId; private Long ebomRowId;
/** // /**
* 单重 // * 单重
*/ // */
private BigDecimal unitWeight; // private BigDecimal unitWeight;
//
public BigDecimal getUnitWeight() { // public BigDecimal getUnitWeight() {
if (Objects.nonNull(unitWeight)) { // if (Objects.nonNull(unitWeight)) {
return unitWeight; // return unitWeight;
} // }
return BigDecimal.ZERO; // return BigDecimal.ZERO;
} // }
} }

View File

@ -92,11 +92,11 @@ public class BomCostCalculateService {
config.setManday(manday); config.setManday(manday);
config.setVirtualWorkings(virtualWorkingService.listDTO()); config.setVirtualWorkings(virtualWorkingService.listDTO());
List<EBomCostCacheDTO> result = Collections.synchronizedList(new ArrayList<>(50)); List<EBomCostCacheDTO> result = Collections.synchronizedList(new ArrayList<>(50));
calculateBom(month, true, pDto, datas, config, result); calculateBom(materialNo, month, true, pDto, datas, config, result);
return result; return result;
} }
private EBomCostCacheDTO calculateBom(String month, boolean isRoot, EBomDTO dto, List<EBomDTO> datas, BomCostCalculateConfig config, List<EBomCostCacheDTO> result) { private EBomCostCacheDTO calculateBom(String rootMaterialNo, String month, boolean isRoot, EBomDTO dto, List<EBomDTO> datas, BomCostCalculateConfig config, List<EBomCostCacheDTO> result) {
String cdata = redisTemplate.opsForValue().get(buildKey(dto)); String cdata = redisTemplate.opsForValue().get(buildKey(dto));
boolean purchaseTypeIsF = materialMainAttrService.purchaseTypeIsF(dto.getMaterialNo()); boolean purchaseTypeIsF = materialMainAttrService.purchaseTypeIsF(dto.getMaterialNo());
boolean purchaseTypeIsE50 = materialMainAttrService.purchaseTypeIsE50(dto.getMaterialNo()); boolean purchaseTypeIsE50 = materialMainAttrService.purchaseTypeIsE50(dto.getMaterialNo());
@ -117,8 +117,6 @@ public class BomCostCalculateService {
cdto.setWorkshopOfficeExpenses(calculateWorkshopOfficeExpenses(dto, config, workingHours)); cdto.setWorkshopOfficeExpenses(calculateWorkshopOfficeExpenses(dto, config, workingHours));
cdto.setAuxiliaryDepartmentLaborCost(calculateAuxiliaryDepartmentLaborCost(dto, config, workingHours)); cdto.setAuxiliaryDepartmentLaborCost(calculateAuxiliaryDepartmentLaborCost(dto, config, workingHours));
cdto.setAuxiliaryDepartmentExpenses(calculateAuxiliaryDepartmentExpenses(dto, config, workingHours)); cdto.setAuxiliaryDepartmentExpenses(calculateAuxiliaryDepartmentExpenses(dto, config, workingHours));
cdto.setPaintCost(calculatePaintCost(dto, month));
cdto.setPaintWeight(dto.getUnitWeight());
cdto.setProductionCosts(calculateProductionCosts(dto, config, workingHours)); cdto.setProductionCosts(calculateProductionCosts(dto, config, workingHours));
if (purchaseTypeIsF) { if (purchaseTypeIsF) {
cdto.setHasChildren(false); cdto.setHasChildren(false);
@ -135,19 +133,25 @@ public class BomCostCalculateService {
if (cdto.isPurchasedParts()) { if (cdto.isPurchasedParts()) {
// 外购件只计算采购成本 // 外购件只计算采购成本
cdto.setPurchasedPartsCost(calculatePurchasedPartsCost(dto)); cdto.setPurchasedPartsCost(calculatePurchasedPartsCost(dto));
// 计算损耗成本
cdto.setWasteCost(calculateWasteCost(dto, month));
} else { } else {
// 非外购件计算材料成本和制作成本 // 非外购件计算材料成本和制作成本
// 计算材料成本 // 计算材料成本
cdto.setSteelsCost(calculateSteelsCost(dto)); cdto.setSteelsCost(calculateSteelsCost(dto));
// 计算损耗成本 // 计算损耗成本
cdto.setWasteCost(calculateWasteCost(dto, month)); cdto.setWasteCost(calculateWasteCost(dto, month));
cdto.setPaintCost(calculatePaintCost(rootMaterialNo, dto, month));
if (cdto.getPaintCost().compareTo(BigDecimal.ZERO) > 0) {
cdto.setPaintWeight(dto.getNum());
}
} }
} else { } else {
cdto.setHasChildren(true); cdto.setHasChildren(true);
cdto.setPurchasedParts(false); cdto.setPurchasedParts(false);
//计算子级成本 //计算子级成本
List<EBomCostCacheDTO> childrenCost = children.parallelStream() List<EBomCostCacheDTO> childrenCost = children.parallelStream()
.map(c -> calculateBom(month, false, c, datas, config, result)) .map(c -> calculateBom(rootMaterialNo, month, false, c, datas, config, result))
.collect(Collectors.toList()); .collect(Collectors.toList());
for (EBomCostCacheDTO c : childrenCost) { for (EBomCostCacheDTO c : childrenCost) {
EBomDTO dto1 = children.stream().filter(cc -> StrUtil.equals(cc.getMaterialNo(), c.getMaterialNo())).findFirst().orElse(null); EBomDTO dto1 = children.stream().filter(cc -> StrUtil.equals(cc.getMaterialNo(), c.getMaterialNo())).findFirst().orElse(null);
@ -163,7 +167,7 @@ public class BomCostCalculateService {
cdto.setAuxiliaryDepartmentLaborCost(cdto.getAuxiliaryDepartmentLaborCost().add(c.getAuxiliaryDepartmentLaborCost().multiply(dto1.getNum()))); cdto.setAuxiliaryDepartmentLaborCost(cdto.getAuxiliaryDepartmentLaborCost().add(c.getAuxiliaryDepartmentLaborCost().multiply(dto1.getNum())));
cdto.setAuxiliaryDepartmentExpenses(cdto.getAuxiliaryDepartmentExpenses().add(c.getAuxiliaryDepartmentExpenses().multiply(dto1.getNum()))); cdto.setAuxiliaryDepartmentExpenses(cdto.getAuxiliaryDepartmentExpenses().add(c.getAuxiliaryDepartmentExpenses().multiply(dto1.getNum())));
cdto.setPaintCost(cdto.getPaintCost().add(c.getPaintCost().multiply(dto1.getNum()))); cdto.setPaintCost(cdto.getPaintCost().add(c.getPaintCost().multiply(dto1.getNum())));
cdto.setPaintWeight(cdto.getPaintWeight().add(c.getPaintWeight().multiply(dto1.getUnitWeight()))); cdto.setPaintWeight(cdto.getPaintWeight().add(c.getPaintWeight().multiply(dto1.getNum())));
if (CollectionUtil.isNotEmpty(c.getProductionCosts())) { if (CollectionUtil.isNotEmpty(c.getProductionCosts())) {
c.getProductionCosts().forEach(pc -> { c.getProductionCosts().forEach(pc -> {
ProductionCostDTO pdto = cdto.getProductionCosts().parallelStream() ProductionCostDTO pdto = cdto.getProductionCosts().parallelStream()
@ -197,7 +201,7 @@ public class BomCostCalculateService {
List<EBomDTO> children = datas.stream() List<EBomDTO> children = datas.stream()
.filter(d -> StrUtil.equals(d.getParentMaterialNo(), dto.getMaterialNo())) .filter(d -> StrUtil.equals(d.getParentMaterialNo(), dto.getMaterialNo()))
.collect(Collectors.toList()); .collect(Collectors.toList());
children.parallelStream().forEach(c -> calculateBom(month, false, c, datas, config, result)); children.parallelStream().forEach(c -> calculateBom(rootMaterialNo, month, false, c, datas, config, result));
} }
return cdto; return cdto;
} }
@ -232,7 +236,7 @@ public class BomCostCalculateService {
return productionCosts; return productionCosts;
} }
private BigDecimal calculatePaintCost(EBomDTO dto, String month) { private BigDecimal calculatePaintCost(String rootMaterialNo, EBomDTO dto, String month) {
// PaintCostConfigEntity entity = paintCostConfigService.getCost(dto.getRawMaterialGroup()); // PaintCostConfigEntity entity = paintCostConfigService.getCost(dto.getRawMaterialGroup());
// return Optional.ofNullable(entity).map(PaintCostConfigEntity::getCost).orElse(BigDecimal.ZERO); // return Optional.ofNullable(entity).map(PaintCostConfigEntity::getCost).orElse(BigDecimal.ZERO);
BigDecimal price = null; BigDecimal price = null;
@ -240,21 +244,31 @@ public class BomCostCalculateService {
PaintCostConfigHistoryEntity history = paintCostConfigHistoryService.getCost(dto.getRawMaterialGroup(), month); PaintCostConfigHistoryEntity history = paintCostConfigHistoryService.getCost(dto.getRawMaterialGroup(), month);
if (Objects.nonNull(history)) { if (Objects.nonNull(history)) {
price = history.getCost(); price = history.getCost();
log.info("{},{},油漆计算:价格:{}(使用{}数据)", rootMaterialNo, dto.getMaterialNo(), price.toPlainString(), month);
} }
} }
if (Objects.isNull(price)) { if (Objects.isNull(price)) {
PaintCostConfigEntity entity = paintCostConfigService.getCost(dto.getRawMaterialGroup()); PaintCostConfigEntity entity = paintCostConfigService.getCost(dto.getRawMaterialGroup());
if (Objects.nonNull(entity)) { if (Objects.nonNull(entity)) {
price = entity.getCost(); price = entity.getCost();
log.info("{},{},油漆计算:价格:{}(使用最新数据)", rootMaterialNo, dto.getMaterialNo(), price.toPlainString());
} else { } else {
price = BigDecimal.ZERO; log.info("{},{},油漆计算:未配置油漆价格", rootMaterialNo, dto.getMaterialNo());
} }
} }
// VUtils.isTure(Objects.isNull(dto.getUnitWeight())).throwMessage(dto.getMaterialNo() + "未设置单重,无法计算油漆价格"); // VUtils.isTure(Objects.isNull(dto.getUnitWeight())).throwMessage(dto.getMaterialNo() + "未设置单重,无法计算油漆价格");
if (Objects.isNull(dto.getUnitWeight())) { // if (Objects.isNull(dto.getUnitWeight())) {
// log.info("{},{},油漆计算:未设置重量", rootMaterialNo, dto.getMaterialNo());
// return BigDecimal.ZERO;
// }
if (Objects.nonNull(price)) {
log.info("{},{},油漆计算:重量{}", rootMaterialNo, dto.getMaterialNo(), dto.getNum().toPlainString());
price = BigDecimalUtil.multiply(price, dto.getNum());
log.info("{},{},油漆计算:费用{}", rootMaterialNo, dto.getMaterialNo(), price.toPlainString());
return price;
} else {
return BigDecimal.ZERO; return BigDecimal.ZERO;
} }
return BigDecimalUtil.multiply(price, dto.getUnitWeight());
} }
private BigDecimal calculateWorkshopOfficeExpenses(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) { private BigDecimal calculateWorkshopOfficeExpenses(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
@ -350,20 +364,24 @@ public class BomCostCalculateService {
if (StrUtil.isNotBlank(month)) { if (StrUtil.isNotBlank(month)) {
SteelsCostConfigHistoryEntity history = steelsCostConfigHistoryService.getCost(dto.getRawMaterialGroup(), month); SteelsCostConfigHistoryEntity history = steelsCostConfigHistoryService.getCost(dto.getRawMaterialGroup(), month);
if (Objects.nonNull(history)) { if (Objects.nonNull(history)) {
log.info("{},计算损耗:损耗{}({}数据)", dto.getMaterialNo(), history.getWastage().toPlainString(), month);
return history.getWastage(); return history.getWastage();
} }
} }
SteelsCostConfigEntity steelsCostConfigEntity = steelsCostConfigService.getCost(dto.getRawMaterialGroup()); SteelsCostConfigEntity steelsCostConfigEntity = steelsCostConfigService.getCost(dto.getRawMaterialGroup());
if (Objects.nonNull(steelsCostConfigEntity)) { if (Objects.nonNull(steelsCostConfigEntity)) {
log.info("{},计算损耗:损耗{}", dto.getMaterialNo(), steelsCostConfigEntity.getWastage().toPlainString());
return steelsCostConfigEntity.getWastage(); return steelsCostConfigEntity.getWastage();
} else { } else {
return null; log.info("{},计算损耗:损耗0", dto.getMaterialNo());
return BigDecimal.ZERO;
} }
} }
private BigDecimal calculateWasteCost(EBomDTO dto, String month) { private BigDecimal calculateWasteCost(EBomDTO dto, String month) {
//是钢材 //是钢材
BigDecimal price = Optional.ofNullable(dto.getMaterialPrice()).orElse(BigDecimal.ZERO); BigDecimal price = Optional.ofNullable(dto.getMaterialPrice()).orElse(BigDecimal.ZERO);
log.info("{},计算损耗:价格{}", dto.getMaterialNo(), price.toPlainString());
BigDecimal wastage = BigDecimal.ZERO; BigDecimal wastage = BigDecimal.ZERO;
if (StrUtil.isNotBlank(dto.getRawMaterialGroup())) { if (StrUtil.isNotBlank(dto.getRawMaterialGroup())) {
// SteelsCostConfigEntity steelsCostConfigEntity = steelsCostConfigService.getCost(dto.getRawMaterialGroup()); // SteelsCostConfigEntity steelsCostConfigEntity = steelsCostConfigService.getCost(dto.getRawMaterialGroup());
@ -371,9 +389,11 @@ public class BomCostCalculateService {
//// price = Optional.ofNullable(steelsCostConfigEntity.getCost()).orElse(BigDecimal.ZERO); //// price = Optional.ofNullable(steelsCostConfigEntity.getCost()).orElse(BigDecimal.ZERO);
// wastage = Optional.ofNullable(steelsCostConfigEntity.getWastage()).orElse(BigDecimal.ZERO); // wastage = Optional.ofNullable(steelsCostConfigEntity.getWastage()).orElse(BigDecimal.ZERO);
// } // }
wastage = Optional.ofNullable(getWastage(dto, month)).orElse(BigDecimal.ZERO); wastage = getWastage(dto, month);
} }
return price.multiply(wastage.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP)); price = price.multiply(wastage.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP));
log.info("{},计算损耗:费用{}", dto.getMaterialNo(), price.toPlainString());
return price;
} }
private String buildKey(EBomDTO dto) { private String buildKey(EBomDTO dto) {

View File

@ -3,7 +3,7 @@ nacos:
spring: spring:
redis: redis:
database: 2 database: 2
host: 192.168.0.194 host: 192.168.0.191
password: password:
port: 6379 port: 6379
timeout: 0 timeout: 0

View File

@ -80,8 +80,7 @@
<select id="getInfos" resultType="com.nflg.product.technology.pojo.dto.EBomDTO"> <select id="getInfos" resultType="com.nflg.product.technology.pojo.dto.EBomDTO">
select m.row_id AS 'materialRowId',m.material_no AS 'materialNo',m.drawing_no AS 'drawingNo' select m.row_id AS 'materialRowId',m.material_no AS 'materialNo',m.drawing_no AS 'drawingNo'
,m.material_desc AS 'materialDesc',m.material_unit AS 'materialUnit' ,m.material_desc AS 'materialDesc',m.material_unit AS 'materialUnit',m.material_category_code AS
,CONVERT(m.material_weight, DECIMAL(12,4)) AS 'unitWeight',m.material_category_code AS
'materialCategoryCode',m.material_price AS 'materialPrice' 'materialCategoryCode',m.material_price AS 'materialPrice'
,c.rel_category_code AS 'relCategoryCode',c.category_name AS 'categoryName' ,c.rel_category_code AS 'relCategoryCode',c.category_name AS 'categoryName'
,m.raw_material_group AS 'rawMaterialGroup',m.material_stock AS 'inventory',t.plan_delivery_time AS 'leadTime' ,m.raw_material_group AS 'rawMaterialGroup',m.material_stock AS 'inventory',t.plan_delivery_time AS 'leadTime'