@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
@@ -0,0 +1,762 @@
1
+ import { Request } from '@simonbackx/simple-endpoints';
2
+ import { BalanceItemFactory, GroupFactory, MemberFactory, MemberWithRegistrations, Organization, OrganizationFactory, OrganizationRegistrationPeriod, Platform, RegistrationFactory, RegistrationPeriod, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
3
+ import { AdministrationFeeSettings, BalanceItemCartItem, BalanceItemType, DefaultAgeGroup, FreeContributionSettings, GroupOption, GroupOptionMenu, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, PaymentMethod, PermissionLevel, Permissions, PlatformMembershipType, PlatformMembershipTypeConfig, ReceivableBalanceType, ReduceablePrice, RegisterItemOption, Version } from '@stamhoofd/structures';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import { GetMemberFamilyEndpoint } from '../../src/endpoints/global/members/GetMemberFamilyEndpoint';
6
+ import { RegisterMembersEndpoint } from '../../src/endpoints/global/registration/RegisterMembersEndpoint';
7
+ import { GetMemberBalanceEndpoint } from '../../src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint';
8
+ import { GetReceivableBalanceEndpoint } from '../../src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint';
9
+ import { testServer } from '../helpers/TestServer';
10
+
11
+ describe('E2E.Register', () => {
12
+ // #region global
13
+ const registerEndpoint = new RegisterMembersEndpoint();
14
+ const memberBalanceEndpoint = new GetMemberBalanceEndpoint();
15
+ const receivableBalancesEndpoint = new GetReceivableBalanceEndpoint();
16
+ const getMemberFamilyEndpoint = new GetMemberFamilyEndpoint();
17
+
18
+ let period: RegistrationPeriod;
19
+
20
+ // #region helpers
21
+ const register = async (body: IDRegisterCheckout, organization: Organization, token: Token) => {
22
+ const request = Request.buildJson('POST', `/v${Version}/members/register`, organization.getApiHost(), body);
23
+ request.headers.authorization = 'Bearer ' + token.accessToken;
24
+ return await testServer.test(registerEndpoint, request);
25
+ };
26
+
27
+ const getBalance = async (memberId: string, organization: Organization, token: Token) => {
28
+ const request = Request.buildJson('GET', `/v${Version}/organization/members/${memberId}/balance`, organization.getApiHost());
29
+ request.headers.authorization = 'Bearer ' + token.accessToken;
30
+ return await testServer.test(memberBalanceEndpoint, request);
31
+ };
32
+
33
+ const getReceivableBalance = async (type: ReceivableBalanceType, id: string, organization: Organization, token: Token) => {
34
+ const request = Request.buildJson('GET', `/v${Version}/receivable-balances/${type}/${id}`, organization.getApiHost());
35
+ request.headers.authorization = 'Bearer ' + token.accessToken;
36
+ return await testServer.test(receivableBalancesEndpoint, request);
37
+ };
38
+
39
+ const getMemberFamily = async (memberId: string, organization: Organization, token: Token) => {
40
+ const request = Request.buildJson('GET', `/v${Version}/organization/members/${memberId}/family`, organization.getApiHost());
41
+ request.headers.authorization = 'Bearer ' + token.accessToken;
42
+ return await testServer.test(getMemberFamilyEndpoint, request);
43
+ };
44
+ // #endregion
45
+
46
+ // #endregion
47
+
48
+ beforeAll(async () => {
49
+ const previousPeriod = await new RegistrationPeriodFactory({
50
+ startDate: new Date(2022, 0, 1),
51
+ endDate: new Date(2022, 11, 31),
52
+ }).create();
53
+
54
+ period = await new RegistrationPeriodFactory({
55
+ startDate: new Date(2023, 0, 1),
56
+ endDate: new Date(2023, 11, 31),
57
+ }).create();
58
+
59
+ period.previousPeriodId = previousPeriod.id;
60
+ await period.save();
61
+ });
62
+
63
+ const initData = async ({ otherMemberAmount = 0, permissionLevel = PermissionLevel.Full }: { otherMemberAmount?: number; permissionLevel?: PermissionLevel } = {}) => {
64
+ const organization = await new OrganizationFactory({ period })
65
+ .create();
66
+
67
+ const user = await new UserFactory({
68
+ organization,
69
+ permissions: Permissions.create({
70
+ level: permissionLevel,
71
+ }),
72
+ })
73
+ .create();
74
+
75
+ const token = await Token.createToken(user);
76
+
77
+ const member = await new MemberFactory({ organization, user })
78
+ .create();
79
+
80
+ const otherMembers: MemberWithRegistrations[] = [];
81
+
82
+ for (let i = 0; i < otherMemberAmount; i++) {
83
+ otherMembers.push(await new MemberFactory({ organization, user })
84
+ .create());
85
+ }
86
+
87
+ const group = await new GroupFactory({
88
+ organization,
89
+ price: 25,
90
+ stock: 5,
91
+ })
92
+ .create();
93
+
94
+ const groupPrice = group.settings.prices[0];
95
+
96
+ return {
97
+ organization,
98
+ user,
99
+ token,
100
+ member,
101
+ otherMembers,
102
+ group,
103
+ groupPrice,
104
+ };
105
+ };
106
+
107
+ beforeEach(async () => {
108
+ });
109
+
110
+ describe('Register', () => {
111
+ test('Register by member should create balance for member', async () => {
112
+ // #region arrange
113
+ const { organization, group, groupPrice, token, member } = await initData();
114
+
115
+ const body = IDRegisterCheckout.create({
116
+ cart: IDRegisterCart.create({
117
+ items: [
118
+ IDRegisterItem.create({
119
+ id: uuidv4(),
120
+ replaceRegistrationIds: [],
121
+ options: [],
122
+ groupPrice,
123
+ organizationId: organization.id,
124
+ groupId: group.id,
125
+ memberId: member.id,
126
+ }),
127
+ ],
128
+ balanceItems: [
129
+ ],
130
+ deleteRegistrationIds: [],
131
+ }),
132
+ administrationFee: 0,
133
+ freeContribution: 0,
134
+ paymentMethod: PaymentMethod.PointOfSale,
135
+ totalPrice: 25,
136
+ customer: null,
137
+ });
138
+ // #endregion
139
+
140
+ // #region act and assert
141
+ const balanceBefore = await getBalance(member.id, organization, token);
142
+ expect(balanceBefore).toBeDefined();
143
+ expect(balanceBefore.body.length).toBe(0);
144
+
145
+ await register(body, organization, token);
146
+
147
+ const balance = await getBalance(member.id, organization, token);
148
+ expect(balance).toBeDefined();
149
+ expect(balance.body.length).toBe(1);
150
+ expect(balance.body[0].price).toBe(25);
151
+ expect(balance.body[0].pricePaid).toBe(0);
152
+ // #endregion
153
+ });
154
+
155
+ // todo: test max option + allowAmount
156
+ // todo: test stock?
157
+ // todo: test reduced price?
158
+
159
+ test('Should create balance items for options', async () => {
160
+ // #region arrange
161
+ const { organization, group, groupPrice, token, member } = await initData();
162
+
163
+ const option1 = GroupOption.create({
164
+ name: 'option 1',
165
+ price: ReduceablePrice.create({
166
+ price: 5,
167
+ reducedPrice: 3,
168
+ }),
169
+ });
170
+
171
+ const option2 = GroupOption.create({
172
+ name: 'option 2',
173
+ price: ReduceablePrice.create({
174
+ price: 3,
175
+ reducedPrice: 1,
176
+ }),
177
+ });
178
+
179
+ const optionMenu = GroupOptionMenu.create({
180
+ name: 'option menu 1',
181
+ multipleChoice: true,
182
+ options: [option1, option2],
183
+ });
184
+
185
+ group.settings.optionMenus = [
186
+ optionMenu,
187
+ ];
188
+
189
+ await group.save();
190
+
191
+ const body = IDRegisterCheckout.create({
192
+ cart: IDRegisterCart.create({
193
+ items: [
194
+ IDRegisterItem.create({
195
+ id: uuidv4(),
196
+ replaceRegistrationIds: [],
197
+ options: [
198
+ RegisterItemOption.create({
199
+ option: option1,
200
+ amount: 2,
201
+ optionMenu,
202
+ }),
203
+ RegisterItemOption.create({
204
+ option: option2,
205
+ amount: 5,
206
+ optionMenu,
207
+ }),
208
+ ],
209
+ groupPrice,
210
+ organizationId: organization.id,
211
+ groupId: group.id,
212
+ memberId: member.id,
213
+ }),
214
+ ],
215
+ balanceItems: [
216
+ ],
217
+ deleteRegistrationIds: [],
218
+ }),
219
+ administrationFee: 0,
220
+ freeContribution: 0,
221
+ paymentMethod: PaymentMethod.PointOfSale,
222
+ totalPrice: 50,
223
+ customer: null,
224
+ });
225
+ // #endregion
226
+
227
+ // #region act and assert
228
+ const balanceBefore = await getBalance(member.id, organization, token);
229
+ expect(balanceBefore).toBeDefined();
230
+ expect(balanceBefore.body.length).toBe(0);
231
+
232
+ await register(body, organization, token);
233
+
234
+ const balance = await getBalance(member.id, organization, token);
235
+ expect(balance).toBeDefined();
236
+ expect(balance.body.length).toBe(3);
237
+ expect(balance.body).toEqual(expect.arrayContaining([
238
+ expect.objectContaining({
239
+ price: 25,
240
+ pricePaid: 0,
241
+ }),
242
+ expect.objectContaining({
243
+ price: 15,
244
+ pricePaid: 0,
245
+ }),
246
+ expect.objectContaining({
247
+ price: 10,
248
+ pricePaid: 0,
249
+ }),
250
+ ]));
251
+ // #endregion
252
+ });
253
+
254
+ test('Should reset free contribution if no options on organization', async () => {
255
+ // #region arrange
256
+ const { organization, group, groupPrice, token, member, user } = await initData();
257
+
258
+ const body = IDRegisterCheckout.create({
259
+ cart: IDRegisterCart.create({
260
+ items: [
261
+ IDRegisterItem.create({
262
+ id: uuidv4(),
263
+ replaceRegistrationIds: [],
264
+ options: [],
265
+ groupPrice,
266
+ organizationId: organization.id,
267
+ groupId: group.id,
268
+ memberId: member.id,
269
+ }),
270
+ ],
271
+ balanceItems: [
272
+ ],
273
+ deleteRegistrationIds: [],
274
+ }),
275
+ administrationFee: 0,
276
+ freeContribution: 31,
277
+ paymentMethod: PaymentMethod.PointOfSale,
278
+ totalPrice: 25,
279
+ customer: null,
280
+ });
281
+ // #endregion
282
+
283
+ // #region act and assert
284
+ const receivableBalanceBefore = await getReceivableBalance(ReceivableBalanceType.user, user.id, organization, token);
285
+ expect(receivableBalanceBefore).toBeDefined();
286
+ expect(receivableBalanceBefore.body.balanceItems.length).toBe(0);
287
+ expect(receivableBalanceBefore.body.amountOpen).toBe(0);
288
+
289
+ await register(body, organization, token);
290
+
291
+ const receivableBalanceAfter = await getReceivableBalance(ReceivableBalanceType.user, user.id, organization, token);
292
+ expect(receivableBalanceAfter).toBeDefined();
293
+ expect(receivableBalanceAfter.body.balanceItems.length).toBe(1);
294
+ expect(receivableBalanceAfter.body.amountOpen).toBe(0);
295
+ expect(receivableBalanceAfter.body.balanceItems).toEqual(expect.arrayContaining([
296
+ expect.objectContaining({
297
+ price: 25,
298
+ pricePaid: 0,
299
+ }),
300
+ ]));
301
+ // #endregion
302
+ });
303
+
304
+ test('Should create balance item for free contribution', async () => {
305
+ // #region arrange
306
+ const { organization, group, groupPrice, token, member, user } = await initData();
307
+
308
+ organization.meta.recordsConfiguration.freeContribution = FreeContributionSettings.create({
309
+ description: 'free contribution settings',
310
+ amounts: [30, 20],
311
+ });
312
+
313
+ await organization.save();
314
+
315
+ const body = IDRegisterCheckout.create({
316
+ cart: IDRegisterCart.create({
317
+ items: [
318
+ IDRegisterItem.create({
319
+ id: uuidv4(),
320
+ replaceRegistrationIds: [],
321
+ options: [],
322
+ groupPrice,
323
+ organizationId: organization.id,
324
+ groupId: group.id,
325
+ memberId: member.id,
326
+ }),
327
+ ],
328
+ balanceItems: [
329
+ ],
330
+ deleteRegistrationIds: [],
331
+ }),
332
+ administrationFee: 0,
333
+ freeContribution: 30,
334
+ paymentMethod: PaymentMethod.PointOfSale,
335
+ totalPrice: 55,
336
+ customer: null,
337
+ });
338
+ // #endregion
339
+
340
+ // #region act and assert
341
+ const receivableBalanceBefore = await getReceivableBalance(ReceivableBalanceType.user, user.id, organization, token);
342
+ expect(receivableBalanceBefore).toBeDefined();
343
+ expect(receivableBalanceBefore.body.balanceItems.length).toBe(0);
344
+ expect(receivableBalanceBefore.body.amountOpen).toBe(0);
345
+
346
+ await register(body, organization, token);
347
+
348
+ const receivableBalanceAfter = await getReceivableBalance(ReceivableBalanceType.user, user.id, organization, token);
349
+ expect(receivableBalanceAfter).toBeDefined();
350
+ expect(receivableBalanceAfter.body.balanceItems.length).toBe(2);
351
+ expect(receivableBalanceAfter.body.amountPending).toBe(55);
352
+
353
+ expect(receivableBalanceAfter.body.balanceItems).toEqual(expect.arrayContaining([
354
+ expect.objectContaining({
355
+ price: 30,
356
+ pricePaid: 0,
357
+ type: BalanceItemType.FreeContribution,
358
+ }),
359
+ expect.objectContaining({
360
+ price: 25,
361
+ pricePaid: 0,
362
+ }),
363
+ ]));
364
+ // #endregion
365
+ });
366
+
367
+ test('Should create balance item for free administration fee if register by member', async () => {
368
+ // #region arrange
369
+ const { organization, group, groupPrice, token, member, user } = await initData();
370
+
371
+ organization.meta.registrationPaymentConfiguration.administrationFee = AdministrationFeeSettings.create({
372
+ fixed: 33,
373
+ });
374
+
375
+ await organization.save();
376
+
377
+ const body = IDRegisterCheckout.create({
378
+ cart: IDRegisterCart.create({
379
+ items: [
380
+ IDRegisterItem.create({
381
+ id: uuidv4(),
382
+ replaceRegistrationIds: [],
383
+ options: [],
384
+ groupPrice,
385
+ organizationId: organization.id,
386
+ groupId: group.id,
387
+ memberId: member.id,
388
+ }),
389
+ ],
390
+ balanceItems: [
391
+ ],
392
+ deleteRegistrationIds: [],
393
+ }),
394
+ administrationFee: 33,
395
+ freeContribution: 0,
396
+ paymentMethod: PaymentMethod.PointOfSale,
397
+ totalPrice: 58,
398
+ });
399
+ // #endregion
400
+
401
+ // #region act and assert
402
+ const receivableBalanceBefore = await getReceivableBalance(ReceivableBalanceType.user, user.id, organization
403
+ , token);
404
+ expect(receivableBalanceBefore).toBeDefined();
405
+ expect(receivableBalanceBefore.body.balanceItems.length).toBe(0);
406
+ expect(receivableBalanceBefore.body.amountOpen).toBe(0);
407
+
408
+ await register(body, organization, token);
409
+
410
+ const receivableBalanceAfter = await getReceivableBalance(ReceivableBalanceType.user, user.id, organization, token);
411
+ expect(receivableBalanceAfter).toBeDefined();
412
+ expect(receivableBalanceAfter.body.balanceItems.length).toBe(2);
413
+ expect(receivableBalanceAfter.body.amountPending).toBe(58);
414
+
415
+ expect(receivableBalanceAfter.body.balanceItems).toEqual(expect.arrayContaining([
416
+ expect.objectContaining({
417
+ price: 25,
418
+ pricePaid: 0,
419
+ type: BalanceItemType.Registration,
420
+ }),
421
+ expect.objectContaining({
422
+ price: 33,
423
+ pricePaid: 0,
424
+ type: BalanceItemType.AdministrationFee,
425
+ }),
426
+ ]));
427
+ // #endregion
428
+ });
429
+
430
+ test('Should create balance item for cart item', async () => {
431
+ // #region arrange
432
+ const { organization, group, groupPrice, token, member, user } = await initData();
433
+
434
+ const balanceItem1 = await new BalanceItemFactory({
435
+ organizationId: organization.id,
436
+ memberId: member.id,
437
+ userId: user.id,
438
+ payingOrganizationId: organization.id,
439
+ type: BalanceItemType.Registration,
440
+ amount: 10,
441
+ unitPrice: 2,
442
+ }).create();
443
+
444
+ const cartItem = BalanceItemCartItem.create({
445
+ item: balanceItem1.getStructure(),
446
+ price: 10,
447
+ });
448
+
449
+ const body = IDRegisterCheckout.create({
450
+ cart: IDRegisterCart.create({
451
+ items: [
452
+ IDRegisterItem.create({
453
+ id: uuidv4(),
454
+ replaceRegistrationIds: [],
455
+ options: [],
456
+ groupPrice,
457
+ organizationId: organization.id,
458
+ groupId: group.id,
459
+ memberId: member.id,
460
+ }),
461
+ ],
462
+ balanceItems: [
463
+ cartItem,
464
+ ],
465
+ deleteRegistrationIds: [],
466
+ }),
467
+ administrationFee: 0,
468
+ freeContribution: 0,
469
+ paymentMethod: PaymentMethod.PointOfSale,
470
+ totalPrice: 35,
471
+ });
472
+
473
+ // #endregion
474
+
475
+ // #region act and assert
476
+ const response = await register(body, organization, token);
477
+ expect(response.body.registrations.length).toBe(1);
478
+
479
+ const receivableBalanceAfter = await getReceivableBalance(ReceivableBalanceType.user, user.id, organization, token);
480
+
481
+ expect(receivableBalanceAfter.body.balanceItems.length).toBe(2);
482
+ expect(receivableBalanceAfter.body.amountPending).toBe(35);
483
+ expect(receivableBalanceAfter.body.amountOpen).toBe(10);
484
+
485
+ expect(receivableBalanceAfter.body.balanceItems).toEqual(expect.arrayContaining([
486
+ expect.objectContaining({
487
+ pricePending: 10,
488
+ }),
489
+ expect.objectContaining({
490
+ pricePending: 25,
491
+ }),
492
+ ]));
493
+ // #endregion
494
+ });
495
+ });
496
+
497
+ describe('Delete registrations', () => {
498
+ // todo: should include call to other endpoints?
499
+ test.skip('Should create negative balance items', async () => {
500
+ // #region arrange
501
+ const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
502
+
503
+ const registration = await new RegistrationFactory({
504
+ member,
505
+ group: group1,
506
+ groupPrice: groupPrice1,
507
+ }).create();
508
+
509
+ const group = await new GroupFactory({
510
+ organization,
511
+ price: 30,
512
+ stock: 5,
513
+ }).create();
514
+
515
+ const groupPrice = group.settings.prices[0];
516
+
517
+ const body = IDRegisterCheckout.create({
518
+ cart: IDRegisterCart.create({
519
+ items: [
520
+ IDRegisterItem.create({
521
+ id: uuidv4(),
522
+ replaceRegistrationIds: [],
523
+ options: [],
524
+ groupPrice,
525
+ organizationId: organization.id,
526
+ groupId: group.id,
527
+ memberId: member.id,
528
+ }),
529
+ ],
530
+ balanceItems: [],
531
+ deleteRegistrationIds: [registration.id],
532
+ }),
533
+ administrationFee: 0,
534
+ freeContribution: 0,
535
+ paymentMethod: PaymentMethod.PointOfSale,
536
+ totalPrice: 5,
537
+ asOrganizationId: organization.id,
538
+ customer: null,
539
+ });
540
+ // #endregion
541
+
542
+ // #region act and assert
543
+ const response = await register(body, organization, token);
544
+
545
+ throw new Error('not implemented');
546
+ // #endregion
547
+ });
548
+
549
+ test.skip('Should apply cancelation fee', async () => {
550
+ throw new Error('Not implemented');
551
+ });
552
+
553
+ test.skip('Should fail if invalid cancelation fee', async () => {
554
+ throw new Error('Not implemented');
555
+ });
556
+ });
557
+
558
+ describe('Register for group with default age group', () => {
559
+ test('Should create membership', async () => {
560
+ // #region arrange
561
+ const date = new Date('2023-05-14');
562
+ jest.useFakeTimers().setSystemTime(date);
563
+
564
+ try {
565
+ const platformMembershipTypeConfig = PlatformMembershipTypeConfig.create({
566
+ startDate: period.startDate,
567
+ endDate: period.endDate,
568
+ });
569
+
570
+ const platformMembershipType = PlatformMembershipType.create({
571
+ name: 'werkjaar',
572
+ periods: new Map([
573
+ [period.id, platformMembershipTypeConfig],
574
+ ]),
575
+ });
576
+
577
+ const platform = await Platform.getShared();
578
+
579
+ platform.config.membershipTypes = [
580
+ platformMembershipType,
581
+ ];
582
+
583
+ const defaultAgeGroup = DefaultAgeGroup.create({
584
+ names: ['test groep'],
585
+ defaultMembershipTypeId: platformMembershipType.id,
586
+ });
587
+
588
+ platform.config.defaultAgeGroups = [defaultAgeGroup];
589
+
590
+ await platform.save();
591
+
592
+ const { member, group, groupPrice, organization, token } = await initData();
593
+
594
+ // todo: remove from initData
595
+ member.organizationId = null;
596
+ await member.save();
597
+
598
+ group.defaultAgeGroupId = defaultAgeGroup.id;
599
+ await group.save();
600
+
601
+ const organizationPeriod = new OrganizationRegistrationPeriod();
602
+ organizationPeriod.organizationId = organization.id;
603
+ organizationPeriod.periodId = period.id;
604
+ await organizationPeriod.save();
605
+
606
+ const body = IDRegisterCheckout.create({
607
+ cart: IDRegisterCart.create({
608
+ items: [
609
+ IDRegisterItem.create({
610
+ id: uuidv4(),
611
+ replaceRegistrationIds: [],
612
+ options: [],
613
+ groupPrice: groupPrice,
614
+ organizationId: organization.id,
615
+ groupId: group.id,
616
+ memberId: member.id,
617
+ trial: false,
618
+ }),
619
+ ],
620
+ balanceItems: [],
621
+ deleteRegistrationIds: [],
622
+ }),
623
+ administrationFee: 0,
624
+ freeContribution: 0,
625
+ paymentMethod: PaymentMethod.PointOfSale,
626
+ totalPrice: 25,
627
+ asOrganizationId: organization.id,
628
+ customer: null,
629
+ });
630
+ // #endregion
631
+
632
+ // act and assert
633
+ const familyBefore = await getMemberFamily(member.id, organization, token);
634
+ expect(familyBefore).toBeDefined();
635
+ expect(familyBefore.body.members.length).toBe(1);
636
+ expect(familyBefore.body.members[0]).toBeDefined();
637
+ expect(familyBefore.body.members[0].platformMemberships.length).toBe(0);
638
+
639
+ const response = await register(body, organization, token);
640
+
641
+ expect(response.body).toBeDefined();
642
+ expect(response.body.registrations.length).toBe(1);
643
+
644
+ const familyAfter = await getMemberFamily(member.id, organization, token);
645
+ expect(familyAfter).toBeDefined();
646
+ expect(familyAfter.body.members.length).toBe(1);
647
+ expect(familyAfter.body.members[0]).toBeDefined();
648
+ expect(familyAfter.body.members[0].platformMemberships.length).toBe(1);
649
+ expect(familyAfter.body.members[0].platformMemberships[0].membershipTypeId).toBe(platformMembershipType.id);
650
+ }
651
+ finally {
652
+ jest.useFakeTimers().resetAllMocks();
653
+ }
654
+ });
655
+
656
+ test('Should set trial until on membership if trial', async () => {
657
+ // #region arrange
658
+ const date = new Date('2023-05-14');
659
+ jest.useFakeTimers().setSystemTime(date);
660
+
661
+ try {
662
+ const platformMembershipTypeConfig = PlatformMembershipTypeConfig.create({
663
+ startDate: period.startDate,
664
+ endDate: period.endDate,
665
+ trialDays: 10,
666
+ });
667
+
668
+ const platformMembershipType = PlatformMembershipType.create({
669
+ name: 'werkjaar',
670
+ periods: new Map([
671
+ [period.id, platformMembershipTypeConfig],
672
+ ]),
673
+ });
674
+
675
+ const platform = await Platform.getShared();
676
+
677
+ platform.config.membershipTypes = [
678
+ platformMembershipType,
679
+ ];
680
+
681
+ const defaultAgeGroup = DefaultAgeGroup.create({
682
+ names: ['test groep'],
683
+ defaultMembershipTypeId: platformMembershipType.id,
684
+ });
685
+
686
+ platform.config.defaultAgeGroups = [defaultAgeGroup];
687
+
688
+ await platform.save();
689
+
690
+ const { member, group, groupPrice, organization, token } = await initData();
691
+
692
+ // todo: remove from initData
693
+ member.organizationId = null;
694
+ await member.save();
695
+
696
+ group.settings.trialDays = 5;
697
+ group.defaultAgeGroupId = defaultAgeGroup.id;
698
+ await group.save();
699
+
700
+ const organizationPeriod = new OrganizationRegistrationPeriod();
701
+ organizationPeriod.organizationId = organization.id;
702
+ organizationPeriod.periodId = period.id;
703
+ await organizationPeriod.save();
704
+
705
+ const body = IDRegisterCheckout.create({
706
+ cart: IDRegisterCart.create({
707
+ items: [
708
+ IDRegisterItem.create({
709
+ id: uuidv4(),
710
+ replaceRegistrationIds: [],
711
+ options: [],
712
+ groupPrice: groupPrice,
713
+ organizationId: organization.id,
714
+ groupId: group.id,
715
+ memberId: member.id,
716
+ trial: true,
717
+ }),
718
+ ],
719
+ balanceItems: [],
720
+ deleteRegistrationIds: [],
721
+ }),
722
+ administrationFee: 0,
723
+ freeContribution: 0,
724
+ paymentMethod: PaymentMethod.PointOfSale,
725
+ totalPrice: 0,
726
+ asOrganizationId: organization.id,
727
+ customer: null,
728
+ });
729
+ // #endregion
730
+
731
+ // act and assert
732
+ const familyBefore = await getMemberFamily(member.id, organization, token);
733
+ expect(familyBefore).toBeDefined();
734
+ expect(familyBefore.body.members.length).toBe(1);
735
+ expect(familyBefore.body.members[0]).toBeDefined();
736
+ expect(familyBefore.body.members[0].platformMemberships.length).toBe(0);
737
+
738
+ const response = await register(body, organization, token);
739
+
740
+ expect(response.body).toBeDefined();
741
+ expect(response.body.registrations.length).toBe(1);
742
+
743
+ const familyAfter = await getMemberFamily(member.id, organization, token);
744
+ expect(familyAfter).toBeDefined();
745
+ expect(familyAfter.body.members.length).toBe(1);
746
+ expect(familyAfter.body.members[0]).toBeDefined();
747
+ expect(familyAfter.body.members[0].platformMemberships.length).toBe(1);
748
+ expect(familyAfter.body.members[0].platformMemberships[0].membershipTypeId).toBe(platformMembershipType.id);
749
+
750
+ const trialUntil = familyAfter.body.members[0].platformMemberships[0].trialUntil;
751
+
752
+ expect(trialUntil).not.toBeNull();
753
+ expect(trialUntil!.getFullYear()).toBe(2023);
754
+ expect(trialUntil!.getMonth()).toBe(4);
755
+ expect(trialUntil!.getDate()).toBe(24);
756
+ }
757
+ finally {
758
+ jest.useFakeTimers().resetAllMocks();
759
+ }
760
+ });
761
+ });
762
+ });