/**
 * Created by zhang on 2018/2/9.
 */

module.exports = {
  replaceRations: replaceRations,
  addNewRation:addNewRation,
  updateMaterialRation:updateMaterialRation,
  addMaterialRation:addMaterialRation,
  addMultiRation: addMultiRation,
  getSameSectionRations:getSameSectionRations,
  getExtendData:getExtendData,
  getDefaultProgramID:getDefaultProgramID,
  deleteSubListByQuery:deleteSubListByQuery,
  updateCoeAdjust:updateCoeAdjust,
  getUnitPriceData:getUnitPriceData,
  setIDfromCounter:setIDfromCounter,
  getNewProjectGLJFromMissMixratio:getNewProjectGLJFromMissMixratio
};


let mongoose = require('mongoose');
import SearchDao from '../../complementary_ration_lib/models/searchModel';
import GLJListModel from "../../glj/models/glj_list_model";
import e from 'express';
const scMathUtil = require('../../../public/scMathUtil').getUtil();
let gljUtil = require('../../../public/gljUtil');
let ration_glj_facade = require("../../ration_glj/facade/ration_glj_facade");
let glj_calculate_facade = require("../../ration_glj/facade/glj_calculate_facade");
let quantity_detail = require("../facade/quantity_detail_facade");
let ration_glj = mongoose.model('ration_glj');
let ration_coe = mongoose.model('ration_coe');
let ration_model = require('../models/ration');
let bill_model = require('../models/bills');
let decimal_facade = require('./decimal_facade');
let installationFeeModel = mongoose.model("installation_fee");
let rationInstallationModel = mongoose.model('ration_installation');
let rationTemplateModel = mongoose.model('ration_template');
const uuidV1 = require('uuid/v1');
let std_glj_lib_gljList_model = mongoose.model('std_glj_lib_gljList');
let complementary_glj_model =  mongoose.model('complementary_glj_lib');
let rationItemModel = mongoose.model("std_ration_lib_ration_items");
let complementaryRationModel = mongoose.model('complementary_ration_items');
let freightCalcModel = mongoose.model('freight_calc');
let originaltCalcModel = mongoose.model('original_calc');

let coeMolde = mongoose.model('std_ration_lib_coe_list');
let compleCoeModel = mongoose.model('complementary_ration_coe_list');
let projectGLJModel = mongoose.model("glj_list");
let mixRatioModel = mongoose.model("mix_ratio");
let complementaryGljLibModel = mongoose.model('complementary_glj_lib');
let counterModel =  mongoose.model('counter');

let _= require('lodash');
const projectDao = require('../../pm/models/project_model').project;
let projectModel = mongoose.model('projects');
let unitPriceModel = mongoose.model('unit_price');
let unitPriceFileModel = mongoose.model('unit_price_file');
let vvTaxModel =  mongoose.model("std_vehicleVesselTax_items");

const fs = require('fs');

async function addNewRation(data,compilation) {
    let query = data.itemQuery;
    let stdRation = null;
    let startTime = +new Date();
    if(query){
        let searchDao = new SearchDao();
        stdRation = await searchDao.getRationItem(query.userID, compilation._id, [query.rationRepId],query.code, query.ID);
        //data.newData.code = query.code;
    }
    let stdRationTime = +new Date();
    console.log("取std定额时间-------------------------------"+(stdRationTime - startTime));
    if(data.brUpdate.length>0){
        await updateSerialNo(data.brUpdate);
    }
    let newRation =await insertNewRation(data.newData,data.defaultLibID,stdRation,data.calQuantity);
    let addRationGLJTime = +new Date();
    console.log("插入新定额时间-------------------------------"+(addRationGLJTime - stdRationTime));
    if(stdRation){
        return await addRationSubList(stdRation,newRation,data.needInstall,compilation);
    }else {
        return {ration:newRation};
    }
}

async function updateMaterialRation(data,compilation){
    let result = {};
    switch (data.actionType){
        case "add":
            result = await addMaterialRation(data,compilation);
            break;
        case "delete":
            result = await deleteMaterialRation(data);
        case "update":
            result = await modifyMaterialRation(data,compilation);
    }
    return result;
}

async function deleteMaterialRation(data) {
    let model = data.type == "freight"?freightCalcModel:originaltCalcModel;
    await model.update(
        {ID:data.parentID},
        { $pull: { rations: { ID: data.rationID},ration_gljs:{rationID:data.rationID} } },
        { multi: true }
    );
    return data;
}

async function modifyMaterialRation(data,compilation) {
    let model = data.type == "freight"?freightCalcModel:originaltCalcModel;
    if(data.field == "code"){
        let [newRation,ration_gljs,projectGLJList] = await getNewMaterialRationDatas(data,compilation);
        let quantity = data.rations[data.row].quantity;
        newRation.quantity = quantity;
        data.rations[data.row] = newRation;
        _.remove(data.ration_gljs,{rationID:data.rationID});
        data.ration_gljs = data.ration_gljs.concat(ration_gljs);
        await  model.update({'ID':data.parentID},{rations:data.rations,ration_gljs:data.ration_gljs});
        return {ration:newRation,ration_gljs:ration_gljs,projectGLJList:projectGLJList}
    }else {
        let doc = {},pre = "rations.$.";
        let field = pre+data.field;
        doc[field] = data.value;
        if(data.ext){
            for(let key in data.ext){
                doc[pre+key] = data.ext[key];
            }
        }
        if(data.ration_gljs){
            let tasks = [];
            for(let g of data.ration_gljs){
                tasks.push({updateOne: {filter: {'ID':data.parentID,'ration_gljs.ID':g.ID}, update: {"ration_gljs.$.quantity":g.quantity}}})
            }
            await model.bulkWrite(tasks);
        }
        return await  model.update({'ID':data.parentID,'rations.ID':data.rationID},doc);
    }
}

async function addMaterialRation(data,compilation) {
    let [newRation,ration_gljs,projectGLJList] = await getNewMaterialRationDatas(data,compilation);
    let model = data.type == "freight"?freightCalcModel:originaltCalcModel;
    await model.update({ID:data.parentID},{$push:{rations:newRation,ration_gljs:{$each:ration_gljs}}});
    return{ration:newRation,ration_gljs:ration_gljs,projectGLJList:projectGLJList};
}

async function getNewMaterialRationDatas(data,compilation){
    let searchDao = new SearchDao();
    let stdRation = await searchDao.getRationItem(data.userID, compilation._id, data.rationRepIds,data.code);
    if(!stdRation) throw  "找不到指定的定额！";//new Error("找不到指定的定额！");

    let newRation = await createNewMaterialRation(stdRation,data.quantityDecimal,data.projectID);
    let [ration_gljs,projectGLJList] = await addRationGLJ(stdRation,newRation,compilation,true,data.connect_key);
    return [newRation,ration_gljs,projectGLJList];
}


