123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 |
- 'use strict';
- /**
- *
- *
- * @author Mai
- * @date 2019/2/27
- * @version
- */
- const auditConst = require('../const/audit').financial;
- const auditType = require('../const/audit').auditType;
- const shenpiConst = require('../const/shenpi');
- const pushType = require('../const/audit').pushType;
- module.exports = app => {
- class FinancialPayAudit extends app.BaseService {
- /**
- * 构造函数
- *
- * @param {Object} ctx - egg全局变量
- * @return {void}
- */
- constructor(ctx) {
- super(ctx);
- this.tableName = 'financial_pay_audit';
- }
- async getAuditorGroup(fpId, times) {
- const auditors = await this.getAuditors(fpId, times); // 全部参与的审批人
- return this.ctx.helper.groupAuditors(auditors, 'order', true);
- }
- async getUserGroup(fpId, times) {
- const group = await this.getAuditorGroup(fpId, times);
- const sql =
- 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As fpid, 0 As `order`, 1 As audit_type, 0 As audit_order' +
- ' FROM ' + this.ctx.service.financialPay.tableName + ' As s' +
- ' LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
- ' ON s.uid = pa.id' +
- ' WHERE s.id = ?';
- const sqlParam = [times, fpId, fpId];
- const user = await this.db.queryOne(sql, sqlParam);
- user.audit_order = 0;
- group.unshift([ user ]);
- return group;
- }
- async getUniqUserGroup(fpId, times) {
- const group = await this.getAuditorGroup(fpId, times);
- const sql =
- 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As fpid, 0 As `order`, 1 As audit_type, 0 As audit_order' +
- ' FROM ' + this.ctx.service.financialPay.tableName + ' As s' +
- ' LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
- ' ON s.uid = pa.id' +
- ' WHERE s.id = ?';
- const sqlParam = [times, fpId, fpId];
- const user = await this.db.queryOne(sql, sqlParam);
- user.audit_order = 0;
- group.unshift([ user ]);
- return this.ctx.helper.groupAuditorsUniq(group);
- }
- async getAuditorHistory(fpId, times, reverse = false) {
- const history = [];
- if (times >= 1) {
- for (let i = 1; i <= times; i++) {
- const auditors = await this.getAuditors(fpId, i);
- const group = this.ctx.helper.groupAuditors(auditors);
- const historyGroup = [];
- // 找出group里audit_order最大值
- const max_info = group.length > 0 ? this._.maxBy(group, function(item) {
- return item && item[0] && item[0].audit_order;
- }) : null;
- const max_order = max_info ? max_info[0].audit_order : -1;
- for (const g of group) {
- const his = {
- beginYear: '', beginDate: '', beginTime: '', endYear: '', endDate: '', endTime: '', begin_time: null, end_time: null,
- audit_type: g[0].audit_type, audit_order: g[0].audit_order,
- auditors: g,
- };
- if (his.audit_type === auditType.key.common) {
- his.name = g[0].name;
- } else {
- his.name = this.ctx.helper.transFormToChinese(his.audit_order) + '审';
- }
- his.is_final = his.audit_order === max_order;
- if (g[0].begin_time) {
- his.begin_time = g[0].begin_time;
- const beginTime = this.ctx.moment(g[0].begin_time);
- his.beginYear = beginTime.format('YYYY');
- his.beginDate = beginTime.format('MM-DD');
- his.beginTime = beginTime.format('HH:mm:ss');
- }
- let end_time;
- g.forEach(x => {
- if (x.status === auditConst.status.checkSkip) return;
- if (!his.status || x.status === auditConst.status.checking) his.status = x.status;
- if (x.end_time && (!end_time || x.end_time > end_time)) {
- end_time = x.end_time;
- if (his.status !== auditConst.status.checking) his.status = x.status;
- }
- });
- if (end_time) {
- his.end_time = end_time;
- const endTime = this.ctx.moment(end_time);
- his.endYear = endTime.format('YYYY');
- his.endDate = endTime.format('MM-DD');
- his.endTime = endTime.format('HH:mm:ss');
- }
- historyGroup.push(his);
- }
- if (reverse) {
- history.push(historyGroup.reverse());
- } else {
- history.push(historyGroup);
- }
- }
- }
- return history;
- }
- async getUniqAuditor(fpId, times) {
- const auditors = await this.getAuditors(fpId, times); // 全部参与的审批人
- const result = [];
- auditors.forEach(x => {
- if (result.findIndex(r => { return x.aid === r.aid && x.audit_order === r.audit_order; }) < 0) {
- result.push(x);
- }
- });
- return result;
- }
- /**
- * 获取 审核列表信息
- *
- * @param {Number} cpId - 变更立项id
- * @param {Number} times - 第几次审批
- * @return {Promise<*>}
- */
- async getAuditors(fpId, times = 1, order_sort = 'asc', noYB = false) {
- // const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, g.`sort` ' +
- // 'FROM ?? AS la, ?? AS pa, (SELECT t1.`aid`,(@i:=@i+1) as `sort` FROM (SELECT t.`aid`, t.`order` FROM (select `aid`, `order` from ?? WHERE `cpid` = ? AND `times` = ? ORDER BY `order` LIMIT 200) t GROUP BY t.`aid` ORDER BY t.`order`) t1, (select @i:=0) as it) as g ' +
- // 'WHERE la.`cpid` = ? and la.`times` = ? and la.`aid` = pa.`id` and g.`aid` = la.`aid` order by la.`order`';
- // const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.tableName, cpId, times, cpId, times];
- // const result = await this.db.query(sql, sqlParam);
- // const sql2 = 'SELECT COUNT(a.`aid`) as num FROM (SELECT `aid` FROM ?? WHERE `cpid` = ? AND `times` = ? GROUP BY `aid`) as a';
- // const sqlParam2 = [this.tableName, cpId, times];
- // const count = await this.db.queryOne(sql2, sqlParam2);
- // for (const i in result) {
- // result[i].max_sort = count.num;
- // }
- const ybSql = noYB ? ' AND la.audit_order != 0' : '';
- const sql = 'SELECT la.id, la.aid, la.times, la.order, la.status, la.opinion, la.begin_time, la.end_time, la.audit_type, la.audit_order,' +
- ' pa.name, pa.company, pa.role, pa.mobile, pa.telephone' +
- ` FROM ${this.tableName} la LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON la.aid = pa.id` +
- ' WHERE la.fpid = ? AND la.times = ?' + ybSql +
- ' ORDER BY la.order ' + order_sort;
- const sqlParam = [fpId, times];
- const result = await this.db.query(sql, sqlParam);
- const max_sort = this._.max(result.map(x => { return x.audit_order; }));
- for (const i in result) {
- result[i].max_sort = max_sort;
- }
- return result;
- }
- async getCurAuditors(fpId, times = 1) {
- const sql =
- 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, la.audit_type, la.audit_order ' +
- ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
- ' WHERE la.`fpid` = ? and la.`status` = ? and la.`times` = ?';
- const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, fpId, auditConst.status.checking, times];
- return await this.db.query(sql, sqlParam);
- }
- /**
- * 获取审核人流程列表
- *
- * @param auditorId
- * @return {Promise<*>}
- */
- async getAuditGroupByList(fpId, times, transaction = false) {
- const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`fpid`, la.`aid`, la.`order`, la.`status`, la.audit_type, la.audit_order ' +
- ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
- ' WHERE la.`fpid` = ? and la.`times` = ? GROUP BY la.`aid` ORDER BY la.`order`';
- const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, fpId, times];
- return transaction !== false ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);
- }
- async getAuditorsByStatus(fpId, status, times = 1) {
- let auditor = [];
- let sql = '';
- let sqlParam = '';
- let cur;
- switch (status) {
- case auditConst.status.checking :
- case auditConst.status.checked :
- case auditConst.status.cancelRevise :
- cur = await this.db.queryOne('SELECT * From ?? where fpid = ? AND times = ? AND status = ? ORDER By times DESC, `order` DESC', [this.tableName, fpId, times, status]);
- if (!cur) return [];
- sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`fpid`, la.`order`, la.`status`, la.`audit_order`, la.`audit_type` ' +
- ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
- ' WHERE la.`fpid` = ? and la.`order` = ? and times = ?';
- sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, fpId, cur.order, times];
- auditor = await this.db.query(sql, sqlParam);
- break;
- case auditConst.status.checkNo :
- cur = await this.db.queryOne('SELECT * From ?? where fpid = ? AND times = ? AND status = ? ORDER By times DESC, `order` DESC', [this.tableName, fpId, parseInt(times) - 1, status]);
- if (!cur) return [];
- sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`fpid`, la.`order`, la.`status`, la.`audit_order`, la.`audit_type` ' +
- ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
- ' WHERE la.`fpid` = ? and la.`order` = ? and la.`times` = ?';
- sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, fpId, cur.order, parseInt(times) - 1];
- auditor = await this.db.query(sql, sqlParam);
- break;
- case auditConst.status.uncheck:
- default:
- break;
- }
- return auditor;
- }
- /**
- * 获取审核人流程列表(包括原报)
- * @param {Number} materialId 调差id
- * @param {Number} times 审核次数
- * @return {Promise<Array>} 查询结果集(包括原报)
- */
- async getAuditorsWithOwner(fpId, times = 1) {
- const result = await this.getAuditGroupByList(fpId, times);
- const sql =
- 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As fpid, 0 As `order`' +
- ' FROM ' +
- this.ctx.service.financialPay.tableName +
- ' As s' +
- ' LEFT JOIN ' +
- this.ctx.service.projectAccount.tableName +
- ' As pa' +
- ' ON s.uid = pa.id' +
- ' WHERE s.id = ?';
- const sqlParam = [times, fpId, fpId];
- const user = await this.db.queryOne(sql, sqlParam);
- result.unshift(user);
- return result;
- }
- async updateNewAuditList(financialPay, newList) {
- const transaction = await this.db.beginTransaction();
- try {
- await this.updateNewAuditors(financialPay, newList, transaction);
- await transaction.commit();
- } catch (err) {
- await transaction.rollback();
- throw err;
- }
- }
- async updateNewAuditors(financialPay, newList, transaction) {
- // 先删除旧的审批流,再添加新的
- await transaction.delete(this.tableName, { fpid: financialPay.id, times: financialPay.times });
- const newAuditors = [];
- for (const auditor of newList) {
- newAuditors.push({
- spid: financialPay.spid, tid: financialPay.tid, fpid: financialPay.id, aid: auditor.audit_id,
- times: financialPay.times, order: auditor.audit_order, status: auditConst.status.uncheck,
- audit_type: auditor.audit_type, audit_order: auditor.audit_order,
- });
- }
- if (newAuditors.length > 0) await transaction.insert(this.tableName, newAuditors);
- }
- /**
- * 开始审批
- * @param {Number} cpId - 方案id
- * @param {Number} times - 第几次审批
- * @return {Promise<boolean>}
- */
- async start(fpId, times = 1) {
- const audits = await this.getAllDataByCondition({ where: { fpid: fpId, times, order: 1 } });
- if (audits.length === 0) {
- throw '请联系管理员添加审批人';
- }
- const transaction = await this.db.beginTransaction();
- try {
- const begin_time = new Date();
- const updateData = audits.map(x => {
- return {id: x.id, status: auditConst.status.checking, begin_time};
- });
- await transaction.updateRows(this.tableName, updateData);
- await transaction.update(this.ctx.service.financialPay.tableName, {
- id: fpId, status: auditConst.status.checking,
- // entities: await this.ctx.service.financialPayContract.getEntities(fpId),
- });
- // todo 更新标段tender状态 ?
- await transaction.commit();
- } catch (err) {
- await transaction.rollback();
- throw err;
- }
- return true;
- }
- /**
- * 审批
- * @param {Object} fp - 资金支付信息
- * @param {auditConst.status.checked|auditConst.status.checkNo} checkType - 审批结果
- * @return {Promise<void>}
- */
- async check(fp, checkData) {
- if (checkData.checkType !== auditConst.status.checked && checkData.checkType !== auditConst.status.checkNo) {
- throw '提交数据错误';
- }
- const pid = this.ctx.session.sessionProject.id;
- switch (checkData.checkType) {
- case auditConst.status.checked:
- await this._checked(pid, fp, checkData);
- break;
- case auditConst.status.checkNo:
- await this._checkNo(pid, fp, checkData);
- break;
- default:
- throw '无效审批操作';
- }
- }
- async _checked(pid, fp, checkData) {
- const accountId = this.ctx.session.sessionUser.accountId;
- const time = new Date();
- // 整理当前流程审核人状态更新
- const audits = fp.curAuditors;
- if (audits.length === 0) throw '审核数据错误';
- const selfAudit = audits.find(x => { return x.aid === accountId; });
- if (!selfAudit) throw '当前标段您无权审批';
- // const flowAudits = await this.getAllDataByCondition({ where: { cpid: cpId, times, order: selfAudit.order } });
- const nextAudits = fp.nextAuditors;
- const transaction = await this.db.beginTransaction();
- try {
- // 更新本人审批状态
- await transaction.update(this.tableName, {
- id: selfAudit.id,
- status: checkData.checkType,
- opinion: checkData.opinion,
- end_time: time,
- });
- // await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, selfAudit.id);
- // 获取推送必要信息
- const noticeContent = await this.getNoticeContent(pid, fp.spid, fp.id, selfAudit.aid, checkData.opinion);
- // 添加推送
- const records = [];
- const auditors = await this.getAuditorsWithOwner(fp.id, fp.times);
- auditors.forEach(audit => {
- records.push({ pid, spid: fp.spid, type: pushType.financial, uid: audit.aid, status: auditConst.status.checked, content: noticeContent });
- });
- await transaction.insert('zh_notice', records);
- if (audits.length === 1 || selfAudit.audit_type !== auditType.key.and) {
- // 或签更新他人审批状态
- if (selfAudit.audit_type === auditType.key.or) {
- const updateOther = [];
- for (const audit of audits) {
- if (audit.aid === selfAudit.aid) continue;
- updateOther.push({
- id: audit.id,
- status: auditConst.status.checkSkip,
- opinion: '',
- end_time: time,
- });
- // await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, audit.id);
- }
- if (updateOther.length > 0) transaction.updateRows(this.tableName, updateOther);
- }
- // 无下一审核人表示,审核结束
- if (nextAudits.length > 0) {
- // 流程至下一审批人
- const updateData = nextAudits.map(x => { return { id: x.id, status: auditConst.status.checking, begin_time: time }; });
- await transaction.updateRows(this.tableName, updateData);
- // 同步 期信息
- await transaction.update(this.ctx.service.financialPay.tableName, {
- id: fp.id, status: auditConst.status.checking,
- });
- } else {
- // 本期结束
- // 生成截止本期数据 final数据
- // 同步 期信息
- await transaction.update(this.ctx.service.financialPay.tableName, {
- id: fp.id, status: checkData.checkType,
- entities: await this.ctx.service.financialPayContract.getEntities(fp.id),
- });
- }
- } else {
- // 同步 期信息
- await transaction.update(this.ctx.service.financialPay.tableName, {
- id: fp.id,
- status: auditConst.status.checking,
- });
- }
- await transaction.commit();
- } catch (err) {
- await transaction.rollback();
- throw err;
- }
- }
- async _checkNo(pid, fp, checkData) {
- const accountId = this.ctx.session.sessionUser.accountId;
- const time = new Date();
- const audits = fp.curAuditors;
- if (!audits) throw '审核数据错误';
- const selfAudit = audits.find(x => { return x.aid === accountId; });
- if (!selfAudit) throw '当前标段您无权审批';
- const auditors = await this.getUniqAuditor(fp.id, fp.times); // 全部参与的审批人
- const newAuditors = auditors.map(x => {
- return {
- aid: x.aid, spid: fp.spid, tid: fp.tid, fpid: fp.id,
- times: fp.times + 1, order: x.audit_order, status: auditConst.status.uncheck,
- audit_type: x.audit_type, audit_order: x.audit_order,
- };
- });
- const transaction = await this.db.beginTransaction();
- try {
- const updateData = [];
- audits.forEach(x => {
- updateData.push({
- id: x.id,
- status: x.aid === selfAudit.aid ? checkData.checkType : auditConst.status.checkSkip,
- opinion: x.aid === selfAudit.aid ? checkData.opinion : '',
- end_time: x.aid === selfAudit.aid ? time : null,
- });
- });
- await transaction.updateRows(this.tableName, updateData);
- // 添加到消息推送表
- const noticeContent = await this.getNoticeContent(pid, fp.spid, fp.id, selfAudit.aid, checkData.opinion);
- const records = [{ pid, spid: fp.spid, type: pushType.financial, uid: fp.uid, status: auditConst.status.checkNo, content: noticeContent }];
- auditors.forEach(audit => {
- records.push({ pid, spid: fp.spid, type: pushType.financial, uid: audit.aid, status: auditConst.status.checkNo, content: noticeContent });
- });
- await transaction.insert(this.ctx.service.noticePush.tableName, records);
- // 同步期信息
- await transaction.update(this.ctx.service.financialPay.tableName, {
- id: fp.id, status: checkData.checkType,
- times: fp.times + 1,
- entities: '',
- });
- // 拷贝新一次审核流程列表
- await transaction.insert(this.tableName, newAuditors);
- await transaction.commit();
- } catch (err) {
- await transaction.rollback();
- throw err;
- }
- }
- /**
- * 获取审核人需要审核的期列表
- *
- * @param auditorId
- * @return {Promise<*>}
- */
- async getAuditFinancial(auditorId, spid = '') {
- const spSql = spid ? ' and ma.`spid` = "' + spid + '"' : '';
- const sql = 'SELECT ma.`aid`, ma.`times`, ma.`order`, ma.`begin_time`, ma.`end_time`, ma.`spid`, ma.`fpid`,' +
- ' m.`status` As `fpstatus`, m.`code` As `fpcode`,' +
- ' sp.`name`, sp.`project_id` ' +
- ' FROM ?? AS ma LEFT JOIN ?? AS m ON ma.`fpid` = m.`id` LEFT JOIN ?? As sp ON ma.`spid` = sp.`id`' +
- ' WHERE ((ma.`aid` = ? and ma.`status` = ?) OR (m.`uid` = ? and ma.`status` = ? and m.`status` = ? and ma.`times` = (m.`times`-1)))' + spSql +
- ' ORDER BY ma.`begin_time` DESC';
- const sqlParam = [this.tableName, this.ctx.service.financialPay.tableName, this.ctx.service.subProject.tableName, auditorId, auditConst.status.checking, auditorId, auditConst.status.checkNo, auditConst.status.checkNo];
- const result = await this.db.query(sql, sqlParam);
- // 过滤result中存在重复sid的值, 保留最新的一条
- const filterResult = [];
- const fpidArr = [];
- for (const r of result) {
- if (fpidArr.indexOf(r.fpid) === -1) {
- filterResult.push(r);
- fpidArr.push(r.fpid);
- }
- }
- return filterResult;
- }
- /**
- * 获取审核人审核的次数
- *
- * @param auditorId
- * @return {Promise<*>}
- */
- async getCountByChecked(auditorId, spid = '') {
- if (spid) {
- return await this.db.count(this.tableName, { spid, aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
- }
- return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
- }
- /**
- * 获取最近一次审批结束时间
- *
- * @param auditorId
- * @return {Promise<*>}
- */
- async getLastEndTimeByChecked(auditorId, spid = '') {
- const spSql = spid ? ' and `spid` = "' + spid + '"' : '';
- const sql = 'SELECT `end_time` FROM ?? WHERE `aid` = ? ' +
- 'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ')' + spSql +
- ' ORDER BY `end_time` DESC';
- const sqlParam = [this.tableName, auditorId];
- const result = await this.db.queryOne(sql, sqlParam);
- return result ? result.end_time : null;
- }
- /**
- * 用于添加推送所需的content内容
- * @param {Number} pid 项目id
- * @param {Number} tid 台账id
- * @param {Number} cpId 方案id
- * @param {Number} uid 审批人id
- */
- async getNoticeContent(pid, spid, fpId, uid, opinion = '') {
- const noticeSql = 'SELECT * FROM (SELECT ' +
- ' sp.`id` As `spid`, ma.`fpid`, m.`code`, sp.`name`, pa.`name` As `su_name`, pa.role As `su_role`' +
- ' FROM (SELECT * FROM ?? WHERE `id` = ? ) As sp' +
- ' LEFT JOIN ?? As m On sp.`id` = m.`spid` AND m.`id` = ?' +
- ' LEFT JOIN ?? As ma ON m.`id` = ma.`fpid`' +
- ' LEFT JOIN ?? As pa ON pa.`id` = ?' +
- ' WHERE sp.`project_id` = ? ) as new_t GROUP BY new_t.`spid`';
- const noticeSqlParam = [this.ctx.service.subProject.tableName, spid, this.ctx.service.financialPay.tableName, fpId, this.tableName, this.ctx.service.projectAccount.tableName, uid, pid];
- const content = await this.db.query(noticeSql, noticeSqlParam);
- if (content.length) {
- content[0].opinion = opinion;
- }
- return content.length ? JSON.stringify(content[0]) : '';
- }
- }
- return FinancialPayAudit;
- };
|