@accounter/server 0.0.9-alpha-20251210155614-e6e65aaecafef9e8fedd0b933f613ffcf478cecf → 0.0.9-alpha-20251210171954-c9c0e7693ebe08d3643d9ee2c00c03606a53e334

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/CHANGELOG.md +43 -5
  2. package/dist/server/src/__tests__/factories/business.d.ts +2 -2
  3. package/dist/server/src/__tests__/factories/business.js +5 -4
  4. package/dist/server/src/__tests__/factories/business.js.map +1 -1
  5. package/dist/server/src/__tests__/factories/business.test.js +2 -2
  6. package/dist/server/src/__tests__/factories/business.test.js.map +1 -1
  7. package/dist/server/src/__tests__/factories/charge.d.ts +9 -9
  8. package/dist/server/src/__tests__/factories/charge.js +15 -15
  9. package/dist/server/src/__tests__/factories/charge.js.map +1 -1
  10. package/dist/server/src/__tests__/factories/charge.test.js +14 -14
  11. package/dist/server/src/__tests__/factories/charge.test.js.map +1 -1
  12. package/dist/server/src/__tests__/factories/document.d.ts +9 -9
  13. package/dist/server/src/__tests__/factories/document.js +11 -11
  14. package/dist/server/src/__tests__/factories/document.js.map +1 -1
  15. package/dist/server/src/__tests__/factories/document.test.js +38 -38
  16. package/dist/server/src/__tests__/factories/document.test.js.map +1 -1
  17. package/dist/server/src/__tests__/factories/financial-account.js +2 -2
  18. package/dist/server/src/__tests__/factories/financial-account.js.map +1 -1
  19. package/dist/server/src/__tests__/factories/financial-account.test.js +7 -7
  20. package/dist/server/src/__tests__/factories/financial-account.test.js.map +1 -1
  21. package/dist/server/src/__tests__/factories/index.d.ts +2 -2
  22. package/dist/server/src/__tests__/factories/index.js +2 -2
  23. package/dist/server/src/__tests__/factories/index.js.map +1 -1
  24. package/dist/server/src/__tests__/factories/index.test.js +12 -12
  25. package/dist/server/src/__tests__/factories/index.test.js.map +1 -1
  26. package/dist/server/src/__tests__/factories/tax-category.d.ts +3 -3
  27. package/dist/server/src/__tests__/factories/tax-category.js +6 -5
  28. package/dist/server/src/__tests__/factories/tax-category.js.map +1 -1
  29. package/dist/server/src/__tests__/factories/tax-category.test.js +4 -4
  30. package/dist/server/src/__tests__/factories/tax-category.test.js.map +1 -1
  31. package/dist/server/src/__tests__/factories/transaction.d.ts +7 -7
  32. package/dist/server/src/__tests__/factories/transaction.js +11 -11
  33. package/dist/server/src/__tests__/factories/transaction.js.map +1 -1
  34. package/dist/server/src/__tests__/factories/transaction.test.js +27 -27
  35. package/dist/server/src/__tests__/factories/transaction.test.js.map +1 -1
  36. package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-a.js +20 -20
  37. package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-a.js.map +1 -1
  38. package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-b.js +20 -20
  39. package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-b.js.map +1 -1
  40. package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-b.test.js +8 -8
  41. package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-b.test.js.map +1 -1
  42. package/dist/server/src/__tests__/helpers/db-setup.d.ts +0 -1
  43. package/dist/server/src/__tests__/helpers/db-setup.js +0 -2
  44. package/dist/server/src/__tests__/helpers/db-setup.js.map +1 -1
  45. package/dist/server/src/__tests__/helpers/fixture-loader.js +2 -2
  46. package/dist/server/src/__tests__/helpers/fixture-loader.js.map +1 -1
  47. package/dist/server/src/__tests__/helpers/fixture-loader.test.js +32 -29
  48. package/dist/server/src/__tests__/helpers/fixture-loader.test.js.map +1 -1
  49. package/dist/server/src/__tests__/helpers/fixture-validation.test.js +50 -50
  50. package/dist/server/src/__tests__/helpers/fixture-validation.test.js.map +1 -1
  51. package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js +23 -31
  52. package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js.map +1 -1
  53. package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js +8 -8
  54. package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js.map +1 -1
  55. package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js +41 -50
  56. package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js.map +1 -1
  57. package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js +23 -31
  58. package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js.map +1 -1
  59. package/dist/server/src/__tests__/helpers/test-db-config.js +1 -1
  60. package/dist/server/src/__tests__/helpers/test-db-config.js.map +1 -1
  61. package/dist/server/src/__tests__/seed-admin-context.integration.test.js +128 -131
  62. package/dist/server/src/__tests__/seed-admin-context.integration.test.js.map +1 -1
  63. package/dist/server/src/demo-fixtures/__tests__/deterministic-uuid.test.js +58 -0
  64. package/dist/server/src/demo-fixtures/__tests__/deterministic-uuid.test.js.map +1 -0
  65. package/dist/server/src/demo-fixtures/helpers/deterministic-uuid.d.ts +50 -0
  66. package/dist/server/src/demo-fixtures/helpers/deterministic-uuid.js +66 -0
  67. package/dist/server/src/demo-fixtures/helpers/deterministic-uuid.js.map +1 -0
  68. package/dist/server/src/modules/admin-context/{heplers → helpers}/admin-context.helper.d.ts +1 -1
  69. package/dist/server/src/modules/admin-context/{heplers → helpers}/admin-context.helper.js +2 -2
  70. package/dist/server/src/modules/admin-context/{heplers → helpers}/admin-context.helper.js.map +1 -1
  71. package/dist/server/src/modules/admin-context/resolvers/admin-context.resolvers.js +1 -1
  72. package/dist/server/src/modules/business-trips/providers/business-trips.provider.d.ts +1 -1
  73. package/dist/server/src/modules/business-trips/providers/business-trips.provider.js +1 -1
  74. package/dist/server/src/modules/business-trips/providers/business-trips.provider.js.map +1 -1
  75. package/dist/server/src/modules/charges/helpers/common.helper.js +3 -3
  76. package/dist/server/src/modules/charges/helpers/common.helper.js.map +1 -1
  77. package/dist/server/src/modules/charges/helpers/{merge-charges.hepler.js → merge-charges.helper.js} +6 -6
  78. package/dist/server/src/modules/charges/helpers/{merge-charges.hepler.js.map → merge-charges.helper.js.map} +1 -1
  79. package/dist/server/src/modules/charges/resolvers/charges.resolver.js +1 -1
  80. package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.js +2 -2
  81. package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.js.map +1 -1
  82. package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.js +1 -1
  83. package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.js.map +1 -1
  84. package/dist/server/src/modules/corn-jobs/resolvers/corn-jobs.resolver.js +1 -1
  85. package/dist/server/src/modules/corn-jobs/resolvers/corn-jobs.resolver.js.map +1 -1
  86. package/dist/server/src/modules/ledger/__tests__/helpers/ledger-assertions.d.ts +0 -2
  87. package/dist/server/src/modules/ledger/__tests__/helpers/ledger-assertions.js +0 -4
  88. package/dist/server/src/modules/ledger/__tests__/helpers/ledger-assertions.js.map +1 -1
  89. package/dist/server/src/modules/ledger/__tests__/ledger-scenario-a.integration.test.js +20 -20
  90. package/dist/server/src/modules/ledger/__tests__/ledger-scenario-a.integration.test.js.map +1 -1
  91. package/dist/server/src/modules/ledger/__tests__/ledger-scenario-b.integration.test.js +21 -21
  92. package/dist/server/src/modules/ledger/__tests__/ledger-scenario-b.integration.test.js.map +1 -1
  93. package/dist/server/src/modules/transactions/helpers/common.helper.js +11 -6
  94. package/dist/server/src/modules/transactions/helpers/common.helper.js.map +1 -1
  95. package/package.json +1 -1
  96. package/src/__tests__/factories/business.test.ts +3 -3
  97. package/src/__tests__/factories/business.ts +5 -4
  98. package/src/__tests__/factories/charge.test.ts +14 -14
  99. package/src/__tests__/factories/charge.ts +16 -16
  100. package/src/__tests__/factories/document.test.ts +38 -38
  101. package/src/__tests__/factories/document.ts +11 -11
  102. package/src/__tests__/factories/financial-account.test.ts +7 -7
  103. package/src/__tests__/factories/financial-account.ts +3 -3
  104. package/src/__tests__/factories/index.test.ts +12 -12
  105. package/src/__tests__/factories/index.ts +2 -2
  106. package/src/__tests__/factories/tax-category.test.ts +4 -4
  107. package/src/__tests__/factories/tax-category.ts +7 -6
  108. package/src/__tests__/factories/transaction.test.ts +27 -27
  109. package/src/__tests__/factories/transaction.ts +11 -11
  110. package/src/__tests__/fixtures/expenses/expense-scenario-a.ts +20 -20
  111. package/src/__tests__/fixtures/expenses/expense-scenario-b.test.ts +8 -8
  112. package/src/__tests__/fixtures/expenses/expense-scenario-b.ts +20 -20
  113. package/src/__tests__/helpers/db-setup.ts +0 -3
  114. package/src/__tests__/helpers/fixture-loader.test.ts +31 -29
  115. package/src/__tests__/helpers/fixture-loader.ts +2 -2
  116. package/src/__tests__/helpers/fixture-validation.test.ts +50 -50
  117. package/src/__tests__/helpers/seed-helpers.business.test.ts +145 -147
  118. package/src/__tests__/helpers/seed-helpers.concurrent.test.ts +10 -10
  119. package/src/__tests__/helpers/seed-helpers.financial-entity.test.ts +218 -231
  120. package/src/__tests__/helpers/seed-helpers.tax-category.test.ts +162 -164
  121. package/src/__tests__/helpers/test-db-config.ts +1 -1
  122. package/src/__tests__/seed-admin-context.integration.test.ts +199 -208
  123. package/src/demo-fixtures/__tests__/deterministic-uuid.test.ts +75 -0
  124. package/src/demo-fixtures/helpers/deterministic-uuid.ts +68 -0
  125. package/src/modules/admin-context/{heplers → helpers}/admin-context.helper.ts +3 -3
  126. package/src/modules/admin-context/resolvers/admin-context.resolvers.ts +1 -1
  127. package/src/modules/business-trips/providers/business-trips.provider.ts +1 -1
  128. package/src/modules/charges/helpers/common.helper.ts +3 -3
  129. package/src/modules/charges/helpers/{merge-charges.hepler.ts → merge-charges.helper.ts} +5 -5
  130. package/src/modules/charges/resolvers/charges.resolver.ts +1 -1
  131. package/src/modules/charges-matcher/__tests__/auto-match-integration.test.ts +2 -2
  132. package/src/modules/charges-matcher/providers/charges-matcher.provider.ts +1 -1
  133. package/src/modules/corn-jobs/resolvers/corn-jobs.resolver.ts +1 -1
  134. package/src/modules/ledger/__tests__/helpers/ledger-assertions.ts +0 -5
  135. package/src/modules/ledger/__tests__/ledger-scenario-a.integration.test.ts +20 -20
  136. package/src/modules/ledger/__tests__/ledger-scenario-b.integration.test.ts +21 -21
  137. package/src/modules/transactions/helpers/common.helper.ts +12 -6
  138. package/dist/server/src/__tests__/factories/ids.d.ts +0 -22
  139. package/dist/server/src/__tests__/factories/ids.js +0 -46
  140. package/dist/server/src/__tests__/factories/ids.js.map +0 -1
  141. package/dist/server/src/__tests__/factories/ids.test.js +0 -71
  142. package/dist/server/src/__tests__/factories/ids.test.js.map +0 -1
  143. package/src/__tests__/factories/ids.test.ts +0 -80
  144. package/src/__tests__/factories/ids.ts +0 -49
  145. /package/dist/server/src/{__tests__/factories/ids.test.d.ts → demo-fixtures/__tests__/deterministic-uuid.test.d.ts} +0 -0
  146. /package/dist/server/src/modules/charges/helpers/{merge-charges.hepler.d.ts → merge-charges.helper.d.ts} +0 -0
