docs: 添加注释
This commit is contained in:
parent
34ccf46e7f
commit
e115e52676
|
|
@ -147,8 +147,14 @@ public class EBomCostCacheDTO implements Serializable {
|
|||
*/
|
||||
public BigDecimal materialPrice;
|
||||
|
||||
/**
|
||||
* 采购类型是否是E50
|
||||
*/
|
||||
private boolean purchaseTypeIsE50;
|
||||
|
||||
/**
|
||||
* 采购类型是否是F
|
||||
*/
|
||||
private boolean purchaseTypeIsF;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算BOM(Bill 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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue