Browse Source

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

# Conflicts:
#	app/controller/payment_controller.js
#	app/service/payment_detail.js
Tony Kang 1 year ago
parent
commit
65199b1eba

+ 1 - 0
app/controller/payment_controller.js

@@ -393,6 +393,7 @@ module.exports = app => {
                 // 获取当前报表人
                 const rptAudit = await ctx.service.paymentRptAudit.getDataByCondition({ td_id: ctx.detail.id, uid: ctx.session.sessionUser.accountId });
                 if (report_json && report_json.items && report_json.items.length > 0 && report_json.items[0].interact_cells.length > 0) {
+                // if (report_json && report_json.items && report_json.items[0].interact_cells.length > 0) {
                     for (const [i, cell] of report_json.items[0].interact_cells.entries()) {
                         cell.index = i;
                     }

+ 0 - 7
app/controller/stage_controller.js

@@ -626,14 +626,7 @@ module.exports = app => {
                 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);

+ 5 - 5
app/lib/rm/payment_safe.js

@@ -70,15 +70,15 @@ class rptMemPaymentSafe extends RptMemBase {
             d.cur_his.sort((x, y) => { return x.times === y.times ? x.order - y.order : x.times - y.times; });
             for (const r of roles) {
                 if (r.latest) {
-                    d[`qty_${r.order}`] = d.cur_qty;
-                    d[`tp_${r.order}`] = d.cur_tp;
+                    d[`r_qty_${r.order}`] = d.cur_qty;
+                    d[`r_tp_${r.order}`] = d.cur_tp;
                     d.his_qty.push(d.cur_qty);
                     d.his_tp.push(d.cur_tp);
                 } else {
                     const rHis = findHis(r, d.cur_his);
                     if (rHis) {
-                        d[`qty_${r.order}`] = rHis.qty;
-                        d[`tp_${r.order}`] = rHis.tp;
+                        d[`r_qty_${r.order}`] = rHis.qty;
+                        d[`r_tp_${r.order}`] = rHis.tp;
                     }
                     d.his_qty.push(rHis ? rHis.qty : 0);
                     d.his_tp.push(rHis ? rHis.tp : 0);
@@ -99,7 +99,7 @@ class rptMemPaymentSafe extends RptMemBase {
             fullPath: 'tree_full_path',
             rootId: -1,
         };
-        setting.calcFields = roles.map(x => { return `tp_${x.order}`});
+        setting.calcFields = roles.map(x => { return `r_tp_${x.order}`});
         setting.calcFields.push('pre_tp');
         const compareTree = new Ledger.billsTree(this.ctx, setting);
         compareTree.loadDatas(bills);

+ 1 - 0
app/public/js/file_detail.js

@@ -391,6 +391,7 @@ $(document).ready(function() {
                 return !treeNode.source_node.is_fixed;
             },
             renameTitle: '编辑',
+            removeTitle: '删除',
             drag: {
                 isCopy: false,
                 isMove: true,

+ 3 - 4
app/public/js/payment_compare.js

@@ -19,11 +19,11 @@ $(document).ready(function() {
                     {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 185, formatter: '@'},
                     {title: '规格', colSpan: '1', rowSpan: '2', field: 'spec', hAlign: 0, width: 150, formatter: '@'},
                     {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', cellType: 'unit'},
-                    {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+                    {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 80, type: 'Number'},
                 ],
                 extraCols: [
-                    {title: '%s|数量', colSpan: '2|1', rowSpan: '1|1', field: 'qty_{%d}', hAlign: 2, width: 60, type: 'Number', },
-                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'tp_{%d}', hAlign: 2, width: 60, type: 'Number', },
+                    {title: '%s|数量', colSpan: '2|1', rowSpan: '1|1', field: 'qty_{%d}', hAlign: 2, width: 80, type: 'Number', },
+                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'tp_{%d}', hAlign: 2, width: 80, type: 'Number', },
                 ],
                 emptyRows: 3,
                 headRows: 2,
@@ -100,7 +100,6 @@ $(document).ready(function() {
             }
         }
         loadData(datas, roles) {
-            // todo 整理数据
             this.initSpread(roles);
             this.analysisCompareData(datas, roles);
             this.tree.loadDatas(datas);

+ 24 - 9
app/public/js/payment_safe.js

@@ -30,13 +30,13 @@ $(document).ready(function() {
                     {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 185, formatter: '@'},
                     {title: '规格', colSpan: '1', rowSpan: '2', field: 'spec', hAlign: 0, width: 150, formatter: '@'},
                     {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', cellType: 'unit'},
-                    {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
-                    {title: '本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'cur_qty', hAlign: 2, width: 60, type: 'Number'},
-                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'cur_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
-                    {title: '截止本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_qty', hAlign: 2, width: 60, type: 'Number'},
-                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
-                    {title: '发票号', colSpan: '1', rowSpan: '2', field: 'invoice_code', hAlign: 0, width: 80, formatter: '@'},
-                    {title: '备注', colSpan: '1', rowSpan: '2', field: 'memo', hAlign: 0, width: 100, formatter: '@', cellType: 'ellipsisAutoTip'},
+                    {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 80, type: 'Number'},
+                    {title: '本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'cur_qty', hAlign: 2, width: 80, type: 'Number'},
+                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'cur_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true},
+                    {title: '截止本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_qty', hAlign: 2, width: 80, type: 'Number'},
+                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true},
+                    {title: '发票号', colSpan: '1', rowSpan: '2', field: 'invoice_code', hAlign: 0, width: 100, formatter: '@'},
+                    {title: '备注', colSpan: '1', rowSpan: '2', field: 'memo', hAlign: 0, width: 120, formatter: '@', cellType: 'ellipsisAutoTip'},
                 ],
                 emptyRows: 3,
                 headRows: 2,
@@ -45,6 +45,10 @@ $(document).ready(function() {
                 headerFont: '12px 微软雅黑',
                 font: '12px 微软雅黑',
                 readOnly: readOnly,
+                localCache: {
+                    key: 'payment-safe-bills',
+                    colWidth: true,
+                },
             };
             this.ckBillsSpread = window.location.pathname + '-billsSelect';
 
@@ -383,7 +387,7 @@ $(document).ready(function() {
                     info.cancel = readOnly || billsObj.checkNodeUsed(tree, node);
                     break;
                 case 'unit_price':
-                    info.cancel = readOnly || (node.children && node.children.length > 0) || billsObj.checkNodeUsed(tree, node);
+                    info.cancel = readOnly || (node.children && node.children.length > 0);
                     break;
                 case 'cur_qty':
                 case 'cur_tp':
@@ -597,7 +601,7 @@ $(document).ready(function() {
         reCalcPage() {
             this.allTotalPage = Math.ceil(this.atts.length / this.pageCount);
             const curNode = SpreadJsObj.getSelectObject(billsObj.sheet);
-            const curAttIndex = this.billsIndexes[curNode.safe_id] || [];
+            const curAttIndex = curNode ? this.billsIndexes[curNode.safe_id] || [] : [];
             this.curTotalPage = Math.ceil(curAttIndex.length / this.pageCount);
             this.refreshShowPage();
         }
@@ -786,6 +790,17 @@ $(document).ready(function() {
     $('body').on('click', '[name=del-file]', function() {
        attObj.deleteAtt(parseInt(this.getAttribute('file_id')));
     });
+    $('body').on('click', 'a[file_id]', function() {
+        const file_id = parseInt(this.getAttribute('file_id'));
+        const file = attObj.atts.find(x => { return x.id === file_id; });
+        if (!file) return;
+
+        if (file.viewpath) {
+            window.open(file.viewpath, '_blank');
+        } else {
+            AliOss.downloadFile(file.filepath, `${file.filename}${file.fileext}`)
+        }
+    });
     $('.page-select').click(function() {
         const content = this.getAttribute('content');
         if (content === 'pre') {

+ 73 - 70
app/public/js/stage.js

@@ -3900,39 +3900,42 @@ $(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 is_debug && stage.status === 1;
-                    //     }
-                    // },
+                    '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('无可调用的清单或计量单元');
+                                return;
+                            }
+
+                            const data = { autoType: 'bills', bills: [{ ...billsPos, cid: changeBills.cid, cbid: changeBills.id }] };
+                            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 is_debug && stage.status === 1;
+                        }
+                    },
                 }
             });
 
@@ -3943,40 +3946,40 @@ $(document).ready(() => {
                     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 is_debug && stage.status === 1;
-                    //     }
-                    // },
+                    'autoUseCur': {
+                        name: '自动调用',
+                        icon: 'fa-play',
+                        callback: function (key, opt) {
+                            const curChange = SpreadJsObj.getSelectObject(self.changeSheet);
+                            const changeBills = self.changeBillsSheet.zh_data;
+                            const data = { bills: [], autoType: 'bills' };
+                            for (const cb of changeBills) {
+                                const billsPos = self.findBillsPos(curChange, cb);
+                                if (billsPos) data.bills.push({ ...billsPos, cid: cb.cid, cbid: cb.id })
+                            }
+                            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 is_debug && stage.status === 1;
+                        }
+                    },
                     'autoUseAll': {
                         name: '自动调用(全部变更令)',
                         icon: 'fa-play',
@@ -4073,9 +4076,9 @@ $(document).ready(() => {
                 return null;
             } else if (changeBills.gcl_id) {
                 const node = stageTree.nodes.find(x => {return x.id === changeBills.gcl_id});
-                posData = stagePos.getLedgerPos(node.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) };
+                return { lid: node.id, pid: changePos ? changePos.id : (posData.length > 0 ? posData[0].id : '-1') };
             } else {
                 const cb = {
                     b_code: changeBills.code || '',
@@ -4094,7 +4097,7 @@ $(document).ready(() => {
                     };
                     if (_.isMatch(cb, b)) {
                         posData = stagePos.getLedgerPos(node.id);
-                        return { lid: node.id, pid: posData.length > 0 ? posData[0].id : -1 };
+                        return { lid: node.id, pid: posData.length > 0 ? posData[0].id : '-1' };
                     }
                 }
                 return null;

+ 2 - 1
app/service/payment_detail.js

@@ -60,6 +60,7 @@ module.exports = app => {
             return preDetail;
         }
 
+        // async addFormDetail(trInfo, code, s_time) {
         async addFormDetail(ctx, trInfo, code, s_time) {
             const transaction = await this.db.beginTransaction();
             try {
@@ -68,7 +69,7 @@ module.exports = app => {
                 }
                 const preDetail = await this.addCommomCheck(trInfo, code);
                 const rptTpl = await this.ctx.service.rptTpl.getDataById(trInfo.rpt_id);
-                const pageRst = this.ctx.service.jpcReport.getAllPreviewPagesCommon(rptTpl, 'A4');
+                const pageRst = await this.ctx.service.jpcReport.getAllPreviewPagesCommon(rptTpl, 'A4');
                 // const pageRst = await ctx.service.jpcReport.getPreviewPagesWithDiscreteDataCommon(ctx, rptTpl, 'A4', this.app.baseDir, null);
                 const newDetail = {
                     tender_id: this.ctx.paymentTender.id,

+ 2 - 1
app/service/payment_detail_audit.js

@@ -107,12 +107,13 @@ module.exports = app => {
             } else {
                 result.push({
                     aid: user.id, name: user.name, company: user.company, role: user.role, mobile: user.mobile, telephone: user.telephone,
-                    times: detail.curTimes, order: 0, status: auditConst.status.uncheck, latest: detail.readOnly,
+                    times: detail.curTimes, order: 0, status: auditConst.status.uncheck, latest: !detail.readOnly,
                 });
 
                 const sql = `SELECT pda.aid, pa.name, pa.company, pa.role, pa.mobile, pa.telephone, pda.times, pda.order, pda.status, pda.opinion, pda.begin_time, pda.end_time` +
                     `  FROM ${this.tableName} pda LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON pda.aid = pa.id` +
                     '  WHERE pda.td_id = ? AND pda.times = ?';
+                //const flow = await this.db.query(sql, [detail.id, detail.status === auditConst.status.checkNo && !detail.readOnly ? detail.curTimes - 1 : detail.curTimes]);
                 const flow = await this.db.query(sql, [detail.id, detail.curTimes]);
                 flow.forEach(x => {
                     if (x.status === auditConst.status.checked) result.push(x);

+ 1 - 1
app/service/payment_safe_bills.js

@@ -501,7 +501,7 @@ module.exports = app => {
                 if (l.cur_read_qty !== l.cur_qty || l.cur_read_tp !== l.cur_tp) {
                     const data = { id: l.id, cur_read_qty: l.cur_qty, cur_read_tp: l.cur_tp };
                     const his = l.cur_his ? JSON.parse(l.cur_his) : [];
-                    his.push({ ...auditInfo, qty: l.cur_qty, tp: l.cur_tp });
+                    his.push({ ...auditInfo, qty: l.cur_qty, tp: l.cur_tp, up: l.unit_price });
                     data.cur_his = JSON.stringify(his);
                     data.cur_read_qty = l.cur_qty;
                     data.cur_read_tp = l.cur_tp;

+ 133 - 37
app/service/stage_change.js

@@ -24,9 +24,11 @@ class autoUseChange {
         this.updateBills = [];
         this.updatePos = [];
         this.insertChange = [];
+        this.updateChange = [];
 
         this.changeBills = {};
         this.changePos = {};
+        this.changeDetail = [];
     }
 
     init(source) {
@@ -42,11 +44,12 @@ class autoUseChange {
 
         this.stageBills = source.stageBills;
         this.stagePos = source.stagePos;
+        this.stageChange = source.stageChange || [];
     }
 
     findBillsPos(changeBills){
         if (changeBills.gcl_id) {
-            const node = this.ledgerTree.nodes.find(x => {return x.id === changeBills.gcl_id});
+            const node = this.ledgerTree.datas.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') };
@@ -78,52 +81,107 @@ class autoUseChange {
     }
 
     useBills(bills) {
-        const billsPos = this.findBillsPos(bills);
+        if (bills.billsPos) bills.billsPos.bills = this.ledgerTree.datas.find(x => {return x.id === bills.billsPos.lid; });
+        const billsPos = bills.billsPos || this.findBillsPos(bills);
         if (!billsPos) return;
-        this.insertChange.push({
+        const bamount = parseFloat(bills.samount);
+        const minus = bamount < 0;
+        this.changeDetail.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,
+            lid: billsPos.lid, pid: billsPos.pid + '', cid: bills.cid, cbid: bills.id,
+            qty: bills.valid_qty, stimes: 1, sorder: 0, unit_price: bills.unit_price, minus, no_value: false,
         });
 
         if (billsPos.pid !== '-1') {
-            const cp = this.changePos[billsPos.pid];
+            let cp = this.changePos[billsPos.pid];
             if (!cp) {
-                this.changePos[billsPos.pid] = { lid: billsPos.lid, pid: billsPos.pid, qty: bills.valid_qty, bills: billsPos.bills };
+                cp = { lid: billsPos.lid, pid: billsPos.pid, qty: 0, bills: billsPos.bills };
+                this.changePos[billsPos.pid] = cp
+            }
+            cp.qty = this.helper.add(cp.qty, bills.valid_qty);
+            if (minus) {
+                cp.negative_qc_qty = cp.qty;
             } else {
-                cp.qty = this.helper.add(cp.qty, bills.valid_qty);
+                cp.positive_qc_qty = cp.qty;
             }
         } else {
-            const cb = this.changeBills[billsPos.lid];
+            let cb = this.changeBills[billsPos.lid];
             if (!cb) {
-                this.changeBills[billsPos.lid] = { lid: billsPos.lid, qty: bills.valid_qty, bills: billsPos.bills };
+                cb = { lid: billsPos.lid, qty: 0, bills: billsPos.bills };
+                this.changeBills[billsPos.lid] = cb;
+            }
+            cb.qty = this.helper.add(cb.qty, bills.valid_qty);
+            if (minus) {
+                cb.negative_qc_qty = this.helper.add(cb.negative_qc_qty, bills.valid_qty);
             } else {
-                cb.qty = this.helper.add(cb.qty, bills.valid_qty);
+                cb.positive_qc_qty = this.helper.add(cb.positive_qc_qty, bills.valid_qty);
             }
         }
     }
 
     calculateAll() {
+        for (const cd of this.changeDetail) {
+            const sci = this.stageChange.findIndex(x => {
+                return x.lid === cd.lid && x.pid === cd.pid && x.cbid === cd.cbid;
+            });
+            const sc = this.stageChange[sci];
+            if (sc) {
+                this.updateChange.push({ id: sc.id, qty: cd.qty });
+                this.stageChange.splice(sci, 1);
+            } else {
+                this.insertChange.push(cd);
+            }
+        }
+        for (const sc of this.stageChange) {
+            if (sc.no_value) continue;
+            const cp = this.changePos[sc.pid];
+            if (cp) {
+                cp.qty = this.helper.add(cp.qty, sc.qty);
+                if (sc.minus) {
+                    cp.negative_qc_qty = this.helper.add(cp.negative_qc_qty, sc.qty);
+                } else {
+                    cp.positive_qc_qty = this.helper.add(cp.positive_qc_qty, sc.qty);
+                }
+            }
+        }
         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 positive_qc_qty = this.helper.round(cp.positive_qc_qty || 0, precision.value);
+            const negative_qc_qty = this.helper.round(cp.negative_qc_qty || 0, precision.value);
             const sp = this.stagePos.find(x => {return x.pid === pid});
             if (sp) {
-                this.updatePos.push({ id: sp.id, qc_qty });
+                this.updatePos.push({ id: sp.id, qc_qty, positive_qc_qty, negative_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
+                    lid: cp.lid, pid, qc_qty, positive_qc_qty, negative_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 };
+                this.changeBills[cp.lid] = { lid: cp.lid, qty: qc_qty, positive_qc_qty, negative_qc_qty, bills: cp.bills };
             } else {
-                cb.qty = this.helper.add(cb.qty, cp.qty);
+                cb.qty = this.helper.add(cb.qty, qc_qty);
+                cb.positive_qc_qty = this.helper.add(cb.positive_qc_qty, positive_qc_qty);
+                cb.negative_qc_qty = this.helper.add(cb.negative_qc_qty, negative_qc_qty);
+            }
+        }
+        for (const sc of this.stageChange) {
+            if (sc.no_value) continue;
+            const cp = this.changePos[sc.pid];
+            if (cp) continue;
+            const cb = this.changeBills[sc.lid];
+            if (cb) {
+                cb.qty = this.helper.add(cb.qty, sc.qty);
+                if (sc.minus) {
+                    cb.negative_qc_qty = this.helper.add(cb.negative_qc_qty, sc.qty);
+                } else {
+                    cb.positive_qc_qty = this.helper.add(cb.positive_qc_qty, sc.qty);
+                }
             }
         }
         for (const lid in this.changeBills) {
@@ -132,13 +190,17 @@ class autoUseChange {
             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 positive_qc_qty = this.helper.round(cb.positive_qc_qty || 0, precision.value);
+            const positive_qc_tp = this.helper.mul(positive_qc_qty, cb.bills.unit_price, this.decimal.tp);
+            const negative_qc_qty = this.helper.round(cb.negative_qc_qty || 0, precision.value);
+            const negative_qc_tp = this.helper.mul(negative_qc_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 });
+                this.updateBills.push({ id: sb.id, qc_qty, qc_tp, positive_qc_qty, positive_qc_tp, negative_qc_qty, negative_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
+                    lid, qc_qty, qc_tp, positive_qc_qty, positive_qc_tp, negative_qc_qty, negative_qc_tp, times: 1, order: 0
                 });
             }
         }
@@ -676,21 +738,53 @@ module.exports = app => {
         };
 
         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} });
+            const lid = [], cbid = [];
+            data.forEach(x => {
+                lid.push(x.lid);
+                cbid.push(x.cbid);
+            });
+            const validChangeBills = await this.ctx.service.stageChangeFinal.getListChangeBillsValidQty(tender.id, cbid);
+            validChangeBills.forEach(x => {
+                x.billsPos = data.find(y => { return x.id === y.cbid; });
+            });
+            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: { id: lid },
+            });
+            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: { lid },
+            });
+            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 stageChange = await this.ctx.service.stageChange.getAllDataByCondition({ where: { sid: stage.id, lid }});
+
+            const useModal = new autoUseChange(this.ctx.helper, tender.info);
+            useModal.use({ledgerData, posData, stageBills, stagePos, stageChange, 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) await conn.insert(this.ctx.service.stageBills.tableName, useModal.insertBills);
+                if (useModal.updateBills.length > 0) await conn.updateRows(this.ctx.service.stageBills.tableName, useModal.updateBills);
+                if (useModal.insertPos.length > 0) await conn.insert(this.ctx.service.stagePos.tableName, useModal.insertPos);
+                if (useModal.updatePos.length > 0) await conn.updateRows(this.ctx.service.stagePos.tableName, useModal.updatePos);
+                if (useModal.insertChange.length > 0) await conn.insert(this.tableName, useModal.insertChange);
+                if (useModal.updateChange.length > 0) await conn.updateRows(this.tableName, useModal.updateChange);
+                await conn.commit();
+            } catch (err) {
+                await conn.rollback();
+                this.ctx.log(err);
+                throw '保存导入数据失败';
+            }
+
+            const rst = { bills: {}, pos: {} };
+            rst.bills.curStageData = await this.ctx.service.stageBills.getLastestStageData2(this.ctx.tender.id, this.ctx.stage.id, lid);
+            rst.pos.curStageData = await this.ctx.service.stagePos.getLastestStageData2(this.ctx.tender.id, this.ctx.stage.id, { lid });
+            return rst;
         };
 
         async autoUseAllChange(tender, stage) {
@@ -713,14 +807,16 @@ module.exports = app => {
             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);
 
+            // if (useModal.insertChange.length === 0) return '无可调用的清单或计量单元';
+
             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);
+                if (useModal.insertBills.length > 0) await conn.insert(this.ctx.service.stageBills.tableName, useModal.insertBills);
+                if (useModal.updateBills.length > 0) await conn.updateRows(this.ctx.service.stageBills.tableName, useModal.updateBills);
+                if (useModal.insertPos.length > 0) await conn.insert(this.ctx.service.stagePos.tableName, useModal.insertPos);
+                if (useModal.updatePos.length > 0) await conn.updateRows(this.ctx.service.stagePos.tableName, useModal.updatePos);
                 await conn.delete(this.tableName, { sid: stage.id });
-                await conn.insert(this.tableName, useModal.insertChange);
+                if (useModal.insertChange.length > 0) await conn.insert(this.tableName, useModal.insertChange);
                 await conn.commit();
             } catch (err) {
                 await conn.rollback();

+ 18 - 0
app/service/stage_change_final.js

@@ -89,6 +89,24 @@ module.exports = app => {
             return usedQty ? this.ctx.helper.sub(qty, usedQty.qty) : qty;
         }
 
+        async getListChangeBillsValidQty(tid, cbid) {
+            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 ' +
+                '  ' + this.ctx.helper.whereSql({ id: cbid }, 'cal') + ' AND 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;
+            });
+        }
+
         async getAllChangeBillsValidQty(tid) {
             const self = this;
             const sql = 'SELECT cal.*, scf.used_qty FROM ' + this.ctx.service.changeAuditList.tableName + ' cal' +

+ 1 - 1
app/view/stage/pay.ejs

@@ -15,7 +15,7 @@
                         <div class="input-group-prepend">
                             <span class="input-group-text" id="basic-addon1">表达式</span>
                         </div>
-                        <input type="text" class="form-control m-0" <% if (stage.readOnly) { %> readonly="" <% } %> id="expr" onpaste="pasteExpr(event, this);" style="width: 270px">
+                        <input type="text" class="form-control m-0" <% if (stage.readOnly) { %> readonly="" <% } %> id="expr" onpaste="pasteExpr(event, this);" style="width: 400px">
                     </div>
                 </div>
             </div>