tender_approval_setting.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. 'use strict';
  2. const auditConst = require('../const/audit');
  3. const shenpiConst = require('../const/shenpi');
  4. const crypto = require('crypto');
  5. const TenderApprovalDraft = require('../public/js/shares/tender_approval_draft');
  6. class TenderApprovalSetting {
  7. constructor(ctx) {
  8. this.ctx = ctx;
  9. }
  10. async load(tid) {
  11. const ctx = this.ctx;
  12. if (!ctx.session.sessionUser.is_admin) throw '没有设置权限';
  13. const tenderId = Number(tid);
  14. if (!Number.isSafeInteger(tenderId) || tenderId <= 0) throw '参数有误';
  15. const tender = await ctx.service.tender.getDataById(tenderId);
  16. if (!tender || tender.spid !== ctx.subProject.id || tender.project_id !== ctx.session.sessionProject.id) {
  17. throw '标段不存在或不属于当前项目';
  18. }
  19. const tenderInfo = await ctx.service.tenderInfo.getTenderInfo(tender.id);
  20. if (!tenderInfo) throw '标段信息不存在';
  21. const lastRevise = await ctx.service.ledgerRevise.getLastestRevise(tender.id);
  22. return {
  23. tender,
  24. revising: Boolean(lastRevise && lastRevise.status !== auditConst.revise.status.checked),
  25. shenpi: await ctx.service.shenpiAudit.getShenpi(tender.id, tenderInfo),
  26. };
  27. }
  28. async loadDraft(tid, code) {
  29. const current = await this.load(tid);
  30. const spec = shenpiConst.sp_lc.find(x => x.code === code);
  31. if (!spec) throw '审批栏目不存在';
  32. const snapshot = await this.ctx.service.tenderApprovalSetting.getSnapshot(current.tender.id, spec.type, code === 'stage');
  33. if (!snapshot.info) throw '标段信息不存在';
  34. const options = await this.getOptions(current, spec);
  35. return { snapshot: this.toState(snapshot, code, options.accounts), options, version: this.version(snapshot, code) };
  36. }
  37. async saveDraft(tid, code, version, operations) {
  38. const current = await this.load(tid);
  39. const spec = shenpiConst.sp_lc.find(x => x.code === code);
  40. if (!spec || !Array.isArray(operations) || operations.length > 1000 || !operations.length) throw '保存参数有误';
  41. const service = this.ctx.service.tenderApprovalSetting;
  42. const transaction = await service.beginTransaction();
  43. try {
  44. const tenders = await this.ctx.service.tender.getAllDataForUpdate({ id: current.tender.id }, transaction);
  45. if (!tenders.length || tenders[0].spid !== this.ctx.subProject.id || tenders[0].project_id !== this.ctx.session.sessionProject.id) throw '标段已变更,请刷新';
  46. current.tender = tenders[0];
  47. const snapshot = await service.getSnapshot(current.tender.id, spec.type, code === 'stage', transaction);
  48. if (!snapshot.info || this.version(snapshot, code) !== version) throw '审批配置已被修改,请关闭弹窗后重新编辑';
  49. const options = await this.getOptions(current, spec);
  50. const before = this.toState(snapshot, code, options.accounts);
  51. const draft = new TenderApprovalDraft(before, options);
  52. for (const operation of operations) draft.apply(operation);
  53. draft.validate();
  54. const shenpi = snapshot.info.shenpi ? JSON.parse(snapshot.info.shenpi) : {};
  55. shenpi[code] = draft.state.status;
  56. await service.persist(transaction, current.tender.id, spec.type, {
  57. before: this.databaseRows(before), after: this.databaseRows(draft.state), shenpi,
  58. stage: code === 'stage', cooperation: draft.cooperation,
  59. });
  60. await transaction.commit();
  61. } catch (error) {
  62. await transaction.rollback();
  63. throw error;
  64. }
  65. return { saved: true };
  66. }
  67. async getOptions(current, spec) {
  68. const accounts = await this.ctx.service.projectAccount.getAllSubProjectAccount(this.ctx.subProject);
  69. let ledgerIds = null;
  70. if (spec.code === 'stage') {
  71. const ledgers = await this.ctx.service.ledger.getAllDataByCondition({ columns: ['ledger_id', 'b_code'], where: { tender_id: current.tender.id } });
  72. ledgerIds = ledgers.filter(x => !x.b_code).map(x => String(x.ledger_id));
  73. }
  74. return {
  75. code: spec.code, spType: spec.type, name: spec.name, owner: current.tender.user_id,
  76. canCooperate: !current.revising && current.tender.ledger_status === auditConst.ledger.status.checked,
  77. accounts: accounts.map(x => ({ id: x.id, name: x.name, company: x.company, role: x.role })),
  78. auditTypes: auditConst.auditType.types, ledgerIds,
  79. };
  80. }
  81. toState(snapshot, code, accounts) {
  82. const shenpi = snapshot.info.shenpi ? JSON.parse(snapshot.info.shenpi) : {};
  83. const rows = this.databaseRows(snapshot);
  84. for (const row of rows.groups) row.change_type = row.change_type ? JSON.parse(row.change_type) : null;
  85. for (const row of rows.audits) {
  86. const account = accounts.find(x => x.id === row.audit_id);
  87. Object.assign(row, { name: account ? account.name : '用户' + row.audit_id, company: account ? account.company : '', role: account ? account.role : '' });
  88. }
  89. return Object.assign(rows, { status: shenpi[code] || 1 });
  90. }
  91. version(snapshot, code) {
  92. const shenpi = snapshot.info.shenpi ? JSON.parse(snapshot.info.shenpi) : {};
  93. const rows = this.databaseRows(snapshot);
  94. for (const key of Object.keys(rows)) rows[key].sort((a, b) => a.id - b.id);
  95. return crypto.createHash('sha256').update(JSON.stringify({ status: shenpi[code] || 1, rows })).digest('hex');
  96. }
  97. databaseRows(state) {
  98. const fields = {
  99. groups: ['id', 'name', 'is_select', 'change_type'],
  100. audits: ['id', 'audit_id', 'sp_status', 'sp_group', 'audit_order', 'audit_type', 'audit_group', 'audit_group_order', 'audit_group_limit', 'audit_checkno_valid', 'audit_group_need', 'audit_ledger_id'],
  101. assistants: ['id', 'user_id', 'ass_user_id', 'name', 'company', 'role', 'ass_ledger_id'],
  102. };
  103. const result = {};
  104. for (const key of Object.keys(fields)) {
  105. result[key] = state[key].map(row => {
  106. const data = {};
  107. for (const field of fields[key]) {
  108. if (row[field] !== undefined) data[field] = row[field];
  109. }
  110. if (key === 'groups' && data.change_type && typeof data.change_type !== 'string') data.change_type = JSON.stringify(data.change_type);
  111. return data;
  112. });
  113. }
  114. return result;
  115. }
  116. }
  117. module.exports = TenderApprovalSetting;