@accounter/server 0.0.9-alpha-20251210155614-e6e65aaecafef9e8fedd0b933f613ffcf478cecf → 0.0.9-alpha-20251210170728-fe2c044a6279c36a9ba58b13bae56b181e8f85f5
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.
- package/CHANGELOG.md +27 -5
- package/dist/green-invoice-graphql/src/mesh-artifacts/index.d.ts +1 -1
- package/dist/server/src/__tests__/factories/business.d.ts +2 -2
- package/dist/server/src/__tests__/factories/business.js +5 -4
- package/dist/server/src/__tests__/factories/business.js.map +1 -1
- package/dist/server/src/__tests__/factories/business.test.js +2 -2
- package/dist/server/src/__tests__/factories/business.test.js.map +1 -1
- package/dist/server/src/__tests__/factories/charge.d.ts +9 -9
- package/dist/server/src/__tests__/factories/charge.js +15 -15
- package/dist/server/src/__tests__/factories/charge.js.map +1 -1
- package/dist/server/src/__tests__/factories/charge.test.js +14 -14
- package/dist/server/src/__tests__/factories/charge.test.js.map +1 -1
- package/dist/server/src/__tests__/factories/document.d.ts +9 -9
- package/dist/server/src/__tests__/factories/document.js +11 -11
- package/dist/server/src/__tests__/factories/document.js.map +1 -1
- package/dist/server/src/__tests__/factories/document.test.js +38 -38
- package/dist/server/src/__tests__/factories/document.test.js.map +1 -1
- package/dist/server/src/__tests__/factories/financial-account.js +2 -2
- package/dist/server/src/__tests__/factories/financial-account.js.map +1 -1
- package/dist/server/src/__tests__/factories/financial-account.test.js +7 -7
- package/dist/server/src/__tests__/factories/financial-account.test.js.map +1 -1
- package/dist/server/src/__tests__/factories/index.d.ts +2 -2
- package/dist/server/src/__tests__/factories/index.js +2 -2
- package/dist/server/src/__tests__/factories/index.js.map +1 -1
- package/dist/server/src/__tests__/factories/index.test.js +12 -12
- package/dist/server/src/__tests__/factories/index.test.js.map +1 -1
- package/dist/server/src/__tests__/factories/tax-category.d.ts +3 -3
- package/dist/server/src/__tests__/factories/tax-category.js +6 -5
- package/dist/server/src/__tests__/factories/tax-category.js.map +1 -1
- package/dist/server/src/__tests__/factories/tax-category.test.js +4 -4
- package/dist/server/src/__tests__/factories/tax-category.test.js.map +1 -1
- package/dist/server/src/__tests__/factories/transaction.d.ts +7 -7
- package/dist/server/src/__tests__/factories/transaction.js +11 -11
- package/dist/server/src/__tests__/factories/transaction.js.map +1 -1
- package/dist/server/src/__tests__/factories/transaction.test.js +27 -27
- package/dist/server/src/__tests__/factories/transaction.test.js.map +1 -1
- package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-a.js +20 -20
- package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-a.js.map +1 -1
- package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-b.js +20 -20
- package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-b.js.map +1 -1
- package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-b.test.js +8 -8
- package/dist/server/src/__tests__/fixtures/expenses/expense-scenario-b.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/db-setup.d.ts +0 -1
- package/dist/server/src/__tests__/helpers/db-setup.js +0 -2
- package/dist/server/src/__tests__/helpers/db-setup.js.map +1 -1
- package/dist/server/src/__tests__/helpers/fixture-loader.js +2 -2
- package/dist/server/src/__tests__/helpers/fixture-loader.js.map +1 -1
- package/dist/server/src/__tests__/helpers/fixture-loader.test.js +32 -29
- package/dist/server/src/__tests__/helpers/fixture-loader.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/fixture-validation.test.js +50 -50
- package/dist/server/src/__tests__/helpers/fixture-validation.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js +23 -31
- package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js +8 -8
- package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js +41 -50
- package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js +23 -31
- package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js.map +1 -1
- package/dist/server/src/__tests__/seed-admin-context.integration.test.js +128 -131
- package/dist/server/src/__tests__/seed-admin-context.integration.test.js.map +1 -1
- package/dist/server/src/demo-fixtures/__tests__/deterministic-uuid.test.js +58 -0
- package/dist/server/src/demo-fixtures/__tests__/deterministic-uuid.test.js.map +1 -0
- package/dist/server/src/demo-fixtures/helpers/deterministic-uuid.d.ts +50 -0
- package/dist/server/src/demo-fixtures/helpers/deterministic-uuid.js +66 -0
- package/dist/server/src/demo-fixtures/helpers/deterministic-uuid.js.map +1 -0
- package/dist/server/src/modules/admin-context/{heplers → helpers}/admin-context.helper.d.ts +1 -1
- package/dist/server/src/modules/admin-context/{heplers → helpers}/admin-context.helper.js +2 -2
- package/dist/server/src/modules/admin-context/{heplers → helpers}/admin-context.helper.js.map +1 -1
- package/dist/server/src/modules/admin-context/resolvers/admin-context.resolvers.js +1 -1
- package/dist/server/src/modules/business-trips/providers/business-trips.provider.d.ts +1 -1
- package/dist/server/src/modules/business-trips/providers/business-trips.provider.js +1 -1
- package/dist/server/src/modules/business-trips/providers/business-trips.provider.js.map +1 -1
- package/dist/server/src/modules/charges/helpers/common.helper.js +3 -3
- package/dist/server/src/modules/charges/helpers/common.helper.js.map +1 -1
- package/dist/server/src/modules/charges/helpers/{merge-charges.hepler.js → merge-charges.helper.js} +6 -6
- package/dist/server/src/modules/charges/helpers/{merge-charges.hepler.js.map → merge-charges.helper.js.map} +1 -1
- package/dist/server/src/modules/charges/resolvers/charges.resolver.js +1 -1
- package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.js +2 -2
- package/dist/server/src/modules/charges-matcher/__tests__/auto-match-integration.test.js.map +1 -1
- package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.js +1 -1
- package/dist/server/src/modules/charges-matcher/providers/charges-matcher.provider.js.map +1 -1
- package/dist/server/src/modules/corn-jobs/resolvers/corn-jobs.resolver.js +1 -1
- package/dist/server/src/modules/corn-jobs/resolvers/corn-jobs.resolver.js.map +1 -1
- package/dist/server/src/modules/ledger/__tests__/helpers/ledger-assertions.d.ts +0 -2
- package/dist/server/src/modules/ledger/__tests__/helpers/ledger-assertions.js +0 -4
- package/dist/server/src/modules/ledger/__tests__/helpers/ledger-assertions.js.map +1 -1
- package/dist/server/src/modules/ledger/__tests__/ledger-scenario-a.integration.test.js +20 -20
- package/dist/server/src/modules/ledger/__tests__/ledger-scenario-a.integration.test.js.map +1 -1
- package/dist/server/src/modules/ledger/__tests__/ledger-scenario-b.integration.test.js +21 -21
- package/dist/server/src/modules/ledger/__tests__/ledger-scenario-b.integration.test.js.map +1 -1
- package/dist/server/src/modules/transactions/helpers/common.helper.js +11 -6
- package/dist/server/src/modules/transactions/helpers/common.helper.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/factories/business.test.ts +3 -3
- package/src/__tests__/factories/business.ts +5 -4
- package/src/__tests__/factories/charge.test.ts +14 -14
- package/src/__tests__/factories/charge.ts +16 -16
- package/src/__tests__/factories/document.test.ts +38 -38
- package/src/__tests__/factories/document.ts +11 -11
- package/src/__tests__/factories/financial-account.test.ts +7 -7
- package/src/__tests__/factories/financial-account.ts +3 -3
- package/src/__tests__/factories/index.test.ts +12 -12
- package/src/__tests__/factories/index.ts +2 -2
- package/src/__tests__/factories/tax-category.test.ts +4 -4
- package/src/__tests__/factories/tax-category.ts +7 -6
- package/src/__tests__/factories/transaction.test.ts +27 -27
- package/src/__tests__/factories/transaction.ts +11 -11
- package/src/__tests__/fixtures/expenses/expense-scenario-a.ts +20 -20
- package/src/__tests__/fixtures/expenses/expense-scenario-b.test.ts +8 -8
- package/src/__tests__/fixtures/expenses/expense-scenario-b.ts +20 -20
- package/src/__tests__/helpers/db-setup.ts +0 -3
- package/src/__tests__/helpers/fixture-loader.test.ts +31 -29
- package/src/__tests__/helpers/fixture-loader.ts +2 -2
- package/src/__tests__/helpers/fixture-validation.test.ts +50 -50
- package/src/__tests__/helpers/seed-helpers.business.test.ts +145 -147
- package/src/__tests__/helpers/seed-helpers.concurrent.test.ts +10 -10
- package/src/__tests__/helpers/seed-helpers.financial-entity.test.ts +218 -231
- package/src/__tests__/helpers/seed-helpers.tax-category.test.ts +162 -164
- package/src/__tests__/seed-admin-context.integration.test.ts +199 -208
- package/src/demo-fixtures/__tests__/deterministic-uuid.test.ts +75 -0
- package/src/demo-fixtures/helpers/deterministic-uuid.ts +68 -0
- package/src/modules/admin-context/{heplers → helpers}/admin-context.helper.ts +3 -3
- package/src/modules/admin-context/resolvers/admin-context.resolvers.ts +1 -1
- package/src/modules/business-trips/providers/business-trips.provider.ts +1 -1
- package/src/modules/charges/helpers/common.helper.ts +3 -3
- package/src/modules/charges/helpers/{merge-charges.hepler.ts → merge-charges.helper.ts} +5 -5
- package/src/modules/charges/resolvers/charges.resolver.ts +1 -1
- package/src/modules/charges-matcher/__tests__/auto-match-integration.test.ts +2 -2
- package/src/modules/charges-matcher/providers/charges-matcher.provider.ts +1 -1
- package/src/modules/corn-jobs/resolvers/corn-jobs.resolver.ts +1 -1
- package/src/modules/ledger/__tests__/helpers/ledger-assertions.ts +0 -5
- package/src/modules/ledger/__tests__/ledger-scenario-a.integration.test.ts +20 -20
- package/src/modules/ledger/__tests__/ledger-scenario-b.integration.test.ts +21 -21
- package/src/modules/transactions/helpers/common.helper.ts +12 -6
- package/dist/server/src/__tests__/factories/ids.d.ts +0 -22
- package/dist/server/src/__tests__/factories/ids.js +0 -46
- package/dist/server/src/__tests__/factories/ids.js.map +0 -1
- package/dist/server/src/__tests__/factories/ids.test.js +0 -71
- package/dist/server/src/__tests__/factories/ids.test.js.map +0 -1
- package/src/__tests__/factories/ids.test.ts +0 -80
- package/src/__tests__/factories/ids.ts +0 -49
- /package/dist/server/src/{__tests__/factories/ids.test.d.ts → demo-fixtures/__tests__/deterministic-uuid.test.d.ts} +0 -0
- /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.
|
|
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
|
-
'
|
|
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 '../../../
|
|
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 '../../../
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
}
|
|
File without changes
|
|
File without changes
|