package com.zzsmart.qomo.kn.cost.manage.plugin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zzsmart.qomo.kn.cost.manage.entity.*;
import com.zzsmart.qomo.kn.cost.manage.enums.FeeTypeEnum;
import com.zzsmart.qomo.kn.cost.manage.enums.HourOrRateTypeEnum;
import com.zzsmart.qomo.kn.cost.manage.enums.TotalCostEnum;
import com.zzsmart.qomo.kn.cost.manage.mapper.AppSceneCostBomRelevancyMapper;
import com.zzsmart.qomo.kn.cost.manage.service.*;
import com.zzsmart.qomo.kn.cost.manage.vo.BomTreeVo;
import com.zzsmart.qomo.kn.cost.manage.vo.FlowTaskInfoVO;
import com.zzsmart.qomo.kn.cost.manage.vo.TotalResultValue;
import com.zzsmart.qomo.plugin.task.api.TaskExecutionContext;
import io.swagger.models.auth.In;
//import liquibase.pro.packaged.B;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class StandardCostService {
    /**
     * 物料BOM信息
     */
    @Autowired
    AppSceneCostBomRelevancyMapper appSceneCostBomRelevancyMapper;
    @Autowired
    IAppSceneCostBomRelevancyService costMaterialBomService;
    @Autowired
    IAppSceneCostStandardBomService iAppSceneCostStandardBomService;
    @Autowired
    IAppSceneCostStandardProductprocessService iAppSceneCostStandardProductprocessService;

    /**
     * 小时费率
     */
    @Autowired
    IAppSceneCostHourRateService iHourRateService;
    /**
     * 采购单价
     */
    //@Autowired
    //IAppSceneCostPurchaseRecordService costPurchaseRecordService;
    /**
     * 工序
     */
    @Autowired
    IAppSceneCostProductProcessMaintenanceService costMaterialProcessHoursService;
    /**
     * 标准成本计算结果
     */
    @Autowired
    IAppSceneCostResultValueService iAppSceneCostResultValueService;
    /**
     * 标准成本服务
     */
    public static StandardCostService standardCostService;
    /**
     * 成本计算服务
     */
    @Autowired
    IAppSceneCostCountService appSceneCostCountService;
    /**
     * 标准成本明细服务（单行查询服务）
     */
    @Autowired
    private IAppSceneCostStandardResultService iAppSceneCostStandardResultService;

    @Autowired
    private IAppSceneCostMaterialService iAppSceneCostMaterialService;

    @Autowired
    private IAppSceneCostSapEineService iAppSceneCostSapEineService;

    @Autowired
    private IAppSceneCostSapEkpoService iAppSceneCostSapEkpoService;

    @Autowired
    private IAppSceneCostInvoiceService iAppSceneCostInvoiceService;

    @Autowired
    private IAppSceneCostAufnrMatnrService iAppSceneCostAufnrMatnrService;

    //@Autowired
    //private IAppSceneCostStandardBomService iAppSceneCostStandardBomService;

    //@Autowired
    //private IAppSceneCostStandardProductprocessService iAppSceneCostStandardProductprocessService;

    @Autowired
    private IAppSceneCostBomRelevancyService iAppSceneCostBomRelevancyService;

    @Autowired
    private IAppSceneCostProductProcessMaintenanceService iAppSceneCostProductProcessMaintenanceService;

    @PostConstruct
    public void init() {
        standardCostService = this;
        standardCostService.appSceneCostBomRelevancyMapper = this.appSceneCostBomRelevancyMapper;
        standardCostService.appSceneCostCountService = this.appSceneCostCountService;
        standardCostService.costMaterialBomService = this.costMaterialBomService;
        //standardCostService.costPurchaseRecordService = this.costPurchaseRecordService;
        standardCostService.iHourRateService = this.iHourRateService;
        standardCostService.costMaterialProcessHoursService = this.costMaterialProcessHoursService;
        standardCostService.iAppSceneCostResultValueService = this.iAppSceneCostResultValueService;
        standardCostService.iAppSceneCostStandardResultService = this.iAppSceneCostStandardResultService;
        standardCostService.iAppSceneCostMaterialService = this.iAppSceneCostMaterialService;
        standardCostService.iAppSceneCostSapEineService=this.iAppSceneCostSapEineService;
        standardCostService.iAppSceneCostSapEkpoService=this.iAppSceneCostSapEkpoService;
        standardCostService.iAppSceneCostInvoiceService=this.iAppSceneCostInvoiceService;
        standardCostService.iAppSceneCostAufnrMatnrService = this.iAppSceneCostAufnrMatnrService;
        standardCostService.iAppSceneCostBomRelevancyService = this.iAppSceneCostBomRelevancyService;
        standardCostService.iAppSceneCostStandardBomService=this.iAppSceneCostStandardBomService;
        standardCostService.iAppSceneCostStandardProductprocessService=this.iAppSceneCostStandardProductprocessService;
        standardCostService.iAppSceneCostProductProcessMaintenanceService=this.iAppSceneCostProductProcessMaintenanceService;
    }

    /**
     * 更新成本计算模型任务状态
     */
    public static void updateCostCountTaskStatus(Boolean isSuccess, Integer costCountTaskId) {
        log.info("更新成本计算模型任务状态");
        standardCostService.appSceneCostCountService.updateById(AppSceneCostCount.builder().id(costCountTaskId).status(isSuccess != null && isSuccess ? 1 : 0).build());
    }

    /**
     * 1.物料编号输入任务
     */
    public static void materialInputTask(TaskExecutionContext parameters) {
        try {
            //获取任务流程相关信息
            FlowTaskInfoVO flowTaskInfoVO = analysisFlowTaskInfo(parameters);
            //获取最上层的物料号
            String topMaterialCode = flowTaskInfoVO.getTopMaterialCode();
            //获取任务类型
            String taskType = parameters.getTaskType();
            //获取任务代码
            String taskCode = flowTaskInfoVO.getTaskCode();
            //获取流程id
            String flowInstanceId = flowTaskInfoVO.getFlowInstanceId();
            //1.查询出所有满足物料编号的物料（BOM物料）
            String sql = flowTaskInfoVO.getSqlString();
            log.info("传递过来的SQL语句：" + sql);
            //获取顶部物料下所有的物料信息并存储到新的表中
            getAllMaterialBomInfoByTopMaterialCode(flowTaskInfoVO.getWerks(),topMaterialCode, taskType, taskCode, flowInstanceId != null ? Integer.valueOf(flowInstanceId) : null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 【1.成本参数查询】查询最顶部的BOM物料编号下所有的物料并进行层级排序
     * * 获取顶部物料下所有的物料信息并存储到新的表中
     *
     * @param topMaterialCode 顶部物料编号
     * @param taskType        任务类型
     * @param taskCode        任务编号
     * @param flowInstanceId  流程实例id
     */
    public static void getAllMaterialBomInfoByTopMaterialCode(String werks,String topMaterialCode, String taskType, String taskCode, Integer flowInstanceId) {
        log.info("getAllMaterialBomInfoByTopMaterialCode");
        List<BomTreeVo> list = standardCostService.costMaterialBomService.queryAllBomInfoByTopMaterialCode(topMaterialCode,werks);
        List<String> MarterialNoList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            MarterialNoList = list.stream().filter(s -> s.getIdnrk() != null).map(BomTreeVo::getIdnrk).collect(Collectors.toList());
        }
        Map<String, String> manuTypeMap = standardCostService.iAppSceneCostMaterialService.getManuTypeByMaterialNo(MarterialNoList);

        int maxdepth = 0;
        List<AppSceneCostResultValue> appSceneCostResultValues = new ArrayList<>();
        log.info("Full ParamTask list: {}", list);
        //TODO material.getMeins()领用量？？为什么是ST字母
        for (int i = 0; list != null && i < list.size(); i++) {
            BomTreeVo material = list.get(i);
            String manutype = "";
            if (manuTypeMap.containsKey(material.getIdnrk())) {
                manutype = manuTypeMap.get(material.getIdnrk());
            }
            if(material.getPlayer().equals("00000000000000000000")){
                material.setPlayer("0");
            }
            //TODO  物料领用数据
            BigDecimal num1 = material.getMenge();
            AppSceneCostResultValue appSceneCostResultValue = AppSceneCostResultValue.builder()
                    .belongTopMaterialNo(topMaterialCode)
                    .marterialNo(material.getIdnrk())
                    .parentMarterialNo(material.getMatnr())
                    .taskType(taskType)
                    .taskCode(taskCode)
                    .flowInstanceId(flowInstanceId)
                    .num(material.getMenge())
                    .pnum(material.getPmenge())
                    .topnum(material.getTopmenge())
                    .depth(material.depth)
                    .manuType(manutype)
                    .layer(material.layer)
                    .player(material.player)
                    .werks(material.werks)
                    .build();
            appSceneCostResultValues.add(appSceneCostResultValue);
            if (material.depth > maxdepth) {
                maxdepth = material.depth;
            }
            //standardCostService.iAppSceneCostResultValueService.save(appSceneCostResultValue);
        }
//        Map<String, Integer> mapIndex = new HashMap<>();
//        for (int i = 1; i <= maxdepth; ++i) {
//            //int index=1;
//            for (AppSceneCostResultValue appSceneCostResultValue : appSceneCostResultValues) {
//                if (appSceneCostResultValue.getDepth() == i) {
//                    String parentlayer = "";
//                    if (i == 1) {
//                        parentlayer = "0";
//                    } else {
//                        for (AppSceneCostResultValue appSceneCostResultValue1 : appSceneCostResultValues) {
//                            if (appSceneCostResultValue1.getMarterialNo().equals(appSceneCostResultValue.getParentMarterialNo()) && (appSceneCostResultValue1.getDepth() + 1 == appSceneCostResultValue.getDepth())) {
//                                parentlayer = appSceneCostResultValue1.getLayer();
//                            }
//                        }
//                    }
//                    int index = 1;
//                    if (mapIndex.containsKey(parentlayer)) {
//                        index = mapIndex.get(parentlayer);
//                    } else {
//                        mapIndex.put(parentlayer, index);
//                    }
//                    String layer = parentlayer + "." + String.valueOf(index);
//                    if(parentlayer.equals("0")){
//                        layer=String.valueOf(index);
//                    }
//                    index++;
//                    mapIndex.put(parentlayer, index);
//                    appSceneCostResultValue.setLayer(layer);
//                }
//            }
//        }
        standardCostService.iAppSceneCostResultValueService.saveBatch(appSceneCostResultValues);

        AppSceneCostResultValue appSceneCostResultValue = AppSceneCostResultValue.builder()
                .belongTopMaterialNo(topMaterialCode)
                .marterialNo(topMaterialCode)
                .parentMarterialNo(topMaterialCode)
                .taskType(taskType)
                .taskCode(taskCode)
                .flowInstanceId(flowInstanceId)
                .num(new BigDecimal(1))
                .pnum(new BigDecimal(1))
                .topnum(new BigDecimal(1))
                .depth(0)
                .werks(werks)
                .layer("0")
                .player("")
                .manuType("E")
                .build();
        standardCostService.iAppSceneCostResultValueService.save(appSceneCostResultValue);
    }

    /**
     * 【2.物料成本计算】计算物料成本
     *
     * @param topMaterialCode 顶部物料编号
     * @param taskType        任务类型
     * @param taskCode        任务编号
     * @param flowInstanceId  流程实例id
     */
    public static void countMaterialCostByTopMaterialCode(String topMaterialCode, String taskType, String taskCode, Integer flowInstanceId, String feeType) {
        log.info("countMaterialCostByTopMaterialCode");
        //1.查询出物料编号对应的下所有的BOM信息
        List<AppSceneCostResultValue> list = standardCostService.iAppSceneCostResultValueService.getResultValueByTopMaterialNo(topMaterialCode, "MaterialInput", String.valueOf(flowInstanceId));
        //2.计算出所有的单个物料的物料成本
        //2.1查询出物料的单价和采购数量
        List<String> MarterialNoList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            MarterialNoList = list.stream().filter(s -> s.getMarterialNo() != null).map(AppSceneCostResultValue::getMarterialNo).collect(Collectors.toList());
        }
        //查询物料的采购价
        Map<String, AppSceneCostSapEine> purchasePriceMap = standardCostService.iAppSceneCostSapEineService.getPrices(MarterialNoList);
        //查询物料的临时合同估价
        Map<String, BigDecimal> ekpoPriceMap = standardCostService.iAppSceneCostSapEkpoService.getPrices(MarterialNoList);
        //查询物料的临时合同估价
        Map<String, BigDecimal> invoicePriceMap = standardCostService.iAppSceneCostInvoiceService.getPrices(MarterialNoList);
        for (int i = 0; i < list.size(); i++) {
            AppSceneCostResultValue appSceneCostResultValue = list.get(i);
            String marterialNo = appSceneCostResultValue.getMarterialNo();
            BigDecimal num = appSceneCostResultValue.getTopnum();
            if (marterialNo != null && num != null && (new BigDecimal(num.toString()).compareTo(BigDecimal.ZERO)) != 0) {
                BigDecimal price = new BigDecimal(0);
                String price_type = "";
                String supplier = "";
                String suppliername = "";
                BigDecimal ekpo_price = new BigDecimal(0);
                BigDecimal invoice_price = new BigDecimal(0);
                if (appSceneCostResultValue.getManuType() != null && (appSceneCostResultValue.getManuType().equals("F") || appSceneCostResultValue.getManuType().equals("F30"))) {
                    if(purchasePriceMap.containsKey(marterialNo)) {
                        price = purchasePriceMap.get(marterialNo).getCnyPrice();
                        supplier = purchasePriceMap.get(marterialNo).getLifnr();
                        suppliername=purchasePriceMap.get(marterialNo).getName1();
                        price_type = "purchase_record";
                    }
                    if(ekpoPriceMap.containsKey(marterialNo)){
                        ekpo_price = ekpoPriceMap.get(marterialNo);
                        if(price_type.equals("")){
                            price_type = "ekpo_price";
                            price = ekpo_price;
                        }
                    }
                }
                if(invoicePriceMap.containsKey(marterialNo)){
                    invoice_price = invoicePriceMap.get(marterialNo);
                }
                //purchasePriceMap.get(marterialNo);
                //if (price == null) {
                //    price = BigDecimal.ZERO;
                //} else {
                //    price_type = "purchase_record";
                //}
                BigDecimal number = new BigDecimal(num.toString());
                //单价乘以数量
                BigDecimal totalCost = price.multiply(number);
                //2.2计算出人工成本并存储到成本结果数据表中
                AppSceneCostResultValue resultValue = AppSceneCostResultValue.builder()
                        .belongTopMaterialNo(topMaterialCode)
                        .marterialNo(marterialNo)
                        .parentMarterialNo(appSceneCostResultValue.getParentMarterialNo())
                        .taskType(taskType)
                        .costType(feeType)
                        .taskCode(taskCode)
                        .priceType(price_type)
                        .flowInstanceId(flowInstanceId)
                        .countValue(totalCost + "")
                        .material(price)
                        .num(num)
                        .pnum(appSceneCostResultValue.getPnum())
                        .topnum(appSceneCostResultValue.getTopnum())
                        .manuType(appSceneCostResultValue.getManuType())
                        .depth(appSceneCostResultValue.getDepth())
                        .layer(appSceneCostResultValue.getLayer())
                        .player(appSceneCostResultValue.getPlayer())
                        .supplier(supplier)
                        .supplierName(suppliername)
                        .ekpoPrice(ekpo_price)
                        .invoicePrice(invoice_price)
                        .werks(appSceneCostResultValue.getWerks())
                        .build();
                standardCostService.iAppSceneCostResultValueService.save(resultValue);
            }
        }
    }

    /**
     * 【3.人工成本计算】
     *
     * @param topMaterialCode 顶部物料编号
     * @param taskType        任务类型
     * @param taskCode        任务编号
     * @param flowInstanceId  流程实例id
     */
    public static void countLaborCostByTopMaterialCode(String topMaterialCode, String taskType, String taskCode, Integer flowInstanceId, String feeType, AppSceneCostHourRate appSceneCostHourRate) {
        log.info("countLaborCostByTopMaterialCode");
        //1.查询出人员工时费率
        //AppSceneCostHourRate hourRateInfo = standardCostService.iHourRateService.getOneHourRateInfo();
        BigDecimal hourRate = new BigDecimal("0");
        //if (hourRateInfo != null) {
        //    hourRate = hourRateInfo.getLaborHourRate();
        //}
        //1.查询出物料编号对应的下所有的BOM信息
        List<AppSceneCostResultValue> list = standardCostService.iAppSceneCostResultValueService.getResultValueByTopMaterialNo(topMaterialCode, "MaterialInput", String.valueOf(flowInstanceId));
        //2.计算出所有的单个物料的人工成本
        //2.1查询出物料的人员工时和人工小时费率（涉及：小时费率表和工序表）
        List<String> MarterialNoList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            MarterialNoList = list.stream().filter(s -> s.getMarterialNo() != null).map(AppSceneCostResultValue::getMarterialNo).collect(Collectors.toList());
        }
        //查询工序工时
        Map<String, List<AppSceneCostProductProcessMaintenance>> processHoursMap = standardCostService.costMaterialProcessHoursService.getProcessHoursByMaterialNo(MarterialNoList);
        for (int i = 0; i < list.size(); i++) {
            AppSceneCostResultValue appSceneCostResultValue = list.get(i);
            String marterialNo = appSceneCostResultValue.getMarterialNo();
            if (marterialNo != null) {
                BigDecimal totalCost = new BigDecimal("0.0");
                BigDecimal laborHours = new BigDecimal("0.0");
                List<AppSceneCostProductProcessMaintenance> costMaterialProcessHours = processHoursMap.get(marterialNo);
                if (costMaterialProcessHours != null && costMaterialProcessHours.size() > 0) {
                    for (int j = 0; j < costMaterialProcessHours.size(); j++) {
                        AppSceneCostProductProcessMaintenance processHours = costMaterialProcessHours.get(j);
                        laborHours = laborHours.add(processHours.getLaborHour());
                        //计算总人工成本
                        totalCost = totalCost.add(processHours.getLaborHour().multiply(hourRate));
                    }
                }
                //2.2计算出人工成本并存储到成本结果数据表中
                AppSceneCostResultValue resultValue = AppSceneCostResultValue.builder()
                        .belongTopMaterialNo(topMaterialCode)
                        .marterialNo(marterialNo)
                        .parentMarterialNo(appSceneCostResultValue.getParentMarterialNo())
                        .taskType(taskType).taskCode(taskCode)
                        .flowInstanceId(Integer.valueOf(flowInstanceId))
                        .countValue(totalCost + "")
                        .costType(feeType)
                        .priceOrRate(hourRate)
                        .hour(laborHours)
                        .num(appSceneCostResultValue.getNum())
                        .pnum(appSceneCostResultValue.getPnum())
                        .topnum(appSceneCostResultValue.getTopnum())
                        .manuType(appSceneCostResultValue.getManuType())
                        .build();
                standardCostService.iAppSceneCostResultValueService.save(resultValue);
            }
        }
    }

    public static void countManufacturingCost(String topMaterialCode, String taskType, String taskCode, Integer flowInstanceId) {
        log.info("countManufacturingCost");
        //1.查询出人员工时费率
        Map<String, AppSceneCostHourRate> mapHourRate = standardCostService.iHourRateService.getOneHourRateInfo();
        BigDecimal hourRate = new BigDecimal("0");
        //if (hourRateInfo != null) {
        //    hourRate = hourRateInfo.getLaborHourRate();
        //}
        //1.查询出物料编号对应的下所有的BOM信息
        List<AppSceneCostResultValue> list = standardCostService.iAppSceneCostResultValueService.getResultValueByTopMaterialNo(topMaterialCode, "MaterialCost", String.valueOf(flowInstanceId));
        //2.根据费用类型进行不同的费用计算
        //查询工序工时
        List<String> MarterialNoList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            MarterialNoList = list.stream().filter(s -> s.getMarterialNo() != null).map(AppSceneCostResultValue::getMarterialNo).collect(Collectors.toList());
        }
        Map<String, List<AppSceneCostProductProcessMaintenance>> processHoursMap = standardCostService.costMaterialProcessHoursService.getProcessHoursByMaterialNo(MarterialNoList);
        for (AppSceneCostResultValue appSceneCostResultValue : list) {
            double labor = 0;
            double equip = 0;
            double fuel = 0;
            double auxi = 0;
            double other = 0;
            if(processHoursMap.containsKey(appSceneCostResultValue.getMarterialNo())){
            List<AppSceneCostProductProcessMaintenance> appSceneCostProductProcessMaintenances = processHoursMap.get(appSceneCostResultValue.getMarterialNo());
            for (AppSceneCostProductProcessMaintenance pm : appSceneCostProductProcessMaintenances) {
                String costcenter = pm.getCostCenterCode();
                //if(mapHourRate.containsKey(costcenter)){
                AppSceneCostHourRate hourrate = mapHourRate.get(costcenter);
//                        labor+=hourrate.getLaborHourRate().doubleValue()*pm.getLaborHour().doubleValue();
//                        equip+=hourrate.getEquipHourRate().doubleValue()*pm.getMachineHour().doubleValue();
//                        fuel+=hourrate.getFuelHourRate().doubleValue()*pm.getBurningHour().doubleValue();
//                        auxi+=hourrate.getAuxiliaryHourRate().doubleValue()*pm.getAuxiliaryHour().doubleValue();
//                        other+=hourrate.getOtherHourRate().doubleValue()*pm.getOtherHour().doubleValue();
                labor += pm.getLaborHour().doubleValue();
                equip += pm.getMachineHour().doubleValue();
                fuel += pm.getBurningHour().doubleValue();
                auxi += pm.getAuxiliaryHour().doubleValue();
                other += pm.getOtherHour().doubleValue();
                //}
            }
            }
            AppSceneCostResultValue resultValue = AppSceneCostResultValue.builder()
                    .belongTopMaterialNo(topMaterialCode)
                    .marterialNo(appSceneCostResultValue.getMarterialNo())
                    .parentMarterialNo(appSceneCostResultValue.getParentMarterialNo())
                    .taskType(taskType)
                    .taskCode(taskCode)
                    .flowInstanceId(Integer.valueOf(flowInstanceId))
                    .countValue("")
                    .material(appSceneCostResultValue.getMaterial())
                    .priceType(appSceneCostResultValue.getPriceType())
                    .labor(new BigDecimal(labor))
                    .equip(new BigDecimal(equip))
                    .fuel(new BigDecimal(fuel))
                    .auxi(new BigDecimal(auxi))
                    .other(new BigDecimal(other))
                    .num(appSceneCostResultValue.getNum())
                    .pnum(appSceneCostResultValue.getPnum())
                    .topnum(appSceneCostResultValue.getTopnum())
                    .manuType(appSceneCostResultValue.getManuType())
                    .depth(appSceneCostResultValue.getDepth())
                    .layer(appSceneCostResultValue.getLayer())
                    .player(appSceneCostResultValue.getPlayer())
                    .supplierName(appSceneCostResultValue.getSupplierName())
                    .supplier(appSceneCostResultValue.getSupplier())
                    .ekpoPrice(appSceneCostResultValue.getEkpoPrice())
                    .invoicePrice(appSceneCostResultValue.getInvoicePrice())
                    .werks(appSceneCostResultValue.getWerks())
                    .build();
            standardCostService.iAppSceneCostResultValueService.save(resultValue);
        }
    }

    /**
     * 【4.制造费用】
     *
     * @param topMaterialCode 顶部物料编号
     * @param taskType        任务类型
     * @param taskCode        任务编号
     * @param flowInstanceId  流程实例id
     */
    public static void countManufacturingCostByTopMaterialCode(String topMaterialCode, String taskType, String taskCode, Integer flowInstanceId, String feeType, AppSceneCostHourRate appSceneCostHourRate) {
        log.info("countManufacturingCostByTopMaterialCode");
        //1.查询出人员工时费率
        //AppSceneCostHourRate hourRateInfo = standardCostService.iHourRateService.getOneHourRateInfo(appSceneCostHourRate);
        BigDecimal hourRate = new BigDecimal("0");
        //if (hourRateInfo != null) {
        //    hourRate = hourRateInfo.getLaborHourRate();
        //}
        //1.查询出物料编号对应的下所有的BOM信息
        List<AppSceneCostResultValue> list = standardCostService.iAppSceneCostResultValueService.getResultValueByTopMaterialNo(topMaterialCode, "MaterialInput", String.valueOf(flowInstanceId));
        //2.根据费用类型进行不同的费用计算
        //查询工序工时
        List<String> MarterialNoList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            MarterialNoList = list.stream().filter(s -> s.getMarterialNo() != null).map(AppSceneCostResultValue::getMarterialNo).collect(Collectors.toList());
        }
        Map<String, List<AppSceneCostProductProcessMaintenance>> processHoursMap = standardCostService.costMaterialProcessHoursService.getProcessHoursByMaterialNo(MarterialNoList);
        //2.1机器折旧费（机器工时*费率）
        if (FeeTypeEnum.EquipmentFee.getCode().equals(feeType)) {
            for (int i = 0; i < list.size(); i++) {
                AppSceneCostResultValue appSceneCostResultValue = list.get(i);
                String marterialNo = appSceneCostResultValue.getMarterialNo();
                if (marterialNo != null) {
                    BigDecimal totalCost = new BigDecimal("0.0");
                    BigDecimal laborHours = new BigDecimal("0.0");
                    List<AppSceneCostProductProcessMaintenance> costMaterialProcessHours = processHoursMap.get(marterialNo);
                    if (costMaterialProcessHours != null && costMaterialProcessHours.size() > 0) {
                        for (int j = 0; j < costMaterialProcessHours.size(); j++) {
                            AppSceneCostProductProcessMaintenance processHours = costMaterialProcessHours.get(j);
                            laborHours = laborHours.add(processHours.getMachineHour());
                            //计算机器成本
                            totalCost = totalCost.add(processHours.getMachineHour().multiply(hourRate));
                        }
                    }
                    //2.2计算机器成本并存储到成本结果数据表中
                    AppSceneCostResultValue resultValue = AppSceneCostResultValue.builder()
                            .belongTopMaterialNo(topMaterialCode)
                            .marterialNo(marterialNo)
                            .parentMarterialNo(appSceneCostResultValue.getParentMarterialNo())
                            .taskType(taskType)
                            .taskCode(taskCode)
                            .flowInstanceId(Integer.valueOf(flowInstanceId))
                            .countValue(totalCost + "")
                            .costType(feeType)
                            .priceOrRate(hourRate)
                            .hour(laborHours)
                            .num(appSceneCostResultValue.getNum())
                            .pnum(appSceneCostResultValue.getPnum())
                            .topnum(appSceneCostResultValue.getTopnum())
                            .manuType(appSceneCostResultValue.getManuType())
                            .build();
                    standardCostService.iAppSceneCostResultValueService.save(resultValue);
                }
            }
        } else if (FeeTypeEnum.SupplyMaterialFee.getCode().equals(feeType)) {
            //机物料消耗（辅料工时*费率）
            for (int i = 0; i < list.size(); i++) {
                AppSceneCostResultValue appSceneCostResultValue = list.get(i);
                String marterialNo = appSceneCostResultValue.getMarterialNo();
                if (marterialNo != null) {
                    BigDecimal totalCost = new BigDecimal("0.0");
                    BigDecimal laborHours = new BigDecimal("0.0");
                    List<AppSceneCostProductProcessMaintenance> costMaterialProcessHours = processHoursMap.get(marterialNo);
                    if (costMaterialProcessHours != null && costMaterialProcessHours.size() > 0) {
                        for (int j = 0; j < costMaterialProcessHours.size(); j++) {
                            AppSceneCostProductProcessMaintenance processHours = costMaterialProcessHours.get(j);
                            //辅料工时
                            laborHours = laborHours.add(processHours.getAuxiliaryHour());
                            //机物料消耗
                            totalCost = totalCost.add(processHours.getAuxiliaryHour().multiply(hourRate));
                        }
                    }
                    //2.2计算机物料消耗存储到成本结果数据表中
                    AppSceneCostResultValue resultValue = AppSceneCostResultValue.builder()
                            .belongTopMaterialNo(topMaterialCode)
                            .marterialNo(marterialNo)
                            .parentMarterialNo(appSceneCostResultValue.getParentMarterialNo())
                            .taskType(taskType)
                            .taskCode(taskCode)
                            .flowInstanceId(Integer.valueOf(flowInstanceId))
                            .countValue(totalCost + "")
                            .costType(feeType)
                            .priceOrRate(hourRate)
                            .hour(laborHours)
                            .num(appSceneCostResultValue.getNum())
                            .pnum(appSceneCostResultValue.getPnum())
                            .topnum(appSceneCostResultValue.getTopnum())
                            .manuType(appSceneCostResultValue.getManuType())
                            .build();
                    standardCostService.iAppSceneCostResultValueService.save(resultValue);
                }
            }
        } else if (FeeTypeEnum.DriverFee.getCode().equals(feeType)) {
            //2.3水电费（燃动力工时*费率）
            for (int i = 0; i < list.size(); i++) {
                AppSceneCostResultValue appSceneCostResultValue = list.get(i);
                String marterialNo = appSceneCostResultValue.getMarterialNo();
                if (marterialNo != null) {
                    BigDecimal totalCost = new BigDecimal("0.0");
                    BigDecimal laborHours = new BigDecimal("0.0");
                    List<AppSceneCostProductProcessMaintenance> costMaterialProcessHours = processHoursMap.get(marterialNo);
                    if (costMaterialProcessHours != null && costMaterialProcessHours.size() > 0) {
                        for (int j = 0; j < costMaterialProcessHours.size(); j++) {
                            AppSceneCostProductProcessMaintenance processHours = costMaterialProcessHours.get(j);
                            //燃动力工时来源
                            laborHours = laborHours.add(processHours.getBurningHour());
                            //水电费（燃动力工时*费率）成本
                            totalCost = totalCost.add(processHours.getBurningHour().multiply(hourRate));
                        }
                    }
                    //2.2计算机物料消耗存储到成本结果数据表中
                    AppSceneCostResultValue resultValue = AppSceneCostResultValue.builder()
                            .belongTopMaterialNo(topMaterialCode)
                            .marterialNo(marterialNo)
                            .parentMarterialNo(appSceneCostResultValue.getParentMarterialNo())
                            .taskType(taskType)
                            .taskCode(taskCode)
                            .flowInstanceId(Integer.valueOf(flowInstanceId))
                            .countValue(totalCost + "")
                            .costType(feeType)
                            .priceOrRate(hourRate)
                            .hour(laborHours)
                            .num(appSceneCostResultValue.getNum())
                            .pnum(appSceneCostResultValue.getPnum())
                            .topnum(appSceneCostResultValue.getTopnum())
                            .manuType(appSceneCostResultValue.getManuType())
                            .build();
                    standardCostService.iAppSceneCostResultValueService.save(resultValue);
                }
            }
        } else if (FeeTypeEnum.OtherFee.getCode().equals(feeType)) {
            //2.4其他制费（其他工时*费率）
            for (int i = 0; i < list.size(); i++) {
                AppSceneCostResultValue appSceneCostResultValue = list.get(i);
                String marterialNo = appSceneCostResultValue.getMarterialNo();
                if (marterialNo != null) {
                    BigDecimal totalCost = new BigDecimal("0.0");
                    BigDecimal laborHours = new BigDecimal("0.0");
                    List<AppSceneCostProductProcessMaintenance> costMaterialProcessHours = processHoursMap.get(marterialNo);
                    if (costMaterialProcessHours != null && costMaterialProcessHours.size() > 0) {
                        for (int j = 0; j < costMaterialProcessHours.size(); j++) {
                            AppSceneCostProductProcessMaintenance processHours = costMaterialProcessHours.get(j);
                            //其他工时来源
                            laborHours = laborHours.add(processHours.getOtherHour());
                            //其他制费成本
                            totalCost = totalCost.add(processHours.getOtherHour().multiply(hourRate));
                        }
                    }
                    //2.2计算机物料消耗存储到成本结果数据表中
                    AppSceneCostResultValue resultValue = AppSceneCostResultValue.builder()
                            .belongTopMaterialNo(topMaterialCode)
                            .marterialNo(marterialNo)
                            .parentMarterialNo(appSceneCostResultValue.getParentMarterialNo())
                            .taskType(taskType)
                            .taskCode(taskCode)
                            .flowInstanceId(Integer.valueOf(flowInstanceId))
                            .countValue(totalCost + "")
                            .costType(feeType)
                            .priceOrRate(hourRate)
                            .hour(laborHours)
                            .num(appSceneCostResultValue.getNum())
                            .pnum(appSceneCostResultValue.getPnum())
                            .topnum(appSceneCostResultValue.getTopnum())
                            .manuType(appSceneCostResultValue.getManuType())
                            .build();
                    standardCostService.iAppSceneCostResultValueService.save(resultValue);
                }
            }
        }
