@stamhoofd/backend 2.7.0 → 2.9.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/.env.template.json +3 -1
- package/package.json +3 -3
- package/src/crons.ts +3 -3
- package/src/decoders/StringArrayDecoder.ts +24 -0
- package/src/decoders/StringNullableDecoder.ts +18 -0
- package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +14 -0
- package/src/endpoints/global/email/PatchEmailEndpoint.ts +1 -0
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +21 -1
- package/src/endpoints/global/groups/GetGroupsEndpoint.ts +79 -0
- package/src/endpoints/global/members/GetMembersEndpoint.ts +0 -31
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +34 -367
- package/src/endpoints/global/registration/GetUserBalanceEndpoint.ts +3 -3
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +8 -11
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +205 -110
- package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +2 -3
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +20 -23
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +22 -1
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +3 -2
- package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +3 -40
- package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +22 -37
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +1 -0
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +14 -4
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +12 -2
- package/src/helpers/AdminPermissionChecker.ts +35 -24
- package/src/helpers/AuthenticatedStructures.ts +16 -7
- package/src/helpers/Context.ts +21 -0
- package/src/helpers/EmailResumer.ts +22 -2
- package/src/helpers/MemberUserSyncer.ts +42 -14
- package/src/seeds/1722344160-update-membership.ts +19 -22
- package/src/seeds/1722344161-sync-member-users.ts +60 -0
|
@@ -2,8 +2,8 @@ import { OneToManyRelation } from '@simonbackx/simple-database';
|
|
|
2
2
|
import { ConvertArrayToPatchableArray, Decoder, PatchableArrayAutoEncoder, PatchableArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
|
|
3
3
|
import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
|
|
4
4
|
import { SimpleError } from "@simonbackx/simple-errors";
|
|
5
|
-
import { BalanceItem,
|
|
6
|
-
import {
|
|
5
|
+
import { BalanceItem, Document, Group, Member, MemberFactory, MemberPlatformMembership, MemberResponsibilityRecord, MemberWithRegistrations, Organization, Platform, Registration, User } from '@stamhoofd/models';
|
|
6
|
+
import { MemberWithRegistrationsBlob, MembersBlob, PermissionLevel } from "@stamhoofd/structures";
|
|
7
7
|
import { Formatter } from '@stamhoofd/utility';
|
|
8
8
|
|
|
9
9
|
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
@@ -76,15 +76,6 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
76
76
|
const balanceItemRegistrationIdsPerOrganization: Map<string, string[]> = new Map()
|
|
77
77
|
const updateMembershipMemberIds = new Set<string>()
|
|
78
78
|
|
|
79
|
-
function addBalanceItemRegistrationId(organizationId: string, registrationId: string) {
|
|
80
|
-
const existing = balanceItemRegistrationIdsPerOrganization.get(organizationId);
|
|
81
|
-
if (existing) {
|
|
82
|
-
existing.push(registrationId)
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
balanceItemRegistrationIdsPerOrganization.set(organizationId, [registrationId])
|
|
86
|
-
}
|
|
87
|
-
|
|
88
79
|
// Loop all members one by one
|
|
89
80
|
for (const put of request.body.getPuts()) {
|
|
90
81
|
const struct = put.put
|
|
@@ -118,38 +109,14 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
118
109
|
}
|
|
119
110
|
}
|
|
120
111
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
statusCode: 400
|
|
130
|
-
})
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Throw early
|
|
135
|
-
for (const registrationStruct of struct.registrations) {
|
|
136
|
-
const group = await getGroup(registrationStruct.groupId)
|
|
137
|
-
if (!group || group.organizationId !== registrationStruct.organizationId || !await Context.auth.canAccessGroup(group, PermissionLevel.Write)) {
|
|
138
|
-
throw Context.auth.notFoundOrNoAccess("Je hebt niet voldoende rechten om leden toe te voegen in deze groep")
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const period = await RegistrationPeriod.getByID(group.periodId)
|
|
142
|
-
if (!period || period.locked) {
|
|
143
|
-
throw new SimpleError({
|
|
144
|
-
code: "period_locked",
|
|
145
|
-
message: "Deze inschrijvingsperiode is afgesloten en staat geen wijzigingen meer toe.",
|
|
146
|
-
})
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Set organization id of member based on registrations
|
|
150
|
-
if (!organization && STAMHOOFD.userMode !== 'platform' && !member.organizationId) {
|
|
151
|
-
member.organizationId = group.organizationId
|
|
152
|
-
}
|
|
112
|
+
// We risk creating a new member without being able to access it manually afterwards
|
|
113
|
+
if ((organization && !await Context.auth.hasFullAccess(organization.id)) || (!organization && !Context.auth.hasPlatformFullAccess())) {
|
|
114
|
+
throw new SimpleError({
|
|
115
|
+
code: "missing_group",
|
|
116
|
+
message: "Missing group",
|
|
117
|
+
human: "Je moet hoofdbeheerder zijn om een lid toe te voegen in het systeem",
|
|
118
|
+
statusCode: 400
|
|
119
|
+
})
|
|
153
120
|
}
|
|
154
121
|
|
|
155
122
|
if (STAMHOOFD.userMode !== 'platform' && !member.organizationId) {
|
|
@@ -167,16 +134,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
167
134
|
if ((STAMHOOFD.environment == "development" || STAMHOOFD.environment == "staging") && organization) {
|
|
168
135
|
if (member.details.firstName.toLocaleLowerCase() == "create" && parseInt(member.details.lastName) > 0) {
|
|
169
136
|
const count = parseInt(member.details.lastName);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
for (const registrationStruct of struct.registrations) {
|
|
173
|
-
const g = await getGroup(registrationStruct.groupId)
|
|
174
|
-
if (g) {
|
|
175
|
-
group = g
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
await this.createDummyMembers(organization, group, count)
|
|
137
|
+
await this.createDummyMembers(organization, count)
|
|
180
138
|
|
|
181
139
|
// Skip creating this member
|
|
182
140
|
continue;
|
|
@@ -188,20 +146,6 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
188
146
|
balanceItemMemberIds.push(member.id)
|
|
189
147
|
updateMembershipMemberIds.add(member.id)
|
|
190
148
|
|
|
191
|
-
// Add registrations
|
|
192
|
-
for (const registrationStruct of struct.registrations) {
|
|
193
|
-
const group = await getGroup(registrationStruct.groupId)
|
|
194
|
-
if (!group || group.organizationId !== registrationStruct.organizationId || !await Context.auth.canAccessGroup(group, PermissionLevel.Write)) {
|
|
195
|
-
throw Context.auth.notFoundOrNoAccess("Je hebt niet voldoende rechten om leden toe te voegen in deze groep")
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const reg = await this.addRegistration(member, registrationStruct, group)
|
|
199
|
-
addBalanceItemRegistrationId(reg.organizationId, reg.id)
|
|
200
|
-
|
|
201
|
-
// Update occupancy at the end of the call
|
|
202
|
-
updateGroups.set(group.id, group)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
149
|
// Auto link users based on data
|
|
206
150
|
await MemberUserSyncer.onChangeMember(member)
|
|
207
151
|
}
|
|
@@ -233,192 +177,6 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
233
177
|
// Update documents
|
|
234
178
|
await Document.updateForMember(member.id)
|
|
235
179
|
|
|
236
|
-
// Update registrations
|
|
237
|
-
for (const patchRegistration of patch.registrations.getPatches()) {
|
|
238
|
-
const registration = member.registrations.find(r => r.id === patchRegistration.id)
|
|
239
|
-
if (!registration || registration.memberId != member.id || (!await Context.auth.canAccessRegistration(registration, PermissionLevel.Write))) {
|
|
240
|
-
throw new SimpleError({
|
|
241
|
-
code: "permission_denied",
|
|
242
|
-
message: "You don't have permissions to access this endpoint",
|
|
243
|
-
human: "Je hebt geen toegang om deze registratie te wijzigen"
|
|
244
|
-
})
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
let group: Group | null = null
|
|
248
|
-
|
|
249
|
-
console.log('Patch registration', patchRegistration)
|
|
250
|
-
|
|
251
|
-
if (patchRegistration.group) {
|
|
252
|
-
patchRegistration.groupId = patchRegistration.group.id
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (patchRegistration.groupId) {
|
|
256
|
-
group = await getGroup(patchRegistration.groupId)
|
|
257
|
-
if (group) {
|
|
258
|
-
// We need to update group occupancy because we moved a member to it
|
|
259
|
-
updateGroups.set(group.id, group)
|
|
260
|
-
}
|
|
261
|
-
const oldGroup = await getGroup(registration.groupId)
|
|
262
|
-
if (oldGroup) {
|
|
263
|
-
// We need to update this group occupancy because we moved one member away from it
|
|
264
|
-
updateGroups.set(oldGroup.id, oldGroup)
|
|
265
|
-
}
|
|
266
|
-
} else {
|
|
267
|
-
group = await getGroup(registration.groupId)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (!group || group.organizationId !== (patchRegistration.organizationId ?? registration.organizationId)) {
|
|
271
|
-
throw new SimpleError({
|
|
272
|
-
code: "invalid_field",
|
|
273
|
-
message: "Group doesn't exist",
|
|
274
|
-
human: "De groep naarwaar je dit lid wilt verplaatsen bestaat niet",
|
|
275
|
-
field: "groupId"
|
|
276
|
-
})
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (!await Context.auth.canAccessGroup(group, PermissionLevel.Write)) {
|
|
280
|
-
throw Context.auth.error("Je hebt niet voldoende rechten om leden te verplaatsen naar deze groep")
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (patchRegistration.cycle && patchRegistration.cycle > group.cycle) {
|
|
284
|
-
throw new SimpleError({
|
|
285
|
-
code: "invalid_field",
|
|
286
|
-
message: "Invalid cycle",
|
|
287
|
-
human: "Je kan een lid niet inschrijven voor een groep die nog moet starten",
|
|
288
|
-
field: "cycle"
|
|
289
|
-
})
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const period = await RegistrationPeriod.getByID(group.periodId)
|
|
293
|
-
if (!period || period.locked) {
|
|
294
|
-
throw new SimpleError({
|
|
295
|
-
code: "period_locked",
|
|
296
|
-
message: "Deze inschrijvingsperiode is afgesloten en staat geen wijzigingen meer toe.",
|
|
297
|
-
})
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// TODO: allow group changes
|
|
301
|
-
registration.waitingList = patchRegistration.waitingList ?? registration.waitingList
|
|
302
|
-
|
|
303
|
-
if (!registration.waitingList && registration.registeredAt === null) {
|
|
304
|
-
registration.registeredAt = new Date()
|
|
305
|
-
}
|
|
306
|
-
registration.canRegister = patchRegistration.canRegister ?? registration.canRegister
|
|
307
|
-
if (!registration.waitingList) {
|
|
308
|
-
registration.canRegister = false
|
|
309
|
-
}
|
|
310
|
-
registration.cycle = patchRegistration.cycle ?? registration.cycle
|
|
311
|
-
registration.groupId = patchRegistration.groupId ?? registration.groupId
|
|
312
|
-
registration.group = group
|
|
313
|
-
registration.organizationId = patchRegistration.organizationId ?? registration.organizationId
|
|
314
|
-
|
|
315
|
-
// Check if we should create a placeholder payment?
|
|
316
|
-
|
|
317
|
-
if (patchRegistration.cycle !== undefined || patchRegistration.waitingList !== undefined || patchRegistration.canRegister !== undefined) {
|
|
318
|
-
// We need to update occupancy (because cycle / waitlist change)
|
|
319
|
-
updateGroups.set(group.id, group)
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (patchRegistration.price) {
|
|
323
|
-
// Create balance item
|
|
324
|
-
const balanceItem = new BalanceItem();
|
|
325
|
-
balanceItem.registrationId = registration.id;
|
|
326
|
-
balanceItem.price = patchRegistration.price
|
|
327
|
-
balanceItem.description = group ? `Inschrijving ${group.settings.name}` : `Inschrijving`
|
|
328
|
-
balanceItem.pricePaid = patchRegistration.pricePaid ?? 0
|
|
329
|
-
balanceItem.memberId = registration.memberId;
|
|
330
|
-
balanceItem.userId = member.users[0]?.id ?? null
|
|
331
|
-
balanceItem.organizationId = group.organizationId
|
|
332
|
-
balanceItem.status = BalanceItemStatus.Pending;
|
|
333
|
-
await balanceItem.save();
|
|
334
|
-
|
|
335
|
-
addBalanceItemRegistrationId(registration.organizationId, registration.id)
|
|
336
|
-
balanceItemMemberIds.push(member.id)
|
|
337
|
-
|
|
338
|
-
if (balanceItem.pricePaid > 0) {
|
|
339
|
-
// Create an Unknown payment and attach it to the balance item
|
|
340
|
-
const payment = new Payment();
|
|
341
|
-
payment.userId = member.users[0]?.id ?? null
|
|
342
|
-
payment.organizationId = member.organizationId
|
|
343
|
-
payment.method = PaymentMethod.Unknown
|
|
344
|
-
payment.status = PaymentStatus.Succeeded
|
|
345
|
-
payment.price = balanceItem.pricePaid;
|
|
346
|
-
payment.paidAt = new Date()
|
|
347
|
-
payment.provider = null
|
|
348
|
-
await payment.save()
|
|
349
|
-
|
|
350
|
-
const balanceItemPayment = new BalanceItemPayment()
|
|
351
|
-
balanceItemPayment.balanceItemId = balanceItem.id;
|
|
352
|
-
balanceItemPayment.paymentId = payment.id;
|
|
353
|
-
balanceItemPayment.organizationId = group.organizationId
|
|
354
|
-
balanceItemPayment.price = payment.price;
|
|
355
|
-
await balanceItemPayment.save();
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
await registration.save()
|
|
360
|
-
updateMembershipMemberIds.add(member.id)
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
for (const deleteId of patch.registrations.getDeletes()) {
|
|
364
|
-
const registration = member.registrations.find(r => r.id === deleteId)
|
|
365
|
-
if (!registration || registration.memberId != member.id) {
|
|
366
|
-
throw new SimpleError({
|
|
367
|
-
code: "permission_denied",
|
|
368
|
-
message: "You don't have permissions to access this endpoint",
|
|
369
|
-
human: "Je hebt geen toegang om deze registratie te wijzigen"
|
|
370
|
-
})
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (!await Context.auth.canAccessRegistration(registration, PermissionLevel.Write)) {
|
|
374
|
-
throw Context.auth.error("Je hebt niet voldoende rechten om deze inschrijving te verwijderen")
|
|
375
|
-
}
|
|
376
|
-
const oldGroup = await getGroup(registration.groupId)
|
|
377
|
-
const period = oldGroup && await RegistrationPeriod.getByID(oldGroup.periodId)
|
|
378
|
-
if (!period || period.locked) {
|
|
379
|
-
throw new SimpleError({
|
|
380
|
-
code: "period_locked",
|
|
381
|
-
message: "Deze inschrijvingsperiode is afgesloten en staat geen wijzigingen meer toe.",
|
|
382
|
-
})
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
balanceItemMemberIds.push(member.id)
|
|
386
|
-
updateMembershipMemberIds.add(member.id)
|
|
387
|
-
await BalanceItem.deleteForDeletedRegistration(registration.id)
|
|
388
|
-
await registration.delete()
|
|
389
|
-
member.registrations = member.registrations.filter(r => r.id !== deleteId)
|
|
390
|
-
|
|
391
|
-
if (oldGroup) {
|
|
392
|
-
// We need to update this group occupancy because we moved one member away from it
|
|
393
|
-
updateGroups.set(oldGroup.id, oldGroup)
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Add registrations
|
|
398
|
-
for (const registrationStruct of patch.registrations.getPuts()) {
|
|
399
|
-
const struct = registrationStruct.put
|
|
400
|
-
const group = await getGroup(struct.groupId)
|
|
401
|
-
|
|
402
|
-
if (!group || group.organizationId !== struct.organizationId || !await Context.auth.canAccessGroup(group, PermissionLevel.Write)) {
|
|
403
|
-
throw Context.auth.error("Je hebt niet voldoende rechten om inschrijvingen in deze groep te maken")
|
|
404
|
-
}
|
|
405
|
-
const period = await RegistrationPeriod.getByID(group.periodId)
|
|
406
|
-
if (!period || period.locked) {
|
|
407
|
-
throw new SimpleError({
|
|
408
|
-
code: "period_locked",
|
|
409
|
-
message: "Deze inschrijvingsperiode is afgesloten en staat geen wijzigingen meer toe.",
|
|
410
|
-
})
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
const reg = await this.addRegistration(member, struct, group)
|
|
414
|
-
balanceItemMemberIds.push(member.id)
|
|
415
|
-
updateMembershipMemberIds.add(member.id)
|
|
416
|
-
addBalanceItemRegistrationId(reg.organizationId, reg.id)
|
|
417
|
-
|
|
418
|
-
// We need to update this group occupancy because we moved one member away from it
|
|
419
|
-
updateGroups.set(group.id, group)
|
|
420
|
-
}
|
|
421
|
-
|
|
422
180
|
// Update responsibilities
|
|
423
181
|
for (const patchResponsibility of patch.responsibilities.getPatches()) {
|
|
424
182
|
if (!Context.auth.hasPlatformFullAccess() && !(organization && await Context.auth.hasFullAccess(organization.id))) {
|
|
@@ -570,6 +328,26 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
570
328
|
// Auto link users based on data
|
|
571
329
|
await MemberUserSyncer.onChangeMember(member)
|
|
572
330
|
|
|
331
|
+
// Allow to remove access for certain users
|
|
332
|
+
for (const id of patch.users.getDeletes()) {
|
|
333
|
+
const user = member.users.find(u => u.id === id)
|
|
334
|
+
if (!user) {
|
|
335
|
+
// Ignore silently
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (MemberUserSyncer.doesEmailHaveAccess(member.details, user.email)) {
|
|
340
|
+
throw new SimpleError({
|
|
341
|
+
code: "invalid_field",
|
|
342
|
+
message: "Invalid email",
|
|
343
|
+
human: "Je kan een account niet de toegang ontzetten 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."
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Remove access
|
|
348
|
+
await MemberUserSyncer.unlinkUser(user, member)
|
|
349
|
+
}
|
|
350
|
+
|
|
573
351
|
// Add platform memberships
|
|
574
352
|
for (const {put} of patch.platformMemberships.getPuts()) {
|
|
575
353
|
if (put.periodId !== platform.periodId) {
|
|
@@ -745,120 +523,9 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
745
523
|
}
|
|
746
524
|
}
|
|
747
525
|
|
|
748
|
-
async
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
const existings = await Registration.where({
|
|
752
|
-
memberId: member.id,
|
|
753
|
-
groupId: registrationStruct.groupId,
|
|
754
|
-
cycle: registrationStruct.cycle
|
|
755
|
-
}, { limit: 1 })
|
|
756
|
-
const existing = existings.length > 0 ? existings[0] : null
|
|
757
|
-
|
|
758
|
-
// If the existing is invalid, delete it.
|
|
759
|
-
if (existing && !existing.registeredAt && !existing.waitingList) {
|
|
760
|
-
console.log('Deleting invalid registration', existing.id)
|
|
761
|
-
await existing.delete()
|
|
762
|
-
} else if (existing) {
|
|
763
|
-
throw new SimpleError({
|
|
764
|
-
code: "invalid_field",
|
|
765
|
-
message: "Registration already exists",
|
|
766
|
-
human: existing.waitingList ? "Dit lid staat al op de wachtlijst voor deze groep" : "Dit lid is al ingeschreven voor deze groep",
|
|
767
|
-
field: "groupId"
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
if (!group) {
|
|
772
|
-
throw new SimpleError({
|
|
773
|
-
code: 'invalid_field',
|
|
774
|
-
field: 'groupId',
|
|
775
|
-
message: 'Invalid groupId',
|
|
776
|
-
human: 'Deze inschrijvingsgroep is ongeldig'
|
|
777
|
-
})
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
const registration = new Registration()
|
|
781
|
-
registration.groupId = registrationStruct.groupId
|
|
782
|
-
registration.organizationId = group.organizationId
|
|
783
|
-
registration.periodId = group.periodId
|
|
784
|
-
registration.cycle = registrationStruct.cycle
|
|
785
|
-
registration.memberId = member.id
|
|
786
|
-
registration.registeredAt = registrationStruct.registeredAt
|
|
787
|
-
registration.waitingList = registrationStruct.waitingList
|
|
788
|
-
registration.createdAt = registrationStruct.createdAt ?? new Date()
|
|
789
|
-
|
|
790
|
-
if (registration.waitingList) {
|
|
791
|
-
registration.registeredAt = null
|
|
792
|
-
}
|
|
793
|
-
registration.canRegister = registrationStruct.canRegister
|
|
794
|
-
|
|
795
|
-
if (!registration.waitingList) {
|
|
796
|
-
registration.canRegister = false
|
|
797
|
-
}
|
|
798
|
-
registration.deactivatedAt = registrationStruct.deactivatedAt
|
|
799
|
-
|
|
800
|
-
await registration.save()
|
|
801
|
-
member.registrations.push(registration.setRelation(Registration.group, group))
|
|
802
|
-
|
|
803
|
-
if (registrationStruct.price) {
|
|
804
|
-
// Create balance item
|
|
805
|
-
const balanceItem = new BalanceItem();
|
|
806
|
-
balanceItem.registrationId = registration.id;
|
|
807
|
-
balanceItem.price = registrationStruct.price
|
|
808
|
-
balanceItem.description = group ? `Inschrijving ${group.settings.name}` : `Inschrijving`
|
|
809
|
-
balanceItem.pricePaid = registrationStruct.pricePaid ?? 0
|
|
810
|
-
balanceItem.memberId = registration.memberId;
|
|
811
|
-
balanceItem.userId = member.users[0]?.id ?? null
|
|
812
|
-
balanceItem.organizationId = group.organizationId
|
|
813
|
-
balanceItem.status = BalanceItemStatus.Pending;
|
|
814
|
-
await balanceItem.save();
|
|
815
|
-
|
|
816
|
-
if (balanceItem.pricePaid > 0) {
|
|
817
|
-
// Create an Unknown payment and attach it to the balance item
|
|
818
|
-
const payment = new Payment();
|
|
819
|
-
payment.userId = member.users[0]?.id ?? null
|
|
820
|
-
payment.organizationId = member.organizationId
|
|
821
|
-
payment.method = PaymentMethod.Unknown
|
|
822
|
-
payment.status = PaymentStatus.Succeeded
|
|
823
|
-
payment.price = balanceItem.pricePaid;
|
|
824
|
-
payment.paidAt = new Date()
|
|
825
|
-
payment.provider = null
|
|
826
|
-
await payment.save()
|
|
827
|
-
|
|
828
|
-
const balanceItemPayment = new BalanceItemPayment()
|
|
829
|
-
balanceItemPayment.balanceItemId = balanceItem.id;
|
|
830
|
-
balanceItemPayment.paymentId = payment.id;
|
|
831
|
-
balanceItemPayment.organizationId = group.organizationId
|
|
832
|
-
balanceItemPayment.price = payment.price;
|
|
833
|
-
await balanceItemPayment.save();
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
return registration
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
async createDummyMembers(organization: Organization, group: Group, count: number) {
|
|
841
|
-
const members = await new MemberFactory({
|
|
842
|
-
organization,
|
|
843
|
-
minAge: group.settings.minAge ?? undefined,
|
|
844
|
-
maxAge: group.settings.maxAge ?? undefined
|
|
526
|
+
async createDummyMembers(organization: Organization, count: number) {
|
|
527
|
+
await new MemberFactory({
|
|
528
|
+
organization
|
|
845
529
|
}).createMultiple(count)
|
|
846
|
-
|
|
847
|
-
for (const m of members) {
|
|
848
|
-
const member = m.setManyRelation(Member.registrations as unknown as OneToManyRelation<"registrations", Member, Registration>, []).setManyRelation(Member.users, [])
|
|
849
|
-
const d = new Date(new Date().getTime() - Math.random() * 60 * 1000 * 60 * 24 * 60)
|
|
850
|
-
|
|
851
|
-
// Create a registration for this member for thisg roup
|
|
852
|
-
const registration = new Registration()
|
|
853
|
-
registration.organizationId = organization.id
|
|
854
|
-
registration.memberId = member.id
|
|
855
|
-
registration.groupId = group.id
|
|
856
|
-
registration.periodId = group.periodId
|
|
857
|
-
registration.cycle = group.cycle
|
|
858
|
-
registration.registeredAt = d
|
|
859
|
-
|
|
860
|
-
member.registrations.push(registration)
|
|
861
|
-
await registration.save()
|
|
862
|
-
}
|
|
863
530
|
}
|
|
864
531
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
|
|
2
2
|
import { BalanceItem, Member } from "@stamhoofd/models";
|
|
3
|
-
import {
|
|
3
|
+
import { BalanceItemWithPayments } from "@stamhoofd/structures";
|
|
4
4
|
|
|
5
5
|
import { Context } from "../../../helpers/Context";
|
|
6
6
|
|
|
7
7
|
type Params = Record<string, never>;
|
|
8
8
|
type Query = undefined
|
|
9
9
|
type Body = undefined
|
|
10
|
-
type ResponseBody =
|
|
10
|
+
type ResponseBody = BalanceItemWithPayments[]
|
|
11
11
|
|
|
12
12
|
export class GetUserBalanceEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
13
13
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
@@ -33,7 +33,7 @@ export class GetUserBalanceEndpoint extends Endpoint<Params, Query, Body, Respon
|
|
|
33
33
|
const balanceItems = await BalanceItem.balanceItemsForUsersAndMembers(organization?.id ?? null, [user.id], members.map(m => m.id))
|
|
34
34
|
|
|
35
35
|
return new Response(
|
|
36
|
-
await BalanceItem.
|
|
36
|
+
await BalanceItem.getStructureWithPayments(balanceItems)
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -4,10 +4,10 @@ import { SimpleError } from '@simonbackx/simple-errors';
|
|
|
4
4
|
import { Document, Member } from '@stamhoofd/models';
|
|
5
5
|
import { MemberWithRegistrationsBlob, MembersBlob } from "@stamhoofd/structures";
|
|
6
6
|
|
|
7
|
-
import { Context } from '../../../helpers/Context';
|
|
8
|
-
import { PatchOrganizationMembersEndpoint } from '../../global/members/PatchOrganizationMembersEndpoint';
|
|
9
7
|
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
8
|
+
import { Context } from '../../../helpers/Context';
|
|
10
9
|
import { MemberUserSyncer } from '../../../helpers/MemberUserSyncer';
|
|
10
|
+
import { PatchOrganizationMembersEndpoint } from '../../global/members/PatchOrganizationMembersEndpoint';
|
|
11
11
|
type Params = Record<string, never>;
|
|
12
12
|
type Query = undefined;
|
|
13
13
|
type Body = PatchableArrayAutoEncoder<MemberWithRegistrationsBlob>
|
|
@@ -48,15 +48,6 @@ export class PatchUserMembersEndpoint extends Endpoint<Params, Query, Body, Resp
|
|
|
48
48
|
struct.details.cleanData()
|
|
49
49
|
member.details = struct.details
|
|
50
50
|
|
|
51
|
-
if (!struct.details) {
|
|
52
|
-
throw new SimpleError({
|
|
53
|
-
code: "invalid_data",
|
|
54
|
-
message: "No details provided",
|
|
55
|
-
human: "Opgelet! Je gebruikt een oudere versie van de inschrijvingspagina die niet langer wordt ondersteund. Herlaad de website grondig en wis je browser cache.",
|
|
56
|
-
field: "details"
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
51
|
// Check for duplicates and prevent creating a duplicate member by a user
|
|
61
52
|
const duplicate = await PatchOrganizationMembersEndpoint.checkDuplicate(member);
|
|
62
53
|
if (duplicate) {
|
|
@@ -85,6 +76,12 @@ export class PatchUserMembersEndpoint extends Endpoint<Params, Query, Body, Resp
|
|
|
85
76
|
if (updatedMember) {
|
|
86
77
|
// Make sure we also give access to other parents
|
|
87
78
|
await MemberUserSyncer.onChangeMember(updatedMember)
|
|
79
|
+
|
|
80
|
+
if (!updatedMember.users.find(u => u.id === user.id)) {
|
|
81
|
+
// Also link the user to the member if the email address is missing in the details
|
|
82
|
+
await MemberUserSyncer.linkUser(user.email, updatedMember, true)
|
|
83
|
+
}
|
|
84
|
+
|
|
88
85
|
await Document.updateForMember(updatedMember.id)
|
|
89
86
|
}
|
|
90
87
|
}
|