@stamhoofd/backend 2.73.3 → 2.75.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 (52) hide show
  1. package/index.ts +7 -2
  2. package/package.json +13 -13
  3. package/src/audit-logs/MemberPlatformMembershipLogger.ts +1 -1
  4. package/src/crons/update-cached-balances.ts +1 -2
  5. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +2 -2
  6. package/src/endpoints/auth/CreateAdminEndpoint.ts +4 -15
  7. package/src/endpoints/global/audit-logs/GetAuditLogsEndpoint.ts +2 -2
  8. package/src/endpoints/global/events/GetEventNotificationsCountEndpoint.ts +43 -0
  9. package/src/endpoints/global/events/GetEventNotificationsEndpoint.ts +181 -0
  10. package/src/endpoints/global/events/GetEventsEndpoint.ts +2 -2
  11. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.ts +288 -0
  12. package/src/endpoints/global/events/PatchEventsEndpoint.ts +2 -2
  13. package/src/endpoints/global/files/UploadFile.ts +56 -4
  14. package/src/endpoints/global/files/UploadImage.ts +9 -3
  15. package/src/endpoints/global/members/GetMembersEndpoint.ts +2 -2
  16. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +14 -5
  17. package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +1 -5
  18. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +7 -0
  19. package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +1 -1
  20. package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +1756 -164
  21. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +2 -2
  22. package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +48 -2
  23. package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +2 -2
  24. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +1 -1
  25. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +2 -2
  26. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts +2 -2
  27. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +8 -0
  28. package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +3 -3
  29. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +2 -2
  30. package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +2 -2
  31. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +1 -2
  32. package/src/helpers/AdminPermissionChecker.ts +80 -2
  33. package/src/helpers/AuthenticatedStructures.ts +88 -2
  34. package/src/helpers/FlagMomentCleanup.ts +1 -8
  35. package/src/helpers/GlobalHelper.ts +15 -0
  36. package/src/helpers/MembershipCharger.ts +2 -1
  37. package/src/seeds-temporary/README.md +1 -0
  38. package/src/services/EventNotificationService.ts +201 -0
  39. package/src/services/FileSignService.ts +227 -0
  40. package/src/services/PlatformMembershipService.ts +38 -14
  41. package/src/sql-filters/event-notifications.ts +39 -0
  42. package/src/sql-filters/organizations.ts +1 -1
  43. package/src/sql-sorters/event-notifications.ts +96 -0
  44. package/src/sql-sorters/events.ts +2 -2
  45. package/src/sql-sorters/organizations.ts +2 -2
  46. package/tests/e2e/private-files.test.ts +497 -0
  47. package/tests/e2e/register.test.ts +762 -0
  48. package/tests/helpers/TestServer.ts +3 -0
  49. package/tests/jest.setup.ts +15 -2
  50. package/tsconfig.json +1 -0
  51. /package/src/{seeds → seeds-temporary}/1732117645-move-rrn.ts +0 -0
  52. /package/src/{seeds → seeds-temporary}/1736266448-recall-balance-item-price-paid.ts +0 -0
@@ -1,6 +1,7 @@
1
1
  import { Request } from '@simonbackx/simple-endpoints';
