@stamhoofd/backend 2.39.1 → 2.40.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/eslint.config.mjs +5 -0
- package/index.ts +81 -74
- package/jest.config.cjs +10 -0
- package/migrations.ts +16 -14
- package/package.json +11 -11
- package/src/crons/clear-excel-cache.test.ts +48 -50
- package/src/crons/clear-excel-cache.ts +18 -18
- package/src/crons/setup-steps.ts +2 -2
- package/src/crons.ts +325 -306
- package/src/decoders/StringArrayDecoder.ts +7 -7
- package/src/decoders/StringNullableDecoder.ts +1 -2
- package/src/email-recipient-loaders/members.ts +22 -22
- package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +8 -9
- package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +39 -40
- package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +8 -8
- package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +44 -45
- package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +58 -57
- package/src/endpoints/auth/CreateAdminEndpoint.ts +48 -45
- package/src/endpoints/auth/CreateTokenEndpoint.test.ts +31 -31
- package/src/endpoints/auth/CreateTokenEndpoint.ts +146 -147
- package/src/endpoints/auth/DeleteTokenEndpoint.ts +7 -7
- package/src/endpoints/auth/DeleteUserEndpoint.ts +15 -15
- package/src/endpoints/auth/ForgotPasswordEndpoint.ts +17 -18
- package/src/endpoints/auth/GetOtherUserEndpoint.ts +9 -10
- package/src/endpoints/auth/GetUserEndpoint.test.ts +32 -35
- package/src/endpoints/auth/GetUserEndpoint.ts +5 -6
- package/src/endpoints/auth/PatchApiUserEndpoint.ts +35 -33
- package/src/endpoints/auth/PatchUserEndpoint.ts +55 -52
- package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +9 -9
- package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +8 -8
- package/src/endpoints/auth/SignupEndpoint.ts +37 -36
- package/src/endpoints/auth/VerifyEmailEndpoint.ts +29 -28
- package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +33 -33
- package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +7 -7
- package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +37 -37
- package/src/endpoints/global/email/CreateEmailEndpoint.ts +30 -30
- package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +13 -13
- package/src/endpoints/global/email/GetEmailEndpoint.ts +13 -13
- package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +16 -16
- package/src/endpoints/global/email/PatchEmailEndpoint.ts +25 -25
- package/src/endpoints/global/events/GetEventsEndpoint.ts +43 -44
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +127 -172
- package/src/endpoints/global/files/ExportToExcelEndpoint.ts +49 -50
- package/src/endpoints/global/files/GetFileCache.ts +13 -13
- package/src/endpoints/global/files/UploadFile.ts +51 -54
- package/src/endpoints/global/files/UploadImage.ts +53 -53
- package/src/endpoints/global/groups/GetGroupsEndpoint.ts +25 -25
- package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +24 -23
- package/src/endpoints/global/members/GetMembersCountEndpoint.ts +8 -8
- package/src/endpoints/global/members/GetMembersEndpoint.ts +105 -102
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +240 -239
- package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +12 -14
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +32 -33
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +48 -57
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +21 -22
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +28 -28
- package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +18 -18
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +20 -20
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +17 -17
- package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +81 -75
- package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +14 -14
- package/src/endpoints/global/platform/GetPlatformEnpoint.ts +11 -11
- package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +71 -68
- package/src/endpoints/global/registration/GetPaymentRegistrations.ts +27 -27
- package/src/endpoints/global/registration/GetUserBillingStatusEndpoint.ts +30 -30
- package/src/endpoints/global/registration/GetUserDetailedBillingStatusEndpoint.ts +34 -34
- package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +26 -26
- package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +12 -12
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +90 -90
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +118 -121
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +362 -350
- package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +8 -9
- package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +21 -21
- package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +65 -65
- package/src/endpoints/organization/dashboard/billing/GetOrganizationBillingStatusEndpoint.ts +9 -9
- package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedBillingStatusEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +17 -17
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +21 -21
- package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +15 -15
- package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +52 -52
- package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplateEndpoint.ts +37 -37
- package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/email/EmailEndpoint.ts +113 -112
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +29 -29
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +48 -47
- package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +22 -21
- package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +13 -14
- package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +12 -13
- package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +24 -24
- package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +10 -12
- package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +14 -14
- package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +13 -13
- package/src/endpoints/organization/dashboard/organization/GetOrganizationSSOEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +120 -124
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +172 -173
- package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +88 -89
- package/src/endpoints/organization/dashboard/organization/SetOrganizationSSOEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +17 -17
- package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +8 -8
- package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +66 -67
- package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +47 -47
- package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +93 -91
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +16 -17
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +170 -167
- package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +25 -24
- package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +22 -23
- package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +22 -22
- package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +17 -18
- package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +8 -9
- package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +17 -18
- package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +14 -15
- package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +19 -19
- package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +19 -19
- package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +103 -100
- package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +11 -12
- package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +15 -15
- package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +23 -23
- package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +54 -52
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +84 -81
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +120 -111
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +24 -24
- package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +18 -18
- package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +141 -130
- package/src/endpoints/organization/shared/GetDocumentHtml.ts +25 -25
- package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +18 -18
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +36 -37
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +9 -9
- package/src/endpoints/organization/shared/auth/OpenIDConnectCallbackEndpoint.ts +11 -11
- package/src/endpoints/organization/shared/auth/OpenIDConnectStartEndpoint.ts +28 -27
- package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +20 -20
- package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +22 -22
- package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +14 -14
- package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +57 -56
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +65 -66
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +18 -17
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +124 -128
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +154 -145
- package/src/excel-loaders/members.ts +275 -273
- package/src/excel-loaders/payments.ts +155 -156
- package/src/helpers/AddressValidator.test.ts +32 -32
- package/src/helpers/AddressValidator.ts +128 -122
- package/src/helpers/AdminPermissionChecker.ts +339 -236
- package/src/helpers/AuthenticatedStructures.ts +233 -134
- package/src/helpers/BuckarooHelper.ts +134 -134
- package/src/helpers/CheckSettlements.ts +94 -88
- package/src/helpers/Context.ts +87 -86
- package/src/helpers/CookieHelper.ts +23 -22
- package/src/helpers/EmailResumer.ts +10 -10
- package/src/helpers/FileCache.ts +62 -62
- package/src/helpers/ForwardHandler.test.ts +122 -124
- package/src/helpers/ForwardHandler.ts +76 -70
- package/src/helpers/MemberUserSyncer.ts +101 -96
- package/src/helpers/MembershipCharger.ts +69 -69
- package/src/helpers/MembershipHelper.ts +11 -12
- package/src/helpers/OpenIDConnectHelper.ts +85 -82
- package/src/helpers/PeriodHelper.ts +65 -70
- package/src/helpers/StripeHelper.ts +146 -137
- package/src/helpers/StripePayoutChecker.ts +51 -52
- package/src/helpers/ViesHelper.ts +46 -44
- package/src/helpers/fetchToAsyncIterator.ts +14 -14
- package/src/helpers/xlsxAddressTransformerColumnFactory.ts +58 -60
- package/src/middleware/ContextMiddleware.ts +5 -5
- package/src/migrations/1646578856-validate-addresses.ts +6 -9
- package/src/seeds/0000000000-example.ts +3 -5
- package/src/seeds/1715028563-user-permissions.ts +16 -18
- package/src/seeds/1722256498-group-update-occupancy.ts +12 -12
- package/src/seeds/1722344162-sync-member-users.ts +14 -15
- package/src/seeds/1722344162-update-membership.ts +6 -6
- package/src/seeds/1726055544-balance-item-paid.ts +4 -4
- package/src/seeds/1726055545-balance-item-pending.ts +4 -4
- package/src/seeds/1726494419-update-cached-outstanding-balance.ts +16 -16
- package/src/seeds/1726494420-update-cached-outstanding-balance-from-items.ts +12 -12
- package/src/seeds/1726572303-schedule-stock-updates.ts +12 -12
- package/src/seeds/1726847064-setup-steps.ts +16 -0
- package/src/sql-filters/balance-item-payments.ts +7 -7
- package/src/sql-filters/events.ts +14 -14
- package/src/sql-filters/members.ts +96 -96
- package/src/sql-filters/organizations.ts +139 -75
- package/src/sql-filters/payments.ts +28 -28
- package/src/sql-filters/registrations.ts +14 -14
- package/src/sql-sorters/events.ts +25 -25
- package/src/sql-sorters/members.ts +26 -26
- package/src/sql-sorters/organizations.ts +36 -36
- package/src/sql-sorters/payments.ts +26 -26
- package/tests/e2e/stock.test.ts +616 -621
- package/tests/e2e/tickets.test.ts +255 -260
- package/tests/helpers/StripeMocker.ts +177 -179
- package/tests/helpers/TestServer.ts +9 -9
- package/tests/jest.global.setup.ts +14 -13
- package/tests/jest.setup.ts +33 -32
- package/.eslintrc.js +0 -61
- package/jest.config.js +0 -11
- package/src/helpers/SetupStepsUpdater.ts +0 -359
- package/src/seeds/1724076679-setup-steps.ts +0 -16
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { OneToManyRelation } from '@simonbackx/simple-database';
|
|
2
2
|
import { ConvertArrayToPatchableArray, Decoder, PatchableArrayAutoEncoder, PatchableArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
|
|
3
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
4
|
-
import { SimpleError } from
|
|
5
|
-
import { BalanceItem, Document, Group, Member, MemberFactory, MemberPlatformMembership, MemberResponsibilityRecord, MemberWithRegistrations, Organization, Platform, Registration, User } from '@stamhoofd/models';
|
|
6
|
-
import { GroupType, MemberWithRegistrationsBlob, MembersBlob, PermissionLevel } from
|
|
3
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
4
|
+
import { SimpleError } from '@simonbackx/simple-errors';
|
|
5
|
+
import { BalanceItem, Document, Group, Member, MemberFactory, MemberPlatformMembership, MemberResponsibilityRecord, MemberWithRegistrations, Organization, Platform, Registration, SetupStepUpdater, User } from '@stamhoofd/models';
|
|
6
|
+
import { GroupType, MemberWithRegistrationsBlob, MembersBlob, PermissionLevel } from '@stamhoofd/structures';
|
|
7
7
|
import { Formatter } from '@stamhoofd/utility';
|
|
8
8
|
|
|
9
|
+
import { QueueHandler } from '@stamhoofd/queues';
|
|
9
10
|
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
10
11
|
import { Context } from '../../../helpers/Context';
|
|
11
|
-
import { MemberUserSyncer } from '../../../helpers/MemberUserSyncer';
|
|
12
|
-
import { SetupStepUpdater } from '../../../helpers/SetupStepsUpdater';
|
|
13
12
|
import { MembershipCharger } from '../../../helpers/MembershipCharger';
|
|
14
|
-
import {
|
|
13
|
+
import { MemberUserSyncer } from '../../../helpers/MemberUserSyncer';
|
|
15
14
|
|
|
16
15
|
type Params = Record<string, never>;
|
|
17
16
|
type Query = undefined;
|
|
18
|
-
type Body = PatchableArrayAutoEncoder<MemberWithRegistrationsBlob
|
|
19
|
-
type ResponseBody = MembersBlob
|
|
17
|
+
type Body = PatchableArrayAutoEncoder<MemberWithRegistrationsBlob>;
|
|
18
|
+
type ResponseBody = MembersBlob;
|
|
20
19
|
|
|
21
20
|
/**
|
|
22
21
|
* One endpoint to create, patch and delete members and their registrations and payments
|
|
@@ -24,14 +23,14 @@ type ResponseBody = MembersBlob
|
|
|
24
23
|
|
|
25
24
|
export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
26
25
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
27
|
-
bodyDecoder = new PatchableArrayDecoder(MemberWithRegistrationsBlob as any, MemberWithRegistrationsBlob.patchType(), StringDecoder) as any as Decoder<ConvertArrayToPatchableArray<MemberWithRegistrationsBlob[]
|
|
26
|
+
bodyDecoder = new PatchableArrayDecoder(MemberWithRegistrationsBlob as any, MemberWithRegistrationsBlob.patchType(), StringDecoder) as any as Decoder<ConvertArrayToPatchableArray<MemberWithRegistrationsBlob[]>>;
|
|
28
27
|
|
|
29
28
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
30
|
-
if (request.method
|
|
29
|
+
if (request.method !== 'PATCH') {
|
|
31
30
|
return [false];
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
const params = Endpoint.parseParameters(request.url,
|
|
33
|
+
const params = Endpoint.parseParameters(request.url, '/organization/members', {});
|
|
35
34
|
|
|
36
35
|
if (params) {
|
|
37
36
|
return [true, params as Params];
|
|
@@ -41,240 +40,241 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
41
40
|
|
|
42
41
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
43
42
|
const organization = await Context.setOptionalOrganizationScope();
|
|
44
|
-
await Context.authenticate()
|
|
43
|
+
await Context.authenticate();
|
|
45
44
|
|
|
46
45
|
// Fast throw first (more in depth checking for patches later)
|
|
47
46
|
if (organization) {
|
|
48
47
|
if (!await Context.auth.hasSomeAccess(organization.id)) {
|
|
49
|
-
throw Context.auth.error()
|
|
50
|
-
}
|
|
51
|
-
}
|
|
48
|
+
throw Context.auth.error();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
52
|
if (!Context.auth.hasSomePlatformAccess()) {
|
|
53
|
-
throw Context.auth.error()
|
|
54
|
-
}
|
|
53
|
+
throw Context.auth.error();
|
|
54
|
+
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
const members: MemberWithRegistrations[] = []
|
|
57
|
+
const members: MemberWithRegistrations[] = [];
|
|
58
58
|
|
|
59
|
-
const platform = await Platform.getShared()
|
|
59
|
+
const platform = await Platform.getShared();
|
|
60
60
|
|
|
61
61
|
// Cache
|
|
62
|
-
const groups: Group[] = []
|
|
63
|
-
|
|
62
|
+
const groups: Group[] = [];
|
|
63
|
+
|
|
64
64
|
async function getGroup(id: string) {
|
|
65
|
-
const f = groups.find(g => g.id === id)
|
|
65
|
+
const f = groups.find(g => g.id === id);
|
|
66
66
|
if (f) {
|
|
67
|
-
return f
|
|
67
|
+
return f;
|
|
68
68
|
}
|
|
69
|
-
const group = await Group.getByID(id)
|
|
69
|
+
const group = await Group.getByID(id);
|
|
70
70
|
if (group) {
|
|
71
|
-
groups.push(group)
|
|
72
|
-
return group
|
|
71
|
+
groups.push(group);
|
|
72
|
+
return group;
|
|
73
73
|
}
|
|
74
|
-
return null
|
|
74
|
+
return null;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const updateMembershipMemberIds = new Set<string>()
|
|
78
|
-
const updateMembershipsForOrganizations = new Set<string>()
|
|
77
|
+
const updateMembershipMemberIds = new Set<string>();
|
|
78
|
+
const updateMembershipsForOrganizations = new Set<string>();
|
|
79
79
|
|
|
80
80
|
// Loop all members one by one
|
|
81
81
|
for (const put of request.body.getPuts()) {
|
|
82
|
-
const struct = put.put
|
|
82
|
+
const struct = put.put;
|
|
83
83
|
let member = new Member()
|
|
84
|
-
.setManyRelation(Member.registrations as any as OneToManyRelation<
|
|
85
|
-
.setManyRelation(Member.users, [])
|
|
86
|
-
member.id = struct.id
|
|
84
|
+
.setManyRelation(Member.registrations as any as OneToManyRelation<'registrations', Member, Registration & { group: Group }>, [])
|
|
85
|
+
.setManyRelation(Member.users, []);
|
|
86
|
+
member.id = struct.id;
|
|
87
87
|
|
|
88
88
|
if (organization && STAMHOOFD.userMode !== 'platform') {
|
|
89
|
-
member.organizationId = organization.id
|
|
89
|
+
member.organizationId = organization.id;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
struct.details.cleanData()
|
|
93
|
-
member.details = struct.details
|
|
92
|
+
struct.details.cleanData();
|
|
93
|
+
member.details = struct.details;
|
|
94
94
|
|
|
95
95
|
const duplicate = await PatchOrganizationMembersEndpoint.checkDuplicate(member);
|
|
96
96
|
if (duplicate) {
|
|
97
97
|
// Merge data
|
|
98
|
-
duplicate.details.merge(member.details)
|
|
99
|
-
member = duplicate
|
|
98
|
+
duplicate.details.merge(member.details);
|
|
99
|
+
member = duplicate;
|
|
100
100
|
|
|
101
101
|
// You need write permissions, because a user can potentially earn write permissions on a member
|
|
102
102
|
// by registering it
|
|
103
103
|
if (!await Context.auth.canAccessMember(duplicate, PermissionLevel.Write)) {
|
|
104
104
|
throw new SimpleError({
|
|
105
|
-
code:
|
|
106
|
-
message:
|
|
107
|
-
human:
|
|
108
|
-
statusCode: 400
|
|
109
|
-
})
|
|
105
|
+
code: 'known_member_missing_rights',
|
|
106
|
+
message: 'Creating known member without sufficient access rights',
|
|
107
|
+
human: 'Dit lid is al bekend in het systeem, maar je hebt er geen toegang tot. Vraag iemand met de juiste toegangsrechten om dit lid voor jou toe te voegen, of vraag het lid om zelf in te schrijven via het ledenportaal.',
|
|
108
|
+
statusCode: 400,
|
|
109
|
+
});
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
// We risk creating a new member without being able to access it manually afterwards
|
|
114
114
|
if ((organization && !await Context.auth.hasFullAccess(organization.id)) || (!organization && !Context.auth.hasPlatformFullAccess())) {
|
|
115
115
|
throw new SimpleError({
|
|
116
|
-
code:
|
|
117
|
-
message:
|
|
118
|
-
human:
|
|
119
|
-
statusCode: 400
|
|
120
|
-
})
|
|
116
|
+
code: 'missing_group',
|
|
117
|
+
message: 'Missing group',
|
|
118
|
+
human: 'Je moet hoofdbeheerder zijn om een lid toe te voegen in het systeem',
|
|
119
|
+
statusCode: 400,
|
|
120
|
+
});
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
if (STAMHOOFD.userMode !== 'platform' && !member.organizationId) {
|
|
124
124
|
throw new SimpleError({
|
|
125
|
-
code:
|
|
126
|
-
message:
|
|
127
|
-
human:
|
|
128
|
-
statusCode: 400
|
|
129
|
-
})
|
|
125
|
+
code: 'missing_organization',
|
|
126
|
+
message: 'Missing organization',
|
|
127
|
+
human: 'Je moet een organisatie selecteren voor dit lid',
|
|
128
|
+
statusCode: 400,
|
|
129
|
+
});
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
133
|
* In development mode, we allow some secret usernames to create fake data
|
|
134
134
|
*/
|
|
135
|
-
if ((STAMHOOFD.environment ==
|
|
136
|
-
if (member.details.firstName.toLocaleLowerCase() ==
|
|
135
|
+
if ((STAMHOOFD.environment == 'development' || STAMHOOFD.environment == 'staging') && organization) {
|
|
136
|
+
if (member.details.firstName.toLocaleLowerCase() == 'create' && parseInt(member.details.lastName) > 0) {
|
|
137
137
|
const count = parseInt(member.details.lastName);
|
|
138
|
-
await this.createDummyMembers(organization, count)
|
|
138
|
+
await this.createDummyMembers(organization, count);
|
|
139
139
|
|
|
140
140
|
// Skip creating this member
|
|
141
141
|
continue;
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
await member.save()
|
|
146
|
-
members.push(member)
|
|
147
|
-
updateMembershipMemberIds.add(member.id)
|
|
145
|
+
await member.save();
|
|
146
|
+
members.push(member);
|
|
147
|
+
updateMembershipMemberIds.add(member.id);
|
|
148
148
|
|
|
149
149
|
// Auto link users based on data
|
|
150
|
-
await MemberUserSyncer.onChangeMember(member)
|
|
150
|
+
await MemberUserSyncer.onChangeMember(member);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
let shouldUpdateSetupSteps = false;
|
|
154
154
|
|
|
155
155
|
// Loop all members one by one
|
|
156
156
|
for (let patch of request.body.getPatches()) {
|
|
157
|
-
const member = members.find(m => m.id === patch.id) ?? await Member.getWithRegistrations(patch.id)
|
|
157
|
+
const member = members.find(m => m.id === patch.id) ?? await Member.getWithRegistrations(patch.id);
|
|
158
158
|
if (!member || !await Context.auth.canAccessMember(member, PermissionLevel.Write)) {
|
|
159
|
-
throw Context.auth.notFoundOrNoAccess(
|
|
159
|
+
throw Context.auth.notFoundOrNoAccess('Je hebt geen toegang tot dit lid of het bestaat niet');
|
|
160
160
|
}
|
|
161
|
-
patch = await Context.auth.filterMemberPatch(member, patch)
|
|
161
|
+
patch = await Context.auth.filterMemberPatch(member, patch);
|
|
162
162
|
|
|
163
163
|
if (patch.details) {
|
|
164
164
|
if (patch.details.isPut()) {
|
|
165
165
|
throw new SimpleError({
|
|
166
|
-
code:
|
|
167
|
-
message:
|
|
168
|
-
human:
|
|
169
|
-
field:
|
|
170
|
-
})
|
|
166
|
+
code: 'not_allowed',
|
|
167
|
+
message: 'Cannot override details',
|
|
168
|
+
human: 'Er ging iets mis bij het aanpassen van de gegevens van dit lid. Probeer het later opnieuw en neem contact op als het probleem zich blijft voordoen.',
|
|
169
|
+
field: 'details',
|
|
170
|
+
});
|
|
171
171
|
}
|
|
172
|
-
|
|
173
|
-
const wasReduced = member.details.shouldApplyReducedPrice
|
|
174
|
-
member.details.patchOrPut(patch.details)
|
|
175
|
-
member.details.cleanData()
|
|
172
|
+
|
|
173
|
+
const wasReduced = member.details.shouldApplyReducedPrice;
|
|
174
|
+
member.details.patchOrPut(patch.details);
|
|
175
|
+
member.details.cleanData();
|
|
176
176
|
|
|
177
177
|
if (wasReduced !== member.details.shouldApplyReducedPrice) {
|
|
178
|
-
updateMembershipMemberIds.add(member.id)
|
|
178
|
+
updateMembershipMemberIds.add(member.id);
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
await member.save();
|
|
183
183
|
|
|
184
184
|
// Update documents
|
|
185
|
-
await Document.updateForMember(member.id)
|
|
185
|
+
await Document.updateForMember(member.id);
|
|
186
186
|
|
|
187
187
|
// Update responsibilities
|
|
188
188
|
for (const patchResponsibility of patch.responsibilities.getPatches()) {
|
|
189
189
|
if (!Context.auth.hasPlatformFullAccess() && !(organization && await Context.auth.hasFullAccess(organization.id))) {
|
|
190
|
-
throw Context.auth.error(
|
|
190
|
+
throw Context.auth.error('Je hebt niet voldoende rechten om functies van leden aan te passen');
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
const responsibilityRecord = await MemberResponsibilityRecord.getByID(patchResponsibility.id)
|
|
194
|
-
if (!responsibilityRecord || responsibilityRecord.memberId
|
|
193
|
+
const responsibilityRecord = await MemberResponsibilityRecord.getByID(patchResponsibility.id);
|
|
194
|
+
if (!responsibilityRecord || responsibilityRecord.memberId !== member.id || (organization && responsibilityRecord.organizationId !== organization.id)) {
|
|
195
195
|
throw new SimpleError({
|
|
196
|
-
code:
|
|
196
|
+
code: 'permission_denied',
|
|
197
197
|
message: "You don't have permissions to access this endpoint",
|
|
198
|
-
human:
|
|
199
|
-
})
|
|
198
|
+
human: 'Je hebt geen toegang om deze functie te wijzigen',
|
|
199
|
+
});
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
const platform = await Platform.getShared()
|
|
203
|
-
const responsibility = platform.config.responsibilities.find(r => r.id === patchResponsibility.responsibilityId)
|
|
202
|
+
const platform = await Platform.getShared();
|
|
203
|
+
const responsibility = platform.config.responsibilities.find(r => r.id === patchResponsibility.responsibilityId);
|
|
204
204
|
|
|
205
205
|
if (responsibility && !responsibility.organizationBased && !Context.auth.hasPlatformFullAccess()) {
|
|
206
|
-
throw Context.auth.error(
|
|
206
|
+
throw Context.auth.error('Je hebt niet voldoende rechten om deze functie aan te passen');
|
|
207
207
|
}
|
|
208
|
-
|
|
208
|
+
|
|
209
209
|
// Allow patching begin and end date
|
|
210
210
|
if (patchResponsibility.endDate !== undefined) {
|
|
211
211
|
if (responsibilityRecord.endDate) {
|
|
212
212
|
if (!Context.auth.hasPlatformFullAccess()) {
|
|
213
|
-
throw Context.auth.error(
|
|
213
|
+
throw Context.auth.error('Je hebt niet voldoende rechten om reeds beëindigde functies aan te passen');
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
|
-
responsibilityRecord.endDate = patchResponsibility.endDate
|
|
216
|
+
responsibilityRecord.endDate = patchResponsibility.endDate;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
if (patchResponsibility.startDate !== undefined) {
|
|
220
220
|
if (patchResponsibility.startDate.getTime() > Date.now() + 5 * 60 * 1000) {
|
|
221
|
-
throw Context.auth.error(
|
|
221
|
+
throw Context.auth.error('Je kan de startdatum van een functie niet in de toekomst zetten');
|
|
222
222
|
}
|
|
223
223
|
if (patchResponsibility.startDate.getTime() > Date.now()) {
|
|
224
|
-
patchResponsibility.startDate = new Date() // force now
|
|
224
|
+
patchResponsibility.startDate = new Date(); // force now
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
const daysDiff = Math.abs((new Date().getTime() - patchResponsibility.startDate.getTime()) / (1000 * 60 * 60 * 24))
|
|
227
|
+
const daysDiff = Math.abs((new Date().getTime() - patchResponsibility.startDate.getTime()) / (1000 * 60 * 60 * 24));
|
|
228
228
|
|
|
229
229
|
if (daysDiff > 60 && !Context.auth.hasPlatformFullAccess()) {
|
|
230
|
-
throw Context.auth.error(
|
|
230
|
+
throw Context.auth.error('Je kan de startdatum van een functie niet zoveel verplaatsen');
|
|
231
231
|
}
|
|
232
|
-
responsibilityRecord.startDate = patchResponsibility.startDate
|
|
232
|
+
responsibilityRecord.startDate = patchResponsibility.startDate;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
await responsibilityRecord.save()
|
|
235
|
+
await responsibilityRecord.save();
|
|
236
236
|
shouldUpdateSetupSteps = true;
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
// Create responsibilities
|
|
240
|
-
for (const {put} of patch.responsibilities.getPuts()) {
|
|
240
|
+
for (const { put } of patch.responsibilities.getPuts()) {
|
|
241
241
|
if (!Context.auth.hasPlatformFullAccess() && !(organization && await Context.auth.hasFullAccess(organization.id))) {
|
|
242
|
-
throw Context.auth.error(
|
|
242
|
+
throw Context.auth.error('Je hebt niet voldoende rechten om functies van leden aan te passen');
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
const platform = await Platform.getShared()
|
|
246
|
-
const platformResponsibility = platform.config.responsibilities.find(r => r.id === put.responsibilityId)
|
|
247
|
-
const org = organization ?? (put.organizationId ? await Organization.getByID(put.organizationId) : null)
|
|
245
|
+
const platform = await Platform.getShared();
|
|
246
|
+
const platformResponsibility = platform.config.responsibilities.find(r => r.id === put.responsibilityId);
|
|
247
|
+
const org = organization ?? (put.organizationId ? await Organization.getByID(put.organizationId) : null);
|
|
248
248
|
|
|
249
249
|
if (!org && put.organizationId) {
|
|
250
250
|
throw new SimpleError({
|
|
251
|
-
code:
|
|
252
|
-
message:
|
|
253
|
-
human:
|
|
254
|
-
field:
|
|
255
|
-
})
|
|
251
|
+
code: 'invalid_field',
|
|
252
|
+
message: 'Invalid organization',
|
|
253
|
+
human: 'Deze vereniging bestaat niet',
|
|
254
|
+
field: 'organizationId',
|
|
255
|
+
});
|
|
256
256
|
}
|
|
257
|
-
const responsibility = platformResponsibility ?? org?.privateMeta.responsibilities.find(r => r.id === put.responsibilityId)
|
|
257
|
+
const responsibility = platformResponsibility ?? org?.privateMeta.responsibilities.find(r => r.id === put.responsibilityId);
|
|
258
258
|
|
|
259
259
|
if (!responsibility) {
|
|
260
260
|
throw new SimpleError({
|
|
261
|
-
code:
|
|
262
|
-
message:
|
|
263
|
-
human:
|
|
264
|
-
field:
|
|
265
|
-
})
|
|
261
|
+
code: 'invalid_field',
|
|
262
|
+
message: 'Invalid responsibility',
|
|
263
|
+
human: 'Deze functie bestaat niet',
|
|
264
|
+
field: 'responsibilityId',
|
|
265
|
+
});
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
if (!org && responsibility.organizationBased) {
|
|
269
269
|
throw new SimpleError({
|
|
270
|
-
code:
|
|
271
|
-
message:
|
|
272
|
-
human:
|
|
273
|
-
field:
|
|
274
|
-
})
|
|
270
|
+
code: 'invalid_field',
|
|
271
|
+
message: 'Invalid organization',
|
|
272
|
+
human: 'Deze functie kan niet worden toegewezen aan deze vereniging',
|
|
273
|
+
field: 'organizationId',
|
|
274
|
+
});
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
-
const hasRegistration = member.registrations.some(registration => {
|
|
277
|
+
const hasRegistration = member.registrations.some((registration) => {
|
|
278
278
|
if (platformResponsibility) {
|
|
279
279
|
if (registration.group.defaultAgeGroupId === null) {
|
|
280
280
|
return false;
|
|
@@ -285,95 +285,96 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
285
285
|
if (registration.periodId !== org.periodId) {
|
|
286
286
|
return false;
|
|
287
287
|
}
|
|
288
|
-
}
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
289
290
|
if (registration.periodId !== platform.periodId) {
|
|
290
291
|
return false;
|
|
291
292
|
}
|
|
292
293
|
}
|
|
293
|
-
return registration.deactivatedAt === null && registration.registeredAt !== null && registration.group.type === GroupType.Membership
|
|
294
|
-
})
|
|
294
|
+
return registration.deactivatedAt === null && registration.registeredAt !== null && registration.group.type === GroupType.Membership;
|
|
295
|
+
});
|
|
295
296
|
|
|
296
297
|
if (!hasRegistration) {
|
|
297
298
|
throw new SimpleError({
|
|
298
|
-
code:
|
|
299
|
-
message:
|
|
300
|
-
human:
|
|
301
|
-
})
|
|
299
|
+
code: 'invalid_field',
|
|
300
|
+
message: 'Invalid organization',
|
|
301
|
+
human: 'Je kan een functie enkel toekennen aan leden die zijn ingeschreven in het huidige werkjaar',
|
|
302
|
+
});
|
|
302
303
|
}
|
|
303
304
|
|
|
304
|
-
const model = new MemberResponsibilityRecord()
|
|
305
|
-
model.memberId = member.id
|
|
306
|
-
model.responsibilityId = responsibility.id
|
|
307
|
-
model.organizationId = org?.id ?? null
|
|
305
|
+
const model = new MemberResponsibilityRecord();
|
|
306
|
+
model.memberId = member.id;
|
|
307
|
+
model.responsibilityId = responsibility.id;
|
|
308
|
+
model.organizationId = org?.id ?? null;
|
|
308
309
|
|
|
309
310
|
if (responsibility.organizationTagIds !== null && (!org || !org.meta.matchTags(responsibility.organizationTagIds))) {
|
|
310
311
|
throw new SimpleError({
|
|
311
|
-
code:
|
|
312
|
-
message:
|
|
313
|
-
human:
|
|
314
|
-
field:
|
|
315
|
-
})
|
|
312
|
+
code: 'invalid_field',
|
|
313
|
+
message: 'Invalid organization',
|
|
314
|
+
human: 'Deze functie is niet beschikbaar voor deze vereniging',
|
|
315
|
+
field: 'organizationId',
|
|
316
|
+
});
|
|
316
317
|
}
|
|
317
318
|
|
|
318
319
|
if (responsibility.defaultAgeGroupIds !== null) {
|
|
319
320
|
if (!put.groupId) {
|
|
320
321
|
throw new SimpleError({
|
|
321
|
-
code:
|
|
322
|
-
message:
|
|
323
|
-
human:
|
|
324
|
-
field:
|
|
325
|
-
})
|
|
322
|
+
code: 'invalid_field',
|
|
323
|
+
message: 'Missing groupId',
|
|
324
|
+
human: 'Kies een leeftijdsgroep waarvoor je deze functie wilt toekennen',
|
|
325
|
+
field: 'groupId',
|
|
326
|
+
});
|
|
326
327
|
}
|
|
327
328
|
|
|
328
|
-
const group = await Group.getByID(put.groupId)
|
|
329
|
+
const group = await Group.getByID(put.groupId);
|
|
329
330
|
if (!group || group.organizationId !== model.organizationId) {
|
|
330
331
|
throw new SimpleError({
|
|
331
|
-
code:
|
|
332
|
-
message:
|
|
333
|
-
human:
|
|
334
|
-
field:
|
|
335
|
-
})
|
|
332
|
+
code: 'invalid_field',
|
|
333
|
+
message: 'Invalid groupId',
|
|
334
|
+
human: 'Deze leeftijdsgroep bestaat niet',
|
|
335
|
+
field: 'groupId',
|
|
336
|
+
});
|
|
336
337
|
}
|
|
337
338
|
|
|
338
339
|
if (group.defaultAgeGroupId === null || !responsibility.defaultAgeGroupIds.includes(group.defaultAgeGroupId)) {
|
|
339
340
|
throw new SimpleError({
|
|
340
|
-
code:
|
|
341
|
-
message:
|
|
342
|
-
human:
|
|
343
|
-
field:
|
|
344
|
-
})
|
|
341
|
+
code: 'invalid_field',
|
|
342
|
+
message: 'Invalid groupId',
|
|
343
|
+
human: 'Deze leeftijdsgroep komt niet in aanmerking voor deze functie',
|
|
344
|
+
field: 'groupId',
|
|
345
|
+
});
|
|
345
346
|
}
|
|
346
347
|
|
|
347
|
-
model.groupId = group.id
|
|
348
|
+
model.groupId = group.id;
|
|
348
349
|
}
|
|
349
|
-
|
|
350
|
+
|
|
350
351
|
// Allow patching begin and end date
|
|
351
|
-
model.endDate = put.endDate
|
|
352
|
+
model.endDate = put.endDate;
|
|
352
353
|
|
|
353
354
|
if (put.startDate.getTime() > Date.now() + 5 * 60 * 1000) {
|
|
354
|
-
throw Context.auth.error(
|
|
355
|
+
throw Context.auth.error('Je kan de startdatum van een functie niet in de toekomst zetten');
|
|
355
356
|
}
|
|
356
357
|
|
|
357
358
|
if (put.startDate.getTime() > Date.now()) {
|
|
358
|
-
put.startDate = new Date() // force now
|
|
359
|
+
put.startDate = new Date(); // force now
|
|
359
360
|
}
|
|
360
361
|
|
|
361
|
-
if (put.endDate && put.endDate > new Date(Date.now() + 60*1000)) {
|
|
362
|
-
throw Context.auth.error(
|
|
362
|
+
if (put.endDate && put.endDate > new Date(Date.now() + 60 * 1000)) {
|
|
363
|
+
throw Context.auth.error('Je kan de einddatum van een functie niet in de toekomst zetten - kijk indien nodig je systeemtijd na');
|
|
363
364
|
}
|
|
364
365
|
|
|
365
|
-
model.startDate = put.startDate
|
|
366
|
+
model.startDate = put.startDate;
|
|
366
367
|
|
|
367
|
-
await model.save()
|
|
368
|
+
await model.save();
|
|
368
369
|
shouldUpdateSetupSteps = true;
|
|
369
370
|
}
|
|
370
371
|
|
|
371
372
|
// Auto link users based on data
|
|
372
|
-
await MemberUserSyncer.onChangeMember(member)
|
|
373
|
+
await MemberUserSyncer.onChangeMember(member);
|
|
373
374
|
|
|
374
375
|
// Allow to remove access for certain users
|
|
375
376
|
for (const id of patch.users.getDeletes()) {
|
|
376
|
-
const user = member.users.find(u => u.id === id)
|
|
377
|
+
const user = member.users.find(u => u.id === id);
|
|
377
378
|
if (!user) {
|
|
378
379
|
// Ignore silently
|
|
379
380
|
continue;
|
|
@@ -381,138 +382,138 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
381
382
|
|
|
382
383
|
if (MemberUserSyncer.doesEmailHaveAccess(member.details, user.email)) {
|
|
383
384
|
throw new SimpleError({
|
|
384
|
-
code:
|
|
385
|
-
message:
|
|
386
|
-
human:
|
|
385
|
+
code: 'invalid_field',
|
|
386
|
+
message: 'Invalid email',
|
|
387
|
+
human: 'Je kan een account niet de toegang ontzeggen tot een lid als het e-mailadres nog steeds is opgeslagen als onderdeel van de gegevens van dat lid. Verwijder eerst het e-mailadres uit de gegevens van het lid en ontkoppel daarna het account.',
|
|
387
388
|
});
|
|
388
389
|
}
|
|
389
390
|
|
|
390
391
|
// Remove access
|
|
391
|
-
await MemberUserSyncer.unlinkUser(user, member)
|
|
392
|
+
await MemberUserSyncer.unlinkUser(user, member);
|
|
392
393
|
}
|
|
393
394
|
|
|
394
395
|
// Add platform memberships
|
|
395
|
-
for (const {put} of patch.platformMemberships.getPuts()) {
|
|
396
|
+
for (const { put } of patch.platformMemberships.getPuts()) {
|
|
396
397
|
if (put.periodId !== platform.periodId) {
|
|
397
398
|
throw new SimpleError({
|
|
398
|
-
code:
|
|
399
|
-
message:
|
|
400
|
-
human:
|
|
401
|
-
field:
|
|
402
|
-
})
|
|
399
|
+
code: 'invalid_field',
|
|
400
|
+
message: 'Invalid period',
|
|
401
|
+
human: 'Je kan geen aansluitingen maken voor een andere werkjaar dan het actieve werkjaar',
|
|
402
|
+
field: 'periodId',
|
|
403
|
+
});
|
|
403
404
|
}
|
|
404
405
|
|
|
405
406
|
if (organization && put.organizationId !== organization.id) {
|
|
406
407
|
throw new SimpleError({
|
|
407
|
-
code:
|
|
408
|
-
message:
|
|
409
|
-
human:
|
|
410
|
-
field:
|
|
411
|
-
})
|
|
408
|
+
code: 'invalid_field',
|
|
409
|
+
message: 'Invalid organization',
|
|
410
|
+
human: 'Je kan geen aansluitingen maken voor een andere vereniging',
|
|
411
|
+
field: 'organizationId',
|
|
412
|
+
});
|
|
412
413
|
}
|
|
413
414
|
|
|
414
415
|
if (!await Context.auth.hasFullAccess(put.organizationId)) {
|
|
415
|
-
throw Context.auth.error(
|
|
416
|
+
throw Context.auth.error('Je hebt niet voldoende rechten om deze aansluiting toe te voegen');
|
|
416
417
|
}
|
|
417
418
|
|
|
418
419
|
if (!platform.config.membershipTypes.find(t => t.id === put.membershipTypeId)) {
|
|
419
420
|
throw new SimpleError({
|
|
420
|
-
code:
|
|
421
|
-
field:
|
|
422
|
-
message:
|
|
423
|
-
human:
|
|
424
|
-
})
|
|
421
|
+
code: 'invalid_field',
|
|
422
|
+
field: 'membershipTypeId',
|
|
423
|
+
message: 'Invalid membership type',
|
|
424
|
+
human: 'Dit aansluitingstype bestaat niet',
|
|
425
|
+
});
|
|
425
426
|
}
|
|
426
|
-
|
|
427
|
+
|
|
427
428
|
// Check duplicate memberships
|
|
428
429
|
|
|
429
430
|
// Check dates
|
|
430
431
|
|
|
431
432
|
// Calculate prices
|
|
432
433
|
|
|
433
|
-
const membership = new MemberPlatformMembership()
|
|
434
|
-
membership.id = put.id
|
|
435
|
-
membership.memberId = member.id
|
|
436
|
-
membership.membershipTypeId = put.membershipTypeId
|
|
437
|
-
membership.organizationId = put.organizationId
|
|
438
|
-
membership.periodId = put.periodId
|
|
434
|
+
const membership = new MemberPlatformMembership();
|
|
435
|
+
membership.id = put.id;
|
|
436
|
+
membership.memberId = member.id;
|
|
437
|
+
membership.membershipTypeId = put.membershipTypeId;
|
|
438
|
+
membership.organizationId = put.organizationId;
|
|
439
|
+
membership.periodId = put.periodId;
|
|
439
440
|
|
|
440
|
-
membership.startDate = put.startDate
|
|
441
|
-
membership.endDate = put.endDate
|
|
442
|
-
membership.expireDate = put.expireDate
|
|
441
|
+
membership.startDate = put.startDate;
|
|
442
|
+
membership.endDate = put.endDate;
|
|
443
|
+
membership.expireDate = put.expireDate;
|
|
443
444
|
|
|
444
|
-
await membership.calculatePrice(member)
|
|
445
|
-
await membership.save()
|
|
445
|
+
await membership.calculatePrice(member);
|
|
446
|
+
await membership.save();
|
|
446
447
|
|
|
447
|
-
updateMembershipMemberIds.add(member.id)
|
|
448
|
+
updateMembershipMemberIds.add(member.id);
|
|
448
449
|
}
|
|
449
450
|
|
|
450
451
|
// Delete platform memberships
|
|
451
452
|
for (const id of patch.platformMemberships.getDeletes()) {
|
|
452
|
-
const membership = await MemberPlatformMembership.getByID(id)
|
|
453
|
+
const membership = await MemberPlatformMembership.getByID(id);
|
|
453
454
|
|
|
454
455
|
if (!membership || membership.memberId !== member.id) {
|
|
455
456
|
throw new SimpleError({
|
|
456
|
-
code:
|
|
457
|
-
field:
|
|
458
|
-
message:
|
|
459
|
-
human:
|
|
460
|
-
})
|
|
457
|
+
code: 'invalid_field',
|
|
458
|
+
field: 'id',
|
|
459
|
+
message: 'Invalid id',
|
|
460
|
+
human: 'Deze aansluiting bestaat niet',
|
|
461
|
+
});
|
|
461
462
|
}
|
|
462
463
|
|
|
463
464
|
if (!await Context.auth.hasFullAccess(membership.organizationId)) {
|
|
464
|
-
throw Context.auth.error(
|
|
465
|
+
throw Context.auth.error('Je hebt niet voldoende rechten om deze aansluiting te verwijderen');
|
|
465
466
|
}
|
|
466
467
|
|
|
467
468
|
if (membership.periodId !== platform.periodId) {
|
|
468
469
|
throw new SimpleError({
|
|
469
|
-
code:
|
|
470
|
-
message:
|
|
471
|
-
human:
|
|
472
|
-
field:
|
|
473
|
-
})
|
|
470
|
+
code: 'invalid_field',
|
|
471
|
+
message: 'Invalid period',
|
|
472
|
+
human: 'Je kan geen aansluitingen meer verwijderen voor een ander werkjaar dan het actieve werkjaar',
|
|
473
|
+
field: 'periodId',
|
|
474
|
+
});
|
|
474
475
|
}
|
|
475
476
|
|
|
476
477
|
if (!membership.canDelete() && !Context.auth.hasPlatformFullAccess()) {
|
|
477
478
|
throw new SimpleError({
|
|
478
|
-
code:
|
|
479
|
-
message:
|
|
480
|
-
human:
|
|
481
|
-
})
|
|
479
|
+
code: 'invalid_field',
|
|
480
|
+
message: 'Invalid invoice',
|
|
481
|
+
human: 'Je kan geen aansluiting verwijderen die al werd gefactureerd',
|
|
482
|
+
});
|
|
482
483
|
}
|
|
483
484
|
|
|
484
485
|
await membership.doDelete();
|
|
485
|
-
updateMembershipsForOrganizations.add(membership.organizationId) // can influence free memberships in other members of same organization
|
|
486
|
-
updateMembershipMemberIds.add(member.id)
|
|
486
|
+
updateMembershipsForOrganizations.add(membership.organizationId); // can influence free memberships in other members of same organization
|
|
487
|
+
updateMembershipMemberIds.add(member.id);
|
|
487
488
|
}
|
|
488
489
|
|
|
489
490
|
if (!members.find(m => m.id === member.id)) {
|
|
490
|
-
members.push(member)
|
|
491
|
+
members.push(member);
|
|
491
492
|
}
|
|
492
493
|
}
|
|
493
494
|
|
|
494
|
-
await PatchOrganizationMembersEndpoint.deleteMembers(request.body.getDeletes())
|
|
495
|
-
|
|
495
|
+
await PatchOrganizationMembersEndpoint.deleteMembers(request.body.getDeletes());
|
|
496
|
+
|
|
496
497
|
for (const member of members) {
|
|
497
498
|
if (updateMembershipMemberIds.has(member.id)) {
|
|
498
|
-
await member.updateMemberships()
|
|
499
|
+
await member.updateMemberships();
|
|
499
500
|
}
|
|
500
501
|
}
|
|
501
502
|
|
|
502
503
|
if (updateMembershipsForOrganizations.size) {
|
|
503
504
|
QueueHandler.schedule('update-membership-prices', async () => {
|
|
504
505
|
for (const id of updateMembershipsForOrganizations) {
|
|
505
|
-
await MembershipCharger.updatePrices(id)
|
|
506
|
+
await MembershipCharger.updatePrices(id);
|
|
506
507
|
}
|
|
507
508
|
}).catch(console.error);
|
|
508
509
|
}
|
|
509
510
|
|
|
510
|
-
if(shouldUpdateSetupSteps && organization) {
|
|
511
|
+
if (shouldUpdateSetupSteps && organization) {
|
|
511
512
|
SetupStepUpdater.updateForOrganization(organization).catch(console.error);
|
|
512
513
|
}
|
|
513
514
|
|
|
514
515
|
return new Response(
|
|
515
|
-
await AuthenticatedStructures.membersBlob(members)
|
|
516
|
+
await AuthenticatedStructures.membersBlob(members),
|
|
516
517
|
);
|
|
517
518
|
}
|
|
518
519
|
|
|
@@ -520,20 +521,20 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
520
521
|
const updateGroups = new Set<string>();
|
|
521
522
|
const updateRegistrations = new Map<string, Registration>();
|
|
522
523
|
const updateSteps = new Set<string>();
|
|
523
|
-
|
|
524
|
+
|
|
524
525
|
// Loop all members one by one
|
|
525
526
|
for (const id of ids) {
|
|
526
|
-
const member = await Member.getWithRegistrations(id)
|
|
527
|
+
const member = await Member.getWithRegistrations(id);
|
|
527
528
|
if (!member || !await Context.auth.canDeleteMember(member)) {
|
|
528
|
-
throw Context.auth.error(
|
|
529
|
+
throw Context.auth.error('Je hebt niet voldoende rechten om dit lid te verwijderen');
|
|
529
530
|
}
|
|
530
531
|
|
|
531
|
-
await MemberUserSyncer.onDeleteMember(member)
|
|
532
|
-
await User.deleteForDeletedMember(member.id)
|
|
533
|
-
await BalanceItem.deleteForDeletedMember(member.id)
|
|
534
|
-
await member.delete()
|
|
532
|
+
await MemberUserSyncer.onDeleteMember(member);
|
|
533
|
+
await User.deleteForDeletedMember(member.id);
|
|
534
|
+
await BalanceItem.deleteForDeletedMember(member.id);
|
|
535
|
+
await member.delete();
|
|
535
536
|
|
|
536
|
-
for(const registration of member.registrations) {
|
|
537
|
+
for (const registration of member.registrations) {
|
|
537
538
|
const groupId = registration.groupId;
|
|
538
539
|
updateRegistrations.set(registration.id, registration);
|
|
539
540
|
updateGroups.add(groupId);
|
|
@@ -541,7 +542,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
541
542
|
}
|
|
542
543
|
}
|
|
543
544
|
|
|
544
|
-
for(const registration of updateRegistrations.values()) {
|
|
545
|
+
for (const registration of updateRegistrations.values()) {
|
|
545
546
|
registration.scheduleStockUpdate();
|
|
546
547
|
}
|
|
547
548
|
|
|
@@ -549,12 +550,12 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
549
550
|
|
|
550
551
|
// Loop all groups and update occupancy if needed
|
|
551
552
|
for (const group of groups) {
|
|
552
|
-
await group.updateOccupancy()
|
|
553
|
-
await group.save()
|
|
553
|
+
await group.updateOccupancy();
|
|
554
|
+
await group.save();
|
|
554
555
|
}
|
|
555
556
|
|
|
556
557
|
const organizations = await Organization.getByIDs(...Array.from(updateSteps));
|
|
557
|
-
|
|
558
|
+
|
|
558
559
|
for (const organization of organizations) {
|
|
559
560
|
SetupStepUpdater.updateForOrganization(organization).catch(console.error);
|
|
560
561
|
}
|
|
@@ -562,31 +563,31 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
562
563
|
|
|
563
564
|
static async checkDuplicate(member: Member) {
|
|
564
565
|
if (!member.details.birthDay) {
|
|
565
|
-
return
|
|
566
|
+
return;
|
|
566
567
|
}
|
|
567
568
|
let existingMembers = await Member.where({ organizationId: member.organizationId, firstName: member.details.firstName, lastName: member.details.lastName, birthDay: Formatter.dateIso(member.details.birthDay) });
|
|
568
569
|
|
|
569
570
|
if (member.existsInDatabase) {
|
|
570
|
-
existingMembers = existingMembers.filter(e => e.id !== member.id)
|
|
571
|
+
existingMembers = existingMembers.filter(e => e.id !== member.id);
|
|
571
572
|
}
|
|
572
|
-
|
|
573
|
+
|
|
573
574
|
if (existingMembers.length > 0) {
|
|
574
|
-
const withRegistrations = await Member.getBlobByIds(...existingMembers.map(m => m.id))
|
|
575
|
+
const withRegistrations = await Member.getBlobByIds(...existingMembers.map(m => m.id));
|
|
575
576
|
for (const m of withRegistrations) {
|
|
576
577
|
if (m.registrations.length > 0) {
|
|
577
|
-
return m
|
|
578
|
+
return m;
|
|
578
579
|
}
|
|
579
580
|
}
|
|
580
581
|
|
|
581
582
|
if (withRegistrations.length > 0) {
|
|
582
|
-
return withRegistrations[0]
|
|
583
|
+
return withRegistrations[0];
|
|
583
584
|
}
|
|
584
585
|
}
|
|
585
586
|
}
|
|
586
587
|
|
|
587
588
|
async createDummyMembers(organization: Organization, count: number) {
|
|
588
|
-
await new MemberFactory({
|
|
589
|
-
organization
|
|
590
|
-
}).createMultiple(count)
|
|
589
|
+
await new MemberFactory({
|
|
590
|
+
organization,
|
|
591
|
+
}).createMultiple(count);
|
|
591
592
|
}
|
|
592
593
|
}
|