'use strict'; /** * * * @author Mai * @date 2018/10/30 * @version */ const infoConst = require('../const/tender_info'); const parseInfo = infoConst.parseInfo; const arrayInfo = infoConst.arrayInfo; const advanceConst = require('../const/audit').advance; const auditConst = require('../const/audit'); const measureType = require('../const/tender').measureType; module.exports = app => { class TenderInfo extends app.BaseService { /** * 构造函数 * * @param {Object} ctx - egg全局变量 * @return {void} */ constructor(ctx) { super(ctx); this.tableName = 'tender_info'; } async getDefaultInfo (tenderId) { const tender = await this.ctx.service.tender.getTender(tenderId); return tender.measure_type === measureType.tz.value ? infoConst.tzDefaultInfo : infoConst.gclDefaultInfo; } /** * 新增 标段相关信息 * * @param tenderId - 标段Id * @param projectId - 项目Id * @param transaction - 事务 * @return {Promise} */ async addTenderInfo(tenderId, projectId, transaction) { const defaultInfo = await this.getDefaultInfo(tenderId); const info = JSON.parse(JSON.stringify(defaultInfo)); info.tid = tenderId; info.pid = projectId; for (const pi of parseInfo) { info[pi] = JSON.stringify(info[pi]); } for (const pi of arrayInfo) { info[pi] = JSON.stringify(info[pi]); } if (transaction) { await transaction.insert(this.tableName, info); } else { await this.db.insert(this.tableName, info); } return info; } /** * 获取标段相关信息 * @param tenderId * @return {Promise} */ async getTenderInfo(tenderId, projectId) { const defaultInfo = await this.getDefaultInfo(tenderId); let info = await this.getDataByCondition({ tid: tenderId }); // 兼容不存在info的情况 if (!info) info = await this.addTenderInfo(tenderId, projectId || this.ctx.session.sessionProject.id); for (const pi of parseInfo) { info[pi] = !info[pi] || info[pi] === '' ? (pi === 'shenpi' ? JSON.parse(JSON.stringify(defaultInfo[pi])) : defaultInfo[pi]) : JSON.parse(info[pi]); this.ctx.helper._.defaultsDeep(info[pi], defaultInfo[pi]); } for (const ai of arrayInfo) { info[ai] = !info[ai] || info[ai] === '' ? defaultInfo[ai] : JSON.parse(info[ai]); } if (info.decimal) { info.decimal._pay_tp = info.decimal.pay ? info.decimal.payTp : info.decimal.tp; } return info; } /** * 获取标段相关信息(报表用) * @param tenderId * @return {Promise} */ async getTenderInfoEx(tenderId) { const defaultInfo = await this.getDefaultInfo(tenderId); const sql = 'select t2.name, t1.* from zh_tender_info t1 inner join zh_tender t2 on t2.id = t1.tid where t1.tid = ?'; const sqlParam = [tenderId]; const list = await this.db.query(sql, sqlParam); const info = list[0]; const len = info.deal_info.length; info.deal_info = info.deal_info.slice(0, len - 1) + ',"name":"' + info.name + '"' + info.deal_info.slice(len - 1); for (const pi of parseInfo) { info[pi] = !info[pi] || info[pi] === '' ? defaultInfo[pi] : JSON.parse(info[pi]); this.ctx.helper._.defaults(info[pi], defaultInfo[pi]); } for (const ai of arrayInfo) { info[ai] = !info[ai] || info[ai] === '' ? defaultInfo[ai] : JSON.parse(info[ai]); } if (info.decimal) { info.decimal._pay_tp = info.decimal.pay ? info.decimal.payTp : info.decimal.tp; } return info; } /** * 保存标段相关信息 * * @param data * @return {Promise} */ async saveTenderInfo(tenderId, data) { for (const di in data) { if (parseInfo.indexOf(di) >= 0 || arrayInfo.indexOf(di) >= 0) { data[di] = JSON.stringify(data[di]); } } await this.db.update(this.tableName, data, { where: { tid: tenderId } }); } async _getLedgerService() { try { if (this.ctx.tender.data.ledger_status === auditConst.ledger.status.checked) { const revise = await this.ctx.service.ledgerRevise.getLastestRevise(this.ctx.tender.id); if (revise.status === auditConst.revise.status.uncheck || revise.status === auditConst.revise.status.checkNo) { return [this.ctx.service.reviseBills, this.ctx.service.revisePos]; } } else { return [this.ctx.service.ledger, this.ctx.service.pos]; } } catch(err) { } return []; } async savePrecision(tenderId, newPrecision, oldPrecision, decimal) { const changePrecision = []; const units = await this.ctx.service.ledger.getTenderUsedUnits(tenderId); const defUnits = this._.map(newPrecision, 'units'); const otherUnits = units.filter(function(u) { return defUnits.indexOf(u) === -1; }); let changeUnits = []; for (const prop in newPrecision) { if (oldPrecision[prop]) { if (newPrecision[prop].value < oldPrecision[prop].value) { changePrecision.push(newPrecision[prop]); } } else { changePrecision.push(newPrecision[prop]); } } for (const cp of changePrecision) { if (cp.unit) { changeUnits.push(cp.unit); } else { changeUnits.push(otherUnits); } } changeUnits = this._.flatten(changeUnits); const [billsService, posService] = await this._getLedgerService(); if (changeUnits.length > 0 && billsService && posService) { const bills = await billsService.getAllDataByCondition({ columns: ['id', 'unit', 'unit_price', 'sgfh_qty', 'sjcl_qty', 'qtcl_qty', 'deal_qty'], where: { tender_id: tenderId, unit: changeUnits, is_leaf: true }, }); const pos = changeUnits.length > 0 ? await posService.getPosDataByUnits(tenderId, changeUnits) : []; for (const b of bills) { const precision = this.ctx.helper.findPrecision(newPrecision, b.unit); const bPos = this._.filter(pos, { lid: b.id }); if (bPos.length > 0) { let sgfh_qty = 0, sjcl_qty = 0, qtcl_qty = 0, quantity = 0; for (const p of bPos) { this.ctx.helper.checkFieldPrecision(p, ['sgfh_qty', 'sjcl_qty', 'qtcl_qty'], precision.value); p.quantity = this.ctx.helper.add(this.ctx.helper.add(p.sgfh_qty, p.sjcl_qty), p.qtcl_qty); sgfh_qty = this.ctx.helper.add(sgfh_qty, p.sgfh_qty); sjcl_qty = this.ctx.helper.add(sjcl_qty, p.sjcl_qty); qtcl_qty = this.ctx.helper.add(qtcl_qty, p.qtcl_qty); quantity = this.ctx.helper.add(quantity, p.quantity); } b.sgfh_qty = sgfh_qty; b.sjcl_qty = sjcl_qty; b.qtcl_qty = qtcl_qty; b.quantity = quantity; // this.ctx.helper.checkFieldPrecision(b, ['deal_qty'], precision.value); } else { this.ctx.helper.checkFieldPrecision(b, ['sgfh_qty', 'sjcl_qty', 'qtcl_qty', 'deal_qty'], precision.value); } b.quantity = this.ctx.helper.add(this.ctx.helper.add(b.sgfh_qty, b.sjcl_qty), b.qtcl_qty); b.sgfh_tp = this.ctx.helper.mul(b.sgfh_qty, b.unit_price, decimal.tp); b.sjcl_tp = this.ctx.helper.mul(b.sjcl_qty, b.unit_price, decimal.tp); b.qtcl_tp = this.ctx.helper.mul(b.qtcl_qty, b.unit_price, decimal.tp); b.deal_tp = this.ctx.helper.mul(b.deal_qty, b.unit_price, decimal.tp); b.total_price = this.ctx.helper.mul(b.quantity, b.unit_price, decimal.tp); } const transaction = await this.db.beginTransaction(); try { await transaction.update(this.tableName, { precision: JSON.stringify(newPrecision) }, { where: { tid: tenderId } }); if (bills.length > 0) await transaction.updateRows(billsService.tableName, bills); if (pos.length > 0) await transaction.updateRows(posService.tableName, pos); await transaction.commit(); } catch (err) { await transaction.rollback(); throw err; } } else { await this.db.update(this.tableName, { precision: JSON.stringify(newPrecision) }, { where: { tid: tenderId } }); } } async _reCalcLedger(tenderId, billsService, newDecimal, oldDecimal) { if (!billsService) return []; const changeBills = []; const calcUp = newDecimal.up < oldDecimal.up, calcTp = newDecimal.tp !== oldDecimal.tp; if (calcUp || calcTp) { const bills = await billsService.getAllDataByCondition({ columns: ['id', 'unit_price', 'sgfh_qty', 'sjcl_qty', 'qtcl_qty', 'deal_qty', 'quantity'], where: { tender_id: tenderId, is_leaf: true }, }); for (const b of bills) { const cb = { id: b.id }; cb.unit_price = calcUp ? this.ctx.helper.round(b.unit_price, newDecimal.up) : b.unit_price; cb.sgfh_tp = this.ctx.helper.mul(b.sgfh_qty, cb.unit_price, newDecimal.tp); cb.sjcl_tp = this.ctx.helper.mul(b.sjcl_qty, cb.unit_price, newDecimal.tp); cb.qtcl_tp = this.ctx.helper.mul(b.qtcl_qty, cb.unit_price, newDecimal.tp); cb.deal_tp = this.ctx.helper.mul(b.deal_qty, cb.unit_price, newDecimal.tp); cb.total_price = this.ctx.helper.mul(b.quantity, cb.unit_price, newDecimal.tp); changeBills.push(cb); } } return changeBills; } async _reCalcStageBills(tenderId, newDecimal, oldDecimal) { const updateStageBills = [], insertStageBills = []; const stages = await this.ctx.service.stage.getUnCompleteStages(tenderId); if (stages.length === 0 || newDecimal.tp === oldDecimal.tp) return [updateStageBills, insertStageBills]; for (const stage of stages) { const stageBills = await this.ctx.service.stageBills.getLastestStageData2(stage.tid, stage.id); const bills = await this.ctx.service.ledger.getAllDataByCondition({ columns: ['id', 'unit_price'], where: { tender_id: tenderId, is_leaf: true }, }); for (const sb of stageBills) { const b = bills.find(x => {return x.id === sb.lid}); const contract_tp = this.ctx.helper.mul(b.unit_price, sb.contract_qty, newDecimal.tp); const qc_tp = this.ctx.helper.mul(b.unit_price, sb.qc_qty, newDecimal.tp); if (contract_tp == sb.contract_tp && qc_tp === sb.qc_tp) continue; if (sb.times === stage.times && sb.order === 0) { updateStageBills.push({ id: sb.id, contract_tp, qc_tp }); } else { insertStageBills.push({ tid: stage.tid, lid: sb.lid, sid: stage.id, said: this.ctx.session.sessionUser.accountId, times: stage.times, order: 0, contract_qty: sb.contract_qty, contract_expr: sb.contract_expr, contract_tp, qc_qty: sb.qc_qty, qc_tp, postil: sb.postil, }); } } } return [updateStageBills, insertStageBills]; } async _reCalcStageExtra(tenderId, newDecimal, oldDecimal) { const changeSj = [], changeSb = [], changeSo = []; const stages = await this.ctx.service.stage.getUnCompleteStages(tenderId); if (stages.length === 0) return [changeSj, changeSb, changeSo]; const upDecimal = newDecimal.up, tpDecimal = newDecimal.extra ? newDecimal.extraTp : newDecimal.tp; const calcUp = upDecimal < oldDecimal.up, calcTp = tpDecimal < (oldDecimal.extra ? oldDecimal.extraTp : oldDecimal.tp); for (const stage of stages) { if (calcUp || calcTp) { const stageJgcl = await this.ctx.service.stageJgcl.getAllDataByCondition({ columns: ['id', 'unit_price', 'arrive_qty', 'deduct_qty'], where: { sid: stage.id } }); for (const sj of stageJgcl) { const cj = { id: sj.id }; cj.unit_price = calcUp ? this.ctx.helper.round(sj.unit_price, upDecimal) : sj.unit_price; cj.arrive_tp = this.ctx.helper.mul(sj.arrive_qty, sj.unit_price, tpDecimal); cj.deduct_tp = this.ctx.helper.mul(sj.deduct_qty, sj.unit_price, tpDecimal); changeSj.push(cj); } } if (calcTp) { const stageChangeSb = await this.ctx.service.stageBonus.getAllDataByCondition({ columns: ['id', 'tp'], where: { sid: stage.id } }); for (const cb of stageChangeSb) { cb.tp = this.ctx.helper.round(cb.tp, tpDecimal); } changeSb.push(...stageChangeSb); const stageChangeSo = await this.ctx.service.stageOther.getAllDataByCondition({ columns: ['id', 'total_price', 'tp'], where: { sid: stage.id } }); for (const co of stageChangeSo) { if (stage.order === 1) co.total_price = this.ctx.helper.round(co.total_price, tpDecimal); co.tp = this.ctx.helper.round(co.tp, tpDecimal); } changeSo.push(...stageChangeSo); } } return [changeSj, changeSb, changeSo]; } async saveDecimal(tenderId, newDecimal, oldDecimal) { const changeAdvanceBills = []; const caclPayTp = (newDecimal.pay ? newDecimal.payTp : newDecimal.tp) < (oldDecimal.pay ? oldDecimal.payTp : oldDecimal.tp); if (caclPayTp) { // 获取预付款需要修改的相关记录 const ad_bills = await this.ctx.service.advance.getAllDataByCondition({ columns: ['id', 'cur_amount', 'prev_amount', 'prev_total_amount'], where: { status: [advanceConst.status.uncheck, advanceConst.status.checkNo], tid: tenderId }, }); const decimal = newDecimal.pay ? newDecimal.payTp : newDecimal.tp; // 根据精度重新计算相关金额 for (const ad of ad_bills) { const cb = { id: ad.id }; const cur_amount = this.ctx.helper.round(ad.cur_amount, decimal); cb.cur_amount = cur_amount; cb.prev_total_amount = this.ctx.helper.add(cur_amount, ad.prev_amount); changeAdvanceBills.push(cb); } } const [billsService] = await this._getLedgerService(); const changeBills = await this._reCalcLedger(tenderId, billsService, newDecimal, oldDecimal); const [updateStageBills, insertStageBills] = await this._reCalcStageBills(tenderId, newDecimal, oldDecimal); const [changeSj, changeSb, changeSo] = await this._reCalcStageExtra(tenderId, newDecimal, oldDecimal); if (changeBills.length > 0 || changeAdvanceBills.length > 0 || updateStageBills.length > 0 || insertStageBills.length > 0 || changeSj.length > 0 || changeSb.length > 0 || changeSo.length > 0) { const transaction = await this.db.beginTransaction(); try { await transaction.update(this.tableName, { decimal: JSON.stringify(newDecimal) }, { where: { tid: tenderId } }); if (changeBills.length > 0) await transaction.updateRows(billsService.tableName, changeBills); if (updateStageBills.length > 0) await transaction.updateRows(this.ctx.service.stageBills.tableName, updateStageBills); if (insertStageBills.length > 0) await transaction.insert(this.ctx.service.stageBills.tableName, insertStageBills); if (changeSj.length > 0) await transaction.updateRows(this.ctx.service.stageJgcl.tableName, changeSj); if (changeSb.length > 0) await transaction.updateRows(this.ctx.service.stageBonus.tableName, changeSb); if (changeSo.length > 0) await transaction.updateRows(this.ctx.service.stageOther.tableName, changeSo); if (changeAdvanceBills.length) await transaction.updateRows(this.ctx.service.advance.tableName, changeAdvanceBills); await transaction.commit(); } catch (error) { await transaction.rollback(); throw error; } } else { await this.db.update(this.tableName, { decimal: JSON.stringify(newDecimal) }, { where: { tid: tenderId } }); } } /** * 获取标段审批相关信息 (审批设置用) * @param tenderId * @return {Promise} */ async getTenderShenpiInfo(tenderId) { const defaultInfo = await this.getDefaultInfo(tenderId); const info = await this.getDataByCondition({ tid: tenderId }); // 还没选择模式的标段不应该可以选择审批流程设置 if (!info) { return false; } const defaultShenpiInfo = JSON.parse(JSON.stringify(defaultInfo.shenpi)); const shenpiInfo = !info.shenpi || info.shenpi === null || info.shenpi === '' ? defaultShenpiInfo : JSON.parse(info.shenpi); // 查漏补缺 for (const sp in defaultShenpiInfo) { if (!shenpiInfo[sp]) { shenpiInfo[sp] = defaultShenpiInfo[sp]; } } return shenpiInfo; } /** * 拷贝标段数据至当前标段 * @param {number} id - 当前标段id * @param {number} copy_id - 被拷贝的标段id * @param {Array} typeArr - 需要拷贝的类型数组 */ async copyTenderHandler(id, copy_id, typeArr) { const columns = []; typeArr.forEach(item => { if (item === 'tender') { columns.push('deal_info', 'construction_unit', 'tech_param', 'bid_info'); } else if (item === 'chapter') { columns.push('chapter'); } else if (item === 'pay_account') { columns.push('pay_account'); } }); if (!columns.length) throw '未选择需要拷贝的设置'; const [data] = await this.getAllDataByCondition({ where: { tid: copy_id, }, columns, }); const isUpdate = await this.update(data, { tid: id }); if (isUpdate) { await this.ctx.service.tender.update({ copy_id }, { id }); } } } return TenderInfo; };