async function createNewMaterialRation(std,quantityDecimal,projectID){
    let newData = {};
    newData.ID = uuidV1();
    newData.projectID = projectID;
    newData.code = std.code;
    newData.name = std.name;
    newData.caption = std.caption;
    newData.unit = std.unit;
    newData.libID = std.rationRepId;
    newData.stdID = std.ID;
    newData.quantity=scMathUtil.roundForObj(1 / FilterNumberFromUnit(std.unit),quantityDecimal);
    newData.from = std.type === 'complementary' ? 'cpt' : 'std';
    newData.rationAssList =await  createRationAss(std,true);
    return newData;
}

async function addMultiRation(datas,compilation) {
    /* let rst = [];
    for(let data of datas){
        let r = await addNewRation(data,compilation);
        rst.push(r);
    }
    return rst; */
    const task = [];
    for (const data of datas) {
        task.push(addNewRation(data, compilation));
    }
    return await Promise.all(task);
}

async function getSameSectionRations(data,userId,compilationId){
    //let userId
    //要先根据定额获取所属章节的ID
    let from = data.from;    //定额类型，是标准的还是用户定义的
    let code = data.code;
    let libID = data.libID;
    let sectionId,rations=[];
    if(from == 'std'){
        let ration = await rationItemModel.findOne({rationRepId:libID,code:code},['sectionId']);
        sectionId = ration? ration.sectionId:null;
    }else {
        let ration = await complementaryRationModel.findOne({userId:userId,compilationId: compilationId,code:code},['sectionId']);
        sectionId = ration?ration.sectionId:null;
    }
    if(sectionId){
        if (from == 'std') {
            rations = await rationItemModel.find({sectionId: sectionId});
        } else {
            rations = await complementaryRationModel.find({userId: userId, sectionId: sectionId});
        }
        rations = _.sortBy(rations,'code');
    }
    return rations
}


async function  updateSerialNo(serialNoUpdate){
    let tasks=[];
    for(let data of serialNoUpdate){
        let task={
            updateOne:{
                filter:{
                    ID:data.ID,
                    projectID:data.projectID
                },
                update :{
                    serialNo:data.serialNo
                }
            }
        };
        tasks.push(task);
    }
    await ration_model.model.bulkWrite(tasks);
}

async function insertNewRation(newData,defaultLibID,std,calQuantity) {//插入新的定额
    let startTime = +new Date();
    if(std){
        newData.code = std.code;
        newData.name = std.name;
        newData.caption = std.caption;
        newData.unit = std.unit;
        newData.libID = std.rationRepId;
        newData.stdID = std.ID;
        newData.content = std.jobContent;
        newData.annotation = std.annotation;
        if (std.chapter) {
            newData.comments = std.chapter.explanation;
            newData.ruleText = std.chapter.ruleText;
        }
        newData.prefix = '';
        newData.from = std.type === 'complementary' ? 'cpt' : 'std';
        if(defaultLibID !== std.rationRepId){//借
            newData.prefix = '借';
        }
        else if(std.rationRepId === defaultLibID && newData.from === 'cpt') {
            newData.prefix = '补';
        }
        if(std.feeType == undefined || std.feeType == null || std.feeType ==''){//定额取费专业为空的情况下，取项目属性中的定额取费专业ID
            newData.programID = await getProgramForProject(newData.projectID);
        }else {
            newData.programID = std.feeType;
        }
        newData.rationAssList =await  createRationAss(std);
        // calculate ration Quantity
    }
    if(calQuantity){
        await CalculateQuantity(newData,newData.billsItemID,newData.projectID);
    }
    let addRationGLJTime = +new Date();
    console.log("计算消耗量时间-------------------------------"+(addRationGLJTime - startTime));
    await ration_model.model.insertMany([newData]);
    return newData;
    /*ration_model.model.create(newData);
    return newData;*/
}

async function replaceRations(userID,data,compilation) {
    let searchDao = new SearchDao();
    let recodes = [];
    for(let recode of data.nodeInfo){
        let stdRation = await searchDao.getRationItem(userID,compilation._id,data.libIDs,recode.newCode, null);
        let newRecode = await replaceRation(recode,stdRation,data.defaultLibID,data.projectID,data.calQuantity,compilation,data.cleanzmhs);
        if(newRecode){
            recodes.push(newRecode);
        }else {
            break;
        }
    }
    return recodes;
}

async function getDefaultProgramID(data) {
    let searchDao = new SearchDao();
    let programID;
    let std = await searchDao.getRationItem(data.userID,data.compilationId,[data.libID],data.code, null);
    if(std == null||std ==undefined || std.feeType == undefined || std.feeType == null || std.feeType ==''){//定额取费专业为空的情况下，取项目属性中的定额取费专业ID
        programID = await getProgramForProject(data.projectID);
    }else {
        programID = std.feeType;
    }
    return programID;
}

async function replaceRation(nodeInfo,stdRation,defaultLibID,projectID,calQuantity,compilation,cleanzmhs) {
    if(nodeInfo.newCode == null||nodeInfo.newCode ==""){//说明是删除编号，则要变成一条空定额
        await deleRationSubRecode(projectID,nodeInfo.ID);//删除定额下挂的各种数据，如定额工料机等
        return await setEmptyRation(projectID,nodeInfo.ID);
    }else if(stdRation){
        await deleRationSubRecode(projectID,nodeInfo.ID,cleanzmhs);//删除定额下挂的各种数据，如定额工料机等
        let newRation = await updateRation(stdRation,defaultLibID,nodeInfo.ID,nodeInfo.billsItemID,projectID,calQuantity,cleanzmhs);//生成并插入新的定额
        return await addRationSubList(stdRation,newRation,nodeInfo.needInstall,compilation,cleanzmhs);
    }else {
        return null;
    }
}

async function addRationSubList(stdRation,newRation,needInstall,compilation,cleanzmhs=false) {
    let startTime = +new Date();
    let [ration_gljs,projectGLJList] = await addRationGLJ(stdRation,newRation,compilation);
    let addRationGLJTime = +new Date();
    console.log("添加定额工料机时间-----"+(addRationGLJTime - startTime));
    let ration_coes = await addRationCoe(stdRation,newRation,compilation);
    let addRationCoeTime = +new Date();
    console.log("添加定额coe时间-----"+(addRationCoeTime - addRationGLJTime));
    let ration_installations = [];
    let ration_template = [];
    if(cleanzmhs == false){//清除子目换算即cleanzmh==true时 模板子目、安装增加费不用恢复成标准的
        if(needInstall && stdRation.type == 'std'){//只有标准的定额才有安装增加费，补充的定额没有安装增加费
            ration_installations =  await addRationInstallFee(stdRation,newRation);
        }
        let addRationInstallFeeTime = +new Date();
        console.log("添加定额install时间-----"+(addRationInstallFeeTime - addRationCoeTime));
        //添加定额模板子目
        ration_template = await addRationTemplate(stdRation,newRation);
    }
    return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:ration_template?[ration_template]:[],projectGLJList:projectGLJList};
}

