@stamhoofd/backend 2.143.1 → 2.145.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 (111) hide show
  1. package/package.json +19 -19
  2. package/src/crons/fake-settlements.test.ts +13 -11
  3. package/src/crons/fake-settlements.ts +22 -38
  4. package/src/crons/mollie-chargebacks.ts +31 -29
  5. package/src/crons/mollie-refunds.ts +61 -59
  6. package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +16 -5
  7. package/src/endpoints/auth/CreateTokenEndpoint.test.ts +210 -4
  8. package/src/endpoints/auth/CreateTokenEndpoint.ts +9 -20
  9. package/src/endpoints/auth/DeleteTokenEndpoint.test.ts +29 -0
  10. package/src/endpoints/auth/DeleteTokenEndpoint.ts +2 -1
  11. package/src/endpoints/auth/GetUserEndpoint.test.ts +32 -11
  12. package/src/endpoints/auth/MFA.security.test.ts +9 -7
  13. package/src/endpoints/auth/MFA.test.ts +42 -15
  14. package/src/endpoints/auth/PatchUserEndpoint.ts +3 -2
  15. package/src/endpoints/auth/VerifyEmailEndpoint.ts +5 -4
  16. package/src/endpoints/global/email/GetAdminEmailsEndpoint.test.ts +4 -3
  17. package/src/endpoints/global/email/GetUserEmailsEndpoint.test.ts +6 -5
  18. package/src/endpoints/global/email/PatchEmailEndpoint.test.ts +5 -4
  19. package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.test.ts +5 -4
  20. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.test.ts +2 -1
  21. package/src/endpoints/global/events/PatchEventsEndpoint.test.ts +2 -1
  22. package/src/endpoints/global/files/UploadFile.test.ts +2 -1
  23. package/src/endpoints/global/files/UploadFile.ts +53 -25
  24. package/src/endpoints/global/files/UploadImage.test.ts +2 -1
  25. package/src/endpoints/global/files/UploadImage.ts +32 -6
  26. package/src/endpoints/global/files/upload-security.test.ts +3 -2
  27. package/src/endpoints/global/groups/GetGroupsEndpoint.test.ts +4 -3
  28. package/src/endpoints/global/members/GetMembersEndpoint.test.ts +26 -25
  29. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.test.ts +57 -56
  30. package/src/endpoints/global/members/SendMemberSecurityCodeEndpoint.test.ts +4 -3
  31. package/src/endpoints/global/platform/GetPlatformEndpoint.test.ts +6 -4
  32. package/src/endpoints/global/platform/PatchPlatformEnpoint.test.ts +6 -6
  33. package/src/endpoints/global/platform/SignOutPlatformAdminsEndpoint.test.ts +9 -8
  34. package/src/endpoints/global/registration/GetRegistrationsEndpoint.test.ts +14 -13
  35. package/src/endpoints/global/registration/PatchUserMembersEndpoint.test.ts +24 -23
  36. package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +4 -3
  37. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.test.ts +2 -1
  38. package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.test.ts +2 -1
  39. package/src/endpoints/global/webshops/GetWebshopsEndpoint.test.ts +20 -19
  40. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemBreakdownEndpoint.test.ts +2 -1
  41. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsEndpoint.test.ts +2 -1
  42. package/src/endpoints/organization/dashboard/billing/ApplyRegisterCodeEndpoint.test.ts +3 -2
  43. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.test.ts +4 -3
  44. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.test.ts +5 -4
  45. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.test.ts +5 -4
  46. package/src/endpoints/organization/dashboard/invoices/GetInvoicesEndpoint.test.ts +2 -1
  47. package/src/endpoints/organization/dashboard/invoices/PatchInvoicesEndpoint.test.ts +2 -1
  48. package/src/endpoints/organization/dashboard/invoices/PatchInvoicesEndpoint.ts +0 -1
  49. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +23 -22
  50. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +4 -4
  51. package/src/endpoints/organization/dashboard/payments/GetPaymentBreakdownEndpoint.test.ts +2 -1
  52. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.test.ts +4 -3
  53. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +2 -2
  54. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint.test.ts +2 -1
  55. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.test.ts +5 -4
  56. package/src/endpoints/organization/dashboard/registration-periods/MoveRegistrationPeriods.test.ts +7 -6
  57. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.test.ts +9 -8
  58. package/src/endpoints/organization/dashboard/settlements/SettlementsExportEndpoint.test.ts +3 -2
  59. package/src/endpoints/organization/dashboard/settlements/SettlementsSyncEndpoint.test.ts +2 -1
  60. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.test.ts +5 -4
  61. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +2 -1
  62. package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.test.ts +3 -2
  63. package/src/endpoints/organization/dashboard/users/PatchApiUserEndpoint.test.ts +6 -5
  64. package/src/endpoints/organization/dashboard/users/SignOutOrganizationAdminsEndpoint.test.ts +16 -15
  65. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.test.ts +2 -1
  66. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.test.ts +2 -1
  67. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.test.ts +2 -1
  68. package/src/endpoints/organization/dashboard/webshops/WebshopReservedPathSegments.test.ts +2 -1
  69. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +4 -3
  70. package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +6 -5
  71. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +94 -8
  72. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +18 -18
  73. package/src/helpers/ApplicationFeeInvoicer.ts +1 -1
  74. package/src/helpers/Context.ts +14 -21
  75. package/src/helpers/ContextStorage.ts +5 -0
  76. package/src/helpers/MollieSettlementSync.test.ts +94 -41
  77. package/src/helpers/MollieSettlementSync.ts +174 -78
  78. package/src/helpers/StripeSettlementSync.test.ts +0 -85
  79. package/src/helpers/StripeSettlementSync.ts +47 -70
  80. package/src/helpers/TwoFactorHelper.ts +21 -22
  81. package/src/helpers/streamForBreakdown.ts +1 -1
  82. package/src/services/AdminSessionService.ts +5 -3
  83. package/src/services/InvoiceService.ts +2 -2
  84. package/src/services/MollieService.ts +168 -126
  85. package/src/services/PaymentService.ts +2 -2
  86. package/src/services/SSOService.test.ts +25 -1
  87. package/src/services/SSOService.ts +17 -6
  88. package/src/services/SessionService.test.ts +319 -0
  89. package/src/services/SessionService.ts +357 -0
  90. package/src/services/SettlementService.test.ts +13 -85
  91. package/src/services/SettlementService.ts +5 -113
  92. package/src/services/WebshopCrowdfundingService.test.ts +4 -3
  93. package/src/sql-filters/balance-items.ts +10 -0
  94. package/src/sql-filters/registrations.ts +59 -1
  95. package/tests/actions/patchUserMember.ts +2 -1
  96. package/tests/e2e/api-rate-limits.test.ts +2 -1
  97. package/tests/e2e/bundle-discounts.test.ts +4 -3
  98. package/tests/e2e/charge-members.test.ts +6 -5
  99. package/tests/e2e/documents.test.ts +4 -3
  100. package/tests/e2e/private-files.test.ts +9 -8
  101. package/tests/e2e/register.test.ts +4 -3
  102. package/tests/e2e/stock.test.ts +4 -3
  103. package/tests/e2e/tickets.test.ts +4 -3
  104. package/tests/helpers/ExportSlice.ts +2 -1
  105. package/tests/helpers/MollieMocker.ts +173 -38
  106. package/tests/init/initAdmin.ts +2 -1
  107. package/tests/init/initPlatformAdmin.ts +2 -1
  108. package/src/helpers/ViesHelper.test.ts +0 -401
  109. package/src/helpers/ViesHelper.ts +0 -215
  110. package/src/services/PeppolDirectoryService.test.ts +0 -139
  111. package/src/services/PeppolDirectoryService.ts +0 -111
