Forráskód Böngészése

Merge branch 'master' of http://192.168.1.41:3000/maixinrong/Calculation

TonyKang 5 éve
szülő
commit
25abb6e306

+ 51 - 3
app/lib/rpt_data_analysis.js

@@ -233,6 +233,16 @@ const gatherChapter = {
             {name: '暂列金额(不含计日工总额)(即10×暂列金额比列)', order: 5, match: [{node_type: '暂列金额'}, {field: 'name', part: '暂列金额'}, {field: 'name', part: '暂定金额'}]},
             {name: '投标报价、台账价(8+11+12)=13', order_calc: 'o1+o4+o5', order: 6},
         ],
+        rela: [
+            {
+                table: 'deal_bills', key: 'code',
+                fields: {source: 'total_price', target: 'ex_value1'},
+            },
+            {
+                table: 'mem_change_bills', key: 'code',
+                fields: {source: '', target: 'ex_value2'},
+            }
+        ]
     },
     _getCalcChapter: function (chapter, options) {
         const gclChapter = [], otherChapter = [], customChapter = [];
@@ -285,11 +295,11 @@ const gatherChapter = {
         }
         return [gclChapter, otherChapter, customChapter];
     },
-    _getGclChapter: function (chapter, data) {
+    _getGclChapter: function (chapter, data, field) {
         for (const c of chapter) {
             if (c.filter) {
                 const reg = new RegExp(c.filter);
-                if (reg.test(data.b_code)) {
+                if (reg.test(data[field])) {
                     return c;
                 }
             } else {
@@ -303,6 +313,40 @@ const gatherChapter = {
         }
         return false;
     },
+    _gatherRela: function (ctx, data, rela, gclChapter, otherChapter) {
+        if (!rela) return;
+
+        const gatherRelaFields = function (chapter, source, field) {
+            const fields = field instanceof Array ? field : [field];
+            for (const f of fields) {
+                chapter[f.target] = ctx.helper.add(chapter[f.target], source[f.source]);
+            }
+        };
+
+        const relaBills = rela instanceof Array ? rela : [rela];
+        for (const rb of relaBills) {
+            if (!rb.table) continue;
+
+            const relaData = data[rb.table];
+            if (!relaData) continue;
+
+            for (const rd of relaData) {
+                for (const c of otherChapter) {
+                    if (c.cType === 41) {
+                        gatherRelaFields(c, rd, rb.fields);
+                    } else if (c.cType === 31 && (!rd[rb.key] || rd[rb.key] === '')) {
+                        gatherRelaFields(c, rd, rb.fields);
+                    } else if (c.cType === 11 && (rd[rb.key])) {
+                        gatherRelaFields(c, rd, rb.fields);
+                    }
+                }
+                if (rd[rb.key]) {
+                    const c = this._getGclChapter(gclChapter, rd, rb.key);
+                    gatherRelaFields(c, rd, rb.fields);
+                }
+            }
+        }
+    },
     _orderCalc: function (ctx, chapter, fields) {
         const orderMatch = new RegExp('o[0-9]+', 'igm');
         for (const c of chapter) {
@@ -387,10 +431,11 @@ const gatherChapter = {
                 }
             }
             if (d.b_code) {
-                const c = this._getGclChapter(gclChapter, d);
+                const c = this._getGclChapter(gclChapter, d, 'b_code');
                 gatherData(c, d);
             }
         }
+        this._gatherRela(ctx, data, options.rela, gclChapter, otherChapter);
         const chapter = gclChapter.concat(otherChapter).concat(customChapter);
         this._orderCalc(ctx, chapter, calcFields);
         chapter.sort(function (a, b) {return a.serialNo - b.serialNo});
@@ -405,6 +450,7 @@ const gatherChapter = {
                 return true;
             }
         });
+        //console.log(data[fieldsKey[0].table]);
     },
 };
 const join = {
@@ -691,6 +737,7 @@ const union = {
     fun: function(ctx, data, fields, options) {
         if (!options || !options.union) return;
 
+        console.log(data.mem_stage_pay);
         const result = [];
         for (const u of options.union) {
             const unionData = data[u.table];
@@ -707,6 +754,7 @@ const union = {
             }
         }
         data.mem_union_data = result;
+        //console.log(data.mem_union_data);
     }
 };
 

+ 3 - 1
app/reports/util/rpt_calculation_data_util.js

@@ -554,10 +554,12 @@ function preDefineProcess(ctx, tpl, preDefineCfg, rawDataObj, $CURRENT_RPT) {
                         preSetup = JSON.parse(preSetup);
                     }
                 } catch (ex) {
-                    console.log(ex);
+                    console.log(analysisKey);
+                    ctx.helper.log(ex);
                 }
                 data_analyze_util[analysisKey].fun(ctx, rawDataObj, fields, preSetup);
             } catch (err) {
+                ctx.helper.log(err);
                 throw '报表预处理数据出错';
             }
         } else {

+ 4 - 1
app/service/report.js

@@ -94,7 +94,10 @@ module.exports = app => {
                             break;
                         case 'mem_stage_pay':
                             runnableRst.push(service.reportMemory.getStagePayData(params.tender_id, params.stage_id, memFieldKeys[filter]));
-                            runnableKey.push(filter);
+                            runnableKey.push('mem_stage_pay');
+                        case 'mem_change_bills':
+                            runnableRst.push(service.reportMemory.getChangeBillsData(params.tender_id, params.stage_id, memFieldKeys[filter]));
+                            runnableKey.push('mem_change_bills');
                             break;
                         case 'change':
                             runnableRst.push(service.change.getListByStatus(params.tender_id, 3)); // 获取所有审核通过的变更主信息

+ 54 - 0
app/service/report_memory.js

@@ -97,6 +97,15 @@ module.exports = app => {
             }
             return false;
         }
+        _checkFieldsExistReg(source, regStr) {
+            const reg = new RegExp(regStr, 'igm');
+            for (const s of source) {
+                if (reg.test(s)) {
+                    return true;
+                }
+            }
+            return false;
+        }
 
         // build-time: 162-384ms, redis-cache: 0-41ms, mysql + IO: 116-146ms
         // 一定程度上算是大Value缓存,数据多了以后:
@@ -522,8 +531,53 @@ module.exports = app => {
                 const payCalculator = new PayCalculator(this.ctx, this.ctx.stage, this.ctx.tender.info);
                 await payCalculator.calculateAll(dealPay);
             }
+
+            if (this._checkFieldsExistReg(fields, 'r[0-9]+_tp')) {
+                const validRole = this._getStageValidRole();
+                const allStagePays = await this.ctx.service.stagePay.getAllDataByCondition({
+                    where: {sid: this.ctx.stage.id, stimes: this.ctx.stage.curTimes}
+                });
+
+                for (const [i, role] of validRole.entries()) {
+                    if (i < validRole.length - 1) {
+                        const stagePays = this.ctx.helper._.filter(allStagePays, function (x) {
+                            return x.times === stage.curTimes && x.order === role.dataOrder;
+                        });
+                        this.ctx.helper._.pullAll(allStagePays, stagePays);
+
+                        for (const sp of stagePays) {
+                            const dp = dealPay.find(function (x) {return x.pid === sp.pid});
+                            if (dp) {
+                                dp['r' + role.flowOrder + '_tp'] = sp.tp;
+                            }
+                        }
+                    } else {
+                        for (const dp of dealPay) {
+                            dp['r' + role.flowOrder + '_tp'] = dp.tp;
+                        }
+                    }
+                }
+            }
+
             return dealPay;
         }