async function addRationInstallFee(std,newRation) {
    let install_fee_list = [];
    if(std.hasOwnProperty('rationInstList') && std.rationInstList.length > 0){
        let installFee = await installationFeeModel.findOne({'projectID': newRation.projectID});
        if(!installFee) return;//如果没有找到项目对应的安装增加费，则不添加
        for(let ri of std.rationInstList){
            let feeItem = _.find(installFee.installFeeItem,{'ID':ri.feeItemId});
            let section = _.find(installFee.installSection,{'ID':ri.sectionId});
            if(feeItem&&section){
                let tem_r_i = {
                    libID:installFee.libID,
                    projectID:newRation.projectID,
                    rationID:newRation.ID,
                    feeItemId:feeItem.ID,
                    sectionId:section.ID,
                    itemName:feeItem.feeItem,
                    feeType:feeItem.feeType,
                    sectionName:section.name,
                    unifiedSetting:1,
                    ruleId:''
                };
                if(feeItem.isCal==1&&section.feeRuleId&&section.feeRuleId!=''){//勾选记取时并且有规则ID时才读取
                    let feeRule = _.find(installFee.feeRule,{'ID':section.feeRuleId});
                    if(feeRule){
                        tem_r_i.ruleId = feeRule.ID;
                    }
                }
                tem_r_i.ID = uuidV1();
                install_fee_list.push(tem_r_i);
            }
        }
        if(install_fee_list.length>0){
            await rationInstallationModel.insertMany(install_fee_list);
        }
    }

    return install_fee_list;
}

async function addRationTemplate(std,newRation) {
    let templateList = [];
    if(std.hasOwnProperty('rationTemplateList') && std.rationTemplateList.length > 0){
        for(let tem of std.rationTemplateList){
            let re_ration = await rationItemModel.findOne({rationRepId:std.rationRepId,ID:tem.rationID});
            if(re_ration){
                let template = {
                    billID:"",
                    fxID:"",
                    quantity:"0",
                    coe:"0"
                };
                template.code = re_ration.code;
                template.name = re_ration.name;
                template.type = tem.type;
                template.unit = re_ration.unit;
                template.billsLocation = tem.billsLocation;
                template.defaultLocation = tem.billsLocation;
                templateList.push(template)
            }
        }
    }
    if(templateList.length > 0){
        let ration_template = {};
        ration_template.ID = uuidV1();
        ration_template.projectID = newRation.projectID;
        ration_template.rationID = newRation.ID;
        ration_template.createLocation = 1; //默认模板子目分别放在措施项目下
        ration_template.templateList = templateList;
        await  rationTemplateModel.create(ration_template);
        return ration_template;
    }
    return null;
}


