@accounter/server 0.0.9-alpha-20251231123714-6cdd9de71b4672d74ece5d34c438d162987b2c93 → 0.0.9-alpha-20251231163357-33d4c33fec5e21dad2e04d1f293f6248d2550588

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 (124) hide show
  1. package/CHANGELOG.md +27 -5
  2. package/README.md +66 -3
  3. package/dist/server/scripts/seed-admin-context.js +20 -25
  4. package/dist/server/scripts/seed-admin-context.js.map +1 -1
  5. package/dist/server/src/__tests__/db-bootstrap.test.js +7 -2
  6. package/dist/server/src/__tests__/db-bootstrap.test.js.map +1 -1
  7. package/dist/server/src/__tests__/factories/business.d.ts +1 -1
  8. package/dist/server/src/__tests__/factories/financial-account.d.ts +1 -1
  9. package/dist/server/src/__tests__/factories/index.test.js +1 -0
  10. package/dist/server/src/__tests__/factories/index.test.js.map +1 -1
  11. package/dist/server/src/__tests__/factories/tax-category.d.ts +1 -1
  12. package/dist/server/src/__tests__/factories/tax-category.js +1 -1
  13. package/dist/server/src/__tests__/factories/tax-category.js.map +1 -1
  14. package/dist/server/src/__tests__/factories/tax-category.test.js +8 -6
  15. package/dist/server/src/__tests__/factories/tax-category.test.js.map +1 -1
  16. package/dist/server/src/__tests__/helpers/fixture-loader.d.ts +1 -1
  17. package/dist/server/src/__tests__/helpers/fixture-loader.js +25 -52
  18. package/dist/server/src/__tests__/helpers/fixture-loader.js.map +1 -1
  19. package/dist/server/src/__tests__/helpers/migration-verification.d.ts +1 -1
  20. package/dist/server/src/__tests__/helpers/migration-verification.js.map +1 -1
  21. package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js +4 -4
  22. package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js.map +1 -1
  23. package/dist/server/src/__tests__/helpers/seed-helpers.d.ts +9 -9
  24. package/dist/server/src/__tests__/helpers/seed-helpers.js +57 -54
  25. package/dist/server/src/__tests__/helpers/seed-helpers.js.map +1 -1
  26. package/dist/server/src/__tests__/seed-admin-context.integration.test.js +2 -1
  27. package/dist/server/src/__tests__/seed-admin-context.integration.test.js.map +1 -1
  28. package/dist/server/src/demo-fixtures/__tests__/deterministic-uuid.test.js +3 -2
  29. package/dist/server/src/demo-fixtures/__tests__/deterministic-uuid.test.js.map +1 -1
  30. package/dist/server/src/demo-fixtures/__tests__/seed-and-validate.test.d.ts +1 -0
  31. package/dist/server/src/demo-fixtures/__tests__/seed-and-validate.test.js +69 -0
  32. package/dist/server/src/demo-fixtures/__tests__/seed-and-validate.test.js.map +1 -0
  33. package/dist/server/src/demo-fixtures/__tests__/use-case-registry.test.d.ts +1 -0
  34. package/dist/server/src/demo-fixtures/__tests__/use-case-registry.test.js +26 -0
  35. package/dist/server/src/demo-fixtures/__tests__/use-case-registry.test.js.map +1 -0
  36. package/dist/server/src/demo-fixtures/helpers/admin-context.d.ts +10 -0
  37. package/dist/server/src/demo-fixtures/helpers/admin-context.js +40 -0
  38. package/dist/server/src/demo-fixtures/helpers/admin-context.js.map +1 -0
  39. package/dist/server/src/demo-fixtures/helpers/placeholder.d.ts +45 -0
  40. package/dist/server/src/demo-fixtures/helpers/placeholder.js +50 -0
  41. package/dist/server/src/demo-fixtures/helpers/placeholder.js.map +1 -0
  42. package/dist/server/src/demo-fixtures/helpers/seed-exchange-rates.d.ts +21 -0
  43. package/dist/server/src/demo-fixtures/helpers/seed-exchange-rates.js +26 -0
  44. package/dist/server/src/demo-fixtures/helpers/seed-exchange-rates.js.map +1 -0
  45. package/dist/server/src/demo-fixtures/helpers/seed-vat.d.ts +20 -0
  46. package/dist/server/src/demo-fixtures/helpers/seed-vat.js +30 -0
  47. package/dist/server/src/demo-fixtures/helpers/seed-vat.js.map +1 -0
  48. package/dist/server/src/demo-fixtures/use-cases/equity/shareholder-dividend.d.ts +9 -0
  49. package/dist/server/src/demo-fixtures/use-cases/equity/shareholder-dividend.js +86 -0
  50. package/dist/server/src/demo-fixtures/use-cases/equity/shareholder-dividend.js.map +1 -0
  51. package/dist/server/src/demo-fixtures/use-cases/expenses/monthly-expense-foreign-currency.d.ts +12 -0
  52. package/dist/server/src/demo-fixtures/use-cases/expenses/monthly-expense-foreign-currency.js +375 -0
  53. package/dist/server/src/demo-fixtures/use-cases/expenses/monthly-expense-foreign-currency.js.map +1 -0
  54. package/dist/server/src/demo-fixtures/use-cases/income/client-payment-with-refund.d.ts +10 -0
  55. package/dist/server/src/demo-fixtures/use-cases/income/client-payment-with-refund.js +113 -0
  56. package/dist/server/src/demo-fixtures/use-cases/income/client-payment-with-refund.js.map +1 -0
  57. package/dist/server/src/demo-fixtures/use-cases/index.d.ts +41 -0
  58. package/dist/server/src/demo-fixtures/use-cases/index.js +50 -0
  59. package/dist/server/src/demo-fixtures/use-cases/index.js.map +1 -0
  60. package/dist/server/src/demo-fixtures/validate-demo-data.d.ts +1 -0
  61. package/dist/server/src/demo-fixtures/validate-demo-data.js +117 -0
  62. package/dist/server/src/demo-fixtures/validate-demo-data.js.map +1 -0
  63. package/dist/server/src/demo-fixtures/validators/ledger-validators.d.ts +349 -0
  64. package/dist/server/src/demo-fixtures/validators/ledger-validators.js +602 -0
  65. package/dist/server/src/demo-fixtures/validators/ledger-validators.js.map +1 -0
  66. package/dist/server/src/demo-fixtures/validators/ledger-validators.test.d.ts +1 -0
  67. package/dist/server/src/demo-fixtures/validators/ledger-validators.test.js +247 -0
  68. package/dist/server/src/demo-fixtures/validators/ledger-validators.test.js.map +1 -0
  69. package/dist/server/src/demo-fixtures/validators/types.d.ts +69 -0
  70. package/dist/server/src/demo-fixtures/validators/types.js +8 -0
  71. package/dist/server/src/demo-fixtures/validators/types.js.map +1 -0
  72. package/dist/server/src/fixtures/fixture-spec.d.ts +146 -0
  73. package/dist/server/src/fixtures/fixture-spec.js +2 -0
  74. package/dist/server/src/fixtures/fixture-spec.js.map +1 -0
  75. package/dist/server/src/modules/charges-matcher/__tests__/single-match-integration.test.js +4 -0
  76. package/dist/server/src/modules/charges-matcher/__tests__/single-match-integration.test.js.map +1 -1
  77. package/dist/server/src/modules/deel/resolvers/deel.resolvers.js +0 -3
  78. package/dist/server/src/modules/deel/resolvers/deel.resolvers.js.map +1 -1
  79. package/dist/server/src/modules/ledger/__tests__/ledger-scenario-a.integration.test.js +4 -3
  80. package/dist/server/src/modules/ledger/__tests__/ledger-scenario-a.integration.test.js.map +1 -1
  81. package/dist/server/src/modules/ledger/__tests__/ledger-scenario-b.integration.test.js +5 -3
  82. package/dist/server/src/modules/ledger/__tests__/ledger-scenario-b.integration.test.js.map +1 -1
  83. package/dist/server/src/shared/constants.d.ts +1 -0
  84. package/dist/server/src/shared/constants.js +1 -0
  85. package/dist/server/src/shared/constants.js.map +1 -1
  86. package/dist/server/src/shared/helpers/misc.js +2 -2
  87. package/dist/server/src/shared/helpers/misc.js.map +1 -1
  88. package/docs/demo-staging-guide.md +611 -0
  89. package/package.json +5 -2
  90. package/scripts/seed-admin-context.ts +22 -33
  91. package/src/__tests__/db-bootstrap.test.ts +9 -2
  92. package/src/__tests__/factories/business.ts +1 -1
  93. package/src/__tests__/factories/financial-account.ts +1 -1
  94. package/src/__tests__/factories/index.test.ts +1 -0
  95. package/src/__tests__/factories/tax-category.test.ts +8 -6
  96. package/src/__tests__/factories/tax-category.ts +2 -2
  97. package/src/__tests__/helpers/fixture-loader.ts +26 -61
  98. package/src/__tests__/helpers/migration-verification.ts +2 -2
  99. package/src/__tests__/helpers/seed-helpers.business.test.ts +4 -4
  100. package/src/__tests__/helpers/seed-helpers.ts +66 -75
  101. package/src/__tests__/seed-admin-context.integration.test.ts +2 -1
  102. package/src/demo-fixtures/__tests__/deterministic-uuid.test.ts +3 -2
  103. package/src/demo-fixtures/__tests__/seed-and-validate.test.ts +96 -0
  104. package/src/demo-fixtures/__tests__/use-case-registry.test.ts +27 -0
  105. package/src/demo-fixtures/helpers/admin-context.ts +59 -0
  106. package/src/demo-fixtures/helpers/placeholder.ts +50 -0
  107. package/src/demo-fixtures/helpers/seed-exchange-rates.ts +29 -0
  108. package/src/demo-fixtures/helpers/seed-vat.ts +35 -0
  109. package/src/demo-fixtures/use-cases/equity/shareholder-dividend.ts +88 -0
  110. package/src/demo-fixtures/use-cases/expenses/monthly-expense-foreign-currency.ts +377 -0
  111. package/src/demo-fixtures/use-cases/income/client-payment-with-refund.ts +115 -0
  112. package/src/demo-fixtures/use-cases/index.ts +52 -0
  113. package/src/demo-fixtures/validate-demo-data.ts +153 -0
  114. package/src/demo-fixtures/validators/README.md +190 -0
  115. package/src/demo-fixtures/validators/ledger-validators.test.ts +298 -0
  116. package/src/demo-fixtures/validators/ledger-validators.ts +711 -0
  117. package/src/demo-fixtures/validators/types.ts +83 -0
  118. package/src/fixtures/fixture-spec.ts +158 -0
  119. package/src/modules/charges-matcher/__tests__/single-match-integration.test.ts +6 -0
  120. package/src/modules/deel/resolvers/deel.resolvers.ts +0 -3
  121. package/src/modules/ledger/__tests__/ledger-scenario-a.integration.test.ts +4 -3
  122. package/src/modules/ledger/__tests__/ledger-scenario-b.integration.test.ts +6 -3
  123. package/src/shared/constants.ts +2 -0
  124. package/src/shared/helpers/misc.ts +2 -3
