'use strict'; /** * 期计量 数据模型 * * @author Mai * @date 2018/8/13 * @version */ const auditConst = require('../const/audit').material; const materialConst = require('../const/material'); const MaterialCalculator = require('../lib/material_calc'); module.exports = app => { class MaterialBills extends app.BaseService { /** * 构造函数 * * @param {Object} ctx - egg全局变量 * @return {void} */ constructor(ctx) { super(ctx); this.tableName = 'material_bills'; } /** * 添加工料 * @return {void} */ async add() { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } const order = await this._getMaxOrder(this.ctx.tender.id); const transaction = await this.db.beginTransaction(); try { const resultData = {}; const newBills = { tid: this.ctx.tender.id, mid: this.ctx.material.id, order: order + 1, in_time: new Date(), }; // 新增工料 const result = await transaction.insert(this.tableName, newBills); if (result.affectedRows !== 1) { throw '新增工料数据失败'; } if (this.ctx.material.is_stage_self) { await this.ctx.service.materialStageBills.add(transaction, result.insertId); resultData.pushStageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, mb_id: result.insertId } }); } const insertArray = []; const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : []; for (const ym of material_month) { const one_month = { tid: this.ctx.tender.id, mid: this.ctx.material.id, mb_id: result.insertId, msg_tp: null, yearmonth: ym, }; insertArray.push(one_month); } if (insertArray.length !== 0) await transaction.insert(this.ctx.service.materialMonth.tableName, insertArray); await transaction.commit(); resultData.info = await this.getDataById(result.insertId); return resultData; } catch (error) { console.log(error); await transaction.rollback(); throw error; } } /** * 导入工料 * @return {void} */ async exportData(datas, includeSpec = false, ms_id = null) { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } let order = await this._getMaxOrder(this.ctx.tender.id); const transaction = await this.db.beginTransaction(); try { const resultData = {}; let needUpdateTp = false; // 找出需要导入的工料 (隐藏未存在的工料导入问题) const bills = await this.getAllDataByCondition({ where: { tid: this.ctx.tender.id } }); // const newBills = this._.differenceWith(datas, bills, function(item1, item2) { // return item1.code.toString() === item2.code.toString() && item1.name === item2.name && item1.unit === item2.unit && (!includeSpec || (includeSpec && item1.spec.toString() === item2.spec.toString())); // }); const newBills = []; const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : []; if (newBills.length !== 0) { const newBillsData = []; const newMonthList = []; for (const t of newBills) { // 判断msg_tp是否为数字,不是则报错 if (t.msg_tp && !this._.isNumber(t.msg_tp)) { throw '信息价数据存在非数字字符,无法导入'; } t.msg_tp = t.msg_tp ? this.ctx.helper.round(t.msg_tp, this.ctx.material.decimal.up) : null; const newBill = { tid: this.ctx.tender.id, mid: this.ctx.material.id, order: order + 1, code: t.code.toString(), name: t.name, unit: t.unit, spec: t.spec, msg_tp: this.ctx.material.is_stage_self ? null : t.msg_tp, msg_times: this.ctx.material.is_stage_self ? null : t.msg_times, msg_spread: this.ctx.material.is_stage_self ? null : t.msg_tp, m_spread: this.ctx.material.is_stage_self ? null : t.msg_tp, m_tp: 0, m_tax_tp: 0, in_time: new Date(), }; order = order + 1; newBillsData.push(newBill); } const result = await transaction.insert(this.tableName, newBillsData); resultData.addNum = newBillsData.length; for (let j = 0; j < newBills.length; j++) { newBills[j].id = result.insertId + j; if (material_month.length > 0) { for (const ym of material_month) { const one_month = { tid: this.ctx.tender.id, mid: this.ctx.material.id, mb_id: newBills[j].id, msg_tp: newBills[j].msg_tp, yearmonth: ym, }; newMonthList.push(one_month); } } } if (this.ctx.material.is_stage_self) { // 获取刚批量添加的所有list await this.ctx.service.materialStageBills.adds(transaction, newBills, null, ms_id); } if (newMonthList.length > 0) await transaction.insert(this.ctx.service.materialMonth.tableName, newMonthList); } // 找出需要更新的工料 const updateBills = this._.intersectionWith(bills, datas, function(item1, item2) { return item1.code.toString() === item2.code.toString() && item1.name === item2.name && item1.unit === item2.unit && (!includeSpec || (includeSpec && (item1.spec === null ? '' : item1.spec).toString() === (item2.spec === null ? '' : item2.spec).toString())); }); if (updateBills.length !== 0) { const updateDatas = []; const updateMonthList = []; for (const u of updateBills) { const oneData = this._.find(datas, function(item) { return item.code.toString() === u.code.toString() && item.name === u.name && item.unit === u.unit && (!includeSpec || (includeSpec && (item.spec === null ? '' : item.spec).toString() === (u.spec === null ? '' : u.spec).toString())); }); const upd = { id: u.id }; oneData.msg_tp = this.ctx.helper.round(oneData.msg_tp, this.ctx.material.decimal.up); // 判断msg_tp是否为数字,不是则报错 if (oneData.msg_tp && !this._.isNumber(oneData.msg_tp)) { throw '信息价数据存在非数字字符,无法导入'; } if (!this.ctx.material.is_stage_self) { if (oneData.msg_tp !== u.msg_tp) { needUpdateTp = true; upd.msg_tp = oneData.msg_tp; const [newmsg_spread, newm_spread] = await this.getSpread(u, oneData.msg_tp); upd.msg_spread = newmsg_spread; upd.m_spread = newm_spread; const newTp = this.ctx.helper.round(this.ctx.helper.mul(u.quantity, newm_spread), this.ctx.material.decimal.tp); upd.m_tp = newTp; upd.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(u.m_tax, 100))), this.ctx.material.decimal.tp); } if (oneData.msg_times !== u.msg_times) { upd.msg_times = oneData.msg_times; } } if (!includeSpec && (oneData.spec === null ? '' : oneData.spec).toString() !== (u.spec === null ? '' : u.spec).toString()) { upd.spec = oneData.spec; } if (!this._.isEqual(upd, { id: u.id })) updateDatas.push(upd); // 判断是否有月信息价,如果有则msg_tp都更改为统一值 if (material_month.length > 0) { const monthList = await transaction.select(this.ctx.service.materialMonth.tableName, { where: { mb_id: u.id, mid: this.ctx.material.id } }); if (monthList.length !== 0) { for (const m of monthList) { // 更新月信息单价小数位 if (oneData.msg_tp !== m.msg_tp) { m.msg_tp = oneData.msg_tp; updateMonthList.push({ id: m.id, msg_tp: m.msg_tp }); } } } } } if (updateDatas.length !== 0) await transaction.updateRows(this.tableName, updateDatas); resultData.updateNum = updateDatas.length; if (updateMonthList.length !== 0) await transaction.updateRows(this.ctx.service.materialMonth.tableName, updateMonthList); if (this.ctx.material.is_stage_self) { let selfUpdateNum = 0; [needUpdateTp, selfUpdateNum] = await this.ctx.service.materialStageBills.updateByExport(transaction, updateBills, datas, includeSpec, ms_id); if (resultData.updateNum === 0 || resultData.updateNum < selfUpdateNum) resultData.updateNum = selfUpdateNum; } } // 更新materialStage 值 if (this.ctx.material.is_stage_self) { resultData.stageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id } }); resultData.stageData = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }); } resultData.billsData = await transaction.select(this.tableName, { where: { tid: this.ctx.tender.id }, orders: [['order', 'asc']] }); if (material_month.length > 0) { resultData.monthsList = await this.ctx.service.materialMonth.getMonthList(resultData.billsData, transaction); } resultData.m_tp = needUpdateTp ? await this.calcMaterialMTp(transaction) : this.ctx.material.m_tp; await transaction.commit(); return resultData; } catch (error) { console.log(error); await transaction.rollback(); throw error; } } /** * 添加工料 * @return {void} */ async addByGlj(data, order = null) { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } const newOrder = this._.isNumber(order) ? parseInt(order) + 1 : await this._getMaxOrder(this.ctx.tender.id); const transaction = await this.db.beginTransaction(); try { // order以下的工料+1 await this._syncOrder(transaction, this.ctx.tender.id, newOrder, '+'); const resultData = {}; const newBills = { tid: this.ctx.tender.id, mid: this.ctx.material.id, code: data.code, name: data.name, unit: data.unit, m_up_risk: data.rise_range, m_down_risk: data.fall_range, spec: data.spec, m_type: data.type, remark: data.memo, order: newOrder, in_time: new Date(), }; // 新增工料 const result = await transaction.insert(this.tableName, newBills); if (result.affectedRows !== 1) { throw '新增工料数据失败'; } if (this.ctx.material.is_stage_self) { await this.ctx.service.materialStageBills.add(transaction, result.insertId, data.memo); resultData.pushStageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, mb_id: result.insertId } }); } const insertArray = []; const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : []; for (const ym of material_month) { const one_month = { tid: this.ctx.tender.id, mid: this.ctx.material.id, mb_id: result.insertId, msg_tp: null, yearmonth: ym, }; insertArray.push(one_month); } if (insertArray.length !== 0) await transaction.insert(this.ctx.service.materialMonth.tableName, insertArray); await transaction.commit(); resultData.info = await this.getDataById(result.insertId); return resultData; } catch (error) { console.log(error); await transaction.rollback(); throw error; } } /** * 移除清单时,同步其后清单order * @param transaction - 事务 * @param {Number} cid - 变更cid * @param {Number} order - order之后的 * @return {Promise<*>} * @private */ async _syncOrder(transaction, tid, order, selfOperate = '-', num = 1) { this.initSqlBuilder(); this.sqlBuilder.setAndWhere('tid', { value: this.db.escape(tid), operate: '=', }); this.sqlBuilder.setAndWhere('order', { value: order, operate: '>=', }); this.sqlBuilder.setUpdateData('order', { value: num, selfOperate, }); const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update'); const data = await transaction.query(sql, sqlParam); return data; } async _getMaxOrder(tenderId) { const sql = 'SELECT Max(??) As value FROM ?? Where tid = ' + tenderId; const sqlParam = ['order', this.tableName]; const queryResult = await this.db.queryOne(sql, sqlParam); return queryResult.value ? queryResult.value : 0; } /** * 删除工料 * @param {int} id 工料id * @return {void} */ async del(id) { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } // 判断t_type是否为费用,且存在quantity,m_spread值 const transaction = await this.db.beginTransaction(); try { // 防止多页面操作时,清单工料含量存在时工料可删 const materialListNum = await this.ctx.service.materialList.count({ tid: this.ctx.tender.id, mb_id: id }); if (materialListNum > 0) { throw '该工料已存在对应的清单工料含量,删除失败'; } const mbInfo = await this.getDataById(id); await transaction.delete(this.tableName, { id }); const m_tp = this.ctx.material.m_tp; const result = { m_tp }; if (this.ctx.material.is_stage_self) { await transaction.delete(this.ctx.service.materialStageBills.tableName, { mb_id: id }); // 金额发生变化,则重新计算本期金额 for (const sid of this.ctx.material.stage_id.split(',')) { const msInfo = await transaction.get(this.ctx.service.materialStage.tableName, { tid: this.ctx.tender.id, sid }); await this.ctx.service.materialStage.updateMtp(transaction, msInfo.id); } result.stageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id } }); result.stageData = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }); result.m_tp = await this.calcMaterialMTp(transaction); } else if (mbInfo.t_type === materialConst.t_type[1].value && mbInfo.quantity !== null && mbInfo.m_spread !== null) { // 金额发生变化,则重新计算本期金额 result.m_tp = await this.calcMaterialMTp(transaction); } const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : []; if (material_month.length > 0) { await transaction.delete(this.ctx.service.materialMonth.tableName, { mb_id: id }); } // order以下的清单-1 await this._syncOrder(transaction, this.ctx.tender.id, mbInfo.order, '-'); await transaction.commit(); return result; } catch (err) { await transaction.rollback(); throw err; } } /** * 交换两个工料的顺序 * @param {Number} id1 - 工料1的id * @param {Number} id2 - 工料2的id * @returns {Promise} */ async changeOrder(datas) { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } // const bill1 = await this.getDataByCondition({ tid: this.ctx.tender.id, id: id1 }); // const bill2 = await this.getDataByCondition({ tid: this.ctx.tender.id, id: id2 }); // if (!bill1 || !bill2) { // throw '数据错误'; // } const transaction = await this.db.beginTransaction(); try { // const order = bill1.order; // bill1.order = bill2.order; // bill2.order = order; // await transaction.update(this.tableName, { id: bill1.id, order: bill1.order }); // await transaction.update(this.tableName, { id: bill2.id, order: bill2.order }); await transaction.updateRows(this.tableName, datas); await transaction.commit(); return true; } catch (err) { await transaction.rollback(); throw err; } } /** * 修改工料信息 * @param {Object} data 工料内容 * @return {void} */ async save(data, ms_id = null) { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } delete data.in_time; // delete data.m_tp; // 判断是否可修改 // 判断t_type是否为费用 const transaction = await this.db.beginTransaction(); try { const result = {}; if (this.ctx.material.is_stage_self) { if (!ms_id) { throw '期参数有误'; } const needUp = await this.updateOneBillsData(transaction, data, ms_id); const [one_m_tp, one_tax_tp] = await this.ctx.service.materialStageBills.update(transaction, data, ms_id); // 更新materialStage 值 data.m_tp = this.ctx.helper.round(one_m_tp, this.ctx.material.decimal.tp); data.m_tax_tp = this.ctx.helper.round(one_tax_tp, this.ctx.material.decimal.tp); data.quantity = null; data.msg_tp = null; data.msg_times = null; data.msg_spread = null; data.m_spread = null; delete data.ms_id; // 更新materialStage 值 await this.ctx.service.materialStage.updateMtp(transaction, ms_id); result.stageBillsData = this.ctx.material.is_stage_self && needUp ? await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, mb_id: data.id } }) : await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, ms_id, mb_id: data.id } }); result.stageData = this.ctx.material.is_stage_self && needUp ? await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }) : await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id, id: ms_id } }); } await transaction.update(this.tableName, data); if (this.ctx.material.is_stage_self) { result.billsData = await transaction.select(this.tableName, { where: { id: data.id } }); } result.m_tp = await this.calcMaterialMTp(transaction); await transaction.commit(); return result; } catch (err) { await transaction.rollback(); throw err; } } async updateOneBillsData(transaction, data, ms_id) { // 当以下值和bills值不相同时,需要同步更新最新的计算值到stageBills表里 const updateColsArray = ['t_type', 'm_tax', 'basic_price', 'm_up_risk', 'm_down_risk', 'is_summary']; let needUp = null; const mbInfo = await this.getDataById(data.id); for (const uc of updateColsArray) { if (data[uc] !== undefined && data[uc] !== mbInfo[uc]) { needUp = uc; break; } } if (needUp) { const msList = await this.ctx.service.materialStage.getAllDataByCondition({ where: { mid: this.ctx.material.id } }); for (const ms of msList) { if (ms.id !== parseInt(ms_id)) { const msbInfo = await this.ctx.service.materialStageBills.getDataByCondition({ mid: this.ctx.material.id, ms_id: ms.id, mb_id: data.id, }); const updateData = { id: msbInfo.id, }; if (needUp === 'm_tax') { updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(msbInfo.m_tp, (1 + this.ctx.helper.div(data.m_tax, 100))), this.ctx.material.decimal.tp); } else if (needUp === 'm_up_risk' || needUp === 'm_down_risk' || needUp === 'basic_price') { const basic_price = needUp === 'basic_price' ? data.basic_price : mbInfo.basic_price; mbInfo.m_up_risk = data.m_up_risk !== undefined ? data.m_up_risk : mbInfo.m_up_risk; mbInfo.m_down_risk = data.m_down_risk !== undefined ? data.m_down_risk : mbInfo.m_down_risk; const [msg_spread, m_spread] = await this.getSpread(mbInfo, msbInfo.msg_tp, this.ctx.material.decimal.up, basic_price); updateData.msg_spread = msg_spread; updateData.m_spread = m_spread; const newTp = this.ctx.helper.round(this.ctx.helper.mul(msbInfo.quantity, m_spread), this.ctx.material.decimal.tp); updateData.m_tp = newTp; updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp); } else if (needUp === 't_type') { updateData.quantity = null; updateData.m_tp = null; updateData.m_tax_tp = null; } else if (needUp === 'is_summary') { updateData.is_summary = data.is_summary; } await transaction.update(this.ctx.service.materialStageBills.tableName, updateData); await this.ctx.service.materialStage.updateMtp(transaction, ms.id); } } } return needUp; } async saveOrigin(data) { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } return await this.db.update(this.tableName, { id: data.mb_id, origin: data.value }); } async saveOrigins(datas) { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } const updateData = []; for (const data of datas) { updateData.push({ id: data.mb_id, origin: data.origin, }); } if (updateData.length > 0) await this.db.updateRows(this.tableName, updateData); return true; } /** * 修改工料信息 * @param {Object} data 工料内容 * @return {void} */ async saveDatas(datas, ms_id = null) { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } // 判断是否可修改 // 判断t_type是否为费用 const transaction = await this.db.beginTransaction(); try { for (const data of datas) { delete data.in_time; let needUp = null; if (this.ctx.material.is_stage_self) { needUp = await this.updateOneBillsData(transaction, data, ms_id); const [one_m_tp, one_tax_tp] = await this.ctx.service.materialStageBills.update(transaction, data, ms_id); // 更新materialStage 值 data.m_tp = this.ctx.helper.round(one_m_tp, this.ctx.material.decimal.tp); data.m_tax_tp = this.ctx.helper.round(one_tax_tp, this.ctx.material.decimal.tp); data.quantity = null; data.msg_tp = null; data.msg_times = null; data.msg_spread = null; data.msg_spread = null; data.m_spread = null; } // delete data.m_tp; // console.log(data); await transaction.update(this.tableName, data); } // 更新materialStage 值 const result = {}; if (this.ctx.material.is_stage_self) { await this.ctx.service.materialStage.updateMtp(transaction, ms_id); result.stageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id } }); result.stageData = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }); result.billsData = await transaction.select(this.tableName, { where: { mid: this.ctx.material.id }, orders: [['order', 'asc']] }); } result.m_tp = await this.calcMaterialMTp(transaction); await transaction.commit(); return result; } catch (err) { await transaction.rollback(); throw err; } } /** * 更新新一期的quantity和截止上期金额并返回本期总金额 * @param transaction * @param tid * @param mid * @returns {Promise} */ async updateNewMaterial(transaction, tid, mid, ctx, stage_id, decimal, pre_is_stage_self = 0, qty_source = 1, rate) { const materialBillsData = await this.getAllDataByCondition({ where: { tid } }); let m_tp = 0; let m_tax_tp = 0; const materialCalculator = new MaterialCalculator(ctx, stage_id, ctx.tender.info); for (const mb of materialBillsData) { const [one_tp, one_tax_tp] = await this.calcQuantityByMB(transaction, mid, mb, materialCalculator, decimal, pre_is_stage_self, qty_source); m_tp = this.ctx.helper.add(m_tp, one_tp); m_tax_tp = this.ctx.helper.add(m_tax_tp, one_tax_tp); } const rate_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(rate, 100))), decimal.tp); return [m_tp, m_tax_tp, rate_tp]; } /** * 修改quantity,m_spread值和返回单条调差金额(新增一期) * @param transaction * @param mid * @param mb * @returns {Promise<*>} */ async calcQuantityByMB(transaction, mid, mb, materialCalculator, decimal, pre_is_stage_self, qty_source) { const [newmsg_spread, newm_spread] = await this.getSpread(mb, null, decimal.up); if (mb.t_type === materialConst.t_type[0].value) { const newQuantity = await this.ctx.service.materialList.getMbQuantity(transaction, mid, qty_source, decimal.qty, mb.id); const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, newm_spread), decimal.tp); const updateData = { id: mb.id, quantity: newQuantity, msg_tp: null, msg_times: null, msg_spread: newmsg_spread, m_spread: newm_spread, origin: null, m_tp: newTp, pre_tp: mb.m_tp !== null ? this.ctx.helper.add(mb.pre_tp, mb.m_tp) : mb.pre_tp, m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp), tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp) : mb.tax_pre_tp, }; await transaction.update(this.tableName, updateData); const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(newQuantity, newm_spread), decimal.tp) : 0; const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp); return [m_tp, m_tax_tp]; } else if (mb.t_type === materialConst.t_type[1].value) { const quantity = pre_is_stage_self ? 0 : await materialCalculator.calculateExpr(mb.expr); const newTp = quantity !== 0 && quantity !== null ? this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(quantity, decimal.qty), newm_spread), decimal.tp) : null; const updateData = { id: mb.id, quantity: quantity !== 0 && quantity !== null ? this.ctx.helper.round(quantity, decimal.qty) : null, expr: pre_is_stage_self ? null : mb.expr, msg_tp: null, msg_times: null, msg_spread: newmsg_spread, m_spread: newm_spread, origin: null, m_tp: newTp, pre_tp: mb.m_tp !== null ? this.ctx.helper.add(mb.pre_tp, mb.m_tp) : mb.pre_tp, m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp), tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp) : mb.tax_pre_tp, }; await transaction.update(this.tableName, updateData); const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(quantity, newm_spread), decimal.tp) : 0; const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp); return [m_tp, m_tax_tp]; } } /** * 清空本期信息价后更新价差和有效价差 * @param data * @returns {Promise} */ async getSpread(data, msg_tp, newDecimalUp = this.ctx.material.decimal.up, basic_price = null) { data.msg_tp = msg_tp; const newBp = basic_price ? basic_price : data.basic_price; const msg_spread = this.ctx.helper.round(this.ctx.helper.sub(data.msg_tp, newBp), newDecimalUp); const cor = msg_spread >= 0 ? this.ctx.helper.mul(newBp, this.ctx.helper.div(data.m_up_risk, 100)) : this.ctx.helper.mul(newBp, this.ctx.helper.div(data.m_down_risk, 100)); const m_spread = Math.abs(msg_spread) > Math.abs(cor) ? (msg_spread > 0 ? this.ctx.helper.round(this.ctx.helper.sub(msg_spread, cor), newDecimalUp) : this.ctx.helper.round(this.ctx.helper.add(msg_spread, cor), newDecimalUp)) : 0; return [msg_spread, m_spread]; } /** * 修改 expr和quantity值,返回本期金额和单条数据 * @param data * @returns {Promise} */ async updateFYQuantity(data) { if (!this.ctx.tender || !this.ctx.material) { throw '数据错误'; } const transaction = await this.db.beginTransaction(); try { const returnData = {}; returnData.m_tp = this.ctx.material.m_tp; if (this.ctx.material.is_stage_self) { if (!data.ms_id) throw '参数有误'; const mbInfo = await this.getDataById(data.id); const msInfo = await this.ctx.service.materialStage.getDataById(data.ms_id); const msbInfo = await this.ctx.service.materialStageBills.getDataByCondition({ mid: this.ctx.material.id, mb_id: data.id, ms_id: data.ms_id }); // let all_m_tp = 0; // let all_tax_tp = 0; const materialCalculator = new MaterialCalculator(this.ctx, msInfo.sid, this.ctx.tender.info); const quantity = await materialCalculator.calculateExpr(data.expr); const newQuantity = quantity !== 0 ? this.ctx.helper.round(quantity, this.ctx.material.decimal.qty) : null; const m_tp = newQuantity ? this.ctx.helper.round(this.ctx.helper.mul(newQuantity, msbInfo.m_spread), this.ctx.material.decimal.tp) : null; const updateData = { id: data.id, quantity: newQuantity, expr: data.expr, m_tp, m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp), }; const [one_bill_m_tp, one_bill_tax_tp] = await this.ctx.service.materialStageBills.update(transaction, updateData, msInfo.id); await this.ctx.service.materialStage.updateMtp(transaction, msInfo.id); const all_m_tp = this.ctx.helper.round(one_bill_m_tp, this.ctx.material.decimal.tp); const all_tax_tp = this.ctx.helper.round(one_bill_tax_tp, this.ctx.material.decimal.tp); // for (const sid of this.ctx.material.stage_id.split(',')) { // const materialCalculator = new MaterialCalculator(this.ctx, sid, this.ctx.tender.info); // const quantity = await materialCalculator.calculateExpr(data.expr); // const msInfo = await this.ctx.service.materialStage.getDataByCondition({ mid: this.ctx.material.id, sid }); // const msbInfo = await this.ctx.service.materialStageBills.getDataByCondition({ mid: this.ctx.material.id, mb_id: data.id, ms_id: msInfo.id }); // const newQuantity = quantity !== 0 ? this.ctx.helper.round(quantity, this.ctx.material.decimal.qty) : null; // const m_tp = newQuantity ? this.ctx.helper.round(this.ctx.helper.mul(newQuantity, msbInfo.m_spread), this.ctx.material.decimal.tp) : null; // const updateData = { // id: data.id, // quantity: newQuantity, // m_tp, // m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp), // }; // const [one_bill_m_tp, one_bill_tax_tp] = await this.ctx.service.materialStageBills.update(transaction, updateData, msInfo.id); // await this.ctx.service.materialStage.updateMtp(transaction, msInfo.id); // all_m_tp = this.ctx.helper.round(one_bill_m_tp, this.ctx.material.decimal.tp); // all_tax_tp = this.ctx.helper.round(one_bill_tax_tp, this.ctx.material.decimal.tp); // } const updateBillsData = { id: data.id, // expr: data.expr, m_tp: all_m_tp ? all_m_tp : null, m_tax_tp: all_tax_tp ? all_tax_tp : null, }; console.log(all_m_tp); await transaction.update(this.tableName, updateBillsData); returnData.m_tp = await this.calcMaterialMTp(transaction); returnData.stageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, mb_id: data.id } }); returnData.stageData = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }); } else { const materialCalculator = new MaterialCalculator(this.ctx, this.ctx.material.stage_id, this.ctx.tender.info); const quantity = await materialCalculator.calculateExpr(data.expr); // 更新quantity值并重新返回计算本期金额,截止本期金额 const updateData = { id: data.id, quantity: quantity !== 0 ? this.ctx.helper.round(quantity, this.ctx.material.decimal.qty) : null, expr: data.expr, }; const mbInfo = await this.getDataById(updateData.id); updateData.m_tp = this.ctx.helper.round(this.ctx.helper.mul(updateData.quantity, mbInfo.m_spread), this.ctx.material.decimal.tp); updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(updateData.m_tp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp); await transaction.update(this.tableName, updateData); if (mbInfo.quantity !== updateData.quantity) { returnData.m_tp = await this.calcMaterialMTp(transaction); } } await transaction.commit(); returnData.info = await this.getDataById(data.id); return returnData; } catch (err) { await transaction.rollback(); throw err; } } // 更改计算总金额并返回值 async calcMaterialMTp(transaction) { // 金额发生变化,则重新计算本期金额 const sql = 'SELECT SUM(`m_tp`) as total_price, SUM(IF(`m_tax_tp` is null, `m_tp`, `m_tax_tp`)) as tax_total_price FROM ' + this.tableName + ' WHERE `tid` = ? AND `is_summary` = 1'; const sqlParam = [this.ctx.tender.id]; const tp = await transaction.queryOne(sql, sqlParam); const updateData2 = { id: this.ctx.material.id, m_tp: tp.total_price, m_tax_tp: tp.tax_total_price, }; // 计算建筑税价 if (this.ctx.material.is_stage_self) { const materialStages = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }); let rate_tp = 0; for (const ms of materialStages) { const ms_rate_tp = this.ctx.helper.round(this.ctx.helper.mul(ms.m_tp, 1 + this.ctx.material.rate / 100), this.ctx.material.decimal.tp); rate_tp = this.ctx.helper.add(rate_tp, ms_rate_tp); } updateData2.rate_tp = rate_tp; } else { updateData2.rate_tp = this.ctx.helper.round(this.ctx.helper.mul(tp.total_price, 1 + this.ctx.material.rate / 100), this.ctx.material.decimal.tp); } console.log(tp); // if (this.ctx.material.material_tax) { // updateData2.m_tax_tp = tp.tax_total_price; // } await transaction.update(this.ctx.service.material.tableName, updateData2); // 找出当前人并更新tp_data const tp_data = await this.ctx.service.materialAudit.getTpData(transaction, this.ctx.material.id); if (this.ctx.material.status === auditConst.status.uncheck || this.ctx.material.status === auditConst.status.checkNo) { await transaction.update(this.ctx.service.material.tableName, { id: this.ctx.material.id, tp_data: JSON.stringify(tp_data), }); } else if (this.ctx.material.curAuditor) { await transaction.update(this.ctx.service.materialAudit.tableName, { id: this.ctx.material.curAuditor.id, tp_data: JSON.stringify(tp_data), }); } return tp.total_price; } // 小数位变化更新单价和金额 async resetDecimal(transaction, newDecimalUp, newDecimalTp, newDecimalQty) { const mbList = await transaction.select(this.tableName, { where: { tid: this.ctx.tender.id }, orders: [['order', 'asc']] }); const updateList = []; const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : []; const updateMonthList = []; const materialStageList = this.ctx.material.is_stage_self ? await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }) : []; for (const mb of mbList) { const updateData = { id: mb.id, }; if (this.ctx.material.is_stage_self) { const updateStageBillsList = []; for (const ms of materialStageList) { const msb = await transaction.get(this.ctx.service.materialStageBills.tableName, { mid: this.ctx.material.id, mb_id: mb.id, ms_id: ms.id }); msb.m_up_risk = mb.m_up_risk; msb.m_down_risk = mb.m_down_risk; const updateStageBillData = { id: msb.id, }; if (newDecimalQty !== this.ctx.material.decimal.qty) { // 通过管理重新算出quantity并保留小数位 if (mb.t_type === materialConst.t_type[0].value) { // 通过管理重新算出quantity并保留小数位 const newQuantity = await this.ctx.service.materialList.getMbQuantity(transaction, this.ctx.material.id, this.ctx.material.qty_source, newDecimalQty, mb.id, ms.id); if (newQuantity !== msb.quantity) { updateStageBillData.quantity = newQuantity; msb.quantity = newQuantity; } } else if (mb.t_type === materialConst.t_type[1].value) { const materialCalculator = new MaterialCalculator(this.ctx, ms.sid, this.ctx.tender.info); const quantity = await materialCalculator.calculateExpr(msb.expr); const newQuantity = this.ctx.helper.round(quantity, newDecimalQty); if (newQuantity !== msb.quantity) { updateStageBillData.quantity = newQuantity; msb.quantity = newQuantity; } } } if (newDecimalUp !== this.ctx.material.decimal.up) { const newmsg_tp = this.ctx.helper.round(msb.msg_tp, newDecimalUp); msb.msg_tp = newmsg_tp; const newbasic_price = this.ctx.helper.round(mb.basic_price, newDecimalUp); const [newmsg_spread, newm_spread] = await this.getSpread(msb, msb.msg_tp, newDecimalUp, newbasic_price); msb.m_spread = newm_spread; updateStageBillData.msg_tp = newmsg_tp; updateStageBillData.msg_spread = newmsg_spread; updateStageBillData.m_spread = newm_spread; } const newTp = this.ctx.helper.round(this.ctx.helper.mul(msb.quantity, msb.m_spread), newDecimalTp); updateStageBillData.m_tp = newTp; updateStageBillData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), newDecimalTp); updateStageBillsList.push(updateStageBillData); } if (newDecimalUp !== this.ctx.material.decimal.up) { const newbasic_price = this.ctx.helper.round(mb.basic_price, newDecimalUp); updateData.basic_price = newbasic_price; } if (updateStageBillsList.length > 0) await transaction.updateRows(this.ctx.service.materialStageBills.tableName, updateStageBillsList); const sql = 'SELECT SUM(`m_tp`) as total_price, SUM(IF(`m_tax_tp` is null, `m_tp`, `m_tax_tp`)) as tax_total_price FROM ' + this.ctx.service.materialStageBills.tableName + ' WHERE `tid` = ? AND `mid` = ? AND `mb_id` = ? AND `is_summary` = 1'; const sqlParam = [this.ctx.tender.id, this.ctx.material.id, mb.id]; const tp = await transaction.queryOne(sql, sqlParam); updateData.m_tp = this.ctx.helper.round(tp.total_price, newDecimalTp); updateData.m_tax_tp = this.ctx.helper.round(tp.tax_total_price, newDecimalTp); updateList.push(updateData); } else { if (newDecimalUp !== this.ctx.material.decimal.up) { let newmsg_tp = this.ctx.helper.round(mb.msg_tp, newDecimalUp); mb.msg_tp = newmsg_tp; // 判断是否有月信息价,如果有则msg_tp值由月信息价的平均单价获得,并更新月信息价单价 if (material_month.length > 0) { const monthList = await transaction.select(this.ctx.service.materialMonth.tableName, { where: { mb_id: mb.id, mid: this.ctx.material.id } }); if (monthList.length !== 0) { for (const m of monthList) { // 更新月信息单价小数位 const newMonthMsgTP = this.ctx.helper.round(m.msg_tp, newDecimalUp); if (m.msg_tp && newMonthMsgTP !== m.msg_tp) { m.msg_tp = newMonthMsgTP; updateMonthList.push({ id: m.id, msg_tp: m.msg_tp }); } } const mb_msg_tp_sum = this._.sumBy(monthList, 'msg_tp'); const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(monthList, 'msg_tp'), [null, '', 0]); newmsg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), newDecimalUp) : null; mb.msg_tp = newmsg_tp; } } const newbasic_price = this.ctx.helper.round(mb.basic_price, newDecimalUp); mb.basic_price = newbasic_price; const [newmsg_spread, newm_spread] = await this.getSpread(mb, mb.msg_tp, newDecimalUp); mb.m_spread = newm_spread; updateData.basic_price = newbasic_price; updateData.msg_tp = newmsg_tp; updateData.msg_spread = newmsg_spread; updateData.m_spread = newm_spread; } if (newDecimalQty !== this.ctx.material.decimal.qty) { // 通过管理重新算出quantity并保留小数位 if (mb.t_type === materialConst.t_type[0].value) { const newQuantity = await this.ctx.service.materialList.getMbQuantity(transaction, this.ctx.material.id, this.ctx.material.qty_source, newDecimalQty, mb.id); mb.quantity = newQuantity; updateData.quantity = newQuantity; } else if (mb.t_type === materialConst.t_type[1].value) { const materialCalculator = new MaterialCalculator(this.ctx, this.ctx.material.stage_id, this.ctx.tender.info); const quantity = await materialCalculator.calculateExpr(mb.expr); const newQuantity = this.ctx.helper.round(quantity, newDecimalQty); mb.quantity = newQuantity; updateData.quantity = newQuantity; } } const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, mb.m_spread), newDecimalTp); updateData.m_tp = newTp; updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), newDecimalTp); updateList.push(updateData); } } if (updateMonthList.length > 0) await transaction.updateRows(this.ctx.service.materialMonth.tableName, updateMonthList); if (updateList.length > 0) await transaction.updateRows(this.tableName, updateList); if (this.ctx.material.is_stage_self) { for (const ms of materialStageList) { await this.ctx.service.materialStage.updateMtp(transaction, ms.id); } } } // 来源模式变化更新单价和金额 async resetQuantityByQtySource(transaction, newQtySource) { const mbList = await transaction.select(this.tableName, { where: { tid: this.ctx.tender.id }, orders: [['order', 'asc']] }); const updateList = []; const materialStageList = this.ctx.material.is_stage_self ? await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }) : []; for (const mb of mbList) { if (mb.t_type === materialConst.t_type[0].value) { const updateData = { id: mb.id, }; if (this.ctx.material.is_stage_self) { const updateStageBillsList = []; for (const ms of materialStageList) { const msb = await transaction.get(this.ctx.service.materialStageBills.tableName, { mid: this.ctx.material.id, mb_id: mb.id, ms_id: ms.id, }); // 通过管理重新算出quantity并保留小数位 const newQuantity = await this.ctx.service.materialList.getMbQuantity(transaction, this.ctx.material.id, newQtySource, this.ctx.material.decimal.qty, mb.id, ms.id); if (newQuantity !== msb.quantity) { const updateStageBillData = { id: msb.id, quantity: newQuantity, }; msb.quantity = newQuantity; const newTp = this.ctx.helper.round(this.ctx.helper.mul(msb.quantity, msb.m_spread), this.ctx.material.decimal.tp); updateStageBillData.m_tp = newTp; updateStageBillData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), this.ctx.material.decimal.tp); updateStageBillsList.push(updateStageBillData); } } if (updateStageBillsList.length > 0) await transaction.updateRows(this.ctx.service.materialStageBills.tableName, updateStageBillsList); const sql = 'SELECT SUM(`m_tp`) as total_price, SUM(IF(`m_tax_tp` is null, `m_tp`, `m_tax_tp`)) as tax_total_price FROM ' + this.ctx.service.materialStageBills.tableName + ' WHERE `tid` = ? AND `mid` = ? AND `mb_id` = ? AND `is_summary` = 1'; const sqlParam = [this.ctx.tender.id, this.ctx.material.id, mb.id]; const tp = await transaction.queryOne(sql, sqlParam); updateData.m_tp = this.ctx.helper.round(tp.total_price, this.ctx.material.decimal.tp); updateData.m_tax_tp = this.ctx.helper.round(tp.tax_total_price, this.ctx.material.decimal.tp); updateList.push(updateData); } else { const newQuantity = await this.ctx.service.materialList.getMbQuantity(transaction, this.ctx.material.id, newQtySource, this.ctx.material.decimal.qty, mb.id); if (newQuantity !== mb.quantity) { mb.quantity = newQuantity; updateData.quantity = newQuantity; const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, mb.m_spread), this.ctx.material.decimal.tp); updateData.m_tp = newTp; updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), this.ctx.material.decimal.tp); updateList.push(updateData); } } } } if (updateList.length > 0) await transaction.updateRows(this.tableName, updateList); if (this.ctx.material.is_stage_self) { for (const ms of materialStageList) { await this.ctx.service.materialStage.updateMtp(transaction, ms.id); } } } async updateAllOrder(updateList) { await this.db.updateRows(this.tableName, updateList); } } return MaterialBills; };