Просмотр исходного кода

调差清单本期调差数量及汇总计算

ellisran 3 недель назад
Родитель
Сommit
7b0600c68d

+ 1 - 0
app/const/account_permission.js

@@ -54,6 +54,7 @@ const permission = {
             { title: '批量设置材差清单', value: 1, hint: '开启该选项,当前账号可设置允许调差的清单', hintIcon: 'fa-question-circle' },
             { title: '修改调差工料消耗量', value: 2, hint: '开启该选项,可在新材差期修改工料的消耗量', hintIcon: 'fa-question-circle' },
             // { title: '修改材料税税率', value: 3, hint: '开启该选项,可在新材差期修改材料税税率', hintIcon: 'fa-question-circle' },
+            { title: '修改调差数量', value: 4, hint: '开启该选项,可在调差清单页修改本期调差数量', hintIcon: 'fa-question-circle' },
         ],
     },
     other: {

+ 18 - 1
app/controller/material_controller.js

@@ -555,6 +555,7 @@ module.exports = app => {
             try {
                 await this._getMaterialAuditViewData(ctx);
                 await this._setEditListPermission(ctx);
+                await this._setEditQtyPermission(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
                 // 根据期判断需要获取的工料信息值表
                 const searchsql = { tid: ctx.tender.id };
@@ -612,6 +613,7 @@ module.exports = app => {
                 responseData.data.materialListData = await ctx.service.materialList.getMaterialData(ctx.tender.id, ctx.material.id);
                 responseData.data.materialNotJoinListData = await ctx.service.materialListNotjoin.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id, type: 1 } });
                 responseData.data.materialNotChangeListData = await ctx.service.materialListNotjoin.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id, type: 2 } });
+                responseData.data.materialQtyListData = await ctx.service.materialListQty.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } });
                 responseData.data.materialSelfListData = await ctx.service.materialListSelf.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } });
                 // 获取清单数据
                 responseData.data.ledger = await ctx.service.ledger.getData(ctx.tender.id);
@@ -970,7 +972,7 @@ module.exports = app => {
                     msg: '',
                     data: {},
                 };
-                const notControlList = ['join', 'notjoin', 'change', 'notchange', 'self', 'noself', 'useOther', 'add', 'del', 'update', 'paste'];
+                const notControlList = ['join', 'notjoin', 'change', 'notchange', 'self', 'noself', 'useOther', 'add', 'del', 'update', 'paste', 'update-qty', 'pastes-qty'];
                 if (ctx.subProject.page_show.openMaterialChecklist && ctx.app._.indexOf(notControlList, data.type) === -1) {
                     throw '清单设置功能已启动,请前往清单设置页操作清单内容';
                 }
@@ -1035,10 +1037,20 @@ module.exports = app => {
                         }
                         responseData.data = await ctx.service.materialList.saves(data.updateData, false, data.ms_id);
                         break;
+                    case 'update-qty':
+                        if (!data.updateData) {
+                            throw '参数有误';
+                        }
+                        responseData.data = await ctx.service.materialListQty.save(data.updateData, data.ms_id);
+                        break;
                     case 'pastes':
                         responseData.data = await ctx.service.materialList.savePastes(data.updateData, false, data.ms_id);
                         // 取所有工料表
                         break;
+                    case 'pastes-qty':
+                        responseData.data = await ctx.service.materialListQty.savePastes(data.updateData, data.ms_id);
+                        // 取所有工料表
+                        break;
                     default: throw '参数有误';
                 }
                 ctx.body = responseData;
@@ -1727,6 +1739,11 @@ module.exports = app => {
             ctx.material.editTaxPermission = permission && permission.material !== undefined && permission.material.indexOf('3') !== -1;
         }
 
+        async _setEditQtyPermission(ctx) {
+            const permission = ctx.session.sessionUser.permission;
+            ctx.material.editQtyPermission = permission && permission.material !== undefined && permission.material.indexOf('4') !== -1;
+        }
+
         async _setChecklistPermission(ctx) {
             // 清单设置权限判断
             ctx.material.checklistPermission = false;

+ 1 - 0
app/controller/report_controller.js

@@ -426,6 +426,7 @@ module.exports = app => {
                     }
                 }
             } catch (err) {
+                console.log(err);
                 this.log(err);
                 ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
             }

+ 13 - 0
app/extend/helper.js

@@ -1661,6 +1661,19 @@ module.exports = {
             console.log(err);
         }
     },