@@ -0,0 +1,377 @@
1
+ import type { UseCaseSpec } from '../../../fixtures/fixture-spec.js';
2
+ import { CountryCode, Currency } from '../../../shared/enums.js';
3
+ import { makeUUID } from '../../helpers/deterministic-uuid.js';
4
+
5
+ /**
6
+ * Monthly Expense Use-Case: Foreign Currency Transaction
7
+ *
8
+ * Demonstrates a US-based supplier invoice paid via bank transfer with
9
+ * exchange rate conversion from USD to ILS. This use-case validates:
10
+ * - Foreign currency transaction handling
11
+ * - Exchange rate application
12
+ * - Cross-border payment processing
13
+ * - Ledger generation with currency conversion
14
+ */
15
+ export const monthlyExpenseForeignCurrency: UseCaseSpec = {
16
+ id: 'monthly-expense-foreign-currency',
17
+ name: 'Monthly Expense (Foreign Currency)',
18
+ description:
19
+ 'US-based supplier invoice paid via bank transfer with exchange rate conversion from USD to ILS. Validates foreign currency handling and ledger generation.',
20
+ category: 'expenses',
21
+ fixtures: {
22
+ businesses: [
23
+ {
24
+ id: makeUUID('business', 'us-supplier-acme-llc'),
25
+ name: 'Acme Consulting LLC',
26
+ country: CountryCode['United States of America (the)'],
27
+ canSettleWithReceipt: false,
28
+ },
29
+ ],
30
+ taxCategories: [
31
+ {
32
+ id: makeUUID('tax-category', 'consulting-expenses'),
33
+ name: 'Consulting Expenses',
34
+ },
35
+ ],
36
+ financialAccounts: [
37
+ {
38
+ id: makeUUID('financial-account', 'bank-usd-account'),
39
+ accountNumber: '123-456-7890',
40
+ type: 'BANK_ACCOUNT',
41
+ currency: Currency.Usd,
42
+ taxCategoryMappings: [
43
+ {
44
+ taxCategoryId: makeUUID('tax-category', 'consulting-expenses'),
45
+ currency: Currency.Usd,
46
+ },
47
+ ],
48
+ },
49
+ ],
50
+ charges: [
51
+ {
52
+ id: makeUUID('charge', 'consulting-invoice-2024-01'),
53
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
54
+ userDescription: 'January consulting services',
55
+ },
56
+ {
57
+ id: makeUUID('charge', 'consulting-invoice-2024-02'),
58
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
59
+ userDescription: 'February consulting services',
60
+ },
61
+ {
62
+ id: makeUUID('charge', 'consulting-invoice-2024-03'),
63
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
64
+ userDescription: 'March consulting services',
65
+ },
66
+ {
67
+ id: makeUUID('charge', 'consulting-invoice-2024-04'),
68
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
69
+ userDescription: 'April consulting services',
70
+ },
71
+ {
72
+ id: makeUUID('charge', 'consulting-invoice-2024-05'),
73
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
74
+ userDescription: 'May consulting services',
75
+ },
76
+ {
77
+ id: makeUUID('charge', 'consulting-invoice-2024-06'),
78
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
79
+ userDescription: 'June consulting services',
80
+ },
81
+ {
82
+ id: makeUUID('charge', 'consulting-invoice-2024-07'),
83
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
84
+ userDescription: 'July consulting services',
85
+ },
86
+ {
87
+ id: makeUUID('charge', 'consulting-invoice-2024-08'),
88
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
89
+ userDescription: 'August consulting services',
90
+ },
91
+ {
92
+ id: makeUUID('charge', 'consulting-invoice-2024-09'),
93
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
94
+ userDescription: 'September consulting services',
95
+ },
96
+ {
97
+ id: makeUUID('charge', 'consulting-invoice-2024-10'),
98
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
99
+ userDescription: 'October consulting services',
100
+ },
101
+ {
102
+ id: makeUUID('charge', 'consulting-invoice-2024-11'),
103
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
104
+ userDescription: 'November consulting services',
105
+ },
106
+ {
107
+ id: makeUUID('charge', 'consulting-invoice-2024-12'),
108
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
109
+ userDescription: 'December consulting services',
110
+ },
111
+ ],
112
+ transactions: [
113
+ {
114
+ id: makeUUID('transaction', 'consulting-payment-usd-01'),
115
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-01'),
116
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
117
+ amount: '-500.00',
118
+ currency: Currency.Usd,
119
+ eventDate: '2024-01-15',
120
+ debitDate: '2024-01-15',
121
+ accountNumber: '123-456-7890',
122
+ },
123
+ {
124
+ id: makeUUID('transaction', 'consulting-payment-usd-02'),
125
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-02'),
126
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
127
+ amount: '-500.00',
128
+ currency: Currency.Usd,
129
+ eventDate: '2024-02-15',
130
+ debitDate: '2024-02-15',
131
+ accountNumber: '123-456-7890',
132
+ },
133
+ {
134
+ id: makeUUID('transaction', 'consulting-payment-usd-03'),
135
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-03'),
136
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
137
+ amount: '-500.00',
138
+ currency: Currency.Usd,
139
+ eventDate: '2024-03-15',
140
+ debitDate: '2024-03-15',
141
+ accountNumber: '123-456-7890',
142
+ },
143
+ {
144
+ id: makeUUID('transaction', 'consulting-payment-usd-04'),
145
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-04'),
146
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
147
+ amount: '-500.00',
148
+ currency: Currency.Usd,
149
+ eventDate: '2024-04-15',
150
+ debitDate: '2024-04-15',
151
+ accountNumber: '123-456-7890',
152
+ },
153
+ {
154
+ id: makeUUID('transaction', 'consulting-payment-usd-05'),
155
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-05'),
156
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
157
+ amount: '-500.00',
158
+ currency: Currency.Usd,
159
+ eventDate: '2024-05-15',
160
+ debitDate: '2024-05-15',
161
+ accountNumber: '123-456-7890',
162
+ },
163
+ {
164
+ id: makeUUID('transaction', 'consulting-payment-usd-06'),
165
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-06'),
166
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
167
+ amount: '-500.00',
168
+ currency: Currency.Usd,
169
+ eventDate: '2024-06-15',
170
+ debitDate: '2024-06-15',
171
+ accountNumber: '123-456-7890',
172
+ },
173
+ {
174
+ id: makeUUID('transaction', 'consulting-payment-usd-07'),
175
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-07'),
176
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
177
+ amount: '-500.00',
178
+ currency: Currency.Usd,
179
+ eventDate: '2024-07-15',
180
+ debitDate: '2024-07-15',
181
+ accountNumber: '123-456-7890',
182
+ },
183
+ {
184
+ id: makeUUID('transaction', 'consulting-payment-usd-08'),
185
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-08'),
186
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
187
+ amount: '-500.00',
188
+ currency: Currency.Usd,
189
+ eventDate: '2024-08-15',
190
+ debitDate: '2024-08-15',
191
+ accountNumber: '123-456-7890',
192
+ },
193
+ {
194
+ id: makeUUID('transaction', 'consulting-payment-usd-09'),
195
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-09'),
196
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
197
+ amount: '-500.00',
198
+ currency: Currency.Usd,
199
+ eventDate: '2024-09-15',
200
+ debitDate: '2024-09-15',
201
+ accountNumber: '123-456-7890',
202
+ },
203
+ {
204
+ id: makeUUID('transaction', 'consulting-payment-usd-10'),
205
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-10'),
206
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
207
+ amount: '-500.00',
208
+ currency: Currency.Usd,
209
+ eventDate: '2024-10-15',
210
+ debitDate: '2024-10-15',
211
+ accountNumber: '123-456-7890',
212
+ },
213
+ {
214
+ id: makeUUID('transaction', 'consulting-payment-usd-11'),
215
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-11'),
216
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
217
+ amount: '-500.00',
218
+ currency: Currency.Usd,
219
+ eventDate: '2024-11-15',
220
+ debitDate: '2024-11-15',
221
+ accountNumber: '123-456-7890',
222
+ },
223
+ {
224
+ id: makeUUID('transaction', 'consulting-payment-usd-12'),
225
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-12'),
226
+ businessId: makeUUID('business', 'us-supplier-acme-llc'),
227
+ amount: '-500.00',
228
+ currency: Currency.Usd,
229
+ eventDate: '2024-12-15',
230
+ debitDate: '2024-12-15',
231
+ accountNumber: '123-456-7890',
232
+ },
233
+ ],
234
+ documents: [
235
+ {
236
+ id: makeUUID('document', 'consulting-invoice-inv-2024-01-15'),
237
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-01'),
238
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
239
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
240
+ serialNumber: 'INV-2024-01-15',
241
+ type: 'INVOICE',
242
+ date: '2024-01-01',
243
+ totalAmount: '500.00',
244
+ currencyCode: Currency.Usd,
245
+ },
246
+ {
247
+ id: makeUUID('document', 'consulting-invoice-inv-2024-02-15'),
248
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-02'),
249
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
250
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
251
+ serialNumber: 'INV-2024-02-15',
252
+ type: 'INVOICE',
253
+ date: '2024-02-01',
254
+ totalAmount: '500.00',
255
+ currencyCode: Currency.Usd,
256
+ },
257
+ {
258
+ id: makeUUID('document', 'consulting-invoice-inv-2024-03-15'),
259
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-03'),
260
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
261
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
262
+ serialNumber: 'INV-2024-03-15',
263
+ type: 'INVOICE',
264
+ date: '2024-03-01',
265
+ totalAmount: '500.00',
266
+ currencyCode: Currency.Usd,
267
+ },
268
+ {
269
+ id: makeUUID('document', 'consulting-invoice-inv-2024-04-15'),
270
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-04'),
271
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
272
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
273
+ serialNumber: 'INV-2024-04-15',
274
+ type: 'INVOICE',
275
+ date: '2024-04-01',
276
+ totalAmount: '500.00',
277
+ currencyCode: Currency.Usd,
278
+ },
279
+ {
280
+ id: makeUUID('document', 'consulting-invoice-inv-2024-05-15'),
281
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-05'),
282
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
283
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
284
+ serialNumber: 'INV-2024-05-15',
285
+ type: 'INVOICE',
286
+ date: '2024-05-01',
287
+ totalAmount: '500.00',
288
+ currencyCode: Currency.Usd,
289
+ },
290
+ {
291
+ id: makeUUID('document', 'consulting-invoice-inv-2024-06-15'),
292
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-06'),
293
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
294
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
295
+ serialNumber: 'INV-2024-06-15',
296
+ type: 'INVOICE',
297
+ date: '2024-06-01',
298
+ totalAmount: '500.00',
299
+ currencyCode: Currency.Usd,
300
+ },
301
+ {
302
+ id: makeUUID('document', 'consulting-invoice-inv-2024-07-15'),
303
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-07'),
304
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
305
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
306
+ serialNumber: 'INV-2024-07-15',
307
+ type: 'INVOICE',
308
+ date: '2024-07-01',
309
+ totalAmount: '500.00',
310
+ currencyCode: Currency.Usd,
311
+ },
312
+ {
313
+ id: makeUUID('document', 'consulting-invoice-inv-2024-08-15'),
314
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-08'),
315
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
316
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
317
+ serialNumber: 'INV-2024-08-15',
318
+ type: 'INVOICE',
319
+ date: '2024-08-01',
320
+ totalAmount: '500.00',
321
+ currencyCode: Currency.Usd,
322
+ },
323
+ {
324
+ id: makeUUID('document', 'consulting-invoice-inv-2024-09-15'),
325
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-09'),
326
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
327
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
328
+ serialNumber: 'INV-2024-09-15',
329
+ type: 'INVOICE',
330
+ date: '2024-09-01',
331
+ totalAmount: '500.00',
332
+ currencyCode: Currency.Usd,
333
+ },
334
+ {
335
+ id: makeUUID('document', 'consulting-invoice-inv-2024-10-15'),
336
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-10'),
337
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
338
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
339
+ serialNumber: 'INV-2024-10-15',
340
+ type: 'INVOICE',
341
+ date: '2024-10-01',
342
+ totalAmount: '500.00',
343
+ currencyCode: Currency.Usd,
344
+ },
345
+ {
346
+ id: makeUUID('document', 'consulting-invoice-inv-2024-11-15'),
347
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-11'),
348
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
349
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
350
+ serialNumber: 'INV-2024-11-15',
351
+ type: 'INVOICE',
352
+ date: '2024-11-01',
353
+ totalAmount: '500.00',
354
+ currencyCode: Currency.Usd,
355
+ },
356
+ {
357
+ id: makeUUID('document', 'consulting-invoice-inv-2024-12-15'),
358
+ chargeId: makeUUID('charge', 'consulting-invoice-2024-12'),
359
+ creditorId: makeUUID('business', 'us-supplier-acme-llc'),
360
+ debtorId: '{{ADMIN_BUSINESS_ID}}',
361
+ serialNumber: 'INV-2024-12-15',
362
+ type: 'INVOICE',
363
+ date: '2024-12-01',
364
+ totalAmount: '500.00',
365
+ currencyCode: Currency.Usd,
366
+ },
367
+ ],
368
+ },
369
+ metadata: {
370
+ author: 'demo-team',
371
+ createdAt: '2024-01-01',
372
+ updatedAt: '2024-01-01',
373
+ },
374
+ expectations: {
375
+ ledgerRecordCount: 24,
376
+ },
377
+ };
@@ -0,0 +1,115 @@
1
+ import type { UseCaseSpec } from '../../../fixtures/fixture-spec.js';
2
+ import { CountryCode, Currency } from '../../../shared/enums.js';
3
+ import { makeUUID } from '../../helpers/deterministic-uuid.js';
4
+
5
+ /**
6
+ * Client Payment with Refund Cycle
7
+ *
8
+ * Models an income scenario where a client pays an invoice
9
+ * and later receives a partial refund via a credit invoice.
10
+ * Sign convention follows demo rules: negative amount = income,
11
+ * positive amount = reversal/refund.
12
+ */
13
+ export const clientPaymentWithRefund: UseCaseSpec = {
14
+ id: 'client-payment-with-refund',
15
+ name: 'Client Payment with Refund',
16
+ description:
17
+ 'Client invoice paid (income) followed by a partial refund via credit invoice. Uses ILS bank account.',
18
+ category: 'income',
19
+ fixtures: {
20
+ businesses: [
21
+ {
22
+ id: makeUUID('business', 'acme-retail-client'),
23
+ name: 'Acme Retail Client',
24
+ country: CountryCode['Israel'],
25
+ canSettleWithReceipt: false,
26
+ },
27
+ ],
28
+ taxCategories: [
29
+ {
30
+ id: makeUUID('tax-category', 'service-income'),
31
+ name: 'Service Income',
32
+ },
33
+ ],
34
+ financialAccounts: [
35
+ {
36
+ id: makeUUID('financial-account', 'bank-ils-account-income'),
37
+ accountNumber: '22-333-4444',
38
+ type: 'BANK_ACCOUNT',
39
+ currency: Currency.Ils,
40
+ taxCategoryMappings: [
41
+ {
42
+ taxCategoryId: makeUUID('tax-category', 'service-income'),
43
+ currency: Currency.Ils,
44
+ },
45
+ ],
46
+ },
47
+ ],
48
+ charges: [
49
+ {
50
+ id: makeUUID('charge', 'client-invoice-2024-11'),
51
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
52
+ userDescription: 'Client invoice for November services',
53
+ },
54
+ {
55
+ id: makeUUID('charge', 'client-refund-credit-2024-11'),
56
+ ownerId: '{{ADMIN_BUSINESS_ID}}',
57
+ userDescription: 'Refund credit for November services',
58
+ },
59
+ ],
60
+ transactions: [
61
+ {
62
+ id: makeUUID('transaction', 'client-payment-2024-11-15'),
63
+ chargeId: makeUUID('charge', 'client-invoice-2024-11'),
64
+ businessId: makeUUID('business', 'acme-retail-client'),
65
+ amount: '-2000.00',
66
+ currency: Currency.Ils,
67
+ eventDate: '2024-11-15',
68
+ debitDate: '2024-11-15',
69
+ accountNumber: '22-333-4444',
70
+ },
71
+ {
72
+ id: makeUUID('transaction', 'client-refund-2024-11-20'),
73
+ chargeId: makeUUID('charge', 'client-refund-credit-2024-11'),
74
+ businessId: makeUUID('business', 'acme-retail-client'),
75
+ amount: '500.00',
76
+ currency: Currency.Ils,
77
+ eventDate: '2024-11-20',
78
+ debitDate: '2024-11-20',
79
+ accountNumber: '22-333-4444',
80
+ },
81
+ ],
82
+ documents: [
83
+ {
84
+ id: makeUUID('document', 'client-invoice-inv-2024-11-01'),
85
+ chargeId: makeUUID('charge', 'client-invoice-2024-11'),
86
+ creditorId: '{{ADMIN_BUSINESS_ID}}',
87
+ debtorId: makeUUID('business', 'acme-retail-client'),
88
+ serialNumber: 'INV-2024-11-01',
89
+ type: 'INVOICE',
90
+ date: '2024-11-01',
91
+ totalAmount: '2000.00',
92
+ currencyCode: Currency.Ils,
93
+ },
94
+ {
95
+ id: makeUUID('document', 'client-credit-invoice-2024-11-20'),
96
+ chargeId: makeUUID('charge', 'client-refund-credit-2024-11'),
97
+ creditorId: '{{ADMIN_BUSINESS_ID}}',
98
+ debtorId: makeUUID('business', 'acme-retail-client'),
99
+ serialNumber: 'CR-2024-11-20',
100
+ type: 'CREDIT_INVOICE',
101
+ date: '2024-11-20',
102
+ totalAmount: '500.00',
103
+ currencyCode: Currency.Ils,
104
+ },
105
+ ],
106
+ },
107
+ metadata: {
108
+ author: 'demo-team',
109
+ createdAt: '2024-11-24',
110
+ updatedAt: '2024-11-24',
111
+ },
112
+ expectations: {
113
+ ledgerRecordCount: 4,
114
+ },
115
+ };
@@ -0,0 +1,52 @@
1
+ import type { UseCaseSpec } from '../../fixtures/fixture-spec.js';
2
+ import { shareholderDividend } from './equity/shareholder-dividend.js';
3
+ import { monthlyExpenseForeignCurrency } from './expenses/monthly-expense-foreign-currency.js';
4
+ import { clientPaymentWithRefund } from './income/client-payment-with-refund.js';
5
+
6
+ /**
7
+ * Central registry of all demo use-cases organized by category.
8
+ *
9
+ * Each category contains an array of use-case specifications that will be
10
+ * seeded into the staging environment. Use-cases are processed in the order
11
+ * they appear in each category array.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // Adding a new use-case:
16
+ * import { monthlyExpense } from './expenses/monthly-expense.js';
17
+ *
18
+ * export const USE_CASE_REGISTRY: Record<string, UseCaseSpec[]> = {
19
+ * expenses: [monthlyExpense],
20
+ * income: [],
21
+ * equity: [],
22
+ * };
23
+ * ```
24
+ */
25
+ export const USE_CASE_REGISTRY: Record<string, UseCaseSpec[]> = {
26
+ expenses: [monthlyExpenseForeignCurrency],
27
+ equity: [shareholderDividend],
28
+ income: [clientPaymentWithRefund],
29
+ };
30
+
31
+ /**
32
+ * Get all registered use-cases across all categories.
33
+ *
34
+ * This function flattens the registry into a single array, maintaining
35
+ * the order: expenses first, then income, then equity (based on object
36
+ * key insertion order).
37
+ *
38
+ * @returns Array of all use-case specifications
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const allUseCases = getAllUseCases();
43
+ * console.log(`Total use-cases: ${allUseCases.length}`);
44
+ *
45
+ * allUseCases.forEach(useCase => {
46
+ * console.log(`${useCase.category}: ${useCase.name}`);
47
+ * });
48
+ * ```
49
+ */
50
+ export function getAllUseCases(): UseCaseSpec[] {
51
+ return Object.values(USE_CASE_REGISTRY).flat();
52
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Demo Data Validation Script
3
+ *
4
+ * Validates the integrity of seeded demo data with comprehensive ledger validation.
5
+ *
6
+ * Validation Checks:
7
+ * - Admin business entity exists
8
+ * - Charge count matches expected
9
+ * - Ledger records for each use-case:
10
+ * - Per-record internal balance (FR1)
11
+ * - Aggregate balance (FR2)
12
+ * - Entity-level balance (FR3)
13
+ * - No orphaned amounts (FR4)
14
+ * - Positive amounts only (FR5)
15
+ * - Foreign currency consistency (FR6)
16
+ * - Valid dates (FR7)
17
+ * - Record count matches (FR8)
18
+ *
19
+ * Exit codes:
20
+ * - 0: All validations passed
21
+ * - 1: Validation errors found or database connection failed
22
+ */
23
+ import { config } from 'dotenv';
24
+ import pg from 'pg';
25
+ import { getAllUseCases } from './use-cases/index.js';
26
+ import { validateLedgerRecords } from './validators/ledger-validators.js';
27
+ import type { LedgerRecord, ValidationContext } from './validators/types.js';
28
+
29
+ config({
30
+ path: '../../.env',
31
+ });
32
+
33
+ const DEFAULT_CURRENCY = 'ILS';
34
+ const BALANCE_TOLERANCE = 0.005;
35
+
36
+ /**
37
+ * Main validation function - connects to DB and runs all checks
38
+ */
39
+ async function validateDemoData() {
40
+ const client = new pg.Client({
41
+ user: process.env.POSTGRES_USER,
42
+ password: process.env.POSTGRES_PASSWORD,
43
+ host: process.env.POSTGRES_HOST,
44
+ port: parseInt(process.env.POSTGRES_PORT || '5432'),
45
+ database: process.env.POSTGRES_DB,
46
+ ssl: process.env.POSTGRES_SSL === '1',
47
+ });
48
+
49
+ const errors: string[] = [];
50
+
51
+ try {
52
+ await client.connect();
53
+
54
+ // 1. Admin business exists
55
+ const adminCheck = await client.query(
56
+ `SELECT id FROM accounter_schema.financial_entities WHERE type = 'business' AND name = 'Accounter Admin Business'`,
57
+ );
58
+ if (adminCheck.rows.length === 0) {
59
+ errors.push('Admin business entity missing');
60
+ }
61
+
62
+ // 2. Use-case charge count reconciliation
63
+ const useCases = getAllUseCases();
64
+ const expectedChargeCount = useCases.reduce((sum, uc) => sum + uc.fixtures.charges.length, 0);
65
+ const actualChargeCount = await client.query(`SELECT COUNT(*) FROM accounter_schema.charges`);
66
+ if (parseInt(actualChargeCount.rows[0].count) !== expectedChargeCount) {
67
+ errors.push(
68
+ `Charge count mismatch: expected ${expectedChargeCount}, got ${actualChargeCount.rows[0].count}`,
69
+ );
70
+ }
71
+
72
+ // 3. Comprehensive ledger validation for all use-cases with expectations (FR9)
73
+ const useCasesWithExpectations = useCases.filter(uc => uc.expectations);
74
+
75
+ console.log(
76
+ `\nValidating ledger records for ${useCasesWithExpectations.length} use-case(s)...`,
77
+ );
78
+
79
+ let ledgerRecordsExist = false;
80
+
81
+ for (const useCase of useCasesWithExpectations) {
82
+ // Get all charges for this use-case
83
+ const chargeIds = useCase.fixtures.charges.map(c => c.id);
84
+
85
+ // Fetch all ledger records for these charges
86
+ const ledgerRecords = await client.query<LedgerRecord>(
87
+ `SELECT * FROM accounter_schema.ledger_records WHERE charge_id = ANY($1) ORDER BY created_at`,
88
+ [chargeIds],
89
+ );
90
+
91
+ if (ledgerRecords.rows.length === 0) {
92
+ // Ledger generation is separate from seeding - this is expected
93
+ console.log(` ⚠ ${useCase.id}: no ledger records (ledger generation not run)`);
94
+ continue;
95
+ }
96
+
97
+ ledgerRecordsExist = true;
98
+
99
+ // Create validation context
100
+ const context: ValidationContext = {
101
+ useCaseId: useCase.id,
102
+ defaultCurrency: DEFAULT_CURRENCY,
103
+ tolerance: BALANCE_TOLERANCE,
104
+ };
105
+
106
+ // Run comprehensive validation
107
+ const validationErrors = validateLedgerRecords(
108
+ ledgerRecords.rows,
109
+ useCase.expectations!.ledgerRecordCount,
110
+ context,
111
+ );
112
+
113
+ errors.push(...validationErrors);
114
+
115
+ // Log progress
116
+ if (validationErrors.length === 0) {
117
+ console.log(` ✓ ${useCase.id} (${ledgerRecords.rows.length} records)`);
118
+ } else {
119
+ console.log(` ✗ ${useCase.id} (${validationErrors.length} error(s))`);
120
+ }
121
+ }
122
+
123
+ if (!ledgerRecordsExist) {
124
+ console.log(
125
+ ' ℹ️ Ledger records not found. Run ledger generation to create and validate ledger entries.',
126
+ );
127
+ }
128
+
129
+ // 4. VAT row present (percentage stored as decimal 0.17 for 17%)
130
+ const vatCheck = await client.query(
131
+ `SELECT 1 FROM accounter_schema.vat_value WHERE percentage = 0.17`,
132
+ );
133
+ if (vatCheck.rows.length === 0) {
134
+ errors.push('VAT default (17%) missing');
135
+ }
136
+
137
+ // Report errors or success
138
+ if (errors.length > 0) {
139
+ console.error('❌ Validation failed:');
140
+ for (const err of errors) console.error(` - ${err}`);
141
+ process.exit(1);
142
+ }
143
+
144
+ console.log('✅ Demo data validation passed');
145
+ } catch (error) {
146
+ console.error('❌ Validation error:', error);
147
+ process.exit(1);
148
+ } finally {
149
+ await client.end();
150
+ }
151
+ }
152
+
153
+ validateDemoData();