//        else if (FeeTypeEnum.LogisticsFee.getCode().equals(feeType)) {
//            //查出所有的机器折旧费、机物料消耗、水电费、其他制费
//            list = standardCostService.iAppSceneCostResultValueService.getResultValueByTopMaterialNo(topMaterialCode, "ManufacturingCost", String.valueOf(flowInstanceId));
//            //2.5物流费（（机器折旧+机物料消耗+水电费+其他制费）*10.16%）
//            //按照物料编号进行分组
//            Map<String, List<AppSceneCostResultValue>> materialNoMap = list.stream().collect(Collectors.groupingBy(AppSceneCostResultValue::getMarterialNo));
//            for (String key : materialNoMap.keySet()) {
//                List<AppSceneCostResultValue> appSceneCostResultValues = materialNoMap.get(key);
//                BigDecimal totalCost = new BigDecimal("0.0");
//                for (int j = 0; j < appSceneCostResultValues.size(); j++) {
//                    AppSceneCostResultValue appSceneCostResultValue = appSceneCostResultValues.get(j);
//                    String countValue = appSceneCostResultValue.getCountValue();
//                    if (countValue != null) {
//                        totalCost = totalCost.add(new BigDecimal(countValue));
//                    }
//                }
//                AppSceneCostResultValue resultValue = AppSceneCostResultValue.builder()
//                        .belongTopMaterialNo(topMaterialCode)
//                        .marterialNo(key)
//                        .parentMarterialNo(appSceneCostResultValues.get(0).getParentMarterialNo())
//                        .taskType(taskType)
//                        .taskCode(taskCode)
//                        .flowInstanceId(Integer.valueOf(flowInstanceId))
//                        .countValue(totalCost.multiply(new BigDecimal("0.1016")).toString())
//                        .costType(feeType)
//                        .build();
//                standardCostService.iAppSceneCostResultValueService.save(resultValue);
//            }
//        }
    }

    /**
     * 【5.制造费用】
     *
     * @param topMaterialCode 顶部物料编号
     * @param taskType        任务类型
     * @param taskCode        任务编号
     * @param flowInstanceId  流程实例id
     * @param costType        流程实例id
     */
    public static void countStandardCostByTopMaterialCode(String topMaterialCode, String taskType, String taskCode, Integer flowInstanceId, String costType, String stage, String versionNumber) {
        log.info("countStandardCostByTopMaterialCode");
        //1.查询出根物料编号对应的下所有的BOM信息结果值
        //List<AppSceneCostResultValue> list = standardCostService.iAppSceneCostResultValueService.getAllResultValueByTopMaterialNo(topMaterialCode, String.valueOf(flowInstanceId));
        List<AppSceneCostResultValue> list = standardCostService.iAppSceneCostResultValueService.getResultValueByTopMaterialNo(topMaterialCode, "ManufacturingCost", String.valueOf(flowInstanceId));
        List<String> MarterialNoList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            MarterialNoList = list.stream().filter(s -> s.getMarterialNo() != null).map(AppSceneCostResultValue::getMarterialNo).collect(Collectors.toList());
        }
        Map<String, String> maktxMap = standardCostService.iAppSceneCostMaterialService.getMaktxByMaterialNo(MarterialNoList);
        //2.计算出所有的单个物料的本阶的标准成本(标准成本=物料成本+人工成本+制造费用)
        //按照物料编号进行分组
        Map<Integer, List<AppSceneCostResultValue>> materialNoMap = list.stream().collect(Collectors.groupingBy(AppSceneCostResultValue::getDepth));

        Set<Integer> soredDepth = new HashSet<>();
        for (Integer depth : materialNoMap.keySet()) {
            soredDepth.add(depth);
        }
        ArrayList<Integer> deplist = new ArrayList<>(soredDepth);
        Collections.reverse(deplist);

        List<AppSceneCostStandardResult> appSceneCostStandardResults = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");

        Set<String> matnrs = new HashSet<>();
        Set<String> idnrks = new HashSet<>();

        //遍历根物料下所有的物料进行该物料本阶成本和费用类别的统计
        for (Integer depth : deplist) {
            List<AppSceneCostResultValue> appSceneCostResultValues = materialNoMap.get(depth);
            for (AppSceneCostResultValue ascr : appSceneCostResultValues) {
                if(!matnrs.contains(ascr.getParentMarterialNo())){
                    matnrs.add(ascr.getParentMarterialNo());
                }
                if(!idnrks.contains(ascr.getMarterialNo())){
                    idnrks.add(ascr.getMarterialNo());
                }
                //BigDecimal currentCost = new BigDecimal("0.0");
                //1.本阶物料成本
                double materialCost = 0;
                //2.本阶人工成本
                double laborCost = 0;
                //3.本阶制造费（设备费）
                double equipmentCost = 0;
                //4.本阶制造费（辅料费用）
                double fuelcost = 0;
                //5.本阶制造费（水电费、燃动费）
                double auxicost = 0;
                //6.本阶制造费（其他制造费用）
                double otherCost = 0;
                //7.本阶物料成本
                double materialCost_acc = 0;
                //8.本阶人工成本
                double laborCost_acc = 0;
                //9.本阶制造费（设备费）
                double equipmentCost_acc = 0;
                //10.本阶制造费（辅料费用）
                double fuelcost_acc = 0;
                //11.本阶制造费（水电费、燃动费）
                double auxicost_acc = 0;
                //12.本阶制造费（其他制造费用）
                double otherCost_acc = 0;

                double laborhour = 0;
                double machinehour = 0;
                double fuelhour = 0;
                double auxihour = 0;
                double otherhour = 0;
                double laborhourTotal = 0;
                double machinehourTotal = 0;
                double fuelhourTotal = 0;
                double auxihourTotal = 0;
                double otherhourTotal = 0;
                double laborcostTotal = 0;
                double machinecostTotal = 0;
                double fuelcostTotal = 0;
                double auxicostTotal = 0;
                double othercostTotal = 0;
                if(ascr.getLayer().equals("12")){
                    log.info("12");
                }

                if (ascr.getManuType().equals("F")) {
                    materialCost = ascr.getMaterial().doubleValue() * ascr.getTopnum().doubleValue();
                    materialCost_acc+=materialCost;
                } else if ((ascr.getManuType().equals("E") || ascr.getManuType().equals("F30"))) {
                    double labor = ascr.getLabor().doubleValue();
                    double equip = ascr.getEquip().doubleValue();
                    double fuel = ascr.getFuel().doubleValue();
                    double auxi = ascr.getAuxi().doubleValue();
                    double other = ascr.getOther().doubleValue();
                    materialCost = ascr.getMaterial().doubleValue()* ascr.getTopnum().doubleValue();;
                    laborhour = labor * ascr.getTopnum().doubleValue()/60;
                    machinehour = equip * ascr.getTopnum().doubleValue()/60;
                    fuelhour = fuel * ascr.getTopnum().doubleValue()/60;
                    auxihour = auxi * ascr.getTopnum().doubleValue()/60;
                    otherhour = other * ascr.getTopnum().doubleValue()/60;

                    laborCost = laborhour*0.82548;
                    equipmentCost = machinehour*1.20312;
                    fuelcost = fuelhour*0.17544;
                    auxicost = auxihour*0.21342;
                    otherCost = otherhour*0.77826;


//                    if(ascr.getLayer().equals("0-15")){
//                        log.info("Debug");
//                    }

                    for (AppSceneCostStandardResult child : appSceneCostStandardResults) {
                        String layer = child.getLayer();
                        int index = layer.lastIndexOf(".");
                        String player = "0";
                        if(index!=-1){
                            player = layer.substring(0,index);
                        }
                        if(player.equals(ascr.getLayer())){
                            if (child.getManuType().equals("F")) {
                                //materialCost_acc += child.getMaterialCostTotal().doubleValue() * ascr.getNum().doubleValue();
                                materialCost_acc += child.getMaterialCostTotal().doubleValue() ;
                            } else if ((child.getManuType().equals("E") || child.getManuType().equals("F30"))) {
                                materialCost_acc += child.getMaterialCostTotal().doubleValue()  ;
                                laborhourTotal += child.getLaborHourTotal().doubleValue() ;
                                machinehourTotal += ( child.getEquipHourTotal().doubleValue()) ;
                                fuelhourTotal += ( child.getFuelHourTotal().doubleValue()) ;
                                auxihourTotal += ( child.getAuxiHourTotal().doubleValue()) ;
                                otherhourTotal += (child.getOtherHourTotal().doubleValue()) ;
                            }
                        }
//                        if ((Integer.parseInt(child.getLowOrderCode()) == depth + 1) && child.getParentMatnr().equals(ascr.getMarterialNo())) {
//
//                            if (child.getManuType().equals("F")) {
//                                materialCost_acc += child.getMaterialCostTotal().doubleValue() * ascr.getNum().doubleValue();
//                            } else if ((child.getManuType().equals("E") || child.getManuType().equals("F30"))) {
//                                materialCost_acc += child.getMaterialCostTotal().doubleValue() * ascr.getNum().doubleValue() ;
//                                laborhourTotal += child.getLaborHourTotal().doubleValue() * ascr.getNum().doubleValue();
//                                machinehourTotal += ( child.getMachineHourTotal().doubleValue()) * ascr.getNum().doubleValue();
//                                fuelhourTotal += ( child.getFuelHourTotal().doubleValue()) * ascr.getNum().doubleValue();
//                                auxihourTotal += ( child.getAuxiHourTotal().doubleValue()) * ascr.getNum().doubleValue();
//                                otherhourTotal += (child.getOtherHourTotal().doubleValue()) * ascr.getNum().doubleValue();
//                            }
//                        }
                    }
                    laborhourTotal+=laborhour;
                    machinehourTotal+=machinehour;
                    fuelhourTotal+=fuelhour;
                    auxihourTotal+=auxihour;
                    otherhourTotal+=otherhour;

                    laborcostTotal = laborhourTotal*0.82548;
                    machinecostTotal = machinehourTotal*1.20312;
                    fuelcostTotal = fuelhourTotal*0.17544;
                    auxicostTotal = auxihourTotal*0.21342;
                    othercostTotal = otherhourTotal*0.77826;

                    materialCost_acc+=materialCost;
                }
                String maktx = "";
                if (maktxMap.containsKey(ascr.getMarterialNo())) {
                    maktx = maktxMap.get(ascr.getMarterialNo());
                }
                //if(ascr.getLayer().equals("0")){
                //    materialCost = materialCost_acc;
                //}
                double standardCost = materialCost+laborCost+equipmentCost+fuelcost+auxicost+otherCost;
                double total = materialCost_acc + laborcostTotal + machinecostTotal + fuelcostTotal + auxicostTotal + othercostTotal;
                AppSceneCostStandardResult appSceneCostStandardResult = AppSceneCostStandardResult.builder()
                        .materialNumber(ascr.getMarterialNo())
                        .parentMatnr(ascr.getParentMarterialNo())
                        .pricetype(ascr.getPriceType())
                        .laborHour(new BigDecimal(laborhour))
                        .equipHour(new BigDecimal(machinehour))
                        .fuelHour(new BigDecimal(fuelhour))
                        .auxiHour(new BigDecimal(auxihour))
                        .otherHour(new BigDecimal(otherhour))
                        .laborCost(new BigDecimal(laborCost))
                        .equipCost(new BigDecimal(equipmentCost))
                        .fuelCost(new BigDecimal(fuelcost))
                        .auxiliaryCost(new BigDecimal(auxicost))
                        .otherCost(new BigDecimal(otherCost))
                        .laborHourTotal(new BigDecimal(laborhourTotal))
                        .equipHourTotal(new BigDecimal(machinehourTotal))
                        .fuelHourTotal(new BigDecimal(fuelhourTotal))
                        .auxiHourTotal(new BigDecimal(auxihourTotal))
                        .otherHourTotal(new BigDecimal(otherhourTotal))
                        .standardCost(new BigDecimal(standardCost))
                        .purchasePrice(new BigDecimal(ascr.getMaterial().doubleValue()))
                        .materialCost(new BigDecimal(materialCost))
                        .supplier(ascr.getSupplier())
                        .supplierName(ascr.getSupplierName())
                        .tempContractPrice(ascr.getEkpoPrice())
                        .invoicePrice(ascr.getInvoicePrice())
                        .invoiceTotal(ascr.getInvoicePrice().multiply(ascr.getTopnum()))
                        .invoiceDiff(ascr.getInvoicePrice().multiply(ascr.getTopnum()).subtract(new BigDecimal(total)))
                        //.materialCostStage(new BigDecimal(materialCost))
//                        .laborCostStage(new BigDecimal(laborCost))
//                        .equipCostStage(new BigDecimal(equipmentCost))
//                        .burningCostStage(new BigDecimal(fuelcost))
//                        .auxiliaryCostStage(new BigDecimal(auxicost))
//                        .otherCostStage(new BigDecimal(otherCost))
                        //.materialCostAccumulated(new BigDecimal(materialCost_acc))
//                        .laborCostAccumulated(new BigDecimal(laborCost_acc))
//                        .equipCostAccumulated(new BigDecimal(equipmentCost_acc))
//                        .burningCostAccumulated(new BigDecimal(fuelcost_acc))
//                        .auxiliaryCostAccumulated(new BigDecimal(auxicost_acc))
//                        .otherCostAccumulated(new BigDecimal(otherCost_acc))
                        .materialCostTotal(new BigDecimal(materialCost_acc))
                        .laborCostTotal(new BigDecimal(laborcostTotal ))
                        .equipCostTotal(new BigDecimal(machinecostTotal ))
                        .fuelCostTotal(new BigDecimal(fuelcostTotal ))
                        .auxiliaryCostTotal(new BigDecimal(auxicostTotal ))
                        .otherCostTotal(new BigDecimal(othercostTotal ))
                        .totalStandardCost(new BigDecimal(total))
                        .lowOrderCode(String.valueOf(depth))
                        //.relativeDosage(ascr.getNum())
                        .createdTime(new Date())
                        .menge(ascr.getTopnum())
                        .manuType(ascr.getManuType())
                        .versionNumber(versionNumber)
                        .stage(stage)
                        .layer(ascr.getLayer())
                        .player(ascr.getPlayer())
                        .pricetype(ascr.getPlayer())
                        .factory(ascr.getWerks())
                        .maktx(maktx)
                        .ymonth(sdf.format(new Date()))
                        .factory(ascr.getWerks())
                        .build();
                appSceneCostStandardResults.add(appSceneCostStandardResult);
            }
        }
        Collections.sort(appSceneCostStandardResults, new Comparator<AppSceneCostStandardResult>() {

            public double convertlayertodouble(String layer){
                String[] array = layer.split("\\.");
                if(array.length==0){
                    return Double.parseDouble(layer);
                }else{
                    double value = 0;
                    for(int i=0;i<array.length;++i){
                        value+=Double.parseDouble(array[i])*Math.pow(10.0,-i*3.0);
                    }
                    return value;
                }
            }
            @Override
            public int compare(AppSceneCostStandardResult o1, AppSceneCostStandardResult o2) {
                double d1=convertlayertodouble(o1.getLayer());
                double d2 = convertlayertodouble(o2.getLayer());
                if(d1>d2){
                    return 1;
                }else{
                    return -1;
                }
                //return Double.parseDouble(o1.getLayer())-Double.parseDouble(o2.getLayer());
            }
        });
        standardCostService.iAppSceneCostStandardResultService.saveBatch(appSceneCostStandardResults);

        List<String> idnrklist = new ArrayList<>();
        for (String matnr:idnrks){
            idnrklist.add(matnr);
        }
        QueryWrapper<AppSceneCostMaterial> queryWrapper1=new QueryWrapper<>();
        queryWrapper1.in("material_number",idnrklist);
        List<AppSceneCostMaterial> materials=standardCostService.iAppSceneCostMaterialService.list(queryWrapper1);
        Map<String,AppSceneCostMaterial> mapMaterial=new HashMap<>();
        for (AppSceneCostMaterial material:materials){
            if(!mapMaterial.containsKey(material.getMaterialNumber())){
                mapMaterial.put(material.getMaterialNumber(),material);
            }
        }

        List<String> matnrlist = new ArrayList<>();
        for (String matnr:matnrs){
            matnrlist.add(matnr);
        }
        //保存app_scene_cost_standard_bom
        QueryWrapper<AppSceneCostBomRelevancy> queryWrapper=new QueryWrapper<>();
        queryWrapper.in("matnr",matnrlist);
        List<AppSceneCostBomRelevancy> appSceneCostBomRelevancies=standardCostService.iAppSceneCostBomRelevancyService.list(queryWrapper);
        List<AppSceneCostStandardBom> standardBoms=new ArrayList<>();
        for (AppSceneCostBomRelevancy bomRelevancy:appSceneCostBomRelevancies){
            AppSceneCostStandardBom standardBom=AppSceneCostStandardBom.builder()
                    .matnr(bomRelevancy.getMatnr())
                    .versionNumber(versionNumber)
                    .posnr(bomRelevancy.getPosnr())
                    .werks(bomRelevancy.getWerks())
                    .bmeng(bomRelevancy.getBmeng())
                    .idnrk(bomRelevancy.getIdnrk())
                    .menge(bomRelevancy.getMenge())
                    .oldMaterialGroup("")
                    .manufacturingType("")
                    .sobsl("")
                    .productName("")
                    .materialType("")
                    .build();
            if(mapMaterial.containsKey(bomRelevancy.getIdnrk())){
                AppSceneCostMaterial material=mapMaterial.get(bomRelevancy.getIdnrk());
                standardBom.setOldMaterialGroup(material.getOldMaterialGroup());
                standardBom.setManufacturingType(material.getManufacturingType());
                standardBom.setSobsl(material.getSobsl());
                standardBom.setProductName(material.getProductName());
                standardBom.setMaterialType(material.getMaterialType());
            }
            standardBoms.add(standardBom);
        }
        standardCostService.iAppSceneCostStandardBomService.saveBatch(standardBoms);

        List<AppSceneCostHourRate> hourRates=standardCostService.iHourRateService.list();
        Map<String,AppSceneCostHourRate> hourRateMap=new HashMap<>();
        for (AppSceneCostHourRate hourRate:hourRates){
            hourRateMap.put(hourRate.getCostCenterCode(),hourRate);
        }

        //保存app_scene_cost_standard_productprocess
        QueryWrapper<AppSceneCostProductProcessMaintenance> queryWrapper2=new QueryWrapper<>();
        queryWrapper2.in("main_part_number",matnrlist);
        List<AppSceneCostProductProcessMaintenance> productProcessMaintenances=standardCostService.iAppSceneCostProductProcessMaintenanceService.list(queryWrapper2);
        List<AppSceneCostStandardProductprocess> standardProductprocesses=new ArrayList<>();
        for (AppSceneCostProductProcessMaintenance maintenance:productProcessMaintenances){
            AppSceneCostStandardProductprocess productprocess=AppSceneCostStandardProductprocess.builder()
                    .factory(maintenance.getFactory())
                    .mainPartNumber(maintenance.getMainPartNumber())
                    .processRouteNumber(maintenance.getProcessRouteNumber())
                    .serialNumber(maintenance.getSerialNumber())
                    .processName(maintenance.getProcessName())
                    .costCenterCode(maintenance.getCostCenterCode())
                    .prepareHour(maintenance.getPrepareHour())
                    .laborHour(maintenance.getLaborHour())
                    .machineHour(maintenance.getMachineHour())
                    .burningHour(maintenance.getBurningHour())
                    .auxiliaryHour(maintenance.getAuxiliaryHour())
                    .otherHour(maintenance.getOtherHour())
                    .versionNumber(versionNumber)
                    .build();
            if(hourRateMap.containsKey(maintenance.getCostCenterCode())){
                AppSceneCostHourRate hourRate=hourRateMap.get(maintenance.getCostCenterCode());
                productprocess.setLaborHourRate(hourRate.getLaborHourRate());
                productprocess.setEquipHourRate(hourRate.getEquipHourRate());
                productprocess.setFuelHourRate(hourRate.getFuelHourRate());
                productprocess.setAuxiliaryHourRate(hourRate.getAuxiliaryHourRate());
                productprocess.setOtherHourRate(hourRate.getOtherHourRate());
            }
            standardProductprocesses.add(productprocess);
        }
        standardCostService.iAppSceneCostStandardProductprocessService.saveBatch(standardProductprocesses);


        //更新标准成本计算状态
        if(appSceneCostStandardResults.size()>0){
            AppSceneCostStandardResult appSceneCostStandardResult = appSceneCostStandardResults.get(0);

            QueryWrapper<AppSceneCostAufnrMatnr> wrapper=new QueryWrapper<>();
            wrapper.eq("matnr",appSceneCostStandardResult.getMaterialNumber());
            List<AppSceneCostAufnrMatnr> appSceneCostAufnrMatnrs=standardCostService.iAppSceneCostAufnrMatnrService.list(wrapper);



            AppSceneCostCount appSceneCostCount = standardCostService.appSceneCostCountService.queryByVersion(appSceneCostStandardResult.getVersionNumber());
            if(appSceneCostCount!=null){
                appSceneCostCount.setStatus(2);
                appSceneCostCount.setStandardTotal(appSceneCostStandardResult.getTotalStandardCost());
                appSceneCostCount.setMaterialCost(appSceneCostStandardResult.getMaterialCostTotal());
                appSceneCostCount.setLaborCost(appSceneCostStandardResult.getLaborCostTotal());
                appSceneCostCount.setEquipCost(appSceneCostStandardResult.getEquipCostTotal());
                appSceneCostCount.setFuelCost(appSceneCostStandardResult.getFuelCostTotal());
                appSceneCostCount.setAuxiCost(appSceneCostStandardResult.getAuxiliaryCostTotal());
                appSceneCostCount.setOtherCost(appSceneCostStandardResult.getOtherCostTotal());
                appSceneCostCount.setLaborHour(appSceneCostStandardResult.getLaborHourTotal());
                appSceneCostCount.setMachineHour(appSceneCostStandardResult.getEquipHourTotal());
                appSceneCostCount.setFlowDefinitionId(flowInstanceId);
                appSceneCostCount.setCreateBy(0);
                appSceneCostCount.setUpdateBy(0);
                appSceneCostCount.setUpdateTime(new Date());
                appSceneCostCount.setAufnr("");
                appSceneCostCount.setMaktx(appSceneCostStandardResult.getMaktx());
                if(appSceneCostAufnrMatnrs.size()>0){
                    appSceneCostCount.setAufnr(appSceneCostAufnrMatnrs.get(0).getAufnr());
                }
                standardCostService.appSceneCostCountService.updateById(appSceneCostCount);
            }
        }

        //3.计算出所有的单个物料的累计标准成本
        //List<AppSceneCostResultValue> standardCostList = standardCostService.iAppSceneCostResultValueService.getResultValueByTopMaterialNo(topMaterialCode, taskType, String.valueOf(flowInstanceId));
        //【累计成本】的计算
        //totalCountCost(standardCostList, topMaterialCode, taskType, taskCode, String.valueOf(flowInstanceId), versionNumber);
    }

    /**
     * 获取任务流程相关信息
     *
     * @param parameters
     * @return
     */
    private static FlowTaskInfoVO analysisFlowTaskInfo(TaskExecutionContext parameters) {
        FlowTaskInfoVO flowTaskInfoVO = new FlowTaskInfoVO();
        if (parameters != null) {
            String s = parameters.toString();
            String[] split = s.split(",");
            for (int i = 0; i < split.length; i++) {
                String s1 = split[i];
                if (s1.contains("taskType")) {
                    String[] split1 = s1.split("=");
                    if (split1[1].contains("\"")) {
                        split1[1] = split1[1].replaceAll("^\"|\"$", ""); // 去除首尾引号
                        flowTaskInfoVO.setTaskType(split1[1]);
                    } else {
                        flowTaskInfoVO.setTaskType(split1[1]);
                    }
                } else if (s1.contains("taskCode")) {
                    String[] split1 = s1.split(":");
                    if (split1[1].contains("\"")) {
                        split1[1] = split1[1].replaceAll("^\"|\"$", ""); // 去除首尾引号
                        flowTaskInfoVO.setTaskCode(split1[1]);
                    } else {
                        flowTaskInfoVO.setTaskCode(split1[1]);
                    }
                } else if (s1.contains("flowInstanceId")) {
                    String[] split1 = s1.split("=");
                    if (split1[1].contains("\"")) {
                        split1[1] = split1[1].replaceAll("^\"|\"$", ""); // 去除首尾引号
                        flowTaskInfoVO.setFlowInstanceId(split1[1]);
                    } else {
                        flowTaskInfoVO.setFlowInstanceId(split1[1]);
                    }
                } else if (s1.contains("sqlString")) {
                    String[] split1 = s1.split(":");
                    if (split1[1].contains("\"")) {
                        split1[1] = split1[1].replaceAll("^\"|\"$", ""); // 去除首尾引号
                        flowTaskInfoVO.setSqlString(split1[1]);
                    } else {
                        flowTaskInfoVO.setSqlString(split1[1]);
                    }
                } else if (s.contains("feeType") && s1.contains("feeType")) {
                    String[] split1 = s1.split(":");
                    if (split1[1].contains("\"")) {
                        split1[1] = split1[1].replaceAll("^\"|\"$", ""); // 去除首尾引号
                        flowTaskInfoVO.setFeeType(split1[1]);
                    } else {
                        flowTaskInfoVO.setFeeType(split1[1]);
                    }
                }
            }
        }
        //通过任务流程id查询流程定义信息（qomo_flow_definition）
        flowTaskInfoVO = queryFlowDefinitionByFlowInstanceId(flowTaskInfoVO);
        return flowTaskInfoVO;
    }

    /**
     * @param flowTaskInfoVO
     */
    private static FlowTaskInfoVO queryFlowDefinitionByFlowInstanceId(FlowTaskInfoVO flowTaskInfoVO) {
        String sql = "SELECT A.model_json from qomo_flow_definition as A LEFT JOIN   qomo_flow_instance AS B ON A.`code`=B.flow_definition_code  WHERE B.id=" + flowTaskInfoVO.getFlowInstanceId() + " limit 1";
        String blob = standardCostService.appSceneCostBomRelevancyMapper.customSelectBlobModelJson(sql);
        if (blob != null) {
            if (blob != null && blob.contains("topMaterialCode")) {
                JSONObject jsonObject1 = JSON.parseObject(blob);
                String topMaterialCode = jsonObject1.getString("topMaterialCode");
                flowTaskInfoVO.setTopMaterialCode(topMaterialCode);
            }
        }
        return flowTaskInfoVO;
    }

    /**
     * 2. 物料成本任务
     */
    public static void materialCostTask(TaskExecutionContext parameters) {
        try {
            //获取任务流程相关信息
            FlowTaskInfoVO flowTaskInfoVO = analysisFlowTaskInfo(parameters);
            //获取最上层的物料号
            String topMaterialCode = flowTaskInfoVO.getTopMaterialCode();
            //获取任务类型
            String taskType = parameters.getTaskType();
            //获取任务代码
            String taskCode = flowTaskInfoVO.getTaskCode();
            //获取流程id
            String flowInstanceId = flowTaskInfoVO.getFlowInstanceId();
            //成本类型
            String feeType = FeeTypeEnum.MaterialCost.getCode();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 3.人工成本任务
     */
    public static void laborCostTask(TaskExecutionContext parameters) {
        try {
            //获取任务流程相关信息
            FlowTaskInfoVO flowTaskInfoVO = analysisFlowTaskInfo(parameters);
            //获取最上层的物料号
            String topMaterialCode = flowTaskInfoVO.getTopMaterialCode();
            //获取任务类型
            String taskType = parameters.getTaskType();
            //获取任务代码
            String taskCode = flowTaskInfoVO.getTaskCode();
            //获取流程id
            String flowInstanceId = flowTaskInfoVO.getFlowInstanceId();
            //成本类型
            String feeType = FeeTypeEnum.LaborCost.getCode();
            String sql1 = flowTaskInfoVO.getSqlString();
            log.info("sql1:" + sql1);
            String sql = sql1.replaceAll("^\"|\"$", ""); // 去除首尾引号
            log.info("sql:" + sql);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 4.制造费用成本任务
     */
    public static void manufacturingCostTask(TaskExecutionContext parameters) {
        try {
            //获取任务流程相关信息
            FlowTaskInfoVO flowTaskInfoVO = analysisFlowTaskInfo(parameters);
            //获取最上层的物料号
            String topMaterialCode = flowTaskInfoVO.getTopMaterialCode();
            //获取任务类型
            String taskType = parameters.getTaskType();
            //获取任务代码
            String taskCode = flowTaskInfoVO.getTaskCode();
            //获取流程id
            String flowInstanceId = flowTaskInfoVO.getFlowInstanceId();
            /**
             * 费用类别
             */
            String feeType = flowTaskInfoVO.getFeeType();
            /**
             * 小时费率
             */
            String sql1 = flowTaskInfoVO.getSqlString();
            log.info("sql1:" + sql1);
            String sql = sql1.replaceAll("^\"|\"$", ""); // 去除首尾引号
            log.info("sql:" + sql);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 5.标准成本计算任务
     */
    public static void standardCostTask(TaskExecutionContext parameters) {
        try {
            //获取任务流程相关信息
            FlowTaskInfoVO flowTaskInfoVO = analysisFlowTaskInfo(parameters);
            //获取最上层的物料号
            String topMaterialCode = flowTaskInfoVO.getTopMaterialCode();
            //获取任务类型
            String taskType = parameters.getTaskType();
            //获取任务代码
            String taskCode = flowTaskInfoVO.getTaskCode();
            //获取流程id
            String flowInstanceId = flowTaskInfoVO.getFlowInstanceId();
            String costType = FeeTypeEnum.StandardCost.getCode();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("计算成本失败");
        }
    }

    /**
     * 循环算出各个物料的累计成本
     *
     * @param standardCostList
     * @param topMaterialCode
     * @param taskType
     * @param taskCode
     * @param flowInstanceId
     */
    private static void totalCountCost(List<AppSceneCostResultValue> standardCostList, String topMaterialCode, String taskType, String taskCode, String flowInstanceId, String versionNumber) {
        try {
            List<AppSceneCostStandardResult> costStandardResults = new ArrayList<>();
            //父类对应的子节点（除了最上层节点）
            Map<String, List<AppSceneCostResultValue>> parentMaterialNoMap = standardCostList.stream().filter(appSceneCostResultValue -> appSceneCostResultValue.getParentMarterialNo() != null).collect(Collectors.groupingBy(AppSceneCostResultValue::getParentMarterialNo));
            for (int i = 0; i < standardCostList.size(); i++) {
                //当前节点及其对应的本阶成本
                AppSceneCostResultValue oldAppSceneCostResultValue = standardCostList.get(i);
                BigDecimal totalCost = new BigDecimal(oldAppSceneCostResultValue.getCountValue());
                //循环计算出当前节点的累计成本
                String costDetail = oldAppSceneCostResultValue.getCostDetail();
                //查询当前节点各个类型的成本
                BigDecimal totalMaterialCost = new BigDecimal(0);
                BigDecimal totalLabourCost = new BigDecimal(0);
                BigDecimal totalEquipmentCost = new BigDecimal(0);
                BigDecimal totalSupplyMaterialCost = new BigDecimal(0);
                BigDecimal totalDriveCost = new BigDecimal(0);
                BigDecimal totalLogisticsCost = new BigDecimal(0);
                BigDecimal totalOtherCost = new BigDecimal(0);
                JSONObject costDetailJson = JSON.parseObject(costDetail);
                TotalResultValue hourOrRateResultValue = loopCount(oldAppSceneCostResultValue, parentMaterialNoMap, totalMaterialCost, totalLabourCost, totalEquipmentCost, totalSupplyMaterialCost, totalDriveCost, totalLogisticsCost, totalOtherCost, totalCost);
                costDetailJson.put(TotalCostEnum.TotalMaterialCost.getCode(), hourOrRateResultValue.getTotalMaterialCost());
                costDetailJson.put(TotalCostEnum.TotalLaborCost.getCode(), hourOrRateResultValue.getTotalLabourCost());
                costDetailJson.put(TotalCostEnum.TotalEquipmentFee.getCode(), hourOrRateResultValue.getTotalEquipmentCost());
                costDetailJson.put(TotalCostEnum.TotalSupplyMaterialFee.getCode(), hourOrRateResultValue.getTotalSupplyMaterialCost());
                costDetailJson.put(TotalCostEnum.TotalDriverFee.getCode(), hourOrRateResultValue.getTotalDriveCost());
                costDetailJson.put(TotalCostEnum.TotalLogisticsFee.getCode(), hourOrRateResultValue.getTotalLogisticsCost());
                costDetailJson.put(TotalCostEnum.TotalOtherFee.getCode(), hourOrRateResultValue.getTotalOtherCost());
                costDetailJson.put(TotalCostEnum.TotalStandardCost.getCode(), hourOrRateResultValue.getTotalCost());
                oldAppSceneCostResultValue.setCostDetail(costDetailJson.toJSONString());
                oldAppSceneCostResultValue.setTotalValue(hourOrRateResultValue.getTotalCost().toString());
                standardCostService.iAppSceneCostResultValueService.updateById(oldAppSceneCostResultValue);
                //构造单行成本查询记录
                AppSceneCostStandardResult costStandardResultValue = AppSceneCostStandardResult.builder().materialNumber(oldAppSceneCostResultValue.getMarterialNo()).parentMatnr(oldAppSceneCostResultValue.getParentMarterialNo()).versionNumber(versionNumber)
//                    .level()
//                    .sort()
//                    .figureNumber()
//                        .dosage(oldAppSceneCostResultValue.getNum() != null ? oldAppSceneCostResultValue.getNum().doubleValue() : 0).unit(oldAppSceneCostResultValue.getUnit())
                        .materialCostTotal(costDetailJson.getBigDecimal(FeeTypeEnum.MaterialCost.getCode()))
                        //.laborCostStage(costDetailJson.getBigDecimal(FeeTypeEnum.LaborCost.getCode()))
                        //.equipCostStage(costDetailJson.getBigDecimal(FeeTypeEnum.EquipmentFee.getCode()))
                        //.auxiliaryCostStage(costDetailJson.getBigDecimal(FeeTypeEnum.SupplyMaterialFee.getCode()))
                        //.burningCostStage(costDetailJson.getBigDecimal(FeeTypeEnum.DriverFee.getCode()))
                        //.otherCostStage(costDetailJson.getBigDecimal(FeeTypeEnum.OtherFee.getCode()))
                        .totalStandardCost(new BigDecimal(oldAppSceneCostResultValue.getCountValue()))
                        //.materialCostAccumulated(costDetailJson.getBigDecimal(TotalCostEnum.TotalMaterialCost.getCode()))
                        //.laborCostAccumulated(costDetailJson.getBigDecimal(TotalCostEnum.TotalLaborCost.getCode()))
                        //.equipCostAccumulated(costDetailJson.getBigDecimal(TotalCostEnum.TotalEquipmentFee.getCode()))
                        //.auxiliaryCostAccumulated(costDetailJson.getBigDecimal(TotalCostEnum.TotalSupplyMaterialFee.getCode()))
                        //.burningCostAccumulated(costDetailJson.getBigDecimal(TotalCostEnum.TotalDriverFee.getCode()))
                        //.otherCostAccumulated(costDetailJson.getBigDecimal(TotalCostEnum.TotalOtherFee.getCode()))
                        .totalStandardCost(costDetailJson.getBigDecimal(TotalCostEnum.TotalStandardCost.getCode()))
                        .lowOrderCode(String.valueOf(oldAppSceneCostResultValue.getDepth()))
                        .createdTime(new Date()).build();
                costStandardResults.add(costStandardResultValue);
            }
            //更新结果集到标准成本单行查询中去
            standardCostService.iAppSceneCostStandardResultService.saveBatch(costStandardResults);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * //循环算出各个物料的累计成本
     * 递归计算出累计成本
     *
     * @param appSceneCostResultValue
     * @param parentMaterialNoMap
     */
    private static TotalResultValue loopCount(AppSceneCostResultValue appSceneCostResultValue, Map<String, List<AppSceneCostResultValue>> parentMaterialNoMap, BigDecimal totalMaterialCost, BigDecimal totalLabourCost, BigDecimal totalEquipmentCost, BigDecimal totalSupplyMaterialCost, BigDecimal totalDriveCost, BigDecimal totalLogisticsCost, BigDecimal totalOtherCost, BigDecimal totalCost) {
        String marterialNo = appSceneCostResultValue.getMarterialNo();
        if (parentMaterialNoMap.containsKey(marterialNo)) {
            //获取当前节点的子节点并遍历
            List<AppSceneCostResultValue> appSceneCostResultValues = parentMaterialNoMap.get(marterialNo);
            for (int j = 0; j < appSceneCostResultValues.size(); j++) {
                AppSceneCostResultValue appSceneCostResultValue1 = appSceneCostResultValues.get(j);
                String countValue = appSceneCostResultValue1.getCountValue();
                //标准成本累计
                if (countValue != null) {
                    totalCost = totalCost.add(new BigDecimal(countValue));
                }
                //各个费用类别成本累计
                if (appSceneCostResultValue1.getCostDetail() != null) {
                    JSONObject costDetailJson = JSON.parseObject(appSceneCostResultValue1.getCostDetail());
                    if (costDetailJson != null) {
                        totalMaterialCost = totalMaterialCost.add(costDetailJson.getBigDecimal(FeeTypeEnum.MaterialCost.getCode()));
                        totalLabourCost = totalLabourCost.add(costDetailJson.getBigDecimal(FeeTypeEnum.LaborCost.getCode()));
                        totalEquipmentCost = totalEquipmentCost.add(costDetailJson.getBigDecimal(FeeTypeEnum.EquipmentFee.getCode()));
                        totalSupplyMaterialCost = totalSupplyMaterialCost.add(costDetailJson.getBigDecimal(FeeTypeEnum.SupplyMaterialFee.getCode()));
                        totalDriveCost = totalDriveCost.add(costDetailJson.getBigDecimal(FeeTypeEnum.DriverFee.getCode()));
                        totalLogisticsCost = totalLogisticsCost.add(costDetailJson.getBigDecimal(FeeTypeEnum.LogisticsFee.getCode()));
                        totalOtherCost = totalOtherCost.add(costDetailJson.getBigDecimal(FeeTypeEnum.OtherFee.getCode()));
                    }
                }
                //判断当前子节点是否还有子节点
                if (parentMaterialNoMap.containsKey(appSceneCostResultValue1.getMarterialNo())) {
                    //如果还有子节点则继续递归
                    loopCount(appSceneCostResultValue1, parentMaterialNoMap, totalMaterialCost, totalLabourCost, totalEquipmentCost, totalSupplyMaterialCost, totalDriveCost, totalLogisticsCost, totalOtherCost, totalCost);
                }
            }
        }
        TotalResultValue hourOrRateResultValue = TotalResultValue.builder().totalMaterialCost(totalMaterialCost).totalLabourCost(totalLabourCost).totalEquipmentCost(totalEquipmentCost).totalSupplyMaterialCost(totalSupplyMaterialCost).totalDriveCost(totalDriveCost).totalLogisticsCost(totalLogisticsCost).totalOtherCost(totalOtherCost).totalCost(totalCost).build();
        appSceneCostResultValue.setTotalValue(totalCost.toString());
        return hourOrRateResultValue;
    }
}
