Pārlūkot izejas kodu

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost

zhangweicheng 7 gadi atpakaļ
vecāks
revīzija
d57a49c336

+ 2 - 1
modules/main/models/ration.js

@@ -46,7 +46,8 @@ let rationSchema = new Schema({
     deleteInfo: deleteSchema,
     type: Number,                               // 1 定额、2 量价、3 工料机定额
     subType: Number,                            // 子类型:1人工、201材料、301机械、4主材、5设备
-    from:{type: String,default:'std'},//std, cpt  来自标准、补充
+    from:{type: String,default:'std'},          //std, cpt  来自标准、补充
+    isSubcontract: Boolean,                     // 是否分包
 
     // 定额特有属性:
     libID: Number,

+ 174 - 173
web/building_saas/main/js/models/calc_program.js

@@ -98,28 +98,16 @@ let defaultBillTemplate = {
     ]
 };*/
 
-const priceTypes = {ptBasePrice: 1, ptAdjustPrice: 2, ptMarketPrice: 3, ptDiffPrice: 4};
-const cpFeeTypes = [
-    {type: 'direct', name: '直接费'},
-    {type: 'labour', name: '人工费'},
-    {type: 'material', name: '材料费'},
-    {type: 'machine', name: '机械费'},
-    {type: 'mainMaterial', name: '主材费'},
-    {type: 'equipment', name: '设备费'},
-    {type: 'manage', name: '企业管理费'},
-    {type: 'profit', name: '利润'},
-    {type: 'risk', name: '风险费'},
-    {type: 'labourDiff', name: '人工价差'},
-    {type: 'materialDiff', name: '材料价差'},
-    {type: 'machineDiff', name: '机械价差'},
-    {type: 'adjustLabour', name: '调整人工费'},
-    {type: 'adjustMachineLabour', name: '调整机上人工费'},
-    {type: 'estimate', name: '暂估费'},
-    {type: 'fee1', name: '甲供材料费'},
-    {type: 'common', name: '工程造价'}
-];
-
-let nodeTools = {
+let calcTools = {
+    getNodeByFlag: function (flag) {
+        let bill = cbTools.findBill(flag);
+        if (bill) return this.getNodeByID(bill.ID)
+        else return null;
+    },
+    getNodeByID: function (ID){
+        return cbTools.getNodeByID(ID);
+    },
+
     isBill: function(treeNode){
         return treeNode.sourceType === ModuleNames.bills;
     },
@@ -135,18 +123,17 @@ let nodeTools = {
         return treeNode.data.flagsIndex && treeNode.data.flagsIndex.fixed && treeNode.data.flagsIndex.fixed.flag &&
             treeNode.data.flagsIndex.fixed.flag == fixedFlag.ENGINEERINGCOST;
     },
-
     isRationCategory: function(treeNode){
         return treeNode.sourceType === ModuleNames.ration;
     },
-    isRation: function(treeNode){
-        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.ration;
+    isRationItem: function(treeNode){
+        return this.isRationCategory(treeNode) && treeNode.data.type === rationType.ration;
     },
     isVolumePrice: function (treeNode) {
-        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.volumePrice;
+        return this.isRationCategory(treeNode) && treeNode.data.type === rationType.volumePrice;
     },
     isGljRation: function (treeNode) {
-        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.gljRation;
+        return this.isRationCategory(treeNode) && treeNode.data.type === rationType.gljRation;
     },
 
     initFees: function (treeNode){
@@ -203,33 +190,6 @@ let nodeTools = {
             treeNode.changed = true;
         };
     },
-    getCalcType: function (treeNode) {
-        if (this.isRationCategory(treeNode)){
-            return treeNodeCalcType.ctRationCalcProgram;
-        }
-        else if (this.isNullBill(treeNode)){
-            return treeNodeCalcType.ctNull;
-        }
-        else if (this.isLeafBill(treeNode)) {
-            if (treeNode.children && treeNode.children.length > 0){
-                // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
-                if (projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
-                    return treeNodeCalcType.ctBillCalcProgram;
-                else                                        // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
-                    return treeNodeCalcType.ctGatherRationsFees;
-            }
-            else{                                          // 公式计算
-                return treeNodeCalcType.ctCalcBaseValue;
-            };
-        }
-        else if (this.isBill(treeNode)) {                              // 父清单:汇总子清单的费用类别
-            return treeNodeCalcType.ctGatherBillsFees;
-        }
-        else {
-            return treeNodeCalcType.ctRationCalcProgram;
-        };
-    },
-
     // 参数fieldName值: 'common.totalFee'、'equipment.unitFee'
     getFee: function (treeNode, fieldName) {
         let ns = fieldName.split(".");
@@ -240,66 +200,40 @@ let nodeTools = {
         else
             return 0;
     },
-    getNodeByFlag: function (flag) {
-        let bill = cbTools.findBill(flag);
-        if (bill) return this.getNodeByID(bill.ID)
-        else return null;
-    },
-    getNodeByID: function (ID){
-        return cbTools.getNodeByID(ID);
-    }
-};
-
-let assistCalcer = {
-    // 界面显示的结点的工程量的数值。
-    uiQuantity: function (treeNode){
-        return parseFloatPlus(treeNode.data.quantity).toDecimal(decimalObj.decimal("quantity", treeNode));
-    },
-    // 界面显示的工料机价格,包括定额价、市场价等。参数 price 传入一个普通的价格数值即可。
-    uiGLJPrice: function (price){
-        if (price)
-            return parseFloat(price).toDecimal(decimalObj.glj.unitPrice)
-        else return 0;
-    },
-    // 界面显示的工料机数量。参数 quantity 传入一个普通的数量数值即可。
-    uiGLJQuantity: function (quantity){
-        if (quantity)
-            return parseFloat(quantity).toDecimal(decimalObj.glj.quantity)
-        else return 0;
-    },
     rationBaseFee: function (treeNode, gljTypes, priceType){
         if (!treeNode.data.gljList) return 0;
-        let result = 0;
-        let me = this;
+        let me = this, result = 0;
         for (let glj of treeNode.data.gljList) {
             let price = 0, temp = 0;
             if (gljTypes.indexOf(glj.type) >= 0) {
                 if (priceType == priceTypes.ptDiffPrice){
                     let aprice = me.uiGLJPrice(glj["adjustPrice"]);
                     let mprice = me.uiGLJPrice(glj["marketPrice"]);
-                    temp = (me.uiGLJQuantity(glj["quantity"]) * mprice).toDecimal(decimalObj.ration.unitPrice) - (me.uiGLJQuantity(glj["quantity"]) * aprice).toDecimal(decimalObj.ration.unitPrice);
+                    temp = (me.uiGLJQty(glj["quantity"]) * mprice).toDecimal(decimalObj.ration.unitPrice) - (me.uiGLJQty(glj["quantity"]) * aprice).toDecimal(decimalObj.ration.unitPrice);
                     temp = temp.toDecimal(decimalObj.ration.unitPrice);
                 }
                 else {
                     if (priceType == priceTypes.ptBasePrice){ price = me.uiGLJPrice(glj["basePrice"]);}
                     else if (priceType == priceTypes.ptAdjustPrice){price = me.uiGLJPrice(glj["adjustPrice"]);}
                     else if (priceType == priceTypes.ptMarketPrice){price = me.uiGLJPrice(glj["marketPrice"]);}
-                    temp = (me.uiGLJQuantity(glj["quantity"]) * price).toDecimal(decimalObj.ration.unitPrice);
+                    temp = (me.uiGLJQty(glj["quantity"]) * price).toDecimal(decimalObj.process);
                 };
-
-                result = (result + temp).toDecimal(decimalObj.ration.unitPrice);
+                result = (result + temp).toDecimal(decimalObj.process);
             };
         };
+
+        result = result.toDecimal(decimalObj.ration.unitPrice);
         return result;
     },
     machineLabourFee: function (gljArr) {
         if (!gljArr) return 0;
-        let result = 0, mdSum = 0;
+        let result = 0;
         for (let glj of gljArr) {
             if (glj.type == gljType.GENERAL_MACHINE) {
                 // 获取机械组成物
                 let mds = projectObj.project.composition.getCompositionByGLJ(glj);
                 if (!mds) mds = [];
+                let mdSum = 0;
                 for (let md of mds) {
                     if (md.type == gljType.MACHINE_LABOUR) {
                         let q = md["consumption"] ? md["consumption"] : 0;
@@ -317,10 +251,10 @@ let assistCalcer = {
     estimateFee: function (treeNode, isBase = false){
         let me = this, sumU = 0, sumT = 0;
         // 父清单暂估费的汇总计算走计算程序逻辑,不在这里。
-        if (nodeTools.isTotalCostBill(treeNode)){
+        if (me.isTotalCostBill(treeNode)){
             let nodes = projectObj.project.mainTree.roots;
             for (let node of nodes){
-                if (nodeTools.isTotalCostBill(node)) break;
+                if (me.isTotalCostBill(node)) break;
                 let eU = 0, eT = 0;
                 if (node.data.feesIndex && node.data.feesIndex.estimate){
                     eU = node.data.feesIndex.estimate.unitFee;
@@ -351,12 +285,12 @@ let assistCalcer = {
                             for (let md of mds){
                                 if (md.isEstimate){
                                     let isExist = false;
-                                    let mdQ = (me.uiGLJQuantity(glj.quantity) * me.uiGLJQuantity(md.consumption)).toDecimal(decimalObj.process);
+                                    let mdQ = (me.uiGLJQty(glj.quantity) * me.uiGLJQty(md.consumption)).toDecimal(decimalObj.process);
 
                                     for (let obj of GLJObjs){
                                         if (gljOprObj.getIndex(md, gljKeyArray) == gljOprObj.getIndex(obj, gljKeyArray)){
                                             isExist = true;
-                                            obj.quantity = (me.uiGLJQuantity(obj.quantity) + mdQ).toDecimal(decimalObj.process);
+                                            obj.quantity = (me.uiGLJQty(obj.quantity) + mdQ).toDecimal(decimalObj.process);
                                             break;
                                         }
                                     };
@@ -371,16 +305,16 @@ let assistCalcer = {
             };
 
             for (let obj of GLJObjs){
-                sumU = sumU + (me.uiGLJQuantity(obj.quantity) * me.uiGLJPrice(obj.marketPrice)).toDecimal(decimalObj.process);
+                sumU = sumU + (me.uiGLJQty(obj.quantity) * me.uiGLJPrice(obj.marketPrice)).toDecimal(decimalObj.process);
                 sumU = sumU.toDecimal(decimalObj.process);
 
-                let q = (me.uiGLJQuantity(obj.quantity) * me.uiQuantity(treeNode)).toDecimal(decimalObj.process);
+                let q = (me.uiGLJQty(obj.quantity) * me.uiNodeQty(treeNode)).toDecimal(decimalObj.glj.quantity);
                 sumT = sumT + (q * me.uiGLJPrice(obj.marketPrice)).toDecimal(decimalObj.process);
                 sumT = sumT.toDecimal(decimalObj.process);
             };
             sumU = sumU.toDecimal(decimalObj.bills.unitPrice);
             if (projectObj.project.property.zanguCalcMode == zanguCalcType.common){
-                sumT = (me.uiQuantity(treeNode) * sumU).toDecimal(decimalObj.bills.totalPrice);
+                sumT = (me.uiNodeQty(treeNode) * sumU).toDecimal(decimalObj.bills.totalPrice);
             }
             else if (projectObj.project.property.zanguCalcMode == zanguCalcType.gatherMaterial){
                 sumT = sumT.toDecimal(decimalObj.bills.totalPrice);
@@ -390,7 +324,7 @@ let assistCalcer = {
         if (isBase)
             return sumU
         else
-            nodeTools.checkFeeField(treeNode, {'fieldName': 'estimate', 'unitFee': sumU, 'totalFee': sumT});
+            me.checkFeeField(treeNode, {'fieldName': 'estimate', 'unitFee': sumU, 'totalFee': sumT});
     },
     marketPriceToBase: function (treeNode, baseName) {
         if (treeNode.data.type != rationType.volumePrice && treeNode.data.type != rationType.gljRation) return;
@@ -415,56 +349,138 @@ let assistCalcer = {
                 'quantity': 1,
                 'type': treeNode.data.subType      // 注意:这里要取subType
             };
-            result = assistCalcer.machineLabourFee([glj]);
+            result = me.machineLabourFee([glj]);
         }
         else if (
             (treeNode.data.type == rationType.gljRation) &&
             ((treeNode.data.subType === gljType.LABOUR && baseName === '人工费价差') ||
-            (baseMaterialTypes.includes(treeNode.data.subType) && baseName === '材料费价差') ||
-            (treeNode.data.subType === gljType.GENERAL_MACHINE && baseName === '机械费价差'))
+                (baseMaterialTypes.includes(treeNode.data.subType) && baseName === '材料费价差') ||
+                (treeNode.data.subType === gljType.GENERAL_MACHINE && baseName === '机械费价差'))
         ) {
             let aprice = me.uiGLJPrice(treeNode.data.adjustPrice);
             let mprice = me.uiGLJPrice(treeNode.data.marketUnitFee);
             result = (mprice - aprice).toDecimal(decimalObj.ration.unitPrice);
         }
         return result;
+    },
+    getCalcType: function (treeNode) {
+        if (this.isRationCategory(treeNode)){
+            return treeNodeCalcType.ctRationCalcProgram;
+        }
+        else if (this.isNullBill(treeNode)){
+            return treeNodeCalcType.ctNull;
+        }
+        else if (this.isLeafBill(treeNode)) {
+            if (treeNode.children && treeNode.children.length > 0){
+                // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
+                if (projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
+                    return treeNodeCalcType.ctBillCalcProgram;
+                else                                        // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
+                    return treeNodeCalcType.ctGatherRationsFees;
+            }
+            else{                                          // 公式计算
+                return treeNodeCalcType.ctCalcBaseValue;
+            };
+        }
+        else if (this.isBill(treeNode)) {                              // 父清单:汇总子清单的费用类别
+            return treeNodeCalcType.ctGatherBillsFees;
+        }
+        else {
+            return treeNodeCalcType.ctRationCalcProgram;
+        };
+    },
+    cutNodeForSave(treeNode){
+        let me = this;
+        /*  subType、quantity、calcBase、programID、marketUnitFee等等字段较为特殊,它们的改变一定会触发计算并导致计算
+            结果的变化,从而引发保存动作。将这些字段放在该位置跟计算结果一起保存,可减少前端跟后端的通讯频率。              */
+        let data = {
+            projectID: projectObj.project.ID(),
+            ID: treeNode.data.ID,
+            unit: treeNode.data.unit,   //对清单来说,改变单位,工程量精度会跟着改变从而影响计算。
+            subType: treeNode.data.subType,
+            quantity: treeNode.data.quantity,
+            calcBase: treeNode.data.calcBase,
+            calcBaseValue: treeNode.data.calcBaseValue,
+            programID: treeNode.data.programID,
+            marketUnitFee: treeNode.data.marketUnitFee,
+            marketTotalFee: treeNode.data.marketTotalFee,
+            fees: treeNode.data.fees,
+            isFromDetail:treeNode.data.isFromDetail,
+            feeRate: treeNode.data.feeRate,
+            feeRateID: treeNode.data.feeRateID,
+            contain: treeNode.data.contain,
+            quantityEXP: treeNode.data.quantityEXP,
+            summaryFees: treeNode.data.summaryFees
+        };
+
+        // 定额大类
+        if (me.isRationCategory(treeNode)) {
+            data.isSubcontract = treeNode.data.isSubcontract;
+
+            //定额类型的工料机做特殊处理
+            if(me.isGljRation(treeNode)){
+                data.code = treeNode.data.code;
+                data.projectGLJID = treeNode.data.projectGLJID;
+                delete data.marketUnitFee;
+            };
+        };
+
+        // 优化掉 undefined 属性
+        data = JSON.parse(JSON.stringify(data));
+        return data;
+    },
+
+    uiNodeQty: function (treeNode){
+        return parseFloatPlus(treeNode.data.quantity).toDecimal(decimalObj.decimal("quantity", treeNode));
+    },
+    // 界面显示的工料机价格,包括定额价、市场价等。参数 price 传入一个普通的价格数值即可。
+    uiGLJPrice: function (price){
+        if (price)
+            return parseFloat(price).toDecimal(decimalObj.glj.unitPrice)
+        else return 0;
+    },
+    // 界面显示的工料机数量。参数 quantity 传入一个普通的数量数值即可。
+    uiGLJQty: function (quantity){
+        if (quantity)
+            return parseFloat(quantity).toDecimal(decimalObj.glj.quantity)
+        else return 0;
     }
 };
 
-const rationCalcBaser = {
+const rationCalcBases = {
     '定额基价人工费': function (node) {
-        return assistCalcer.rationBaseFee(node, [gljType.LABOUR], priceTypes.ptBasePrice);
+        return calcTools.rationBaseFee(node, [gljType.LABOUR], priceTypes.ptBasePrice);
     },
     '定额基价材料费': function (node) {
-        return assistCalcer.rationBaseFee(node, baseMaterialTypes, priceTypes.ptBasePrice);
+        return calcTools.rationBaseFee(node, baseMaterialTypes, priceTypes.ptBasePrice);
     },
     '定额基价机械费': function (node) {
-        return assistCalcer.rationBaseFee(node, [gljType.GENERAL_MACHINE], priceTypes.ptBasePrice);
+        return calcTools.rationBaseFee(node, [gljType.GENERAL_MACHINE], priceTypes.ptBasePrice);
     },
     '定额基价机上人工费': function (node) {
-        return assistCalcer.machineLabourFee(node.data.gljList);
+        return calcTools.machineLabourFee(node.data.gljList);
     },
     '人工费价差': function (node) {
-        return assistCalcer.rationBaseFee(node, [gljType.LABOUR], priceTypes.ptDiffPrice);
+        return calcTools.rationBaseFee(node, [gljType.LABOUR], priceTypes.ptDiffPrice);
     },
     '材料费价差': function (node) {
-        return assistCalcer.rationBaseFee(node, baseMaterialTypes, priceTypes.ptDiffPrice);
+        return calcTools.rationBaseFee(node, baseMaterialTypes, priceTypes.ptDiffPrice);
     },
     '机械费价差': function (node) {
-        return assistCalcer.rationBaseFee(node, [gljType.GENERAL_MACHINE], priceTypes.ptDiffPrice);
+        return calcTools.rationBaseFee(node, [gljType.GENERAL_MACHINE], priceTypes.ptDiffPrice);
     },
     '主材费': function (node) {
-        return assistCalcer.rationBaseFee(node, [gljType.MAIN_MATERIAL], priceTypes.ptMarketPrice);
+        return calcTools.rationBaseFee(node, [gljType.MAIN_MATERIAL], priceTypes.ptMarketPrice);
     },
     '设备费': function (node) {
-        return assistCalcer.rationBaseFee(node, [gljType.EQUIPMENT], priceTypes.ptMarketPrice);
+        return calcTools.rationBaseFee(node, [gljType.EQUIPMENT], priceTypes.ptMarketPrice);
     },
     '人工工日': function (node) {
         if (!node.data.gljList) return 0;
         let rst = 0;
         for (let glj of node.data.gljList) {
             if (glj.type == gljType.LABOUR) {
-                rst = rst + (assistCalcer.uiGLJQuantity(glj["quantity"]) * assistCalcer.uiQuantity(node)).toDecimal(decimalObj.process);
+                rst = rst + (calcTools.uiGLJQty(glj["quantity"]) * calcTools.uiNodeQty(node)).toDecimal(decimalObj.process);
                 rst = rst.toDecimal(decimalObj.process);
             }
         };
@@ -491,19 +507,31 @@ const rationCalcBaser = {
     '甲定设备费': function (node) {
     },
     '暂估材料费': function (node) {
-        return assistCalcer.estimateFee(node, true);
+        return calcTools.estimateFee(node, true);
     },
     '分包定额基价人工费': function (node) {
+        if (node.data.isSubcontract) return this.定额基价人工费(node)
+        else return 0;
     },
     '分包定额基价材料费': function (node) {
+        if (node.data.isSubcontract) return this.定额基价材料费(node)
+        else return 0;
     },
     '分包定额基价机械费': function (node) {
+        if (node.data.isSubcontract) return this.定额基价机械费(node)
+        else return 0;
     },
     '分包主材费': function (node) {
+        if (node.data.isSubcontract) return this.主材费(node)
+        else return 0;
     },
     '分包设备费': function (node) {
+        if (node.data.isSubcontract) return this.设备费(node)
+        else return 0;
     },
     '分包人工工日': function (node) {
+        if (node.data.isSubcontract) return this.人工工日(node)
+        else return 0;
     }
 };
 
@@ -663,21 +691,21 @@ let executeObj = {
         let me = executeObj;
 
         // 量价、工料机形式的定额, 要把自己的市场单价用于计算程序中的基数。
-        if (me.treeNode.data.type == rationType.volumePrice || me.treeNode.data.type == rationType.gljRation)
-            return assistCalcer.marketPriceToBase(me.treeNode, baseName)
+        if (calcTools.isVolumePrice(me.treeNode) || calcTools.isGljRation(me.treeNode))
+            return calcTools.marketPriceToBase(me.treeNode, baseName)
         else{
-            if (!rationCalcBaser[baseName]){
+            if (!rationCalcBases[baseName]){
                 alert('定额基数“' + baseName + '”末定义,计算错误。 (模板 ' + me.template.ID + ',规则 ' + me.tempCalcItem.ID +')');
                 return 0;
             }
             else
-                return rationCalcBaser[baseName](me.treeNode);
+                return rationCalcBases[baseName](me.treeNode);
         }
     },
     HJ: function () {
         let me = this;
         let p = me.treeNode.data.calcBaseValue ? me.treeNode.data.calcBaseValue : 0;
-        let q = assistCalcer.uiQuantity(me.treeNode) ? assistCalcer.uiQuantity(me.treeNode) : 1;
+        let q = calcTools.uiNodeQty(me.treeNode) ? calcTools.uiNodeQty(me.treeNode) : 1;
         let u = (p / q).toDecimal(decimalObj.decimal('unitPrice', me.treeNode));
         return u;
     }
@@ -889,37 +917,10 @@ class CalcProgram {
         }
 
         let me = this;
-
         me.project.beginUpdate('');
         for (let node of treeNodes){
             if (node.changed){
-                let data = {
-                    ID: node.data.ID,
-                    projectID: me.project.ID(),
-                    unit:node.data.unit,//对清单来说,改变单位,工程量精度会跟着改变从而影响计算。
-                    /*  subType、quantity、calcBase、programID、marketUnitFee等等字段较为特殊,它们的改变一定会触发计算并导致计算
-                    结果的变化,从而引发保存动作。将这些字段放在该位置跟计算结果一起保存,可减少前端跟后端的通讯频率。              */
-                    subType: node.data.subType,
-                    quantity: node.data.quantity,
-                    calcBase: node.data.calcBase,
-                    calcBaseValue: node.data.calcBaseValue,
-                    programID: node.data.programID,
-                    marketUnitFee: node.data.marketUnitFee,
-                    marketTotalFee: node.data.marketTotalFee,
-                    fees: node.data.fees,
-                    isFromDetail:node.data.isFromDetail,
-                    feeRate: node.data.feeRate,
-                    feeRateID: node.data.feeRateID,
-                    contain:node.data.contain,
-                    quantityEXP:node.data.quantityEXP
-                };
-                if (node.data.summaryFees) data.summaryFees = node.data.summaryFees;
-                if(node.sourceType==ModuleNames.ration && node.data.type==rationType.gljRation){//定额类型的工料机做特殊处理
-                    data.code=node.data.code;
-                    data.projectGLJID = node.data.projectGLJID;
-                    delete data.marketUnitFee;
-                }
-
+                let data = calcTools.cutNodeForSave(node);
                 let newData = {'updateType': 'ut_update', 'updateData': data};
                 me.project.push(node.sourceType, [newData]);
             }
@@ -939,10 +940,9 @@ class CalcProgram {
     innerCalc(treeNode, changedArr){
         let me = this;
         // 仅用作树节点显示的工料机不能参与计算。
-        if (treeNode.sourceType === me.project.ration_glj.getSourceType()) return;
+        if (treeNode.sourceType === ModuleNames.ration_glj) return;
 
-        treeNode.calcType = nodeTools.getCalcType(treeNode);
-        // if (treeNode.calcType == treeNodeCalcType.ctCalcBaseValue) return;
+        treeNode.calcType = calcTools.getCalcType(treeNode);
 
         function isBaseFeeType(type){
             return ['labour', 'material', 'machine', 'mainMaterial', 'equipment'].indexOf(type) > -1;
@@ -961,7 +961,7 @@ class CalcProgram {
                 }
             }
             else{   // 总造价清单只留common, estimate两个费用类别。其它公式清单只留common。
-                let reserveArr = nodeTools.isTotalCostBill(treeNode)? ['common', 'estimate']:['common'];
+                let reserveArr = calcTools.isTotalCostBill(treeNode)? ['common', 'estimate']:['common'];
                 if (treeNode.data.fees && treeNode.data.fees.length > 0){
                     let feesArr = treeNode.data.fees;
                     for (let i = 0; i < feesArr.length; i++) {
@@ -978,7 +978,7 @@ class CalcProgram {
         // 父清单汇总子项(子清单或定额)的费用类别
         if (treeNode.calcType == treeNodeCalcType.ctGatherBillsFees || treeNode.calcType == treeNodeCalcType.ctGatherRationsFees){
             treeNode.data.programID = null;
-            nodeTools.initFees(treeNode);
+            calcTools.initFees(treeNode);
             let nodes = (treeNode.calcType == treeNodeCalcType.ctGatherBillsFees) ? treeNode.children : me.project.Ration.getRationNodes(treeNode);
             let rst = [];
             for (let ft of cpFeeTypes) {
@@ -990,18 +990,19 @@ class CalcProgram {
                 if (treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
                     for (let node of nodes) {
                         if (node.data.feesIndex && node.data.feesIndex[ft.type]) {
-                            buf = (buf + parseFloatPlus(node.data.feesIndex[ft.type].unitFee)).toDecimal(decimalObj.process);
+                            // 父清单不要汇总综合单价。
+                            // buf = (buf + parseFloatPlus(node.data.feesIndex[ft.type].unitFee)).toDecimal(decimalObj.process);
                             btf = (btf + parseFloatPlus(node.data.feesIndex[ft.type].totalFee)).toDecimal(decimalObj.process);
-                            btuf = (btuf + parseFloatPlus(node.data.feesIndex[ft.type].tenderUnitFee)).toDecimal(decimalObj.process);
+                            // btuf = (btuf + parseFloatPlus(node.data.feesIndex[ft.type].tenderUnitFee)).toDecimal(decimalObj.process);
                             bttf = (bttf + parseFloatPlus(node.data.feesIndex[ft.type].tenderTotalFee)).toDecimal(decimalObj.process);
                         };
                     };
                 }
                 else if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees){     // 这里的算法要配合冷姐姐的神图才能看懂^_^
                     let sum_rtf = 0, sum_rttf = 0;
-                    let bq = assistCalcer.uiQuantity(treeNode) ? assistCalcer.uiQuantity(treeNode) : 1;
+                    let bq = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 1;
                     for (let node of nodes) {
-                        let rq = assistCalcer.uiQuantity(node) ? assistCalcer.uiQuantity(node) : 0;
+                        let rq = calcTools.uiNodeQty(node) ? calcTools.uiNodeQty(node) : 0;
                         let ruf = 0, rtuf = 0, rtf = 0, rttf = 0;
                         if (node.data.feesIndex && node.data.feesIndex[ft.type]) {
                             ruf = parseFloat(node.data.feesIndex[ft.type].unitFee);
@@ -1028,8 +1029,8 @@ class CalcProgram {
                         bttf = sum_rttf;
                     }
                     else{
-                        btf = (buf * bq).toDecimal(decimalObj.process);
-                        bttf = (btuf * bq).toDecimal(decimalObj.process);
+                        btf = (buf.toDecimal(decimalObj.bills.unitPrice) * bq).toDecimal(decimalObj.process);
+                        bttf = (btuf.toDecimal(decimalObj.bills.unitPrice) * bq).toDecimal(decimalObj.process);
                     };
                 };
 
@@ -1037,7 +1038,7 @@ class CalcProgram {
                 ftObj.totalFee = btf.toDecimal(decimalObj.bills.totalPrice);
                 ftObj.tenderUnitFee = btuf.toDecimal(decimalObj.bills.unitPrice);
                 ftObj.tenderTotalFee = bttf.toDecimal(decimalObj.bills.totalPrice);
-                nodeTools.checkFeeField(treeNode, ftObj);
+                calcTools.checkFeeField(treeNode, ftObj);
 
                 rst.push(ftObj);
             };
@@ -1080,24 +1081,24 @@ class CalcProgram {
             }
 
             let f = treeNode.data.feeRate ? treeNode.data.feeRate : 100;
-            let q = assistCalcer.uiQuantity(treeNode) ? assistCalcer.uiQuantity(treeNode) : 1;
+            let q = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 1;
             let b = treeNode.data.calcBaseValue ? treeNode.data.calcBaseValue : 0;
             let uf = (b * f * q / 100).toDecimal(decimalObj.bills.unitPrice);
             let tuf = uf;
             let tf = (me.project.property.billsCalcMode === leafBillGetFeeType.rationPrice) ? (b * f / 100).toDecimal(decimalObj.bills.totalPrice) : (uf * q).toDecimal(decimalObj.bills.totalPrice);
             let ttf = tf;
             deleteUselessFees(treeNode);
-            nodeTools.checkFeeField(treeNode, {'fieldName': 'common', 'unitFee': uf, 'totalFee': tf});
+            calcTools.checkFeeField(treeNode, {'fieldName': 'common', 'unitFee': uf, 'totalFee': tf});
 
             // 总造价清单还要做单项工程、建设项目的四大项金额汇总
-            if (nodeTools.isTotalCostBill(treeNode)){
+            if (calcTools.isTotalCostBill(treeNode)){
                 // 公式叶子清单没有暂估费,但总造价清单除外。
-                assistCalcer.estimateFee(treeNode);
-                nodeTools.initSummaryFee(treeNode);
+                calcTools.estimateFee(treeNode);
+                calcTools.initSummaryFee(treeNode);
                 treeNode.data.summaryFees.totalFee = tf;
-                treeNode.data.summaryFees.estimateFee = nodeTools.getFee(treeNode, 'estimate.totalFee');
-                treeNode.data.summaryFees.safetyFee = nodeTools.getFee(nodeTools.getNodeByFlag(fixedFlag.SAFETY_CONSTRUCTION), 'common.totalFee');
-                treeNode.data.summaryFees.chargeFee = nodeTools.getFee(nodeTools.getNodeByFlag(fixedFlag.CHARGE), 'common.totalFee');
+                treeNode.data.summaryFees.estimateFee = calcTools.getFee(treeNode, 'estimate.totalFee');
+                treeNode.data.summaryFees.safetyFee = calcTools.getFee(calcTools.getNodeByFlag(fixedFlag.SAFETY_CONSTRUCTION), 'common.totalFee');
+                treeNode.data.summaryFees.chargeFee = calcTools.getFee(calcTools.getNodeByFlag(fixedFlag.CHARGE), 'common.totalFee');
             }
 
             treeNode.data.calcTemplate = {"calcItems": []};
@@ -1109,7 +1110,7 @@ class CalcProgram {
                 if (treeNode.data.type == rationType.volumePrice){
                     delete treeNode.data.gljList;
                     let muf = treeNode.data.marketUnitFee ? treeNode.data.marketUnitFee : 0;
-                    let q = assistCalcer.uiQuantity(treeNode) ? assistCalcer.uiQuantity(treeNode) : 0;
+                    let q = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 0;
                     treeNode.data.marketTotalFee = (muf * q).toDecimal(decimalObj.ration.totalPrice);
                 }
                 else if (treeNode.data.type == rationType.gljRation){
@@ -1118,7 +1119,7 @@ class CalcProgram {
                 else{
                     treeNode.data.gljList = me.project.ration_glj.getGljArrByRation(treeNode.data.ID);
                     // 计算程序里没有暂估费的计算规则,会漏掉,所以这里要专门算。
-                    assistCalcer.estimateFee(treeNode);
+                    calcTools.estimateFee(treeNode);
                     fnArr.push('estimate');
                 };
 
@@ -1135,7 +1136,7 @@ class CalcProgram {
                 }
 
                 // 叶子清单自己的计算程序计算,其暂估费也要汇总算。
-                assistCalcer.estimateFee(treeNode);
+                calcTools.estimateFee(treeNode);
                 fnArr.push('estimate');
             };
 
@@ -1147,7 +1148,7 @@ class CalcProgram {
                 $CE.treeNode = treeNode;
                 $CE.template = template;
 
-                nodeTools.initFees(treeNode);
+                calcTools.initFees(treeNode);
 
                 for (let idx of template.compiledSeq) {
                     let calcItem = template.calcItems[idx];
@@ -1155,12 +1156,12 @@ class CalcProgram {
                     let feeRate = parseFloatPlus(calcItem.feeRate) ? parseFloatPlus(calcItem.feeRate).toDecimal(decimalObj.feeRate) : 100;  // 100%
                     calcItem.unitFee = (eval(calcItem.compiledExpr) * feeRate * 0.01).toDecimal(decimalObj.decimal('unitPrice', treeNode));   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
 
-                    let q = assistCalcer.uiQuantity(treeNode) ? assistCalcer.uiQuantity(treeNode) : 0;
+                    let q = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 0;
                     calcItem.totalFee = (calcItem.unitFee * q).toDecimal(decimalObj.decimal('totalPrice', treeNode));
 
                     if (calcItem.fieldName) {
                         fnArr.push(calcItem.fieldName);
-                        nodeTools.checkFeeField(treeNode, calcItem);
+                        calcTools.checkFeeField(treeNode, calcItem);
                     };
                 };
                 deleteUselessFees(treeNode, fnArr);
@@ -1250,7 +1251,7 @@ class CalcProgram {
     // 计算叶子清单下的所有子结点、自身、所有父结点、公式引用结点(即跟该叶子清单相关的所有结点)。最后打包存储。
     calcLeafAndSave(treeNode){
         let me = this;
-        if(!nodeTools.isLeafBill(treeNode)) return;
+        if(!calcTools.isLeafBill(treeNode)) return;
         if (treeNode.children && treeNode.children.length > 0) {
             let changedNodes = [];
             for (let child of treeNode.children){
@@ -1306,7 +1307,7 @@ class CalcProgram {
 
     // 排除指定项的综合合价计算(用于带循环计算的情况)
     getTotalFee(excludeNodes){
-        excludeNodes.push(nodeTools.getNodeByFlag(fixedFlag.ENGINEERINGCOST));
+        excludeNodes.push(calcTools.getNodeByFlag(fixedFlag.ENGINEERINGCOST));
         let me = this;
         let rst = 0;
 
@@ -1318,7 +1319,7 @@ class CalcProgram {
                     }
                     else{
                         if (node.sourceType != ModuleNames.ration_glj) {
-                            rst = (rst + nodeTools.getFee(node, 'common.totalFee')).toDecimal(decimalObj.bills.totalPrice);
+                            rst = (rst + calcTools.getFee(node, 'common.totalFee')).toDecimal(decimalObj.bills.totalPrice);
                         };
                     }
                 }

+ 25 - 10
web/building_saas/main/js/models/main_consts.js

@@ -45,7 +45,6 @@ const gljType = {
     // 设备
     EQUIPMENT: 5
 };
-
 // 计算基数 [定额基价材料费] 要用到的材料类型。
 const baseMaterialTypes = [
     gljType.GENERAL_MATERIAL,
@@ -55,7 +54,6 @@ const baseMaterialTypes = [
     gljType.COMMERCIAL_CONCRETE,
     gljType.COMMERCIAL_MORTAR
 ];
-
 // 全部材料类型。用于暂估等 (多了主材和设备)
 const allMaterialTypes = [
     gljType.GENERAL_MATERIAL,
@@ -67,14 +65,12 @@ const allMaterialTypes = [
     gljType.MAIN_MATERIAL,
     gljType.EQUIPMENT
 ];
-
 // 会有组成物的材料
 const compositionTypes = [
     gljType.MAIN_MATERIAL,
     gljType.CONCRETE,
     gljType.MORTAR,
     gljType.MIX_RATIO];
-
 const notEditType = [
     gljType.CONCRETE,
     gljType.MORTAR,
@@ -107,13 +103,17 @@ const treeNodeCalcType = {
     ctNull: 6
     // ctCommonUnitFee: 6       // 树结点的手工输入综合单价的方式已废弃,现综合单价只读,引入市场单价。
 };
-
 const calcAllType = {
     catAll: 'all',
     catBills: 'bills',
     catRations: 'ration'
 };
-
+const priceTypes = {
+    ptBasePrice: 1,
+    ptAdjustPrice: 2,
+    ptMarketPrice: 3,
+    ptDiffPrice: 4
+};
 const subSheetIndex = {
     ssiRationGLJ: 0,
     ssiRationCoe: 1,
@@ -123,7 +123,6 @@ const subSheetIndex = {
     ssiMemo: 5,
     ssiFeature: 6
 };
-
 const volumePriceMaps = {
     "量人": gljType.LABOUR,
     "量材": gljType.GENERAL_MATERIAL,
@@ -143,20 +142,17 @@ const volumePriceMaps = {
     4: "量主",
     5: "量设"
 };
-
 const rationType = {
     ration: 1,
     volumePrice: 2,
     gljRation: 3
 };
-
 const leafBillGetFeeType = {
     rationContent: 0,
     rationPriceConverse: 1,
     rationPrice: 2,
     billsPrice: 3
 };
-
 const zanguCalcType = {
     common: 0,
     gatherMaterial: 1
@@ -219,3 +215,22 @@ const billText = {
     3:'分项',
     4:'清单'
 };
+
+const cpFeeTypes = [
+    {type: 'direct', name: '直接费'},
+    {type: 'labour', name: '人工费'},
+    {type: 'material', name: '材料费'},
+    {type: 'machine', name: '机械费'},
+    {type: 'mainMaterial', name: '主材费'},
+    {type: 'equipment', name: '设备费'},
+    {type: 'manage', name: '企业管理费'},
+    {type: 'profit', name: '利润'},
+    {type: 'risk', name: '风险费'},
+    {type: 'labourDiff', name: '人工价差'},
+    {type: 'materialDiff', name: '材料价差'},
+    {type: 'machineDiff', name: '机械价差'},
+    {type: 'adjustLabour', name: '调整人工费'},
+    {type: 'adjustMachineLabour', name: '调整机上人工费'},
+    {type: 'estimate', name: '暂估费'},
+    {type: 'common', name: '工程造价'}
+];

+ 16 - 6
web/building_saas/main/js/views/main_tree_col.js

@@ -25,7 +25,7 @@ let MainTreeCol = {
           if(node.sourceType === projectObj.project.ration_glj.getSourceType()){
               return gljOprObj.getTotalQuantity(node.data);
           }else {
-              return assistCalcer.uiQuantity(node)?assistCalcer.uiQuantity(node):null;
+              return calcTools.uiNodeQty(node)?calcTools.uiNodeQty(node):null;
           }
         },
         // CSL, 2017-11-28
@@ -56,6 +56,8 @@ let MainTreeCol = {
     readOnly: {
         // Vincent, 2018-01-09
         subType: function (node) {
+            if (calcTools.isVolumePrice(node)) return false;
+
             if(MainTreeCol.readOnly.bills(node)){
                 return true;
             }
@@ -72,7 +74,7 @@ let MainTreeCol = {
         calcProgramName: function (node) {
             if (
                 node.sourceType === projectObj.project.Ration.getSourceType() ||
-                (nodeTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
+                (calcTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
             ) return false
             else return true;
         },
@@ -80,7 +82,7 @@ let MainTreeCol = {
             return node.data.subType != 201 && node.data.subType != 4 && node.data.subType != 5
         },
         commonUnitFee: function (node) {
-            return !nodeTools.isNullBill(node);
+            return !calcTools.isNullBill(node);
         },
         //根据节点、父节点类型判断是否可用计算基数
         calcBaseType: function (node) {
@@ -114,7 +116,10 @@ let MainTreeCol = {
             return node.sourceType === projectObj.project.Bills.getSourceType();
         },
         ration: function (node) {
-            return nodeTools.isRation(node);
+            return calcTools.isRationItem(node);
+        },
+        isSubcontract: function (node) {
+            return !calcTools.isRationCategory(node);
         },
         glj: function (node) {
             return node.sourceType == projectObj.project.ration_glj.getSourceType();
@@ -178,7 +183,7 @@ let MainTreeCol = {
             if(MainTreeCol.readOnly.bills(node)&&(node.data.type==billType.DXFY||node.data.type==billType.FB)){//在大项费用、分部行,计量单位只读。
                 return true;
             }else {
-               return nodeTools.isRation(node);
+               return calcTools.isRationItem(node);
             }
         }
     },
@@ -207,7 +212,7 @@ let MainTreeCol = {
         calcProgramName: function (node) {
             if (
                 node.sourceType === projectObj.project.Ration.getSourceType() ||
-                (nodeTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
+                (calcTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
             ) {
                 // var names = new GC.Spread.Sheets.CellTypes.ComboBox();
                 var names = sheetCommonObj.getDynamicCombo();
@@ -238,6 +243,11 @@ let MainTreeCol = {
                 }
             }
         },
+
+        isSubcontract: function (node){
+            if (calcTools.isRationCategory(node))
+                return new GC.Spread.Sheets.CellTypes.CheckBox();
+        }
     },
     getEvent: function (eventName) {
         let names = eventName.split('.');

+ 24 - 28
web/building_saas/main/js/views/project_view.js

@@ -34,8 +34,9 @@ var projectObj = {
 
         // for test interface.  CSLAAAAA
 /*        node.data.gljList = project.ration_glj.getGljArrByRation(node.data.ID);
-        let bname = '暂估材料费';
-        alert(bname + ': ' + rationCalcBaser[bname](node));*/
+        node.data.isSubcontract = true;
+        let bname = '分包人工工日';
+        alert(bname + ': ' + rationCalcBases[bname](node));*/
     },
     refreshBaseActn: function (tree) {
         let setButtonValid = function (valid, btn) {
@@ -273,11 +274,11 @@ var projectObj = {
         if(node.sourceType==project.ration_glj.getSourceType()){
             project.ration_glj.updateFromMainSpread(value,node,fieldName);
         }
-        else if(nodeTools.isGljRation(node)){
+        else if(calcTools.isGljRation(node)){
             gljOprObj.updateRationTypeGLJ(value,node,fieldName);
         }
         else if (value !== calcFees.getFee(node.data, fieldName)||fieldName == 'quantity') {//工程量需要进行转换,所以做特殊处理
-            if (fieldName === 'code' && !nodeTools.isVolumePrice(node)) {
+            if (fieldName === 'code' && !calcTools.isVolumePrice(node)) {
                 projectObj.updateCode(node, value);
             }
             else if(fieldName ==='feeRate'){
@@ -287,7 +288,7 @@ var projectObj = {
                 project.Ration.updateContain(value,node);
             }
             else if (fieldName === 'quantity' || fieldName === 'marketUnitFee' || fieldName === 'programID' ||
-                fieldName === 'subType' || fieldName === 'calcBase'){
+                fieldName === 'subType' || fieldName === 'calcBase' || fieldName === 'isSubcontract'){
                 if (fieldName === 'quantity') {
                     project.quantity_detail.editMainTreeNodeQuantity(value,node,fieldName,editingText);
                     return;
@@ -416,7 +417,7 @@ var projectObj = {
                 that.project.property = projectInfoObj.projectInfo.property;
                 //that.project.calcProgram.compileAllTemps();
                 that.project.calcBase.init(that.project);
-                that.project.calcFields = JSON.parse(JSON.stringify(cpFeeTypes));
+                // that.project.calcFields = JSON.parse(JSON.stringify(cpFeeTypes));
                 // that.project.initCalcFields();
                 let str = JSON.stringify(that.project.projSetting.main_tree_col);
                 that.project.projSetting.mainGridSetting = JSON.parse(str);
@@ -467,12 +468,12 @@ var projectObj = {
                     }
 
                     // 综合单价、综合合价,小数部分应补0对齐。  CSLAAAAA
-                    if (col.data.field.hasSubStr("common")){
-                        if (col.data.field.hasSubStr("totalFee"))
+                    // if (col.data.field.hasSubStr("common")){
+                        if (col.data.field.hasSubStr(".totalFee"))
                             col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.totalPrice, true)
-                        else if (col.data.field.hasSubStr("unitFee"))
+                        else if (col.data.field.hasSubStr(".unitFee"))
                             col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.unitPrice, true)
-                    }
+                    // }
 
                 });
 
@@ -488,6 +489,7 @@ var projectObj = {
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EditEnded, that.mainSpreadEditEnded);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.RangeChanged, that.mainSpreadRangeChanged);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.SelectionChanged, that.amountAreaNumber);
+                that.mainSpread.bind(GC.Spread.Sheets.Events.ButtonClicked, that.onButtonClick);
                 that.loadMainSpreadContextMenu();
                 that.loadFocusLocation();
                 let endTime = +new Date();
@@ -840,6 +842,15 @@ var projectObj = {
         };
  },
 
+    onButtonClick: function (e, info) {
+        let node = projectObj.project.mainTree.items[info.row];
+        if (node.data.isSubcontract) node.data.isSubcontract = false
+        else node.data.isSubcontract = true;
+
+        node.changed = true;
+        projectObj.project.calcProgram.calcAndSave(node);
+    },
+
     //根据节点获取行style(颜色、字体加粗)
     getNodeColorStyle: function (node, colSetting) {
         let colorSetting = optionsOprObj.getOption(optionsOprObj.optionsTypes.COLOROPTS);
@@ -1147,24 +1158,9 @@ $('#property_ok').click(function () {
         changedNodes = project.calcProgram.calcAllNodes(calcAllType.catBills);
     if (changedNodes.length > 0) {
         for (let node of changedNodes){
-            let data = {
-                // projectID: projectID,
-                ID: node.data.ID,
-                quantity: node.data.quantity,
-                calcBase: node.data.calcBase,
-                calcBaseValue: node.data.calcBaseValue,
-                marketUnitFee: node.data.marketUnitFee,
-                marketTotalFee: node.data.marketTotalFee,
-                fees: node.data.fees,
-                feeRate: node.data.feeRate,
-                feeRateID: node.data.feeRateID
-            };
-            if (node.sourceType == 'ration'){
-                rations.push(data);
-            }
-            else if (node.sourceType == 'bills'){
-                bills.push(data);
-            };
+            let data = calcTools.cutNodeForSave(node);
+            if (node.sourceType == 'ration') rations.push(data)
+            else if (node.sourceType == 'bills') bills.push(data);
         };
     };