@stamhoofd/backend 2.121.0 → 2.122.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/output-2.txt +1 -0
- package/output.txt +1 -0
- package/package.json +69 -52
- package/src/audit-logs/EventNotificationLogger.ts +40 -0
- package/src/audit-logs/ModelLogger.ts +19 -15
- package/src/audit-logs/OrganizationLogger.ts +1 -1
- package/src/audit-logs/RegistrationInvitationLogger.ts +24 -24
- package/src/audit-logs/init.ts +8 -2
- package/src/boot.ts +19 -18
- package/src/crons/amazon-ses.ts +13 -26
- package/src/crons/balance-emails.ts +3 -5
- package/src/crons/clearExcelCache.test.ts +1 -1
- package/src/crons/clearExcelCache.ts +1 -2
- package/src/crons/drip-emails.ts +42 -0
- package/src/crons/endFunctionsOfUsersWithoutRegistration.ts +4 -0
- package/src/crons/helpers/isOutside.ts +11 -0
- package/src/crons/helpers/useSavedIterator.ts +32 -0
- package/src/crons/index.ts +5 -0
- package/src/crons/invoices.ts +32 -38
- package/src/crons/members-fees.ts +50 -0
- package/src/crons/mollie-chargebacks.ts +14 -15
- package/src/crons/service-fees.ts +152 -0
- package/src/crons/stripe-invoices.ts +48 -0
- package/src/crons/transfer-fees.ts +176 -0
- package/src/crons/update-cached-balances.ts +4 -4
- package/src/crons.ts +7 -64
- package/src/debug.ts +4 -2
- package/src/email-recipient-loaders/documents.ts +1 -1
- package/src/email-recipient-loaders/members.ts +1 -1
- package/src/email-recipient-loaders/payments.ts +4 -6
- package/src/email-recipient-loaders/registrations.ts +1 -1
- package/src/email-replacements/getEmailReplacementsForPayment.ts +5 -9
- package/src/endpoints/admin/members/ChargeMembersEndpoint.ts +1 -1
- package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +1 -1
- package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +3 -5
- package/src/endpoints/admin/organizations/ChargeOrganizationsEndpoint.ts +1 -1
- package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +1 -1
- package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +13 -7
- package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +4 -6
- package/src/endpoints/admin/organizations/PatchPackagesEndpoint.test.ts +10 -6
- package/src/endpoints/admin/organizations/PatchPackagesEndpoint.ts +39 -21
- package/src/endpoints/admin/registrations/ChargeRegistrationsEndpoint.ts +1 -1
- package/src/endpoints/auth/CreateAdminEndpoint.ts +23 -5
- package/src/endpoints/auth/CreateTokenEndpoint.ts +2 -2
- package/src/endpoints/auth/DeleteTokenEndpoint.ts +1 -1
- package/src/endpoints/auth/DeleteUserEndpoint.ts +3 -3
- package/src/endpoints/auth/ForgotPasswordEndpoint.ts +1 -1
- package/src/endpoints/auth/GetOtherUserEndpoint.ts +1 -1
- package/src/endpoints/auth/GetUserEndpoint.ts +1 -1
- package/src/endpoints/auth/OpenIDConnectAuthTokenEndpoint.ts +1 -1
- package/src/endpoints/auth/OpenIDConnectStartEndpoint.ts +1 -1
- package/src/endpoints/auth/PatchUserEndpoint.ts +5 -8
- package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +1 -1
- package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +1 -1
- package/src/endpoints/auth/SignupEndpoint.ts +2 -3
- package/src/endpoints/auth/VerifyEmailEndpoint.ts +20 -3
- package/src/endpoints/frontend/FrontendEnvironmentEndpoint.ts +2 -1
- package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +2 -4
- package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +1 -1
- package/src/endpoints/global/audit-logs/GetAuditLogsEndpoint.ts +5 -7
- package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +2 -2
- package/src/endpoints/global/email/CreateEmailEndpoint.ts +3 -4
- package/src/endpoints/global/email/GetAdminEmailsEndpoint.test.ts +1 -1
- package/src/endpoints/global/email/GetAdminEmailsEndpoint.ts +1 -2
- package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +4 -6
- package/src/endpoints/global/email/GetEmailEndpoint.ts +1 -1
- package/src/endpoints/global/email/GetUserEmailsEndpoint.test.ts +1 -1
- package/src/endpoints/global/email/GetUserEmailsEndpoint.ts +1 -1
- package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +6 -10
- package/src/endpoints/global/email/PatchEmailEndpoint.test.ts +4 -7
- package/src/endpoints/global/email/PatchEmailEndpoint.ts +6 -9
- package/src/endpoints/global/email-recipients/GetEmailRecipientsCountEndpoint.ts +1 -1
- package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.test.ts +1 -1
- package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.ts +1 -1
- package/src/endpoints/global/email-recipients/RetryEmailRecipientEndpoint.ts +2 -2
- package/src/endpoints/global/events/GetEventNotificationsCountEndpoint.ts +1 -1
- package/src/endpoints/global/events/GetEventNotificationsEndpoint.ts +3 -3
- package/src/endpoints/global/events/GetEventsEndpoint.ts +3 -3
- package/src/endpoints/global/events/PatchEventNotificationsEndpoint.test.ts +49 -4
- package/src/endpoints/global/events/PatchEventNotificationsEndpoint.ts +5 -8
- package/src/endpoints/global/events/PatchEventsEndpoint.test.ts +12 -44
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +128 -127
- package/src/endpoints/global/files/ExportToExcelEndpoint.ts +9 -9
- package/src/endpoints/global/files/GetFileCache.ts +3 -4
- package/src/endpoints/global/files/UploadFile.ts +3 -4
- package/src/endpoints/global/files/UploadImage.ts +3 -4
- package/src/endpoints/global/groups/GetGroupsCountEndpoint.ts +1 -1
- package/src/endpoints/global/groups/GetGroupsEndpoint.test.ts +1 -1
- package/src/endpoints/global/groups/GetGroupsEndpoint.ts +4 -2
- package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +2 -3
- package/src/endpoints/global/members/GetMembersCountEndpoint.ts +1 -1
- package/src/endpoints/global/members/GetMembersEndpoint.test.ts +2 -2
- package/src/endpoints/global/members/GetMembersEndpoint.ts +10 -12
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.test.ts +195 -12
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +16 -22
- package/src/endpoints/global/members/helpers/validateGroupFilter.ts +6 -30
- package/src/endpoints/global/members/shouldCheckIfMemberIsDuplicate.ts +1 -1
- package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +1 -1
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +40 -8
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +2 -2
- package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +2 -2
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +4 -1
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +4 -5
- package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +9 -16
- package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +1 -1
- package/src/endpoints/global/platform/GetPlatformEndpoint.ts +1 -1
- package/src/endpoints/global/platform/PatchPlatformEnpoint.test.ts +1 -1
- package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +11 -11
- package/src/endpoints/global/platform-memberships/GetPlatformMembershipsCountEndpoint.ts +31 -31
- package/src/endpoints/global/platform-memberships/GetPlatformMembershipsEndpoint.ts +18 -20
- package/src/endpoints/global/registration/GetRegistrationsCountEndpoint.ts +1 -1
- package/src/endpoints/global/registration/GetRegistrationsEndpoint.test.ts +1 -1
- package/src/endpoints/global/registration/GetRegistrationsEndpoint.ts +6 -10
- package/src/endpoints/global/registration/GetUserDetailedPayableBalanceEndpoint.ts +35 -6
- package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +2 -2
- package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +1 -1
- package/src/endpoints/global/registration/GetUserPayableBalanceEndpoint.ts +1 -1
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.test.ts +2 -2
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +3 -3
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +90 -6
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +35 -34
- package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsCountEndpoint.ts +1 -1
- package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.test.ts +62 -63
- package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.ts +6 -9
- package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.test.ts +51 -52
- package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.ts +6 -7
- package/src/endpoints/global/registration-periods/GetRegistrationPeriodsCountEndpoint.ts +43 -0
- package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +1 -1
- package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +13 -5
- package/src/endpoints/global/sso/GetSSOEndpoint.ts +2 -3
- package/src/endpoints/global/sso/SetSSOEndpoint.ts +1 -1
- package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +2 -2
- package/src/endpoints/global/webshops/GetWebshopsEndpoint.test.ts +1 -2
- package/src/endpoints/global/webshops/GetWebshopsEndpoint.ts +2 -4
- package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsCountEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsEndpoint.ts +3 -4
- package/src/endpoints/organization/dashboard/balance-items/PatchBalanceItemsEndpoint.ts +7 -9
- package/src/endpoints/organization/dashboard/billing/ApplyRegisterCodeEndpoint.test.ts +73 -0
- package/src/endpoints/organization/dashboard/billing/ApplyRegisterCodeEndpoint.ts +89 -0
- package/src/endpoints/organization/dashboard/billing/DeactivatePackageEndpoint.ts +1 -5
- package/src/endpoints/organization/dashboard/billing/DeleteOrganizationMandateEndpoint.ts +11 -11
- package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceCollectionEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceEndpoint.ts +8 -8
- package/src/endpoints/organization/dashboard/billing/GetOrganizationMandatesEndpoint.ts +9 -9
- package/src/endpoints/organization/dashboard/billing/GetOrganizationPayableBalanceEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/billing/GetOrganizationPayableInvoicesEndpoint.ts +68 -0
- package/src/endpoints/organization/dashboard/billing/GetPackagesEndpoint.ts +4 -4
- package/src/endpoints/organization/dashboard/billing/GetRegisterCodeEndpoint.ts +66 -0
- package/src/endpoints/organization/dashboard/billing/OrganizationCheckoutEndpoint.test.ts +949 -0
- package/src/endpoints/organization/dashboard/billing/OrganizationCheckoutEndpoint.ts +60 -57
- package/src/endpoints/organization/dashboard/billing/PatchOrganizationMandatesEndpoint.ts +20 -20
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +1 -1
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesCountEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/documents/GetDocumentsCountEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +10 -2
- package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.test.ts +2 -2
- package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.test.ts +1 -1
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +10 -8
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.test.ts +1 -1
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +5 -6
- package/src/endpoints/organization/dashboard/invoices/GetInvoicesCountEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/invoices/GetInvoicesEndpoint.ts +10 -6
- package/src/endpoints/organization/dashboard/invoices/PatchInvoicesEndpoint.ts +11 -2
- package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +4 -5
- package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +5 -5
- package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +7 -7
- 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 +1 -1
- package/src/endpoints/organization/dashboard/organization/GetUitpasClientIdEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +50 -12
- package/src/endpoints/organization/dashboard/organization/SearchUitpasOrganizersEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +5 -10
- package/src/endpoints/organization/dashboard/organization/SetUitpasClientCredentialsEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +3 -4
- package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +21 -14
- package/src/endpoints/organization/dashboard/receivable-balances/ChargeReceivableBalancesEndpoint.ts +35 -28
- package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint.ts +2 -3
- package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesCountEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.test.ts +1 -1
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +2 -3
- package/src/endpoints/organization/dashboard/registration-periods/MoveRegistrationPeriods.test.ts +1 -1
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.test.ts +1 -1
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +19 -18
- package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +4 -5
- package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +2 -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 +1 -1
- 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.ts +4 -6
- package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +10 -15
- package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersCountEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +11 -2
- package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +4 -6
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +22 -7
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +20 -27
- 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 +2 -3
- package/src/endpoints/organization/dashboard/webshops/WebshopReservedPathSegments.test.ts +95 -0
- package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +2 -2
- package/src/endpoints/organization/shared/GetDocumentHtml.ts +1 -1
- package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +1 -1
- package/src/endpoints/organization/shared/GetUitpasNumberDetailsEndpoint.ts +3 -5
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +1 -1
- package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +4 -1
- package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +14 -3
- package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +14 -2
- package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +37 -16
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +34 -2
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +4 -2
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +74 -3
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +16 -33
- package/src/endpoints/organization/webshops/RetrieveUitpasSocialTariffPriceEndpoint.ts +3 -5
- package/src/endpoints/organization/webshops/WebshopAuthHelper.ts +36 -0
- package/src/endpoints/system/HealthEndpoint.ts +1 -1
- package/src/excel-loaders/balance-items.ts +1 -1
- package/src/excel-loaders/event-notifications.ts +1 -1
- package/src/excel-loaders/members.ts +1 -1
- package/src/excel-loaders/organizations.ts +3 -3
- package/src/excel-loaders/payments.ts +31 -1
- package/src/excel-loaders/platform-memberships.ts +13 -14
- package/src/excel-loaders/receivable-balances.ts +2 -2
- package/src/excel-loaders/registrations.ts +2 -3
- package/src/helpers/AddressValidator.ts +7 -14
- package/src/helpers/AdminPermissionChecker.ts +50 -63
- package/src/helpers/AuthenticatedStructures.ts +69 -55
- package/src/helpers/BalanceItemRelationsBackfiller.test.ts +174 -0
- package/src/helpers/BalanceItemRelationsBackfiller.ts +163 -0
- package/src/helpers/BuckarooHelper.ts +2 -4
- package/src/helpers/CheckSettlements.ts +12 -24
- package/src/helpers/Context.ts +15 -10
- package/src/helpers/CookieHelper.ts +1 -2
- package/src/helpers/EmailResumer.ts +1 -2
- package/src/helpers/FileCache.ts +2 -3
- package/src/helpers/FinancialSupportHelper.ts +2 -2
- package/src/helpers/FlagMomentCleanup.ts +1 -2
- package/src/helpers/ForwardHandler.ts +5 -10
- package/src/helpers/GlobalHelper.ts +3 -3
- package/src/helpers/LegacyBillingConverter.ts +787 -0
- package/src/helpers/MemberMerger.test.ts +782 -0
- package/src/helpers/MemberMerger.ts +600 -0
- package/src/helpers/MemberUserSyncer.ts +6 -12
- package/src/helpers/MembershipCharger.ts +2 -4
- package/src/helpers/PaymentCustomerResolver.test.ts +203 -0
- package/src/helpers/PaymentCustomerResolver.ts +144 -0
- package/src/helpers/PeriodHelper.ts +2 -3
- package/src/helpers/RecordAnswerHelper.test.ts +105 -110
- package/src/helpers/RecordAnswerHelper.ts +7 -7
- package/src/helpers/SeedTools.ts +106 -0
- package/src/helpers/ServiceFeeHelper.ts +125 -15
- package/src/helpers/SetupStepUpdater.ts +38 -32
- package/src/helpers/StamhoofdFilterAccessHelper.ts +52 -0
- package/src/helpers/StripeHelper.ts +14 -36
- package/src/helpers/StripeInvoicer.ts +419 -0
- package/src/helpers/StripePayoutChecker.ts +5 -10
- package/src/helpers/TagHelper.ts +7 -8
- package/src/helpers/TemporaryMemberAccess.ts +1 -2
- package/src/helpers/ThrottledQueue.ts +1 -2
- package/src/helpers/UitpasTokenRepository.ts +1 -2
- package/src/helpers/ViesHelper.ts +7 -11
- package/src/helpers/XlsxTransformerColumnHelper.ts +1 -1
- package/src/helpers/outstandingBalanceJoin.ts +2 -2
- package/src/helpers/updateMemberDetailsUitpasNumber.ts +3 -5
- package/src/migrate.ts +12 -5
- package/src/{seeds → migrations}/0000000004-single-organization.ts +10 -1
- package/src/migrations/0000000006-default-organization.ts +139 -0
- package/src/{seeds → migrations}/1715028563-user-permissions.ts +17 -27
- package/src/{seeds/1765896674-document-update-year.test.ts → migrations/1750090029-document-update-year.test.ts} +27 -26
- package/src/migrations/1750090029-document-update-year.ts +103 -0
- package/src/{seeds → migrations}/1750090030-records-configuration.ts +33 -32
- package/src/migrations/1750090031-records-configuration-webshops.ts +36 -0
- package/src/migrations/1752848540-national-numbers.ts +585 -0
- package/src/migrations/1752848550-records-configuration-group-filter.ts +1064 -0
- package/src/{seeds → migrations}/1752848561-groups-registration-periods.ts +70 -26
- package/src/{seeds → migrations}/1754560914-groups-prices.test.ts +1 -1
- package/src/{seeds → migrations}/1754560914-groups-prices.ts +9 -15
- package/src/{seeds → migrations}/1756293699-fill-previous-next-period-id.ts +1 -2
- package/src/migrations/1761665607-sync-member-users.ts +40 -0
- package/src/migrations/1779121240-invoice-email-template.sql +6 -0
- package/src/migrations/1779986893-default-payment-failed-email-templates.sql +4 -0
- package/src/migrations/1780578166-convert-legacy-billing.ts +13 -0
- package/src/{seeds/1755876819-remove-duplicate-members.ts → migrations/1780665426-remove-duplicate-members.ts} +23 -4
- package/src/migrations/1780933598-document-groups.ts +88 -0
- package/src/migrations/1781692342-balance-item-relations.ts +13 -0
- package/src/migrations/1781857866-platform-admins.ts +103 -0
- package/src/migrations/1781857867-rm-old-platform-admins.ts +25 -0
- package/src/seeds/0000000001-throw.ts +5 -0
- package/src/seeds/1760702452-update-balance-price-paid.ts +19 -0
- package/src/seeds/1760702453-update-balance-invoiced.ts +19 -0
- package/src/seeds/1760702454-update-cached-outstanding-balance-from-items.ts +51 -14
- package/src/seeds/1773754928-force-save-members.ts +41 -8
- package/src/seeds/1780665427-schedule-stock-updates.ts +45 -0
- package/src/seeds/1780665428-group-update-occupancy.ts +31 -0
- package/src/seeds/1780915001-fill-payment-customer.ts +70 -0
- package/src/seeds/1780915002-update-orders.ts +39 -0
- package/src/seeds/1782047708-organization-company-address.ts +44 -0
- package/src/seeds-temporary/1769088653-uitpas-status.ts +1 -2
- package/src/seeds-temporary/1780416000-migrate-audit-log-legacy-enums.test.ts +69 -0
- package/src/seeds-temporary/1780416000-migrate-audit-log-legacy-enums.ts +85 -0
- package/src/services/AuditLogService.test.ts +51 -0
- package/src/services/AuditLogService.ts +45 -0
- package/src/services/BalanceItemService.ts +141 -44
- package/src/services/CpuService.ts +3 -6
- package/src/services/DatabaseCollationService.test.ts +1 -2
- package/src/services/DocumentService.ts +1 -2
- package/src/services/EventNotificationService.ts +1 -1
- package/src/services/FileSignService.ts +2 -4
- package/src/services/InvoicePdfService.ts +286 -0
- package/src/services/InvoiceService.ts +204 -251
- package/src/services/InvoiceXMLService.ts +424 -0
- package/src/services/MemberNumberService.ts +6 -11
- package/src/services/MemberRecordStore.ts +8 -10
- package/src/services/MollieService.ts +114 -121
- package/src/services/PaymentMandateService.ts +45 -45
- package/src/services/PaymentReallocationService.test.ts +1 -1
- package/src/services/PaymentReallocationService.ts +7 -9
- package/src/services/PaymentService.ts +444 -308
- package/src/services/PlatformMembershipService.ts +4 -8
- package/src/services/ReferralService.ts +223 -0
- package/src/services/RegistrationService.ts +63 -53
- package/src/services/SSOService.test.ts +119 -0
- package/src/services/SSOService.ts +56 -49
- package/src/services/STPackageService.ts +97 -61
- package/src/services/UniqueMemberNumberService.ts +69 -0
- package/src/services/UniqueUserService.ts +3 -6
- package/src/services/VATService.ts +85 -0
- package/src/services/uitpas/PassholderEndpoints.ts +3 -6
- package/src/services/uitpas/UitpasService.ts +6 -10
- package/src/services/uitpas/checkUitpasNumbers.ts +2 -4
- package/src/services/uitpas/getSocialTariffForUitpasNumbers.ts +3 -6
- package/src/services/uitpas/searchUitpasEvents.ts +1 -2
- package/src/sql-filters/audit-logs.ts +1 -1
- package/src/sql-filters/balance-item-payments.ts +1 -1
- package/src/sql-filters/balance-items.ts +1 -1
- package/src/sql-filters/base-registration-filter-compilers.ts +5 -33
- package/src/sql-filters/document-templates.ts +1 -1
- package/src/sql-filters/documents.ts +1 -1
- package/src/sql-filters/email-recipients.ts +1 -1
- package/src/sql-filters/emails.ts +1 -1
- package/src/sql-filters/event-notifications.ts +1 -1
- package/src/sql-filters/events.ts +6 -1
- package/src/sql-filters/groups.ts +5 -0
- package/src/sql-filters/invoiced-balance-items.ts +1 -1
- package/src/sql-filters/invoices.ts +1 -1
- package/src/sql-filters/member-responsibility-records.ts +1 -1
- package/src/sql-filters/members.ts +1 -1
- package/src/sql-filters/orders.ts +4 -4
- package/src/sql-filters/organization-registration-periods.ts +1 -1
- package/src/sql-filters/organizations.ts +1 -1
- package/src/sql-filters/platform-memberships.ts +3 -3
- package/src/sql-filters/receivable-balances.ts +1 -1
- package/src/sql-filters/registration-periods.ts +1 -1
- package/src/sql-filters/registrations.ts +1 -1
- package/src/sql-filters/tickets.ts +1 -1
- package/src/sql-filters/users.ts +1 -1
- package/src/sql-sorters/groups.ts +23 -0
- package/src/sql-sorters/platform-memberships.ts +16 -16
- package/src/sql-sorters/registration-invitations.ts +2 -2
- package/tests/actions/patchOrganizationMember.ts +1 -1
- package/tests/actions/patchUserMember.ts +1 -1
- package/tests/assertions/assertBalances.ts +6 -12
- package/tests/e2e/api-rate-limits.test.ts +12 -24
- package/tests/e2e/bundle-discounts.test.ts +4 -1
- package/tests/e2e/charge-members.test.ts +13 -11
- package/tests/e2e/documents.test.ts +4 -1
- package/tests/e2e/register.test.ts +7 -9
- package/tests/e2e/stock.test.ts +4 -3
- package/tests/e2e/tickets.test.ts +1 -1
- package/tests/helpers/MollieMocker.ts +462 -0
- package/tests/helpers/PayconiqMocker.ts +138 -45
- package/tests/helpers/StripeMocker.ts +9 -6
- package/tests/helpers/index.ts +4 -0
- package/tests/init/initAdmin.ts +2 -2
- package/tests/init/initBundleDiscount.ts +1 -1
- package/tests/init/initMembershipOrganization.ts +13 -0
- package/tests/init/initPermissionRole.ts +3 -4
- package/tests/vitest.global.setup.ts +1 -1
- package/vitest.config.js +6 -0
- package/.nvmrc +0 -1
- package/src/helpers/GroupBuilder.ts +0 -418
- package/src/seeds/0000000000-example.ts +0 -11
- package/src/seeds/1722256498-group-update-occupancy.ts +0 -52
- package/src/seeds/1726572303-schedule-stock-updates.ts +0 -52
- package/src/seeds/1726847064-setup-steps.ts +0 -16
- package/src/seeds/1728928974-update-cached-outstanding-balance-from-items.ts +0 -31
- package/src/seeds/1729253172-update-orders.ts +0 -21
- package/src/seeds/1733319079-fill-paying-organization-ids.ts +0 -68
- package/src/seeds/1733748412-update-deleted-order-numbers.ts +0 -109
- package/src/seeds/1733994455-balance-item-status-open.ts +0 -30
- package/src/seeds/1740046783-update-membership.ts +0 -17
- package/src/seeds/1741008870-fix-auditlog-description.ts +0 -50
- package/src/seeds/1741011468-fix-auditlog-description-uft16.ts +0 -88
- package/src/seeds/1741268179-fix-group-dates-of-events.ts +0 -32
- package/src/seeds/1751445358-upload-email-attachments.ts +0 -106
- package/src/seeds/1755532883-update-email-sender-ids.ts +0 -47
- package/src/seeds/1755790070-fill-email-recipient-errors.ts +0 -96
- package/src/seeds/1756115432-remove-old-drafts.ts +0 -16
- package/src/seeds/1756115433-fill-email-recipient-organization-id.ts +0 -30
- package/src/seeds/1756303697-update-email-counts.ts +0 -76
- package/src/seeds/1761665607-sync-member-users.ts +0 -59
- package/src/seeds/1765896674-document-update-year.ts +0 -66
- /package/src/{seeds → migrations}/0000000001-development-user.ts +0 -0
- /package/src/{seeds → migrations}/0000000002-clear-stamhoofd-email-templates.ts +0 -0
- /package/src/{seeds → migrations}/0000000003-default-email-templates.ts +0 -0
- /package/src/{seeds → migrations}/1752848561-groups-registration-periods.test.ts +0 -0
- /package/src/{seeds → migrations}/1766150402-document-published-at.test.ts +0 -0
- /package/src/{seeds → migrations}/1766150402-document-published-at.ts +0 -0
- /package/src/{seeds → migrations}/1779121239-default-invoice-email-template.sql +0 -0
- /package/src/{seeds → migrations}/data/default-email-templates.sql +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Migration } from '@simonbackx/simple-database';
|
|
2
|
+
import { AuditLog } from '@stamhoofd/models';
|
|
3
|
+
import { AuditLogReplacement, AuditLogReplacementType, getLegacyAuditLogEnumReplacement } from '@stamhoofd/structures';
|
|
4
|
+
|
|
5
|
+
export function migrateAuditLogReplacementLegacyEnums(replacement: AuditLogReplacement | undefined): { replacement: AuditLogReplacement | undefined; changed: boolean } {
|
|
6
|
+
if (!replacement) {
|
|
7
|
+
return { replacement, changed: false };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (replacement.type === AuditLogReplacementType.Key) {
|
|
11
|
+
const migrated = getLegacyAuditLogEnumReplacement(replacement.value);
|
|
12
|
+
if (migrated) {
|
|
13
|
+
return { replacement: migrated, changed: true };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (replacement.type === AuditLogReplacementType.Array) {
|
|
18
|
+
let changed = false;
|
|
19
|
+
const values = replacement.values.map((value) => {
|
|
20
|
+
const result = migrateAuditLogReplacementLegacyEnums(value);
|
|
21
|
+
changed ||= result.changed;
|
|
22
|
+
return result.replacement ?? value;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (changed) {
|
|
26
|
+
const clone = replacement.clone();
|
|
27
|
+
clone.values = values;
|
|
28
|
+
return { replacement: clone, changed: true };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { replacement, changed: false };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function migrateAuditLogLegacyEnums(log: AuditLog): boolean {
|
|
36
|
+
let changed = false;
|
|
37
|
+
|
|
38
|
+
for (const [key, replacement] of log.replacements) {
|
|
39
|
+
const result = migrateAuditLogReplacementLegacyEnums(replacement);
|
|
40
|
+
if (result.changed && result.replacement) {
|
|
41
|
+
log.replacements.set(key, result.replacement);
|
|
42
|
+
changed = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (const item of log.patchList) {
|
|
47
|
+
const key = migrateAuditLogReplacementLegacyEnums(item.key);
|
|
48
|
+
if (key.changed && key.replacement) {
|
|
49
|
+
item.key = key.replacement;
|
|
50
|
+
changed = true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const oldValue = migrateAuditLogReplacementLegacyEnums(item.oldValue);
|
|
54
|
+
if (oldValue.changed) {
|
|
55
|
+
item.oldValue = oldValue.replacement;
|
|
56
|
+
changed = true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const value = migrateAuditLogReplacementLegacyEnums(item.value);
|
|
60
|
+
if (value.changed) {
|
|
61
|
+
item.value = value.replacement;
|
|
62
|
+
changed = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return changed;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default new Migration(async () => {
|
|
70
|
+
console.log('Start migrating legacy audit log enum replacements.');
|
|
71
|
+
|
|
72
|
+
const batchSize = 100;
|
|
73
|
+
let count = 0;
|
|
74
|
+
|
|
75
|
+
for await (const log of AuditLog.select().limit(batchSize).all()) {
|
|
76
|
+
if (!migrateAuditLogLegacyEnums(log)) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await log.save();
|
|
81
|
+
count += 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log('Finished migrating legacy audit log enum replacements for ' + count + ' audit logs.');
|
|
85
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { column, Model } from '@simonbackx/simple-database';
|
|
2
|
+
import { EnumDecoder } from '@simonbackx/simple-encoding';
|
|
3
|
+
import { PaymentStatus } from '@stamhoofd/structures';
|
|
4
|
+
|
|
5
|
+
import { AuditLogService, modelLogDefinitions } from './AuditLogService.js';
|
|
6
|
+
|
|
7
|
+
enum UnregisteredAuditLogStatus {
|
|
8
|
+
Pending = 'Pending',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class UnregisteredAuditLogModel extends Model {
|
|
12
|
+
static table = 'unregistered_audit_log_models';
|
|
13
|
+
|
|
14
|
+
@column({ type: 'string', decoder: new EnumDecoder(UnregisteredAuditLogStatus) })
|
|
15
|
+
status = UnregisteredAuditLogStatus.Pending;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class RegisteredAuditLogModel extends Model {
|
|
19
|
+
static table = 'registered_audit_log_models';
|
|
20
|
+
|
|
21
|
+
@column({ type: 'string', decoder: new EnumDecoder(PaymentStatus) })
|
|
22
|
+
status = PaymentStatus.Pending;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('AuditLogService', () => {
|
|
26
|
+
const originalModelLogDefinitions = new Map(modelLogDefinitions);
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
modelLogDefinitions.clear();
|
|
30
|
+
for (const [model, definition] of originalModelLogDefinitions) {
|
|
31
|
+
modelLogDefinitions.set(model, definition);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('It throws when an audited enum column has no registered translation helper', () => {
|
|
36
|
+
modelLogDefinitions.clear();
|
|
37
|
+
modelLogDefinitions.set(UnregisteredAuditLogModel, {
|
|
38
|
+
async logEvent() {
|
|
39
|
+
// Not needed for validation.
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
modelLogDefinitions.set(RegisteredAuditLogModel, {
|
|
43
|
+
async logEvent() {
|
|
44
|
+
// Not needed for validation.
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(() => AuditLogService.validateAuditLogEnumTranslations())
|
|
49
|
+
.toThrow('Missing audit log enum translation registration for: UnregisteredAuditLogModel.status');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ModelEvent } from '@simonbackx/simple-database';
|
|
2
2
|
import { Model } from '@simonbackx/simple-database';
|
|
3
|
+
import { ArrayDecoder, EnumDecoder, MapDecoder, SymbolDecoder } from '@simonbackx/simple-encoding';
|
|
4
|
+
import { getAuditLogEnumDecoderObject, getAuditLogEnumType } from '@stamhoofd/structures';
|
|
3
5
|
import type { AuditLogSource } from '@stamhoofd/structures';
|
|
4
6
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
5
7
|
|
|
@@ -15,6 +17,26 @@ export type AuditLogContextSettings = {
|
|
|
15
17
|
};
|
|
16
18
|
export const modelLogDefinitions = new Map<typeof Model, { logEvent: (event: ModelEvent) => Promise<any> }>();
|
|
17
19
|
|
|
20
|
+
function getEnumDecoders(decoder: unknown): EnumDecoder<any>[] {
|
|
21
|
+
if (decoder instanceof EnumDecoder) {
|
|
22
|
+
return [decoder];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (decoder instanceof SymbolDecoder) {
|
|
26
|
+
return getEnumDecoders(decoder.decoder);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (decoder instanceof ArrayDecoder) {
|
|
30
|
+
return getEnumDecoders(decoder.decoder);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (decoder instanceof MapDecoder) {
|
|
34
|
+
return [...getEnumDecoders(decoder.keyDecoder), ...getEnumDecoders(decoder.valueDecoder)];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
|
|
18
40
|
export class AuditLogService {
|
|
19
41
|
private constructor() { }
|
|
20
42
|
static disableLocalStore = new AsyncLocalStorage<AuditLogContextSettings>();
|
|
@@ -47,6 +69,29 @@ export class AuditLogService {
|
|
|
47
69
|
|
|
48
70
|
static listening = false;
|
|
49
71
|
|
|
72
|
+
static validateAuditLogEnumTranslations() {
|
|
73
|
+
const missing: string[] = [];
|
|
74
|
+
|
|
75
|
+
for (const [model] of modelLogDefinitions) {
|
|
76
|
+
const columns = model.columns;
|
|
77
|
+
if (!columns) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
for (const [key, column] of columns) {
|
|
82
|
+
for (const enumDecoder of getEnumDecoders(column.decoder)) {
|
|
83
|
+
if (!getAuditLogEnumType(getAuditLogEnumDecoderObject(enumDecoder))) {
|
|
84
|
+
missing.push(`${model.name}.${key}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (missing.length > 0) {
|
|
91
|
+
throw new Error(`Missing audit log enum translation registration for: ${missing.join(', ')}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
50
95
|
static listen() {
|
|
51
96
|
if (this.listening) {
|
|
52
97
|
return;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Model } from '@simonbackx/simple-database';
|
|
2
|
-
import type { Organization
|
|
3
|
-
import { BalanceItem, CachedBalance, Document, MemberUser, Order, Webshop } from '@stamhoofd/models';
|
|
4
|
-
import {
|
|
2
|
+
import type { Organization } from '@stamhoofd/models';
|
|
3
|
+
import { BalanceItem, CachedBalance, Document, MemberUser, Order, Payment, Platform, Webshop } from '@stamhoofd/models';
|
|
4
|
+
import { SQL } from '@stamhoofd/sql';
|
|
5
|
+
import { AuditLogSource, BalanceItemStatus, BalanceItemType, OrderStatus, PaymentStatus, PaymentType, ReceivableBalanceType } from '@stamhoofd/structures';
|
|
5
6
|
import { Formatter } from '@stamhoofd/utility';
|
|
6
7
|
import { GroupedThrottledQueue } from '../helpers/GroupedThrottledQueue.js';
|
|
7
8
|
import { ThrottledQueue } from '../helpers/ThrottledQueue.js';
|
|
@@ -33,11 +34,21 @@ const userUpdateQueue = new GroupedThrottledQueue(async (organizationId: string,
|
|
|
33
34
|
}, { maxDelay: 10_000 });
|
|
34
35
|
|
|
35
36
|
const organizationUpdateQueue = new GroupedThrottledQueue(async (organizationId: string, organizationIds: string[]) => {
|
|
36
|
-
await CachedBalance.updateForOrganizations(organizationId, organizationIds);
|
|
37
|
+
const results = await CachedBalance.updateForOrganizations(organizationId, organizationIds);
|
|
37
38
|
|
|
38
39
|
for (const payingOrganizationId of organizationIds) {
|
|
39
40
|
await PaymentReallocationService.reallocate(organizationId, payingOrganizationId, ReceivableBalanceType.organization);
|
|
40
41
|
}
|
|
42
|
+
|
|
43
|
+
const platform = await Platform.getShared();
|
|
44
|
+
if (organizationId === platform.membershipOrganizationId) {
|
|
45
|
+
// Clear failed payments
|
|
46
|
+
for (const [organizationId, result] of results) {
|
|
47
|
+
if (result.amountOpen === 0 && result.amountPending === 0) {
|
|
48
|
+
await STPackageService.markBalanceRestored(organizationId);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
41
52
|
}, { maxDelay: 60_000 });
|
|
42
53
|
|
|
43
54
|
export const registrationUpdateQueue = new GroupedThrottledQueue(async (organizationId: string, registrationIds: string[]) => {
|
|
@@ -51,10 +62,10 @@ const bundleDiscountsUpdateQueue = new ThrottledQueue(async (registrationIds: st
|
|
|
51
62
|
}
|
|
52
63
|
}, { maxDelay: 10_000 });
|
|
53
64
|
|
|
54
|
-
export
|
|
55
|
-
listening
|
|
65
|
+
export class BalanceItemService {
|
|
66
|
+
static listening = false;
|
|
56
67
|
|
|
57
|
-
listen() {
|
|
68
|
+
static listen() {
|
|
58
69
|
if (this.listening) {
|
|
59
70
|
return;
|
|
60
71
|
}
|
|
@@ -65,7 +76,7 @@ export const BalanceItemService = {
|
|
|
65
76
|
}
|
|
66
77
|
|
|
67
78
|
if (event.type === 'created' || event.type === 'deleted') {
|
|
68
|
-
|
|
79
|
+
this.scheduleUpdate(event.model);
|
|
69
80
|
return;
|
|
70
81
|
}
|
|
71
82
|
|
|
@@ -80,10 +91,10 @@ export const BalanceItemService = {
|
|
|
80
91
|
|| 'payingOrganizationId' in event.changedFields
|
|
81
92
|
|| 'registrationId' in event.changedFields
|
|
82
93
|
) {
|
|
83
|
-
|
|
94
|
+
this.scheduleUpdate(event.model);
|
|
84
95
|
}
|
|
85
96
|
});
|
|
86
|
-
}
|
|
97
|
+
}
|
|
87
98
|
|
|
88
99
|
/**
|
|
89
100
|
* Schedule an update for the balance item:
|
|
@@ -91,8 +102,8 @@ export const BalanceItemService = {
|
|
|
91
102
|
*
|
|
92
103
|
* Does not execute the update immediately, but schedules it to be run in the background.
|
|
93
104
|
*/
|
|
94
|
-
|
|
95
|
-
|
|
105
|
+
static scheduleUpdate(item: BalanceItem) {
|
|
106
|
+
this.scheduleUpdates([item]);
|
|
96
107
|
|
|
97
108
|
// Todo: optimize
|
|
98
109
|
if (item.type === BalanceItemType.RegistrationBundleDiscount) {
|
|
@@ -101,58 +112,58 @@ export const BalanceItemService = {
|
|
|
101
112
|
bundleDiscountsUpdateQueue.addItem(item.registrationId);
|
|
102
113
|
}
|
|
103
114
|
}
|
|
104
|
-
}
|
|
115
|
+
}
|
|
105
116
|
|
|
106
117
|
/**
|
|
107
118
|
* Call this when a payment or payment balance items have changed.
|
|
108
119
|
* It will also call updateOutstanding automatically, so no need to call that separately again
|
|
109
120
|
*/
|
|
110
|
-
async updatePaidAndPending(items: BalanceItem[]) {
|
|
121
|
+
static async updatePaidAndPending(items: BalanceItem[]) {
|
|
111
122
|
console.log('updatePaidAndPending for', items.length, 'items');
|
|
112
123
|
await BalanceItem.updatePricePaid(Formatter.uniqueArray(items.map(i => i.id)));
|
|
113
|
-
|
|
114
|
-
}
|
|
124
|
+
this.scheduleUpdates(items);
|
|
125
|
+
}
|
|
115
126
|
|
|
116
127
|
/**
|
|
117
128
|
* Call this when a payment or payment balance items have changed.
|
|
118
129
|
* It will also call updateOutstanding automatically, so no need to call that separately again
|
|
119
130
|
*/
|
|
120
|
-
async updateInvoiced(items: (BalanceItem | string)[]) {
|
|
131
|
+
static async updateInvoiced(items: (BalanceItem | string)[]) {
|
|
121
132
|
console.log('updateInvoiced for', items.length, 'items');
|
|
122
133
|
await BalanceItem.updateInvoiced(Formatter.uniqueArray(items.map(i => typeof i === 'string' ? i : i.id)));
|
|
123
|
-
}
|
|
134
|
+
}
|
|
124
135
|
|
|
125
136
|
/**
|
|
126
137
|
* In some situations we need immediate updates
|
|
127
138
|
*/
|
|
128
|
-
async flushRegistrationDiscountsCache() {
|
|
139
|
+
static async flushRegistrationDiscountsCache() {
|
|
129
140
|
await bundleDiscountsUpdateQueue.flushAndWait();
|
|
130
|
-
}
|
|
141
|
+
}
|
|
131
142
|
|
|
132
143
|
/**
|
|
133
144
|
* Make sure all the pending changes for cached balances are run
|
|
134
145
|
*/
|
|
135
|
-
async flushCaches(organizationId: string) {
|
|
146
|
+
static async flushCaches(organizationId: string) {
|
|
136
147
|
await memberUpdateQueue.flushGroupAndWait(organizationId);
|
|
137
148
|
await userUpdateQueue.flushGroupAndWait(organizationId);
|
|
138
149
|
await organizationUpdateQueue.flushGroupAndWait(organizationId);
|
|
139
150
|
await registrationUpdateQueue.flushGroupAndWait(organizationId);
|
|
140
151
|
await bundleDiscountsUpdateQueue.flushAndWait();
|
|
141
|
-
}
|
|
152
|
+
}
|
|
142
153
|
|
|
143
|
-
async flushAll() {
|
|
154
|
+
static async flushAll() {
|
|
144
155
|
await memberUpdateQueue.flushAndWait();
|
|
145
156
|
await userUpdateQueue.flushAndWait();
|
|
146
157
|
await organizationUpdateQueue.flushAndWait();
|
|
147
158
|
await registrationUpdateQueue.flushAndWait();
|
|
148
159
|
await bundleDiscountsUpdateQueue.flushAndWait();
|
|
149
|
-
}
|
|
160
|
+
}
|
|
150
161
|
|
|
151
162
|
/**
|
|
152
163
|
* Update how many every object in the system owes or needs to be reimbursed
|
|
153
164
|
* and also updates the pricePaid/pricePending cached values in Balance items and members
|
|
154
165
|
*/
|
|
155
|
-
|
|
166
|
+
static scheduleUpdates(items: BalanceItem[]) {
|
|
156
167
|
console.log('Schedule outstanding balance for', items.length, 'items');
|
|
157
168
|
|
|
158
169
|
for (const item of items) {
|
|
@@ -172,21 +183,21 @@ export const BalanceItemService = {
|
|
|
172
183
|
registrationUpdateQueue.addItem(item.organizationId, item.registrationId);
|
|
173
184
|
}
|
|
174
185
|
}
|
|
175
|
-
}
|
|
186
|
+
}
|
|
176
187
|
|
|
177
|
-
scheduleUserUpdate(organizationId: string, userId: string) {
|
|
188
|
+
static scheduleUserUpdate(organizationId: string, userId: string) {
|
|
178
189
|
userUpdateQueue.addItem(organizationId, userId);
|
|
179
|
-
}
|
|
190
|
+
}
|
|
180
191
|
|
|
181
|
-
|
|
192
|
+
static cheduleMemberUpdate(organizationId: string, memberId: string) {
|
|
182
193
|
memberUpdateQueue.addItem(organizationId, memberId);
|
|
183
|
-
}
|
|
194
|
+
}
|
|
184
195
|
|
|
185
|
-
scheduleOrganizationUpdate(organizationId: string, payingOrganizationId: string) {
|
|
196
|
+
static scheduleOrganizationUpdate(organizationId: string, payingOrganizationId: string) {
|
|
186
197
|
organizationUpdateQueue.addItem(organizationId, payingOrganizationId);
|
|
187
|
-
}
|
|
198
|
+
}
|
|
188
199
|
|
|
189
|
-
async markDue(balanceItem: BalanceItem) {
|
|
200
|
+
static async markDue(balanceItem: BalanceItem) {
|
|
190
201
|
if (balanceItem.status === BalanceItemStatus.Hidden) {
|
|
191
202
|
balanceItem.status = BalanceItemStatus.Due;
|
|
192
203
|
await balanceItem.save();
|
|
@@ -200,9 +211,21 @@ export const BalanceItemService = {
|
|
|
200
211
|
await balanceItem.save();
|
|
201
212
|
}
|
|
202
213
|
}
|
|
203
|
-
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
static async markPaid(balanceItem: BalanceItem, payment: Payment | null, organization: Organization) {
|
|
217
|
+
if (payment && payment.type === PaymentType.Chargeback) {
|
|
218
|
+
const realPayment = payment.reversingPaymentId ? (await Payment.getByID(payment.reversingPaymentId) ?? null) : null;
|
|
219
|
+
await this.handleChargeback(balanceItem, payment, realPayment, organization);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (payment && payment.price !== 0 && payment.refundedAmount === payment.price) {
|
|
224
|
+
// Charged back, already handled
|
|
225
|
+
// First cancel the chargeback if the payment should resucceed again
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
204
228
|
|
|
205
|
-
async markPaid(balanceItem: BalanceItem, payment: Payment | null, organization: Organization) {
|
|
206
229
|
await this.markDue(balanceItem);
|
|
207
230
|
let shouldMarkUpdated = true;
|
|
208
231
|
|
|
@@ -260,9 +283,9 @@ export const BalanceItemService = {
|
|
|
260
283
|
|
|
261
284
|
balanceItem.paidAt = new Date();
|
|
262
285
|
await balanceItem.save();
|
|
263
|
-
}
|
|
286
|
+
}
|
|
264
287
|
|
|
265
|
-
async markUpdated(balanceItem: BalanceItem, payment: Payment | null, organization: Organization) {
|
|
288
|
+
static async markUpdated(balanceItem: BalanceItem, payment: Payment | null, organization: Organization) {
|
|
266
289
|
// For orders: mark order as changed (so they are refetched in front ends)
|
|
267
290
|
if (balanceItem.orderId) {
|
|
268
291
|
await AuditLogService.setContext({ source: AuditLogSource.Payment }, async () => {
|
|
@@ -274,9 +297,9 @@ export const BalanceItemService = {
|
|
|
274
297
|
}
|
|
275
298
|
});
|
|
276
299
|
}
|
|
277
|
-
}
|
|
300
|
+
}
|
|
278
301
|
|
|
279
|
-
async undoPaid(balanceItem: BalanceItem, payment: Payment | null, organization: Organization) {
|
|
302
|
+
static async undoPaid(balanceItem: BalanceItem, payment: Payment | null, organization: Organization) {
|
|
280
303
|
// If order
|
|
281
304
|
if (balanceItem.orderId) {
|
|
282
305
|
const order = await Order.getByID(balanceItem.orderId);
|
|
@@ -285,9 +308,24 @@ export const BalanceItemService = {
|
|
|
285
308
|
await order.undoPaid(payment, organization);
|
|
286
309
|
}
|
|
287
310
|
}
|
|
288
|
-
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
*
|
|
315
|
+
*/
|
|
316
|
+
static async handleChargeback(balanceItem: BalanceItem, chargeback: Payment | null, payment: Payment | null, organization: Organization) {
|
|
317
|
+
if (balanceItem.failedAt) {
|
|
318
|
+
// Already ran side effects
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
289
321
|
|
|
290
|
-
|
|
322
|
+
// todo
|
|
323
|
+
|
|
324
|
+
balanceItem.failedAt = new Date();
|
|
325
|
+
await balanceItem.save();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
static async markFailed(balanceItem: BalanceItem, payment: Payment, organization: Organization) {
|
|
291
329
|
// If order
|
|
292
330
|
if (balanceItem.orderId) {
|
|
293
331
|
const order = await Order.getByID(balanceItem.orderId);
|
|
@@ -300,9 +338,10 @@ export const BalanceItemService = {
|
|
|
300
338
|
}
|
|
301
339
|
}
|
|
302
340
|
}
|
|
303
|
-
|
|
341
|
+
await this.handleChargeback(balanceItem, null, payment, organization);
|
|
342
|
+
}
|
|
304
343
|
|
|
305
|
-
async undoFailed(balanceItem: BalanceItem, payment: Payment, organization: Organization) {
|
|
344
|
+
static async undoFailed(balanceItem: BalanceItem, payment: Payment, organization: Organization) {
|
|
306
345
|
// If order
|
|
307
346
|
if (balanceItem.orderId) {
|
|
308
347
|
const order = await Order.getByID(balanceItem.orderId);
|
|
@@ -310,5 +349,63 @@ export const BalanceItemService = {
|
|
|
310
349
|
await order.undoPaymentFailed(payment, organization);
|
|
311
350
|
}
|
|
312
351
|
}
|
|
313
|
-
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Apply discounts to the balance a user is going to checkout
|
|
356
|
+
*/
|
|
357
|
+
static async applyDiscountsToCheckout({ minimumAmount, totalPrice, balanceItems, sellingOrganizationId, payingOrganizationId, payingUserId }: {
|
|
358
|
+
balanceItems: Map<BalanceItem, number>;
|
|
359
|
+
totalPrice: number;
|
|
360
|
+
minimumAmount?: number;
|
|
361
|
+
sellingOrganizationId: string;
|
|
362
|
+
payingOrganizationId?: string | null | undefined;
|
|
363
|
+
payingUserId?: string | null | undefined;
|
|
364
|
+
}) {
|
|
365
|
+
if (totalPrice <= (minimumAmount ?? 0)) {
|
|
366
|
+
return {
|
|
367
|
+
totalPrice,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
let items: BalanceItem[];
|
|
372
|
+
if (payingOrganizationId) {
|
|
373
|
+
items = await BalanceItem.select()
|
|
374
|
+
.where('organizationId', sellingOrganizationId)
|
|
375
|
+
.where('payingOrganizationId', payingOrganizationId)
|
|
376
|
+
.whereNot('status', BalanceItemStatus.Hidden)
|
|
377
|
+
.where('priceOpen', '<', 0)
|
|
378
|
+
.fetch();
|
|
379
|
+
} else if (payingUserId) {
|
|
380
|
+
const memberUsers = await MemberUser.select().where('usersId', payingUserId).fetch();
|
|
381
|
+
const memberIds = Formatter.uniqueArray(memberUsers.map(mu => mu.membersId));
|
|
382
|
+
|
|
383
|
+
items = await BalanceItem.select()
|
|
384
|
+
.where('organizationId', sellingOrganizationId)
|
|
385
|
+
.where(
|
|
386
|
+
SQL.where('userId', payingUserId)
|
|
387
|
+
.or('memberId', memberIds),
|
|
388
|
+
)
|
|
389
|
+
.whereNot('status', BalanceItemStatus.Hidden)
|
|
390
|
+
.where('priceOpen', '<', 0)
|
|
391
|
+
.fetch();
|
|
392
|
+
} else {
|
|
393
|
+
return {
|
|
394
|
+
totalPrice,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
for (const item of items) {
|
|
399
|
+
const remove = Math.min(totalPrice - (minimumAmount ?? 0), -item.priceOpen);
|
|
400
|
+
if (remove === 0) {
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
balanceItems.set(item, -remove);
|
|
404
|
+
totalPrice -= remove;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
totalPrice,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
314
411
|
};
|
|
@@ -56,8 +56,7 @@ class StaticCpuService {
|
|
|
56
56
|
}
|
|
57
57
|
if (size === this.maxSamples) {
|
|
58
58
|
return this.samples.reduce((a, b) => a + b, 0) / size;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
59
|
+
} else {
|
|
61
60
|
// To read before current index
|
|
62
61
|
const toReadBeforeIndex = Math.min(size, this.currentIndex);
|
|
63
62
|
const toReadFromEnd = size - toReadBeforeIndex;
|
|
@@ -89,13 +88,11 @@ class StaticCpuService {
|
|
|
89
88
|
if (five > 80) {
|
|
90
89
|
// Danger zone, in this case we don't want to log all slow queries any longer because the information won't be trustworthy.
|
|
91
90
|
SQLLogger.slowQueryThresholdMs = null;
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
91
|
+
} else {
|
|
94
92
|
if (five < 20) {
|
|
95
93
|
// No load, safe to log all slow queries
|
|
96
94
|
SQLLogger.slowQueryThresholdMs = 300;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
95
|
+
} else {
|
|
99
96
|
SQLLogger.slowQueryThresholdMs = 500;
|
|
100
97
|
}
|
|
101
98
|
}
|
|
@@ -10,8 +10,7 @@ describe('DatabaseCollationService', () => {
|
|
|
10
10
|
expect(error).toContain('MySQL collation mismatch');
|
|
11
11
|
expect(error).toContain('expected utf8mb4_0900_ai_ci');
|
|
12
12
|
expect(error).toContain('collation_connection=utf8mb4_general_ci');
|
|
13
|
-
}
|
|
14
|
-
finally {
|
|
13
|
+
} finally {
|
|
15
14
|
await Database.statement('SET collation_connection = DEFAULT');
|
|
16
15
|
}
|
|
17
16
|
});
|
|
@@ -33,8 +33,7 @@ export class DocumentService {
|
|
|
33
33
|
// If a group is changed - update the documents for it
|
|
34
34
|
await Document.updateForGroup(event.model.id, event.model.organizationId);
|
|
35
35
|
}
|
|
36
|
-
}
|
|
37
|
-
catch (e) {
|
|
36
|
+
} catch (e) {
|
|
38
37
|
console.error('Failed to update documents after group change', e);
|
|
39
38
|
}
|
|
40
39
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
2
2
|
import { EventNotification, Member, MemberResponsibilityRecord, Organization, Platform, sendEmailTemplate, User } from '@stamhoofd/models';
|
|
3
|
-
import type { EmailTemplateType} from '@stamhoofd/structures';
|
|
3
|
+
import type { EmailTemplateType } from '@stamhoofd/structures';
|
|
4
4
|
import { PermissionLevel, Recipient, RecordCategory, Replacement } from '@stamhoofd/structures';
|
|
5
5
|
import { Formatter } from '@stamhoofd/utility';
|
|
6
6
|
import { AdminPermissionChecker } from '../helpers/AdminPermissionChecker.js';
|
|
@@ -74,8 +74,7 @@ export class FileSignService {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
return true;
|
|
77
|
-
}
|
|
78
|
-
catch (e) {
|
|
77
|
+
} catch (e) {
|
|
79
78
|
if (e instanceof jose.errors.JWSSignatureVerificationFailed) {
|
|
80
79
|
return false;
|
|
81
80
|
}
|
|
@@ -120,8 +119,7 @@ export class FileSignService {
|
|
|
120
119
|
...file,
|
|
121
120
|
signedUrl: url,
|
|
122
121
|
});
|
|
123
|
-
}
|
|
124
|
-
catch (e) {
|
|
122
|
+
} catch (e) {
|
|
125
123
|
console.error('Failed to generate signedUrl for file:', e);
|
|
126
124
|
return null;
|
|
127
125
|
}
|