contract_sp_audit.js 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date 2018/8/14
  7. * @version
  8. */
  9. const auditConst = require('../const/audit').contract;
  10. const auditType = require('../const/audit').auditType;
  11. // const pushType = require('../const/audit').pushType;
  12. const shenpiConst = require('../const/sp_shenpi');
  13. const contractConst = require('../const/contract');
  14. module.exports = app => {
  15. class ContractSpAudit extends app.BaseService {
  16. /**
  17. * 构造函数
  18. *
  19. * @param {Object} ctx - egg全局变量
  20. * @return {void}
  21. */
  22. constructor(ctx) {
  23. super(ctx);
  24. this.tableName = 'contract_sp_audit';
  25. }
  26. async checkShenpi(contract, type = 'contract') {
  27. const cid = contract.cid ? contract.cid : contract.id;
  28. const cpid = type === 'pay' ? contract.id : null;
  29. const csid = type === 'supplement' ? contract.id : null;
  30. const change_type = type === 'contract' || type === 'supplement' ? 'contract' : contractConst.typeMap[contract.contract_type];
  31. const tableName = {
  32. contract: this.ctx.service.contract,
  33. pay: this.ctx.service.contractPay,
  34. supplement: this.ctx.service.contractSupplement,
  35. }[type];
  36. const status = auditConst.status;
  37. let shenpi = '';
  38. if (this.ctx.contract_tender) {
  39. const tenderInfo = await this.ctx.service.tenderInfo.getTenderInfo(this.ctx.contract.id);
  40. shenpi = tenderInfo ? tenderInfo.shenpi : '';
  41. } else {
  42. shenpi = this.ctx.subProject.shenpi;
  43. }
  44. const shenpi_status = shenpi.contract;
  45. if ((contract.status === status.uncheck || contract.status === status.checkNo) && shenpi_status !== shenpiConst.sp_status.sqspr) {
  46. // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
  47. const auditList = await this.getAllDataByCondition({ where: { cid, cpid, csid, times: contract.times }, orders: [['order', 'asc']] });
  48. // auditList.shift();
  49. if (shenpi_status === shenpiConst.sp_status.gdspl) {
  50. // 判断并获取审批组
  51. const group = await this.ctx.service.shenpiGroup.getSelectGroupByChangeType(this.ctx.contract.id, shenpiConst.sp_type.contract, change_type, contract.sp_group);
  52. if ((group && contract.sp_group !== group.id) || (!group && contract.sp_group !== 0)) {
  53. contract.sp_group = group ? group.id : 0;
  54. await tableName.defaultUpdate({ id: contract.id, sp_group: contract.sp_group });
  55. }
  56. const condition = this._.assign({ sp_type: shenpiConst.sp_type.contract, sp_status: shenpi_status, sp_group: contract.sp_group }, this.ctx.contractOptions);
  57. const shenpiList = await this.ctx.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
  58. if (contract.sp_group !== 0 || shenpiList.length !== 0) {
  59. // const shenpiIdList = _.map(shenpiList, 'audit_id');
  60. // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
  61. let sameAudit = auditList.length === shenpiList.length;
  62. if (sameAudit) {
  63. for (const audit of auditList) {
  64. const shenpi = shenpiList.find(x => { return x.audit_id === audit.aid; });
  65. if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
  66. sameAudit = false;
  67. break;
  68. }
  69. }
  70. }
  71. if (!sameAudit) {
  72. await this.updateNewAuditList(contract, type, shenpiList);
  73. await this.loadUser(contract, type);
  74. await this.loadAuditViewData(contract, type);
  75. }
  76. }
  77. } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
  78. const shenpiInfo = await this.service.shenpiAudit.getDataByCondition(this._.assign({ sp_type: shenpiConst.sp_type.contract, sp_status: shenpi_status }, this.ctx.contractOptions));
  79. // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
  80. const lastAuditors = auditList.filter(x => { return x.audit_order === auditList.length - 1; });
  81. if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].aid))) {
  82. await this.updateLastAudit(contract, type, auditList, shenpiInfo.audit_id);
  83. } else if (!shenpiInfo) {
  84. // 不存在终审人的状态下这里恢复为授权审批人
  85. shenpi.contract = shenpiConst.sp_status.sqspr;
  86. }
  87. }
  88. }
  89. }
  90. async loadUser(contract, type = 'contract') {
  91. const status = auditConst.status;
  92. const accountId = this.ctx.session.sessionUser.accountId;
  93. contract.user = await this.ctx.service.projectAccount.getAccountInfoById(contract.uid);
  94. contract.auditors = await this.getAuditors(contract, type, contract.times); // 全部参与的审批人
  95. contract.auditorIds = this._.map(contract.auditors, 'aid');
  96. contract.curAuditors = contract.auditors.filter(x => { return x.status === status.checking; }); // 当前流程中审批中的审批人
  97. contract.curAuditorIds = this._.map(contract.curAuditors, 'aid');
  98. contract.flowAuditors = contract.curAuditors.length > 0 ? contract.auditors.filter(x => { return x.order === contract.curAuditors[0].order; }) : []; // 当前流程中参与的审批人(包含会签时,审批通过的人)
  99. contract.flowAuditorIds = this._.map(contract.flowAuditors, 'aid');
  100. contract.nextAuditors = contract.curAuditors.length > 0 ? contract.auditors.filter(x => { return x.order === contract.curAuditors[0].order + 1; }) : [];
  101. contract.nextAuditorIds = this._.map(contract.nextAuditors, 'aid');
  102. contract.auditorGroups = this.ctx.helper.groupAuditors(contract.auditors);
  103. contract.userGroups = this.ctx.helper.groupAuditorsUniq(contract.auditorGroups);
  104. contract.finalAuditorIds = this._.map(contract.userGroups[contract.userGroups.length - 1], 'aid');
  105. }
  106. async loadAuditViewData(contract, type = 'contract') {
  107. const times = contract.status === auditConst.status.checkNo ? contract.times - 1 : contract.times;
  108. if (!contract.user) contract.user = await this.ctx.service.projectAccount.getAccountInfoById(contract.uid);
  109. contract.auditHistory = await this.getAuditorHistory(contract, type, times);
  110. // 获取审批流程中左边列表
  111. // if ((contract.status === auditConst.status.checkNo) && !(contract.uid === this.ctx.session.sessionUser.accountId || this.ctx.contract_audit_permission.permission_edit_contract || this.ctx.session.sessionUser.is_admin)) {
  112. const auditors = await this.getAuditors(contract, type, times); // 全部参与的审批人
  113. const auditorGroups = this.ctx.helper.groupAuditors(auditors);
  114. contract.auditors2 = this.ctx.helper.groupAuditorsUniq(auditorGroups);
  115. // } else {
  116. // contract.auditors2 = contract.userGroups;
  117. // }
  118. if (contract.status === auditConst.status.uncheck || contract.status === auditConst.status.checkNo) {
  119. contract.auditorList = await this.getAuditors(contract, type, contract.times);
  120. }
  121. }
  122. /**
  123. * 获取 审核列表信息
  124. *
  125. * @param {Number} cpId - 变更立项id
  126. * @param {Number} times - 第几次审批
  127. * @return {Promise<*>}
  128. */
  129. async getAuditors(contract, type, times = 1, order_sort = 'asc', noYB = false) {
  130. // const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, g.`sort` ' +
  131. // 'FROM ?? AS la, ?? AS pa, (SELECT t1.`aid`,(@i:=@i+1) as `sort` FROM (SELECT t.`aid`, t.`order` FROM (select `aid`, `order` from ?? WHERE `cpid` = ? AND `times` = ? ORDER BY `order` LIMIT 200) t GROUP BY t.`aid` ORDER BY t.`order`) t1, (select @i:=0) as it) as g ' +
  132. // 'WHERE la.`cpid` = ? and la.`times` = ? and la.`aid` = pa.`id` and g.`aid` = la.`aid` order by la.`order`';
  133. // const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.tableName, cpId, times, cpId, times];
  134. // const result = await this.db.query(sql, sqlParam);
  135. // const sql2 = 'SELECT COUNT(a.`aid`) as num FROM (SELECT `aid` FROM ?? WHERE `cpid` = ? AND `times` = ? GROUP BY `aid`) as a';
  136. // const sqlParam2 = [this.tableName, cpId, times];
  137. // const count = await this.db.queryOne(sql2, sqlParam2);
  138. // for (const i in result) {
  139. // result[i].max_sort = count.num;
  140. // }
  141. const cid = contract.cid ? contract.cid : contract.id;
  142. const cpid = type === 'pay' ? contract.id : null;
  143. const csid = type === 'supplement' ? contract.id : null;
  144. const cpidSql = type === 'pay'
  145. ? ' AND la.cpid = ' + cpid
  146. : ' AND la.cpid is null';
  147. const csidSql = type === 'supplement'
  148. ? ' AND la.csid = ' + csid
  149. : ' AND la.csid is null';
  150. const ybSql = noYB ? ' AND la.audit_order != 0' : '';
  151. const sql = 'SELECT la.id, la.aid, la.times, la.order, la.status, la.opinion, la.begin_time, la.end_time, la.audit_type, la.audit_order,' +
  152. ' pa.name, pa.company, pa.role, pa.mobile, pa.telephone' +
  153. ` FROM ${this.tableName} la LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON la.aid = pa.id` +
  154. ' WHERE la.cid = ?' + cpidSql + csidSql + ' AND la.times = ?' + ybSql +
  155. ' ORDER BY la.order ' + order_sort;
  156. const sqlParam = [cid, times];
  157. const result = await this.db.query(sql, sqlParam);
  158. const max_sort = this._.max(result.map(x => { return x.audit_order; }));
  159. for (const i in result) {
  160. result[i].max_sort = max_sort;
  161. }
  162. return result;
  163. }
  164. /**
  165. * 获取 当前审核人
  166. *
  167. * @param {Number} cpId - 变更立项id
  168. * @param {Number} times - 第几次审批
  169. * @return {Promise<*>}
  170. */
  171. async getCurAuditor(contract, type, times = 1) {
  172. const cid = contract.cid ? contract.cid : contract.id;
  173. const cpid = type === 'pay' ? contract.id : null;
  174. const csid = type === 'supplement' ? contract.id : null;
  175. const cpidSql = type === 'pay'
  176. ? ' AND la.cpid = ' + cpid
  177. : ' AND la.cpid is null';
  178. const csidSql = type === 'supplement'
  179. ? ' AND la.csid = ' + csid
  180. : ' AND la.csid is null';
  181. const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
  182. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
  183. ' WHERE la.`cid` = ?' + cpidSql + csidSql + ' and la.`status` = ? and la.`times` = ? and la.`audit_order` != 0';
  184. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, auditConst.status.checking, times];
  185. return await this.db.queryOne(sql, sqlParam);
  186. }
  187. async getCurAuditors(contract, type, times = 1) {
  188. const cid = contract.cid ? contract.cid : contract.id;
  189. const cpid = type === 'pay' ? contract.id : null;
  190. const csid = type === 'supplement' ? contract.id : null;
  191. const cpidSql = type === 'pay'
  192. ? ' AND la.cpid = ' + cpid
  193. : ' AND la.cpid is null';
  194. const csidSql = type === 'supplement'
  195. ? ' AND la.csid = ' + csid
  196. : ' AND la.csid is null';
  197. const sql =
  198. 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, la.audit_type, la.audit_order ' +
  199. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
  200. ' WHERE la.`cid` = ?' + cpidSql + csidSql + ' and la.`status` = ? and la.`times` = ? and la.`audit_order` != 0';
  201. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, auditConst.status.checking, times];
  202. return await this.db.query(sql, sqlParam);
  203. }
  204. /**
  205. * 获取审核人流程列表
  206. *
  207. * @param auditorId
  208. * @return {Promise<*>}
  209. */
  210. // async getAuditGroupByList(cid, cpid = null, times, noYB = true, transaction = false) {
  211. // const cpidSql = cpid ? ' AND la.cpid = ' + cpid : ' AND la.cpid is null';
  212. // const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`cpid`, la.`aid`, la.`order`, la.`status`, la.audit_type, la.audit_order ' +
  213. // ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
  214. // ' WHERE la.`cid` = ?' + cpidSql + ' and la.`times` = ? GROUP BY la.`aid` ORDER BY la.`order`';
  215. // const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, times];
  216. // return transaction !== false ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);
  217. // }
  218. /**
  219. * 获取审核人流程列表(除去原报)
  220. *
  221. * @param auditorId
  222. * @return {Promise<*>}
  223. */
  224. async getAuditGroupByList(contract, type, times, transaction = false) {
  225. const cid = contract.cid ? contract.cid : contract.id;
  226. const cpid = type === 'pay' ? contract.id : null;
  227. const csid = type === 'supplement' ? contract.id : null;
  228. const cpidSql = type === 'pay'
  229. ? ' AND la.cpid = ' + cpid
  230. : ' AND la.cpid is null';
  231. const csidSql = type === 'supplement'
  232. ? ' AND la.csid = ' + csid
  233. : ' AND la.csid is null';
  234. const sql =
  235. 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`cpid`, la.`aid`, la.`order`, la.`status`, la.audit_type, la.audit_order ' +
  236. ' FROM (SELECT `aid`, max(`order`) `order` FROM ?? WHERE `cid` = ? and `cpid` ' + (cpid ? '= ' + cpid : 'is null') + ' and `csid` ' + (csid ? '= ' + csid : 'is null') + ' and `times` = ? and `audit_order` != 0 GROUP BY aid) sa' +
  237. ' LEFT JOIN ?? la ON sa.`aid` = la.`aid` AND sa.`order` = la.`order`' +
  238. ' Left JOIN ?? AS pa On la.`aid` = pa.`id` WHERE la.`cid` = ?' + cpidSql + csidSql + ' and la.`times` = ? and la.`audit_order` != 0 order BY la.`order`';
  239. const sqlParam = [this.tableName, cid, times, this.tableName, this.ctx.service.projectAccount.tableName, cid, times];
  240. return transaction !== false ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);
  241. }
  242. /**
  243. * 移除审核人
  244. *
  245. * @param {Number} materialId - 材料调差期id
  246. * @param {Number} status - 期状态
  247. * @param {Number} status - 期次数
  248. * @return {Promise<boolean>}
  249. */
  250. async getAuditorByStatus(contract, type, status, times = 1) {
  251. const cid = contract.cid ? contract.cid : contract.id;
  252. const cpid = type === 'pay' ? contract.id : null;
  253. const csid = type === 'supplement' ? contract.id : null;
  254. const cpidSql = type === 'pay'
  255. ? ' AND la.cpid = ' + cpid
  256. : ' AND la.cpid is null';
  257. const csidSql = type === 'supplement'
  258. ? ' AND la.csid = ' + csid
  259. : ' AND la.csid is null';
  260. let auditor = null;
  261. let sql = '';
  262. let sqlParam = '';
  263. switch (status) {
  264. case auditConst.status.checking :
  265. case auditConst.status.checked :
  266. sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`cpid`, la.`aid`, la.`order`, la.`status` ' +
  267. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
  268. ' WHERE la.`cid` = ?' + cpidSql + csidSql + ' and la.`status` = ? ' +
  269. ' ORDER BY la.`times` desc, la.`order` desc';
  270. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, status];
  271. auditor = await this.db.queryOne(sql, sqlParam);
  272. break;
  273. case auditConst.status.checkNo :
  274. sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`cpid`, la.`aid`, la.`order`, la.`status` ' +
  275. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
  276. ' WHERE la.`cid` = ?' + cpidSql + csidSql + ' and la.`status` = ? and la.`times` = ?' +
  277. ' ORDER BY la.`times` desc, la.`order` desc';
  278. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, auditConst.status.checkNo, parseInt(times) - 1];
  279. auditor = await this.db.queryOne(sql, sqlParam);
  280. break;
  281. case auditConst.status.uncheck :
  282. break;
  283. default:break;
  284. }
  285. return auditor;
  286. }
  287. async getAuditorsByStatus(contract, type, status, times = 1) {
  288. const cid = contract.cid ? contract.cid : contract.id;
  289. const cpid = type === 'pay' ? contract.id : null;
  290. const csid = type === 'supplement' ? contract.id : null;
  291. const cpidSql = type === 'pay'
  292. ? ' AND la.cpid = ' + cpid
  293. : ' AND la.cpid is null';
  294. const csidSql = type === 'supplement'
  295. ? ' AND la.csid = ' + csid
  296. : ' AND la.csid is null';
  297. let auditor = [];
  298. let sql = '';
  299. let sqlParam = '';
  300. let cur;
  301. switch (status) {
  302. case auditConst.status.checking :
  303. case auditConst.status.checked :
  304. case auditConst.status.checkNoPre:
  305. cur = await this.db.queryOne('SELECT * From ?? where cid = ? AND cpid ' + (cpid ? '= ' + cpid : 'is null') + ' AND csid ' + (csid ? '= ' + csid : 'is null') + ' AND times = ? AND status = ? AND audit_order != 0 ORDER By times DESC, `order` DESC', [this.tableName, cid, times, status]);
  306. if (!cur) return [];
  307. sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`cpid`, la.`order`, la.`status`, la.`audit_order`, la.`audit_type` ' +
  308. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
  309. ' WHERE la.`cid` = ?' + cpidSql + csidSql + ' and la.`order` = ? and times = ?';
  310. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, cur.order, times];
  311. auditor = await this.db.query(sql, sqlParam);
  312. break;
  313. case auditConst.status.checkNo :
  314. cur = await this.db.queryOne('SELECT * From ?? where cid = ? AND cpid ' + (cpid ? '= ' + cpid : 'is null') + ' AND csid ' + (csid ? '= ' + csid : 'is null') + ' AND times = ? AND status = ? AND audit_order != 0 ORDER By times DESC, `order` DESC', [this.tableName, cid, parseInt(times) - 1, status]);
  315. if (!cur) return [];
  316. sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`cpid`, la.`order`, la.`status`, la.`audit_order`, la.`audit_type` ' +
  317. ' FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
  318. ' WHERE la.`cid` = ?' + cpidSql + csidSql + ' and la.`order` = ? and la.`times` = ?';
  319. sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, cur.order, parseInt(times) - 1];
  320. auditor = await this.db.query(sql, sqlParam);
  321. break;
  322. case auditConst.status.uncheck:
  323. default:
  324. break;
  325. }
  326. return auditor;
  327. }
  328. async getLastAudit(contract, type, times, transaction = null) {
  329. const cid = contract.cid ? contract.cid : contract.id;
  330. const cpid = type === 'pay' ? contract.id : null;
  331. const csid = type === 'supplement' ? contract.id : null;
  332. const cpidSql = type === 'pay'
  333. ? ' AND cpid = ' + cpid
  334. : ' AND cpid is null';
  335. const csidSql = type === 'supplement'
  336. ? ' AND csid = ' + csid
  337. : ' AND csid is null';
  338. const sql = 'SELECT * FROM ?? WHERE `cid` = ?' + cpidSql + csidSql + ' AND `times` = ? ORDER BY `order` DESC';
  339. const sqlParam = [this.tableName, cid, times];
  340. return transaction ? await transaction.queryOne(sql, sqlParam) : await this.db.queryOne(sql, sqlParam);
  341. }
  342. /**
  343. * 获取审核人流程列表(包括原报)
  344. * @param {Number} materialId 调差id
  345. * @param {Number} times 审核次数
  346. * @return {Promise<Array>} 查询结果集(包括原报)
  347. */
  348. async getAuditorsWithOwner(contract, type, times = 1) {
  349. // const cpidSql = cpid ? ' AND la.cpid = ' + cpid : ' AND la.cpid is null';
  350. const result = await this.getAuditGroupByList(contract, type, times);
  351. // const sql =
  352. // 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As cpid, 0 As `order`' +
  353. // ' FROM ' +
  354. // this.ctx.service.changePlan.tableName +
  355. // ' As s' +
  356. // ' LEFT JOIN ' +
  357. // this.ctx.service.projectAccount.tableName +
  358. // ' As pa' +
  359. // ' ON s.uid = pa.id' +
  360. // ' WHERE s.id = ?';
  361. // const sqlParam = [times, cid, cid];
  362. // const user = await this.db.queryOne(sql, sqlParam);
  363. // result.unshift(user);
  364. return result;
  365. }
  366. /**
  367. * 新增审核人
  368. *
  369. * @param {Number} cpId - 方案id
  370. * @param {Number} auditorId - 审核人id
  371. * @param {Number} times - 第几次审批
  372. * @return {Promise<number>}
  373. */
  374. async addAuditor(options, contract, type, auditorId, times = 1, is_gdzs = 0) {
  375. const cid = contract.cid ? contract.cid : contract.id;
  376. const cpid = type === 'pay' ? contract.id : null;
  377. const csid = type === 'supplement' ? contract.id : null;
  378. const transaction = await this.db.beginTransaction();
  379. let flag = false;
  380. try {
  381. let [newOrder, newAuditOrder] = await this.getNewOrder(contract, type, times);
  382. // 判断是否存在固定终审,存在则newOrder - 1并使终审order+1
  383. newOrder = is_gdzs === 1 ? newOrder - 1 : newOrder;
  384. newAuditOrder = is_gdzs === 1 ? newAuditOrder - 1 : newAuditOrder;
  385. if (is_gdzs) await this._syncOrderByDelete(transaction, contract, type, newOrder, times, '+');
  386. const data = {
  387. spid: options.spid || null,
  388. tid: options.tid || null,
  389. cid,
  390. cpid,
  391. csid,
  392. aid: auditorId,
  393. times,
  394. order: newOrder,
  395. status: auditConst.status.uncheck,
  396. audit_order: newAuditOrder,
  397. };
  398. const result = await transaction.insert(this.tableName, data);
  399. await this.ctx.service.contractAudit.saveAudits(options, [{ id: auditorId }], transaction);
  400. await transaction.commit();
  401. flag = result.effectRows = 1;
  402. } catch (err) {
  403. await transaction.rollback();
  404. throw err;
  405. }
  406. return flag;
  407. }
  408. /**
  409. * 获取 最新审核顺序
  410. *
  411. * @param {Number} cpId - 方案id
  412. * @param {Number} times - 第几次审批
  413. * @return {Promise<number>}
  414. */
  415. async getNewOrder(contract, type, times = 1) {
  416. const cid = contract.cid ? contract.cid : contract.id;
  417. const cpid = type === 'pay' ? contract.id : null;
  418. const csid = type === 'supplement' ? contract.id : null;
  419. const cpidSql = type === 'pay'
  420. ? ' AND cpid = ' + cpid
  421. : ' AND cpid is null';
  422. const csidSql = type === 'supplement'
  423. ? ' AND csid = ' + csid
  424. : ' AND csid is null';
  425. const sql = 'SELECT Max(`order`) As max_order, Max(audit_order) As max_audit_order FROM ?? Where `cid` = ?' + cpidSql + csidSql + ' and `times` = ?';
  426. const sqlParam = [this.tableName, cid, times];
  427. const result = await this.db.queryOne(sql, sqlParam);
  428. return result && result.max_order ? [result.max_order + 1, result.max_audit_order + 1] : [1, 1];
  429. }
  430. /**
  431. * 移除审核人
  432. *
  433. * @param {Number} cpId - 变更方案id
  434. * @param {Number} auditorId - 审核人id
  435. * @param {Number} times - 第几次审批
  436. * @return {Promise<boolean>}
  437. */
  438. async deleteAuditor(contract, type, auditorId, times = 1) {
  439. const transaction = await this.db.beginTransaction();
  440. try {
  441. const cid = contract.cid ? contract.cid : contract.id;
  442. const cpid = type === 'pay' ? contract.id : null;
  443. const csid = type === 'supplement' ? contract.id : null;
  444. const cpidSql = type === 'pay'
  445. ? ' AND cpid = ' + cpid
  446. : ' AND cpid is null';
  447. const csidSql = type === 'supplement'
  448. ? ' AND csid = ' + csid
  449. : ' AND csid is null';
  450. const sql = 'SELECT * FROM ?? WHERE `cid` = ?' + cpidSql + csidSql + ' and `times` = ? and `aid` = ? and `audit_order` != 0 ORDER BY `order` DESC';
  451. const sqlParam = [this.tableName, cid, times, auditorId];
  452. const auditor = await transaction.queryOne(sql, sqlParam);
  453. // const condition = { cid, cpid, aid: auditorId, times };
  454. // const auditor = await this.getDataByCondition(condition);
  455. if (!auditor) {
  456. throw '该审核人不存在';
  457. }
  458. await transaction.delete(this.tableName, { cid, cpid, csid, order: auditor.order, times });
  459. await this._syncOrderByDelete(transaction, contract, type, auditor.order, times);
  460. await transaction.commit();
  461. } catch (err) {
  462. await transaction.rollback();
  463. throw err;
  464. }
  465. return true;
  466. }
  467. /**
  468. * 移除审核人时,同步其后审核人order
  469. * @param transaction - 事务
  470. * @param {Number} cpId - 变更方案id
  471. * @param {Number} auditorId - 审核人id
  472. * @param {Number} times - 第几次审批
  473. * @return {Promise<*>}
  474. * @private
  475. */
  476. async _syncOrderByDelete(transaction, contract, type, order, times, selfOperate = '-') {
  477. const cid = contract.cid ? contract.cid : contract.id;
  478. const cpid = type === 'pay' ? contract.id : null;
  479. const csid = type === 'supplement' ? contract.id : null;
  480. const sql = 'UPDATE ?? SET `order` = `order` ' + selfOperate + ' ?, `audit_order` = `audit_order` ' + selfOperate + ' ? WHERE `cid` = ? AND `cpid` ' + (cpid ? '= ' + cpid : 'is null') + ' AND `csid` ' + (csid ? '= ' + csid : 'is null') + ' AND `order` >= ? AND `times` = ?';
  481. const sqlParam = [this.tableName, 1, 1, cid, order, times];
  482. const data = await transaction.query(sql, sqlParam);
  483. return data;
  484. }
  485. /**
  486. * 开始审批
  487. * @param {Number} cpId - 方案id
  488. * @param {Number} times - 第几次审批
  489. * @return {Promise<boolean>}
  490. */
  491. async start(options, shenpi, contract, type, times = 1) {
  492. const cid = contract.cid ? contract.cid : contract.id;
  493. const cpid = type === 'pay' ? contract.id : null;
  494. const csid = type === 'supplement' ? contract.id : null;
  495. const audits = await this.getAllDataByCondition({ where: { cid, cpid, csid, times, order: 1 } });
  496. if (audits.length === 0) {
  497. if (shenpi.contract === shenpiConst.sp_status.gdspl) {
  498. throw '请联系管理员添加审批人';
  499. } else {
  500. throw '请先选择审批人,再上报数据';
  501. }
  502. }
  503. const transaction = await this.db.beginTransaction();
  504. try {
  505. const begin_time = new Date();
  506. const data = {
  507. spid: options.spid || null,
  508. tid: options.tid || null,
  509. cid,
  510. cpid,
  511. csid,
  512. aid: this.ctx.session.sessionUser.accountId,
  513. times,
  514. order: 0,
  515. status: auditConst.status.checked,
  516. begin_time,
  517. end_time: begin_time,
  518. audit_order: 0,
  519. };
  520. const result = await transaction.insert(this.tableName, data);
  521. const updateData = audits.map(x => { return { id: x.id, status: auditConst.status.checking, begin_time }; });
  522. await transaction.updateRows(this.tableName, updateData);
  523. if (cpid) {
  524. await transaction.update(this.ctx.service.contractPay.tableName, {
  525. id: cpid, status: auditConst.status.checking,
  526. });
  527. } else if (csid) {
  528. await transaction.update(this.ctx.service.contractSupplement.tableName, {
  529. id: csid, status: auditConst.status.checking,
  530. });
  531. } else {
  532. await transaction.update(this.ctx.service.contract.tableName, {
  533. id: cid, status: auditConst.status.checking,
  534. });
  535. }
  536. await transaction.commit();
  537. } catch (err) {
  538. await transaction.rollback();
  539. throw err;
  540. }
  541. return true;
  542. }
  543. /**
  544. * 获取审核人需要审核的期列表
  545. *
  546. * @param auditorId
  547. * @return {Promise<*>}
  548. */
  549. async getAuditList(options, auditorId) {
  550. const optionsSql = options.spid ? 'c.spid = "' + options.spid + '"' : 'c.tid = ' + options.tid;
  551. const sql = 'SELECT c.`id`, c.`uid`, c.`status`' +
  552. ' FROM ?? AS c LEFT JOIN ?? AS ca ON c.`id` = ca.`cid`' +
  553. ' WHERE ' + optionsSql + ' AND ca.`aid` = ?';
  554. const sqlParam = [this.ctx.service.contract.tableName, this.tableName, auditorId];
  555. const result = await this.db.query(sql, sqlParam);
  556. // 过滤result中存在重复sid的值, 保留最新的一条
  557. const filterResult = [];
  558. const idArr = [];
  559. for (const r of result) {
  560. if (idArr.indexOf(r.id) === -1 && r.status !== auditConst.status.uncheck) {
  561. filterResult.push(r);
  562. idArr.push(r.id);
  563. }
  564. }
  565. return filterResult;
  566. }
  567. /**
  568. * 获取审核人审核的次数
  569. *
  570. * @param auditorId
  571. * @return {Promise<*>}
  572. */
  573. async getCountByChecked(auditorId, spid = '') {
  574. if (spid) {
  575. const sql = 'SELECT count(*) AS count FROM ?? AS a LEFT JOIN ?? AS t ON a.tid = t.id WHERE a.`aid` = ? AND a.`status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ') AND t.`spid` = ?';
  576. const sqlParam = [this.tableName, this.ctx.service.tender.tableName, auditorId, spid];
  577. const result = await this.db.queryOne(sql, sqlParam);
  578. return result.count ? result.count : 0;
  579. }
  580. return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });
  581. }
  582. /**
  583. * 获取最近一次审批结束时间
  584. *
  585. * @param auditorId
  586. * @return {Promise<*>}
  587. */
  588. async getLastEndTimeByChecked(auditorId, spid = '') {
  589. const sqSql = spid ? ' AND t.`spid` = "' + spid + '"' : '';
  590. const sql = 'SELECT a.`end_time` FROM ?? AS a LEFT JOIN ?? AS t ON a.`tid` = t.`id` WHERE a.`aid` = ? ' +
  591. 'AND a.`status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo]) + ')' + sqSql +
  592. ' ORDER BY a.`end_time` DESC';
  593. const sqlParam = [this.tableName, this.ctx.service.tender.tableName, auditorId];
  594. const result = await this.db.queryOne(sql, sqlParam);
  595. return result ? result.end_time : null;
  596. }
  597. /**
  598. * 用于添加推送所需的content内容
  599. * @param {Number} pid 项目id
  600. * @param {Number} tid 台账id
  601. * @param {Number} cpId 方案id
  602. * @param {Number} uid 审批人id
  603. */
  604. async getNoticeContent(pid, tid, cpId, uid, opinion = '') {
  605. const noticeSql = 'SELECT * FROM (SELECT ' +
  606. ' t.`id` As `tid`, ma.`cpid`, m.`code` as `c_code`, t.`name`, pa.`name` As `su_name`, pa.role As `su_role`' +
  607. ' FROM (SELECT * FROM ?? WHERE `id` = ? ) As t' +
  608. ' LEFT JOIN ?? As m On t.`id` = m.`tid` AND m.`id` = ?' +
  609. ' LEFT JOIN ?? As ma ON m.`id` = ma.`cpid`' +
  610. ' LEFT JOIN ?? As pa ON pa.`id` = ?' +
  611. ' WHERE t.`project_id` = ? ) as new_t GROUP BY new_t.`tid`';
  612. const noticeSqlParam = [this.ctx.service.tender.tableName, tid, this.ctx.service.changePlan.tableName, cpId, this.tableName, this.ctx.service.projectAccount.tableName, uid, pid];
  613. const content = await this.db.query(noticeSql, noticeSqlParam);
  614. if (content.length) {
  615. content[0].opinion = opinion;
  616. }
  617. return content.length ? JSON.stringify(content[0]) : '';
  618. }
  619. /**
  620. * 审批
  621. * @param {Number} cpId - 方案id
  622. * @param {auditConst.status.checked|auditConst.status.checkNo} checkType - 审批结果
  623. * @param {Number} times - 第几次审批
  624. * @return {Promise<void>}
  625. */
  626. async check(contract, type, checkData) {
  627. if (!this._.includes([auditConst.status.checked, auditConst.status.checkNo, auditConst.status.checkNoPre], checkData.checkType)) {
  628. throw '提交数据错误';
  629. }
  630. const pid = this.ctx.session.sessionProject.id;
  631. switch (checkData.checkType) {
  632. case auditConst.status.checked:
  633. await this._checked(pid, contract, type, checkData);
  634. break;
  635. case auditConst.status.checkNo:
  636. await this._checkNo(pid, contract, type, checkData);
  637. break;
  638. case auditConst.status.checkNoPre:
  639. await this._checkNoPre(pid, contract, type, checkData);
  640. break;
  641. default:
  642. throw '无效审批操作';
  643. }
  644. }
  645. async _checked(pid, contract, type, checkData) {
  646. const accountId = this.ctx.session.sessionUser.accountId;
  647. const time = new Date();
  648. const tableName = {
  649. contract: this.ctx.service.contract.tableName,
  650. pay: this.ctx.service.contractPay.tableName,
  651. supplement: this.ctx.service.contractSupplement.tableName,
  652. }[type];
  653. // 整理当前流程审核人状态更新
  654. if (contract.curAuditorIds.length === 0) throw '审核数据错误';
  655. if (!this._.includes(contract.curAuditorIds, accountId)) throw '当前标段您无权审批';
  656. const flowAudits = contract.flowAuditors;
  657. const selfAudit = this._.find(flowAudits, { aid: accountId });
  658. const nextAudits = contract.nextAuditors;
  659. const transaction = await this.db.beginTransaction();
  660. try {
  661. // 更新本人审批状态
  662. await transaction.update(this.tableName, {
  663. id: selfAudit.id,
  664. status: checkData.checkType,
  665. opinion: checkData.opinion,
  666. end_time: time,
  667. });
  668. // await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, selfAudit.id);
  669. // 获取推送必要信息
  670. // const noticeContent = await this.getNoticeContent(pid, selfAudit.tid, cpId, selfAudit.aid, checkData.opinion);
  671. // 添加推送
  672. // const records = [];
  673. // const auditors = await this.getAuditorsWithOwner(cpId, times);
  674. // auditors.forEach(audit => {
  675. // records.push({ pid, tid: selfAudit.tid, type: pushType.changePlan, uid: audit.aid, status: auditConst.status.checked, content: noticeContent });
  676. // });
  677. // await transaction.insert('zh_notice', records);
  678. if (contract.curAuditors.length === 1 || selfAudit.audit_type !== auditType.key.and) {
  679. // 或签更新他人审批状态
  680. if (selfAudit.audit_type === auditType.key.or) {
  681. const updateOther = [];
  682. for (const audit of flowAudits) {
  683. if (audit.aid === selfAudit.aid) continue;
  684. updateOther.push({
  685. id: audit.id,
  686. status: auditConst.status.checkSkip,
  687. opinion: '',
  688. end_time: time,
  689. });
  690. // await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, audit.id);
  691. }
  692. if (updateOther.length > 0) transaction.updateRows(this.tableName, updateOther);
  693. }
  694. // 无下一审核人表示,审核结束
  695. if (nextAudits.length > 0) {
  696. // 流程至下一审批人
  697. const updateData = nextAudits.map(x => { return { id: x.id, status: auditConst.status.checking, begin_time: time }; });
  698. await transaction.updateRows(this.tableName, updateData);
  699. // 同步 期信息
  700. await transaction.update(tableName, {
  701. id: contract.id, status: auditConst.status.checking,
  702. });
  703. } else {
  704. // 本期结束
  705. // 生成截止本期数据 final数据
  706. // 同步 期信息
  707. const final_auditor_str = flowAudits[0].audit_type === auditType.key.common
  708. ? flowAudits[0].name + (flowAudits[0].role ? '-' + flowAudits[0].role : '')
  709. : this.ctx.helper.transFormToChinese(flowAudits[0].audit_order) + '审';
  710. await transaction.update(tableName, {
  711. id: contract.id, status: checkData.checkType, final_auditor_str,
  712. });
  713. }
  714. } else {
  715. await transaction.update(tableName, {
  716. id: contract.id, status: auditConst.status.checking,
  717. });
  718. }
  719. await transaction.commit();
  720. } catch (err) {
  721. await transaction.rollback();
  722. throw err;
  723. }
  724. }
  725. async _checkNo(pid, contract, type, checkData) {
  726. const accountId = this.ctx.session.sessionUser.accountId;
  727. const time = new Date();
  728. const cid = contract.cid ? contract.cid : contract.id;
  729. const cpid = type === 'pay' ? contract.id : null;
  730. const csid = type === 'supplement' ? contract.id : null;
  731. const tableName = {
  732. contract: this.ctx.service.contract.tableName,
  733. pay: this.ctx.service.contractPay.tableName,
  734. supplement: this.ctx.service.contractSupplement.tableName,
  735. }[type];
  736. const audits = contract.curAuditors;
  737. if (audits.length === 0) throw '审核数据错误';
  738. const selfAudit = audits.find(x => { return x.aid === accountId; });
  739. if (!selfAudit) throw '当前标段您无权审批';
  740. const auditors = await this.getUniqAuditor(contract, type, contract.times, true); // 全部参与的审批人
  741. const newAuditors = auditors.map(x => {
  742. return {
  743. aid: x.aid, spid: contract.spid || null, tid: contract.tid || null, cid, cpid, csid,
  744. times: contract.times + 1, order: x.audit_order, status: auditConst.status.uncheck,
  745. audit_type: x.audit_type, audit_order: x.audit_order,
  746. };
  747. });
  748. const transaction = await this.db.beginTransaction();
  749. try {
  750. const updateData = [];
  751. audits.forEach(x => {
  752. updateData.push({
  753. id: x.id,
  754. status: x.aid === selfAudit.aid ? checkData.checkType : auditConst.status.checkSkip,
  755. opinion: x.aid === selfAudit.aid ? checkData.opinion : '',
  756. end_time: x.aid === selfAudit.aid ? time : null,
  757. });
  758. });
  759. await transaction.updateRows(this.tableName, updateData);
  760. // await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, this._.map(updateData, 'id'));
  761. // 添加到消息推送表
  762. // const noticeContent = await this.getNoticeContent(pid, selfAudit.tid, cpId, selfAudit.aid, checkData.opinion);
  763. // const records = [{ pid, tid: selfAudit.tid, type: pushType.changePlan, uid: this.ctx.change.uid, status: auditConst.status.checkNo, content: noticeContent }];
  764. // auditors.forEach(audit => {
  765. // records.push({ pid, tid: selfAudit.tid, type: pushType.changePlan, uid: audit.aid, status: auditConst.status.checkNo, content: noticeContent });
  766. // });
  767. // await transaction.insert(this.ctx.service.noticePush.tableName, records);
  768. // 同步期信息
  769. await transaction.update(tableName, {
  770. id: contract.id, status: checkData.checkType, times: contract.times + 1,
  771. });
  772. // 拷贝新一次审核流程列表
  773. await transaction.insert(this.tableName, newAuditors);
  774. await transaction.commit();
  775. } catch (err) {
  776. await transaction.rollback();
  777. throw err;
  778. }
  779. }
  780. /**
  781. * 审批退回到上一个审批人
  782. * @param {Number} pid 项目id
  783. * @param {int} postData - 表单提交的数据
  784. * @param {int} changeData - 变更令的数据
  785. * @return {void}
  786. */
  787. async _checkNoPre(pid, contract, type, checkData) {
  788. const accountId = this.ctx.session.sessionUser.accountId;
  789. const time = new Date();
  790. const cid = contract.cid ? contract.cid : contract.id;
  791. const cpid = type === 'pay' ? contract.id : null;
  792. const csid = type === 'supplement' ? contract.id : null;
  793. const tableName = {
  794. contract: this.ctx.service.contract.tableName,
  795. pay: this.ctx.service.contractPay.tableName,
  796. supplement: this.ctx.service.contractSupplement.tableName,
  797. }[type];
  798. // 整理当前流程审核人状态更新
  799. const audits = contract.curAuditors;
  800. if (audits.length === 0 || audits[0].order <= 1) throw '审核数据错误';
  801. const selfAudit = audits.find(x => { return x.aid === accountId; });
  802. if (!selfAudit) throw '当前标段您无权审批';
  803. const flowAudits = contract.flowAuditors;
  804. // 添加重新审批后,不能用order-1,取groupby值里的上一个才对
  805. // const preAuditor = await this.getDataByCondition({sid: stageId, times: times, order: audit.order - 1});
  806. const auditors2 = await this.getAuditGroupByList(contract, type, contract.times);
  807. const preAuditors = auditors2.filter(x => { return x.audit_order === selfAudit.audit_order - 1});
  808. const transaction = await this.db.beginTransaction();
  809. try {
  810. // 添加通知
  811. // const noticeContent = await this.getNoticeContent(pid, selfAudit.tid, inspection.id, selfAudit.aid, checkData.opinion);
  812. // const defaultNoticeRecord = {
  813. // pid,
  814. // tid: selfAudit.tid,
  815. // type: pushType.inspection,
  816. // status: auditConst.status.checkNoPre,
  817. // content: noticeContent,
  818. // };
  819. // const records = [
  820. // {
  821. // uid: inspection.uid,
  822. // ...defaultNoticeRecord
  823. // },
  824. // ];
  825. // auditors2.forEach(audit => {
  826. // records.push({
  827. // uid: audit.aid,
  828. // ...defaultNoticeRecord
  829. // });
  830. // });
  831. // await transaction.insert('zh_notice', records);
  832. // 更新同一流程所有审批人状态
  833. const updateData = [];
  834. for (const audit of audits) {
  835. if (audit.aid === selfAudit.aid) {
  836. updateData.push({
  837. id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time,
  838. });
  839. } else {
  840. updateData.push({
  841. id: audit.id, status: auditConst.status.checkSkip, opinion: '', end_time: null,
  842. });
  843. }
  844. }
  845. await transaction.updateRows(this.tableName, updateData);
  846. // await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, this._.map(updateData, 'id'));
  847. // 顺移其后审核人流程顺序
  848. const sql = 'UPDATE ' + this.tableName + ' SET `order` = `order` + 2 WHERE cid = ? AND cpid' + (cpid ? ' = ' + cpid : ' is null') + ' AND csid' + (csid ? ' = ' + csid : ' is null') + ' AND times = ? AND `order` > ?';
  849. await transaction.query(sql, [cid, selfAudit.times, selfAudit.order]);
  850. // 上一审批人,当前审批人 再次添加至流程
  851. const newAuditors = [];
  852. preAuditors.forEach(x => {
  853. newAuditors.push({
  854. spid: contract.spid || null, tid: contract.tid || null, cid, cpid, csid, aid: x.aid,
  855. times: x.times, order: selfAudit.order + 1,
  856. status: auditConst.status.checking, begin_time: time,
  857. audit_type: x.audit_type, audit_order: x.audit_order,
  858. });
  859. });
  860. // 获取ids值
  861. const newAuditors_result = await transaction.insert(this.tableName, newAuditors);
  862. // 获取刚批量添加的所有list
  863. for (let j = 0; j < preAuditors.length; j++) {
  864. newAuditors[j].id = newAuditors_result.insertId + j;
  865. }
  866. const newFlowAuditors = [];
  867. flowAudits.forEach(x => {
  868. newFlowAuditors.push({
  869. spid: contract.spid || null, tid: contract.tid || null, cid, cpid, csid, aid: x.aid,
  870. times: x.times, order: selfAudit.order + 2,
  871. status: auditConst.status.uncheck,
  872. audit_type: x.audit_type, audit_order: x.audit_order,
  873. });
  874. });
  875. await transaction.insert(this.tableName, newFlowAuditors);
  876. // 同步 期信息
  877. await transaction.update(tableName, {
  878. id: contract.id,
  879. status: checkData.checkType,
  880. });
  881. await transaction.commit();
  882. } catch (err) {
  883. await transaction.rollback();
  884. throw err;
  885. }
  886. }
  887. async getAuditorGroup(contract, type, times) {
  888. const auditors = await this.getAuditors(contract, type, times); // 全部参与的审批人
  889. return this.ctx.helper.groupAuditors(auditors, 'order');
  890. }
  891. async getUserGroup(contract, type, times) {
  892. const group = await this.getAuditorGroup(contract, type, times);
  893. // const sql =
  894. // 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As cpid, 0 As `order`, 1 As audit_type, 0 As audit_order' +
  895. // ' FROM ' + this.ctx.service.changePlan.tableName + ' As s' +
  896. // ' LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
  897. // ' ON s.uid = pa.id' +
  898. // ' WHERE s.id = ?';
  899. // const sqlParam = [times, cpId, cpId];
  900. // const user = await this.db.queryOne(sql, sqlParam);
  901. // user.audit_order = 0;
  902. // group.unshift([ user ]);
  903. return group;
  904. }
  905. async getUniqUserGroup(contract, type, times) {
  906. const group = await this.getAuditorGroup(contract, type, times);
  907. // const sql =
  908. // 'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As cpid, 0 As `order`, 1 As audit_type, 0 As audit_order' +
  909. // ' FROM ' + this.ctx.service.changePlan.tableName + ' As s' +
  910. // ' LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
  911. // ' ON s.uid = pa.id' +
  912. // ' WHERE s.id = ?';
  913. // const sqlParam = [times, cpId, cpId];
  914. // const user = await this.db.queryOne(sql, sqlParam);
  915. // user.audit_order = 0;
  916. // group.unshift([ user ]);
  917. return this.ctx.helper.groupAuditorsUniq(group);
  918. }
  919. async getAuditorHistory(contract, type, times, reverse = false) {
  920. const history = [];
  921. if (times >= 1) {
  922. for (let i = 1; i <= times; i++) {
  923. const auditors = await this.getAuditors(contract, type, i);
  924. const group = this.ctx.helper.groupAuditors(auditors);
  925. const historyGroup = [];
  926. // 找出group里audit_order最大值
  927. const max_info = group.length > 0 ? this._.maxBy(group, function(item) {
  928. return item && item[0] && item[0].audit_order;
  929. }) : null;
  930. const max_order = max_info ? max_info[0].audit_order : -1;
  931. for (const g of group) {
  932. const his = {
  933. beginYear: '', beginDate: '', beginTime: '', endYear: '', endDate: '', endTime: '', begin_time: null, end_time: null,
  934. audit_type: g[0].audit_type, audit_order: g[0].audit_order,
  935. auditors: g,
  936. };
  937. if (his.audit_type === auditType.key.common) {
  938. his.name = g[0].name;
  939. } else {
  940. his.name = this.ctx.helper.transFormToChinese(his.audit_order) + '审';
  941. }
  942. his.is_final = his.audit_order === max_order;
  943. if (g[0].begin_time) {
  944. his.begin_time = g[0].begin_time;
  945. const beginTime = this.ctx.moment(g[0].begin_time);
  946. his.beginYear = beginTime.format('YYYY');
  947. his.beginDate = beginTime.format('MM-DD');
  948. his.beginTime = beginTime.format('HH:mm:ss');
  949. }
  950. let end_time;
  951. g.forEach(x => {
  952. if (x.status === auditConst.status.checkSkip) return;
  953. if (!his.status || x.status === auditConst.status.checking) his.status = x.status;
  954. if (x.end_time && (!end_time || x.end_time > end_time)) {
  955. end_time = x.end_time;
  956. if (his.status !== auditConst.status.checking) his.status = x.status;
  957. }
  958. });
  959. if (end_time) {
  960. his.end_time = end_time;
  961. const endTime = this.ctx.moment(end_time);
  962. his.endYear = endTime.format('YYYY');
  963. his.endDate = endTime.format('MM-DD');
  964. his.endTime = endTime.format('HH:mm:ss');
  965. }
  966. historyGroup.push(his);
  967. }
  968. if (reverse) {
  969. history.push(historyGroup.reverse());
  970. } else {
  971. history.push(historyGroup);
  972. }
  973. }
  974. }
  975. return history;
  976. }
  977. async getUniqAuditor(contract, type, times, noYb = false) {
  978. const auditors = await this.getAuditors(contract, type, times, 'asc', noYb); // 全部参与的审批人
  979. const result = [];
  980. auditors.forEach(x => {
  981. if (result.findIndex(r => { return x.aid === r.aid && x.audit_order === r.audit_order; }) < 0) {
  982. result.push(x);
  983. }
  984. });
  985. return result;
  986. }
  987. async makeAudits(transaction, options, contract, type, uid) {
  988. const cid = contract.cid ? contract.cid : contract.id;
  989. const cpid = type === 'pay' ? contract.id : null;
  990. const csid = type === 'supplement' ? contract.id : null;
  991. // 创建审批人列表
  992. const lastContractInfo = await this.getHaveAuditLastInfo(options, contract, type, uid);
  993. let auditList = [];
  994. if (lastContractInfo) {
  995. // 再获取非原报审批人
  996. auditList = await this.getUniqAuditor(lastContractInfo, type, lastContractInfo.times, true); // 全部参与的审批人
  997. } else if ((type === 'supplement' || type === 'pay') && contract.cid) {
  998. // 取该合同的审批人列表
  999. const contractInfo = await this.ctx.service.contract.getDataById(contract.cid);
  1000. auditList = await this.getUniqAuditor(contractInfo, 'contract', contractInfo.times, true); // 全部参与的审批人
  1001. }
  1002. if (auditList.length > 0) {
  1003. const spAudits = [];
  1004. for (const x of auditList) {
  1005. if (x.audit_order !== 0) {
  1006. spAudits.push({
  1007. spid: options.spid || null,
  1008. tid: options.tid || null,
  1009. cid, cpid, csid, aid: x.aid,
  1010. times: 1, order: x.audit_order, status: auditConst.status.uncheck,
  1011. audit_type: x.audit_type, audit_order: x.audit_order,
  1012. });
  1013. }
  1014. }
  1015. if (spAudits.length > 0) await transaction.insert(this.ctx.service.contractSpAudit.tableName, spAudits);
  1016. }
  1017. }
  1018. async getHaveAuditLastInfo(options, contract, type, uid) {
  1019. const optionsSql = options.spid ? 'c.spid = "' + options.spid + '"' : 'c.tid = ' + options.tid;
  1020. const cpid = type === 'pay' ? contract.id : null;
  1021. const csid = type === 'supplement' ? contract.id : null;
  1022. const tableName = {
  1023. contract: this.ctx.service.contract.tableName,
  1024. pay: this.ctx.service.contractPay.tableName,
  1025. supplement: this.ctx.service.contractSupplement.tableName,
  1026. }[type];
  1027. const joinSql = cpid ? 'ca.`cpid`' : (csid ? 'ca.`csid`' : 'ca.`cid`');
  1028. const cpidSql = cpid ? ' AND ca.`cpid` is not null' : ' AND ca.`cpid` is null';
  1029. const csidSql = cpid ? ' AND ca.`csid` is not null' : ' AND ca.`csid` is null';
  1030. const sql = 'SELECT c.* FROM ?? as c LEFT JOIN ?? as ca ON c.`id` = ' + joinSql + ' WHERE ' + optionsSql + ' AND c.`contract_type` = ? AND c.`uid` = ?' + cpidSql + csidSql + ' AND ca.`audit_order` > 0 ORDER BY c.`create_time` DESC';
  1031. const sqlParam = [tableName, this.tableName, options.contract_type, uid];
  1032. return await this.db.queryOne(sql, sqlParam);
  1033. }
  1034. async saveAudit(contract, type, times, sp_group, data) {
  1035. const transaction = await this.db.beginTransaction();
  1036. try {
  1037. const cid = contract.cid ? contract.cid : contract.id;
  1038. const cpid = type === 'pay' ? contract.id : null;
  1039. const csid = type === 'supplement' ? contract.id : null;
  1040. const auditors = await this.getAuditGroupByList(contract, type, times);
  1041. const now_audit = this._.find(auditors, { aid: data.old_aid });
  1042. if (data.operate !== 'del') {
  1043. // const exist = await this.getDataByCondition({ cpid: cpId, times, aid: data.new_aid });
  1044. // if (exist) throw '该审核人已存在,请勿重复添加';
  1045. const groupAuditors = this._.flattenDeep(contract.userGroups);
  1046. const exist = this._.find(groupAuditors, { aid: data.new_aid });
  1047. if (exist) throw '该审核人已存在,请勿重复添加';
  1048. }
  1049. if (data.operate === 'add') {
  1050. if (now_audit.status !== auditConst.status.uncheck && now_audit.status !== auditConst.status.checking) {
  1051. throw '当前人下无法操作新增';
  1052. }
  1053. const newAudit = {
  1054. spid: contract.spid || null, tid: contract.tid || null, cid, cpid, csid, aid: data.new_aid,
  1055. order: now_audit.order + 1,
  1056. audit_order: now_audit.audit_order + 1, audit_type: auditType.key.common,
  1057. times, status: auditConst.status.uncheck,
  1058. };
  1059. // order+1
  1060. await this._syncOrderByDelete(transaction, contract, type, now_audit.order + 1, times, '+');
  1061. await transaction.insert(this.tableName, newAudit);
  1062. // 更新审批流程页数据,如果存在
  1063. } else if (data.operate === 'add-sibling') {
  1064. if (now_audit.status !== auditConst.status.uncheck && now_audit.status !== auditConst.status.checking) {
  1065. throw '当前人下无法操作新增';
  1066. }
  1067. const newAudit = {
  1068. spid: contract.spid || null, tid: contract.tid || null, cid, cpid, csid, aid: data.new_aid,
  1069. order: now_audit.order,
  1070. audit_order: now_audit.audit_order, audit_type: now_audit.audit_type,
  1071. times, status: auditConst.status.uncheck,
  1072. };
  1073. await transaction.insert(this.tableName, newAudit);
  1074. } else if (data.operate === 'del') {
  1075. if (now_audit.status !== auditConst.status.uncheck) {
  1076. throw '当前人无法操作删除';
  1077. }
  1078. const flowAuditors = auditors.filter(x => { return x.audit_order === now_audit.audit_order; });
  1079. await transaction.delete(this.tableName, { cid, cpid, csid, times, aid: now_audit.aid, order: now_audit.order });
  1080. if (flowAuditors.length === 1) await this._syncOrderByDelete(transaction, contract, type, now_audit.order, times);
  1081. // 旧的更新为is_old为1
  1082. // await transaction.update(this.tableName, { is_old: 1 }, {
  1083. // where: {
  1084. // sid: stageId,
  1085. // times,
  1086. // aid: data.old_aid,
  1087. // }
  1088. // });
  1089. } else if (data.operate === 'change') {
  1090. const nowAudit = await this.getDataByCondition({ cid, cpid, csid, times, aid: now_audit.aid, order: now_audit.order });
  1091. if (now_audit.status !== auditConst.status.uncheck || !nowAudit) {
  1092. throw '当前人无法操作替换';
  1093. }
  1094. nowAudit.aid = data.new_aid;
  1095. await transaction.update(this.tableName, nowAudit);
  1096. // 旧的更新为is_old为1
  1097. // await transaction.update(this.tableName, { is_old: 1 }, {
  1098. // where: {
  1099. // sid: stageId,
  1100. // times,
  1101. // aid: data.old_aid,
  1102. // }
  1103. // });
  1104. }
  1105. if (this.ctx.contract_tender) {
  1106. const tenderInfo = await this.ctx.service.tenderInfo.getTenderInfo(this.ctx.contract.id);
  1107. if (tenderInfo.shenpi.contract === shenpiConst.sp_status.gdspl) {
  1108. const newAuditors = await transaction.select(this.tableName, { where: { cid, cpid, csid, times }, orders: [['order', 'asc']] });
  1109. newAuditors.shift();
  1110. const newAuditorGroup = this.ctx.helper.groupAuditors(newAuditors, 'order');
  1111. const uniqNewAuditorGroup = this.ctx.helper.groupAuditorsUniq(newAuditorGroup);
  1112. await this.ctx.service.shenpiAudit.updateAuditListWithAuditType(transaction, this.ctx.contract.id, tenderInfo.shenpi.contract, shenpiConst.sp_type.contract, uniqNewAuditorGroup, sp_group);
  1113. } else if (tenderInfo.shenpi.contract === shenpiConst.sp_status.gdzs) {
  1114. const newAuditors = await this.getAuditGroupByList(contract, type, times, transaction);
  1115. await this.ctx.service.shenpiAudit.updateAuditList(transaction, this.ctx.contract.id, tenderInfo.shenpi.contract, shenpiConst.sp_type.contract, this._.map(newAuditors, 'aid'));
  1116. }
  1117. } else {
  1118. if (this.ctx.subProject.shenpi.contract === shenpiConst.sp_status.gdspl) {
  1119. const newAuditors = await transaction.select(this.tableName, { where: { cid, cpid, csid, times }, orders: [['order', 'asc']] });
  1120. newAuditors.shift();
  1121. const newAuditorGroup = this.ctx.helper.groupAuditors(newAuditors, 'order');
  1122. const uniqNewAuditorGroup = this.ctx.helper.groupAuditorsUniq(newAuditorGroup);
  1123. await this.ctx.service.shenpiAudit.updateAuditListWithAuditType(transaction, this.ctx.subProject.id, this.ctx.subProject.shenpi.contract, shenpiConst.sp_type.contract, uniqNewAuditorGroup, sp_group);
  1124. } else if (this.ctx.subProject.shenpi.contract === shenpiConst.sp_status.gdzs) {
  1125. const newAuditors = await this.getAuditGroupByList(contract, type, times, transaction);
  1126. await this.ctx.service.shenpiAudit.updateAuditList(transaction, this.ctx.subProject.id, this.ctx.subProject.shenpi.contract, shenpiConst.sp_type.contract, this._.map(newAuditors, 'aid'));
  1127. }
  1128. }
  1129. // 更新到审批流程方法
  1130. await transaction.commit();
  1131. } catch (err) {
  1132. await transaction.rollback();
  1133. throw err;
  1134. }
  1135. }
  1136. async changeSpGroup(contract, type, sp_group) {
  1137. const transaction = await this.db.beginTransaction();
  1138. try {
  1139. const group = await this.ctx.service.shenpiGroup.getDataById(sp_group);
  1140. if (!group) {
  1141. throw '该固定审批组不存在,请刷新页面重新获取';
  1142. }
  1143. const condition = { sp_type: shenpiConst.sp_type.contract, sp_status: shenpiConst.sp_status.gdspl, sp_group: group.id };
  1144. if (this.ctx.contract_tender) {
  1145. condition.tid = contract.tid;
  1146. } else {
  1147. condition.spid = contract.spid;
  1148. }
  1149. const shenpiList = await this.ctx.service.shenpiAudit.getAllDataByCondition({ where: condition });
  1150. // await this.ctx.service.shenpiAudit.noYbShenpiList(change.uid, shenpiList);
  1151. await this.updateNewAuditors(contract, type, shenpiList, transaction);
  1152. if (type === 'contract') {
  1153. await transaction.update(this.ctx.service.contract.tableName, { id: contract.id, sp_group: group.id });
  1154. } else if (type === 'pay') {
  1155. await transaction.update(this.ctx.service.contractPay.tableName, { id: contract.id, sp_group: group.id });
  1156. } else if (type === 'supplement') {
  1157. await transaction.update(this.ctx.service.contractSupplement.tableName, { id: contract.id, sp_group: group.id });
  1158. }
  1159. await transaction.commit();
  1160. } catch (err) {
  1161. await transaction.rollback();
  1162. throw err;
  1163. }
  1164. return true;
  1165. }
  1166. async updateNewAuditList(contract, type, newList) {
  1167. const transaction = await this.db.beginTransaction();
  1168. try {
  1169. await this.updateNewAuditors(contract, type, newList, transaction);
  1170. await transaction.commit();
  1171. } catch (err) {
  1172. await transaction.rollback();
  1173. throw err;
  1174. }
  1175. }
  1176. async updateNewAuditors(contract, type, newList, transaction) {
  1177. const condition = { times: contract.times };
  1178. const cid = contract.cid ? contract.cid : contract.id;
  1179. const cpid = type === 'pay' ? contract.id : null;
  1180. const csid = type === 'supplement' ? contract.id : null;
  1181. condition.cid = cid;
  1182. condition.cpid = cpid;
  1183. condition.csid = csid;
  1184. // 先删除旧的审批流,再添加新的
  1185. await transaction.delete(this.tableName, condition);
  1186. const newAuditors = [];
  1187. for (const auditor of newList) {
  1188. newAuditors.push({
  1189. spid: contract.spid || null, tid: contract.tid || null, cid, cpid, csid, aid: auditor.audit_id,
  1190. times: contract.times, order: auditor.audit_order, status: auditConst.status.uncheck,
  1191. audit_type: auditor.audit_type, audit_order: auditor.audit_order,
  1192. });
  1193. }
  1194. if (newAuditors.length > 0) {
  1195. await transaction.insert(this.tableName, newAuditors);
  1196. // 增加到权限表
  1197. const options = {};
  1198. if (contract.spid) options.spid = contract.spid;
  1199. if (contract.tid) options.tid = contract.tid;
  1200. const auditorIds = this._.map(newAuditors, 'aid');
  1201. const list = [];
  1202. for (const aid of auditorIds) {
  1203. list.push({ id: aid });
  1204. }
  1205. await this.ctx.service.contractAudit.saveAudits(options, list, transaction);
  1206. }
  1207. }
  1208. async updateLastAudit(contract, type, auditList, lastId) {
  1209. const transaction = await this.db.beginTransaction();
  1210. try {
  1211. // 先判断auditList里的aid是否与lastId相同,相同则删除并重新更新order
  1212. const existAudit = auditList.find(x => { return x.aid === lastId; });
  1213. const cid = contract.cid ? contract.cid : contract.id;
  1214. const cpid = type === 'pay' ? contract.id : null;
  1215. const csid = type === 'supplement' ? contract.id : null;
  1216. let order = auditList.length > 0 ? auditList.reduce((rst, a) => { return Math.max(rst, a.order); }, 0) + 1 : 1; // 最大值 + 1
  1217. if (existAudit) {
  1218. const condition = { times: contract.times, aid: lastId };
  1219. condition.cid = cid;
  1220. condition.cpid = cpid;
  1221. condition.csid = csid;
  1222. await transaction.delete(this.tableName, condition);
  1223. const sameOrder = auditList.filter(x => { return x.order === existAudit.order; });
  1224. if (sameOrder.length === 1) {
  1225. const updateData = [];
  1226. auditList.forEach(x => {
  1227. if (x.order <= existAudit.order) return;
  1228. updateData.push({ id: x.id, order: x.order - 1, audit_order: x.audit_order - 1 });
  1229. });
  1230. if (updateData.length > 0) {
  1231. await transaction.updateRows(this.tableName, updateData);
  1232. }
  1233. order = order - 1;
  1234. }
  1235. }
  1236. // 添加终审
  1237. const newAuditor = {
  1238. spid: contract.spid || null, tid: contract.tid || null, cid, cpid, csid, aid: lastId,
  1239. times: contract.times, order, status: auditConst.status.uncheck,
  1240. audit_type: auditType.key.common, audit_order: order,
  1241. };
  1242. await transaction.insert(this.tableName, newAuditor);
  1243. await transaction.commit();
  1244. } catch (err) {
  1245. await transaction.rollback();
  1246. throw err;
  1247. }
  1248. }
  1249. /**
  1250. * 获取审核人已经审核过的审批信息(包括退回,通过,重新审批等)
  1251. *
  1252. * @param auditorId
  1253. * @return {Promise<*>}
  1254. */
  1255. // async getDonesByAudit(auditorId, spid = '') {
  1256. // const spSql = spid ? ' and t.`spid` = "' + spid + '"' : '';
  1257. // const status = [auditConst.status.checked, auditConst.status.checkNo, auditConst.status.checkNoPre];
  1258. // const sql =
  1259. // 'SELECT la.`status`, la.`end_time` as `shenpi_time`, la.`cid`, la.`cpid`, t.`id`, cp.`code`, t.`name`, t.`spid` ' +
  1260. // ' FROM ?? AS la Left Join ?? AS t ON la.`tid` = t.`id` LEFT JOIN ?? AS cp ON la.`cpid` = cp.`id`' +
  1261. // ' WHERE la.`aid` = ? AND la.`status` in (' + this.ctx.helper.getInArrStrSqlFilter(status) + ')' + spSql +
  1262. // ' ORDER BY la.`end_time` DESC';
  1263. // const sqlParam = [
  1264. // this.tableName,
  1265. // this.ctx.service.tender.tableName,
  1266. // this.ctx.service.contract.tableName,
  1267. // auditorId,
  1268. // ];
  1269. // return await this.db.query(sql, sqlParam);
  1270. // }
  1271. }
  1272. return ContractSpAudit;
  1273. };