소스 검색

报表数据源,材差相关

MaiXinRong 1 년 전
부모
커밋
f3b428158d
4개의 변경된 파일596개의 추가작업 그리고 118개의 파일을 삭제
  1. 119 100
      app/lib/rm/material.js
  2. 2 2
      app/lib/rm/tender.js
  3. 451 0
      app/lib/rm/tender_material.js
  4. 24 16
      app/service/report.js

+ 119 - 100
app/lib/rm/material.js

@@ -8,8 +8,12 @@
  * @version
  */
 
-const materialConst = require('../../const/material');
+const RptMemBase = require('./base');
+const bindData = {
+    materialGather: ['mem_material_gather_bills', 'mem_material_gather_xmj', 'mem_material_gather_gl'],
+};
 
+const materialConst = require('../../const/material');
 const Ledger = require('../../lib/ledger');
 
 const billsFields = (function () {
@@ -39,9 +43,26 @@ const posFields = (function () {
     return {cur, pre, end, final, stage, stageEnd, bgl};
 })();
 
-class ReportMemoryMaterial {
+class rptMemChange extends RptMemBase {
     constructor(ctx) {
-        this.ctx = ctx;
+        super(ctx, bindData);
+    }
+
+    async doCheckMaterial(materialId) {
+        if (this.ctx.material) return;
+        this.ctx.material = await this.ctx.service.material.getDataByCondition({ id: materialId });
+    }
+
+    async doCheckTender(tenderId) {
+        if (this.ctx.tender) return;
+        this.ctx.tender = { id: tenderId };
+        this.ctx.tender.data = await this.ctx.service.tender.getTender(tenderId);
+        this.ctx.tender.info = await this.ctx.service.tenderInfo.getTenderInfo(tenderId);
+    }
+
+    async doBeforeLoadReport(params) {
+        await this.doCheckMaterial(params.material_id);
+        await this.doCheckTender(this.ctx.material.tid);
     }
 
     _getNewPos(updateFields) {
@@ -59,7 +80,6 @@ class ReportMemoryMaterial {
             }
         });
     }
-
     _getNewBillsTree(calcFields) {
         return new Ledger.billsTree(this.ctx, {
             id: 'ledger_id',
@@ -91,17 +111,7 @@ class ReportMemoryMaterial {
         });
     }
 
-    _checkFieldsExist(source, check) {
-        for (const s of source) {
-            if (check.indexOf(s) >= 0) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    async getSelectMaterialAuditors(tid, material_order, fields) {
-        await this.ctx.service.material.checkMaterial(tid, material_order);
+    async getMaterialAuditors() {
         const auditors = await this.ctx.service.materialAudit.getFinalAuditGroup(this.ctx.material.id, this.ctx.material.curTimes);
         const user = await this.ctx.service.projectAccount.getDataById(this.ctx.material.user_id);
         const result = [{
@@ -120,17 +130,22 @@ class ReportMemoryMaterial {
         return result;
     }
 
-    async getMaterial(tender_id, material_order, fields) {
-        const result = await this.ctx.service.material.getValidMaterials(tender_id);
-        if (this._checkFieldsExist(fields, ['checked_time'])) {
-            for (const r of result) {
-                const auditors = await this.ctx.service.materialAudit.getFinalAuditGroup(r.id, r.curTimes || r.times);
-                r.checked_time = !r.curTimes ? auditors[auditors.length - 1].end_time : null;
-            }
+    async _loadMaterialMonth(material, gl) {
+        const materialMonth = await this.ctx.service.materialMonth.getAllDataByCondition({
+            where: { mid: material.id },
+            orders: [['mb_id', 'asc'], ['yearmonth', 'asc']],
+        });
+
+        const month = this.ctx.helper._.uniq(materialMonth.map(x => { return x.yearmonth; }));
+        let g;
+        for (const mm of materialMonth) {
+            if (!g || g.id !== mm.mb_id) g = gl.find(x => { return mm.mb_id === x.id; });
+            if (!g.month_msg_tp) g.month_msg_tp = [];
+            if (!g.month) g.month = month.concat([]);
+            const index = month.indexOf(mm.yearmonth);
+            if (index >= 0) g.month_msg_tp[index] = mm.msg_tp;
         }
-        return result;
     }
-
     _completeMaterialGl(materialGl, decimal) {
         const tTypeStr = [], mTypeStr = [];
         for (const t of materialConst.t_type) {
@@ -146,34 +161,18 @@ class ReportMemoryMaterial {
             gl.end_tp = this.ctx.helper.add(gl.tp, gl.pre_tp);
         }
     }
+    async getMaterialGl(fields) {
+        if (!this.ctx.material) return [];
 
-    async _loadMaterialMonth(material, gl) {
-        const materialMonth = await this.ctx.service.materialMonth.getAllDataByCondition({
-            where: { mid: material.id },
-            orders: [['mb_id', 'asc'], ['yearmonth', 'asc']],
-        });
-
-        const month = this.ctx.helper._.uniq(materialMonth.map(x => { return x.yearmonth; }));
-        let g;
-        for (const mm of materialMonth) {
-            if (!g || g.id !== mm.mb_id) g = gl.find(x => { return mm.mb_id === x.id; });
-            if (!g.month_msg_tp) g.month_msg_tp = [];
-            if (!g.month) g.month = month.concat([]);
-            const index = month.indexOf(mm.yearmonth);
-            if (index >= 0) g.month_msg_tp[index] = mm.msg_tp;
-        }
-    }
-
-    async getMaterialGl(tender_id, material_order, fields) {
         const materials = await this.ctx.service.material.getAllDataByCondition({
-            where: {tid: tender_id},
+            where: {tid: this.ctx.material.tid},
             orders: [['order', 'desc']],
         });
         if (materials.length === 0) return [];
 
         let result, material, decimal;
-        if (materials[0].order === material_order) {
-            material = materials[0];
+        material = this.ctx.material;
+        if (materials[0].order === material.order) {
             decimal = material.decimal ? JSON.parse(material.decimal) : { qty: 3, up: 3, tp: 2 };
             if (material.is_stage_self) {
                 const sql = 'SELECT msb.id, msb.tid, msb.mid, msb.ms_id, ms.sid, ms.`order` as s_order, mb.order, mb.t_type, mb.code, mb.name, mb.unit, mb.spec, mb.m_type,' +
@@ -189,13 +188,10 @@ class ReportMemoryMaterial {
                 result = await this.ctx.app.mysql.query(sql, [material.id]);
             } else {
                 result = await this.ctx.service.materialBills.getAllDataByCondition({
-                    where: {tid: tender_id}
+                    where: {tid: material.tid}
                 });
             }
         } else {
-            material = this.ctx.helper._.find(materials, {order: material_order});
-            if (!material) return [];
-
             decimal = material.decimal ? JSON.parse(material.decimal) : { tp: 2 };
             if (material.is_stage_self) {
                 const sql = 'SELECT msb.id, msb.tid, msb.mid, msb.ms_id, ms.sid, ms.`order` as s_order, mb.order, mb.t_type, mb.code, mb.name, mb.unit, mb.spec, mb.m_type,' +
@@ -220,7 +216,7 @@ class ReportMemoryMaterial {
                     '  LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' mb ON mbh.mb_id = mb.id ' +
                     '  WHERE mbh.tid = ? And mbh.mid = ?'+
                     '  ORDER By mb.order';
-                result = await this.ctx.app.mysql.query(sql, [tender_id, material.id]);
+                result = await this.ctx.app.mysql.query(sql, [material.tid, material.id]);
             }
         }
         this._completeMaterialGl(result, decimal);
@@ -229,26 +225,25 @@ class ReportMemoryMaterial {
         return result;
     }
 
-    async getMaterialGlDetail(tender_id, material_order, fields) {
-        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+    async getMaterialGlDetail(fields) {
+        const material = this.ctx.material;
         if (!material) return [];
 
         if (material.is_stage_self) {
-            return await this.ctx.service.materialList.getMaterialStageData(tender_id, material.id);
+            return await this.ctx.service.materialList.getMaterialStageData(material.tid, material.id);
         } else {
-            return await this.ctx.service.materialList.getMaterialData(tender_id, material.id);
+            return await this.ctx.service.materialList.getMaterialData(material.tid, material.id);
         }
     }
 
-    async getMaterialBills(tender_id, material_order, fields, showLevel) {
-        await this.ctx.service.tender.checkTender(tender_id);
-        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+    async getMaterialBills(fields, showLevel) {
+        const material = this.ctx.material;
         if (!material) return [];
 
         try {
-            const billsData = await this.ctx.service.ledger.getData(tender_id);
+            const billsData = await this.ctx.service.ledger.getData(material.tid);
             if (this._checkFieldsExist(fields, billsFields.stage)) {
-                const curStage = await this.ctx.service.stageBills.getStagesData(tender_id, material.stage_id);
+                const curStage = await this.ctx.service.stageBills.getStagesData(material.tid, material.stage_id);
                 this.ctx.helper.assignRelaData(billsData, [
                     {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil'], prefix: '', relaId: 'lid'}
                 ]);
@@ -265,14 +260,14 @@ class ReportMemoryMaterial {
         }
     }
 
-    async getMaterialPos(tender_id, material_order, fields) {
-        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+    async getMaterialPos(fields) {
+        const material = this.ctx.material;
         if (!material) return [];
 
         try {
-            const posData = await this.ctx.service.pos.getAllDataByCondition({ where: {tid: tender_id }});
+            const posData = await this.ctx.service.pos.getAllDataByCondition({ where: {tid: material.tid }});
             if (this._checkFieldsExist(fields, posFields.stage)) {
-                const curPosStage = await this.ctx.service.stagePos.getStagesData(tender_id, material.stage_id);
+                const curPosStage = await this.ctx.service.stagePos.getStagesData(material.tid, material.stage_id);
                 this.ctx.helper.assignRelaData(posData, [
                     {data: curPosStage, fields: ['contract_qty', 'qc_qty', 'qc_minus_qty', 'contract_expr', 'postil'], prefix: '', relaId: 'pid'}
                 ]);
@@ -288,23 +283,51 @@ class ReportMemoryMaterial {
         }
     }
 
-    getMaterialCalcQty(qtySource, info, is_join) {
-        let qty = 0;
-        switch(qtySource) {
-            case materialConst.qty_source_value.gather_qty: qty = info.gather_qty; break;
-            case materialConst.qty_source_value.contract_qty: qty = info.contract_qty; break;
-            case materialConst.qty_source_value.gather_minus_qty: qty = info.gather_minus_qty; break;
-            default: throw '未配置计量来源';
+    async getMaterialStage(fields) {
+        const material = this.ctx.material;
+        if (!material) return [];
+
+        if (material.is_stage_self) {
+            return await this.ctx.service.materialStage.getAllDataByCondition({ where: { mid: material.id } });
+        } else {
+            return [{
+                id: -1, tid: material.id, mid: material.id, sid: material.stage_id, order: material.stage_order,
+                m_tp: material.m_tp, m_tax_tp: material.m_tax_tp,
+            }];
         }
-        if (qtySource !== materialConst.qty_source_value.contract_qty && is_join === 2) {
-            qty = info.contract_qty;
+    }
+
+    getCommonData(params, tableName, fields, customDefine, customSelect) {
+        switch (tableName) {
+            case 'mem_project':
+                return this.ctx.service.project.getDataByCondition({ id: this.ctx.session.sessionProject.id });
+            case 'mem_tender':
+                return [this.ctx.tender.data];
+            case 'mem_tender_info':
+                return [this.ctx.tender.info];
+            case 'mem_material':
+                return [this.ctx.material];
+            case 'mem_material_audit':
+                return this.getMaterialAuditors();
+            case 'mem_material_gl':
+                return this.getMaterialGl(fields);
+            case 'mem_material_gl_detail':
+                return this.getMaterialGlDetail(fields);
+            case 'mem_material_bills':
+                return this.getMaterialBills(fields);
+            case 'mem_material_bills_filter':
+                return this.getMaterialBills(fields, true);
+            case 'mem_material_pos':
+                return this.getMaterialPos(fields);
+            case 'mem_material_stage':
+                return this.getMaterialStage(fields);
+            default:
+                return [];
         }
-        return qty;
     }
 
     async _getMaterialStageGatherBills(tender_id, stage_id, stage_order, stageSelf, stageIndex = 0) {
         const decimal = this.materialGatherBase.decimal;
-        //const billsData = this.ctx.helper.clone(this.materialGatherBase.billsData);
         const billsData = this.materialGatherBase.billsData;
         billsData.forEach(x => {
             for (const prop of ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty']) {
@@ -319,7 +342,6 @@ class ReportMemoryMaterial {
         billsTree.loadDatas(billsData);
         billsTree.calculateAll();
 
-        //const posData = this.ctx.helper.clone(this.materialGatherBase.posData);
         const posData = this.materialGatherBase.posData;
         posData.forEach(x => {
             for (const prop of ['contract_qty', 'qc_qty', 'qc_minus_qty']) {
@@ -385,29 +407,31 @@ class ReportMemoryMaterial {
         return [gatherUtil.gclList, gatherUtil.leafXmjs];
     }
 
-    async getMaterialGatherBills(tender_id, material_order) {
+    async getMaterialGatherBills() {
+        const material = this.ctx.material;
+        if (!material) return {};
+
         const materials = await this.ctx.service.material.getAllDataByCondition({
-            where: { tid: tender_id },
+            where: { tid: material.tid },
             orders: [['order', 'desc']],
         });
         if (materials.length === 0) return {};
 
-        const material = await this.ctx.service.material.getDataByCondition({ tid: tender_id, order: material_order });
         this.materialGatherBase = {};
         this.materialGatherBase.qtySource = material.qty_source;
         this.materialGatherBase.decimal = material.decimal ? JSON.parse(material.decimal) : materialConst.decimal;
         try {
             // 获取基础数据
-            this.materialGatherBase.billsData = await this.ctx.service.ledger.getData(tender_id);
-            this.materialGatherBase.posData = await this.ctx.service.pos.getPosData({ tid: tender_id });
+            this.materialGatherBase.billsData = await this.ctx.service.ledger.getData(material.tid);
+            this.materialGatherBase.posData = await this.ctx.service.pos.getPosData({ tid: material.tid });
             if (material.is_stage_self) {
-                this.materialGatherBase.materialGl = material_order === materials[0].order
-                    ? await this.ctx.service.materialList.getMaterialStageData(tender_id, material.id)
-                    : await this.ctx.service.materialList.getPreMaterialStageData(tender_id, material.id);
+                this.materialGatherBase.materialGl = material.order === materials[0].order
+                    ? await this.ctx.service.materialList.getMaterialStageData(material.tid, material.id)
+                    : await this.ctx.service.materialList.getPreMaterialStageData(material.tid, material.id);
             } else {
-                this.materialGatherBase.materialGl = material_order === materials[0].order
-                    ? await this.ctx.service.materialList.getMaterialData(tender_id, material.id)
-                    : await this.ctx.service.materialList.getPreMaterialData(tender_id, material.id);
+                this.materialGatherBase.materialGl = material.order === materials[0].order
+                    ? await this.ctx.service.materialList.getMaterialData(material.tid, material.id)
+                    : await this.ctx.service.materialList.getPreMaterialData(material.tid, material.id);
             }
             this.materialGatherBase.materialNotJoin = await this.ctx.service.materialListNotjoin.getAllDataByCondition({ where: { mid: material.id, type: 1 } });
             this.materialGatherBase.materialNotChange = await this.ctx.service.materialListNotjoin.getAllDataByCondition({ where: { mid: material.id, type: 2 } });
@@ -417,12 +441,12 @@ class ReportMemoryMaterial {
                 const stageIds = material.stage_id.split(',');
                 const stageOrders = material.s_order.split(',');
                 for (const [i, sid] of stageIds.entries()) {
-                    const [gclList, leafXmjs] = await this._getMaterialStageGatherBills(tender_id, sid, stageOrders[i], true, i + 1);
+                    const [gclList, leafXmjs] = await this._getMaterialStageGatherBills(material.tid, sid, stageOrders[i], true, i + 1);
                     mem_material_gather_bills.push(...gclList);
                     mem_material_gather_xmj.push(...leafXmjs);
                 }
             } else {
-                const [gclList, leafXmjs] = await this._getMaterialStageGatherBills(tender_id, material.stage_id, material.stage_order, false);
+                const [gclList, leafXmjs] = await this._getMaterialStageGatherBills(material.tid, material.stage_id, material.stage_order, false);
                 mem_material_gather_bills.push(...gclList);
                 mem_material_gather_xmj.push(...leafXmjs);
             }
@@ -433,19 +457,14 @@ class ReportMemoryMaterial {
         }
     }
 
-    async getMaterialStage(tender_id, material_order, fields) {
-        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
-        if (!material) return [];
-
-        if (material.is_stage_self) {
-            return await this.ctx.service.materialStage.getAllDataByCondition({ where: { mid: material.id } });
-        } else {
-            return [{
-                id: -1, tid: material.id, mid: material.id, sid: material.stage_id, order: material.stage_order,
-                m_tp: material.m_tp, m_tax_tp: material.m_tax_tp,
-            }];
+    async getBindData(params, key, fields, customDefine, customSelect) {
+        switch (key) {
+            case 'materialGather':
+                return await this.getMaterialGatherBills();
+            default:
+                return {};
         }
     }
 }
 
-module.exports = ReportMemoryMaterial;
+module.exports = rptMemChange;

+ 2 - 2
app/lib/rm/tender.js

@@ -14,8 +14,8 @@ const bindData = {
     gatherChange: ['mem_gather_change', 'mem_gather_change_bills'],
     fjChange: ['mem_fj_change_progress', 'mem_fj_change_sum'],
 };
-const BudgetSource = require('./budget');
-const MaterialSource = require('./material');
+const BudgetSource = require('./tender_budget');
+const MaterialSource = require('./tender_material');
 const rptCustomData = require('../rptCustomData');
 
 class rptMemPaymentSafe extends RptMemBase {

+ 451 - 0
app/lib/rm/tender_material.js

@@ -0,0 +1,451 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const materialConst = require('../../const/material');
+
+const Ledger = require('../../lib/ledger');
+
+const billsFields = (function () {
+    const cur = ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'gather_qty', 'gather_tp', 'postil'];
+    const pre = ['pre_contract_qty', 'pre_contract_tp', 'pre_qc_qty', 'pre_qc_tp', 'pre_gather_qty', 'pre_gather_tp'];
+    const end = ['end_contract_qty', 'end_contract_tp', 'end_qc_qty', 'end_qc_tp', 'end_gather_qty', 'end_gather_tp'];
+    const final = ['final_tp', 'final_ratio'];
+    const stageDgn = ['deal_dgn_qty1', 'deal_dgn_qty2', 'c_dgn_qty1', 'c_dgn_qty2'];
+
+    const stage = cur.concat(pre, end, final);
+    const stageEnd = pre.concat(end, final);
+    const bgl = ['qc_bgl_code'];
+    const leafXmj = ['leaf_xmj_id'];
+
+    return {cur, pre, end, final, stageDgn, stage, stageEnd, bgl, leafXmj};
+})();
+const posFields = (function () {
+    const cur = ['contract_qty', 'qc_qty', 'gather_qty', 'postil'];
+    const pre = ['pre_contract_qty', 'pre_qc_qty', 'pre_gather_qty'];
+    const end = ['end_contract_qty', 'end_qc_qty', 'end_gather_qty'];
+    const final = ['final_ratio'];
+
+    const stage = cur.concat(pre, end, final);
+    const stageEnd = pre.concat(end, final);
+    const bgl = ['qc_bgl_code'];
+
+    return {cur, pre, end, final, stage, stageEnd, bgl};
+})();
+
+class ReportMemoryMaterial {
+    constructor(ctx) {
+        this.ctx = ctx;
+    }
+
+    _getNewPos(updateFields) {
+        const helper = this.ctx.helper;
+        return new Ledger.pos({
+            id: 'id', ledgerId: 'lid',
+            updateFields: ['contract_qty', 'qc_qty', 'postil'],
+            calc: function (p) {
+                p.pre_gather_qty = helper.add(p.pre_contract_qty, p.pre_qc_qty);
+                p.gather_qty = helper.add(p.contract_qty, p.qc_qty);
+                p.gather_minus_qty = helper.add(p.gather_qty, p.qc_minus_qty);
+                p.end_contract_qty = helper.add(p.pre_contract_qty, p.contract_qty);
+                p.end_qc_qty = helper.add(p.pre_qc_qty, p.qc_qty);
+                p.end_gather_qty = helper.add(p.pre_gather_qty, p.gather_qty);
+            }
+        });
+    }
+
+    _getNewBillsTree(calcFields) {
+        return new Ledger.billsTree(this.ctx, {
+            id: 'ledger_id',
+            pid: 'ledger_pid',
+            order: 'order',
+            level: 'level',
+            rootId: -1,
+            keys: ['id', 'tender_id', 'ledger_id'],
+            stageId: 'id',
+            calcFields: calcFields || ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp'],
+            calc: function (node, helper) {
+                if (node.children && node.children.length === 0) {
+                    node.pre_gather_qty = helper.add(node.pre_contract_qty, node.pre_qc_qty);
+                    node.gather_qty = helper.add(node.contract_qty, node.qc_qty);
+                    node.gather_minus_qty = helper.add(node.gather_qty, node.qc_minus_qty);
+                    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.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
+                node.gather_tp = helper.add(node.contract_tp, node.qc_tp);
+                node.end_contract_tp = helper.add(node.pre_contract_tp, node.contract_tp);
+                node.end_qc_tp = helper.add(node.pre_qc_tp, node.qc_tp);
+                node.end_gather_tp = helper.add(node.pre_gather_tp, node.gather_tp);
+
+                node.final_tp = helper.add(node.total_price, node.end_qc_tp);
+                node.final_ratio = helper.mul(helper.div(node.end_gather_tp, node.final_tp, 4), 100);
+            }
+        });
+    }
+
+    _checkFieldsExist(source, check) {
+        for (const s of source) {
+            if (check.indexOf(s) >= 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    async getSelectMaterialAuditors(tid, material_order, fields) {
+        await this.ctx.service.material.checkMaterial(tid, material_order);
+        const auditors = await this.ctx.service.materialAudit.getFinalAuditGroup(this.ctx.material.id, this.ctx.material.curTimes);
+        const user = await this.ctx.service.projectAccount.getDataById(this.ctx.material.user_id);
+        const result = [{
+            aid: user.id,
+            name: user.name,
+            company: user.company,
+            role: user.role,
+            mobile: user.mobile,
+            telephone: user.telephone,
+            sign_path: user.sign_path,
+            opinion: user.opinion,
+            end_time: auditors && auditors.length > 0 ? auditors[0].begin_time : null,
+            sort: 0,
+            tp_data: this.ctx.material.tp_data,
+        }, ...auditors];
+        return result;
+    }
+
+    async getMaterial(tender_id, material_order, fields) {
+        const result = await this.ctx.service.material.getValidMaterials(tender_id);
+        if (this._checkFieldsExist(fields, ['checked_time'])) {
+            for (const r of result) {
+                const auditors = await this.ctx.service.materialAudit.getFinalAuditGroup(r.id, r.curTimes || r.times);
+                r.checked_time = !r.curTimes ? auditors[auditors.length - 1].end_time : null;
+            }
+        }
+        return result;
+    }
+
+    _completeMaterialGl(materialGl, decimal) {
+        const tTypeStr = [], mTypeStr = [];
+        for (const t of materialConst.t_type) {
+            tTypeStr[t.value] = t.text;
+        }
+        for (const m of materialConst.m_type) {
+            mTypeStr[m.value] = m.text;
+        }
+        for (const gl of materialGl) {
+            gl.tp = this.ctx.helper.mul(gl.quantity, gl.m_spread, decimal.tp);
+            gl.t_type_str = tTypeStr[gl.t_type];
+            gl.m_type_str = mTypeStr[gl.m_type];
+            gl.end_tp = this.ctx.helper.add(gl.tp, gl.pre_tp);
+        }
+    }
+
+    async _loadMaterialMonth(material, gl) {
+        const materialMonth = await this.ctx.service.materialMonth.getAllDataByCondition({
+            where: { mid: material.id },
+            orders: [['mb_id', 'asc'], ['yearmonth', 'asc']],
+        });
+
+        const month = this.ctx.helper._.uniq(materialMonth.map(x => { return x.yearmonth; }));
+        let g;
+        for (const mm of materialMonth) {
+            if (!g || g.id !== mm.mb_id) g = gl.find(x => { return mm.mb_id === x.id; });
+            if (!g.month_msg_tp) g.month_msg_tp = [];
+            if (!g.month) g.month = month.concat([]);
+            const index = month.indexOf(mm.yearmonth);
+            if (index >= 0) g.month_msg_tp[index] = mm.msg_tp;
+        }
+    }
+
+    async getMaterialGl(tender_id, material_order, fields) {
+        const materials = await this.ctx.service.material.getAllDataByCondition({
+            where: {tid: tender_id},
+            orders: [['order', 'desc']],
+        });
+        if (materials.length === 0) return [];
+
+        let result, material, decimal;
+        if (materials[0].order === material_order) {
+            material = materials[0];
+            decimal = material.decimal ? JSON.parse(material.decimal) : { qty: 3, up: 3, tp: 2 };
+            if (material.is_stage_self) {
+                const sql = 'SELECT msb.id, msb.tid, msb.mid, msb.ms_id, ms.sid, ms.`order` as s_order, mb.order, mb.t_type, mb.code, mb.name, mb.unit, mb.spec, mb.m_type,' +
+                    '    msb.quantity, mb.expr,' +
+                    '    mb.basic_price, mb.basic_times, ' +
+                    '    msb.msg_tp, msb.msg_times, msb.msg_spread, mb.m_up_risk, mb.m_down_risk, msb.m_spread, msb.m_tp, mb.pre_tp, msb.m_tax_tp, mb.tax_pre_tp, mb.origin, ' +
+                    '    msb.remark, msb.is_summary, mb.m_tax, mb.in_time, mb.origin' +
+                    `  FROM ${this.ctx.service.materialStageBills.tableName} msb` +
+                    `  LEFT JOIN ${this.ctx.service.materialBills.tableName} mb ON msb.mb_id = mb.id` +
+                    '  LEFT JOIN ' + this.ctx.service.materialStage.tableName + ' ms ON msb.ms_id = ms.id ' +
+                    `  WHERE msb.mid = ?` +
+                    '  ORDER By msb.ms_id, mb.order';
+                result = await this.ctx.app.mysql.query(sql, [material.id]);
+            } else {
+                result = await this.ctx.service.materialBills.getAllDataByCondition({
+                    where: {tid: tender_id}
+                });
+            }
+        } else {
+            material = this.ctx.helper._.find(materials, {order: material_order});
+            if (!material) return [];
+
+            decimal = material.decimal ? JSON.parse(material.decimal) : { tp: 2 };
+            if (material.is_stage_self) {
+                const sql = 'SELECT msb.id, msb.tid, msb.mid, msb.ms_id, ms.sid, ms.`order` as s_order, mb.order, mb.t_type, mb.code, mb.name, mb.unit, mb.spec, mb.m_type,' +
+                    '    msb.quantity, mbh.expr,' +
+                    '    mb.basic_price, mb.basic_times, ' +
+                    '    msb.msg_tp, msb.msg_times, msb.msg_spread, mbh.m_up_risk, mbh.m_down_risk, msb.m_spread, msb.m_tp, mbh.pre_tp, msb.m_tax_tp, mbh.tax_pre_tp, mbh.origin, ' +
+                    '    msb.remark, msb.is_summary, mbh.m_tax, mb.in_time, mbh.origin' +
+                    `  FROM ${this.ctx.service.materialStageBills.tableName} msb` +
+                    '  LEFT JOIN ' + this.ctx.service.materialBillsHistory.tableName + ' mbh ON msb.mb_id = mbh.mb_id AND msb.mid = mbh.mid' +
+                    '  LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' mb ON msb.mb_id = mb.id ' +
+                    '  LEFT JOIN ' + this.ctx.service.materialStage.tableName + ' ms ON msb.ms_id = ms.id ' +
+                    '  WHERE msb.mid = ?'+
+                    '  ORDER By msb.ms_id, mb.order';
+                result = await this.ctx.app.mysql.query(sql, [material.id]);
+            } else {
+                const sql = 'SELECT mb.id, mb.tid, mb.mid, mb.order, mb.t_type, mb.code, mb.name, mb.unit, mb.spec, mb.m_type,' +
+                    '    mbh.quantity, mbh.expr,' +
+                    '    mb.basic_price, mb.basic_times, ' +
+                    '    mbh.msg_tp, mbh.msg_times, mbh.msg_spread, mbh.m_up_risk, mbh.m_down_risk, mbh.m_spread, mbh.m_tp, mbh.pre_tp, mbh.m_tax_tp, mbh.tax_pre_tp, mbh.origin, ' +
+                    '    mb.remark, mb.is_summary, mbh.m_tax, mb.in_time, mbh.origin' +
+                    '  FROM ' + this.ctx.service.materialBillsHistory.tableName + ' mbh ' +
+                    '  LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' mb ON mbh.mb_id = mb.id ' +
+                    '  WHERE mbh.tid = ? And mbh.mid = ?'+
+                    '  ORDER By mb.order';
+                result = await this.ctx.app.mysql.query(sql, [tender_id, material.id]);
+            }
+        }
+        this._completeMaterialGl(result, decimal);
+
+        if (this._checkFieldsExist(fields, ['month_msg_tp', 'month'])) await this._loadMaterialMonth(material, result);
+        return result;
+    }
+
+    async getMaterialGlDetail(tender_id, material_order, fields) {
+        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+        if (!material) return [];
+
+        if (material.is_stage_self) {
+            return await this.ctx.service.materialList.getMaterialStageData(tender_id, material.id);
+        } else {
+            return await this.ctx.service.materialList.getMaterialData(tender_id, material.id);
+        }
+    }
+
+    async getMaterialBills(tender_id, material_order, fields, showLevel) {
+        await this.ctx.service.tender.checkTender(tender_id);
+        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+        if (!material) return [];
+
+        try {
+            const billsData = await this.ctx.service.ledger.getData(tender_id);
+            if (this._checkFieldsExist(fields, billsFields.stage)) {
+                const curStage = await this.ctx.service.stageBills.getStagesData(tender_id, material.stage_id);
+                this.ctx.helper.assignRelaData(billsData, [
+                    {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil'], prefix: '', relaId: 'lid'}
+                ]);
+            }
+
+            const billsTree = this._getNewBillsTree();
+            billsTree.loadDatas(billsData);
+            billsTree.calculateAll();
+
+            return showLevel ? billsTree.getDefaultDatasByLevel(this.ctx.tender.rpt_show_level) : billsTree.getDefaultDatas();
+        } catch(err) {
+            this.ctx.helper.log(err);
+            return [];
+        }
+    }
+
+    async getMaterialPos(tender_id, material_order, fields) {
+        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+        if (!material) return [];
+
+        try {
+            const posData = await this.ctx.service.pos.getAllDataByCondition({ where: {tid: tender_id }});
+            if (this._checkFieldsExist(fields, posFields.stage)) {
+                const curPosStage = await this.ctx.service.stagePos.getStagesData(tender_id, material.stage_id);
+                this.ctx.helper.assignRelaData(posData, [
+                    {data: curPosStage, fields: ['contract_qty', 'qc_qty', 'qc_minus_qty', 'contract_expr', 'postil'], prefix: '', relaId: 'pid'}
+                ]);
+            }
+            const pos = this._getNewPos();
+            pos.loadDatas(posData);
+            pos.calculateAll();
+
+            return pos.getDatas();
+        } catch (err) {
+            this.ctx.helper.log(err);
+            return [];
+        }
+    }
+
+    getMaterialCalcQty(qtySource, info, is_join) {
+        let qty = 0;
+        switch(qtySource) {
+            case materialConst.qty_source_value.gather_qty: qty = info.gather_qty; break;
+            case materialConst.qty_source_value.contract_qty: qty = info.contract_qty; break;
+            case materialConst.qty_source_value.gather_minus_qty: qty = info.gather_minus_qty; break;
+            default: throw '未配置计量来源';
+        }
+        if (qtySource !== materialConst.qty_source_value.contract_qty && is_join === 2) {
+            qty = info.contract_qty;
+        }
+        return qty;
+    }
+
+    async _getMaterialStageGatherBills(tender_id, stage_id, stage_order, stageSelf, stageIndex = 0) {
+        const decimal = this.materialGatherBase.decimal;
+        //const billsData = this.ctx.helper.clone(this.materialGatherBase.billsData);
+        const billsData = this.materialGatherBase.billsData;
+        billsData.forEach(x => {
+            for (const prop of ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty']) {
+                x[prop] = undefined;
+            }
+        });
+        const curStageBills = await this.ctx.service.stageBills.getStagesData(tender_id, stage_id);
+        this.ctx.helper.assignRelaData(billsData, [
+            { data: curStageBills, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: '', relaId: 'lid' },
+        ]);
+        const billsTree = this._getNewBillsTree();
+        billsTree.loadDatas(billsData);
+        billsTree.calculateAll();
+
+        //const posData = this.ctx.helper.clone(this.materialGatherBase.posData);
+        const posData = this.materialGatherBase.posData;
+        posData.forEach(x => {
+            for (const prop of ['contract_qty', 'qc_qty', 'qc_minus_qty']) {
+                x[prop] = undefined;
+            }
+        });
+        const curStage = await this.ctx.service.stagePos.getStagesData(tender_id, stage_id);
+        this.ctx.helper.assignRelaData(posData, [
+            { data: curStage, fields: ['contract_qty', 'qc_qty', 'qc_minus_qty'], prefix: '', relaId: 'pid' },
+        ]);
+        const pos = this._getNewPos();
+        pos.loadDatas(posData);
+        pos.calculateAll();
+
+        const gclGatherModel = require('../gcl_gather').gclGather;
+        const gatherUtil = new gclGatherModel(this.ctx);
+        gatherUtil.gatherObj(billsTree, pos);
+
+        const materialGl = stageSelf
+            ? this.materialGatherBase.materialGl.filter(x => { return x.sid === parseInt(stage_id); })
+            : this.materialGatherBase.materialGl;
+        if (stageIndex) materialGl.forEach(x => { x.s_index = stageIndex });
+        const materialNotJoin = this.materialGatherBase.materialNotJoin;
+        const materialNotChange = this.materialGatherBase.materialNotChange;
+
+        const helper = this.ctx.helper;
+
+        for (const g of gatherUtil.gclList) {
+            if (!g.contract_qty && !g.qc_qty && !g.qc_minus_qty) continue;
+            g.sid = stage_id;
+            g.sorder = stage_order;
+            g.s_index = stageIndex;
+            g.jiacha = 0;
+            g.jiacha_qty = 0;
+            for (const x of g.leafXmjs) {
+                x.sid = stage_id;
+                x.sorder = stage_order;
+                x.s_index = stageIndex;
+                x.jiacha = 0;
+                const mnj = materialNotJoin.find(m => {
+                    return m.gcl_id === x.org_gcl_id && m.xmj_id === x.id && (x.mx_id && x.mx_id !== x.id  ? x.mx_id === m.mx_id : true);
+                });
+                x.is_join = !mnj;
+                const mnc = materialNotChange.find(m => {
+                    return m.gcl_id === x.org_gcl_id && m.xmj_id === x.id && (x.mx_id && x.mx_id !== x.id  ? x.mx_id === m.mx_id : true);
+                });
+                x.is_change = mnc ? 2 : 1;
+                const list = materialGl.filter(gl => {
+                    return gl.gcl_id === x.org_gcl_id && gl.xmj_id === x.id && (x.mx_id && x.mx_id !== x.id ? x.mx_id === gl.mx_id : true);
+                });
+                list.forEach(l => { l.gather_gcl_id = x.gcl_id});
+
+                if (mnj) continue;
+                x.jiacha_qty = this.getMaterialCalcQty(this.materialGatherBase.qtySource, x, x.is_change);
+                for (const l of list) {
+                    x.jiacha = helper.add(x.jiacha, helper.mul(helper.mul(x.jiacha_qty, l.quantity), l.m_spread));
+                }
+                x.jiacha = helper.round(x.jiacha, decimal.tp);
+                g.jiacha = helper.add(g.jiacha, x.jiacha);
+                g.jiacha_qty = helper.add(g.jiacha_qty, x.jiacha_qty);
+            }
+        }
+        return [gatherUtil.gclList, gatherUtil.leafXmjs];
+    }
+
+    async getMaterialGatherBills(tender_id, material_order) {
+        const materials = await this.ctx.service.material.getAllDataByCondition({
+            where: { tid: tender_id },
+            orders: [['order', 'desc']],
+        });
+        if (materials.length === 0) return {};
+
+        const material = await this.ctx.service.material.getDataByCondition({ tid: tender_id, order: material_order });
+        this.materialGatherBase = {};
+        this.materialGatherBase.qtySource = material.qty_source;
+        this.materialGatherBase.decimal = material.decimal ? JSON.parse(material.decimal) : materialConst.decimal;
+        try {
+            // 获取基础数据
+            this.materialGatherBase.billsData = await this.ctx.service.ledger.getData(tender_id);
+            this.materialGatherBase.posData = await this.ctx.service.pos.getPosData({ tid: tender_id });
+            if (material.is_stage_self) {
+                this.materialGatherBase.materialGl = material_order === materials[0].order
+                    ? await this.ctx.service.materialList.getMaterialStageData(tender_id, material.id)
+                    : await this.ctx.service.materialList.getPreMaterialStageData(tender_id, material.id);
+            } else {
+                this.materialGatherBase.materialGl = material_order === materials[0].order
+                    ? await this.ctx.service.materialList.getMaterialData(tender_id, material.id)
+                    : await this.ctx.service.materialList.getPreMaterialData(tender_id, material.id);
+            }
+            this.materialGatherBase.materialNotJoin = await this.ctx.service.materialListNotjoin.getAllDataByCondition({ where: { mid: material.id, type: 1 } });
+            this.materialGatherBase.materialNotChange = await this.ctx.service.materialListNotjoin.getAllDataByCondition({ where: { mid: material.id, type: 2 } });
+
+            const mem_material_gather_bills = [], mem_material_gather_xmj = [];
+            if (material.is_stage_self) {
+                const stageIds = material.stage_id.split(',');
+                const stageOrders = material.s_order.split(',');
+                for (const [i, sid] of stageIds.entries()) {
+                    const [gclList, leafXmjs] = await this._getMaterialStageGatherBills(tender_id, sid, stageOrders[i], true, i + 1);
+                    mem_material_gather_bills.push(...gclList);
+                    mem_material_gather_xmj.push(...leafXmjs);
+                }
+            } else {
+                const [gclList, leafXmjs] = await this._getMaterialStageGatherBills(tender_id, material.stage_id, material.stage_order, false);
+                mem_material_gather_bills.push(...gclList);
+                mem_material_gather_xmj.push(...leafXmjs);
+            }
+            return {mem_material_gather_bills, mem_material_gather_xmj, mem_material_gather_gl: this.materialGatherBase.materialGl};
+        } catch (err) {
+            this.ctx.log(err);
+            return {};
+        }
+    }
+
+    async getMaterialStage(tender_id, material_order, fields) {
+        const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+        if (!material) return [];
+
+        if (material.is_stage_self) {
+            return await this.ctx.service.materialStage.getAllDataByCondition({ where: { mid: material.id } });
+        } else {
+            return [{
+                id: -1, tid: material.id, mid: material.id, sid: material.stage_id, order: material.stage_order,
+                m_tp: material.m_tp, m_tax_tp: material.m_tax_tp,
+            }];
+        }
+    }
+}
+
+module.exports = ReportMemoryMaterial;

+ 24 - 16
app/service/report.js

@@ -9,7 +9,7 @@
  */
 
 const BudgetSource = require('../lib/rm/tender_budget');
-const MaterialSource = require('../lib/rm/material');
+const MaterialSource = require('../lib/rm/tender_material');
 
 const rptCustomData = require('../lib/rptCustomData');
 const bindData = {
@@ -552,42 +552,50 @@ module.exports = app => {
 
         // params = { sp_id: int, budget_id: int }
         async budget(params, sourceFilters, memFieldKeys, customDefine, customSelect) {
-            const RptPayment = require('../lib/rm/budget');
-            const rptPayment = new RptPayment(this.ctx);
+            const RptBudget = require('../lib/rm/budget');
+            const rptBudget = new RptBudget(this.ctx);
 
-            return rptPayment.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
+            return rptBudget.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
         }
 
         // params = { change_id: uuid }
         async change(params, sourceFilters, memFieldKeys, customDefine, customSelect) {
-            const RptPayment = require('../lib/rm/change');
-            const rptPayment = new RptPayment(this.ctx);
+            const RptChange = require('../lib/rm/change');
+            const rptChange = new RptChange(this.ctx);
 
-            return rptPayment.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
+            return rptChange.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
         }
 
         // params = { change_plan_id: int }
         async change_plan(params, sourceFilters, memFieldKeys, customDefine, customSelect) {
-            const RptPayment = require('../lib/rm/change_plan');
-            const rptPayment = new RptPayment(this.ctx);
+            const RptChangePlan = require('../lib/rm/change_plan');
+            const rptChangePlan = new RptChangePlan(this.ctx);
 
-            return rptPayment.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
+            return rptChangePlan.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
         }
 
         // params = { change_project_id: int }
         async change_project(params, sourceFilters, memFieldKeys, customDefine, customSelect) {
-            const RptPayment = require('../lib/rm/change_project');
-            const rptPayment = new RptPayment(this.ctx);
+            const RptChangeProj = require('../lib/rm/change_project');
+            const rptChangeProj = new RptChangeProj(this.ctx);
 
-            return rptPayment.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
+            return rptChangeProj.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
         }
 
         // params = { change_apply_id: int }
         async change_apply(params, sourceFilters, memFieldKeys, customDefine, customSelect) {
-            const RptPayment = require('../lib/rm/change_apply');
-            const rptPayment = new RptPayment(this.ctx);
+            const RptChangeApply = require('../lib/rm/change_apply');
+            const rptChangeApply = new RptChangeApply(this.ctx);
 
-            return rptPayment.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
+            return rptChangeApply.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
+        }
+
+        // params = { material_id: int }
+        async material(params, sourceFilters, memFieldKeys, customDefine, customSelect) {
+            const RptMaterial = require('../lib/rm/material');
+            const rptMaterial = new RptMaterial(this.ctx);
+
+            return rptMaterial.getReportData(params, sourceFilters, memFieldKeys, customDefine, customSelect);
         }
 
         async getReportData(source_type, params, sourceFilters, memFieldKeys, customDefine, customSelect) {