settle_audit.js 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. 'use strict';
  2. /**
  3. * 与期不同,含原报
  4. *
  5. * @author Mai
  6. * @date
  7. * @version
  8. */
  9. const auditConst = require('../const/audit');
  10. const auditType = auditConst.auditType;
  11. const pushType = auditConst.pushType;
  12. const smsTypeConst = require('../const/sms_type');
  13. const wxConst = require('../const/wechat_template');
  14. module.exports = app => {
  15. class SettleAudit extends app.BaseService {
  16. /**
  17. * 构造函数
  18. *
  19. * @param {Object} ctx - egg全局变量
  20. * @return {void}
  21. */
  22. constructor(ctx) {
  23. super(ctx);
  24. this.tableName = 'settle_audit';
  25. }
  26. // ***** 查询审批人相关
  27. // 获取全部参与人
  28. async getAuditors(settleId, auditTimes) {
  29. return await this.getAllDataByCondition({ where: { settle_id: settleId, audit_times: auditTimes }, orders: [['active_order', 'asc']] }); // 全部参与的审批人
  30. }
  31. // 获取全部参与人 分组
  32. async getAuditorGroup(settleId, auditTimes) {
  33. const auditors = await this.getAuditors(settleId, auditTimes); // 全部参与的审批人
  34. return this.ctx.helper.groupAuditors(auditors, 'active_order');
  35. }
  36. // 获取全部参与人 去重
  37. async getUniqAuditors(settle) {
  38. const auditors = await this.getAuditors(settle.id, settle.audit_times); // 全部参与的审批人
  39. const result = [];
  40. auditors.forEach(x => {
  41. if (result.findIndex(r => { return x.audit_id === r.audit_id && x.audit_order === x.audit_order; }) < 0) {
  42. result.push(x);
  43. }
  44. });
  45. return result;
  46. }
  47. // 获取全部参与人 分组 去重
  48. async getUniqAuditorsGroup(settleId, auditTimes) {
  49. const group = await this.getAuditorGroup(settleId, auditTimes);
  50. return this.ctx.helper.groupAuditorsUniq(group);
  51. }
  52. // 获取某个状态的审批人
  53. async getAuditorsByStatus(settleId, auditStatus, auditTimes) {
  54. const cur = await this.db.queryOne(`SELECT * From ${this.tableName} where settle_id = ? AND audit_times = ? AND audit_status = ? ORDER By audit_times DESC, active_order DESC `, [settleId, auditTimes, auditStatus]);
  55. if (!cur) return [];
  56. return await this.getAllDataByCondition({ where: { settle_id: settleId, audit_times: auditTimes, audit_order: cur.audit_order, audit_status: auditStatus}});
  57. }
  58. // 获取全部审批历史
  59. async getAuditorHistory(settleId, auditTimes, reverse = false) {
  60. const history = [];
  61. if (auditTimes >= 1) {
  62. for (let i = 1; i <= auditTimes; i++) {
  63. const auditors = await this.getAuditors(settleId, i);
  64. const group = this.ctx.helper.groupAuditors(auditors, 'active_order');
  65. const historyGroup = [];
  66. const max_order = group.length > 0 && group[group.length - 1].length > 0 ? group[group.length - 1][0].audit_order : -1;
  67. for (const g of group) {
  68. const his = {
  69. auditYear: '', auditDate: '', auditTime: '', audit_time: null,
  70. audit_type: g[0].audit_type, audit_order: g[0].audit_order,
  71. auditors: g
  72. };
  73. his.is_final = his.audit_order === max_order;
  74. his.auditName = his.audit_order === 0 ? '原报' : (his.is_final ? '终审' : his.audit_order + '审');
  75. his.auditCnName = his.audit_order === 0 ? '原报' : (his.is_final ? '终审' : this.ctx.helper.transFormToChinese(his.audit_order) + '审');
  76. his.name = his.audit_type === auditType.key.common ? g[0].name : his.auditName;
  77. let audit_time;
  78. g.forEach(x => {
  79. if (x.audit_status === auditConst.settle.status.checkSkip) return;
  80. if (!his.audit_status || x.audit_status === auditConst.settle.status.checking) his.audit_status = x.audit_status;
  81. if (x.audit_time && (!audit_time || x.audit_time > audit_time)) {
  82. audit_time = x.audit_time;
  83. if (his.audit_status !== auditConst.settle.status.checking) his.audit_status = x.audit_status;
  84. }
  85. });
  86. if (audit_time) {
  87. his.audit_time = audit_time;
  88. const auditTime = this.ctx.moment(audit_time);
  89. his.auditYear = auditTime.format('YYYY');
  90. his.auditDate = auditTime.format('MM-DD');
  91. his.auditTime = auditTime.format('HH:mm:ss');
  92. }
  93. historyGroup.push(his);
  94. }
  95. if (reverse) {
  96. history.push(historyGroup.reverse());
  97. } else {
  98. history.push(historyGroup);
  99. }
  100. }
  101. }
  102. return history;
  103. }
  104. async getAllAuditors(tenderId) {
  105. const sql =
  106. 'SELECT audit_id, tid FROM ' + this.tableName +
  107. ' WHERE tid = ?' +
  108. ' GROUP BY audit_id';
  109. const sqlParam = [tenderId];
  110. return this.db.query(sql, sqlParam);
  111. }
  112. // ***** 查询审批人相关
  113. // ***** 修改审批人相关
  114. /**
  115. * 获取 最新审核顺序
  116. *
  117. * @param {Number} settleId - 期id
  118. * @param {Number} auditTimes - 第几次审批
  119. * @return {Promise<number>}
  120. */
  121. async getNewOrder(settleId, auditTimes = 1) {
  122. const sql = `SELECT Max(active_order) As max_order, Max(audit_order) As max_audit_order FROM ${this.tableName} Where settle_id = ? and audit_times = ?`;
  123. const result = await this.db.queryOne(sql, [settleId, auditTimes]);
  124. return result && result.max_order ? [result.max_order + 1, result.max_audit_order + 1] : [1, 1];
  125. }
  126. /**
  127. * 同步审核人order
  128. * @param transaction - 事务
  129. * @param {Number} settleId - 结算期id
  130. * @param {Number} auditOrder - 审核顺序(实际顺序)
  131. * @param {Number} auditTimes - 第几次审批
  132. * @param {String} selfOperate - 操作符(+/-)
  133. * @return {Promise<*>}
  134. * @private
  135. */
  136. async _syncAuditOrder(transaction, settleId, auditOrder, auditTimes, selfOperate = '-') {
  137. this.initSqlBuilder();
  138. this.sqlBuilder.setAndWhere('settle_id', {
  139. value: settleId,
  140. operate: '=',
  141. });
  142. this.sqlBuilder.setAndWhere('active_order', {
  143. value: auditOrder,
  144. operate: '>=',
  145. });
  146. this.sqlBuilder.setAndWhere('audit_times', {
  147. value: auditTimes,
  148. operate: '=',
  149. });
  150. this.sqlBuilder.setUpdateData('active_order', {
  151. value: 1,
  152. selfOperate: selfOperate,
  153. });
  154. this.sqlBuilder.setUpdateData('audit_order', {
  155. value: 1,
  156. selfOperate: selfOperate,
  157. });
  158. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  159. const data = await transaction.query(sql, sqlParam);
  160. return data;
  161. }
  162. /**
  163. * 新增审核人
  164. *
  165. * @param {Number} settleId - 期id
  166. * @param {Number} auditor - 审核人
  167. * @param {Number} auditTimes - 第几次审批
  168. * @param {Number} is_gdzs - 是否固定终审
  169. * @return {Promise<number>}
  170. */
  171. async addAuditor(settleId, auditor, auditTimes = 1, is_gdzs = 0) {
  172. let [newOrder, newAuditOrder] = await this.getNewOrder(settleId, auditTimes);
  173. // 判断是否存在固定终审,存在则newOrder - 1并使终审order+1
  174. newOrder = is_gdzs === 1 ? newOrder - 1 : newOrder;
  175. newAuditOrder = is_gdzs === 1 ? newAuditOrder - 1 : newAuditOrder;
  176. const transaction = await this.db.beginTransaction();
  177. try {
  178. if (is_gdzs) await this._syncAuditOrder(transaction, settleId, newOrder, auditTimes, '+');
  179. const data = {
  180. tid: this.ctx.tender.id, settle_id: settleId, audit_id: auditor.id,
  181. name: auditor.name, company: auditor.company, role: auditor.role, mobile: auditor.mobile,
  182. audit_times: auditTimes, active_order: newOrder, audit_status: auditConst.settle.status.uncheck,
  183. audit_order: newAuditOrder, audit_type: auditType.key.common,
  184. };
  185. const result = await transaction.insert(this.tableName, data);
  186. await transaction.commit();
  187. return result.effectRows = 1;
  188. } catch (err) {
  189. await transaction.rollback();
  190. throw err;
  191. }
  192. return false;
  193. }
  194. /**
  195. * 移除审核人
  196. *
  197. * @param {Number} settleId - 期id
  198. * @param {Number} auditorId - 审核人id
  199. * @param {Number} auditTimes - 第几次审批
  200. * @return {Promise<boolean>}
  201. */
  202. async deleteAuditor(settleId, auditorId, auditTimes = 1) {
  203. const transaction = await this.db.beginTransaction();
  204. try {
  205. const condition = { settle_id: settleId, audit_id: auditorId, audit_times: auditTimes };
  206. const auditor = await this.getDataByCondition(condition);
  207. if (!auditor) throw '审批人不存在';
  208. // 移除整个流程的人
  209. await transaction.delete(this.tableName, { settle_id: settleId, active_order: auditor.active_order, audit_times: auditTimes});
  210. await this._syncAuditOrder(transaction, settleId, auditor.active_order, auditTimes);
  211. await transaction.commit();
  212. } catch (err) {
  213. await transaction.rollback();
  214. throw err;
  215. }
  216. return true;
  217. }
  218. // 拷贝上一期审批流程
  219. async copyPreAuditors(transaction, preSettle, newSettle) {
  220. const auditors = preSettle ? await this.getUniqAuditors(preSettle) : [];
  221. const newAuditors = [];
  222. // 添加原报
  223. const user = await this.ctx.service.projectAccount.getDataById(this.ctx.session.sessionUser.accountId);
  224. newAuditors.push({
  225. tid: newSettle.tid, settle_id: newSettle.id,
  226. audit_id: this.ctx.session.sessionUser.accountId,
  227. audit_times: 1, audit_order: 0, audit_type: auditConst.auditType.key.common,
  228. active_order: 0, audit_status: auditConst.settle.status.uncheck,
  229. name: user.name, company: user.company, role: user.role, mobile: user.mobile,
  230. });
  231. // 添加其他参与人
  232. for (const a of auditors) {
  233. if (a.audit_order === 0) continue;
  234. newAuditors.push({
  235. tid: newSettle.tid, settle_id: newSettle.id,
  236. audit_id: a.audit_id,
  237. audit_times: 1, audit_order: a.audit_order, audit_type: a.audit_type,
  238. active_order: a.audit_order, audit_status: auditConst.settle.status.uncheck,
  239. name: a.name, company: a.company, role: a.role, mobile: a.mobile,
  240. });
  241. }
  242. const result = await transaction.insert(this.tableName, newAuditors);
  243. if (result.affectedRows !== newAuditors.length) throw '初始化审批流程错误';
  244. }
  245. // 固定审批流-更新
  246. async updateNewAuditList(settle, newList) {
  247. const newAuditsInfo = await this.ctx.service.projectAccount.getAllDataByCondition({ where: { id: newList.map(x => { return x.audit_id; })} });
  248. const transaction = await this.db.beginTransaction();
  249. try {
  250. // 先删除旧的审批流,再添加新的
  251. await transaction.query(`DELETE FROM ${this.tableName} where settle_id = ? and audit_times = ? and audit_order > 0`, [settle.id, settle.audit_times]);
  252. // todo 协同
  253. //await transaction.delete(this.ctx.service.settleAuditAss.tableName, { settle_id: settle.id, audit_times: settle.audit_times });
  254. const newAuditors = [];
  255. for (const auditor of newList) {
  256. const auditorInfo = newAuditsInfo.find(x => { return x.id === auditor.audit_id; });
  257. if (!auditorInfo) throw '配置的审批人不存在';
  258. newAuditors.push({
  259. tid: settle.tid, settle_id: settle.id, audit_id: auditor.audit_id,
  260. name: auditorInfo.name, company: auditorInfo.company, role: auditorInfo.role, mobile: auditorInfo.mobile,
  261. audit_times: settle.audit_times, active_order: auditor.audit_order, audit_status: auditConst.settle.status.uncheck,
  262. audit_type: auditor.audit_type, audit_order: auditor.audit_order,
  263. });
  264. }
  265. if(newAuditors.length > 0) await transaction.insert(this.tableName, newAuditors);
  266. await transaction.commit();
  267. } catch (err) {
  268. await transaction.rollback();
  269. throw err;
  270. }
  271. }
  272. // 固定终审-更新
  273. async updateLastAudit(settle, auditList, lastId) {
  274. const lastUser = lastId ? await this.ctx.service.projectAccount.getDataById(lastId) : null;
  275. const transaction = await this.db.beginTransaction();
  276. try {
  277. // 先判断auditList里的aid是否与lastId相同,相同则删除并重新更新order
  278. const existAudit = auditList.find(x => { return x.audit_id === lastId });
  279. let auditOrder = auditList.length > 0 ? auditList.reduce((rst, a) => { return Math.max(rst, a.active_order)}, 0) + 1 : 1; // 最大值 + 1
  280. if (existAudit) {
  281. await transaction.delete(this.tableName, { settle_id: settle.id, audit_times: settle.audit_times, audit_id: lastId });
  282. const sameOrder = auditList.filter(x => { return x.active_order === existAudit.active_order });
  283. if (sameOrder.length === 1) {
  284. const updateData = [];
  285. auditList.forEach(x => {
  286. if (x.active_order <= existAudit.active_order) return;
  287. updateData.push({id: x.id, active_order: x.active_order - 1, audit_order: x.audit_order - 1});
  288. });
  289. if (updateData.length > 0) {
  290. await transaction.updateRows(updateData);
  291. }
  292. auditOrder = auditOrder - 1;
  293. }
  294. }
  295. // 添加终审
  296. if (lastUser) {
  297. const newAuditor = {ttle_id: settle.id, audit_id: lastId,
  298. name: lastUser.name, company: lastUser.company, role: lastUser.role, mobile: lastUser.mobile,
  299. audit_times: settle.audit_times, active_order: auditOrder, audit_status: auditConst.settle.status.uncheck,
  300. audit_type: auditType.key.common, audit_order: auditOrder,
  301. };
  302. await transaction.insert(this.tableName, newAuditor);
  303. }
  304. tid: settle.tid, se
  305. await transaction.commit();
  306. } catch (err) {
  307. await transaction.rollback();
  308. throw err;
  309. }
  310. }
  311. // ***** 修改审批人相关
  312. // ***** 审批操作
  313. /**
  314. * 用于添加推送所需的content内容
  315. * @param {Number} pid 项目id
  316. * @param {Number} tid 台账id
  317. * @param {Number} sid 期id
  318. * @param {Number} uid 审核人id
  319. */
  320. async _getNoticeContent(pid, tid, sid, uid, opinion = '') {
  321. const noticeSql =
  322. 'SELECT * FROM (SELECT ' +
  323. ' t.`id` As `tid`, t.`name`, s.`settle_order` as `order`, pa.`name` As `su_name`, pa.role As `su_role`' +
  324. ` FROM (SELECT * FROM ${this.ctx.service.tender.tableName} WHERE id = ? ) As t` +
  325. ` LEFT JOIN ${this.ctx.service.settle.tableName} As s On s.id = ?` +
  326. ` LEFT JOIN ${this.ctx.service.projectAccount.tableName} As pa ON pa.id = ?` +
  327. ' WHERE t.`project_id` = ? ) as new_t GROUP BY new_t.`tid`';
  328. const noticeSqlParam = [tid, sid, uid, pid];
  329. const content = await this.db.query(noticeSql, noticeSqlParam);
  330. if (content.length) {
  331. content[0].opinion = opinion;
  332. }
  333. return content.length ? JSON.stringify(content[0]) : '';
  334. }
  335. async start(settle) {
  336. const audits = await this.getAllDataByCondition({ where: { settle_id: settle.id, audit_times: settle.audit_times, audit_order: 1 } });
  337. if (audits.length === 0) {
  338. if(this.ctx.tender.info.shenpi.settle === shenpiConst.sp_status.gdspl) {
  339. throw '请联系管理员添加审批人';
  340. } else {
  341. throw '请先选择审批人,再上报数据';
  342. }
  343. }
  344. const transaction = await this.db.beginTransaction();
  345. try {
  346. const audit_time = new Date();
  347. // 更新原报数据
  348. await transaction.update(this.tableName, { audit_status: auditConst.settle.status.checked, audit_time }, { where: { settle_id: settle.id, audit_times: settle.audit_times, audit_order: 0 } });
  349. // 更新下一审批人数据
  350. const updateData = audits.map(x => { return { id: x.id, audit_status: auditConst.settle.status.checking } });
  351. await transaction.updateRows(this.tableName, updateData);
  352. // 生成结算台账
  353. const settleSum = await this.ctx.service.settle.doSettle(transaction, settle);
  354. // todo 计算部分缓存汇总数据
  355. await transaction.update(this.ctx.service.settle.tableName, {
  356. id: settle.id, audit_status: auditConst.settle.status.checking,
  357. ...settleSum,
  358. final_sid: settle.latestStage.id, final_sorder: settle.latestStage.order,
  359. });
  360. // 多人协同,取消下一审批人存在的锁定
  361. // await this.ctx.service.settleAuditAss.cancelLock(settle, audits.map(x => { return x.audit_id; }), transaction);
  362. // todo 添加短信通知-需要审批提醒功能
  363. const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + settle.tid + '/settle/' + settle.settle_order);
  364. const auditIds = this._.map(audits, 'audit_id');
  365. const users = this._.map(settle.auditAssists.filter(x => { return auditIds.indexOf(x.user_id) >= 0; }), 'ass_user_id');
  366. users.push(...auditIds);
  367. // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), SmsAliConst.template.settle_check, {
  368. // qi: settle.audit_order,
  369. // code: shenpiUrl,
  370. // });
  371. // 微信模板通知
  372. const wechatData = {
  373. wap_url: shenpiUrl,
  374. qi: settle.settle_order,
  375. status: wxConst.status.check,
  376. tips: wxConst.tips.check,
  377. code: this.ctx.session.sessionProject.code,
  378. };
  379. await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.settle, wechatData);
  380. console.log(audits);
  381. for (const a of audits) {
  382. await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.JS, {
  383. pid: this.ctx.session.sessionProject.id,
  384. tid: settle.tid,
  385. uid: a.audit_id,
  386. sp_type: 'settle',
  387. sp_id: a.id,
  388. table_name: this.tableName,
  389. template: wxConst.template.settle,
  390. wx_data: wechatData,
  391. });
  392. }
  393. // todo 上报/审批 - 检查三方特殊推送
  394. // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.flow);
  395. await transaction.commit();
  396. } catch (err) {
  397. await transaction.rollback();
  398. throw err;
  399. }
  400. }
  401. async _checked(settle, opinion) {
  402. const accountId = this.ctx.session.sessionUser.accountId;
  403. const time = new Date();
  404. const selfAudit = settle.curAuditors.find(x => { return x.audit_id === accountId; });
  405. if (!selfAudit) throw '当前标段您无权审批';
  406. const nextAudits = await this.getAllDataByCondition({ where: { settle_id: settle.id, audit_times: settle.audit_times, active_order: selfAudit.active_order + 1 } });
  407. const transaction = await this.db.beginTransaction();
  408. try {
  409. // 添加通知
  410. const noticeContent = await this._getNoticeContent(this.ctx.session.sessionProject.id, settle.tid, settle.id, accountId, opinion);
  411. const defaultNoticeRecord = {
  412. pid: this.ctx.session.sessionProject.id,
  413. type: pushType.settle,
  414. status: auditConst.settle.status.checked,
  415. content: noticeContent,
  416. };
  417. const records = settle.userIds.map(x => {
  418. return { uid: x, ...defaultNoticeRecord };
  419. });
  420. await transaction.insert('zh_notice', records);
  421. // 更新本人审批状态
  422. await transaction.update(this.tableName, {
  423. id: selfAudit.id,
  424. audit_status: auditConst.settle.status.checked, opinion: opinion,
  425. audit_time: time,
  426. });
  427. await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, selfAudit.id);
  428. let auditStatus;
  429. if (settle.curAuditors.length === 1 || selfAudit.audit_type === auditType.key.or) {
  430. // 或签更新他人审批状态
  431. if (selfAudit.audit_type === auditType.key.or) {
  432. const updateOther = [];
  433. for (const audit of settle.curAuditors) {
  434. if (audit.audit_id === selfAudit.audit_id) continue;
  435. updateOther.push({
  436. id: audit.id,
  437. audit_status: auditConst.settle.status.checkSkip,
  438. opinion: '',
  439. audit_time: time,
  440. });
  441. await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, audit.id);
  442. }
  443. if (updateOther.length > 0) transaction.updateRows(this.tableName, updateOther);
  444. }
  445. // 无下一审核人表示,审核结束
  446. auditStatus = nextAudits.length > 0 ? auditConst.settle.status.checking : auditConst.settle.status.checked;
  447. if (nextAudits.length > 0) {
  448. // 流程至下一审批人
  449. const updateData = nextAudits.map(x => { return { id: x.id, audit_status: auditConst.settle.status.checking }; });
  450. await transaction.updateRows(this.tableName, updateData);
  451. // todo 多人协同,取消下一审批人存在的锁定
  452. // await this.ctx.service.settleAuditAss.cancelLock(settle, nextAudits.map(x => { return x.audit_id; }), transaction);
  453. // todo 添加短信通知-需要审批提醒功能
  454. const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + this.ctx.tender.id + '/settle/' + settle.settle_order);
  455. const nextAuditIds = this._.map(nextAudits, 'audit_id');
  456. const users = this._.map(this._.filter(this.ctx.auditAssists, function (x) { return nextAuditIds.indexOf(x.user_id) >= 0; }), 'ass_user_id');
  457. users.push(...nextAuditIds);
  458. // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), SmsAliConst.template.settle_check, {
  459. // qi: settle.settle_order,
  460. // code: shenpiUrl,
  461. // });
  462. // 微信模板通知
  463. const wechatData = {
  464. wap_url: shenpiUrl,
  465. qi: settle.settle_order,
  466. status: wxConst.status.check,
  467. tips: wxConst.tips.check,
  468. code: this.ctx.session.sessionProject.code,
  469. };
  470. await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.settle, wechatData);
  471. for (const a of nextAudits) {
  472. await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.JS, {
  473. pid: this.ctx.session.sessionProject.id,
  474. tid: this.ctx.tender.id,
  475. uid: a.audit_id,
  476. sp_type: 'settle',
  477. sp_id: a.id,
  478. table_name: this.tableName,
  479. template: wxConst.template.settle,
  480. wx_data: wechatData,
  481. });
  482. }
  483. } else {
  484. // 添加短信通知-审批通过提醒功能
  485. const users = this._.uniq(settle.userIds);
  486. // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), SmsAliConst.template.settle_result, {
  487. // qi: settle.settle_order,
  488. // status: SmsAliConst.status.success,
  489. // });
  490. // 微信模板通知
  491. const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + this.ctx.tender.id + '/settle/' + settle.settle_order);
  492. const wechatData = {
  493. wap_url: shenpiUrl,
  494. qi: settle.settle_order,
  495. status: wxConst.status.success,
  496. tips: wxConst.tips.success,
  497. code: this.ctx.session.sessionProject.code,
  498. };
  499. await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), wxConst.template.settle, wechatData);
  500. // todo 审批通过 - 检查三方特殊推送
  501. // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.checked);
  502. }
  503. // todo 上报/审批 - 检查三方特殊推送
  504. // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.flow);
  505. } else {
  506. auditStatus = auditConst.settle.status.checking;
  507. }
  508. // 同步 期信息
  509. await transaction.update(this.ctx.service.settle.tableName, { id: settle.id, audit_status: auditStatus });
  510. await transaction.commit();
  511. } catch (err) {
  512. await transaction.rollback();
  513. throw err;
  514. }
  515. }
  516. async _checkNo(settle, opinion) {
  517. const pid = this.ctx.session.sessionProject.id;
  518. const accountId = this.ctx.session.sessionUser.accountId;
  519. const time = new Date();
  520. // 整理当前流程审核人状态更新
  521. const selfAudit = settle.curAuditors.find(x => { return x.audit_id === accountId; });
  522. if (!selfAudit) throw '当前标段您无权审批';
  523. const auditors = await this.getUniqAuditors(settle); // 全部参与的审批人
  524. const newAuditors = auditors.map(x => {
  525. return {
  526. tid: settle.tid, settle_id: settle.id, audit_id: x.audit_id,
  527. audit_times: settle.audit_times + 1, audit_order: x.audit_order, audit_type: x.audit_type,
  528. active_order: x.audit_order, audit_status: auditConst.settle.status.uncheck,
  529. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  530. }
  531. });
  532. const transaction = await this.db.beginTransaction();
  533. try {
  534. // 添加提醒
  535. const noticeContent = await this._getNoticeContent(pid, selfAudit.tid, settle.id, selfAudit.audit_id, opinion);
  536. const defaultNoticeRecord = { pid, type: pushType.settle, status: auditConst.settle.status.checkNo, content: noticeContent };
  537. const records = settle.userIds.map(x => {
  538. return { uid: x, ...defaultNoticeRecord };
  539. });
  540. await transaction.insert(this.ctx.service.noticePush.tableName, records);
  541. // 更新审批人状态数据
  542. const updateData = [];
  543. settle.curAuditors.forEach(x => {
  544. if (x.audit_id === selfAudit.audit_id) {
  545. updateData.push({ id: x.id, audit_status: auditConst.settle.status.checkNo, opinion: opinion, audit_time: time});
  546. } else {
  547. updateData.push({ id: x.id, audit_status: auditConst.settle.status.checkSkip, opinion: '', audit_time: null});
  548. }
  549. });
  550. await transaction.updateRows(this.tableName, updateData);
  551. await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, this._.map(updateData, 'id'));
  552. // 更新 期信息
  553. await transaction.update(this.ctx.service.settle.tableName, {
  554. id: settle.id, audit_status: auditConst.settle.status.checkNo, audit_times: settle.audit_times + 1,
  555. });
  556. // 拷贝新一次审核流程列表
  557. await transaction.insert(this.tableName, newAuditors);
  558. // todo 锁定本人数据,保留锁定数据相关确认状态
  559. // await this.ctx.service.settleAuditAss.lockConfirm4CheckNo(settle, curAuditorIds, auditors, transaction);
  560. // todo 添加短信通知-审批退回提醒功能
  561. const users = this._.uniq(settle.userIds);
  562. // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), SmsAliConst.template.settle_result, {
  563. // qi: settle.settle_order, status: SmsAliConst.status.back,
  564. // });
  565. // 微信模板通知
  566. const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + settle.tid + '/settle/' + settle.settle_order);
  567. const wechatData = {
  568. wap_url: shenpiUrl,
  569. qi: settle.settle_order,
  570. status: wxConst.status.back,
  571. tips: wxConst.tips.back,
  572. code: this.ctx.session.sessionProject.code,
  573. };
  574. await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), wxConst.template.settle, wechatData);
  575. // todo 上报/审批 - 检查三方特殊推送
  576. // await this.ctx.service.specMsg.addSettleMsg(transaction, pid, settle, pushOperate.settle.flow);
  577. await transaction.commit();
  578. } catch (err) {
  579. await transaction.rollback();
  580. throw err;
  581. }
  582. }
  583. async _checkNoPre(settle, opinion) {
  584. const pid = this.ctx.session.sessionProject.id;
  585. const accountId = this.ctx.session.sessionUser.accountId;
  586. const time = new Date();
  587. // 整理当前流程审核人状态更新
  588. const selfAudit = settle.curAuditors.find(x => { return x.audit_id === accountId; });
  589. if (!selfAudit) throw '当前标段您无权审批';
  590. const preAuditors = settle.userGroups.find(x => { return x[0].audit_order === selfAudit.audit_order - 1; });
  591. const transaction = await this.db.beginTransaction();
  592. try {
  593. // 添加通知
  594. const noticeContent = await this._getNoticeContent(pid, settle.tid, settle.id, selfAudit.audit_id, opinion);
  595. const defaultNoticeRecord = {
  596. pid, type: pushType.settle, status: auditConst.settle.status.checkNoPre, content: noticeContent,
  597. };
  598. const records = settle.userIds.map(x => {
  599. return { uid: x, ...defaultNoticeRecord };
  600. });
  601. await transaction.insert('zh_notice', records);
  602. // 更新同一流程所有审批人状态
  603. const updateData = [];
  604. for (const audit of settle.curAuditors) {
  605. if (audit.audit_id === selfAudit.audit_id) {
  606. updateData.push({
  607. id: audit.id, audit_status: auditConst.settle.status.checkNoPre, opinion, audit_time: time,
  608. });
  609. } else {
  610. updateData.push({
  611. id: audit.id, audit_status: auditConst.settle.status.checkSkip, opinion: '', audit_time: null,
  612. });
  613. }
  614. }
  615. await transaction.updateRows(this.tableName, updateData);
  616. await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, this._.map(updateData, 'id'));
  617. // 顺移其后审核人流程顺序
  618. const sql = 'UPDATE ' + this.tableName + ' SET `active_order` = `active_order` + 2 WHERE settle_id = ? AND audit_times = ? AND `active_order` > ?';
  619. await transaction.query(sql, [settle.id, selfAudit.audit_times, selfAudit.active_order]);
  620. // 上一审批人,当前审批人 再次添加至流程
  621. const newAuditors = [], uncheckAuditors = [];
  622. preAuditors.forEach(x => {
  623. newAuditors.push({
  624. tid: x.tid, settle_id: x.settle_id, audit_id: x.audit_id,
  625. audit_times: x.audit_times, audit_order: selfAudit.audit_order - 1,
  626. audit_status: auditConst.settle.status.checking,
  627. audit_type: x.audit_type, active_order: selfAudit.active_order + 1,
  628. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  629. });
  630. });
  631. const checkingAuditors_result = await transaction.insert(this.tableName, newAuditors);
  632. // 获取刚批量添加的所有list
  633. for (let j = 0; j < newAuditors.length; j++) {
  634. newAuditors[j].id = checkingAuditors_result.insertId + j;
  635. }
  636. settle.flowAuditors.forEach(x => {
  637. uncheckAuditors.push({
  638. tid: x.tid, settle_id: x.settle_id, audit_id: x.audit_id,
  639. audit_times: x.audit_times, active_order: selfAudit.active_order + 2,
  640. audit_status: auditConst.settle.status.uncheck,
  641. audit_type: x.audit_type, audit_order: x.audit_order,
  642. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  643. });
  644. });
  645. await transaction.insert(this.tableName, uncheckAuditors);
  646. const preAuditorIds = preAuditors.map(x => { return x.audit_id; });
  647. // todo 锁定本人数据,保留锁定数据相关确认状态
  648. // await this.ctx.service.settleAuditAss.lockConfirm4CheckNoPre(settle, settle.curAuditorIds, preAuditorIds, transaction);
  649. // 同步 期信息
  650. await transaction.update(this.ctx.service.settle.tableName, {
  651. id: settle.id, audit_status: auditConst.settle.status.checkNoPre,
  652. });
  653. const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + settle.tid + '/settle/' + settle.settle_order);
  654. const users = this._.map(settle.auditAssists.filter(x => {return preAuditorIds.indexOf(x.user_id) >= 0 }), 'ass_user_id');
  655. users.push(...preAuditorIds);
  656. // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), SmsAliConst.template.settle_check, {
  657. // qi: settle.settle_order,
  658. // code: shenpiUrl,
  659. // });
  660. // 微信模板通知
  661. const wechatData = {
  662. wap_url: shenpiUrl,
  663. qi: settle.settle_order,
  664. status: wxConst.status.check,
  665. tips: wxConst.tips.check,
  666. code: this.ctx.session.sessionProject.code,
  667. };
  668. await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.settle, wechatData);
  669. for (const a of newAuditors) {
  670. await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.JS, {
  671. pid: this.ctx.session.sessionProject.id,
  672. tid: settle.tid,
  673. uid: a.audit_id,
  674. sp_type: 'settle',
  675. sp_id: a.id,
  676. table_name: this.tableName,
  677. template: wxConst.template.settle,
  678. wx_data: wechatData,
  679. });
  680. }
  681. // todo 上报/审批 - 检查三方特殊推送
  682. // await this.ctx.service.specMsg.addSettleMsg(transaction, pid, settle, pushOperate.settle.flow);
  683. await transaction.commit();
  684. } catch (err) {
  685. await transaction.rollback();
  686. throw err;
  687. }
  688. }
  689. async check(settle, checkType, opinion = '') {
  690. switch (checkType) {
  691. case auditConst.settle.status.checked:
  692. await this._checked(settle, opinion);
  693. break;
  694. case auditConst.settle.status.checkNo:
  695. await this._checkNo(settle, opinion);
  696. break;
  697. case auditConst.settle.status.checkNoPre:
  698. await this._checkNoPre(settle, opinion);
  699. break;
  700. default:
  701. throw '无效审批操作';
  702. }
  703. }
  704. async checkAgain(settle, force = false) {
  705. const accountId = this.ctx.session.sessionUser.accountId;
  706. const time = new Date();
  707. // 整理当前流程审核人状态更新
  708. const finalAudits = settle.auditorGroups[settle.auditorGroups.length - 1];
  709. if (!finalAudits || finalAudits.length === 0 || finalAudits[0].audit_order < 1) throw '审核数据错误';
  710. const selfAudit = finalAudits.find(x => { return x.audit_id === accountId; });
  711. if (!selfAudit && !force) throw '当前标段您无权审批';
  712. const finalAudit = selfAudit || finalAudits[0];
  713. const transaction = await this.db.beginTransaction();
  714. try {
  715. // 当前审批人2次添加至流程中
  716. const checkAgainAuditors = [], checkingAuditors = [];
  717. finalAudits.forEach(x => {
  718. checkAgainAuditors.push({
  719. tid: x.tid, settle_id: x.settle_id, audit_id: x.audit_id,
  720. audit_type: x.audit_type, audit_order: x.audit_order,
  721. audit_times: x.audit_times, active_order: x.active_order + 1,
  722. audit_status: x.audit_id === finalAudit.audit_id ? auditConst.settle.status.checkAgain : auditConst.settle.status.checkSkip,
  723. audit_time: time, opinion: '',
  724. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  725. });
  726. });
  727. finalAudits.forEach(x => {
  728. checkingAuditors.push({
  729. tid: x.tid, settle_id: x.settle_id, audit_id: x.audit_id,
  730. audit_type: x.audit_type, audit_order: x.audit_order,
  731. audit_times: x.audit_times, active_order: x.active_order + 2,
  732. audit_status: auditConst.settle.status.checking, audit_time: time, opinion: '',
  733. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  734. });
  735. });
  736. await transaction.insert(this.tableName, checkAgainAuditors);
  737. const checkingAuditors_result = await transaction.insert(this.tableName, checkingAuditors);
  738. // 获取刚批量添加的所有list
  739. for (let j = 0; j < checkingAuditors.length; j++) {
  740. checkingAuditors[j].id = checkingAuditors_result.insertId + j;
  741. }
  742. // 同步 期信息
  743. await transaction.update(this.ctx.service.settle.tableName, {
  744. id: settle.id, audit_status: auditConst.settle.status.checking,
  745. });
  746. // todo 添加短信通知-需要审批提醒功能
  747. const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + settle.tid + '/settle/' + settle.settle_order);
  748. const users = this._.map(settle.auditAssists.filter(x => { return settle.finalAuditorIds.indexOf(x.user_id) >= 0; }), 'ass_user_id');
  749. users.push(...settle.finalAuditorIds);
  750. // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), SmsAliConst.template.settle_check, {
  751. // qi: settle.settle_order, code: shenpiUrl,
  752. // });
  753. // 微信模板通知
  754. const wechatData = {
  755. wap_url: shenpiUrl,
  756. qi: settle.settle_order,
  757. status: wxConst.status.check,
  758. tips: wxConst.tips.check,
  759. code: this.ctx.session.sessionProject.code,
  760. };
  761. await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.settle, wechatData);
  762. for (const a of checkingAuditors) {
  763. await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.JS, {
  764. pid: this.ctx.session.sessionProject.id,
  765. tid: settle.tid,
  766. uid: a.audit_id,
  767. sp_type: 'settle',
  768. sp_id: a.id,
  769. table_name: this.tableName,
  770. template: wxConst.template.settle,
  771. wx_data: wechatData,
  772. });
  773. }
  774. // todo 上报/审批 - 检查三方特殊推送
  775. // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.flow);
  776. await transaction.commit();
  777. } catch (err) {
  778. await transaction.rollback();
  779. throw err;
  780. }
  781. }
  782. /**
  783. * 原报撤回,直接改动审批人状态
  784. * 如果存在审批人数据,将其改为原报流程数据,但保留原提交人
  785. *
  786. * 一审 1 A checking -> A uncheck status改 pay/jl:删0(jl为增量数据,只删重复部分) 1->0 删1
  787. * ...
  788. *
  789. * @param settle
  790. * @returns {Promise<void>}
  791. * @private
  792. */
  793. async _userCheckCancel(settle) {
  794. const transaction = await this.db.beginTransaction();
  795. try {
  796. // 整理当前流程审核人状态更新
  797. // 审批人变成待审批状态
  798. const updateData = settle.curAuditors.map(x => {
  799. return {
  800. id: x.id, audit_status: auditConst.settle.status.uncheck,
  801. audit_time: null, opinion: '',
  802. }
  803. });
  804. await transaction.updateRows(this.tableName, updateData);
  805. await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, this._.map(updateData, 'id'));
  806. await transaction.update(this.ctx.service.settle.tableName, {
  807. id: settle.id, audit_times: settle.audit_times,
  808. audit_status: settle.audit_times === 1 ? auditConst.settle.status.uncheck : auditConst.settle.status.checkNo,
  809. });
  810. // todo 上报/审批 - 检查三方特殊推送
  811. // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.flow);
  812. await transaction.commit();
  813. } catch(err) {
  814. await transaction.rollback();
  815. throw err;
  816. }
  817. }
  818. /**
  819. * 审批人撤回审批通过,插入两条数据
  820. *
  821. * @param settle
  822. * @returns {Promise<void>}
  823. * @private
  824. */
  825. async _auditCheckCancel(settle) {
  826. if (settle.curAuditors.length === 0 || settle.curAuditors[0].active_order <= 1) {
  827. throw '撤回用户数据错误';
  828. }
  829. const accountId = this.ctx.session.sessionUser.accountId;
  830. const selfAuditor = settle.preAuditors.find(x => { return x.audit_id === accountId; });
  831. if (!selfAuditor) throw '撤回用户数据错误';
  832. const time = new Date();
  833. const transaction = await this.db.beginTransaction();
  834. try {
  835. // 整理当前流程审核人状态更新
  836. // 顺移其后审核人流程顺序
  837. const sql = 'UPDATE ' + this.tableName + ' SET `active_order` = `active_order` + 2 WHERE settle_id = ? AND audit_times = ? AND `active_order` > ?';
  838. await transaction.query(sql, [settle.id, selfAuditor.audit_times, settle.curAuditors[0].active_order]);
  839. // 当前审批人2次添加至流程中
  840. const checkCancelAuditors = [], checkingAuditors = [];
  841. settle.preAuditors.forEach(x => {
  842. checkCancelAuditors.push({
  843. tid: settle.tid, settle_id: settle.id, audit_id: x.audit_id,
  844. audit_times: x.audit_times, active_order: x.active_order + 1,
  845. audit_type: x.audit_type, audit_order: x.audit_order,
  846. status: x.audit_id === selfAuditor.audit_id ? auditConst.settle.status.checkCancel : auditConst.settle.status.checkSkip,
  847. audit_time: time, opinion: '',
  848. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  849. });
  850. });
  851. settle.preAuditors.forEach(x => {
  852. checkingAuditors.push({
  853. tid: settle.tid, settle_id: settle.id, audit_id: x.audit_id,
  854. audit_times: x.audit_times, active_order: x.active_order + 2,
  855. audit_type: x.audit_type, audit_order: x.audit_order,
  856. status: auditConst.settle.status.checking,
  857. audit_time: time, opinion: '',
  858. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  859. });
  860. });
  861. await transaction.insert(this.tableName, [...checkCancelAuditors, ...checkingAuditors]);
  862. // 当前审批人变成待审批
  863. await transaction.updateRows(this.tableName, settle.curAuditors.map(x => { return {
  864. id: x.id, audit_time: null, status: auditConst.settle.status.uncheck, active_order: x.active_order + 2
  865. }}));
  866. await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, this._.map(settle.curAuditors, 'id'));
  867. // 同步 期信息
  868. await transaction.update(this.ctx.service.settle.tableName, {
  869. id: settle.id, audit_times: settle.audit_times,
  870. });
  871. // todo 上报/审批 - 检查三方特殊推送
  872. // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.flow);
  873. await transaction.commit();
  874. } catch(err) {
  875. await transaction.rollback();
  876. throw err;
  877. }
  878. }
  879. /**
  880. * 审批人撤回审批退回上一人,插入两条数据
  881. *
  882. * @param settle
  883. * @returns {Promise<void>}
  884. * @private
  885. */
  886. async _auditCheckCancelNoPre(settle) {
  887. if (settle.curAuditors.length === 0 || settle.curAuditors[0].active_order <= 1) {
  888. throw '撤回用户数据错误';
  889. }
  890. const accountId = this.ctx.session.sessionUser.accountId;
  891. const selfAuditor = settle.preAuditors.find(x => { return x.audit_id === accountId; });
  892. if (!selfAuditor) throw '撤回用户数据错误';
  893. const time = new Date();
  894. const transaction = await this.db.beginTransaction();
  895. try {
  896. // 整理当前流程审核人状态更新
  897. // 删除当前审批人
  898. await transaction.delete(this.tableName, { id: settle.curAuditors.map(x => { return x.id; }) });
  899. await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, this._.map(settle.curAuditors, 'id'));
  900. // 添加撤回人到审批流程中
  901. const newAuditors = [];
  902. settle.preAuditors.forEach(x => {
  903. newAuditors.push({
  904. tid: settle.tid, settle_id: settle.id, audit_id: x.audit_id,
  905. audit_times: x.audit_times, active_order: x.active_order + 1,
  906. audit_type: x.audit_type, audit_order: x.audit_order,
  907. audit_status: x.audit_id === selfAuditor.audit_id ? auditConst.settle.status.checkCancel : auditConst.settle.status.checkSkip,
  908. audit_time: time, opinion: '',
  909. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  910. });
  911. });
  912. await transaction.insert(this.tableName, newAuditors);
  913. // 更新上一个人,最新审批状态为审批中
  914. await transaction.update(this.tableName, { audit_time: null, opinion: '', audit_status: auditConst.settle.status.checking }, {
  915. where: { settle_id: settle.id, audit_times: selfAuditor.audit_times, active_order: selfAuditor.active_order + 2 }
  916. });
  917. // 同步 期信息
  918. await transaction.update(this.ctx.service.settle.tableName, {
  919. id: settle.id, audit_times: settle.audit_times, status: auditConst.settle.status.checking,
  920. });
  921. // todo 上报/审批 - 检查三方特殊推送
  922. // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.flow);
  923. await transaction.commit();
  924. } catch(err) {
  925. await transaction.rollback();
  926. throw err;
  927. }
  928. }
  929. /**
  930. * 审批人撤回审批退回原报
  931. *
  932. * @param settle
  933. * @returns {Promise<void>}
  934. * @private
  935. */
  936. async _auditCheckCancelNo(settle) {
  937. const accountId = this.ctx.session.sessionUser.accountId;
  938. const selfAuditor = settle.preAuditors.find(x => { return x.audit_id === accountId && x.audit_status === auditConst.settle.status.checkNo; });
  939. if (!selfAuditor) throw '该标段由他人审批退回,您不可撤回';
  940. const time = new Date();
  941. const transaction = await this.db.beginTransaction();
  942. try {
  943. // 整理上一个流程审核人状态更新
  944. // 顺移其后审核人流程顺序
  945. const sql = 'UPDATE ' + this.tableName + ' SET `active_order` = `active_order` + 2 WHERE settle_id = ? AND audit_times = ? AND `active_order` > ?';
  946. await transaction.query(sql, [settle.id, selfAuditor.audit_times, selfAuditor.active_order]);
  947. // 当前审批人2次添加至流程中
  948. const checkCancelAuditors = [], checkingAuditors = [];
  949. settle.preAuditors.forEach(x => {
  950. checkCancelAuditors.push({
  951. tid: settle.tid, settle_id: settle.id, audit_id: x.audit_id,
  952. audit_times: x.audit_times, active_order: x.active_order + 1,
  953. audit_type: x.audit_type, audit_order: x.audit_order,
  954. audit_status: x.audit_id === selfAuditor.audit_id ? auditConst.settle.status.checkCancel : auditConst.settle.status.checkSkip,
  955. audit_time: time, opinion: '',
  956. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  957. });
  958. });
  959. settle.preAuditors.forEach(x => {
  960. checkingAuditors.push({
  961. tid: settle.tid, settle_id: settle.id, audit_id: x.audit_id,
  962. audit_times: x.audit_times, active_order: x.active_order + 2,
  963. audit_type: x.audit_type, audit_order: x.audit_order,
  964. audit_status: auditConst.settle.status.checking,
  965. audit_time: time, opinion: '',
  966. name: x.name, company: x.company, role: x.role, mobile: x.mobile,
  967. });
  968. });
  969. await transaction.insert(this.tableName, [...checkCancelAuditors, ...checkingAuditors]);
  970. // 删除当前次审批流
  971. await transaction.delete(this.tableName, { settle_id: settle.id, audit_times: settle.audit_times });
  972. // 计算并合同支付最终数据
  973. await transaction.update(this.ctx.service.settle.tableName, {
  974. id: settle.id, audit_times: settle.audit_times - 1, status: auditConst.settle.status.checking,
  975. });
  976. // todo 上报/审批 - 检查三方特殊推送
  977. // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.flow);
  978. await transaction.commit();
  979. } catch(err) {
  980. await transaction.rollback();
  981. throw err;
  982. }
  983. }
  984. /**
  985. * 会签未全部审批通过时,撤回仅修改本人状态
  986. *
  987. * @param settle
  988. * @returns {Promise<void>}
  989. * @private
  990. */
  991. async _auditCheckCancelAnd(settle) {
  992. const accountId = this.ctx.session.sessionUser.accountId;
  993. const selfAuditor = settle.flowAuditors.find(x => { return x.audit_id === accountId; });
  994. if (!selfAuditor || selfAuditor.audit_status !== auditConst.settle.status.checked) throw '不可撤回';
  995. const transaction = await this.db.beginTransaction();
  996. try {
  997. await transaction.update(this.tableName, {
  998. id: selfAuditor.id, status: auditConst.settle.status.checking, opinion: '', audit_time: null,
  999. });
  1000. await transaction.commit();
  1001. } catch(err) {
  1002. await transaction.rollback();
  1003. throw err;
  1004. }
  1005. }
  1006. /**
  1007. * 审批撤回
  1008. * @param {Number} settle - 结算期
  1009. * @return {Promise<void>}
  1010. */
  1011. async checkCancel(settle) {
  1012. // 分5种情况,根据settle.cancancel值判断:
  1013. // 1.原报发起撤回,当前流程删除,并回到待上报
  1014. // 2.审批人撤回审批通过,增加流程,并回到它审批中
  1015. // 3.审批人撤回审批退回上一人,并删除退回人,增加流程,并回到它审批中,并更新计量期状态为审批中
  1016. // 4.审批人撤回退回原报操作,删除新增的审批流,增加流程,回滚到它审批中
  1017. // 5.会签审批人撤回审批通过(还有其他审批人未审批通过),仅修改本人流程状态
  1018. console.log(settle.cancancel);
  1019. if (settle.cancancel === 5) {
  1020. await this._auditCheckCancelAnd(settle);
  1021. } else {
  1022. switch (settle.cancancel) {
  1023. case 1: await this._userCheckCancel(settle); break;
  1024. case 2: await this._auditCheckCancel(settle); break;
  1025. case 3: await this._auditCheckCancelNoPre(settle); break;
  1026. case 4: await this._auditCheckCancelNo(settle); break;
  1027. default: throw '不可撤回,请刷新页面重试';
  1028. }
  1029. }
  1030. }
  1031. // ***** 审批操作
  1032. }
  1033. return SettleAudit;
  1034. };