Bläddra i källkod

自动调用全部变更令

MaiXinRong 2 år sedan
förälder
incheckning
d2fb9db697

+ 38 - 0
app/controller/stage_controller.js

@@ -576,6 +576,44 @@ module.exports = app => {
                 ctx.body = { err: 1, msg: err.toString(), data: null };
             }
         }
+
+        /**
+         * 调用变更令 (Ajax-Post)
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async autoUseChange(ctx) {
+            try {
+                this._checkStageCanModify(ctx);
+
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.autoType) throw '参数错误';
+
+                let result;
+                switch (data.autoType) {
+                    case 'bills':
+                        if (!data.cid || !data.cbid) throw '参数错误';
+                        result = await ctx.service.stageChange.autoUseChangeBills(this.ctx.tender, this.ctx.stage, data.bills);
+                        result.change = { target: [] };
+                        for (const b of data.bills) {
+                            result.change.push({ lid: b.lid, pid: b.pid });
+                        }
+                        result.change.data = await ctx.service.stageChange.getLastestStageData(ctx.tender.id,
+                            ctx.stage.id, data.target.pos.lid, data.target.pos.id);
+                        break;
+                    case 'all':
+                        result = await ctx.service.stageChange.autoUseAllChange(this.ctx.tender, this.ctx.stage);
+                        break;
+                    default: throw '参数错误';
+                }
+                await ctx.service.stage.updateCheckCalcFlag(ctx.stage, true);
+                await ctx.service.stage.updateCacheTime(ctx.stage.id);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
         /**
          * 查询变更令 明细数据(包括附件、变更清单、累计使用情况、本期使用情况) (Ajax-Post)
          * @param ctx

+ 0 - 1
app/public/js/shares/cs_tools.js

@@ -1172,7 +1172,6 @@ const showSelectTab = function(select, spread, afterShow) {
         const sheet = spread.getActiveSheet();
         SpreadJsObj.initSheet(sheet, spreadSetting);
 
-
         if (setting.cellDoubleClick) sheet.bind(spreadNS.Events.CellDoubleClick, setting.cellDoubleClick);
         sheet.bind(spreadNS.Events.SelectionChanged, function (e, info) {
             if (!info.oldSelections || !info.oldSelections[0] || info.newSelections[0].row !== info.oldSelections[0].row) {

+ 125 - 0
app/public/js/stage.js

@@ -3812,6 +3812,99 @@ $(document).ready(() => {
                             return !changeBills;
                         }
                     },
+                    'autoUse': {
+                        name: '调用',
+                        icon: 'fa-play',
+                        callback: function (key, opt) {
+                            const curChange = SpreadJsObj.getSelectObject(self.changeSheet);
+                            const changeBills = SpreadJsObj.getSelectObject(self.changeBillsSheet);
+                            const billsPos = self.findBillsPos(curChange, changeBills);
+                            if (!billsPos) toastr.warning('无可调用的清单或计量单元');
+
+                            const data = { autoType: 'bills', bills: [{ ...billsPos, cid: changeBills.cid, cbid: changeBills.cbid }] };
+                            postData(window.location.pathname + '/auto-change', data, function(result) {
+                                if (result.pos) {
+                                    stagePos.loadCurStageData(result.pos.curStageData);
+                                }
+                                const nodes = stageTree.loadPostStageData(result.bills);
+                                stageTreeSpreadObj.refreshTreeNodes(slSpread.getActiveSheet(), nodes);
+                                stagePosSpreadObj.loadCurPosData();
+                                if (detail) {
+                                    detail.loadStageChangeUpdateData(result, nodes);
+                                } else {
+                                    stageIm.loadUpdateChangeData(result, nodes)
+                                }
+                            });
+                        },
+                        disable: function (key, opt) {
+                            const curChange = SpreadJsObj.getSelectObject(self.changeSheet);
+                            const changeBills = SpreadJsObj.getSelectObject(self.changeBillsSheet);
+                            return !changeBills || curChange.is_import;
+                        },
+                        visible: function (key, opt) {
+                            return false;
+                        }
+                    },
+                }
+            });
+
+            $.contextMenu({
+                selector: '#' + setting.changeObj.attr('id'),
+                build: function ($trigger, e) {
+                    const target = SpreadJsObj.safeRightClickSelection($trigger, e, self.changeSpread);
+                    return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
+                },
+                items: {
+                    'autoUseCur': {
+                        name: '自动调用',
+                        icon: 'fa-play',
+                        callback: function (key, opt) {
+                            const curChange = SpreadJsObj.getSelectObject(self.changeSheet);
+                            const changeBills = SpreadJsObj.zh_data;
+                            const data = { bills: [], autoType: 'bills' };
+                            for (const cb of changeBills) {
+                                const billsPos = self.findBillsPos(curChange, cb);
+                                if (billsPos) data.push({ ...billsPos, cid: curChange.cid, cbid: cb.cbid })
+                            }
+                            postData(window.location.pathname + '/auto-use-change', data, function(result) {
+                                if (result.pos) {
+                                    stagePos.loadCurStageData(result.pos.curStageData);
+                                }
+                                const nodes = stageTree.loadPostStageData(result.bills);
+                                stageTreeSpreadObj.refreshTreeNodes(slSpread.getActiveSheet(), nodes);
+                                stagePosSpreadObj.loadCurPosData();
+                                if (detail) {
+                                    detail.loadStageChangeUpdateData(result, nodes);
+                                } else {
+                                    stageIm.loadUpdateChangeData(result, nodes)
+                                }
+                            });
+                        },
+                        disable: function (key, opt) {
+                            const curChange = SpreadJsObj.getSelectObject(self.changeSheet);
+                            const changeBills = SpreadJsObj.getSelectObject(self.changeBillsSheet);
+                            return !changeBills || curChange.is_import;
+                        },
+                        visible: function (key, opt) {
+                            return false;
+                        }
+                    },
+                    'autoUseAll': {
+                        name: '自动调用(全部变更令)',
+                        icon: 'fa-play',
+                        callback: function (key, opt) {
+                            postData(window.location.pathname + '/auto-use-change', { autoType: 'all' }, function(result) {
+                                window.location.reload();
+                            });
+                        },
+                        disable: function (key, opt) {
+                            const curChange = SpreadJsObj.getSelectObject(self.changeSheet);
+                            return !curChange || curChange.is_import;
+                        },
+                        visible: function (key, opt) {
+                            return is_debug && stage.status === 1;
+                        }
+                    }
                 }
             });
         }
@@ -3886,6 +3979,38 @@ $(document).ready(() => {
                 this._analyzeCommon(change);
             }
         }
+        findBillsPos(change, changeBills) {
+            if (change.is_import) {
+                return null;
+            } else if (changeBills.gcl_id) {
+                const node = stageTree.nodes.find(x => {return x.id === changeBills.gcl_id});
+                posData = stagePos.getLedgerPos(node.id);
+                const changePos = posData.find(x => { return x.name === changeBills.bwmx; });
+                return { lid: node.id, pid: changePos ? changePos.id : (posData.length > 0 ? posData[0].id : -1) };
+            } else {
+                const cb = {
+                    b_code: changeBills.code || '',
+                    name: changeBills.name || '',
+                    unit: changeBills.unit || '',
+                    unit_price: changeBills.unit_price || 0,
+                };
+                for (const node of stageTree.nodes) {
+                    if (node.children && node.children.length > 0) continue;
+
+                    const b = {
+                        b_code: node.b_code || '',
+                        name: node.name || '',
+                        unit: node.unit || '',
+                        unit_price: node.unit_price || 0,
+                    };
+                    if (_.isMatch(cb, b)) {
+                        posData = stagePos.getLedgerPos(node.id);
+                        return { lid: node.id, pid: posData.length > 0 ? posData[0].id : -1 };
+                    }
+                }
+                return null;
+            }
+        }
     }
     // 展开收起附件
     $('a', '.right-nav').bind('click', function () {

+ 1 - 0
app/router.js

@@ -281,6 +281,7 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/update', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.updateStageData');
     app.post('/tender/:id/measure/stage/:order/valid-change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.searchValidChange');
     app.post('/tender/:id/measure/stage/:order/use-change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.useChange');
+    app.post('/tender/:id/measure/stage/:order/auto-use-change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.autoUseChange');
     app.post('/tender/:id/measure/stage/:order/check', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.check');
     app.post('/tender/:id/measure/stage/:order/save/cooperation', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.saveCooperationData');
     app.post('/tender/:id/measure/stage/:order/im-file/upload', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.uploadImFile');

+ 187 - 1
app/service/stage_change.js

@@ -13,6 +13,139 @@ const audit = require('../const/audit');
 const timesLen = audit.stage.timesLen;
 const changeConst = require('../const/change');
 
+class autoUseChange {
+    constructor(helper, info) {
+        this.helper = helper;
+        this.precision = info.precision;
+        this.decimal = info.decimal;
+
+        this.insertBills = [];
+        this.insertPos = [];
+        this.updateBills = [];
+        this.updatePos = [];
+        this.insertChange = [];
+
+        this.changeBills = {};
+        this.changePos = {};
+    }
+
+    init(source) {
+        this.default = source.default;
+
+        const LedgerModel = require('../lib/ledger');
+        this.ledgerTree = new LedgerModel.billsTree(this.ctx, {
+            id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: [],
+        });
+        this.pos = new LedgerModel.pos({ id: 'id', ledgerId: 'lid' });
+        this.ledgerTree.loadDatas(source.ledgerData);
+        this.pos.loadDatas(source.posData);
+
+        this.stageBills = source.stageBills;
+        this.stagePos = source.stagePos;
+    }
+
+    findBillsPos(changeBills){
+        if (changeBills.gcl_id) {
+            const node = this.ledgerTree.nodes.find(x => {return x.id === changeBills.gcl_id});
+            const posData = this.pos.getLedgerPos(node.id) || [];
+            const changePos = posData.find(x => { return x.name === changeBills.bwmx; });
+            return { bills: node, lid: node.id, pid: changePos ? changePos.id : (posData.length > 0 ? posData[0].id : '-1') };
+        } else {
+            const cb = {
+                b_code: changeBills.code || '',
+                name: changeBills.name || '',
+                unit: changeBills.unit || '',
+                unit_price: changeBills.unit_price || 0,
+                is_tp: false,
+            };
+            for (const node of this.ledgerTree.nodes) {
+                if (node.children && node.children.length > 0) continue;
+
+                const b = {
+                    b_code: node.b_code || '',
+                    name: node.name || '',
+                    unit: node.unit || '',
+                    unit_price: node.unit_price || 0,
+                    is_tp: !!node.is_tp,
+                };
+                if (_.isMatch(cb, b)) {
+                    posData = this.pos.getLedgerPos(node.id) || [];
+                    return { bills: node, lid: node.id, pid: posData.length > 0 ? posData[0].id : '-1' };
+                }
+            }
+            return null;
+        }
+    }
+
+    useBills(bills) {
+        const billsPos = this.findBillsPos(bills);
+        if (!billsPos) return;
+        this.insertChange.push({
+            tid: this.default.tid, sid: this.default.sid, lid: billsPos.lid, pid: billsPos.pid, cid: bills.cid, cbid: bills.id, qty: bills.valid_qty, stimes: 1, sorder: 0,
+        });
+
+        if (billsPos.pid !== '-1') {
+            const cp = this.changePos[billsPos.pid];
+            if (!cp) {
+                this.changePos[billsPos.pid] = { lid: billsPos.lid, pid: billsPos.pid, qty: bills.valid_qty, bills: billsPos.bills };
+            } else {
+                cp.qty = this.helper.add(cp.qty, bills.valid_qty);
+            }
+        } else {
+            const cb = this.changeBills[billsPos.lid];
+            if (!cb) {
+                this.changeBills[billsPos.lid] = { lid: billsPos.lid, qty: bills.valid_qty, bills: billsPos.bills };
+            } else {
+                cb.qty = this.helper.add(cb.qty, bills.valid_qty);
+            }
+        }
+    }
+
+    calculateAll() {
+        for (const pid in this.changePos) {
+            const cp = this.changePos[pid];
+            if (!cp) continue;
+
+            const precision = this.helper.findPrecision(this.precision, cp.bills.unit);
+            const qc_qty = this.helper.round(cp.qty, precision.value);
+            const sp = this.stagePos.find(x => {return x.pid === pid});
+            if (sp) {
+                this.updatePos.push({ id: sp.id, qc_qty });
+            } else {
+                this.insertPos.push({ tid: this.default.tid, sid: this.default.sid, said: this.default.said, lid: cp.lid, pid, qc_qty, times: 1, order: 0 });
+            }
+            const cb = this.changeBills[cp.lid];
+            if (!cb) {
+                this.changeBills[cp.lid] = { lid: cp.lid, qty: cp.qty, bills: cp.bills };
+            } else {
+                cb.qty = this.helper.add(cb.qty, cp.qty);
+            }
+        }
+        for (const lid in this.changeBills) {
+            const cb = this.changeBills[lid];
+            if (!cb) continue;
+            const precision = this.helper.findPrecision(this.precision, cb.bills.unit);
+            const qc_qty = this.helper.round(cb.qty, precision.value);
+            const qc_tp = this.helper.mul(cb.qty, cb.bills.unit_price, this.decimal.tp);
+            const sb = this.stageBills.find(x => {return x.lid === lid});
+            if (sb) {
+                this.updateBills.push({ id: sb.id, qc_qty, qc_tp });
+            } else {
+                this.insertBills.push({ tid: this.default.tid, sid: this.default.sid, said: this.default.said, lid, qc_qty, qc_tp, times: 1, order: 0 });
+            }
+        }
+    }
+
+    use(source, validChangeBills) {
+        this.init(source);
+
+        for (const bills of validChangeBills) {
+            this.useBills(bills);
+        }
+        this.calculateAll();
+    }
+}
+
 module.exports = app => {
 
     class StageChange extends app.BaseService {
@@ -498,12 +631,65 @@ module.exports = app => {
             return { lid, qty: this.ctx.helper.sum(filter.map(x => { return x.qty; })) };
         };
 
-
         async getPosMinusQty(stage, pid) {
             const data = await this.getAllDataByCondition({ where: { sid: stage.id, pid, minus: 1 } });
             const filter = this.ctx.helper.filterLastestData(data, ['lid', 'pid', 'cbid'], 'stimes', 'sorder');
             return { pid, qty: this.ctx.helper.sum(filter.map(x => { return x.qty; })) };
         };
+
+        async autoUseChangeBills(tender, stage, data) {
+            for (const d of data) {
+                const changeBills = await this.ctx.service.changeAuditList.getDataById(d.cbid);
+                const bills = await this.ctx.service.ledger.getDataById(data.lid);
+                const pos = await this.ctx.service.pos.getDataById(data.pid);
+                if (pos && pos.lid !== bills.id) throw '数据错误';
+
+                const allSc = await this.getAllDataByCondition({ where: { cbid: d.cbid, lid: data.lid, pid: data.pid } });
+                const curSc = this.ctx.helper.filterLastestData(allSc, ['lid', 'pid', 'cbid'], 'stimes', 'sorder');
+            }
+            const changeBills = await this.ctx.service.changeAuditList.getDataById(cbid);
+            const source = changeBills.gcl_id
+                ? await this.ctx.service.ledger.getDataByCondition({ where: { id: [changeBills.gcl_id] } })
+                : await this.ctx.service.ledger.getDataByCondition({ where: { tid: tender.id, b_code: changeBills.code, name: changeBills.name, unit: changeBills.unit, unit_price: changeBills.unit_price, is_leaf: true }});
+            if (source.length < 1) then
+            const pos = this.ctx.service.pos.getDataByCondition({ where: { lid: bills.id, name: changeBills.bwmx} });
+        };
+
+        async autoUseAllChange(tender, stage) {
+            const validChangeBills = await this.ctx.service.stageChangeFinal.getAllChangeBillsValidQty(tender.id);
+            const ledgerData = await this.ctx.service.ledger.getAllDataByCondition({
+                columns: ['id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf', 'code', 'b_code', 'name', 'unit', 'unit_price'],
+                where: { tender_id: stage.tid },
+            });
+            const extraData = await this.ctx.service.ledgerExtra.getData(this.ctx.tender.id, ['is_tp']);
+            this.ctx.helper.assignRelaData(ledgerData, [
+                { data: extraData, fields: ['is_tp'], prefix: '', relaId: 'id' },
+            ]);
+
+            const posData = await this.ctx.service.pos.getAllDataByCondition({
+                columns: ['id', 'lid', 'name', 'porder'],
+                where: { tid: stage.tid },
+            });
+            const stageBills = await this.ctx.service.stageBills.getAllDataByCondition({ where: { sid: stage.id } });
+            const stagePos = await this.ctx.service.stagePos.getAllDataByCondition({ where: { sid: stage.id } });
+            const useModal = new autoUseChange(this.ctx.helper, tender.info);
+            useModal.use({ledgerData, posData, stageBills, stagePos, default: { tid: stage.tid, sid: stage.id, said: this.ctx.session.sessionUser.accountId } }, validChangeBills);
+
+            const conn = await this.db.beginTransaction();
+            try {
+                if (useModal.insertBills.length > 0) conn.insert(this.ctx.service.stageBills.tableName, useModal.insertBills);
+                if (useModal.updateBills.length > 0) conn.updateRows(this.ctx.service.stageBills.tableName, useModal.updateBills);
+                if (useModal.insertPos.length > 0) conn.insert(this.ctx.service.stagePos.tableName, useModal.insertPos);
+                if (useModal.updatePos.length > 0) conn.updateRows(this.ctx.service.stagePos.tableName, useModal.updatePos);
+                await conn.delete(this.tableName, { sid: stage.id });
+                await conn.insert(this.tableName, useModal.insertChange);
+                await conn.commit();
+            } catch (err) {
+                await conn.rollback();
+                this.ctx.log(err);
+                throw '保存导入数据失败';
+            }
+        }
     }
 
     return StageChange;

+ 18 - 0
app/service/stage_change_final.js

@@ -102,6 +102,24 @@ module.exports = app => {
             const usedQty = await this.db.queryOne('Select SUM(qty) as qty FROM ' + this.tableName + ' WHERE cbid = ?', [cbid]);
             return usedQty ? this.ctx.helper.sub(qty, usedQty.qty) : qty;
         }
+
+        async getAllChangeBillsValidQty(tid) {
+            const self = this;
+            const sql = 'SELECT cal.*, scf.used_qty FROM ' + this.ctx.service.changeAuditList.tableName + ' cal' +
+                '  LEFT JOIN ' + this.ctx.service.change.tableName + ' c ON cal.cid = c.cid ' +
+                '  LEFT JOIN (' +
+                '    SELECT cbid, SUM(qty) as used_qty FROM ' + this.tableName + ' WHERE tid = ? GROUP BY cbid ' +
+                '  ) scf ON cal.id = scf.cbid ' +
+                '  WHERE c.tid = ? AND c.valid AND c.status = ?';
+            const changeBills = await this.db.query(sql, [tid, tid, auditConst.status.checked]);
+            if (!changeBills || changeBills.length === 0) return [];
+
+            return changeBills.filter(cb => {
+                cb.qty = parseFloat(cb.samount);
+                cb.valid_qty = self.ctx.helper.sub(cb.qty, cb.used_qty);
+                return cb.valid_qty;
+            });
+        }
     }
 
     return StageChangeFinal;