2
- import { Group, GroupFactory, MemberFactory, MemberWithRegistrations, Organization, OrganizationFactory, RegistrationFactory, RegistrationPeriod, RegistrationPeriodFactory, Token, User, UserFactory } from '@stamhoofd/models';
3
- import { GroupPrice, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, PayconiqAccount, PaymentMethod, PermissionLevel, Permissions, Version } from '@stamhoofd/structures';
2
+ import { Email } from '@stamhoofd/email';
3
+ import { BalanceItemFactory, Group, GroupFactory, MemberFactory, MemberWithRegistrations, Organization, OrganizationFactory, Registration, RegistrationFactory, RegistrationPeriod, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
4
+ import { BalanceItemCartItem, BalanceItemType, Company, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, OrganizationPackages, PayconiqAccount, PaymentCustomer, PaymentMethod, PermissionLevel, Permissions, STPackageStatus, STPackageType, UserPermissions, Version } from '@stamhoofd/structures';
4
5
  import nock from 'nock';
5
6
  import { v4 as uuidv4 } from 'uuid';
6
7
  import { testServer } from '../../../../tests/helpers/TestServer';
@@ -12,17 +13,9 @@ describe('Endpoint.RegisterMembers', () => {
12
13
  // #region global
13
14
  const endpoint = new RegisterMembersEndpoint();
14
15
  let period: RegistrationPeriod;
15
- let organization: Organization;
16
- let user: User;
17
- let token: Token;
18
- let member: MemberWithRegistrations;
19
- let group1: Group;
20
- let groupPrice1: GroupPrice;
21
- let group2: Group;
22
- let groupPrice2: GroupPrice;
23
16
 
24
17
  // #region helpers
25
- const post = async (body: IDRegisterCheckout) => {
18
+ const post = async (body: IDRegisterCheckout, organization: Organization, token: Token) => {
26
19
  const request = Request.buildJson('POST', baseUrl, organization.getApiHost(), body);
27
20
  request.headers.authorization = 'Bearer ' + token.accessToken;
28
21
  return await testServer.test(endpoint, request);
@@ -32,54 +25,162 @@ describe('Endpoint.RegisterMembers', () => {
32
25
  // #endregion
33
26
 
34
27
  beforeAll(async () => {
35
- period = await new RegistrationPeriodFactory({}).create();
36
- organization = await new OrganizationFactory({ period }).create();
37
- organization.meta.registrationPaymentConfiguration.paymentMethods = [PaymentMethod.PointOfSale, PaymentMethod.Payconiq];
38
-
39
- organization.privateMeta.payconiqAccounts = [PayconiqAccount.create({
40
- id: uuidv4(),
41
- apiKey: 'test',
42
- merchantId: 'test',
43
- profileId: 'test',
44
- name: 'test',
45
- iban: 'BE56587127952688', // = random IBAN
46
- callbackUrl: 'https://example.com',
47
- })];
48
-
49
- user = await new UserFactory({
28
+ const previousPeriod = await new RegistrationPeriodFactory({
29
+ startDate: new Date(2022, 0, 1),
30
+ endDate: new Date(2022, 11, 31),
31
+ }).create();
32
+
33
+ period = await new RegistrationPeriodFactory({
34
+ startDate: new Date(2023, 0, 1),
35
+ endDate: new Date(2023, 11, 31),
36
+ }).create();
37
+
38
+ period.previousPeriodId = previousPeriod.id;
39
+ await period.save();
40
+ });
41
+
42
+ afterEach(() => {
43
+ jest.restoreAllMocks();
44
+ });
45
+
46
+ const initOrganization = async (registrationPeriod: RegistrationPeriod = period) => {
47
+ return await new OrganizationFactory({ period: registrationPeriod })
48
+ .create();
49
+ };
50
+
51
+ const initData = async ({ otherMemberAmount = 0, permissionLevel = PermissionLevel.Full }: { otherMemberAmount?: number; permissionLevel?: PermissionLevel } = {}) => {
52
+ const organization = await initOrganization(period);
53
+
54
+ const user = await new UserFactory({
50
55
  organization,
51
56
  permissions: Permissions.create({
52
- level: PermissionLevel.Full,
57
+ level: permissionLevel,
53
58
  }),
54
- }).create();
55
- token = await Token.createToken(user);
56
- member = await new MemberFactory({ organization, user }).create();
57
- });
59
+ })
60
+ .create();
58
61
 
59
- beforeEach(async () => {
60
- // #region groups
61
- group1 = await new GroupFactory({
62
+ const token = await Token.createToken(user);
63
+
64
+ const member = await new MemberFactory({ organization, user })
65
+ .create();
66
+
67
+ const otherMembers: MemberWithRegistrations[] = [];
68
+
69
+ for (let i = 0; i < otherMemberAmount; i++) {
70
+ otherMembers.push(await new MemberFactory({ organization, user })
71
+ .create());
72
+ }
73
+
74
+ const group = await new GroupFactory({
62
75
  organization,
63
76
  price: 25,
64
77
  stock: 5,
65
- }).create();
78
+ })
79
+ .create();
66
80
 
67
- groupPrice1 = group1.settings.prices[0];
81
+ const groupPrice = group.settings.prices[0];
68
82
 
69
- group2 = await new GroupFactory({
83
+ return {
70
84
  organization,
71
- price: 15,
72
- stock: 4,
73
- maxMembers: 1,
74
- }).create();
85
+ user,
86
+ token,
87
+ member,
88
+ otherMembers,
89
+ group,
90
+ groupPrice,
91
+ };
92
+ };
75
93
 
76
- groupPrice2 = group2.settings.prices[0];
77
- // #endregion
78
- });
94
+ describe('Register', () => {
95
+ test('Should fail if cannot manage finances', async () => {
96
+ // #region arrange
97
+ const { member, group, groupPrice, organization, token } = await initData();
98
+ const organization2 = await initOrganization();
99
+
100
+ const registration = await new RegistrationFactory({
101
+ member,
102
+ group,
103
+ groupPrice,
104
+ }).create();
105
+
106
+ const body = IDRegisterCheckout.create({
107
+ cart: IDRegisterCart.create({
108
+ items: [
109
+ IDRegisterItem.create({
110
+ id: uuidv4(),
111
+ replaceRegistrationIds: [],
112
+ options: [],
113
+ groupPrice,
114
+ organizationId: organization.id,
115
+ groupId: group.id,
116
+ memberId: member.id,
117
+ }),
118
+ ],
119
+ balanceItems: [],
120
+ deleteRegistrationIds: [registration.id],
121
+ }),
122
+ administrationFee: 0,
123
+ freeContribution: 0,
124
+ paymentMethod: PaymentMethod.PointOfSale,
125
+ totalPrice: 5,
126
+ asOrganizationId: organization2.id,
127
+ customer: null,
128
+ });
129
+ // #endregion
130
+
131
+ // #region act and assert
132
+ await expect(async () => await post(body, organization, token))
133
+ .rejects
134
+ .toThrow('No permission to register as this organization for a different organization');
135
+ // #endregion
136
+ });
79
137
 
80
- describe('Register member', () => {
81
- test('Should update registered mmebers', async () => {
138
+ test('Should fail if demo limit reached', async () => {
82
139
  // #region arrange
140
+ (STAMHOOFD.userMode as string) = 'organization';
141
+
142
+ const spySendWebmaster = jest.spyOn(Email, 'sendWebmaster').mockImplementation(() => {
143
+ // do nothing
144
+ });
145
+
146
+ const { member, group, groupPrice, organization, token, otherMembers } = await initData({ otherMemberAmount: 10 });
147
+
148
+ organization.meta.packages = OrganizationPackages.create({
149
+ packages: new Map([
150
+ [STPackageType.TrialMembers, STPackageStatus.create({
151
+ startDate: new Date(),
152
+ })],
153
+ ]),
154
+ });
155
+
156
+ for (const member of otherMembers) {
157
+ const body = IDRegisterCheckout.create({
158
+ cart: IDRegisterCart.create({
159
+ items: [
160
+ IDRegisterItem.create({
161
+ id: uuidv4(),
162
+ replaceRegistrationIds: [],
163
+ options: [],
164
+ groupPrice,
165
+ organizationId: organization.id,
166
+ groupId: group.id,
167
+ memberId: member.id,
168
+ }),
169
+ ],
170
+ balanceItems: [],
171
+ deleteRegistrationIds: [],
172
+ }),
173
+ administrationFee: 0,
174
+ freeContribution: 0,
175
+ paymentMethod: PaymentMethod.PointOfSale,
176
+ totalPrice: 25,
177
+ asOrganizationId: organization.id,
178
+ customer: null,
179
+ });
180
+
181
+ await post(body, organization, token);
182
+ }
183
+
83
184
  const body = IDRegisterCheckout.create({
84
185
  cart: IDRegisterCart.create({
85
186
  items: [
@@ -87,9 +188,9 @@ describe('Endpoint.RegisterMembers', () => {
87
188
  id: uuidv4(),
88
189
  replaceRegistrationIds: [],
89
190
  options: [],
90
- groupPrice: groupPrice1,
191
+ groupPrice,
91
192
  organizationId: organization.id,
92
- groupId: group1.id,
193
+ groupId: group.id,
93
194
  memberId: member.id,
94
195
  }),
95
196
  ],
@@ -105,30 +206,1337 @@ describe('Endpoint.RegisterMembers', () => {
105
206
  });
106
207
  // #endregion
107
208
 
108
- // act
109
- const response = await post(body);
209
+ // #region act and assert
110
210
 
111
- // assert
112
- expect(response.body).toBeDefined();
113
- expect(response.body.registrations.length).toBe(1);
211
+ await expect(async () => await post(body, organization, token))
212
+ .rejects
213
+ .toThrow('Too many e-mails limited');
214
+
215
+ expect(spySendWebmaster).toHaveBeenCalledOnce();
216
+ // #endregion
217
+
218
+ (STAMHOOFD.userMode as string) = 'platform';
219
+ });
220
+
221
+ test('Should fail if balance items changed', async () => {
222
+ // #region arrange
223
+ const { member, group, user, groupPrice, organization, token } = await initData();
224
+
225
+ const balanceItem1 = await new BalanceItemFactory({
226
+ organizationId: organization.id,
227
+ memberId: member.id,
228
+ userId: user.id,
229
+ payingOrganizationId: organization.id,
230
+ type: BalanceItemType.Registration,
231
+ amount: 10,
232
+ unitPrice: 2,
233
+ }).create();
234
+
235
+ const cartItem = BalanceItemCartItem.create({
236
+ item: balanceItem1.getStructure(),
237
+ price: 20,
238
+ });
239
+
240
+ const body = IDRegisterCheckout.create({
241
+ cart: IDRegisterCart.create({
242
+ items: [
243
+ IDRegisterItem.create({
244
+ id: uuidv4(),
245
+ replaceRegistrationIds: [],
246
+ options: [],
247
+ groupPrice,
248
+ organizationId: organization.id,
249
+ groupId: group.id,
250
+ memberId: member.id,
251
+ }),
252
+ ],
253
+ balanceItems: [
254
+ cartItem,
255
+ ],
256
+ deleteRegistrationIds: [],
257
+ }),
258
+ administrationFee: 0,
259
+ freeContribution: 0,
260
+ paymentMethod: PaymentMethod.PointOfSale,
261
+ totalPrice: 45,
262
+ customer: null,
263
+ });
264
+ // #endregion
265
+
266
+ // #region act and assert
267
+ await balanceItem1.delete();
268
+
269
+ await expect(async () => await post(body, organization, token))
270
+ .rejects
271
+ .toThrow(new RegExp('Oeps, één of meerdere openstaande bedragen in jouw winkelmandje zijn aangepast'));
272
+ // #endregion
273
+ });
274
+
275
+ test('Should fail when pay balance item as organization', async () => {
276
+ // #region arrange
277
+ const { member, group, user, groupPrice, organization, token } = await initData();
278
+
279
+ const balanceItem1 = await new BalanceItemFactory({
280
+ organizationId: organization.id,
281
+ memberId: member.id,
282
+ userId: user.id,
283
+ payingOrganizationId: organization.id,
284
+ type: BalanceItemType.Registration,
285
+ amount: 10,
286
+ unitPrice: 2,
287
+ }).create();
288
+
289
+ const cartItem = BalanceItemCartItem.create({
290
+ item: balanceItem1.getStructure(),
291
+ price: 20,
292
+ });
293
+
294
+ const body = IDRegisterCheckout.create({
295
+ cart: IDRegisterCart.create({
296
+ items: [
297
+ IDRegisterItem.create({
298
+ id: uuidv4(),
299
+ replaceRegistrationIds: [],
300
+ options: [],
301
+ groupPrice,
302
+ organizationId: organization.id,
303
+ groupId: group.id,
304
+ memberId: member.id,
305
+ }),
306
+ ],
307
+ balanceItems: [
308
+ cartItem,
309
+ ],
310
+ deleteRegistrationIds: [],
311
+ }),
312
+ administrationFee: 0,
313
+ freeContribution: 0,
314
+ paymentMethod: PaymentMethod.PointOfSale,
315
+ totalPrice: 45,
316
+ asOrganizationId: organization.id,
317
+ customer: null,
318
+ });
319
+ // #endregion
320
+
321
+ // #region act and assert
322
+ await expect(async () => await post(body, organization, token))
323
+ .rejects
324
+ .toThrow(new RegExp('Not possible to pay balance items as the organization'));
325
+ // #endregion
326
+ });
327
+
328
+ test('Should fail if has no write access for member', async () => {
329
+ // #region arrange
330
+ const { organization, group, groupPrice, token } = await initData();
331
+ const { member: member2 } = await initData();
332
+
333
+ const body = IDRegisterCheckout.create({
334
+ cart: IDRegisterCart.create({
335
+ items: [
336
+ IDRegisterItem.create({
337
+ id: uuidv4(),
338
+ replaceRegistrationIds: [],
339
+ options: [],
340
+ groupPrice,
341
+ organizationId: organization.id,
342
+ groupId: group.id,
343
+ memberId: member2.id,
344
+ }),
345
+ ],
346
+ balanceItems: [
347
+ ],
348
+ deleteRegistrationIds: [],
349
+ }),
350
+ administrationFee: 0,
351
+ freeContribution: 0,
352
+ paymentMethod: PaymentMethod.PointOfSale,
353
+ totalPrice: 25,
354
+ customer: null,
355
+ });
356
+ // #endregion
357
+
358
+ // #region act and assert
359
+ await expect(async () => await post(body, organization, token))
360
+ .rejects
361
+ .toThrow(new RegExp('No permission to register this member'));
362
+ // #endregion
363
+ });
364
+
365
+ test('Should fail if empty cart', async () => {
366
+ // #region arrange
367
+ const { member, user, organization, token } = await initData();
368
+
369
+ const balanceItem1 = await new BalanceItemFactory({
370
+ organizationId: organization.id,
371
+ memberId: member.id,
372
+ userId: user.id,
373
+ payingOrganizationId: organization.id,
374
+ type: BalanceItemType.Registration,
375
+ amount: 10,
376
+ unitPrice: 2,
377
+ }).create();
378
+
379
+ const body = IDRegisterCheckout.create({
380
+ cart: IDRegisterCart.create({
381
+ items: [
382
+ ],
383
+ balanceItems: [
384
+ ],
385
+ deleteRegistrationIds: [],
386
+ }),
387
+ administrationFee: 0,
388
+ freeContribution: 0,
389
+ paymentMethod: PaymentMethod.PointOfSale,
390
+ totalPrice: 45,
391
+ customer: null,
392
+ });
393
+ // #endregion
394
+
395
+ // #region act and assert
396
+ await balanceItem1.delete();
397
+
398
+ await expect(async () => await post(body, organization, token))
399
+ .rejects
400
+ .toThrow(new RegExp('Oeps, jouw mandje is leeg.'));
401
+ // #endregion
402
+ });
403
+
404
+ test('Should fail if price changed', async () => {
405
+ // #region arrange
406
+ const { member, group, groupPrice, organization, token } = await initData();
407
+
408
+ const body = IDRegisterCheckout.create({
409
+ cart: IDRegisterCart.create({
410
+ items: [
411
+ IDRegisterItem.create({
412
+ id: uuidv4(),
413
+ replaceRegistrationIds: [],
414
+ options: [],
415
+ groupPrice,
416
+ organizationId: organization.id,
417
+ groupId: group.id,
418
+ memberId: member.id,
419
+ }),
420
+ ],
421
+ deleteRegistrationIds: [],
422
+ }),
423
+ administrationFee: 0,
424
+ freeContribution: 0,
425
+ paymentMethod: PaymentMethod.PointOfSale,
426
+ totalPrice: 30,
427
+ asOrganizationId: organization.id,
428
+ customer: null,
429
+ });
430
+ // #endregion
431
+
432
+ // #region act and assert
433
+
434
+ await expect(async () => await post(body, organization, token))
435
+ .rejects
436
+ .toThrow(new RegExp('Oeps! De prijs is gewijzigd terwijl je aan het afrekenen was'));
437
+ // #endregion
438
+ });
439
+
440
+ test('Should fail if member is already registered', async () => {
441
+ // #region arrange
442
+ const { organization, group, groupPrice, token, member } = await initData();
443
+
444
+ const body = IDRegisterCheckout.create({
445
+ cart: IDRegisterCart.create({
446
+ items: [
447
+ IDRegisterItem.create({
448
+ id: uuidv4(),
449
+ replaceRegistrationIds: [],
450
+ options: [],
451
+ groupPrice,
452
+ organizationId: organization.id,
453
+ groupId: group.id,
454
+ memberId: member.id,
455
+ }),
456
+ ],
457
+ balanceItems: [
458
+ ],
459
+ deleteRegistrationIds: [],
460
+ }),
461
+ administrationFee: 0,
462
+ freeContribution: 0,
463
+ paymentMethod: PaymentMethod.PointOfSale,
464
+ totalPrice: 25,
465
+ customer: null,
466
+ });
467
+ // #endregion
468
+
469
+ // #region act and assert
470
+ // register first time
471
+ await post(body, organization, token);
472
+
473
+ // second time should fail
474
+ await expect(async () => await post(body, organization, token))
475
+ .rejects
476
+ .toThrow(new RegExp('Already registered'));
477
+ // #endregion
478
+ });
479
+
480
+ test('Should fail if duplicate registration in cart', async () => {
481
+ // #region arrange
482
+ const { organization, group, groupPrice, token, member } = await initData();
483
+
484
+ const body = IDRegisterCheckout.create({
485
+ cart: IDRegisterCart.create({
486
+ items: [
487
+ IDRegisterItem.create({
488
+ id: uuidv4(),
489
+ replaceRegistrationIds: [],
490
+ options: [],
491
+ groupPrice,
492
+ organizationId: organization.id,
493
+ groupId: group.id,
494
+ memberId: member.id,
495
+ }),
496
+ IDRegisterItem.create({
497
+ id: uuidv4(),
498
+ replaceRegistrationIds: [],
499
+ options: [],
500
+ groupPrice,
501
+ organizationId: organization.id,
502
+ groupId: group.id,
503
+ memberId: member.id,
504
+ }),
505
+ ],
506
+ balanceItems: [
507
+ ],
508
+ deleteRegistrationIds: [],
509
+ }),
510
+ administrationFee: 0,
511
+ freeContribution: 0,
512
+ paymentMethod: PaymentMethod.PointOfSale,
513
+ totalPrice: 50,
514
+ customer: null,
515
+ });
516
+ // #endregion
517
+
518
+ // #region act and assert
519
+ await expect(async () => await post(body, organization, token))
520
+ .rejects
521
+ .toThrow(new RegExp('duplicate_register_item'));
522
+ // #endregion
523
+ });
524
+
525
+ test('Should fail register by other organization if disabled by group', async () => {
526
+ // #region arrange
527
+ const { organization, group, groupPrice, token, member, user } = await initData();
528
+
529
+ const { organization: organization2 } = await initData();
530
+
531
+ user.permissions = UserPermissions.create({
532
+ organizationPermissions: new Map([
533
+ [organization2.id, Permissions.create({
534
+ level: PermissionLevel.Full,
535
+ })],
536
+ ]),
537
+ });
538
+
539
+ await user.save();
540
+
541
+ const body = IDRegisterCheckout.create({
542
+ cart: IDRegisterCart.create({
543
+ items: [
544
+ IDRegisterItem.create({
545
+ id: uuidv4(),
546
+ replaceRegistrationIds: [],
547
+ options: [],
548
+ groupPrice,
549
+ organizationId: organization.id,
550
+ groupId: group.id,
551
+ memberId: member.id,
552
+ }),
553
+ ],
554
+ balanceItems: [
555
+ ],
556
+ deleteRegistrationIds: [],
557
+ }),
558
+ administrationFee: 0,
559
+ freeContribution: 0,
560
+ paymentMethod: PaymentMethod.PointOfSale,
561
+ totalPrice: 25,
562
+ customer: null,
563
+ asOrganizationId: organization2.id,
564
+ });
565
+ // #endregion
566
+
567
+ // #region act and assert
568
+ await expect(async () => await post(body, organization, token))
569
+ .rejects
570
+ .toThrow(new RegExp('allowRegistrationsByOrganization disabled'));
571
+ // #endregion
572
+ });
573
+
574
+ test('Should fail if invalid payment', async () => {
575
+ // #region arrange
576
+ const { organization, group, groupPrice, token, member } = await initData();
577
+
578
+ const body = IDRegisterCheckout.create({
579
+ cart: IDRegisterCart.create({
580
+ items: [
581
+ IDRegisterItem.create({
582
+ id: uuidv4(),
583
+ replaceRegistrationIds: [],
584
+ options: [],
585
+ groupPrice,
586
+ organizationId: organization.id,
587
+ groupId: group.id,
588
+ memberId: member.id,
589
+ }),
590
+ ],
591
+ balanceItems: [
592
+ ],
593
+ deleteRegistrationIds: [],
594
+ }),
595
+ administrationFee: 0,
596
+ freeContribution: 0,
597
+ paymentMethod: PaymentMethod.CreditCard,
598
+ totalPrice: 25,
599
+ customer: null,
600
+ });
601
+ // #endregion
602
+
603
+ // #region act and assert
604
+ await expect(async () => await post(body, organization, token))
605
+ .rejects
606
+ .toThrow(new RegExp('Oeps, je hebt geen geldige betaalmethode geselecteerd'));
607
+ // #endregion
608
+ });
609
+
610
+ test('Should fail if no redirect url for online payment', async () => {
611
+ // #region arrange
612
+ const { organization, group, groupPrice, token, member } = await initData();
613
+ organization.meta.registrationPaymentConfiguration.paymentMethods.push(PaymentMethod.Bancontact);
614
+ await organization.save();
615
+
616
+ const body = IDRegisterCheckout.create({
617
+ cart: IDRegisterCart.create({
618
+ items: [
619
+ IDRegisterItem.create({
620
+ id: uuidv4(),
621
+ replaceRegistrationIds: [],
622
+ options: [],
623
+ groupPrice,
624
+ organizationId: organization.id,
625
+ groupId: group.id,
626
+ memberId: member.id,
627
+ }),
628
+ ],
629
+ balanceItems: [
630
+ ],
631
+ deleteRegistrationIds: [],
632
+ }),
633
+ administrationFee: 0,
634
+ freeContribution: 0,
635
+ paymentMethod: PaymentMethod.Bancontact,
636
+ totalPrice: 25,
637
+ cancelUrl: new URL('https://www.stamhoofd.be'),
638
+ customer: null,
639
+ });
640
+ // #endregion
641
+
642
+ // #region act and assert
643
+ await expect(async () => await post(body, organization, token))
644
+ .rejects
645
+ .toThrow(new RegExp('redirectUrl or cancelUrl is missing'));
646
+ // #endregion
647
+ });
648
+
649
+ test('Should fail if no cancel url for online payment', async () => {
650
+ // #region arrange
651
+ const { organization, group, groupPrice, token, member } = await initData();
652
+ organization.meta.registrationPaymentConfiguration.paymentMethods.push(PaymentMethod.Bancontact);
653
+ await organization.save();
654
+
655
+ const body = IDRegisterCheckout.create({
656
+ cart: IDRegisterCart.create({
657
+ items: [
658
+ IDRegisterItem.create({
659
+ id: uuidv4(),
660
+ replaceRegistrationIds: [],
661
+ options: [],
662
+ groupPrice,
663
+ organizationId: organization.id,
664
+ groupId: group.id,
665
+ memberId: member.id,
666
+ }),
667
+ ],
668
+ balanceItems: [
669
+ ],
670
+ deleteRegistrationIds: [],
671
+ }),
672
+ administrationFee: 0,
673
+ freeContribution: 0,
674
+ paymentMethod: PaymentMethod.Bancontact,
675
+ totalPrice: 25,
676
+ redirectUrl: new URL('https://www.stamhoofd.be'),
677
+ customer: null,
678
+ });
679
+ // #endregion
680
+
681
+ // #region act and assert
682
+ await expect(async () => await post(body, organization, token))
683
+ .rejects
684
+ .toThrow(new RegExp('redirectUrl or cancelUrl is missing'));
685
+ // #endregion
686
+ });
687
+
688
+ test('Should reserve if group has max members', async () => {
689
+ // #region arrange
690
+ const { organization, group, groupPrice, token, member } = await initData();
691
+ group.settings.maxMembers = 5;
692
+ await group.save();
693
+
694
+ const body = IDRegisterCheckout.create({
695
+ cart: IDRegisterCart.create({
696
+ items: [
697
+ IDRegisterItem.create({
698
+ id: uuidv4(),
699
+ replaceRegistrationIds: [],
700
+ options: [],
701
+ groupPrice,
702
+ organizationId: organization.id,
703
+ groupId: group.id,
704
+ memberId: member.id,
705
+ }),
706
+ ],
707
+ balanceItems: [
708
+ ],
709
+ deleteRegistrationIds: [],
710
+ }),
711
+ administrationFee: 0,
712
+ freeContribution: 0,
713
+ paymentMethod: PaymentMethod.PointOfSale,
714
+ totalPrice: 25,
715
+ });
716
+ // #endregion
717
+
718
+ // #region act and assert
719
+ const response = await post(body, organization, token);
720
+ expect(response.body.registrations.length).toBe(1);
721
+ expect(response.body.registrations[0].reservedUntil).not.toBeNull();
722
+ // #endregion
723
+ });
724
+
725
+ test('Should reuse existing registration', async () => {
726
+ // #region arrange
727
+ const { organization, group, groupPrice, token, member, user } = await initData();
728
+ group.settings.allowRegistrationsByOrganization = true;
729
+ await group.save();
730
+
731
+ user.permissions = UserPermissions.create({
732
+ organizationPermissions: new Map([
733
+ [organization.id, Permissions.create({
734
+ level: PermissionLevel.Full,
735
+ })],
736
+ ]),
737
+ });
738
+
739
+ await user.save();
740
+
741
+ const group2 = await new GroupFactory({
742
+ organization,
743
+ price: 25,
744
+ stock: 5,
745
+ }).create();
746
+
747
+ const firstRegistration = await new RegistrationFactory({
748
+ member,
749
+ group: group2,
750
+ groupPrice: group2.settings.prices[0],
751
+ }).create();
752
+
753
+ const body = IDRegisterCheckout.create({
754
+ cart: IDRegisterCart.create({
755
+ items: [
756
+ IDRegisterItem.create({
757
+ id: uuidv4(),
758
+ replaceRegistrationIds: [firstRegistration.id],
759
+ options: [],
760
+ groupPrice,
761
+ organizationId: organization.id,
762
+ groupId: group.id,
763
+ memberId: member.id,
764
+ }),
765
+ ],
766
+ balanceItems: [
767
+ ],
768
+ deleteRegistrationIds: [],
769
+ }),
770
+ administrationFee: 0,
771
+ freeContribution: 0,
772
+ paymentMethod: PaymentMethod.PointOfSale,
773
+ totalPrice: 0,
774
+ asOrganizationId: organization.id,
775
+ });
776
+
777
+ // #endregion
778
+
779
+ // #region act and assert
780
+ const response = await post(body, organization, token);
781
+ expect(response.body.registrations.length).toBe(1);
782
+ expect(response.body.registrations[0].id).toEqual(firstRegistration.id);
783
+ // #endregion
784
+ });
785
+
786
+ test('Should reuse recently deactivated registration', async () => {
787
+ // #region arrange
788
+ const { organization, group, groupPrice, token, member, user } = await initData();
789
+ group.settings.allowRegistrationsByOrganization = true;
790
+ await group.save();
791
+
792
+ user.permissions = UserPermissions.create({
793
+ organizationPermissions: new Map([
794
+ [organization.id, Permissions.create({
795
+ level: PermissionLevel.Full,
796
+ })],
797
+ ]),
798
+ });
799
+
800
+ await user.save();
801
+
802
+ const firstRegistration = await new RegistrationFactory({
803
+ member,
804
+ group,
805
+ groupPrice,
806
+ }).create();
807
+
808
+ firstRegistration.deactivatedAt = new Date();
809
+ await firstRegistration.save();
810
+
811
+ const body = IDRegisterCheckout.create({
812
+ cart: IDRegisterCart.create({
813
+ items: [
814
+ IDRegisterItem.create({
815
+ id: uuidv4(),
816
+ replaceRegistrationIds: [],
817
+ options: [],
818
+ groupPrice,
819
+ organizationId: organization.id,
820
+ groupId: group.id,
821
+ memberId: member.id,
822
+ }),
823
+ ],
824
+ balanceItems: [
825
+ ],
826
+ deleteRegistrationIds: [],
827
+ }),
828
+ administrationFee: 0,
829
+ freeContribution: 0,
830
+ paymentMethod: PaymentMethod.PointOfSale,
831
+ totalPrice: 25,
832
+ asOrganizationId: organization.id,
833
+ });
834
+
835
+ // #endregion
836
+
837
+ // #region act and assert
838
+ const response = await post(body, organization, token);
839
+ expect(response.body.registrations.length).toBe(1);
840
+ expect(response.body.registrations[0].id).toEqual(firstRegistration.id);
841
+ // #endregion
842
+ });
843
+
844
+ test('Should update registered members', async () => {
845
+ // #region arrange
846
+ const { member, group, groupPrice, organization, token } = await initData();
847
+
848
+ const body = IDRegisterCheckout.create({
849
+ cart: IDRegisterCart.create({
850
+ items: [
851
+ IDRegisterItem.create({
852
+ id: uuidv4(),
853
+ replaceRegistrationIds: [],
854
+ options: [],
855
+ groupPrice,
856
+ organizationId: organization.id,
857
+ groupId: group.id,
858
+ memberId: member.id,
859
+ }),
860
+ ],
861
+ balanceItems: [],
862
+ deleteRegistrationIds: [],
863
+ }),
864
+ administrationFee: 0,
865
+ freeContribution: 0,
866
+ paymentMethod: PaymentMethod.PointOfSale,
867
+ totalPrice: 25,
868
+ asOrganizationId: organization.id,
869
+ customer: null,
870
+ });
871
+ // #endregion
872
+
873
+ // act
874
+ const response = await post(body, organization, token);
875
+
876
+ // assert
877
+ expect(response.body).toBeDefined();
878
+ expect(response.body.registrations.length).toBe(1);
879
+
880
+ const updatedGroup = await Group.getByID(group.id);
881
+ expect(updatedGroup!.settings.registeredMembers).toBe(1);
882
+ expect(updatedGroup!.settings.reservedMembers).toBe(0);
883
+ });
884
+
885
+ test('Should update reserved members', async () => {
886
+ // #region arrange
887
+ const { member, organization, token } = await initData();
888
+
889
+ organization.meta.registrationPaymentConfiguration.paymentMethods = [PaymentMethod.PointOfSale, PaymentMethod.Payconiq];
890
+
891
+ organization.privateMeta.payconiqAccounts = [PayconiqAccount.create({
892
+ id: uuidv4(),
893
+ apiKey: 'testKey',
894
+ merchantId: 'test',
895
+ profileId: 'test',
896
+ name: 'test',
897
+ iban: 'BE56587127952688', // = random IBAN
898
+ callbackUrl: 'https://www.example.com',
899
+ })];
900
+
901
+ await organization.save();
902
+
903
+ const group2 = await new GroupFactory({
904
+ organization,
905
+ price: 15,
906
+ stock: 4,
907
+ maxMembers: 1,
908
+ }).create();
909
+
910
+ const groupPrice2 = group2.settings.prices[0];
911
+
912
+ const body = IDRegisterCheckout.create({
913
+ cart: IDRegisterCart.create({
914
+ items: [
915
+ IDRegisterItem.create({
916
+ id: uuidv4(),
917
+ replaceRegistrationIds: [],
918
+ options: [],
919
+ groupPrice: groupPrice2,
920
+ organizationId: organization.id,
921
+ groupId: group2.id,
922
+ memberId: member.id,
923
+ }),
924
+ ],
925
+ balanceItems: [],
926
+ deleteRegistrationIds: [],
927
+ }),
928
+ administrationFee: 0,
929
+ freeContribution: 0,
930
+ paymentMethod: PaymentMethod.Payconiq,
931
+ redirectUrl: new URL('https://www.example.com'),
932
+ cancelUrl: new URL('https://www.example.com'),
933
+ totalPrice: 15,
934
+ customer: null,
935
+ });
936
+
937
+ nock('https://api.ext.payconiq.com')
938
+ .post('/v3/payments')
939
+ .reply(200, {
940
+ paymentId: 'testPaymentId',
941
+ _links: {
942
+ checkout: {
943
+ href: 'https://www.example.com',
944
+ },
945
+ },
946
+ });
947
+ // #endregion
948
+
949
+ // act
950
+ const response = await post(body, organization, token);
951
+
952
+ // assert
953
+ expect(response.body).toBeDefined();
954
+ expect(response.body.registrations.length).toBe(1);
955
+
956
+ const updatedGroup = await Group.getByID(group2.id);
957
+ expect(updatedGroup!.settings.registeredMembers).toBe(0);
958
+ expect(updatedGroup!.settings.reservedMembers).toBe(1);
959
+ });
960
+
961
+ test('Register for group with trial should set trail period', async () => {
962
+ // #region arrange
963
+ const date = new Date('2023-05-14');
964
+ jest.useFakeTimers().setSystemTime(date);
965
+
966
+ try {
967
+ const { member, group, groupPrice, organization, token } = await initData();
968
+ group.settings.trialDays = 5;
969
+ await group.save();
970
+
971
+ const body = IDRegisterCheckout.create({
972
+ cart: IDRegisterCart.create({
973
+ items: [
974
+ IDRegisterItem.create({
975
+ id: uuidv4(),
976
+ replaceRegistrationIds: [],
977
+ options: [],
978
+ groupPrice: groupPrice,
979
+ organizationId: organization.id,
980
+ groupId: group.id,
981
+ memberId: member.id,
982
+ trial: true,
983
+ }),
984
+ ],
985
+ balanceItems: [],
986
+ deleteRegistrationIds: [],
987
+ }),
988
+ administrationFee: 0,
989
+ freeContribution: 0,
990
+ paymentMethod: PaymentMethod.PointOfSale,
991
+ totalPrice: 0,
992
+ asOrganizationId: organization.id,
993
+ customer: null,
994
+ });
995
+ // #endregion
996
+
997
+ // act
998
+ const response = await post(body, organization, token);
999
+
1000
+ // assert
1001
+ expect(response.body).toBeDefined();
1002
+ expect(response.body.registrations.length).toBe(1);
1003
+ const trialUntil = response.body.registrations[0].trialUntil;
1004
+ expect(trialUntil).not.toBeNull();
1005
+ // 2023-05-14
1006
+ expect(trialUntil!.getFullYear()).toBe(2023);
1007
+ expect(trialUntil!.getMonth()).toBe(4);
1008
+ expect(trialUntil!.getDate()).toBe(19);
1009
+ }
1010
+ finally {
1011
+ jest.useFakeTimers().resetAllMocks();
1012
+ }
1013
+ });
1014
+ });
1015
+
1016
+ describe('Register by other organization', () => {
1017
+ test('Should fail if disabled by group', async () => {
1018
+ // #region arrange
1019
+ const { organization, group, groupPrice, token, member, user } = await initData();
1020
+
1021
+ const { organization: organization2 } = await initData();
1022
+
1023
+ user.permissions = UserPermissions.create({
1024
+ organizationPermissions: new Map([
1025
+ [organization2.id, Permissions.create({
1026
+ level: PermissionLevel.Full,
1027
+ })],
1028
+ ]),
1029
+ });
1030
+
1031
+ await user.save();
1032
+
1033
+ const body = IDRegisterCheckout.create({
1034
+ cart: IDRegisterCart.create({
1035
+ items: [
1036
+ IDRegisterItem.create({
1037
+ id: uuidv4(),
1038
+ replaceRegistrationIds: [],
1039
+ options: [],
1040
+ groupPrice,
1041
+ organizationId: organization.id,
1042
+ groupId: group.id,
1043
+ memberId: member.id,
1044
+ }),
1045
+ ],
1046
+ balanceItems: [
1047
+ ],
1048
+ deleteRegistrationIds: [],
1049
+ }),
1050
+ administrationFee: 0,
1051
+ freeContribution: 0,
1052
+ paymentMethod: PaymentMethod.PointOfSale,
1053
+ totalPrice: 25,
1054
+ customer: null,
1055
+ asOrganizationId: organization2.id,
1056
+ });
1057
+ // #endregion
1058
+
1059
+ // #region act and assert
1060
+ await expect(async () => await post(body, organization, token))
1061
+ .rejects
1062
+ .toThrow(new RegExp('allowRegistrationsByOrganization disabled'));
1063
+ // #endregion
1064
+ });
1065
+
1066
+ test('Should fail if no customer', async () => {
1067
+ // #region arrange
1068
+ const { organization, group, groupPrice, token, member, user } = await initData();
1069
+ group.settings.allowRegistrationsByOrganization = true;
1070
+ await group.save();
1071
+
1072
+ const { organization: organization2 } = await initData();
1073
+
1074
+ user.permissions = UserPermissions.create({
1075
+ organizationPermissions: new Map([
1076
+ [organization2.id, Permissions.create({
1077
+ level: PermissionLevel.Full,
1078
+ })],
1079
+ ]),
1080
+ });
1081
+
1082
+ await user.save();
1083
+
1084
+ const body = IDRegisterCheckout.create({
1085
+ cart: IDRegisterCart.create({
1086
+ items: [
1087
+ IDRegisterItem.create({
1088
+ id: uuidv4(),
1089
+ replaceRegistrationIds: [],
1090
+ options: [],
1091
+ groupPrice,
1092
+ organizationId: organization.id,
1093
+ groupId: group.id,
1094
+ memberId: member.id,
1095
+ }),
1096
+ ],
1097
+ balanceItems: [
1098
+ ],
1099
+ deleteRegistrationIds: [],
1100
+ }),
1101
+ administrationFee: 0,
1102
+ freeContribution: 0,
1103
+ paymentMethod: PaymentMethod.PointOfSale,
1104
+ totalPrice: 25,
1105
+ customer: null,
1106
+ asOrganizationId: organization2.id,
1107
+ });
1108
+ // #endregion
1109
+
1110
+ // #region act and assert
1111
+ await expect(async () => await post(body, organization, token))
1112
+ .rejects
1113
+ .toThrow(new RegExp('customer is required when paying as an organization'));
1114
+ // #endregion
1115
+ });
1116
+
1117
+ test('Should fail if no company on customer', async () => {
1118
+ // #region arrange
1119
+ const { organization, group, groupPrice, token, member, user } = await initData();
1120
+ group.settings.allowRegistrationsByOrganization = true;
1121
+ await group.save();
1122
+
1123
+ const { organization: organization2 } = await initData();
1124
+
1125
+ user.permissions = UserPermissions.create({
1126
+ organizationPermissions: new Map([
1127
+ [organization2.id, Permissions.create({
1128
+ level: PermissionLevel.Full,
1129
+ })],
1130
+ ]),
1131
+ });
1132
+
1133
+ await user.save();
1134
+
1135
+ const body = IDRegisterCheckout.create({
1136
+ cart: IDRegisterCart.create({
1137
+ items: [
1138
+ IDRegisterItem.create({
1139
+ id: uuidv4(),
1140
+ replaceRegistrationIds: [],
1141
+ options: [],
1142
+ groupPrice,
1143
+ organizationId: organization.id,
1144
+ groupId: group.id,
1145
+ memberId: member.id,
1146
+ }),
1147
+ ],
1148
+ balanceItems: [
1149
+ ],
1150
+ deleteRegistrationIds: [],
1151
+ }),
1152
+ administrationFee: 0,
1153
+ freeContribution: 0,
1154
+ paymentMethod: PaymentMethod.PointOfSale,
1155
+ totalPrice: 25,
1156
+ customer: PaymentCustomer.create({
1157
+ company: null,
1158
+ }),
1159
+ asOrganizationId: organization2.id,
1160
+ });
1161
+ // #endregion
1162
+
1163
+ // #region act and assert
1164
+ await expect(async () => await post(body, organization, token))
1165
+ .rejects
1166
+ .toThrow(new RegExp('customer.company is required'));
1167
+ // #endregion
1168
+ });
1169
+
1170
+ test('Should fail if company does not exist on organization', async () => {
1171
+ // #region arrange
1172
+ const { organization, group, groupPrice, token, member, user } = await initData();
1173
+ group.settings.allowRegistrationsByOrganization = true;
1174
+ await group.save();
1175
+
1176
+ const { organization: organization2 } = await initData();
1177
+
1178
+ user.permissions = UserPermissions.create({
1179
+ organizationPermissions: new Map([
1180
+ [organization2.id, Permissions.create({
1181
+ level: PermissionLevel.Full,
1182
+ })],
1183
+ ]),
1184
+ });
1185
+
1186
+ await user.save();
1187
+
1188
+ const body = IDRegisterCheckout.create({
1189
+ cart: IDRegisterCart.create({
1190
+ items: [
1191
+ IDRegisterItem.create({
1192
+ id: uuidv4(),
1193
+ replaceRegistrationIds: [],
1194
+ options: [],
1195
+ groupPrice,
1196
+ organizationId: organization.id,
1197
+ groupId: group.id,
1198
+ memberId: member.id,
1199
+ }),
1200
+ ],
1201
+ balanceItems: [
1202
+ ],
1203
+ deleteRegistrationIds: [],
1204
+ }),
1205
+ administrationFee: 0,
1206
+ freeContribution: 0,
1207
+ paymentMethod: PaymentMethod.PointOfSale,
1208
+ totalPrice: 25,
1209
+ customer: PaymentCustomer.create({
1210
+ company: Company.create({
1211
+ name: 'test company',
1212
+ }),
1213
+ }),
1214
+ asOrganizationId: organization2.id,
1215
+ });
1216
+ // #endregion
1217
+
1218
+ // #region act and assert
1219
+ await expect(async () => await post(body, organization, token))
1220
+ .rejects
1221
+ .toThrow(new RegExp('Oeps, de facturatiegegevens die je probeerde te selecteren lijken niet meer te bestaan.'));
1222
+ // #endregion
1223
+ });
1224
+
1225
+ test('Should set paying organization id', async () => {
1226
+ // #region arrange
1227
+ const { organization, group, groupPrice, token, member, user } = await initData();
1228
+ group.settings.allowRegistrationsByOrganization = true;
1229
+ await group.save();
1230
+
1231
+ const { organization: organization2 } = await initData();
1232
+ const company = Company.create({
1233
+ name: 'test company',
1234
+ });
1235
+
1236
+ organization2.meta.companies.push(company);
1237
+ await organization2.save();
1238
+
1239
+ user.permissions = UserPermissions.create({
1240
+ organizationPermissions: new Map([
1241
+ [organization2.id, Permissions.create({
1242
+ level: PermissionLevel.Full,
1243
+ })],
1244
+ ]),
1245
+ });
1246
+
1247
+ await user.save();
1248
+
1249
+ const body = IDRegisterCheckout.create({
1250
+ cart: IDRegisterCart.create({
1251
+ items: [
1252
+ IDRegisterItem.create({
1253
+ id: uuidv4(),
1254
+ replaceRegistrationIds: [],
1255
+ options: [],
1256
+ groupPrice,
1257
+ organizationId: organization.id,
1258
+ groupId: group.id,
1259
+ memberId: member.id,
1260
+ }),
1261
+ ],
1262
+ balanceItems: [
1263
+ ],
1264
+ deleteRegistrationIds: [],
1265
+ }),
1266
+ administrationFee: 0,
1267
+ freeContribution: 0,
1268
+ paymentMethod: PaymentMethod.PointOfSale,
1269
+ totalPrice: 25,
1270
+ customer: PaymentCustomer.create({
1271
+ company,
1272
+ }),
1273
+ asOrganizationId: organization2.id,
1274
+ });
1275
+ // #endregion
1276
+
1277
+ // #region act and assert
1278
+ const response = await post(body, organization, token);
1279
+ expect(response.body.registrations.length).toBe(1);
1280
+ expect(response.body.registrations[0].payingOrganizationId).toEqual(organization2.id);
1281
+ // #endregion
1282
+ });
1283
+ });
1284
+
1285
+ describe('Replace registrations', () => {
1286
+ test('Should update registered members', async () => {
1287
+ // #region arrange
1288
+ const { organization, group: group1, groupPrice: groupPrice1, token, member } = await initData();
1289
+
1290
+ const registration = await new RegistrationFactory({
1291
+ member,
1292
+ group: group1,
1293
+ groupPrice: groupPrice1,
1294
+ })
1295
+ .create();
1296
+
1297
+ const group = await new GroupFactory({
1298
+ organization,
1299
+ price: 30,
1300
+ stock: 5,
1301
+ }).create();
1302
+
1303
+ const groupPrice = group.settings.prices[0];
1304
+
1305
+ const body = IDRegisterCheckout.create({
1306
+ cart: IDRegisterCart.create({
1307
+ items: [
1308
+ IDRegisterItem.create({
1309
+ id: uuidv4(),
1310
+ replaceRegistrationIds: [registration.id],
1311
+ options: [],
1312
+ groupPrice,
1313
+ organizationId: organization.id,
1314
+ groupId: group.id,
1315
+ memberId: member.id,
1316
+ }),
1317
+ ],
1318
+ balanceItems: [],
1319
+ deleteRegistrationIds: [],
1320
+ }),
1321
+ administrationFee: 0,
1322
+ freeContribution: 0,
1323
+ paymentMethod: PaymentMethod.PointOfSale,
1324
+ totalPrice: 5,
1325
+ asOrganizationId: organization.id,
1326
+ customer: null,
1327
+ });
1328
+ // #endregion
1329
+
1330
+ // #region act and assert
1331
+
1332
+ // update occupancy to be sure occupancy is 1
1333
+ await group1.updateOccupancy();
1334
+ expect(group1.settings.registeredMembers).toBe(1);
1335
+
1336
+ // send request and check occupancy
1337
+ const response = await post(body, organization, token);
1338
+
1339
+ expect(response.body).toBeDefined();
1340
+ expect(response.body.registrations.length).toBe(1);
1341
+
1342
+ const updatedGroup = await Group.getByID(group.id);
1343
+ expect(updatedGroup!.settings.registeredMembers).toBe(1);
1344
+ expect(updatedGroup!.settings.reservedMembers).toBe(0);
1345
+
1346
+ const updatedGroup1After = await Group.getByID(group1.id);
1347
+ // occupancy should go from 1 to 0 because the registration should be replaced
1348
+ expect(updatedGroup1After!.settings.registeredMembers).toBe(0);
1349
+ expect(updatedGroup1After!.settings.reservedMembers).toBe(0);
1350
+ // #endregion
1351
+ });
1352
+
1353
+ test('Should set paid as organization on new registration', async () => {
1354
+ // #region arrange
1355
+ const { organization, group: group1, groupPrice: groupPrice1, token, member, user } = await initData();
1356
+
1357
+ group1.settings.allowRegistrationsByOrganization = true;
1358
+ await group1.save();
1359
+ const organization2 = await initOrganization();
1360
+
1361
+ user.permissions = UserPermissions.create({
1362
+ organizationPermissions: new Map([
1363
+ [organization2.id, Permissions.create({
1364
+ level: PermissionLevel.Full,
1365
+ })],
1366
+ [organization.id, Permissions.create({
1367
+ level: PermissionLevel.Full,
1368
+ })],
1369
+ ]),
1370
+ });
1371
+
1372
+ await user.save();
1373
+
1374
+ const company = Company.create({
1375
+ name: 'test company',
1376
+ });
1377
+
1378
+ organization2.meta.companies.push(company);
1379
+ await organization2.save();
1380
+
1381
+ organization.meta.companies.push(company);
1382
+ await organization.save();
1383
+
1384
+ const body = IDRegisterCheckout.create({
1385
+ cart: IDRegisterCart.create({
1386
+ items: [
1387
+ IDRegisterItem.create({
1388
+ id: uuidv4(),
1389
+ replaceRegistrationIds: [],
1390
+ options: [],
1391
+ groupPrice: groupPrice1,
1392
+ organizationId: organization.id,
1393
+ groupId: group1.id,
1394
+ memberId: member.id,
1395
+ }),
1396
+ ],
1397
+ balanceItems: [],
1398
+ deleteRegistrationIds: [],
1399
+ }),
1400
+ administrationFee: 0,
1401
+ freeContribution: 0,
1402
+ paymentMethod: PaymentMethod.PointOfSale,
1403
+ totalPrice: 25,
1404
+ asOrganizationId: organization2.id,
1405
+ customer: PaymentCustomer.create({
1406
+ company,
1407
+ }),
1408
+ });
1409
+
1410
+ const response1 = await post(body, organization, token);
1411
+ const registration = response1.body.registrations[0];
1412
+ expect(registration).toBeDefined();
1413
+
1414
+ const group = await new GroupFactory({
1415
+ organization,
1416
+ price: 30,
1417
+ stock: 5,
1418
+ }).create();
1419
+
1420
+ const groupPrice = group.settings.prices[0];
1421
+
1422
+ const body2 = IDRegisterCheckout.create({
1423
+ cart: IDRegisterCart.create({
1424
+ items: [
1425
+ IDRegisterItem.create({
1426
+ id: uuidv4(),
1427
+ replaceRegistrationIds: [registration.id],
1428
+ options: [],
1429
+ groupPrice,
1430
+ organizationId: organization.id,
1431
+ groupId: group.id,
1432
+ memberId: member.id,
1433
+ }),
1434
+ ],
1435
+ balanceItems: [],
1436
+ deleteRegistrationIds: [],
1437
+ }),
1438
+ administrationFee: 0,
1439
+ freeContribution: 0,
1440
+ paymentMethod: PaymentMethod.PointOfSale,
1441
+ totalPrice: 30,
1442
+ asOrganizationId: organization.id,
1443
+ customer: PaymentCustomer.create({
1444
+ company,
1445
+ }),
1446
+ });
1447
+ // #endregion
1448
+
1449
+ // #region act and assert
1450
+ const response = await post(body2, organization, token);
1451
+
1452
+ expect(response.body).toBeDefined();
1453
+ expect(response.body.registrations.length).toBe(1);
1454
+
1455
+ // the payingOrganizationId should equal the id of the paying organization of the replaced registration
1456
+ expect(response.body.registrations[0].payingOrganizationId).toEqual(organization2.id);
1457
+ // #endregion
1458
+ });
1459
+
1460
+ test('Replace registration by registration of other member should fail', async () => {
1461
+ // #region arrange
1462
+ const { organization, group: group1, groupPrice: groupPrice1, token, member, otherMembers: [member2] } = await initData({ otherMemberAmount: 1 });
1463
+
1464
+ const registration = await new RegistrationFactory({
1465
+ member: member2,
1466
+ group: group1,
1467
+ groupPrice: groupPrice1,
1468
+ })
1469
+ .create();
1470
+
1471
+ const group = await new GroupFactory({
1472
+ organization,
1473
+ price: 30,
1474
+ stock: 5,
1475
+ }).create();
1476
+
1477
+ const groupPrice = group.settings.prices[0];
1478
+
1479
+ const body = IDRegisterCheckout.create({
1480
+ cart: IDRegisterCart.create({
1481
+ items: [
1482
+ IDRegisterItem.create({
1483
+ id: uuidv4(),
1484
+ replaceRegistrationIds: [registration.id],
1485
+ options: [],
1486
+ groupPrice,
1487
+ organizationId: organization.id,
1488
+ groupId: group.id,
1489
+ memberId: member.id,
1490
+ }),
1491
+ ],
1492
+ balanceItems: [],
1493
+ deleteRegistrationIds: [],
1494
+ }),
1495
+ administrationFee: 0,
1496
+ freeContribution: 0,
1497
+ paymentMethod: PaymentMethod.PointOfSale,
1498
+ totalPrice: 5,
1499
+ asOrganizationId: organization.id,
1500
+ customer: null,
1501
+ });
1502
+ // #endregion
1503
+
1504
+ // #region act and assert
1505
+ await expect(async () => await post(body, organization, token))
1506
+ .rejects
1507
+ .toThrow(new RegExp('Registration not found'));
1508
+ // #endregion
1509
+ });
1510
+
1511
+ test('Move registration should fail if admin of same organization', async () => {
1512
+ // #region arrange
1513
+ const { organization, group: group1, groupPrice: groupPrice1, token, member } = await initData();
1514
+
1515
+ const registration = await new RegistrationFactory({
1516
+ member,
1517
+ group: group1,
1518
+ groupPrice: groupPrice1,
1519
+ })
1520
+ .create();
1521
+
1522
+ const group = await new GroupFactory({
1523
+ organization,
1524
+ price: 30,
1525
+ stock: 5,
1526
+ }).create();
114
1527
 
115
- const updatedGroup = await Group.getByID(group1.id);
116
- expect(updatedGroup!.settings.registeredMembers).toBe(1);
117
- expect(updatedGroup!.settings.reservedMembers).toBe(0);
118
- });
1528
+ const groupPrice = group.settings.prices[0];
119
1529
 
120
- test('Should update reserved members', async () => {
121
- // #region arrange
122
1530
  const body = IDRegisterCheckout.create({
123
1531
  cart: IDRegisterCart.create({
124
1532
  items: [
125
1533
  IDRegisterItem.create({
126
1534
  id: uuidv4(),
127
- replaceRegistrationIds: [],
1535
+ replaceRegistrationIds: [registration.id],
128
1536
  options: [],
129
- groupPrice: groupPrice2,
1537
+ groupPrice,
130
1538
  organizationId: organization.id,
131
- groupId: group2.id,
1539
+ groupId: group.id,
132
1540
  memberId: member.id,
133
1541
  }),
134
1542
  ],
@@ -137,41 +1545,26 @@ describe('Endpoint.RegisterMembers', () => {
137
1545
  }),
138
1546
  administrationFee: 0,
139
1547
  freeContribution: 0,
140
- paymentMethod: PaymentMethod.Payconiq,
141
- redirectUrl: new URL('https://www.example.com'),
142
- cancelUrl: new URL('https://www.example.com'),
143
- totalPrice: 15,
1548
+ paymentMethod: PaymentMethod.PointOfSale,
1549
+ totalPrice: 5,
144
1550
  customer: null,
145
1551
  });
146
-
147
- nock('https://api.ext.payconiq.com')
148
- .post('/v3/payments')
149
- .reply(200, {
150
- paymentId: 'testPaymentId',
151
- _links: {
152
- checkout: {
153
- href: 'https://www.example.com',
154
- },
155
- },
156
- });
157
1552
  // #endregion
158
1553
 
159
- // act
160
- const response = await post(body);
1554
+ // #region act and assert
161
1555
 
162
- // assert
163
- expect(response.body).toBeDefined();
164
- expect(response.body.registrations.length).toBe(1);
1556
+ // send request and check occupancy
1557
+ await expect(async () => await post(body, organization, token)).rejects.toThrow('Not allowed to move registrations');
165
1558
 
166
- const updatedGroup = await Group.getByID(group2.id);
167
- expect(updatedGroup!.settings.registeredMembers).toBe(0);
168
- expect(updatedGroup!.settings.reservedMembers).toBe(1);
1559
+ // #endregion
169
1560
  });
170
1561
  });
171
1562
 
172
- describe('Register member with replace registration', () => {
1563
+ describe('Delete registrations', () => {
173
1564
  test('Should update registered members', async () => {
174
1565
  // #region arrange
1566
+ const { member, group: group1, groupPrice: groupPrice1, organization: organization1, token } = await initData();
1567
+
175
1568
  const registration = await new RegistrationFactory({
176
1569
  member,
177
1570
  group: group1,
@@ -180,7 +1573,7 @@ describe('Endpoint.RegisterMembers', () => {
180
1573
  .create();
181
1574
 
182
1575
  const group = await new GroupFactory({
183
- organization,
1576
+ organization: organization1,
184
1577
  price: 30,
185
1578
  stock: 5,
186
1579
  }).create();
@@ -192,22 +1585,22 @@ describe('Endpoint.RegisterMembers', () => {
192
1585
  items: [
193
1586
  IDRegisterItem.create({
194
1587
  id: uuidv4(),
195
- replaceRegistrationIds: [registration.id],
1588
+ replaceRegistrationIds: [],
196
1589
  options: [],
197
1590
  groupPrice,
198
- organizationId: organization.id,
1591
+ organizationId: organization1.id,
199
1592
  groupId: group.id,
200
1593
  memberId: member.id,
201
1594
  }),
202
1595
  ],
203
1596
  balanceItems: [],
204
- deleteRegistrationIds: [],
1597
+ deleteRegistrationIds: [registration.id],
205
1598
  }),
206
1599
  administrationFee: 0,
207
1600
  freeContribution: 0,
208
1601
  paymentMethod: PaymentMethod.PointOfSale,
209
1602
  totalPrice: 5,
210
- asOrganizationId: organization.id,
1603
+ asOrganizationId: organization1.id,
211
1604
  customer: null,
212
1605
  });
213
1606
  // #endregion
@@ -219,7 +1612,7 @@ describe('Endpoint.RegisterMembers', () => {
219
1612
  expect(group1.settings.registeredMembers).toBe(1);
220
1613
 
221
1614
  // send request and check occupancy
222
- const response = await post(body);
1615
+ const response = await post(body, organization1, token);
223
1616
 
224
1617
  expect(response.body).toBeDefined();
225
1618
  expect(response.body.registrations.length).toBe(1);
@@ -229,7 +1622,7 @@ describe('Endpoint.RegisterMembers', () => {
229
1622
  expect(updatedGroup!.settings.reservedMembers).toBe(0);
230
1623
 
231
1624
  const updatedGroup1After = await Group.getByID(group1.id);
232
- // occupancy should go from 1 to 0 because the registration should be replaced
1625
+ // occupancy should go from 1 to 0 because the registration should be deleted
233
1626
  expect(updatedGroup1After!.settings.registeredMembers).toBe(0);
234
1627
  expect(updatedGroup1After!.settings.reservedMembers).toBe(0);
235
1628
  // #endregion
@@ -237,6 +1630,8 @@ describe('Endpoint.RegisterMembers', () => {
237
1630
 
238
1631
  test('Should throw error if with payment', async () => {
239
1632
  // #region arrange
1633
+ const { member, group: group1, groupPrice: groupPrice1, organization: organization1, token } = await initData();
1634
+
240
1635
  const registration = await new RegistrationFactory({
241
1636
  member,
242
1637
  group: group1,
@@ -245,7 +1640,7 @@ describe('Endpoint.RegisterMembers', () => {
245
1640
  .create();
246
1641
 
247
1642
  const group = await new GroupFactory({
248
- organization,
1643
+ organization: organization1,
249
1644
  price: 30,
250
1645
  stock: 5,
251
1646
  maxMembers: 1,
@@ -258,16 +1653,16 @@ describe('Endpoint.RegisterMembers', () => {
258
1653
  items: [
259
1654
  IDRegisterItem.create({
260
1655
  id: uuidv4(),
261
- replaceRegistrationIds: [registration.id],
1656
+ replaceRegistrationIds: [],
262
1657
  options: [],
263
1658
  groupPrice,
264
- organizationId: organization.id,
1659
+ organizationId: organization1.id,
265
1660
  groupId: group.id,
266
1661
  memberId: member.id,
267
1662
  }),
268
1663
  ],
269
1664
  balanceItems: [],
270
- deleteRegistrationIds: [],
1665
+ deleteRegistrationIds: [registration.id],
271
1666
  }),
272
1667
  administrationFee: 0,
273
1668
  freeContribution: 0,
@@ -285,20 +1680,19 @@ describe('Endpoint.RegisterMembers', () => {
285
1680
  await group1.updateOccupancy();
286
1681
  expect(group1.settings.registeredMembers).toBe(1);
287
1682
 
288
- await expect(async () => await post(body)).rejects.toThrow('Not allowed to move registrations');
1683
+ await expect(async () => await post(body, organization1, token)).rejects.toThrow('Permission denied: you are not allowed to delete registrations');
289
1684
  // #endregion
290
1685
  });
291
- });
292
1686
 
293
- describe('Register member with delete registration', () => {
294
- test('Should update registered members', async () => {
1687
+ test('Should deactivate registration', async () => {
295
1688
  // #region arrange
1689
+ const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
1690
+
296
1691
  const registration = await new RegistrationFactory({
297
1692
  member,
298
1693
  group: group1,
299
1694
  groupPrice: groupPrice1,
300
- })
301
- .create();
1695
+ }).create();
302
1696
 
303
1697
  const group = await new GroupFactory({
304
1698
  organization,
@@ -334,45 +1728,107 @@ describe('Endpoint.RegisterMembers', () => {
334
1728
  // #endregion
335
1729
 
336
1730
  // #region act and assert
1731
+ await post(body, organization, token);
337
1732
 
338
- // update occupancy to be sure occupancy is 1
339
- await group1.updateOccupancy();
340
- expect(group1.settings.registeredMembers).toBe(1);
1733
+ const updatedRegistration = await Registration.getByID(registration.id);
1734
+ expect(updatedRegistration).toBeDefined();
1735
+ expect(updatedRegistration!.deactivatedAt).not.toBe(null);
1736
+ // #endregion
1737
+ });
341
1738
 
342
- // send request and check occupancy
343
- const response = await post(body);
1739
+ test('Should fail if invalid cancelation fee', async () => {
1740
+ for (const cancellationFeePercentage of [10001, -1]) {
1741
+ // #region arrange
1742
+ const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
344
1743
 
345
- expect(response.body).toBeDefined();
346
- expect(response.body.registrations.length).toBe(1);
1744
+ const body1 = IDRegisterCheckout.create({
1745
+ cart: IDRegisterCart.create({
1746
+ items: [
1747
+ IDRegisterItem.create({
1748
+ id: uuidv4(),
1749
+ replaceRegistrationIds: [],
1750
+ options: [],
1751
+ groupPrice: groupPrice1,
1752
+ organizationId: organization.id,
1753
+ groupId: group1.id,
1754
+ memberId: member.id,
1755
+ }),
1756
+ ],
1757
+ balanceItems: [],
1758
+ deleteRegistrationIds: [],
1759
+ }),
1760
+ administrationFee: 0,
1761
+ freeContribution: 0,
1762
+ paymentMethod: PaymentMethod.PointOfSale,
1763
+ totalPrice: 25,
1764
+ asOrganizationId: organization.id,
1765
+ customer: null,
1766
+ });
347
1767
 
348
- const updatedGroup = await Group.getByID(group.id);
349
- expect(updatedGroup!.settings.registeredMembers).toBe(1);
350
- expect(updatedGroup!.settings.reservedMembers).toBe(0);
1768
+ const group2 = await new GroupFactory({
1769
+ organization,
1770
+ price: 30,
1771
+ stock: 5,
1772
+ }).create();
351
1773
 
352
- const updatedGroup1After = await Group.getByID(group1.id);
353
- // occupancy should go from 1 to 0 because the registration should be deleted
354
- expect(updatedGroup1After!.settings.registeredMembers).toBe(0);
355
- expect(updatedGroup1After!.settings.reservedMembers).toBe(0);
1774
+ const groupPrice2 = group2.settings.prices[0];
1775
+
1776
+ const firstResponse = await post(body1, organization, token);
1777
+ expect(firstResponse).toBeDefined();
1778
+ expect(firstResponse.body.registrations.length).toBe(1);
1779
+ const registration = firstResponse.body.registrations[0];
1780
+
1781
+ const body2 = IDRegisterCheckout.create({
1782
+ cart: IDRegisterCart.create({
1783
+ items: [
1784
+ IDRegisterItem.create({
1785
+ id: uuidv4(),
1786
+ replaceRegistrationIds: [],
1787
+ options: [],
1788
+ groupPrice: groupPrice2,
1789
+ organizationId: organization.id,
1790
+ groupId: group2.id,
1791
+ memberId: member.id,
1792
+ }),
1793
+ ],
1794
+ balanceItems: [],
1795
+ deleteRegistrationIds: [registration.id],
1796
+ }),
1797
+ cancellationFeePercentage,
1798
+ administrationFee: 0,
1799
+ freeContribution: 0,
1800
+ paymentMethod: PaymentMethod.PointOfSale,
1801
+ totalPrice: 30,
1802
+ asOrganizationId: organization.id,
1803
+ customer: null,
1804
+ });
1805
+ // #endregion
1806
+
1807
+ // #region act and assert
1808
+ await expect(async () => await post(body2, organization, token))
1809
+ .rejects
1810
+ .toThrow(new RegExp('Invalid cancellation fee percentage.'));
356
1811
  // #endregion
1812
+ }
357
1813
  });
358
1814
 
359
- test('Should throw error if with payment', async () => {
1815
+ test('Delete by member should fail if no permission to delete registration', async () => {
360
1816
  // #region arrange
1817
+ const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
1818
+
361
1819
  const registration = await new RegistrationFactory({
362
1820
  member,
363
1821
  group: group1,
364
1822
  groupPrice: groupPrice1,
365
- })
366
- .create();
1823
+ }).create();
367
1824
 
368
- const group = await new GroupFactory({
1825
+ const group2 = await new GroupFactory({
369
1826
  organization,
370
1827
  price: 30,
371
1828
  stock: 5,
372
- maxMembers: 1,
373
1829
  }).create();
374
1830
 
375
- const groupPrice = group.settings.prices[0];
1831
+ const groupPrice = group2.settings.prices[0];
376
1832
 
377
1833
  const body = IDRegisterCheckout.create({
378
1834
  cart: IDRegisterCart.create({
@@ -383,7 +1839,7 @@ describe('Endpoint.RegisterMembers', () => {
383
1839
  options: [],
384
1840
  groupPrice,
385
1841
  organizationId: organization.id,
386
- groupId: group.id,
1842
+ groupId: group2.id,
387
1843
  memberId: member.id,
388
1844
  }),
389
1845
  ],
@@ -392,59 +1848,195 @@ describe('Endpoint.RegisterMembers', () => {
392
1848
  }),
393
1849
  administrationFee: 0,
394
1850
  freeContribution: 0,
395
- paymentMethod: PaymentMethod.Payconiq,
396
- redirectUrl: new URL('https://www.example.com'),
397
- cancelUrl: new URL('https://www.example.com'),
1851
+ paymentMethod: PaymentMethod.PointOfSale,
398
1852
  totalPrice: 5,
399
1853
  customer: null,
400
1854
  });
401
1855
  // #endregion
402
1856
 
403
1857
  // #region act and assert
1858
+ await expect(async () => await post(body, organization, token))
1859
+ .rejects
1860
+ .toThrow(new RegExp('Permission denied: you are not allowed to delete registrations'));
1861
+ // #endregion
1862
+ });
404
1863
 
405
- // update occupancy to be sure occupancy is 1
406
- await group1.updateOccupancy();
407
- expect(group1.settings.registeredMembers).toBe(1);
1864
+ test('Delete by organization should fail if no permission to delete registration', async () => {
1865
+ // #region arrange
1866
+ const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData({ permissionLevel: PermissionLevel.Read });
1867
+
1868
+ const registration = await new RegistrationFactory({
1869
+ member,
1870
+ group: group1,
1871
+ groupPrice: groupPrice1,
1872
+ }).create();
1873
+
1874
+ const group2 = await new GroupFactory({
1875
+ organization,
1876
+ price: 30,
1877
+ stock: 5,
1878
+ }).create();
1879
+
1880
+ const groupPrice = group2.settings.prices[0];
1881
+
1882
+ const body = IDRegisterCheckout.create({
1883
+ cart: IDRegisterCart.create({
1884
+ items: [
1885
+ IDRegisterItem.create({
1886
+ id: uuidv4(),
1887
+ replaceRegistrationIds: [],
1888
+ options: [],
1889
+ groupPrice,
1890
+ organizationId: organization.id,
1891
+ groupId: group2.id,
1892
+ memberId: member.id,
1893
+ }),
1894
+ ],
1895
+ balanceItems: [],
1896
+ deleteRegistrationIds: [registration.id],
1897
+ }),
1898
+ administrationFee: 0,
1899
+ freeContribution: 0,
1900
+ paymentMethod: PaymentMethod.PointOfSale,
1901
+ totalPrice: 5,
1902
+ customer: null,
1903
+ asOrganizationId: organization.id,
1904
+ });
1905
+ // #endregion
408
1906
 
409
- await expect(async () => await post(body)).rejects.toThrow('Permission denied: you are not allowed to delete registrations');
1907
+ // #region act and assert
1908
+ await expect(async () => await post(body, organization, token)).rejects.toThrow(new RegExp('Je hebt geen toegangsrechten om deze inschrijving te verwijderen'));
410
1909
  // #endregion
411
1910
  });
412
- });
413
1911
 
414
- it('Register member that is already registered should throw error', async () => {
415
- // create existing registration
416
- await new RegistrationFactory({
417
- member,
418
- group: group1,
419
- groupPrice: groupPrice1,
420
- })
421
- .create();
1912
+ test('Should fail if registration does not exist anymore', async () => {
1913
+ // #region arrange
1914
+ const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
422
1915
 
423
- // register again
424
- const body = IDRegisterCheckout.create({
425
- cart: IDRegisterCart.create({
426
- items: [
427
- IDRegisterItem.create({
428
- id: uuidv4(),
429
- replaceRegistrationIds: [],
430
- options: [],
431
- groupPrice: groupPrice1,
432
- organizationId: organization.id,
433
- groupId: group1.id,
434
- memberId: member.id,
435
- }),
436
- ],
437
- balanceItems: [],
438
- deleteRegistrationIds: [],
439
- }),
440
- administrationFee: 0,
441
- freeContribution: 0,
442
- paymentMethod: PaymentMethod.PointOfSale,
443
- totalPrice: groupPrice1.price.price,
444
- asOrganizationId: organization.id,
445
- customer: null,
1916
+ const registration = await new RegistrationFactory({
1917
+ member,
1918
+ group: group1,
1919
+ groupPrice: groupPrice1,
1920
+ }).create();
1921
+
1922
+ const group2 = await new GroupFactory({
1923
+ organization,
1924
+ price: 30,
1925
+ stock: 5,
1926
+ }).create();
1927
+
1928
+ const groupPrice = group2.settings.prices[0];
1929
+
1930
+ const body = IDRegisterCheckout.create({
1931
+ cart: IDRegisterCart.create({
1932
+ items: [
1933
+ IDRegisterItem.create({
1934
+ id: uuidv4(),
1935
+ replaceRegistrationIds: [],
1936
+ options: [],
1937
+ groupPrice,
1938
+ organizationId: organization.id,
1939
+ groupId: group2.id,
1940
+ memberId: member.id,
1941
+ }),
1942
+ ],
1943
+ balanceItems: [],
1944
+ deleteRegistrationIds: [registration.id],
1945
+ }),
1946
+ administrationFee: 0,
1947
+ freeContribution: 0,
1948
+ paymentMethod: PaymentMethod.PointOfSale,
1949
+ totalPrice: 5,
1950
+ customer: null,
1951
+ asOrganizationId: organization.id,
1952
+ });
1953
+ // #endregion
1954
+
1955
+ // #region act and assert
1956
+ await registration.delete();
1957
+ await expect(async () => await post(body, organization, token)).rejects.toThrow(new RegExp('Registration not found'));
1958
+ // #endregion
446
1959
  });
447
1960
 
448
- await expect(async () => await post(body)).rejects.toThrow('Already registered');
1961
+ test('Should fail if already deleted', async () => {
1962
+ // #region arrange
1963
+ const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
1964
+
1965
+ const registration = await new RegistrationFactory({
1966
+ member,
1967
+ group: group1,
1968
+ groupPrice: groupPrice1,
1969
+ }).create();
1970
+
1971
+ const group2 = await new GroupFactory({
1972
+ organization,
1973
+ price: 30,
1974
+ stock: 5,
1975
+ }).create();
1976
+
1977
+ const groupPrice2 = group2.settings.prices[0];
1978
+
1979
+ const group3 = await new GroupFactory({
1980
+ organization,
1981
+ price: 30,
1982
+ stock: 5,
1983
+ }).create();
1984
+
1985
+ const groupPrice3 = group3.settings.prices[0];
1986
+
1987
+ const body1 = IDRegisterCheckout.create({
1988
+ cart: IDRegisterCart.create({
1989
+ items: [
1990
+ IDRegisterItem.create({
1991
+ id: uuidv4(),
1992
+ replaceRegistrationIds: [],
1993
+ options: [],
1994
+ groupPrice: groupPrice2,
1995
+ organizationId: organization.id,
1996
+ groupId: group2.id,
1997
+ memberId: member.id,
1998
+ }),
1999
+ ],
2000
+ balanceItems: [],
2001
+ deleteRegistrationIds: [registration.id],
2002
+ }),
2003
+ administrationFee: 0,
2004
+ freeContribution: 0,
2005
+ paymentMethod: PaymentMethod.PointOfSale,
2006
+ totalPrice: 5,
2007
+ customer: null,
2008
+ asOrganizationId: organization.id,
2009
+ });
2010
+
2011
+ const body2 = IDRegisterCheckout.create({
2012
+ cart: IDRegisterCart.create({
2013
+ items: [
2014
+ IDRegisterItem.create({
2015
+ id: uuidv4(),
2016
+ replaceRegistrationIds: [],
2017
+ options: [],
2018
+ groupPrice: groupPrice3,
2019
+ organizationId: organization.id,
2020
+ groupId: group3.id,
2021
+ memberId: member.id,
2022
+ }),
2023
+ ],
2024
+ balanceItems: [],
2025
+ deleteRegistrationIds: [registration.id],
2026
+ }),
2027
+ administrationFee: 0,
2028
+ freeContribution: 0,
2029
+ paymentMethod: PaymentMethod.PointOfSale,
2030
+ totalPrice: 5,
2031
+ customer: null,
2032
+ asOrganizationId: organization.id,
2033
+ });
2034
+ // #endregion
2035
+
2036
+ // #region act and assert
2037
+ await post(body1, organization, token);
2038
+ await expect(async () => await post(body2, organization, token)).rejects.toThrow(new RegExp('Oeps, één of meerdere inschrijvingen die je probeert te verwijderen was al verwijderd. Herlaad de pagina en probeer opnieuw'));
2039
+ // #endregion
2040
+ });
449
2041
  });
450
2042
  });