refactor(technology): 优化 BOM 成本计算逻辑
-调整了成本计算的顺序,先计算外购件成本,再计算其他成本 - 优化了缓存逻辑,只在非根节点或非外购件时才进行缓存 - 移除了不必要的注释代码 -重构了部分代码结构,提高了可读性和维护性
This commit is contained in:
parent
6beddbd2ac
commit
0fef01e0c8
|
|
@ -1,5 +1,6 @@
|
|||
package com.nflg.product.technology.api;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.nflg.product.base.core.api.BaseApi;
|
||||
import com.nflg.product.technology.pojo.query.*;
|
||||
import com.nflg.product.technology.pojo.vo.*;
|
||||
|
|
@ -104,14 +105,18 @@ public class ProductCostAnalysisApi extends BaseApi {
|
|||
BomCostMultilayerVO vo = productCostAnalysisService.getBomCostMultilayer(query.getMaterialNo(), query.getMonth());
|
||||
List<BomCostMultilayerVO> vos = new ArrayList<>();
|
||||
vos.add(vo);
|
||||
vo.getChildren().forEach(c -> add(c, vos));
|
||||
if (CollectionUtil.isNotEmpty(vo.getChildren())) {
|
||||
vo.getChildren().forEach(c -> add(c, vos));
|
||||
}
|
||||
|
||||
ExcelUtil.export(response, vos, BomCostMultilayerVO.class, query.getMaterialNo() + "组件成本(多层)", query.getMaterialNo());
|
||||
}
|
||||
|
||||
private void add(BomCostMultilayerVO child, List<BomCostMultilayerVO> vos) {
|
||||
vos.add(child);
|
||||
child.getChildren().forEach(c -> add(c, vos));
|
||||
if (CollectionUtil.isNotEmpty(child.getChildren())) {
|
||||
child.getChildren().forEach(c -> add(c, vos));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("getMaterialComposition")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import lombok.Data;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
|
|
@ -89,7 +90,7 @@ public class EBomCostCacheDTO implements Serializable {
|
|||
/**
|
||||
* 制作成本
|
||||
*/
|
||||
private List<ProductionCostDTO> productionCosts;
|
||||
private List<ProductionCostDTO> productionCosts = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 是否外购件
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
package com.nflg.product.technology.pojo.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class WorkingHourDTO implements Serializable {
|
||||
|
||||
private String materialWork;
|
||||
|
||||
private BigDecimal workHours = BigDecimal.ZERO;
|
||||
|
||||
private String factory;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import lombok.Data;
|
|||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -37,5 +36,5 @@ public class BomCostMultilayerVO extends BomCostSingleLayerVO implements Seriali
|
|||
|
||||
@ApiModelProperty("子物料列表")
|
||||
@ExcelIgnore
|
||||
private List<BomCostMultilayerVO> children = new ArrayList<>();
|
||||
private List<BomCostMultilayerVO> children;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.nflg.product.technology.pojo.vo;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.idev.excel.annotation.ExcelIgnore;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import cn.idev.excel.annotation.format.NumberFormat;
|
||||
|
|
@ -30,6 +31,10 @@ import java.math.BigDecimal;
|
|||
@ContentFontStyle(fontHeightInPoints = 10)
|
||||
public class BomCostSingleLayerVO implements Serializable {
|
||||
|
||||
@ApiModelProperty("前端使用的主键")
|
||||
@ExcelIgnore
|
||||
private String key = IdUtil.fastUUID();
|
||||
|
||||
@ApiModelProperty("物料编码")
|
||||
@ExcelProperty("物料编码")
|
||||
@ColumnWidth(15)
|
||||
|
|
|
|||
|
|
@ -109,16 +109,6 @@ public class BomCostCalculateService {
|
|||
cdto.setMaterialNo(dto.getMaterialNo());
|
||||
cdto.setMaterialPrice(dto.getMaterialPrice());
|
||||
cdto.setCategoryCode(dto.getMaterialCategoryCode());
|
||||
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));
|
||||
// cdto.setPaintCost(calculatePaintCost(rootMaterialNo, dto, month));
|
||||
if (purchaseTypeIsF) {
|
||||
cdto.setHasChildren(false);
|
||||
cdto.setPurchasedParts(true);
|
||||
|
|
@ -126,6 +116,15 @@ public class BomCostCalculateService {
|
|||
// 计算损耗成本
|
||||
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));
|
||||
List<EBomDTO> children = datas.stream()
|
||||
.filter(d -> StrUtil.equals(d.getParentMaterialNo(), dto.getMaterialNo()))
|
||||
.collect(Collectors.toList());
|
||||
|
|
@ -168,14 +167,6 @@ public class BomCostCalculateService {
|
|||
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())));
|
||||
// cdto.setPaintCost(cdto.getPaintCost().add(c.getPaintCost().multiply(dto1.getNum())));
|
||||
// if (c.getPaintCost().compareTo(BigDecimal.ZERO) > 0) {
|
||||
// if (cdto.getPaintWeight().compareTo(BigDecimal.ZERO) == 0) {
|
||||
// cdto.setPaintWeight(cdto.getPaintWeight().add(dto1.getNum()));
|
||||
// } else {
|
||||
// cdto.setPaintWeight(cdto.getPaintWeight().add(c.getPaintWeight().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)));
|
||||
|
|
@ -203,9 +194,11 @@ public class BomCostCalculateService {
|
|||
}
|
||||
log.debug(StrUtil.format("BOM成本计算 {} 实时计算", dto.getMaterialNo()));
|
||||
result.add(cdto);
|
||||
cdata = JsonUtil.toJson(cdto);
|
||||
//log.debug(cdata);
|
||||
redisTemplate.opsForValue().set(buildKey(dto), cdata, CACHE_DURATION);
|
||||
if (!(isRoot && purchaseTypeIsE50)) {
|
||||
cdata = JsonUtil.toJson(cdto);
|
||||
//log.debug(cdata);
|
||||
redisTemplate.opsForValue().set(buildKey(dto), cdata, CACHE_DURATION);
|
||||
}
|
||||
return cdto;
|
||||
} else {
|
||||
log.debug(StrUtil.format("BOM成本计算 {} 从缓存读取", dto.getMaterialNo()));
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.nflg.product.technology.pojo.entity.EBomParentEntity;
|
|||
import com.nflg.product.technology.util.JsonUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.core.BoundZSetOperations;
|
||||
import org.springframework.data.redis.core.BoundListOperations;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.SessionCallback;
|
||||
|
|
@ -15,7 +15,10 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
|
|
@ -74,7 +77,8 @@ public class EBomService {
|
|||
|
||||
public List<EBomChildEntity> getChildren(long parentRowId) {
|
||||
String key = buildChildCacheKey(parentRowId);
|
||||
Set<String> kvs = redisTemplate.opsForZSet().range(key, 0, -1);
|
||||
// Set<String> kvs = redisTemplate.opsForZSet().range(key, 0, -1);
|
||||
List<String> kvs = redisTemplate.opsForList().range(key, 0, -1);
|
||||
List<EBomChildEntity> entities = null;
|
||||
if (CollectionUtil.isEmpty(kvs)) {
|
||||
entities = ebomChildService.lambdaQuery()
|
||||
|
|
@ -82,16 +86,28 @@ public class EBomService {
|
|||
.orderByAsc(EBomChildEntity::getOrderNumber)
|
||||
.list();
|
||||
if (CollectionUtil.isNotEmpty(entities)) {
|
||||
Map<String, Double> scoreMembers = new HashMap<>();
|
||||
for (EBomChildEntity entity : entities) {
|
||||
scoreMembers.put(JsonUtil.toJson(entity), Double.valueOf(entity.getOrderNumber()));
|
||||
}
|
||||
// Map<String, Double> scoreMembers = new HashMap<>();
|
||||
// for (EBomChildEntity entity : entities) {
|
||||
// scoreMembers.put(JsonUtil.toJson(entity), Double.valueOf(entity.getOrderNumber()));
|
||||
// }
|
||||
// redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||
// @Override
|
||||
// public Object execute(RedisOperations operations) throws DataAccessException {
|
||||
// BoundZSetOperations<String, String> zSetOps = operations.boundZSetOps(key);
|
||||
// scoreMembers.forEach(zSetOps::add);
|
||||
// zSetOps.expire(CACHE_DURATION_CHILD);
|
||||
// return null;
|
||||
// }
|
||||
// });
|
||||
List<EBomChildEntity> finalEntities = entities;
|
||||
redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||
@Override
|
||||
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||
BoundZSetOperations<String, String> zSetOps = operations.boundZSetOps(key);
|
||||
scoreMembers.forEach(zSetOps::add);
|
||||
zSetOps.expire(CACHE_DURATION_CHILD);
|
||||
BoundListOperations<String, String> listOperations = redisTemplate.boundListOps(key);
|
||||
finalEntities.forEach((v) -> {
|
||||
listOperations.rightPush(JsonUtil.toJson(v));
|
||||
});
|
||||
listOperations.expire(CACHE_DURATION_CHILD);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
package com.nflg.product.technology.service;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.nflg.product.technology.mapper.master.ProcessRouteTaskProcessesMapper;
|
||||
import com.nflg.product.technology.pojo.dto.WorkingHourDTO;
|
||||
import com.nflg.product.technology.pojo.entity.ProcessRouteTaskProcessesEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
|
@ -22,6 +22,14 @@ import java.util.Optional;
|
|||
public class ProcessRouteTaskProcessesService extends ServiceImpl<ProcessRouteTaskProcessesMapper, ProcessRouteTaskProcessesEntity> {
|
||||
|
||||
public List<WorkingHourDTO> getWorkingHour(String materialNo) {
|
||||
return Optional.ofNullable(this.baseMapper.getWorkingHour(materialNo)).orElse(Collections.emptyList());
|
||||
List<WorkingHourDTO> all = this.baseMapper.getWorkingHour(materialNo);
|
||||
List<WorkingHourDTO> temps1010 = all.stream().filter(t -> StrUtil.equals("1010", t.getFactory())).collect(Collectors.toList());
|
||||
all.removeAll(temps1010);
|
||||
all.forEach(temp -> {
|
||||
if (temps1010.stream().noneMatch(data -> data.getMaterialWork().equals(temp.getMaterialWork()))) {
|
||||
temps1010.add(temp);
|
||||
}
|
||||
});
|
||||
return temps1010;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,11 @@ public class ProductCostAnalysisService {
|
|||
vo.setHasChildren(true);
|
||||
buildMultilayerChildren(parent.getRowId(), vo, materials, datas, false);
|
||||
}
|
||||
return Convert.toList(BomCostSingleLayerVO.class, vo.getChildren());
|
||||
if (CollectionUtil.isEmpty(vo.getChildren())) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return Convert.toList(BomCostSingleLayerVO.class, vo.getChildren());
|
||||
}
|
||||
}
|
||||
|
||||
public BomCostMultilayerVO getBomCostMultilayer(String materialNo, String month) {
|
||||
|
|
@ -151,6 +155,9 @@ public class ProductCostAnalysisService {
|
|||
cvo.setTotalCost(cvo.getPrice().add(ccost.getSteelsWasteCost()).add(ccost.getPurchasedPartsWasteCost()).multiply(cvo.getNum()));
|
||||
}
|
||||
}
|
||||
if (CollectionUtil.isEmpty(pvo.getChildren())) {
|
||||
pvo.setChildren(new ArrayList<>());
|
||||
}
|
||||
pvo.getChildren().add(cvo);
|
||||
EBomParentEntity cparent = ebomService.getParent(child.getMaterialNo());
|
||||
if (Objects.nonNull(cparent) && !materialMainAttrService.purchaseTypeIsF(cparent.getMaterialNo())) {
|
||||
|
|
|
|||
|
|
@ -11,14 +11,23 @@
|
|||
|
||||
<select id="getWorkingHour" resultType="com.nflg.product.technology.pojo.dto.WorkingHourDTO">
|
||||
SELECT CONCAT_WS('-', rt.material_no, t.`name`) AS 'material_work',
|
||||
SUM(IFNULL(r.two_work_hours, 0)) work_hours
|
||||
SUM(IFNULL(r.two_work_hours, 0)) work_hours,
|
||||
w.factory
|
||||
FROM t_technology_working_type t
|
||||
INNER JOIN t_process_workcenter w ON w.working_type = t.`code`
|
||||
INNER JOIN t_process_route_task_processes r ON r.work_center = w.work_center
|
||||
INNER JOIN t_process_route_task rt ON r.task_row_id = rt.row_id
|
||||
WHERE w.factory = '1010'
|
||||
AND rt.material_no = #{materialNo}
|
||||
AND r.two_work_hours > 0
|
||||
GROUP BY rt.material_no, t.`name`
|
||||
GROUP BY rt.material_no, t.`name`, w.factory
|
||||
</select>
|
||||
|
||||
<!-- <select id="getWorkingHour" resultType="com.nflg.product.technology.pojo.dto.WorkingHourTempDTO">-->
|
||||
<!-- SELECT rt.material_no, w.factory, t.`name`, IFNULL(r.two_work_hours, 0) AS `workHours`-->
|
||||
<!-- FROM t_technology_working_type t-->
|
||||
<!-- INNER JOIN t_process_workcenter w ON w.working_type = t.`code`-->
|
||||
<!-- INNER JOIN t_process_route_task_processes r ON r.work_center = w.work_center-->
|
||||
<!-- INNER JOIN t_process_route_task rt ON r.task_row_id = rt.row_id-->
|
||||
<!-- WHERE rt.material_no = #{materialNo}-->
|
||||
<!-- </select>-->
|
||||
</mapper>
|
||||
|
|
|
|||
Loading…
Reference in New Issue