@stamhoofd/backend 2.140.0 → 2.141.0

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 (61) hide show
  1. package/package.json +17 -17
  2. package/src/crons/fake-settlements.test.ts +129 -8
  3. package/src/crons/fake-settlements.ts +256 -9
  4. package/src/crons/index.ts +1 -1
  5. package/src/crons/invoices.ts +13 -8
  6. package/src/crons/settlement-sync.test.ts +39 -0
  7. package/src/crons/settlement-sync.ts +109 -0
  8. package/src/crons/stripe-invoices.ts +19 -13
  9. package/src/crons.ts +1 -5
  10. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemBreakdownEndpoint.test.ts +4 -4
  11. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +2 -2
  12. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +1 -1
  13. package/src/endpoints/organization/dashboard/payments/GetPaymentBreakdownEndpoint.test.ts +3 -3
  14. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.test.ts +150 -2
  15. package/src/endpoints/organization/dashboard/{stripe/GetStripePayoutsExportStatusEndpoint.ts → settlements/GetSettlementsSyncStatusEndpoint.ts} +9 -7
  16. package/src/endpoints/organization/dashboard/settlements/SettlementsExportEndpoint.test.ts +157 -0
  17. package/src/endpoints/organization/dashboard/settlements/SettlementsExportEndpoint.ts +140 -0
  18. package/src/endpoints/organization/dashboard/settlements/SettlementsSyncEndpoint.test.ts +110 -0
  19. package/src/endpoints/organization/dashboard/settlements/SettlementsSyncEndpoint.ts +104 -0
  20. package/src/excel-loaders/payments.ts +18 -1
  21. package/src/helpers/ApplicationFeeDetails.ts +66 -0
  22. package/src/helpers/ApplicationFeeInvoicer.test.ts +285 -0
  23. package/src/helpers/ApplicationFeeInvoicer.ts +419 -0
  24. package/src/helpers/AuthenticatedStructures.ts +14 -1
  25. package/src/helpers/MollieSettlementSync.test.ts +361 -0
  26. package/src/helpers/MollieSettlementSync.ts +323 -0
  27. package/src/helpers/MollieSettlementSyncRunner.ts +53 -0
  28. package/src/helpers/ProviderSettlementSyncRunner.ts +37 -0
  29. package/src/helpers/SettlementExporter.test.ts +366 -0
  30. package/src/helpers/SettlementExporter.ts +583 -0
  31. package/src/helpers/SettlementSyncRunner.test.ts +165 -0
  32. package/src/helpers/SettlementSyncRunner.ts +64 -0
  33. package/src/helpers/StripeHelper.ts +2 -1
  34. package/src/helpers/StripeSettlementSync.test.ts +828 -0
  35. package/src/helpers/StripeSettlementSync.ts +947 -0
  36. package/src/helpers/StripeSettlementSyncRunner.test.ts +66 -0
  37. package/src/helpers/StripeSettlementSyncRunner.ts +152 -0
  38. package/src/helpers/WebmasterReport.test.ts +109 -0
  39. package/src/helpers/WebmasterReport.ts +115 -0
  40. package/src/helpers/getPaymentIdForStripeCharge.test.ts +91 -0
  41. package/src/helpers/getPaymentIdForStripeCharge.ts +71 -0
  42. package/src/services/ApplicationFeeService.test.ts +256 -0
  43. package/src/services/ApplicationFeeService.ts +283 -0
  44. package/src/services/InvoiceService.ts +18 -1
  45. package/src/services/SettlementService.test.ts +559 -0
  46. package/src/services/SettlementService.ts +607 -0
  47. package/src/sql-filters/payment-settlement.test.ts +2 -2
  48. package/src/sql-filters/payments.ts +73 -0
  49. package/tests/helpers/MollieMocker.ts +64 -6
  50. package/tests/helpers/StripeMocker.ts +209 -17
  51. package/src/crons/stripe-payout-reports.ts +0 -69
  52. package/src/endpoints/organization/dashboard/stripe/StripePayoutsExportEndpoint.test.ts +0 -103
  53. package/src/endpoints/organization/dashboard/stripe/StripePayoutsExportEndpoint.ts +0 -125
  54. package/src/helpers/CheckSettlements.test.ts +0 -190
  55. package/src/helpers/CheckSettlements.ts +0 -237
  56. package/src/helpers/StripeInvoicer.ts +0 -419
  57. package/src/helpers/StripePayoutChecker.ts +0 -193
  58. package/src/helpers/StripePayoutExportData.ts +0 -195
  59. package/src/helpers/StripePayoutExportExcel.ts +0 -280
  60. package/src/helpers/StripePayoutReporter.test.ts +0 -419
  61. package/src/helpers/StripePayoutReporter.ts +0 -585
