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 java.math.BigDecimal;
import java.util.Objects;
@Data
public class EBomDTO {
@ -82,15 +81,15 @@ public class EBomDTO {
private Long ebomRowId;
/**
* 单重
*/
private BigDecimal unitWeight;
public BigDecimal getUnitWeight() {
if (Objects.nonNull(unitWeight)) {
return unitWeight;
}
return BigDecimal.ZERO;
}
// /**
// * 单重
// */
// private BigDecimal unitWeight;
//
// public BigDecimal getUnitWeight() {
// if (Objects.nonNull(unitWeight)) {
// return unitWeight;
// }
// return BigDecimal.ZERO;
// }
}

View File

@ -92,11 +92,11 @@ public class BomCostCalculateService {
config.setManday(manday);
config.setVirtualWorkings(virtualWorkingService.listDTO());
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;
}
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));
boolean purchaseTypeIsF = materialMainAttrService.purchaseTypeIsF(dto.getMaterialNo());
boolean purchaseTypeIsE50 = materialMainAttrService.purchaseTypeIsE50(dto.getMaterialNo());
@ -117,8 +117,6 @@ public class BomCostCalculateService {
cdto.setWorkshopOfficeExpenses(calculateWorkshopOfficeExpenses(dto, config, workingHours));
cdto.setAuxiliaryDepartmentLaborCost(calculateAuxiliaryDepartmentLaborCost(dto, config, workingHours));
cdto.setAuxiliaryDepartmentExpenses(calculateAuxiliaryDepartmentExpenses(dto, config, workingHours));
cdto.setPaintCost(calculatePaintCost(dto, month));
cdto.setPaintWeight(dto.getUnitWeight());
cdto.setProductionCosts(calculateProductionCosts(dto, config, workingHours));
if (purchaseTypeIsF) {
cdto.setHasChildren(false);
@ -135,19 +133,25 @@ public class BomCostCalculateService {
if (cdto.isPurchasedParts()) {
// 外购件只计算采购成本
cdto.setPurchasedPartsCost(calculatePurchasedPartsCost(dto));
// 计算损耗成本
cdto.setWasteCost(calculateWasteCost(dto, month));
} else {
// 非外购件计算材料成本和制作成本
// 计算材料成本
cdto.setSteelsCost(calculateSteelsCost(dto));
// 计算损耗成本
cdto.setWasteCost(calculateWasteCost(dto, month));
cdto.setPaintCost(calculatePaintCost(rootMaterialNo, dto, month));
if (cdto.getPaintCost().compareTo(BigDecimal.ZERO) > 0) {
cdto.setPaintWeight(dto.getNum());
}
}
} else {
cdto.setHasChildren(true);
cdto.setPurchasedParts(false);
//计算子级成本
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());
for (EBomCostCacheDTO c : childrenCost) {
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.setAuxiliaryDepartmentExpenses(cdto.getAuxiliaryDepartmentExpenses().add(c.getAuxiliaryDepartmentExpenses().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())) {
c.getProductionCosts().forEach(pc -> {
ProductionCostDTO pdto = cdto.getProductionCosts().parallelStream()
@ -197,7 +201,7 @@ public class BomCostCalculateService {
List<EBomDTO> children = datas.stream()
.filter(d -> StrUtil.equals(d.getParentMaterialNo(), dto.getMaterialNo()))
.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;
}
@ -232,7 +236,7 @@ public class BomCostCalculateService {
return productionCosts;
}
private BigDecimal calculatePaintCost(EBomDTO dto, String month) {
private BigDecimal calculatePaintCost(String rootMaterialNo, EBomDTO dto, String month) {
// PaintCostConfigEntity entity = paintCostConfigService.getCost(dto.getRawMaterialGroup());
// return Optional.ofNullable(entity).map(PaintCostConfigEntity::getCost).orElse(BigDecimal.ZERO);
BigDecimal price = null;
@ -240,21 +244,31 @@ public class BomCostCalculateService {
PaintCostConfigHistoryEntity history = paintCostConfigHistoryService.getCost(dto.getRawMaterialGroup(), month);
if (Objects.nonNull(history)) {
price = history.getCost();
log.info("{},{},油漆计算:价格:{}(使用{}数据)", rootMaterialNo, dto.getMaterialNo(), price.toPlainString(), month);
}
}
if (Objects.isNull(price)) {
PaintCostConfigEntity entity = paintCostConfigService.getCost(dto.getRawMaterialGroup());
if (Objects.nonNull(entity)) {
price = entity.getCost();
log.info("{},{},油漆计算:价格:{}(使用最新数据)", rootMaterialNo, dto.getMaterialNo(), price.toPlainString());
} else {
price = BigDecimal.ZERO;
log.info("{},{},油漆计算:未配置油漆价格", rootMaterialNo, 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 BigDecimalUtil.multiply(price, dto.getUnitWeight());
}
private BigDecimal calculateWorkshopOfficeExpenses(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
@ -350,20 +364,24 @@ public class BomCostCalculateService {
if (StrUtil.isNotBlank(month)) {
SteelsCostConfigHistoryEntity history = steelsCostConfigHistoryService.getCost(dto.getRawMaterialGroup(), month);
if (Objects.nonNull(history)) {
log.info("{},计算损耗:损耗{}({}数据)", dto.getMaterialNo(), history.getWastage().toPlainString(), month);
return history.getWastage();
}
}
SteelsCostConfigEntity steelsCostConfigEntity = steelsCostConfigService.getCost(dto.getRawMaterialGroup());
if (Objects.nonNull(steelsCostConfigEntity)) {
log.info("{},计算损耗:损耗{}", dto.getMaterialNo(), steelsCostConfigEntity.getWastage().toPlainString());
return steelsCostConfigEntity.getWastage();
} else {
return null;
log.info("{},计算损耗:损耗0", dto.getMaterialNo());
return BigDecimal.ZERO;
}
}
private BigDecimal calculateWasteCost(EBomDTO dto, String month) {
//是钢材
BigDecimal price = Optional.ofNullable(dto.getMaterialPrice()).orElse(BigDecimal.ZERO);
log.info("{},计算损耗:价格{}", dto.getMaterialNo(), price.toPlainString());
BigDecimal wastage = BigDecimal.ZERO;
if (StrUtil.isNotBlank(dto.getRawMaterialGroup())) {
// SteelsCostConfigEntity steelsCostConfigEntity = steelsCostConfigService.getCost(dto.getRawMaterialGroup());
@ -371,9 +389,11 @@ public class BomCostCalculateService {
//// price = Optional.ofNullable(steelsCostConfigEntity.getCost()).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) {

View File

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

View File

@ -80,8 +80,7 @@
<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'
,m.material_desc AS 'materialDesc',m.material_unit AS 'materialUnit'
,CONVERT(m.material_weight, DECIMAL(12,4)) AS 'unitWeight',m.material_category_code AS
,m.material_desc AS 'materialDesc',m.material_unit AS 'materialUnit',m.material_category_code AS
'materialCategoryCode',m.material_price AS 'materialPrice'
,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'