@@ -6,7 +6,8 @@ import { ApplicationFee } from '@stamhoofd/models/models/ApplicationFee.js';
6
6
  import { PaymentSettlement } from '@stamhoofd/models/models/PaymentSettlement.js';
7
7
  import { Settlement } from '@stamhoofd/models/models/Settlement.js';
8
8
  import { SettlementCharge } from '@stamhoofd/models/models/SettlementCharge.js';
9
- import { AbortSignal, QueueHandler } from '@stamhoofd/queues';
9
+ import type { AbortSignal } from '@stamhoofd/queues';
10
+ import { QueueHandler } from '@stamhoofd/queues';
10
11
  import { SQL } from '@stamhoofd/sql';
11
12
  import type { PaymentProvider } from '@stamhoofd/structures';
12
13
  import { PaymentMethod, SettlementReference } from '@stamhoofd/structures';
@@ -67,44 +68,6 @@ const CHARGE_UPDATE_BATCH_SIZE = 500;
67
68
  */
68
69
  const FEE_BATCH_SIZE = 500;
69
70
 
70
- /**
71
- * Collects which rows the provider still reports in a settlement while a sync walks it. A stored
72
- * row of the settlement that is not in here after the walk has moved or disappeared at the
73
- * provider, and gets swept.
74
- */
75
- export class ReportedRows {
76
- readonly paymentLineExternalIds = new Set<string>();
77
- readonly chargeExternalIds = new Set<string>();
78
- readonly applicationFeeIds = new Set<string>();
79
-
80
- paymentLine(line: PaymentSettlement) {
81
- if (line.externalId === null) {
82
- return;
83
- }
84
- this.paymentLineExternalIds.add(line.externalId);
85
- }
86
-
87
- charge(charge: SettlementCharge) {
88
- this.chargeExternalIds.add(charge.externalId);
89
- }
90
-
91
- charges(charges: SettlementCharge[]) {
92
- for (const charge of charges) {
93
- this.charge(charge);
94
- }
95
- }
96
-
97
- applicationFee(fee: ApplicationFee) {
98
- this.applicationFeeIds.add(fee.id);
99
- }
100
-
101
- applicationFees(fees: ApplicationFee[]) {
102
- for (const fee of fees) {
103
- this.applicationFee(fee);
104
- }
105
- }
106
- }
107
-
108
71
  /**
109
72
  * All writes to the settlements tables go through this service. Every write is an upsert on the
110
73
  * deterministic unique key of its table, so re-running a sync can never duplicate rows.
@@ -317,77 +280,6 @@ export class SettlementService {
317
280
  }
318
281
  }
319
282
 
320
- /**
321
- * After a complete walk of a settlement: remove rows the provider no longer reports in this
322
- * settlement (a transaction can move to another payout). Rows that only exist because of the
323
- * payout are deleted; rows that outlive the payout link are only unlinked: derived fee lines
324
- * (owned by updatePaymentSettlementsForAccountDeductionPayment), deduction charges referenced
325
- * by an application fee, and the application fee rows themselves.
326
- *
327
- * Returns the fees unlinked from this settlement, so the caller can refresh the derived lines
328
- * of their fee payments.
329
- */
330
- static async sweepSettlement(settlement: Settlement, reported: ReportedRows): Promise<{ unlinkedFees: ApplicationFee[] }> {
331
- const lines = await PaymentSettlement.select()
332
- .where('settlementId', settlement.id)
333
- .fetch();
334
-
335
- const sweptPaymentIds = new Set<string>();
336
- for (const line of lines) {
337
- if (line.externalId === null) {
338
- continue;
339
- }
340
- if (!reported.paymentLineExternalIds.has(line.externalId)) {
341
- await line.delete();
342
- sweptPaymentIds.add(line.paymentId);
343
- }
344
- }
345
-
346
- // The legacy blob points at one of the lines, so a payment that lost one has to be
347
- // repointed at what is left
348
- if (sweptPaymentIds.size > 0) {
349
- const payments = await PaymentModel.getByIDs(...sweptPaymentIds);
350
- for (const payment of payments) {
351
- await this.updateLegacySettlementReference(payment);
352
- }
353
- }
354
-
355
- const charges = await SettlementCharge.select()
356
- .where('settlementId', settlement.id)
357
- .fetch();
358
-
359
- const unreportedCharges = charges.filter(charge => !reported.chargeExternalIds.has(charge.externalId));
360
- const referencedChargeIds = unreportedCharges.length > 0
361
- ? new Set((await ApplicationFee.select()
362
- .where('settlementChargeId', unreportedCharges.map(c => c.id))
363
- .fetch()).map(fee => fee.settlementChargeId))
364
- : new Set<string>();
365
-
366
- for (const charge of unreportedCharges) {
367
- if (referencedChargeIds.has(charge.id)) {
368
- charge.settlementId = null;
369
- await charge.save();
370
- } else {
371
- await charge.delete();
372
- }
373
- }
374
-
375
- const fees = await ApplicationFee.select()
376
- .where('settlementId', settlement.id)
377
- .fetch();
378
-
379
- const unlinkedFees: ApplicationFee[] = [];
380
- for (const fee of fees) {
381
- if (!reported.applicationFeeIds.has(fee.id)) {
382
- fee.settlementId = null;
383
- await fee.save();
384
- unlinkedFees.push(fee);
385
- }
386
- }
387
-
388
- return { unlinkedFees };
389
- }
390
-
391
283
  /**
392
284
  * Recomputes the cached reconciliation columns from the stored rows: `unexplainedAmount` should
393
285
  * be 0 — a non-zero value is a real question to answer — and `pendingFees` holds what is
@@ -500,7 +392,7 @@ export class SettlementService {
500
392
  * payout that contains fees billed by this payment, amount = the sum of those fees. When the
501
393
  * total of the lines matches the payment's price, the payment is completely paid out.
502
394
  */
