Browse Source

1. 动态投资,项目信息,新增数据指标
2. 导入台账Excel,识别23广东编号
3. 台账修订,计算变更清单缓存金额
4. 报表,新增预估决算类指标

MaiXinRong 1 year ago
parent
commit
e308d7a5e1

+ 5 - 0
app/const/spread.js

@@ -223,6 +223,11 @@ const stageTz = {
             {title: '|项目节数量2',  colSpan: '|1', rowSpan: '|1', field: 'deal_dgn_qty2', hAlign: 2, width: 60, type: 'Number'},
             {title: '变更|项目节数量1',  colSpan: '2|1', rowSpan: '1|1', field: 'c_dgn_qty1', hAlign: 2, width: 60, type: 'Number'},
             {title: '|项目节数量2',  colSpan: '|1', rowSpan: '|1', field: 'c_dgn_qty2', hAlign: 2, width: 60, type: 'Number'},
+            {title: '预估变更|数量', colSpan: '3|1', rowSpan: '1|1', field: 'due_qc_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|不计价', colSpan: '|1', rowSpan: '|1', field: 'due_qc_minus_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'due_qc_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '预估决算|数量', colSpan: '2|1', rowSpan: '1|1', field: 'due_final_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'due_final_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
             {title: '经济指标',  colSpan: '1', rowSpan: '2', field: 'final_dgn_price', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
             {title: '本期批注', colSpan: '1', rowSpan: '2', field: 'postil', hAlign: 0, width: 100, formatter: '@', cellType: 'autoTip'},
             {title: '图(册)号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@', readOnly: true},

+ 1 - 0
app/const/standard.js

@@ -23,6 +23,7 @@ const nodeType = [
     {text: '索赔', value: 9},
     {text: '零星工程', value: 16},
     {text: '报废工程', value: 17},
+    {text: '代付代扣', value: 19},
     {text: '新增费用', value: 10},
     {text: '其他费用', value: 11},
     {text: '回收金额', value: 12},

+ 3 - 1
app/controller/stage_controller.js

@@ -226,7 +226,6 @@ module.exports = app => {
             if (this.ctx.session.sessionProject.dagl) this.ledgerExtraColumn.push('dagl_status', 'dagl_url', 'dagl_limit');
             this.ledgerMemoColumn = ['memo'];
 
-
             this.posColumn = ['id', 'tid', 'lid', 'name', 'position', 'porder', 'quantity', 'add_stage_order', 'drawing_code'];
             if (tender.info.display.stage.realComplete) this.posColumn.push('real_qty');
 
@@ -268,6 +267,8 @@ module.exports = app => {
                     await ctx.service.stageBills.deleteById(surplus);
                 }
             }
+            const changeData = await ctx.service.changeAuditList.getBillsSum(ctx.tender.id);
+
             // 查询截止上期数据
             const preStageData = ctx.stage.order > 1 ? await ctx.service.stageBillsFinal.getFinalData(ctx.tender.data, ctx.stage.order - 1) : [];
             this.ctx.helper.assignRelaData(ledgerData, [
@@ -278,6 +279,7 @@ module.exports = app => {
                 { data: curStageData, fields: ['contract_qty', 'contract_expr', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil'], prefix: '', relaId: 'lid' },
                 { data: preStageData, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'used'], prefix: 'pre_', relaId: 'lid' },
                 { data: pcData, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'org_price'], prefix: '', relaId: 'lid' },
+                { data: changeData, fields: ['qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'due_', relaId: 'gcl_id' },
             ]);
             return ledgerData;
         }

+ 26 - 6
app/lib/analysis_excel.js

@@ -13,7 +13,7 @@ const colDefineType = {
     pos: 2,
 };
 
-const mainReg = /^(GD*)?G?(\d\d)*\d$/i;
+const mainReg = /^(GD*)?G?(\d\d)*\d$/ig;
 const subReg = /^(GD*)?G?[A-Z]{2}(\d\d)+$/i;
 const gdXmjPartReg = /^(GD*)?G?/;
 const specCode106 = {
@@ -60,9 +60,25 @@ const aeUtils = {
             return x.code.indexOf('-') > 0;
         })
     },
+    check18MainCode(code) {
+        const splitPos = code.indexOf('-');
+        if (splitPos < 0) {
+            return !!code.match(mainReg);
+        } else {
+            const codeArr = code.split('-');
+            if (codeArr.length > 3) return false;
+
+            for (const codePart of codeArr) {
+                if (!codePart || !codePart.match(mainReg)) return false;
+            }
+            return true;
+        }
+    },
     isMatch18(tempData) {
+        const checkCode = this.check18MainCode;
         return _.every(tempData, x => {
-            return !x.code || !!x.code.match(mainReg);
+            return !x.code ||  checkCode(x.code);
+            // return !x.code || !!x.code.match(mainReg);
         });
     }
 };
@@ -380,6 +396,7 @@ class ImportStd18Tree extends ImportBaseTree {
         if (!parent.code) return false;
         const numberPart = parent.code.replace(gdXmjPartReg, '');
         if (!numberPart || !codeNumberPart || numberPart.length >= codeNumberPart.length) return false;
+        if (parent === '1060501' && code == '1060501-102') console.log(numberPart);
         return code.indexOf(numberPart) === 0 ||
             code.indexOf('G' + numberPart) === 0 ||
             code.indexOf('GD' + numberPart) === 0;
@@ -422,7 +439,8 @@ class ImportStd18Tree extends ImportBaseTree {
      * @returns {*}
      */
     findXmjParent(code) {
-        if (code.match(mainReg)) {
+        if (aeUtils.check18MainCode(code)) {
+        // if (code.match(mainReg)) {
             if (!this.cacheMainXmjNode) throw '主表项目节找不到父项';
             return this.findMainXmjParent(code);
         } else if (code.match(subReg)) {
@@ -438,7 +456,8 @@ class ImportStd18Tree extends ImportBaseTree {
     defineCacheData(node) {
         super.defineCacheData(node);
         if (node.code) {
-            if (node.code.match(mainReg)) {
+            if (aeUtils.check18MainCode(node.code)) {
+            //if (node.code.match(mainReg)) {
                 node.is_main = true;
                 this.cacheMainXmjNode = node;
                 this.cacheSubXmjNode = null;
@@ -465,7 +484,8 @@ class ImportStd18Tree extends ImportBaseTree {
      * @returns {*}
      */
     addXmjNode(node) {
-        if (!node.code || (!node.code.match(mainReg) && !node.code.match(subReg))) return null;
+        //if (!node.code || (!node.code.match(mainReg) && !node.code.match(subReg))) return null;
+        if (!node.code || (!aeUtils.check18MainCode(node.code) && !node.code.match(subReg))) return null;
 
         node.id = this.ctx.app.uuid.v4();
         node.children = [];
@@ -549,7 +569,7 @@ class AnalysisExcelTree {
     _loadXmjNode(row) {
         try {
             const node = {};
-            node.code = this.ctx.helper.replaceReturn(row[this.colsDef.code]);
+            node.code = _.trimEnd(this.ctx.helper.replaceReturn(row[this.colsDef.code]));
             node.name = this.ctx.helper.replaceReturn(row[this.colsDef.name]);
             node.unit = this.ctx.helper.replaceReturn(row[this.colsDef.unit]);
             node.dgn_qty1 = aeUtils.toNumber(row[this.colsDef.dgn_qty1]);

+ 1 - 1
app/lib/revise_price.js

@@ -213,8 +213,8 @@ class revisePriceCalc {
             const p = this.findChangeBillsPrice(b.code, b.name, b.unit, b.unit_price, change.cid);
             let bills_tp;
             if (p) {
-                updateBills.push({ id: b.id, unit_price: p.new_price });
                 bills_tp = this.ctx.helper.mul(p.new_price, b.spamount, change.tp_decimal || decimal.tp);
+                updateBills.push({ id: b.id, unit_price: p.new_price, checked_price: bills_tp });
                 if (!p.rela_cid) p.his_rela_cid.push(change.cid);
             } else {
                 bills_tp = this.ctx.helper.mul(b.unit_price, b.spamount, change.tp_decimal || decimal.tp);

+ 4 - 1
app/public/js/stage.js

@@ -266,7 +266,8 @@ $(document).ready(() => {
     // 台账树结构计算相关设置
     stageTreeSetting.updateFields = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil', 'used', 'contract_expr'];
     stageTreeSetting.calcFields = ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp',
-        'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'end_contract_tp', 'end_qc_tp', 'end_gather_tp', 'end_correct_tp', 'final_1_tp', 'end_final_1_tp'];
+        'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'end_contract_tp', 'end_qc_tp', 'end_gather_tp', 'end_correct_tp',
+        'final_1_tp', 'end_final_1_tp', 'due_qc_tp', 'due_final_tp'];
     stageTreeSetting.calcFun = function (node) {
         if (!node.children || node.children.length === 0) {
             node.pre_gather_qty = ZhCalc.add(node.pre_contract_qty, node.pre_qc_qty);
@@ -279,6 +280,7 @@ $(document).ready(() => {
             node.final_1_tp = ZhCalc.mul(node.final_1_qty, node.unit_price, tenderInfo.decimal.tp);
             node.deal_final_1_qty = ZhCalc.add(node.end_qc_minus_qty, node.deal_qty);
             node.end_final_1_qty = ZhCalc.add(node.end_qc_qty, node.final_1_qty);
+            node.due_final_qty = ZhCalc.add(node.quantity, node.due_qc_qty);
         }
         node.pre_gather_tp = ZhCalc.add(node.pre_contract_tp, node.pre_qc_tp);
         node.gather_tp = ZhCalc.sum([node.contract_tp, node.qc_tp, node.pc_tp]);
@@ -287,6 +289,7 @@ $(document).ready(() => {
         node.end_gather_tp = ZhCalc.add(node.pre_gather_tp, node.gather_tp);
         node.end_final_tp = ZhCalc.add(node.end_qc_tp, node.total_price);
         node.end_final_1_tp = ZhCalc.add(node.end_qc_tp, node.final_1_tp);
+        node.due_final_tp = ZhCalc.add(node.quantity, node.due_qc_tp);
         if (!node.children || node.children.length === 0) {
             if (node.end_contract_qty) {
                 node.end_correct_tp = ZhCalc.add(node.end_qc_tp, ZhCalc.mul(node.end_contract_qty, node.unit_price, tenderInfo.decimal.tp));

+ 32 - 0
app/service/change_audit_list.js

@@ -1049,6 +1049,38 @@ module.exports = app => {
                 },
             });
         }
+
+        async getBillsSum(tid) {
+            const sql = 'SELECT gcl_id, Sum(qc_qty) AS qc_qty, Sum(qc_tp) AS qc_tp, Sum(qc_minus_qty) AS qc_minus_qty' +
+                '  FROM(' +
+                '    SELECT cal.gcl_id, Sum(cal.checked_amount) AS qc_qty, Sum(cal.checked_price) AS qc_tp, 0 As qc_minus_qty' +
+                `      FROM ${this.tableName} cal LEFT JOIN ${this.ctx.service.change.tableName} c ON cal.cid = c.cid` +
+                '      WHERE c.tid = ? AND c.valid AND c.status = ? AND cal.is_valuation' +
+                '      GROUP BY cal.gcl_id' +
+                '    UNION ALL ' +
+                '    SELECT cal.gcl_id, 0 As qc_qty, 0 As qc_tp, Sum(cal.checked_amount) AS qc_minus_qty' +
+                `      FROM ${this.tableName} cal LEFT JOIN ${this.ctx.service.change.tableName} c ON cal.cid = c.cid` +
+                '      WHERE c.tid = ? AND c.valid AND c.status = ? AND not cal.is_valuation' +
+                '      GROUP BY cal.gcl_id) As TEMP' +
+                '  GROUP BY gcl_id';
+            return await this.db.query(sql, [tid, audit.flow.status.checked, tid, audit.flow.status.checked]);
+        }
+
+        async getPosSum(tid) {
+            const sql = 'SELECT mx_id, Sum(qc_qty) AS qc_qty, Sum(qc_tp) AS qc_tp, Sum(qc_minus_qty) AS qc_minus_qty' +
+                '  FROM(' +
+                '    SELECT cal.gcl_id, Sum(cal.checked_amount) AS qc_qty, Sum(cal.checked_price) AS qc_tp, 0 As qc_minus_qty' +
+                `      FROM ${this.tableName} cal LEFT JOIN ${this.ctx.service.change.tableName} c ON cal.cid = c.cid` +
+                '      WHERE c.tid = ? AND c.valid AND c.status = ? AND cal.is_valuation' +
+                '      GROUP BY cal.mx_id' +
+                '    UNION ALL ' +
+                '    SELECT cal.mx_id, 0 As qc_qty, 0 As qc_tp, Sum(cal.checked_amount) AS qc_minus_qty' +
+                `      FROM ${this.tableName} cal LEFT JOIN ${this.ctx.service.change.tableName} c ON cal.cid = c.cid` +
+                '      WHERE c.tid = ? AND c.valid AND c.status = ? AND not cal.is_valuation' +
+                '      GROUP BY cal.mx_id) As TEMP' +
+                '  GROUP BY mx_id';
+            return await this.db.query(sql, [tid, audit.flow.status.checked, tid, audit.flow.status.checked]);
+        }
     }
 
     return ChangeAuditList;

+ 17 - 1
app/service/report_memory.js

@@ -90,6 +90,8 @@ module.exports = app => {
                     p.final_1_qty = ctx.helper.add(p.end_qc_minus_qty, p.quantity);
                     p.end_final_1_qty = ctx.helper.add(p.end_qc_qty, p.final_1_qty);
                     p.final_1_ratio = ctx.helper.mul(ctx.helper.div(p.end_gather_qty, p.end_final_1_qty, 4), 100);
+
+                    p.due_final_qty = ctx.helper.add(p.quantity, p.due_qc_qty);
                 }
             });
             // 需要缓存的数据
@@ -114,6 +116,7 @@ module.exports = app => {
                     'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'final_1_tp',
                     'end_contract_pc_tp', 'end_qc_pc_tp', 'end_pc_tp',
                     'year_contract_tp', 'year_qc_tp', 'year_contract_pc_tp', 'year_qc_pc_tp', 'year_pc_tp', 'year_gather_tp',
+                    'due_qc_tp', 'due_final_tp',
                 ],
                 calc: function (node, helper, decimal) {
                     if (node.children && node.children.length === 0) {
@@ -123,8 +126,11 @@ module.exports = app => {
                         node.end_qc_qty = helper.add(node.pre_qc_qty, node.qc_qty);
                         node.end_gather_qty = helper.add(node.pre_gather_qty, node.gather_qty);
                         node.end_qc_minus_qty = helper.add(node.pre_qc_minus_qty, node.qc_minus_qty);
+
                         node.final_1_qty = helper.add(node.quantity, node.end_qc_minus_qty);
                         node.end_final_1_qty = helper.add(node.final_1_qty, node.end_qc_qty);
+
+                        node.due_final_qty = helper.add(node.quantity, node.due_qc_qty);
                     }
                     node.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
                     node.gather_tp = helper.sum([node.contract_tp, node.qc_tp, node.pc_tp]);
@@ -138,6 +144,8 @@ module.exports = app => {
                     node.final_1_tp = helper.mul(node.unit_price, node.final_1_qty, decimal.tp);
                     node.end_final_1_tp = helper.add(node.final_1_tp, node.end_qc_tp);
                     node.final_1_ratio = helper.mul(helper.div(node.end_gather_tp, node.end_final_1_tp, 4), 100);
+
+                    node.due_final_tp = helper.add(node.total_price, node.due_qc_tp);
                 }
             });
         }
@@ -502,6 +510,9 @@ module.exports = app => {
                 const yearStage = this._checkFieldsExistReg(fields, 'year_') && this.ctx.stage.s_time
                     ? await this._loadStageBillsYear(this.ctx.tender, this.ctx.stage.s_time.split('-')[0])
                     : [];
+                const changeData = this._checkFieldsExistReg(fields, 'due_')
+                    ? await ctx.service.changeAuditList.getBillsSum(this.ctx.tender.id)
+                    : [];
                 this.ctx.helper.assignRelaData(billsData, [
                     { data: memoData, fields: ['memo'], prefix: '', relaId: 'id' },
                     { data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil'], prefix: '', relaId: 'lid' },
@@ -509,6 +520,7 @@ module.exports = app => {
                     { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'org_price'], prefix: '', relaId: 'lid' },
                     { data: endBpcStage, fields: ['end_contract_pc_tp', 'end_qc_pc_tp', 'end_pc_tp', 'org_price_his'], prefix: '', relaId: 'lid' },
                     { data: yearStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'gather_qty', 'gather_tp'], prefix: 'year_', relaId: 'lid' },
+                    { data: changeData, fields: ['qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'due_', relaId: 'gcl_id' },
                 ]);
                 billsData.forEach(x => {
                     if (x.org_price_his && x.org_price_his.length > 0) {
@@ -582,9 +594,13 @@ module.exports = app => {
                 if (this._checkFieldsExist(fields, posFields.stageEnd)) {
                     prePosStage = this.ctx.stage.order > 1 ? await this.ctx.service.stagePosFinal.getFinalData(this.ctx.tender, this.ctx.stage.order - 1) : [];
                 }
+                const changeData = this._checkFieldsExistReg(fields, 'due_')
+                    ? await ctx.service.changeAuditList.getPosSum(this.ctx.tender.id)
+                    : [];
                 this.ctx.helper.assignRelaData(posData, [
                     {data: curPosStage, fields: ['contract_qty', 'qc_qty', 'qc_minus_qty', 'contract_expr', 'postil'], prefix: '', relaId: 'pid'},
-                    {data: prePosStage, fields: ['contract_qty', 'qc_qty', 'qc_minus_qty'], prefix: 'pre_', relaId: 'pid'}
+                    {data: prePosStage, fields: ['contract_qty', 'qc_qty', 'qc_minus_qty'], prefix: 'pre_', relaId: 'pid'},
+                    {data: changeData, fields: ['qc_qty', 'qc_minus_qty'], prefix: 'due_', relaId: 'mx_id'},
                 ]);
                 this.pos.loadDatas(posData);
                 this.pos.calculateAll();

+ 44 - 5
app/service/rpt_gather_memory.js

@@ -70,6 +70,11 @@ const gatherUtils = {
         gatherNode[prefix + "c_dgn_qty1"] = helper.add(gatherNode[prefix + "c_dgn_qty1"], sourceNode.c_dgn_qty1);
         gatherNode[prefix + "c_dgn_qty2"] = helper.add(gatherNode[prefix + "c_dgn_qty2"], sourceNode.c_dgn_qty2);
 
+        gatherNode[prefix + "due_qc_qty"] = helper.add(gatherNode[prefix + "due_qc_qty"], sourceNode.due_qc_qty);
+        gatherNode[prefix + "due_qc_tp"] = helper.add(gatherNode[prefix + "due_qc_tp"], sourceNode.due_qc_tp);
+        gatherNode[prefix + "due_final_qty"] = helper.add(gatherNode[prefix + "due_final_qty"], sourceNode.due_final_qty);
+        gatherNode[prefix + "due_final_tp"] = helper.add(gatherNode[prefix + "due_final_tp"], sourceNode.due_final_tp);
+
         gatherNode.s_qty = helper.add(gatherNode.s_qty, sourceNode.quantity);
         gatherNode.s_tp = helper.add(gatherNode.s_tp, sourceNode.total_price);
         gatherNode.s_deal_qty = helper.add(gatherNode.s_deal_qty, sourceNode.deal_qty);
@@ -104,6 +109,11 @@ const gatherUtils = {
         gatherNode.s_deal_dgn_qty2 = helper.add(gatherNode.s_deal_dgn_qty2, sourceNode.deal_dgn_qty2);
         gatherNode.s_c_dgn_qty1 = helper.add(gatherNode.s_c_dgn_qty1, sourceNode.c_dgn_qty1);
         gatherNode.s_c_dgn_qty2 = helper.add(gatherNode.s_c_dgn_qty2, sourceNode.c_dgn_qty2);
+
+        gatherNode.s_due_qc_qty = helper.add(gatherNode.s_due_qc_qty, sourceNode.due_qc_qty);
+        gatherNode.s_due_qc_tp = helper.add(gatherNode.s_due_qc_tp, sourceNode.due_qc_tp);
+        gatherNode.s_due_final_qty = helper.add(gatherNode.s_due_final_qty, sourceNode.due_final_qty);
+        gatherNode.s_due_final_tp = helper.add(gatherNode.s_due_final_tp, sourceNode.due_final_tp);
     },
     gatherZone: function (tender, gatherNode, sourceNode, prefix, helper) {
         gatherNode[prefix + 'id'] = tender.id;
@@ -188,6 +198,9 @@ const gatherUtils = {
         gatherNode[prefix + "end_qc_qty"] = helper.add(gatherNode[prefix + "end_qc_qty"], sourceNode.end_qc_qty);
         gatherNode[prefix + "end_gather_qty"] = helper.add(gatherNode[prefix + "end_gather_qty"], sourceNode.end_gather_qty);
 
+        gatherNode[prefix + "due_qc_qty"] = helper.add(gatherNode[prefix + "due_qc_qty"], sourceNode.due_qc_qty);
+        gatherNode[prefix + "due_final_qty"] = helper.add(gatherNode[prefix + "due_final_qty"], sourceNode.due_final_qty);
+
         gatherNode.s_qty = helper.add(gatherNode.s_qty, sourceNode.quantity);
 
         gatherNode.s_contract_qty = helper.add(gatherNode.s_contract_qty, sourceNode.contract_qty);
@@ -201,6 +214,9 @@ const gatherUtils = {
         gatherNode.s_end_contract_qty = helper.add(gatherNode.s_end_contract_qty, sourceNode.end_contract_qty);
         gatherNode.s_end_qc_qty = helper.add(gatherNode.s_end_qc_qty, sourceNode.end_qc_qty);
         gatherNode.s_end_gather_qty = helper.add(gatherNode.s_end_gather_qty, sourceNode.end_gather_qty);
+
+        gatherNode.s_due_qc_qty = helper.add(gatherNode.s_due_qc_qty, sourceNode.due_qc_qty);
+        gatherNode.s_due_final_qty = helper.add(gatherNode.s_due_final_qty, sourceNode.due_final_qty);
     },
     gatherZonePos: function (tender, gatherNode, sourceNode, prefix, helper) {
         gatherNode[prefix + 'id'] = tender.id;
@@ -252,6 +268,16 @@ module.exports = app => {
             this.resultDealBills = [];
         }
 
+        _checkFieldsExistReg(source, regStr) {
+            const reg = new RegExp(regStr, 'igm');
+            for (const s of source) {
+                if (reg.test(s)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
         async _getValidStages(tenderId, sort = 'desc') {
             const stages = await this.db.select(this.ctx.service.stage.tableName, {
                 where: { tid: tenderId },
@@ -530,7 +556,12 @@ module.exports = app => {
                 rootId: -1,
                 keys: ['id', 'tender_id', 'ledger_id'],
                 stageId: 'id',
-                calcFields: ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'gather_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp'],
+                calcFields: ['deal_tp', 'total_price',
+                    'contract_tp', 'qc_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'gather_tp',
+                    'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp',
+                    'end_contract_tp', 'end_qc_tp', 'end_gather_tp',
+                    'due_qc_tp', 'due_final_tp',
+                ],
                 calc: function (node) {
                     if (node.children && node.children.length === 0) {
                         node.pre_gather_qty = helper.add(node.pre_contract_qty, node.pre_qc_qty);
@@ -538,20 +569,23 @@ module.exports = app => {
                         node.end_contract_qty = helper.add(node.pre_contract_qty, node.contract_qty);
                         node.end_qc_qty = helper.add(node.pre_qc_qty, node.qc_qty);
                         node.end_gather_qty = helper.add(node.pre_gather_qty, node.gather_qty);
+                        node.due_final_qty = helper.add(node.quantity, node.due_qc_qty);
                     }
                     node.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
                     node.gather_tp = helper.sum([node.contract_tp, node.qc_tp, node.pc_tp]);
                     node.end_contract_tp = helper.sum([node.pre_contract_tp, node.contract_tp, node.contract_pc_tp]);
                     node.end_qc_tp = helper.sum([node.pre_qc_tp, node.qc_tp, node.qc_pc_tp]);
                     node.end_gather_tp = helper.add(node.pre_gather_tp, node.gather_tp);
+                    node.due_final_tp = helper.add(node.total_price, node.due_qc_tp);
                 }
             });
             const billsData = await this.ctx.service.ledger.getData(tender.id);
             const dgnData = await this.ctx.service.stageBillsDgn.getDgnData(tender.id);
-            for (const d of dgnData) {
-                const l = this.ctx.helper._.find(billsData, {id: d.id});
-                this.ctx.helper._.assignIn(l, d);
-            }
+            const changeBillsData = await ctx.service.changeAuditList.getBillsSum(this.ctx.tender.id);
+            this.ctx.helper.assignRelaData(billsData, [
+                { data: dgnData, fields: ['deal_dgn_qty1', 'deal_dgn_qty2', 'c_dgn_qty1', 'c_dgn_qty2'], prefix: '', relaId: 'id' },
+                { data: changeBillsData, fields: ['qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'due_', relaId: 'gcl_id' },
+            ]);
             const pos = new Ledger.pos({
                 id: 'id', ledgerId: 'lid',
                 calc: function (node) {
@@ -560,9 +594,14 @@ module.exports = app => {
                     node.end_contract_qty = helper.add(node.pre_contract_qty, node.contract_qty);
                     node.end_qc_qty = helper.add(node.pre_qc_qty, node.qc_qty);
                     node.end_gather_qty = helper.add(node.pre_gather_qty, node.gather_qty);
+                    node.due_final_qty = ctx.helper.add(node.quantity, node.due_qc_qty);
                 },
             });
             const posData = await this.ctx.service.pos.getPosData({ tid: tender.id });
+            const changePosData = await ctx.service.changeAuditList.getPosSum(this.ctx.tender.id);
+            this.ctx.helper.assignRelaData(posData, [
+                { data: changePosData, fields: ['qc_qty', 'qc_minus_qty'], prefix: 'due_', relaId: 'mx_id' },
+            ]);
             if (stage) {
                 await this.ctx.service.stage.doCheckStage(stage);
                 const curStage = stage.readOnly

+ 21 - 0
app/view/sub_proj/data_index.ejs

@@ -76,6 +76,27 @@
                                 </div>
                             </div>
                         </div>
+                        <div class="py-2 font-weight-bold">土地使用及拆迁</div>
+                        <div class="row">
+                            <div class="col-3">
+                                <div class="form-group">
+                                    <label for="">批复用地(亩):</label>
+                                    <input type="text" class="form-control form-control-sm" name="reply_land" value="<%- info.reply_land %>" org="<%- info.reply_land %>"  placeholder="请输入" maxlength="20" oninput="limitMaxLength(this)" onblur="changeInfo(this)">
+                                </div>
+                            </div>
+                            <div class="col-3">
+                                <div class="form-group">
+                                    <label for="">永久占用土地(亩):</label>
+                                    <input type="text" class="form-control form-control-sm" name="occupy_land" value="<%- info.occupy_land %>" org="<%- info.occupy_land %>" placeholder="请输入" maxlength="20" oninput="limitMaxLength(this)" onblur="changeInfo(this)">
+                                </div>
+                            </div>
+                            <div class="col-3">
+                                <div class="form-group">
+                                    <label for="">实际拆迁房屋(m2):</label>
+                                    <input type="text" class="form-control form-control-sm" name="demolish_building" value="<%- info.demolish_building %>" org="<%- info.demolish_building %>" placeholder="请输入" maxlength="20" oninput="limitMaxLength(this)" onblur="changeInfo(this)">
+                                </div>
+                            </div>
+                        </div>
                     </form>
                 </div>
                 <div class="col-12 px-3">

+ 60 - 0
db_script/change_bills.js

@@ -0,0 +1,60 @@
+// 计算变更令,正负变更数
+
+const defaultInfo = require('../app/const/tender_info');
+const BaseUtil = require('./baseUtils');
+const querySql = BaseUtil.querySql;
+const ZhCalc = BaseUtil.ZhCalc;
+
+const checkChange = async function(change, decimal) {
+    const changeBills = await querySql('Select * From zh_change_audit_list where cid = ?', [change.cid]);
+    for (const cb of changeBills) {
+        cb.checked_amount = cb.checked_amount ? cb.checked_amount : 0;
+        cb.checked_price = ZhCalc.mul(cb.checked_amount, cb.unit_price, change.tp_decimal || decimal.tp);
+        await querySql('Update zh_change_audit_list Set checked_price = ?, checked_amount = ? Where id = ?', [cb.checked_price, cb.checked_amount, cb.id]);
+    }
+    console.log(`Update Change ${change.cid}`);
+};
+
+const doComplete = async function() {
+    try {
+        const tender = await querySql('Select * From zh_tender');
+        for (const t of tender) {
+            console.log(`Update Tender ${t.id}:`);
+            const info = await querySql('Select * From zh_tender_info where tid = ?', [t.id]);
+            const decimal = info.length > 0 && info[0].decimal ? JSON.parse(info[0].decimal) : defaultInfo.defaultInfo.decimal;
+
+            const changes = await querySql('Select * From zh_change where tid = ?', [t.id]);
+            for (const c of changes) {
+                await checkChange(c, decimal);
+            }
+        }
+    } catch (err) {
+        console.log(err);
+    }
+    BaseUtil.closePool();
+};
+const doCompleteTest = async function(tid) {
+    try {
+        const tender = await querySql('Select * From zh_tender where id = ?', [tid]);
+        for (const t of tender) {
+            console.log(`Update Tender ${t.id}:`);
+            const info = await querySql('Select * From zh_tender_info where tid = ?', [t.id]);
+            const decimal = info.length > 0 && info[0].decimal ? JSON.parse(info[0].decimal) : defaultInfo.defaultInfo.decimal;
+
+            const changes = await querySql('Select * From zh_change where tid = ?', [t.id]);
+            for (const c of changes) {
+                await checkChange(c, decimal);
+            }
+        }
+    } catch (err) {
+        console.log(err);
+    }
+    BaseUtil.closePool();
+};
+
+const tenderId = process.argv[3];
+if (tenderId) {
+    doCompleteTest(tenderId);
+} else {
+    doComplete()
+}

+ 5 - 0
sql/update.sql

@@ -3,3 +3,8 @@ ADD COLUMN `checked_amount` decimal(30, 8) NULL DEFAULT 0 COMMENT '审批变更
 ADD COLUMN `checked_price` decimal(30, 8) NULL DEFAULT 0 COMMENT '审批变更后金额(整型)' AFTER `checked_amount`;
 
 UPDATE `zh_change_audit_list` SET `checked_amount` = CONVERT(`samount`, DECIMAL) WHERE `samount` != '';
+
+ALTER TABLE `zh_sub_project_info`
+ADD COLUMN `reply_land`  varchar(20) NOT NULL DEFAULT '' COMMENT '批复用地' AFTER `quake_peak_value`,
+ADD COLUMN `occupy_land`  varchar(20) NOT NULL DEFAULT '' COMMENT '永久占用土地' AFTER `reply_land`,
+ADD COLUMN `demolish_building`  varchar(20) NOT NULL DEFAULT '' COMMENT '实际拆迁房屋' AFTER `occupy_land`;