safe_stage.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date
  7. * @version
  8. */
  9. const audit = require('../const/audit').common;
  10. const shenpiConst = require('../const/shenpi');
  11. module.exports = app => {
  12. class SafeStage extends app.BaseService {
  13. /**
  14. * 构造函数
  15. *
  16. * @param {Object} ctx - egg全局变量
  17. * @return {void}
  18. */
  19. constructor(ctx) {
  20. super(ctx);
  21. this.tableName = 'safe_stage';
  22. }
  23. calculateStage(data) {
  24. const helper = this.ctx.helper;
  25. const datas = data instanceof Array ? data : [data];
  26. const formatNum = this.ctx.tender.info.display.thousandth ? this.ctx.helper.formatNum : function(num) { return num ? num + '' : ''; };
  27. datas.forEach(x => {
  28. x.end_tp = helper.add(x.tp, x.pre_tp);
  29. for (const prop in x) {
  30. if (prop.indexOf('_tp') > 0) {
  31. x['display_' + prop] = formatNum(x[prop]);
  32. }
  33. }
  34. });
  35. }
  36. /**
  37. * 获取全部修订
  38. * @param tid
  39. * @returns {Promise<*>}
  40. */
  41. async getAllStages (tid, sort = 'ASC') {
  42. const result = await this.getAllDataByCondition({
  43. where: { tid: tid },
  44. orders: [['stage_order', sort]],
  45. });
  46. return result;
  47. }
  48. async getStage(id) {
  49. const result = await this.getDataById(id);
  50. result.decimal = result.bills_decimal ? JSON.parse(result.bills_decimal) : { qty: 3, tp: 2, up: 2};
  51. return result;
  52. }
  53. async getStageByOrder(tid, stage_order) {
  54. const result = await this.getDataByCondition({ tid, stage_order });
  55. result.decimal = result.bills_decimal ? JSON.parse(result.bills_decimal) : { qty: 3, tp: 2, up: 2};
  56. return result;
  57. }
  58. async getMaxOrder(tid) {
  59. const sql = 'SELECT Max(`stage_order`) As max_order FROM ' + this.tableName + ' Where `tid` = ?';
  60. const sqlParam = [tid];
  61. const result = await this.db.queryOne(sql, sqlParam);
  62. return result.max_order || 0;
  63. }
  64. async add(tid, stage_code, stage_date) {
  65. if (!tid) throw '数据错误';
  66. const user_id = this.ctx.session.sessionUser.accountId;
  67. const maxOrder = await this.getMaxOrder(tid);
  68. const data = {
  69. id: this.uuid.v4(), tid: tid, create_user_id: user_id, update_user_id: user_id,
  70. stage_order: maxOrder + 1, stage_code, stage_date,
  71. audit_times: 1, audit_status: audit.status.uncheck,
  72. bills_decimal: JSON.stringify({ up: 2, tp: 2, qty: 3 }),
  73. };
  74. const preStage = maxOrder > 0 ? await this.getStageByOrder(tid, maxOrder) : null;
  75. if (preStage) {
  76. data.pre_bills_tp = this.ctx.helper.add(preStage.bills_tp, preStage.pre_bills_tp);
  77. }
  78. const transaction = await this.db.beginTransaction();
  79. try {
  80. const result = await transaction.insert(this.tableName, data);
  81. if (result.affectedRows !== 1) throw '新增安全计量期失败';
  82. await this.ctx.service.safeStageBills.initStageBills(transaction, data, preStage);
  83. await this.ctx.service.safeStageAudit.copyPreAuditors(transaction, preStage, data);
  84. await transaction.commit();
  85. return data;
  86. } catch(err) {
  87. await transaction.rollback();
  88. throw err;
  89. }
  90. }
  91. async delete(id) {
  92. // const info = await this.getDataById(id);
  93. const conn = await this.db.beginTransaction();
  94. try {
  95. await conn.delete(this.tableName, { id });
  96. await conn.delete(this.ctx.service.safeStageBills.tableName, { stage_id: id });
  97. const files = await this.ctx.service.safeStageFile.getFiles({ where: { stage_id: id} });
  98. for (const f of files) {
  99. this.ctx.app.fujianOss.delete(f.filepath);
  100. }
  101. await conn.delete(this.ctx.service.safeStageFile.tableName, { stage_id: id });
  102. await conn.delete(this.ctx.service.safeStageAudit.tableName, { stage_id: id });
  103. // 记录删除日志
  104. // await this.ctx.service.projectLog.addProjectLog(conn, projectLogConst.type.safeStage, projectLogConst.status.delete, `第${info.phase_order}期`);
  105. await conn.commit();
  106. } catch (err) {
  107. await conn.rollback();
  108. throw err;
  109. }
  110. }
  111. async save(stage, data) {
  112. await this.defaultUpdate({ id: stage.id, stage_date: data.stage_date, stage_code: data.stage_code });
  113. }
  114. async loadUser(safeStage) {
  115. safeStage.user = await this.ctx.service.projectAccount.getAccountInfoById(safeStage.create_user_id);
  116. safeStage.auditors = await this.ctx.service.safeStageAudit.getAuditors(safeStage.id, safeStage.curTimes || safeStage.audit_times);
  117. safeStage.auditorIds = this._.map(safeStage.auditors, 'audit_id');
  118. safeStage.curAuditors = safeStage.auditors.filter(x => { return x.audit_status === audit.status.checking; });
  119. safeStage.curAuditorIds = safeStage.curAuditors.map(x => { return x.audit_id; });
  120. safeStage.flowAuditors = safeStage.curAuditors.length === 0 ? [] : safeStage.auditors.filter(x => { return x.active_order === safeStage.curAuditors[0].active_order; });
  121. safeStage.flowAuditorIds = safeStage.flowAuditors.map(x => { return x.audit_id; });
  122. safeStage.nextAuditors = safeStage.curAuditors.length > 0 ? safeStage.auditors.filter(x => { return x.active_order === safeStage.curAuditors[0].active_order + 1; }) : [];
  123. safeStage.nextAuditorIds = this._.map(safeStage.nextAuditors, 'audit_id');
  124. safeStage.auditorGroups = this.ctx.helper.groupAuditors(safeStage.auditors, 'active_order');
  125. safeStage.userGroups = this.ctx.helper.groupAuditorsUniq(safeStage.auditorGroups);
  126. safeStage.finalAuditorIds = safeStage.userGroups.length > 1 ? safeStage.userGroups[safeStage.userGroups.length - 1].map(x => { return x.audit_id; }) : [];
  127. safeStage.userIds = safeStage.audit_status === audit.status.uncheck // 当前流程下全部参与人id
  128. ? [safeStage.user_id]
  129. : safeStage.auditorIds;
  130. }
  131. async loadAuditViewData(safeStage) {
  132. if (!safeStage.user) safeStage.user = await this.ctx.service.projectAccount.getAccountInfoById(safeStage.user_id);
  133. const auditTimes = safeStage.audit_status === audit.status.checkNo ? safeStage.audit_times - 1 : safeStage.audit_times;
  134. safeStage.auditHistory = await this.ctx.service.safeStageAudit.getAuditorHistory(safeStage.id, auditTimes);
  135. // 获取审批流程中左边列表
  136. if (safeStage.audit_status === audit.status.checkNo && safeStage.create_user_id !== this.ctx.session.sessionUser.accountId) {
  137. const auditors = await this.ctx.service.safeStageAudit.getAuditors(safeStage.id, safeStage.audit_times - 1); // 全部参与的审批人
  138. const auditorGroups = this.ctx.helper.groupAuditors(auditors);
  139. safeStage.hisUserGroup = this.ctx.helper.groupAuditorsUniq(auditorGroups);
  140. } else {
  141. safeStage.hisUserGroup = safeStage.userGroups;
  142. }
  143. }
  144. /**
  145. * cancancel = 0 不可撤回
  146. * cancancel = 1 原报撤回
  147. * cancancel = 2 审批人撤回 审批通过
  148. * cancancel = 3 审批人撤回 审批退回上一人
  149. * cancancel = 4 审批人撤回 退回原报
  150. * cancancel = 5 会签未全部审批通过时,审批人撤回 审批通过
  151. *
  152. * @param safeStage
  153. * @returns {Promise<void>}
  154. */
  155. async doCheckCanCancel(safeStage) {
  156. // 默认不可撤回
  157. safeStage.cancancel = 0;
  158. // 获取当前审批人的上一个审批人,判断是否是当前登录人,并赋予撤回功能,(当审批人存在有审批过时,上一人不允许再撤回)
  159. const status = audit.status;
  160. if (safeStage.audit_status === status.checked || safeStage.audit_status === status.uncheck) return;
  161. const accountId = this.ctx.session.sessionUser.accountId;
  162. if (safeStage.audit_status !== status.checkNo) {
  163. // 找出当前操作人上一个审批人,包括审批完成的和退回上一个审批人的,同时当前操作人为第一人时,就是则为原报
  164. if (safeStage.flowAuditors.find(x => { return x.audit_status !== status.checking}) && safeStage.flowAuditorIds.indexOf(accountId) < 0) return; // 当前流程存在审批人审批通过时,不可撤回
  165. if (safeStage.curAuditorIds.indexOf(accountId) < 0 && safeStage.flowAuditorIds.indexOf(accountId) >= 0) {
  166. safeStage.cancancel = 5; // 会签未全部审批通过时,审批人撤回审批通过
  167. return;
  168. }
  169. const preAuditors = safeStage.curAuditors[0] && safeStage.curAuditors[0].active_order !== 1 ? safeStage.auditors.filter(x => { return x.active_order === safeStage.curAuditors[0].active_order - 1; }) : [];
  170. const preAuditorCheckAgain = preAuditors.find(pa => { return pa.audit_status === status.checkAgain; });
  171. const preAuditorCheckCancel = preAuditors.find(pa => { return pa.audit_status === status.checkCancel; });
  172. const preAuditorHasOld = preAuditors.find(pa => { return pa.is_old === 1; });
  173. const preAuditorIds = (preAuditorCheckAgain ? [] : preAuditors.map(x => { return x.audit_id })); // 重审不可撤回
  174. if ((this._.isEqual(safeStage.flowAuditorIds, preAuditorIds) && preAuditorCheckCancel) || preAuditorHasOld) {
  175. return; // 不可以多次撤回
  176. }
  177. const preAuditChecked = preAuditors.find(pa => { return pa.audit_status === status.checked && pa.audit_id === accountId; });
  178. const preAuditCheckNoPre = preAuditors.find(pa => { return pa.audit_status === status.checkNoPre && pa.audit_id === accountId; });
  179. if (preAuditorIds.indexOf(accountId) >= 0) {
  180. if (preAuditChecked) {
  181. safeStage.cancancel = 2;// 审批人撤回审批通过
  182. } else if (preAuditCheckNoPre) {
  183. safeStage.cancancel = 3;// 审批人撤回审批退回上一人
  184. }
  185. safeStage.preAuditors = preAuditors;
  186. } else if (preAuditors.length === 0 && accountId === safeStage.create_user_id) {
  187. safeStage.cancancel = 1;// 原报撤回
  188. }
  189. } else {
  190. const lastAuditors = await this.ctx.service.safeStageAudit.getAuditors(safeStage.id, safeStage.audit_times - 1);
  191. const onAuditor = this._.findLast(lastAuditors, { audit_status: status.checkNo });
  192. if (onAuditor.audit_id === accountId) {
  193. safeStage.cancancel = 4;// 审批人撤回退回原报
  194. safeStage.preAuditors = lastAuditors.filter(x => { return x.active_order === onAuditor.active_order });
  195. }
  196. }
  197. }
  198. async doCheckStage(safeStage) {
  199. const accountId = this.ctx.session.sessionUser.accountId;
  200. // 审批退回时,原报读取本轮流程,其他人读取上一轮流程
  201. if (safeStage.audit_status === audit.status.checkNo) {
  202. safeStage.curTimes = safeStage.create_user_id === accountId ? safeStage.audit_times : safeStage.audit_times - 1;
  203. } else {
  204. safeStage.curTimes = safeStage.audit_times;
  205. }
  206. // 加载参与人
  207. await this.loadUser(safeStage);
  208. if (safeStage.audit_status === audit.status.uncheck) {
  209. safeStage.readOnly = accountId !== safeStage.create_user_id;
  210. safeStage.curSort = 0;
  211. } else if (safeStage.audit_status === audit.status.checkNo) {
  212. safeStage.readOnly = accountId !== safeStage.create_user_id;
  213. if (!safeStage.readOnly) {
  214. safeStage.curSort = 0;
  215. } else {
  216. const checkNoAudit = await this.service.safeStageAudit.getDataByCondition({
  217. phase_id: safeStage.id, audit_times: safeStage.audit_times - 1, audit_status: audit.status.checkNo,
  218. });
  219. safeStage.curSort = checkNoAudit.active_order;
  220. }
  221. } else if (safeStage.audit_status === audit.status.checked) {
  222. safeStage.readOnly = true;
  223. safeStage.curSort = safeStage.audit_max_sort;
  224. } else {
  225. // 会签,会签人部分审批通过时,只读,但是curSort需按原来的取值
  226. safeStage.curSort = safeStage.flowAuditorIds.indexOf(accountId) >= 0 ? safeStage.curAuditors[0].active_order : safeStage.curAuditors[0].active_order - 1;
  227. safeStage.readOnly = safeStage.curAuditorIds.indexOf(accountId) < 0;
  228. safeStage.canCheck = safeStage.readOnly && safeStage.curAuditorIds.indexOf(accountId) > 0;
  229. }
  230. await this.doCheckCanCancel(safeStage);
  231. }
  232. async checkShenpi(safeStage) {
  233. const status = audit.status;
  234. const info = this.ctx.tender.info;
  235. const shenpi_status = info.shenpi.safe_stage;
  236. if ((safeStage.audit_status === status.uncheck || safeStage.audit_status === status.checkNo) && shenpi_status !== shenpiConst.sp_status.sqspr) {
  237. // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
  238. const auditList = await this.ctx.service.safeStageAudit.getAllDataByCondition({ where: { phase_id: safeStage.id, audit_times: safeStage.audit_times }, orders: [['audit_order', 'asc']] });
  239. auditList.shift();
  240. if (shenpi_status === shenpiConst.sp_status.gdspl) {
  241. const shenpiList = await this.ctx.service.shenpiAudit.getAllDataByCondition({ where: { tid: safeStage.tid, sp_type: shenpiConst.sp_type.safe_payment, sp_status: shenpi_status } });
  242. // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
  243. let sameAudit = auditList.length === shenpiList.length;
  244. if (sameAudit) {
  245. for (const audit of auditList) {
  246. const shenpi = shenpiList.find(x => { return x.audit_id === audit.audit_id; });
  247. if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
  248. sameAudit = false;
  249. break;
  250. }
  251. }
  252. }
  253. if (!sameAudit) {
  254. await this.ctx.service.safeStageAudit.updateNewAuditList(safeStage, shenpiList);
  255. await this.loadUser(safeStage);
  256. }
  257. } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
  258. const shenpiInfo = await this.ctx.service.shenpiAudit.getDataByCondition({ tid: safeStage.tid, sp_type: shenpiConst.sp_type.safe_payment, sp_status: shenpi_status });
  259. // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
  260. const lastAuditors = auditList.filter(x => { x.active_order === auditList.active_order; });
  261. if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].audit_id))) {
  262. await this.ctx.service.safeStageAudit.updateLastAudit(safeStage, auditList, shenpiInfo.audit_id);
  263. await this.loadUser(safeStage);
  264. } else if (!shenpiInfo) {
  265. // 不存在终审人的状态下这里恢复为授权审批人
  266. this.ctx.tender.info.shenpi.safe_stage = shenpiConst.sp_status.sqspr;
  267. }
  268. }
  269. }
  270. }
  271. }
  272. return SafeStage;
  273. };