@stamhoofd/backend 2.83.4 → 2.84.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.
- 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
|
@@ -50,12 +50,15 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
|
|
|
50
50
|
periods.push(await PatchOrganizationRegistrationPeriodsEndpoint.createOrganizationPeriod(organization, put));
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
const forceGroupIds: string[] = [];
|
|
54
|
+
|
|
53
55
|
for (const patch of request.body.getPatches()) {
|
|
54
56
|
const organizationPeriod = await OrganizationRegistrationPeriod.getByID(patch.id);
|
|
55
57
|
if (!organizationPeriod || organizationPeriod.organizationId !== organization.id) {
|
|
56
58
|
throw new SimpleError({
|
|
57
59
|
code: 'not_found',
|
|
58
60
|
message: 'Period not found',
|
|
61
|
+
human: $t('347463a0-1e9a-40fe-996c-d77ba13bc05b'),
|
|
59
62
|
statusCode: 404,
|
|
60
63
|
});
|
|
61
64
|
}
|
|
@@ -66,16 +69,16 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
|
|
|
66
69
|
throw new SimpleError({
|
|
67
70
|
code: 'not_found',
|
|
68
71
|
message: 'Period not found',
|
|
72
|
+
human: $t('347463a0-1e9a-40fe-996c-d77ba13bc05b'),
|
|
69
73
|
statusCode: 404,
|
|
70
74
|
});
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
if (period.locked) {
|
|
74
78
|
throw new SimpleError({
|
|
75
|
-
code: '
|
|
76
|
-
message: '
|
|
77
|
-
human: $t(`
|
|
78
|
-
statusCode: 404,
|
|
79
|
+
code: 'locked_period',
|
|
80
|
+
message: 'This period is locked',
|
|
81
|
+
human: $t(`cc658db0-ee90-40fc-8a8c-1074a4f1f2f2`, { '2000-2001': period.getStructure().nameShort }),
|
|
79
82
|
});
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -209,12 +212,14 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
|
|
|
209
212
|
|
|
210
213
|
for (const groupPut of patch.groups.getPuts()) {
|
|
211
214
|
shouldUpdateSetupSteps = true;
|
|
212
|
-
await PatchOrganizationRegistrationPeriodsEndpoint.createGroup(groupPut.put, organization.id, period, { allowedIds });
|
|
215
|
+
const group = await PatchOrganizationRegistrationPeriodsEndpoint.createGroup(groupPut.put, organization.id, period, { allowedIds });
|
|
213
216
|
deleteUnreachable = true;
|
|
217
|
+
forceGroupIds.push(group.id);
|
|
214
218
|
}
|
|
215
219
|
|
|
216
220
|
for (const struct of patch.groups.getPatches()) {
|
|
217
|
-
await PatchOrganizationRegistrationPeriodsEndpoint.patchGroup(struct, period);
|
|
221
|
+
const group = await PatchOrganizationRegistrationPeriodsEndpoint.patchGroup(struct, period);
|
|
222
|
+
forceGroupIds.push(group.id);
|
|
218
223
|
}
|
|
219
224
|
|
|
220
225
|
if (deleteUnreachable) {
|
|
@@ -233,7 +238,7 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
|
|
|
233
238
|
}
|
|
234
239
|
|
|
235
240
|
return new Response(
|
|
236
|
-
await AuthenticatedStructures.organizationRegistrationPeriods(periods),
|
|
241
|
+
await AuthenticatedStructures.organizationRegistrationPeriods(periods, undefined, { forceGroupIds }),
|
|
237
242
|
);
|
|
238
243
|
}
|
|
239
244
|
|
|
@@ -272,19 +277,39 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
|
|
|
272
277
|
static async createOrganizationPeriod(organization: Organization, struct: OrganizationRegistrationPeriodStruct) {
|
|
273
278
|
const period = await RegistrationPeriod.getByID(struct.period.id);
|
|
274
279
|
|
|
275
|
-
if (!period
|
|
280
|
+
if (!period) {
|
|
276
281
|
throw new SimpleError({
|
|
277
282
|
code: 'not_found',
|
|
278
283
|
message: 'Period not found',
|
|
284
|
+
human: $t('347463a0-1e9a-40fe-996c-d77ba13bc05b'),
|
|
279
285
|
statusCode: 404,
|
|
280
286
|
});
|
|
281
287
|
}
|
|
282
288
|
|
|
289
|
+
if (period?.locked) {
|
|
290
|
+
throw new SimpleError({
|
|
291
|
+
code: 'locked_period',
|
|
292
|
+
message: 'Period is locked',
|
|
293
|
+
human: $t(`cc658db0-ee90-40fc-8a8c-1074a4f1f2f2`, { '2000-2001': period.getStructure().nameShort }),
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
283
297
|
const maximumStart = 1000 * 60 * 60 * 24 * 31 * 2; // 2 months in advance
|
|
284
|
-
if (period.startDate > new Date(Date.now() + maximumStart)) {
|
|
298
|
+
if (STAMHOOFD.environment !== 'development' && period.startDate > new Date(Date.now() + maximumStart)) {
|
|
285
299
|
throw new SimpleError({
|
|
286
300
|
code: 'invalid_field',
|
|
287
|
-
message: '
|
|
301
|
+
message: 'Period start date is too far in the future',
|
|
302
|
+
human: $t('2655c006-55af-47e6-959c-16acdb1917dc'),
|
|
303
|
+
field: 'period',
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Period has ended
|
|
308
|
+
if (STAMHOOFD.environment !== 'development' && period.endDate < new Date()) {
|
|
309
|
+
throw new SimpleError({
|
|
310
|
+
code: 'invalid_field',
|
|
311
|
+
message: 'Period has ended',
|
|
312
|
+
human: $t('44ff6618-ecbf-408b-9cc1-b1479e8ba8a2'),
|
|
288
313
|
field: 'period',
|
|
289
314
|
});
|
|
290
315
|
}
|
|
@@ -450,6 +475,8 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
|
|
|
450
475
|
|
|
451
476
|
await model.updateOccupancy();
|
|
452
477
|
await model.save();
|
|
478
|
+
|
|
479
|
+
return model;
|
|
453
480
|
}
|
|
454
481
|
|
|
455
482
|
static async createGroup(struct: GroupStruct, organizationId: string, period: RegistrationPeriod, options?: { allowedIds?: string[] }): Promise<Group> {
|
|
@@ -465,6 +492,9 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
|
|
|
465
492
|
}
|
|
466
493
|
}
|
|
467
494
|
}
|
|
495
|
+
else {
|
|
496
|
+
// For events, permission checking needs to happen outside this method (access to event = access to group)
|
|
497
|
+
}
|
|
468
498
|
|
|
469
499
|
if (period.locked) {
|
|
470
500
|
throw new SimpleError({
|
|
@@ -3,7 +3,7 @@ import { OrganizationFactory, Token, UserFactory } from '@stamhoofd/models';
|
|
|
3
3
|
|
|
4
4
|
import { testServer } from '../../../../../tests/helpers/TestServer';
|
|
5
5
|
import { PatchApiUserEndpoint } from './PatchApiUserEndpoint';
|
|
6
|
-
import {
|
|
6
|
+
import { STExpect, TestUtils } from '@stamhoofd/test-utils';
|
|
7
7
|
import { ApiUser, ApiUserRateLimits, PermissionLevel, Permissions, UserMeta, UserPermissions } from '@stamhoofd/structures';
|
|
8
8
|
import { CreateApiUserEndpoint } from './CreateApiUserEndpoint';
|
|
9
9
|
|
|
@@ -63,7 +63,7 @@ describe('Endpoint.CreateApiUserEndpoint', () => {
|
|
|
63
63
|
}));
|
|
64
64
|
createRequest.headers.authorization = 'Bearer ' + token.accessToken;
|
|
65
65
|
|
|
66
|
-
await expect(testServer.test(endpoint, createRequest)).rejects.toThrow(
|
|
66
|
+
await expect(testServer.test(endpoint, createRequest)).rejects.toThrow(STExpect.simpleError({
|
|
67
67
|
code: 'permission_denied',
|
|
68
68
|
}));
|
|
69
69
|
});
|
|
@@ -3,7 +3,7 @@ import { OrganizationFactory, Token, UserFactory } from '@stamhoofd/models';
|
|
|
3
3
|
|
|
4
4
|
import { testServer } from '../../../../../tests/helpers/TestServer';
|
|
5
5
|
import { PatchApiUserEndpoint } from './PatchApiUserEndpoint';
|
|
6
|
-
import {
|
|
6
|
+
import { STExpect, TestUtils } from '@stamhoofd/test-utils';
|
|
7
7
|
import { ApiUser, ApiUserRateLimits, PermissionLevel, Permissions, PermissionsResourceType, ResourcePermissions, UserMeta, UserPermissions } from '@stamhoofd/structures';
|
|
8
8
|
import { CreateApiUserEndpoint } from './CreateApiUserEndpoint';
|
|
9
9
|
import { PatchMap } from '@simonbackx/simple-encoding';
|
|
@@ -82,7 +82,7 @@ describe('Endpoint.PatchApiUserEndpoint', () => {
|
|
|
82
82
|
}));
|
|
83
83
|
r.headers.authorization = 'Bearer ' + token.accessToken;
|
|
84
84
|
|
|
85
|
-
await expect(testServer.test(endpoint, r)).rejects.toThrow(
|
|
85
|
+
await expect(testServer.test(endpoint, r)).rejects.toThrow(STExpect.simpleError({
|
|
86
86
|
code: 'permission_denied',
|
|
87
87
|
}));
|
|
88
88
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AutoEncoderPatchType, Decoder } from '@simonbackx/simple-encoding';
|
|
2
2
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
|
-
import {
|
|
4
|
+
import { Webshop } from '@stamhoofd/models';
|
|
5
5
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
6
6
|
import { PermissionLevel, PrivateWebshop, WebshopPrivateMetaData } from '@stamhoofd/structures';
|
|
7
7
|
import { Formatter } from '@stamhoofd/utility';
|
|
@@ -52,6 +52,9 @@ export class PatchWebshopEndpoint extends Endpoint<Params, Query, Body, Response
|
|
|
52
52
|
// Do all updates
|
|
53
53
|
if (request.body.meta) {
|
|
54
54
|
request.body.meta.domainActive = undefined;
|
|
55
|
+
if (request.body.meta.customCode !== undefined && !await Context.auth.hasFullAccess(organization.id)) {
|
|
56
|
+
throw Context.auth.error($t('c8e499c2-8d90-480c-a15e-d9da5291b40e'));
|
|
57
|
+
}
|
|
55
58
|
webshop.meta.patchOrPut(request.body.meta);
|
|
56
59
|
}
|
|
57
60
|
|
|
@@ -3,7 +3,7 @@ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-
|
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
4
|
import { BalanceItem, BalanceItemPayment, Order, Payment, Webshop, WebshopCounter } from '@stamhoofd/models';
|
|
5
5
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
6
|
-
import { AuditLogSource, BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItemType, OrderStatus, PaymentMethod, PaymentStatus, PermissionLevel, PrivateOrder, Webshop as WebshopStruct } from '@stamhoofd/structures';
|
|
6
|
+
import { AuditLogSource, BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItemType, OrderStatus, PaymentMethod, PaymentStatus, PermissionLevel, PrivateOrder, TranslatedString, Webshop as WebshopStruct } from '@stamhoofd/structures';
|
|
7
7
|
|
|
8
8
|
import { Context } from '../../../../helpers/Context';
|
|
9
9
|
import { AuditLogService } from '../../../../services/AuditLogService';
|
|
@@ -178,7 +178,7 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
178
178
|
BalanceItemRelationType.Webshop,
|
|
179
179
|
BalanceItemRelation.create({
|
|
180
180
|
id: webshop.id,
|
|
181
|
-
name: webshop.meta.name,
|
|
181
|
+
name: new TranslatedString(webshop.meta.name),
|
|
182
182
|
}),
|
|
183
183
|
],
|
|
184
184
|
]);
|
|
@@ -5,7 +5,7 @@ import { SimpleError } from '@simonbackx/simple-errors';
|
|
|
5
5
|
import { Email } from '@stamhoofd/email';
|
|
6
6
|
import { BalanceItem, BalanceItemPayment, MolliePayment, MollieToken, Order, PayconiqPayment, Payment, RateLimiter, Webshop, WebshopDiscountCode } from '@stamhoofd/models';
|
|
7
7
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
8
|
-
import { AuditLogSource, BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItemType, OrderData, OrderResponse, Order as OrderStruct, PaymentCustomer, PaymentMethod, PaymentMethodHelper, PaymentProvider, PaymentStatus, Payment as PaymentStruct, Version, WebshopAuthType, Webshop as WebshopStruct } from '@stamhoofd/structures';
|
|
8
|
+
import { AuditLogSource, BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItemType, OrderData, OrderResponse, Order as OrderStruct, PaymentCustomer, PaymentMethod, PaymentMethodHelper, PaymentProvider, PaymentStatus, Payment as PaymentStruct, TranslatedString, Version, WebshopAuthType, Webshop as WebshopStruct } from '@stamhoofd/structures';
|
|
9
9
|
import { Formatter } from '@stamhoofd/utility';
|
|
10
10
|
|
|
11
11
|
import { BuckarooHelper } from '../../../helpers/BuckarooHelper';
|
|
@@ -205,7 +205,7 @@ export class PlaceOrderEndpoint extends Endpoint<Params, Query, Body, ResponseBo
|
|
|
205
205
|
BalanceItemRelationType.Webshop,
|
|
206
206
|
BalanceItemRelation.create({
|
|
207
207
|
id: webshop.id,
|
|
208
|
-
name: webshop.meta.name,
|
|
208
|
+
name: new TranslatedString(webshop.meta.name),
|
|
209
209
|
}),
|
|
210
210
|
],
|
|
211
211
|
]);
|