'use strict'; /** * * * @author Mai * @date 2018/8/14 * @version */ const audit = require('../const/audit'); const fs = require('fs'); const path = require('path'); const changeConst = require('../const/change'); const smsTypeConst = require('../const/sms_type'); const SMS = require('../lib/sms'); const SmsAliConst = require('../const/sms_alitemplate'); const wxConst = require('../const/wechat_template'); const pushType = require('../const/audit').pushType; const projectLogConst = require('../const/project_log'); module.exports = app => { class Change extends app.BaseService { /** * 构造函数 * * @param {Object} ctx - egg全局变量 * @return {void} */ constructor(ctx) { super(ctx); this.tableName = 'change'; } /** * 查找数据 * * @param {Object} data - 筛选表单中的get数据 * @return {void} */ searchFilter(data) { this.initSqlBuilder(); // this.sqlBuilder.columns = ['id', 'username', 'real_name', 'create_time', 'last_login', 'login_ip', // 'group_id', 'token', 'can_login']; data.type = parseInt(data.status); if (data.keyword !== undefined) { switch (data.type) { // 用户名 case 1: this.sqlBuilder.setAndWhere('username', { value: this.db.escape(data.keyword + '%'), operate: 'like', }); break; // 姓名 case 2: this.sqlBuilder.setAndWhere('real_name', { value: this.db.escape(data.keyword + '%'), operate: 'like', }); break; // 联系电话 case 3: this.sqlBuilder.setAndWhere('telephone', { value: this.db.escape(data.keyword + '%'), operate: 'like', }); break; default: break; } } // 办事处筛选 if (data.office !== undefined && data.office !== '') { this.sqlBuilder.setAndWhere('office', { value: this.db.escape(data.office), operate: '=', }); } } async add(tenderId, userId, code, plan_code, name) { const sql = 'SELECT COUNT(*) as count FROM ?? WHERE `tid` = ? AND ((`code` = ? AND `status` != ?) OR (`p_code` = ? AND `status` = ?))'; const sqlParam = [this.tableName, tenderId, code, audit.flow.status.checked, code, audit.flow.status.checked]; const codeCount = await this.db.queryOne(sql, sqlParam); const count = codeCount.count; if (count > 0) { throw '变更令号重复'; } // 初始化事务 this.transaction = await this.db.beginTransaction(); let result = false; try { const cid = this.uuid.v4(); const change = { cid, tid: tenderId, uid: userId, status: audit.flow.status.uncheck, times: 1, valid: true, in_time: new Date(), code, name, plan_code, // tp_decimal: this.ctx.tender.info.decimal.tp, // up_decimal: this.ctx.tender.info.decimal.up, }; if (plan_code) { const planInfo = await this.ctx.service.changePlan.getDataByCondition({ tid: tenderId, code: plan_code }); if (planInfo) { change.org_name = planInfo.org_name; change.peg = planInfo.peg; change.org_code = planInfo.new_code; change.new_code = planInfo.c_new_code; change.new_name = planInfo.design_name; const classIndex = planInfo.class && this._.indexOf(changeConst.className, planInfo.class) !== -1 ? this._.indexOf(changeConst.className, planInfo.class) : 0; change.class = classIndex ? classIndex : changeConst.class.A.value; const qualityIndex = planInfo.quality && this._.indexOf(changeConst.qualityName, planInfo.quality) !== -1 ? this._.indexOf(changeConst.qualityName, planInfo.quality) : 0; change.quality = qualityIndex ? qualityIndex : changeConst.quality.common.value; let content = planInfo.reason ? planInfo.reason.replace(/[\r\n]/g, '\r\n') : ''; content = content + (planInfo.content ? (planInfo.reason ? '\r\n' : '') + planInfo.content.replace(/[\r\n]/g, '\r\n') : ''); change.content = content ? content : null; } } const operate = await this.transaction.insert(this.tableName, change); if (operate.affectedRows <= 0) { throw '新建变更令数据失败'; } // 把提交人信息添加到zh_change_audit const userInfo = await this.ctx.service.projectAccount.getDataById(userId); const changeaudit = [ { tid: tenderId, cid, uid: userId, name: userInfo.name, jobs: userInfo.role, company: userInfo.company, times: 1, usite: 0, usort: 0, status: 2, }, ]; // 并把之前存在的变更令审批人添加到zh_change_audit // 先找出标段最近存在的变更令审批人的变更令info const changeInfo = await this.ctx.service.change.getHaveAuditLastInfo(tenderId); if (changeInfo) { // 再获取非原报审批人 const auditList = await this.ctx.service.changeAudit.getListGroupByTimes(changeInfo.cid, changeInfo.times); let sort = 1; for (const audit of auditList) { if (audit.usite !== 0) { const oneaudit = { tid: tenderId, cid, uid: audit.uid, name: audit.name, jobs: audit.jobs, company: audit.company, times: 1, usite: audit.usite, usort: sort++, status: 1, }; changeaudit.push(oneaudit); } } } await this.transaction.insert(this.ctx.service.changeAudit.tableName, changeaudit); result = change; this.transaction.commit(); } catch (error) { console.log(error); // 回滚 await this.transaction.rollback(); } return result; } async getHaveAuditLastInfo(tenderId) { const sql = 'SELECT a.* FROM ?? as a LEFT JOIN ?? as b ON a.`cid` = b.`cid` WHERE a.`tid` = ? AND b.`usite` > 0 ORDER BY a.`in_time` DESC'; const sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId]; return await this.db.queryOne(sql, sqlParam); } async pendingDatas(tenderId, userId) { return await this.getAllDataByCondition({ tid: tenderId, uid: userId, status: audit.flow.status.checking, }); } async uncheckDatas(tenderId, userId) { return await this.getAllDataByCondition({ tid: tenderId, uid: userId, status: audit.flow.status.uncheck, }); } async checkingDatas(tenderId, userId) { return await this.getAllDataByCondition({ tid: tenderId, uid: userId, status: audit.flow.status.checking, }); } async checkedDatas(tenderId, userId) { return await this.getAllDataByCondition({ tid: tenderId, uid: userId, status: audit.flow.status.checked, }); } async checkNoDatas(tenderId, userId) { return await this.getAllDataByCondition({ tid: tenderId, uid: userId, status: audit.flow.status.checkNo, }); } async checkNoCount(tenderId, userId) { return await this.count({ tid: tenderId, uid: userId, status: audit.flow.status.checkNo, }); } /** * 获取变更令列表 * @param {int} tenderId - 标段id * @param {int} status - 状态 * @param {int} hadlimit - 分页 * @return {object} list - 列表 */ async getListByStatus(tenderId, status = 0, hadlimit = 1, sortBy = '', orderBy = '') { let sql = ''; let sqlParam = ''; if (this.ctx.tender.isTourist && status === 0) { sql = 'SELECT a.* FROM ?? As a WHERE a.tid = ?'; sqlParam = [this.tableName, tenderId]; } else { switch (status) { case 0: // 包含你的所有变更令 sql = 'SELECT a.* FROM ?? AS a WHERE a.tid = ? AND ' + '(a.uid = ? OR (a.status != ? AND a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid)) OR a.status = ? )'; sqlParam = [ this.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.status.uncheck, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, audit.flow.status.checked, ]; break; case 1: // 待处理(你的) sql = 'SELECT a.* FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?)'; sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.auditStatus.checking]; break; case 5: // 待上报(所有的)PS:取未上报,退回,修订的变更令 sql = 'SELECT a.* FROM ?? AS a WHERE ' + 'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? GROUP BY b.cid) AND ' + '(a.status = ? OR a.status = ? OR a.status = ?) AND a.tid = ?'; sqlParam = [ this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, audit.flow.status.uncheck, audit.flow.status.back, audit.flow.status.revise, tenderId, ]; break; case 2: // 进行中(所有的) case 4: // 终止(所有的) sql = 'SELECT a.* FROM ?? AS a WHERE ' + 'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) AND ' + 'a.status = ? AND a.tid = ?'; sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, status, tenderId]; break; case 3: // 已完成(所有的) sql = 'SELECT a.* FROM ?? AS a WHERE a.status = ? AND a.tid = ?'; sqlParam = [this.tableName, status, tenderId]; break; default: break; } } if (sortBy && orderBy) { if (sortBy === 'code') { sql += ' ORDER BY CHAR_LENGTH(a.code) ' + orderBy + ',convert(a.code using gbk) ' + orderBy; } else { sql += ' ORDER BY a.in_time ' + orderBy; } } else { sql += ' ORDER BY a.in_time DESC'; } if (hadlimit) { const limit = this.app.config.pageSize; const offset = limit * (this.ctx.page - 1); const limitString = offset >= 0 ? offset + ',' + limit : limit; sql += ' LIMIT ' + limitString; } const list = await this.db.query(sql, sqlParam); return list; } /** * 获取变更令个数 * @param {int} tenderId - 标段id * @param {int} status - 状态 * @return {void} */ async getCountByStatus(tenderId, status) { if (this.ctx.tender.isTourist && status === 0) { const sql5 = 'SELECT count(*) AS count FROM ?? WHERE tid = ? ORDER BY in_time DESC'; const sqlParam5 = [this.tableName, tenderId]; const result5 = await this.db.query(sql5, sqlParam5); return result5[0].count; } switch (status) { case 0: // 包含你的所有变更令 const sql = 'SELECT count(*) AS count FROM ?? AS a WHERE a.tid = ? AND ' + '(a.uid = ? OR (a.status != ? AND a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid)) OR a.status = ? )'; const sqlParam = [ this.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.status.uncheck, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, audit.flow.status.checked, ]; const result = await this.db.query(sql, sqlParam); return result[0].count; case 1: // 待处理(你的) // return await this.ctx.service.changeAudit.count({ // tid: tenderId, // uid: this.ctx.session.sessionUser.accountId, // status: 2, // }); const sql6 = 'SELECT count(*) AS count FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?)'; const sqlParam6 = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.auditStatus.checking]; const result6 = await this.db.query(sql6, sqlParam6); return result6[0].count; case 5: // 待上报(所有的)PS:取未上报,退回,修订的变更令 const sql2 = 'SELECT count(*) AS count FROM ?? AS a WHERE ' + 'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) ' + 'AND (a.status = ? OR a.status = ? OR a.status = ?) AND a.tid = ?'; const sqlParam2 = [ this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, audit.flow.status.uncheck, audit.flow.status.back, audit.flow.status.revise, tenderId, ]; const result2 = await this.db.query(sql2, sqlParam2); return result2[0].count; case 2: // 进行中(所有的) case 4: // 终止(所有的) const sql3 = 'SELECT count(*) AS count FROM ?? AS a WHERE ' + 'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) AND a.status = ? AND a.tid = ?'; const sqlParam3 = [this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, status, tenderId]; const result3 = await this.db.query(sql3, sqlParam3); return result3[0].count; case 3: // 已完成(所有的) const sql4 = 'SELECT count(*) AS count FROM ?? WHERE status = ? AND tid = ?'; const sqlParam4 = [this.tableName, status, tenderId]; const result4 = await this.db.query(sql4, sqlParam4); return result4[0].count; default: break; } } async getTp(tenderId, status) { if (this.ctx.tender.isTourist && status === 0) { const sql5 = 'SELECT SUM(cast (total_price as decimal(18,6))) AS total_price FROM ?? WHERE tid = ?'; const sqlParam5 = [this.tableName, tenderId]; const result5 = await this.db.query(sql5, sqlParam5); return result5[0].total_price ? result5[0].total_price : 0; } switch (status) { case 0: // 包含你的所有变更令 const sql = 'SELECT SUM(cast (a.total_price as decimal(18,6))) AS total_price FROM ?? AS a WHERE a.tid = ? AND ' + '(a.uid = ? OR (a.status != ? AND a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid)) OR a.status = ? )'; const sqlParam = [ this.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.status.uncheck, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, audit.flow.status.checked, ]; const result = await this.db.query(sql, sqlParam); return result[0].total_price ? result[0].total_price : 0; case 1: // 待处理(你的) const sql6 = 'SELECT SUM(cast (a.total_price as decimal(18,6))) AS total_price FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?)'; const sqlParam6 = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.auditStatus.checking]; const result6 = await this.db.query(sql6, sqlParam6); return result6[0].total_price ? result6[0].total_price : 0; case 5: // 待上报(所有的)PS:取未上报,退回,修订的变更令 const sql2 = 'SELECT SUM(cast (a.total_price as decimal(18,6))) AS total_price FROM ?? AS a WHERE ' + 'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) ' + 'AND (a.status = ? OR a.status = ? OR a.status = ?) AND a.tid = ?'; const sqlParam2 = [ this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, audit.flow.status.uncheck, audit.flow.status.back, audit.flow.status.revise, tenderId, ]; const result2 = await this.db.query(sql2, sqlParam2); return result2[0].total_price ? result2[0].total_price : 0; case 2: // 进行中(所有的) case 4: // 终止(所有的) const sql3 = 'SELECT SUM(cast (a.total_price as decimal(18,6))) AS total_price FROM ?? AS a WHERE ' + 'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) AND a.status = ? AND a.tid = ?'; const sqlParam3 = [this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, status, tenderId]; const result3 = await this.db.query(sql3, sqlParam3); return result3[0].total_price ? result3[0].total_price : 0; case 3: // 已完成(所有的) const sql4 = 'SELECT SUM(cast (total_price as decimal(18,6))) AS total_price FROM ?? WHERE status = ? AND tid = ?'; const sqlParam4 = [this.tableName, status, tenderId]; const result4 = await this.db.query(sql4, sqlParam4); return result4[0].total_price ? result4[0].total_price : 0; default: break; } } /** * 获取变更令个数 * @param {int} tenderId - 标段id * @param {int} quality - 变更性质 * @return {void} */ async getCountByQuality(tenderId, quality) { return await this.db.count(this.tableName, { tid: tenderId, quality }); } /** * 获取变更令个数 * @param {int} tenderId - 标段id * @param {int} status - 状态 * @return {void} */ async getCountByStatus2(tenderId, status) { if (status === audit.filter.status.uncheck) { const sql = 'SELECT count(*) AS count FROM ?? WHERE ' + 'tid = ? AND (status = ? OR status = ? OR status = ?)'; const sqlParam = [ this.tableName, tenderId, audit.flow.status.uncheck, audit.flow.status.back, audit.flow.status.revise, ]; const result = await this.db.queryOne(sql, sqlParam); return result ? result.count : 0; } return await this.db.count(this.tableName, { tid: tenderId, status }); } /** * 获取已批复变更令的总金额 * @param {int} tenderId - 标段id * @param {int} quality - 变更性质 * @return {void} */ async getChangeTp(tenderId) { const sql = 'SELECT SUM(`total_price`) AS tp FROM ?? WHERE tid = ? AND status = ?'; const sqlParam = [this.tableName, tenderId, audit.flow.status.checked]; const result = await this.db.queryOne(sql, sqlParam); return result ? result.tp : 0; } /** * 上报或重新上报或保存修改功能 * @param {int} postData - 表单提交的数据 * @param {int} tenderId - 标段id * @return {void} */ async save(postData, tenderId) { // 初始化事务 this.transaction = await this.db.beginTransaction(); let result = false; try { // 变更令信息 const changeInfo = await this.getDataByCondition({ cid: postData.cid }); // 该变更令原报人信息 const lastUser = await this.ctx.service.changeAudit.getLastUser(changeInfo.cid, changeInfo.times, 0); // 先删除本次原有的变更审批人和清单 await this.ctx.service.changeAudit.deleteAuditData(this.transaction, changeInfo.cid, changeInfo.times); await this.transaction.delete(this.ctx.service.changeAuditList.tableName, { cid: changeInfo.cid }); let change_status = false; // 获取变更令提交状态 if (postData.changestatus !== undefined && parseInt(postData.changestatus) === 1) { change_status = true; // 更新原报人审批状态 await this.transaction.update(this.ctx.service.changeAudit.tableName, { id: lastUser.id, status: audit.flow.auditStatus.checked, sin_time: new Date(), }); } // 再插入postData里的变更审批人和清单 if (postData.changeaudit !== undefined && postData.changeaudit !== '') { const changeAudit = postData.changeaudit.split(','); const insertCA = []; let uSite = 1; let uSort = parseInt(lastUser.usort) + 1; for (const [index, ca] of changeAudit.entries()) { const auditInfo = ca.split('/%/'); const uStatus = change_status && index === 0 ? audit.flow.auditStatus.checking : audit.flow.auditStatus.uncheck; const sin_time = change_status && index === 0 ? new Date() : null; const caArray = { tid: tenderId, cid: changeInfo.cid, uid: auditInfo[0], name: auditInfo[1], jobs: auditInfo[2], company: auditInfo[3], times: changeInfo.times, usite: uSite, usort: uSort, status: uStatus, sin_time, }; uSite++; uSort++; insertCA.push(caArray); // 添加短信通知-需要审批提醒功能 if (change_status && index === 0) { const sms = new SMS(this.ctx); const code = await sms.contentChange(changeInfo.code); const shenpiUrl = await this.ctx.helper.urlToShort( this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + changeInfo.tid + '/change/' + changeInfo.cid + '/info#shenpi' ); await this.ctx.helper.sendAliSms(auditInfo[0], smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), SmsAliConst.template.change_check, { biangeng: code, code: shenpiUrl, }); // 微信模板通知 const wechatData = { wap_url: shenpiUrl, status: wxConst.status.check, tips: wxConst.tips.check, code: this.ctx.session.sessionProject.code, c_name: changeInfo.name, }; await this.ctx.helper.sendWechat(auditInfo[0], smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), wxConst.template.change, wechatData); } } await this.transaction.insert(this.ctx.service.changeAudit.tableName, insertCA); } let changeList = []; if (postData.changelist !== undefined && postData.changelist !== '') { changeList = postData.changelist.split('^_^'); } let changeWhiteList = []; if (postData.changewhitelist !== undefined && postData.changewhitelist !== '') { changeWhiteList = postData.changewhitelist.split('^_^'); } changeList.push.apply(changeList, changeWhiteList); const insertCL = []; let total_price = 0; if (changeList.length > 0) { for (const cl of changeList) { const clInfo = cl.split('*;*'); const clArray = { tid: tenderId, cid: changeInfo.cid, lid: clInfo[8], code: clInfo[0], name: clInfo[1], bwmx: clInfo[2], unit: clInfo[3], unit_price: clInfo[4], oamount: clInfo[5], camount: clInfo[6], samount: '', detail: clInfo[7], spamount: clInfo[6], xmj_code: clInfo[9] !== '' ? clInfo[9] : null, xmj_jldy: clInfo[10] !== '' ? clInfo[10] : null, gcl_id: clInfo[11] !== '' ? clInfo[11] : '', }; if (clInfo[4] === '') { delete clArray.unit_price; } insertCL.push(clArray); total_price = this.ctx.helper.accAdd(total_price, this.ctx.helper.mul(clArray.unit_price, clArray.spamount, this.ctx.tender.info.decimal.tp)); } await this.transaction.insert(this.ctx.service.changeAuditList.tableName, insertCL); } // 修改变更令基本数据 const cArray = { code: postData.code, name: postData.name, peg: postData.peg, org_name: postData.org_name, org_code: postData.org_code, new_name: postData.new_name, new_code: postData.new_code, content: postData.content, basis: postData.basis, expr: postData.expr, memo: postData.memo, type: postData.type.join(','), class: postData.class, quality: postData.quality, company: postData.company, charge: postData.charge, w_code: postData.w_code, total_price, // tp_decimal: this.ctx.tender.info.decimal.tp, }; const options = { where: { cid: changeInfo.cid, }, }; if (change_status) { cArray.tp_decimal = this.ctx.tender.info.decimal.tp; cArray.up_decimal = this.ctx.tender.info.decimal.up; cArray.status = audit.flow.status.checking; cArray.cin_time = Date.parse(new Date()) / 1000; } await this.transaction.update(this.tableName, cArray, options); await this.transaction.commit(); result = true; } catch (error) { await this.transaction.rollback(); result = false; } return result; } /** * 保存变更信息 * @param {int} postData - 表单提交的数据 * @param {int} tenderId - 标段id * @return {void} */ async saveInfo(postData) { // 初始化事务 const transaction = await this.db.beginTransaction(); let result = false; try { const options = { where: { cid: this.ctx.change.cid, }, }; await transaction.update(this.tableName, postData, options); await transaction.commit(); result = true; } catch (error) { await transaction.rollback(); result = false; } return result; } /** * 审批通过 * @param {Number} pid 项目id * @param {int} postData - 表单提交的数据 * @param {int} changeData - 变更令的数据 * @return {void} */ async approvalSuccess(pid, postData, changeData) { // 初始化事务 this.transaction = await this.db.beginTransaction(); let result = false; try { // 获取所有审核人列表 const auditors = await this.ctx.service.changeAudit.getAllAuditors(changeData.tid); // console.log('auditors', auditors); // console.log('postData', postData); // 添加到消息推送表 const noticeContent = await this.getNoticeContent(pid, changeData.tid, changeData.cid, this.ctx.session.sessionUser.accountId); const records = []; auditors.forEach(auditor => { records.push({ pid, type: pushType.change, uid: auditor.uid, status: audit.flow.status.checked, content: noticeContent, }); }); await this.transaction.insert('zh_notice', records); // 设置审批人通过 const audit_update = { id: postData.audit_id, sdesc: postData.sdesc, status: audit.flow.auditStatus.checked, sin_time: new Date(), }; const change_update = { w_code: postData.w_code, status: audit.flow.status.checking, cin_time: Date.parse(new Date()) / 1000, }; await this.transaction.update(this.ctx.service.changeAudit.tableName, audit_update); // 清单数据更新 const bills_list = postData.bills_list.split(','); let total_price = 0; const tp_decimal = changeData.tp_decimal ? changeData.tp_decimal : this.ctx.tender.info.decimal.tp; for (const bl of bills_list) { const listInfo = bl.split('_'); const lid = listInfo[0]; const amount = listInfo[1]; const changeListInfo = await this.ctx.service.changeAuditList.getDataById(lid); if (changeListInfo !== undefined) { total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(changeListInfo.unit_price, amount, tp_decimal)); const audit_amount = changeListInfo.audit_amount !== null && changeListInfo.audit_amount !== '' ? changeListInfo.audit_amount.split(',') : []; audit_amount.push(amount); const list_update = { id: lid, audit_amount: audit_amount.join(','), spamount: parseFloat(amount), }; if (postData.audit_next_id === undefined) { list_update.samount = amount; } await this.transaction.update(this.ctx.service.changeAuditList.tableName, list_update); } } if (postData.audit_next_id === undefined) { // 变更令审批完成 change_update.status = audit.flow.status.checked; change_update.p_code = postData.p_code; change_update.sin_time = Date.parse(new Date()) / 1000; change_update.is_revise = 0; await this.ctx.service.tenderTag.saveTenderTag(changeData.tid, { bgl_time: new Date() }, this.transaction); await this.ctx.service.changeAuditList.updateToLedger(this.transaction, changeData.tid, changeData.cid); // 添加短信通知-审批通过提醒功能 // const mobile_array = []; const auditList = await this.ctx.service.changeAudit.getListGroupByTimes(changeData.cid, changeData.times); const users = this._.map(auditList, 'uid'); const sms = new SMS(this.ctx); const code = await sms.contentChange(changeData.code); await this.ctx.helper.sendAliSms(users, smsTypeConst.const.BG, smsTypeConst.judge.result.toString(), SmsAliConst.template.change_result, { biangeng: code, status: SmsAliConst.status.success, }); // 微信模板通知 const shenpiUrl = await this.ctx.helper.urlToShort( this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + changeData.tid + '/change/' + changeData.cid + '/info#shenpi' ); const wechatData = { wap_url: shenpiUrl, status: wxConst.status.success, tips: wxConst.tips.success, code: this.ctx.session.sessionProject.code, c_name: changeData.name, }; await this.ctx.helper.sendWechat(users, smsTypeConst.const.BG, smsTypeConst.judge.result.toString(), wxConst.template.change, wechatData); } else { // 设置下一个审批人为审批状态 const nextAudit_update = { id: postData.audit_next_id, status: audit.flow.auditStatus.checking, sin_time: new Date(), }; await this.transaction.update(this.ctx.service.changeAudit.tableName, nextAudit_update); // 添加短信通知-需要审批提醒功能 const nextAuditData = await this.ctx.service.changeAudit.getDataById(postData.audit_next_id); const sms = new SMS(this.ctx); const code = await sms.contentChange(changeData.code); const shenpiUrl = await this.ctx.helper.urlToShort( this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + changeData.tid + '/change/' + changeData.cid + '/info#shenpi' ); await this.ctx.helper.sendAliSms(nextAuditData.uid, smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), SmsAliConst.template.change_check, { biangeng: code, code: shenpiUrl, }); // 微信模板通知 const wechatData = { wap_url: shenpiUrl, status: wxConst.status.check, tips: wxConst.tips.check, code: this.ctx.session.sessionProject.code, c_name: changeData.name, }; await this.ctx.helper.sendWechat(nextAuditData.uid, smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), wxConst.template.change, wechatData); } change_update.total_price = total_price; const options = { where: { cid: postData.change_id, }, }; await this.transaction.update(this.tableName, change_update, options); await this.transaction.commit(); result = true; } catch (error) { console.log(error); await this.transaction.rollback(); result = false; } return result; } /** * 审批终止 * @param {int} postData - 表单提交的数据 * @return {void} */ async approvalStop(postData) { // 初始化事务 this.transaction = await this.db.beginTransaction(); let result = false; try { // 设置审批人终止 const audit_update = { id: postData.audit_id, sdesc: postData.sdesc, status: 4, sin_time: new Date(), }; await this.transaction.update(this.ctx.service.changeAudit.tableName, audit_update); // 设置变更令终止 const change_update = { w_code: postData.w_code, status: 4, cin_time: Date.parse(new Date()) / 1000, }; const options = { where: { cid: postData.change_id, }, }; await this.transaction.update(this.tableName, change_update, options); await this.transaction.commit(); result = true; } catch (error) { await this.transaction.rollback(); result = false; } return result; } /** * 审批退回到原报人 * @param {Number} pid 项目id * @param {int} postData - 表单提交的数据 * @param {int} changeData - 变更令的数据 * @return {void} */ async approvalBack(pid, postData, changeData) { // 初始化事务 this.transaction = await this.db.beginTransaction(); let result = false; try { // 获取所有审核人列表 const auditors = await this.ctx.service.changeAudit.getAllAuditors(changeData.tid); // 添加到消息推送表 const noticeContent = await this.getNoticeContent(pid, changeData.tid, changeData.cid, this.ctx.session.sessionUser.accountId); const records = []; auditors.forEach(auditor => { records.push({ pid, type: pushType.change, uid: auditor.uid, status: audit.flow.status.backnew, content: noticeContent, }); }); await this.transaction.insert('zh_notice', records); const changeInfo = await this.getDataByCondition({ cid: postData.change_id }); // 设置审批人退回 const audit_update = { id: postData.audit_id, sdesc: postData.sdesc, status: audit.flow.auditStatus.back, sin_time: new Date(), }; await this.transaction.update(this.ctx.service.changeAudit.tableName, audit_update); // 新增新一次的审批人列表 // 获取当前次数审批人列表 const auditList = await this.ctx.service.changeAudit.getListGroupByTimes(changeInfo.cid, changeInfo.times); const lastauditInfo = await this.ctx.service.changeAudit.getLastUser(changeInfo.cid, changeInfo.times, 1, 0); let usort = lastauditInfo.usort + 1; const newTimes = changeInfo.times + 1; const insert_audit_array = []; for (const al of auditList) { const insert_audit = { tid: al.tid, cid: al.cid, uid: al.uid, name: al.name, jobs: al.jobs, company: al.company, times: newTimes, usite: al.usite, usort, status: al.usite !== 0 ? audit.flow.auditStatus.uncheck : audit.flow.auditStatus.checking, }; insert_audit_array.push(insert_audit); usort++; } await this.transaction.insert(this.ctx.service.changeAudit.tableName, insert_audit_array); // 变更金额也退回 const changeList = await this.ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: changeInfo.cid }, }); let total_price = 0; const tp_decimal = changeData.tp_decimal ? changeData.tp_decimal : this.ctx.tender.info.decimal.tp; for (const cl of changeList) { total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, cl.camount, tp_decimal)); } // 设置变更令退回 const change_update = { w_code: postData.w_code, status: audit.flow.status.back, times: newTimes, cin_time: Date.parse(new Date()) / 1000, total_price, tp_decimal: null, up_decimal: null, }; const options = { where: { cid: postData.change_id, }, }; await this.transaction.update(this.tableName, change_update, options); await this.transaction.commit(); result = true; const users = this._.map(insert_audit_array, 'uid'); const sms = new SMS(this.ctx); const code = await sms.contentChange(changeData.code); await this.ctx.helper.sendAliSms(users, smsTypeConst.const.BG, smsTypeConst.judge.result.toString(), SmsAliConst.template.change_result, { biangeng: code, status: SmsAliConst.status.back, }); // 微信模板通知 const shenpiUrl = await this.ctx.helper.urlToShort( this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + changeInfo.tid + '/change/' + changeInfo.cid + '/info#shenpi' ); const wechatData = { wap_url: shenpiUrl, status: wxConst.status.back, tips: wxConst.tips.back, code: this.ctx.session.sessionProject.code, c_name: changeInfo.name, }; await this.ctx.helper.sendWechat(users, smsTypeConst.const.BG, smsTypeConst.judge.result.toString(), wxConst.template.change, wechatData); } catch (error) { await this.transaction.rollback(); result = false; } return result; } /** * 审批退回到上一个审批人 * @param {Number} pid 项目id * @param {int} postData - 表单提交的数据 * @param {int} changeData - 变更令的数据 * @return {void} */ async approvalBackNew(pid, postData, changeData) { // 初始化事务 this.transaction = await this.db.beginTransaction(); let result = false; try { // 获取所有审核人列表 const auditors = await this.ctx.service.changeAudit.getAllAuditors(changeData.tid); // 添加到消息推送表 const noticeContent = await this.getNoticeContent(pid, changeData.tid, changeData.cid, this.ctx.session.sessionUser.accountId); const records = []; auditors.forEach(auditor => { records.push({ pid, type: pushType.change, uid: auditor.uid, status: audit.flow.status.back, content: noticeContent, }); }); await this.transaction.insert('zh_notice', records); const changeInfo = await this.getDataByCondition({ cid: postData.change_id }); // 设置审批人退回 const audit_update = { id: postData.audit_id, sdesc: postData.sdesc, status: audit.flow.auditStatus.backnew, sin_time: new Date(), }; await this.transaction.update(this.ctx.service.changeAudit.tableName, audit_update); // 获取当前审批人信息 const auditInfo = await this.ctx.service.changeAudit.getDataById(postData.audit_id); // 获取当前次数审批人列表 const auditList = await this.ctx.service.changeAudit.getNextAuditList(changeInfo.cid, auditInfo.usort); let usort = auditInfo.usort + 1; // 获取上一个审批人信息 const lastauditInfo = await this.ctx.service.changeAudit.getDataById(postData.audit_last_id); // 新增2个审批人到审批列表中 const insert_audit1 = { tid: lastauditInfo.tid, cid: lastauditInfo.cid, uid: lastauditInfo.uid, name: lastauditInfo.name, jobs: lastauditInfo.jobs, company: lastauditInfo.company, times: lastauditInfo.times, usite: lastauditInfo.usite, usort, status: audit.flow.auditStatus.checking, sin_time: new Date(), }; await this.transaction.insert(this.ctx.service.changeAudit.tableName, insert_audit1); usort++; // 新增2个审批人到审批列表中 const insert_audit2 = { tid: auditInfo.tid, cid: auditInfo.cid, uid: auditInfo.uid, name: auditInfo.name, jobs: auditInfo.jobs, company: auditInfo.company, times: auditInfo.times, usite: auditInfo.usite, usort, status: audit.flow.auditStatus.uncheck, }; await this.transaction.insert(this.ctx.service.changeAudit.tableName, insert_audit2); // 把接下未审批的审批人排序都加2 for (const al of auditList) { const audit_update = { id: al.id, usort: al.usort + 2, }; await this.transaction.update(this.ctx.service.changeAudit.tableName, audit_update); } // 审批列表数据也要回退 const changeList = await this.ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: changeInfo.cid }, }); let total_price = 0; const tp_decimal = changeData.tp_decimal ? changeData.tp_decimal : this.ctx.tender.info.decimal.tp; for (const cl of changeList) { const audit_amount = cl.audit_amount.split(','); const last_amount = audit_amount[audit_amount.length - 1]; audit_amount.splice(-1, 1); const list_update = { id: cl.id, audit_amount: audit_amount.join(','), spamount: parseFloat(last_amount), }; total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, parseFloat(last_amount), tp_decimal)); await this.transaction.update(this.ctx.service.changeAuditList.tableName, list_update); } // 设置变更令退回 const change_update = { w_code: postData.w_code, status: audit.flow.status.backnew, cin_time: Date.parse(new Date()) / 1000, total_price, }; const options = { where: { cid: postData.change_id, }, }; await this.transaction.update(this.tableName, change_update, options); await this.transaction.commit(); result = true; const sms = new SMS(this.ctx); const code = await sms.contentChange(changeData.code); const shenpiUrl = await this.ctx.helper.urlToShort( this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + changeData.tid + '/change/' + changeData.cid + '/info#shenpi' ); await this.ctx.helper.sendAliSms(lastauditInfo.uid, smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), SmsAliConst.template.change_check, { biangeng: code, code: shenpiUrl, }); // 微信模板通知 const wechatData = { wap_url: shenpiUrl, status: wxConst.status.check, tips: wxConst.tips.check, code: this.ctx.session.sessionProject.code, c_name: changeInfo.name, }; await this.ctx.helper.sendWechat(lastauditInfo.uid, smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), wxConst.template.change, wechatData); } catch (error) { await this.transaction.rollback(); result = false; } return result; } /** * 查询可用的变更令 * @param bills - 查询的清单 * @param pos - 查询的部位 * @return {Promise<*>} - 可用的变更令列表 */ async getValidChanges(tid, bills, pos) { const self = this; const getFilterPart = function(field, value) { return value ? field + ' = ' + self.db.escape(value) : self.db.format("(?? = null or ?? = '')", [field, field]); }; const timesLen = 100; const filter = getFilterPart('cb.code', bills.b_code) + ' And ' + getFilterPart('cb.name', bills.name) + ' And ' + getFilterPart('cb.unit', bills.unit) + ' And cb.`unit_price` = ' + this.db.escape(bills.unit_price) + (pos ? getFilterPart('cb.bwmx', pos.name) : ''); const sql = 'SELECT c.cid, c.code, c.name, c.w_code, c.p_code, c.peg, c.org_name, c.org_code, c.new_name, c.new_code,' + ' c.content, c.basis, c.memo, c.type, c.class, c.quality, c.company, c.charge, ' + ' cb.id As cbid, cb.code As b_code, cb.name As b_name, cb.unit As b_unit, cb.samount As b_amount, cb.detail As b_detail, cb.bwmx As b_bwmx, cb.gcl_id, ' + ' scb.used_amount' + ' FROM ' + this.tableName + ' As c ' + ' Left Join ' + this.ctx.service.changeAuditList.tableName + ' As cb On c.cid = cb.cid ' + ' Left Join (' + ' SELECT SUM(sc.qty) As used_amount, sc.cbid' + ' FROM ' + this.ctx.service.stageChange.tableName + ' As sc' + ' INNER JOIN (SELECT MAX(`stimes` * ' + timesLen + ' + `sorder`) As `flow`, cbid, sid ' + ' FROM ' + this.ctx.service.stageChange.tableName + ' WHERE tid = ?' + ' GROUP BY cbid, sid' + ' ) As MF' + ' ON (sc.stimes * ' + timesLen + ' + sc.sorder) = MF.flow And sc.cbid = MF.cbid And sc.sid = MF.sid' + ' GROUP BY sc.cbid' + ' ) As scb ON cb.id = scb.cbid' + ' WHERE c.tid = ? And c.status = ? And c.valid And ' + filter + ' ORDER BY c.in_time'; const sqlParam = [tid, tid, audit.flow.status.checked]; const changes = await this.db.query(sql, sqlParam); for (const c of changes) { const aSql = 'SELECT ca.*, pa.name As u_name, pa.role As u_role ' + ' FROM ?? As ca ' + ' Left Join ?? As pa ' + ' On ca.uid = pa.id ' + ' Where ca.cid = ?'; const aSqlParam = [this.ctx.service.changeAtt.tableName, this.ctx.service.projectAccount.tableName, c.cid]; c.attachments = await this.db.query(aSql, aSqlParam); } return changes; } /** * 查询审批人可用的变更令 * @param bills - 查询的清单 * @param pos - 查询的部位 * @return {Promise<*>} - 可用的变更令列表 */ async getAuditValidChanges(tid, bills, pos, times, order) { const timesLen = 100; const filter = 'cb.`code` = ' + this.db.escape(bills.b_code) + ' And cb.`name` = ' + this.db.escape(bills.name) + ' And cb.`unit` = ' + this.db.escape(bills.unit) + ' And cb.`unit_price` = ' + this.db.escape(bills.unit_price) + (pos ? ' And cb.`bwmx` = ' + this.db.escape(pos.name) : ''); const sql = 'SELECT c.cid, c.code, c.name, c.w_code, c.p_code, c.peg, c.org_name, c.org_code, c.new_name, c.new_code,' + ' c.content, c.basis, c.memo, c.type, c.class, c.quality, c.company, c.charge, ' + ' cb.id As cbid, cb.code As b_code, cb.name As b_name, cb.unit As b_unit, cb.samount As b_amount, cb.detail As b_detail, cb.bwmx As b_bwmx, cb.gcl_id, ' + ' scb.used_amount' + ' FROM ' + this.tableName + ' As c ' + ' Left Join ' + this.ctx.service.changeAuditList.tableName + ' As cb On c.cid = cb.cid ' + ' Left Join (' + ' SELECT SUM(sc.qty) As used_amount, sc.cbid' + ' FROM ' + this.ctx.service.stageChange.tableName + ' As sc' + ' INNER JOIN (SELECT MAX(`stimes` * ' + timesLen + ' + `sorder`) As `flow`, cbid, sid ' + ' FROM ' + this.ctx.service.stageChange.tableName + ' WHERE tid = ? And (`stimes` < ? OR (`stimes` = ? AND `sorder` <= ?)) ' + ' GROUP BY cbid, sid' + ' ) As MF' + ' ON (sc.stimes * ' + timesLen + ' + sc.sorder) = MF.flow And sc.cbid = MF.cbid And sc.sid = MF.sid' + ' GROUP BY sc.cbid' + ' ) As scb ON cb.id = scb.cbid' + ' WHERE c.tid = ? And c.status = ? And c.valid And ' + filter + ' ORDER BY c.in_time'; const sqlParam = [tid, times, times, order, tid, audit.flow.status.checked]; const changes = await this.db.query(sql, sqlParam); for (const c of changes) { const aSql = 'SELECT ca.*, pa.name As u_name, pa.role As u_role ' + ' FROM ?? As ca ' + ' Left Join ?? As pa ' + ' On ca.uid = pa.id ' + ' Where ca.cid = ?'; const aSqlParam = [this.ctx.service.changeAtt.tableName, this.ctx.service.projectAccount.tableName, c.cid]; c.attachments = await this.db.query(aSql, aSqlParam); } return changes; } /** * 查询变更令 + 变更令执行 * @param tid * @return {Promise} */ async getChangeAndUsedInfo(tid) { const lastStage = await this.ctx.service.stage.getLastestStage(tid, true); let filter; if (lastStage.id === this.ctx.stage.id) { filter = this.db.format(' And (s.`order` < ? OR (s.`order` = ? And (sChange.`stimes` < ? OR (sChange.`stimes` = ? And sChange.`sorder` <= ?))))', [ lastStage.order, lastStage.order, this.ctx.stage.curTimes, this.ctx.stage.curTimes, this.ctx.stage.curOrder, ]); } else { if (lastStage.status === audit.stage.status.uncheck) { filter = ' And s.order < ' + lastStage.order; } else if (lastStage.status === audit.stage.status.checked) { filter = ''; } else if (lastStage.status === audit.stage.status.checkNo) { filter = this.db.format(' And (s.`order` < ? OR (s.`order` = ? And sChange.`stimes` <= ?))', [lastStage.order, lastStage.order, lastStage.times]); } else { const curAuditor = await this.ctx.service.stageAudit.getCurAuditor(lastStage.id, lastStage.times); filter = this.db.format(' And (s.`order` < ? OR (s.`order` = ? And (sChange.`stimes` < ? OR (sChange.`stimes` = ? And sChange.`sorder` <= ?))))', [ lastStage.order, lastStage.order, lastStage.times, lastStage.times, curAuditor.order - 1, ]); } } const sql = 'SELECT C.*, Sum(U.utp) As used_tp, TRUNCATE(Sum(U.utp) / C.total_price * 100 + 0.005, 2) As used_pt' + ' FROM ' + this.tableName + ' As C' + ' LEFT JOIN (SELECT sc.tid, sc.cid, sc.cbid, IF(SUM(sc.qty) > 0, TRUNCATE(SUM(sc.qty) * cb.unit_price + ?, ?), TRUNCATE(SUM(sc.qty) * cb.unit_price - ?, ?)) As utp,' + ' IF(SUM(sc.qty) > 0, TRUNCATE(SUM(sc.qty) * cb.unit_price + ?, ?), 0, ?)) As utp_po, IF(SUM(sc.qty) > 0, 0, TRUNCATE(SUM(sc.qty) * cb.unit_price - ?, ?)) As utp_ne' + ' FROM ' + this.ctx.service.stageChange.tableName + ' As sc' + ' INNER JOIN (' + ' SELECT MAX(`stimes`) As `stimes`, MAX(`sorder`) As `sorder`, `lid`, `pid`, `cbid`, sChange.`sid` ' + ' FROM ' + this.ctx.service.stageChange.tableName + ' As sChange ' + ' LEFT JOIN ' + this.ctx.service.stage.tableName + ' As s' + ' ON sChange.sid = s.id' + ' WHERE sChange.tid = ?' + filter + ' GROUP By `lid`, `pid`, `cbid`, `sid`' + ' ) As m' + ' ON sc.stimes = m.stimes And sc.sorder = m.sorder And sc.`cbid` = m.`cbid` AND sc.`sid` = m.`sid` And sc.`lid` = m.`lid` And sc.`pid` = m.`pid`' + ' LEFT JOIN ' + this.ctx.service.changeAuditList.tableName + ' As cb ON sc.cbid = cb.id' + ' GROUP By sc.`cbid`' + ' ) As U ON C.cid = U.cid' + ' WHERE C.tid = ? And C.status = ? And C.valid' + ' GROUP By C.cid' + ' ORDER By in_time'; // 舍入步长 const step = parseFloat('0.' + '0000000'.substr(0, this.ctx.tender.info.decimal.tp) + '5'); const sqlParam = [step, this.ctx.tender.info.decimal.tp, step, this.ctx.tender.info.decimal.tp, tid, tid, audit.flow.status.checked]; const data = await this.db.query(sql, sqlParam); return data; } /** * 查询可用的变更令 * @param { string } cid - 查询的清单 * @return {Promise<*>} - 可用的变更令列表 */ async delete(cid) { // 初始化事务 this.transaction = await this.db.beginTransaction(); let result = false; try { const changeInfo = await this.getDataByCondition({ cid }); // 先删除清单,审批人列表 await this.transaction.delete(this.ctx.service.changeAuditList.tableName, { cid }); await this.transaction.delete(this.ctx.service.changeAudit.tableName, { cid }); // 再删除附件和附件文件ni zuo const attList = await this.ctx.service.changeAtt.getAllDataByCondition({ where: { cid } }); await this.ctx.helper.delFiles(attList); await this.transaction.delete(this.ctx.service.changeAtt.tableName, { cid }); // if (attList.length !== 0) { // for (const att of attList) { // await fs.unlinkSync(path.join(this.app.baseDir, att.filepath)); // } // await this.transaction.delete(this.ctx.service.changeAtt.tableName, { cid }); // } // 最后删除变更令 await this.transaction.delete(this.tableName, { cid }); // 记录删除日志 await this.ctx.service.projectLog.addProjectLog(this.transaction, projectLogConst.type.change, projectLogConst.status.delete, changeInfo.code); await this.transaction.commit(); result = true; } catch (e) { await this.transaction.rollback(); result = false; } return result; } /** * 重新审批变更令 * @param { string } cid - 查询的清单 * @return {Promise<*>} - 可用的变更令列表 */ async checkRevise(cid) { // 初始化事务 this.transaction = await this.db.beginTransaction(); let result = false; try { const changeData = await this.getDataByCondition({ cid }); const pid = this.ctx.session.sessionProject.id; // 获取所有审核人列表 const auditors = await this.ctx.service.changeAudit.getAllAuditors(changeData.tid); // 添加到消息推送表 const noticeContent = await this.getNoticeContent(pid, changeData.tid, changeData.cid, this.ctx.session.sessionUser.accountId); const records = []; auditors.forEach(auditor => { records.push({ pid, type: pushType.change, uid: auditor.uid, status: audit.flow.status.revise, content: noticeContent, }); }); await this.transaction.insert('zh_notice', records); // 获取当前次数审批人列表 const auditList = await this.ctx.service.changeAudit.getListGroupByTimes(changeData.cid, changeData.times); const lastauditInfo = await this.ctx.service.changeAudit.getLastUser(changeData.cid, changeData.times, 1, 0); let usort = lastauditInfo.usort + 1; const newTimes = changeData.times + 1; const insert_audit_array = []; // 新增一个发起修订状态到审批流程中 const revise_audit = { tid: auditList[0].tid, cid: auditList[0].cid, uid: auditList[0].uid, name: auditList[0].name, jobs: auditList[0].jobs, company: auditList[0].company, times: changeData.times, usite: lastauditInfo.usite + 1, usort, status: audit.flow.auditStatus.revise, sin_time: new Date(), }; insert_audit_array.push(revise_audit); usort++; // 新增新一次的审批人列表 for (const al of auditList) { const insert_audit = { tid: al.tid, cid: al.cid, uid: al.uid, name: al.name, jobs: al.jobs, company: al.company, times: newTimes, usite: al.usite, usort, status: al.usite !== 0 ? audit.flow.auditStatus.uncheck : audit.flow.auditStatus.checking, }; insert_audit_array.push(insert_audit); usort++; } await this.transaction.insert(this.ctx.service.changeAudit.tableName, insert_audit_array); const changeList = await this.ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: changeData.cid }, }); // 申请变更金额更新为上一次审批审批变更后数量,清空audit_amount值 const updateTpList = []; for (const cl of changeList) { updateTpList.push({ id: cl.id, camount: cl.spamount, audit_amount: null, samount: '' }); } if (updateTpList.length > 0) { await this.transaction.updateRows(this.ctx.service.changeAuditList.tableName, updateTpList); } // let total_price = 0; // const tp_decimal = changeData.tp_decimal ? changeData.tp_decimal : this.ctx.tender.info.decimal.tp; // for (const cl of changeList) { // total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, cl.camount, tp_decimal)); // } // 设置变更令修订状态 const change_update = { w_code: changeData.w_code, status: audit.flow.status.revise, times: newTimes, cin_time: Date.parse(new Date()) / 1000, // total_price, tp_decimal: null, up_decimal: null, is_revise: 1, }; const options = { where: { cid: changeData.cid, }, }; await this.transaction.update(this.tableName, change_update, options); await this.transaction.commit(); result = true; } catch (error) { await this.transaction.rollback(); result = false; } return result; } /** * 重新审批变更令 * @param { string } cid - 查询的清单 * @return {Promise<*>} - 可用的变更令列表 */ async checkAgain(cid) { // 初始化事务 this.transaction = await this.db.beginTransaction(); let result = false; try { const changeInfo = await this.getDataByCondition({ cid }); // 获取终审 const auditInfo = ( await this.ctx.service.changeAudit.getAllDataByCondition({ where: { cid }, orders: [['usort', 'desc']], limit: 1, offset: 0, }) )[0]; let usort = auditInfo.usort + 1; // 新增2个审批状态到审批列表中 const insert_audit1 = { tid: auditInfo.tid, cid: auditInfo.cid, uid: auditInfo.uid, name: auditInfo.name, jobs: auditInfo.jobs, company: auditInfo.company, times: auditInfo.times, usite: auditInfo.usite, usort, sin_time: new Date(), status: audit.flow.auditStatus.checkAgain, }; await this.transaction.insert(this.ctx.service.changeAudit.tableName, insert_audit1); usort++; // 新增2个审批人到审批列表中 const insert_audit2 = { tid: auditInfo.tid, cid: auditInfo.cid, uid: auditInfo.uid, name: auditInfo.name, jobs: auditInfo.jobs, company: auditInfo.company, times: auditInfo.times, usite: auditInfo.usite, usort, status: audit.flow.auditStatus.checking, sin_time: new Date(), }; await this.transaction.insert(this.ctx.service.changeAudit.tableName, insert_audit2); // 审批列表数据也要回退 let total_price = 0; const tp_decimal = changeInfo.tp_decimal ? changeInfo.tp_decimal : this.ctx.tender.info.decimal.tp; const changeList = await this.ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: changeInfo.cid }, }); for (const cl of changeList) { const audit_amount = cl.audit_amount.split(','); const last_amount = audit_amount[audit_amount.length - 1]; audit_amount.splice(-1, 1); const list_update = { id: cl.id, audit_amount: audit_amount.join(','), samount: '', }; total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, parseFloat(last_amount), tp_decimal)); await this.transaction.update(this.ctx.service.changeAuditList.tableName, list_update); } // 设置变更令审批中 const change_update = { p_code: null, status: audit.flow.status.checking, cin_time: Date.parse(new Date()) / 1000, sin_time: null, total_price, }; const options = { where: { cid: changeInfo.cid, }, }; await this.transaction.update(this.tableName, change_update, options); await this.transaction.commit(); result = true; const sms = new SMS(this.ctx); const code = await sms.contentChange(changeInfo.code); const shenpiUrl = await this.ctx.helper.urlToShort( this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + changeInfo.tid + '/change/' + changeInfo.cid + '/info#shenpi' ); await this.ctx.helper.sendAliSms(auditInfo.uid, smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), SmsAliConst.template.change_check, { biangeng: code, code: shenpiUrl, }); // 微信模板通知 const wechatData = { wap_url: shenpiUrl, status: wxConst.status.check, tips: wxConst.tips.check, code: this.ctx.session.sessionProject.code, c_name: changeInfo.name, }; await this.ctx.helper.sendWechat(auditInfo.uid, smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), wxConst.template.change, wechatData); } catch (error) { await this.transaction.rollback(); result = false; } return result; } /** * 判断是否有重名的变更令 * @param cid * @param code * @param tid * @return {Promise} */ async isRepeat(cid, code, tid) { const sql = 'SELECT COUNT(*) as count FROM ?? WHERE ((`code` = ? AND `status` != ?) OR (`p_code` = ? AND `status` = ?)) AND `cid` != ? AND `tid` = ?'; const sqlParam = [this.tableName, code, audit.flow.status.checked, code, audit.flow.status.checked, cid, tid]; const result = await this.db.queryOne(sql, sqlParam); return result.count !== 0; } async getAllCheckedChanges(tid) { return await this.getAllDataByCondition({ where: { tid, status: audit.flow.status.checked }, orders: [['in_time', 'desc']], }); } /** * 用于添加推送所需的content内容 * @param {Number} pid 项目id * @param {Number} tid 台账id * @param {Number} cid 变更id * @param {Number} uid 审核人id */ async getNoticeContent(pid, tid, cid, uid) { const noticeSql = 'SELECT * FROM (SELECT ' + ' t.`id` As `tid`, t.`name`, c.`cid`, c.`code` As `c_code`, pa.`name` As `su_name`, pa.role As `su_role`' + ' FROM (SELECT * FROM ?? WHERE `id` = ? ) As t' + ' LEFT JOIN ?? As c ON c.`cid` = ?' + ' LEFT JOIN ?? As pa ON pa.`id` = ?' + ' WHERE t.`project_id` = ? ) as new_t GROUP BY new_t.`tid`'; const noticeSqlParam = [this.ctx.service.tender.tableName, tid, this.ctx.service.change.tableName, cid, this.ctx.service.projectAccount.tableName, uid, pid]; const content = await this.db.query(noticeSql, noticeSqlParam); return content.length ? JSON.stringify(content[0]) : ''; } /** * 获取当前标段其他变更令 * @param {Number} tid - 标段id * @param {Number} cid - 当前变更令 */ async getOthersChange(tid, cid) { const sql = 'SELECT * FROM ?? WHERE tid = ? AND cid != ? ORDER By `in_time` desc '; const sqlParam = [this.tableName, tid, cid]; const data = await this.db.query(sql, sqlParam); const changeClassObj = {}; for (const c in changeConst.class) { if (changeConst.class.hasOwnProperty(c)) { const item = changeConst.class[c]; changeClassObj[item.value] = item.name; } } for (let i = 0; i < data.length; i++) { data[i].class = changeClassObj[data[i].class]; } return data; } /** * 拷贝变更令至当前变更令 * @param {String} cid - 当前变更令 * @param {String} copy_cid - 要拷贝的变更令 */ async handleCopyChange(cid, copy_cid) { // const change = await this.getDataByCondition({ cid }); const copyChange = await this.getDataByCondition({ cid: copy_cid }); return await this.update({ peg: copyChange.peg, org_name: copyChange.org_name, org_code: copyChange.org_code, new_name: copyChange.new_name, content: copyChange.content, basis: copyChange.basis, expr: copyChange.expr, memo: copyChange.memo, type: copyChange.type, class: copyChange.class, quality: copyChange.quality, company: copyChange.company, charge: copyChange.charge, new_code: copyChange.new_code }, { cid, }); } async updateDecimalAndTp() { // 判断是否可修改 // 判断t_type是否为费用 const transaction = await this.db.beginTransaction(); try { await this.ctx.service.changeAuditList.calcCamountSum(transaction, true); await transaction.commit(); return true; } catch (err) { await transaction.rollback(); throw err; } } async updateChangeSelect(data) { const conn = await this.db.beginTransaction(); try { for (const d of data) { await conn.update(this.tableName, { selected: d.selected }, { where: { cid: d.cid } }); } await conn.commit(); } catch (err) { await conn.rollback(); throw err; } } } return Change; };