weapp_tender_controller.js 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. 'use strict';
  2. const auditConst = require('../const/audit');
  3. const changeMap = require('../const/weapp').changeMap;
  4. const measureType = require('../const/tender').measureType;
  5. const advanceConst = require('../const/advance');
  6. const shenpiConst = require('../const/shenpi');
  7. const stdConst = require('../const/standard');
  8. const _ = require('lodash');
  9. module.exports = app => {
  10. class WeappTenderController extends app.BaseController {
  11. async listManage(ctx) {
  12. try {
  13. const projectId = ctx.query.projectId;
  14. if (!projectId) {
  15. ctx.body = { err: 1, msg: '缺少projectId参数', data: null };
  16. return;
  17. }
  18. const accountInfo = ctx.session.sessionUser;
  19. const userPermission = accountInfo !== undefined && accountInfo.permission !== '' ? JSON.parse(accountInfo.permission) : null;
  20. if (userPermission !== null && userPermission.tender !== undefined && userPermission.tender.indexOf('1') !== -1) {
  21. const subProject = await this.ctx.service.subProject.getDataById(projectId);
  22. const tenderList = await this.ctx.service.tender.getList('', userPermission, ctx.session.sessionUser.is_admin, '', subProject);
  23. for (const tender of tenderList) {
  24. // 查询当前审批期以及状态
  25. const stage = await this.ctx.service.stage.getLastestStage(tender.id, true);
  26. tender.stage_order = stage && stage.order ? stage.order : null;
  27. tender.stage_status = stage && stage.status ? stage.status : null;
  28. }
  29. const categoryData = await this.ctx.service.category.getAllCategory(subProject);
  30. const renderData = {
  31. categoryData,
  32. tenderList,
  33. };
  34. ctx.body = { err: 0, msg: '', data: renderData };
  35. } else {
  36. ctx.body = { err: 1, msg: '您没有管理权限', data: null };
  37. }
  38. } catch (err) {
  39. this.log(err);
  40. ctx.body = { err: 1, msg: err.toString(), data: null };
  41. }
  42. }
  43. async detail(ctx) {
  44. try {
  45. const tender = ctx.tender.data;
  46. let bCalcTp = ctx.tender.data.user_id === ctx.session.sessionUser.accountId && (
  47. ctx.tender.ledger_status === auditConst.ledger.status.checkNo || ctx.tender.ledger_status === auditConst.ledger.status.uncheck);
  48. const stages = await ctx.service.stage.getValidStages(ctx.tender.id);
  49. const lastStage = stages.length > 0 ? stages[0] : null; // await ctx.service.stage.getLastestStage(ctx.tender.id);
  50. const [change_tp, change_p_tp, change_n_tp, change_valuation_tp, change_unvaluation_tp] = await ctx.service.change.getChangeTp(ctx.tender.id);
  51. tender.change_tp = change_tp;
  52. tender.change_p_tp = change_p_tp;
  53. tender.change_n_tp = change_n_tp;
  54. tender.change_valuation_tp = change_valuation_tp;
  55. tender.change_unvaluation_tp = change_unvaluation_tp;
  56. if (lastStage) {
  57. await this.ctx.service.stage.checkStageGatherData(lastStage, ctx.session.sessionUser.is_admin);
  58. if ((!bCalcTp) && tender.measure_type === measureType.gcl.value) {
  59. bCalcTp = lastStage.status !== auditConst.stage.status.checked && !lastStage.readOnly;
  60. }
  61. if (bCalcTp) {
  62. const sum = await this.ctx.service.ledger.addUp({ tender_id: ctx.tender.id/* , is_leaf: true*/ });
  63. tender.total_price = sum.total_price;
  64. tender.deal_tp = sum.deal_tp;
  65. }
  66. tender.sum = ctx.tender.info.calc_type === 'tp' ? ctx.helper.add(tender.total_price, tender.change_valuation_tp) : ctx.helper.add(tender.total_price, tender.change_tp);
  67. tender.gather_tp = ctx.helper.sum([lastStage.contract_tp, lastStage.qc_tp, lastStage.pc_tp]);
  68. tender.end_contract_tp = ctx.helper.sum([lastStage.contract_tp, lastStage.pre_contract_tp, lastStage.contract_pc_tp]);
  69. tender.end_qc_tp = ctx.helper.sum([lastStage.qc_tp, lastStage.pre_qc_tp, lastStage.qc_pc_tp]);
  70. tender.end_positive_qc_tp = ctx.helper.sum([lastStage.positive_qc_tp, lastStage.pre_positive_qc_tp, lastStage.positive_qc_pc_tp]);
  71. tender.end_negative_qc_tp = ctx.helper.sum([lastStage.negative_qc_tp, lastStage.pre_negative_qc_tp, lastStage.negative_qc_pc_tp]);
  72. tender.end_gather_tp = ctx.helper.add(tender.end_contract_tp, tender.end_qc_tp);
  73. tender.pre_gather_tp = ctx.helper.add(lastStage.pre_contract_tp, lastStage.pre_qc_tp);
  74. tender.yf_tp = lastStage.yf_tp;
  75. tender.sf_tp = lastStage.sf_tp;
  76. tender.qc_ratio = ctx.helper.mul(ctx.helper.div(tender.end_qc_tp, ctx.tender.info.deal_param.contractPrice, 2), 100);
  77. tender.pre_ratio = ctx.helper.mul(ctx.helper.div(tender.pre_gather_tp, tender.sum, 2), 100);
  78. tender.cur_ratio = ctx.helper.mul(ctx.helper.div(tender.gather_tp, tender.sum, 2), 100);
  79. tender.other_tp = ctx.helper.sub(ctx.helper.sub(tender.sum, tender.pre_gather_tp), tender.gather_tp);
  80. tender.other_ratio = Math.max(0, 100 - tender.pre_ratio - tender.cur_ratio);
  81. tender.end_yf_tp = ctx.helper.add(lastStage.yf_tp, lastStage.pre_yf_tp);
  82. tender.end_sf_tp = ctx.helper.add(lastStage.sf_tp, lastStage.pre_sf_tp);
  83. tender.undone_tp = ctx.helper.sub(ctx.helper.sub(ctx.helper.add(tender.total_price, change_tp), tender.end_contract_tp), tender.end_qc_tp);
  84. } else {
  85. if (bCalcTp) {
  86. const sum = await this.ctx.service.ledger.addUp({ tender_id: ctx.tender.id/* , is_leaf: true*/ });
  87. tender.total_price = sum.total_price;
  88. tender.deal_tp = sum.deal_tp;
  89. }
  90. tender.sum = ctx.helper.add(tender.total_price, tender.change_tp);
  91. }
  92. // const monthProgress = [];
  93. // for (const s of stages) {
  94. // if (s.s_time) {
  95. // let progress = monthProgress.find(function(x) {
  96. // return x.month === s.s_time;
  97. // });
  98. // if (!progress) {
  99. // progress = { month: s.s_time };
  100. // monthProgress.push(progress);
  101. // }
  102. // progress.tp = ctx.helper.add(ctx.helper.add(progress.tp, s.contract_tp), s.qc_tp);
  103. // }
  104. // }
  105. // monthProgress.sort(function(x, y) {
  106. // return Date.parse(x.month) - Date.parse(y.month);
  107. // });
  108. // let sum = 0;
  109. // for (const p of monthProgress) {
  110. // p.ratio = ctx.helper.mul(ctx.helper.div(p.tp, tender.sum, 4), 100);
  111. // sum = ctx.helper.add(sum, p.tp);
  112. // p.end_tp = sum;
  113. // p.end_ratio = ctx.helper.mul(ctx.helper.div(p.end_tp, tender.sum, 4), 100);
  114. // }
  115. ctx.body = {
  116. code: 0, msg: '', data: {
  117. tender,
  118. // monthProgress,
  119. // stagesEcharts: JSON.parse(JSON.stringify(stages)).reverse(),
  120. },
  121. };
  122. } catch (error) {
  123. this.log(error);
  124. ctx.body = { code: -1, msg: error.toString(), data: null };
  125. }
  126. }
  127. async advanceList(ctx) {
  128. try {
  129. const { advanceType } = ctx.query;
  130. const typeCol = advanceConst.typeCol.find(x => x.type === Number(advanceType));
  131. if (!typeCol) {
  132. ctx.body = { code: -1, msg: '预付款类型错误', data: null };
  133. return;
  134. }
  135. const { decimal } = ctx.tender.info;
  136. const advancePayTotal = ctx.tender.info.deal_param[typeCol.key + 'Advance'];
  137. const advances = await ctx.service.advance.getAdvanceList(ctx.tender.id, typeCol.type, decimal.pay ? decimal.payTp : decimal.tp, advancePayTotal);
  138. ctx.body = { code: 0, msg: '', data: advances };
  139. } catch (error) {
  140. this.log(error);
  141. ctx.body = { code: -1, msg: error.toString(), data: null };
  142. }
  143. }
  144. async advanceCheck(advance) {
  145. if (!advance) {
  146. throw '预付款数据错误';
  147. }
  148. const times = advance.status === auditConst.advance.status.checkNo ? advance.times - 1 : advance.times;
  149. advance.user = await this.service.projectAccount.getAccountInfoById(advance.uid);
  150. // 读取审核人列表数据
  151. advance.auditors = await this.service.advanceAudit.getAuditorsWithOwner(advance.id, advance.status === auditConst.advance.status.checkNo && this.ctx.session.sessionUser.accountId !== advance.uid ? times : advance.times);
  152. advance.auditHistory = await this.service.advanceAudit.getAuditors(advance.id, advance.times);
  153. advance.curAuditor = await this.service.advanceAudit.getCurAuditor(advance.id, advance.times);
  154. // 根据状态判断是否需要更新审批人列表
  155. if ((advance.status === auditConst.advance.status.uncheck || advance.status === auditConst.advance.status.checkNo) && this.ctx.tender.info.shenpi.advance !== shenpiConst.sp_status.sqspr) {
  156. const shenpi_status = this.ctx.tender.info.shenpi.advance;
  157. // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
  158. const auditList = await this.service.advanceAudit.getAllDataByCondition({ where: { vid: advance.id, times: advance.times }, orders: [['order', 'asc']] });
  159. const auditIdList = _.map(auditList, 'audit_id');
  160. if (shenpi_status === shenpiConst.sp_status.gdspl) {
  161. const shenpiList = await this.service.shenpiAudit.getAllDataByCondition({ where: { tid: advance.tid, sp_type: shenpiConst.sp_type.advance, sp_status: shenpi_status } });
  162. const shenpiIdList = _.map(shenpiList, 'audit_id');
  163. // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
  164. if (!_.isEqual(auditIdList, shenpiIdList)) {
  165. await this.service.advanceAudit.updateNewAuditList(advance, shenpiIdList);
  166. }
  167. } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
  168. const shenpiInfo = await this.service.shenpiAudit.getDataByCondition({ tid: advance.tid, sp_type: shenpiConst.sp_type.advance, sp_status: shenpi_status });
  169. // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
  170. if (shenpiInfo && shenpiInfo.audit_id !== _.last(auditIdList)) {
  171. await this.service.advanceAudit.updateLastAudit(advance, auditList, shenpiInfo.audit_id);
  172. } else if (!shenpiInfo) {
  173. // 不存在终审人的状态下这里恢复为授权审批人
  174. this.ctx.tender.info.shenpi.advance = shenpiConst.sp_status.sqspr;
  175. }
  176. }
  177. }
  178. advance.advancePayTotal = this.ctx.tender.info.deal_param[advanceConst.typeCol[advance.type].key + 'Advance'];
  179. if (advance.status === auditConst.advance.status.checkNo) {
  180. advance.curAuditor = await this.service.advanceAudit.getAuditorByStatus(advance.id, advance.status, times);
  181. advance.auditHistory = await this.service.advanceAudit.getAuditors(advance.id, times);
  182. }
  183. }
  184. async advanceDetail(ctx) {
  185. try {
  186. const { id } = ctx.query;
  187. const advance = await this.service.advance.getDataById(id);
  188. if (!advance) {
  189. throw '预付款数据错误';
  190. }
  191. await this.advanceCheck(advance);
  192. advance.auditHistory = advance.auditHistory.reduce((prev, curr, idx) => {
  193. if (idx === 0) {
  194. const reportor = {
  195. audit_id: advance.uid,
  196. audit_order: 0,
  197. audit_type: 1,
  198. status: advance.status === auditConst.advance.status.uncheck ? auditConst.advance.status.uncheck : auditConst.advance.status.checked,
  199. times: curr.times,
  200. begin_time: advance.pay_time,
  201. end_time: advance.auditHistory.length ? advance.auditHistory[0].create_time : null,
  202. name: advance.user.name,
  203. company: advance.user.company,
  204. role: advance.user.role,
  205. mobile: '',
  206. opinion: '',
  207. };
  208. prev.push({
  209. name: '原报',
  210. status: reportor.status,
  211. audit_type: reportor.audit_type,
  212. auditors: [reportor],
  213. });
  214. }
  215. const currentOrder = advance.auditors.find(auditor => auditor.audit_id === curr.audit_id).order;
  216. prev.push(
  217. {
  218. name: currentOrder === curr.max_sort ? '终审' : `${currentOrder}审`,
  219. status: curr.status,
  220. audit_type: 1,
  221. auditors: [{
  222. audit_id: curr.audit_id,
  223. audit_order: curr.order,
  224. audit_type: curr.type,
  225. status: curr.status,
  226. max_sort: curr.max_sort,
  227. begin_time: curr.create_time,
  228. end_time: curr.end_time,
  229. name: curr.name,
  230. company: curr.company,
  231. mobile: curr.mobile,
  232. opinion: curr.opinion,
  233. role: curr.role,
  234. times: curr.times,
  235. }],
  236. }
  237. );
  238. return prev;
  239. }, []);
  240. if (advance.curAuditor) {
  241. advance.curAuditor.audit_order = advance.auditors.find(auditor => auditor.audit_id === advance.curAuditor.audit_id).order;
  242. }
  243. ctx.body = { code: 0, msg: '', data: { advance } };
  244. } catch (error) {
  245. this.log(error);
  246. ctx.body = { code: -1, msg: error.toString(), data: null };
  247. }
  248. }
  249. async advanceAudit(ctx) {
  250. try {
  251. const advance = await this.service.advance.getDataById(ctx.request.body.id);
  252. await this.advanceCheck(advance);
  253. ctx.advance = advance;
  254. const data = {
  255. checkType: parseInt(ctx.request.body.checkType),
  256. opinion: ctx.request.body.opinion,
  257. };
  258. if (!advance || advance.status !== auditConst.advance.status.checking) {
  259. throw '当前预付款数据有误';
  260. }
  261. if (!advance.curAuditor || advance.curAuditor.audit_id !== ctx.session.sessionUser.accountId) {
  262. throw '您无权进行该操作';
  263. }
  264. if (!data.checkType || isNaN(data.checkType)) {
  265. throw '提交数据错误';
  266. }
  267. if (data.checkType === auditConst.advance.status.checkNo) {
  268. if (!data.checkType || isNaN(data.checkType)) {
  269. throw '提交数据错误';
  270. }
  271. }
  272. await ctx.service.advanceAudit.check(advance.id, data, advance.times, advance.type);
  273. ctx.body = { code: 0, msg: '操作成功', data: null };
  274. } catch (error) {
  275. this.log(error);
  276. ctx.body = { code: -1, msg: error.toString(), data: null };
  277. }
  278. }
  279. async reviseDetail(ctx) {
  280. try {
  281. const { rid } = ctx.query;
  282. const revise = rid
  283. ? await ctx.service.ledgerRevise.getRevise(ctx.tender.id, rid)
  284. : ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
  285. revise.preHis = revise.pre_his_id ? await ctx.service.ledgerHistory.getDataById(revise.pre_his_id) : null;
  286. revise.curHis = revise.his_id ? await ctx.service.ledgerHistory.getDataById(revise.his_id) : null;
  287. await ctx.service.reviseAudit.loadReviseUser(revise);
  288. await ctx.service.reviseAudit.loadReviseAuditViewData(revise);
  289. revise.auditHistory = revise.auditors.reduce((prev, curr, idx) => {
  290. if (idx === 0) {
  291. const reportor = {
  292. audit_id: revise.uid,
  293. audit_order: 0,
  294. audit_type: 1,
  295. status: revise.status === auditConst.revise.status.uncheck ? auditConst.revise.status.uncheck : auditConst.revise.status.checked,
  296. times: curr.times,
  297. begin_time: revise.in_time,
  298. end_time: revise.auditors.length ? revise.auditors[0].begin_time : null,
  299. name: revise.user.name,
  300. company: revise.user.company,
  301. role: revise.user.role,
  302. mobile: '',
  303. opinion: '',
  304. };
  305. prev.push({
  306. name: '原报',
  307. status: reportor.status,
  308. audit_type: reportor.audit_type,
  309. auditors: [reportor],
  310. });
  311. }
  312. const currentOrder = curr.audit_order;
  313. prev.push(
  314. {
  315. name: currentOrder === curr.max_sort ? '终审' : `${currentOrder}审`,
  316. status: curr.status,
  317. audit_type: 1,
  318. auditors: [{
  319. audit_id: curr.audit_id,
  320. audit_order: curr.audit_order,
  321. audit_type: curr.audit_type,
  322. status: curr.status,
  323. max_sort: curr.max_sort,
  324. begin_time: curr.begin_time,
  325. end_time: curr.end_time,
  326. name: curr.name,
  327. company: curr.company,
  328. mobile: curr.mobile,
  329. opinion: curr.opinion,
  330. role: curr.role,
  331. times: curr.times,
  332. }],
  333. }
  334. );
  335. return prev;
  336. }, []);
  337. const GclGather = require('../lib/gcl_gather');
  338. const gclGatherModal = new GclGather.gclCompareGather(this.ctx);
  339. const spec = { zlj: stdConst.zlj, jrg: stdConst.jrg };
  340. spec.zlj.deal_bills_tp = ctx.tender.info.deal_param.zanLiePrice;
  341. gclGatherModal.init(ctx.tender.info.chapter, spec);
  342. const reviseBillsData = revise.readOnly && revise.curHis
  343. ? await ctx.helper.loadLedgerDataFromOss(revise.curHis.bills_file)
  344. : await ctx.service.reviseBills.getAllDataByCondition({ where: { tender_id: ctx.tender.id } });
  345. const revisePosData = revise.readOnly && revise.curHis
  346. ? await this.ctx.helper.loadLedgerDataFromOss(revise.curHis.pos_file)
  347. : await ctx.service.revisePos.getAllDataByCondition({ where: { tid: ctx.tender.id } });
  348. const price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { rid: revise.id } });
  349. gclGatherModal.gatherReviseLedgerData(reviseBillsData, revisePosData, { prefix: 'new_' }, price, ctx.tender.info.decimal);
  350. const billsData = revise.preHis ? await this.ctx.helper.loadLedgerDataFromOss(revise.preHis.bills_file) : [];
  351. const posData = revise.preHis ? await this.ctx.helper.loadLedgerDataFromOss(revise.preHis.pos_file) : [];
  352. gclGatherModal.gatherLedgerData(billsData, posData, { prefix: 'org_' });
  353. revise.chapterList = gclGatherModal.chapterData();
  354. revise.new_tp = gclGatherModal.otherChapter.hj.new_total_price || 0;
  355. revise.org_tp = gclGatherModal.otherChapter.hj.org_total_price || 0;
  356. console.log(ctx.tender.data.name);
  357. revise.tenderName = ctx.tender.data.name;
  358. ctx.body = { code: 0, msg: '', data: { revise } };
  359. } catch (error) {
  360. ctx.log(error);
  361. ctx.body = { code: -1, msg: error.toString(), data: null };
  362. }
  363. }
  364. async ledgerAuditCheck(ctx) {
  365. const tender = ctx.tender.data;
  366. const info = ctx.tender.info;
  367. if (info.shenpi.ledger === shenpiConst.sp_status.sqspr) return;
  368. if (tender.ledger_status !== auditConst.ledger.status.uncheck && tender.ledger_status !== auditConst.ledger.status.checkNo) return;
  369. const shenpi_status = info.shenpi.ledger;
  370. // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
  371. const auditList = await ctx.service.ledgerAudit.getAuditors(tender.id, tender.ledger_times);
  372. if (shenpi_status === shenpiConst.sp_status.gdspl) {
  373. const shenpiList = await ctx.service.shenpiAudit.getAllDataByCondition({ where: { tid: tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status } });
  374. // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
  375. let sameAudit = auditList.length === shenpiList.length;
  376. if (sameAudit) {
  377. for (const audit of auditList) {
  378. const shenpi = shenpiList.find(x => { return x.audit_id === audit.audit_id; });
  379. if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type || shenpi.audit_ledger_id !== audit.audit_ledger_id) {
  380. sameAudit = false;
  381. break;
  382. }
  383. }
  384. }
  385. if (!sameAudit) await ctx.service.ledgerAudit.updateNewAuditList(tender, shenpiList);
  386. } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
  387. const shenpiInfo = await ctx.service.shenpiAudit.getDataByCondition({ tid: tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status });
  388. // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
  389. const lastAuditors = auditList.filter(x => { x.audit_order === auditList[auditList.length - 1].audit_order; });
  390. if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].audit_id))) {
  391. await ctx.service.ledgerAudit.updateLastAudit(tender, auditList, shenpiInfo.audit_id);
  392. } else if (!shenpiInfo) {
  393. // 不存在终审人的状态下这里恢复为授权审批人
  394. info.shenpi.ledger = shenpiConst.sp_status.sqspr;
  395. }
  396. }
  397. }
  398. async ledgerDetail(ctx) {
  399. try {
  400. await this.ledgerAuditCheck(ctx);
  401. const tender = ctx.tender.data;
  402. await ctx.service.ledgerAudit.loadLedgerUser(tender);
  403. await ctx.service.ledgerAudit.loadLedgerAuditViewData(tender);
  404. const auditHistory = tender.auditHistory && tender.auditHistory.length && tender.auditHistory[tender.auditHistory.length - 1].reduce((prev, curr, idx) => {
  405. if (idx === 0) {
  406. const reportor = {
  407. audit_id: tender.user.id,
  408. audit_order: 0,
  409. audit_type: 1,
  410. status: tender.ledger_status === auditConst.ledger.status.uncheck ? auditConst.ledger.status.uncheck : auditConst.ledger.status.checked,
  411. times: tender.ledger_status === auditConst.ledger.status.checkNo ? tender.ledger_times - 1 : tender.ledger_times,
  412. begin_time: curr.begin_time,
  413. end_time: curr.begin_time,
  414. name: tender.user.name,
  415. company: tender.user.company,
  416. role: tender.user.role,
  417. mobile: '',
  418. opinion: '',
  419. };
  420. prev.push({
  421. name: '原报',
  422. status: reportor.status,
  423. audit_type: reportor.audit_type,
  424. auditors: [reportor],
  425. });
  426. }
  427. prev.push({
  428. name: curr.is_final ? '终审' : `${curr.order}审`,
  429. audit_type: curr.audit_type,
  430. status: curr.status,
  431. auditors: curr.auditors,
  432. });
  433. return prev;
  434. }, []);
  435. const curAuditors = tender.curAuditors;
  436. const ledger = {
  437. contractPrice: ctx.tender.info.deal_param.contractPrice,
  438. totalPrice: tender.total_price || 0,
  439. auditHistory,
  440. curAuditors,
  441. };
  442. ctx.body = { code: 0, msg: '', data: { ledger } };
  443. } catch (error) {
  444. this.log(error);
  445. ctx.body = { code: -1, msg: error.toString(), data: null };
  446. }
  447. }
  448. async ledgerAudit(ctx) {
  449. try {
  450. await this.ledgerAuditCheck(ctx);
  451. const tender = ctx.tender;
  452. if (!tender.data || tender.data.ledger_status !== auditConst.ledger.status.checking) {
  453. throw '当前标段数据有误';
  454. }
  455. const curAudits = await ctx.service.ledgerAudit.getCurAuditors(tender.id, tender.data.ledger_times);
  456. const curAuditIds = curAudits.map(x => { return x.audit_id; });
  457. if (curAuditIds.indexOf(ctx.session.sessionUser.accountId) < 0) {
  458. throw '审批失败';
  459. }
  460. const checkType = parseInt(ctx.request.body.checkType);
  461. if (!checkType || isNaN(checkType)) {
  462. throw '提交数据错误';
  463. }
  464. await ctx.service.ledgerAudit.check(tender.id, checkType, ctx.request.body.opinion, tender.data.ledger_times);
  465. ctx.body = { code: 0, msg: '操作成功', data: null };
  466. } catch (error) {
  467. this.log(error);
  468. ctx.body = { code: -1, msg: error.toString(), data: null };
  469. }
  470. }
  471. async changeList(ctx) {
  472. try {
  473. const { type } = ctx.request.query;
  474. const curChangeMap = changeMap[type];
  475. if (!curChangeMap) {
  476. throw '变更类型错误';
  477. }
  478. const tender = ctx.tender.data;
  479. const list = await ctx.service[curChangeMap.service].getListByStatus(tender.id, 0, 1, 0, 0, 0);
  480. ctx.body = { code: 0, msg: '', data: list };
  481. } catch (error) {
  482. this.log(error);
  483. ctx.body = { code: -1, msg: error.toString(), data: null };
  484. }
  485. }
  486. async changeCheck(ctx) {
  487. try {
  488. const { type } = ctx.request.query || ctx.request.body;
  489. const curChangeMap = changeMap[type];
  490. const subProject = await ctx.service.subProject.getDataById(ctx.tender.data.spid);
  491. if (curChangeMap && curChangeMap.pageShowKey && !subProject.page_show[curChangeMap.pageShowKey]) {
  492. throw '该功能已关闭';
  493. }
  494. const id = ctx.request.query.id || this.request.body.id;
  495. if (!id) {
  496. throw '您访问的变更数据不存在';
  497. }
  498. const condition = { [type === 'change' ? 'cid' : 'id']: id };
  499. const change = await ctx.service[curChangeMap.service].getDataByCondition(condition);
  500. console.log(change);
  501. if (!change) throw '变更方案数据有误';
  502. // 读取原报、审核人数据
  503. await ctx.service[curChangeMap.service].loadChangeUser(change);
  504. // decimal小数位设置
  505. change.decimal = change.decimal ? JSON.parse(change.decimal) : { tp: ctx.tender.info.decimal.tp, up: ctx.tender.info.decimal.up, precision: ctx.tender.info.precision };
  506. // 权限相关
  507. // todo 校验权限 (标段参与人、分享)
  508. const accountId = ctx.session.sessionUser.accountId,
  509. shareIds = [];
  510. const permission = ctx.session.sessionUser.permission;
  511. const status = auditConst[type].status;
  512. if (accountId === change.uid) { // 原报
  513. change.curTimes = change.times;
  514. change.filePermission = true;
  515. } else if (change.auditorIds.indexOf(accountId) !== -1) { // 审批人
  516. if (change.status === status.uncheck) {
  517. throw '您无权查看该数据';
  518. }
  519. // change.readOnly = change.status !== status.checking || accountId !== change.curAuditor.aid;
  520. change.curTimes = change.status === status.checkNo || change.status === status.revise ? change.times - 1 : change.times;
  521. change.filePermission = true;
  522. } else if ((change.status === status.checkNo || change.status === status.revise) && change.uid !== accountId) {
  523. const preAuditors = await ctx.service[curChangeMap.auditService].getAuditors(change.id, change.times - 1);
  524. const preAuditorIds = _.map(preAuditors, 'aid');
  525. if (preAuditorIds.indexOf(accountId) === -1) {
  526. throw '您无权查看该数据';
  527. }
  528. change.filePermission = true;
  529. } else if (ctx.tender.isTourist || ctx.session.sessionUser.is_admin) {
  530. change.curTimes = change.times;
  531. change.filePermission = ctx.tender.touristPermission.file || change.auditorIds.indexOf(accountId) !== -1;
  532. } else if (shareIds.indexOf(accountId) !== -1 || (permission !== null && permission.tender !== undefined && permission.tender.indexOf('2') !== -1)) { // 分享人
  533. if (change.status === auditConsts[type].status.uncheck) {
  534. throw '您无权查看该数据';
  535. }
  536. // change.readOnly = true;
  537. change.curTimes = change.status === auditConsts[type].status.checkNo || change.status === auditConsts[type].status.revise ? change.times - 1 : change.times;
  538. change.filePermission = false;
  539. } else { // 其他不可见
  540. throw '您无权查看该数据';
  541. }
  542. // 调差的readOnly 指表格和页面只能看不能改,和审批无关
  543. change.readOnly = !((change.status === status.uncheck || change.status === status.checkNo || change.status === status.revise) && accountId === change.uid);
  544. change.shenpiPower = change.status === status.checking && change.curAuditorIds.indexOf(accountId) !== -1;
  545. this.change = change;
  546. await ctx.service[curChangeMap.service].doCheckChangeCanCancel(this.change);
  547. } catch (error) {
  548. this.log(error);
  549. ctx.body = { code: -1, msg: error.toString(), data: null };
  550. }
  551. }
  552. async changeDetail(ctx) {
  553. try {
  554. await this.changeCheck(ctx);
  555. const { type } = ctx.request.query || ctx.request.body;
  556. const curChangeMap = changeMap[type];
  557. await ctx.service[curChangeMap.service].loadChangeUser(this.change);
  558. await ctx.service[curChangeMap.service].loadChangeAuditViewData(this.change);
  559. const tpUnit = ctx.tender.info.decimal.tp;
  560. const subProject = await ctx.service.subProject.getDataById(ctx.tender.data.spid);
  561. const fun_set = subProject.fun_set;
  562. const auditHistory = this.change.auditHistory && this.change.auditHistory.length && this.change.auditHistory[this.change.auditHistory.length - 1].reduce((prev, curr, idx) => {
  563. prev.push({
  564. name: curr.is_final ? '终审' : curr.audit_order === 0 ? '原报' : `${curr.audit_order}审`,
  565. audit_type: curr.audit_type,
  566. status: curr.status,
  567. auditors: curr.auditors.map(a => ({...a, audit_id: a.uid})),
  568. });
  569. return prev;
  570. }, []);
  571. const curAuditors = this.change.curAuditors;
  572. const change = {
  573. id: this.change.id || this.change.cid,
  574. name: this.change.name,
  575. status: this.change.status,
  576. code: this.change.code,
  577. p_code: this.change.p_code,
  578. quality: this.change.quality,
  579. auditHistory,
  580. originHistory: this.change.auditHistory,
  581. curAuditors: curAuditors.map(a => ({...a, audit_id: a.uid})),
  582. total_price: ctx.helper.add(this.change.total_price, tpUnit),
  583. valuation_tp: ctx.helper.add(this.change.valuation_tp, tpUnit),
  584. unvaluation_tp: ctx.helper.add(this.change.unvaluation_tp, tpUnit),
  585. state_name: subProject.page_show.openChangeState ? ctx.helper._.find(fun_set.change_state, { order: this.change.state }).name : '',
  586. plan_code: this.change.plan_code,
  587. peg: this.change.peg,
  588. org_name: this.change.org_name,
  589. };
  590. ctx.body = { code: 0, msg: '', data: {
  591. change,
  592. } };
  593. } catch (error) {
  594. this.log(error);
  595. ctx.body = { code: -1, msg: error.toString(), data: null };
  596. }
  597. }
  598. async changeAuditCheck(ctx) {
  599. const id = ctx.request.body.id;
  600. if (!id) {
  601. throw '您访问的变更数据不存在';
  602. }
  603. const type = ctx.request.body.type;
  604. const curChangeMap = changeMap[type];
  605. if (!this.change) {
  606. const change = await this.service[curChangeMap.service].getDataById(id);
  607. if (!change) throw '变更数据有误';
  608. await this.service[curChangeMap.service].loadChangeUser(change);
  609. this.change = change;
  610. }
  611. const change = this.change;
  612. const status = auditConst[type].status;
  613. if ((change.status === status.uncheck || change.status === status.checkNo || change.status === status.revise) && ctx.tender.info.shenpi.change !== shenpiConst.sp_status.sqspr) {
  614. const shenpi_status = ctx.tender.info.shenpi.change;
  615. // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
  616. const auditList = await ctx.service[curChangeMap.auditService].getAllDataByCondition({ where: { caid: change.id, times: change.times }, orders: [['order', 'asc']] });
  617. if (shenpi_status === shenpiConst.sp_status.gdspl) {
  618. // 判断并获取审批组
  619. const group = await ctx.service.shenpiGroup.getSelectGroupByChangeType(ctx.tender.id, shenpiConst.sp_type.change, type, change.sp_group);
  620. if ((group && change.sp_group !== group.id) || (!group && change.sp_group !== 0)) {
  621. change.sp_group = group ? group.id : 0;
  622. await ctx.service[curChangeMap.service].defaultUpdate({ id: change.id, sp_group: change.sp_group });
  623. }
  624. const condition = { tid: ctx.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: change.sp_group };
  625. const shenpiList = await ctx.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
  626. await ctx.service.shenpiAudit.noYbShenpiList(change.uid, shenpiList);
  627. if (change.sp_group === 0 && shenpiList.length === 0) {
  628. ctx.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
  629. } else {
  630. // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
  631. let sameAudit = auditList.length === shenpiList.length;
  632. if (sameAudit) {
  633. for (const audit of auditList) {
  634. const shenpi = shenpiList.find(x => { return x.audit_id === audit.aid; });
  635. if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
  636. sameAudit = false;
  637. break;
  638. }
  639. }
  640. }
  641. if (!sameAudit) {
  642. await ctx.service[curChangeMap.auditService].updateNewAuditList(change, shenpiList);
  643. await ctx.service[curChangeMap.service].loadChangeUser(change);
  644. await ctx.service[curChangeMap.service].doCheckChangeCanCancel(change);
  645. }
  646. }
  647. } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
  648. const shenpiInfo = await ctx.service.shenpiAudit.getDataByCondition({ tid: ctx.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status });
  649. if (!shenpiInfo || (shenpiInfo && shenpiInfo.audit_id === change.uid)) {
  650. // 不存在终审人 或 存在终审但与原报相同时, 这里恢复为授权审批人
  651. ctx.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
  652. } else {
  653. // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
  654. const lastAuditors = auditList.filter(x => {
  655. return x.order === auditList.length - 1;
  656. });
  657. if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].aid))) {
  658. await ctx.service[curChangeMap.auditService].updateLastAudit(change, auditList, shenpiInfo.audit_id);
  659. await ctx.service[curChangeMap.service].loadChangeUser(change);
  660. await ctx.service[curChangeMap.service].doCheckChangeCanCancel(change);
  661. }
  662. }
  663. }
  664. }
  665. }
  666. async changeAudit(ctx) {
  667. try {
  668. const { type } = ctx.request.body;
  669. await this.changeCheck(ctx);
  670. await this.changeAuditCheck(ctx);
  671. const curChangeMap = changeMap[type];
  672. const auditConst = auditConsts[type];
  673. if (!ctx.change || ctx.change.status !== auditConst.status.checking) {
  674. throw '当前变更申请数据有误';
  675. }
  676. if (ctx.change.curAuditorIds.length === 0 || ctx.change.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) === -1) {
  677. throw '您无权进行该操作';
  678. }
  679. const data = {
  680. checkType: parseInt(ctx.request.body.checkType),
  681. opinion: ctx.request.body.opinion,
  682. };
  683. if (!data.checkType || isNaN(data.checkType)) {
  684. throw '提交数据错误';
  685. }
  686. await ctx.service[auditConst.auditService].check(ctx.change.id, data, ctx.change.times);
  687. ctx.body = { code: 0, msg: '操作成功', data: null };
  688. } catch (error) {
  689. this.log(error);
  690. ctx.body = { code: -1, msg: error.toString(), data: null };
  691. }
  692. }
  693. }
  694. return WeappTenderController;
  695. };