stage_audit.js 65 KB

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