async function addRationCoe(std,newRation,compilation) {
    let ration_coe_list = [];
    let seq = 0;
    let stdCoeIDs = [];
    let coeMap={}

    if(std.hasOwnProperty('rationCoeList')&&std.rationCoeList.length>0){//添加标准库的工料机
        for(let sub of std.rationCoeList){
            let libCoe;
            if (std.type === 'std') {
                libCoe = await coeMolde.findOne({'libID':std.rationRepId,'ID':sub.ID,"$or": [{"isDeleted": null}, {"isDeleted": false}]});//std.rationRepId;
            } else {
                libCoe = await compleCoeModel.findOne({ID: sub.ID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
            }
            if(libCoe){
                let newCoe = {};
                newCoe.ID = uuidV1();
                newCoe.coeID = sub.ID;
                newCoe.seq = seq;
                newCoe.name = libCoe.name;
                newCoe.content = libCoe.content;
                newCoe.original_code = libCoe.original_code;
                newCoe.option_codes = libCoe.option_codes;
                newCoe.option_list = libCoe.option_list;
                newCoe.isAdjust=0;
                newCoe.coes = libCoe.coes;
                newCoe.rationID = newRation.ID;
                newCoe.projectID = newRation.projectID;
                seq++;
                ration_coe_list.push(newCoe);
            }
        }
    }
    let lastCoe = await getCustomerCoe(newRation.projectID,newRation.ID,seq,compilation);
    ration_coe_list.push(lastCoe);
    await ration_coe.insertMany(ration_coe_list);
    return ration_coe_list;

}

function getCustomerCoeData() {
    var coeList = [
         {amount:1, operator:'*', gljCode:null, coeType:'定额'},
        { amount:1, operator:'*', gljCode:null, coeType:'人工'},
        { amount:1, operator:'*', gljCode:null, coeType:'材料'},
        { amount:1, operator:'*', gljCode:null, coeType:'机械'},
       /* { amount:1, operator:'*', gljCode:null, coeType:'主材'},*/
        { amount:1, operator:'*', gljCode:null, coeType:'设备'}
    ];
    return coeList;
};


async function getCustomerCoe(projectID,rationID,seq,compilation){//取自定义乘系数，根据编办不同，内容可能不同
    //生成默认的自定义乘系数
    let lastCoe ={
        coeID:-1,
        name : '自定义系数',
        content:'人工×1，材料×1，机械×1，设备×1',//主材×1，
        isAdjust:1,
        seq:seq,
        rationID : rationID,
        projectID : projectID
    };
    lastCoe.ID = uuidV1();
    lastCoe.coes = getCustomerCoeData();
    try {
    //查看编办中有没有重写路径  -- 养护中暂时没用到
     /* if(compilation.overWriteUrl && compilation.overWriteUrl!=""){
         let overWrite = require("../../.."+compilation.overWriteUrl);
         if(overWrite.getCusCoeContent) lastCoe.content = overWrite.getCusCoeContent();
         if(overWrite.getCustomerCoeData) lastCoe.coes = overWrite.getCustomerCoeData();
     } */
     return lastCoe
   }catch (err){
       console.log("读取自定义系数重写文件失败");
       console.log(err.message);
       return lastCoe
   }
}

//对于多单价，多组成物消耗量的编办，通过这个方法获取单价、组成物消耗量的字段,
function getExtendData(property,compilation) {
    return projectDao.getExtendData(property,compilation);
}




async function addRationGLJ(std,newRation,compilation,isMaterial,connect_key) {
    let newRationGLJList = [];
    let rationGLJShowList = [];
    let projectGLJList = [];
    let gljKeyMap = {};
    let mixRatioMap={};
    let gljCodes=[];
    let unitPriceFileId = 0;
    let property = await projectDao.getProjectProperty(newRation.projectID);
    if(property){
        unitPriceFileId = property.unitPriceFile !== undefined ? property.unitPriceFile.id : 0;
    }
    let ext = getExtendData(property,compilation);
    let first = +new Date();
    if(std.hasOwnProperty('rationGljList') && std.rationGljList.length > 0){
        let stdGLJID =[];//标准工料机ID数组
        let cptGLJID=[];//补充工料机ID数组
            //let stdGLJID = _.map(std.rationGljList,'gljId');
        for(let tem_g  of std.rationGljList){
             if(tem_g.type == 'complementary'){
                cptGLJID.push(tem_g.gljId);
             }else {
                stdGLJID.push(tem_g.gljId);
             }
        }
       let stdGLJList = stdGLJID.length > 0 ? await std_glj_lib_gljList_model.find({'ID':{'$in':stdGLJID}}).lean():[];//速度优化-------先一次性取出所有的工料机列表
       let stdGLJMap = _.indexBy(stdGLJList, 'ID');
       let cptGLJList =  cptGLJID.length > 0 ? await complementary_glj_model.find({'userId':std.userId,'ID':{'$in':cptGLJID}}).lean():[];
       let cptGLJMap = _.indexBy(cptGLJList, 'ID');
        let stdGLJMapTime = +new Date();
        console.log("找到工料机映射表时间-------------------------------"+(stdGLJMapTime - first));
        if(isMaterial == true){//材料计算添加时要先检查
            for(let sub of std.rationGljList){
                let t_g = getStdGlj(sub,stdGLJMap,cptGLJMap,{},ext);
                if(t_g && connect_key == gljUtil.getIndex(t_g)) throw `本定额中包含工料机${t_g.code}，与当前工料机编号相同，添加定额失败`;
            }
        }
        for(let sub of std.rationGljList){
            let newGLJ = {};
            let proportion = sub.proportion || 0;
            newGLJ.ID = uuidV1();
            newGLJ.projectID = newRation.projectID;
            newGLJ.GLJID = sub.gljId;
            newGLJ.rationID = newRation.ID;
            newGLJ.billsItemID = newRation.billsItemID;
            newGLJ.rationItemQuantity = sub.consumeAmt;
            newGLJ.quantity = sub.consumeAmt;
            newGLJ.glj_repository_id = std.rationRepId;
            newGLJ.rationProportion = proportion;
            newGLJ.adjustProportion = proportion;
            let std_glj = getStdGlj(sub,stdGLJMap,cptGLJMap,{},ext);
            if(std_glj){
                ration_glj_facade.setPropertyFromStd(newGLJ,std_glj);
                let tindex = getIndex(newGLJ);
                if(std_glj.component && std_glj.component.length > 0) mixRatioMap[tindex] = std_glj.component
                let tdata = ration_glj_facade.getGLJSearchInfo(newGLJ);
                gljKeyMap[tindex] = tdata;
                gljCodes.push(tdata.code);
                newRationGLJList.push(newGLJ);
            }
            
        }
        [newRationGLJList, projectGLJList] =  await getProjectGLJinfo(newRation.projectID,newRationGLJList,gljKeyMap,gljCodes,mixRatioMap,unitPriceFileId,ext);
        let InfoFromProjectGLJ = +new Date();
        console.log("找到项目工料机时间-------------------------------"+(InfoFromProjectGLJ - stdGLJMapTime));

    }
    if(isMaterial == true) return [newRationGLJList,projectGLJList];//如果是材料计算的工料机，这里返回就可以了

    if(newRationGLJList.length>0){
        await ration_glj.insertMany(newRationGLJList);
    }
    let after = +new Date();
    console.log("总操作时间为-------------------------------"+(after-first));
    return [newRationGLJList,projectGLJList];
}

async function getProjectGLJinfo(projectID,t_newRationGLJList,gljKeyMap,gljCodes,mixRatioMap,unitPriceFileId,ext){//批量插入或查找项目工料机信息
  //先根据工料机编号在项目工料机中查找工料机是否存在
  let projectGLJMap={};
  let projectGLJList = [];
  let newProjectGLJList=[];//工料机ID要重新去取
  let connectKeyList = [];
  let CCSMap = {keyMap:{},codes:[]};//需要添加车船税的机械台班
  let newRationGLJList=[];

  let gljListModel = new GLJListModel();
  let t_projectGLJList = await projectGLJModel.find({'project_id':projectID,'code':{'$in':gljCodes}}).lean();
  for(let pg of t_projectGLJList){
     let pindex = getIndex(pg);  
     projectGLJMap[pindex] = pg;
  }
  for(let key in gljKeyMap){
    if(!projectGLJMap[key]){//如果项目工料机不存在，则添加
      newProjectGLJList.push(gljKeyMap[key]);
      projectGLJMap[key] = gljKeyMap[key];
      if(gljKeyMap[key].type == 301){//如果是机械台班，需看看有没有车船税
        CCSMap.keyMap[key] = true;
        CCSMap.codes.push(gljKeyMap[key].code);
      }
    }
    //查看组成物
    if(gljListModel.ownCompositionTypes.indexOf(gljKeyMap[key].type)!=-1){//有组成物的类型
      connectKeyList.push(key);
    }
  }


  let [existMixRatioMap,mixRatioInsertData,missCodeList] = await getMixRatioInfo(projectID,projectGLJMap,newProjectGLJList,mixRatioMap,connectKeyList,unitPriceFileId,CCSMap,ext);
  if(missCodeList.length > 0) gljCodes = gljCodes.concat(missCodeList);
 
  //处理车般税相关，车船税是添加项目时，项目工料机，和单价文件里自动添加的 --- todo
 
  let [unitPriceMap,newUnitPriceList] = await getUnitPriceData(newProjectGLJList,gljCodes,unitPriceFileId);


  if(mixRatioInsertData.length > 0) await mixRatioModel.insertMany(mixRatioInsertData);

  //插入项目工料机
  if(newProjectGLJList.length > 0){
    await setIDfromCounter("glj_list",newProjectGLJList);
    await projectGLJModel.insertMany(newProjectGLJList);
  }


  //组装数据
  for(let ration_glj of t_newRationGLJList){
    let rkey = getIndex(ration_glj);
    let pglj = projectGLJMap[rkey];
    let subList = [];
    setUnitPrice(pglj,unitPriceMap);
    if(existMixRatioMap[rkey]){//如果有组成物
      for(let m of existMixRatioMap[rkey]){
         let mpglj = projectGLJMap[getIndex(m)]
         if(mpglj){
          let cglj = _.clone(mpglj); 
          setUnitPrice(cglj,unitPriceMap);
          cglj.ratio_data = m;
          subList.push(cglj);
         }else{
            throw  `组成物${m.name}对应的项目工料机没有找到`;
         }
      }
      pglj.subList =subList; 
    }
    ration_glj.projectGLJID = pglj.id;
    newRationGLJList.push(ration_glj_facade.createNewRecord(ration_glj));
    projectGLJList.push(pglj);
  }

  return [newRationGLJList, projectGLJList];




  function setUnitPrice(p,unitPriceMap){
    p.unit_price = unitPriceMap[getIndex(p)];
  }

}


//找到并返回单价文件信息，如果没有自动插入
async function getUnitPriceData(newProjectGLJList,gljCodes,unitPriceFileId){
  let unitPriceMap = {};
  let newUnitPriceList = [];
  let unitPriceList = await unitPriceModel.find({unit_price_file_id: unitPriceFileId,'code':{'$in':gljCodes}}).lean();
  for(let u of unitPriceList){
    unitPriceMap[getIndex(u)]=u;
  }

  for(let np of newProjectGLJList){
    let pkey = getIndex(np);
    if(unitPriceMap[pkey]) continue;

    let insertData = {
      code: np.code,
      base_price: np.base_price,
      market_price: np.market_price,
      unit_price_file_id: unitPriceFileId,
      name: np.name,
      specs:np.specs?np.specs:'',
      original_code:np.original_code,
      unit:np.unit?np.unit:'',
      type: np.type,
      short_name: np.shortName !== undefined ? np.shortName : '',
      glj_id: np.glj_id,
      is_add:0,
      grossWeightCoe:np.grossWeightCoe,
      purchaseStorageRate:np.purchaseStorageRate,
      offSiteTransportLossRate:np.offSiteTransportLossRate,
      handlingLossRate:np.handlingLossRate
    };
    if(np.from=='cpt') insertData.is_add=1;//如果是来自补充工料机，则都添加新增标记
    if(insertData.code != insertData.original_code) insertData.is_add=1;//添加的时候如果是复制整块来的，可能在源项目中是新增的工料机，这里也要添上(暂时可能还用不到)
    newUnitPriceList.push(insertData);
    unitPriceMap[pkey] = insertData;
  }


  if(newUnitPriceList.length > 0){
    await setIDfromCounter("unit_price",newUnitPriceList);
    await unitPriceModel.insertMany(newUnitPriceList);
  } 

  return [unitPriceMap,newUnitPriceList];


}


async function getMixRatioInfo(projectID,projectGLJMap,newProjectGLJList,mixRatioMap,connectKeyList,unitPriceFileId,CCSMap,ext){//取组成物信息，得到缺少的组成物情况
  let missCodeList = []; //所有组成物信息的编码，用来统一查询对应的项目工料机是否存在
  let existMixRatioMap ={};
  let codeMap={};//用来去重
  let mixRatioInsertData = [];


  // 1. 先检查现在的组成物表中，是否有相关信息 - 生成映射记录
  if(connectKeyList.length > 0){//有组成物的话从数据库中取出组成物信息
    let mixRatioList = await mixRatioModel.find({'unit_price_file_id': unitPriceFileId,'connect_key': {'$in':connectKeyList}}).lean();
    for(let m of mixRatioList){
        //组成物信息分组，查看哪些是已经存在的
       existMixRatioMap[m.connect_key]?existMixRatioMap[m.connect_key].push(m):existMixRatioMap[m.connect_key]=[m];
       //查看组成物对应的项目工料机是否存在，如果不存在，要插入项目工料机
       let mkey = getIndex(m);
       if(!projectGLJMap[mkey] && !codeMap[m.code]){//如果之前查出来的项目工料机中不包含组成物的信息，要加到missCode里面再查找一次项目工料机看是否存在
          missCodeList.push(m.code);
          codeMap[m.code] = true;
       } 
    }

    // 2 将第一步得到的映射表 与在标准库查询父工料机得到的映射表对比，得出哪些组物成还需要添加，获得库ID
    let stdIDs = []; 
    let comIDs = [];
    let missMixRatioGroup = [];
    for(let ck of connectKeyList){//查看项目中组成物信息是否已经存在，如果不存在，则用插定额时获取的组成物信息从数据库中获取
       if(!existMixRatioMap[ck] && mixRatioMap[ck] && mixRatioMap[ck].length > 0){//组成物信息不存在
         let pglj = projectGLJMap[ck];//取出父数据 
         let from =  pglj.from === undefined|| pglj.from ===null || pglj.from === ""?'std' : pglj.from;
         for(let c of mixRatioMap[ck]){
            if(from == "std"){//标准的工料机只来自标准的
                stdIDs.push(c.ID); 
            }else{
              c.isStd?stdIDs.push(c.ID):comIDs.push(c.ID);  
            } 
         } 
         missMixRatioGroup.push({'connect_key':ck,'list':mixRatioMap[ck],'from':from});
       }
    }

    //3.统一查询所有组成物在标准库中的详细信息
    let stdMixMap = {};
    //整理需插入的组成物列表的数据
    //来自标准工料机
    if(stdIDs.length > 0){
      stdIDs = _.uniq(stdIDs);//去重
      let stdMixList =  await std_glj_lib_gljList_model.find({'ID':{'$in':stdIDs}}).lean();
      for(let sm of stdMixList){
        stdMixMap[sm.ID] = sm;
        let skey = getIndex(sm,['code','name','specs','unit','gljType']);
        if(!projectGLJMap[skey] && !codeMap[sm.code]){
          missCodeList.push(sm.code);
          codeMap[sm.code] = true;
        }
      }
    }
    //来自组成物工料机
    let comMixMap = {};
    if(comIDs.length > 0){
      comIDs = _.uniq(comIDs);//去重
      let comMixList = await complementaryGljLibModel.find({'ID':{'$in':comIDs}}).lean();
      for(let cm of comMixList){
        comMixMap[cm.ID] = cm;
        let ckey = getIndex(cm,['code','name','specs','unit','gljType']);
        if(!projectGLJMap[ckey] && codeMap[cm.code]){
          missCodeList.push(cm.code);
          codeMap[cm.code] = true;
        } 
      }
    }
  

    //4.生成需要插入组成物表的数据
    for(let mg of missMixRatioGroup){//整理需要插入组成物列表的数据
        for(let tc of mg.list){
          let consumpiton = tc.consumeAmt;
          //只有标准的工料机的组成物才会有多单价、多组成物消耗量的情况
          if(mg.from == 'std' && ext && ext.quantityField &&( tc.consumeAmtProperty[ext.quantityField]!= undefined && tc.consumeAmtProperty[ext.quantityField]!=null)){
              consumpiton = tc.consumeAmtProperty[ext.quantityField];
          }
          let mfrom = mg.from == 'std' || tc.isStd?'std':'cpt'; 
          let tmp = mfrom == 'std'?stdMixMap[tc.ID]:comMixMap[tc.ID];//取出之前库中查到的工料机
          let mixRatioData = {
              consumption: consumpiton,
              glj_id: tmp.ID,
              unit_price_file_id: unitPriceFileId,
              connect_key: mg.connect_key,
              type: tmp.gljType,
              code: tmp.code,
              specs:tmp.specs?tmp.specs:"",
              name:tmp.name,
              unit:tmp.unit?tmp.unit:'',
              from:mfrom
            };
          mixRatioInsertData.push(mixRatioData);
        }
    }

    //4.5 处理车船税问题,查询机械台班是否需要添加车船税
    if(CCSMap.codes.length > 0){
      let unitFileInfo = await unitPriceFileModel.findOne({id:unitPriceFileId}).lean();
      if(unitFileInfo.vvTaxFileID && unitFileInfo.vvTaxFileID!=""){
        let needCCS = false;
        let items =  await vvTaxModel.find({libID:unitFileInfo.vvTaxFileID,'code':{'$in':CCSMap.codes}}).lean();
        for(let i of items){
          let ikey = getIndex(i);
          if(CCSMap.keyMap[ikey]){
            needCCS = true;
            mixRatioInsertData.push(gljUtil.getBaseCCSMixRatio(unitPriceFileId,i.vehicleVesselTax,ikey))
          }
        }
        if(needCCS && !codeMap["80CCS"]) missCodeList.push("80CCS");
      }
    }


    if(mixRatioInsertData.length > 0) await setIDfromCounter("mix_ratio",mixRatioInsertData,existMixRatioMap,'connect_key');
    //await mixRatioModel.insertMany(mixRatioInsertData);  因为没有事务添加组成物数据要放在添加单价文件数据之后
     

    //5.查询组成物对应的项目工料机是否存在，如果不存在，生成项目工料机信息
    let projectGLJList = await projectGLJModel.find({'project_id':projectID,'code':{'$in':missCodeList}}).lean();
    for(let pg of projectGLJList){
      let pindex = getIndex(pg);  
      projectGLJMap[pindex] = pg;
    }

    let lessMix = [];//组成物表存在，项目工料机不存在的数据
    let lessMixMap = {};//防止重复添加
    for(let connect_key in existMixRatioMap){
      let mixRatios = existMixRatioMap[connect_key]; 
      for(let m of mixRatios){
        let mk = getIndex(m);
        if(!projectGLJMap[mk] && !lessMixMap[mk]){//如果组成物对应的项目工料机不存在
          let nglj = null;
          if(m.from == 'std'){//这里有值，说明是刚添加到组成物文件中的数据   
            nglj = stdMixMap[m.glj_id];
          }else if(m.from == 'cpt'){//这里有值，说明是刚添加到组成物文件中的数据   
            nglj = comMixMap[m.glj_id];
          }    
          if(nglj){
            nglj.from = m.from;
            let np = getProjectGLJNewData(nglj,projectID,ext);
            newProjectGLJList.push(np);
            projectGLJMap[mk] = np;
          }else{//这里没找到，说明是组成物文件里有，但是项目工料机没有的数据
            lessMix.push(m);
          }
          lessMixMap[mk] = true;//只要处理过一次，就不用再重新处理了，机械组成物，比如柴油这些，会出现多次
        }
      }
    }


   //6. 组成物文件里有，但是项目工料机没有的数据（共用单价文件等情况产生）    
    let lessIDList=[];
    let uniqMap ={};//去重
    let lessStdMix = [];//防止组成物中改了名称等，但是通过glj_id取出来的是还没改前的原始数据
    if(lessMix.length > 0){
      for(let lm of lessMix){
        let parentglj = projectGLJMap[lm.connect_key];
        if(!parentglj) throw `含有组成物工料机${lm.connect_key}，没有找到，添加定额失败`;
        if((parentglj.from == "std" || lm.from == "std") && lm.code!="80CCS"){//车船税特殊处理
          if(!uniqMap[lm.glj_id]){
            lessIDList.push(lm.glj_id);
            uniqMap[lm.glj_id] = lm;
          }
          lessStdMix.push(lm);
        }else {//来自组成物的直接设置    
          lm.from = 'cpt';
          lm.gljType = lm.type;
          let t_mg = getProjectGLJNewData(lm,projectID);
          newProjectGLJList.push(t_mg);
          projectGLJMap[getIndex(lm)] = t_mg;
        }
      }
    }

    if(lessIDList.length > 0){
      let less_stds =  await std_glj_lib_gljList_model.find({'ID':{'$in':lessIDList}}).lean();
      let less_stds_map = {};
      for(let les of  less_stds){
        less_stds_map[les.ID] = les;
      }
      for(let t_l_m of lessStdMix){
        let t_nglj = less_stds_map[t_l_m.glj_id];
        t_nglj.from = 'std';
        //防止组成物中改了名称等，但是通过glj_id取出来的是还没改前的原始数据
        t_nglj.name = t_l_m.name;
        t_nglj.code = t_l_m.code;
        t_nglj.gljType = t_l_m.type;
        t_nglj.specs = t_l_m.specs;
        t_nglj.unit = t_l_m.unit;
        let t_np = getProjectGLJNewData(t_nglj,projectID,ext);
        newProjectGLJList.push(t_np);
        projectGLJMap[getIndex(t_l_m)] = t_np;
      }
    }

  }
  return [existMixRatioMap,mixRatioInsertData,missCodeList]

}


//根据缺少项目工料机的组成物信息，反向生成对应的项目工料机
async function getNewProjectGLJFromMissMixratio(projectID,lessMix,projectGLJMap,newProjectGLJList,ext){
  let lessIDList=[];
  let uniqMap ={};//去重
  let lessStdMix = [];//防止组成物中改了名称等，但是通过glj_id取出来的是还没改前的原始数据
  if(lessMix.length > 0){
    for(let lm of lessMix){
      let parentglj = projectGLJMap[lm.connect_key];
      if(!parentglj) throw `含有组成物工料机${lm.connect_key}，没有找到，添加定额失败`;
      if((parentglj.from == "std" || lm.from == "std") && lm.code!="80CCS"){//车船税特殊处理
        if(!uniqMap[lm.glj_id]){
          lessIDList.push(lm.glj_id);
          uniqMap[lm.glj_id] = lm;
        }
        lessStdMix.push(lm);
      }else {//来自组成物的直接设置    
        lm.from = 'cpt';
        lm.gljType = lm.type;
        let t_mg = getProjectGLJNewData(lm,projectID);
        newProjectGLJList.push(t_mg);
        projectGLJMap[getIndex(lm)] = t_mg;
      }
    }
  }

  if(lessIDList.length > 0){
    let less_stds =  await std_glj_lib_gljList_model.find({'ID':{'$in':lessIDList}}).lean();
    let less_stds_map = {};
    for(let les of  less_stds){
      less_stds_map[les.ID] = les;
    }
    for(let t_l_m of lessStdMix){
      let t_nglj = less_stds_map[t_l_m.glj_id];
      t_nglj.from = 'std';
      //防止组成物中改了名称等，但是通过glj_id取出来的是还没改前的原始数据
      t_nglj.name = t_l_m.name;
      t_nglj.code = t_l_m.code;
      t_nglj.gljType = t_l_m.type;
      t_nglj.specs = t_l_m.specs;
      t_nglj.unit = t_l_m.unit;
      let t_np = getProjectGLJNewData(t_nglj,projectID,ext);
      newProjectGLJList.push(t_np);
      projectGLJMap[getIndex(t_l_m)] = t_np;
    }
  }
  return newProjectGLJList;
}


function getProjectGLJNewData(tmp,projectId,ext){
  let gljData = {
      glj_id: tmp.ID,
      repositoryId:tmp.repositoryId,
      project_id: projectId,
      code: tmp.code,
      name: tmp.name,
      specs: tmp.specs?tmp.specs:'',
      unit: tmp.unit === undefined ? '' : tmp.unit,
      type: tmp.gljType,
      adjCoe:tmp.adjCoe,
      original_code:tmp.code,
      materialType: tmp.materialType,   //三材类别
      materialCoe: tmp.materialCoe,
      base_price: tmp.basePrice,
      market_price: tmp.basePrice,
      from:tmp.from?tmp.from:"std"
  };
  if(gljData.from == 'std' && ext && ext.priceField &&(tmp.priceProperty && tmp.priceProperty[ext.priceField]!= undefined && tmp.priceProperty[ext.priceField]!=null)){
    const basePrice = scMathUtil.roundTo(tmp.priceProperty[ext.priceField],-6);
    gljData.base_price = basePrice;
    gljData.market_price = basePrice;
  }
  return gljData;
}

async function setIDfromCounter(name,list,map,keyfield){//map,keyfield

  let update = {$inc: {sequence_value: list.length}};
  let condition = {_id: name};
  let options = {new: true};

  // 先查找更新
  let counter = await counterModel.findOneAndUpdate(condition, update, options);
  let firstID = counter.sequence_value - (list.length - 1);
  for(let a of list){
      a.id = firstID;
      firstID+=1
      if(map && keyfield){
        let key = a[keyfield];
        map[key]?map[key].push(a):map[key]=[a]
      }
  }

}


function getStdGlj(sub,stdGLJMap,cptGLJMap,newGLJ,ext) {
    let std_glj = null;
    if(sub.type == 'complementary'){//有可能来自标准工料机库或补充工料机库
        std_glj = cptGLJMap[sub.gljId];
        newGLJ.from = 'cpt';
    }else {
        std_glj = stdGLJMap[sub.gljId];
        newGLJ.from = 'std';
        //多单价情况处理
        if(ext && ext.priceField && std_glj && std_glj.priceProperty){
            std_glj.basePrice =  std_glj.priceProperty[ext.priceField];
        }
    }
    return std_glj;
}


async function deleRationSubRecode(projectID,rationID,cleanzmhs=false) {//删除挂在定额下的数据，如工程量明细，定额工料机等
    let delete_query={projectID: projectID, rationID: rationID};
    //删除工程量明细
    await deleteSubListByQuery(delete_query,cleanzmhs) ;
}

async function deleteSubListByQuery(delete_query,cleanzmhs=false) {
    if(cleanzmhs == false){//清空子目换算即cleanzmh==true时不需要清空工程量明细、模板关联子目、安装增加费
        await quantity_detail.deleteByQuery(delete_query) ;//删除工程量明细
        await rationInstallationModel.deleteMany(delete_query);//删除安装增加费
        await rationTemplateModel.deleteMany(delete_query);//删除模板关联子目
    }
    //to do稳定土也要删除

    await ration_coe.deleteMany(delete_query);//删除附注条件
    await ration_glj.deleteMany(delete_query);//删除定额工料机

}

async function updateCoeAdjust(data,compilation) {
    let replace = [],projectGLJList=[];
    await ration_coe.update({ID:data.ID},data.doc);
    //添加单个工料机的情况
    if (data.add.length > 0){
        let [tg,pl] = await ration_glj_facade.insertAddTypeGLJ(data.add,compilation);
        if(pl.length > 0) projectGLJList = projectGLJList.concat(pl);
    }
    if(data.delete.length > 0) await ration_glj_facade.deleteGLJ(data.delete);

    //替换工料机的情况
    if (data.replace.length > 0){
        for(let r of data.replace){
            let r_result = await  ration_glj_facade.replaceGLJByData(r,compilation);
            replace.push(r_result.data) ;
            projectGLJList.push(r_result.projectGLJ);
            if(r_result.newRecodes.length > 0) data.add = data.add.concat(r_result.newRecodes);
            if(r_result.deleteList.length > 0) data.delete = data.delete.concat(r_result.deleteList);
        }
    }
    let cal_result = await glj_calculate_facade.calculateQuantity({projectID:data.projectID,rationID:data.rationID},null,true);
    let coe = {
        query:{ID:data.ID,projectID:data.projectID},
        doc:data.doc
    };
    let ration_glj ={
        quantityRefresh:true,
        glj_result:cal_result.glj_result
    };
    let ration = {
        ID:cal_result.rationID,
        adjustState:cal_result.adjustState,
        name:cal_result.rationName
    };
    return {coe:coe,ration_glj:ration_glj,ration:ration,add:data.add,delete:data.delete,replace:replace,projectGLJList:projectGLJList}

}



async function  updateRation(std,defaultLibID,rationID,billsItemID,projectID,calQuantity,cleanzmh=false) {
    // insertNewRation
    let ration ={};
    ration.code = std.code;
    ration.name = std.name;
    ration.caption = std.caption;
    ration.unit = std.unit;
    if (std.type === 'std') {
        ration.libID = std.rationRepId;
        ration.stdID = std.ID;
    }
    ration.content = std.jobContent;
    ration.adjustState = '';
    ration.isFromDetail=0;
    ration.isSubcontract=false;
    ration.fees=[];
    if (std.chapter) {
        ration.comments = std.chapter.explanation;
        ration.ruleText = std.chapter.ruleText;
    }
    ration.from = std.type === 'complementary' ? 'cpt' : 'std';
    //定额前缀 none:0, complementary:1, borrow: 2
    ration.prefix = '';
    //借用优先级比补充高
    if(std.rationRepId !== parseInt(defaultLibID)){//借用
        ration.prefix = '借';
    }
    else if(std.rationRepId === defaultLibID && ration.from === 'cpt') {
        ration.prefix = '补';
    }
    ration.rationAssList =await createRationAss(std);//生成辅助定额
    if(cleanzmh==false){//如果是清空子目换算，即cleanzmh==true 保留定额工程量、工程量表达式、含量(分解系数)、取费专业(取费类别)
        if(std.feeType == undefined || std.feeType == null || std.feeType ==''){//定额取费专业为空的情况下，取项目属性中的定额取费专业ID
            ration.programID = await getProgramForProject(projectID);
        }else {
            ration.programID = std.feeType;
        }
        if( calQuantity){
            await CalculateQuantity(ration,billsItemID,projectID);
        }
    }
     let unsetObject = {
         "marketUnitFee":1,
         'marketTotalFee':1,
         "maskName":1
     }
    let newRation = await ration_model.model.findOneAndUpdate({ID:rationID,projectID:projectID},{"$set":ration,"$unset":unsetObject},{new: true});//;
    return newRation;
}

async function setEmptyRation(projectID,rationID){
    let ration ={};
    ration.code = "";
    ration.name = "";
    ration.caption = "";
    ration.unit = "";
    ration.libID = null;
    ration.content = "";
    ration.adjustState = '';
    ration.isFromDetail=0;
    ration.isSubcontract=false;
    ration.fees=[];
    ration.comments = "";
    ration.ruleText = "";
    ration.quantity="";
    ration.contain="";
    ration.quantityEXP="";
    ration.from = 'std';
    //定额前缀 none:0, complementary:1, borrow: 2
    ration.prefix = '';
    ration.rationAssList = [];
    ration.marketUnitFee ="";
    ration.marketTotalFee ="";
    ration.maskName = "";
    ration.targetTotalFee ='';
    ration.targetUnitFee = "";
    ration.deleteInfo = null;
    ration.quantityCoe = {};
    ration.rationQuantityCoe="";
    ration.tenderQuantity = "";
    ration.programID = null;
    let newRation = await ration_model.model.findOneAndUpdate({ID:rationID,projectID:projectID},{"$set":ration},{new: true});//;
    return {ration:newRation,ration_gljs:[],ration_coes:[],ration_installs:[]};
}

async function createRationAss(std,isMaterial) {
    let  rationAssList = [];//生成辅助定额
    if(std.hasOwnProperty('rationAssList')&&std.rationAssList.length>0){
        let assGroup =  _.groupBy(std.rationAssList,'name');
        for(let key in assGroup){
            let assList = assGroup[key];
            let ass = assList[0];
            ass._doc.actualValue = ass.stdValue;
            ass._doc.isAdjust = 0;
            if(_.isString(ass._doc.assistCode)) ass._doc.assistCode = ass._doc.assistCode.replace("\n","");
            if(_.isString(ass._doc.thirdRationCode)) ass._doc.thirdRationCode = ass._doc.thirdRationCode.replace("\n","");
            if(assList.length > 1){
                ass._doc.groupList = JSON.parse(JSON.stringify(assList))  ;
                ass._doc.maxValue = assList[assList.length-1]._doc.maxValue;
            }
            if(isMaterial == true){//材料计算进来的，直接保存辅助定额的信息  //常规的定额以后可以考虑也这样做
                let t_assRation =  await rationItemModel.findOne({rationRepId:std.rationRepId,code:ass.assistCode}).lean();
                if(t_assRation) ass._doc.assRation = t_assRation;
            }
            rationAssList.push(ass);
        }
    }
    return rationAssList;
}

async function CalculateQuantity (ration,billsItemID,projectID) {
    // calculate ration Quantity
    let project = await projectModel.findOne({ID:projectID});
    let decimalObject =await decimal_facade.getProjectDecimal(projectID,project);
    let quantity_decimal = (decimalObject&&decimalObject.ration&&decimalObject.ration.quantity)?decimalObject.ration.quantity:3;
    let pbill = await bill_model.model.findOne({projectID:projectID,ID:billsItemID});
    let rationTimes = 1 ;//清单单位转定额单位的倍数，如 kg 转 t 时是1000
    let t_unit = ration.unit?ration.unit:"";
    let b_unit = pbill.unit?pbill.unit:"";
    ration.quantityEXP="QDL";
    if((/.*kg$/i).test(b_unit)){
      if((/t/i).test(t_unit)) {
        rationTimes = 1000;//如 kg 转 t 时是1000
        ration.quantityEXP="QDL*0.001"
      }
      if((/10t/i).test(t_unit)){
        rationTimes = 10000;//如 kg 转 10t 时是1000
        ration.quantityEXP="QDL*0.0001"
      } 
    }
    
   /* let  t_unit = ration.unit?ration.unit.replace(/^\d+/,""):""; 2019-02-01 养护去掉清单与定额单位的这个判断
    if(t_unit!=pbill.unit){//如果定额工程量的单位去除前面的数字后不等于清单单位，定额工程量保持不变
        return ;
    }*/
    let billsQuantity = pbill.quantity ? pbill.quantity : 0;
    let bill_decimal = await decimal_facade.getBillsQuantityDecimal(projectID,pbill.unit,project);
    let ftimes = rationTimes == 1?FilterNumberFromUnit(ration.unit):rationTimes;
    billsQuantity=scMathUtil.roundForObj(billsQuantity,bill_decimal);
    ration.quantity = scMathUtil.roundForObj(billsQuantity / ftimes ,quantity_decimal);//不管是否打勾都做转换
    ration.contain =  scMathUtil.roundForObj(ration.quantity/billsQuantity,6);
};


async function getProgramForProject(projectID){
    let project = await projectModel.findOne({ID:projectID});
    return project.property.engineering;
}

function FilterNumberFromUnit (unit) {
    let reg = new RegExp('^[0-9]+');
    if (reg.test(unit)) {
        return parseInt(unit.match(reg)[0]);
    } else {
        return 1;
    }
};

function getIndex(obj,tpops){
  let pops = tpops?tpops:['code','name','specs','unit','type'];
  let t_index = '';
  let k_arr=[];
  for(let p of pops){
      let tmpK = (obj[p]==undefined||obj[p]==null||obj[p]=='')?'null':obj[p];
      k_arr.push(tmpK);
  }
  t_index=k_arr.join("|-|");
  return t_index;
}