@@ -0,0 +1,53 @@
1
+ import { MollieToken } from '@stamhoofd/models';
2
+
3
+ import { SettlementService } from '../services/SettlementService.js';
4
+ import { MollieSettlementSync } from './MollieSettlementSync.js';
5
+ import type { ProviderSettlementSyncRunner, ProviderSyncRunOptions } from './ProviderSettlementSyncRunner.js';
6
+
7
+ /**
8
+ * Walks every Mollie account: the platform's own account first, then all organization tokens.
9
+ * No constructor configuration: Mollie has no platform-wide credential — tokens are per account
10
+ * (STAMHOOFD.MOLLIE_ORGANIZATION_TOKEN for the platform, a MollieToken row per organization).
11
+ */
12
+ export class MollieSettlementSyncRunner implements ProviderSettlementSyncRunner {
13
+ async run({ start, end, summary, onProgress }: ProviderSyncRunOptions): Promise<void> {
14
+ const accessToken = STAMHOOFD.MOLLIE_ORGANIZATION_TOKEN;
15
+ if (!accessToken) {
16
+ console.error('Missing mollie organization token');
17
+ } else {
18
+ try {
19
+ // The platform's own Mollie account belongs to the membership organization, but a
20
+ // platform without one must not block the per-organization tokens
21
+ const token = new MollieToken();
22
+ token.organizationId = await SettlementService.getPlatformOrganizationId();
23
+ token.accessToken = accessToken;
24
+ // A plain access token without a refresh flow: the future expiry keeps
25
+ // refreshIfNeeded from attempting one
26
+ token.expiresOn = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
27
+ await new MollieSettlementSync({ token }).syncSettlements({ start, end, summary });
28
+ } catch (e) {
29
+ console.error(e);
30
+ summary.failed += 1;
31
+ }
32
+ onProgress?.();
33
+ }
34
+
35
+ const mollieTokens = await MollieToken.all();
36
+ for (const token of mollieTokens) {
37
+ // Tokens created before the settlements permission was added to the OAuth scope
38
+ // cannot read settlements
39
+ if (token.createdAt < new Date(2021, 8 /* september! */, 8)) {
40
+ console.log('Skipped mollie token that is too old');
41
+ continue;
42
+ }
43
+
44
+ try {
45
+ await new MollieSettlementSync({ token }).syncSettlements({ start, end, summary });
46
+ } catch (e) {
47
+ console.error(e);
48
+ summary.failed += 1;
49
+ }
50
+ onProgress?.();
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,37 @@
1
+ export type SettlementSyncSummary = {
2
+ feeMonths: number;
3
+ failedFeeMonths: number;
4
+ synced: number;
5
+ skipped: number;
6
+ failed: number;
7
+ };
8
+
9
+ export type ProviderSyncRunOptions = {
10
+ /**
11
+ * Sync settlements settled at or after this date...
12
+ */
13
+ start: Date;
14
+
15
+ /**
16
+ * ...and at or before this date.
17
+ */
18
+ end: Date;
19
+
20
+ /**
21
+ * Mutated in place, shared across providers so one run reports one total.
22
+ */
23
+ summary: SettlementSyncSummary;
24
+
25
+ /**
26
+ * Fired after each unit of work (a month for Stripe, an account for Mollie).
27
+ */
28
+ onProgress?: () => void;
29
+ };
30
+
31
+ /**
32
+ * One provider's settlement walk. Constructor = provider-specific configuration; run = uniform
33
+ * execution over a window. Every run option applies to every implementation.
34
+ */
35
+ export interface ProviderSettlementSyncRunner {
36
+ run(options: ProviderSyncRunOptions): Promise<void>;
37
+ }
@@ -0,0 +1,366 @@
1
+ import type { Organization } from '@stamhoofd/models';
2
+ import { BalanceItem, BalanceItemPayment, Invoice, OrganizationFactory, Payment } from '@stamhoofd/models';
3
+ import { ApplicationFee } from '@stamhoofd/models/models/ApplicationFee.js';
4
+ import type { Settlement } from '@stamhoofd/models/models/Settlement.js';
5
+ import { BalanceItemStatus, BalanceItemType, PaymentMethod, PaymentProvider, PaymentStatus } from '@stamhoofd/structures';
6
+ import { ApplicationFeeType } from '@stamhoofd/structures/settlements/ApplicationFeeType.js';
7
+ import { SettlementChargeType } from '@stamhoofd/structures/settlements/SettlementChargeType.js';
8
+ import { v4 as uuidv4 } from 'uuid';
9
+
10
+ import { initMembershipOrganization } from '../../tests/init/initMembershipOrganization.js';
11
+ import { SettlementService } from '../services/SettlementService.js';
12
+ import { SettlementExporter } from './SettlementExporter.js';
13
+
14
+ describe('SettlementExporter', () => {
15
+ let membershipOrganization: Organization;
16
+
17
+ beforeAll(async () => {
18
+ membershipOrganization = await initMembershipOrganization();
19
+ });
20
+
21
+ /**
22
+ * A fresh organization with one settled Mollie payment: a payout of 49,63 explained by a 50,00
23
+ * payment line and Mollie's 0,30 + 0,063 VAT cost rows (invoice inv_123).
24
+ */
25
+ const createSettledPayment = async () => {
26
+ const organization = await new OrganizationFactory({}).create();
27
+
28
+ const payment = new Payment();
29
+ payment.organizationId = organization.id;
30
+ payment.method = PaymentMethod.Bancontact;
31
+ payment.provider = PaymentProvider.Mollie;
32
+ payment.status = PaymentStatus.Succeeded;
33
+ payment.price = 50_00_00;
34
+ payment.paidAt = new Date(2026, 0, 10);
35
+ await payment.save();
36
+
37
+ const settlement = await SettlementService.upsertSettlement({
38
+ provider: PaymentProvider.Mollie,
39
+ externalId: 'stl_' + uuidv4(),
40
+ organizationId: organization.id,
41
+ reference: '1234567.2601.01',
42
+ amount: 49_63_70,
43
+ settledAt: new Date(2026, 0, 15),
44
+ });
45
+ await SettlementService.upsertPaymentLine(settlement, {
46
+ paymentId: payment.id,
47
+ amount: 50_00_00,
48
+ externalId: 'tr_' + uuidv4(),
49
+ occurredAt: new Date(2026, 0, 15),
50
+ });
51
+ await SettlementService.upsertCharge({
52
+ type: SettlementChargeType.ProviderTransactionFee,
53
+ externalId: settlement.externalId + ':cost:0',
54
+ amount: -30_00,
55
+ settlementId: settlement.id,
56
+ organizationId: settlement.organizationId,
57
+ providerInvoiceId: 'inv_123',
58
+ description: 'Transactiekosten',
59
+ occurredAt: new Date(2026, 0, 15),
60
+ });
61
+ await SettlementService.upsertCharge({
62
+ type: SettlementChargeType.Tax,
63
+ externalId: settlement.externalId + ':cost:0:tax',
64
+ amount: -6_30,
65
+ settlementId: settlement.id,
66
+ organizationId: settlement.organizationId,
67
+ providerInvoiceId: 'inv_123',
68
+ description: 'BTW op transactiekosten',
69
+ occurredAt: new Date(2026, 0, 15),
70
+ });
71
+ await SettlementService.finishSync(settlement, { transactionCount: 3 });
72
+
73
+ return { organization, payment, settlement };
74
+ };
75
+
76
+ const createExporter = (organization: Organization) => {
77
+ return new SettlementExporter({
78
+ start: new Date(2026, 0, 1),
79
+ end: new Date(2026, 1, 1),
80
+ organization,
81
+ sellingOrganization: membershipOrganization,
82
+ });
83
+ };
84
+
85
+ test('only walks the settlements of the exported organization', async () => {
86
+ const { organization } = await createSettledPayment();
87
+ await createSettledPayment();
88
+
89
+ const exporter = createExporter(organization);
90
+ let count = 0;
91
+ exporter.callback = () => count++;
92
+ await exporter.build();
93
+
94
+ expect(count).toBe(1);
95
+ });
96
+
97
+ test('a platform payout is included in its owning organization\'s export', async () => {
98
+ // The platform's own payouts belong to the membership organization: there is no separate
99
+ // platform-only mode, scoping to that organization is the platform export
100
+ const owner = await new OrganizationFactory({}).create();
101
+ const platformSettlement = await SettlementService.upsertSettlement({
102
+ provider: PaymentProvider.Stripe,
103
+ externalId: 'po_platform_' + uuidv4(),
104
+ stripeAccountId: null,
105
+ organizationId: owner.id,
106
+ amount: 12_34_00,
107
+ settledAt: new Date(2026, 0, 20),
108
+ });
109
+ await SettlementService.finishSync(platformSettlement, { transactionCount: 0 });
110
+ await createSettledPayment();
111
+
112
+ const exporter = createExporter(owner);
113
+ let count = 0;
114
+ exporter.callback = () => count++;
115
+ await exporter.build();
116
+
117
+ expect(count).toBe(1);
118
+ });
119
+
120
+ test('charges group into the invoice of the party that bills them', async () => {
121
+ const { organization, payment, settlement } = await createSettledPayment();
122
+
123
+ // Application fees the platform deducted: billed by the membership organization's monthly
124
+ // fee invoice
125
+ await SettlementService.upsertCharge({
126
+ type: SettlementChargeType.ApplicationFeeService,
127
+ externalId: 'fee_' + uuidv4() + ':ApplicationFeeService',
128
+ amount: -1_00_00,
129
+ settlementId: settlement.id,
130
+ paymentId: payment.id,
131
+ organizationId: organization.id,
132
+ occurredAt: new Date(2026, 0, 15),
133
+ });
134
+ await SettlementService.upsertCharge({
135
+ type: SettlementChargeType.ApplicationFeeTransfer,
136
+ externalId: 'fee_' + uuidv4() + ':ApplicationFeeTransfer',
137
+ amount: -50_00,
138
+ settlementId: settlement.id,
139
+ paymentId: payment.id,
140
+ organizationId: organization.id,
141
+ occurredAt: new Date(2026, 0, 15),
142
+ });
143
+
144
+ // Money movement: part of no invoice
145
+ await SettlementService.upsertCharge({
146
+ type: SettlementChargeType.Reserve,
147
+ externalId: 'rsv_' + uuidv4(),
148
+ amount: -10_00_00,
149
+ settlementId: settlement.id,
150
+ organizationId: settlement.organizationId,
151
+ occurredAt: new Date(2026, 0, 15),
152
+ });
153
+
154
+ const exporter = createExporter(organization);
155
+ await exporter.build();
156
+
157
+ const totals = exporter.getProviderInvoiceTotals();
158
+ expect(totals).toHaveLength(2);
159
+
160
+ // Mollie's own costs on its invoice document, with the VAT split out
161
+ expect(totals).toContainEqual({
162
+ invoicedBy: PaymentProvider.Mollie,
163
+ invoiceId: 'inv_123',
164
+ stamped: true,
165
+ isSellingOrganization: false,
166
+ transactionFees: 30_00,
167
+ serviceFees: 0,
168
+ accountFees: 0,
169
+ vat: 6_30,
170
+ });
171
+
172
+ // The deducted application fees, still waiting for the invoice that bills them: grouped
173
+ // per month until its number is stamped on them
174
+ expect(totals).toContainEqual({
175
+ invoicedBy: membershipOrganization.name,
176
+ invoiceId: '2026-01',
177
+ stamped: false,
178
+ isSellingOrganization: true,
179
+ transactionFees: 50_00,
180
+ serviceFees: 1_00_00,
181
+ accountFees: 0,
182
+ vat: 0,
183
+ });
184
+ });
185
+
186
+ test('application fees group per invoice once its number is stamped on them', async () => {
187
+ const { organization, payment, settlement } = await createSettledPayment();
188
+
189
+ await SettlementService.upsertCharge({
190
+ type: SettlementChargeType.ApplicationFeeService,
191
+ externalId: 'fee_' + uuidv4() + ':ApplicationFeeService',
192
+ amount: -1_00_00,
193
+ settlementId: settlement.id,
194
+ paymentId: payment.id,
195
+ organizationId: organization.id,
196
+ providerInvoiceId: '2026042',
197
+ occurredAt: new Date(2026, 0, 15),
198
+ });
199
+
200
+ const exporter = createExporter(organization);
201
+ await exporter.build();
202
+
203
+ expect(exporter.getProviderInvoiceTotals()).toContainEqual({
204
+ invoicedBy: membershipOrganization.name,
205
+ invoiceId: '2026042',
206
+ stamped: true,
207
+ isSellingOrganization: true,
208
+ transactionFees: 0,
209
+ serviceFees: 1_00_00,
210
+ accountFees: 0,
211
+ vat: 0,
212
+ });
213
+ });
214
+
215
+ describe('the platform invoice check', () => {
216
+ /**
217
+ * The fee as the sync stores it: a deduction charge on the payer's payout with the
218
+ * application fee row that says what we received for it.
219
+ */
220
+ const addFeeCharge = async (organization: Organization, settlement: Settlement | null, payment: Payment | null, providerInvoiceId: string | null, { amount = 1_00_00, occurredAt = new Date(2026, 0, 15) } = {}) => {
221
+ const externalId = 'fee_' + uuidv4();
222
+ const charge = await SettlementService.upsertCharge({
223
+ type: SettlementChargeType.ApplicationFeeService,
224
+ externalId: externalId + ':ApplicationFeeService',
225
+ amount: -amount,
226
+ applicationFeeId: externalId,
227
+ ...(settlement ? { settlementId: settlement.id } : {}),
228
+ ...(payment ? { paymentId: payment.id } : {}),
229
+ organizationId: organization.id,
230
+ ...(providerInvoiceId ? { providerInvoiceId } : {}),
231
+ occurredAt,
232
+ });
233
+
234
+ const fee = new ApplicationFee();
235
+ fee.externalId = externalId;
236
+ fee.type = ApplicationFeeType.Service;
237
+ fee.amount = amount;
238
+ fee.organizationId = membershipOrganization.id;
239
+ fee.payingOrganizationId = organization.id;
240
+ fee.settlementChargeId = charge.id;
241
+ fee.occurredAt = occurredAt;
242
+ await fee.save();
243
+
244
+ return fee;
245
+ };
246
+
247
+ /**
248
+ * The invoice that bills those fees: one balance item for them, paid by one deduction
249
+ * payment, invoiced next to whatever else the organization owed.
250
+ */
251
+ const billFees = async (organization: Organization, fees: ApplicationFee[], number: string, { billed, otherTotal = 0 }: { billed?: number; otherTotal?: number } = {}) => {
252
+ const total = billed ?? fees.reduce((sum, fee) => sum + fee.amount, 0);
253
+
254
+ const balanceItem = new BalanceItem();
255
+ balanceItem.type = BalanceItemType.ServiceFee;
256
+ balanceItem.organizationId = membershipOrganization.id;
257
+ balanceItem.payingOrganizationId = organization.id;
258
+ balanceItem.unitPrice = total;
259
+ balanceItem.quantity = 1;
260
+ balanceItem.status = BalanceItemStatus.Hidden;
261
+ await balanceItem.save();
262
+
263
+ for (const fee of fees) {
264
+ fee.balanceItemId = balanceItem.id;
265
+ await fee.save();
266
+ }
267
+
268
+ const invoice = new Invoice();
269
+ invoice.organizationId = membershipOrganization.id;
270
+ invoice.payingOrganizationId = organization.id;
271
+ invoice.number = number;
272
+ invoice.totalWithVAT = total + otherTotal;
273
+ await invoice.save();
274
+
275
+ const feePayment = new Payment();
276
+ feePayment.organizationId = membershipOrganization.id;
277
+ feePayment.payingOrganizationId = organization.id;
278
+ feePayment.method = PaymentMethod.AccountDeductions;
279
+ feePayment.provider = PaymentProvider.Stripe;
280
+ feePayment.status = PaymentStatus.Succeeded;
281
+ feePayment.price = total;
282
+ feePayment.invoiceId = invoice.id;
283
+ await feePayment.save();
284
+
285
+ const balanceItemPayment = new BalanceItemPayment();
286
+ balanceItemPayment.balanceItemId = balanceItem.id;
287
+ balanceItemPayment.paymentId = feePayment.id;
288
+ balanceItemPayment.organizationId = membershipOrganization.id;
289
+ balanceItemPayment.price = total;
290
+ await balanceItemPayment.save();
291
+
292
+ if (otherTotal !== 0) {
293
+ const other = new Payment();
294
+ other.organizationId = membershipOrganization.id;
295
+ other.payingOrganizationId = organization.id;
296
+ other.method = PaymentMethod.Transfer;
297
+ other.status = PaymentStatus.Succeeded;
298
+ other.price = otherTotal;
299
+ other.invoiceId = invoice.id;
300
+ await other.save();
301
+ }
302
+
303
+ return invoice;
304
+ };
305
+
306
+ const buildStatus = async (organization: Organization, invoiceNumber: string) => {
307
+ const exporter = createExporter(organization);
308
+ await exporter.build();
309
+ const totals = exporter.getProviderInvoiceTotals().find(t => t.invoiceId === invoiceNumber)!;
310
+ return await exporter.getProviderInvoiceStatus(totals);
311
+ };
312
+
313
+ test('an invoice that also bills something else still matches its fees', async () => {
314
+ const { organization, payment, settlement } = await createSettledPayment();
315
+ const number = uuidv4();
316
+ const fee = await addFeeCharge(organization, settlement, payment, number);
317
+ await billFees(organization, [fee], number, { otherTotal: 250_00_00 });
318
+
319
+ expect(await buildStatus(organization, number)).toMatchObject({ check: '✓', outsideExport: 0 });
320
+ });
321
+
322
+ test('an invoice that bills less than was charged does not match', async () => {
323
+ const { organization, payment, settlement } = await createSettledPayment();
324
+ const number = uuidv4();
325
+ const fee = await addFeeCharge(organization, settlement, payment, number, { amount: 1_00_00 });
326
+ await billFees(organization, [fee], number, { billed: 60_00 });
327
+
328
+ expect(await buildStatus(organization, number)).toMatchObject({ check: 'Nog niet (volledig) gefactureerd' });
329
+ });
330
+
331
+ test('charges outside the exported range still count towards the invoice', async () => {
332
+ const { organization, payment, settlement } = await createSettledPayment();
333
+ const number = uuidv4();
334
+ const inRange = await addFeeCharge(organization, settlement, payment, number, { amount: 1_00_00 });
335
+
336
+ // A charge of the same invoice in a month this export doesn't cover
337
+ const outside = await addFeeCharge(organization, null, null, number, { amount: 40_00, occurredAt: new Date(2026, 5, 15) });
338
+ await billFees(organization, [inRange, outside], number);
339
+
340
+ expect(await buildStatus(organization, number)).toMatchObject({ check: '✓', outsideExport: 40_00 });
341
+ });
342
+
343
+ test('fees without an invoice number are not billed yet', async () => {
344
+ const { organization, payment, settlement } = await createSettledPayment();
345
+ await addFeeCharge(organization, settlement, payment, null);
346
+
347
+ const exporter = createExporter(organization);
348
+ await exporter.build();
349
+ const totals = exporter.getProviderInvoiceTotals().find(t => t.isSellingOrganization)!;
350
+
351
+ expect(await exporter.getProviderInvoiceStatus(totals)).toMatchObject({
352
+ check: 'Nog niet (volledig) gefactureerd',
353
+ outsideExport: null,
354
+ });
355
+ });
356
+
357
+ test('the provider\'s own invoices carry no verdict', async () => {
358
+ const { organization } = await createSettledPayment();
359
+ const exporter = createExporter(organization);
360
+ await exporter.build();
361
+ const totals = exporter.getProviderInvoiceTotals().find(t => t.invoiceId === 'inv_123')!;
362
+
363
+ expect((await exporter.getProviderInvoiceStatus(totals)).check).toBe('');
364
+ });
365
+ });
366
+ });