+
+        async getChangeBillsData(tid, sid, fields) {
+            await this.ctx.service.tender.checkTender(tid);
+
+            const data = await this.ctx.service.changeAuditList.getChangeAuditBills(tid);
+            const decimal = this.ctx.tender.info.decimal;
+            for (const d of data) {
+                //const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, d.unit);
+                d.o_qty = d.oamount;
+                d.o_tp = this.ctx.helper.mul(d.o_qty, d.unit_price, decimal.tp);
+                d.c_qty = d.camount;
+                d.c_tp = this.ctx.helper.mul(d.c_qty, d.unit_price, decimal.tp);
+                d.s_qty = d.samount ? parseFloat(d.samount) : 0;
+                d.s_tp = this.ctx.helper.mul(d.s_qty, d.unit_price, decimal.tp);
+            }
+            return data;
+        }
     }
 
     return ReportMemory;

+ 154 - 84
test/app/service/report_memory.test.js

@@ -9,6 +9,8 @@
  */
 
 const { app, assert } = require('egg-mock/bootstrap');
+const path = require('path');
+let savePath;
 const mockData = {};
 const dataType = {
     int: 'int',
@@ -16,7 +18,7 @@ const dataType = {
     double: 'double',
     currency: 'currency',
 };
-const addFields = function(table, name, field, type) {
+const addFields = function(table, name, field, type, tag) {
     const data = {};
     data.ID = table.ID * 100 + table.items.length + 1;
     data.Name = name + '(' + field + ')';
@@ -24,6 +26,34 @@ const addFields = function(table, name, field, type) {
     data.TableName = table.key;
     data.descr = '';
     data.mapExpression = "$PROJECT.REPORT.getProperty('" + table.key + "', '" + field + "')";
+    if (tag) {
+        switch (tag.type) {
+            case 'up':
+                data.Precision = { type: "fixed", fixedMapExpression: "$PROJECT.REPORT.getProperty('tender_info', 'decimal.up')" };
+                break;
+            case 'tp':
+                if (tag.subType) {
+                    data.Precision = { type: "fixed", fixedMapExpression: "$PROJECT.REPORT.getProperty('tender_info', 'decimal." + "_" + tag.subType + "_tp')" };
+                } else {
+                    data.Precision = { type: "fixed", fixedMapExpression: "$PROJECT.REPORT.getProperty('tender_info', 'decimal.tp')" };
+                }
+                break;
+            case 'qty':
+                data.Precision = { type: "flexible", flexibleRefFieldID: table.ID * 100 + tag.unitKey, flexibleMapExpression: "$PROJECT.REPORT.getProperty('tender_info', 'precision')" };
+                break;
+        }
+    }
+    table.items.push(data);
+};
+const addTpFields = function(table, name, field, type) {
+    const data = {};
+    data.ID = table.ID * 100 + table.items.length + 1;
+    data.Name = name + '(' + field + ')';
+    data.DataType = type;
+    data.TableName = table.key;
+    data.descr = '';
+    data.mapExpression = "$PROJECT.REPORT.getProperty('" + table.key + "', '" + field + "')";
+    data.Precision = { type: 'fixed', fixedMapExpression: '$PROJECT.REPORT.getProperty("tender_info", "decimal.up")' };
     table.items.push(data);
 };
 const saveTableDefine = async function (ctx, tableDefine, file) {
@@ -31,14 +61,19 @@ const saveTableDefine = async function (ctx, tableDefine, file) {
     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'},
+        {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:'},
+        {match: '"Precision":', str: 'Precision:'},
+        {match: '"type":', str: 'type:'},
+        {match: '"flexibleRefFieldID":', str: 'flexibleRefFieldID:'},
+        {match: '"fixedMapExpression":', str: 'fixedMapExpression:'},
+        {match: '"flexibleMapExpression":', str: 'flexibleMapExpression:'},
     ];
     for (const rs of replaceStr) {
         const reg = new RegExp(rs.match, 'gm');
@@ -51,6 +86,7 @@ describe('test/app/service/report_memory.test.js', () => {
     // 准备测试数据
     before(function* () {
         const ctx = app.mockContext();
+        savePath = path.join(ctx.app.baseDir,'report_temp');
         // 模拟登录session
         const postData = {
             account: '734406061@qq.com',
@@ -124,7 +160,7 @@ describe('test/app/service/report_memory.test.js', () => {
             'chapter',
         ]);
         if (mainData instanceof Array) {
-            yield ctx.helper.saveBufferFile(JSON.stringify(mainData,"","\t"), ctx.app.baseDir + '/mem_stage_bills.json');
+            yield ctx.helper.saveBufferFile(JSON.stringify(mainData,"","\t"), path.join(savePath, 'mem_stage_bills.json'));
             const tableDefine = {};
             tableDefine.Name = '期 - 清单数据表(mem_stage_bills)';
             tableDefine.remark = '';
@@ -138,25 +174,25 @@ describe('test/app/service/report_memory.test.js', () => {
             addFields(tableDefine, '树结构-层级', 'level', dataType.int);
             addFields(tableDefine, '树结构-同层排序', 'order', dataType.int);
             addFields(tableDefine, '树结构-完整路径', 'full_path', dataType.int);
-            addFields(tableDefine, '树结构-是否子项', 'is_leaf', dataType.int);
+            addFields(tableDefine, '树结构-是否子项', 'is_leaf', dataType.int); // 8
 
             addFields(tableDefine, '项目节编号', 'code', dataType.str);
             addFields(tableDefine, '清单编号', 'b_code', dataType.str);
             addFields(tableDefine, '名称', 'name', dataType.str);
-            addFields(tableDefine, '单位', 'unit', dataType.str);
-            addFields(tableDefine, '单价', 'unit_price', dataType.currency);
+            addFields(tableDefine, '单位', 'unit', dataType.str); // 12
+            addFields(tableDefine, '单价', 'unit_price', dataType.currency, {type: 'up'});
 
-            addFields(tableDefine, '签约-数量', 'deal_qty', dataType.currency);
-            addFields(tableDefine, '签约-金额', 'deal_tp', dataType.currency);
+            addFields(tableDefine, '签约-数量', 'deal_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '签约-金额', 'deal_tp', dataType.currency, {type: 'tp'});
 
-            addFields(tableDefine, '施工复核-数量', 'sgfh_qty', dataType.currency);
-            addFields(tableDefine, '施工复核-金额', 'sgfh_tp', dataType.currency);
-            addFields(tableDefine, '设计错漏-数量', 'sjcl_qty', dataType.currency);
-            addFields(tableDefine, '设计错漏-金额', 'sjcl_tp', dataType.currency);
-            addFields(tableDefine, '其他错漏-数量', 'qtcl_qty', dataType.currency);
-            addFields(tableDefine, '其他错漏-金额', 'qtcl_tp', dataType.currency);
-            addFields(tableDefine, '台账-数量', 'quantity', dataType.currency);
-            addFields(tableDefine, '台账-金额', 'total_price', dataType.currency);
+            addFields(tableDefine, '施工复核-数量', 'sgfh_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '施工复核-金额', 'sgfh_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '设计错漏-数量', 'sjcl_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '设计错漏-金额', 'sjcl_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '其他错漏-数量', 'qtcl_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '其他错漏-金额', 'qtcl_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '台账-数量', 'quantity', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '台账-金额', 'total_price', dataType.currency, {type: 'tp'});
 
             addFields(tableDefine, '项目节-数量1', 'dgn_qty1', dataType.currency);
             addFields(tableDefine, '项目节-金额2', 'dgn_qty2', dataType.currency);
@@ -166,36 +202,36 @@ describe('test/app/service/report_memory.test.js', () => {
             addFields(tableDefine, '节点类型', 'node_type', dataType.int);
             addFields(tableDefine, '总额计量', 'is_tp', dataType.int);
 
-            addFields(tableDefine, '本期-合同-数量', 'contract_qty', dataType.currency);
-            addFields(tableDefine, '本期-合同-金额', 'contract_tp', dataType.currency);
-            addFields(tableDefine, '本期-数量变更-数量', 'qc_qty', dataType.currency);
-            addFields(tableDefine, '本期-数量变更-金额', 'qc_tp', dataType.currency);
-            addFields(tableDefine, '本期-完成-数量', 'gather_qty', dataType.currency);
-            addFields(tableDefine, '本期-完成-金额', 'gather_tp', dataType.currency);
+            addFields(tableDefine, '本期-合同-数量', 'contract_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '本期-合同-金额', 'contract_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '本期-数量变更-数量', 'qc_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '本期-数量变更-金额', 'qc_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '本期-完成-数量', 'gather_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '本期-完成-金额', 'gather_tp', dataType.currency, {type: 'tp'});
             addFields(tableDefine, '本期批注', 'postil', dataType.str);
 
-            addFields(tableDefine, '截止上期-合同-数量', 'pre_contract_qty', dataType.currency);
-            addFields(tableDefine, '截止上期-合同-金额', 'pre_contract_tp', dataType.currency);
-            addFields(tableDefine, '截止上期-数量变更-数量', 'pre_qc_qty', dataType.currency);
-            addFields(tableDefine, '截止上期-数量变更-金额', 'pre_qc_tp', dataType.currency);
-            addFields(tableDefine, '截止上期-完成-数量', 'pre_gather_qty', dataType.currency);
-            addFields(tableDefine, '截止上期-完成-金额', 'pre_gather_tp', dataType.currency);
-
-            addFields(tableDefine, '截止本期-合同-数量', 'end_contract_qty', dataType.currency);
-            addFields(tableDefine, '截止本期-合同-金额', 'end_contract_tp', dataType.currency);
-            addFields(tableDefine, '截止本期-数量变更-数量', 'end_qc_qty', dataType.currency);
-            addFields(tableDefine, '截止本期-数量变更-金额', 'end_qc_tp', dataType.currency);
-            addFields(tableDefine, '截止本期-完成-数量', 'end_gather_qty', dataType.currency);
-            addFields(tableDefine, '截止本期-完成-金额', 'end_gather_tp', dataType.currency);
-
-            addFields(tableDefine, '(台账 + 截止本期变更)-金额', 'final_tp', dataType.currency);
+            addFields(tableDefine, '截止上期-合同-数量', 'pre_contract_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '截止上期-合同-金额', 'pre_contract_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '截止上期-数量变更-数量', 'pre_qc_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '截止上期-数量变更-金额', 'pre_qc_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '截止上期-完成-数量', 'pre_gather_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '截止上期-完成-金额', 'pre_gather_tp', dataType.currency, {type: 'tp'});
+
+            addFields(tableDefine, '截止本期-合同-数量', 'end_contract_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '截止本期-合同-金额', 'end_contract_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '截止本期-数量变更-数量', 'end_qc_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '截止本期-数量变更-金额', 'end_qc_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '截止本期-完成-数量', 'end_gather_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '截止本期-完成-金额', 'end_gather_tp', dataType.currency, {type: 'tp'});
+
+            addFields(tableDefine, '(台账 + 截止本期变更)-金额', 'final_tp', dataType.currency, {type: 'tp'});
             addFields(tableDefine, '截止本期完成率(%)', 'final_ratio', dataType.double);
 
             addFields(tableDefine, '本期-数量变更-变更令', 'qc_bgl_code', dataType.str);
 
             addFields(tableDefine, '章节编号', 'chapter', dataType.str);
 
-            yield saveTableDefine(ctx, tableDefine, ctx.app.baseDir + '/mem_stage_bills_define.json');
+            yield saveTableDefine(ctx, tableDefine, path.join(savePath, 'mem_stage_bills_define.json'));
         }
     });
     // 期部位明细数据
@@ -206,8 +242,7 @@ describe('test/app/service/report_memory.test.js', () => {
         const stage = yield ctx.service.stage.getDataByCondition({tid: 12, order: 6});
         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');
+            yield ctx.helper.saveBufferFile(JSON.stringify(mainData,"","\t"), path.join(savePath, 'mem_stage_pos.json'));
         }
     });
     // 期 全审核人 数据
@@ -228,7 +263,7 @@ describe('test/app/service/report_memory.test.js', () => {
             'chapter',
         ]);
         if (mainData instanceof Array) {
-            yield ctx.helper.saveBufferFile(JSON.stringify(mainData,"","\t"), ctx.app.baseDir + '/mem_stage_bills_compare.json');
+            yield ctx.helper.saveBufferFile(JSON.stringify(mainData,"","\t"), path.join(savePath, 'mem_stage_bills_compare.json'));
 
             const tableDefine = {};
             tableDefine.Name = '期-清单-全参与人数据表(mem_stage_bills_compare)';
@@ -243,62 +278,62 @@ describe('test/app/service/report_memory.test.js', () => {
             addFields(tableDefine, '树结构-层级', 'level', dataType.int);
             addFields(tableDefine, '树结构-同层排序', 'order', dataType.int);
             addFields(tableDefine, '树结构-完整路径', 'full_path', dataType.int);
-            addFields(tableDefine, '树结构-是否子项', 'is_leaf', dataType.int);
+            addFields(tableDefine, '树结构-是否子项', 'is_leaf', dataType.int); // 8
 
             addFields(tableDefine, '项目节编号', 'code', dataType.str);
             addFields(tableDefine, '清单编号', 'b_code', dataType.str);
             addFields(tableDefine, '名称', 'name', dataType.str);
-            addFields(tableDefine, '单位', 'unit', dataType.str);
-            addFields(tableDefine, '单价', 'unit_price', dataType.currency);
+            addFields(tableDefine, '单位', 'unit', dataType.str); // 12
+            addFields(tableDefine, '单价', 'unit_price', dataType.currency, {type: 'up'});
 
-            addFields(tableDefine, '签约-数量', 'deal_qty', dataType.currency);
-            addFields(tableDefine, '签约-金额', 'deal_tp', dataType.currency);
+            addFields(tableDefine, '签约-数量', 'deal_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '签约-金额', 'deal_tp', dataType.currency, {type: 'tp'});
 
-            addFields(tableDefine, '施工复核-数量', 'sgfh_qty', dataType.currency);
-            addFields(tableDefine, '施工复核-金额', 'sgfh_tp', dataType.currency);
-            addFields(tableDefine, '设计错漏-数量', 'sjcl_qty', dataType.currency);
-            addFields(tableDefine, '设计错漏-金额', 'sjcl_tp', dataType.currency);
-            addFields(tableDefine, '其他错漏-数量', 'qtcl_qty', dataType.currency);
-            addFields(tableDefine, '其他错漏-金额', 'qtcl_tp', dataType.currency);
-            addFields(tableDefine, '台账-数量', 'quantity', dataType.currency);
-            addFields(tableDefine, '台账-金额', 'total_price', dataType.currency);
+            addFields(tableDefine, '施工复核-数量', 'sgfh_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '施工复核-金额', 'sgfh_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '设计错漏-数量', 'sjcl_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '设计错漏-金额', 'sjcl_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '其他错漏-数量', 'qtcl_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '其他错漏-金额', 'qtcl_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '台账-数量', 'quantity', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '台账-金额', 'total_price', dataType.currency, {type: 'tp'});
 
             addFields(tableDefine, '项目节-数量1', 'dgn_qty1', dataType.currency);
-            addFields(tableDefine, '项目节-金额2', 'dgn_qty2', dataType.currency);
+            addFields(tableDefine, '项目节-数量2', 'dgn_qty2', dataType.currency);
 
             addFields(tableDefine, '图册号', 'drawing_code', dataType.str);
             addFields(tableDefine, '备注', 'memo', dataType.str);
             addFields(tableDefine, '节点类型', 'node_type', dataType.int);
             addFields(tableDefine, '总额计量', 'is_tp', dataType.int);
 
-            addFields(tableDefine, '截止上期-合同-数量', 'pre_contract_qty', dataType.currency);
-            addFields(tableDefine, '截止上期-合同-金额', 'pre_contract_tp', dataType.currency);
-            addFields(tableDefine, '截止上期-数量变更-数量', 'pre_qc_qty', dataType.currency);
-            addFields(tableDefine, '截止上期-数量变更-金额', 'pre_qc_tp', dataType.currency);
-            addFields(tableDefine, '截止上期-完成-数量', 'pre_gather_qty', dataType.currency);
-            addFields(tableDefine, '截止上期-完成-金额', 'pre_gather_tp', dataType.currency);
+            addFields(tableDefine, '截止上期-合同-数量', 'pre_contract_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '截止上期-合同-金额', 'pre_contract_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '截止上期-数量变更-数量', 'pre_qc_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '截止上期-数量变更-金额', 'pre_qc_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, '截止上期-完成-数量', 'pre_gather_qty', dataType.currency, {type: 'qty', unitKey: 12});
+            addFields(tableDefine, '截止上期-完成-金额', 'pre_gather_tp', dataType.currency, {type: 'tp'});
 
             for (let i = 0 ;i < 10; i++) {
-                addFields(tableDefine, '本期-合同-数量' + '_' + i, 'r' + i +'_' + 'contract_qty', dataType.currency);
-                addFields(tableDefine, '本期-合同-金额' + '_' + i, 'r' + i +'_' + 'contract_tp', dataType.currency);
-                addFields(tableDefine, '本期-数量变更-数量' + '_' + i, 'r' + i +'_' + 'qc_qty', dataType.currency);
-                addFields(tableDefine, '本期-数量变更-金额' + '_' + i, 'r' + i +'_' + 'qc_tp', dataType.currency);
-                addFields(tableDefine, '本期-完成-数量' + '_' + i, 'r' + i +'_' + 'gather_qty', dataType.currency);
-                addFields(tableDefine, '本期-完成-金额' + '_' + i, 'r' + i +'_' + 'gather_tp', dataType.currency);
+                addFields(tableDefine, '本期-合同-数量' + '_' + i, 'r' + i +'_' + 'contract_qty', dataType.currency, {type: 'qty', unitKey: 12});
+                addFields(tableDefine, '本期-合同-金额' + '_' + i, 'r' + i +'_' + 'contract_tp', dataType.currency, {type: 'tp'});
+                addFields(tableDefine, '本期-数量变更-数量' + '_' + i, 'r' + i +'_' + 'qc_qty', dataType.currency, {type: 'qty', unitKey: 12});
+                addFields(tableDefine, '本期-数量变更-金额' + '_' + i, 'r' + i +'_' + 'qc_tp', dataType.currency, {type: 'tp'});
+                addFields(tableDefine, '本期-完成-数量' + '_' + i, 'r' + i +'_' + 'gather_qty', dataType.currency, {type: 'qty', unitKey: 12});
+                addFields(tableDefine, '本期-完成-金额' + '_' + i, 'r' + i +'_' + 'gather_tp', dataType.currency, {type: 'tp'});
             }
 
             addFields(tableDefine, '章节编号', 'chapter', dataType.str);
 
-            yield saveTableDefine(ctx, tableDefine, ctx.app.baseDir + '/mem_stage_bills_compare_define.json');
+            yield saveTableDefine(ctx, tableDefine, path.join(savePath, 'mem_stage_bills_compare_define.json'));
         }
     });
     it('test getStagePay', function* () {
         const ctx = app.mockContext(mockData);
         // test12 - 第4期
         const stage = yield ctx.service.stage.getDataByCondition({tid: 12, order: 6});
-        const data = yield ctx.service.reportMemory.getStagePayData(stage.tid, stage.id, []);
+        const data = yield ctx.service.reportMemory.getStagePayData(stage.tid, stage.id, ['r0_tp', 'r1_tp']);
         if (data instanceof Array) {
-            yield ctx.helper.saveBufferFile(JSON.stringify(data, '', '\t'), ctx.app.baseDir + '/mem_stage_pay.json');
+            yield ctx.helper.saveBufferFile(JSON.stringify(data, '', '\t'), path.join(savePath, 'mem_stage_pay.json'));
 
             const tableDefine = {};
             tableDefine.Name = '期-合同支付-数据(mem_stage_pay)';
@@ -310,15 +345,18 @@ describe('test/app/service/report_memory.test.js', () => {
 
             addFields(tableDefine, prefix + '名称', 'name', dataType.str);
             addFields(tableDefine, prefix + '计算公式', 'expr', dataType.str);
-            addFields(tableDefine, prefix + '金额', 'tp', dataType.currency);
-            addFields(tableDefine, prefix + '截止上期-金额', 'pre_tp', dataType.currency);
-            addFields(tableDefine, prefix + '截止本期-金额', 'end_tp', dataType.currency);
+            addTpFields(tableDefine, prefix + '金额', 'tp', dataType.currency, {type: 'tp', subType: 'pay'});
+            addTpFields(tableDefine, prefix + '截止上期-金额', 'pre_tp', dataType.currency, {type: 'tp', subType: 'pay'});
+            addTpFields(tableDefine, prefix + '截止本期-金额', 'end_tp', dataType.currency, {type: 'tp', subType: 'pay'});
             addFields(tableDefine, prefix + '排序', 'order', dataType.int);
             addFields(tableDefine, prefix + '是否扣款项', 'minus', dataType.int);
             addFields(tableDefine, prefix + '支付类型', 'ptype', dataType.int);
-            addFields(tableDefine, prefix + '起扣金额', 'sprice', dataType.currency);
-            addFields(tableDefine, prefix + '扣款限额', 'rprice', dataType.currency);
-            yield saveTableDefine(ctx, tableDefine, ctx.app.baseDir + '/mem_stage_pay_define.json');
+            addTpFields(tableDefine, prefix + '起扣金额', 'sprice', dataType.currency, {type: 'tp', subType: 'pay'});
+            addTpFields(tableDefine, prefix + '扣款限额', 'rprice', dataType.currency, {type: 'tp', subType: 'pay'});
+            for (let i = 0 ;i < 10; i++) {
+                addTpFields(tableDefine, prefix + '流程-本期-金额_' + i, 'r' + i + '_tp', dataType.currency, {type: 'tp', subType: 'pay'});
+            }
+            yield saveTableDefine(ctx, tableDefine, path.join(savePath, 'mem_stage_pay_define.json'));
         }
     });
     it('test mem_union_data', function* () {
@@ -368,6 +406,38 @@ describe('test/app/service/report_memory.test.js', () => {
         addFields(tableDefine, prefix + '金额8', 'tp8', dataType.currency);
         addFields(tableDefine, prefix + '金额9', 'tp9', dataType.currency);
         addFields(tableDefine, prefix + '金额10', 'tp10', dataType.currency);
-        yield saveTableDefine(ctx, tableDefine, ctx.app.baseDir + '/mem_union_data.json');
+        yield saveTableDefine(ctx, tableDefine, path.join(savePath, 'mem_union_data.json'));
+    });
+    it('test mem_change_bills', function* () {
+        const ctx = app.mockContext(mockData);
+
+        const data = yield ctx.service.reportMemory.getChangeBillsData(12);
+        if (data instanceof Array) {
+            yield ctx.helper.saveBufferFile(JSON.stringify(data, '', '\t'), path.join(savePath, 'mem_change_bills.json'));
+
+            const tableDefine = {};
+            tableDefine.Name = '变更清单-(mem_change_bills)';
+            tableDefine.remark = '';
+            tableDefine.ID = 29;
+            tableDefine.key = 'mem_change_bills';
+            tableDefine.items = [];
+            const prefix = '变更清单-';
+
+            addFields(tableDefine, prefix + '变更令id', 'cid', dataType.str);
+            addFields(tableDefine, prefix + '签约清单id或台账id', 'lid', dataType.str);
+            addFields(tableDefine, prefix + '清单编号', 'code', dataType.str);
+            addFields(tableDefine, prefix + '名称', 'name', dataType.str);
+            addFields(tableDefine, prefix + '单位', 'unit', dataType.str);
+            addFields(tableDefine, prefix + '单价', 'unit_price', dataType.currency, {type: 'up'});
+            addFields(tableDefine, prefix + '原数量', 'o_qty', dataType.currency, {type: 'qty', unitKey: 5});
+            addFields(tableDefine, prefix + '变更数量', 'c_qty', dataType.currency, {type: 'qty', unitKey: 5});
+            addFields(tableDefine, prefix + '审批变更后数量', 's_qty', dataType.currency, {type: 'qty', unitKey: 5});
+            addFields(tableDefine, prefix + '原-金额', 'o_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, prefix + '变更-金额', 'c_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, prefix + '审批变更后-金额', 's_tp', dataType.currency, {type: 'tp'});
+            addFields(tableDefine, prefix + '部位明细', 'bwmx', dataType.str);
+            addFields(tableDefine, prefix + '变更详情', 'detail', dataType.str);
+            yield saveTableDefine(ctx, tableDefine, path.join(savePath, 'mem_change_bills_define.json'));
+        }
     });
 });