docs: 添加注释

This commit is contained in:
曹鹏飞 2025-04-21 15:43:13 +08:00
parent 34ccf46e7f
commit e115e52676
3 changed files with 136 additions and 1 deletions

View File

@ -147,8 +147,14 @@ public class EBomCostCacheDTO implements Serializable {
*/
public BigDecimal materialPrice;
/**
* 采购类型是否是E50
*/
private boolean purchaseTypeIsE50;
/**
* 采购类型是否是F
*/
private boolean purchaseTypeIsF;
@Override

View File

@ -76,6 +76,12 @@ public class BomCostCalculateService {
*/
private static final Duration CACHE_DURATION = Duration.ofHours(1);
/**
* 计算指定物料在指定月份的成本缓存数据
*
* @param materialNo 物料编号用于标识需要计算成本的物料
* @param month 月份格式为字符串用于指定计算成本的月份如果不为空则从历史表中获取配置信息
*/
public List<EBomCostCacheDTO> calculate(String materialNo, String month) {
VUtils.isTure(StrUtil.isBlank(materialNo)).throwMessage("物料编号不能为空");
List<EBomDTO> datas = new ArrayList<>();
@ -98,11 +104,25 @@ public class BomCostCalculateService {
return result;
}
/**
* 计算BOMBill of Materials成本并将结果缓存到指定的结果列表中
*
* @param rootMaterialNo 根物料的编号用于标识当前计算的BOM的根节点主要用于日志记录
* @param month 计算的月份用于确定成本计算的时间范围
* @param isRoot 标识当前计算的物料是否为根节点与E50逻辑相关
* @param dto 当前物料的BOM数据传输对象包含物料的基本信息和成本数据
* @param datas 所有BOM的单层数据
* @param config BOM成本计算的配置对象包含计算过程中需要的配置参数
* @param result 计算结果缓存列表用于存储每个物料的成本计算结果
* @return 返回当前物料的BOM成本计算结果类型为EBomCostCacheDTO
*/
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, month));
boolean purchaseTypeIsF = materialMainAttrService.purchaseTypeIsF(dto.getMaterialNo());
boolean purchaseTypeIsE50 = materialMainAttrService.purchaseTypeIsE50(dto.getMaterialNo());
//如果是根节点且采购类型为E50或者缓存中没有数据则进行计算
if ((isRoot && purchaseTypeIsE50) || StrUtil.isBlank(cdata)) {
//如果是根节点或者不是E50则查询工时
List<WorkingHourDTO> workingHours = isRoot || !purchaseTypeIsE50 ? processRouteTaskProcessesService.getWorkingHour(dto.getMaterialNo()) : new ArrayList<>();
log.info(StrUtil.format("{},BOM成本计算 {} 物料工时: {}", rootMaterialNo, dto.getMaterialNo(), JsonUtil.toJson(workingHours)));
EBomCostCacheDTO cdto = new EBomCostCacheDTO();
@ -113,26 +133,39 @@ public class BomCostCalculateService {
cdto.setCategoryCode(dto.getMaterialCategoryCode());
if (purchaseTypeIsF) {
cdto.setHasChildren(false);
// 采购类型为F则视为外购件
cdto.setPurchasedParts(true);
// 计算采购成本
cdto.setPurchasedPartsCost(calculatePurchasedPartsCost(dto));
// 计算损耗成本
cdto.setPurchasedPartsWasteCost(calculateWasteCost(dto, month));
} else {
//标准计件工资
cdto.setPieceRateSalary(calculatePieceRateSalary(dto, config, workingHours));
//福利费用
cdto.setWelfareExpenses(calculateWelfareExpenses(dto, config, workingHours));
//水电生产耗材成本
cdto.setHydropowerCost(calculateHydropowerCost(dto, config, workingHours));
//折旧成本
cdto.setDepreciationCost(calculateDepreciationCost(dto, config, workingHours));
//车间管理人工费
cdto.setWorkshopManagementLaborCost(calculateWorkshopManagementLaborCost(dto, config, workingHours));
//车间办公室费用
cdto.setWorkshopOfficeExpenses(calculateWorkshopOfficeExpenses(dto, config, workingHours));
//辅助部门人工费
cdto.setAuxiliaryDepartmentLaborCost(calculateAuxiliaryDepartmentLaborCost(dto, config, workingHours));
//辅助部门费用
cdto.setAuxiliaryDepartmentExpenses(calculateAuxiliaryDepartmentExpenses(dto, config, workingHours));
//制作成本
cdto.setProductionCosts(calculateProductionCosts(dto, config, workingHours));
//获取该物料的子节点
Set<EBomDTO> children = datas.stream()
.filter(d -> StrUtil.equals(d.getParentMaterialNo(), dto.getMaterialNo()))
.collect(Collectors.toSet());
if (CollectionUtil.isEmpty(children)) {
cdto.setHasChildren(false);
// 计算自身
//不在钢材类型列表中就是外购件
cdto.setPurchasedParts(!BomConstant.STEELS_CATEGORY_CODE.contains(dto.getMaterialCategoryCode()));
if (cdto.isPurchasedParts()) {
// 外购件只计算采购成本
@ -155,28 +188,46 @@ public class BomCostCalculateService {
List<EBomCostCacheDTO> childrenCost = children.parallelStream()
.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);
//钢材成本
cdto.setSteelsCost(cdto.getSteelsCost().add(c.getSteelsCost().multiply(dto1.getNum())));
//钢材损耗
cdto.setSteelsWasteCost(cdto.getSteelsWasteCost().add(c.getSteelsWasteCost().multiply(dto1.getNum())));
//外购件成本
cdto.setPurchasedPartsCost(cdto.getPurchasedPartsCost().add(c.getPurchasedPartsCost().multiply(dto1.getNum())));
//外购件损耗
cdto.setPurchasedPartsWasteCost(cdto.getPurchasedPartsWasteCost().add(c.getPurchasedPartsWasteCost().multiply(dto1.getNum())));
//标准计件工资
cdto.setPieceRateSalary(cdto.getPieceRateSalary().add(c.getPieceRateSalary().multiply(dto1.getNum())));
//福利费用
cdto.setWelfareExpenses(cdto.getWelfareExpenses().add(c.getWelfareExpenses().multiply(dto1.getNum())));
//水电生产耗材成本
cdto.setHydropowerCost(cdto.getHydropowerCost().add(c.getHydropowerCost().multiply(dto1.getNum())));
//折旧成本
cdto.setDepreciationCost(cdto.getDepreciationCost().add(c.getDepreciationCost().multiply(dto1.getNum())));
//车间管理人工费
cdto.setWorkshopManagementLaborCost(cdto.getWorkshopManagementLaborCost().add(c.getWorkshopManagementLaborCost().multiply(dto1.getNum())));
//车间办公室费用
cdto.setWorkshopOfficeExpenses(cdto.getWorkshopOfficeExpenses().add(c.getWorkshopOfficeExpenses().multiply(dto1.getNum())));
//辅助部门人工费
cdto.setAuxiliaryDepartmentLaborCost(cdto.getAuxiliaryDepartmentLaborCost().add(c.getAuxiliaryDepartmentLaborCost().multiply(dto1.getNum())));
//辅助部门费用
cdto.setAuxiliaryDepartmentExpenses(cdto.getAuxiliaryDepartmentExpenses().add(c.getAuxiliaryDepartmentExpenses().multiply(dto1.getNum())));
if (StrUtil.equalsIgnoreCase(dto1.getMaterialUnit(), "kg")) {
//设置油漆重量,数量作为重量
cdto.setPaintWeight(cdto.getPaintWeight().add(dto1.getNum()));
//油漆成本
cdto.setPaintCost(cdto.getPaintCost().add(calculatePaintCost(rootMaterialNo, dto1, month)));
} else {
//设置油漆重量
cdto.setPaintWeight(cdto.getPaintWeight().add(c.getPaintWeight().multiply(dto1.getNum())));
//油漆成本
cdto.setPaintCost(cdto.getPaintCost().add(c.getPaintCost().multiply(dto1.getNum())));
}
if (CollectionUtil.isNotEmpty(c.getProductionCosts())) {
//将制作成本根据工艺工序进行分组累加
c.getProductionCosts().forEach(pc -> {
ProductionCostDTO pdto = cdto.getProductionCosts().parallelStream()
.filter(p -> StrUtil.equals(p.getName(), pc.getName()))
@ -196,6 +247,7 @@ public class BomCostCalculateService {
}
log.debug(StrUtil.format("BOM成本计算 {} 实时计算", dto.getMaterialNo()));
result.add(cdto);
//如果不是E50且不是根节点则缓存数据
if (!(isRoot && purchaseTypeIsE50)) {
cdata = JsonUtil.toJson(cdto);
//log.debug(cdata);
@ -207,6 +259,7 @@ public class BomCostCalculateService {
//log.debug(cdata);
EBomCostCacheDTO cdto = JsonUtil.fromJson(cdata, EBomCostCacheDTO.class);
result.add(cdto);
//如果不是F则继续计算子节点
if (!purchaseTypeIsF) {
List<EBomDTO> children = datas.parallelStream()
.filter(d -> StrUtil.equals(d.getParentMaterialNo(), dto.getMaterialNo()))
@ -217,6 +270,9 @@ public class BomCostCalculateService {
}
}
/**
* 计算制作成本
*/
private List<ProductionCostDTO> calculateProductionCosts(EBomDTO d, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
List<ProductionCostDTO> productionCosts = new ArrayList<>();
for (VirtualWorkingItemVO vw : config.getVirtualWorkings()) {
@ -246,6 +302,14 @@ public class BomCostCalculateService {
return productionCosts;
}
/**
* 计算油漆成本
*
* @param rootMaterialNo 根物料编号
* @param dto 物料信息
* @param month 月份
* @return 成本
*/
private BigDecimal calculatePaintCost(String rootMaterialNo, EBomDTO dto, String month) {
if (!StrUtil.equalsIgnoreCase(StrUtil.trim(dto.getMaterialUnit()), "kg")) {
log.info("{},{},油漆计算:单位不符合要求({})", rootMaterialNo, dto.getMaterialNo(), dto.getMaterialUnit());
@ -253,6 +317,7 @@ public class BomCostCalculateService {
}
BigDecimal price = null;
if (StrUtil.isNotBlank(month)) {
//从历史表获取配置
PaintCostConfigHistoryEntity history = paintCostConfigHistoryService.getCost(dto.getRawMaterialGroup(), month);
if (Objects.nonNull(history)) {
price = history.getCost();
@ -260,6 +325,7 @@ public class BomCostCalculateService {
}
}
if (Objects.isNull(price)) {
//从最新表获取配置
PaintCostConfigEntity entity = paintCostConfigService.getCost(dto.getRawMaterialGroup());
if (Objects.nonNull(entity)) {
price = entity.getCost();
@ -280,6 +346,9 @@ public class BomCostCalculateService {
}
}
/**
* 车间办公室费用
*/
private BigDecimal calculateWorkshopOfficeExpenses(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
BigDecimal cost = BigDecimal.ZERO;
for (VirtualWorkingItemVO vw : config.getVirtualWorkings()) {
@ -288,6 +357,9 @@ public class BomCostCalculateService {
return cost;
}
/**
* 计算辅助部门费用
*/
private BigDecimal calculateAuxiliaryDepartmentExpenses(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
BigDecimal cost = BigDecimal.ZERO;
for (VirtualWorkingItemVO vw : config.getVirtualWorkings()) {
@ -296,6 +368,9 @@ public class BomCostCalculateService {
return cost;
}
/**
* 计算辅助部门人工成本
*/
private BigDecimal calculateAuxiliaryDepartmentLaborCost(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
BigDecimal cost = BigDecimal.ZERO;
for (VirtualWorkingItemVO vw : config.getVirtualWorkings()) {
@ -304,6 +379,9 @@ public class BomCostCalculateService {
return cost;
}
/**
* 计算车间管理人工成本
*/
private BigDecimal calculateWorkshopManagementLaborCost(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
BigDecimal cost = BigDecimal.ZERO;
for (VirtualWorkingItemVO vw : config.getVirtualWorkings()) {
@ -312,6 +390,9 @@ public class BomCostCalculateService {
return cost;
}
/**
* 计算折旧成本
*/
private BigDecimal calculateDepreciationCost(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
BigDecimal cost = BigDecimal.ZERO;
for (VirtualWorkingItemVO vw : config.getVirtualWorkings()) {
@ -320,6 +401,9 @@ public class BomCostCalculateService {
return cost;
}
/**
* 计算水电生产耗材成本
*/
private BigDecimal calculateHydropowerCost(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
BigDecimal cost = BigDecimal.ZERO;
for (VirtualWorkingItemVO vw : config.getVirtualWorkings()) {
@ -328,6 +412,9 @@ public class BomCostCalculateService {
return cost;
}
/**
* 根据工序名称获取工时
*/
private BigDecimal getGsForWorkingType(EBomDTO dto, List<WorkingHourDTO> workHours, VirtualWorkingItemVO vw) {
String key = dto.getMaterialNo() + '-' + StrUtil.trim(vw.getWorkingTypeName());
return workHours.stream()
@ -337,14 +424,26 @@ public class BomCostCalculateService {
.getWorkHours();
}
/**
* 计算福利费用
*/
private BigDecimal calculateWelfareExpenses(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
return getTGS(dto, config, workHours).multiply(Optional.ofNullable(config.getManday().getBenefit()).orElse(BigDecimal.ZERO));
}
/**
* 计算标准计件工资
* @param dto 物料信息
* @param config 计算参数
* @param workHours 工时信息
*/
private BigDecimal calculatePieceRateSalary(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
return getTGS(dto, config, workHours).multiply(Optional.ofNullable(config.getManday().getHourlyWages()).orElse(BigDecimal.ZERO));
}
/**
* 计算总工时
*/
private BigDecimal getTGS(EBomDTO dto, BomCostCalculateConfig config, List<WorkingHourDTO> workHours) {
BigDecimal gs = BigDecimal.ZERO;
for (VirtualWorkingItemVO vw : config.getVirtualWorkings()) {
@ -353,10 +452,16 @@ public class BomCostCalculateService {
return gs;
}
/**
* 计算外购件费用
*/
private BigDecimal calculatePurchasedPartsCost(EBomDTO dto) {
return Optional.ofNullable(dto.getMaterialPrice()).orElse(BigDecimal.ZERO);
}
/**
* 计算钢材价格
*/
private BigDecimal calculateSteelsCost(EBomDTO dto) {
//是钢材
BigDecimal price = Optional.ofNullable(dto.getMaterialPrice()).orElse(BigDecimal.ZERO);
@ -369,6 +474,9 @@ public class BomCostCalculateService {
return price;
}
/**
* 获取损耗
*/
private BigDecimal getWastage(EBomDTO dto, String month) {
if (StrUtil.isNotBlank(month)) {
SteelsCostConfigHistoryEntity history = steelsCostConfigHistoryService.getCost(dto.getRawMaterialGroup(), month);
@ -387,8 +495,10 @@ public class BomCostCalculateService {
}
}
/**
* 计算损耗
*/
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;
@ -405,12 +515,18 @@ public class BomCostCalculateService {
return price;
}
/**
* 生成缓存key
*/
private String buildKey(EBomDTO dto, String month) {
return StrUtil.format("technology:cost:{}:{}:{}", dto.getMaterialNo()
, StrUtil.isBlank(dto.getCurrentVersion()) ? "A00" : dto.getCurrentVersion()
, StrUtil.isBlank(month) ? DateUtil.format(LocalDateTime.now(), "yyyyMM") : month);
}
/**
* 获取子物料
*/
private void getChildren(String materialNo, List<EBomDTO> datas, String month) {
EBomParentEntity parent = ebomService.getParent(materialNo);
if (Objects.nonNull(parent)) {
@ -434,6 +550,9 @@ public class BomCostCalculateService {
return dto;
}
/**
* 设置物料价格
*/
private void setMaterialPrice(EBomDTO dto, String month) {
if (StrUtil.isNotBlank(month)) {
BigDecimal price = materialMainPriceService.getPrice(dto.getMaterialNo(), month);

View File

@ -17,6 +17,11 @@ public class MaterialMainAttrService extends ServiceImpl<MaterialMainAttrMapper,
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 判断物料采购类型是否为F类
*
* @param materialNo 物料编码
*/
public boolean purchaseTypeIsF(String materialNo) {
String key = "technology:materialNo:purchaseTypeIsF";
HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
@ -37,6 +42,11 @@ public class MaterialMainAttrService extends ServiceImpl<MaterialMainAttrMapper,
return (boolean) data;
}
/**
* 判断物料采购类型是否为E50类
*
* @param materialNo 物料编码
*/
public boolean purchaseTypeIsE50(String materialNo) {
String key = "technology:materialNo:purchaseTypeIsE50";
HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();