phase_pay_audit.js 55 KB

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