+    getQtySourceValue(item, qty_source, no_qc_qty = 0) {
+        let value = 0;
+        switch (qty_source) {
+            case qtySourceValueConst.gather_qty: value = item.gather_qty; break;
+            case qtySourceValueConst.contract_qty: value = item.contract_qty; break;
+            case qtySourceValueConst.gather_minus_qty: value = this.add(item.gather_qty, item.qc_minus_qty); break;
+            default: throw '未配置计量来源出错';
+        }
+        if (qty_source !== qtySourceValueConst.contract_qty && no_qc_qty) {
+            value = item.contract_qty;
+        }
+        return value;
+    },
     getQtySource(qty_source, no_qc_qty = 0) {
         let qty = '';
         switch (qty_source) {

+ 16 - 3
app/public/js/material.js

@@ -1268,7 +1268,8 @@ $(document).ready(() => {
         {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 100, formatter: '@'},
         {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 150, formatter: '@'},
         {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 70, formatter: '@'},
-        {title: '本期应耗', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100, formatter: '@'},
+        {title: '本期计量应耗', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100, formatter: '@'},
+        {title: '本期应耗', colSpan: '1', rowSpan: '2', field: 'qty', hAlign: 2, width: 100, formatter: '@'},
     ];
     const materialSourceSpread = SpreadJsObj.createNewSpread($('#material-source-spread')[0]);
     const materialSourceSpreadSetting = {
@@ -1291,7 +1292,8 @@ $(document).ready(() => {
         {title: '分项工程', colSpan: '1', rowSpan: '2', field: 'fxgc', hAlign: 0, width: 80, formatter: '@', visible: false},
         {title: '细目', colSpan: '1', rowSpan: '2', field: 'jldy', hAlign: 0, width: 80, formatter: '@', visible: false},
         {title: '计量单元', colSpan: '1', rowSpan: '2', field: 'bwmx', hAlign: 0, width: 80, formatter: '@'},
-        {title: '本期应耗数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100, type: 'Number'},
+        {title: '本期计量数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100, type: 'Number'},
+        {title: '本期应耗数量', colSpan: '1', rowSpan: '2', field: 'qty', hAlign: 2, width: 100, type: 'Number'},
         {title: '本期调差金额', colSpan: '1', rowSpan: '2', field: 'm_tp', hAlign: 2, width: 100, type: 'Number'},
     ];
     const materialXmjGatherSpread = SpreadJsObj.createNewSpread($('#material-xmj-gather-spread')[0]);
@@ -1550,9 +1552,11 @@ $(document).ready(() => {
                                 name: gcl.name,
                                 unit: gcl.unit,
                                 quantity: ZhCalc.mul(calcQty(l), l.quantity),
+                                qty: ZhCalc.mul(getQty(l), l.quantity),
                             });
                         } else {
                             showSourceList[index].quantity = ZhCalc.add(showSourceList[index].quantity, ZhCalc.mul(calcQty(l), l.quantity));
+                            showSourceList[index].qty = ZhCalc.add(showSourceList[index].qty, ZhCalc.mul(getQty(l), l.quantity));
                         }
 
                         // const indexXmj = _.findIndex(showXmjList, { gcl_id: l.gcl_id, xmj_id: l.xmj_id, mx_id: l.mx_id });
@@ -1566,9 +1570,11 @@ $(document).ready(() => {
                             if (!glx) {
                                 const newGcl = _.cloneDeep(xmj);
                                 newGcl.quantity = ZhCalc.mul(calcQty(l), l.quantity);
+                                newGcl.qty = ZhCalc.mul(getQty(l), l.quantity);
                                 showXmjList.push(newGcl);
                             } else {
                                 glx.quantity = ZhCalc.add(glx.quantity, ZhCalc.mul(calcQty(l), l.quantity));
+                                glx.qty = ZhCalc.add(glx.qty, ZhCalc.mul(getQty(l), l.quantity));
                             }
                         }
                     }
@@ -1577,7 +1583,7 @@ $(document).ready(() => {
             const data = SpreadJsObj.getSelectObject(materialSpread.getActiveSheet());
             for (const xmj of showXmjList) {
                 const m_spread = data ? (data.m_spread || data.spread) : 0;
-                xmj.m_tp = ZhCalc.mul(m_spread, xmj.quantity);
+                xmj.m_tp = ZhCalc.mul(m_spread, xmj.qty);
             }
         }
         // 按清单编号排序
@@ -1586,6 +1592,13 @@ $(document).ready(() => {
         SpreadJsObj.loadSheetData(materialXmjGatherSheet, SpreadJsObj.DataType.Data, showXmjList);
     }
 
+    function getQty(info) {
+        if (info && info.qty !== null) {
+            return info.qty;
+        }
+        return calcQty(info);
+    }
+
     function calcQty(info) {
         let qty = '';
         switch (qtySource) {

+ 21 - 0
app/public/js/material_checklist.js

@@ -34,6 +34,18 @@ function findNotChangeLeafXmj(x, type = '') {
     });
 }
 
+function findQtyLeafXmj(x, type = '', get_ms_id = null) {
+    const ms_id = get_ms_id ? get_ms_id : (isStageSelf ? materialStageData[0].id : null);
+    if (type === 'index') {
+        return qtyList.findIndex(function (item) {
+            return item.gcl_id === x.gcl_id && item.xmj_id === x.id && (ms_id ? item.ms_id === ms_id : true) && (x.mx_id === undefined || (x.mx_id !== undefined && x.mx_id === item.mx_id));
+        });
+    }
+    return qtyList.find(function (item) {
+        return item.gcl_id === x.gcl_id && item.xmj_id === x.id && (ms_id ? item.ms_id === ms_id : true) && (x.mx_id === undefined || (x.mx_id !== undefined && x.mx_id === item.mx_id));
+    });
+}
+
 function getPasteHint (str, row = '') {
     let returnObj = str;
     if (row) {
@@ -144,6 +156,7 @@ $(document).ready(() => {
         // materialListData = result.materialListData;
         notJoinList = result.materialNotJoinListData;
         notChangeList = result.materialNotChangeListData;
+        qtyList = result.materialQtyListData;
         materialChecklistData = result.materialChecklistData;
         gclList = result.gclList;
         if (isStageSelf) {
@@ -441,6 +454,7 @@ $(document).ready(() => {
         for (const xmj of gcl) {
             const notx = findNotJoinLeafXmj(xmj);
             const notx2 = findNotChangeLeafXmj(xmj);
+            const qtyInfo = findQtyLeafXmj(xmj, '', ms_id);
             const data = {
                 xmj_id: xmj.id,
                 gcl_id: xmj.gcl_id,
@@ -449,6 +463,7 @@ $(document).ready(() => {
                 qc_qty: xmj.qc_qty,
                 qc_minus_qty: xmj.qc_minus_qty,
                 gather_qty: xmj.gather_qty,
+                qty: qtyInfo ? qtyInfo.qty : null,
                 is_join: notx !== undefined ? 0 : notx2 !== undefined ? 2 : 1,
             };
             if (ms_id) data.ms_id = ms_id;
@@ -467,6 +482,7 @@ $(document).ready(() => {
                         for (const xmj of leafXmjs) {
                             const notx = findNotJoinLeafXmj(xmj);
                             const notx2 = findNotChangeLeafXmj(xmj);
+                            const qtyInfo = findQtyLeafXmj(xmj, '', ms.id);
                             const data = {
                                 xmj_id: xmj.id,
                                 gcl_id: xmj.gcl_id,
@@ -475,6 +491,7 @@ $(document).ready(() => {
                                 qc_qty: xmj.qc_qty,
                                 qc_minus_qty: xmj.qc_minus_qty,
                                 gather_qty: xmj.gather_qty,
+                                qty: qtyInfo ? qtyInfo.qty : null,
                                 is_join: notx !== undefined ? 0 : notx2 !== undefined ? 2 : 1,
                                 ms_id: ms.id,
                             };
@@ -1390,6 +1407,7 @@ $(document).ready(() => {
                 for (const xmj of gcl) {
                     const notx = findNotJoinLeafXmj(xmj);
                     const notx2 = findNotChangeLeafXmj(xmj);
+                    const qtyInfo = findQtyLeafXmj(xmj, '', ms_id);
                     const data = {
                         xmj_id: xmj.id,
                         gcl_id: xmj.gcl_id,
@@ -1398,6 +1416,7 @@ $(document).ready(() => {
                         qc_qty: xmj.qc_qty,
                         qc_minus_qty: xmj.qc_minus_qty,
                         gather_qty: xmj.gather_qty,
+                        qty: qtyInfo ? qtyInfo.qty : null,
                         is_join: notx !== undefined ? 0 : notx2 !== undefined ? 2 : 1,
                     };
                     if (ms_id) data.ms_id = ms_id;
@@ -1419,6 +1438,7 @@ $(document).ready(() => {
                                 for (const xmj of leafXmjs) {
                                     const notx = findNotJoinLeafXmj(xmj);
                                     const notx2 = findNotChangeLeafXmj(xmj);
+                                    const qtyInfo = findQtyLeafXmj(xmj, '', ms.id);
                                     const data = {
                                         xmj_id: xmj.id,
                                         gcl_id: xmj.gcl_id,
@@ -1427,6 +1447,7 @@ $(document).ready(() => {
                                         qc_qty: xmj.qc_qty,
                                         qc_minus_qty: xmj.qc_minus_qty,
                                         gather_qty: xmj.gather_qty,
+                                        qty: qtyInfo ? qtyInfo.qty : null,
                                         is_join: notx !== undefined ? 0 : notx2 !== undefined ? 2 : 1,
                                         ms_id: ms.id,
                                     };

+ 281 - 24
app/public/js/material_list.js

@@ -45,6 +45,18 @@ function findSelfLeafXmj(x, type = '') {
     });
 }
 
+function findQtyLeafXmj(x, type = '', get_ms_id = null) {
+    const ms_id = get_ms_id ? get_ms_id : (isStageSelf ? parseInt($('#myTab').find('.active').data('msid')) : null);
+    if (type === 'index') {
+        return qtyList.findIndex(function (item) {
+            return item.gcl_id === x.gcl_id && item.xmj_id === x.id && (ms_id ? item.ms_id === ms_id : true) && (x.mx_id === undefined || (x.mx_id !== undefined && x.mx_id === item.mx_id));
+        });
+    }
+    return qtyList.find(function (item) {
+        return item.gcl_id === x.gcl_id && item.xmj_id === x.id && (ms_id ? item.ms_id === ms_id : true) && (x.mx_id === undefined || (x.mx_id !== undefined && x.mx_id === item.mx_id));
+    });
+}
+
 function getMpSpreadByMBData(id) {
     const info = materialBillsData.find(function (item) {
         return item.id === parseInt(id);
@@ -63,19 +75,23 @@ function getMaterialListByLeafXmj(gcl_id, xmj_id, mx_id = '') {
     return list;
 }
 
+function getOneQtyByLeafXmj(xmj) {
+    const qtyInfo = findQtyLeafXmj(xmj);
+    if (qtyInfo && qtyInfo.qty !== null) {
+        return qtyInfo.qty;
+    }
+    const notx2 = findNotChangeLeafXmj(xmj);
+    return calcQty(xmj, notx2 !== undefined ? 2 : 1);
+}
+
 function calcOneBQJC(xmj) {
     let jiacha = 0;
     const notx = findNotJoinLeafXmj(xmj);
     if (notx === undefined) {
         const list = xmj.mx_id !== undefined ? getMaterialListByLeafXmj(xmj.gcl_id, xmj.id, xmj.mx_id) : getMaterialListByLeafXmj(xmj.gcl_id, xmj.id);
-        const notx2 = findNotChangeLeafXmj(xmj);
-        // if (notx2 !== undefined) {
-        //     for (const l of list) {
-        //         jiacha = ZhCalc.add(jiacha, ZhCalc.mul(ZhCalc.mul(xmj.contract_qty, l.quantity), getMpSpreadByMBData(l.mb_id)));
-        //     }
-        // } else {
         for (const l of list) {
-            jiacha = ZhCalc.add(jiacha, ZhCalc.mul(ZhCalc.mul(calcQty(xmj, notx2 !== undefined ? 2 : 1), l.quantity), getMpSpreadByMBData(l.mb_id)));
+            const qty = getOneQtyByLeafXmj(xmj);
+            jiacha = ZhCalc.add(jiacha, ZhCalc.mul(ZhCalc.mul(qty, l.quantity), getMpSpreadByMBData(l.mb_id)));
         }
         // }
     }
@@ -113,6 +129,7 @@ function calculateJiaCha(data, index) {
         for (const [index, xmj] of gcld.leafXmjs.entries()) {
             const jiacha = calcOneBQJC(xmj);
             gcld.leafXmjs[index].jiacha = jiacha !== 0 ? jiacha : null;
+            gcld.leafXmjs[index].qty = getOneQtyByLeafXmj(xmj);
             total_jiacha += jiacha;
         }
         gcld.total_jiacha = ZhCalc.round(total_jiacha, materialDecimal.tp)
@@ -122,6 +139,7 @@ function calculateJiaCha(data, index) {
             for (const [index, xmj] of gcld.leafXmjs.entries()) {
                 const jiacha = calcOneBQJC(xmj);
                 gcld.leafXmjs[index].jiacha = jiacha !== 0 ? jiacha : null;
+                gcld.leafXmjs[index].qty = getOneQtyByLeafXmj(xmj);
                 total_jiacha += jiacha;
             }
             gcld.total_jiacha = ZhCalc.round(total_jiacha, materialDecimal.tp)
@@ -247,6 +265,7 @@ $(document).ready(() => {
             for (const [index, xmj] of gcl.leafXmjs.entries()) {
                 const jiacha = calcOneBQJC(xmj);
                 gcl.leafXmjs[index].jiacha = jiacha !== 0 ? ZhCalc.round(jiacha, materialDecimal.tp) : null;
+                gcl.leafXmjs[index].qty = getOneQtyByLeafXmj(xmj);
             }
             const leafXmjs = gcl.leafXmjs.filter(item => {
                 return item.qc_qty || item.contract_qty || item.qc_minus_qty;
@@ -268,27 +287,28 @@ $(document).ready(() => {
     // 项目明细table
     const leafXmjSpread = SpreadJsObj.createNewSpread($('#leaf-xmj-spread')[0]);
     const leafXmjCols = [
-        {title: '项目节|编号', colSpan: '2|1', rowSpan: '1|1', field: 'code', hAlign: 0, width: 80, formatter: '@'},
-        {title: '|项目节名称', colSpan: '|1', rowSpan: '|1', field: 'jldy', hAlign: 0, width: 100, formatter: '@'},
-        {title: '计量单元|计量单元', colSpan: '2|1', rowSpan: '1|1', field: 'bwmx', hAlign: 0, width: 100, formatter: '@'},
-        {title: '|复核数量', colSpan: '|1', rowSpan: '|1', field: 'quantity', hAlign: 0, width: 80, type: 'Number'},
-        {title: '部位信息|单位工程', colSpan: '3|1', rowSpan: '1|1', field: 'dwgc', hAlign: 0, width: 100, formatter: '@'},
-        {title: '|分部工程', colSpan: '|1', rowSpan: '|1', field: 'fbgc', hAlign: 0, width: 100, formatter: '@'},
-        {title: '|分项工程', colSpan: '|1', rowSpan: '|1', field: 'fxgc', hAlign: 0, width: 180, formatter: '@'},
+        {title: '项目节|编号', colSpan: '2|1', rowSpan: '1|1', field: 'code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+        {title: '|项目节名称', colSpan: '|1', rowSpan: '|1', field: 'jldy', hAlign: 0, width: 100, formatter: '@', readOnly: true},
+        {title: '计量单元|计量单元', colSpan: '2|1', rowSpan: '1|1', field: 'bwmx', hAlign: 0, width: 100, formatter: '@', readOnly: true},
+        {title: '|复核数量', colSpan: '|1', rowSpan: '|1', field: 'quantity', hAlign: 0, width: 80, type: 'Number', readOnly: true},
+        {title: '部位信息|单位工程', colSpan: '3|1', rowSpan: '1|1', field: 'dwgc', hAlign: 0, width: 100, formatter: '@', readOnly: true},
+        {title: '|分部工程', colSpan: '|1', rowSpan: '|1', field: 'fbgc', hAlign: 0, width: 100, formatter: '@', readOnly: true},
+        {title: '|分项工程', colSpan: '|1', rowSpan: '|1', field: 'fxgc', hAlign: 0, width: 180, formatter: '@', readOnly: true},
     ];
     if (qtySource === qtySourceValueConst.gather_qty) {
-        leafXmjCols.push({title: '本期计量数量|合同', colSpan: '3|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 60, type: 'Number'});
-        leafXmjCols.push({title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'qc_qty', hAlign: 2, width: 60, type: 'Number'});
-        leafXmjCols.push({title: '|小计', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 60, type: 'Number'});
+        leafXmjCols.push({title: '本期计量数量|合同', colSpan: '3|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true});
+        leafXmjCols.push({title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'qc_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true});
+        leafXmjCols.push({title: '|小计', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true});
     } else if (qtySource === qtySourceValueConst.contract_qty) {
-        leafXmjCols.push({title: '本期计量数量|合同', colSpan: '1|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 100, type: 'Number'});
+        leafXmjCols.push({title: '本期计量数量|合同', colSpan: '1|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 100, type: 'Number', readOnly: true});
     } else if (qtySource === qtySourceValueConst.gather_minus_qty) {
-        leafXmjCols.push({title: '本期计量数量|合同', colSpan: '4|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 60, type: 'Number'});
-        leafXmjCols.push({title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'qc_qty', hAlign: 2, width: 60, type: 'Number'});
-        leafXmjCols.push({title: '|不计价', colSpan: '|1', rowSpan: '|1', field: 'qc_minus_qty', hAlign: 2, width: 60, type: 'Number'});
-        leafXmjCols.push({title: '|小计', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.gather_qty'});
+        leafXmjCols.push({title: '本期计量数量|合同', colSpan: '4|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true});
+        leafXmjCols.push({title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'qc_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true});
+        leafXmjCols.push({title: '|不计价', colSpan: '|1', rowSpan: '|1', field: 'qc_minus_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true});
+        leafXmjCols.push({title: '|小计', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true, getValue: 'getValue.gather_qty'});
     }
-    leafXmjCols.push({title: '本期价差', colSpan: '1', rowSpan: '2', field: 'jiacha', hAlign: 2, width: 80, type: 'Number'});
+    leafXmjCols.push({title: '本期调差数量', colSpan: '1', rowSpan: '2', field: 'qty', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.qty', readOnly: 'readOnly.qty'});
+    leafXmjCols.push({title: '本期价差', colSpan: '1', rowSpan: '2', field: 'jiacha', hAlign: 2, width: 80, type: 'Number', readOnly: true });
     const leafXmjSpreadSetting = {
         // cols: [
         //     {title: '项目节|编号', colSpan: '2|1', rowSpan: '1|1', field: 'code', hAlign: 0, width: 80, formatter: '@'},
@@ -310,7 +330,7 @@ $(document).ready(() => {
         defaultRowHeight: 21,
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
-        readOnly: true,
+        // readOnly: true,
         rowHeader:[
             {
                 rowHeaderType: 'circle',
@@ -328,13 +348,29 @@ $(document).ready(() => {
         ],
     };
     leafXmjSpreadSetting.cols = leafXmjCols;
+    const qtyColIndex = _.findIndex(leafXmjCols, {field: 'qty'});
     const leafXmjCol = {
+        readOnly: {
+            qty: function (data) {
+                return !(!readOnly && editQtyPermission);
+            }
+        },
         getValue: {
             gather_qty: function (data) {
                 if (qtySource === qtySourceValueConst.gather_minus_qty) {
                     return ZhCalc.add(data.gather_qty, data.qc_minus_qty);
                 }
             },
+            qty: function (data) {
+                if (data.qty !== null) return data.qty;
+                if (qtySource === qtySourceValueConst.gather_qty) {
+                    return data.gather_qty;
+                } else if (qtySource === qtySourceValueConst.contract_qty) {
+                    return data.contract_qty;
+                } else if (qtySource === qtySourceValueConst.gather_minus_qty) {
+                    return ZhCalc.add(data.gather_qty, data.qc_minus_qty);
+                }
+            }
         }
     }
     const needUpdateArray = ['quantity', 'msg_tp', 'msg_times', 'msg_spread', 'm_spread', 'm_tp', 'm_tax_tp', 'is_summary', 'remark'];
@@ -370,6 +406,7 @@ $(document).ready(() => {
                 notJoinList = result.materialNotJoinListData;
                 notChangeList = result.materialNotChangeListData;
                 selfList = result.materialSelfListData;
+                qtyList = result.materialQtyListData;
                 materialChecklistData = result.materialChecklistData;
                 if (isStageSelf) {
                     updateBillsData(ms_id);
@@ -858,6 +895,10 @@ $(document).ready(() => {
                 const notx2 = findNotChangeLeafXmj(x);
                 const color2 = notx2 === undefined || qtySource === qtySourceValueConst.contract_qty ? color : '#FFE699';
                 leafXmjSheet.getRange(iRow, -1, 1, -1).backColor(color2);
+                const qtyInfo = findQtyLeafXmj(x);
+                if (x.qty !== undefined && x.qty !== null && qtyInfo) {
+                    leafXmjSheet.getCell(iRow, qtyColIndex).backColor('#f8d7da');
+                }
             }
         }
     }
@@ -906,6 +947,7 @@ $(document).ready(() => {
             for (const xmj of gcl) {
                 const notx = findNotJoinLeafXmj(xmj);
                 const notx2 = findNotChangeLeafXmj(xmj);
+                const qtyInfo = findQtyLeafXmj(xmj);
                 const data = {
                     xmj_id: xmj.id,
                     gcl_id: xmj.gcl_id,
@@ -914,6 +956,7 @@ $(document).ready(() => {
                     qc_qty: xmj.qc_qty,
                     qc_minus_qty: xmj.qc_minus_qty,
                     gather_qty: xmj.gather_qty,
+                    qty: qtyInfo ? qtyInfo.qty : null,
                     is_join: notx !== undefined ? 0 : notx2 !== undefined ? 2 : 1,
                 };
                 if (ms_id) data.ms_id = ms_id;
@@ -933,6 +976,7 @@ $(document).ready(() => {
                             for (const xmj of leafXmjs) {
                                 const notx = findNotJoinLeafXmj(xmj);
                                 const notx2 = findNotChangeLeafXmj(xmj);
+                                const qtyInfo = findQtyLeafXmj(xmj, '', ms.id);
                                 const data = {
                                     xmj_id: xmj.id,
                                     gcl_id: xmj.gcl_id,
@@ -941,6 +985,7 @@ $(document).ready(() => {
                                     qc_qty: xmj.qc_qty,
                                     qc_minus_qty: xmj.qc_minus_qty,
                                     gather_qty: xmj.gather_qty,
+                                    qty: qtyInfo ? qtyInfo.qty : null,
                                     is_join: notx !== undefined ? 0 : notx2 !== undefined ? 2 : 1,
                                     ms_id: ms.id,
                                 };
@@ -979,6 +1024,7 @@ $(document).ready(() => {
             const xmj = gcl[leafXmjIndex];
             const notx = findNotJoinLeafXmj(xmj);
             const notx2 = findNotChangeLeafXmj(xmj);
+            const qtyInfo = findQtyLeafXmj(xmj);
             const data = {
                 xmj_id: xmj.id,
                 gcl_id: xmj.gcl_id,
@@ -988,6 +1034,7 @@ $(document).ready(() => {
                 qc_qty: xmj.qc_qty,
                 qc_minus_qty: xmj.qc_minus_qty,
                 gather_qty: xmj.gather_qty,
+                qty: qtyInfo ? qtyInfo.qty : null,
                 is_join: notx !== undefined ? 0 : notx2 !== undefined ? 2 : 1,
             };
             console.log(data);
@@ -1037,6 +1084,7 @@ $(document).ready(() => {
                 calculateJiaCha(gclGatherData, iGclRow);
                 SpreadJsObj.reLoadRowData(sheet, nRow);
                 sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                leafXmjSpreadObj.refreshQtyColor(select, nRow);
                 loadMaterialData(iGclRow);
                 SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
             });
@@ -1058,9 +1106,12 @@ $(document).ready(() => {
                     notChangeList.push(result);
                 }
                 gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
+                gclGatherData[iGclRow].leafXmjs[iRow].qty = getOneQtyByLeafXmj(select);
                 calculateJiaCha(gclGatherData, iGclRow);
+                console.log(gclGatherData[iGclRow].leafXmjs[iRow]);
                 SpreadJsObj.reLoadRowData(sheet, nRow);
                 sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                leafXmjSpreadObj.refreshQtyColor(select, nRow);
                 loadMaterialData(iGclRow);
                 SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
             });
@@ -1129,21 +1180,225 @@ $(document).ready(() => {
                     materialListData = result.materialListData;
                 }
                 gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
+                gclGatherData[iGclRow].leafXmjs[iRow].qty = getOneQtyByLeafXmj(select);
                 calculateJiaCha(gclGatherData, iGclRow);
                 SpreadJsObj.reLoadRowData(sheet, nRow);
                 sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                leafXmjSpreadObj.refreshQtyColor(select, nRow);
                 loadXmjMaterialData(iGclRow, nRow);
                 SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
             });
         },
+        refreshQtyColor(xmj, row) {
+            const leafXmjSheet = leafXmjSpread.getActiveSheet();
+            const qtyInfo = findQtyLeafXmj(xmj);
+            if (xmj.qty !== undefined && xmj.qty !== null && qtyInfo) {
+                leafXmjSheet.getCell(row, qtyColIndex).backColor('#f8d7da');
+            }
+        },
     }
     if (!readOnly) {
+        // 编辑本期调差数量
+        if (editQtyPermission) {
+            leafXmjSpreadObj.editEnded = function (e, info) {
+                if (info.sheet.zh_setting) {
+                    const [iGclRow, iRow, nRow, sheet, select, color] = leafXmjSpreadObj.getSelect();
+                    const col = info.sheet.zh_setting.cols[info.col];
+                    // 未改变值则不提交
+                    const validText = is_numeric(info.editingText) ? parseFloat(info.editingText) : (info.editingText ? trimInvalidChar(info.editingText) : null);
+                    const orgValue = select[col.field];
+                    if (orgValue == validText || ((orgValue === '' || orgValue === null) && (validText === '' || validText === null))) {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    if (isNaN(validText)) {
+                        toastr.error('不能输入其它非数字类型字符');
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    const qty = parseFloat(validText) !== 0 ? ZhCalc.round(parseFloat(validText), materialDecimal.qty) : 0;
+                    console.log(qty);
+                    let qtyInfo = findQtyLeafXmj(select);
+                    if (qtyInfo) {
+                        qtyInfo.qty = qty;
+                    } else {
+                        if (qty === null) {
+                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                            return;
+                        }
+                        qtyInfo = {
+                            gcl_id: select.gcl_id,
+                            xmj_id: select.id,
+                            mx_id: select.mx_id || '',
+                            qty: qty,
+                        }
+                    }
+                    postData(window.location.pathname + '/save', { type:'update-qty', updateData: qtyInfo, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
+                        if (qtyInfo && qtyInfo.id) {
+                            const index = findQtyLeafXmj(select, 'index');
+                            if (result.info === null) {
+                                qtyList.splice(index, 1);
+                            } else {
+                                qtyList.splice(index, 1, result.info);
+                            }
+                        } else {
+                            qtyList.push(result.info);
+                        }
+                        materialListData = result.materialListData;
+                        gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
+                        gclGatherData[iGclRow].leafXmjs[iRow].qty = getOneQtyByLeafXmj(select);
+                        calculateJiaCha(gclGatherData, iGclRow);
+                        SpreadJsObj.reLoadRowData(sheet, nRow);
+                        sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                        leafXmjSpreadObj.refreshQtyColor(select, nRow);
+                        loadXmjMaterialData(iGclRow, nRow);
+                        SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
+                    }, function () {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                    });
+                    return;
+                }
+            }
+            leafXmjSpreadObj.clipboardPasted = function (e, info) {
+                const range = info.cellRange;
+                const sortData = info.sheet.zh_data || [];
+                const data = [];
+                for (let iRow = 0; iRow < range.rowCount; iRow++) {
+                    let bPaste = true;
+                    const curRow = range.row + iRow;
+                    const select = sortData[curRow];
+                    if (!select) continue;
+                    let qtyInfo = findQtyLeafXmj(select);
+                    const hintRow = range.rowCount > 1 ? curRow : '';
+                    let sameCol = 0;
+                    for (let iCol = 0; iCol < range.colCount; iCol++) {
+                        const curCol = range.col + iCol;
+                        const colSetting = info.sheet.zh_setting.cols[curCol];
+                        if (!colSetting) continue;
+                        let validText = info.sheet.getText(curRow, curCol).replace('\n', '');
+                        validText = is_numeric(validText) ? parseFloat(validText) : (validText ? trimInvalidChar(validText) : null);
+                        const orgValue = sortData[curRow][colSetting.field];
+                        console.log(validText, orgValue);
+                        if (orgValue == validText || ((orgValue === '' || orgValue === null) && (validText === '' || validText === null))) {
+                            sameCol++;
+                            if (range.colCount === sameCol)  {
+                                bPaste = false;
+                            }
+                            continue;
+                        }
+                        if (isNaN(validText)) {
+                            toastr.error('不能粘贴其它非数字类型字符');
+                            bPaste = false;
+                            continue;
+                        }
+                        const qty = parseFloat(validText) !== 0 ? ZhCalc.round(parseFloat(validText), materialDecimal.qty) : 0;
+                        if (qtyInfo) {
+                            qtyInfo.qty = qty;
+                        } else {
+                            if (qty === null) {
+                                bPaste = false;
+                                continue;
+                            }
+                            qtyInfo = {
+                                gcl_id: select.gcl_id,
+                                xmj_id: select.id,
+                                mx_id: select.mx_id || '',
+                                qty: qty,
+                            }
+                        }
+                        sortData[curRow][colSetting.field] = qty;
+                    }
+                    if (bPaste) {
+                        data.push(qtyInfo);
+                    } else {
+                        console.log(curRow, info.cellRange);
+                        SpreadJsObj.reLoadRowData(info.sheet, curRow);
+                    }
+                }
+                if (data.length === 0) {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
+                    checkNotJoinMaterialData();
+                    return;
+                }
+                console.log(data);
+                // 更新至服务器
+                postData(window.location.pathname + '/save', { type:'pastes-qty', updateData: data, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
+                    const ledgerSheet = ledgerSpread.getActiveSheet();
+                    const ledgerSelect = SpreadJsObj.getSelectObject(ledgerSheet);
+                    const index = gclGatherData.indexOf(ledgerSelect);
+                    materialListData = result.materialListData;
+                    qtyList = result.qtyList;
+                    calculateJiaCha(gclGatherData);
+                    loadLeafXmjData(index);
+                    loadMaterialData(index);
+                    checkNotJoinMaterialData();
+                    SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), index);
+                    // leafXmjSpread.getActiveSheet().setSelection(info.cellRange.row, info.cellRange.col, info.cellRange.rowCount, info.cellRange.colCount);
+                }, function () {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                });
+            }
+            leafXmjSpreadObj.deletePress = function (sheet) {
+                if (!sheet.zh_setting) return;
+                // 暂时仅支持移除数量
+                const sel = sheet.getSelections()[0], datas = [];
+                for (let iRow = sel.row; iRow < sel.row + sel.rowCount; iRow++) {
+                    let bDel = false;
+                    const select = sheet.zh_data[iRow];
+                    if (!select) continue;
+                    let qtyInfo = findQtyLeafXmj(select);
+                    for (let iCol = sel.col; iCol < sel.col + sel.colCount; iCol++) {
+                        const col = sheet.zh_setting.cols[iCol];
+                        const orgValue = select[col.field];
+                        if (orgValue === '' || orgValue === null) {
+                            continue;
+                        }
+                        if (qtyInfo) {
+                            qtyInfo.qty = null;
+                            bDel = true;
+                        }
+                    }
+                    if (bDel) datas.push(qtyInfo);
+                }
+                if (datas.length > 0) {
+                    // 更新至服务器
+                    postData(window.location.pathname + '/save', { type:'pastes-qty', updateData: datas, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
+                        const ledgerSheet = ledgerSpread.getActiveSheet();
+                        const ledgerSelect = SpreadJsObj.getSelectObject(ledgerSheet);
+                        const index = gclGatherData.indexOf(ledgerSelect);
+                        materialListData = result.materialListData;
+                        qtyList = result.qtyList;
+                        calculateJiaCha(gclGatherData);
+                        loadLeafXmjData(index);
+                        loadMaterialData(index);
+                        checkNotJoinMaterialData();
+                        SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), index);
+                    }, function () {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                    });
+                }
+                return;
+            }
+            leafXmjSpreadObj.valueChanged = function (e, info) {
+                // 防止ctrl+z撤销数据
+                SpreadJsObj.reLoadRowData(info.sheet, info.row);
+            }
+            leafXmjSpread.bind(spreadNS.Events.EditEnded, leafXmjSpreadObj.editEnded);
+            leafXmjSpread.bind(spreadNS.Events.ClipboardPasted, leafXmjSpreadObj.clipboardPasted);
+            leafXmjSpread.bind(spreadNS.Events.ValueChanged, leafXmjSpreadObj.valueChanged);
+            SpreadJsObj.addDeleteBind(leafXmjSpread, leafXmjSpreadObj.deletePress);
+        }
         // leafXmj右键功能
         if (!editForAudit) {
             $.contextMenu({
                 selector: '#leaf-xmj-spread',
                 build: function ($trigger, e) {
                     const target = SpreadJsObj.safeRightClickSelection($trigger, e, leafXmjSpread);
+                    const sheet = ledgerSpread.getActiveSheet();
+                    const select = SpreadJsObj.getSelectObject(sheet);
+                    const index = gclGatherData.indexOf(select);
+                    const xmj = target.row !== undefined ? gclGatherData[index].leafXmjs[target.row] : null;
+                    if (xmj) leafXmjSpreadObj.refreshQtyColor(xmj, target.row);
                     return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
                 },
                 items: {
@@ -1843,6 +2098,7 @@ $(document).ready(() => {
                         calculateJiaCha(gclGatherData, iGclRow);
                         SpreadJsObj.reLoadRowData(lsheet, nRow);
                         lsheet.getRange(nRow, -1, 1, -1).backColor(color);
+                        leafXmjSpreadObj.refreshQtyColor(lselect, nRow);
                         SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
                     });
                 },
@@ -1927,6 +2183,7 @@ $(document).ready(() => {
                             SpreadJsObj.reLoadRowData(sheet, nRow);
                             console.log(lselect, color);
                             sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                            leafXmjSpreadObj.refreshQtyColor(lselect, nRow);
                             SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
                         }, function () {
                             SpreadJsObj.reLoadRowData(info.sheet, info.row);

+ 1 - 1
app/public/js/stage.js

@@ -4648,7 +4648,7 @@ $(document).ready(() => {
                 selector: '#' + setting.changeObj.attr('id'),
                 build: function ($trigger, e) {
                     const target = SpreadJsObj.safeRightClickSelection($trigger, e, self.changeSpread);
-                    const change = target.cellTypeHintInfo ? self.changes[target.cellTypeHitInfo.row] : null;
+                    const change = target.cellTypeHitInfo ? self.changes[target.cellTypeHitInfo.row] : null;
                     if (change) self.refreshChangeDetailData(change);
                     return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
                 },

+ 31 - 12
app/service/material_list.js

@@ -45,6 +45,7 @@ module.exports = app => {
                     qc_qty: data.qc_qty,
                     qc_minus_qty: data.qc_minus_qty,
                     gather_qty: data.gather_qty,
+                    qty: data.qty || null,
                     is_join: data.is_join,
                     is_self: 1,
                     ms_id: ms_id ? ms_id : null,
@@ -391,7 +392,7 @@ module.exports = app => {
          * @return {void}
          */
         async getMaterialData(tid, mid) {
-            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`contract_qty`, ml.`qc_qty`, ml.`qc_minus_qty`, ml.`gather_qty`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`ms_id`, ml.`tid`, ml.`mid`, mb.m_spread, ml.ms_id, ml.is_join' +
+            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`contract_qty`, ml.`qc_qty`, ml.`qc_minus_qty`, ml.`gather_qty`, ml.`qty`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`ms_id`, ml.`tid`, ml.`mid`, mb.m_spread, ml.ms_id, ml.is_join' +
                 ' FROM ' + this.tableName + ' as ml' +
                 ' LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' as mb' +
                 ' ON ml.`mb_id` = mb.`id`' +
@@ -597,6 +598,7 @@ module.exports = app => {
                                     qc_qty: xmj.qc_qty,
                                     qc_minus_qty: xmj.qc_minus_qty,
                                     gather_qty: xmj.gather_qty,
+                                    qty: xmj.qty || null,
                                     quantity,
                                     in_time: new Date(),
                                     is_join: xmj.is_join,
@@ -879,17 +881,34 @@ module.exports = app => {
         }
 
         async getMbQuantity(transaction, mid, qty_source, qty_decimal, mb_id, ms_id = null, needRound = 1) {
-            const msSql = ms_id ? ' AND `ms_id` = ' + ms_id : '';
-            const sql = `
-                SELECT
-                    SUM(CASE WHEN is_join = 1 THEN ${this.ctx.helper.getQtySource(qty_source)} * quantity ELSE 0 END) AS quantity1,
-                    SUM(CASE WHEN is_join = 2 THEN ${this.ctx.helper.getQtySource(qty_source, 1)} * quantity ELSE 0 END) AS quantity2
-                  FROM ${this.tableName}
-                  WHERE mid = ? AND mb_id = ?${msSql}
-                `;
-            const sqlParam = [mid, mb_id];
-            const result = await transaction.queryOne(sql, sqlParam);
-            const newQuantity = this.ctx.helper.add(result.quantity1, result.quantity2);
+            // const msSql = ms_id ? ' AND `ms_id` = ' + ms_id : '';
+            // const sql = `
+            //     SELECT
+            //         SUM(CASE WHEN is_join = 1 THEN ${this.ctx.helper.getQtySource(qty_source)} * quantity ELSE 0 END) AS quantity1,
+            //         SUM(CASE WHEN is_join = 2 THEN ${this.ctx.helper.getQtySource(qty_source, 1)} * quantity ELSE 0 END) AS quantity2
+            //       FROM ${this.tableName}
+            //       WHERE mid = ? AND mb_id = ?${msSql}
+            //     `;
+            // const sqlParam = [mid, mb_id];
+            // const result = await transaction.queryOne(sql, sqlParam);
+            // const newQuantity = this.ctx.helper.add(result.quantity1, result.quantity2);
+            // return needRound ? this.ctx.helper.round(newQuantity, qty_decimal) : newQuantity;
+            const condition = { mid, mb_id };
+            if (ms_id) condition.ms_id = ms_id;
+            const list = await transaction.select(this.tableName, { where: condition });
+            let quantity1 = 0;
+            let quantity2 = 0;
+            let qty = 0;
+            for (const item of list) {
+                if (item.qty !== null) {
+                    qty = this.ctx.helper.add(qty, this.ctx.helper.mul(item.qty, item.quantity));
+                } else if (item.is_join === 1) {
+                    quantity1 = this.ctx.helper.add(quantity1, this.ctx.helper.mul(this.ctx.helper.getQtySourceValue(item, qty_source), item.quantity));
+                } else if (item.is_join === 2) {
+                    quantity2 = this.ctx.helper.add(quantity2, this.ctx.helper.mul(this.ctx.helper.getQtySourceValue(item, qty_source, 1), item.quantity));
+                }
+            }
+            const newQuantity = this.ctx.helper.sum([quantity1, quantity2, qty]);
             return needRound ? this.ctx.helper.round(newQuantity, qty_decimal) : newQuantity;
         }
 

+ 235 - 0
app/service/material_list_qty.js

@@ -0,0 +1,235 @@
+'use strict';
+
+/**
+ * 调差清单-本期调差数量表 数据模型
+ *
+ * @author Mai
+ * @date 2018/8/13
+ * @version
+ */
+
+
+module.exports = app => {
+    class MaterialListQty extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'material_list_qty';
+        }
+
+        /**
+         * 增删改本期数量及同步至调差清单表
+         * @return {void}
+         */
+        async save(data, ms_id = null) {
+            if (!this.ctx.tender || !this.ctx.material) {
+                throw '数据错误';
+            }
+            const transaction = await this.db.beginTransaction();
+            try {
+                const mx_id = data.mx_id || '';
+                const condition = {
+                    mid: this.ctx.material.id,
+                    ms_id,
+                    gcl_id: data.gcl_id,
+                    xmj_id: data.xmj_id,
+                    mx_id,
+                };
+                const now = new Date();
+                const isDelete = data.qty == null;
+                let record = null;
+                if (data.id > 0) {
+                    record = { id: data.id };
+                } else {
+                    record = await this.getDataByCondition(condition);
+                }
+                if (record) {
+                    if (isDelete) {
+                        await transaction.delete(this.tableName, { id: record.id });
+                        record = null;
+                    } else {
+                        await transaction.update(this.tableName, {
+                            id: record.id,
+                            qty: data.qty,
+                            in_time: now,
+                        });
+                    }
+                } else if (!isDelete) {
+                    const insertData = {
+                        tid: this.ctx.tender.id,
+                        ...condition,
+                        qty: data.qty,
+                        in_time: now,
+                    };
+                    const result = await transaction.insert(this.tableName, insertData);
+                    record = { id: result.insertId };
+                }
+                const newData = record ? await transaction.get(this.tableName, condition) : null;
+                await this.updateAllMaterials(transaction, data, newData, ms_id);
+                await transaction.commit();
+                return {
+                    info: newData,
+                    materialListData: await this.ctx.service.materialList.getMaterialData(this.ctx.tender.id, this.ctx.material.id),
+                };
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        /**
+         * 增删改本期数量及同步至调差清单表
+         * @return {void}
+         */
+        async savePastes(datas, ms_id = null) {
+            if (!this.ctx.tender || !this.ctx.material) {
+                throw '数据错误';
+            }
+            const transaction = await this.db.beginTransaction();
+            try {
+                const insertDatas = [];
+                const updateDatas = [];
+                const delDatas = [];
+                const newDatas = [];
+                for (const data of datas) {
+                    const mx_id = data.mx_id || '';
+                    const condition = {
+                        mid: this.ctx.material.id,
+                        ms_id,
+                        gcl_id: data.gcl_id,
+                        xmj_id: data.xmj_id,
+                        mx_id,
+                    };
+                    const now = new Date();
+                    const isDelete = data.qty == null;
+                    let record = null;
+                    if (data.id > 0) {
+                        record = { id: data.id };
+                    } else {
+                        record = await this.getDataByCondition(condition);
+                    }
+                    if (record) {
+                        if (isDelete) {
+                            delDatas.push(record.id);
+                        } else {
+                            updateDatas.push({
+                                id: record.id,
+                                qty: data.qty,
+                                in_time: now,
+                            });
+                        }
+                    } else if (!isDelete) {
+                        const insertData = {
+                            tid: this.ctx.tender.id,
+                            ...condition,
+                            qty: data.qty,
+                            in_time: now,
+                        };
+                        insertDatas.push(insertData);
+                    }
+                    newDatas.push({...condition, qty: data.qty});
+                }
+                if (insertDatas.length > 0) await transaction.insert(this.tableName, insertDatas);
+                if (updateDatas.length > 0) await transaction.updateRows(this.tableName, updateDatas);
+                if (delDatas.length > 0) await transaction.delete(this.tableName, { id: delDatas });
+                await this.updateAllMaterialsByPastes(transaction, datas, newDatas, ms_id);
+                await transaction.commit();
+                return {
+                    qtyList: await this.getAllDataByCondition({ where: { tid: this.ctx.tender.id, mid: this.ctx.material.id } }),
+                    materialListData: await this.ctx.service.materialList.getMaterialData(this.ctx.tender.id, this.ctx.material.id),
+                };
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        /**
+         * 修改调差list和bill和material对应值
+         * @param transaction
+         * @returns {Promise<void>}
+         */
+        async updateAllMaterials(transaction, data, newData, ms_id = null) {
+            // 先判断material_list是否存在值并quantity不为null
+            const searchSql = {
+                mid: this.ctx.material.id,
+                ms_id,
+                gcl_id: data.gcl_id,
+                xmj_id: data.xmj_id,
+                mx_id: data.mx_id,
+            };
+            const materialListData = await this.ctx.service.materialList.getAllDataByCondition({
+                where: searchSql,
+            });
+            if (materialListData && materialListData.length !== 0) {
+                // 对应修改更新本期应耗数量值和总的本期金额计算
+                const mbIdList = [];
+                const updateList = [];
+                for (const ml of materialListData) {
+                    const updateData = {
+                        id: ml.id,
+                        qty: newData ? newData.qty : null,
+                    };
+                    if (mbIdList.indexOf(ml.mb_id) === -1) {
+                        mbIdList.push(ml.mb_id);
+                    }
+                    updateList.push(updateData);
+                }
+                if (updateList.length > 0) await transaction.updateRows(this.ctx.service.materialList.tableName, updateList);
+                // 重新计算金额
+                for (const mb_id of mbIdList) {
+                    await this.service.materialList.calcQuantityByML(transaction, mb_id, ms_id, 'all');
+                }
+            }
+        }
+
+        /**
+         * 修改调差list和bill和material对应值
+         * @param transaction
+         * @returns {Promise<void>}
+         */
+        async updateAllMaterialsByPastes(transaction, datas, newDatas, ms_id = null) {
+            // 先判断material_list是否存在值并quantity不为null
+            if (datas.length > 0) {
+                const updateList = [];
+                const mbIdList = [];
+                for (const data of datas) {
+                    const searchSql = {
+                        mid: this.ctx.material.id,
+                        ms_id,
+                        gcl_id: data.gcl_id,
+                        xmj_id: data.xmj_id,
+                        mx_id: data.mx_id,
+                    };
+                    const materialListData = await this.ctx.service.materialList.getAllDataByCondition({
+                        where: searchSql,
+                    });
+                    if (materialListData && materialListData.length !== 0) {
+                        const newData = this._.find(newDatas, searchSql);
+                        for (const ml of materialListData) {
+                            const updateData = {
+                                id: ml.id,
+                                qty: newData ? newData.qty : null,
+                            };
+                            if (mbIdList.indexOf(ml.mb_id) === -1) {
+                                mbIdList.push(ml.mb_id);
+                            }
+                            updateList.push(updateData);
+                        }
+                    }
+                }
+                if (updateList.length > 0) await transaction.updateRows(this.ctx.service.materialList.tableName, updateList);
+                // 重新计算金额
+                for (const mb_id of mbIdList) {
+                    await this.service.materialList.calcQuantityByML(transaction, mb_id, ms_id, 'all');
+                }
+            }
+        }
+    }
+    return MaterialListQty;
+};

+ 1 - 1
app/view/material/checklist.ejs

@@ -76,5 +76,5 @@
     const stage_order = <%- material.order %>;
     const materialID = <%- material.id %>;
     const materialDecimal = JSON.parse(unescape('<%- escape(JSON.stringify(material.decimal)) %>'));
-    let materialChecklistData, notJoinList, notChangeList, ledger, curLedgerData, pos, curPosData, gclGatherData, gclList, gclGatherListData;
+    let materialChecklistData, notJoinList, notChangeList, qtyList, ledger, curLedgerData, pos, curPosData, gclGatherData, gclList, gclGatherListData;
 </script>

+ 2 - 1
app/view/material/list.ejs

@@ -106,6 +106,7 @@
     const readOnly = <%- material.readOnly %>;
     const openMaterialSelf = parseInt(<%- ctx.subProject.page_show.openMaterialSelf %>);
     const editListPermission = <%- material.editListPermission ? material.editListPermission : false %>;
+    const editQtyPermission = <%- material.editQtyPermission ? material.editQtyPermission : false %>;
     const stage_order = <%- material.order %>;
     const materialID = <%- material.id %>;
     const tenderID = <%- tender.id %>;
@@ -114,5 +115,5 @@
     const materialIsNewQty = parseInt('<%- material.is_new_qty %>');
     const materialDecimal = JSON.parse(unescape('<%- escape(JSON.stringify(material.decimal)) %>'));
     const openMaterialChecklist = parseInt(<%- ctx.subProject.page_show.openMaterialChecklist %>);
-    let materialListData, materialChecklistData, notJoinList, notChangeList, ledger, curLedgerData, pos, curPosData, gclGatherData, gclList, selfList, gclGatherListData;
+    let materialListData, materialChecklistData, notJoinList, notChangeList, qtyList, ledger, curLedgerData, pos, curPosData, gclGatherData, gclList, selfList, gclGatherListData;
 </script>

+ 16 - 1
sql/update.sql

@@ -54,6 +54,19 @@ CREATE TABLE `zh_material_exponent_shard` (
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='指数调差分表(独立期和分项价格指数结合)';
 
+CREATE TABLE `zh_material_list_qty`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `tid` int(11) NOT NULL COMMENT '标段id',
+  `mid` int(11) NOT NULL COMMENT '调差期id',
+  `ms_id` int(11) DEFAULT NULL COMMENT '调差多期单独计价期id(可以为空)',
+  `gcl_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '清单id',
+  `xmj_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '项目节id',
+  `mx_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT '' COMMENT '部位明细id',
+  `qty` decimal(30, 8) NULL DEFAULT NULL COMMENT '数量',
+  `in_time` datetime NOT NULL COMMENT '添加时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '调差清单本期调差数量表';
+
 ALTER TABLE `zh_sub_project_info`
 ADD COLUMN `lx_tp_unit` varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '元' COMMENT '立项-金额单位' AFTER `lx_tp`,
 ADD COLUMN `cb_tp_unit` varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '元' COMMENT '初步-金额单位' AFTER `cb_tp`,
@@ -296,6 +309,9 @@ CREATE TABLE `zh_pos_calc_detail`  (
   PRIMARY KEY (`id`)
 );
 
+ALTER TABLE `zh_material_list`
+ADD COLUMN `qty` decimal(30, 8) NULL DEFAULT NULL COMMENT '本期调差数量' AFTER `gather_qty`;
+
 ------------------------------------
 -- 表数据
 ------------------------------------
@@ -304,4 +320,3 @@ INSERT INTO `zh_permission` (`id`, `name`, `controller`, `action`, `pid`, `icon_
 
 
 
-