Browse Source

报表处理,新增汇总章节数据

MaiXinRong 5 years ago
parent
commit
0558b1205a
4 changed files with 161 additions and 23 deletions
  1. 33 14
      app/lib/analysis_excel.js
  2. 3 5
      app/lib/ledger.js
  3. 85 3
      app/lib/rpt_data_analysis.js
  4. 40 1
      test/app/lib/rpt_data_analysis.test.js

+ 33 - 14
app/lib/analysis_excel.js

@@ -484,8 +484,8 @@ class AnalysisGclExcelTree {
         this.ctx = ctx;
         this.colsDef = null;
         this.colHeaderMatch = {
-            b_code: ['编号', '清单编号', '子目号'],
-            name: ['名称'],
+            b_code: ['编号', '清单编号', '子目号', '子目编号', '清单号'],
+            name: ['名称', '清单名称', '子目名称'],
             unit: ['单位'],
             quantity: ['清单数量'], // 施工图复核数量
             unit_price: ['单价'],
@@ -534,19 +534,38 @@ class AnalysisGclExcelTree {
             this.errorData = [];
             this.loadEnd = false;
 
-            for (const iRow in sheet.rows) {
+            // for (const iRow in sheet.rows) {
+            //     const row = sheet.rows[iRow];
+            //     if (this.colsDef && !this.loadEnd) {
+            //         const result = this.loadRowData(row);
+            //         // 读取失败则写入错误数据 todo 返回前端告知用户?
+            //         if (!result) {
+            //             this.errorData.push({
+            //                 serialNo: iRow,
+            //                 data: row,
+            //             });
+            //         }
+            //     } else {
+            //         this.checkColHeader(row);
+            //     }
+            // }
+            // 固定列导入
+            this.colsDef = {
+                b_code: 0,
+                name: 1,
+                unit: 2,
+                quantity: 3,
+                unit_price: 4
+            };
+            for (let iRow = 1, iLen = sheet.rows.length; iRow < iLen; iRow++) {
                 const row = sheet.rows[iRow];
-                if (this.colsDef && !this.loadEnd) {
-                    const result = this.loadRowData(row);
-                    // 读取失败则写入错误数据 todo 返回前端告知用户?
-                    if (!result) {
-                        this.errorData.push({
-                            serialNo: iRow,
-                            data: row,
-                        });
-                    }
-                } else {
-                    this.checkColHeader(row);
+                const result = this.loadRowData(row);
+                // 读取失败则写入错误数据 todo 返回前端告知用户?
+                if (!result) {
+                    this.errorData.push({
+                        serialNo: iRow,
+                        data: row,
+                    });
                 }
             }
             return this.cacheTree;

+ 3 - 5
app/lib/ledger.js

@@ -213,14 +213,12 @@ class billsTree {
         const self = this;
         if (node.children && node.children.length > 0) {
             const gather = node.children.reduce(function (rst, x) {
+                const result = {};
                 for (const cf of self.setting.calcFields) {
-                    rst[cf] = self.ctx.helper.add(rst[cf], x[cf]);
+                    result[cf] = self.ctx.helper.add(rst[cf], x[cf]);
                 }
-                return rst;
+                return result;
             });
-            if (node.code === '1-1-6') {
-                console.log(gather);
-            }
             // 汇总子项
             for (const cf of this.setting.calcFields) {
                 if (gather[cf]) {

+ 85 - 3
app/lib/rpt_data_analysis.js

@@ -69,7 +69,7 @@ const gatherGcl = {
         const gatherOther = fields.indexOf('chapter') >= 0;
 
         ctx.helper._.pull(data.mem_stage_bills, 'is_leaf');
-        const gclBills = [], other = {name: '未计入清单章节项', chapter: '100'};
+        const gclBills = [], other = {name: '未计入清单章节项', chapter: '10000'};
 
         for (const b of data.mem_stage_bills) {
             if (b.b_code && b.b_code !== '') {
@@ -81,7 +81,8 @@ const gatherGcl = {
                     gcl = {
                         b_code: b.b_code, name: b.name, unit: b.unit,
                         unit_price: b.unit_price,
-                        qc_bgl_code: [],
+                        qc_bgl_code: [], chapter: b.chapter,
+                        deal_bills_qty: b.deal_bills_qty, deal_bills_tp: b.deal_bills_tp,
                     };
                     gclBills.push(gcl);
                 }
@@ -147,11 +148,92 @@ const sortGcl = {
         });
     }
 };
+const gatherChapter = {
+    name: '汇总章级数据',
+    hint: '请使用mem_stage_bills/mem_stage_bills_compare/ledger,仅对一张表进行汇总,并生成数据:\n'+
+        '1. 因为是汇总章级数据,必须在离散数据中添加"章节代码"&"章节名称"\n' +
+        '2. 需勾选"清单编号(b_code)", "树结构-是否子项(is_leaf)"字段,可以对任何含有这些字段的表汇总\n' +
+        '注意事项:\n' +
+        '1. 算法对数据表没有要求,保证有上述字段,且按顺序勾选即可, 仅汇总金额\n' +
+        '2. 算法计算后,原数据表中非数字类型的字段全部失效(除清单编号、名称外),请勿在指标映射中添加\n' +
+        '示例:\n' +
+        'e.g.1 要对mem_stage_bills汇总,须勾选mem_stage_bills下的"清单编号(b_code)", "树结构-是否子项((is_leaf)"字段\n' +
+        'e.g.2 要对mem_stage_bills_compare汇总,须勾选mem_stage_bills_compare下的"清单编号(b_code)", "树结构-是否子项((is_leaf)"字段\n' +
+        '结果:\n' +
+        '汇总结果可参照 清单汇总--章节合计,但是不过滤1000-1300章数据',
+    fun: function (ctx, data, fieldsKey) {
+        if (!data.tender_info || !data.tender_info.chapter) return;
+        if (!fieldsKey && fieldsKey.length < 0) return;
+
+        const getCalcChapter = function (chapter) {
+            const gclChapter = [], otherChapter = [];
+            let serialNo = 1;
+            for (const c of chapter) {
+                const cc = { code: c.code, name: c.name, cType: 1 };
+                cc.serialNo = serialNo++;
+                cc.filter = '^' + c.code.substr(0, c.code.length - 2) + '[0-9]{2}-';
+                gclChapter.push(cc);
+            }
+            gclChapter.push({ name: '未计入章节清单合计', cType: 21, serialNo: serialNo++, });
+            otherChapter.push({ name: '清单小计(A)', cType: 11, serialNo: serialNo++ });
+            otherChapter.push({ name: '非清单项费用(B)', cType: 31, serialNo: serialNo++ });
+            otherChapter.push({ name: '合计(C=A+B)', cType: 41, serialNo: serialNo });
+            return [gclChapter, otherChapter];
+        };
+        const getGclChapter = function (chapter, data) {
+            for (const c of chapter) {
+                if (c.filter) {
+                    const reg = new RegExp(c.filter);
+                    if (reg.test(data.b_code)) {
+                        return c;
+                    }
+                } else {
+                    return c;
+                }
+            }
+        };
+        const gatherData = function(chapter, data) {
+            for (const f in data) {
+                if (data[f] && (f.indexOf('tp') >= 0 || f === 'total_price')) {
+                    chapter[f] = ctx.helper.add(chapter[f], data[f]);
+                }
+            }
+        };
+
+        const [gclChapter, otherChapter] = getCalcChapter(data.tender_info.chapter);
+        const fields = ctx.helper._.map(fieldsKey, 'field');
+        const needFields = ['b_code', 'is_leaf'];
+        for (const nf of needFields) {
+            if (fields.indexOf(nf) === -1) return;
+        }
+        const sourceData = data[fieldsKey[0].table];
+        if (!sourceData) return;
+        for (const d of sourceData) {
+            if (!d.is_leaf) continue;
+
+            for (const c of otherChapter) {
+                if (c.cType === 41) {
+                    gatherData(c, d);
+                } else if (c.cType === 31 && (!d.b_code || d.b_code === '')) {
+                    gatherData(c, d, fields);
+                } else if (c.cType === 11 && (d.b_code)) {
+                    gatherData(c, d, fields);
+                }
+            }
+            if (d.b_code) {
+                const c = getGclChapter(gclChapter, d);
+                gatherData(c, d, fields);
+            }
+        }
+        data[fieldsKey[0].table] = gclChapter.concat(otherChapter);
+    },
+};
 
 const analysisObj = {
     changeSort,
     gatherGcl,
-    sortGcl
+    sortGcl,
+    gatherChapter,
 };
 const analysisDefine = (function (obj) {
     const result = [];

+ 40 - 1
test/app/lib/rpt_data_analysis.test.js

@@ -110,9 +110,48 @@ describe('test/app/service/report_memory.test.js', () => {
             assert(a === codeResult[i]);
         });
     });
+    it('test gatherChapter', function* () {
+        const ctx = app.mockContext(mockData);
+
+        // test12 - 第6期
+        const stage = yield ctx.service.stage.getDataByCondition({tid: 12, order: 6});
+        const params = {
+            tender_id: stage.tid,
+            stage_id: stage.id,
+        };
+        const filters = ['mem_stage_bills', 'tender_info'];
+        const data = yield ctx.service.report.getReportData(params, filters, {
+            mem_stage_bills: [
+                'id', 'tender_id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf',
+                'code', 'b_code', 'name', 'unit', 'unit_price',
+                'deal_qty', 'deal_tp',
+                'sgfh_qty', 'sgfh_tp', 'sjcl_qty', 'sjcl_tp', 'qtcl_qty', 'qtcl_tp', 'quantity', 'total_price',
+                'dgn_qty1', 'dgn_qty2',
+                'drawing_code', 'memo', 'node_type', 'is_tp',
+                'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'gather_qty', 'gather_tp', 'postil',
+                'pre_contract_qty', 'pre_contract_tp', 'pre_qc_qty', 'pre_qc_tp', 'pre_gather_qty', 'pre_gather_tp',
+                'end_contract_qty', 'end_contract_tp', 'end_qc_qty', 'end_qc_tp', 'end_gather_qty', 'end_gather_tp',
+                'final_tp', 'final_ratio',
+                'qc_bgl_code',
+                'chapter',
+            ]
+        });
+        const bills = data.mem_stage_bills.find(function (x) {return x.b_code === '103-3-a'});
+        reportDataAnalysis.analysisObj.gatherChapter.fun(ctx, data, [
+            {field: 'b_code', table: 'mem_stage_bills'},
+            {field: 'is_leaf', table: 'mem_stage_bills'},
+        ]);
+        const chapter100 = ctx.helper._.find(data.mem_stage_bills, {code: '100'});
+        assert(chapter100.total_price === 1045756);
+        const chapter200 = ctx.helper._.find(data.mem_stage_bills, {code: '200'});
+        assert(chapter200.total_price.toFixed(0) == 3813369);
+        assert(chapter200.contract_tp == 700.5);
+        const chapter400 = ctx.helper._.find(data.mem_stage_bills, {code: '400'});
+        assert(chapter400.total_price.toFixed(0) == 1231018);
+    });
     it('test analysisDefine', function() {
         const define = reportDataAnalysis.analysisDefine;
-        assert(define.length === 3);
+        assert(define.length === 4);
         assert(define[0].key === 'changeSort');
         assert(define[0].name === reportDataAnalysis.analysisObj.changeSort.name);
         assert(define[0].hint === reportDataAnalysis.analysisObj.changeSort.hint);