| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 | 'use strict';/** * * * @author Mai * @date * @version */const itemsPre = 'id_';const BillsTree = require('./ledger').billsTree;const auditConst = require('../const/audit');class FinalTree extends BillsTree {    constructor(ctx, setting) {        super(ctx, setting);        this._newId = 1;    }    get newId() {        return this._newId++;    }    loadNode(node, parent, loadFun) {        if (node.b_code) return;        const siblings = parent ? parent.children : this.children;        let cur = siblings.find(function (x) {            return x.code === node.code && x.name === node.name;        });        if (!cur) {            cur = { children: [], code: node.code || '', name: node.name || '', unit: node.unit || '' };            const id = this.newId;            cur[this.setting.id] = id;            cur[this.setting.pid] = parent ? parent[this.setting.id] : this.setting.rootId;            cur[this.setting.fullPath] = parent ? parent[this.setting.fullPath] + '-' + id : '' + id;            cur[this.setting.level] = parent ? parent[this.setting.level] + 1 : 1;            cur[this.setting.order] = siblings.length + 1;            siblings.push(cur);            this.datas.push(cur);        }        loadFun(cur, node);        for (const c of node.children) {            this.loadNode(c, cur, loadFun);        }    }    loadTree(tree, loadFun) {        for (const node of tree.children) {            this.loadNode(node, null, loadFun);        }    }    generateSortNodes() {        const self = this;        const addSortNode = function (node) {            self.nodes.push(node);            for (const c of node.children) {                addSortNode(c);            }        };        this.nodes = [];        for (const n of this.children) {            addSortNode(n);        }    }    afterLoad(fun) {        for (const d of this.datas) {            fun && fun(d);            d.is_leaf = d.children.length === 0;            d.expanded = true;            d.visible = true;            this.items[itemsPre + d[this.setting.id]] = d;        }        this.generateSortNodes();    }    resortChildrenByCustom(fun) {        for (const n of this.nodes) {            if (n.children && n.children.length > 1) {                n.children.sort(fun);                n.children.forEach((x, y) => { x.order = y + 1; });            }        }        this.generateSortNodes();    }}class BudgetFinal {    constructor (ctx) {        this.ctx = ctx;        this.budgetSetting = { id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price'] };        this.tenderSetting = { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price', 'end_gather_tp', 'end_contract_tp', 'end_qc_tp'] };        this.finalTree = new FinalTree(this.ctx, { id: 'id', pid: 'pid', order: 'order', level: 'level', fullPath: 'full_path', rootId: -1 });    }    async _loadGu(budget) {        const helper = this.ctx.helper;        const gu = await this.ctx.service.budgetGu.getData(budget.id);        const guTree = new BillsTree(this.ctx, { id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price'] });        guTree.loadDatas(gu);        guTree.calculateAll();        this.finalTree.loadTree(guTree, function (cur, source) {            cur.base = true;            cur.gu_dgn_qty1 = helper.add(cur.gu_dgn_qty1, source.dgn_qty1);            cur.gu_dgn_qty2 = helper.add(cur.gu_dgn_qty2, source.dgn_qty2);            cur.gu_tp = helper.add(cur.gu_tp, source.total_price);        });    }    async _loadGai(budget) {        const helper = this.ctx.helper;        const gai = await this.ctx.service.budgetGai.getData(budget.id);        const gaiTree = new BillsTree(this.ctx, { id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price'] });        gaiTree.loadDatas(gai);        gaiTree.calculateAll();        this.finalTree.loadTree(gaiTree, function (cur, source) {            cur.base = true;            cur.gai_dgn_qty1 = helper.add(cur.gai_dgn_qty1, source.dgn_qty1);            cur.gai_dgn_qty2 = helper.add(cur.gai_dgn_qty2, source.dgn_qty2);            cur.gai_tp = helper.add(cur.gai_tp, source.total_price);        });    }    async _loadYu(budget) {        const helper = this.ctx.helper;        const yu = await this.ctx.service.budgetYu.getData(budget.id);        const yuTree = new BillsTree(this.ctx, { id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price'] });        yuTree.loadDatas(yu);        yuTree.calculateAll();        this.finalTree.loadTree(yuTree, function (cur, source) {            cur.base = true;            cur.yu_dgn_qty1 = helper.add(cur.yu_dgn_qty1, source.dgn_qty1);            cur.yu_dgn_qty2 = helper.add(cur.yu_dgn_qty2, source.dgn_qty2);            cur.yu_tp = helper.add(cur.yu_tp, source.total_price);        });    }    async _loadZb(budget) {        const helper = this.ctx.helper;        const zb = await this.ctx.service.budgetZb.getData(budget.id);        const zbTree = new BillsTree(this.ctx, { id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, calcFields: ['total_price'] });        zbTree.loadDatas(zb);        zbTree.calculateAll();        this.finalTree.loadTree(zbTree, function (cur, source) {            cur.base = true;            cur.zb_dgn_qty1 = helper.add(cur.zb_dgn_qty1, source.dgn_qty1);            cur.zb_dgn_qty2 = helper.add(cur.zb_dgn_qty2, source.dgn_qty2);            cur.zb_tp = helper.add(cur.zb_tp, source.total_price);        });    }    async _loadTender(id) {        const helper = this.ctx.helper;        const bills = await this.ctx.service.ledger.getFinalData(id, ['id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf',            'code', 'b_code', 'name', 'unit', 'dgn_qty1', 'dgn_qty2', 'total_price']);        const dgnData = await this.ctx.service.stageBillsDgn.getDgnData(id);        // 使用最新一期对比        const stage = await this.ctx.service.stage.getLastestStage(id);        if (!stage) {            helper.assignRelaData(bills, [                { data: dgnData, fields: ['deal_dgn_qty1', 'deal_dgn_qty2', 'c_dgn_qty1', 'c_dgn_qty2'], prefix: '', relaId: 'id' },            ]);            this.final.tender_info.push({ id, stageCount: 0 });        } else if (stage.status === auditConst.stage.status.checked) {            const finalBills = await this.ctx.service.stageBillsFinal.getFinalData({id}, stage.order);            helper.assignRelaData(bills, [                { data: finalBills, fields: ['contract_tp', 'qc_tp'], prefix: 'end_', relaId: 'lid' },                { data: dgnData, fields: ['deal_dgn_qty1', 'deal_dgn_qty2', 'c_dgn_qty1', 'c_dgn_qty2'], prefix: '', relaId: 'id' },            ]);            bills.forEach(b => {                b.end_gather_tp = helper.add(b.end_qc_tp, b.end_contract_tp);            });            this.final.tender_info.push({ id, stageOrder: stage.order });        } else {            await this.ctx.service.stage.doCheckStage(stage);            const curBills = stage.readOnly                ? await this.ctx.service.stageBills.getAuditorStageData2(id, stage.id, stage.curTimes, stage.curOrder)                : await this.ctx.service.stageBills.getLastestStageData2(id, stage.id);            const preBills = stage.preCheckedStage ? await this.ctx.service.stageBillsFinal.getFinalData({id}, stage.preCheckedStage.order) : [];            const bpcData = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: stage.id } });            helper.assignRelaData(bills, [                { data: curBills, fields: ['contract_tp', 'qc_tp'], prefix: '', relaId: 'lid' },                { data: preBills, fields: ['contract_tp', 'qc_tp'], prefix: 'pre_', relaId: 'lid' },                { data: dgnData, fields: ['deal_dgn_qty1', 'deal_dgn_qty2', 'c_dgn_qty1', 'c_dgn_qty2'], prefix: '', relaId: 'id' },                { data: bpcData, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'org_price'], prefix: '', relaId: 'lid' },            ]);            bills.forEach(b => {                b.end_contract_tp = helper.sum([b.contract_tp, b.pre_contract_tp, b.contract_pc_tp]);                b.end_qc_tp = helper.sum([b.qc_tp, b.pre_qc_tp, b.qc_pc_tp]);                b.end_gather_tp = helper.sum([b.qc_tp, b.contract_tp, b.pre_qc_tp, b.pre_contract_tp, b.pc_tp]);            });            this.final.tender_info.push({ id, stageOrder: stage.order, stageStatus: stage.status, stageFlow: stage.curTimes + '-' + stage.curOrder });        }        const tree = new BillsTree(this.ctx, this.tenderSetting);        tree.loadDatas(bills);        tree.calculateAll();        this.finalTree.loadTree(tree, function (cur, source) {            cur.total_price = helper.add(cur.total_price, source.total_price);            cur.dgn_qty1 = helper.add(cur.dgn_qty1, source.dgn_qty1);            cur.dgn_qty2 = helper.add(cur.dgn_qty2, source.dgn_qty2);            cur.deal_dgn_qty1 = helper.add(cur.deal_dgn_qty1, source.deal_dgn_qty1);            cur.deal_dgn_qty2 = helper.add(cur.deal_dgn_qty2, source.deal_dgn_qty2);            cur.c_dgn_qty1 = helper.add(cur.c_dgn_qty1, source.c_dgn_qty1);            cur.c_dgn_qty2 = helper.add(cur.c_dgn_qty2, source.c_dgn_qty2);            cur.final_dgn_qty1 = helper.sum([cur.final_dgn_qty1, source.deal_dgn_qty1, source.c_dgn_qty1]);            cur.final_dgn_qty2 = helper.sum([cur.final_dgn_qty2, source.deal_dgn_qty2, source.c_dgn_qty2]);            cur.final_contract_tp = helper.add(cur.final_contract_tp, source.end_contract_tp);            cur.final_qc_tp = helper.add(cur.final_qc_tp, source.end_qc_tp);            cur.final_tp = helper.add(cur.final_tp, source.end_gather_tp);        });    }    async _afterLoad() {        const helper = this.ctx.helper;        const checkGaiExist = this.finalTree.datas.findIndex(x => {            if (x.gai_tp || x.gai_dgn_qty1 || x.gai_dgn_qty2) return true;        }) >= 0;        this.finalTree.afterLoad(node => {            node.dgn_price = helper.div(node.total_price, node.dgn_qty1, 2);            node.dgn_qty = node.dgn_qty1                ? (node.dgn_qty2 ? node.dgn_qty1 + '/' + node.dgn_qty2 : node.dgn_qty1)                : (node.dgn_qty2 ? '/' + node.dgn_qty2 : '');            node.gu_dgn_price = helper.div(node.gu_tp, node.gu_dgn_qty1, 2);            node.gu_dgn_qty = node.gu_dgn_qty1                ? (node.gu_dgn_qty2 ? node.gu_dgn_qty1 + '/' + node.gu_dgn_qty2 : node.gu_dgn_qty1 + '')                : (node.gu_dgn_qty2 ? '/' + node.gu_dgn_qty2 : '');            node.gai_dgn_price = helper.div(node.gai_tp, node.gai_dgn_qty1, 2);            node.gai_dgn_qty = node.gai_dgn_qty1                ? (node.gai_dgn_qty2 ? node.gai_dgn_qty1 + '/' + node.gai_dgn_qty2 : node.gai_dgn_qty1 + '')                : (node.gai_dgn_qty2 ? '/' + node.gai_dgn_qty2 : '');            node.yu_dgn_price = helper.div(node.yu_tp, node.yu_dgn_qty1, 2);            node.yu_dgn_qty = node.yu_dgn_qty1                ? (node.yu_dgn_qty2 ? node.yu_dgn_qty1 + '/' + node.yu_dgn_qty2 : node.yu_dgn_qty1 + '')                : (node.yu_dgn_qty2 ? '/' + node.yu_dgn_qty2 : '');            node.zb_dgn_price = helper.div(node.zb_tp, node.zb_dgn_qty1, 2);            node.zb_dgn_qty = node.zb_dgn_qty1                ? (node.zb_dgn_qty2 ? node.zb_dgn_qty1 + '/' + node.zb_dgn_qty2 : node.zb_dgn_qty1 + '')                : (node.zb_dgn_qty2 ? '/' + node.zb_dgn_qty2 : '');            node.final_dgn_price = helper.div(node.final_tp, node.final_dgn_qty1, 2);            node.final_dgn_qty = node.final_dgn_qty1                ? (node.final_dgn_qty2 ? node.final_dgn_qty1 + '/' + node.final_dgn_qty2 : node.final_dgn_qty1)                : (node.final_dgn_qty2 ? '/' + node.final_dgn_qty2 : '');            if (checkGaiExist) {                node.grow_dgn_qty1 = helper.mul(helper.div(helper.sub(node.final_dgn_qty1, node.gai_dgn_qty1), node.gai_dgn_qty1, 4), 100);                node.grow_dgn_qty2 = helper.mul(helper.div(helper.sub(node.final_dgn_qty2, node.gai_dgn_qty2), node.gai_dgn_qty2, 4), 100);                node.grow_dgn_qty = node.grow_dgn_qty1                    ? (node.grow_dgn_qty2 ? node.grow_dgn_qty1 + '/' + node.grow_dgn_qty2 : node.grow_dgn_qty1)                    : (node.grow_dgn_qty2 ? '/' + node.grow_dgn_qty2 : '');                node.grow_tp = helper.mul(helper.div(helper.sub(node.final_tp, node.gai_tp), node.gai_tp, 4), 100);            } else {                node.grow_dgn_qty1 = helper.mul(helper.div(helper.sub(node.final_dgn_qty1, node.yu_dgn_qty1), node.yu_dgn_qty1, 4), 100);                node.grow_dgn_qty2 = helper.mul(helper.div(helper.sub(node.final_dgn_qty2, node.yu_dgn_qty2), node.yu_dgn_qty2, 4), 100);                node.grow_dgn_qty = node.grow_dgn_qty1                    ? (node.grow_dgn_qty2 ? node.grow_dgn_qty1 + '/' + node.grow_dgn_qty2 : node.grow_dgn_qty1)                    : (node.grow_dgn_qty2 ? '/' + node.grow_dgn_qty2 : '');                node.grow_tp = helper.mul(helper.div(helper.sub(node.final_tp, node.yu_tp), node.yu_tp, 4), 100);            }        });        this.finalTree.resortChildrenByCustom(function (x, y) {            const iCode = helper.compareCode(x.code, y.code);            if (iCode) return iCode;            if (!x.name) return -1;            if (!y.name) return 1;            return x.name.localeCompare(y.name);        });    }    getFinalData() {        const data = [], ctx = this.ctx, bid = this.budget.id, final_id = this.final.id;        this.finalTree.datas.forEach(x => {            data.push({                id: ctx.app.uuid.v4(), bid, final_id,                tree_id: x.id, tree_pid: x.pid, order: x.order, level: x.level, full_path: x.full_path, is_leaf: x.children && x.children.length > 0 ? 0 : 1,                code: x.code || '', name: x.name || '', unit: x.unit || '',                gu_dgn_qty1: x.gu_dgn_qty1 || 0, gu_dgn_qty2: x.gu_dgn_qty2 || 0, gu_dgn_qty: x.gu_dgn_qty || '', gu_dgn_price: x.gu_dgn_price || 0, gu_tp: x.gu_tp || 0,                gai_dgn_qty1: x.gai_dgn_qty1 || 0, gai_dgn_qty2: x.gai_dgn_qty2 || 0, gai_dgn_qty: x.gai_dgn_qty || '', gai_dgn_price: x.gai_dgn_price || 0, gai_tp: x.gai_tp || 0,                yu_dgn_qty1: x.yu_dgn_qty1 || 0, yu_dgn_qty2: x.yu_dgn_qty2 || 0, yu_dgn_qty: x.yu_dgn_qty || '', yu_dgn_price: x.yu_dgn_price || 0, yu_tp: x.yu_tp || 0,                zb_dgn_qty1: x.zb_dgn_qty1 || 0, zb_dgn_qty2: x.zb_dgn_qty2 || 0, zb_dgn_qty: x.zb_dgn_qty || '', zb_dgn_price: x.zb_dgn_price || 0, zb_tp: x.zb_tp || 0,                dgn_qty1: x.dgn_qty1 || 0, dgn_qty2: x.dgn_qty2 || 0, total_price: x.total_price || 0,                dgn_price: x.dgn_price || 0, dgn_qty: x.dgn_qty || '',                deal_dgn_qty1: x.deal_dgn_qty1 || 0, deal_dgn_qty2: x.deal_dgn_qty2 || 0, c_dgn_qty1: x.c_dgn_qty1 || 0, c_dgn_qty2: x.c_dgn_qty2 || 0,                final_dgn_qty1: x.final_dgn_qty1 || 0, final_dgn_qty2: x.final_dgn_qty2 || 0, final_tp: x.final_tp || 0,                final_contract_tp: x.final_contract_tp || 0, final_qc_tp: x.final_qc_tp || 0,                final_dgn_price: x.final_dgn_price || 0, final_dgn_qty: x.final_dgn_qty || '',                grow_dgn_qty1: x.grow_dgn_qty1 || 0, grow_dgn_qty2: x.grow_dgn_qty2 || 0, grow_dgn_qty: x.grow_dgn_qty || '', grow_tp: x.grow_tp || 0,            })        });        return data;    }    async doFinal(budget, final) {        this.budget = budget;        this.final = final;        await this._loadGai(budget);        await this._loadGu(budget);        await this._loadYu(budget);        await this._loadZb(budget);        for (const t of final.tender) {            await this._loadTender(t);        }        this._afterLoad();        return this.getFinalData();    }}module.exports = BudgetFinal;
 |