stage_audit.js 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171
  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. const SmsAliConst = require('../const/sms_alitemplate')
  13. const payConst = require('../const/deal_pay')
  14. const pushType = require('../const/audit').pushType
  15. module.exports = app => {
  16. class StageAudit extends app.BaseService {
  17. /**
  18. * 构造函数
  19. *
  20. * @param {Object} ctx - egg全局变量
  21. * @return {void}
  22. */
  23. constructor(ctx) {
  24. super(ctx)
  25. this.tableName = 'stage_audit'
  26. }
  27. /**
  28. * 获取 审核人信息
  29. *
  30. * @param {Number} stageId - 期id
  31. * @param {Number} auditorId - 审核人id
  32. * @param {Number} times - 第几次审批
  33. * @return {Promise<*>}
  34. */
  35. async getAuditor(stageId, auditorId, times = 1) {
  36. const sql =
  37. '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` ' +
  38. 'FROM ?? AS la, ?? AS pa ' +
  39. 'WHERE la.`sid` = ? and la.`aid` = ? and la.`times` = ?' +
  40. ' and la.`aid` = pa.`id`'
  41. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditorId, times]
  42. return await this.db.queryOne(sql, sqlParam)
  43. }
  44. /**
  45. * 获取 审核列表信息
  46. *
  47. * @param {Number} stageId - 期id
  48. * @param {Number} times - 第几次审批
  49. * @param {Number} order_sort - 列表排序方式
  50. * @return {Promise<*>}
  51. */
  52. async getAuditors(stageId, times = 1, order_sort = 'asc') {
  53. const sql =
  54. '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` ' +
  55. '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 ' +
  56. 'WHERE la.`sid` = ? and la.`times` = ? and la.`aid` = pa.`id` and g.`aid` = la.`aid` order by la.`order` ' +
  57. order_sort
  58. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.tableName, stageId, times, stageId, times]
  59. const result = await this.db.query(sql, sqlParam)
  60. const sql2 = 'SELECT COUNT(a.`aid`) as num FROM (SELECT `aid` FROM ?? WHERE `sid` = ? AND `times` = ? GROUP BY `aid`) as a'
  61. const sqlParam2 = [this.tableName, stageId, times]
  62. const count = await this.db.queryOne(sql2, sqlParam2)
  63. for (const i in result) {
  64. result[i].max_sort = count.num
  65. }
  66. return result
  67. }
  68. async getAllAuditors(tenderId) {
  69. const sql =
  70. 'SELECT sa.aid, sa.tid FROM ' +
  71. this.tableName +
  72. ' sa' +
  73. ' LEFT JOIN ' +
  74. this.ctx.service.tender.tableName +
  75. ' t On sa.tid = t.id' +
  76. ' WHERE t.id = ?' +
  77. ' GROUP BY sa.aid'
  78. const sqlParam = [tenderId]
  79. return this.db.query(sql, sqlParam)
  80. }
  81. /**
  82. * 获取标段审核人最后一位的名称
  83. *
  84. * @param {Number} tenderId - 标段id
  85. * @param {Number} auditorId - 审核人id
  86. * @param {Number} times - 第几次审批
  87. * @return {Promise<*>}
  88. */
  89. async getStatusName(stageId) {
  90. const sql =
  91. 'SELECT pa.`name` ' +
  92. 'FROM ?? AS sa, ?? AS pa ' +
  93. 'WHERE sa.`sid` = ?' +
  94. ' and sa.`aid` = pa.`id` and sa.`status` != ? ORDER BY sa.`times` DESC, sa.`order` DESC'
  95. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditConst.status.uncheck]
  96. return await this.db.queryOne(sql, sqlParam)
  97. }
  98. /**
  99. * 获取 当前审核人
  100. *
  101. * @param {Number} stageId - 期id
  102. * @param {Number} times - 第几次审批
  103. * @return {Promise<*>}
  104. */
  105. async getCurAuditor(stageId, times = 1) {
  106. const sql =
  107. '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` ' +
  108. 'FROM ?? AS la, ?? AS pa ' +
  109. 'WHERE la.`sid` = ? and la.`status` = ? and la.`times` = ?' +
  110. ' and la.`aid` = pa.`id`'
  111. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditConst.status.checking, times]
  112. return await this.db.queryOne(sql, sqlParam)
  113. }
  114. /**
  115. * 获取 最新审核顺序
  116. *
  117. * @param {Number} stageId - 期id
  118. * @param {Number} times - 第几次审批
  119. * @return {Promise<number>}
  120. */
  121. async getNewOrder(stageId, times = 1) {
  122. const sql = 'SELECT Max(??) As max_order FROM ?? Where `sid` = ? and `times` = ?'
  123. const sqlParam = ['order', this.tableName, stageId, times]
  124. const result = await this.db.queryOne(sql, sqlParam)
  125. return result && result.max_order ? result.max_order + 1 : 1
  126. }
  127. /**
  128. * 新增审核人
  129. *
  130. * @param {Number} stageId - 期id
  131. * @param {Number} auditorId - 审核人id
  132. * @param {Number} times - 第几次审批
  133. * @return {Promise<number>}
  134. */
  135. async addAuditor(stageId, auditorId, times = 1) {
  136. const newOrder = await this.getNewOrder(stageId, times)
  137. const data = {
  138. tid: this.ctx.tender.id,
  139. sid: stageId,
  140. aid: auditorId,
  141. times,
  142. order: newOrder,
  143. status: auditConst.status.uncheck
  144. }
  145. const result = await this.db.insert(this.tableName, data)
  146. return (result.effectRows = 1)
  147. }
  148. /**
  149. * 移除审核人时,同步其后审核人order
  150. * @param transaction - 事务
  151. * @param {Number} stageId - 标段id
  152. * @param {Number} auditorId - 审核人id
  153. * @param {Number} times - 第几次审批
  154. * @return {Promise<*>}
  155. * @private
  156. */
  157. async _syncOrderByDelete(transaction, stageId, order, times) {
  158. this.initSqlBuilder()
  159. this.sqlBuilder.setAndWhere('sid', {
  160. value: stageId,
  161. operate: '='
  162. })
  163. this.sqlBuilder.setAndWhere('order', {
  164. value: order,
  165. operate: '>='
  166. })
  167. this.sqlBuilder.setAndWhere('times', {
  168. value: times,
  169. operate: '='
  170. })
  171. this.sqlBuilder.setUpdateData('order', {
  172. value: 1,
  173. selfOperate: '-'
  174. })
  175. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update')
  176. const data = await transaction.query(sql, sqlParam)
  177. return data
  178. }
  179. /**
  180. * 移除审核人
  181. *
  182. * @param {Number} stageId - 期id
  183. * @param {Number} auditorId - 审核人id
  184. * @param {Number} times - 第几次审批
  185. * @return {Promise<boolean>}
  186. */
  187. async deleteAuditor(stageId, auditorId, times = 1) {
  188. const transaction = await this.db.beginTransaction()
  189. try {
  190. const condition = { sid: stageId, aid: auditorId, times }
  191. const auditor = await this.getDataByCondition(condition)
  192. if (!auditor) {
  193. throw '该审核人不存在'
  194. }
  195. await this._syncOrderByDelete(transaction, stageId, auditor.order, times)
  196. await transaction.delete(this.tableName, condition)
  197. await transaction.commit()
  198. } catch (err) {
  199. await transaction.rollback()
  200. throw err
  201. }
  202. return true
  203. }
  204. /**
  205. * 开始审批
  206. *
  207. * @param {Number} stageId - 期id
  208. * @param {Number} times - 第几次审批
  209. * @return {Promise<boolean>}
  210. */
  211. async start(stageId, times = 1) {
  212. const audit = await this.getDataByCondition({ sid: stageId, times, order: 1 })
  213. if (!audit) {
  214. throw '请先选择审批人,再上报数据'
  215. }
  216. const transaction = await this.db.beginTransaction()
  217. try {
  218. await transaction.update(this.tableName, {
  219. id: audit.id,
  220. status: auditConst.status.checking,
  221. begin_time: new Date()
  222. })
  223. // 计算原报最终数据
  224. const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction)
  225. // 复制一份下一审核人数据
  226. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, 1, transaction)
  227. await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction)
  228. await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction)
  229. await this.ctx.service.stageOther.updateHistory(this.ctx.stage, transaction)
  230. // 更新期数据
  231. const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage)
  232. this.ctx.stage.tp_history.push({
  233. times: this.ctx.stage.curTimes,
  234. order: 0,
  235. contract_tp: tpData.contract_tp,
  236. qc_tp: tpData.qc_tp,
  237. yf_tp: yfPay.tp,
  238. sf_tp: sfPay.tp
  239. })
  240. await transaction.update(this.ctx.service.stage.tableName, {
  241. id: stageId,
  242. status: auditConst.status.checking,
  243. contract_tp: tpData.contract_tp,
  244. qc_tp: tpData.qc_tp,
  245. yf_tp: yfPay.tp,
  246. sf_tp: sfPay.tp,
  247. tp_history: JSON.stringify(this.ctx.stage.tp_history),
  248. cache_time_r: this.ctx.stage.cache_time_l
  249. })
  250. // 添加短信通知-需要审批提醒功能
  251. // const smsUser = await this.ctx.service.projectAccount.getDataById(audit.aid);
  252. // if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  253. // const smsType = JSON.parse(smsUser.sms_type);
  254. // if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
  255. // const tenderInfo = await this.ctx.service.tender.getDataById(audit.tid);
  256. // const stageInfo = await this.ctx.service.stage.getDataById(audit.sid);
  257. // const sms = new SMS(this.ctx);
  258. // const tenderName = await sms.contentChange(tenderInfo.name);
  259. // const projectName = await sms.contentChange(this.ctx.tender.info.deal_info.buildName);
  260. // const ptmsg = projectName !== '' ? '项目「' + projectName + '」标段「' + tenderName + '」' : tenderName;
  261. // const result = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '/stage/' + stageInfo.order);
  262. // const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,需要您审批。' + result;
  263. // sms.send(smsUser.auth_mobile, content);
  264. // }
  265. // }
  266. const stageInfo = await this.ctx.service.stage.getDataById(audit.sid)
  267. const shenpiUrl = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '/stage/' + stageInfo.order)
  268. await this.ctx.helper.sendAliSms(audit.aid, smsTypeConst.const.JL, smsTypeConst.judge.approval.toString(), SmsAliConst.template.stage_check, {
  269. qi: stageInfo.order,
  270. code: shenpiUrl
  271. })
  272. // todo 更新标段tender状态 ?
  273. await transaction.commit()
  274. } catch (err) {
  275. await transaction.rollback()
  276. throw err
  277. }
  278. return true
  279. }
  280. async _checked(pid, stageId, checkData, times) {
  281. const time = new Date()
  282. // 整理当前流程审核人状态更新
  283. const audit = await this.getDataByCondition({ sid: stageId, times, status: auditConst.status.checking })
  284. if (!audit) {
  285. throw '审核数据错误'
  286. }
  287. const nextAudit = await this.getDataByCondition({ sid: stageId, times, order: audit.order + 1 })
  288. const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage)
  289. const transaction = await this.db.beginTransaction()
  290. try {
  291. // 添加推送
  292. const noticeContent = await this.getNoticeContent(pid, audit.tid, stageId, audit.aid)
  293. const auditors = await this.getAuditGroupByListWithOwner(stageId, times)
  294. const records = [
  295. {
  296. pid,
  297. type: pushType.stage,
  298. uid: this.ctx.stage.user_id,
  299. status: auditConst.status.checked,
  300. content: noticeContent
  301. }
  302. ]
  303. auditors.forEach(audit => {
  304. records.push({
  305. pid,
  306. type: pushType.stage,
  307. uid: audit.aid,
  308. status: auditConst.status.checked,
  309. content: noticeContent
  310. })
  311. })
  312. await transaction.insert('zh_notice', records)
  313. await transaction.update(this.tableName, {
  314. id: audit.id,
  315. status: checkData.checkType,
  316. opinion: checkData.opinion,
  317. end_time: time
  318. })
  319. // 计算并合同支付最终数据
  320. const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction)
  321. this.ctx.stage.tp_history.push({
  322. times,
  323. order: audit.order,
  324. contract_tp: tpData.contract_tp,
  325. qc_tp: tpData.qc_tp,
  326. yf_tp: yfPay.tp,
  327. sf_tp: sfPay.tp
  328. })
  329. // 无下一审核人表示,审核结束
  330. if (nextAudit) {
  331. // 复制一份下一审核人数据
  332. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, nextAudit.order, transaction)
  333. await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction)
  334. await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction)
  335. await this.ctx.service.stageOther.updateHistory(this.ctx.stage, transaction)
  336. // 流程至下一审批人
  337. await transaction.update(this.tableName, {
  338. id: nextAudit.id,
  339. status: auditConst.status.checking,
  340. begin_time: time
  341. })
  342. // 同步 期信息
  343. await transaction.update(this.ctx.service.stage.tableName, {
  344. id: stageId,
  345. status: auditConst.status.checking,
  346. contract_tp: tpData.contract_tp,
  347. qc_tp: tpData.qc_tp,
  348. yf_tp: yfPay.tp,
  349. sf_tp: sfPay.tp,
  350. tp_history: JSON.stringify(this.ctx.stage.tp_history),
  351. cache_time_r: this.ctx.stage.cache_time_l
  352. })
  353. // 添加短信通知-需要审批提醒功能
  354. // const smsUser = await this.ctx.service.projectAccount.getDataById(nextAudit.aid);
  355. // if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  356. // const smsType = JSON.parse(smsUser.sms_type);
  357. // if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
  358. // const tenderInfo = await this.ctx.service.tender.getDataById(nextAudit.tid);
  359. // const stageInfo = await this.ctx.service.stage.getDataById(nextAudit.sid);
  360. // const sms = new SMS(this.ctx);
  361. // const tenderName = await sms.contentChange(tenderInfo.name);
  362. // const projectName = await sms.contentChange(this.ctx.tender.info.deal_info.buildName);
  363. // const result = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '/stage/' + stageInfo.order);
  364. // // const result = '';
  365. // const ptmsg = projectName !== '' ? '项目「' + projectName + '」标段「' + tenderName + '」' : tenderName;
  366. // const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,需要您审批。' + result;
  367. // sms.send(smsUser.auth_mobile, content);
  368. // }
  369. // }
  370. const stageInfo = await this.ctx.service.stage.getDataById(nextAudit.sid)
  371. const shenpiUrl = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '/stage/' + stageInfo.order)
  372. await this.ctx.helper.sendAliSms(nextAudit.aid, smsTypeConst.const.JL, smsTypeConst.judge.approval.toString(), SmsAliConst.template.stage_check, {
  373. qi: stageInfo.order,
  374. code: shenpiUrl
  375. })
  376. } else {
  377. // 本期结束
  378. // 生成截止本期数据 final数据
  379. await this.ctx.service.stageBillsFinal.generateFinalData(transaction, this.ctx.tender, this.ctx.stage)
  380. await this.ctx.service.stagePosFinal.generateFinalData(transaction, this.ctx.tender, this.ctx.stage)
  381. // 同步 期信息
  382. await transaction.update(this.ctx.service.stage.tableName, {
  383. id: stageId,
  384. status: checkData.checkType,
  385. contract_tp: tpData.contract_tp,
  386. qc_tp: tpData.qc_tp,
  387. yf_tp: yfPay.tp,
  388. sf_tp: sfPay.tp,
  389. tp_history: JSON.stringify(this.ctx.stage.tp_history),
  390. cache_time_r: this.ctx.stage.cache_time_l
  391. })
  392. // 添加短信通知-审批通过提醒功能
  393. // const mobile_array = [];
  394. const stageInfo = await this.ctx.service.stage.getDataById(stageId)
  395. const auditList = await this.getAuditors(stageId, stageInfo.times)
  396. // const smsUser1 = await this.ctx.service.projectAccount.getDataById(stageInfo.user_id);
  397. // if (smsUser1.auth_mobile !== undefined && smsUser1.sms_type !== '' && smsUser1.sms_type !== null) {
  398. // const smsType = JSON.parse(smsUser1.sms_type);
  399. // if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
  400. // mobile_array.push(smsUser1.auth_mobile);
  401. // }
  402. // }
  403. // for (const user of auditList) {
  404. // const smsUser = await this.ctx.service.projectAccount.getDataById(user.aid);
  405. // if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  406. // const smsType = JSON.parse(smsUser.sms_type);
  407. // if (mobile_array.indexOf(smsUser.auth_mobile) === -1 && smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
  408. // mobile_array.push(smsUser.auth_mobile);
  409. // }
  410. // }
  411. // }
  412. // if (mobile_array.length > 0) {
  413. // const tenderInfo = await this.ctx.service.tender.getDataById(stageInfo.tid);
  414. // const sms = new SMS(this.ctx);
  415. // const tenderName = await sms.contentChange(tenderInfo.name);
  416. // const projectName = await sms.contentChange(this.ctx.tender.info.deal_info.buildName);
  417. // const ptmsg = projectName !== '' ? '项目「' + projectName + '」标段「' + tenderName + '」' : tenderName;
  418. // const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,审批通过。';
  419. // sms.send(mobile_array, content);
  420. // }
  421. const users = this._.pull(this._.map(auditList, 'aid'), stageInfo.user_id)
  422. await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JL, smsTypeConst.judge.result.toString(), SmsAliConst.template.stage_result, {
  423. qi: stageInfo.order,
  424. status: SmsAliConst.status.success
  425. })
  426. }
  427. await transaction.commit()
  428. } catch (err) {
  429. await transaction.rollback()
  430. throw err
  431. }
  432. }
  433. async _checkNo(pid, stageId, checkData, times) {
  434. const time = new Date()
  435. // 整理当前流程审核人状态更新
  436. const audit = await this.getDataByCondition({ sid: stageId, times, status: auditConst.status.checking })
  437. if (!audit) {
  438. throw '审核数据错误'
  439. }
  440. const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage)
  441. const sql = 'SELECT `tid`, `sid`, `aid`, `order` FROM ?? WHERE `sid` = ? and `times` = ? GROUP BY `aid` ORDER BY `id` ASC'
  442. const sqlParam = [this.tableName, stageId, times]
  443. const auditors = await this.db.query(sql, sqlParam)
  444. let order = 1
  445. for (const a of auditors) {
  446. a.times = times + 1
  447. a.order = order
  448. a.status = auditConst.status.uncheck
  449. order++
  450. }
  451. const transaction = await this.db.beginTransaction()
  452. try {
  453. // 添加推送
  454. const noticeContent = await this.getNoticeContent(pid, audit.tid, stageId, audit.aid)
  455. const records = [
  456. {
  457. pid,
  458. type: pushType.stage,
  459. uid: this.ctx.stage.user_id,
  460. status: auditConst.status.checkNo,
  461. content: noticeContent
  462. }
  463. ]
  464. auditors.forEach(audit => {
  465. records.push({
  466. pid,
  467. type: pushType.stage,
  468. uid: audit.aid,
  469. status: auditConst.status.checkNo,
  470. content: noticeContent
  471. })
  472. })
  473. await transaction.insert('zh_notice', records)
  474. // 计算并合同支付最终数据
  475. const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction)
  476. this.ctx.stage.tp_history.push({
  477. times,
  478. order: audit.order,
  479. contract_tp: tpData.contract_tp,
  480. qc_tp: tpData.qc_tp,
  481. yf_tp: yfPay.tp,
  482. sf_tp: sfPay.tp
  483. })
  484. await transaction.update(this.tableName, {
  485. id: audit.id,
  486. status: checkData.checkType,
  487. opinion: checkData.opinion,
  488. end_time: time
  489. })
  490. // 同步 期信息
  491. await transaction.update(this.ctx.service.stage.tableName, {
  492. id: stageId,
  493. status: checkData.checkType,
  494. contract_tp: tpData.contract_tp,
  495. qc_tp: tpData.qc_tp,
  496. times: times + 1,
  497. yf_tp: yfPay.tp,
  498. sf_tp: sfPay.tp,
  499. tp_history: JSON.stringify(this.ctx.stage.tp_history),
  500. cache_time_r: this.ctx.stage.cache_time_l
  501. })
  502. // 拷贝新一次审核流程列表
  503. await transaction.insert(this.tableName, auditors)
  504. // 计算该审批人最终数据
  505. await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction)
  506. // 复制一份最新数据给原报
  507. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times + 1, 0, transaction)
  508. await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction)
  509. await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction)
  510. // 添加短信通知-审批退回提醒功能
  511. // const mobile_array = [];
  512. const stageInfo = await this.ctx.service.stage.getDataById(stageId)
  513. const auditList = await this.getAuditors(stageId, stageInfo.times)
  514. // const smsUser1 = await this.ctx.service.projectAccount.getDataById(stageInfo.user_id);
  515. // if (smsUser1.auth_mobile !== '' && smsUser1.auth_mobile !== undefined && smsUser1.sms_type !== '' && smsUser1.sms_type !== null) {
  516. // const smsType = JSON.parse(smsUser1.sms_type);
  517. // if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
  518. // mobile_array.push(smsUser1.auth_mobile);
  519. // }
  520. // }
  521. // for (const user of auditList) {
  522. // const smsUser = await this.ctx.service.projectAccount.getDataById(user.aid);
  523. // if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  524. // const smsType = JSON.parse(smsUser.sms_type);
  525. // if (mobile_array.indexOf(smsUser.auth_mobile) === -1 && smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
  526. // mobile_array.push(smsUser.auth_mobile);
  527. // }
  528. // }
  529. // }
  530. // if (mobile_array.length > 0) {
  531. // const tenderInfo = await this.ctx.service.tender.getDataById(stageInfo.tid);
  532. // const sms = new SMS(this.ctx);
  533. // const tenderName = await sms.contentChange(tenderInfo.name);
  534. // const projectName = await sms.contentChange(this.ctx.tender.info.deal_info.buildName);
  535. // const ptmsg = projectName !== '' ? '项目「' + projectName + '」标段「' + tenderName + '」' : tenderName;
  536. // const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,审批退回。';
  537. // sms.send(mobile_array, content);
  538. // }
  539. const users = this._.pull(this._.map(auditList, 'aid'), stageInfo.user_id)
  540. await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JL, smsTypeConst.judge.result.toString(), SmsAliConst.template.stage_result, {
  541. qi: stageInfo.order,
  542. status: SmsAliConst.status.back
  543. })
  544. await transaction.commit()
  545. } catch (err) {
  546. await transaction.rollback()
  547. throw err
  548. }
  549. }
  550. async _checkNoPre(pid, stageId, checkData, times) {
  551. const time = new Date()
  552. // 整理当前流程审核人状态更新
  553. const audit = await this.getDataByCondition({ sid: stageId, times, status: auditConst.status.checking })
  554. if (!audit || audit.order <= 1) {
  555. throw '审核数据错误'
  556. }
  557. // 添加重新审批后,不能用order-1,取groupby值里的上一个才对
  558. // const preAuditor = await this.getDataByCondition({sid: stageId, times: times, order: audit.order - 1});
  559. const auditors2 = await this.getAuditGroupByList(stageId, times)
  560. const auditorIndex = await auditors2.findIndex(function (item) {
  561. return item.aid === audit.aid
  562. })
  563. const preAuditor = auditors2[auditorIndex - 1]
  564. const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage)
  565. const transaction = await this.db.beginTransaction()
  566. try {
  567. // 添加推送
  568. const noticeContent = await this.getNoticeContent(pid, audit.tid, stageId, audit.aid)
  569. const records = [
  570. {
  571. pid,
  572. type: pushType.stage,
  573. uid: this.ctx.stage.user_id,
  574. status: auditConst.status.checkNoPre,
  575. content: noticeContent
  576. }
  577. ]
  578. auditors2.forEach(audit => {
  579. records.push({
  580. pid,
  581. type: pushType.stage,
  582. uid: audit.aid,
  583. status: auditConst.status.checkNoPre,
  584. content: noticeContent
  585. })
  586. })
  587. await transaction.insert('zh_notice', records)
  588. // 计算并合同支付最终数据
  589. const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction)
  590. this.ctx.stage.tp_history.push({
  591. times,
  592. order: audit.order,
  593. contract_tp: tpData.contract_tp,
  594. qc_tp: tpData.qc_tp,
  595. yf_tp: yfPay.tp,
  596. sf_tp: sfPay.tp
  597. })
  598. // 同步 期信息
  599. await transaction.update(this.ctx.service.stage.tableName, {
  600. id: stageId,
  601. contract_tp: tpData.contract_tp,
  602. qc_tp: tpData.qc_tp,
  603. times,
  604. yf_tp: yfPay.tp,
  605. sf_tp: sfPay.tp,
  606. tp_history: JSON.stringify(this.ctx.stage.tp_history),
  607. cache_time_r: this.ctx.stage.cache_time_l
  608. })
  609. await transaction.update(this.tableName, {
  610. id: audit.id,
  611. status: checkData.checkType,
  612. opinion: checkData.opinion,
  613. end_time: time
  614. })
  615. // 顺移气候审核人流程顺序
  616. this.initSqlBuilder()
  617. this.sqlBuilder.setAndWhere('sid', { value: this.ctx.stage.id, operate: '=' })
  618. this.sqlBuilder.setAndWhere('order', { value: audit.order, operate: '>' })
  619. this.sqlBuilder.setUpdateData('order', { value: 2, selfOperate: '+' })
  620. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update')
  621. const data = await transaction.query(sql, sqlParam)
  622. // 上一审批人,当前审批人 再次添加至流程
  623. const newAuditors = []
  624. newAuditors.push({
  625. tid: audit.tid,
  626. sid: audit.sid,
  627. aid: preAuditor.aid,
  628. times: audit.times,
  629. order: audit.order + 1,
  630. status: auditConst.status.checking,
  631. begin_time: time
  632. })
  633. newAuditors.push({
  634. tid: audit.tid,
  635. sid: audit.sid,
  636. aid: audit.aid,
  637. times: audit.times,
  638. order: audit.order + 2,
  639. status: auditConst.status.uncheck
  640. })
  641. await transaction.insert(this.tableName, newAuditors)
  642. // 计算该审批人最终数据
  643. await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction)
  644. // 复制一份最新数据给下一人
  645. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 1, transaction)
  646. await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction)
  647. await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction)
  648. await this.ctx.service.stageOther.updateHistory(this.ctx.stage, transaction)
  649. // 同步 期信息
  650. await transaction.update(this.ctx.service.stage.tableName, {
  651. id: stageId,
  652. status: checkData.checkType,
  653. cache_time_r: this.ctx.stage.cache_time_l
  654. })
  655. // 添加短信通知-需要审批提醒功能
  656. // const smsUser = await this.ctx.service.projectAccount.getDataById(preAuditor.aid);
  657. // if (smsUser.auth_mobile !== '' && smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  658. // const smsType = JSON.parse(smsUser.sms_type);
  659. // if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
  660. // const tenderInfo = await this.ctx.service.tender.getDataById(audit.tid);
  661. // const stageInfo = await this.ctx.service.stage.getDataById(audit.sid);
  662. // const sms = new SMS(this.ctx);
  663. // const tenderName = await sms.contentChange(tenderInfo.name);
  664. // const projectName = await sms.contentChange(this.ctx.tender.info.deal_info.buildName);
  665. // const ptmsg = projectName !== '' ? '项目「' + projectName + '」标段「' + tenderName + '」' : tenderName;
  666. // const result = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '/stage/' + stageInfo.order);
  667. // // const result = '';
  668. // const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,需要您审批。' + result;
  669. // sms.send(smsUser.auth_mobile, content);
  670. // }
  671. // }
  672. const stageInfo = await this.ctx.service.stage.getDataById(audit.sid)
  673. const shenpiUrl = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '/stage/' + stageInfo.order)
  674. await this.ctx.helper.sendAliSms(preAuditor.aid, smsTypeConst.const.JL, smsTypeConst.judge.approval.toString(), SmsAliConst.template.stage_check, {
  675. qi: stageInfo.order,
  676. code: shenpiUrl
  677. })
  678. await transaction.commit()
  679. } catch (err) {
  680. await transaction.rollback()
  681. throw err
  682. }
  683. }
  684. /**
  685. * 审批
  686. * @param {Number} stageId - 标段id
  687. * @param {auditConst.status.checked|auditConst.status.checkNo} checkType - 审批结果
  688. * @param {Number} times - 第几次审批
  689. * @return {Promise<void>}
  690. */
  691. async check(stageId, checkData, times = 1) {
  692. if (checkData.checkType !== auditConst.status.checked && checkData.checkType !== auditConst.status.checkNo && checkData.checkType !== auditConst.status.checkNoPre) {
  693. throw '提交数据错误'
  694. }
  695. // // 整理当前流程审核人状态更新
  696. // const audit = await this.getDataByCondition({sid: stageId, times: times, status: auditConst.status.checking});
  697. // if (!audit) {
  698. // throw '审核数据错误';
  699. // }
  700. // const time = new Date();
  701. const pid = this.ctx.session.sessionProject.id
  702. switch (checkData.checkType) {
  703. case auditConst.status.checked:
  704. await this._checked(pid, stageId, checkData, times)
  705. break
  706. case auditConst.status.checkNo:
  707. await this._checkNo(pid, stageId, checkData, times)
  708. break
  709. case auditConst.status.checkNoPre:
  710. await this._checkNoPre(pid, stageId, checkData, times)
  711. break
  712. default:
  713. throw '无效审批操作'
  714. }
  715. }
  716. /**
  717. * 审批
  718. * @param {Number} stageId - 标段id
  719. * @param {Number} times - 第几次审批
  720. * @return {Promise<void>}
  721. */
  722. async checkAgain(stageId, times = 1) {
  723. const time = new Date()
  724. // 整理当前流程审核人状态更新
  725. const audit = (
  726. await this.getAllDataByCondition({
  727. where: { sid: stageId, times },
  728. orders: [['order', 'desc']],
  729. limit: 1,
  730. offset: 0
  731. })
  732. )[0]
  733. if (!audit || audit.order < 1) {
  734. throw '审核数据错误'
  735. }
  736. const transaction = await this.db.beginTransaction()
  737. try {
  738. // 当前审批人2次添加至流程中
  739. const newAuditors = []
  740. newAuditors.push({
  741. tid: audit.tid,
  742. sid: audit.sid,
  743. aid: audit.aid,
  744. times: audit.times,
  745. order: audit.order + 1,
  746. status: auditConst.status.checkAgain,
  747. begin_time: time,
  748. end_time: time,
  749. opinion: ''
  750. })
  751. newAuditors.push({
  752. tid: audit.tid,
  753. sid: audit.sid,
  754. aid: audit.aid,
  755. times: audit.times,
  756. order: audit.order + 2,
  757. status: auditConst.status.checking,
  758. begin_time: time
  759. })
  760. await transaction.insert(this.tableName, newAuditors)
  761. // 复制一份最新数据给下一人
  762. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 1, transaction)
  763. await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 2, transaction)
  764. await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction)
  765. await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction)
  766. await this.ctx.service.stageOther.updateHistory(this.ctx.stage, transaction)
  767. // 本期结束
  768. // 生成截止本期数据 final数据
  769. await this.ctx.service.stageBillsFinal.delGenerateFinalData(transaction, this.ctx.tender, this.ctx.stage)
  770. await this.ctx.service.stagePosFinal.delGenerateFinalData(transaction, this.ctx.tender, this.ctx.stage)
  771. // 同步 期信息
  772. await transaction.update(this.ctx.service.stage.tableName, {
  773. id: stageId,
  774. status: auditConst.status.checking,
  775. cache_time_r: this.ctx.stage.cache_time_l
  776. })
  777. // 添加短信通知-需要审批提醒功能
  778. // const smsUser = await this.ctx.service.projectAccount.getDataById(audit.aid);
  779. // if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '' && smsUser.sms_type !== null) {
  780. // const smsType = JSON.parse(smsUser.sms_type);
  781. // if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
  782. // const tenderInfo = await this.ctx.service.tender.getDataById(audit.tid);
  783. // const stageInfo = await this.ctx.service.stage.getDataById(audit.sid);
  784. // const sms = new SMS(this.ctx);
  785. // const tenderName = await sms.contentChange(tenderInfo.name);
  786. // const projectName = await sms.contentChange(this.ctx.tender.info.deal_info.buildName);
  787. // const ptmsg = projectName !== '' ? '项目「' + projectName + '」标段「' + tenderName + '」' : tenderName;
  788. // const result = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '/stage/' + stageInfo.order);
  789. // const content = '【纵横计量支付】' + ptmsg + '第' + stageInfo.order + '期,需要您审批。' + result;
  790. // sms.send(smsUser.auth_mobile, content);
  791. // }
  792. // }
  793. const stageInfo = await this.ctx.service.stage.getDataById(audit.sid)
  794. const shenpiUrl = await this.ctx.helper.urlToShort('http://' + this.ctx.request.header.host + '/wap/tender/' + this.ctx.tender.id + '/stage/' + stageInfo.order)
  795. await this.ctx.helper.sendAliSms(audit.aid, smsTypeConst.const.JL, smsTypeConst.judge.approval.toString(), SmsAliConst.template.stage_check, {
  796. qi: stageInfo.order,
  797. code: shenpiUrl
  798. })
  799. await transaction.commit()
  800. } catch (err) {
  801. await transaction.rollback()
  802. throw err
  803. }
  804. }
  805. /**
  806. * 获取审核人需要审核的期列表
  807. *
  808. * @param auditorId
  809. * @return {Promise<*>}
  810. */
  811. async getAuditStage(auditorId) {
  812. const sql =
  813. 'SELECT sa.`aid`, sa.`times`, sa.`order`, sa.`begin_time`, sa.`end_time`, sa.`tid`, sa.`sid`,' +
  814. ' s.`order` As `sorder`, s.`status` As `sstatus`,' +
  815. ' t.`name`, t.`project_id`, t.`type`, t.`user_id` ' +
  816. ' FROM ?? AS sa, ?? AS s, ?? As t ' +
  817. ' WHERE ((sa.`aid` = ? and sa.`status` = ?) OR (s.`user_id` = ? and sa.`status` = ? and s.`status` = ? and sa.`times` = (s.`times`-1)))' +
  818. ' and sa.`sid` = s.`id` and sa.`tid` = t.`id`'
  819. const sqlParam = [
  820. this.tableName,
  821. this.ctx.service.stage.tableName,
  822. this.ctx.service.tender.tableName,
  823. auditorId,
  824. auditConst.status.checking,
  825. auditorId,
  826. auditConst.status.checkNo,
  827. auditConst.status.checkNo
  828. ]
  829. return await this.db.query(sql, sqlParam)
  830. }
  831. /**
  832. * 获取 某时间后 审批进度 更新的期
  833. * @param {Number} pid - 查询标段
  834. * @param {Number} uid - 查询人
  835. * @param {Date} time - 查询时间
  836. * @return {Promise<*>}
  837. */
  838. async getNoticeStage(pid, uid, time) {
  839. // const sql = 'SELECT * FROM (SELECT t.`name`, t.`project_id`, t.`type`, t.`user_id`, ' +
  840. // ' s.`order` As `s_order`, s.`status` As `s_status`, ' +
  841. // ' sa.`aid`, sa.`times`, sa.`order`, sa.`end_time`, sa.`tid`, sa.`sid`, sa.`status`, ' +
  842. // ' pa.`name` As `su_name`, pa.role As `su_role`, pa.company As `su_company`' +
  843. // ' FROM (SELECT * FROM ?? WHERE `user_id` = ? OR `id` in (SELECT `tid` FROM ?? WHERE `aid` = ? GROUP BY `tid`)) As t' +
  844. // ' LEFT JOIN ?? As s On t.`id` = s.`tid`' +
  845. // ' LEFT JOIN ?? As sa ON s.`id` = sa.`sid`' +
  846. // ' LEFT JOIN ?? As pa ON sa.`aid` = pa.`id`' +
  847. // ' WHERE sa.`end_time` > ? and t.`project_id` = ?' +
  848. // ' ORDER By sa.`end_time` DESC LIMIT 1000) as new_t GROUP BY new_t.`tid`' +
  849. // ' ORDER By new_t.`end_time`';
  850. // const sqlParam = [this.ctx.service.tender.tableName, uid, this.tableName, uid, this.ctx.service.stage.tableName, this.tableName,
  851. // this.ctx.service.projectAccount.tableName, time, pid];
  852. // return await this.db.query(sql, sqlParam);
  853. let notice = await this.db.select('zh_notice', {
  854. where: { pid, type: pushType.stage, uid },
  855. orders: [['create_time', 'desc']],
  856. limit: 10,
  857. offset: 0
  858. })
  859. notice = notice.map(v => {
  860. const extra = JSON.parse(v.content)
  861. delete v.content
  862. return { ...v, ...extra }
  863. })
  864. return notice
  865. }
  866. /**
  867. * 用于添加推送所需的content内容
  868. * @param {Number} pid 项目id
  869. * @param {Number} tid 台账id
  870. * @param {Number} sid 期id
  871. * @param {Number} uid 审核人id
  872. */
  873. async getNoticeContent(pid, tid, sid, uid) {
  874. const noticeSql =
  875. 'SELECT * FROM (SELECT ' +
  876. ' t.`id` As `tid`, t.`name`, s.`order`, pa.`name` As `su_name`, pa.role As `su_role`' +
  877. ' FROM (SELECT * FROM ?? WHERE `id` = ? ) As t' +
  878. ' LEFT JOIN ?? As s On s.`id` = ?' +
  879. ' LEFT JOIN ?? As pa ON pa.`id` = ?' +
  880. ' WHERE t.`project_id` = ? ) as new_t GROUP BY new_t.`tid`'
  881. const noticeSqlParam = [this.ctx.service.tender.tableName, tid, this.ctx.service.stage.tableName, sid, this.ctx.service.projectAccount.tableName, uid, pid]
  882. const content = await this.db.query(noticeSql, noticeSqlParam)
  883. return content.length ? JSON.stringify(content[0]) : ''
  884. }
  885. /**
  886. * 获取审核人流程列表
  887. *
  888. * @param auditorId
  889. * @return {Promise<*>}
  890. */
  891. async getAuditGroupByList(stageId, times) {
  892. const sql =
  893. 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`aid`, la.`order` ' +
  894. 'FROM ?? AS la, ?? AS pa ' +
  895. 'WHERE la.`sid` = ? and la.`times` = ? and la.`aid` = pa.`id` GROUP BY la.`aid` ORDER BY la.`order`'
  896. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, times]
  897. return await this.db.query(sql, sqlParam)
  898. // const sql = 'SELECT `tid`, `sid`, `aid`, `order` FROM ?? WHERE `sid` = ? and `times` = ? GROUP BY `aid`';
  899. // const sqlParam = [this.tableName, stageId, times];
  900. // return await this.db.query(sql, sqlParam);
  901. }
  902. /**
  903. * 获取审核人流程列表
  904. *
  905. * @param auditorId
  906. * @return {Promise<*>}
  907. */
  908. async getAuditGroupByListWithOwner(stageId, times) {
  909. const result = await this.getAuditGroupByList(stageId, times)
  910. const sql =
  911. 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As sid, 0 As `order`' +
  912. ' FROM ' +
  913. this.ctx.service.stage.tableName +
  914. ' As s' +
  915. ' LEFT JOIN ' +
  916. this.ctx.service.projectAccount.tableName +
  917. ' As pa' +
  918. ' ON s.user_id = pa.id' +
  919. ' WHERE s.id = ?'
  920. const sqlParam = [times, stageId, stageId]
  921. const user = await this.db.queryOne(sql, sqlParam)
  922. result.unshift(user)
  923. return result
  924. }
  925. /**
  926. * 复制上一期的审批人列表给最新一期
  927. *
  928. * @param transaction - 新增一期的事务
  929. * @param {Object} preStage - 上一期
  930. * @param {Object} newStage - 最新一期
  931. * @return {Promise<*>}
  932. */
  933. async copyPreStageAuditors(transaction, preStage, newStage) {
  934. const auditors = await this.getAuditGroupByList(preStage.id, preStage.times)
  935. const newAuditors = []
  936. for (const a of auditors) {
  937. const na = {
  938. tid: preStage.tid,
  939. sid: newStage.id,
  940. aid: a.aid,
  941. times: newStage.times,
  942. order: newAuditors.length + 1,
  943. status: auditConst.status.uncheck
  944. }
  945. newAuditors.push(na)
  946. }
  947. const result = await transaction.insert(this.tableName, newAuditors)
  948. return (result.effectRows = auditors.length)
  949. }
  950. /**
  951. * 移除审核人
  952. *
  953. * @param {Number} stageId - 期id
  954. * @param {Number} status - 期状态
  955. * @param {Number} status - 期次数
  956. * @return {Promise<boolean>}
  957. */
  958. async getAuditorByStatus(stageId, status, times = 1) {
  959. let auditor = null
  960. let sql = ''
  961. let sqlParam = ''
  962. switch (status) {
  963. case auditConst.status.checking:
  964. case auditConst.status.checked:
  965. case auditConst.status.checkNoPre:
  966. sql =
  967. 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order` ' +
  968. 'FROM ?? AS la, ?? AS pa ' +
  969. 'WHERE la.`sid` = ? and la.`status` = ? and la.`aid` = pa.`id` order by la.`times` desc, la.`order` desc'
  970. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, status]
  971. auditor = await this.db.queryOne(sql, sqlParam)
  972. break
  973. case auditConst.status.checkNo:
  974. sql =
  975. 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order` ' +
  976. 'FROM ?? AS la, ?? AS pa ' +
  977. 'WHERE la.`sid` = ? and la.`status` = ? and la.`times` = ? and la.`aid` = pa.`id` order by la.`times` desc, la.`order` desc'
  978. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditConst.status.checkNo, parseInt(times) - 1]
  979. auditor = await this.db.queryOne(sql, sqlParam)
  980. break
  981. case auditConst.status.uncheck:
  982. default:
  983. break
  984. }
  985. return auditor
  986. }
  987. /**
  988. * 取某一期已批准审核信息(报表用)
  989. *
  990. * @param {Number} stageId - 期id
  991. * @param {Number} times - 期次数
  992. * @return {Promise<boolean>}
  993. */
  994. async getStageAudit(stageId, times = 1) {
  995. const sql = 'SELECT a1.aid, a1.begin_time, a1.end_time, a1.status, a1.opinion ' + 'FROM ?? AS a1 ' + 'WHERE a1.`sid` = ? and a1.`times` = ? ' + 'ORDER BY a1.order'
  996. const sqlParam = [this.tableName, stageId, times]
  997. const rst = await this.db.query(sql, sqlParam)
  998. return rst
  999. }
  1000. /**
  1001. * 取待审批期列表(wap用)
  1002. *
  1003. * @param auditorId
  1004. * @return {Promise<*>}
  1005. */
  1006. async getAuditStageByWap(auditorId) {
  1007. const sql =
  1008. 'SELECT sa.`aid`, sa.`times`, sa.`begin_time`, sa.`end_time`, sa.`tid`, sa.`sid`,' +
  1009. // ' s.`order` As `sorder`, s.`status` As `sstatus`, s.`s_time`, s.`contract_tp`, s.`qc_tp`, s.`pre_contract_tp`, s.`pre_qc_tp`, s.`yf_tp`, s.`pre_yf_tp`, ' +
  1010. ' s.*,' +
  1011. ' t.`name`, t.`project_id`, t.`type`, t.`user_id`,' +
  1012. ' ti.`deal_info` ' +
  1013. ' FROM ?? AS sa, ?? AS s, ?? As t, ?? AS ti ' +
  1014. ' WHERE sa.`aid` = ? and sa.`status` = ?' +
  1015. ' and sa.`sid` = s.`id` and sa.`tid` = t.`id` and ti.`tid` = t.`id`'
  1016. const sqlParam = [
  1017. this.tableName,
  1018. this.ctx.service.stage.tableName,
  1019. this.ctx.service.tender.tableName,
  1020. this.ctx.service.tenderInfo.tableName,
  1021. auditorId,
  1022. auditConst.status.checking
  1023. ]
  1024. return await this.db.query(sql, sqlParam)
  1025. }
  1026. /**
  1027. * 删除 某期 某次 全审批流程
  1028. * 私有,不做判断,不补全最新一轮审批人数据,不计算缓存
  1029. * @param {Number} sid - 标段id
  1030. * @param {Number} times - 第几次审批
  1031. * @param transaction - 删除事务
  1032. * @return {Promise<void>}
  1033. */
  1034. async _timesDelete(sid, times, transaction) {
  1035. // 审批流程
  1036. await transaction.delete(this.tableName, { sid, times })
  1037. await transaction.delete(this.ctx.service.pos.tableName, { add_stage: sid, add_times: times })
  1038. await transaction.delete(this.ctx.service.stageBills.tableName, { sid, times })
  1039. await transaction.delete(this.ctx.service.stagePos.tableName, { sid, times })
  1040. await transaction.delete(this.ctx.service.stageDetail.tableName, { sid, times })
  1041. await transaction.delete(this.ctx.service.stageChange.tableName, { sid, stimes: times })
  1042. await transaction.delete(this.ctx.service.stagePay.tableName, { sid, stimes: times })
  1043. await transaction.delete(this.ctx.service.pay.tableName, { csid: sid, cstimes: times })
  1044. // 其他台账
  1045. await this.ctx.service.stageJgcl.deleteStageTimesData(sid, times, transaction)
  1046. await this.ctx.service.stageOther.deleteStageTimesData(sid, times, transaction)
  1047. await this.ctx.service.stageBonus.deleteStageTimesData(sid, times, transaction)
  1048. }
  1049. /**
  1050. * 删除本次审批流程
  1051. * @param {Number} stageId - 标段id
  1052. * @param {Number} times - 第几次审批
  1053. * @return {Promise<void>}
  1054. */
  1055. async timesDelete() {
  1056. const transaction = await this.db.beginTransaction()
  1057. try {
  1058. // 删除最新一次数据
  1059. await this._timesDelete(this.ctx.stage.id, this.ctx.stage.times, transaction)
  1060. // 审批退回,未重新上报时,需删除最新两次数据
  1061. const isCheckNo = this.ctx.stage.status === auditConst.status.checkNo
  1062. const nowTimes = isCheckNo ? this.ctx.stage.times - 1 : this.ctx.stage.times
  1063. if (isCheckNo) {
  1064. await this._timesDelete(this.ctx.stage.id, nowTimes, transaction)
  1065. }
  1066. // 添加上一次审批人
  1067. const sql = 'SELECT `tid`, `sid`, `aid`, `order` FROM ?? WHERE `sid` = ? and `times` = ? GROUP BY `aid` ORDER BY `id` ASC'
  1068. const sqlParam = [this.tableName, this.ctx.stage.id, nowTimes - 1]
  1069. const auditors = await this.db.query(sql, sqlParam)
  1070. let order = 1
  1071. for (const a of auditors) {
  1072. a.times = nowTimes
  1073. a.order = order
  1074. a.status = auditConst.status.uncheck
  1075. order++
  1076. }
  1077. // 拷贝新一次审核流程列表
  1078. await transaction.insert(this.tableName, auditors)
  1079. // 计算缓存
  1080. const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage)
  1081. // 计算并合同支付最终数据
  1082. const lastAudit = await this.getDataByCondition({
  1083. sid: this.ctx.stage.id,
  1084. times: nowTimes - 1,
  1085. status: auditConst.status.checkNo
  1086. })
  1087. if (!lastAudit) throw '审批数据错误'
  1088. await this.ctx.service.stagePay.copyStagePays4DeleteTimes(this.ctx.stage, nowTimes, 0, lastAudit.times, lastAudit.order, transaction)
  1089. const stagePay = await this.ctx.service.stagePay.getAuditorStageData(this.ctx.stage.id, lastAudit.times, lastAudit.order)
  1090. const yfPay = stagePay.find(function (x) {
  1091. return x.ptype === payConst.payType.yf
  1092. })
  1093. const sfPay = stagePay.find(function (x) {
  1094. return x.ptype === payConst.payType.sf
  1095. })
  1096. // 同步 期信息
  1097. const time = new Date()
  1098. await transaction.update(this.ctx.service.stage.tableName, {
  1099. id: this.ctx.stage.id,
  1100. status: auditConst.status.checkNo,
  1101. contract_tp: tpData.contract_tp,
  1102. qc_tp: tpData.qc_tp,
  1103. times: nowTimes,
  1104. yf_tp: yfPay.tp,
  1105. sf_tp: sfPay.tp,
  1106. tp_history: JSON.stringify(this.ctx.stage.tp_history),
  1107. cache_time_l: time,
  1108. cache_time_r: time
  1109. })
  1110. await transaction.commit()
  1111. } catch (err) {
  1112. await transaction.rollback()
  1113. throw err
  1114. }
  1115. }
  1116. }
  1117. return StageAudit
  1118. }