@stamhoofd/backend 2.83.5 → 2.84.1
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.
- package/index.ts +19 -4
- package/package.json +18 -14
- package/src/crons/amazon-ses.ts +26 -5
- package/src/crons/balance-emails.ts +18 -17
- package/src/email-recipient-loaders/registrations.ts +87 -0
- package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +5 -2
- package/src/endpoints/global/email/PatchEmailEndpoint.test.ts +40 -40
- package/src/endpoints/global/events/PatchEventNotificationsEndpoint.test.ts +28 -22
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +81 -49
- package/src/endpoints/global/files/UploadFile.ts +11 -16
- package/src/endpoints/global/groups/GetGroupsEndpoint.test.ts +234 -0
- package/src/endpoints/global/groups/GetGroupsEndpoint.ts +117 -43
- package/src/endpoints/global/members/GetMembersEndpoint.test.ts +1054 -0
- package/src/endpoints/global/members/GetMembersEndpoint.ts +163 -141
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.test.ts +6 -6
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +0 -16
- package/src/endpoints/global/members/helpers/validateGroupFilter.ts +73 -0
- package/src/endpoints/global/registration/GetPaymentRegistrations.ts +1 -2
- package/src/endpoints/global/registration/GetRegistrationsCountEndpoint.ts +43 -0
- package/src/endpoints/global/registration/GetRegistrationsEndpoint.test.ts +1016 -0
- package/src/endpoints/global/registration/GetRegistrationsEndpoint.ts +234 -0
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.test.ts +5 -5
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +474 -554
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +191 -52
- package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +107 -9
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.test.ts +89 -0
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +9 -6
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.test.ts +88 -0
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +0 -6
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +10 -6
- package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +10 -25
- package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +0 -5
- package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +0 -5
- package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint.ts +4 -0
- package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts +1 -0
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.test.ts +44 -19
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +140 -25
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +40 -10
- package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.test.ts +2 -2
- package/src/endpoints/organization/dashboard/users/PatchApiUserEndpoint.test.ts +2 -2
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +4 -1
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +2 -2
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +2 -2
- package/src/excel-loaders/members.ts +233 -232
- package/src/excel-loaders/payments.ts +1 -1
- package/src/excel-loaders/receivable-balances.ts +1 -1
- package/src/excel-loaders/registrations.ts +153 -0
- package/src/helpers/AdminPermissionChecker.ts +65 -37
- package/src/helpers/AuthenticatedStructures.ts +43 -3
- package/src/helpers/Context.ts +29 -1
- package/src/helpers/GlobalHelper.ts +3 -1
- package/src/helpers/GroupedThrottledQueue.test.ts +219 -0
- package/src/helpers/GroupedThrottledQueue.ts +108 -0
- package/src/helpers/LimitedFilteredRequestHelper.ts +26 -1
- package/src/helpers/MemberCharger.ts +0 -5
- package/src/helpers/MembershipCharger.ts +3 -9
- package/src/helpers/OrganizationCharger.ts +0 -5
- package/src/helpers/ThrottledQueue.test.ts +194 -0
- package/src/helpers/ThrottledQueue.ts +145 -0
- package/src/helpers/XlsxTransformerColumnHelper.ts +44 -1
- package/src/middleware/ContextMiddleware.ts +1 -1
- package/src/seeds/1728928974-update-cached-outstanding-balance-from-items.ts +2 -1
- package/src/seeds/1735577912-update-cached-outstanding-balance-from-items.ts +2 -1
- package/src/services/BalanceItemPaymentService.ts +1 -33
- package/src/services/BalanceItemService.ts +167 -48
- package/src/services/FileSignService.ts +18 -13
- package/src/services/MemberRecordStore.ts +28 -19
- package/src/services/PaymentReallocationService.test.ts +25 -14
- package/src/services/PaymentReallocationService.ts +29 -10
- package/src/services/PaymentService.ts +4 -16
- package/src/services/PlatformMembershipService.ts +8 -4
- package/src/services/RegistrationService.ts +66 -2
- package/src/sql-filters/base-registration-filter-compilers.ts +43 -0
- package/src/sql-filters/groups.ts +67 -0
- package/src/sql-filters/members.ts +33 -58
- package/src/sql-filters/organization-registration-periods.ts +8 -0
- package/src/sql-filters/registration-periods.ts +8 -0
- package/src/sql-filters/registrations.ts +11 -22
- package/src/sql-sorters/groups.ts +24 -0
- package/src/sql-sorters/organization-registration-periods.ts +24 -0
- package/src/sql-sorters/registration-periods.ts +47 -0
- package/src/sql-sorters/registrations.ts +77 -0
- package/tests/actions/patchOrganizationMember.ts +27 -0
- package/tests/actions/patchPaymentStatus.ts +45 -0
- package/tests/actions/patchUserMember.ts +27 -0
- package/tests/assertions/assertBalances.ts +49 -0
- package/tests/e2e/api-rate-limits.test.ts +5 -5
- package/tests/e2e/bundle-discounts.test.ts +4060 -0
- package/tests/e2e/charge-members.test.ts +27 -24
- package/tests/e2e/documents.test.ts +398 -0
- package/tests/e2e/register.test.ts +292 -312
- package/tests/helpers/PayconiqMocker.ts +55 -0
- package/tests/init/index.ts +5 -0
- package/tests/init/initAdmin.ts +14 -0
- package/tests/init/initBundleDiscount.ts +47 -0
- package/tests/init/initPayconiq.ts +9 -0
- package/tests/init/initPlatformAdmin.ts +13 -0
- package/tests/init/initStripe.ts +21 -0
- package/tests/jest.setup.ts +29 -0
- package/src/seeds-temporary/1736266448-recall-balance-item-price-paid.ts +0 -70
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Request, Response } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { GroupFactory, MemberFactory, Organization, OrganizationFactory, RegistrationFactory, RegistrationPeriod, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
|
|
3
3
|
import { AccessRight, BalanceItemWithPayments, ChargeMembersRequest, LimitedFilteredRequest, PermissionLevel, PermissionRoleDetailed, Permissions, PermissionsResourceType, ResourcePermissions, StamhoofdFilter, Version } from '@stamhoofd/structures';
|
|
4
|
-
import { TestUtils } from '@stamhoofd/test-utils';
|
|
4
|
+
import { STExpect, TestUtils } from '@stamhoofd/test-utils';
|
|
5
5
|
import { ChargeMembersEndpoint } from '../../src/endpoints/admin/members/ChargeMembersEndpoint';
|
|
6
|
-
import { GetMemberBalanceEndpoint } from '../../src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint';
|
|
7
6
|
import { testServer } from '../helpers/TestServer';
|
|
7
|
+
import { GetReceivableBalanceEndpoint } from '../../src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint';
|
|
8
8
|
|
|
9
9
|
describe('E2E.ChargeMembers', () => {
|
|
10
10
|
const chargeMembersEndpoint = new ChargeMembersEndpoint();
|
|
11
|
-
const
|
|
11
|
+
const getReceivableBalanceEndpoint = new GetReceivableBalanceEndpoint();
|
|
12
12
|
let period: RegistrationPeriod;
|
|
13
13
|
let organization: Organization;
|
|
14
14
|
let otherOrganization: Organization;
|
|
@@ -27,10 +27,10 @@ describe('E2E.ChargeMembers', () => {
|
|
|
27
27
|
return await testServer.test(chargeMembersEndpoint, request);
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
const getBalance = async (memberId: string, organization: Organization, token: Token): Promise<
|
|
31
|
-
const request = Request.buildJson('GET', `/v${Version}/
|
|
30
|
+
const getBalance = async (memberId: string, organization: Organization, token: Token): Promise<BalanceItemWithPayments[]> => {
|
|
31
|
+
const request = Request.buildJson('GET', `/v${Version}/receivable-balances/member/${memberId}`, organization.getApiHost());
|
|
32
32
|
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
33
|
-
return await testServer.test(
|
|
33
|
+
return (await testServer.test(getReceivableBalanceEndpoint, request)).body.balanceItems;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
const createUserData = async (permissions: Permissions | null | undefined, roles: PermissionRoleDetailed[]) => {
|
|
@@ -149,7 +149,7 @@ describe('E2E.ChargeMembers', () => {
|
|
|
149
149
|
|
|
150
150
|
await expect(async () => await postCharge(filter, organization, body, token))
|
|
151
151
|
.rejects
|
|
152
|
-
.toThrow('
|
|
152
|
+
.toThrow(STExpect.errorWithCode('permission_denied'));
|
|
153
153
|
}
|
|
154
154
|
});
|
|
155
155
|
|
|
@@ -181,10 +181,10 @@ describe('E2E.ChargeMembers', () => {
|
|
|
181
181
|
expect(result.body).toBeUndefined();
|
|
182
182
|
|
|
183
183
|
// act and assert
|
|
184
|
-
const testBalanceResponse = (response:
|
|
184
|
+
const testBalanceResponse = (response: BalanceItemWithPayments[]) => {
|
|
185
185
|
expect(response).toBeDefined();
|
|
186
|
-
expect(response.
|
|
187
|
-
const balanceItem1 = response
|
|
186
|
+
expect(response.length).toBe(1);
|
|
187
|
+
const balanceItem1 = response[0];
|
|
188
188
|
expect(balanceItem1.price).toEqual(12);
|
|
189
189
|
expect(balanceItem1.amount).toEqual(body.amount);
|
|
190
190
|
expect(balanceItem1.description).toEqual(body.description);
|
|
@@ -245,9 +245,9 @@ describe('E2E.ChargeMembers', () => {
|
|
|
245
245
|
expect(result).toBeDefined();
|
|
246
246
|
expect(result.body).toBeUndefined();
|
|
247
247
|
|
|
248
|
-
const testBalanceResponse = (response:
|
|
248
|
+
const testBalanceResponse = (response: BalanceItemWithPayments[]) => {
|
|
249
249
|
expect(response).toBeDefined();
|
|
250
|
-
expect(response.
|
|
250
|
+
expect(response.length).toBe(0);
|
|
251
251
|
};
|
|
252
252
|
|
|
253
253
|
testBalanceResponse(await getBalance(member1.id, otherOrganization, otherFinancialDirectorToken));
|
|
@@ -340,8 +340,10 @@ describe('E2E.ChargeMembers', () => {
|
|
|
340
340
|
await new RegistrationFactory({ member: member2, group }).create();
|
|
341
341
|
|
|
342
342
|
const filter: StamhoofdFilter = {
|
|
343
|
-
|
|
344
|
-
$
|
|
343
|
+
registrations: {
|
|
344
|
+
$elemMatch: {
|
|
345
|
+
groupId: group.id,
|
|
346
|
+
},
|
|
345
347
|
},
|
|
346
348
|
};
|
|
347
349
|
|
|
@@ -358,16 +360,15 @@ describe('E2E.ChargeMembers', () => {
|
|
|
358
360
|
expect(result.body).toBeUndefined();
|
|
359
361
|
|
|
360
362
|
// act and assert
|
|
361
|
-
const testBalanceResponse = (response:
|
|
363
|
+
const testBalanceResponse = (response: BalanceItemWithPayments[]) => {
|
|
362
364
|
expect(response).toBeDefined();
|
|
363
|
-
expect(response.
|
|
364
|
-
const balanceItem1 = response
|
|
365
|
+
expect(response.length).toBe(1);
|
|
366
|
+
const balanceItem1 = response[0];
|
|
365
367
|
expect(balanceItem1.price).toEqual(12);
|
|
366
|
-
expect(balanceItem1.amount).toEqual(
|
|
367
|
-
expect(balanceItem1.description).toEqual(
|
|
368
|
+
expect(balanceItem1.amount).toEqual(4);
|
|
369
|
+
expect(balanceItem1.description).toEqual('test description');
|
|
368
370
|
expect(balanceItem1.organizationId).toEqual(organization.id);
|
|
369
|
-
|
|
370
|
-
expect(balanceItem1.dueAt).toEqual(body.dueAt);
|
|
371
|
+
expect(balanceItem1.dueAt).toEqual(new Date(2023, 0, 10));
|
|
371
372
|
expect(balanceItem1.createdAt).toEqual(body.createdAt);
|
|
372
373
|
};
|
|
373
374
|
|
|
@@ -408,8 +409,10 @@ describe('E2E.ChargeMembers', () => {
|
|
|
408
409
|
await new RegistrationFactory({ member: member2, group }).create();
|
|
409
410
|
|
|
410
411
|
const filter: StamhoofdFilter = {
|
|
411
|
-
|
|
412
|
-
$
|
|
412
|
+
registrations: {
|
|
413
|
+
$elemMatch: {
|
|
414
|
+
groupId: group.id,
|
|
415
|
+
},
|
|
413
416
|
},
|
|
414
417
|
};
|
|
415
418
|
|
|
@@ -423,7 +426,7 @@ describe('E2E.ChargeMembers', () => {
|
|
|
423
426
|
|
|
424
427
|
await expect(async () => await postCharge(filter, organization, body, token))
|
|
425
428
|
.rejects
|
|
426
|
-
.toThrow('
|
|
429
|
+
.toThrow(STExpect.errorWithCode('permission_denied'));
|
|
427
430
|
});
|
|
428
431
|
});
|
|
429
432
|
});
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { Request } from '@simonbackx/simple-endpoints';
|
|
2
|
+
import { Document, DocumentTemplateFactory, Group, GroupFactory, Member, MemberFactory, Organization, OrganizationFactory, OrganizationRegistrationPeriodFactory, Registration, RegistrationPeriod, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
|
|
3
|
+
import { IDRegisterCart, IDRegisterCheckout, IDRegisterItem, MemberDetails, MemberWithRegistrationsBlob, PaymentMethod } from '@stamhoofd/structures';
|
|
4
|
+
import { TestUtils } from '@stamhoofd/test-utils';
|
|
5
|
+
import { Formatter } from '@stamhoofd/utility';
|
|
6
|
+
import { RegisterMembersEndpoint } from '../../src/endpoints/global/registration/RegisterMembersEndpoint';
|
|
7
|
+
import { patchOrganizationMember } from '../actions/patchOrganizationMember';
|
|
8
|
+
import { markNotPaid, markPaid } from '../actions/patchPaymentStatus';
|
|
9
|
+
import { patchUserMember } from '../actions/patchUserMember';
|
|
10
|
+
import { testServer } from '../helpers/TestServer';
|
|
11
|
+
import { initAdmin } from '../init/initAdmin';
|
|
12
|
+
import { initStripe } from '../init/initStripe';
|
|
13
|
+
import { registrationUpdateQueue } from '../../src/services/BalanceItemService';
|
|
14
|
+
|
|
15
|
+
const baseUrl = `/members/register`;
|
|
16
|
+
|
|
17
|
+
describe('E2E.Documents', () => {
|
|
18
|
+
const endpoint = new RegisterMembersEndpoint();
|
|
19
|
+
let period: RegistrationPeriod;
|
|
20
|
+
|
|
21
|
+
const post = async (body: IDRegisterCheckout, organization: Organization, token: Token) => {
|
|
22
|
+
const request = Request.post({
|
|
23
|
+
path: baseUrl,
|
|
24
|
+
host: organization.getApiHost(),
|
|
25
|
+
body,
|
|
26
|
+
headers: {
|
|
27
|
+
authorization: 'Bearer ' + token.accessToken,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
return await testServer.test(endpoint, request);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
beforeAll(async () => {
|
|
34
|
+
const previousPeriod = await new RegistrationPeriodFactory({
|
|
35
|
+
startDate: new Date(2022, 0, 1),
|
|
36
|
+
endDate: new Date(2022, 11, 31),
|
|
37
|
+
}).create();
|
|
38
|
+
|
|
39
|
+
period = await new RegistrationPeriodFactory({
|
|
40
|
+
startDate: new Date(2023, 0, 1),
|
|
41
|
+
endDate: new Date(2030, 11, 31),
|
|
42
|
+
previousPeriodId: previousPeriod.id,
|
|
43
|
+
}).create();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
beforeEach(async () => {
|
|
47
|
+
TestUtils.setEnvironment('userMode', 'platform');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
jest.restoreAllMocks();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const initOrganization = async (registrationPeriod: RegistrationPeriod = period) => {
|
|
55
|
+
const organization = await new OrganizationFactory({ period: registrationPeriod })
|
|
56
|
+
.create();
|
|
57
|
+
|
|
58
|
+
const organizationRegistrationPeriod = await new OrganizationRegistrationPeriodFactory({ organization, period: registrationPeriod }).create();
|
|
59
|
+
|
|
60
|
+
return { organization, organizationRegistrationPeriod };
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
async function initData(options?: { paidOnly?: boolean; maxAge?: number }) {
|
|
64
|
+
const { organization, organizationRegistrationPeriod } = await initOrganization(period);
|
|
65
|
+
|
|
66
|
+
const user = await new UserFactory({
|
|
67
|
+
organization,
|
|
68
|
+
permissions: null,
|
|
69
|
+
}).create();
|
|
70
|
+
|
|
71
|
+
const token = await Token.createToken(user);
|
|
72
|
+
|
|
73
|
+
const member = await new MemberFactory({ organization, user })
|
|
74
|
+
.create();
|
|
75
|
+
|
|
76
|
+
const group = await new GroupFactory({
|
|
77
|
+
organization,
|
|
78
|
+
price: 25_00,
|
|
79
|
+
}).create();
|
|
80
|
+
|
|
81
|
+
const group2 = await new GroupFactory({
|
|
82
|
+
organization,
|
|
83
|
+
price: 15_00,
|
|
84
|
+
}).create();
|
|
85
|
+
|
|
86
|
+
const documentTemplate = await new DocumentTemplateFactory({
|
|
87
|
+
groups: [
|
|
88
|
+
group,
|
|
89
|
+
group2,
|
|
90
|
+
],
|
|
91
|
+
minPricePaid: options?.paidOnly ? 1 : null,
|
|
92
|
+
maxAge: options?.maxAge ?? null,
|
|
93
|
+
}).create();
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
organization,
|
|
97
|
+
organizationRegistrationPeriod,
|
|
98
|
+
user,
|
|
99
|
+
token,
|
|
100
|
+
member,
|
|
101
|
+
group,
|
|
102
|
+
group2,
|
|
103
|
+
documentTemplate,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function assertNoDocument(registration: { id: string }) {
|
|
108
|
+
await registrationUpdateQueue.flushAndWait();
|
|
109
|
+
const document = await Document.select().where('registrationId', registration.id).first(false);
|
|
110
|
+
expect(document).toBeNull();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function assertDocument({ registration, organization, member, group, price, pricePaid }: { registration: { id: string }; organization: Organization; member: Member; group: Group; price: number; pricePaid?: number }) {
|
|
114
|
+
await registrationUpdateQueue.flushAndWait();
|
|
115
|
+
const document = await Document.select().where('registrationId', registration.id).first(false);
|
|
116
|
+
expect(document).not.toBeNull();
|
|
117
|
+
|
|
118
|
+
const html = await document!.getRenderedHtml(organization);
|
|
119
|
+
|
|
120
|
+
const registrationModel = (await Registration.getByID(registration.id))!;
|
|
121
|
+
|
|
122
|
+
const expectations = [
|
|
123
|
+
member.firstName,
|
|
124
|
+
'Member name using other variable: ' + member.firstName,
|
|
125
|
+
member.lastName,
|
|
126
|
+
group.settings.name.toString(),
|
|
127
|
+
'Price: ' + Formatter.price(price),
|
|
128
|
+
organization.name,
|
|
129
|
+
Formatter.dateNumber(registrationModel.startDate!, true),
|
|
130
|
+
Formatter.dateNumber(group.settings.endDate, true),
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
if (pricePaid !== undefined) {
|
|
134
|
+
expectations.push('Price paid: ' + Formatter.price(pricePaid));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Assert some things in the HTML
|
|
138
|
+
for (const expectation of expectations || []) {
|
|
139
|
+
expect(html).toContain(expectation);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return document!;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
test('A document is created when a member registers and pays online', async () => {
|
|
146
|
+
const { organization, group, token, member } = await initData();
|
|
147
|
+
const { stripeMocker } = await initStripe({ organization });
|
|
148
|
+
|
|
149
|
+
// First register the member for group 1. No discount should be applied yet
|
|
150
|
+
const checkout1 = IDRegisterCheckout.create({
|
|
151
|
+
cart: IDRegisterCart.create({
|
|
152
|
+
items: [
|
|
153
|
+
IDRegisterItem.create({
|
|
154
|
+
groupPrice: group.settings.prices[0],
|
|
155
|
+
groupId: group.id,
|
|
156
|
+
organizationId: organization.id,
|
|
157
|
+
memberId: member.id,
|
|
158
|
+
}),
|
|
159
|
+
],
|
|
160
|
+
}),
|
|
161
|
+
paymentMethod: PaymentMethod.Bancontact,
|
|
162
|
+
totalPrice: 25_00,
|
|
163
|
+
redirectUrl: new URL('https://example.com/redirect'),
|
|
164
|
+
cancelUrl: new URL('https://example.com/cancel'),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const response = await post(checkout1, organization, token);
|
|
168
|
+
const registration = response.body.registrations[0];
|
|
169
|
+
await assertNoDocument(registration);
|
|
170
|
+
|
|
171
|
+
// Check no document for this registration yet
|
|
172
|
+
await stripeMocker.succeedPayment(stripeMocker.getLastIntent());
|
|
173
|
+
|
|
174
|
+
const registrationModel = await Registration.getByID(registration.id);
|
|
175
|
+
expect(registrationModel).not.toBeNull();
|
|
176
|
+
expect(registrationModel?.registeredAt).not.toBeNull();
|
|
177
|
+
|
|
178
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 25_00 });
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('Documents are created for non-paid registrations by default', async () => {
|
|
182
|
+
const { organization, group, token, member } = await initData({ paidOnly: false });
|
|
183
|
+
|
|
184
|
+
// First register the member for group 1. No discount should be applied yet
|
|
185
|
+
const checkout1 = IDRegisterCheckout.create({
|
|
186
|
+
cart: IDRegisterCart.create({
|
|
187
|
+
items: [
|
|
188
|
+
IDRegisterItem.create({
|
|
189
|
+
groupPrice: group.settings.prices[0],
|
|
190
|
+
groupId: group.id,
|
|
191
|
+
organizationId: organization.id,
|
|
192
|
+
memberId: member.id,
|
|
193
|
+
}),
|
|
194
|
+
],
|
|
195
|
+
}),
|
|
196
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
197
|
+
totalPrice: 25_00,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const response = await post(checkout1, organization, token);
|
|
201
|
+
const registration = response.body.registrations[0];
|
|
202
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 0 });
|
|
203
|
+
|
|
204
|
+
// Mark paid
|
|
205
|
+
await markPaid({ payment: response.body.payment!, organization });
|
|
206
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 25_00 });
|
|
207
|
+
|
|
208
|
+
// Mark unpaid
|
|
209
|
+
await markNotPaid({ payment: response.body.payment!, organization });
|
|
210
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 0 });
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('A paid-only document is only created when a payment is marked as paid', async () => {
|
|
214
|
+
const { organization, group, token, member } = await initData({ paidOnly: true });
|
|
215
|
+
|
|
216
|
+
// First register the member for group 1. No discount should be applied yet
|
|
217
|
+
const checkout1 = IDRegisterCheckout.create({
|
|
218
|
+
cart: IDRegisterCart.create({
|
|
219
|
+
items: [
|
|
220
|
+
IDRegisterItem.create({
|
|
221
|
+
groupPrice: group.settings.prices[0],
|
|
222
|
+
groupId: group.id,
|
|
223
|
+
organizationId: organization.id,
|
|
224
|
+
memberId: member.id,
|
|
225
|
+
}),
|
|
226
|
+
],
|
|
227
|
+
}),
|
|
228
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
229
|
+
totalPrice: 25_00,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const response = await post(checkout1, organization, token);
|
|
233
|
+
const registration = response.body.registrations[0];
|
|
234
|
+
await assertNoDocument(registration);
|
|
235
|
+
|
|
236
|
+
await markPaid({ payment: response.body.payment!, organization });
|
|
237
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 25_00 });
|
|
238
|
+
|
|
239
|
+
// Should be deleted again
|
|
240
|
+
await markNotPaid({ payment: response.body.payment!, organization });
|
|
241
|
+
await assertNoDocument(registration);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test('A maximum age document is not created for older members', async () => {
|
|
245
|
+
const { organization, group, token, member, user } = await initData({ maxAge: 10 });
|
|
246
|
+
member.details.birthDay = new Date(2000, 0, 1); // Make the member older than the maximum age
|
|
247
|
+
await member.save();
|
|
248
|
+
|
|
249
|
+
// First register the member for group 1. No discount should be applied yet
|
|
250
|
+
const checkout1 = IDRegisterCheckout.create({
|
|
251
|
+
cart: IDRegisterCart.create({
|
|
252
|
+
items: [
|
|
253
|
+
IDRegisterItem.create({
|
|
254
|
+
groupPrice: group.settings.prices[0],
|
|
255
|
+
groupId: group.id,
|
|
256
|
+
organizationId: organization.id,
|
|
257
|
+
memberId: member.id,
|
|
258
|
+
}),
|
|
259
|
+
],
|
|
260
|
+
}),
|
|
261
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
262
|
+
totalPrice: 25_00,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const response = await post(checkout1, organization, token);
|
|
266
|
+
const registration = response.body.registrations[0];
|
|
267
|
+
await assertNoDocument(registration);
|
|
268
|
+
await markPaid({ payment: response.body.payment!, organization });
|
|
269
|
+
await assertNoDocument(registration);
|
|
270
|
+
|
|
271
|
+
// Change the age of this member via an API endpoint
|
|
272
|
+
await patchOrganizationMember({
|
|
273
|
+
organization,
|
|
274
|
+
patch: MemberWithRegistrationsBlob.patch({
|
|
275
|
+
id: member.id,
|
|
276
|
+
details: MemberDetails.patch({
|
|
277
|
+
birthDay: new Date(),
|
|
278
|
+
}),
|
|
279
|
+
}),
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 25_00 });
|
|
283
|
+
await markNotPaid({ payment: response.body.payment!, organization });
|
|
284
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 0 });
|
|
285
|
+
|
|
286
|
+
// Change age again
|
|
287
|
+
await patchOrganizationMember({
|
|
288
|
+
organization,
|
|
289
|
+
patch: MemberWithRegistrationsBlob.patch({
|
|
290
|
+
id: member.id,
|
|
291
|
+
details: MemberDetails.patch({
|
|
292
|
+
birthDay: new Date(2000, 0, 1), // Make the member older than the maximum age
|
|
293
|
+
}),
|
|
294
|
+
}),
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
await assertNoDocument(registration);
|
|
298
|
+
|
|
299
|
+
// Change age as user (different endpoint, but should also have the same side effect)
|
|
300
|
+
await patchUserMember({
|
|
301
|
+
organization,
|
|
302
|
+
user,
|
|
303
|
+
patch: MemberWithRegistrationsBlob.patch({
|
|
304
|
+
id: member.id,
|
|
305
|
+
details: MemberDetails.patch({
|
|
306
|
+
birthDay: new Date(),
|
|
307
|
+
}),
|
|
308
|
+
}),
|
|
309
|
+
});
|
|
310
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 0 });
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test('A document is updated when a registration is moved by an admin', async () => {
|
|
314
|
+
const { organization, group, group2, token, member } = await initData({ paidOnly: false });
|
|
315
|
+
const { adminToken } = await initAdmin({ organization });
|
|
316
|
+
|
|
317
|
+
// First register the member for group 1. No discount should be applied yet
|
|
318
|
+
const checkout1 = IDRegisterCheckout.create({
|
|
319
|
+
cart: IDRegisterCart.create({
|
|
320
|
+
items: [
|
|
321
|
+
IDRegisterItem.create({
|
|
322
|
+
groupPrice: group.settings.prices[0],
|
|
323
|
+
groupId: group.id,
|
|
324
|
+
organizationId: organization.id,
|
|
325
|
+
memberId: member.id,
|
|
326
|
+
}),
|
|
327
|
+
],
|
|
328
|
+
}),
|
|
329
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
330
|
+
totalPrice: 25_00,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const response = await post(checkout1, organization, token);
|
|
334
|
+
const registration = response.body.registrations[0];
|
|
335
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 0 });
|
|
336
|
+
|
|
337
|
+
// Move
|
|
338
|
+
const checkout2 = IDRegisterCheckout.create({
|
|
339
|
+
cart: IDRegisterCart.create({
|
|
340
|
+
items: [
|
|
341
|
+
IDRegisterItem.create({
|
|
342
|
+
groupPrice: group2.settings.prices[0],
|
|
343
|
+
groupId: group2.id,
|
|
344
|
+
organizationId: organization.id,
|
|
345
|
+
memberId: member.id,
|
|
346
|
+
replaceRegistrationIds: [registration.id],
|
|
347
|
+
}),
|
|
348
|
+
],
|
|
349
|
+
}),
|
|
350
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
351
|
+
asOrganizationId: organization.id,
|
|
352
|
+
totalPrice: -10_00,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const response2 = await post(checkout2, organization, adminToken);
|
|
356
|
+
const registration2 = response2.body.registrations[0];
|
|
357
|
+
await assertDocument({ registration: registration2, organization, member, group: group2, price: 15_00, pricePaid: 0 });
|
|
358
|
+
await assertNoDocument(registration);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
test('A document is deleted when a registration is deleted by an admin', async () => {
|
|
362
|
+
const { organization, group, token, member } = await initData({ paidOnly: false });
|
|
363
|
+
const { adminToken } = await initAdmin({ organization });
|
|
364
|
+
|
|
365
|
+
// First register the member for group 1. No discount should be applied yet
|
|
366
|
+
const checkout1 = IDRegisterCheckout.create({
|
|
367
|
+
cart: IDRegisterCart.create({
|
|
368
|
+
items: [
|
|
369
|
+
IDRegisterItem.create({
|
|
370
|
+
groupPrice: group.settings.prices[0],
|
|
371
|
+
groupId: group.id,
|
|
372
|
+
organizationId: organization.id,
|
|
373
|
+
memberId: member.id,
|
|
374
|
+
}),
|
|
375
|
+
],
|
|
376
|
+
}),
|
|
377
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
378
|
+
totalPrice: 25_00,
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
const response = await post(checkout1, organization, token);
|
|
382
|
+
const registration = response.body.registrations[0];
|
|
383
|
+
await assertDocument({ registration, organization, member, group, price: 25_00, pricePaid: 0 });
|
|
384
|
+
|
|
385
|
+
// Move
|
|
386
|
+
const checkout2 = IDRegisterCheckout.create({
|
|
387
|
+
cart: IDRegisterCart.create({
|
|
388
|
+
deleteRegistrationIds: [registration.id],
|
|
389
|
+
}),
|
|
390
|
+
paymentMethod: PaymentMethod.PointOfSale,
|
|
391
|
+
asOrganizationId: organization.id,
|
|
392
|
+
totalPrice: -25_00,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
await post(checkout2, organization, adminToken);
|
|
396
|
+
await assertNoDocument(registration);
|
|
397
|
+
});
|
|
398
|
+
});
|