@stamhoofd/backend 2.120.6 → 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 +70 -53
- 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 +46 -0
- package/src/audit-logs/init.ts +9 -1
- 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 +7 -0
- package/src/crons/invoices.ts +160 -0
- package/src/crons/members-fees.ts +50 -0
- package/src/crons/mollie-chargebacks.ts +86 -0
- 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 +54 -74
- 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 +87 -46
- 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 +51 -0
- 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 +32 -13
- 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 +38 -33
- package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsCountEndpoint.ts +45 -0
- package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.test.ts +494 -0
- package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.ts +213 -0
- package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.test.ts +404 -0
- package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.ts +167 -0
- 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 +19 -6
- package/src/endpoints/organization/dashboard/billing/ApplyRegisterCodeEndpoint.test.ts +73 -0
- package/src/endpoints/organization/dashboard/billing/ApplyRegisterCodeEndpoint.ts +89 -0
- package/src/endpoints/{global → organization/dashboard}/billing/DeactivatePackageEndpoint.ts +4 -9
- package/src/endpoints/organization/dashboard/billing/DeleteOrganizationMandateEndpoint.ts +62 -0
- package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceCollectionEndpoint.ts +56 -0
- package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceEndpoint.ts +41 -18
- package/src/endpoints/organization/dashboard/billing/GetOrganizationMandatesEndpoint.ts +64 -0
- 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 +12 -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 +311 -0
- package/src/endpoints/organization/dashboard/billing/PatchOrganizationMandatesEndpoint.ts +94 -0
- 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 +15 -4
- package/src/endpoints/organization/dashboard/invoices/PatchInvoicesEndpoint.ts +11 -2
- package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +8 -8
- package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +10 -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 +67 -20
- 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 +24 -17
- package/src/endpoints/organization/dashboard/receivable-balances/ChargeReceivableBalancesEndpoint.ts +134 -0
- 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 +32 -22
- 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 +29 -8
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +21 -28
- 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 +15 -13
- 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 +28 -50
- 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 +60 -65
- package/src/helpers/AuthenticatedStructures.ts +153 -51
- 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 +21 -0
- 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 +741 -0
- package/src/helpers/RecordAnswerHelper.ts +116 -0
- 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 +15 -38
- 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 +11 -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/migrations/1750090030-records-configuration.ts +92 -0
- 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 +95 -27
- 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/1779121239-default-invoice-email-template.sql +3 -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 +148 -55
- 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 +330 -77
- 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 +530 -0
- package/src/services/PaymentMandateService.ts +214 -0
- package/src/services/PaymentReallocationService.test.ts +1 -1
- package/src/services/PaymentReallocationService.ts +7 -9
- package/src/services/PaymentService.ts +820 -328
- package/src/services/PlatformMembershipService.ts +5 -9
- package/src/services/ReferralService.ts +223 -0
- package/src/services/RegistrationService.ts +125 -54
- package/src/services/SSOService.test.ts +119 -0
- package/src/services/SSOService.ts +56 -49
- package/src/services/STPackageService.ts +97 -68
- package/src/services/UniqueMemberNumberService.ts +69 -0
- package/src/services/UniqueUserService.ts +3 -6
- package/src/services/VATService.ts +85 -0
- package/src/services/data/invoice.hbs.html +686 -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 +16 -1
- 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/payments.ts +5 -0
- package/src/sql-filters/platform-memberships.ts +3 -3
- package/src/sql-filters/receivable-balances.ts +1 -1
- package/src/sql-filters/registration-invitations.ts +90 -0
- 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 +36 -0
- 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 +7 -0
- package/.nvmrc +0 -1
- package/src/endpoints/global/billing/ActivatePackagesEndpoint.ts +0 -216
- 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/1750090030-records-configuration.ts +0 -26
- 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}/data/default-email-templates.sql +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { AutoEncoderPatchType, Decoder, PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
|
|
2
|
+
import { PatchableArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
|
|
3
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
4
|
+
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
5
|
+
import type { RegistrationInvitation as RegistrationInvitationStruct } from '@stamhoofd/structures';
|
|
6
|
+
import { GroupType, PermissionLevel, RegistrationInvitationRequest } from '@stamhoofd/structures';
|
|
7
|
+
|
|
8
|
+
import { SimpleError } from '@simonbackx/simple-errors';
|
|
9
|
+
import { Group, Member, RegistrationInvitation } from '@stamhoofd/models';
|
|
10
|
+
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures.js';
|
|
11
|
+
import { Context } from '../../../helpers/Context.js';
|
|
12
|
+
|
|
13
|
+
type Params = Record<string, never>;
|
|
14
|
+
type Query = undefined;
|
|
15
|
+
type Body = PatchableArrayAutoEncoder<RegistrationInvitationRequest>;
|
|
16
|
+
type ResponseBody = RegistrationInvitationStruct[];
|
|
17
|
+
|
|
18
|
+
export class PatchRegistrationInvitationsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
19
|
+
bodyDecoder = new PatchableArrayDecoder(
|
|
20
|
+
RegistrationInvitationRequest as Decoder<RegistrationInvitationRequest>,
|
|
21
|
+
RegistrationInvitationRequest.patchType() as Decoder<AutoEncoderPatchType<RegistrationInvitationRequest>>,
|
|
22
|
+
StringDecoder);
|
|
23
|
+
|
|
24
|
+
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
25
|
+
if (request.method !== 'PATCH') {
|
|
26
|
+
return [false];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const params = Endpoint.parseParameters(request.url, '/registration-invitations', {});
|
|
30
|
+
|
|
31
|
+
if (params) {
|
|
32
|
+
return [true, params as Params];
|
|
33
|
+
}
|
|
34
|
+
return [false];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
38
|
+
const organization = await Context.setOrganizationScope();
|
|
39
|
+
await Context.authenticate();
|
|
40
|
+
|
|
41
|
+
// Fast throw first (more in depth checking for patches later)
|
|
42
|
+
if (!await Context.auth.hasSomeAccess(organization.id)) {
|
|
43
|
+
throw Context.auth.error();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const invitations: RegistrationInvitation[] = [];
|
|
47
|
+
let duplicateCount = 0;
|
|
48
|
+
|
|
49
|
+
const puts = request.body.getPuts();
|
|
50
|
+
for (const { put } of puts) {
|
|
51
|
+
await this.checkCanCreateRegistrationInvitation(put, organization.id);
|
|
52
|
+
|
|
53
|
+
const invitation = new RegistrationInvitation();
|
|
54
|
+
invitation.id = put.id;
|
|
55
|
+
invitation.organizationId = organization.id;
|
|
56
|
+
invitation.groupId = put.groupId;
|
|
57
|
+
invitation.memberId = put.memberId;
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
await invitation.save();
|
|
61
|
+
invitations.push(invitation);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
// update if duplicate
|
|
64
|
+
if (e.code === 'ER_DUP_ENTRY') {
|
|
65
|
+
const duplicate = await RegistrationInvitation.select()
|
|
66
|
+
.where('groupId', invitation.groupId)
|
|
67
|
+
.andWhere('memberId', invitation.memberId)
|
|
68
|
+
.first(false);
|
|
69
|
+
|
|
70
|
+
if (duplicate) {
|
|
71
|
+
invitations.push(duplicate);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
duplicateCount += 1;
|
|
75
|
+
continue;
|
|
76
|
+
} else {
|
|
77
|
+
throw e;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (request.body.getPatches().length > 0) {
|
|
83
|
+
throw new SimpleError({
|
|
84
|
+
code: 'patch_not_supported',
|
|
85
|
+
statusCode: 405,
|
|
86
|
+
message: 'Patching invitations is not supported. Only puts and deletes are supported.',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for (const id of request.body.getDeletes()) {
|
|
91
|
+
const invitation = await RegistrationInvitation.getByID(id);
|
|
92
|
+
if (!invitation) {
|
|
93
|
+
throw new SimpleError({
|
|
94
|
+
code: 'not_found',
|
|
95
|
+
statusCode: 404,
|
|
96
|
+
message: 'Registration invitation not found',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Anyone with write access to the group can delete invitations for the group
|
|
101
|
+
const group = await Group.getByID(invitation.groupId);
|
|
102
|
+
|
|
103
|
+
if (!group || !await Context.auth.canAccessGroup(group, PermissionLevel.Write)) {
|
|
104
|
+
throw Context.auth.error($t(`%1UN`));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
await invitation.delete();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// show an error if all puts were duplicates
|
|
111
|
+
if (puts.length > 0 && puts.length === duplicateCount) {
|
|
112
|
+
throw new SimpleError({
|
|
113
|
+
code: 'duplicate_entry',
|
|
114
|
+
statusCode: 409,
|
|
115
|
+
message: 'Duplicate entry',
|
|
116
|
+
human: puts.length === 1 ? $t(`%1RS`) : $t(`%1RP`),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return new Response(
|
|
121
|
+
await AuthenticatedStructures.registrationInvitations(invitations),
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Will throw if not allowed to invite.
|
|
127
|
+
* @param invitation
|
|
128
|
+
* @param organizationId id of organization to invite for, should match the organizationId in the invitation
|
|
129
|
+
*/
|
|
130
|
+
private async checkCanCreateRegistrationInvitation(invitation: RegistrationInvitationRequest, organizationId: string) {
|
|
131
|
+
const group = await Group.getByID(invitation.groupId);
|
|
132
|
+
|
|
133
|
+
if (!group || group.organizationId !== organizationId || !await Context.auth.canAccessGroup(group, PermissionLevel.Write)) {
|
|
134
|
+
throw Context.auth.error($t(`%1ST`));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// cannot invite for waiting list
|
|
138
|
+
if (group.type === GroupType.WaitingList) {
|
|
139
|
+
throw new SimpleError({
|
|
140
|
+
code: 'bad_group',
|
|
141
|
+
statusCode: 400,
|
|
142
|
+
message: 'Not allowed to invite for waiting list',
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const member = await Member.getByIdWithUsersAndRegistrations(invitation.memberId);
|
|
147
|
+
|
|
148
|
+
if (!member
|
|
149
|
+
// in userMode 'organization' we can only invite members from the same organization
|
|
150
|
+
|| (STAMHOOFD.userMode === 'organization' && member.organizationId !== organizationId)
|
|
151
|
+
// read access is suficient
|
|
152
|
+
|| !await Context.auth.canAccessMember(member, PermissionLevel.Read)
|
|
153
|
+
) {
|
|
154
|
+
throw Context.auth.error($t(`%1Qv`));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// cannot invite if already registered
|
|
158
|
+
if (member.registrations.some(r => r.groupId === group.id && r.registeredAt !== null && r.deactivatedAt === null)) {
|
|
159
|
+
throw new SimpleError({
|
|
160
|
+
code: 'bad_group',
|
|
161
|
+
statusCode: 400,
|
|
162
|
+
message: 'The member is already registered for this group',
|
|
163
|
+
human: $t('%1S2'),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Decoder } from '@simonbackx/simple-encoding';
|
|
2
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
3
|
+
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
4
|
+
import { CountFilteredRequest, CountResponse } from '@stamhoofd/structures';
|
|
5
|
+
|
|
6
|
+
import { Context } from '../../../helpers/Context.js';
|
|
7
|
+
import { GetRegistrationPeriodsEndpoint } from './GetRegistrationPeriodsEndpoint.js';
|
|
8
|
+
|
|
9
|
+
type Params = Record<string, never>;
|
|
10
|
+
type Query = CountFilteredRequest;
|
|
11
|
+
type Body = undefined;
|
|
12
|
+
type ResponseBody = CountResponse;
|
|
13
|
+
|
|
14
|
+
export class GetRegistrationPeriodsCountEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
15
|
+
queryDecoder = CountFilteredRequest as Decoder<CountFilteredRequest>;
|
|
16
|
+
|
|
17
|
+
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
18
|
+
if (request.method !== 'GET') {
|
|
19
|
+
return [false];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const params = Endpoint.parseParameters(request.url, '/registration-periods/count', {});
|
|
23
|
+
|
|
24
|
+
if (params) {
|
|
25
|
+
return [true, params as Params];
|
|
26
|
+
}
|
|
27
|
+
return [false];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
31
|
+
await Context.setUserOrganizationScope();
|
|
32
|
+
const query = await GetRegistrationPeriodsEndpoint.buildQuery(request.query);
|
|
33
|
+
|
|
34
|
+
const count = await query
|
|
35
|
+
.count();
|
|
36
|
+
|
|
37
|
+
return new Response(
|
|
38
|
+
CountResponse.create({
|
|
39
|
+
count,
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
1
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import type { CountFilteredRequest, RegistrationPeriod as RegistrationPeriodStruct, StamhoofdFilter } from '@stamhoofd/structures';
|
|
4
4
|
import { assertSort, getSortFilter, LimitedFilteredRequest, PaginatedResponse } from '@stamhoofd/structures';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { ConvertArrayToPatchableArray, Decoder, PatchableArrayAutoEncoder} from '@simonbackx/simple-encoding';
|
|
1
|
+
import type { ConvertArrayToPatchableArray, Decoder, PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
|
|
2
2
|
import { PatchableArrayDecoder, StringDecoder, patchObject } from '@simonbackx/simple-encoding';
|
|
3
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
3
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
4
4
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
5
5
|
import { RegistrationPeriod as RegistrationPeriodStruct } from '@stamhoofd/structures';
|
|
6
6
|
|
|
7
7
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
8
|
-
import { Organization, Platform, RegistrationPeriod } from '@stamhoofd/models';
|
|
8
|
+
import { Group, Organization, Platform, RegistrationPeriod } from '@stamhoofd/models';
|
|
9
9
|
import { Context } from '../../../helpers/Context.js';
|
|
10
10
|
import { PeriodHelper } from '../../../helpers/PeriodHelper.js';
|
|
11
11
|
|
|
@@ -69,8 +69,7 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
|
|
|
69
69
|
if (!await Context.auth.hasFullAccess(organization.id)) {
|
|
70
70
|
throw Context.auth.error();
|
|
71
71
|
}
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
72
|
+
} else {
|
|
74
73
|
if (!Context.auth.hasPlatformFullAccess()) {
|
|
75
74
|
throw Context.auth.error();
|
|
76
75
|
}
|
|
@@ -172,6 +171,8 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
|
|
|
172
171
|
|
|
173
172
|
// Schedule patch of all groups in this period
|
|
174
173
|
PeriodHelper.updateGroupsInPeriod(model).catch(console.error);
|
|
174
|
+
|
|
175
|
+
periods.push(model)
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
for (const id of request.body.getDeletes()) {
|
|
@@ -185,6 +186,13 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
|
|
|
185
186
|
});
|
|
186
187
|
}
|
|
187
188
|
|
|
189
|
+
// Delete all groups in this period
|
|
190
|
+
const q = Group.delete().where('periodId', model.id);
|
|
191
|
+
if (organization) {
|
|
192
|
+
q.where('organizationId', organization.id);
|
|
193
|
+
}
|
|
194
|
+
await q;
|
|
195
|
+
|
|
188
196
|
// Now delete the model
|
|
189
197
|
await model.delete();
|
|
190
198
|
await RegistrationPeriod.updatePreviousNextPeriods(model.organizationId);
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
1
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { LoginProviderType, OpenIDClientConfiguration } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
5
|
import { Context } from '../../../helpers/Context.js';
|
|
6
|
-
import {
|
|
7
|
-
import type { Decoder} from '@simonbackx/simple-encoding';
|
|
6
|
+
import type { Decoder } from '@simonbackx/simple-encoding';
|
|
8
7
|
import { AutoEncoder, EnumDecoder, field } from '@simonbackx/simple-encoding';
|
|
9
8
|
import { SSOService } from '../../../services/SSOService.js';
|
|
10
9
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AutoEncoderPatchType, Decoder } from '@simonbackx/simple-encoding';
|
|
2
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
2
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
4
4
|
import { OpenIDClientConfiguration } from '@stamhoofd/structures';
|
|
5
5
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Decoder} from '@simonbackx/simple-encoding';
|
|
1
|
+
import type { Decoder } from '@simonbackx/simple-encoding';
|
|
2
2
|
import { AutoEncoder, field, StringDecoder } from '@simonbackx/simple-encoding';
|
|
3
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
3
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
4
4
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
5
5
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
6
6
|
import { Organization } from '@stamhoofd/models';
|
|
@@ -383,8 +383,7 @@ describe('Endpoint.GetWebshopsEndpoint', () => {
|
|
|
383
383
|
expect(response.status).toBe(200);
|
|
384
384
|
expect(response.body.results).toHaveLength(1);
|
|
385
385
|
expect(response.body.results[0].id).toBe(closedWebshop.id);
|
|
386
|
-
}
|
|
387
|
-
finally {
|
|
386
|
+
} finally {
|
|
388
387
|
await Database.statement('SET collation_connection = DEFAULT');
|
|
389
388
|
}
|
|
390
389
|
});
|
|
@@ -59,8 +59,7 @@ export class GetWebshopsEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
59
59
|
},
|
|
60
60
|
};
|
|
61
61
|
query.where(await compileToSQLFilter(scopeFilter, filterCompilers));
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
62
|
+
} else {
|
|
64
63
|
// Platform context: check platform access
|
|
65
64
|
const tags = Context.auth.getPlatformAccessibleOrganizationTags(PermissionLevel.Read);
|
|
66
65
|
|
|
@@ -124,8 +123,7 @@ export class GetWebshopsEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
124
123
|
|
|
125
124
|
try {
|
|
126
125
|
data = await query.fetch();
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
126
|
+
} catch (error) {
|
|
129
127
|
if (error.message.includes('ER_QUERY_TIMEOUT')) {
|
|
130
128
|
throw new SimpleError({
|
|
131
129
|
code: 'timeout',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
1
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
4
|
import { BalanceItem } from '@stamhoofd/models';
|
|
@@ -20,7 +20,7 @@ export class GetBalanceItemEndpoint extends Endpoint<Params, Query, Body, Respon
|
|
|
20
20
|
|
|
21
21
|
const params = Endpoint.parseParameters(request.url, '/balance-items/@id', { id: String });
|
|
22
22
|
|
|
23
|
-
if (params) {
|
|
23
|
+
if (params && params.id !== 'count') {
|
|
24
24
|
return [true, params as Params];
|
|
25
25
|
}
|
|
26
26
|
return [false];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Decoder } from '@simonbackx/simple-encoding';
|
|
2
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
2
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
4
4
|
import { CountFilteredRequest, CountResponse } from '@stamhoofd/structures';
|
|
5
5
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Decoder } from '@simonbackx/simple-encoding';
|
|
2
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
2
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
4
4
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
5
5
|
import { BalanceItem } from '@stamhoofd/models';
|
|
6
6
|
import { applySQLSorter, compileToSQLFilter } from '@stamhoofd/sql';
|
|
7
|
-
import type { BalanceItem as BalanceItemStruct, CountFilteredRequest, StamhoofdFilter} from '@stamhoofd/structures';
|
|
7
|
+
import type { BalanceItem as BalanceItemStruct, CountFilteredRequest, StamhoofdFilter } from '@stamhoofd/structures';
|
|
8
8
|
import { LimitedFilteredRequest, PaginatedResponse, assertSort, getSortFilter } from '@stamhoofd/structures';
|
|
9
9
|
|
|
10
10
|
import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures.js';
|
|
@@ -95,8 +95,7 @@ export class GetBalanceItemsEndpoint extends Endpoint<Params, Query, Body, Respo
|
|
|
95
95
|
|
|
96
96
|
try {
|
|
97
97
|
balanceItems = await query.fetch();
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
98
|
+
} catch (error) {
|
|
100
99
|
if (error.message.includes('ER_QUERY_TIMEOUT')) {
|
|
101
100
|
throw new SimpleError({
|
|
102
101
|
code: 'timeout',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { AutoEncoderPatchType, Decoder, PatchableArrayAutoEncoder} from '@simonbackx/simple-encoding';
|
|
1
|
+
import type { AutoEncoderPatchType, Decoder, PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
|
|
2
2
|
import { PatchableArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
|
|
3
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
3
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
4
4
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
5
5
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
6
6
|
import { BalanceItem, Member, Order, User } from '@stamhoofd/models';
|
|
@@ -165,8 +165,7 @@ export class PatchBalanceItemsEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
165
165
|
});
|
|
166
166
|
}
|
|
167
167
|
model.memberId = null;
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
168
|
+
} else {
|
|
170
169
|
model.memberId = (await this.validateMemberId(patch.memberId)).id;
|
|
171
170
|
}
|
|
172
171
|
}
|
|
@@ -188,10 +187,25 @@ export class PatchBalanceItemsEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
188
187
|
model.unitPrice = patch.unitPrice ?? model.unitPrice;
|
|
189
188
|
model.amount = patch.amount ?? model.amount;
|
|
190
189
|
model.dueAt = patch.dueAt === undefined ? model.dueAt : patch.dueAt;
|
|
190
|
+
|
|
191
|
+
const VATPercentageBefore = model.VATPercentage;
|
|
192
|
+
const includedBefore = model.VATIncluded;
|
|
193
|
+
const excemptBefore = model.VATExcempt;
|
|
194
|
+
|
|
191
195
|
model.VATIncluded = patch.VATIncluded === undefined ? model.VATIncluded : patch.VATIncluded;
|
|
192
196
|
model.VATPercentage = patch.VATPercentage === undefined ? model.VATPercentage : patch.VATPercentage;
|
|
193
197
|
model.VATExcempt = patch.VATExcempt === undefined ? model.VATExcempt : patch.VATExcempt;
|
|
194
198
|
|
|
199
|
+
if (model.priceInvoiced !== 0) {
|
|
200
|
+
if (model.VATPercentage !== VATPercentageBefore || model.VATIncluded !== includedBefore || model.VATExcempt !== excemptBefore) {
|
|
201
|
+
throw new SimpleError({
|
|
202
|
+
code: 'invoiced',
|
|
203
|
+
message: 'You cannot change VAT settings of balance items when the balance item has been invoiced',
|
|
204
|
+
human: $t('%1Rt'),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
195
209
|
if ((patch.dueAt !== undefined || patch.unitPrice !== undefined) && model.dueAt && model.price < 0) {
|
|
196
210
|
throw new SimpleError({
|
|
197
211
|
code: 'invalid_price',
|
|
@@ -214,8 +228,7 @@ export class PatchBalanceItemsEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
214
228
|
if (model.pricePaid === 0) {
|
|
215
229
|
model.status = BalanceItemStatus.Hidden;
|
|
216
230
|
}
|
|
217
|
-
}
|
|
218
|
-
else if (patch.status) {
|
|
231
|
+
} else if (patch.status) {
|
|
219
232
|
model.status = patch.status;
|
|
220
233
|
}
|
|
221
234
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Request } from '@simonbackx/simple-endpoints';
|
|
2
|
+
import { BalanceItem, OrganizationFactory, RegisterCodeFactory, Token, UserFactory } from '@stamhoofd/models';
|
|
3
|
+
import { PermissionLevel, Permissions } from '@stamhoofd/structures';
|
|
4
|
+
|
|
5
|
+
import { testServer } from '../../../../../tests/helpers/TestServer.js';
|
|
6
|
+
import { ApplyRegisterCodeEndpoint } from './ApplyRegisterCodeEndpoint.js';
|
|
7
|
+
import { initMembershipOrganization } from '../../../../../tests/init/initMembershipOrganization.js';
|
|
8
|
+
|
|
9
|
+
describe('Endpoint.ApplyRegisterCodeEndpoint', () => {
|
|
10
|
+
// Test endpoint
|
|
11
|
+
const endpoint = new ApplyRegisterCodeEndpoint();
|
|
12
|
+
|
|
13
|
+
beforeAll(async () => {
|
|
14
|
+
await initMembershipOrganization();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('Cannot apply a register code if not platform admin', async () => {
|
|
18
|
+
const otherOrganization = await new OrganizationFactory({}).create();
|
|
19
|
+
const code = await new RegisterCodeFactory({ organization: otherOrganization }).create();
|
|
20
|
+
|
|
21
|
+
const organization = await new OrganizationFactory({}).create();
|
|
22
|
+
const user = await new UserFactory({ organization, permissions: Permissions.create({ level: PermissionLevel.Full }) }).create();
|
|
23
|
+
const token = await Token.createToken(user);
|
|
24
|
+
|
|
25
|
+
const r = Request.buildJson(
|
|
26
|
+
'POST',
|
|
27
|
+
'/billing/register-code',
|
|
28
|
+
organization.getApiHost(),
|
|
29
|
+
{
|
|
30
|
+
registerCode: code.code,
|
|
31
|
+
},
|
|
32
|
+
);
|
|
33
|
+
r.headers.authorization = 'Bearer ' + token.accessToken;
|
|
34
|
+
|
|
35
|
+
await expect(testServer.test(endpoint, r)).rejects.toThrow('You do not have permissions for this action');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('Can apply a register code and apply the discount', async () => {
|
|
39
|
+
const otherOrganization = await new OrganizationFactory({}).create();
|
|
40
|
+
const code = await new RegisterCodeFactory({ organization: otherOrganization }).create();
|
|
41
|
+
|
|
42
|
+
const organization = await new OrganizationFactory({}).create();
|
|
43
|
+
const user = await new UserFactory({
|
|
44
|
+
organization,
|
|
45
|
+
globalPermissions: Permissions.create({ level: PermissionLevel.Full }),
|
|
46
|
+
email: 'admin@stamhoofd.be',
|
|
47
|
+
}).create();
|
|
48
|
+
const token = await Token.createToken(user);
|
|
49
|
+
|
|
50
|
+
const r = Request.buildJson(
|
|
51
|
+
'POST',
|
|
52
|
+
'/billing/register-code',
|
|
53
|
+
organization.getApiHost(),
|
|
54
|
+
{
|
|
55
|
+
registerCode: code.code,
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
r.headers.authorization = 'Bearer ' + token.accessToken;
|
|
59
|
+
|
|
60
|
+
const response = await testServer.test(endpoint, r);
|
|
61
|
+
expect(response.body).toBeUndefined();
|
|
62
|
+
|
|
63
|
+
// Check if this organization has an open register code
|
|
64
|
+
const credits = await BalanceItem.select().where('payingOrganizationId', organization.id).fetch();
|
|
65
|
+
expect(credits.length).toBe(1);
|
|
66
|
+
expect(credits[0].unitPrice).toBe(-code.value);
|
|
67
|
+
|
|
68
|
+
// Other not yet applied because no package bought yet
|
|
69
|
+
// Check if other organization has an open register code
|
|
70
|
+
const otherCredits = await BalanceItem.select().where('payingOrganizationId', otherOrganization.id).fetch();
|
|
71
|
+
expect(otherCredits.length).toBe(0);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Decoder } from '@simonbackx/simple-encoding';
|
|
2
|
+
import { AutoEncoder, field, StringDecoder } from '@simonbackx/simple-encoding';
|
|
3
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
4
|
+
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
5
|
+
import { Email } from '@stamhoofd/email';
|
|
6
|
+
import { RegisterCode, UsedRegisterCode } from '@stamhoofd/models';
|
|
7
|
+
|
|
8
|
+
import { Context } from '../../../../helpers/Context.js';
|
|
9
|
+
import { ReferralService } from '../../../../services/ReferralService.js';
|
|
10
|
+
|
|
11
|
+
type Params = Record<string, never>;
|
|
12
|
+
type Query = undefined;
|
|
13
|
+
type ResponseBody = undefined;
|
|
14
|
+
|
|
15
|
+
class Body extends AutoEncoder {
|
|
16
|
+
@field({ decoder: StringDecoder })
|
|
17
|
+
registerCode: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* One endpoint to create, patch and delete groups. Usefull because on organization setup, we need to create multiple groups at once. Also, sometimes we need to link values and update multiple groups at once
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export class ApplyRegisterCodeEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
25
|
+
bodyDecoder = Body as Decoder<Body>;
|
|
26
|
+
|
|
27
|
+
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
28
|
+
if (request.method !== 'POST') {
|
|
29
|
+
return [false];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const params = Endpoint.parseParameters(request.url, '/billing/register-code', {});
|
|
33
|
+
|
|
34
|
+
if (params) {
|
|
35
|
+
return [true, params as Params];
|
|
36
|
+
}
|
|
37
|
+
return [false];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
41
|
+
const organization = await Context.setOrganizationScope();
|
|
42
|
+
await Context.authenticate();
|
|
43
|
+
|
|
44
|
+
if (!Context.auth.hasPlatformFullAccess()) {
|
|
45
|
+
throw Context.auth.error();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let code = request.body.registerCode;
|
|
49
|
+
|
|
50
|
+
if (code.startsWith('https:')) {
|
|
51
|
+
try {
|
|
52
|
+
const url = new URL(code);
|
|
53
|
+
const codeParam = url.searchParams.get('code');
|
|
54
|
+
if (codeParam) {
|
|
55
|
+
console.log('Parsed code from URL', codeParam);
|
|
56
|
+
code = codeParam;
|
|
57
|
+
}
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.error('Tried parsing code as URL but failed', code);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const { models, emails } = await ReferralService.markUsed(organization, code);
|
|
64
|
+
|
|
65
|
+
for (const model of models) {
|
|
66
|
+
await model.save();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (const email of emails) {
|
|
70
|
+
Email.send({
|
|
71
|
+
...email,
|
|
72
|
+
from: Email.getQuickFromEmail(organization.address.country),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (organization.meta.packages.isPaid) {
|
|
77
|
+
// Already bought something: apply credit to other organization immediately
|
|
78
|
+
const code = await UsedRegisterCode.getFor(organization.id);
|
|
79
|
+
if (code && !code.balanceItemId) {
|
|
80
|
+
console.log('Rewarding code ' + code.id + ' for payment');
|
|
81
|
+
|
|
82
|
+
// Deze code werd nog niet beloond
|
|
83
|
+
await ReferralService.reward(code);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return new Response(undefined);
|
|
88
|
+
}
|
|
89
|
+
}
|
package/src/endpoints/{global → organization/dashboard}/billing/DeactivatePackageEndpoint.ts
RENAMED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
|
|
1
|
+
import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { Endpoint, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
|
-
import { STPackage } from '@stamhoofd/models';
|
|
5
4
|
|
|
6
|
-
import { Context } from '
|
|
7
|
-
import { STPackageService } from '
|
|
5
|
+
import { Context } from '../../../../helpers/Context.js';
|
|
6
|
+
import { STPackageService } from '../../../../services/STPackageService.js';
|
|
8
7
|
type Params = { id: string };
|
|
9
8
|
type Query = undefined;
|
|
10
9
|
type ResponseBody = undefined;
|
|
@@ -53,11 +52,7 @@ export class DeactivatePackageEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
53
52
|
});
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
pack.removeAt = new Date();
|
|
58
|
-
pack.removeAt.setTime(pack.removeAt.getTime() - 5_000);
|
|
59
|
-
await pack.save();
|
|
60
|
-
|
|
55
|
+
await STPackageService.deactivatePackage(pack);
|
|
61
56
|
await STPackageService.updateOrganizationPackages(organization.id);
|
|
62
57
|
|
|
63
58
|
return new Response(undefined);
|