financial_pay_audit.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date 2019/2/27
  7. * @version
  8. */
  9. const auditConst = require('../const/audit').financial;
  10. const auditType = require('../const/audit').auditType;
  11. const shenpiConst = require('../const/shenpi');
  12. const pushType = require('../const/audit').pushType;
  13. module.exports = app => {
  14. class FinancialPayAudit extends app.BaseService {
  15. /**
  16. * 构造函数
  17. *
  18. * @param {Object} ctx - egg全局变量
  19. * @return {void}
  20. */
  21. constructor(ctx) {
  22. super(ctx);
  23. this.tableName = 'financial_pay_audit';
  24. }
  25. async getAuditorGroup(fpId, times) {
  26. const auditors = await this.getAuditors(fpId, times); // 全部参与的审批人
  27. return this.ctx.helper.groupAuditors(auditors, 'order', true);
  28. }
  29. async getUserGroup(fpId, times) {
  30. const group = await this.getAuditorGroup(fpId, times);
  31. const sql =
  32. 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As fpid, 0 As `order`, 1 As audit_type, 0 As audit_order' +
  33. ' FROM ' + this.ctx.service.financialPay.tableName + ' As s' +
  34. ' LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
  35. ' ON s.uid = pa.id' +
  36. ' WHERE s.id = ?';
  37. const sqlParam = [times, fpId, fpId];
  38. const user = await this.db.queryOne(sql, sqlParam);
  39. user.audit_order = 0;
  40. group.unshift([ user ]);
  41. return group;
  42. }
  43. async getUniqUserGroup(fpId, times) {
  44. const group = await this.getAuditorGroup(fpId, times);
  45. const sql =
  46. 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As fpid, 0 As `order`, 1 As audit_type, 0 As audit_order' +
  47. ' FROM ' + this.ctx.service.financialPay.tableName + ' As s' +
  48. ' LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
  49. ' ON s.uid = pa.id' +
  50. ' WHERE s.id = ?';
  51. const sqlParam = [times, fpId, fpId];
  52. const user = await this.db.queryOne(sql, sqlParam);
  53. user.audit_order = 0;
  54. group.unshift([ user ]);
  55. return this.ctx.helper.groupAuditorsUniq(group);
  56. }
  57. async getAuditorHistory(fpId, times, reverse = false) {
  58. const history = [];
  59. if (times >= 1) {
  60. for (let i = 1; i <= times; i++) {
  61. const auditors = await this.getAuditors(fpId, i);
  62. const group = this.ctx.helper.groupAuditors(auditors);
  63. const historyGroup = [];
  64. // 找出group里audit_order最大值
  65. const max_info = group.length > 0 ? this._.maxBy(group, function(item) {
  66. return item && item[0] && item[0].audit_order;
  67. }) : null;
  68. const max_order = max_info ? max_info[0].audit_order : -1;
  69. for (const g of group) {
  70. const his = {
  71. beginYear: '', beginDate: '', beginTime: '', endYear: '', endDate: '', endTime: '', begin_time: null, end_time: null,
  72. audit_type: g[0].audit_type, audit_order: g[0].audit_order,
  73. auditors: g,
  74. };
  75. if (his.audit_type === auditType.key.common) {
  76. his.name = g[0].name;
  77. } else {
  78. his.name = this.ctx.helper.transFormToChinese(his.audit_order) + '审';
  79. }
  80. his.is_final = his.audit_order === max_order;
  81. if (g[0].begin_time) {
  82. his.begin_time = g[0].begin_time;
  83. const beginTime = this.ctx.moment(g[0].begin_time);
  84. his.beginYear = beginTime.format('YYYY');
  85. his.beginDate = beginTime.format('MM-DD');
  86. his.beginTime = beginTime.format('HH:mm:ss');
  87. }
  88. let end_time;
  89. g.forEach(x => {
  90. if (x.status === auditConst.status.checkSkip) return;
  91. if (!his.status || x.status === auditConst.status.checking) his.status = x.status;
  92. if (x.end_time && (!end_time || x.end_time > end_time)) {
  93. end_time = x.end_time;
  94. if (his.status !== auditConst.status.checking) his.status = x.status;
  95. }
  96. });
  97. if (end_time) {
  98. his.end_time = end_time;
  99. const endTime = this.ctx.moment(end_time);
  100. his.endYear = endTime.format('YYYY');
  101. his.endDate = endTime.format('MM-DD');
  102. his.endTime = endTime.format('HH:mm:ss');
  103. }
  104. historyGroup.push(his);
  105. }
  106. if (reverse) {
  107. history.push(historyGroup.reverse());
  108. } else {
  109. history.push(historyGroup);
  110. }
  111. }
  112. }
  113. return history;
  114. }
  115. async getUniqAuditor(fpId, times) {
  116. const auditors = await this.getAuditors(fpId, times); // 全部参与的审批人
  117. const result = [];
  118. auditors.forEach(x => {
  119. if (result.findIndex(r => { return x.aid === r.aid && x.audit_order === r.audit_order; }) < 0) {
  120. result.push(x);
  121. }
  122. });
  123. return result;
  124. }
  125. /**
  126. * 获取 审核列表信息
  127. *
  128. * @param {Number} cpId - 变更立项id
  129. * @param {Number} times - 第几次审批
  130. * @return {Promise<*>}
  131. */
  132. async getAuditors(fpId, times = 1, order_sort = 'asc', noYB = false) {
  133. // 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` ' +
  134. // 'FROM ?? AS la, ?? AS pa, (SELECT t1.`aid`,(@i:=@i+1) as `sort` FROM (SELECT t.`aid`, t.`order` FROM (select `aid`, `order` from ?? WHERE `cpid` = ? AND `times` = ? ORDER BY `order` LIMIT 200) t GROUP BY t.`aid` ORDER BY t.`order`) t1, (select @i:=0) as it) as g ' +
  135. // 'WHERE la.`cpid` = ? and la.`times` = ? and la.`aid` = pa.`id` and g.`aid` = la.`aid` order by la.`order`';
  136. // const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.tableName, cpId, times, cpId, times];
  137. // const result = await this.db.query(sql, sqlParam);
  138. // const sql2 = 'SELECT COUNT(a.`aid`) as num FROM (SELECT `aid` FROM ?? WHERE `cpid` = ? AND `times` = ? GROUP BY `aid`) as a';
  139. // const sqlParam2 = [this.tableName, cpId, times];
  140. // const count = await this.db.queryOne(sql2, sqlParam2);
  141. // for (const i in result) {
  142. // result[i].max_sort = count.num;
  143. // }
  144. const ybSql = noYB ? ' AND la.audit_order != 0' : '';
  145. const sql = 'SELECT la.id, la.aid, la.times, la.order, la.status, la.opinion, la.begin_time, la.end_time, la.audit_type, la.audit_order,' +
  146. ' pa.name, pa.company, pa.role, pa.mobile, pa.telephone' +
  147. ` FROM ${this.tableName} la LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON la.aid = pa.id` +
  148. ' WHERE la.fpid = ? AND la.times = ?' + ybSql +
  149. ' ORDER BY la.order ' + order_sort;
  150. const sqlParam = [fpId, times];
  151. const result = await this.db.query(sql, sqlParam);
  152. const max_sort = this._.max(result.map(x => { return x.audit_order; }));
  153. for (const i in result) {
  154. result[i].max_sort = max_sort;
  155. }
  156. return result;
  157. }
  158. async getCurAuditors(fpId, times = 1) {
  159. const sql =
  160. 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, la.audit_type, la.audit_order ' +
  161. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
  162. ' WHERE la.`fpid` = ? and la.`status` = ? and la.`times` = ?';
  163. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, fpId, auditConst.status.checking, times];
  164. return await this.db.query(sql, sqlParam);
  165. }
  166. /**
  167. * 获取审核人流程列表
  168. *
  169. * @param auditorId
  170. * @return {Promise<*>}
  171. */
  172. async getAuditGroupByList(fpId, times, transaction = false) {
  173. const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`fpid`, la.`aid`, la.`order`, la.`status`, la.audit_type, la.audit_order ' +
  174. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
  175. ' WHERE la.`fpid` = ? and la.`times` = ? GROUP BY la.`aid` ORDER BY la.`order`';
  176. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, fpId, times];
  177. return transaction !== false ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);
  178. }
  179. async getAuditorsByStatus(fpId, status, times = 1) {
  180. let auditor = [];
  181. let sql = '';
  182. let sqlParam = '';
  183. let cur;
  184. switch (status) {
  185. case auditConst.status.checking :
  186. case auditConst.status.checked :
  187. case auditConst.status.cancelRevise :
  188. cur = await this.db.queryOne('SELECT * From ?? where fpid = ? AND times = ? AND status = ? ORDER By times DESC, `order` DESC', [this.tableName, fpId, times, status]);
  189. if (!cur) return [];
  190. sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`fpid`, la.`order`, la.`status`, la.`audit_order`, la.`audit_type` ' +
  191. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
  192. ' WHERE la.`fpid` = ? and la.`order` = ? and times = ?';
  193. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, fpId, cur.order, times];
  194. auditor = await this.db.query(sql, sqlParam);
  195. break;
  196. case auditConst.status.checkNo :
  197. cur = await this.db.queryOne('SELECT * From ?? where fpid = ? AND times = ? AND status = ? ORDER By times DESC, `order` DESC', [this.tableName, fpId, parseInt(times) - 1, status]);
  198. if (!cur) return [];
  199. sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`fpid`, la.`order`, la.`status`, la.`audit_order`, la.`audit_type` ' +
  200. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
  201. ' WHERE la.`fpid` = ? and la.`order` = ? and la.`times` = ?';
  202. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, fpId, cur.order, parseInt(times) - 1];
  203. auditor = await this.db.query(sql, sqlParam);
  204. break;
  205. case auditConst.status.uncheck:
  206. default:
  207. break;
  208. }
  209. return auditor;
  210. }
  211. /**
  212. * 获取审核人流程列表(包括原报)
  213. * @param {Number} materialId 调差id
  214. * @param {Number} times 审核次数
  215. * @return {Promise<Array>} 查询结果集(包括原报)
  216. */
  217. async getAuditorsWithOwner(fpId, times = 1) {
  218. const result = await this.getAuditGroupByList(fpId, times);
  219. const sql =
  220. 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As fpid, 0 As `order`' +
  221. ' FROM ' +
  222. this.ctx.service.financialPay.tableName +
  223. ' As s' +
  224. ' LEFT JOIN ' +
  225. this.ctx.service.projectAccount.tableName +
  226. ' As pa' +
  227. ' ON s.uid = pa.id' +
  228. ' WHERE s.id = ?';
  229. const sqlParam = [times, fpId, fpId];
  230. const user = await this.db.queryOne(sql, sqlParam);
  231. result.unshift(user);
  232. return result;
  233. }
  234. async updateNewAuditList(financialPay, newList) {
  235. const transaction = await this.db.beginTransaction();
  236. try {
  237. await this.updateNewAuditors(financialPay, newList, transaction);
  238. await transaction.commit();
  239. } catch (err) {
  240. await transaction.rollback();
  241. throw err;
  242. }
  243. }
  244. async updateNewAuditors(financialPay, newList, transaction) {
  245. // 先删除旧的审批流,再添加新的
  246. await transaction.delete(this.tableName, { fpid: financialPay.id, times: financialPay.times });
  247. const newAuditors = [];
  248. for (const auditor of newList) {
  249. newAuditors.push({
  250. spid: financialPay.spid, tid: financialPay.tid, fpid: financialPay.id, aid: auditor.audit_id,
  251. times: financialPay.times, order: auditor.audit_order, status: auditConst.status.uncheck,
  252. audit_type: auditor.audit_type, audit_order: auditor.audit_order,
  253. });
  254. }
  255. if (newAuditors.length > 0) await transaction.insert(this.tableName, newAuditors);
  256. }
  257. /**
  258. * 开始审批
  259. * @param {Number} cpId - 方案id
  260. * @param {Number} times - 第几次审批
  261. * @return {Promise<boolean>}
  262. */
  263. async start(fpId, times = 1) {
  264. const audits = await this.getAllDataByCondition({ where: { fpid: fpId, times, order: 1 } });
  265. if (audits.length === 0) {
  266. throw '请联系管理员添加审批人';
  267. }
  268. const transaction = await this.db.beginTransaction();
  269. try {
  270. const begin_time = new Date();
  271. const updateData = audits.map(x => {
  272. return {id: x.id, status: auditConst.status.checking, begin_time};
  273. });
  274. await transaction.updateRows(this.tableName, updateData);
  275. await transaction.update(this.ctx.service.financialPay.tableName, {
  276. id: fpId, status: auditConst.status.checking,
  277. // entities: await this.ctx.service.financialPayContract.getEntities(fpId),
  278. });
  279. // todo 更新标段tender状态 ?
  280. await transaction.commit();
  281. } catch (err) {
  282. await transaction.rollback();
  283. throw err;
  284. }
  285. return true;
  286. }
  287. /**
  288. * 审批
  289. * @param {Object} fp - 资金支付信息
  290. * @param {auditConst.status.checked|auditConst.status.checkNo} checkType - 审批结果
  291. * @return {Promise<void>}
  292. */
  293. async check(fp, checkData) {
  294. if (checkData.checkType !== auditConst.status.checked && checkData.checkType !== auditConst.status.checkNo) {
  295. throw '提交数据错误';
  296. }
  297. const pid = this.ctx.session.sessionProject.id;
  298. switch (checkData.checkType) {
  299. case auditConst.status.checked:
  300. await this._checked(pid, fp, checkData);
  301. break;
  302. case auditConst.status.checkNo:
  303. await this._checkNo(pid, fp, checkData);
  304. break;
  305. default:
  306. throw '无效审批操作';
  307. }
  308. }
  309. async _checked(pid, fp, checkData) {
  310. const accountId = this.ctx.session.sessionUser.accountId;
  311. const time = new Date();
  312. // 整理当前流程审核人状态更新
  313. const audits = fp.curAuditors;
  314. if (audits.length === 0) throw '审核数据错误';
  315. const selfAudit = audits.find(x => { return x.aid === accountId; });
  316. if (!selfAudit) throw '当前标段您无权审批';
  317. // const flowAudits = await this.getAllDataByCondition({ where: { cpid: cpId, times, order: selfAudit.order } });
  318. const nextAudits = fp.nextAuditors;
  319. const transaction = await this.db.beginTransaction();
  320. try {
  321. // 更新本人审批状态
  322. await transaction.update(this.tableName, {
  323. id: selfAudit.id,
  324. status: checkData.checkType,
  325. opinion: checkData.opinion,
  326. end_time: time,
  327. });
  328. // await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, selfAudit.id);
  329. // 获取推送必要信息
  330. const noticeContent = await this.getNoticeContent(pid, fp.spid, fp.id, selfAudit.aid, checkData.opinion);
  331. // 添加推送
  332. const records = [];
  333. const auditors = await this.getAuditorsWithOwner(fp.id, fp.times);
  334. auditors.forEach(audit => {
  335. records.push({ pid, spid: fp.spid, type: pushType.financial, uid: audit.aid, status: auditConst.status.checked, content: noticeContent });
  336. });
  337. await transaction.insert('zh_notice', records);
  338. if (audits.length === 1 || selfAudit.audit_type !== auditType.key.and) {
  339. // 或签更新他人审批状态
  340. if (selfAudit.audit_type === auditType.key.or) {
  341. const updateOther = [];
  342. for (const audit of audits) {
  343. if (audit.aid === selfAudit.aid) continue;
  344. updateOther.push({
  345. id: audit.id,
  346. status: auditConst.status.checkSkip,
  347. opinion: '',
  348. end_time: time,
  349. });
  350. // await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, audit.id);
  351. }
  352. if (updateOther.length > 0) transaction.updateRows(this.tableName, updateOther);
  353. }
  354. // 无下一审核人表示,审核结束
  355. if (nextAudits.length > 0) {
  356. // 流程至下一审批人
  357. const updateData = nextAudits.map(x => { return { id: x.id, status: auditConst.status.checking, begin_time: time }; });
  358. await transaction.updateRows(this.tableName, updateData);
  359. // 同步 期信息
  360. await transaction.update(this.ctx.service.financialPay.tableName, {
  361. id: fp.id, status: auditConst.status.checking,
  362. });
  363. } else {
  364. // 本期结束
  365. // 生成截止本期数据 final数据
  366. // 同步 期信息
  367. await transaction.update(this.ctx.service.financialPay.tableName, {
  368. id: fp.id, status: checkData.checkType,
  369. entities: await this.ctx.service.financialPayContract.getEntities(fp.id),
  370. });
  371. // 合同支付生成对应的支付信息
  372. const pays = await this.ctx.service.financialPayContract.getAllDataByCondition({ where: { fpid: fp.id } });
  373. const contractPays = this._.filter(pays, x => { return x.cid !== null; });
  374. if (contractPays.length > 0) {
  375. await this.ctx.service.contractPay.createContractPays(transaction, fp.id, fp.uid, time, contractPays);
  376. }
  377. }
  378. } else {
  379. // 同步 期信息
  380. await transaction.update(this.ctx.service.financialPay.tableName, {
  381. id: fp.id,
  382. status: auditConst.status.checking,
  383. });
  384. }
  385. await transaction.commit();
  386. } catch (err) {
  387. await transaction.rollback();
  388. throw err;
  389. }
  390. }
  391. async _checkNo(pid, fp, checkData) {
  392. const accountId = this.ctx.session.sessionUser.accountId;
  393. const time = new Date();
  394. const audits = fp.curAuditors;
  395. if (!audits) throw '审核数据错误';
  396. const selfAudit = audits.find(x => { return x.aid === accountId; });
  397. if (!selfAudit) throw '当前标段您无权审批';
  398. const auditors = await this.getUniqAuditor(fp.id, fp.times); // 全部参与的审批人
  399. const newAuditors = auditors.map(x => {
  400. return {
  401. aid: x.aid, spid: fp.spid, tid: fp.tid, fpid: fp.id,
  402. times: fp.times + 1, order: x.audit_order, status: auditConst.status.uncheck,
  403. audit_type: x.audit_type, audit_order: x.audit_order,
  404. };
  405. });
  406. const transaction = await this.db.beginTransaction();
  407. try {
  408. const updateData = [];
  409. audits.forEach(x => {
  410. updateData.push({
  411. id: x.id,
  412. status: x.aid === selfAudit.aid ? checkData.checkType : auditConst.status.checkSkip,
  413. opinion: x.aid === selfAudit.aid ? checkData.opinion : '',
  414. end_time: x.aid === selfAudit.aid ? time : null,
  415. });
  416. });
  417. await transaction.updateRows(this.tableName, updateData);
  418. // 添加到消息推送表
  419. const noticeContent = await this.getNoticeContent(pid, fp.spid, fp.id, selfAudit.aid, checkData.opinion);
  420. const records = [{ pid, spid: fp.spid, type: pushType.financial, uid: fp.uid, status: auditConst.status.checkNo, content: noticeContent }];
  421. auditors.forEach(audit => {
  422. records.push({ pid, spid: fp.spid, type: pushType.financial, uid: audit.aid, status: auditConst.status.checkNo, content: noticeContent });
  423. });
  424. await transaction.insert(this.ctx.service.noticePush.tableName, records);
  425. // 同步期信息
  426. await transaction.update(this.ctx.service.financialPay.tableName, {
  427. id: fp.id, status: checkData.checkType,
  428. times: fp.times + 1,
  429. entities: '',
  430. });
  431. // 拷贝新一次审核流程列表
  432. await transaction.insert(this.tableName, newAuditors);
  433. await transaction.commit();
  434. } catch (err) {
  435. await transaction.rollback();
  436. throw err;
  437. }
  438. }
  439. /**
  440. * 重新审批变更申请
  441. * @param { string } cid - 查询的清单
  442. * @return {Promise<*>} - 可用的变更令列表
  443. */
  444. async checkAgain(fp) {
  445. const accountId = this.ctx.session.sessionUser.accountId;
  446. // 初始化事务
  447. const time = new Date();
  448. const transaction = await this.db.beginTransaction();
  449. let result = false;
  450. try {
  451. const noYbAuditors = fp.auditors.filter(x => { return x.audit_order !== 0; });
  452. const noYbMaxOrder = noYbAuditors[noYbAuditors.length - 1].order;
  453. const maxOrder = fp.auditors[fp.auditors.length - 1].order;
  454. const audits = fp.auditors.filter(x => { return x.order === noYbMaxOrder; });
  455. if (!audits || audits.length === 0 || maxOrder < 1) throw '审核数据错误';
  456. const selfAudit = audits.find(x => { return x.aid === accountId; });
  457. if (!selfAudit) throw '当前标段您无权审批';
  458. // 当前审批人2次添加至流程中
  459. const checkAgainAuditors = [];
  460. audits.forEach(x => {
  461. checkAgainAuditors.push({
  462. spid: fp.spid, tid: fp.tid, fpid: fp.id, aid: x.aid,
  463. times: x.times, order: maxOrder + 1,
  464. status: !selfAudit || x.aid === selfAudit.aid ? auditConst.status.checkAgain : auditConst.status.checkSkip,
  465. begin_time: time, end_time: time, opinion: '',
  466. audit_type: x.audit_type, audit_order: x.audit_order,
  467. });
  468. });
  469. const checkingAuditors = [];
  470. audits.forEach(x => {
  471. checkingAuditors.push({
  472. spid: fp.spid, tid: fp.tid, fpid: fp.id, aid: x.aid,
  473. times: x.times, order: maxOrder + 2,
  474. status: auditConst.status.checking,
  475. begin_time: time,
  476. audit_type: x.audit_type, audit_order: x.audit_order,
  477. });
  478. });
  479. await transaction.insert(this.tableName, checkAgainAuditors);
  480. const checkingAuditors_result = await transaction.insert(this.tableName, checkingAuditors);
  481. // 获取刚批量添加的所有list
  482. // for (let j = 0; j < checkingAuditors.length; j++) {
  483. // checkingAuditors[j].id = checkingAuditors_result.insertId + j;
  484. // }
  485. // 设置审批中
  486. await transaction.update(this.ctx.service.financialPay.tableName, {
  487. id: fp.id,
  488. status: auditConst.status.checking,
  489. entities: '',
  490. final_auditor_str: '',
  491. });
  492. // 合同支付生成对应的支付信息
  493. const pays = await this.ctx.service.financialPayContract.getAllDataByCondition({ where: { fpid: fp.id } });
  494. const contractPays = this._.filter(pays, x => { return x.cid !== null; });
  495. if (contractPays.length > 0) {
  496. await this.ctx.service.contractPay.removeContractPays(transaction, fp.id, contractPays);
  497. }
  498. await transaction.commit();
  499. result = true;
  500. } catch (error) {
  501. await transaction.rollback();
  502. result = false;
  503. }
  504. return result;
  505. }
  506. /**
  507. * 获取审核人需要审核的期列表
  508. *
  509. * @param auditorId
  510. * @return {Promise<*>}
  511. */
  512. async getAuditFinancial(auditorId, spid = '') {
  513. const spSql = spid ? ' and ma.`spid` = "' + spid + '"' : '';
  514. const sql = 'SELECT ma.`aid`, ma.`times`, ma.`order`, ma.`begin_time`, ma.`end_time`, ma.`spid`, ma.`fpid`,' +
  515. ' m.`status` As `fpstatus`, m.`code` As `fpcode`,' +
  516. ' sp.`name`, sp.`project_id` ' +
  517. ' FROM ?? AS ma LEFT JOIN ?? AS m ON ma.`fpid` = m.`id` LEFT JOIN ?? As sp ON ma.`spid` = sp.`id`' +
  518. ' WHERE ((ma.`aid` = ? and ma.`status` = ?) OR (m.`uid` = ? and ma.`status` = ? and m.`status` = ? and ma.`times` = (m.`times`-1)))' + spSql +
  519. ' ORDER BY ma.`begin_time` DESC';
  520. const sqlParam = [this.tableName, this.ctx.service.financialPay.tableName, this.ctx.service.subProject.tableName, auditorId, auditConst.status.checking, auditorId, auditConst.status.checkNo, auditConst.status.checkNo];
  521. const result = await this.db.query(sql, sqlParam);
  522. // 过滤result中存在重复sid的值, 保留最新的一条
  523. const filterResult = [];
  524. const fpidArr = [];
  525. for (const r of result) {
  526. if (fpidArr.indexOf(r.fpid) === -1) {
  527. filterResult.push(r);
  528. fpidArr.push(r.fpid);
  529. }
  530. }
  531. return filterResult;
  532. }
  533. /**
  534. * 获取审核人审核的次数
  535. *
  536. * @param auditorId
  537. * @return {Promise<*>}
  538. */
  539. async getCountByChecked(auditorId, spid = '') {
  540. if (spid) {
  541. return await this.db.count(this.tableName, { spid, aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
  542. }
  543. return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
  544. }
  545. /**
  546. * 获取最近一次审批结束时间
  547. *
  548. * @param auditorId
  549. * @return {Promise<*>}
  550. */
  551. async getLastEndTimeByChecked(auditorId, spid = '') {
  552. const spSql = spid ? ' and `spid` = "' + spid + '"' : '';
  553. const sql = 'SELECT `end_time` FROM ?? WHERE `aid` = ? ' +
  554. 'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ')' + spSql +
  555. ' ORDER BY `end_time` DESC';
  556. const sqlParam = [this.tableName, auditorId];
  557. const result = await this.db.queryOne(sql, sqlParam);
  558. return result ? result.end_time : null;
  559. }
  560. /**
  561. * 用于添加推送所需的content内容
  562. * @param {Number} pid 项目id
  563. * @param {Number} tid 台账id
  564. * @param {Number} cpId 方案id
  565. * @param {Number} uid 审批人id
  566. */
  567. async getNoticeContent(pid, spid, fpId, uid, opinion = '') {
  568. const noticeSql = 'SELECT * FROM (SELECT ' +
  569. ' sp.`id` As `spid`, ma.`fpid`, m.`code`, sp.`name`, pa.`name` As `su_name`, pa.role As `su_role`' +
  570. ' FROM (SELECT * FROM ?? WHERE `id` = ? ) As sp' +
  571. ' LEFT JOIN ?? As m On sp.`id` = m.`spid` AND m.`id` = ?' +
  572. ' LEFT JOIN ?? As ma ON m.`id` = ma.`fpid`' +
  573. ' LEFT JOIN ?? As pa ON pa.`id` = ?' +
  574. ' WHERE sp.`project_id` = ? ) as new_t GROUP BY new_t.`spid`';
  575. const noticeSqlParam = [this.ctx.service.subProject.tableName, spid, this.ctx.service.financialPay.tableName, fpId, this.tableName, this.ctx.service.projectAccount.tableName, uid, pid];
  576. const content = await this.db.query(noticeSql, noticeSqlParam);
  577. if (content.length) {
  578. content[0].opinion = opinion;
  579. }
  580. return content.length ? JSON.stringify(content[0]) : '';
  581. }
  582. /**
  583. * 获取审核人已经审核过的审批信息(包括退回,通过,重新审批等)
  584. *
  585. * @param auditorId
  586. * @return {Promise<*>}
  587. */
  588. async getDonesByAudit(auditorId, spid = '') {
  589. const spSql = spid ? ' and t.`spid` = "' + spid + '"' : '';
  590. const status = [auditConst.status.checked, auditConst.status.checkNo];
  591. const sql =
  592. 'SELECT la.`status`, la.`end_time` as `shenpi_time`, la.`fpid`, t.`id`, fp.`code`, t.`name`, t.`spid` ' +
  593. ' FROM ?? AS la Left Join ?? AS t ON la.`tid` = t.`id` LEFT JOIN ?? AS fp ON la.`fpid` = fp.`id`' +
  594. ' WHERE la.`aid` = ? AND la.`status` in (' + this.ctx.helper.getInArrStrSqlFilter(status) + ')' + spSql +
  595. ' ORDER BY la.`end_time` DESC';
  596. const sqlParam = [
  597. this.tableName,
  598. this.ctx.service.tender.tableName,
  599. this.ctx.service.financialPay.tableName,
  600. auditorId,
  601. ];
  602. return await this.db.query(sql, sqlParam);
  603. }
  604. }
  605. return FinancialPayAudit;
  606. };