浏览代码

材料调差功能(除费用工料未完成)

laiguoran 5 年之前
父节点
当前提交
fa0b5c8414

+ 12 - 6
app/controller/material_controller.js

@@ -227,16 +227,21 @@ module.exports = app => {
                 // 取所有工料表
                 renderData.materialBillsData = await ctx.service.materialBills.getAllDataByCondition({ where: searchsql });
                 // 取对应期的截取上期的调差金额和应耗数量
-                for (const mindex in renderData.materialBillsData) {
-                    const pre_tp = renderData.materialBillsData[mindex].pre_tp !== null ? renderData.materialBillsData[mindex].pre_tp.split(',')[ctx.material.order - 1] : null;
-                    renderData.materialBillsData[mindex].pre_tp = pre_tp;
-                    if (ctx.material.readOnly) {
-                        const quantity = renderData.materialBillsData[mindex].s_quantity.split(',')[ctx.material.order - 1];
+                if (ctx.material.highOrder !== ctx.material.order) {
+                    for (const [mindex, mb] of renderData.materialBillsData.entries()) {
+                        const [quantity, pre_tp] = await ctx.service.materialBillsHistory.getByMbId(ctx.material.id, ctx.material.order, mb.id);
                         renderData.materialBillsData[mindex].quantity = quantity;
+                        renderData.materialBillsData[mindex].pre_tp = pre_tp;
                     }
                 }
                 // 取所有已被调用的工料清单表
                 renderData.materialListData = await ctx.service.materialList.getAllDataByCondition({ tid: ctx.tender.id, mid: ctx.material.id });
+                // 基数
+                // if (!ctx.material.readOnly) {
+                const stage_list = await ctx.service.stage.getStageMsgByStageId(ctx.material.stage_id);
+                renderData.calcBase = await ctx.service.stage.getMaterialCalcBase(stage_list, ctx.tender.info);
+                // }
+
                 renderData.materialType = JSON.stringify(materialConst);
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.material.info);
                 await this.layout('material/info.ejs', renderData, 'material/info_modal.ejs');
@@ -262,6 +267,7 @@ module.exports = app => {
                     midList = await ctx.service.material.getPreMidList(ctx.tender.id, ctx.material.order);
                     searchsql.mid = midList;
                 }
+                searchsql.t_type = materialConst.t_type[0].value;
                 renderData.materialBillsData = await ctx.service.materialBills.getAllDataByCondition({ where: searchsql });
                 // 取所有已被调用的工料清单表
                 renderData.materialListData = await ctx.service.materialList.getMaterialData(ctx.tender.id, ctx.material.id);
@@ -362,7 +368,7 @@ module.exports = app => {
                             throw '长度不超过15个字符';
                         }
                         // 判断编号是否已存在
-                        const billData = await ctx.service.materialBills.getAllDataByCondition({ where: { mid: ctx.material.id, code: data.updateData.code } });
+                        const billData = await ctx.service.materialBills.getAllDataByCondition({ where: { tid: ctx.tender.id, code: data.updateData.code } });
                         if (billData.length > 1 || (billData.length > 0 && billData[0].id !== data.updateData.id)) {
                             throw '该编号已存在,请重新输入。';
                         }

+ 183 - 6
app/public/js/material.js

@@ -52,11 +52,43 @@ $(document).ready(() => {
         readOnly: readOnly,
     };
 
+    const spCol = _.find(materialSpreadSetting.cols, {field: 'quantity'});
+    spCol.readOnly = true;
+    spCol.cellType = 'activeImageBtn';
+    spCol.normalImg = '#ellipsis-icon';
+    spCol.indent = 5;
+    spCol.showImage = function (data) {
+        // return !readOnly && data.t_type === 2 && data.mid === materialID;
+        return data.t_type === 2;
+    };
+    materialSpreadSetting.imageClick = function (data) {
+        if (data.t_type === 2) {
+            $('#bcyy').modal('show');
+            console.log(data);
+            $('#materialbillsId').val(data.id);
+            $('#expr').val(data.expr);
+            if (!readOnly && data.mid === materialID) {
+                $('#expr').attr('readOnly', false);
+                $('#expr_btn').show();
+                $('#expr_select').show();
+            } else {
+                $('#expr').attr('readOnly', true);
+                $('#expr_btn').hide();
+                $('#expr_select').hide();
+            }
+        }
+    };
+
     const materialBase = {
         isEdit: function (data) {
-            return materialListData.find(function (item) {
-                return item.mb_id === data.id;
-            });
+            if (data.t_type === 2) {
+                return data.mid === materialID;
+            } else {
+                const mlInfo = materialListData.find(function (item) {
+                    return item.mb_id === data.id;
+                });
+                return data.mid === materialID && mlInfo === undefined;
+            }
         },
         // isStage: function (data) {
         //     return data.mid === materialID;
@@ -79,7 +111,7 @@ $(document).ready(() => {
         },
         readOnly: {
             isEdit: function (data) {
-                return !(!readOnly && materialBase.isEdit(data) === undefined);
+                return !(!readOnly && materialBase.isEdit(data));
             },
             remark: function () {
                 return readOnly;
@@ -102,7 +134,7 @@ $(document).ready(() => {
             const sheet = materialSpread.getActiveSheet();
             const select = SpreadJsObj.getSelectObject(sheet);
             // 还需判断是否已被调差清单调用
-            setObjEnable($('#del'), !readOnly && select && materialBase.isEdit(select) === undefined);
+            setObjEnable($('#del'), !readOnly && select && materialBase.isEdit(select));
         },
         add: function () {
             const sheet = materialSpread.getActiveSheet();
@@ -250,7 +282,7 @@ $(document).ready(() => {
                         const sheet = materialSpread.getActiveSheet();
                         const select = SpreadJsObj.getSelectObject(sheet);
                         materialSpreadObj.refreshActn();
-                        if (!readOnly && select && materialBase.isEdit(select) === undefined) {
+                        if (!readOnly && select && materialBase.isEdit(select)) {
                             return false;
                         } else {
                             return true;
@@ -267,6 +299,151 @@ $(document).ready(() => {
                 $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
                 $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
             });
+        });
+
+        $('#expr_select button').on('click', function () {
+            const code = $(this).text();
+            $('#expr').val($('#expr').val() + code);
+        });
+
+        const ExprObj = {
+            _checkExprValid(expr, invalidParam) {
+                if (!expr) return [true, null];
+                const param = [];
+                let num = '', base = '';
+                for (let i = 0, iLen = expr.length; i < iLen; i++) {
+                    if (/^[\d\.%]+/.test(expr[i])) {
+                        if (base !== '') {
+                            param.push({type: 'base', value: base});
+                            base = '';
+                        }
+                        num = num + expr[i];
+                    } else if (/^[a-z]/.test(expr[i])) {
+                        if (num !== '') {
+                            param.push({type: 'num', value: num});
+                            base = '';
+                        }
+                        base = base + expr[i];
+                    } else if (expr[i] === '(') {
+                        if (num !== '') {
+                            param.push({type: 'num', value: num});
+                            base = '';
+                        }
+                        if (base !== '') {
+                            param.push({type: 'base', value: base});
+                            base = '';
+                        }
+                        param.push({type: 'left', value: '('});
+                    } else if (expr[i] === ')') {
+                        if (num !== '') {
+                            param.push({type: 'num', value: num});
+                            base = '';
+                        }
+                        if (base !== '') {
+                            param.push({type: 'base', value: base});
+                            base = '';
+                        }
+                        param.push({type: 'right', value: ')'});
+                    } else if (/^[\+\-*\/]/.test(expr[i])) {
+                        if (num !== '') {
+                            param.push({type: 'num', value: num});
+                            base = '';
+                        }
+                        if (base !== '') {
+                            param.push({type: 'base', value: base});
+                            base = '';
+                        }
+                        param.push({type: 'calc', value: expr[i]});
+                    } else {
+                        return [false, '输入的表达式含有非法字符: ' + expr[i]];
+                    }
+                }
+                if (num !== '') {
+                    param.push({type: 'num', value: num});
+                    base = '';
+                }
+                if (base !== '') {
+                    param.push({type: 'base', value: base});
+                    base = '';
+                }
+                if (param.length === 0) return true;
+                if (param.length > 1) {
+                    if (param[0].value === '-') {
+                        param[1].value = '-' + param[1];
+                    }
+                    param.unshift();
+                }
+                const iLen = param.length;
+                let iLeftCount = 0, iRightCount = 0;
+                for (const [i, p] of param.entries()) {
+                    if (p.type === 'calc') {
+                        if (i === 0 || i === iLen - 1)
+                            return [false, '输入的表达式非法:计算符号' + p.value + '前后应有数字或计算基数'];
+                    }
+                    if (p.type === 'num') {
+                        num = p.value.replace('%', '');
+                        if (p.value.length - num.length > 1)
+                            return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
+                        num = _.toNumber(num);
+                        if (num === undefined || num === null || _.isNaN(num))
+                            return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
+                        if (i > 0) {
+                            if (param[i - 1].type !== 'calc') {
+                                return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
+                            } else if (param[i - 1].value === '/' && num === 0) {
+                                return [false, '输入的表达式非法:请勿除0'];
+                            }
+                        }
+                    }
+                    if (p.type === 'base') {
+                        const baseParam = _.find(calcBase, {code: p.value});
+                        if (!baseParam)
+                            return [false, '输入的表达式非法:不存在计算基数' + p.value];
+                        if (invalidParam && invalidParam.indexOf(p.value) >= 0)
+                            return [false, '不可使用计算基数' + p.value];
+                        if (i > 0 && param[i - 1].type === 'calc')
+                            return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
+                    }
+                    if (p.type === 'left') {
+                        iLeftCount += 1;
+                        if (i !== 0 && param[i-1].type !== 'calc')
+                            return [false, '输入的表达式非法:(前应有运算符'];
+                    }
+                    if (p.type === 'right') {
+                        iRightCount += 1;
+                        if (i !== iLen - 1 && param[i+1].type !== 'calc')
+                            return [false, '输入的表达式非法:)后应有运算符'];
+                        if (iRightCount > iLeftCount)
+                            return [false, '输入的表达式非法:")"前无对应的"("'];
+                    }
+                }
+                if (iLeftCount > iRightCount)
+                    return [false, '输入的表达式非法:"("后无对应的")"'];
+                return [true, ''];
+            },
+            _checkExpr: function (text) {
+                if (text) {
+                    const num = _.toNumber(text);
+                    if (num) {
+                        console.log(num);
+                    } else {
+                        const expr = text.replace('=', '').toLowerCase();
+                        const [valid, msg] = this._checkExprValid(expr);
+                        if (!valid) return [valid, msg];
+                    }
+                }
+                return [true, ''];
+            },
+        };
+
+        $('#expr_btn').click(function () {
+            const expr = $('#expr').val();
+            // 判断表达式格式
+            const [valid, msg] = ExprObj._checkExpr(expr);
+            console.log(msg);
+            if (!valid) {
+                toastr.error(msg);
+            }
         })
     } else {
         // SpreadJsObj.forbiddenSpreadContextMenu('#material-spread', materialSpread);

+ 2 - 0
app/public/js/material_list.js

@@ -294,6 +294,8 @@ $(document).ready(() => {
                     } else {
                         notJoinList.push(result);
                     }
+                    gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
+                    SpreadJsObj.reLoadRowData(sheet, iRow);
                     sheet.getRange(iRow, -1, 1, -1).backColor(color);
                     loadMaterialData(iGclRow, iRow);
                 });

+ 19 - 3
app/service/material.js

@@ -147,9 +147,14 @@ module.exports = app => {
                     await this.ctx.service.materialListNotjoin.copyNewStageNotJoinList(transaction, preNotJoinList, newMaterial.id);
                     // 复制调差清单工料关联表
                     await this.ctx.service.materialList.copyPreMaterialList(transaction, preMaterial, newMaterial);
-                    // 修改本期应耗数量值和有效价差,需要剔除不参与调差的清单数据
-                    await this.ctx.service.materialBills.updateNewMaterial(transaction, preNotJoinList);
+                    // 修改本期应耗数量值和有效价差,需要剔除不参与调差的清单数据,并返回总金额
+                    const m_tp = await this.ctx.service.materialBills.updateNewMaterial(transaction, this.ctx.tender.id, newMaterial.id);
                     // 计算得出本期总金额
+                    const updateMaterialData = {
+                        id: newMaterial.id,
+                        m_tp,
+                    };
+                    await transaction.update(this.tableName, updateMaterialData);
                 }
 
                 await transaction.commit();
@@ -169,11 +174,22 @@ module.exports = app => {
         async deleteMaterial(id) {
             const transaction = await this.db.beginTransaction();
             try {
-                await transaction.delete(this.tableName, { id });
                 await transaction.delete(this.ctx.service.materialAudit.tableName, { mid: id });
                 await transaction.delete(this.ctx.service.materialBills.tableName, { mid: id });
                 await transaction.delete(this.ctx.service.materialList.tableName, { mid: id });
                 await transaction.delete(this.ctx.service.materialListNotjoin.tableName, { mid: id });
+                await transaction.delete(this.ctx.service.materialBillsHistory.tableName, { mid: id });
+                // 如果存在上一期,把上一期的quantity,pre_tp添加到bill中
+                const materialInfo = await this.getDataById(id);
+                if (materialInfo.order > 1) {
+                    const sql = 'UPDATE ' + this.ctx.service.materialBills.tableName + ' as mb, ' +
+                        this.ctx.service.materialBillsHistory.tableName + ' as mbh ' +
+                        'SET mb.`quantity` = mbh.`quantity`, mb.`pre_tp` = mbh.`pre_tp` ' +
+                        'WHERE mbh.`tid` = ? AND mbh.`order` = ? AND mbh.`mb_id` = mb.`id`';
+                    const sqlParam = [this.ctx.tender.id, materialInfo.order - 1];
+                    await transaction.query(sql, sqlParam);
+                }
+                await transaction.delete(this.tableName, { id });
                 await transaction.commit();
                 return true;
             } catch (err) {

+ 20 - 11
app/service/material_audit.js

@@ -9,6 +9,7 @@
  */
 
 const auditConst = require('../const/audit').material;
+const materialConst = require('../const/material');
 // const smsTypeConst = require('../const/sms_type');
 const SMS = require('../lib/sms');
 
@@ -188,19 +189,21 @@ module.exports = app => {
                     id: materialId, status: auditConst.status.checking,
                 });
 
-                // 把material_bills本期应耗数量设置成s_quantity里的历史本期应耗数量
-                const materialBillsData = await this.ctx.service.materialBills.getAllDataByCondition({ tid: this.ctx.tender.id });
+                // 本期应耗数量和上期调差金额插入到material_bills_history表里
+                const materialBillsData = await this.ctx.service.materialBills.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
+                const mbhList = [];
                 for (const mb of materialBillsData) {
-                    const order = this.ctx.material.order;
-                    const s_quantity = mb.s_quantity !== null ? mb.s_quantity.split(',') : [];
-                    const quantity = mb.quantity !== null ? mb.quantity : '';
-                    if (s_quantity.length === order) {
-                        s_quantity[order - 1] = quantity;
-                    } else {
-                        s_quantity.push(quantity);
-                    }
-                    await transaction.update(this.ctx.service.materialBills.tableName, { id: mb.id, s_quantity: s_quantity.join(',') });
+                    const newMbh = {
+                        tid: this.ctx.tender.id,
+                        mid: this.ctx.material.id,
+                        order: this.ctx.material.order,
+                        mb_id: mb.id,
+                        quantity: mb.quantity,
+                        pre_tp: mb.pre_tp,
+                    };
+                    mbhList.push(newMbh);
                 }
+                await transaction.insert(this.ctx.service.materialBillsHistory.tableName, mbhList);
 
                 // 添加短信通知-需要审批提醒功能
                 // const smsUser = await this.ctx.service.projectAccount.getDataById(audit.aid);
@@ -336,6 +339,12 @@ module.exports = app => {
                 });
                 // 拷贝新一次审核流程列表
                 await transaction.insert(this.tableName, auditors);
+                // 删除material_bills_history信息
+                await transaction.delete(this.ctx.service.materialBillsHistory.tableName, {
+                    tid: this.ctx.tender.id,
+                    order: this.ctx.material.order,
+                });
+
                 // 计算该审批人最终数据
                 // await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
                 // 复制一份最新数据给原报

+ 41 - 0
app/service/material_bills.js

@@ -68,9 +68,50 @@ module.exports = app => {
                 throw '数据错误';
             }
             delete data.in_time;
+            delete data.m_tp;
             // 判断是否可修改
             return await this.db.update(this.tableName, data);
         }
+
+        async updateNewMaterial(transaction, tid, mid) {
+            const materialBillsData = await this.getAllDataByCondition({ where: { tid } });
+            let m_tp = 0;
+            for (const mb of materialBillsData) {
+                const one_tp = await this.calcQuantityByMB(transaction, mid, mb);
+                m_tp = this.ctx.helper.add(m_tp, one_tp);
+            }
+            return m_tp;
+        }
+
+        /**
+         * 修改quantity,m_spread值和返回单条调差金额(新增一期)
+         * @param transaction
+         * @param mid
+         * @param mb
+         * @returns {Promise<*>}
+         */
+        async calcQuantityByMB(transaction, mid, mb) {
+            if (mb.t_type === 1) {
+                const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.ctx.service.materialList.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `is_join`=1';
+                const sqlParam = [mid, mb.id];
+                const mb_quantity = await transaction.queryOne(sql, sqlParam);
+                console.log(mb_quantity);
+                // 取历史期记录获取截止上期调差金额
+                const updateData = {
+                    id: mb.id,
+                    quantity: this.ctx.helper.round(mb_quantity.quantity, 3),
+                    pre_tp: mb.quantity && mb.m_spread !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.pre_tp, this.ctx.helper.mul(mb.quantity, mb.m_spread)), 2) : mb.pre_tp,
+                };
+                await transaction.update(this.tableName, updateData);
+                return await this.ctx.helper.round(this.ctx.helper.mul(mb_quantity.quantity, mb.m_spread), 2);
+            }
+            const updateData = {
+                id: mb.id,
+                pre_tp: mb.quantity && mb.m_spread !== null ? this.ctx.helper.round(this.ctx.helper.add(mb.pre_tp, this.ctx.helper.mul(mb.quantity, mb.m_spread)), 2) : mb.pre_tp,
+            };
+            await transaction.update(this.tableName, updateData);
+            return await this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, mb.m_spread), 2);
+        }
     }
 
     return MaterialBills;

+ 41 - 0
app/service/material_bills_history.js

@@ -0,0 +1,41 @@
+'use strict';
+
+/**
+ * 工料历史期数据表 数据模型
+ *
+ * @author Mai
+ * @date 2018/8/13
+ * @version
+ */
+
+
+module.exports = app => {
+    class MaterialBillsHistory extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'material_bills_history';
+        }
+
+        /**
+         * 获取历史本期应耗数量和上期调差金额
+         * @param mid
+         * @param order
+         * @param mb_id
+         * @returns {Promise<*[]>}
+         */
+        async getByMbId(mid, order, mb_id) {
+            const result = await this.getDataByCondition({ mid, order, mb_id });
+            if (result) {
+                return [result.quantity, result.pre_tp];
+            }
+            return [null, null];
+        }
+    }
+    return MaterialBillsHistory;
+};

+ 3 - 3
app/service/material_list.js

@@ -155,14 +155,13 @@ module.exports = app => {
             if (!mbInfo) {
                 throw '不存在该工料';
             }
-            const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.tableName + ' WHERE `mid`=? AND `mb_id`=?';
+            const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `is_join`=1';
             const sqlParam = [this.ctx.material.id, mb_id];
             const mb_quantity = await transaction.queryOne(sql, sqlParam);
             console.log(mb_quantity);
-            mbInfo.quantity = this.ctx.helper.round(mb_quantity.quantity, 3);
             const updateData = {
                 id: mb_id,
-                quantity: mbInfo.quantity,
+                quantity: this.ctx.helper.round(mb_quantity.quantity, 3),
             };
             await transaction.update(this.ctx.service.materialBills.tableName, updateData);
             // 计算本期总金额
@@ -221,6 +220,7 @@ module.exports = app => {
                     mx_id: ml.mx_id,
                     gather_qty,
                     quantity: ml.quantity,
+                    is_join: ml.is_join,
                     in_time: new Date(),
                 };
                 copyMLArray.push(newMaterialList);

+ 75 - 16
app/service/material_list_notjoin.js

@@ -30,21 +30,30 @@ module.exports = app => {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
-            const newListNotJoin = {
-                tid: this.ctx.tender.id,
-                mid: this.ctx.material.id,
-                gcl_id: data.gcl_id,
-                xmj_id: data.id,
-                mx_id: data.mx_id !== undefined ? data.mx_id : '',
-                in_time: new Date(),
-            };
-
-            // 新增不参与调差清单
-            const result = await this.db.insert(this.tableName, newListNotJoin);
-            if (result.affectedRows === 0) {
-                throw '新增不参与调差清单数据失败';
+            const transaction = await this.db.beginTransaction();
+            try {
+                const newListNotJoin = {
+                    tid: this.ctx.tender.id,
+                    mid: this.ctx.material.id,
+                    gcl_id: data.gcl_id,
+                    xmj_id: data.id,
+                    mx_id: data.mx_id !== undefined ? data.mx_id : null,
+                    in_time: new Date(),
+                };
+                data.xmj_id = data.id;
+                data.mx_id = data.mx_id !== undefined ? data.mx_id : null;
+                await this.updateAllMaterials(transaction, data, 'add');
+                // 新增不参与调差清单
+                const result = await transaction.insert(this.tableName, newListNotJoin);
+                if (result.affectedRows === 0) {
+                    throw '新增不参与调差清单数据失败';
+                }
+                await transaction.commit();
+                return await this.getDataById(result.insertId);
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
             }
-            return await this.getDataById(result.insertId);
         }
 
         /**
@@ -56,8 +65,58 @@ module.exports = app => {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
-            // 判断是否可删
-            return await this.deleteById(id);
+            const transaction = await this.db.beginTransaction();
+            try {
+                const notJoinInfo = await this.getDataById(id);
+                await this.updateAllMaterials(transaction, notJoinInfo, 'del');
+                // 判断是否可删
+                const result = await transaction.delete(this.tableName, { id });
+                await transaction.commit();
+                return result;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        /**
+         * 修改调差list和bill和material对应值
+         * @param transaction
+         * @returns {Promise<void>}
+         */
+        async updateAllMaterials(transaction, data, type) {
+            // 先判断material_list是否存在值并quantity不为null
+            const searchSql = {
+                mid: this.ctx.material.id,
+                gcl_id: data.gcl_id,
+                xmj_id: data.xmj_id,
+            };
+            if (data.mx_id !== null) {
+                searchSql.mx_id = data.mx_id;
+            }
+            const materialListData = await this.ctx.service.materialList.getAllDataByCondition({
+                where: searchSql,
+            });
+            console.log(data);
+            console.log(materialListData);
+            if (materialListData && materialListData.length !== 0) {
+                // 对应修改更新本期应耗数量值和总的本期金额计算
+                const mbIdList = [];
+                for (const ml of materialListData) {
+                    const updateData = {
+                        id: ml.id,
+                        is_join: type === 'add' ? 0 : 1,
+                    };
+                    if (mbIdList.indexOf(ml.mb_id) === -1) {
+                        mbIdList.push(ml.mb_id);
+                    }
+                    await transaction.update(this.ctx.service.materialList.tableName, updateData);
+                }
+                // 重新计算金额
+                for (const mb_id of mbIdList) {
+                    await this.service.materialList.calcQuantityByML(transaction, mb_id);
+                }
+            }
         }
 
         /**

+ 59 - 0
app/service/stage.js

@@ -12,6 +12,7 @@ const auditConst = require('../const/audit').stage;
 const payConst = require('../const/deal_pay.js');
 const fs = require('fs');
 const path = require('path');
+const _ = require('lodash');
 
 module.exports = app => {
     class Stage extends app.BaseService {
@@ -358,6 +359,64 @@ module.exports = app => {
                 throw err;
             }
         }
+
+        /**
+         * 获取 多期的 计算基数 -(材料调差调用)
+         * @returns {Promise<any>}
+         */
+        async getMaterialCalcBase(stage_list, tenderInfo) {
+            const calcBase = JSON.parse(JSON.stringify(payConst.calcBase));
+            const param = tenderInfo.deal_param;
+            for (const cb of calcBase) {
+                switch (cb.code) {
+                    case 'htj':
+                        cb.value = param.contractPrice;
+                        break;
+                    case 'zlje':
+                        cb.value = param.zanLiePrice;
+                        break;
+                    case 'htjszl':
+                        cb.value = this.ctx.helper.sub(param.contractPrice, param.zanLiePrice);
+                        break;
+                    case 'kgyfk':
+                        cb.value = param.startAdvance;
+                        break;
+                    case 'clyfk':
+                        cb.value = param.materialAdvance;
+                        break;
+                    case 'bqwc':
+                        const sum = await this.ctx.service.stageBills.getSumTotalPriceByMaterial(stage_list);
+                        cb.value = this.ctx.helper.add(sum.contract_tp, sum.qc_tp);
+                        break;
+                    case 'ybbqwc':
+                        const sumGcl = await this.ctx.service.stageBills.getSumTotalPriceGclByMaterial(stage_list, '^1[0-9]{2}-');
+                        cb.value = this.ctx.helper.add(sumGcl.contract_tp, sumGcl.qc_tp);
+                        break;
+                    default:
+                        cb.value = 0;
+                }
+            }
+            return calcBase;
+        }
+
+        /**
+         * 获取必要的stage信息调用curTimes, curOrder, id , times, curAuditor(材料调差)
+         * @param stage_id_list
+         * @returns {Promise<void>}
+         */
+        async getStageMsgByStageId(stage_id_list) {
+            const list = [];
+            stage_id_list = stage_id_list.split(',');
+            for (const sid of stage_id_list) {
+                const stage = await this.getDataById(sid);
+                stage.auditors = await this.service.stageAudit.getAuditors(stage.id, stage.times);
+                stage.curAuditor = await this.service.stageAudit.getCurAuditor(stage.id, stage.times);
+                stage.curOrder = _.max(_.map(stage.auditors, 'order'));
+                stage.curTimes = stage.times;
+                list.push(stage);
+            }
+            return list;
+        }
     }
 
     return Stage;

+ 43 - 1
app/service/stage_bills.js

@@ -416,10 +416,52 @@ module.exports = app => {
                     ' WHERE Bills.lid = ?';
                 const sqlParam = [tid, sid, lid];
                 const result = await this.db.queryOne(sql, sqlParam);
-                gather_qty = this.ctx.helper.add(gather_qty, this.ctx.helper.add(result.contract_qty, result.qc_qty));
+                if (result) {
+                    gather_qty = this.ctx.helper.add(gather_qty, this.ctx.helper.add(result.contract_qty, result.qc_qty));
+                }
             }
             return gather_qty !== 0 ? gather_qty : null;
         }
+
+        async getSumTotalPriceByMaterial(stage_list) {
+            let contract_tp = 0;
+            let qc_tp = 0;
+            for (const stage of stage_list) {
+                const sql = 'SELECT Sum(`contract_tp`) As `contract_tp`, Sum(`qc_tp`) As `qc_tp` FROM ' + this.tableName + ' As Bills ' +
+                    '  INNER JOIN ( ' +
+                    '    SELECT MAX(`times` * ' + timesLen + ' + `order`) As `flow`, `lid` From ' + this.tableName +
+                    '      WHERE `times` <= ? AND `order` <= ?' +
+                    '      GROUP BY `lid`' +
+                    '  ) As MaxFilter ' +
+                    '  ON (Bills.times * ' + timesLen + ' + `order`) = MaxFilter.flow And Bills.lid = MaxFilter.lid' +
+                    '  WHERE Bills.sid = ?';
+                const sqlParam = [stage.curTimes, stage.curOrder, stage.id];
+                const result = await this.db.queryOne(sql, sqlParam);
+                if (result) {
+                    contract_tp = this.ctx.helper.add(contract_tp, result.contract_tp);
+                    qc_tp = this.ctx.helper.add(qc_tp, result.qc_tp);
+                }
+            }
+            return { contract_tp, qc_tp };
+        }
+
+        async getSumTotalPriceGclByMaterial(stage_list, regText) {
+            let contract_tp = 0;
+            let qc_tp = 0;
+            for (const stage of stage_list) {
+                let result = null;
+                if (regText) {
+                    result = await this.getSumTotalPriceFilter(stage, 'REGEXP', regText);
+                } else {
+                    result = await this.getSumTotalPriceFilter(stage, '<>', this.db.escape(''));
+                }
+                if (result) {
+                    contract_tp = this.ctx.helper.add(contract_tp, result.contract_tp);
+                    qc_tp = this.ctx.helper.add(qc_tp, result.qc_tp);
+                }
+            }
+            return { contract_tp, qc_tp };
+        }
     }
 
     return StageBills;

+ 3 - 1
app/service/stage_pos.js

@@ -505,7 +505,9 @@ module.exports = app => {
                     ' WHERE Pos.lid = ? AND Pos.pid = ?';
                 const sqlParam = [tid, sid, tid, sid, lid, pid];
                 const result = await this.db.queryOne(sql, sqlParam);
-                gather_qty = this.ctx.helper.add(gather_qty, this.ctx.helper.add(result.contract_qty, result.qc_qty));
+                if (result) {
+                    gather_qty = this.ctx.helper.add(gather_qty, this.ctx.helper.add(result.contract_qty, result.qc_qty));
+                }
             }
             return gather_qty !== 0 ? gather_qty : null;
         }

+ 5 - 0
app/view/material/info.ejs

@@ -58,6 +58,10 @@
         </div>
     </div>
 </div>
+<div style="display: none">
+    <img src="/public/images/ellipsis_horizontal.png" id="ellipsis-icon" />
+    <img src="/public/images/icon-ok.png" id="icon-ok" />
+</div>
 <% if ((material.status === auditConst.status.uncheck || material.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === material.user_id) {%>
 <script>
     const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');
@@ -71,4 +75,5 @@
     const materialID = <%- material.id %>;
     const m_tp = <%= material.m_tp !== null ? material.m_tp : 0 %>;
     const pre_tp = <%= material.pre_tp !== null ? material.pre_tp : 0 %>;
+    const calcBase = JSON.parse('<%- JSON.stringify(calcBase) %>');
 </script>

+ 34 - 1
app/view/material/info_modal.ejs

@@ -1,2 +1,35 @@
-
+<!--消耗量计算-->
+<div class="modal fade" id="bcyy" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">消耗量计算</h5>
+            </div>
+            <div class="modal-body">
+                <div class="form-group">
+                    <input class="form-control" value="" id="expr" type="text">
+                    <p class="form-text" id="expr_select">
+                        <button class="btn btn-outline-primary btn-sm">+</button>
+                        <button class="btn btn-outline-primary btn-sm">-</button>
+                        <button class="btn btn-outline-primary btn-sm">*</button>
+                        <button class="btn btn-outline-primary btn-sm">/</button>
+                        <button class="btn btn-outline-primary btn-sm">(</button>
+                        <button class="btn btn-outline-primary btn-sm">)</button>
+                    </p>
+                </div>
+                <table class="table table-sm table-bordered">
+                    <tr><th>基数</th><th>代号</th><th>值</th></tr>
+                    <% for (let iBase = 0; iBase < calcBase.length; iBase++) { %>
+                    <tr><td><%- calcBase[iBase].name %></td><td><%- calcBase[iBase].code %></td><td><%- calcBase[iBase].value %></td></tr>
+                    <% } %>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <input type="hidden" id="materialbillsId" value="" />
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-primary" id="expr_btn">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
 <% include ./audit_modal.ejs %>