503
- static async updatePaymentSettlementsForAccountDeductionPayment(payment: Payment): Promise<void> {
395
+ static async updatePaymentSettlementsForApplicationFeePayment(payment: Payment): Promise<void> {
504
396
  if (payment.method !== PaymentMethod.AccountDeductions) {
505
397
  return;
506
398
  }
@@ -567,7 +459,7 @@ export class SettlementService {
567
459
  * Refreshes the derived lines of every fee payment that billed one of these balance items:
568
460
  * called after a walk linked or unlinked invoiced fees, so the lines follow the fees.
569
461
  */
570
- static async updatePaymentSettlementsForAccountDeductionBalanceItems(balanceItemIds: string[]): Promise<void> {
462
+ static async updatePaymentSettlementsForApplicationFeeBalanceItems(balanceItemIds: string[]): Promise<void> {
571
463
  if (balanceItemIds.length === 0) {
572
464
  return;
573
465
  }
@@ -582,7 +474,7 @@ export class SettlementService {
582
474
 
583
475
  const payments = await PaymentModel.getByIDs(...paymentIds);
584
476
  for (const payment of payments) {
585
- await this.updatePaymentSettlementsForAccountDeductionPayment(payment);
477
+ await this.updatePaymentSettlementsForApplicationFeePayment(payment);
586
478
  }
587
479
  }
588
480
 
@@ -1,11 +1,12 @@
1
1
  import type { PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
2
2
  import { PatchableArray } from '@simonbackx/simple-encoding';
3
3
  import { Request } from '@simonbackx/simple-endpoints';
4
- import type { Organization, StripeAccount } from '@stamhoofd/models';
5
- import { BalanceItem, BalanceItemFactory, BalanceItemPayment, Order, OrderFactory, OrganizationFactory, Payment, Token, UserFactory, Webshop, WebshopFactory } from '@stamhoofd/models';
4
+ import type { Organization, StripeAccount, Token } from '@stamhoofd/models';
5
+ import { BalanceItem, BalanceItemFactory, BalanceItemPayment, Order, OrderFactory, OrganizationFactory, Payment, UserFactory, Webshop, WebshopFactory } from '@stamhoofd/models';
6
6
  import type { OrderResponse } from '@stamhoofd/structures';
7
7
  import { BalanceItemStatus, Cart, CartItem, Customer, OrderData, OrderStatus, PaymentConfiguration, PaymentMethod, PaymentStatus, PermissionLevel, Permissions, PrivateOrder, PrivatePaymentConfiguration, PrivateWebshop, Product, ProductPrice, TransferSettings, WebshopCrowdfunding, WebshopMetaData, WebshopPrivateMetaData } from '@stamhoofd/structures';
8
8
  import { v4 as uuidv4 } from 'uuid';
9
+ import { SessionService } from './SessionService.js';
9
10
 
10
11
  import type { StripeObject } from '../../tests/helpers/StripeMocker.js';
11
12
  import { StripeMocker } from '../../tests/helpers/StripeMocker.js';
@@ -234,7 +235,7 @@ describe('WebshopCrowdfundingService', () => {
234
235
  level: PermissionLevel.Full,
235
236
  }),
236
237
  }).create();
237
- token = await Token.createToken(user);
238
+ token = await SessionService.createSession(user);
238
239
  });
239
240
 
240
241
  afterAll(() => {
@@ -99,6 +99,16 @@ export const balanceItemFilterCompilers: SQLFilterDefinitions = {
99
99
  type: SQLValueType.String,
100
100
  nullable: true,
101
101
  }),
102
+ orderId: createColumnFilter({
103
+ expression: SQL.column('balance_items', 'orderId'),
104
+ type: SQLValueType.String,
105
+ nullable: true,
106
+ }),
107
+ registrationId: createColumnFilter({
108
+ expression: SQL.column('balance_items', 'registrationId'),
109
+ type: SQLValueType.String,
110
+ nullable: true,
111
+ }),
102
112
  type: createColumnFilter({
103
113
  expression: SQL.column('balance_items', 'type'),
104
114
  type: SQLValueType.String,
@@ -1,6 +1,6 @@
1
1
  import { Group, Member, Organization, Registration } from '@stamhoofd/models';
2
2
  import type { SQLFilterDefinitions } from '@stamhoofd/sql';
3
- import { baseSQLFilterCompilers, createColumnFilter, createJoinedRelationFilter, SQL, SQLValueType } from '@stamhoofd/sql';
3
+ import { baseSQLFilterCompilers, createColumnFilter, createExistsFilter, createJoinedRelationFilter, SQL, SQLValueType } from '@stamhoofd/sql';
4
4
  import { SQLTranslatedString } from '../helpers/SQLTranslatedString.js';
5
5
  import { baseRegistrationFilterCompilers } from './base-registration-filter-compilers.js';
6
6
  import { memberFilterCompilers } from './members.js';
@@ -55,6 +55,64 @@ export const registrationFilterCompilers: SQLFilterDefinitions = {
55
55
  }),
56
56
  },
57
57
  ),
58
+ /**
59
+ * There is a bug in MySQL 8 that is fixed in 9.3
60
+ * where EXISTS (select * from json_table(...)) does not work
61
+ * To fix this, we do a double select with join inside the select
62
+ * It is a bit slower, but it works for now.
63
+ */
64
+ options: createExistsFilter(
65
+ SQL.select()
66
+ .from(SQL.table('registrations', 'innerRegistrations'))
67
+ .join(
68
+ SQL.join(
69
+ SQL.jsonTable(
70
+ SQL.jsonExtract(SQL.column('innerRegistrations', 'options'), '$.value'),
71
+ 'options',
72
+ )
73
+ .addColumn(
74
+ 'amount',
75
+ 'INT',
76
+ '$.amount',
77
+ )
78
+ .addColumn(
79
+ 'optionId',
80
+ 'TEXT',
81
+ '$.option.id',
82
+ )
83
+ .addColumn(
84
+ 'optionMenuId',
85
+ 'TEXT',
86
+ '$.optionMenu.id',
87
+ ),
88
+ ),
89
+ )
90
+ .where(SQL.column('innerRegistrations', 'id'), SQL.column('registrations', 'id')),
91
+ {
92
+ ...baseSQLFilterCompilers,
93
+ amount: createColumnFilter({
94
+ expression: SQL.column('options', 'amount'),
95
+ type: SQLValueType.Number,
96
+ nullable: false,
97
+ }),
98
+ option: {
99
+ ...baseSQLFilterCompilers,
100
+ id: createColumnFilter({
101
+ expression: SQL.column('options', 'optionId'),
102
+ type: SQLValueType.String,
103
+ nullable: false,
104
+ }),
105
+ },
106
+ optionMenu: {
107
+ ...baseSQLFilterCompilers,
108
+ id: createColumnFilter({
109
+ expression: SQL.column('options', 'optionMenuId'),
110
+ type: SQLValueType.String,
111
+ nullable: false,
112
+ }),
113
+ },
114
+ },
115
+ ),
58
116
  organization: createJoinedRelationFilter(
59
117
  organizationJoin,
60
118
  organizationFilterCompilers,
@@ -6,11 +6,12 @@ import { Token } from '@stamhoofd/models';
6
6
  import type { MemberWithRegistrationsBlob } from '@stamhoofd/structures';
7
7
  import { PatchUserMembersEndpoint } from '../../src/endpoints/global/registration/PatchUserMembersEndpoint.js';
8
8
  import { testServer } from '../helpers/TestServer.js';
9
+ import { SessionService } from '../../src/services/SessionService.js';
9
10
 
10
11
  export async function patchUserMember({ patch, organization, user }: { patch: AutoEncoderPatchType<MemberWithRegistrationsBlob>; organization: Organization; user: User }) {
11
12
  expect(patch.id).toEqual(expect.any(String));
12
13
 
13
- const token = await Token.createToken(user);
14
+ const token = await SessionService.createSession(user);
14
15
 
15
16
  const arr = new PatchableArray();
16
17
  arr.addPatch(patch);
@@ -1,6 +1,7 @@
1
1
  import { Request } from '@simonbackx/simple-endpoints';
2
2
  import type { Organization } from '@stamhoofd/models';
3
3
  import { OrganizationFactory, Token, UserFactory } from '@stamhoofd/models';
4
+ import { SessionService } from '../../src/services/SessionService.js';
4
5
 
5
6
  import { ApiUser, ApiUserRateLimits, PermissionLevel, Permissions, UserMeta, UserPermissions } from '@stamhoofd/structures';
6
7
  import { STExpect, TestUtils } from '@stamhoofd/test-utils';
@@ -29,7 +30,7 @@ describe('E2E.APIRateLimits', () => {
29
30
  level: PermissionLevel.Full,
30
31
  }),
31
32
  }).create();
32
- const token = await Token.createToken(user, new Date());
33
+ const token = await SessionService.createSession(user, { authenticatedAt: new Date() });
33
34
 
34
35
  const createRequest = Request.buildJson('POST', '/api-keys', organization.getApiHost(), ApiUser.create({
35
36
  permissions: UserPermissions.create({
@@ -1,6 +1,6 @@
1
1
  import { Request } from '@simonbackx/simple-endpoints';
2
- import type { BalanceItem, Organization, RegistrationPeriod } from '@stamhoofd/models';
3
- import { BalanceItemFactory, GroupFactory, MemberFactory, OrganizationFactory, OrganizationRegistrationPeriodFactory, Registration, RegistrationFactory, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
2
+ import type { BalanceItem, Organization, RegistrationPeriod, Token } from '@stamhoofd/models';
3
+ import { BalanceItemFactory, GroupFactory, MemberFactory, OrganizationFactory, OrganizationRegistrationPeriodFactory, Registration, RegistrationFactory, RegistrationPeriodFactory, UserFactory } from '@stamhoofd/models';
4
4
  import { AccessRight, AppliedRegistrationDiscount, BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItemType, BooleanStatus, GroupPriceDiscount, GroupPriceDiscountType, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, PaymentMethod, PermissionLevel, Permissions, PermissionsResourceType, ReduceablePrice, ResourcePermissions } from '@stamhoofd/structures';
5
5
  import { STExpect, TestUtils } from '@stamhoofd/test-utils';
6
6
  import { RegisterMembersEndpoint } from '../../src/endpoints/global/registration/RegisterMembersEndpoint.js';
@@ -12,6 +12,7 @@ import { initBundleDiscount } from '../init/initBundleDiscount.js';
12
12
  import { initPermissionRole } from '../init/initPermissionRole.js';
13
13
  import { initStripe } from '../init/initStripe.js';
14
14
  import { initMembershipOrganization } from '../init/initMembershipOrganization.js';
15
+ import { SessionService } from '../../src/services/SessionService.js';
15
16
 
16
17
  const baseUrl = `/members/register`;
17
18
 
@@ -64,7 +65,7 @@ describe('E2E.Bundle Discounts', () => {
64
65
  permissions: null,
65
66
  }).create();
66
67
 
67
- const token = await Token.createToken(user);
68
+ const token = await SessionService.createSession(user);
68
69
 
69
70
  const member = await new MemberFactory({ organization, user })
70
71
  .create();
@@ -1,12 +1,13 @@
1
1
  import { Request, Response } from '@simonbackx/simple-endpoints';
2
- import type { Organization, RegistrationPeriod } from '@stamhoofd/models';
3
- import { GroupFactory, MemberFactory, OrganizationFactory, RegistrationFactory, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
2
+ import type { Organization, RegistrationPeriod, Token } from '@stamhoofd/models';
3
+ import { GroupFactory, MemberFactory, OrganizationFactory, RegistrationFactory, RegistrationPeriodFactory, UserFactory } from '@stamhoofd/models';
4
4
  import type { BalanceItemWithPayments, StamhoofdFilter } from '@stamhoofd/structures';
5
5
  import { AccessRight, ChargeRequest, LimitedFilteredRequest, PermissionLevel, PermissionRoleDetailed, Permissions, PermissionsResourceType, ResourcePermissions, Version } from '@stamhoofd/structures';
6
6
  import { STExpect, TestUtils } from '@stamhoofd/test-utils';
7
7
  import { ChargeMembersEndpoint } from '../../src/endpoints/admin/members/ChargeMembersEndpoint.js';
8
8
  import { testServer } from '../helpers/TestServer.js';
9
9
  import { GetReceivableBalanceEndpoint } from '../../src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint.js';
10
+ import { SessionService } from '../../src/services/SessionService.js';
10
11
 
11
12
  describe('E2E.ChargeMembers', () => {
12
13
  const chargeMembersEndpoint = new ChargeMembersEndpoint();
@@ -45,7 +46,7 @@ describe('E2E.ChargeMembers', () => {
45
46
  })
46
47
  .create();
47
48
 
48
- const token = await Token.createToken(user);
49
+ const token = await SessionService.createSession(user);
49
50
 
50
51
  return { organization, user, token };
51
52
  };
@@ -148,7 +149,7 @@ describe('E2E.ChargeMembers', () => {
148
149
  for (const userFactory of testUserFactories) {
149
150
  const user = await userFactory.create();
150
151
 
151
- const token = await Token.createToken(user);
152
+ const token = await SessionService.createSession(user);
152
153
 
153
154
  await expect(postCharge(filter, organization, body, token))
154
155
  .rejects
@@ -234,7 +235,7 @@ describe('E2E.ChargeMembers', () => {
234
235
  })
235
236
  .create();
236
237
 
237
- const otherFinancialDirectorToken = await Token.createToken(otherFinancialDirector);
238
+ const otherFinancialDirectorToken = await SessionService.createSession(otherFinancialDirector);
238
239
 
239
240
  const body = ChargeRequest.create({
240
241
  description: 'test description',
@@ -1,6 +1,6 @@
1
1
  import { Request } from '@simonbackx/simple-endpoints';
2
- import type { Group, Member, Organization, RegistrationPeriod } from '@stamhoofd/models';
3
- import { Document, DocumentTemplateFactory, GroupFactory, MemberFactory, OrganizationFactory, OrganizationRegistrationPeriodFactory, Registration, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
2
+ import type { Group, Member, Organization, RegistrationPeriod, Token } from '@stamhoofd/models';
3
+ import { Document, DocumentTemplateFactory, GroupFactory, MemberFactory, OrganizationFactory, OrganizationRegistrationPeriodFactory, Registration, RegistrationPeriodFactory, UserFactory } from '@stamhoofd/models';
4
4
  import { IDRegisterCart, IDRegisterCheckout, IDRegisterItem, MemberDetails, MemberWithRegistrationsBlob, PaymentMethod } from '@stamhoofd/structures';
5
5
  import { TestUtils } from '@stamhoofd/test-utils';
6
6
  import { Formatter } from '@stamhoofd/utility';
@@ -14,6 +14,7 @@ import { initStripe } from '../init/initStripe.js';
14
14
  import { registrationUpdateQueue } from '../../src/services/BalanceItemService.js';
15
15
  import { DocumentRenderService } from '../../src/services/DocumentRenderService.js';
16
16
  import { initMembershipOrganization } from '../init/initMembershipOrganization.js';
17
+ import { SessionService } from '../../src/services/SessionService.js';
17
18
 
18
19
  const baseUrl = `/members/register`;
19
20
 
@@ -73,7 +74,7 @@ describe('E2E.Documents', () => {
73
74
  permissions: null,
74
75
  }).create();
75
76
 
76
- const token = await Token.createToken(user);
77
+ const token = await SessionService.createSession(user);
77
78
 
78
79
  const member = await new MemberFactory({ organization, user })
79
80
  .create();
@@ -1,4 +1,5 @@
1
1
  import { File, MemberDetails, MemberWithRegistrationsBlob, RecordCategory, RecordFileAnswer, RecordSettings, RecordType, TranslatedString, Version } from '@stamhoofd/structures';
2
+ import { SessionService } from '../../src/services/SessionService.js';
2
3
 
3
4
  import type { PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
4
5
  import { encodeObject, EncodeMedium, PatchableArray } from '@simonbackx/simple-encoding';
@@ -48,7 +49,7 @@ describe('E2E.PrivateFiles', () => {
48
49
  level: PermissionLevel.Full,
49
50
  }),
50
51
  }).create();
51
- const token = await Token.createToken(user);
52
+ const token = await SessionService.createSession(user);
52
53
 
53
54
  // Create a user member
54
55
  const member = MemberWithRegistrationsBlob.create({
@@ -91,7 +92,7 @@ describe('E2E.PrivateFiles', () => {
91
92
  level: PermissionLevel.Full,
92
93
  }),
93
94
  }).create();
94
- const token = await Token.createToken(user);
95
+ const token = await SessionService.createSession(user);
95
96
 
96
97
  // Create a user member
97
98
  const member = MemberWithRegistrationsBlob.create({
@@ -135,7 +136,7 @@ describe('E2E.PrivateFiles', () => {
135
136
  level: PermissionLevel.Full,
136
137
  }),
137
138
  }).create();
138
- const token = await Token.createToken(user);
139
+ const token = await SessionService.createSession(user);
139
140
 
140
141
  // Create a user member
141
142
  const member = MemberWithRegistrationsBlob.create({
@@ -197,7 +198,7 @@ describe('E2E.PrivateFiles', () => {
197
198
  level: PermissionLevel.Full,
198
199
  }),
199
200
  }).create();
200
- const token = await Token.createToken(user);
201
+ const token = await SessionService.createSession(user);
201
202
 
202
203
  // Public files are not signed, so a malicious user can put anything in them. The url of a file ends up
203
204
  // in a link (and in the source of an image), so a javascript: url would run on our own domain.
@@ -260,7 +261,7 @@ describe('E2E.PrivateFiles', () => {
260
261
  level: PermissionLevel.Full,
261
262
  }),
262
263
  }).create();
263
- const token = await Token.createToken(user);
264
+ const token = await SessionService.createSession(user);
264
265
 
265
266
  // Create a user member
266
267
  const member = MemberWithRegistrationsBlob.create({
@@ -324,7 +325,7 @@ describe('E2E.PrivateFiles', () => {
324
325
  level: PermissionLevel.Full,
325
326
  }),
326
327
  }).create();
327
- const token = await Token.createToken(user);
328
+ const token = await SessionService.createSession(user);
328
329
 
329
330
  // Create a user member
330
331
  const member = MemberWithRegistrationsBlob.create({
@@ -404,7 +405,7 @@ describe('E2E.PrivateFiles', () => {
404
405
  level: PermissionLevel.Full,
405
406
  }),
406
407
  }).create();
407
- const token = await Token.createToken(user);
408
+ const token = await SessionService.createSession(user);
408
409
 
409
410
  // Create a user member
410
411
  const member = MemberWithRegistrationsBlob.create({
@@ -662,7 +663,7 @@ describe('E2E.PrivateFiles', () => {
662
663
  level: PermissionLevel.Full,
663
664
  }),
664
665
  }).create();
665
- const token = await Token.createToken(user);
666
+ const token = await SessionService.createSession(user);
666
667
 
667
668
  // Create a user member
668
669
  const member = MemberWithRegistrationsBlob.create({
@@ -1,6 +1,6 @@
1
1
  import { Request } from '@simonbackx/simple-endpoints';
2
- import type { MemberWithUsersRegistrationsAndGroups, Organization, RegistrationPeriod } from '@stamhoofd/models';
3
- import { BalanceItemFactory, GroupFactory, MemberFactory, OrganizationFactory, OrganizationRegistrationPeriod, Platform, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
2
+ import type { MemberWithUsersRegistrationsAndGroups, Organization, RegistrationPeriod, Token } from '@stamhoofd/models';
3
+ import { BalanceItemFactory, GroupFactory, MemberFactory, OrganizationFactory, OrganizationRegistrationPeriod, Platform, RegistrationPeriodFactory, UserFactory } from '@stamhoofd/models';
4
4
  import { AdministrationFeeSettings, BalanceItemCartItem, BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItemType, BooleanStatus, DefaultAgeGroup, FreeContributionSettings, GroupOption, GroupOptionMenu, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, PaymentMethod, PermissionLevel, Permissions, PlatformMembershipType, PlatformMembershipTypeConfig, ReceivableBalanceType, ReduceablePrice, RegisterItemOption, TranslatedString, Version } from '@stamhoofd/structures';
5
5
  import { TestUtils } from '@stamhoofd/test-utils';
6
6
  import { v4 as uuidv4 } from 'uuid';
@@ -11,6 +11,7 @@ import { BalanceItemService } from '../../src/services/BalanceItemService.js';
11
11
  import { PlatformMembershipService } from '../../src/services/PlatformMembershipService.js';
12
12
  import { assertBalances } from '../assertions/assertBalances.js';
13
13
  import { testServer } from '../helpers/TestServer.js';
14
+ import { SessionService } from '../../src/services/SessionService.js';
14
15
 
15
16
  describe('E2E.Register', () => {
16
17
  const registerEndpoint = new RegisterMembersEndpoint();
@@ -74,7 +75,7 @@ describe('E2E.Register', () => {
74
75
  })
75
76
  .create();
76
77
 
77
- const token = await Token.createToken(user);
78
+ const token = await SessionService.createSession(user);
78
79
 
79
80
  const member = await new MemberFactory({ organization, user }).create();
80
81
 
@@ -1,11 +1,12 @@
1
1
  import type { PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
2
2
  import { PatchableArray } from '@simonbackx/simple-encoding';
3
3
  import { Request } from '@simonbackx/simple-endpoints';
4
- import type { Organization, StripeAccount } from '@stamhoofd/models';
5
- import { Order, OrganizationFactory, Token, UserFactory, Webshop, WebshopFactory } from '@stamhoofd/models';
4
+ import type { Organization, StripeAccount, Token } from '@stamhoofd/models';
5
+ import { Order, OrganizationFactory, UserFactory, Webshop, WebshopFactory } from '@stamhoofd/models';
6
6
  import { Address, Cart, CartItem, CartItemOption, CartReservedSeat, Customer, Option, OptionMenu, OrderData, OrderStatus, PaymentConfiguration, PaymentMethod, PermissionLevel, Permissions, PrivateOrder, PrivatePaymentConfiguration, Product, ProductPrice, ProductType, ReservedSeat, SeatingPlan, SeatingPlanRow, SeatingPlanSeat, SeatingPlanSection, TransferSettings, ValidatedAddress, WebshopDeliveryMethod, WebshopMetaData, WebshopOnSiteMethod, WebshopPrivateMetaData, WebshopTakeoutMethod, WebshopTimeSlot } from '@stamhoofd/structures';
7
7
  import { Country } from '@stamhoofd/types/Country';
8
8
  import { v4 as uuidv4 } from 'uuid';
9
+ import { SessionService } from '../../src/services/SessionService.js';
9
10
 
10
11
  import { PatchWebshopOrdersEndpoint } from '../../src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.js';
11
12
  import { PlaceOrderEndpoint } from '../../src/endpoints/organization/webshops/PlaceOrderEndpoint.js';
@@ -253,7 +254,7 @@ describe('E2E.Stock', () => {
253
254
  level: PermissionLevel.Full,
254
255
  }),
255
256
  }).create();
256
- token = await Token.createToken(user);
257
+ token = await SessionService.createSession(user);
257
258
 
258
259
  await initMembershipOrganization();
259
260
  });
@@ -1,9 +1,10 @@
1
1
  import type { PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
2
2
  import { PatchableArray } from '@simonbackx/simple-encoding';
3
3
  import { Request } from '@simonbackx/simple-endpoints';
4
- import type { Organization, StripeAccount, Webshop } from '@stamhoofd/models';
5
- import { OrganizationFactory, Ticket, Token, UserFactory, WebshopFactory } from '@stamhoofd/models';
4
+ import type { Organization, StripeAccount, Webshop, Token } from '@stamhoofd/models';
5
+ import { OrganizationFactory, Ticket, UserFactory, WebshopFactory } from '@stamhoofd/models';
6
6
  import { Cart, CartItem, CartReservedSeat, Customer, OrderData, OrderStatus, PaymentConfiguration, PaymentMethod, PermissionLevel, Permissions, PrivateOrder, PrivatePaymentConfiguration, Product, ProductType, SeatingPlan, SeatingPlanRow, SeatingPlanSeat, SeatingPlanSection, TransferSettings, WebshopMetaData, WebshopPrivateMetaData, WebshopTicketType } from '@stamhoofd/structures';
7
+ import { SessionService } from '../../src/services/SessionService.js';
7
8
 
8
9
  import { PatchWebshopOrdersEndpoint } from '../../src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.js';
9
10
  import { PlaceOrderEndpoint } from '../../src/endpoints/organization/webshops/PlaceOrderEndpoint.js';
@@ -66,7 +67,7 @@ describe('E2E.Tickets', () => {
66
67
  level: PermissionLevel.Full,
67
68
  }),
68
69
  }).create();
69
- token = await Token.createToken(user);
70
+ token = await SessionService.createSession(user);
70
71
  });
71
72
 
72
73
  afterAll(() => {
@@ -6,6 +6,7 @@ import { ExcelExportType, LimitedFilteredRequest, SortItemDirection } from '@sta
6
6
  import { ExportToExcelEndpoint } from '../../src/endpoints/global/files/ExportToExcelEndpoint.js';
7
7
  import { Context } from '../../src/helpers/Context.js';
8
8
  import { testServer } from './TestServer.js';
9
+ import { SessionService } from '../../src/services/SessionService.js';
9
10
 
10
11
  // Registers the balance item payment export, which is what a row that holds a part of its objects is
11
12
  // written out with
@@ -56,7 +57,7 @@ class ExportSliceEndpoint extends Endpoint<Record<string, never>, undefined, und
56
57
  * How many balance item payments a filter selects, and what they are worth together.
57
58
  */
58
59
  export async function exportSlice({ organization, user, filter, search = null }: { organization: Organization; user: User; filter: StamhoofdFilter; search?: string | null }) {
59
- const token = await Token.createToken(user);
60
+ const token = await SessionService.createSession(user);
60
61
 
61
62
  const request = Request.get({
62
63
  path: '/exports/balance-item-payments',