/**
 * Created by Mai on 2017/4/1.
 */

var Ration = {
    createNew: function (project) {
        // 用户定义private方法
        var tools = {
            formatRationUpdateData: function (data) {
                let uData = JSON.parse(JSON.stringify(data));
                delete uData.feesIndex;
                delete uData.flagsIndex;
                // if (uData.fees) {
                //     for (let fee of uData.fees) {
                //         fee.unitFee = fee.unitFee.toFixed(2);
                //         fee.totalFee = fee.totalFee.toFixed(2);
                //         fee.tenderUnitFee = fee.tenderUnitFee.toFixed(2);
                //         fee.tenderTotalFee = fee.tenderTotalFee.toFixed(2);
                //     }
                // }
                return uData;
            }
        };

        // 所有通过this访问的属性，都不应在此单元外部进行写入操作
        var ration = function (proj) {
            this.project = proj;
            this.datas = null;

            var sourceType = ModuleNames.ration;
            this.getSourceType = function () {
                return sourceType;
            }
            proj.registerModule(ModuleNames.ration, this);

            var maxRationID = 0;
            this.getNewRationID = function () {
                return uuid.v1();
                //return maxRationID += 1;
            };
            this.maxRationID = function (maxID) {
                if (arguments.length === 0) {
                    return maxRationID;
                } else {
                    maxRationID = Math.max(maxID, maxRationID);
                }
            };
        };

        // prototype用于定义public方法
        ration.prototype.loadData = function (datas) {
            var that = this;
            this.datas = datas;
            // generate Fees & Flags Index，For View & Calculate
            this.datas.forEach(function (data) {
                data.feesIndex = getFeeIndex(data.fees);
                data.flagsIndex = {};
                data.flags.forEach(function (flag) {
                    data.flagsIndex[flag.fieldName] = flag;
                });
                that.maxRationID(data.ID);
            });
        };

        ration.prototype.setMaxID = function (ID) {
            this.maxRationID(ID);
        }
        ration.prototype.addDatasToList = function (new_datas) {
            let me = this;
            if(me.datas && Array.isArray(me.datas)){
                for(let d of new_datas){
                    me.datas.push(d);
                }
            }else {
                me.datas = new_datas;
            }
        };
        // refresh after update
        ration.prototype.doAfterUpdate = function(err, data){
            if(data.stateRefresh){
                this.refreshAdjustState(data);
            }
            if(data.quantityRefresh){
                this.refreshQuantity(data);
            }
        };
        ration.prototype.refreshAdjustState = function(data){
            this.refreshDatas(data,'adjustState');
            if(data.hasOwnProperty('name')){
              this.refreshDatas(data,'name')
            }
        };
        ration.prototype.refreshQuantity = function(data){
            this.refreshDatas(data,'quantity');
        };
        ration.prototype.refreshDatas = function(data,fieldName){
            var dataIndex = _.findIndex(this.datas,function(item) {
                return item.ID ==data.rationID;
            });
            this.datas[dataIndex][fieldName] = data[fieldName];
            if(fieldName=='quantity'){
                this.datas[dataIndex]['isFromDetail']=1
            }
            var controller = projectObj.mainController;
            var selected = controller.sheet.getSelections();
            var col =   _.findIndex(project.projSetting.main_tree_col.cols,function (col) {
                return col.data.field ==fieldName;
            });
            controller.sheet.getCell(selected[0].row,col).value(data[fieldName]);
        };
        ration.prototype.getContain = function (billNode,quantity) {
            if(billNode && billNode.data.quantity&&billNode.data.quantity!=0&&billNode.data.quantity!=""){
                let billQuantity = scMathUtil.roundForObj(billNode.data.quantity,getDecimal("quantity",billNode));
                return scMathUtil.roundForObj(parseFloat(quantity)/billQuantity,getDecimal("process"));
            }
            return 0
        };
        ration.prototype.getTempRationData = function (id, billsID, serialNo, rType,priceType) {
            let newData = {'ID': id, 'serialNo': serialNo, projectID: this.project.ID()};
            let pEngineer = projectObj.project.projectInfo.property.projectEngineering;//量价默认使用后台设置的单位工程取费专业
            newData[project.masterField.ration] = billsID;
            newData['type'] = rType;
            // 插入定额的时候，定额工作内容默认取清单的第一个工作内容
            if (_compilationConfig.dynamicRationWorkContent) {
                let billsNode = projectObj.project.mainTree.nodes['id_' + billsID];
                let contentText = contentOprObj.getDefaultContent(billsNode);
                newData.jobContentText = contentText;
            }
            if (rType == rationType.volumePrice){
                newData['subType'] =  priceType?priceType:gljType.GENERAL_MATERIAL;   // 如果priceType 没传，默认的量价类型为材料
            };
            if(rType == rationType.ration){//空定额暂时不输入取费专业
               // newData['programID'] = projectObj.project.projectInfo.property.engineering;
            }else {
                if(pEngineer) newData['programID'] = pEngineer;
            }

            return newData;
        };
        ration.prototype.getBillsSortRation = function (billsID) {     // 该方法只适用于叶子清单
            var rations = this.datas.filter(function (data) {
                return data[project.masterField.ration] === billsID;
            });
            rations.sort(function (x, y) {
                return x.serialNo - y.serialNo;
            });
            return rations;
        };

        // CSL, 2017-11-13 取任何清单（父清单、叶子清单）下的所有定额
        ration.prototype.getRationNodes = function (billNode) {
            if (billNode.sourceType != ModuleNames.bills) return [];

            let rations = [], IDs = [];

            function getSubBillsIDs(node) {
                if (!node) return;
                if (node.sourceType != ModuleNames.bills) return;
                if (!node.children || node.children.length == 0 || node.children[0].sourceType != ModuleNames.bills)
                    IDs.push(node.data.ID)
                else
                    getSubBillsIDs(node.children[0]);
                getSubBillsIDs(node.nextSibling);
            };

            if (billNode.source.children.length == 0)
                IDs.push(billNode.data.ID)
            else
                getSubBillsIDs(billNode.children[0]);

            for (let id of IDs){
                let subRations = this.datas.filter(function (data) {
                    return data[project.masterField.ration] === id;
                });
                rations.push(...subRations);
            };

            rations.sort(function (x, y) {
                return x.serialNo - y.serialNo;
            });

            let rationNodes = [];
            for (let ration of rations){
                  rationNodes.push(projectObj.project.mainTree.nodes['id_' + ration.ID]);
            }

            return rationNodes;
        };

        ration.prototype.getInsertRationData = function (billsID, preRation, rationType) {
            var br = this.getBillsSortRation(billsID);
            var updateData = [];
            if (preRation) {
                var preIndex = br.indexOf(preRation), i;
                updateData.push({updateType: 'ut_create', updateData: this.getTempRationData(this.getNewRationID(), billsID, preIndex < br.length - 1 ? br[preIndex + 1].serialNo : br[preIndex].serialNo + 1, rationType)});
                for (i = preIndex + 1; i < br.length; i++) {
                    updateData.push({updateType: 'ut_update', updateData: this.getTempRationData(br[i].ID, billsID, i < br.length - 1 ? br[i+1].serialNo : br[i].serialNo + 1, br[i].type)});
                }
            } else {
                updateData.push({updateType: 'ut_create', updateData: this.getTempRationData(this.getNewRationID(), billsID, br.length > 0 ? br[br.length - 1].serialNo + 1 : 1, rationType)});
            }
            return updateData;
        };
        ration.prototype.getCounterData = function (count) {
            var updateData = {'projectID': this.project.ID()};
            if (count) {
                updateData[this.getSourceType()] = this.maxRationID() + count;
            } else {
                updateData[this.getSourceType()] = this.maxRationID() + 1;
            }
            return updateData;
        };
        ration.prototype.insertRation = function (billsID, preRation, rationType) {
            var br = this.getBillsSortRation(billsID);
            let insertData = this.getInsertRationData(billsID, preRation, rationType);
            this.project.pushNow('insertRation', [this.getSourceType(), this.project.projCounter()],
                [insertData, this.getCounterData()]);

            var newRation = null;
            let newID = -1;
            for(let data of insertData){
                if(data.updateType === 'ut_create'){
                    newID = data.updateData.ID;
                }
            }
            if (preRation) {
                var preIndex = br.indexOf(preRation), i;
                newRation = this.getTempRationData(newID, billsID, preIndex < br.length - 1 ? br[preIndex + 1].serialNo : br[preIndex].serialNo + 1, rationType);
                this.datas.push(newRation);
                for (i = preIndex + 1; i < br.length; i++) {
                    br[i].serialNo = i < br.length - 1 ? br [i + 1].serialNo : br[i].serialNo + 1;
                }
            } else {
                newRation = this.getTempRationData(newID, billsID, br.length > 0 ? br[br.length - 1].serialNo + 1 : 1, rationType);
                this.datas.push(newRation);
            }
            return newRation;
        };
        ration.prototype.insertStdRation = function (billsID, preRation, std) {
            var br = this.getBillsSortRation(billsID), updateData = this.getInsertRationData(billsID, preRation, rationType.ration), newRation = null, that = this;
            updateData.forEach(function (data) {

                if (data.updateType === 'ut_create') {
                    data.updateData.code = std.code;
                    data.updateData.name = std.name;
                    data.updateData.caption = std.caption;
                    data.updateData.unit = std.unit;
                    data.updateData.libID = std.rationRepId;
                    data.updateData.content = std.jobContent;
                    if (std.chapter) {
                        data.updateData.comments = std.chapter.explanation;
                        data.updateData.ruleText = std.chapter.ruleText;
                    }
                    data.updateData.from = std.type === 'complementary' ? 'cpt' : 'std';
                    data.updateData.programID = std.feeType;
                    data.updateData.rationAssList =  projectObj.project.ration_ass.CreateNewAss(std);
                    // calculate ration Quantity
                    that.CalculateQuantity(data.updateData);
                    newRation = data.updateData;
                }
            });
            this.project.pushNow('insertRation', [this.getSourceType(), this.project.projCounter()], [updateData, this.getCounterData()]);

            //newRation.ID = this.getNewRationID();
            if (preRation) {
                var preIndex = br.indexOf(preRation), i;
                this.datas.push(newRation);
                for (i = preIndex + 1; i < br.length; i++) {
                    br[i].serialNo = i < br.length - 1 ? br [i + 1].serialNo : br[i].serialNo + 1;
                }
            } else {
                this.datas.push(newRation);
            }
            return newRation;
        };

        ration.prototype.getDeleteData = function (rationData) {
            var updateData = [];
            updateData.push({'updateType': 'ut_delete', 'updateData': {'ID': rationData.ID, 'projectID': this.project.ID()}});
            return updateData;
        };
        ration.prototype.delete = function (ration) {
            var ration_glj =projectObj.project.ration_glj;
            this.project.pushNow('deleteRation', [this.getSourceType(),ration_glj.getSourceType()], [this.getDeleteData(ration),ration_glj.getDeleteDataByRation(ration)]);
            this.deleteSubListOfRation(ration);
            this.datas.splice(this.datas.indexOf(ration), 1);
        };
        ration.prototype.removeByID = function(ID){
            _.remove(this.datas,{'ID':ID});
        };
        ration.prototype.getDeleteDataByBill = function (nodes) {
            let updateData = [];
            for (let node of nodes) {
                if (node.children.length > 0) {
                    updateData = updateData.concat(this.getDeleteDataByBill(node.children));
                } else {
                    let rations = this.getBillsSortRation(node.getID());
                    for (let r of rations) {
                        updateData.push({'updateType': 'ut_delete', 'updateData': {'ID': r.ID, 'projectID': this.project.ID()}});
                    }
                }
            }
            return updateData;
        };
        ration.prototype.deleteByBills = function (nodes) {
            for (let node of nodes) {
                if (node.children.length > 0) {
                    this.deleteByBills(node.children);
                } else {
                    let rations = this.getBillsSortRation(node.getID());
                    for (let r of rations) {
                        this.datas.splice(this.datas.indexOf(r), 1);
                    }
                }
            }
        }

        ration.prototype.getChangePosUpdateData = function (ration1, ration2) {
            var updateData = [];
            updateData.push({updateType: 'ut_update', updateData: { ID: ration1.ID, serialNo: ration2.serialNo, projectID: this.project.ID() }});
            updateData.push({updateType: 'ut_update', updateData: { ID: ration2.ID, serialNo: ration1.serialNo, projectID: this.project.ID() }});
            return updateData;
        };
        ration.prototype.changePos = function (ration1, ration2) {
            var updateData = this.getChangePosUpdateData(ration1, ration2);
            this.project.pushNow('insertRation', [this.getSourceType()], [updateData]);

            var preSerialNo = ration1.serialNo;
            ration1.serialNo = ration2.serialNo;
            ration2.serialNo = preSerialNo;
        };

        ration.prototype.updateField = function (ration, field, newValue) {
            calcFees.setFee(ration, field, newValue);
            let updateData = [];
            let data = {'ID': ration.ID, 'projectID': this.project.ID()};
            if (field === 'quantity') {
                data[field] = newValue;
                data.isFromDetail=0;
                // to do Calculate
                if (ration.fees) {
                    data.fees = ration.fees;
                }
            } else if (field === 'feesIndex.common.unitFee') {
                // to do Calculate
                if (ration.fees) {
                    data.fees = ration.fees;
                }
            } else {
                data[field] = newValue;
            }
            updateBillsOprRation();
            updateData.push({'updateType': 'ut_update', 'updateData': data});
            this.project.pushNow('updateBills', this.getSourceType(), updateData);
        };

        ration.prototype.updateRation = function (ration, updateNow) {
            let updateData = [];
            updateData.push({'updateType': 'ut_update', 'updateData': tools.formatRationUpdateData(ration)});
            if (updateNow) {
                this.project.pushNow('updateRations', this.getSourceType(), updateData);
            } else {
                this.project.push(this.getSourceType(), updateData);
            }
        };

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

        ration.prototype.CalculateQuantity = function (ration) {
            // calculate ration Quantity
            let quantity_decimal = getDecimal("ration.quantity");
            let process_decimal = getDecimal("process");
            if (optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToBillsQuan')) {
                let billsNode = this.project.Bills.tree.findNode(ration[this.project.masterField.ration]);
                let billsQuantity = billsNode.data.quantity ? billsNode.data.quantity : 0;
                billsQuantity=scMathUtil.roundForObj(billsQuantity,quantity_decimal);
                ration.quantityEXP="QDL";
               /* if (optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToRationUnit')) {
                    ration.quantity = (billsQuantity / this.FilterNumberFromUnit(ration.unit)).toDecimal(quantity_decimal);
                } else {
                    ration.quantity = billsQuantity.toDecimal(quantity_decimal);
                }*/
                ration.quantity = (billsQuantity / this.FilterNumberFromUnit(ration.unit)).toDecimal(quantity_decimal);//改成不管是否打勾都做转换
                ration.contain = scMathUtil.roundForObj(ration.quantity/billsQuantity,process_decimal);
            }
        };
        ration.prototype.updateRationCodes = function (recodes,cleanzmhs = false) {
            let libID =  rationLibObj.getCurrentStdRationLibID();
            let libIDs = rationLibObj.getStdRationLibIDs();
            let defaultLibID = rationLibObj.getDefaultStdRationLibID();
            let engineering = projectObj.project.projectInfo.property.engineering;
            let projectID = projectObj.project.projectInfo.ID;
            let project = projectObj.project;
            let mainTree = project.mainTree;
            let nodeInfo =[];
            let refershNodes = [];
            if(libIDs == null) return;

            //设置定额库的优先级， 当是清空子目换算时，使用原定额的定额库ID,其它情况再按： 默认先取选中的定额库，如果没有再取default定额库
            let selectedLib = (cleanzmhs == true && recodes.length > 0)? recodes[0].node.data.libID : sessionStorage.getItem("stdRationLib");
            selectedLib&&selectedLib!='undefined'?libIDs.unshift(selectedLib):libIDs.unshift(defaultLibID);
            for(let r of recodes){
                let needInstall = false;
                if(projectObj.project.isInstall()) {//如果是安装工程，要看需不需要生成安装增加费
                    needInstall = project.Bills.isFBFX(r.node);
                }
                r.value===null||r.value===undefined?"":r.value = r.value.replace(/[\s\r\n]/g, "");//去掉空格回车换行等字符
                if(cleanzmhs  == true||r.value != r.node.data.code){
                    nodeInfo.push({ID:r.node.data.ID,billsItemID:r.node.data.billsItemID,newCode:r.value,needInstall:needInstall});
                    refershNodes.push(r.node);
                }
            }
            let calQuantity = optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToBillsQuan');
            $.bootstrapLoading.start();
            CommonAjax.post("/ration/replaceRations",{nodeInfo:nodeInfo,libIDs:libIDs,defaultLibID: defaultLibID,projectID:projectID,calQuantity:calQuantity,cleanzmhs:cleanzmhs},function (data) {
                for(let recode of data){
                   let node =  mainTree.getNodeByID(recode.ration.ID);
                   if(node) {
                       for(let temkey in recode.ration){//更新缓存
                           node.data[temkey] = recode.ration[temkey];
                       }
                       node.data.feesIndex = {};
                       //删除定额节点下的主材和设备节点
                       project.ration_glj.removeNodeByRation(recode.ration,projectObj.mainController);
                       project.Ration.deleteSubListOfRation(recode.ration,cleanzmhs);//删除旧定额下的相关记录
                       //添加新的记录
                       project.Ration.addSubListOfRation(recode,false);
                       project.ration_glj.addToMainTree(recode.ration_gljs);
                   }
                }
                project.projectGLJ.calcQuantity();
                mbzm_obj.nodeChanged = true;//子目模板关联刷新
                gljOprObj.showDataIfRationSelect(projectObj.project.mainTree.selected,"-111111111");//这里第二个参数是为了使改前和改后selectedID不一样，删除了的话下方的定额工料机不会刷新
                project.calcProgram.calcNodesAndSave(refershNodes, async function () {
                    await OVER_HEIGHT.reCalcOverHeightFee();
                    await itemIncreaseFeeObj.calcItemIncreaseFeeByNodes(refershNodes);
                });
                projectObj.mainController.refreshTreeNode(refershNodes, true);
                $.bootstrapLoading.end();
                if(data.length < nodeInfo.length && nodeInfo[data.length].newCode!=null){//说明有部分定额编号没找到记录
                    alert('当前库中找不到定额"' + nodeInfo[data.length].newCode + '"');
                }
                updateBillsOprRation();
            })
        };
        ration.prototype.addMultiRation = async function (items) {
            let me = this;
            let project = projectObj.project, sheetController = projectObj.mainController;
            let engineering = projectObj.project.projectInfo.property.engineering;
            let selected = project.mainTree.selected, newSource = null, newNode = null,pre = null,br = null;
            let billItemID = null,serialNo=1,nextID=null;
            let needInstall = false;
            let newDatas = [];
            if (selected === null) { return; }
            if (selected.sourceType === project.Bills.getSourceType() && selected.depth() > 0) {
                if (selected.source.children.length > 0) {
                    alert('当前清单已有清单子项，不能套用定额。');
                } else if (selected.data.calcBase&&selected.data.calcBase!="") {
                    alert('当前有基数计算，不能插入定额/量价/人材机。');
                } else {
                    if(selected.data.type === billType.FB){
                        return;
                    }
                    billItemID = selected.source.getID();
                    nextID = selected.tree.rootID();
                    br = this.getBillsSortRation(billItemID);
                    serialNo = br.length > 0 ? br[br.length - 1].serialNo + 1 : 1
                }
            } else if (selected.sourceType === project.Ration.getSourceType()) {
                billItemID = selected.getParentID();
                br = this.getBillsSortRation(billItemID);
                serialNo = selected.data.serialNo+1;
                nextID = selected.getNextSiblingID();
                pre = selected.source;
            };
            if(billItemID){
                let calQuantity = optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToBillsQuan');
                if(projectObj.project.isInstall()) {//如果是安装工程，要看需不需要生成安装增加费
                    let billsNode = project.mainTree.getNodeByID(billItemID);
                    needInstall = project.Bills.isFBFX(billsNode);//在分部分项插入的定额才需要定额安装增加费
                }
                for(let i = 0; i < items.length; i++){
                    let newData = me.getTempRationData(me.getNewRationID(), billItemID, serialNo, items[i].rationType);
                    serialNo++;
                    let brUpdate = [];
                    //更新兄弟节点的序列号
                    if (i ===0 && pre) {
                        let preIndex = br.indexOf(pre), i;
                        for (i = preIndex + 1; i < br.length; i++) {
                            br[i].serialNo = i < br.length - 1 ? br [i + 1].serialNo + items.length - 1 : br[i].serialNo + items.length;
                            brUpdate.push({projectID:newData.projectID,ID:br[i].ID,serialNo:br[i].serialNo});
                        }
                    }
                    newDatas.push({itemQuery: items[i].itemQuery, newData: newData, defaultLibID: rationLibObj.getDefaultStdRationLibID(), calQuantity: calQuantity, brUpdate: brUpdate, needInstall: needInstall})
                }
                const rstData = await ajaxPost('/ration/addMultiRation', { projectID:me.project.ID(), newDatas });
                let newNodes = [];
                //更新缓存
                for(let data of rstData){
                    me.datas.push(data.ration);
                    me.addSubListOfRation(data,false);
                    //插入树节点
                    newSource = data.ration;
                    newNode = project.mainTree.insert(billItemID, nextID, newSource.ID);
                    newNodes.push(newNode);
                    newNode.source = newSource;
                    newNode.sourceType = project.Ration.getSourceType();
                    newNode.data = newSource;
                    ProjectController.syncDisplayNewNode(sheetController, newNode);
                    nextID =  project.mainTree.selected.getNextSiblingID();
                }
                project.projectGLJ.calcQuantity();
                for(let data of rstData){
                    project.ration_glj.addToMainTree(data.ration_gljs);
                }
                projectObj.mainController.refreshTreeNode(newNodes, false);
                if(project.Bills.isFBFX(newNodes[0])) { //判断是否属于分部分项工程 ，是的话才需要做计取安装费计算
                    project.installation_fee.calcInstallationFee(function (isChange,rations) {
                        if(isChange){
                            rations = rations.concat(newNodes);
                            project.calcProgram.calcNodesAndSave(rations);
                            itemIncreaseFeeObj.calcItemIncreaseFeeByNodes(rations);
                        }else {
                            project.calcProgram.calcNodesAndSave(newNodes);
                            itemIncreaseFeeObj.calcItemIncreaseFeeByNodes(newNodes);
                        }
                    });
                }else {
                    project.calcProgram.calcNodesAndSave(newNodes);
                    itemIncreaseFeeObj.calcItemIncreaseFeeByNodes(newNodes);
                }
                updateBillsOprRation();
            }
        };
        ration.prototype.insertVolumePrice = function(type,ext){
            let isEmpty = ext?false:true;
            this.addNewRation(null,rationType.volumePrice,function (newNode) {//插入人工不需要自动定位到编号列
                projectObj.selectColAndFocus(newNode,null);
            },isEmpty,type,true,ext);
        };
        // 已经有数据，更新前端缓存及节点，不进行通信
        ration.prototype.addNewDataSimply = function (newData) {
            const newNodes = [];
            const controller = projectObj.mainController;
            this.addDatasToList(newData);
            newData.forEach(item => {
                const newNode = project.mainTree.insert(item.billsItemID, -1, item.ID);
                newNode.source = item;
                newNode.sourceType = project.Ration.getSourceType();
                newNode.data = item;
                controller.sheet.addRows(newNode.serialNo(), 1);
                newNodes.push(newNode);
            });
            TREE_SHEET_HELPER.refreshTreeNodeData(controller.setting, controller.sheet, newNodes, false);
        };
        // 数据库的数据已删除，删除前端缓存及节点，不进行通信
        ration.prototype.deleteDataSimply = function (IDList) {
            const rationNodes = projectObj.project.mainTree.items.filter(node => IDList.includes(node.data.ID));
            const controller = projectObj.mainController;
            rationNodes.forEach(node => {
                controller.sheet.deleteRows(node.serialNo(),1);
                controller.tree.delete(node);
                projectObj.project.Ration.removeByID(node.data.ID);
                projectObj.project.ration_glj.deleteByRation(node.data);
            });
        };
        ration.prototype.addNewRation = function (itemQuery,rationType,callback=null,isEmpty=false,priceType,needCalcAndSave=true,ext) {//priceType 是量价类型
            console.log('addNewRation');
            let me = this;
            let project = projectObj.project, sheetController = projectObj.mainController;
            let engineering = projectObj.project.projectInfo.property.engineering;
            let selected = project.mainTree.selected, newSource = null, newNode = null,pre=null,br=null;
            let billItemID = null,serialNo=1,nextID=null;
            let needInstall = false;
            if (selected === null) { return null; }
            if (selected.sourceType === project.Bills.getSourceType() && selected.depth() > 0) {
                if(selected.data.type === billType.FB){
                    return null;
                }
                else if (selected.source.children.length > 0) {
                    alert('当前清单已有清单子项，不能套用定额。');
                } else if (selected.data.calcBase&&selected.data.calcBase!="") {
                    alert('当前有基数计算，不能插入定额/量价/人材机。');
                } else {
                    billItemID = selected.source.getID();
                    nextID = selected.tree.rootID();
                    br = this.getBillsSortRation(billItemID);
                    serialNo = br.length > 0 ? br[br.length - 1].serialNo + 1 : 1
                }
            } else if (selected.sourceType === project.Ration.getSourceType()) {
                billItemID = selected.getParentID();
                br = this.getBillsSortRation(billItemID);
                serialNo = selected.data.serialNo+1;
                nextID = selected.getNextSiblingID();
                pre = selected.source;
            };
            if(billItemID){
                let newID = me.getNewRationID();
                let newData =  me.getTempRationData(newID, billItemID, serialNo, rationType,priceType);
                let calQuantity =  isEmpty===true?false:optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToBillsQuan');
                let brUpdate = [];
                //更新兄弟节点的序列号
                if (pre) {
                    let preIndex = br.indexOf(pre), i;
                    for (i = preIndex + 1; i < br.length; i++) {
                        br[i].serialNo = i < br.length - 1 ? br [i + 1].serialNo : br[i].serialNo + 1;
                        brUpdate.push({projectID:newData.projectID,ID:br[i].ID,serialNo:br[i].serialNo});
                    }
                }
                if(projectObj.project.isInstall()) {//如果是安装工程，要看需不需要生成安装增加费
                    let billsNode = project.mainTree.getNodeByID(billItemID);
                    needInstall = project.Bills.isFBFX(billsNode);//在分部分项插入的定额才需要定额安装增加费
                }
                if(ext) gljUtil.setProperty(newData,ext);
                $.bootstrapLoading.start();
                CommonAjax.post("/ration/addNewRation",{projectID:me.project.ID(),itemQuery:itemQuery,newData:newData,defaultLibID: rationLibObj.getDefaultStdRationLibID(),calQuantity:calQuantity,brUpdate:brUpdate,needInstall:needInstall},function (data) {
                    //更新缓存
                    me.datas.push(data.ration);
                    me.addSubListOfRation(data);
                    //插入树节点
                    newSource = data.ration;
                    if(needCalcAndSave == false){
                        syncNodeOper(data);
                        if(callback) callback(newNode);
                    }else {
                        //if(data.projectGLJDatas) projectObj.project.projectGLJ.refreshByDatas(data.projectGLJDatas);
                        syncNodeOper(data);
                        project.calcProgram.calcAndSave(newNode,async function () {
                            await itemIncreaseFeeObj.calcItemIncreaseFeeByNodes([newNode]);
                            if(project.Bills.isFBFX(newNode)) { //判断是否属于分部分项工程 ，是的话才需要做计取安装费计算
                                installationFeeObj.calcInstallationFee();
                            }
                        });
                        //如果添加规则中，添加内容为定额子目，则更新相关清单
                        updateBillsOprRation();
                        if(callback) callback(newNode);

                    }
                    $.bootstrapLoading.end();
                })
                return newNode;
            }
            else return null;

            function syncNodeOper(data) {//插入后刷新节点操作
                newNode = project.mainTree.insert(billItemID, nextID, newSource.ID);
                newNode.source = newSource;
                newNode.sourceType = project.Ration.getSourceType();
                newNode.data = newSource;
                ProjectController.syncDisplayNewNode(sheetController, newNode,function(){
                  project.ration_glj.addToMainTree(data.ration_gljs);
                  projectObj.mainController.refreshTreeNode([newNode], false);
                });
            }


        };
        ration.prototype.addNewRationFast = function (rationType,callback) {
            console.log('addNewRationFast');
            let me = this;
            let project = projectObj.project, sheetController = projectObj.mainController;
            let engineering = projectObj.project.projectInfo.property.engineering;
            let selected = project.mainTree.selected, newSource = null, newNode = null,pre=null,br=null;
            let billItemID = null,serialNo=1,nextID=null;
            if (selected === null) { return null; }
            if (selected.sourceType === project.Bills.getSourceType() && selected.depth() > 0) {
                if(selected.data.type === billType.FB){
                    return null;
                }
                else if (selected.source.children.length > 0) {
                    alert('当前清单已有清单子项，不能套用定额。');
                } else if (selected.data.calcBase&&selected.data.calcBase!="") {
                    alert('当前有基数计算，不能插入定额/量价/人材机。');
                } else {
                    billItemID = selected.source.getID();
                    nextID = selected.tree.rootID();
                    br = this.getBillsSortRation(billItemID);
                    serialNo = br.length > 0 ? br[br.length - 1].serialNo + 1 : 1
                }
            } else if (selected.sourceType === project.Ration.getSourceType()) {
                billItemID = selected.getParentID();
                br = this.getBillsSortRation(billItemID);
                serialNo = selected.data.serialNo+1;
                nextID = selected.getNextSiblingID();
                pre = selected.source;
            };
            if(billItemID){
                let newID = me.getNewRationID();
                let newData =  me.getTempRationData(newID, billItemID, serialNo, rationType);
                let brUpdate = [];
                //更新兄弟节点的序列号
                if (pre) {
                    let preIndex = br.indexOf(pre), i;
                    for (i = preIndex + 1; i < br.length; i++) {
                        br[i].serialNo = i < br.length - 1 ? br [i + 1].serialNo : br[i].serialNo + 1;
                        brUpdate.push({projectID:newData.projectID,ID:br[i].ID,serialNo:br[i].serialNo});
                    }
                }
                if(projectObj.project.isInstall()) {//如果是安装工程，要看需不需要生成安装增加费
                    let billsNode = project.mainTree.getNodeByID(billItemID);
                }
                $.bootstrapLoading.start();
                newNode = project.mainTree.insert(billItemID, nextID, newID);
                newNode.sourceType = project.Ration.getSourceType();
                newNode.data = newData;
                CommonAjax.post("/ration/addNewRation",{itemQuery:null,newData:newData,defaultLibID: rationLibObj.getDefaultStdRationLibID(),calQuantity:false,brUpdate:brUpdate,needInstall:false},function (data) {
                    //更新缓存
                    me.datas.push(data.ration);
                    me.addSubListOfRation(data);
                    //插入树节点
                    newSource = data.ration;
                    newNode.source = newSource;
                    newNode.data = newSource;
                })
                ProjectController.syncDisplayNewNode(sheetController, newNode);
                if(callback){
                    callback(newNode);
                }
                $.bootstrapLoading.end();
                return newNode;
            }
            else return null;
        };
        ration.prototype.deleteSubListOfRation = function(ration,cleanzmhs=false){
            projectObj.project.ration_glj.deleteByRation(ration);
            projectObj.project.ration_coe.deleteByRation(ration);
            if(cleanzmhs == false){
                projectObj.project.ration_installation.deleteByRation(ration);
                projectObj.project.quantity_detail.deleteByRation(ration);
                projectObj.project.ration_template.deleteByRation(ration);
            }

        };
        ration.prototype.addSubListOfRation = function (data,calquantity = true) {
             project.ration_glj.addDatasToList(data.ration_gljs);
             project.ration_coe.addDatasToList(data.ration_coes);
             project.ration_installation.addDatasToList(data.ration_installations);
             project.ration_template.addDatasToList(data.ration_templates);
             project.quantity_detail.addDatasToList(data.quantity_details);
             if(data.projectGLJList ) projectObj.project.projectGLJ.loadNewProjectGLJToCaches(data.projectGLJList,calquantity);
        };

        ration.prototype.replaceRation = function (ration, std) {
            this.project.beginUpdate('replaceRation');
            
            // delete
            let ration_glj =projectObj.project.ration_glj;
            this.project.push(this.project.ration_glj.getSourceType(), this.project.ration_glj.getDeleteDataByRation(ration));
            this.deleteSubListOfRation(ration);

            // insertNewRation
            let updateData = [];
            ration.code = std.code;
            ration.name = std.name;
            ration.caption = std.caption;
            ration.unit = std.unit;
            ration.libID = std.rationRepId;
            ration.content = std.jobContent;
            ration.adjustState = '';
            if (std.chapter) {
                ration.comments = std.chapter.explanation;
                ration.ruleText = std.chapter.ruleText;
            }
            ration.from = std.type === 'complementary' ? 'cpt' : 'std';
            ration.programID = std.feeType;
            ration.rationAssList = projectObj.project.ration_ass.CreateNewAss(std);
            // calculate ration Quantity
            this.CalculateQuantity(ration);
            updateData.push({updateType: 'ut_update', updateData: ration});
            this.project.push(this.getSourceType(), updateData);

            this.project.endUpdate();
        };
        ration.prototype.updateContain=function (value,node) {
            let me = this;
            if(isNaN(value)){
                alert("当前输入的数据类型不正确，请重新输入");
                projectObj.mainController.refreshTreeNode([node]);
                return;
            }

            if(node.data.quantityEXP=="GCLMXHJ"){//如果定额工程量是来自工程量明细
                hintBox.infoBox('操作确认', '已有工程量明细，是否清空明细表？', 2, function () {
                    node.data.isFromDetail=0;
                    project.quantity_detail.cleanQuantityDetail(node,true);
                    me.doContainUpdate(value,node);
                }, function () {
                    projectObj.mainController.refreshTreeNode([node]);
                },['确定','取消'],false);
            }else {
                me.doContainUpdate(value,node);
            }
        };
        ration.prototype.getNearRations = function (ration,callback) {
            if(ration&&ration.code && ration.code !=""){
                CommonAjax.post("/ration/getSameSectionRations",{from:ration.from,code:ration.code,libID:ration.libID},function(rations){
                    callback(rations);
                })
            }else {
                callback([]);
            }

        };
        ration.prototype.doContainUpdate = function (value,node) {

            let billNode = node.parent;
            let contain = scMathUtil.roundForObj(value,getDecimal("process"));
            let billQuantity = billNode.data.quantity||billNode.data.quantity!=""?billNode.data.quantity:0;
            billQuantity = parseFloat(billQuantity);
            node.data.contain = contain;
            node.data.quantityEXP="QDL*"+contain;
            node.data.quantity=scMathUtil.roundForObj(billQuantity*contain,getDecimal("quantity",node));
            let times = parseInt(node.data.unit);
            if (!isNaN(times)) {
                node.data.quantityEXP+='*'+times;
            }
            //  node.data.quantity = projectObj.project.quantity_detail.autoTransformQuantity(node.data.quantity,node);//按单位做转换
            node.changed = true;
            project.calcProgram.calcAndSave(node, function () {
                project.projectGLJ.calcQuantity();
            });
            projectObj.mainController.refreshTreeNode(node.children);//刷新子工料机树节点总消耗量



        };

        ration.prototype.addRationChecking=function(selected){
            if (selected) {// Vincent, 2018-01-02
                if(selected.sourceType === project.Ration.getSourceType()){ // 焦点行是定额/量价/工料机，有效显示。
                    return false;
                }else if(selected.sourceType === project.Bills.getSourceType()){
                    if(selected.data.type == billType.FX||selected.data.type == billType.BX){//焦点行是分项，有效显示。
                        return false
                    }
                    if(selected.data.type == billType.BILL && selected.source.children.length === 0){//焦点行是清单，且没有子项，有效显示。
                        return false
                    }
                }
            }
            return true;
        };
        ration.prototype.canAdd = function (node) {     // CSL.2018.07.23
            if (!node) return false;
            if (calcTools.isRationCategory(node)) return true;
            if (calcTools.isBill(node)){
                if (node.data.type == billType.FX || node.data.type == billType.BX) return true;  // 分项、补项
                if (calcTools.isLeafBill(node)
                    && (node.data.type != billType.DXFY)
                    && (node.data.type != billType.FB)
                    && project.Bills.isMeasure(node)) return true;  // 叶子清单项
            };

            return false;
        }
        ration.prototype.getAllInstallTypeRation = function () {//取所有计取安装增加费生成的定额
            return _.filter(this.datas,{'type':rationType.install});
        };

        ration.prototype.getLabourTotalFee=function(ration){//feesIndex.labour.totalFee  取定额的人工费合价
            if(ration.feesIndex&&ration.feesIndex.labour&&ration.feesIndex.labour.totalFee){
                return ration.feesIndex.labour.totalFee;
            }else {
                return 0;
            }
        };
        ration.prototype.getMaterialTotalFee=function(ration){//feesIndex.material.totalFee 取定额的材料费合价
            if(ration.feesIndex&&ration.feesIndex.material&&ration.feesIndex.material.totalFee){
                return ration.feesIndex.material.totalFee;
            }else {
                return 0;
            }
        } ;
        ration.prototype.getMachineTotalFee=function(ration){//feesIndex.machine.totalFee 取定额的机械费合价
            if(ration.feesIndex&&ration.feesIndex.machine&&ration.feesIndex.machine.totalFee){
                return ration.feesIndex.machine.totalFee;
            }else {
                return 0;
            }
        } ;
        //获取定额前缀
        ration.prototype.getRationPrefix = function(defaultLibID, ration){
            if(ration.from && ration.from === rationFrom.cpt){
                return rationPrefix.complementary;
            }
            if(defaultLibID !== ration.libID){
                return rationPrefix.borrow;
            }
            return rationPrefix.none;
        };

        return new ration(project);
    }
};

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