@stamhoofd/backend 2.115.1 → 2.117.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/migrations.ts +1 -1
- package/package.json +10 -10
- package/src/audit-logs/DocumentTemplateLogger.ts +1 -1
- package/src/audit-logs/EmailAddressLogger.ts +1 -1
- package/src/audit-logs/EmailLogger.ts +1 -1
- package/src/audit-logs/EmailTemplateLogger.ts +1 -1
- package/src/audit-logs/EventLogger.ts +1 -1
- package/src/audit-logs/GroupLogger.ts +1 -1
- package/src/audit-logs/MemberLogger.ts +1 -1
- package/src/audit-logs/MemberPlatformMembershipLogger.ts +1 -1
- package/src/audit-logs/MemberResponsibilityRecordLogger.ts +1 -1
- package/src/audit-logs/ModelLogger.ts +27 -19
- package/src/audit-logs/OrderLogger.ts +1 -1
- package/src/audit-logs/OrganizationLogger.ts +23 -3
- package/src/audit-logs/OrganizationRegistrationPeriodLogger.ts +1 -1
- package/src/audit-logs/PaymentLogger.ts +1 -1
- package/src/audit-logs/PlatformLogger.ts +1 -1
- package/src/audit-logs/RegistrationLogger.ts +1 -1
- package/src/audit-logs/RegistrationPeriodLogger.ts +1 -1
- package/src/audit-logs/StripeAccountLogger.ts +1 -1
- package/src/audit-logs/UserLogger.ts +1 -1
- package/src/audit-logs/WebshopLogger.ts +1 -1
- package/src/audit-logs/init.ts +40 -0
- package/src/boot.ts +6 -4
- package/src/crons/amazon-ses.ts +1 -1
- package/src/crons/balance-emails.ts +1 -1
- package/src/crons/clearExcelCache.test.ts +1 -1
- package/src/crons/delete-archived-data.ts +47 -0
- package/src/crons/endFunctionsOfUsersWithoutRegistration.ts +1 -1
- package/src/crons/index.ts +1 -0
- package/src/crons.ts +3 -3
- package/src/debug.ts +230 -0
- package/src/email-recipient-loaders/documents.ts +1 -1
- package/src/email-recipient-loaders/members.ts +1 -1
- package/src/email-recipient-loaders/orders.ts +3 -3
- package/src/email-recipient-loaders/payments.ts +118 -353
- package/src/email-replacements/getEmailReplacementsForPayment.ts +321 -0
- package/src/endpoints/admin/members/ChargeMembersEndpoint.ts +9 -7
- package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +2 -2
- package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +1 -1
- package/src/endpoints/admin/organizations/ChargeOrganizationsEndpoint.ts +16 -50
- package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +2 -2
- package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +4 -4
- package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +21 -6
- package/src/endpoints/admin/registrations/ChargeRegistrationsEndpoint.ts +9 -7
- package/src/endpoints/auth/CreateAdminEndpoint.ts +2 -2
- package/src/endpoints/auth/CreateTokenEndpoint.test.ts +2 -2
- package/src/endpoints/auth/CreateTokenEndpoint.ts +1 -1
- package/src/endpoints/auth/DeleteTokenEndpoint.ts +1 -1
- package/src/endpoints/auth/DeleteUserEndpoint.ts +1 -1
- package/src/endpoints/auth/ForgotPasswordEndpoint.ts +1 -1
- package/src/endpoints/auth/GetOtherUserEndpoint.ts +2 -2
- package/src/endpoints/auth/GetUserEndpoint.test.ts +2 -2
- package/src/endpoints/auth/GetUserEndpoint.ts +2 -2
- package/src/endpoints/auth/OpenIDConnectAuthTokenEndpoint.ts +2 -2
- package/src/endpoints/auth/OpenIDConnectCallbackEndpoint.ts +2 -2
- package/src/endpoints/auth/OpenIDConnectStartEndpoint.ts +2 -2
- package/src/endpoints/auth/PatchUserEndpoint.ts +4 -4
- package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +1 -1
- package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +1 -1
- package/src/endpoints/auth/SignupEndpoint.ts +1 -1
- package/src/endpoints/auth/VerifyEmailEndpoint.ts +1 -1
- package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +1 -1
- package/src/endpoints/global/audit-logs/GetAuditLogsEndpoint.ts +4 -4
- package/src/endpoints/global/billing/ActivatePackagesEndpoint.ts +191 -7
- package/src/endpoints/global/billing/DeactivatePackageEndpoint.ts +64 -0
- package/src/endpoints/global/email/GetAdminEmailsEndpoint.test.ts +2 -2
- package/src/endpoints/global/email/GetAdminEmailsEndpoint.ts +3 -3
- package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +1 -1
- package/src/endpoints/global/email/GetEmailEndpoint.ts +1 -1
- package/src/endpoints/global/email/GetUserEmailsEndpoint.test.ts +2 -2
- package/src/endpoints/global/email/GetUserEmailsEndpoint.ts +3 -3
- package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +62 -16
- package/src/endpoints/global/email/PatchEmailEndpoint.test.ts +6 -6
- package/src/endpoints/global/email-recipients/GetEmailRecipientsCountEndpoint.ts +2 -2
- package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.test.ts +2 -2
- package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.ts +4 -4
- package/src/endpoints/global/email-recipients/RetryEmailRecipientEndpoint.ts +1 -1
- package/src/endpoints/global/email-recipients/helpers/validateEmailRecipientFilter.ts +1 -1
- package/src/endpoints/global/events/GetEventNotificationsCountEndpoint.ts +2 -2
- package/src/endpoints/global/events/GetEventNotificationsEndpoint.ts +4 -4
- package/src/endpoints/global/events/GetEventsEndpoint.ts +4 -4
- package/src/endpoints/global/events/PatchEventNotificationsEndpoint.test.ts +2 -2
- package/src/endpoints/global/events/PatchEventNotificationsEndpoint.ts +3 -3
- package/src/endpoints/global/events/PatchEventsEndpoint.test.ts +2 -2
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +5 -5
- package/src/endpoints/global/files/ExportToExcelEndpoint.ts +4 -4
- package/src/endpoints/global/files/GetFileCache.ts +2 -2
- package/src/endpoints/global/files/UploadFile.ts +2 -2
- package/src/endpoints/global/files/UploadImage.ts +1 -1
- package/src/endpoints/global/groups/GetGroupsEndpoint.test.ts +3 -3
- package/src/endpoints/global/groups/GetGroupsEndpoint.ts +4 -4
- package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +4 -4
- package/src/endpoints/global/members/GetMembersEndpoint.test.ts +3 -3
- package/src/endpoints/global/members/GetMembersEndpoint.ts +4 -16
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +8 -7
- package/src/endpoints/global/members/helpers/validateGroupFilter.ts +1 -1
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +2 -2
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +23 -12
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +2 -2
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +1 -1
- package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +1 -1
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +2 -2
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +1 -1
- package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +3 -3
- package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +1 -1
- package/src/endpoints/global/platform/GetPlatformEndpoint.test.ts +2 -2
- package/src/endpoints/global/platform/GetPlatformEndpoint.ts +1 -1
- package/src/endpoints/global/platform/PatchPlatformEnpoint.test.ts +2 -2
- package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +7 -7
- package/src/endpoints/global/registration/GetRegistrationsEndpoint.test.ts +2 -2
- package/src/endpoints/global/registration/GetRegistrationsEndpoint.ts +1 -2
- package/src/endpoints/global/registration/GetUserDetailedPayableBalanceEndpoint.ts +2 -2
- package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +2 -2
- package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +2 -2
- package/src/endpoints/global/registration/GetUserPayableBalanceEndpoint.ts +2 -2
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +2 -2
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +24 -389
- package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +3 -3
- package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +2 -2
- package/src/endpoints/global/sso/GetSSOEndpoint.ts +2 -2
- package/src/endpoints/global/sso/SetSSOEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemEndpoint.ts +55 -0
- package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsCountEndpoint.ts +43 -0
- package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsEndpoint.ts +160 -0
- package/src/endpoints/organization/dashboard/{payments → balance-items}/PatchBalanceItemsEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/billing/GetOrganizationPayableBalanceEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/billing/GetPackagesEndpoint.test.ts +3 -3
- package/src/endpoints/organization/dashboard/billing/GetPackagesEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +1 -1
- package/src/endpoints/organization/dashboard/documents/GetDocumentsCountEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +37 -6
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.test.ts +2 -2
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.test.ts +2 -2
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/invoices/PatchInvoicesEndpoint.ts +53 -0
- package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/GetUitpasClientIdEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +12 -1
- package/src/endpoints/organization/dashboard/organization/SearchUitpasOrganizersEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/SetUitpasClientCredentialsEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +4 -4
- package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesCountEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts +4 -4
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.test.ts +2 -2
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +4 -4
- package/src/endpoints/organization/dashboard/registration-periods/MoveRegistrationPeriods.test.ts +2 -2
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.test.ts +2 -2
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.test.ts +3 -3
- package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/users/PatchApiUserEndpoint.test.ts +3 -3
- package/src/endpoints/organization/dashboard/users/PatchApiUserEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersCountEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +5 -5
- package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +5 -5
- package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/SearchUitpasEventsEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +1 -1
- package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +3 -3
- package/src/endpoints/organization/shared/GetDocumentHtml.ts +1 -1
- package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +2 -2
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +2 -2
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +2 -2
- package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +1 -1
- package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +1 -1
- package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +1 -1
- package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +1 -1
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +2 -2
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +2 -2
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +4 -4
- package/src/excel-loaders/balance-items.ts +268 -0
- package/src/excel-loaders/event-notifications.ts +3 -3
- package/src/excel-loaders/index.ts +6 -5
- package/src/excel-loaders/organizations.ts +4 -4
- package/src/excel-loaders/payments.ts +11 -3
- package/src/excel-loaders/receivable-balances.ts +2 -2
- package/src/helpers/AddressValidator.test.ts +1 -1
- package/src/helpers/AddressValidator.ts +1 -1
- package/src/helpers/AdminPermissionChecker.ts +20 -17
- package/src/helpers/AuthenticatedStructures.ts +194 -109
- package/src/helpers/Context.ts +2 -0
- package/src/helpers/EmailResumer.ts +1 -1
- package/src/helpers/FlagMomentCleanup.ts +1 -1
- package/src/helpers/ForwardHandler.test.ts +1 -1
- package/src/helpers/ForwardHandler.ts +1 -1
- package/src/helpers/GlobalHelper.ts +4 -4
- package/src/helpers/GroupBuilder.ts +417 -0
- package/src/helpers/GroupedThrottledQueue.test.ts +1 -1
- package/src/helpers/GroupedThrottledQueue.ts +1 -1
- package/src/helpers/MemberUserSyncer.test.ts +1 -1
- package/src/helpers/MemberUserSyncer.ts +1 -1
- package/src/helpers/PeriodHelper.ts +5 -45
- package/src/helpers/ServiceFeeHelper.ts +5 -1
- package/src/helpers/SetupStepUpdater.ts +5 -4
- package/src/helpers/TagHelper.ts +1 -1
- package/src/helpers/ThrottledQueue.test.ts +1 -1
- package/src/helpers/ViesHelper.ts +9 -0
- package/src/helpers/email-html-helpers.ts +0 -41
- package/src/helpers/outstandingBalanceJoin.ts +3 -1
- package/src/middleware/ContextMiddleware.ts +1 -1
- package/src/seeds/1726572303-schedule-stock-updates.ts +1 -1
- package/src/seeds/1726847064-setup-steps.ts +1 -1
- package/src/seeds/1728928974-update-cached-outstanding-balance-from-items.ts +1 -1
- package/src/seeds/1740046783-update-membership.ts +1 -1
- package/src/seeds/1754560914-groups-prices.test.ts +1 -1
- package/src/seeds/1755876819-remove-duplicate-members.ts +1 -1
- package/src/seeds/1760702454-update-cached-outstanding-balance-from-items.ts +1 -1
- package/src/seeds/1761665607-sync-member-users.ts +1 -1
- package/src/seeds/data/default-email-templates.sql +1 -1
- package/src/seeds-temporary/1732117645-move-rrn.ts +1 -1
- package/src/services/AuditLogService.ts +1 -41
- package/src/services/BalanceItemPaymentService.ts +1 -1
- package/src/services/BalanceItemService.ts +12 -5
- package/src/services/EventNotificationService.ts +3 -3
- package/src/services/InvoiceService.ts +131 -17
- package/src/services/MemberRecordStore.ts +1 -1
- package/src/services/PaymentReallocationService.test.ts +9 -10
- package/src/services/PaymentReallocationService.ts +1 -1
- package/src/services/PaymentService.ts +560 -18
- package/src/services/PlatformMembershipService.ts +3 -3
- package/src/services/RegistrationService.ts +3 -3
- package/src/services/SSOService.ts +2 -2
- package/src/services/STPackageService.ts +241 -0
- package/src/services/uitpas/UitpasService.test.ts +1 -1
- package/src/sql-filters/balance-items.ts +56 -0
- package/src/sql-filters/emails.ts +1 -1
- package/src/sql-filters/event-notifications.ts +2 -2
- package/src/sql-filters/events.ts +51 -0
- package/src/sql-filters/members.ts +38 -2
- package/src/sql-filters/receivable-balances.ts +3 -3
- package/src/sql-filters/users.ts +10 -0
- package/src/sql-sorters/balance-items.ts +36 -0
- package/src/sql-sorters/document-templates.ts +2 -2
- package/src/sql-sorters/documents.ts +2 -2
- package/src/sql-sorters/event-notifications.ts +1 -1
- package/src/sql-sorters/members.ts +2 -2
- package/src/sql-sorters/orders.ts +2 -2
- package/src/sql-sorters/tickets.ts +2 -2
- package/tests/actions/patchOrganizationMember.ts +3 -3
- package/tests/actions/patchPaymentStatus.ts +3 -3
- package/tests/actions/patchUserMember.ts +2 -2
- package/tests/assertions/assertBalances.ts +1 -1
- package/tests/e2e/api-rate-limits.test.ts +3 -3
- package/tests/e2e/charge-members.test.ts +14 -14
- package/tests/e2e/documents.test.ts +8 -8
- package/tests/e2e/private-files.test.ts +4 -4
- package/tests/e2e/register.test.ts +10 -10
- package/tests/e2e/stock.test.ts +4 -4
- package/tests/e2e/tickets.test.ts +4 -4
- package/tests/helpers/TestServer.ts +2 -2
- package/tests/init/index.ts +7 -7
- package/tests/init/initAdmin.ts +1 -1
- package/src/endpoints/global/registration/GetPaymentRegistrations.ts +0 -67
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AutoEncoderPatchType, PatchMap } from '@simonbackx/simple-encoding';
|
|
2
2
|
import { isSimpleError, isSimpleErrors, SimpleError } from '@simonbackx/simple-errors';
|
|
3
|
-
import { BalanceItem, CachedBalance, Document, Email, EmailTemplate, Event, EventNotification, Group, Member, MemberPlatformMembership, MemberWithRegistrations, Order, Organization, OrganizationRegistrationPeriod, Payment, Registration, User, Webshop } from '@stamhoofd/models';
|
|
3
|
+
import { BalanceItem, CachedBalance, Document, Email, EmailTemplate, Event, EventNotification, Group, Member, MemberPlatformMembership, MemberWithRegistrations, MemberWithUsers, MemberWithUsersAndRegistrations, MemberWithUsersRegistrationsAndGroups, Order, Organization, OrganizationRegistrationPeriod, Payment, Registration, User, Webshop } from '@stamhoofd/models';
|
|
4
4
|
import { AccessRight, EmailTemplate as EmailTemplateStruct, EventPermissionChecker, FinancialSupportSettings, GroupCategory, GroupStatus, GroupType, MemberWithRegistrationsBlob, PermissionLevel, PermissionsResourceType, Platform as PlatformStruct, ReceivableBalanceType, RecordSettings, ResourcePermissions, UitpasNumberDetails, UitpasSocialTariff, UitpasSocialTariffStatus } from '@stamhoofd/structures';
|
|
5
5
|
import { Formatter } from '@stamhoofd/utility';
|
|
6
6
|
import { MemberRecordStore } from '../services/MemberRecordStore.js';
|
|
@@ -16,7 +16,7 @@ export class AdminPermissionChecker {
|
|
|
16
16
|
/**
|
|
17
17
|
* The member that is linked to this user = is this user
|
|
18
18
|
*/
|
|
19
|
-
member:
|
|
19
|
+
member: MemberWithUsersRegistrationsAndGroups | null = null;
|
|
20
20
|
platform: PlatformStruct;
|
|
21
21
|
|
|
22
22
|
organizationCache: Map<string, Organization | Promise<Organization | undefined>> = new Map();
|
|
@@ -361,7 +361,7 @@ export class AdminPermissionChecker {
|
|
|
361
361
|
return await this.hasFullAccess(organizationId);
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
-
async canAccessMember(member:
|
|
364
|
+
async canAccessMember(member: MemberWithUsersAndRegistrations, permissionLevel: PermissionLevel = PermissionLevel.Read) {
|
|
365
365
|
if (permissionLevel !== PermissionLevel.Full && this.isUserManager(member)) {
|
|
366
366
|
return true;
|
|
367
367
|
}
|
|
@@ -407,7 +407,7 @@ export class AdminPermissionChecker {
|
|
|
407
407
|
* The server will temporarily grant the user access to this member, and store this in the server
|
|
408
408
|
* memory. This is required for adding new members to an organization (first add member -> then patch with registrations, which requires write access).
|
|
409
409
|
*/
|
|
410
|
-
async temporarilyGrantMemberAccess(member:
|
|
410
|
+
async temporarilyGrantMemberAccess(member: MemberWithUsersRegistrationsAndGroups, permissionLevel: PermissionLevel = PermissionLevel.Write) {
|
|
411
411
|
console.log('Temporarily granting access to member', member.id, 'for user', this.user.id);
|
|
412
412
|
addTemporaryMemberAccess(this.user.id, member.id, permissionLevel);
|
|
413
413
|
}
|
|
@@ -415,11 +415,11 @@ export class AdminPermissionChecker {
|
|
|
415
415
|
/**
|
|
416
416
|
* Only full admins can delete members permanently
|
|
417
417
|
*/
|
|
418
|
-
async canDeleteMember(member:
|
|
418
|
+
async canDeleteMember(member: MemberWithUsersAndRegistrations) {
|
|
419
419
|
if (member.registrations.length === 0 && this.isUserManager(member)) {
|
|
420
420
|
const cachedBalance = await CachedBalance.getForObjects([member.id], null, ReceivableBalanceType.member);
|
|
421
421
|
if (cachedBalance.length === 0 || (cachedBalance[0].amountOpen === 0 && cachedBalance[0].amountPending === 0)) {
|
|
422
|
-
const platformMemberships = await MemberPlatformMembership.where(
|
|
422
|
+
const platformMemberships = await MemberPlatformMembership.select().where('memberId', member.id).fetch();
|
|
423
423
|
if (platformMemberships.length === 0) {
|
|
424
424
|
return true;
|
|
425
425
|
}
|
|
@@ -436,7 +436,7 @@ export class AdminPermissionChecker {
|
|
|
436
436
|
/**
|
|
437
437
|
* Note: only checks admin permissions. Users that 'own' this member can also access it but that does not use the AdminPermissionChecker
|
|
438
438
|
*/
|
|
439
|
-
async canAccessRegistration(registration: Registration, permissionLevel: PermissionLevel = PermissionLevel.Read, checkMember: boolean |
|
|
439
|
+
async canAccessRegistration(registration: Registration, permissionLevel: PermissionLevel = PermissionLevel.Read, checkMember: boolean | MemberWithUsersRegistrationsAndGroups = true) {
|
|
440
440
|
if (registration.deactivatedAt || !registration.registeredAt) {
|
|
441
441
|
if (!checkMember) {
|
|
442
442
|
// We can't grant access to a member because of a deactivated registration
|
|
@@ -840,7 +840,7 @@ export class AdminPermissionChecker {
|
|
|
840
840
|
return false;
|
|
841
841
|
}
|
|
842
842
|
|
|
843
|
-
async canLinkBalanceItemToMember(member:
|
|
843
|
+
async canLinkBalanceItemToMember(member: MemberWithUsersAndRegistrations) {
|
|
844
844
|
if (!this.checkScope(member.organizationId)) {
|
|
845
845
|
return false;
|
|
846
846
|
}
|
|
@@ -928,8 +928,11 @@ export class AdminPermissionChecker {
|
|
|
928
928
|
return this.hasFullAccess(organizationId);
|
|
929
929
|
}
|
|
930
930
|
|
|
931
|
-
async canAccessEmailBounces(organizationId: string) {
|
|
932
|
-
|
|
931
|
+
async canAccessEmailBounces(organizationId: string | null) {
|
|
932
|
+
if (organizationId) {
|
|
933
|
+
return this.hasSomeAccess(organizationId);
|
|
934
|
+
}
|
|
935
|
+
return this.hasSomePlatformAccess();
|
|
933
936
|
}
|
|
934
937
|
|
|
935
938
|
async canSendEmails(organizationId: Organization | string | null) {
|
|
@@ -1105,14 +1108,14 @@ export class AdminPermissionChecker {
|
|
|
1105
1108
|
return !!organizationPermissions && organizationPermissions.hasAccess(level);
|
|
1106
1109
|
}
|
|
1107
1110
|
|
|
1108
|
-
isUserManager(member:
|
|
1111
|
+
isUserManager(member: MemberWithUsers) {
|
|
1109
1112
|
return !!member.users.find(u => u.id === this.user.id);
|
|
1110
1113
|
}
|
|
1111
1114
|
|
|
1112
1115
|
/**
|
|
1113
1116
|
* Return a list of RecordSettings the current user can view or edit
|
|
1114
1117
|
*/
|
|
1115
|
-
async hasFinancialMemberAccess(member:
|
|
1118
|
+
async hasFinancialMemberAccess(member: MemberWithUsersAndRegistrations, level: PermissionLevel = PermissionLevel.Read, organizationId?: string): Promise<boolean> {
|
|
1116
1119
|
const isUserManager = this.isUserManager(member);
|
|
1117
1120
|
|
|
1118
1121
|
if (isUserManager && level === PermissionLevel.Read) {
|
|
@@ -1197,7 +1200,7 @@ export class AdminPermissionChecker {
|
|
|
1197
1200
|
/**
|
|
1198
1201
|
* Return a list of RecordSettings the current user can view or edit
|
|
1199
1202
|
*/
|
|
1200
|
-
async hasNRNAccess(member:
|
|
1203
|
+
async hasNRNAccess(member: MemberWithUsersAndRegistrations, level: PermissionLevel = PermissionLevel.Read): Promise<boolean> {
|
|
1201
1204
|
const isUserManager = this.isUserManager(member);
|
|
1202
1205
|
|
|
1203
1206
|
if (isUserManager) {
|
|
@@ -1319,7 +1322,7 @@ export class AdminPermissionChecker {
|
|
|
1319
1322
|
};
|
|
1320
1323
|
}
|
|
1321
1324
|
|
|
1322
|
-
async checkRecordAccess(member:
|
|
1325
|
+
async checkRecordAccess(member: MemberWithUsersRegistrationsAndGroups, recordId: string, level: PermissionLevel = PermissionLevel.Read): Promise<{ canAccess: false; record: RecordSettings | null } | { canAccess: true; record: RecordSettings }> {
|
|
1323
1326
|
const record = await MemberRecordStore.getRecord(recordId);
|
|
1324
1327
|
if (!record) {
|
|
1325
1328
|
return {
|
|
@@ -1452,7 +1455,7 @@ export class AdminPermissionChecker {
|
|
|
1452
1455
|
/**
|
|
1453
1456
|
* Changes data inline
|
|
1454
1457
|
*/
|
|
1455
|
-
async filterMemberData(member:
|
|
1458
|
+
async filterMemberData(member: MemberWithUsersRegistrationsAndGroups, data: MemberWithRegistrationsBlob, options?: { forAdminCartCalculation?: boolean }): Promise<MemberWithRegistrationsBlob> {
|
|
1456
1459
|
const cloned = data.clone();
|
|
1457
1460
|
|
|
1458
1461
|
for (const [key, value] of cloned.details.recordAnswers.entries()) {
|
|
@@ -1511,7 +1514,7 @@ export class AdminPermissionChecker {
|
|
|
1511
1514
|
/**
|
|
1512
1515
|
* Only for creating new members
|
|
1513
1516
|
*/
|
|
1514
|
-
filterMemberPut(member:
|
|
1517
|
+
filterMemberPut(member: MemberWithUsersRegistrationsAndGroups, data: MemberWithRegistrationsBlob, options: { asUserManager: boolean }) {
|
|
1515
1518
|
if (options.asUserManager || STAMHOOFD.userMode === 'platform') {
|
|
1516
1519
|
// A user manager cannot choose the member number + in platform mode, nobody can choose the member number
|
|
1517
1520
|
data.details.memberNumber = null;
|
|
@@ -1526,7 +1529,7 @@ export class AdminPermissionChecker {
|
|
|
1526
1529
|
}
|
|
1527
1530
|
}
|
|
1528
1531
|
|
|
1529
|
-
async filterMemberPatch(member:
|
|
1532
|
+
async filterMemberPatch(member: MemberWithUsersRegistrationsAndGroups, data: AutoEncoderPatchType<MemberWithRegistrationsBlob>): Promise<AutoEncoderPatchType<MemberWithRegistrationsBlob>> {
|
|
1530
1533
|
if (!data.details) {
|
|
1531
1534
|
return data;
|
|
1532
1535
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
2
|
-
import { AuditLog, BalanceItem, CachedBalance, Document, Event, EventNotification, Group, Invoice, Member, MemberPlatformMembership, MemberResponsibilityRecord,
|
|
3
|
-
import { AuditLogReplacement, AuditLogReplacementType, AuditLog as AuditLogStruct,
|
|
2
|
+
import { AuditLog, BalanceItem, CachedBalance, Document, Event, EventNotification, Group, Invoice, Member, MemberPlatformMembership, MemberResponsibilityRecord, MemberWithUsersRegistrationsAndGroups, Order, Organization, OrganizationRegistrationPeriod, Payment, Registration, RegistrationPeriod, Ticket, User, Webshop } from '@stamhoofd/models';
|
|
3
|
+
import { AuditLogReplacement, AuditLogReplacementType, AuditLog as AuditLogStruct, DetailedReceivableBalance, Document as DocumentStruct, EventNotification as EventNotificationStruct, Event as EventStruct, GenericBalance, Group as GroupStruct, GroupType, InvoicedBalanceItem, InvoiceStruct, MemberPlatformMembership as MemberPlatformMembershipStruct, MembersBlob, MemberWithRegistrationsBlob, NamedObject, OrganizationRegistrationPeriod as OrganizationRegistrationPeriodStruct, Organization as OrganizationStruct, PaymentCustomer, PaymentGeneral, PermissionLevel, Platform, PrivateOrder, PrivateWebshop, ReceivableBalanceObject, ReceivableBalanceObjectContact, ReceivableBalance as ReceivableBalanceStruct, ReceivableBalanceType, RegistrationsBlob, RegistrationWithMemberBlob, TicketPrivate, UserWithMembers, WebshopPreview, Webshop as WebshopStruct, BalanceItem as BalanceItemStruct } from '@stamhoofd/structures';
|
|
4
4
|
import { Sorter } from '@stamhoofd/utility';
|
|
5
5
|
|
|
6
6
|
import { SQL } from '@stamhoofd/sql';
|
|
7
7
|
import { Formatter } from '@stamhoofd/utility';
|
|
8
|
-
import { BalanceItemService } from '../services/BalanceItemService.js';
|
|
9
8
|
import { Context } from './Context.js';
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -61,6 +60,9 @@ export class AuthenticatedStructures {
|
|
|
61
60
|
|
|
62
61
|
const { invoicedBalanceItems } = await Invoice.loadBalanceItems(invoices);
|
|
63
62
|
|
|
63
|
+
const paymentModels = await Payment.select().where('invoiceId', invoices.map(i => i.id)).fetch();
|
|
64
|
+
const payments = await this.paymentsGeneral(paymentModels, false);
|
|
65
|
+
|
|
64
66
|
return invoices.map((invoice) => {
|
|
65
67
|
const items = invoicedBalanceItems.filter(i => i.invoiceId === invoice.id);
|
|
66
68
|
return InvoiceStruct.create({
|
|
@@ -68,6 +70,7 @@ export class AuthenticatedStructures {
|
|
|
68
70
|
items: items.map((item) => {
|
|
69
71
|
return InvoicedBalanceItem.create(item);
|
|
70
72
|
}),
|
|
73
|
+
payments: payments.filter(p => p.invoiceId === invoice.id),
|
|
71
74
|
});
|
|
72
75
|
});
|
|
73
76
|
}
|
|
@@ -222,8 +225,8 @@ export class AuthenticatedStructures {
|
|
|
222
225
|
return [];
|
|
223
226
|
}
|
|
224
227
|
|
|
225
|
-
// #region get period ids / organizations map
|
|
226
228
|
const periodIdOrganizationsMap = new Map<string, Organization[]>();
|
|
229
|
+
const organizationIdsToGetWebshopsFor: string[] = [];
|
|
227
230
|
|
|
228
231
|
for (const organization of organizations) {
|
|
229
232
|
const periodId = organization.periodId;
|
|
@@ -235,47 +238,62 @@ export class AuthenticatedStructures {
|
|
|
235
238
|
periodIdOrganizationsMap.set(periodId, [organization]);
|
|
236
239
|
}
|
|
237
240
|
}
|
|
238
|
-
// #endregion
|
|
239
241
|
|
|
240
|
-
//
|
|
241
|
-
const organizationData: Map<string, { organizationRegistrationPeriod:
|
|
242
|
-
const
|
|
242
|
+
// Get registration period and whether private data can be accessed for each organization
|
|
243
|
+
const organizationData: Map<string, { organizationRegistrationPeriod: OrganizationRegistrationPeriodStruct; canAccessPrivateData: boolean }> = new Map();
|
|
244
|
+
const allPeriodIds = periodIdOrganizationsMap.keys();
|
|
245
|
+
const allPeriods = await RegistrationPeriod.getByIDs(...allPeriodIds);
|
|
246
|
+
const periodMap = new Map<string, RegistrationPeriod>(allPeriods.map(p => [p.id, p]));
|
|
243
247
|
|
|
244
248
|
for (const [periodId, organizations] of periodIdOrganizationsMap.entries()) {
|
|
245
|
-
const organizationMap = new Map(organizations.map(o => [o.id, o]));
|
|
246
|
-
|
|
247
249
|
const result = await OrganizationRegistrationPeriod.where({
|
|
248
250
|
periodId,
|
|
249
251
|
organizationId: {
|
|
250
252
|
sign: 'IN',
|
|
251
|
-
value:
|
|
253
|
+
value: Formatter.uniqueArray(organizations.map(o => o.id)),
|
|
252
254
|
},
|
|
253
255
|
});
|
|
256
|
+
const period = periodMap.get(periodId);
|
|
257
|
+
if (!period) {
|
|
258
|
+
console.error('Period not found for id', periodId);
|
|
259
|
+
throw new Error('Period not found for id ' + periodId);
|
|
260
|
+
}
|
|
254
261
|
|
|
255
|
-
|
|
262
|
+
// Automatically create missing organization periods for now
|
|
263
|
+
for (const organization of organizations) {
|
|
264
|
+
const organizationPeriodModel = result.find(r => r.organizationId === organization.id);
|
|
265
|
+
if (!organizationPeriodModel) {
|
|
266
|
+
result.push(await organization.getPeriod());
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Do this onece per period, because otherwise we can't optimize fetching the groups for each period
|
|
271
|
+
const organizationRegistrationPeriods = await this.organizationRegistrationPeriods(result, [period]);
|
|
256
272
|
|
|
257
273
|
for (const organization of organizations) {
|
|
258
274
|
const organizationId = organization.id;
|
|
259
|
-
const
|
|
275
|
+
const organizationPeriodModel = result.find(r => r.organizationId === organizationId);
|
|
276
|
+
if (organizationPeriodModel) {
|
|
277
|
+
const organizationRegistrationPeriod = organizationRegistrationPeriods.find(o => o.id === organizationPeriodModel.id);
|
|
278
|
+
if (!organizationRegistrationPeriod) {
|
|
279
|
+
throw new Error('Organization registration period not found for id ' + organizationPeriodModel.id);
|
|
280
|
+
}
|
|
260
281
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
282
|
+
// check if private data can be accessed
|
|
283
|
+
const canAccessPrivateData = await Context.optionalAuth?.canAccessPrivateOrganizationData(organization) ?? false;
|
|
284
|
+
if (canAccessPrivateData) {
|
|
285
|
+
organizationIdsToGetWebshopsFor.push(organization.id);
|
|
286
|
+
}
|
|
287
|
+
organizationData.set(organizationId, { organizationRegistrationPeriod, canAccessPrivateData });
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
// Should never happen
|
|
291
|
+
throw new Error('Organization registration period model not found for organization id ' + organizationId + ' and period id ' + periodId);
|
|
265
292
|
}
|
|
266
|
-
|
|
267
|
-
organizationData.set(organizationId, { organizationRegistrationPeriod, canAccessPrivateData });
|
|
268
293
|
}
|
|
269
294
|
}
|
|
270
|
-
// #endregion
|
|
271
|
-
|
|
272
|
-
// #region get periods
|
|
273
|
-
const allPeriodIds = periodIdOrganizationsMap.keys();
|
|
274
|
-
const allPeriods = await RegistrationPeriod.getByIDs(...allPeriodIds);
|
|
275
|
-
const periodMap = new Map<string, RegistrationPeriod>(allPeriods.map(p => [p.id, p]));
|
|
276
|
-
// #endregion
|
|
277
295
|
|
|
278
|
-
//
|
|
296
|
+
// Get webshop previews
|
|
279
297
|
const webshops = organizationIdsToGetWebshopsFor.length > 0
|
|
280
298
|
? await Webshop.where(
|
|
281
299
|
{
|
|
@@ -306,9 +324,8 @@ export class AuthenticatedStructures {
|
|
|
306
324
|
webshopPreviews.set(organizationId, [preview]);
|
|
307
325
|
}
|
|
308
326
|
}
|
|
309
|
-
// #endregion
|
|
310
327
|
|
|
311
|
-
//
|
|
328
|
+
// Create organization structs
|
|
312
329
|
const results: OrganizationStruct[] = [];
|
|
313
330
|
|
|
314
331
|
for (const organization of organizations) {
|
|
@@ -327,7 +344,7 @@ export class AuthenticatedStructures {
|
|
|
327
344
|
|
|
328
345
|
let result: OrganizationStruct;
|
|
329
346
|
|
|
330
|
-
const period =
|
|
347
|
+
const period = data.organizationRegistrationPeriod;
|
|
331
348
|
const baseStruct = organization.getBaseStructure();
|
|
332
349
|
|
|
333
350
|
if (data.canAccessPrivateData) {
|
|
@@ -347,7 +364,6 @@ export class AuthenticatedStructures {
|
|
|
347
364
|
|
|
348
365
|
results.push(result);
|
|
349
366
|
}
|
|
350
|
-
// #endregion
|
|
351
367
|
|
|
352
368
|
return results;
|
|
353
369
|
}
|
|
@@ -365,7 +381,7 @@ export class AuthenticatedStructures {
|
|
|
365
381
|
|
|
366
382
|
static async userWithMembers(user: User): Promise<UserWithMembers> {
|
|
367
383
|
const members = await Member.getMembersWithRegistrationForUser(user);
|
|
368
|
-
const filtered:
|
|
384
|
+
const filtered: MemberWithUsersRegistrationsAndGroups[] = [];
|
|
369
385
|
for (const member of members) {
|
|
370
386
|
if (await Context.auth.canAccessMember(member, PermissionLevel.Read)) {
|
|
371
387
|
filtered.push(member);
|
|
@@ -403,28 +419,142 @@ export class AuthenticatedStructures {
|
|
|
403
419
|
return structs;
|
|
404
420
|
}
|
|
405
421
|
|
|
406
|
-
static async members(members:
|
|
422
|
+
static async members(members: MemberWithUsersRegistrationsAndGroups[]): Promise<MemberWithRegistrationsBlob[]> {
|
|
407
423
|
return (await this.membersBlob(members, false)).members;
|
|
408
424
|
}
|
|
409
425
|
|
|
410
|
-
static async membersBlob(members:
|
|
426
|
+
static async membersBlob(members: MemberWithUsersRegistrationsAndGroups[], includeContextOrganization = false, includeUser?: User, options?: { forAdminCartCalculation?: boolean }): Promise<MembersBlob> {
|
|
411
427
|
if (members.length === 0 && !includeUser) {
|
|
412
428
|
return MembersBlob.create({ members: [], organizations: [] });
|
|
413
429
|
}
|
|
430
|
+
|
|
414
431
|
const organizations = new Map<string, Organization>();
|
|
432
|
+
const relevantPeriodIds = Formatter.uniqueArray([
|
|
433
|
+
Platform.shared.period.previousPeriodId,
|
|
434
|
+
Platform.shared.period.id,
|
|
435
|
+
Platform.shared.period.nextPeriodId,
|
|
436
|
+
Context.organization?.periodId ?? null,
|
|
437
|
+
].filter(id => id !== null)) as string[];
|
|
415
438
|
|
|
416
439
|
const registrationIds = Formatter.uniqueArray(members.flatMap(m => m.registrations.map(r => r.id)));
|
|
417
440
|
|
|
418
|
-
|
|
419
|
-
|
|
441
|
+
// This code is a bit messy, we need to optimize it a bit. But it is this complex because it tries
|
|
442
|
+
// to load as many relations as possible in advance in one go, to avoid doing queries inside the loops.
|
|
443
|
+
// this is very important as this method is called very often.
|
|
444
|
+
|
|
445
|
+
// Load responsibilities
|
|
446
|
+
const responsibilities = members.length > 0
|
|
447
|
+
? await MemberResponsibilityRecord.select()
|
|
448
|
+
.where('memberId', members.map(m => m.id))
|
|
449
|
+
.where(SQL.where('endDate', null).or('endDate', '>', new Date()))
|
|
450
|
+
.fetch()
|
|
451
|
+
: [];
|
|
452
|
+
const platformMemberships = members.length > 0
|
|
453
|
+
? await MemberPlatformMembership.select()
|
|
454
|
+
.where('memberId', members.map(m => m.id))
|
|
455
|
+
.where('deletedAt', null)
|
|
456
|
+
.where('periodId', relevantPeriodIds)
|
|
457
|
+
.fetch()
|
|
458
|
+
: [];
|
|
459
|
+
|
|
460
|
+
// Load organizations
|
|
461
|
+
const organizationIds = responsibilities.map(r => r.organizationId)
|
|
462
|
+
.concat(
|
|
463
|
+
platformMemberships.map(r => r.organizationId),
|
|
464
|
+
)
|
|
465
|
+
.filter(id => id !== null);
|
|
466
|
+
|
|
467
|
+
if (includeUser) {
|
|
468
|
+
for (const organizationId of includeUser.permissions?.organizationPermissions.keys() ?? []) {
|
|
469
|
+
if (includeContextOrganization || organizationId !== Context.auth.organization?.id) {
|
|
470
|
+
organizationIds.push(organizationId);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (STAMHOOFD.singleOrganization && !Context.auth.organization) {
|
|
476
|
+
organizationIds.push(STAMHOOFD.singleOrganization);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const membershipOrganizationId = Platform.shared.membershipOrganizationId;
|
|
480
|
+
if (membershipOrganizationId && Context.auth.hasSomePlatformAccess()) {
|
|
481
|
+
if (await Context.auth.hasSomeAccess(membershipOrganizationId)) {
|
|
482
|
+
organizationIds.push(membershipOrganizationId);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
for (const member of members) {
|
|
487
|
+
for (const registration of member.registrations) {
|
|
488
|
+
organizationIds.push(registration.organizationId);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Now fetch organizations
|
|
493
|
+
// todo: optimize this
|
|
494
|
+
for (const id of organizationIds) {
|
|
495
|
+
if (includeContextOrganization || id !== Context.auth.organization?.id) {
|
|
496
|
+
const found = organizations.get(id);
|
|
497
|
+
if (!found) {
|
|
498
|
+
const organization = await Context.auth.getOrganization(id);
|
|
499
|
+
organizations.set(organization.id, organization);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Already fetch these organizations fully, because then we can reuse the groups in here
|
|
505
|
+
const activeOrganizations: Organization[] = [];
|
|
506
|
+
|
|
507
|
+
for (const organization of organizations.values()) {
|
|
508
|
+
if (organization.active || await Context.auth.hasFullAccess(organization.id)) {
|
|
509
|
+
activeOrganizations.push(organization);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const organizationStructs = await this.organizations(activeOrganizations);
|
|
513
|
+
|
|
514
|
+
let groupIds = Formatter.uniqueArray(
|
|
515
|
+
[
|
|
516
|
+
...members.flatMap(m => m.registrations.map(r => r.groupId)).filter(id => id !== null),
|
|
517
|
+
...responsibilities.map(r => r.groupId).filter(id => id !== null),
|
|
518
|
+
],
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
// Set gropus that we already loaded
|
|
522
|
+
const allGroups = new Map<string, GroupStruct>();
|
|
523
|
+
for (const organization of organizationStructs) {
|
|
524
|
+
for (const group of organization.period.groups) {
|
|
525
|
+
allGroups.set(group.id, group);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const preloadedGroupModels: Map<string, Group> = new Map();
|
|
530
|
+
|
|
531
|
+
for (const member of members) {
|
|
532
|
+
for (const registration of member.registrations) {
|
|
533
|
+
if (!allGroups.has(registration.groupId) && !preloadedGroupModels.has(registration.groupId)) {
|
|
534
|
+
preloadedGroupModels.set(registration.group.id, registration.group);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
420
537
|
}
|
|
538
|
+
|
|
539
|
+
// Remove duplicates and already loaded ones
|
|
540
|
+
groupIds = groupIds.filter(id => !allGroups.has(id) && !preloadedGroupModels.has(id));
|
|
541
|
+
const groups = groupIds.length > 0 ? [...preloadedGroupModels.values(), ...await Group.getByIDs(...groupIds)] : [...preloadedGroupModels.values()];
|
|
542
|
+
if (groupIds.length > 0 && STAMHOOFD.environment === 'development') {
|
|
543
|
+
console.log('Doing extra group query for groups', groupIds);
|
|
544
|
+
}
|
|
545
|
+
const groupStructs = await this.groups(groups);
|
|
546
|
+
for (const group of groupStructs) {
|
|
547
|
+
allGroups.set(group.id, group);
|
|
548
|
+
}
|
|
549
|
+
|
|
421
550
|
const balances = await CachedBalance.getForObjects(registrationIds, null, ReceivableBalanceType.registration);
|
|
422
551
|
const memberIds = members.map(m => m.id);
|
|
423
552
|
const allMemberBalances = Context.organization
|
|
424
553
|
? (await CachedBalance.getForObjects(memberIds, Context.organization.id, ReceivableBalanceType.member))
|
|
425
554
|
: [];
|
|
426
555
|
|
|
427
|
-
|
|
556
|
+
// Delete organizations that no longer exist in the permissions of the user
|
|
557
|
+
/* if (includeUser) {
|
|
428
558
|
for (const organizationId of includeUser.permissions?.organizationPermissions.keys() ?? []) {
|
|
429
559
|
if (includeContextOrganization || organizationId !== Context.auth.organization?.id) {
|
|
430
560
|
const found = organizations.get(organizationId);
|
|
@@ -452,26 +582,7 @@ export class AuthenticatedStructures {
|
|
|
452
582
|
}
|
|
453
583
|
}
|
|
454
584
|
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
if (includeContextOrganization && STAMHOOFD.singleOrganization && !Context.auth.organization) {
|
|
458
|
-
const found = organizations.get(STAMHOOFD.singleOrganization);
|
|
459
|
-
if (!found) {
|
|
460
|
-
const organization = await Context.auth.getOrganization(STAMHOOFD.singleOrganization);
|
|
461
|
-
organizations.set(organization.id, organization);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
const membershipOrganizationId = Platform.shared.membershipOrganizationId;
|
|
466
|
-
if (Context.auth.hasSomePlatformAccess() && membershipOrganizationId) {
|
|
467
|
-
if (await Context.auth.hasSomeAccess(membershipOrganizationId)) {
|
|
468
|
-
const found = organizations.get(membershipOrganizationId);
|
|
469
|
-
if (!found) {
|
|
470
|
-
const organization = await Context.auth.getOrganization(membershipOrganizationId);
|
|
471
|
-
organizations.set(organization.id, organization);
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
585
|
+
} */
|
|
475
586
|
|
|
476
587
|
const memberBlobs: MemberWithRegistrationsBlob[] = [];
|
|
477
588
|
for (const member of members) {
|
|
@@ -524,7 +635,13 @@ export class AuthenticatedStructures {
|
|
|
524
635
|
return GenericBalance.create(b);
|
|
525
636
|
}))
|
|
526
637
|
: [];
|
|
527
|
-
|
|
638
|
+
const g = allGroups.get(r.groupId);
|
|
639
|
+
if (g) {
|
|
640
|
+
base.group = g;
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
console.error('Group not preloaded for registration', r.id, r.groupId);
|
|
644
|
+
}
|
|
528
645
|
|
|
529
646
|
return base;
|
|
530
647
|
}),
|
|
@@ -538,55 +655,6 @@ export class AuthenticatedStructures {
|
|
|
538
655
|
);
|
|
539
656
|
}
|
|
540
657
|
|
|
541
|
-
// Load responsibilities
|
|
542
|
-
const responsibilities = members.length > 0 ? await MemberResponsibilityRecord.where({ memberId: { sign: 'IN', value: members.map(m => m.id) } }) : [];
|
|
543
|
-
const platformMemberships = members.length > 0 ? await MemberPlatformMembership.where({ deletedAt: null, memberId: { sign: 'IN', value: members.map(m => m.id) } }) : [];
|
|
544
|
-
|
|
545
|
-
// Load missing organizations
|
|
546
|
-
const organizationIds = Formatter.uniqueArray(responsibilities.map(r => r.organizationId).concat(platformMemberships.map(r => r.organizationId)).filter(id => id !== null));
|
|
547
|
-
for (const id of organizationIds) {
|
|
548
|
-
if (includeContextOrganization || id !== Context.auth.organization?.id) {
|
|
549
|
-
const found = organizations.get(id);
|
|
550
|
-
if (!found) {
|
|
551
|
-
const organization = await Context.auth.getOrganization(id);
|
|
552
|
-
organizations.set(organization.id, organization);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
const activeOrganizations: Organization[] = [];
|
|
558
|
-
|
|
559
|
-
for (const organization of organizations.values()) {
|
|
560
|
-
if (organization.active || await Context.auth.hasFullAccess(organization.id)) {
|
|
561
|
-
activeOrganizations.push(organization);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
const organizationStructs = await this.organizations(activeOrganizations);
|
|
565
|
-
|
|
566
|
-
// Load missing groups
|
|
567
|
-
const allGroups = new Map<string, GroupStruct>();
|
|
568
|
-
for (const organization of organizationStructs) {
|
|
569
|
-
for (const group of organization.period.groups) {
|
|
570
|
-
allGroups.set(group.id, group);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
for (const blob of memberBlobs) {
|
|
575
|
-
for (const registration of blob.registrations) {
|
|
576
|
-
if (registration.group) {
|
|
577
|
-
allGroups.set(registration.group.id, registration.group);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
const groupIds = Formatter.uniqueArray(responsibilities.map(r => r.groupId).filter(id => id !== null)).filter(id => !allGroups.has(id));
|
|
583
|
-
const groups = groupIds.length > 0 ? await Group.getByIDs(...groupIds) : [];
|
|
584
|
-
const groupStructs = await this.groups(groups);
|
|
585
|
-
|
|
586
|
-
for (const group of groupStructs) {
|
|
587
|
-
allGroups.set(group.id, group);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
658
|
for (const blob of memberBlobs) {
|
|
591
659
|
blob.responsibilities = responsibilities.filter(r => r.memberId == blob.id).map((r) => {
|
|
592
660
|
const group = allGroups.get(r.groupId ?? '') ?? null;
|
|
@@ -627,7 +695,7 @@ export class AuthenticatedStructures {
|
|
|
627
695
|
return (await this.eventNotifications([eventNotification]))[0];
|
|
628
696
|
}
|
|
629
697
|
|
|
630
|
-
static async registrationsBlob(registrations: (Registration & { group: Group })[], members:
|
|
698
|
+
static async registrationsBlob(registrations: (Registration & { group: Group })[], members: MemberWithUsersRegistrationsAndGroups[], includeContextOrganization = false, includeUser?: User): Promise<RegistrationsBlob> {
|
|
631
699
|
const membersBlob = await this.membersBlob(members, includeContextOrganization, includeUser);
|
|
632
700
|
|
|
633
701
|
const memberBlobs = membersBlob.members;
|
|
@@ -756,6 +824,10 @@ export class AuthenticatedStructures {
|
|
|
756
824
|
}
|
|
757
825
|
|
|
758
826
|
static async orders(orders: Order[]): Promise<PrivateOrder[]> {
|
|
827
|
+
if (orders.length === 0) {
|
|
828
|
+
return [];
|
|
829
|
+
}
|
|
830
|
+
|
|
759
831
|
const result: PrivateOrder[] = [];
|
|
760
832
|
const webshopIds = new Set(orders.map(o => o.webshopId));
|
|
761
833
|
|
|
@@ -775,9 +847,10 @@ export class AuthenticatedStructures {
|
|
|
775
847
|
});
|
|
776
848
|
}
|
|
777
849
|
}
|
|
850
|
+
const allBalanceItems = await BalanceItem.select().where('orderId', orders.map(o => o.id)).fetch();
|
|
778
851
|
|
|
779
852
|
for (const order of orders) {
|
|
780
|
-
const balanceItems =
|
|
853
|
+
const balanceItems = allBalanceItems.filter(b => b.orderId === order.id);
|
|
781
854
|
|
|
782
855
|
const struct = PrivateOrder.create({
|
|
783
856
|
...order,
|
|
@@ -1133,4 +1206,16 @@ export class AuthenticatedStructures {
|
|
|
1133
1206
|
|
|
1134
1207
|
return structs;
|
|
1135
1208
|
}
|
|
1209
|
+
|
|
1210
|
+
static async balanceItems(balanceItems: BalanceItem[]) {
|
|
1211
|
+
return balanceItems.map((balanceItem) => {
|
|
1212
|
+
return BalanceItemStruct.create({
|
|
1213
|
+
...balanceItem,
|
|
1214
|
+
});
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
static async balanceItemsWithPayments(balanceItems: BalanceItem[]) {
|
|
1219
|
+
return await BalanceItem.getStructureWithPayments(balanceItems);
|
|
1220
|
+
}
|
|
1136
1221
|
}
|
package/src/helpers/Context.ts
CHANGED
|
@@ -52,6 +52,8 @@ export class AuthorizationPostBody extends AutoEncoder {
|
|
|
52
52
|
|
|
53
53
|
export class ContextInstance {
|
|
54
54
|
request: Request;
|
|
55
|
+
queries: { query: string; time?: number }[] = [];
|
|
56
|
+
timers: Map<string, number> = new Map();
|
|
55
57
|
|
|
56
58
|
user?: User;
|
|
57
59
|
organization?: Organization;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Email, Organization, User } from '@stamhoofd/models';
|
|
2
2
|
import { SQL } from '@stamhoofd/sql';
|
|
3
3
|
import { EmailStatus } from '@stamhoofd/structures';
|
|
4
|
-
import { ContextInstance } from './Context';
|
|
4
|
+
import { ContextInstance } from './Context.js';
|
|
5
5
|
|
|
6
6
|
export async function resumeEmails() {
|
|
7
7
|
const query = SQL.select()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Group, Member, MemberResponsibilityRecord, Organization, Platform, Registration } from '@stamhoofd/models';
|
|
2
2
|
import { SQL, SQLWhereExists } from '@stamhoofd/sql';
|
|
3
3
|
import { GroupType } from '@stamhoofd/structures';
|
|
4
|
-
import { MemberUserSyncer } from './MemberUserSyncer';
|
|
4
|
+
import { MemberUserSyncer } from './MemberUserSyncer.js';
|
|
5
5
|
|
|
6
6
|
export class FlagMomentCleanup {
|
|
7
7
|
/**
|
|
@@ -2,7 +2,7 @@ import { EmailAddress } from '@stamhoofd/email';
|
|
|
2
2
|
import { OrganizationFactory, UserFactory } from '@stamhoofd/models';
|
|
3
3
|
import { OrganizationEmail, PermissionLevel, Permissions } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
|
-
import { ForwardHandler } from './ForwardHandler';
|
|
5
|
+
import { ForwardHandler } from './ForwardHandler.js';
|
|
6
6
|
|
|
7
7
|
describe('ForwardHandler', () => {
|
|
8
8
|
it('should send to default e-mail', async () => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { I18n } from '@stamhoofd/backend-i18n';
|
|
2
|
-
import { BalanceItemService } from '../services/BalanceItemService';
|
|
3
|
-
import { FileSignService } from '../services/FileSignService';
|
|
4
|
-
import { MemberRecordStore } from '../services/MemberRecordStore';
|
|
5
|
-
import { ContextInstance } from './Context';
|
|
2
|
+
import { BalanceItemService } from '../services/BalanceItemService.js';
|
|
3
|
+
import { FileSignService } from '../services/FileSignService.js';
|
|
4
|
+
import { MemberRecordStore } from '../services/MemberRecordStore.js';
|
|
5
|
+
import { ContextInstance } from './Context.js';
|
|
6
6
|
|
|
7
7
|
export class GlobalHelper {
|
|
8
8
|
static async load() {
|