stage_audit.js 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date 2019/2/27
  7. * @version
  8. */
  9. const auditConst = require('../const/audit').stage;
  10. const smsTypeConst = require('../const/sms_type');
  11. const SMS = require('../lib/sms');
  12. module.exports = app => {
  13. class StageAudit extends app.BaseService {
  14. /**
  15. * 构造函数
  16. *
  17. * @param {Object} ctx - egg全局变量
  18. * @return {void}
  19. */
  20. constructor(ctx) {
  21. super(ctx);
  22. this.tableName = 'stage_audit';
  23. }
  24. /**
  25. * 获取 审核人信息
  26. *
  27. * @param {Number} stageId - 期id
  28. * @param {Number} auditorId - 审核人id
  29. * @param {Number} times - 第几次审批
  30. * @returns {Promise<*>}
  31. */
  32. async getAuditor(stageId, auditorId, times = 1) {
  33. const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
  34. 'FROM ?? AS la, ?? AS pa ' +
  35. 'WHERE la.`sid` = ? and la.`aid` = ? and la.`times` = ?' +
  36. ' and la.`aid` = pa.`id`';
  37. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditorId, times];
  38. return await this.db.queryOne(sql, sqlParam);
  39. }
  40. /**
  41. * 获取 审核列表信息
  42. *
  43. * @param {Number} stageId - 期id
  44. * @param {Number} times - 第几次审批
  45. * @returns {Promise<*>}
  46. */
  47. async getAuditors(stageId, times = 1) {
  48. const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, g.`sort` ' +
  49. 'FROM ?? AS la, ?? AS pa, (SELECT `aid`,(@i:=@i+1) as `sort` FROM ??, (select @i:=0) as it WHERE `sid` = ? AND `times` = ? GROUP BY `aid`) as g ' +
  50. 'WHERE la.`sid` = ? and la.`times` = ? and la.`aid` = pa.`id` and g.`aid` = la.`aid` order by la.`order`';
  51. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.tableName, stageId, times, stageId, times];
  52. const result = await this.db.query(sql, sqlParam);
  53. const sql2 = 'SELECT COUNT(a.`aid`) as num FROM (SELECT `aid` FROM ?? WHERE `sid` = ? AND `times` = ? GROUP BY `aid`) as a';
  54. const sqlParam2 = [this.tableName, stageId, times];
  55. const count = await this.db.queryOne(sql2, sqlParam2);
  56. for (const i in result) {
  57. result[i].max_sort = count.num;
  58. }
  59. return result;
  60. }
  61. /**
  62. * 获取 当前审核人
  63. *
  64. * @param {Number} stageId - 期id
  65. * @param {Number} times - 第几次审批
  66. * @returns {Promise<*>}
  67. */
  68. async getCurAuditor(stageId, times = 1) {
  69. const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
  70. 'FROM ?? AS la, ?? AS pa ' +
  71. 'WHERE la.`sid` = ? and la.`status` = ? and la.`times` = ?' +
  72. ' and la.`aid` = pa.`id`';
  73. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditConst.status.checking, times];
  74. return await this.db.queryOne(sql, sqlParam);
  75. }
  76. /**
  77. * 获取 最新审核顺序
  78. *
  79. * @param {Number} stageId - 期id
  80. * @param {Number} times - 第几次审批
  81. * @returns {Promise<number>}
  82. */
  83. async getNewOrder(stageId, times = 1) {
  84. const sql = 'SELECT Max(??) As max_order FROM ?? Where `sid` = ? and `times` = ?';
  85. const sqlParam = ['order', this.tableName, stageId, times];
  86. const result = await this.db.queryOne(sql, sqlParam);
  87. return result && result.max_order ? result.max_order + 1 : 1;
  88. }
  89. /**
  90. * 新增审核人
  91. *
  92. * @param {Number} stageId - 期id
  93. * @param {Number} auditorId - 审核人id
  94. * @param {Number} times - 第几次审批
  95. * @returns {Promise<number>}
  96. */
  97. async addAuditor(stageId, auditorId, times = 1) {
  98. const newOrder = await this.getNewOrder(stageId, times);
  99. const data = {
  100. tid: this.ctx.tender.id,
  101. sid: stageId,
  102. aid: auditorId,
  103. times: times,
  104. order: newOrder,
  105. status: auditConst.status.uncheck,
  106. };
  107. const result = await this.db.insert(this.tableName, data);
  108. return result.effectRows = 1;
  109. }
  110. /**
  111. * 移除审核人时,同步其后审核人order
  112. * @param transaction - 事务
  113. * @param {Number} stageId - 标段id
  114. * @param {Number} auditorId - 审核人id
  115. * @param {Number} times - 第几次审批
  116. * @returns {Promise<*>}
  117. * @private
  118. */
  119. async _syncOrderByDelete(transaction, stageId, order, times) {
  120. this.initSqlBuilder();
  121. this.sqlBuilder.setAndWhere('sid', {
  122. value: stageId,
  123. operate: '='
  124. });
  125. this.sqlBuilder.setAndWhere('order', {
  126. value: order,
  127. operate: '>=',
  128. });
  129. this.sqlBuilder.setAndWhere('times', {
  130. value: times,
  131. operate: '=',
  132. });
  133. this.sqlBuilder.setUpdateData('order', {
  134. value: 1,
  135. selfOperate: '-',
  136. });
  137. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  138. const data = await transaction.query(sql, sqlParam);
  139. return data;
  140. }
  141. /**
  142. * 移除审核人
  143. *
  144. * @param {Number} stageId - 期id
  145. * @param {Number} auditorId - 审核人id
  146. * @param {Number} times - 第几次审批
  147. * @returns {Promise<boolean>}
  148. */
  149. async deleteAuditor(stageId, auditorId, times = 1) {
  150. const transaction = await this.db.beginTransaction();
  151. try {
  152. const condition = {sid: stageId, aid: auditorId, times: times};
  153. const auditor = await this.getDataByCondition(condition);
  154. if (!auditor) {
  155. throw '该审核人不存在';
  156. }
  157. await this._syncOrderByDelete(transaction, stageId, auditor.order, times);
  158. await transaction.delete(this.tableName, condition);
  159. await transaction.commit();
  160. } catch(err) {
  161. await transaction.rollback();
  162. throw err;
  163. }
  164. return true;
  165. }
  166. /**
  167. * 开始审批
  168. *
  169. * @param {Number} stageId - 期id
  170. * @param {Number} times - 第几次审批
  171. * @returns {Promise<boolean>}
  172. */
  173. async start(stageId, times = 1) {
  174. const audit = await this.getDataByCondition({sid: stageId, times: times, order: 1});
  175. if (!audit) {
  176. throw '请先选择审批人,再上报数据';
  177. }
  178. const transaction = await this.db.beginTransaction();
  179. try {
  180. await transaction.update(this.tableName, {id: audit.id, status: auditConst.status.checking, begin_time: new Date()});
  181. // 计算原报最终数据
  182. const yfPay = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
  183. // 复制一份下一审核人数据
  184. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, 1, transaction);
  185. // 更新期数据
  186. const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
  187. await transaction.update(this.ctx.service.stage.tableName, {
  188. id: stageId, status: auditConst.status.checking,
  189. contract_tp: tpData.contract_tp,
  190. qc_tp: tpData.qc_tp,
  191. yf_tp: yfPay.tp,
  192. cache_time_r: this.ctx.stage.cache_time_l,
  193. });
  194. // 添加短信通知-需要审批提醒功能
  195. const smsUser = await this.ctx.service.projectAccount.getDataById(audit.aid);
  196. if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  197. const smsType = JSON.parse(smsUser.sms_type);
  198. if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
  199. const tenderInfo = await this.ctx.service.tender.getDataById(audit.tid);
  200. const stageInfo = await this.ctx.service.stage.getDataById(audit.sid);
  201. const sms = new SMS(this.ctx);
  202. const tenderName = await sms.contentChange(tenderInfo.name);
  203. const content = '【纵横计量支付】' + tenderName + '第' + stageInfo.order + '期,需要您审批。';
  204. sms.send(smsUser.auth_mobile, content);
  205. }
  206. }
  207. // todo 更新标段tender状态 ?
  208. await transaction.commit();
  209. } catch(err) {
  210. await transaction.rollback();
  211. throw err;
  212. }
  213. return true;
  214. }
  215. async _checked(stageId, checkData, times) {
  216. const time = new Date();
  217. // 整理当前流程审核人状态更新
  218. const audit = await this.getDataByCondition({sid: stageId, times: times, status: auditConst.status.checking});
  219. if (!audit) {
  220. throw '审核数据错误';
  221. }
  222. const nextAudit = await this.getDataByCondition({sid: stageId, times: times, order: audit.order + 1});
  223. const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
  224. const transaction = await this.db.beginTransaction();
  225. try {
  226. console.log(checkData.opinion);
  227. await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});
  228. // 计算并合同支付最终数据
  229. const yfPay = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
  230. // 无下一审核人表示,审核结束
  231. if (nextAudit) {
  232. // 复制一份下一审核人数据
  233. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, nextAudit.order, transaction);
  234. // 流程至下一审批人
  235. await transaction.update(this.tableName, {id: nextAudit.id, status: auditConst.status.checking, begin_time: time});
  236. // 同步 期信息
  237. await transaction.update(this.ctx.service.stage.tableName, {
  238. id: stageId, status: auditConst.status.checking,
  239. contract_tp: tpData.contract_tp,
  240. qc_tp: tpData.qc_tp,
  241. yf_tp: yfPay.tp,
  242. cache_time_r: this.ctx.stage.cache_time_l,
  243. });
  244. // 添加短信通知-需要审批提醒功能
  245. const smsUser = await this.ctx.service.projectAccount.getDataById(nextAudit.aid);
  246. if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  247. const smsType = JSON.parse(smsUser.sms_type);
  248. if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
  249. const tenderInfo = await this.ctx.service.tender.getDataById(nextAudit.tid);
  250. const stageInfo = await this.ctx.service.stage.getDataById(nextAudit.sid);
  251. const sms = new SMS(this.ctx);
  252. const tenderName = await sms.contentChange(tenderInfo.name);
  253. const content = '【纵横计量支付】' + tenderName + '第' + stageInfo.order + '期,需要您审批。';
  254. sms.send(smsUser.auth_mobile, content);
  255. }
  256. }
  257. } else {
  258. // 本期结束
  259. // 生成截止本期数据 final数据
  260. console.time('generatePre');
  261. await this.ctx.service.stageBillsFinal.generateFinalData(transaction, this.ctx.tender, this.ctx.stage);
  262. await this.ctx.service.stagePosFinal.generateFinalData(transaction, this.ctx.tender, this.ctx.stage);
  263. console.timeEnd('generatePre');
  264. // 同步 期信息
  265. await transaction.update(this.ctx.service.stage.tableName, {
  266. id: stageId, status: checkData.checkType,
  267. contract_tp: tpData.contract_tp,
  268. qc_tp: tpData.qc_tp,
  269. yf_tp: yfPay.tp,
  270. cache_time_r: this.ctx.stage.cache_time_l,
  271. });
  272. // 添加短信通知-审批通过提醒功能
  273. const mobile_array = [];
  274. const stageInfo = await this.ctx.service.stage.getDataById(stageId);
  275. const auditList = await this.getAuditors(stageId, stageInfo.times);
  276. const smsUser1 = await this.ctx.service.projectAccount.getDataById(stageInfo.user_id);
  277. if (smsUser1.auth_mobile !== undefined && smsUser1.sms_type !== '' && smsUser1.sms_type !== null) {
  278. const smsType = JSON.parse(smsUser1.sms_type);
  279. if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
  280. mobile_array.push(smsUser1.auth_mobile);
  281. }
  282. }
  283. for (const user of auditList) {
  284. const smsUser = await this.ctx.service.projectAccount.getDataById(user.aid);
  285. if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
  286. const smsType = JSON.parse(smsUser.sms_type);
  287. if (mobile_array.indexOf(smsUser.auth_mobile) === -1 && smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
  288. mobile_array.push(smsUser.auth_mobile);
  289. }
  290. }
  291. }
  292. if (mobile_array.length > 0) {
  293. const tenderInfo = await this.ctx.service.tender.getDataById(stageInfo.tid);
  294. const sms = new SMS(this.ctx);
  295. const tenderName = await sms.contentChange(tenderInfo.name);
  296. const content = '【纵横计量支付】' + tenderName + '第' + stageInfo.order + '期,审批通过。';
  297. sms.send(mobile_array, content);
  298. }
  299. }
  300. await transaction.commit();
  301. } catch (err) {
  302. await transaction.rollback();
  303. throw err;
  304. }
  305. }
  306. async _checkNo(stageId, checkData, times) {
  307. const time = new Date();
  308. // 整理当前流程审核人状态更新
  309. const audit = await this.getDataByCondition({sid: stageId, times: times, status: auditConst.status.checking});
  310. if (!audit) {
  311. throw '审核数据错误';
  312. }
  313. const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
  314. const sql = 'SELECT `tid`, `sid`, `aid`, `order` FROM ?? WHERE `sid` = ? and `times` = ? GROUP BY `aid` ORDER BY `id` ASC';
  315. const sqlParam = [this.tableName, stageId, times];
  316. const auditors = await this.db.query(sql, sqlParam);
  317. let order = 1;
  318. for (const a of auditors) {
  319. a.times = times + 1;
  320. a.order = order;
  321. a.status = auditConst.status.uncheck;
  322. order++;
  323. }
  324. const transaction = await this.db.beginTransaction();
  325. try {
  326. await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});
  327. // 同步 期信息
  328. await transaction.update(this.ctx.service.stage.tableName, {
  329. id: stageId, status: checkData.checkType,
  330. contract_tp: tpData.contract_tp,
  331. qc_tp: tpData.qc_tp,
  332. times: times + 1,
  333. cache_time_r: this.ctx.stage.cache_time_l,
  334. });
  335. // 拷贝新一次审核流程列表
  336. await transaction.insert(this.tableName, auditors);
  337. // 计算该审批人最终数据
  338. await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
  339. // 复制一份最新数据给原报
  340. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times + 1, 0, transaction);
  341. // 添加短信通知-审批退回提醒功能
  342. const mobile_array = [];
  343. const stageInfo = await this.ctx.service.stage.getDataById(stageId);
  344. const auditList = await this.getAuditors(stageId, stageInfo.times);
  345. const smsUser1 = await this.ctx.service.projectAccount.getDataById(stageInfo.user_id);
  346. if (smsUser1.auth_mobile !== '' && smsUser1.auth_mobile !== undefined && smsUser1.sms_type !== '' && smsUser1.sms_type !== null) {
  347. const smsType = JSON.parse(smsUser1.sms_type);
  348. if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
  349. mobile_array.push(smsUser1.auth_mobile);
  350. }
  351. }
  352. for (const user of auditList) {
  353. const smsUser = await this.ctx.service.projectAccount.getDataById(user.aid);
  354. if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  355. const smsType = JSON.parse(smsUser.sms_type);
  356. if (mobile_array.indexOf(smsUser.auth_mobile) === -1 && smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
  357. mobile_array.push(smsUser.auth_mobile);
  358. }
  359. }
  360. }
  361. if (mobile_array.length > 0) {
  362. const tenderInfo = await this.ctx.service.tender.getDataById(stageInfo.tid);
  363. const sms = new SMS(this.ctx);
  364. const tenderName = await sms.contentChange(tenderInfo.name);
  365. const content = '【纵横计量支付】' + tenderName + '第' + stageInfo.order + '期,审批退回。';
  366. sms.send(mobile_array, content);
  367. }
  368. await transaction.commit();
  369. } catch (err) {
  370. await transaction.rollback();
  371. throw err;
  372. }
  373. }
  374. async _checkNoPre(stageId, checkData, times) {
  375. const time = new Date();
  376. // 整理当前流程审核人状态更新
  377. const audit = await this.getDataByCondition({sid: stageId, times: times, status: auditConst.status.checking});
  378. if (!audit || audit.order <= 1) {
  379. throw '审核数据错误';
  380. }
  381. // 添加重新审批后,不能用order-1,取groupby值里的上一个才对
  382. // const preAuditor = await this.getDataByCondition({sid: stageId, times: times, order: audit.order - 1});
  383. const auditors2 = await this.getAuditGroupByList(stageId, times);
  384. const auditorIndex = await auditors2.findIndex(function(item) {
  385. return item.aid === audit.aid;
  386. });
  387. const preAuditor = auditors2[auditorIndex - 1];
  388. const transaction = await this.db.beginTransaction();
  389. try {
  390. await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});
  391. // 顺移气候审核人流程顺序
  392. this.initSqlBuilder();
  393. this.sqlBuilder.setAndWhere('sid', { value: this.ctx.stage.id, operate: '=', });
  394. this.sqlBuilder.setAndWhere('order', { value: audit.order, operate: '>', });
  395. this.sqlBuilder.setUpdateData('order', { value: 2, selfOperate: '+', });
  396. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  397. const data = await transaction.query(sql, sqlParam);
  398. // 上一审批人,当前审批人 再次添加至流程
  399. const newAuditors = [];
  400. newAuditors.push({
  401. tid: audit.tid, sid: audit.sid, aid: preAuditor.aid,
  402. times: audit.times, order: audit.order + 1, status: auditConst.status.checking,
  403. begin_time: time,
  404. });
  405. newAuditors.push({
  406. tid: audit.tid, sid: audit.sid, aid: audit.aid,
  407. times: audit.times, order: audit.order + 2, status: auditConst.status.uncheck,
  408. });
  409. await transaction.insert(this.tableName, newAuditors);
  410. // 计算该审批人最终数据
  411. await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
  412. // 复制一份最新数据给下一人
  413. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 1, transaction);
  414. // 同步 期信息
  415. await transaction.update(this.ctx.service.stage.tableName, {
  416. id: stageId, status: checkData.checkType,
  417. cache_time_r: this.ctx.stage.cache_time_l,
  418. });
  419. // 添加短信通知-需要审批提醒功能
  420. const smsUser = await this.ctx.service.projectAccount.getDataById(preAuditor.aid);
  421. if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  422. const smsType = JSON.parse(smsUser.sms_type);
  423. if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
  424. const tenderInfo = await this.ctx.service.tender.getDataById(audit.tid);
  425. const stageInfo = await this.ctx.service.stage.getDataById(audit.sid);
  426. const sms = new SMS(this.ctx);
  427. const tenderName = await sms.contentChange(tenderInfo.name);
  428. const content = '【纵横计量支付】' + tenderName + '第' + stageInfo.order + '期,需要您审批。';
  429. sms.send(smsUser.auth_mobile, content);
  430. }
  431. }
  432. await transaction.commit();
  433. } catch(err) {
  434. await transaction.rollback();
  435. throw err;
  436. }
  437. }
  438. /**
  439. * 审批
  440. * @param {Number} stageId - 标段id
  441. * @param {auditConst.status.checked|auditConst.status.checkNo} checkType - 审批结果
  442. * @param {Number} times - 第几次审批
  443. * @returns {Promise<void>}
  444. */
  445. async check(stageId, checkData, times = 1) {
  446. if (checkData.checkType !== auditConst.status.checked && checkData.checkType !== auditConst.status.checkNo && checkData.checkType !== auditConst.status.checkNoPre) {
  447. throw '提交数据错误';
  448. }
  449. // // 整理当前流程审核人状态更新
  450. // const audit = await this.getDataByCondition({sid: stageId, times: times, status: auditConst.status.checking});
  451. // if (!audit) {
  452. // throw '审核数据错误';
  453. // }
  454. //const time = new Date();
  455. switch (checkData.checkType) {
  456. case auditConst.status.checked:
  457. await this._checked(stageId, checkData, times);
  458. break;
  459. case auditConst.status.checkNo:
  460. await this._checkNo(stageId, checkData, times);
  461. break;
  462. case auditConst.status.checkNoPre:
  463. await this._checkNoPre(stageId, checkData, times);
  464. break;
  465. default:
  466. throw '无效审批操作';
  467. }
  468. // const transaction = await this.db.beginTransaction();
  469. // try {
  470. // // 更新当前审核流程
  471. // await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});
  472. // if (checkData.checkType === auditConst.status.checked) { // 审批通过
  473. // const nextAudit = await this.getDataByCondition({sid: stageId, times: times, order: audit.order + 1});
  474. // // 无下一审核人表示,审核结束
  475. // if (nextAudit) {
  476. // // 计算该审批人最终数据
  477. // await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
  478. // // 复制一份下一审核人数据
  479. // await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, nextAudit.order, transaction);
  480. // // 流程至下一审批人
  481. // await transaction.update(this.tableName, {id: nextAudit.id, status: auditConst.status.checking, begin_time: time});
  482. // // 同步 期信息
  483. // const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
  484. // await transaction.update(this.ctx.service.stage.tableName, {
  485. // id: stageId, status: auditConst.status.checking,
  486. // contract_tp: tpData.contract_tp,
  487. // qc_tp: tpData.qc_tp,
  488. // });
  489. // } else {
  490. // // 本期结束
  491. // // 生成截止本期数据 final数据
  492. // await this.ctx.service.stageBillsFinal.generateFinalData(transaction, this.ctx.tender, this.ctx.stage);
  493. // await this.ctx.service.stagePosFinal.generateFinalData(transaction, this.ctx.tender, this.ctx.stage);
  494. // // 计算并合同支付最终数据
  495. // await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
  496. // // 同步 期信息
  497. // const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
  498. // await transaction.update(this.ctx.service.stage.tableName, {
  499. // id: stageId, status: checkData.checkType,
  500. // contract_tp: tpData.contract_tp,
  501. // qc_tp: tpData.qc_tp,
  502. // });
  503. // }
  504. // } else if (checkData.checkType === auditConst.status.checkNo) { // 审批退回 原报, times+1
  505. // // 同步 期信息
  506. // const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
  507. // await transaction.update(this.ctx.service.stage.tableName, {
  508. // id: stageId, status: checkData.checkType,
  509. // contract_tp: tpData.contract_tp,
  510. // qc_tp: tpData.qc_tp,
  511. // times: times + 1,
  512. // });
  513. // // 拷贝新一次审核流程列表
  514. // // const auditors = await this.getAllDataByCondition({
  515. // // where: {sid: stageId, times: times},
  516. // // columns: ['tid', 'sid', 'aid', 'order']
  517. // // });
  518. // const sql = 'SELECT `tid`, `sid`, `aid`, `order` FROM ?? WHERE `sid` = ? and `times` = ? GROUP BY `aid`';
  519. // const sqlParam = [this.tableName, stageId, times];
  520. // const auditors = await this.db.query(sql, sqlParam);
  521. // let order = 1;
  522. // for (const a of auditors) {
  523. // a.times = times + 1;
  524. // a.order = order;
  525. // a.status = auditConst.status.uncheck;
  526. // order++;
  527. // }
  528. // await transaction.insert(this.tableName, auditors);
  529. // // 计算该审批人最终数据
  530. // await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
  531. // // 复制一份最新数据给原报
  532. // await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times + 1, 0, transaction);
  533. // } else if (checkData.checkType === auditConst.status.checkNoPre) { // 审批退回 上一审批人
  534. // // 同步 期信息
  535. // const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
  536. // await transaction.update(this.ctx.service.stage.tableName, {
  537. // id: stageId, status: checkData.checkType,
  538. // contract_tp: tpData.contract_tp,
  539. // qc_tp: tpData.qc_tp,
  540. // });
  541. // // 将当前审批人 与 上一审批人再次添加至流程,顺移其后审批人流程顺序
  542. // if (audit.order > 1) {
  543. // // 顺移气候审核人流程顺序
  544. // this.initSqlBuilder();
  545. // this.sqlBuilder.setAndWhere('sid', { value: this.ctx.stage.id, operate: '=', });
  546. // this.sqlBuilder.setAndWhere('order', { value: audit.order, operate: '>', });
  547. // this.sqlBuilder.setUpdateData('order', { value: 2, selfOperate: '+', });
  548. // const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  549. // const data = await transaction.query(sql, sqlParam);
  550. //
  551. // // 上一审批人,当前审批人 再次添加至流程
  552. // const preAuditor = await this.getDataByCondition({sid: stageId, times: times, order: audit.order - 1});
  553. // const newAuditors = [];
  554. // newAuditors.push({
  555. // tid: preAuditor.tid, sid: preAuditor.sid, aid: preAuditor.aid,
  556. // times: preAuditor.times, order: preAuditor.order + 2, status: auditConst.status.checking,
  557. // begin_time: time,
  558. // });
  559. // newAuditors.push({
  560. // tid: audit.tid, sid: audit.sid, aid: audit.aid,
  561. // times: audit.times, order: audit.order + 2, status: auditConst.status.uncheck
  562. // });
  563. // await transaction.insert(this.tableName, newAuditors);
  564. //
  565. // // 计算该审批人最终数据
  566. // await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
  567. // // 复制一份最新数据给上一人
  568. // await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 1, transaction);
  569. // } else {
  570. // throw '审核数据错误';
  571. // }
  572. // } else {
  573. // throw '无效审批操作';
  574. // }
  575. //
  576. // await transaction.commit();
  577. // } catch (err) {
  578. // await transaction.rollback();
  579. // throw err;
  580. // }
  581. }
  582. /**
  583. * 审批
  584. * @param {Number} stageId - 标段id
  585. * @param {Number} times - 第几次审批
  586. * @returns {Promise<void>}
  587. */
  588. async checkAgain(stageId, times = 1) {
  589. const time = new Date();
  590. // 整理当前流程审核人状态更新
  591. const audit = (await this.getAllDataByCondition({ where: { sid: stageId, times }, orders: [['order', 'desc']], limit: 1, offset: 0 }))[0];
  592. if (!audit || audit.order < 1) {
  593. throw '审核数据错误';
  594. }
  595. const transaction = await this.db.beginTransaction();
  596. try {
  597. // 当前审批人2次添加至流程中
  598. const newAuditors = [];
  599. newAuditors.push({
  600. tid: audit.tid, sid: audit.sid, aid: audit.aid,
  601. times: audit.times, order: audit.order + 1, status: auditConst.status.checkAgain,
  602. begin_time: time, end_time: time, opinion: '',
  603. });
  604. newAuditors.push({
  605. tid: audit.tid, sid: audit.sid, aid: audit.aid,
  606. times: audit.times, order: audit.order + 2, status: auditConst.status.checking,
  607. begin_time: time,
  608. });
  609. await transaction.insert(this.tableName, newAuditors);
  610. // 复制一份最新数据给下一人
  611. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 2, transaction);
  612. // 本期结束
  613. // 生成截止本期数据 final数据
  614. await this.ctx.service.stageBillsFinal.delGenerateFinalData(transaction, this.ctx.tender, this.ctx.stage);
  615. await this.ctx.service.stagePosFinal.delGenerateFinalData(transaction, this.ctx.tender, this.ctx.stage);
  616. // 同步 期信息
  617. await transaction.update(this.ctx.service.stage.tableName, {
  618. id: stageId, status: auditConst.status.checking,
  619. cache_time_r: this.ctx.stage.cache_time_l,
  620. });
  621. // 添加短信通知-需要审批提醒功能
  622. const smsUser = await this.ctx.service.projectAccount.getDataById(audit.aid);
  623. if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  624. const smsType = JSON.parse(smsUser.sms_type);
  625. if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
  626. const tenderInfo = await this.ctx.service.tender.getDataById(audit.tid);
  627. const stageInfo = await this.ctx.service.stage.getDataById(audit.sid);
  628. const sms = new SMS(this.ctx);
  629. const tenderName = await sms.contentChange(tenderInfo.name);
  630. const content = '【纵横计量支付】' + tenderName + '第' + stageInfo.order + '期,需要您审批。';
  631. sms.send(smsUser.auth_mobile, content);
  632. }
  633. }
  634. await transaction.commit();
  635. } catch (err) {
  636. await transaction.rollback();
  637. throw err;
  638. }
  639. }
  640. /**
  641. * 获取审核人需要审核的期列表
  642. *
  643. * @param auditorId
  644. * @returns {Promise<*>}
  645. */
  646. async getAuditStage(auditorId) {
  647. const sql = 'SELECT sa.`aid`, sa.`times`, sa.`order`, sa.`begin_time`, sa.`end_time`, sa.`tid`, sa.`sid`,' +
  648. ' s.`order` As `sorder`, s.`status` As `sstatus`,' +
  649. ' t.`name`, t.`project_id`, t.`type`, t.`user_id` ' +
  650. ' FROM ?? AS sa, ?? AS s, ?? As t ' +
  651. ' WHERE ((sa.`aid` = ? and sa.`status` = ?) OR (s.`user_id` = ? and sa.`status` = ? and s.`status` = ? and sa.`times` = (s.`times`-1)))' +
  652. ' and sa.`sid` = s.`id` and sa.`tid` = t.`id`';
  653. const sqlParam = [this.tableName, this.ctx.service.stage.tableName, this.ctx.service.tender.tableName, auditorId, auditConst.status.checking, auditorId, auditConst.status.checkNo, auditConst.status.checkNo];
  654. return await this.db.query(sql, sqlParam);
  655. }
  656. /**
  657. * 获取 某时间后 审批进度 更新的期
  658. * @param {Number} pid - 查询标段
  659. * @param {Number} uid - 查询人
  660. * @param {Date} time - 查询时间
  661. * @returns {Promise<*>}
  662. */
  663. async getNoticeStage(pid, uid, time) {
  664. const sql = 'SELECT t.`name`, t.`project_id`, t.`type`, t.`user_id`, ' +
  665. ' s.`order` As `s_order`, s.`status` As `s_status`, ' +
  666. ' sa.`aid`, sa.`times`, sa.`order`, sa.`end_time`, sa.`tid`, sa.`sid`, sa.`status`, ' +
  667. ' pa.`name` As `su_name`, pa.role As `su_role`, pa.company As `su_company`' +
  668. ' FROM ?? As t' +
  669. ' LEFT JOIN ?? As s On t.`id` = s.`tid`' +
  670. ' LEFT JOIN ?? As sa ON s.`id` = sa.`sid`' +
  671. ' LEFT JOIN ?? As pa ON sa.`aid` = pa.`id`' +
  672. ' WHERE sa.`aid` <> ? and sa.`end_time` > ? and t.`project_id` = ?' +
  673. ' GROUP By t.`id`' +
  674. ' ORDER By sa.`end_time`';
  675. const sqlParam = [this.ctx.service.tender.tableName, this.ctx.service.stage.tableName, this.tableName,
  676. this.ctx.service.projectAccount.tableName, uid, time, pid];
  677. return await this.db.query(sql, sqlParam);
  678. }
  679. /**
  680. * 获取审核人流程列表
  681. *
  682. * @param auditorId
  683. * @returns {Promise<*>}
  684. */
  685. async getAuditGroupByList(stageId, times) {
  686. const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`aid`, la.`order` ' +
  687. 'FROM ?? AS la, ?? AS pa ' +
  688. 'WHERE la.`sid` = ? and la.`times` = ? and la.`aid` = pa.`id` GROUP BY la.`aid` ORDER BY la.`order`';
  689. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, times];
  690. return await this.db.query(sql, sqlParam);
  691. // const sql = 'SELECT `tid`, `sid`, `aid`, `order` FROM ?? WHERE `sid` = ? and `times` = ? GROUP BY `aid`';
  692. // const sqlParam = [this.tableName, stageId, times];
  693. // return await this.db.query(sql, sqlParam);
  694. }
  695. /**
  696. * 复制上一期的审批人列表给最新一期
  697. *
  698. * @param transaction - 新增一期的事务
  699. * @param {Object} preStage - 上一期
  700. * @param {Object} newStage - 最新一期
  701. * @returns {Promise<*>}
  702. */
  703. async copyPreStageAuditors(transaction, preStage, newStage) {
  704. const auditors = await this.getAuditGroupByList(preStage.id, preStage.times);
  705. const newAuditors = [];
  706. for (const a of auditors) {
  707. const na = {
  708. tid: preStage.tid,
  709. sid: newStage.id,
  710. aid: a.aid,
  711. times: newStage.times,
  712. order: newAuditors.length + 1,
  713. status: auditConst.status.uncheck
  714. };
  715. newAuditors.push(na);
  716. }
  717. const result = await transaction.insert(this.tableName, newAuditors);
  718. return result.effectRows = auditors.length;
  719. }
  720. /**
  721. * 移除审核人
  722. *
  723. * @param {Number} stageId - 期id
  724. * @param {Number} status - 期状态
  725. * @param {Number} status - 期次数
  726. * @return {Promise<boolean>}
  727. */
  728. async getAuditorByStatus(stageId, status, times = 1) {
  729. let auditor = null;
  730. let sql = '';
  731. let sqlParam = '';
  732. switch (status) {
  733. case auditConst.status.checking :
  734. case auditConst.status.checked :
  735. case auditConst.status.checkNoPre :
  736. sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`aid`, la.`order` ' +
  737. 'FROM ?? AS la, ?? AS pa ' +
  738. 'WHERE la.`sid` = ? and la.`status` = ? and la.`aid` = pa.`id` order by la.`times` desc, la.`id` desc';
  739. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, status];
  740. auditor = await this.db.queryOne(sql, sqlParam);
  741. break;
  742. case auditConst.status.checkNo :
  743. sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`aid`, la.`order` ' +
  744. 'FROM ?? AS la, ?? AS pa ' +
  745. 'WHERE la.`sid` = ? and la.`status` = ? and la.`times` = ? and la.`aid` = pa.`id` order by la.`times` desc, la.`id` desc';
  746. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditConst.status.checkNo, parseInt(times) - 1];
  747. auditor = await this.db.queryOne(sql, sqlParam);
  748. break;
  749. case auditConst.status.uncheck :
  750. default:break;
  751. }
  752. return auditor;
  753. }
  754. /**
  755. * 取某一期已批准审核信息(报表用)
  756. *
  757. * @param {Number} stageId - 期id
  758. * @param {Number} times - 期次数
  759. * @return {Promise<boolean>}
  760. */
  761. async getStageAudit(stageId, times = 1) {
  762. const sql = 'SELECT a1.aid, a1.end_time, a1.opinion ' +
  763. 'FROM ?? AS a1 ' +
  764. 'WHERE a1.`sid` = ? and a1.`status` = 3 and a1.`times` = ?';
  765. const sqlParam = [this.tableName, stageId, times];
  766. const rst = await this.db.query(sql, sqlParam);
  767. return rst;
  768. }
  769. }
  770. return StageAudit;
  771. };