Selaa lähdekoodia

报表数据,在主表中引入关联表数据

MaiXinRong 5 vuotta sitten
vanhempi
commit
17070f6893

+ 74 - 4
app/lib/rpt_data_analysis.js

@@ -263,19 +263,15 @@ const gatherChapter = {
         const orderMatch = new RegExp('o[0-9]+', 'igm');
         for (const c of chapter) {
             if (c.order_calc && c.order_calc !== '') {
-                console.log(c.order_calc);
                 const matchs = c.order_calc.match(orderMatch);
                 const calcMatch = [];
                 for (const m of matchs) {
                     const order = m.substring(1, m.length);
-                    console.log(order);
                     const orderChapter = chapter.find(function (x) {return x.order == order});
-                    console.log(orderChapter);
                     if (orderChapter) {
                         calcMatch.push({match: m, value: orderChapter})
                     }
                 }
-                console.log(calcMatch);
                 for (const f of fields) {
                     let expr = c.order_calc;
                     for (const m of calcMatch) {
@@ -345,12 +341,86 @@ const gatherChapter = {
         data[fieldsKey[0].table] = chapter;
     },
 };
+const join = {
+    name: "连接两张数据表",
+    hint: "用于处理类似于关联签约清单的情况,会改变主表的数据",
+    defaultSetting: {
+        main: 'mem_stage_bills',
+        sub: 'deal_bills',
+        keyFields: [
+            {main: 'b_code', sub: 'code', type: 'string'},
+            {main: 'name', sub: 'name',type: 'string'},
+            {main: 'unit', sub: 'unit',type: 'string'},
+            {main: 'unit_price', sub: 'unit_price',type: 'number'},
+        ],
+        importFields: [
+            {main: 'ex_value1', sub: 'quantity', type: 'number'},
+            {main: 'ex_value2', sub: 'total_price', type: 'number'}
+        ],
+        joinType: 'outer', //'outer', 'main', 'sub', 'inner',
+    },
+    fun: function (ctx, data, fields, options) {
+        if (!options || !options.main || !options.sub || !options.keyFields || options.keyFields.length === 0) return;
+
+        const main = data[options.main];
+        const sub = data[options.sub];
+        if (!main || !sub) return;
+
+        const _ = ctx.helper._, result = _.cloneDeep(main);
+        for (const r of result) {
+            r._join_tag = 'main';
+        }
+        for (const s of sub) {
+            let r = result.find(function (x) {
+                for (const k of options.keyFields) {
+                    switch (k.type) {
+                        case 'string':
+                            if (x[k.main] !== s[k.sub] && (!_.isNil(x[k.main]) || !_.isNil(s[k.sub]))) return false;
+                            break;
+                        case 'number':
+                            if (!ctx.helper.checkZero(ctx.helper.sub(x[k.main] - s[k.sub]))) return false;
+                            break;
+                    }
+                }
+                return true;
+            });
+            if (r && r._join_tag === 'main') {
+                r._join_tag = 'both';
+            }
+            if (!r) {
+                r = {_join_tag: 'sub'};
+                for (const k of options.keyFields) {
+                    r[k.main] = s[k.sub];
+                }
+                result.push(r);
+            }
+            for (const i of options.importFields) {
+                r[i.main] = s[i.sub];
+            }
+        }
+        switch (options.joinType) {
+            case 'main':
+                data[options.main] = _.filter(result, function (r) {return ['main', 'both'].indexOf(r._join_tag) >= 0});
+                break;
+            case 'sub':
+                data[options.main] = _.filter(result, function (r) {return ['sub', 'both'].indexOf(r._join_tag) >= 0});
+                break;
+            case 'inner':
+                data[options.main] = _.filter(result, function (r) {return r._join_tag === 'both'});
+                break;
+            case 'outer':
+                data[options.main] = result;
+                break;
+        }
+    }
+};
 
 const analysisObj = {
     changeSort,
     gatherGcl,
     sortGcl,
     gatherChapter,
+    join,
 };
 const analysisDefine = (function (obj) {
     const result = [];

+ 4 - 0
app/service/report.js

@@ -37,6 +37,10 @@ module.exports = app => {
                             runnableRst.push(service.tenderInfo.getTenderInfo(params.tender_id));
                             runnableKey.push(filter);
                             break;
+                        case 'deal_bills' :
+                            runnableRst.push(service.dealBills.getDataByTenderId(params.tender_id));
+                            runnableKey.push('deal_bills');
+                            break;
                         case 'ledger' :
                             runnableRst.push(service.ledger.getData(params.tender_id, 0));
                             runnableKey.push(filter);

+ 142 - 12
test/app/lib/rpt_data_analysis.test.js

@@ -19,16 +19,16 @@ describe('test/app/service/report_memory.test.js', () => {
     before(function* () {
         const ctx = app.mockContext();
         // 模拟登录session
-        const postData = {
-            account: 'fuqingqing',
-            project: 'P0505',
-            project_password: '123456',
-        };
         // const postData = {
-        //     account: '734406061@qq.com',
-        //     project: 'T201711273363',
-        //     project_password: 'mai654321',
+        //     account: 'fuqingqing',
+        //     project: 'P0505',
+        //     project_password: '123456',
         // };
+        const postData = {
+            account: '734406061@qq.com',
+            project: 'T201711273363',
+            project_password: 'mai654321',
+        };
         ctx.session = {};
         const loginResult = yield ctx.service.projectAccount.accountLogin(postData, 2);
         assert(loginResult);
@@ -119,7 +119,6 @@ describe('test/app/service/report_memory.test.js', () => {
             tender_id: stage.tid,
             stage_id: stage.id,
         };
-        const params = {tender_id: 2072};
         const filters = ['mem_stage_bills', 'tender_info'];
         const data = yield ctx.service.report.getReportData(params, filters, {
             mem_stage_bills: [
@@ -141,7 +140,6 @@ describe('test/app/service/report_memory.test.js', () => {
             {field: 'b_code', table: 'mem_stage_bills'},
             {field: 'is_leaf', table: 'mem_stage_bills'},
         ]);
-        console.log(data.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'});
@@ -150,6 +148,120 @@ describe('test/app/service/report_memory.test.js', () => {
         const chapter400 = ctx.helper._.find(data.mem_stage_bills, {code: '400'});
         assert(chapter400.total_price.toFixed(0) == 1231018);
     });
+    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',
+            ]
+        });
+        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 join', 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', 'deal_bills'];
+        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',
+            ]
+        });
+        assert(data.mem_stage_bills.length === 216);
+        reportDataAnalysis.analysisObj.gatherGcl.fun(ctx, data, [
+            {field: 'b_code', table: 'mem_stage_bills'},
+            {field: 'name', table: 'mem_stage_bills'},
+            {field: 'unit', table: 'mem_stage_bills'},
+            {field: 'unit_price', table: 'mem_stage_bills'},
+            {field: 'is_leaf', table: 'mem_stage_bills'},
+        ]);
+        assert(data.mem_stage_bills.length === 43);
+        reportDataAnalysis.analysisObj.join.fun(ctx, data, [], {
+            main: 'mem_stage_bills',
+            sub: 'deal_bills',
+            keyFields: [
+                {main: 'b_code', sub: 'code', type: 'string'},
+                {main: 'name', sub: 'name',type: 'string'},
+                {main: 'unit', sub: 'unit',type: 'string'},
+                {main: 'unit_price', sub: 'unit_price',type: 'number'},
+            ],
+            importFields: [
+                {main: 'ex_value1', sub: 'quantity', type: 'number'},
+                {main: 'ex_value2', sub: 'total_price', type: 'number'}
+            ],
+            joinType: 'outer', //'outer', 'main', 'sub', 'inner'
+        });
+        assert(data.mem_stage_bills.length === 132);
+        reportDataAnalysis.analysisObj.sortGcl.fun(ctx, data, [
+            {field: 'b_code', table: 'mem_stage_bills'},
+        ]);
+        const codeIndex = ctx.helper._.map(data.mem_stage_bills, 'b_code');
+        const codeIndex100 = ['101-1-b', '102-2', '102-3', '102-4', '102-5', '103-1', '103-2',
+            '103-3',  '103-3-a', '103-3-b', '103-4', '104-1', '123-1'];
+        const codeIndex200 = [
+            '203-1-a', '203-1-a', '203-1-b', '203-1-b', '203-1-d', '203-1-d', '204-1-b', '204-1-b',
+            '204-1-c', '204-1-d',
+            '204-1-g-4', '204-1-g-4', '204-1-j', '204-1-j', '205-1-o-1', '205-1-o-1', '206-2', '206-2',
+            '207-1-b',
+            '207-2-a', '207-2-a',
+            '207-2-b', '207-2-c', '207-3-a',
+            '207-4-a', '207-4-a',
+            '207-4-c', '207-10-a',
+            '208-1-a', '208-1-a', '208-3-a', '208-3-a',
+            '208-3-b',
+            '208-3-c', '208-3-c', '208-4-b-1', '208-4-b-1', '209-1-a', '209-1-a',
+            '209-3', '209-3-b', '215-12', '215-12-a'
+        ];
+        let codeResult = codeIndex100.concat(codeIndex200);
+        codeResult.forEach(function (a, i) {
+            assert(a === codeIndex[i]);
+        });
+    });
     // it('test gatherChapter custom', function* () {
     //     const ctx = app.mockContext(mockData);
     //
@@ -200,8 +312,10 @@ describe('test/app/service/report_memory.test.js', () => {
     //     assert(chapterSum.total_price === 534287);
     // });
     it('test analysisDefine', function() {
+        const ctx = app.mockContext(mockData);
+
         const define = reportDataAnalysis.analysisDefine;
-        assert(define.length === 4);
+        assert(define.length === 5);
         assert(define[0].key === 'changeSort');
         assert(define[0].name === reportDataAnalysis.analysisObj.changeSort.name);
         assert(define[0].hint === reportDataAnalysis.analysisObj.changeSort.hint);
@@ -211,5 +325,21 @@ describe('test/app/service/report_memory.test.js', () => {
         assert(define[2].key === 'sortGcl');
         assert(define[2].name === reportDataAnalysis.analysisObj.sortGcl.name);
         assert(define[2].hint === reportDataAnalysis.analysisObj.sortGcl.hint);
+
+        const x = {
+            count: 7,
+            gclSum: {
+                name: '第100章至700章清单合计',
+                order: 1,
+            },
+            custom: [
+                {name: '已包含在清单合计中的材料、工程设备、专业工程暂估价', order: 2},
+                {name: '清单合计减去材料、工程设备、专业工程暂估价(即8-9=10)', order_calc: 'o1-o2', order: 3},
+                {name: '计日工合计', node_type: '计日工', order: 4},
+                {name: '暂列金额(不含计日工总额)(即10×暂列金额比列)', node_type: '暂列金额', order: 5},
+                {name: '投标报价、台账价(8+11+12)=13', order_calc: 'o1+o4+o5', order: 6},
+            ],
+        };
+        ctx.helper.saveBufferFile(JSON.stringify(x, "", "\t"), ctx.app.baseDir + '/mem_stage_pos.json');
     });
-});
+});

+ 24 - 7
test/app/service/report_memory.test.js

@@ -19,13 +19,33 @@ const dataType = {
 const addFields = function(table, name, field, type) {
     const data = {};
     data.ID = table.ID * 100 + table.items.length + 1;
-    data.Name = name;
+    data.Name = name + '(' + field + ')';
     data.DataType = type;
     data.TableName = table.key;
     data.descr = '';
     data.mapExpression = "$PROJECT.REPORT.getProperty('" + table.key + "', '" + field + "')";
     table.items.push(data);
 };
+const saveTableDefine = async function (ctx, tableDefine, file) {
+    delete tableDefine.ID;
+    delete tableDefine.key;
+    let defineStr = JSON.stringify(tableDefine, "", "\t");
+    const replaceStr = [
+        {match: '"Name"', str: 'Name'},
+        {match: '"remark"', str: 'remark'},
+        {match: '"items"', str: 'items'},
+        {match: '"ID"', str: 'ID'},
+        {match: '"DataType"', str: 'DataType'},
+        {match: '"TableName"', str: 'TableName'},
+        {match: '"descr"', str: 'descr'},
+        {match: '"mapExpression"', str: 'mapExpression'},
+    ];
+    for (const rs of replaceStr) {
+        const reg = new RegExp(rs.match, 'gm');
+        defineStr = defineStr.replace(reg, rs.str);
+    }
+    await ctx.helper.saveBufferFile(defineStr, file);
+};
 
 describe('test/app/service/report_memory.test.js', () => {
     // 准备测试数据
@@ -175,9 +195,7 @@ describe('test/app/service/report_memory.test.js', () => {
 
             addFields(tableDefine, '章节编号', 'chapter', dataType.str);
 
-            delete tableDefine.ID;
-            delete tableDefine.key;
-            yield ctx.helper.saveBufferFile(JSON.stringify(tableDefine,"","\t"), ctx.app.baseDir + '/mem_stage_bills_define.json');
+            yield saveTableDefine(ctx, tableDefine, ctx.app.baseDir + '/mem_stage_bills_define.json');
         }
     });
     // 期部位明细数据
@@ -189,6 +207,7 @@ describe('test/app/service/report_memory.test.js', () => {
         const mainData = yield ctx.service.reportMemory.getStagePosData(12, stage.id);
         if (mainData instanceof Array) {
             yield ctx.helper.saveBufferFile(JSON.stringify(mainData,"","\t"), ctx.app.baseDir + '/mem_stage_pos.json');
+            //yield saveTableDefine(ctx, tableDefine, ctx.app.baseDir + '/mem_stage_bills_compare_define.json');
         }
     });
     // 期 全审核人 数据
@@ -270,9 +289,7 @@ describe('test/app/service/report_memory.test.js', () => {
 
             addFields(tableDefine, '章节编号', 'chapter', dataType.str);
 
-            delete tableDefine.ID;
-            delete tableDefine.key;
-            yield ctx.helper.saveBufferFile(JSON.stringify(tableDefine,"","\t"), ctx.app.baseDir + '/mem_stage_bills_compare_define.json');
+            yield saveTableDefine(ctx, tableDefine, ctx.app.baseDir + '/mem_stage_bills_compare_define.json');
         }
     });
 });