@@ -20,7 +20,7 @@ vi.mock('../../../modules/transactions/providers/transactions.provider.js', () =
20
20
  TransactionsProvider: class {},
21
21
  }));
22
22
 
23
- vi.mock('../../../modules/charges/helpers/merge-charges.hepler.js', () => ({
23
+ vi.mock('../../../modules/charges/helpers/merge-charges.helper.js', () => ({
24
24
  mergeChargesExecutor: vi.fn(),
25
25
  }));
26
26
 
@@ -31,7 +31,7 @@ vi.mock('../../../shared/helpers/index.js', () => ({
31
31
  // Import after mocking
32
32
  const { ChargesMatcherProvider } = await import('../providers/charges-matcher.provider.js');
33
33
  const { mergeChargesExecutor } = await import(
34
- '../../../modules/charges/helpers/merge-charges.hepler.js'
34
+ '../../charges/helpers/merge-charges.helper.js'
35
35
  );
36
36
 
37
37
  type Injector = {
@@ -7,11 +7,11 @@
7
7
 
8
8
  import { subYears } from 'date-fns';
9
9
  import { Injectable, Scope } from 'graphql-modules';
10
- import { mergeChargesExecutor } from '../../../modules/charges/helpers/merge-charges.hepler.js';
11
10
  import { ChargesProvider } from '../../../modules/charges/providers/charges.provider.js';
12
11
  import { DocumentsProvider } from '../../../modules/documents/providers/documents.provider.js';
13
12
  import { TransactionsProvider } from '../../../modules/transactions/providers/transactions.provider.js';
14
13
  import { dateToTimelessDateString } from '../../../shared/helpers/index.js';
14
+ import { mergeChargesExecutor } from '../../charges/helpers/merge-charges.helper.js';
15
15
  import { validateChargeIsUnmatched } from '../helpers/charge-validator.helper.js';
16
16
  import {
17
17
  ChargeType,
@@ -1,8 +1,8 @@
1
1
  import { GraphQLError } from 'graphql';
2
- import { mergeChargesExecutor } from '../../../modules/charges/helpers/merge-charges.hepler.js';
3
2
  import { ChargesProvider } from '../../../modules/charges/providers/charges.provider.js';
4
3
  import type { IGetChargesByIdsResult } from '../../../modules/charges/types.js';
5
4
  import type { IGetTransactionsByChargeIdsResult } from '../../../modules/transactions/types.js';
5
+ import { mergeChargesExecutor } from '../../charges/helpers/merge-charges.helper.js';
6
6
  import { CornJobsProvider } from '../providers/corn-jobs.provider.js';
7
7
  import type { CornJobsModule } from '../types.js';
8
8
 
@@ -1,6 +1,4 @@
1
1
  import { expect } from 'vitest';
2
- // Adjusted relative path: helper is one directory deeper than scenario tests
3
- import { makeUUID } from '../../../../__tests__/factories/ids.js';
4
2
 
5
3
  // Minimal ledger record type based on DB result interface
6
4
  export interface LedgerRecord {
@@ -243,9 +241,6 @@ export function assertExpenseScenarioLogic(records: LedgerRecord[], opts: {
243
241
  });
244
242
  }
245
243
 
246
- /** Helper to prepare deterministic UUID sets for known fixture aliases */
247
- export function fixtureUUID(alias: string): string { return makeUUID(alias); }
248
-
249
244
  /** Combined high-level assertion for typical simple local expense scenario */
250
245
  export function assertSimpleLocalExpenseScenario(records: LedgerRecord[], params: {
251
246
  chargeId: string;
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
2
  import { TestDatabase } from '../../../__tests__/helpers/db-setup.js';
3
3
  import { insertFixture } from '../../../__tests__/helpers/fixture-loader.js';
4
4
  import { expenseScenarioA } from '../../../__tests__/fixtures/expenses/expense-scenario-a.js';
5
- import { makeUUID } from '../../../__tests__/factories/ids.js';
5
+ import { makeUUID } from '../../../demo-fixtures/helpers/deterministic-uuid.js';
6
6
  import { qualifyTable } from '../../../__tests__/helpers/test-db-config.js';
7
7
  import { buildAdminContextFromDb } from '../../../__tests__/helpers/admin-context-builder.js';
8
8
  import { env } from '../../../environment.js';
@@ -43,7 +43,7 @@ describe('Ledger Generation - Expense Scenario A', () => {
43
43
  afterEach(async () => {
44
44
  const client = await db.getPool().connect();
45
45
  try {
46
- const chargeId = makeUUID('charge-office-supplies');
46
+ const chargeId = makeUUID('charge', 'charge-office-supplies');
47
47
  await client.query(
48
48
  `DELETE FROM ${qualifyTable('ledger_records')} WHERE charge_id = $1`,
49
49
  [chargeId],
@@ -65,7 +65,7 @@ describe('Ledger Generation - Expense Scenario A', () => {
65
65
  await client.query(
66
66
  `DELETE FROM ${qualifyTable('financial_accounts_tax_categories')}
67
67
  WHERE tax_category_id IN ($1, $2)`,
68
- [makeUUID('expense-general'), makeUUID('bank-account-tax-category')],
68
+ [makeUUID('tax-category', 'expense-general'), makeUUID('tax-category', 'bank-account-tax-category')],
69
69
  );
70
70
  await client.query(
71
71
  `DELETE FROM ${qualifyTable('financial_accounts')} WHERE account_number = $1`,
@@ -73,19 +73,19 @@ describe('Ledger Generation - Expense Scenario A', () => {
73
73
  );
74
74
  await client.query(
75
75
  `DELETE FROM ${qualifyTable('tax_categories')} WHERE id IN ($1, $2)`,
76
- [makeUUID('expense-general'), makeUUID('bank-account-tax-category')],
76
+ [makeUUID('tax-category', 'expense-general'), makeUUID('tax-category', 'bank-account-tax-category')],
77
77
  );
78
78
  await client.query(
79
79
  `DELETE FROM ${qualifyTable('businesses')} WHERE id IN ($1, $2)`,
80
- [makeUUID('admin-business'), makeUUID('supplier-local-ltd')],
80
+ [makeUUID('business', 'admin-business-scenario-a'), makeUUID('business', 'supplier-local-ltd')],
81
81
  );
82
82
  await client.query(
83
83
  `DELETE FROM ${qualifyTable('financial_entities')} WHERE id IN ($1, $2, $3, $4)`,
84
84
  [
85
- makeUUID('admin-business'),
86
- makeUUID('supplier-local-ltd'),
87
- makeUUID('expense-general'),
88
- makeUUID('bank-account-tax-category'),
85
+ makeUUID('business', 'admin-business-scenario-a'),
86
+ makeUUID('business', 'supplier-local-ltd'),
87
+ makeUUID('tax-category', 'expense-general'),
88
+ makeUUID('tax-category', 'bank-account-tax-category'),
89
89
  ],
90
90
  );
91
91
  } finally {
@@ -101,7 +101,7 @@ describe('Ledger Generation - Expense Scenario A', () => {
101
101
 
102
102
  await insertFixture(insertClient, expenseScenarioA);
103
103
 
104
- const chargeId = makeUUID('charge-office-supplies');
104
+ const chargeId = makeUUID('charge', 'charge-office-supplies');
105
105
 
106
106
  // Verify inserts within the same transaction
107
107
  const chargeResult = await insertClient.query(
@@ -137,7 +137,7 @@ describe('Ledger Generation - Expense Scenario A', () => {
137
137
  // Re-open a new client (outside prior transaction) for verification & generation
138
138
  const client = await db.getPool().connect();
139
139
  try {
140
- const chargeId = makeUUID('charge-office-supplies');
140
+ const chargeId = makeUUID('charge', 'charge-office-supplies');
141
141
  const chargeResult = await client.query(
142
142
  `SELECT * FROM ${qualifyTable('charges')} WHERE id = $1`,
143
143
  [chargeId],
@@ -192,8 +192,8 @@ describe('Ledger Generation - Expense Scenario A', () => {
192
192
  assertSimpleLocalExpenseScenario(ledgerResult.rows as any, {
193
193
  chargeId: charge.id,
194
194
  ownerId: charge.owner_id, // Use actual charge owner for ledger record owner assertions
195
- expenseEntity: makeUUID('expense-general'),
196
- bankEntity: makeUUID('bank-account-tax-category'),
195
+ expenseEntity: makeUUID('tax-category', 'expense-general'),
196
+ bankEntity: makeUUID('tax-category', 'bank-account-tax-category'),
197
197
  expectedCurrency: Currency.Ils,
198
198
  expectedTotal: ledgerExpectation?.totalDebitLocal || 500.0,
199
199
  });
@@ -212,7 +212,7 @@ describe('Ledger Generation - Expense Scenario A', () => {
212
212
  it('should be idempotent on repeated ledger generation (no duplicate records)', async () => {
213
213
  const client = await db.getPool().connect();
214
214
  try {
215
- const chargeId = makeUUID('charge-office-supplies');
215
+ const chargeId = makeUUID('charge', 'charge-office-supplies');
216
216
  // Ensure fixture inserted (if previous test did cleanup, reinsert minimal fixture)
217
217
  const existingCharge = await client.query(
218
218
  `SELECT * FROM ${qualifyTable('charges')} WHERE id = $1`,
@@ -296,7 +296,7 @@ describe('Ledger Generation - Expense Scenario A', () => {
296
296
  expect(expenseScenarioA.expectations?.ledger).toHaveLength(1);
297
297
 
298
298
  const ledgerExpectation = expenseScenarioA.expectations?.ledger?.[0];
299
- expect(ledgerExpectation?.chargeId).toBe(makeUUID('charge-office-supplies'));
299
+ expect(ledgerExpectation?.chargeId).toBe(makeUUID('charge', 'charge-office-supplies'));
300
300
  expect(ledgerExpectation?.recordCount).toBe(2);
301
301
  expect(ledgerExpectation?.balanced).toBe(true);
302
302
  expect(ledgerExpectation?.totalDebitLocal).toBe(500.0);
@@ -307,11 +307,11 @@ describe('Ledger Generation - Expense Scenario A', () => {
307
307
 
308
308
  it('should create deterministic UUIDs for reproducible tests', () => {
309
309
  // Verify all IDs are deterministic and match expected values
310
- const adminBusinessId = makeUUID('admin-business');
311
- const supplierId = makeUUID('supplier-local-ltd');
312
- const chargeId = makeUUID('charge-office-supplies');
313
- const transactionId = makeUUID('transaction-supplies-payment');
314
- const documentId = makeUUID('document-supplies-receipt');
310
+ const adminBusinessId = makeUUID('business', 'admin-business-scenario-a');
311
+ const supplierId = makeUUID('business', 'supplier-local-ltd');
312
+ const chargeId = makeUUID('charge', 'charge-office-supplies');
313
+ const transactionId = makeUUID('transaction', 'transaction-supplies-payment');
314
+ const documentId = makeUUID('document', 'document-supplies-receipt');
315
315
 
316
316
  expect(adminBusinessId).toBe(expenseScenarioA.businesses?.businesses[0]?.id);
317
317
  expect(supplierId).toBe(expenseScenarioA.businesses?.businesses[1]?.id);
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
2
  import { TestDatabase } from '../../../__tests__/helpers/db-setup.js';
3
3
  import { insertFixture } from '../../../__tests__/helpers/fixture-loader.js';
4
4
  import { expenseScenarioB } from '../../../__tests__/fixtures/expenses/expense-scenario-b.js';
5
- import { makeUUID } from '../../../__tests__/factories/ids.js';
5
+ import { makeUUID } from '../../../demo-fixtures/helpers/deterministic-uuid.js';
6
6
  import { qualifyTable } from '../../../__tests__/helpers/test-db-config.js';
7
7
  import { buildAdminContextFromDb } from '../../../__tests__/helpers/admin-context-builder.js';
8
8
  import { mockExchangeRate } from '../../../__tests__/helpers/exchange-mock.js';
@@ -48,7 +48,7 @@ describe('Ledger Generation - Expense Scenario B (Foreign Currency)', () => {
48
48
  afterEach(async () => {
49
49
  const client = await db.getPool().connect();
50
50
  try {
51
- const chargeId = makeUUID('charge-consulting-services');
51
+ const chargeId = makeUUID('charge', 'charge-consulting-services');
52
52
  await client.query(
53
53
  `DELETE FROM ${qualifyTable('ledger_records')} WHERE charge_id = $1`,
54
54
  [chargeId],
@@ -70,7 +70,7 @@ describe('Ledger Generation - Expense Scenario B (Foreign Currency)', () => {
70
70
  await client.query(
71
71
  `DELETE FROM ${qualifyTable('financial_accounts_tax_categories')}
72
72
  WHERE tax_category_id IN ($1, $2)`,
73
- [makeUUID('expense-consulting'), makeUUID('usd-account-tax-category')],
73
+ [makeUUID('tax-category', 'expense-consulting'), makeUUID('tax-category', 'usd-account-tax-category')],
74
74
  );
75
75
  await client.query(
76
76
  `DELETE FROM ${qualifyTable('financial_accounts')} WHERE account_number = $1`,
@@ -78,19 +78,19 @@ describe('Ledger Generation - Expense Scenario B (Foreign Currency)', () => {
78
78
  );
79
79
  await client.query(
80
80
  `DELETE FROM ${qualifyTable('tax_categories')} WHERE id IN ($1, $2)`,
81
- [makeUUID('expense-consulting'), makeUUID('usd-account-tax-category')],
81
+ [makeUUID('tax-category', 'expense-consulting'), makeUUID('tax-category', 'usd-account-tax-category')],
82
82
  );
83
83
  await client.query(
84
84
  `DELETE FROM ${qualifyTable('businesses')} WHERE id IN ($1, $2)`,
85
- [makeUUID('admin-business-usd'), makeUUID('supplier-us-vendor-llc')],
85
+ [makeUUID('business', 'admin-business-usd'), makeUUID('business', 'supplier-us-vendor-llc')],
86
86
  );
87
87
  await client.query(
88
88
  `DELETE FROM ${qualifyTable('financial_entities')} WHERE id IN ($1, $2, $3, $4)`,
89
89
  [
90
- makeUUID('admin-business-usd'),
91
- makeUUID('supplier-us-vendor-llc'),
92
- makeUUID('expense-consulting'),
93
- makeUUID('usd-account-tax-category'),
90
+ makeUUID('business', 'admin-business-usd'),
91
+ makeUUID('business', 'supplier-us-vendor-llc'),
92
+ makeUUID('tax-category', 'expense-consulting'),
93
+ makeUUID('tax-category', 'usd-account-tax-category'),
94
94
  ],
95
95
  );
96
96
  } finally {
@@ -106,7 +106,7 @@ describe('Ledger Generation - Expense Scenario B (Foreign Currency)', () => {
106
106
 
107
107
  await insertFixture(insertClient, expenseScenarioB);
108
108
 
109
- const chargeId = makeUUID('charge-consulting-services');
109
+ const chargeId = makeUUID('charge', 'charge-consulting-services');
110
110
 
111
111
  // Verify inserts within the same transaction
112
112
  const chargeResult = await insertClient.query(
@@ -143,7 +143,7 @@ describe('Ledger Generation - Expense Scenario B (Foreign Currency)', () => {
143
143
  // Re-open a new client (outside prior transaction) for verification & generation
144
144
  const client = await db.getPool().connect();
145
145
  try {
146
- const chargeId = makeUUID('charge-consulting-services');
146
+ const chargeId = makeUUID('charge', 'charge-consulting-services');
147
147
  const chargeResult = await client.query(
148
148
  `SELECT * FROM ${qualifyTable('charges')} WHERE id = $1`,
149
149
  [chargeId],
@@ -200,8 +200,8 @@ describe('Ledger Generation - Expense Scenario B (Foreign Currency)', () => {
200
200
  assertForeignExpenseScenario(ledgerResult.rows as any, {
201
201
  chargeId: charge.id,
202
202
  ownerId: charge.owner_id, // Use actual charge owner id
203
- expenseEntity: makeUUID('expense-consulting'),
204
- bankEntity: makeUUID('usd-account-tax-category'),
203
+ expenseEntity: makeUUID('tax-category', 'expense-consulting'),
204
+ bankEntity: makeUUID('tax-category', 'usd-account-tax-category'),
205
205
  expectedCurrency: Currency.Usd,
206
206
  expectedForeignAmount: ledgerExpectation?.foreignAmount || 200.0,
207
207
  expectedRate: ledgerExpectation?.exchangeRate || 3.5,
@@ -222,7 +222,7 @@ describe('Ledger Generation - Expense Scenario B (Foreign Currency)', () => {
222
222
  it('should be idempotent on repeated foreign ledger generation (no duplicate records)', async () => {
223
223
  const client = await db.getPool().connect();
224
224
  try {
225
- const chargeId = makeUUID('charge-consulting-services');
225
+ const chargeId = makeUUID('charge', 'charge-consulting-services');
226
226
  // Ensure fixture inserted if absent
227
227
  const existingCharge = await client.query(
228
228
  `SELECT * FROM ${qualifyTable('charges')} WHERE id = $1`,
@@ -310,14 +310,14 @@ describe('Ledger Generation - Expense Scenario B (Foreign Currency)', () => {
310
310
  const accountMapping = expenseScenarioB.accountTaxCategories?.mappings[0];
311
311
  expect(accountMapping?.accountNumber).toBe('USD-ACCOUNT-001');
312
312
  expect(accountMapping?.currency).toBe(Currency.Usd);
313
- expect(accountMapping?.taxCategoryId).toBe(makeUUID('usd-account-tax-category'));
313
+ expect(accountMapping?.taxCategoryId).toBe(makeUUID('tax-category', 'usd-account-tax-category'));
314
314
 
315
315
  // Verify expectations are defined
316
316
  expect(expenseScenarioB.expectations).toBeDefined();
317
317
  expect(expenseScenarioB.expectations?.ledger).toHaveLength(1);
318
318
 
319
319
  const ledgerExpectation = expenseScenarioB.expectations?.ledger?.[0];
320
- expect(ledgerExpectation?.chargeId).toBe(makeUUID('charge-consulting-services'));
320
+ expect(ledgerExpectation?.chargeId).toBe(makeUUID('charge', 'charge-consulting-services'));
321
321
  expect(ledgerExpectation?.recordCount).toBe(2);
322
322
  expect(ledgerExpectation?.balanced).toBe(true);
323
323
  expect(ledgerExpectation?.totalDebitLocal).toBe(1400.0);
@@ -331,11 +331,11 @@ describe('Ledger Generation - Expense Scenario B (Foreign Currency)', () => {
331
331
 
332
332
  it('should create deterministic UUIDs for reproducible tests', () => {
333
333
  // Verify all IDs are deterministic and match expected values
334
- const adminBusinessId = makeUUID('admin-business-usd');
335
- const supplierId = makeUUID('supplier-us-vendor-llc');
336
- const chargeId = makeUUID('charge-consulting-services');
337
- const transactionId = makeUUID('transaction-consulting-payment');
338
- const documentId = makeUUID('document-consulting-invoice');
334
+ const adminBusinessId = makeUUID('business', 'admin-business-usd');
335
+ const supplierId = makeUUID('business', 'supplier-us-vendor-llc');
336
+ const chargeId = makeUUID('charge', 'charge-consulting-services');
337
+ const transactionId = makeUUID('transaction', 'transaction-consulting-payment');
338
+ const documentId = makeUUID('document', 'document-consulting-invoice');
339
339
 
340
340
  expect(adminBusinessId).toBe(expenseScenarioB.businesses?.businesses[0]?.id);
341
341
  expect(supplierId).toBe(expenseScenarioB.businesses?.businesses[1]?.id);
@@ -9,13 +9,19 @@ export function getTransactionsMeta(transactions: IGetTransactionsByIdsResult[])
9
9
  let transactionsMinDebitDate: Date | null = null;
10
10
  let transactionsMinEventDate: Date | null = null;
11
11
 
12
+ const hasFee = transactions.some(t => t.is_fee);
13
+ const onlyFee = transactions.every(t => t.is_fee);
14
+ const hasSomeFeeTransactions = hasFee && !onlyFee;
15
+
12
16
  transactions.map(t => {
13
- const amountAsNumber = Number(t.amount);
14
- const amount = Number.isNaN(amountAsNumber) ? null : amountAsNumber;
15
- if (amount != null) {
16
- transactionsAmount ??= 0;
17
- transactionsAmount += amount;
18
- currenciesSet.add(t.currency as Currency);
17
+ if ((hasSomeFeeTransactions && !t.is_fee) || !hasSomeFeeTransactions) {
18
+ const amountAsNumber = Number(t.amount);
19
+ const amount = Number.isNaN(amountAsNumber) ? null : amountAsNumber;
20
+ if (amount != null) {
21
+ transactionsAmount ??= 0;
22
+ transactionsAmount += amount;
23
+ currenciesSet.add(t.currency as Currency);
24
+ }
19
25
  }
20
26
  if (t.debit_timestamp) {
21
27
  transactionsMinDebitDate ??= t.debit_timestamp;
@@ -1,22 +0,0 @@
1
- /**
2
- * Generate a UUID for use in test fixtures
3
- *
4
- * @param seed - Optional seed string for deterministic UUID generation
5
- * @returns A valid UUID v4 string
6
- *
7
- * @remarks
8
- * - When seed is provided, generates a deterministic UUID based on the seed
9
- * - When seed is omitted, generates a random UUID
10
- * - Deterministic mode uses a simple hash-based approach for test reproducibility
11
- *
12
- * @example
13
- * ```typescript
14
- * // Random UUID
15
- * const id1 = makeUUID(); // e.g., '123e4567-e89b-12d3-a456-426614174000'
16
- *
17
- * // Deterministic UUID (same seed always produces same UUID)
18
- * const id2 = makeUUID('admin-business'); // Always same UUID
19
- * const id3 = makeUUID('admin-business'); // Same as id2
20
- * ```
21
- */
22
- export declare function makeUUID(seed?: string): string;
@@ -1,46 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- /**
3
- * Generate a UUID for use in test fixtures
4
- *
5
- * @param seed - Optional seed string for deterministic UUID generation
6
- * @returns A valid UUID v4 string
7
- *
8
- * @remarks
9
- * - When seed is provided, generates a deterministic UUID based on the seed
10
- * - When seed is omitted, generates a random UUID
11
- * - Deterministic mode uses a simple hash-based approach for test reproducibility
12
- *
13
- * @example
14
- * ```typescript
15
- * // Random UUID
16
- * const id1 = makeUUID(); // e.g., '123e4567-e89b-12d3-a456-426614174000'
17
- *
18
- * // Deterministic UUID (same seed always produces same UUID)
19
- * const id2 = makeUUID('admin-business'); // Always same UUID
20
- * const id3 = makeUUID('admin-business'); // Same as id2
21
- * ```
22
- */
23
- export function makeUUID(seed) {
24
- // Check for undefined or null (not provided), but treat empty string as valid seed
25
- if (seed === undefined || seed === null) {
26
- return randomUUID();
27
- }
28
- // Simple deterministic UUID generation from seed
29
- // Use a basic hash to convert seed to hex values
30
- let hash = 0;
31
- for (let i = 0; i < seed.length; i++) {
32
- hash = (hash << 5) - hash + seed.charCodeAt(i);
33
- hash = hash & hash; // Convert to 32-bit integer
34
- }
35
- // Generate deterministic hex values
36
- const hex = (Math.abs(hash) * 123456789).toString(16).padStart(32, '0').slice(0, 32);
37
- // Format as UUID v4 (with version and variant bits set correctly)
38
- return [
39
- hex.slice(0, 8),
40
- hex.slice(8, 12),
41
- `4${hex.slice(13, 16)}`, // Version 4
42
- `${((parseInt(hex.slice(16, 18), 16) & 0x3f) | 0x80).toString(16)}${hex.slice(18, 20)}`, // Variant bits
43
- hex.slice(20, 32),
44
- ].join('-');
45
- }
46
- //# sourceMappingURL=ids.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ids.js","sourceRoot":"","sources":["../../../../../src/__tests__/factories/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAa;IACpC,mFAAmF;IACnF,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QACxC,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IAED,iDAAiD;IACjD,iDAAiD;IACjD,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC/C,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,4BAA4B;IAClD,CAAC;IAED,oCAAoC;IACpC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAErF,kEAAkE;IAClE,OAAO;QACL,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChB,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,YAAY;QACrC,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,eAAe;QACxG,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;KAClB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC"}
@@ -1,71 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { UUID_REGEX } from '../../shared/constants.js';
3
- import { makeUUID } from './ids.js';
4
- describe('Factory Helpers: IDs', () => {
5
- describe('makeUUID', () => {
6
- it('should generate a valid UUID format', () => {
7
- const id = makeUUID();
8
- expect(id).toMatch(UUID_REGEX);
9
- });
10
- it('should generate different UUIDs without seed', () => {
11
- const id1 = makeUUID();
12
- const id2 = makeUUID();
13
- expect(id1).not.toBe(id2);
14
- });
15
- it('should generate deterministic UUID with seed', () => {
16
- const seed = 'admin-business';
17
- const id1 = makeUUID(seed);
18
- const id2 = makeUUID(seed);
19
- expect(id1).toBe(id2);
20
- });
21
- it('should generate different UUIDs for different seeds', () => {
22
- const id1 = makeUUID('seed-one');
23
- const id2 = makeUUID('seed-two');
24
- expect(id1).not.toBe(id2);
25
- });
26
- it('should generate valid UUID v4 format with seed', () => {
27
- const id = makeUUID('test-seed');
28
- expect(id).toMatch(UUID_REGEX);
29
- // Version bits should be 4
30
- expect(id.charAt(14)).toBe('4');
31
- });
32
- it('should handle empty string seed', () => {
33
- const id1 = makeUUID('');
34
- const id2 = makeUUID('');
35
- // Empty string seed should produce same deterministic UUID
36
- expect(id1).toBe(id2);
37
- expect(id1).toMatch(UUID_REGEX);
38
- // Empty string produces specific deterministic UUID (hash of '' = 0)
39
- expect(id1).toBe('00000000-0000-4000-8000-000000000000');
40
- });
41
- it('should handle complex seed strings', () => {
42
- const seeds = [
43
- 'admin-business-123',
44
- 'supplier_with_underscores',
45
- 'UPPERCASE-SEED',
46
- 'seed with spaces',
47
- 'seed-with-special-chars-!@#$%',
48
- ];
49
- seeds.forEach(seed => {
50
- const id = makeUUID(seed);
51
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
52
- expect(id).toMatch(uuidRegex);
53
- });
54
- });
55
- it('should be consistent across multiple calls with same seed', () => {
56
- const seed = 'consistent-seed';
57
- const ids = Array.from({ length: 10 }, () => makeUUID(seed));
58
- const uniqueIds = new Set(ids);
59
- expect(uniqueIds.size).toBe(1);
60
- });
61
- it('should generate different IDs for similar but different seeds', () => {
62
- const id1 = makeUUID('test');
63
- const id2 = makeUUID('test1');
64
- const id3 = makeUUID('test-');
65
- expect(id1).not.toBe(id2);
66
- expect(id1).not.toBe(id3);
67
- expect(id2).not.toBe(id3);
68
- });
69
- });
70
- });
71
- //# sourceMappingURL=ids.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ids.test.js","sourceRoot":"","sources":["../../../../../src/__tests__/factories/ids.test.ts"],"names":[],"mappings":"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"}
@@ -1,80 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { UUID_REGEX } from '../../shared/constants.js';
3
- import { makeUUID } from './ids.js';
4
-
5
- describe('Factory Helpers: IDs', () => {
6
- describe('makeUUID', () => {
7
- it('should generate a valid UUID format', () => {
8
- const id = makeUUID();
9
- expect(id).toMatch(UUID_REGEX);
10
- });
11
-
12
- it('should generate different UUIDs without seed', () => {
13
- const id1 = makeUUID();
14
- const id2 = makeUUID();
15
- expect(id1).not.toBe(id2);
16
- });
17
-
18
- it('should generate deterministic UUID with seed', () => {
19
- const seed = 'admin-business';
20
- const id1 = makeUUID(seed);
21
- const id2 = makeUUID(seed);
22
- expect(id1).toBe(id2);
23
- });
24
-
25
- it('should generate different UUIDs for different seeds', () => {
26
- const id1 = makeUUID('seed-one');
27
- const id2 = makeUUID('seed-two');
28
- expect(id1).not.toBe(id2);
29
- });
30
-
31
- it('should generate valid UUID v4 format with seed', () => {
32
- const id = makeUUID('test-seed');
33
- expect(id).toMatch(UUID_REGEX);
34
- // Version bits should be 4
35
- expect(id.charAt(14)).toBe('4');
36
- });
37
-
38
- it('should handle empty string seed', () => {
39
- const id1 = makeUUID('');
40
- const id2 = makeUUID('');
41
- // Empty string seed should produce same deterministic UUID
42
- expect(id1).toBe(id2);
43
- expect(id1).toMatch(UUID_REGEX);
44
- // Empty string produces specific deterministic UUID (hash of '' = 0)
45
- expect(id1).toBe('00000000-0000-4000-8000-000000000000');
46
- });
47
-
48
- it('should handle complex seed strings', () => {
49
- const seeds = [
50
- 'admin-business-123',
51
- 'supplier_with_underscores',
52
- 'UPPERCASE-SEED',
53
- 'seed with spaces',
54
- 'seed-with-special-chars-!@#$%',
55
- ];
56
-
57
- seeds.forEach(seed => {
58
- const id = makeUUID(seed);
59
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
60
- expect(id).toMatch(uuidRegex);
61
- });
62
- });
63
-
64
- it('should be consistent across multiple calls with same seed', () => {
65
- const seed = 'consistent-seed';
66
- const ids = Array.from({ length: 10 }, () => makeUUID(seed));
67
- const uniqueIds = new Set(ids);
68
- expect(uniqueIds.size).toBe(1);
69
- });
70
-
71
- it('should generate different IDs for similar but different seeds', () => {
72
- const id1 = makeUUID('test');
73
- const id2 = makeUUID('test1');
74
- const id3 = makeUUID('test-');
75
- expect(id1).not.toBe(id2);
76
- expect(id1).not.toBe(id3);
77
- expect(id2).not.toBe(id3);
78
- });
79
- });
80
- });
@@ -1,49 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
-
3
- /**
4
- * Generate a UUID for use in test fixtures
5
- *
6
- * @param seed - Optional seed string for deterministic UUID generation
7
- * @returns A valid UUID v4 string
8
- *
9
- * @remarks
10
- * - When seed is provided, generates a deterministic UUID based on the seed
11
- * - When seed is omitted, generates a random UUID
12
- * - Deterministic mode uses a simple hash-based approach for test reproducibility
13
- *
14
- * @example
15
- * ```typescript
16
- * // Random UUID
17
- * const id1 = makeUUID(); // e.g., '123e4567-e89b-12d3-a456-426614174000'
18
- *
19
- * // Deterministic UUID (same seed always produces same UUID)
20
- * const id2 = makeUUID('admin-business'); // Always same UUID
21
- * const id3 = makeUUID('admin-business'); // Same as id2
22
- * ```
23
- */
24
- export function makeUUID(seed?: string): string {
25
- // Check for undefined or null (not provided), but treat empty string as valid seed
26
- if (seed === undefined || seed === null) {
27
- return randomUUID();
28
- }
29
-
30
- // Simple deterministic UUID generation from seed
31
- // Use a basic hash to convert seed to hex values
32
- let hash = 0;
33
- for (let i = 0; i < seed.length; i++) {
34
- hash = (hash << 5) - hash + seed.charCodeAt(i);
35
- hash = hash & hash; // Convert to 32-bit integer
36
- }
37
-
38
- // Generate deterministic hex values
39
- const hex = (Math.abs(hash) * 123456789).toString(16).padStart(32, '0').slice(0, 32);
40
-
41
- // Format as UUID v4 (with version and variant bits set correctly)
42
- return [
43
- hex.slice(0, 8),
44
- hex.slice(8, 12),
45
- `4${hex.slice(13, 16)}`, // Version 4
46
- `${((parseInt(hex.slice(16, 18), 16) & 0x3f) | 0x80).toString(16)}${hex.slice(18, 20)}`, // Variant bits
47
- hex.slice(20, 32),
48
- ].join('-');
49
- }