advance_audit_order.test.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. 'use strict';
  2. // 独立回归测试:node --test test/app/service/advance_audit_order.test.js(无需连接数据库)
  3. const { test } = require('node:test');
  4. const assert = require('node:assert/strict');
  5. const _ = require('lodash');
  6. const status = require('../../../app/const/audit').advance.status;
  7. const Service = require('../../../app/service/advance_audit')({ BaseService: class {} });
  8. const { buildUpdates } = require('../../../db_script/bak/advance_audit_order');
  9. function fixture(rows) {
  10. const service = new Service();
  11. service._ = _;
  12. service.initSqlBuilder = () => { service.sqlBuilder = new (require('../../../app/lib/sql_builder'))(); };
  13. const advance = { id: 1, tid: 2, times: 1, type: 1, uid: 99, order: 1, cur_amount: 0 };
  14. let records = rows.map(x => ({ vid: 1, tid: 2, times: 1, type: 1, audit_type: 1, ...x }));
  15. const tx = {
  16. select: async (table, options) => _.orderBy(records.filter(x => _.isMatch(x, options.where)), options.orders.map(x => x[0]), options.orders.map(x => x[1])).map(x => ({ ...x })),
  17. insert: async (table, data) => {
  18. if (table === 'advance_audit') for (const row of [].concat(data)) records.push({ id: Math.max(0, ...records.map(x => x.id)) + 1, ...row });
  19. return { affectedRows: 1 };
  20. },
  21. update: async (table, row) => { if (table === 'advance_audit') Object.assign(records.find(x => x.id === row.id), row); },
  22. delete: async (table, where) => { records = records.filter(x => !_.isMatch(x, where)); },
  23. query: async (sql, params) => { assert(params.includes('times'), '退回顺移必须限定本轮'); },
  24. commit: async () => {}, rollback: async () => {},
  25. };
  26. service.db = { beginTransaction: async () => tx, query: async sql => {
  27. assert(sql.includes('`audit_order`') && sql.includes('`audit_type`'));
  28. return _.uniqBy(_.sortBy(records, 'audit_order'), 'audit_order').map(x => _.pick(x, ['tid', 'vid', 'type', 'audit_id', 'audit_order', 'audit_type']));
  29. } };
  30. service.getAllDataByCondition = async options => records.filter(x => _.isMatch(x, options.where));
  31. service.getDataByCondition = async where => records.find(x => _.isMatch(x, where));
  32. service.getAuditors = async () => _.sortBy(records, 'order').map(x => ({ ...x }));
  33. service._syncOrderByDelete = async (transaction, vid, order, times, operation, auditOrder) => {
  34. for (const x of records.filter(x => x.vid === vid && x.times === times)) {
  35. if (x.order >= order) x.order += operation === '+' ? 1 : -1;
  36. if (x.audit_order >= auditOrder) x.audit_order += operation === '+' ? 1 : -1;
  37. }
  38. };
  39. service.getNoticeContent = async () => '';
  40. service.ctx = { advance, tender: { id: 2, info: { shenpi: { advance: 1 } } }, session: { sessionProject: { id: 1 }, sessionUser: { accountId: 30 } },
  41. helper: { urlToShort: async () => '', sendWechat: async () => {} },
  42. service: { projectAccount: { getDataById: async () => ({ enable: 1, project_id: 1 }) },
  43. advance: { tableName: 'advance', getDataById: async () => advance }, noticePush: { tableName: 'notice' },
  44. noticeAgain: { stopNoticeAgain: async () => {}, addNoticeAgain: async () => {} }, specMsg: { addAdvanceMsg: async () => {} } } };
  45. return { service, advance, records: () => records };
  46. }
  47. test('中途插人后退回原报,保留插入位置和原终审', async () => {
  48. const f = fixture([{ id: 1, audit_id: 10, order: 1, audit_order: 1, status: status.checking }, { id: 2, audit_id: 30, order: 2, audit_order: 2, status: status.uncheck }]);
  49. await f.service.saveAudit(f.advance, { operate: 'add', old_aid: 10, new_aid: 20 });
  50. assert.deepEqual(_.sortBy(f.records(), 'order').map(x => [x.audit_id, x.audit_order]), [[10, 1], [20, 2], [30, 3]]);
  51. await f.service._checkNo(1, 1, { checkType: status.checkNo, opinion: '' }, 1);
  52. assert.deepEqual(f.records().filter(x => x.times === 2).map(x => [x.audit_id, x.order, x.audit_order, x.audit_type]), [[10, 1, 1, 1], [20, 2, 2, 1], [30, 3, 3, 1]]);
  53. });
  54. test('过程顺序与节点不同,插人分别移动两种序号,管理员取最新节点', async () => {
  55. const f = fixture([{ id: 1, audit_id: 10, order: 1, audit_order: 1, status: status.checked }, { id: 2, audit_id: 10, order: 4, audit_order: 1, status: status.checking }, { id: 3, audit_id: 30, order: 5, audit_order: 2, status: status.uncheck }]);
  56. await f.service.saveAudit(f.advance, { operate: 'add', old_aid: 10, new_aid: 20 });
  57. assert.deepEqual(_.sortBy(f.records(), 'order').map(x => [x.order, x.audit_order]), [[1, 1], [4, 1], [5, 2], [6, 3]]);
  58. assert.deepEqual((await f.service.getAuditGroupByList(1, 1)).map(x => x.audit_id), [10, 20, 30]);
  59. });
  60. test('顺移SQL使用独立边界并限定轮次', async () => {
  61. const s = new Service(), calls = [];
  62. s.db = { escape: x => x };
  63. s.initSqlBuilder = () => { s.sqlBuilder = new (require('../../../app/lib/sql_builder'))(); };
  64. await s._syncOrderByDelete({ query: async (...args) => calls.push(args) }, 1, 7, 2, '+', 3);
  65. assert(calls[0][0].includes('>= 7') && calls[0][0].includes('= 2'));
  66. assert.deepEqual(calls[1][1], ['advance_audit', 1, 2, 3]);
  67. });
  68. test('退回上一审只追加过程记录,节点序号保持不变', async () => {
  69. const f = fixture([{ id: 1, audit_id: 10, order: 1, audit_order: 1, status: status.checked }, { id: 2, audit_id: 30, order: 2, audit_order: 2, status: status.checking }]);
  70. await f.service._checkNoPre(1, 1, { checkType: status.checkNoPre, opinion: '' }, 1, 1);
  71. assert.deepEqual(f.records().slice(2).map(x => [x.audit_id, x.order, x.audit_order, x.audit_type]), [[10, 3, 1, 1], [30, 4, 2, 1]]);
  72. });
  73. test('终审重新审批,新增两条过程记录沿用终审节点', async () => {
  74. const f = fixture([{ id: 1, audit_id: 10, order: 1, audit_order: 1, status: status.checked }, { id: 2, audit_id: 30, order: 6, audit_order: 2, status: status.checked }]);
  75. f.advance.auditors = f.records();
  76. assert.equal(await f.service.checkAgain(f.advance), true);
  77. assert.deepEqual(f.records().slice(2).map(x => [x.order, x.audit_order, x.audit_type]), [[7, 2, 1], [8, 2, 1]]);
  78. });
  79. test('历史回填去重且可重复运行,冲突轮次跳过', () => {
  80. const rows = [{ id: 1, audit_id: 10, order: 1 }, { id: 2, audit_id: 30, order: 3 }, { id: 3, audit_id: 20, order: 2 }, { id: 4, audit_id: 10, order: 4 }];
  81. const updates = buildUpdates(rows).updates;
  82. assert.deepEqual(updates.map(x => x.audit_order), [1, 2, 3, 1]);
  83. assert.equal(buildUpdates(rows.map(x => ({ ...x, ...updates.find(y => y.id === x.id) }))).updates.length, 0);
  84. assert(buildUpdates([{ ...rows[0], audit_order: 5 }]).skip);
  85. });
  86. test('普通增加固定终审前人员、删除及替换同步节点', async () => {
  87. const f = fixture([{ id: 1, audit_id: 10, order: 1, audit_order: 1, status: status.uncheck }, { id: 2, audit_id: 30, order: 2, audit_order: 2, status: status.uncheck }]);
  88. await f.service.addAuditor(2, 1, 20, 1, 1, 1);
  89. assert.deepEqual(_.sortBy(f.records(), 'audit_order').map(x => x.audit_id), [10, 20, 30]);
  90. await f.service.saveAudit(f.advance, { operate: 'change', old_aid: 20, new_aid: 40 });
  91. assert.equal(f.records().find(x => x.audit_id === 40).audit_order, 2);
  92. await f.service.deleteAuditor(1, 40, 1);
  93. assert.deepEqual(_.sortBy(f.records(), 'audit_order').map(x => [x.audit_id, x.order, x.audit_order]), [[10, 1, 1], [30, 2, 2]]);
  94. });