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

-优化了工时获取逻辑,提高效率
- 改进了油漆成本计算方式,增加对非 kg单位的处理
-调整了日志输出级别,增加必要的日志记录
-重构了 EBomCostCacheDTO 结构,更准确地表示各种成本
- 优化了产品成本分析相关代码,确保成本计算准确性- 调整了虚拟工时相关实体和 Mapper,细化成本分类
This commit is contained in:
曹鹏飞 2025-03-28 19:15:27 +08:00
parent 3e9626a671
commit 6beddbd2ac
10 changed files with 113 additions and 58 deletions

View File

@ -2,7 +2,6 @@ package com.nflg.product.technology.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.client.RestTemplate;
@Configuration

View File

@ -22,14 +22,20 @@ public class EBomCostCacheDTO implements Serializable {
private BigDecimal steelsCost = BigDecimal.ZERO;
/**
* 损耗成本
* 钢材损耗成本
*/
private BigDecimal wasteCost = BigDecimal.ZERO;
private BigDecimal steelsWasteCost = BigDecimal.ZERO;
/**
* 外购件成本
*/
private BigDecimal purchasedPartsCost = BigDecimal.ZERO;
/**
* 外购件损耗成本
*/
private BigDecimal purchasedPartsWasteCost = BigDecimal.ZERO;
/**
* 标准计件工资
*/
@ -101,7 +107,7 @@ public class EBomCostCacheDTO implements Serializable {
private BigDecimal materialCost;
public BigDecimal getMaterialCost() {
return getSteelsCost().add(getPurchasedPartsCost()).add(getWasteCost());
return getSteelsCost().add(getSteelsWasteCost()).add(getPurchasedPartsCost()).add(getPurchasedPartsWasteCost());
}
/**
@ -140,6 +146,10 @@ public class EBomCostCacheDTO implements Serializable {
*/
public BigDecimal materialPrice;
private boolean purchaseTypeIsE50;
private boolean purchaseTypeIsF;
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -38,34 +38,50 @@ public class VirtualWorkingEntity extends EntityBase implements Serializable {
@ApiModelProperty(value = "本车间一线人数")
private Integer userNum = 0;
@TableField(value = "workshop_total_fee")
@ApiModelProperty(value = "年度总费用")
private BigDecimal workshopTotalFee = BigDecimal.ZERO;
@TableField(value = "consumables_total_fee")
@ApiModelProperty(value = "水电费、生产耗材费用年度总费用")
private BigDecimal consumablesTotalFee = BigDecimal.ZERO;
@TableField(value = "consumables_fee")
@ApiModelProperty(value = "水电费、生产耗材费用")
private BigDecimal consumablesFee = BigDecimal.ZERO;
@TableField(value = "equipment_depreciation_total_fee")
@ApiModelProperty(value = "设备折旧年度总费用")
private BigDecimal equipmentDepreciationTotalFee = BigDecimal.ZERO;
@TableField(value = "equipment_depreciation_fee")
@ApiModelProperty("设备折旧")
private BigDecimal equipmentDepreciationFee = BigDecimal.ZERO;
@TableField(value = "workshop_labor_total_fee")
@ApiModelProperty(value = "车间管理人工费年度总费用")
private BigDecimal workshopLaborTotalFee = BigDecimal.ZERO;
@TableField(value = "workshop_labor_fee")
@ApiModelProperty("车间管理人工费")
private BigDecimal workshopLaborFee = BigDecimal.ZERO;
@TableField(value = "workshop_office_total_fee")
@ApiModelProperty(value = "车间办公室费用年度总费")
private BigDecimal workshopOfficeTotalFee = BigDecimal.ZERO;
@TableField(value = "workshop_office_fee")
@ApiModelProperty("车间办公室费用")
private BigDecimal workshopOfficeFee = BigDecimal.ZERO;
@TableField(value = "assistant_total_fee")
@ApiModelProperty("辅助部门年度总费用")
private BigDecimal assistantTotalFee = BigDecimal.ZERO;
@TableField(value = "assistant_labor_total_fee")
@ApiModelProperty(value = "辅助部门人工费年度总费用")
private BigDecimal assistantLaborTotalFee = BigDecimal.ZERO;
@TableField(value = "assistant_labor_fee")
@ApiModelProperty("辅助部门人工费")
private BigDecimal assistantLaborFee = BigDecimal.ZERO;
@TableField(value = "assistant_total_fee")
@ApiModelProperty("辅助部门费用年度总费用")
private BigDecimal assistantTotalFee = BigDecimal.ZERO;
@TableField(value = "assistant_fee")
@ApiModelProperty("辅助部门费用")
private BigDecimal assistantFee = BigDecimal.ZERO;

View File

@ -38,10 +38,6 @@ public class VirtualWorkingHistoryEntity implements Serializable {
@ApiModelProperty(value = "本车间一线人数")
private Integer userNum = 0;
@TableField(value = "workshop_total_fee")
@ApiModelProperty(value = "年度总费用")
private BigDecimal workshopTotalFee = BigDecimal.ZERO;
@TableField(value = "consumables_fee")
@ApiModelProperty(value = "水电费、生产耗材费用")
private BigDecimal consumablesFee = BigDecimal.ZERO;
@ -58,10 +54,6 @@ public class VirtualWorkingHistoryEntity implements Serializable {
@ApiModelProperty("车间办公室费用")
private BigDecimal workshopOfficeFee = BigDecimal.ZERO;
@TableField(value = "assistant_total_fee")
@ApiModelProperty("辅助部门年度总费用")
private BigDecimal assistantTotalFee = BigDecimal.ZERO;
@TableField(value = "assistant_labor_fee")
@ApiModelProperty("辅助部门人工费")
private BigDecimal assistantLaborFee = BigDecimal.ZERO;

View File

@ -41,34 +41,50 @@ public class VirtualWorking implements Serializable {
@Min(value = 0, message = "本车间一线人数必须大于等于0")
private Integer userNum;
@ApiModelProperty("年度总费用")
@Min(value = 0, message = "年度总费用必须大于等于0")
private BigDecimal workshopTotalFee;
@ApiModelProperty("水电费、生产耗材费用年度总费用")
@Min(value = 0, message = "水电费、生产耗材费用年度总费用必须大于等于0")
private BigDecimal consumablesTotalFee;
@ApiModelProperty("水电费、生产耗材费用")
@Min(value = 0, message = "水电费、生产耗材费用用必须大于等于0")
private BigDecimal consumablesFee;
@ApiModelProperty("设备折旧年度总费用")
@Min(value = 0, message = "设备折旧年度总费用必须大于等于0")
private BigDecimal equipmentDepreciationTotalFee;
@ApiModelProperty("设备折旧")
@Min(value = 0, message = "设备折旧必须大于等于0")
private BigDecimal equipmentDepreciationFee;
@ApiModelProperty("车间管理人工费年度总费")
@Min(value = 0, message = "车间管理人工费年度总费用必须大于等于0")
private BigDecimal workshopLaborTotalFee;
@ApiModelProperty("车间管理人工费")
@Min(value = 0, message = "车间管理人工费必须大于等于0")
private BigDecimal workshopLaborFee;
@ApiModelProperty("车间办公室费用年度总费")
@Min(value = 0, message = "车间办公室费用年度总费用必须大于等于0")
private BigDecimal workshopOfficeTotalFee;
@ApiModelProperty("车间办公室费用")
@Min(value = 0, message = "车间办公室费用必须大于等于0")
private BigDecimal workshopOfficeFee;
@ApiModelProperty("辅助部门年度总费用")
@Min(value = 0, message = "辅助部门年度总费用用必须大于等于0")
private BigDecimal assistantTotalFee;
@ApiModelProperty("辅助部门人工费年度总费用")
@Min(value = 0, message = "辅助部门人工费年度总费用用必须大于等于0")
private BigDecimal assistantLaborTotalFee;
@ApiModelProperty("辅助部门人工费")
@Min(value = 0, message = "辅助部门人工费必须大于等于0")
private BigDecimal assistantLaborFee;
@ApiModelProperty("辅助部门费用年度总费用")
@Min(value = 0, message = "辅助部门费用年度总费用用必须大于等于0")
private BigDecimal assistantTotalFee;
@ApiModelProperty("辅助部门费用")
@Min(value = 0, message = "辅助部门费用必须大于等于0")
private BigDecimal assistantFee;

View File

@ -101,11 +101,11 @@ public class BomCostCalculateService {
boolean purchaseTypeIsF = materialMainAttrService.purchaseTypeIsF(dto.getMaterialNo());
boolean purchaseTypeIsE50 = materialMainAttrService.purchaseTypeIsE50(dto.getMaterialNo());
if ((isRoot && purchaseTypeIsE50) || StrUtil.isBlank(cdata)) {
List<WorkingHourDTO> workingHours = isRoot
? processRouteTaskProcessesService.getWorkingHour(dto.getParentMaterialNo())
: (purchaseTypeIsE50 ? new ArrayList<>() : processRouteTaskProcessesService.getWorkingHour(dto.getMaterialNo()));
log.debug(StrUtil.format("BOM成本计算 {} 物料工时: {}", dto.getMaterialNo(), JsonUtil.toJson(workingHours)));
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();
cdto.setPurchaseTypeIsE50(purchaseTypeIsE50);
cdto.setPurchaseTypeIsF(purchaseTypeIsF);
cdto.setMaterialNo(dto.getMaterialNo());
cdto.setMaterialPrice(dto.getMaterialPrice());
cdto.setCategoryCode(dto.getMaterialCategoryCode());
@ -118,10 +118,13 @@ public class BomCostCalculateService {
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);
cdto.setPurchasedPartsCost(calculatePurchasedPartsCost(dto));
// 计算损耗成本
cdto.setPurchasedPartsWasteCost(calculateWasteCost(dto, month));
} else {
List<EBomDTO> children = datas.stream()
.filter(d -> StrUtil.equals(d.getParentMaterialNo(), dto.getMaterialNo()))
@ -134,21 +137,19 @@ public class BomCostCalculateService {
// 外购件只计算采购成本
cdto.setPurchasedPartsCost(calculatePurchasedPartsCost(dto));
// 计算损耗成本
cdto.setWasteCost(calculateWasteCost(dto, month));
cdto.setPurchasedPartsWasteCost(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());
}
cdto.setSteelsWasteCost(calculateWasteCost(dto, month));
}
} else {
cdto.setHasChildren(true);
cdto.setPurchasedParts(false);
// 计算损耗成本
cdto.setSteelsWasteCost(calculateWasteCost(dto, month));
//计算子级成本
List<EBomCostCacheDTO> childrenCost = children.parallelStream()
.map(c -> calculateBom(rootMaterialNo, month, false, c, datas, config, result))
@ -156,8 +157,9 @@ public class BomCostCalculateService {
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.setWasteCost(cdto.getWasteCost().add(c.getWasteCost().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())));
@ -166,8 +168,21 @@ 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())));
// 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)));
} 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()
@ -198,7 +213,7 @@ public class BomCostCalculateService {
EBomCostCacheDTO cdto = JsonUtil.fromJson(cdata, EBomCostCacheDTO.class);
result.add(cdto);
if (!purchaseTypeIsF) {
List<EBomDTO> children = datas.stream()
List<EBomDTO> children = datas.parallelStream()
.filter(d -> StrUtil.equals(d.getParentMaterialNo(), dto.getMaterialNo()))
.collect(Collectors.toList());
children.parallelStream().forEach(c -> calculateBom(rootMaterialNo, month, false, c, datas, config, result));
@ -227,7 +242,7 @@ public class BomCostCalculateService {
dto.setWorkHours(gs);
productionCosts.add(dto);
if (dto.getCost().compareTo(BigDecimal.ZERO) > 0) {
log.debug(StrUtil.format(
log.info(StrUtil.format(
"BOM成本计算 {} 制作成本 {},价格: {},其中工时: {},工时工资: {},人工福利: {},水电费、生产耗材费用: {},设备折旧: {},车间管理人工费: {},车间办公室费用: {},辅助部门人工费: {},辅助部门费用: {}"
, d.getMaterialNo(), dto.getName(), dto.getCost(), gs, hourlyWages, benefit, auxiliaryMaterialsAndConsumables
, feeEquipmentDepreciation, feeWorkshopLaborCost, feeWorkshopOffice, auxiliaryDepartmentLaborCosts, assistantFee));
@ -237,8 +252,10 @@ public class BomCostCalculateService {
}
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);
if (!StrUtil.equalsIgnoreCase(StrUtil.trim(dto.getMaterialUnit()), "kg")) {
log.info("{},{},油漆计算:单位不符合要求({})", rootMaterialNo, dto.getMaterialNo(), dto.getMaterialUnit());
return BigDecimal.ZERO;
}
BigDecimal price = null;
if (StrUtil.isNotBlank(month)) {
PaintCostConfigHistoryEntity history = paintCostConfigHistoryService.getCost(dto.getRawMaterialGroup(), month);
@ -253,14 +270,11 @@ public class BomCostCalculateService {
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())) {
// log.info("{},{},油漆计算:未设置重量", rootMaterialNo, dto.getMaterialNo());
// return BigDecimal.ZERO;
// }
// return price;
if (Objects.nonNull(price)) {
log.info("{},{},油漆计算:重量{}", rootMaterialNo, dto.getMaterialNo(), dto.getNum().toPlainString());
price = BigDecimalUtil.multiply(price, dto.getNum());

View File

@ -148,7 +148,7 @@ public class ProductCostAnalysisService {
cvo.setTotalCost(ccost.getTotalCost().multiply(cvo.getTotalNum()));
} else {
cvo.setPrice(ccost.isPurchasedParts() ? ccost.getPurchasedPartsCost() : ccost.getSteelsCost());
cvo.setTotalCost(cvo.getPrice().multiply(cvo.getNum()));
cvo.setTotalCost(cvo.getPrice().add(ccost.getSteelsWasteCost()).add(ccost.getPurchasedPartsWasteCost()).multiply(cvo.getNum()));
}
}
pvo.getChildren().add(cvo);
@ -235,6 +235,9 @@ public class ProductCostAnalysisService {
return;
}
EBomCostCacheDTO dto = datas.stream().filter(d -> StrUtil.equals(d.getMaterialNo(), child.getMaterialNo())).findFirst().orElse(null);
if (Objects.isNull(dto)) {
return;
}
MaterialCostVO vo = null;
if (dto.isPurchasedParts()) {
vo = pvos.stream().filter(v -> Objects.equals(v.getMaterialNo(), child.getMaterialNo())).findFirst().orElseGet(() -> {
@ -309,6 +312,9 @@ public class ProductCostAnalysisService {
return;
}
EBomCostCacheDTO dto = datas.stream().filter(d -> StrUtil.equals(d.getMaterialNo(), child.getMaterialNo())).findFirst().orElse(null);
if (Objects.isNull(dto)) {
return;
}
MaterialCostVO vo = vos.stream().filter(v -> Objects.equals(v.getMaterialNo(), child.getMaterialNo())).findFirst().orElseGet(() -> {
MaterialCostVO v = new MaterialCostVO();
v.setMaterialNo(child.getMaterialNo());
@ -406,13 +412,13 @@ public class ProductCostAnalysisService {
productCostVO.setMaterialCost(matrialsCost);
//钢材成本
CostItemInfoVO materialsSteelsCost = new CostItemInfoVO();
materialsSteelsCost.setCost(cost.getSteelsCost());
materialsSteelsCost.setCost(cost.getSteelsCost().add(cost.getSteelsWasteCost()));
materialsSteelsCost.setSubclassRatio(calculateRatio(materialsSteelsCost.getCost(), matrialsCost.getCost()));
materialsSteelsCost.setTotalRatio(calculateRatio(materialsSteelsCost.getCost(), cost.getTotalCost()));
productCostVO.setSteelsMaterialCost(materialsSteelsCost);
//采购件成本
CostItemInfoVO materialsPurchasedPartsCost = new CostItemInfoVO();
materialsPurchasedPartsCost.setCost(cost.getPurchasedPartsCost());
materialsPurchasedPartsCost.setCost(cost.getPurchasedPartsCost().add(cost.getPurchasedPartsWasteCost()));
materialsPurchasedPartsCost.setSubclassRatio(calculateRatio(materialsPurchasedPartsCost.getCost(), matrialsCost.getCost()));
materialsPurchasedPartsCost.setTotalRatio(calculateRatio(materialsPurchasedPartsCost.getCost(), cost.getTotalCost()));
productCostVO.setPurchasedPartsCost(materialsPurchasedPartsCost);

View File

@ -64,13 +64,17 @@ public class VirtualWorkingService extends ServiceImpl<VirtualWorkingMapper, Vir
}
entity.setHourlyAuxiliaryFee(vw.getHourlyAuxiliaryFee());
entity.setUserNum(vw.getUserNum());
entity.setWorkshopTotalFee(vw.getWorkshopTotalFee());
entity.setConsumablesTotalFee(vw.getConsumablesTotalFee());
entity.setConsumablesFee(vw.getConsumablesFee());
entity.setEquipmentDepreciationTotalFee(vw.getEquipmentDepreciationTotalFee());
entity.setEquipmentDepreciationFee(vw.getEquipmentDepreciationFee());
entity.setWorkshopLaborTotalFee(vw.getWorkshopLaborTotalFee());
entity.setWorkshopLaborFee(vw.getWorkshopLaborFee());
entity.setWorkshopOfficeTotalFee(vw.getWorkshopOfficeTotalFee());
entity.setWorkshopOfficeFee(vw.getWorkshopOfficeFee());
entity.setAssistantTotalFee(vw.getAssistantTotalFee());
entity.setAssistantLaborTotalFee(vw.getAssistantLaborTotalFee());
entity.setAssistantLaborFee(vw.getAssistantLaborFee());
entity.setAssistantTotalFee(vw.getAssistantTotalFee());
entity.setAssistantFee(vw.getAssistantFee());
}
});

View File

@ -59,6 +59,7 @@
<!-- 忽略Nacos服务器的INFO日志 -->
<logger name="com.alibaba.nacos" level="WARN" />
<logger name="com.nflg" level="DEBUG"/>
<!-- 日志输出级别 -->
<root level="ERROR">

View File

@ -2,21 +2,18 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nflg.product.technology.mapper.master.VirtualWorkingHistoryMapper">
<insert id="backup">
INSERT INTO t_technology_virtual_working_history (`year`, workingtype_id, hourly_auxiliary_fee, user_num,
workshop_total_fee, consumables_fee,
equipment_depreciation_fee, workshop_labor_fee,
workshop_office_fee, assistant_total_fee, assistant_labor_fee,
assistant_fee)
INSERT INTO t_technology_virtual_working_history ( `year`, workingtype_id, hourly_auxiliary_fee, user_num
, consumables_fee, equipment_depreciation_fee
, workshop_labor_fee, workshop_office_fee, assistant_labor_fee
, assistant_fee)
SELECT #{year},
workingtype_id,
hourly_auxiliary_fee,
user_num,
workshop_total_fee,
consumables_fee,
equipment_depreciation_fee,
workshop_labor_fee,
workshop_office_fee,
assistant_total_fee,
assistant_labor_fee,
assistant_fee
FROM t_technology_virtual_working