@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.
Files changed (429) hide show
  1. package/output-2.txt +1 -0
  2. package/output.txt +1 -0
  3. package/package.json +69 -52
  4. package/src/audit-logs/EventNotificationLogger.ts +40 -0
  5. package/src/audit-logs/ModelLogger.ts +19 -15
  6. package/src/audit-logs/OrganizationLogger.ts +1 -1
  7. package/src/audit-logs/RegistrationInvitationLogger.ts +24 -24
  8. package/src/audit-logs/init.ts +8 -2
  9. package/src/boot.ts +19 -18
  10. package/src/crons/amazon-ses.ts +13 -26
  11. package/src/crons/balance-emails.ts +3 -5
  12. package/src/crons/clearExcelCache.test.ts +1 -1
  13. package/src/crons/clearExcelCache.ts +1 -2
  14. package/src/crons/drip-emails.ts +42 -0
  15. package/src/crons/endFunctionsOfUsersWithoutRegistration.ts +4 -0
  16. package/src/crons/helpers/isOutside.ts +11 -0
  17. package/src/crons/helpers/useSavedIterator.ts +32 -0
  18. package/src/crons/index.ts +5 -0
  19. package/src/crons/invoices.ts +32 -38
  20. package/src/crons/members-fees.ts +50 -0
  21. package/src/crons/mollie-chargebacks.ts +14 -15
  22. package/src/crons/service-fees.ts +152 -0
  23. package/src/crons/stripe-invoices.ts +48 -0
  24. package/src/crons/transfer-fees.ts +176 -0
  25. package/src/crons/update-cached-balances.ts +4 -4
  26. package/src/crons.ts +7 -64
  27. package/src/debug.ts +4 -2
  28. package/src/email-recipient-loaders/documents.ts +1 -1
  29. package/src/email-recipient-loaders/members.ts +1 -1
  30. package/src/email-recipient-loaders/payments.ts +4 -6
  31. package/src/email-recipient-loaders/registrations.ts +1 -1
  32. package/src/email-replacements/getEmailReplacementsForPayment.ts +5 -9
  33. package/src/endpoints/admin/members/ChargeMembersEndpoint.ts +1 -1
  34. package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +1 -1
  35. package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +3 -5
  36. package/src/endpoints/admin/organizations/ChargeOrganizationsEndpoint.ts +1 -1
  37. package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +1 -1
  38. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +13 -7
  39. package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +4 -6
  40. package/src/endpoints/admin/organizations/PatchPackagesEndpoint.test.ts +10 -6
  41. package/src/endpoints/admin/organizations/PatchPackagesEndpoint.ts +39 -21
  42. package/src/endpoints/admin/registrations/ChargeRegistrationsEndpoint.ts +1 -1
  43. package/src/endpoints/auth/CreateAdminEndpoint.ts +23 -5
  44. package/src/endpoints/auth/CreateTokenEndpoint.ts +2 -2
  45. package/src/endpoints/auth/DeleteTokenEndpoint.ts +1 -1
  46. package/src/endpoints/auth/DeleteUserEndpoint.ts +3 -3
  47. package/src/endpoints/auth/ForgotPasswordEndpoint.ts +1 -1
  48. package/src/endpoints/auth/GetOtherUserEndpoint.ts +1 -1
  49. package/src/endpoints/auth/GetUserEndpoint.ts +1 -1
  50. package/src/endpoints/auth/OpenIDConnectAuthTokenEndpoint.ts +1 -1
  51. package/src/endpoints/auth/OpenIDConnectStartEndpoint.ts +1 -1
  52. package/src/endpoints/auth/PatchUserEndpoint.ts +5 -8
  53. package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +1 -1
  54. package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +1 -1
  55. package/src/endpoints/auth/SignupEndpoint.ts +2 -3
  56. package/src/endpoints/auth/VerifyEmailEndpoint.ts +20 -3
  57. package/src/endpoints/frontend/FrontendEnvironmentEndpoint.ts +2 -1
  58. package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +2 -4
  59. package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +1 -1
  60. package/src/endpoints/global/audit-logs/GetAuditLogsEndpoint.ts +5 -7
  61. package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +2 -2
  62. package/src/endpoints/global/email/CreateEmailEndpoint.ts +3 -4
  63. package/src/endpoints/global/email/GetAdminEmailsEndpoint.test.ts +1 -1
  64. package/src/endpoints/global/email/GetAdminEmailsEndpoint.ts +1 -2
  65. package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +4 -6
  66. package/src/endpoints/global/email/GetEmailEndpoint.ts +1 -1
  67. package/src/endpoints/global/email/GetUserEmailsEndpoint.test.ts +1 -1
  68. package/src/endpoints/global/email/GetUserEmailsEndpoint.ts +1 -1
  69. package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +6 -10
  70. package/src/endpoints/global/email/PatchEmailEndpoint.test.ts +4 -7
  71. package/src/endpoints/global/email/PatchEmailEndpoint.ts +6 -9
  72. package/src/endpoints/global/email-recipients/GetEmailRecipientsCountEndpoint.ts +1 -1
  73. package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.test.ts +1 -1
  74. package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.ts +1 -1
  75. package/src/endpoints/global/email-recipients/RetryEmailRecipientEndpoint.ts +2 -2
  76. package/src/endpoints/global/events/GetEventNotificationsCountEndpoint.ts +1 -1
  77. package/src/endpoints/global/events/GetEventNotificationsEndpoint.ts +3 -3
  78. package/src/endpoints/global/events/GetEventsEndpoint.ts +3 -3
  79. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.test.ts +49 -4
  80. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.ts +5 -8
  81. package/src/endpoints/global/events/PatchEventsEndpoint.test.ts +12 -44
  82. package/src/endpoints/global/events/PatchEventsEndpoint.ts +128 -127
  83. package/src/endpoints/global/files/ExportToExcelEndpoint.ts +9 -9
  84. package/src/endpoints/global/files/GetFileCache.ts +3 -4
  85. package/src/endpoints/global/files/UploadFile.ts +3 -4
  86. package/src/endpoints/global/files/UploadImage.ts +3 -4
  87. package/src/endpoints/global/groups/GetGroupsCountEndpoint.ts +1 -1
  88. package/src/endpoints/global/groups/GetGroupsEndpoint.test.ts +1 -1
  89. package/src/endpoints/global/groups/GetGroupsEndpoint.ts +4 -2
  90. package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +2 -3
  91. package/src/endpoints/global/members/GetMembersCountEndpoint.ts +1 -1
  92. package/src/endpoints/global/members/GetMembersEndpoint.test.ts +2 -2
  93. package/src/endpoints/global/members/GetMembersEndpoint.ts +10 -12
  94. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.test.ts +195 -12
  95. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +16 -22
  96. package/src/endpoints/global/members/helpers/validateGroupFilter.ts +6 -30
  97. package/src/endpoints/global/members/shouldCheckIfMemberIsDuplicate.ts +1 -1
  98. package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +1 -1
  99. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +40 -8
  100. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +2 -2
  101. package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +2 -2
  102. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +4 -1
  103. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +4 -5
  104. package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +9 -16
  105. package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +1 -1
  106. package/src/endpoints/global/platform/GetPlatformEndpoint.ts +1 -1
  107. package/src/endpoints/global/platform/PatchPlatformEnpoint.test.ts +1 -1
  108. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +11 -11
  109. package/src/endpoints/global/platform-memberships/GetPlatformMembershipsCountEndpoint.ts +31 -31
  110. package/src/endpoints/global/platform-memberships/GetPlatformMembershipsEndpoint.ts +18 -20
  111. package/src/endpoints/global/registration/GetRegistrationsCountEndpoint.ts +1 -1
  112. package/src/endpoints/global/registration/GetRegistrationsEndpoint.test.ts +1 -1
  113. package/src/endpoints/global/registration/GetRegistrationsEndpoint.ts +6 -10
  114. package/src/endpoints/global/registration/GetUserDetailedPayableBalanceEndpoint.ts +35 -6
  115. package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +2 -2
  116. package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +1 -1
  117. package/src/endpoints/global/registration/GetUserPayableBalanceEndpoint.ts +1 -1
  118. package/src/endpoints/global/registration/PatchUserMembersEndpoint.test.ts +2 -2
  119. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +3 -3
  120. package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +90 -6
  121. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +35 -34
  122. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsCountEndpoint.ts +1 -1
  123. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.test.ts +62 -63
  124. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.ts +6 -9
  125. package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.test.ts +51 -52
  126. package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.ts +6 -7
  127. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsCountEndpoint.ts +43 -0
  128. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +1 -1
  129. package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +13 -5
  130. package/src/endpoints/global/sso/GetSSOEndpoint.ts +2 -3
  131. package/src/endpoints/global/sso/SetSSOEndpoint.ts +1 -1
  132. package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +2 -2
  133. package/src/endpoints/global/webshops/GetWebshopsEndpoint.test.ts +1 -2
  134. package/src/endpoints/global/webshops/GetWebshopsEndpoint.ts +2 -4
  135. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemEndpoint.ts +2 -2
  136. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsCountEndpoint.ts +1 -1
  137. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsEndpoint.ts +3 -4
  138. package/src/endpoints/organization/dashboard/balance-items/PatchBalanceItemsEndpoint.ts +7 -9
  139. package/src/endpoints/organization/dashboard/billing/ApplyRegisterCodeEndpoint.test.ts +73 -0
  140. package/src/endpoints/organization/dashboard/billing/ApplyRegisterCodeEndpoint.ts +89 -0
  141. package/src/endpoints/organization/dashboard/billing/DeactivatePackageEndpoint.ts +1 -5
  142. package/src/endpoints/organization/dashboard/billing/DeleteOrganizationMandateEndpoint.ts +11 -11
  143. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceCollectionEndpoint.ts +2 -2
  144. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceEndpoint.ts +8 -8
  145. package/src/endpoints/organization/dashboard/billing/GetOrganizationMandatesEndpoint.ts +9 -9
  146. package/src/endpoints/organization/dashboard/billing/GetOrganizationPayableBalanceEndpoint.ts +2 -2
  147. package/src/endpoints/organization/dashboard/billing/GetOrganizationPayableInvoicesEndpoint.ts +68 -0
  148. package/src/endpoints/organization/dashboard/billing/GetPackagesEndpoint.ts +4 -4
  149. package/src/endpoints/organization/dashboard/billing/GetRegisterCodeEndpoint.ts +66 -0
  150. package/src/endpoints/organization/dashboard/billing/OrganizationCheckoutEndpoint.test.ts +949 -0
  151. package/src/endpoints/organization/dashboard/billing/OrganizationCheckoutEndpoint.ts +60 -57
  152. package/src/endpoints/organization/dashboard/billing/PatchOrganizationMandatesEndpoint.ts +20 -20
  153. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +1 -1
  154. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesCountEndpoint.ts +1 -1
  155. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +1 -1
  156. package/src/endpoints/organization/dashboard/documents/GetDocumentsCountEndpoint.ts +1 -1
  157. package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +1 -1
  158. package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +10 -2
  159. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.test.ts +2 -2
  160. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.ts +2 -2
  161. package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +1 -1
  162. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.test.ts +1 -1
  163. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +10 -8
  164. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.test.ts +1 -1
  165. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +5 -6
  166. package/src/endpoints/organization/dashboard/invoices/GetInvoicesCountEndpoint.ts +1 -1
  167. package/src/endpoints/organization/dashboard/invoices/GetInvoicesEndpoint.ts +10 -6
  168. package/src/endpoints/organization/dashboard/invoices/PatchInvoicesEndpoint.ts +11 -2
  169. package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +4 -5
  170. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +5 -5
  171. package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +2 -2
  172. package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +7 -7
  173. package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +1 -1
  174. package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +2 -2
  175. package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +1 -1
  176. package/src/endpoints/organization/dashboard/organization/GetUitpasClientIdEndpoint.ts +1 -1
  177. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +2 -2
  178. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +50 -12
  179. package/src/endpoints/organization/dashboard/organization/SearchUitpasOrganizersEndpoint.ts +2 -2
  180. package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +5 -10
  181. package/src/endpoints/organization/dashboard/organization/SetUitpasClientCredentialsEndpoint.ts +1 -1
  182. package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +1 -1
  183. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +3 -4
  184. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +21 -14
  185. package/src/endpoints/organization/dashboard/receivable-balances/ChargeReceivableBalancesEndpoint.ts +35 -28
  186. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint.ts +2 -3
  187. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesCountEndpoint.ts +1 -1
  188. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts +1 -1
  189. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.test.ts +1 -1
  190. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +2 -3
  191. package/src/endpoints/organization/dashboard/registration-periods/MoveRegistrationPeriods.test.ts +1 -1
  192. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.test.ts +1 -1
  193. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +19 -18
  194. package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +4 -5
  195. package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +1 -1
  196. package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +2 -3
  197. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +2 -2
  198. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +1 -1
  199. package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +2 -2
  200. package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +1 -1
  201. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +1 -1
  202. package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +1 -1
  203. package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +1 -1
  204. package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +1 -1
  205. package/src/endpoints/organization/dashboard/users/PatchApiUserEndpoint.ts +4 -6
  206. package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +10 -15
  207. package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +1 -1
  208. package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +2 -2
  209. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersCountEndpoint.ts +1 -1
  210. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +1 -1
  211. package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +1 -1
  212. package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +11 -2
  213. package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +4 -6
  214. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +22 -7
  215. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +20 -27
  216. package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +1 -1
  217. package/src/endpoints/organization/dashboard/webshops/SearchUitpasEventsEndpoint.ts +2 -2
  218. package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +2 -3
  219. package/src/endpoints/organization/dashboard/webshops/WebshopReservedPathSegments.test.ts +95 -0
  220. package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +2 -2
  221. package/src/endpoints/organization/shared/GetDocumentHtml.ts +1 -1
  222. package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +1 -1
  223. package/src/endpoints/organization/shared/GetUitpasNumberDetailsEndpoint.ts +3 -5
  224. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +1 -1
  225. package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +4 -1
  226. package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +14 -3
  227. package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +14 -2
  228. package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +37 -16
  229. package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +34 -2
  230. package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +4 -2
  231. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +74 -3
  232. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +16 -33
  233. package/src/endpoints/organization/webshops/RetrieveUitpasSocialTariffPriceEndpoint.ts +3 -5
  234. package/src/endpoints/organization/webshops/WebshopAuthHelper.ts +36 -0
  235. package/src/endpoints/system/HealthEndpoint.ts +1 -1
  236. package/src/excel-loaders/balance-items.ts +1 -1
  237. package/src/excel-loaders/event-notifications.ts +1 -1
  238. package/src/excel-loaders/members.ts +1 -1
  239. package/src/excel-loaders/organizations.ts +3 -3
  240. package/src/excel-loaders/payments.ts +31 -1
  241. package/src/excel-loaders/platform-memberships.ts +13 -14
  242. package/src/excel-loaders/receivable-balances.ts +2 -2
  243. package/src/excel-loaders/registrations.ts +2 -3
  244. package/src/helpers/AddressValidator.ts +7 -14
  245. package/src/helpers/AdminPermissionChecker.ts +50 -63
  246. package/src/helpers/AuthenticatedStructures.ts +69 -55
  247. package/src/helpers/BalanceItemRelationsBackfiller.test.ts +174 -0
  248. package/src/helpers/BalanceItemRelationsBackfiller.ts +163 -0
  249. package/src/helpers/BuckarooHelper.ts +2 -4
  250. package/src/helpers/CheckSettlements.ts +12 -24
  251. package/src/helpers/Context.ts +15 -10
  252. package/src/helpers/CookieHelper.ts +1 -2
  253. package/src/helpers/EmailResumer.ts +1 -2
  254. package/src/helpers/FileCache.ts +2 -3
  255. package/src/helpers/FinancialSupportHelper.ts +2 -2
  256. package/src/helpers/FlagMomentCleanup.ts +1 -2
  257. package/src/helpers/ForwardHandler.ts +5 -10
  258. package/src/helpers/GlobalHelper.ts +3 -3
  259. package/src/helpers/LegacyBillingConverter.ts +787 -0
  260. package/src/helpers/MemberMerger.test.ts +782 -0
  261. package/src/helpers/MemberMerger.ts +600 -0
  262. package/src/helpers/MemberUserSyncer.ts +6 -12
  263. package/src/helpers/MembershipCharger.ts +2 -4
  264. package/src/helpers/PaymentCustomerResolver.test.ts +203 -0
  265. package/src/helpers/PaymentCustomerResolver.ts +144 -0
  266. package/src/helpers/PeriodHelper.ts +2 -3
  267. package/src/helpers/RecordAnswerHelper.test.ts +105 -110
  268. package/src/helpers/RecordAnswerHelper.ts +7 -7
  269. package/src/helpers/SeedTools.ts +106 -0
  270. package/src/helpers/ServiceFeeHelper.ts +125 -15
  271. package/src/helpers/SetupStepUpdater.ts +38 -32
  272. package/src/helpers/StamhoofdFilterAccessHelper.ts +52 -0
  273. package/src/helpers/StripeHelper.ts +14 -36
  274. package/src/helpers/StripeInvoicer.ts +419 -0
  275. package/src/helpers/StripePayoutChecker.ts +5 -10
  276. package/src/helpers/TagHelper.ts +7 -8
  277. package/src/helpers/TemporaryMemberAccess.ts +1 -2
  278. package/src/helpers/ThrottledQueue.ts +1 -2
  279. package/src/helpers/UitpasTokenRepository.ts +1 -2
  280. package/src/helpers/ViesHelper.ts +7 -11
  281. package/src/helpers/XlsxTransformerColumnHelper.ts +1 -1
  282. package/src/helpers/outstandingBalanceJoin.ts +2 -2
  283. package/src/helpers/updateMemberDetailsUitpasNumber.ts +3 -5
  284. package/src/migrate.ts +12 -5
  285. package/src/{seeds → migrations}/0000000004-single-organization.ts +10 -1
  286. package/src/migrations/0000000006-default-organization.ts +139 -0
  287. package/src/{seeds → migrations}/1715028563-user-permissions.ts +17 -27
  288. package/src/{seeds/1765896674-document-update-year.test.ts → migrations/1750090029-document-update-year.test.ts} +27 -26
  289. package/src/migrations/1750090029-document-update-year.ts +103 -0
  290. package/src/{seeds → migrations}/1750090030-records-configuration.ts +33 -32
  291. package/src/migrations/1750090031-records-configuration-webshops.ts +36 -0
  292. package/src/migrations/1752848540-national-numbers.ts +585 -0
  293. package/src/migrations/1752848550-records-configuration-group-filter.ts +1064 -0
  294. package/src/{seeds → migrations}/1752848561-groups-registration-periods.ts +70 -26
  295. package/src/{seeds → migrations}/1754560914-groups-prices.test.ts +1 -1
  296. package/src/{seeds → migrations}/1754560914-groups-prices.ts +9 -15
  297. package/src/{seeds → migrations}/1756293699-fill-previous-next-period-id.ts +1 -2
  298. package/src/migrations/1761665607-sync-member-users.ts +40 -0
  299. package/src/migrations/1779121240-invoice-email-template.sql +6 -0
  300. package/src/migrations/1779986893-default-payment-failed-email-templates.sql +4 -0
  301. package/src/migrations/1780578166-convert-legacy-billing.ts +13 -0
  302. package/src/{seeds/1755876819-remove-duplicate-members.ts → migrations/1780665426-remove-duplicate-members.ts} +23 -4
  303. package/src/migrations/1780933598-document-groups.ts +88 -0
  304. package/src/migrations/1781692342-balance-item-relations.ts +13 -0
  305. package/src/migrations/1781857866-platform-admins.ts +103 -0
  306. package/src/migrations/1781857867-rm-old-platform-admins.ts +25 -0
  307. package/src/seeds/0000000001-throw.ts +5 -0
  308. package/src/seeds/1760702452-update-balance-price-paid.ts +19 -0
  309. package/src/seeds/1760702453-update-balance-invoiced.ts +19 -0
  310. package/src/seeds/1760702454-update-cached-outstanding-balance-from-items.ts +51 -14
  311. package/src/seeds/1773754928-force-save-members.ts +41 -8
  312. package/src/seeds/1780665427-schedule-stock-updates.ts +45 -0
  313. package/src/seeds/1780665428-group-update-occupancy.ts +31 -0
  314. package/src/seeds/1780915001-fill-payment-customer.ts +70 -0
  315. package/src/seeds/1780915002-update-orders.ts +39 -0
  316. package/src/seeds/1782047708-organization-company-address.ts +44 -0
  317. package/src/seeds-temporary/1769088653-uitpas-status.ts +1 -2
  318. package/src/seeds-temporary/1780416000-migrate-audit-log-legacy-enums.test.ts +69 -0
  319. package/src/seeds-temporary/1780416000-migrate-audit-log-legacy-enums.ts +85 -0
  320. package/src/services/AuditLogService.test.ts +51 -0
  321. package/src/services/AuditLogService.ts +45 -0
  322. package/src/services/BalanceItemService.ts +141 -44
  323. package/src/services/CpuService.ts +3 -6
  324. package/src/services/DatabaseCollationService.test.ts +1 -2
  325. package/src/services/DocumentService.ts +1 -2
  326. package/src/services/EventNotificationService.ts +1 -1
  327. package/src/services/FileSignService.ts +2 -4
  328. package/src/services/InvoicePdfService.ts +286 -0
  329. package/src/services/InvoiceService.ts +204 -251
  330. package/src/services/InvoiceXMLService.ts +424 -0
  331. package/src/services/MemberNumberService.ts +6 -11
  332. package/src/services/MemberRecordStore.ts +8 -10
  333. package/src/services/MollieService.ts +114 -121
  334. package/src/services/PaymentMandateService.ts +45 -45
  335. package/src/services/PaymentReallocationService.test.ts +1 -1
  336. package/src/services/PaymentReallocationService.ts +7 -9
  337. package/src/services/PaymentService.ts +444 -308
  338. package/src/services/PlatformMembershipService.ts +4 -8
  339. package/src/services/ReferralService.ts +223 -0
  340. package/src/services/RegistrationService.ts +63 -53
  341. package/src/services/SSOService.test.ts +119 -0
  342. package/src/services/SSOService.ts +56 -49
  343. package/src/services/STPackageService.ts +97 -61
  344. package/src/services/UniqueMemberNumberService.ts +69 -0
  345. package/src/services/UniqueUserService.ts +3 -6
  346. package/src/services/VATService.ts +85 -0
  347. package/src/services/uitpas/PassholderEndpoints.ts +3 -6
  348. package/src/services/uitpas/UitpasService.ts +6 -10
  349. package/src/services/uitpas/checkUitpasNumbers.ts +2 -4
  350. package/src/services/uitpas/getSocialTariffForUitpasNumbers.ts +3 -6
  351. package/src/services/uitpas/searchUitpasEvents.ts +1 -2
  352. package/src/sql-filters/audit-logs.ts +1 -1
  353. package/src/sql-filters/balance-item-payments.ts +1 -1
  354. package/src/sql-filters/balance-items.ts +1 -1
  355. package/src/sql-filters/base-registration-filter-compilers.ts +5 -33
  356. package/src/sql-filters/document-templates.ts +1 -1
  357. package/src/sql-filters/documents.ts +1 -1
  358. package/src/sql-filters/email-recipients.ts +1 -1
  359. package/src/sql-filters/emails.ts +1 -1
  360. package/src/sql-filters/event-notifications.ts +1 -1
  361. package/src/sql-filters/events.ts +6 -1
  362. package/src/sql-filters/groups.ts +5 -0
  363. package/src/sql-filters/invoiced-balance-items.ts +1 -1
  364. package/src/sql-filters/invoices.ts +1 -1
  365. package/src/sql-filters/member-responsibility-records.ts +1 -1
  366. package/src/sql-filters/members.ts +1 -1
  367. package/src/sql-filters/orders.ts +4 -4
  368. package/src/sql-filters/organization-registration-periods.ts +1 -1
  369. package/src/sql-filters/organizations.ts +1 -1
  370. package/src/sql-filters/platform-memberships.ts +3 -3
  371. package/src/sql-filters/receivable-balances.ts +1 -1
  372. package/src/sql-filters/registration-periods.ts +1 -1
  373. package/src/sql-filters/registrations.ts +1 -1
  374. package/src/sql-filters/tickets.ts +1 -1
  375. package/src/sql-filters/users.ts +1 -1
  376. package/src/sql-sorters/groups.ts +23 -0
  377. package/src/sql-sorters/platform-memberships.ts +16 -16
  378. package/src/sql-sorters/registration-invitations.ts +2 -2
  379. package/tests/actions/patchOrganizationMember.ts +1 -1
  380. package/tests/actions/patchUserMember.ts +1 -1
  381. package/tests/assertions/assertBalances.ts +6 -12
  382. package/tests/e2e/api-rate-limits.test.ts +12 -24
  383. package/tests/e2e/bundle-discounts.test.ts +4 -1
  384. package/tests/e2e/charge-members.test.ts +13 -11
  385. package/tests/e2e/documents.test.ts +4 -1
  386. package/tests/e2e/register.test.ts +7 -9
  387. package/tests/e2e/stock.test.ts +4 -3
  388. package/tests/e2e/tickets.test.ts +1 -1
  389. package/tests/helpers/MollieMocker.ts +462 -0
  390. package/tests/helpers/PayconiqMocker.ts +138 -45
  391. package/tests/helpers/StripeMocker.ts +9 -6
  392. package/tests/helpers/index.ts +4 -0
  393. package/tests/init/initAdmin.ts +2 -2
  394. package/tests/init/initBundleDiscount.ts +1 -1
  395. package/tests/init/initMembershipOrganization.ts +13 -0
  396. package/tests/init/initPermissionRole.ts +3 -4
  397. package/tests/vitest.global.setup.ts +1 -1
  398. package/vitest.config.js +6 -0
  399. package/.nvmrc +0 -1
  400. package/src/helpers/GroupBuilder.ts +0 -418
  401. package/src/seeds/0000000000-example.ts +0 -11
  402. package/src/seeds/1722256498-group-update-occupancy.ts +0 -52
  403. package/src/seeds/1726572303-schedule-stock-updates.ts +0 -52
  404. package/src/seeds/1726847064-setup-steps.ts +0 -16
  405. package/src/seeds/1728928974-update-cached-outstanding-balance-from-items.ts +0 -31
  406. package/src/seeds/1729253172-update-orders.ts +0 -21
  407. package/src/seeds/1733319079-fill-paying-organization-ids.ts +0 -68
  408. package/src/seeds/1733748412-update-deleted-order-numbers.ts +0 -109
  409. package/src/seeds/1733994455-balance-item-status-open.ts +0 -30
  410. package/src/seeds/1740046783-update-membership.ts +0 -17
  411. package/src/seeds/1741008870-fix-auditlog-description.ts +0 -50
  412. package/src/seeds/1741011468-fix-auditlog-description-uft16.ts +0 -88
  413. package/src/seeds/1741268179-fix-group-dates-of-events.ts +0 -32
  414. package/src/seeds/1751445358-upload-email-attachments.ts +0 -106
  415. package/src/seeds/1755532883-update-email-sender-ids.ts +0 -47
  416. package/src/seeds/1755790070-fill-email-recipient-errors.ts +0 -96
  417. package/src/seeds/1756115432-remove-old-drafts.ts +0 -16
  418. package/src/seeds/1756115433-fill-email-recipient-organization-id.ts +0 -30
  419. package/src/seeds/1756303697-update-email-counts.ts +0 -76
  420. package/src/seeds/1761665607-sync-member-users.ts +0 -59
  421. package/src/seeds/1765896674-document-update-year.ts +0 -66
  422. /package/src/{seeds → migrations}/0000000001-development-user.ts +0 -0
  423. /package/src/{seeds → migrations}/0000000002-clear-stamhoofd-email-templates.ts +0 -0
  424. /package/src/{seeds → migrations}/0000000003-default-email-templates.ts +0 -0
  425. /package/src/{seeds → migrations}/1752848561-groups-registration-periods.test.ts +0 -0
  426. /package/src/{seeds → migrations}/1766150402-document-published-at.test.ts +0 -0
  427. /package/src/{seeds → migrations}/1766150402-document-published-at.ts +0 -0
  428. /package/src/{seeds → migrations}/1779121239-default-invoice-email-template.sql +0 -0
  429. /package/src/{seeds → migrations}/data/default-email-templates.sql +0 -0
@@ -0,0 +1,174 @@
1
+ import type { Organization, RegistrationPeriod, Webshop } from '@stamhoofd/models';
2
+ import { BalanceItem, BalanceItemFactory, GroupFactory, MemberFactory, OrganizationFactory, OrganizationRegistrationPeriodFactory, Order, RegistrationFactory, RegistrationPeriodFactory, WebshopFactory } from '@stamhoofd/models';
3
+ import { BalanceItemRelation, BalanceItemRelationType, BalanceItemType, OrderData, ReduceablePrice, TranslatedString } from '@stamhoofd/structures';
4
+ import { TestUtils } from '@stamhoofd/test-utils';
5
+ import { v4 as uuidv4 } from 'uuid';
6
+ import { backfillBalanceItemRelations } from './BalanceItemRelationsBackfiller.js';
7
+
8
+ describe('helper.BalanceItemRelationsBackfiller', () => {
9
+ let period: RegistrationPeriod;
10
+
11
+ beforeAll(async () => {
12
+ period = await new RegistrationPeriodFactory({
13
+ startDate: new Date(2023, 0, 1),
14
+ endDate: new Date(2030, 11, 31),
15
+ }).create();
16
+ });
17
+
18
+ beforeEach(() => {
19
+ TestUtils.setEnvironment('userMode', 'platform');
20
+ });
21
+
22
+ async function createOrder(organization: Organization, webshop: Webshop) {
23
+ const order = new Order();
24
+ order.organizationId = organization.id;
25
+ order.webshopId = webshop.id;
26
+ order.data = OrderData.create({});
27
+ await order.save();
28
+ return order;
29
+ }
30
+
31
+ it('fills member, group and group price relations for registration balance items', async () => {
32
+ const organization = await new OrganizationFactory({ period }).create();
33
+ await new OrganizationRegistrationPeriodFactory({ organization, period }).create();
34
+
35
+ const member = await new MemberFactory({ organization, firstName: 'John', lastName: 'Doe' }).create();
36
+ const group = await new GroupFactory({ organization, period }).create();
37
+ const registration = await new RegistrationFactory({ member, group }).create();
38
+
39
+ const balanceItem = await new BalanceItemFactory({
40
+ organizationId: organization.id,
41
+ memberId: member.id,
42
+ registrationId: registration.id,
43
+ type: BalanceItemType.Registration,
44
+ amount: 1,
45
+ unitPrice: 25_00,
46
+ }).create();
47
+
48
+ expect(balanceItem.relations.size).toBe(0);
49
+
50
+ await backfillBalanceItemRelations();
51
+
52
+ const updated = await BalanceItem.getByID(balanceItem.id);
53
+ expect(updated?.relations.get(BalanceItemRelationType.Member)).toMatchObject({ id: member.id });
54
+ expect(updated?.relations.get(BalanceItemRelationType.Member)?.name.toString()).toBe('John Doe');
55
+ expect(updated?.relations.get(BalanceItemRelationType.Group)).toMatchObject({ id: group.id });
56
+ // Only one price configured, so no group price relation
57
+ expect(updated?.relations.has(BalanceItemRelationType.GroupPrice)).toBe(false);
58
+ });
59
+
60
+ it('fills the group price relation when the group has multiple prices', async () => {
61
+ const organization = await new OrganizationFactory({ period }).create();
62
+ await new OrganizationRegistrationPeriodFactory({ organization, period }).create();
63
+
64
+ const member = await new MemberFactory({ organization }).create();
65
+ const group = await new GroupFactory({ organization, period }).create();
66
+
67
+ // Add a second price so the relation should be filled
68
+ group.settings.prices.push(group.settings.prices[0].clone());
69
+ group.settings.prices[1].id = uuidv4();
70
+ group.settings.prices[1].name = new TranslatedString('Late price');
71
+ group.settings.prices[1].price = ReduceablePrice.create({ price: 30_00 });
72
+ await group.save();
73
+
74
+ const registration = await new RegistrationFactory({ member, group, groupPrice: group.settings.prices[1] }).create();
75
+
76
+ const balanceItem = await new BalanceItemFactory({
77
+ organizationId: organization.id,
78
+ memberId: member.id,
79
+ registrationId: registration.id,
80
+ type: BalanceItemType.Registration,
81
+ amount: 1,
82
+ unitPrice: 30_00,
83
+ }).create();
84
+
85
+ await backfillBalanceItemRelations();
86
+
87
+ const updated = await BalanceItem.getByID(balanceItem.id);
88
+ expect(updated?.relations.get(BalanceItemRelationType.GroupPrice)).toMatchObject({ id: group.settings.prices[1].id });
89
+ });
90
+
91
+ it('copies the registration period dates onto the balance item', async () => {
92
+ const organization = await new OrganizationFactory({ period }).create();
93
+ await new OrganizationRegistrationPeriodFactory({ organization, period }).create();
94
+
95
+ const member = await new MemberFactory({ organization }).create();
96
+ const group = await new GroupFactory({ organization, period }).create();
97
+ const registration = await new RegistrationFactory({ member, group }).create();
98
+
99
+ const startDate = new Date(2024, 7, 1);
100
+ const endDate = new Date(2025, 6, 31);
101
+ registration.startDate = startDate;
102
+ registration.endDate = endDate;
103
+ await registration.save();
104
+
105
+ const balanceItem = await new BalanceItemFactory({
106
+ organizationId: organization.id,
107
+ memberId: member.id,
108
+ registrationId: registration.id,
109
+ type: BalanceItemType.Registration,
110
+ amount: 1,
111
+ unitPrice: 25_00,
112
+ }).create();
113
+
114
+ await backfillBalanceItemRelations();
115
+
116
+ const updated = await BalanceItem.getByID(balanceItem.id);
117
+ expect(updated?.startDate?.getTime()).toBe(startDate.getTime());
118
+ expect(updated?.endDate?.getTime()).toBe(endDate.getTime());
119
+ });
120
+
121
+ it('fills the webshop relation for order balance items', async () => {
122
+ const organization = await new OrganizationFactory({ period }).create();
123
+ const webshop = await new WebshopFactory({ organizationId: organization.id, name: 'My webshop' }).create();
124
+ const order = await createOrder(organization, webshop);
125
+
126
+ const balanceItem = await new BalanceItemFactory({
127
+ organizationId: organization.id,
128
+ orderId: order.id,
129
+ type: BalanceItemType.Order,
130
+ amount: 1,
131
+ unitPrice: 12_00,
132
+ }).create();
133
+
134
+ expect(balanceItem.relations.size).toBe(0);
135
+
136
+ await backfillBalanceItemRelations();
137
+
138
+ const updated = await BalanceItem.getByID(balanceItem.id);
139
+ expect(updated?.relations.get(BalanceItemRelationType.Webshop)).toMatchObject({ id: webshop.id });
140
+ expect(updated?.relations.get(BalanceItemRelationType.Webshop)?.name.toString()).toBe('My webshop');
141
+ });
142
+
143
+ it('does not overwrite existing relations', async () => {
144
+ const organization = await new OrganizationFactory({ period }).create();
145
+ await new OrganizationRegistrationPeriodFactory({ organization, period }).create();
146
+
147
+ const member = await new MemberFactory({ organization }).create();
148
+ const group = await new GroupFactory({ organization, period }).create();
149
+ const registration = await new RegistrationFactory({ member, group }).create();
150
+
151
+ const existingRelations = new Map([
152
+ [
153
+ BalanceItemRelationType.Member,
154
+ BalanceItemRelation.create({ id: member.id, name: new TranslatedString('Custom name') }),
155
+ ],
156
+ ]);
157
+
158
+ const balanceItem = await new BalanceItemFactory({
159
+ organizationId: organization.id,
160
+ memberId: member.id,
161
+ registrationId: registration.id,
162
+ type: BalanceItemType.Registration,
163
+ amount: 1,
164
+ unitPrice: 25_00,
165
+ relations: existingRelations,
166
+ }).create();
167
+
168
+ await backfillBalanceItemRelations();
169
+
170
+ const updated = await BalanceItem.getByID(balanceItem.id);
171
+ expect(updated?.relations.size).toBe(1);
172
+ expect(updated?.relations.get(BalanceItemRelationType.Member)?.name.toString()).toBe('Custom name');
173
+ });
174
+ });
@@ -0,0 +1,163 @@
1
+ import { BalanceItem, Group, Member, Order, Registration, Webshop } from '@stamhoofd/models';
2
+ import { SQL } from '@stamhoofd/sql';
3
+ import { BalanceItemRelation, BalanceItemRelationType, BalanceItemType, TranslatedString } from '@stamhoofd/structures';
4
+ import { Formatter } from '@stamhoofd/utility';
5
+ import { SeedTools } from './SeedTools.js';
6
+
7
+ /**
8
+ * Backfills the `relations` (and registration `startDate`/`endDate`) of legacy v1 balance items.
9
+ *
10
+ * V1 balance items were created without relations, so the frontend cannot show the member name, the
11
+ * registration group, the working year or the webshop name (it falls back to "Onbekende
12
+ * inschrijvingsgroep" / "Onbekende webshop"). We reconstruct that data from the linked registration or
13
+ * order.
14
+ *
15
+ * Only balance items that still have empty relations are touched, so the migration is idempotent and
16
+ * never overwrites relations that were already set by the current flows.
17
+ */
18
+
19
+ /**
20
+ * Build the relations for a registration balance item, mirroring RegisterMembersEndpoint.
21
+ * Returns null when the linked registration/group/member can no longer be resolved.
22
+ */
23
+ function buildRegistrationRelations(registration: Registration, group: Group, member: Member | undefined): Map<BalanceItemRelationType, BalanceItemRelation> {
24
+ const relations = new Map<BalanceItemRelationType, BalanceItemRelation>();
25
+
26
+ if (member) {
27
+ relations.set(BalanceItemRelationType.Member, BalanceItemRelation.create({
28
+ id: member.id,
29
+ name: new TranslatedString(member.details.name),
30
+ }));
31
+ }
32
+
33
+ relations.set(BalanceItemRelationType.Group, BalanceItemRelation.create({
34
+ id: group.id,
35
+ name: group.settings.name,
36
+ }));
37
+
38
+ // Mirror RegisterMembersEndpoint: only add the group price relation when there are multiple prices.
39
+ if (group.settings.prices.length > 1 && registration.groupPrice) {
40
+ relations.set(BalanceItemRelationType.GroupPrice, BalanceItemRelation.create({
41
+ id: registration.groupPrice.id,
42
+ name: registration.groupPrice.name,
43
+ }));
44
+ }
45
+
46
+ return relations;
47
+ }
48
+
49
+ async function backfillRegistrationBalanceItems(): Promise<number> {
50
+ let updated = 0;
51
+
52
+ await SeedTools.loopBatched({
53
+ batchSize: 100,
54
+ query: BalanceItem.select()
55
+ .whereNot('registrationId', null)
56
+ .where(SQL.jsonLength(SQL.column('relations'), '$.value'), 0),
57
+ batchAction: async (items: BalanceItem[]) => {
58
+ const registrationIds = Formatter.uniqueArray(items.map(i => i.registrationId!).filter(id => !!id));
59
+ const registrations = await Registration.getByIDs(...registrationIds);
60
+ const registrationMap = new Map(registrations.map(r => [r.id, r]));
61
+
62
+ const groups = await Group.getByIDs(...Formatter.uniqueArray(registrations.map(r => r.groupId)));
63
+ const groupMap = new Map(groups.map(g => [g.id, g]));
64
+
65
+ const members = await Member.getByIDs(...Formatter.uniqueArray(registrations.map(r => r.memberId)));
66
+ const memberMap = new Map(members.map(m => [m.id, m]));
67
+
68
+ for (const item of items) {
69
+ // A second safety check: never overwrite existing relations.
70
+ if (item.relations.size > 0) {
71
+ continue;
72
+ }
73
+
74
+ const registration = registrationMap.get(item.registrationId!);
75
+ if (!registration) {
76
+ continue;
77
+ }
78
+
79
+ const group = groupMap.get(registration.groupId);
80
+ if (!group) {
81
+ continue;
82
+ }
83
+
84
+ const member = memberMap.get(registration.memberId);
85
+
86
+ item.relations = buildRegistrationRelations(registration, group, member);
87
+
88
+ // Reconstruct the period (working year) so the frontend can show it.
89
+ if (item.startDate === null && registration.startDate) {
90
+ item.startDate = registration.startDate;
91
+ }
92
+ if (item.endDate === null && registration.endDate) {
93
+ item.endDate = registration.endDate;
94
+ }
95
+
96
+ await item.save();
97
+ updated += 1;
98
+ }
99
+ },
100
+ });
101
+
102
+ return updated;
103
+ }
104
+
105
+ async function backfillOrderBalanceItems(): Promise<number> {
106
+ let updated = 0;
107
+
108
+ await SeedTools.loopBatched({
109
+ batchSize: 100,
110
+ query: BalanceItem.select()
111
+ .where('type', BalanceItemType.Order)
112
+ .whereNot('orderId', null)
113
+ .where(SQL.jsonLength(SQL.column('relations'), '$.value'), 0),
114
+ batchAction: async (items: BalanceItem[]) => {
115
+ const orderIds = Formatter.uniqueArray(items.map(i => i.orderId!).filter(id => !!id));
116
+ const orders = await Order.getByIDs(...orderIds);
117
+ const orderMap = new Map(orders.map(o => [o.id, o]));
118
+
119
+ const webshops = await Webshop.getByIDs(...Formatter.uniqueArray(orders.map(o => o.webshopId)));
120
+ const webshopMap = new Map(webshops.map(w => [w.id, w]));
121
+
122
+ for (const item of items) {
123
+ if (item.relations.size > 0) {
124
+ continue;
125
+ }
126
+
127
+ const order = orderMap.get(item.orderId!);
128
+ if (!order) {
129
+ continue;
130
+ }
131
+
132
+ const webshop = webshopMap.get(order.webshopId);
133
+ if (!webshop) {
134
+ continue;
135
+ }
136
+
137
+ item.relations = new Map([
138
+ [
139
+ BalanceItemRelationType.Webshop,
140
+ BalanceItemRelation.create({
141
+ id: webshop.id,
142
+ name: new TranslatedString(webshop.meta.name),
143
+ }),
144
+ ],
145
+ ]);
146
+
147
+ await item.save();
148
+ updated += 1;
149
+ }
150
+ },
151
+ });
152
+
153
+ return updated;
154
+ }
155
+
156
+ export async function backfillBalanceItemRelations(): Promise<{ registrations: number; orders: number }> {
157
+ const registrations = await backfillRegistrationBalanceItems();
158
+ const orders = await backfillOrderBalanceItems();
159
+
160
+ console.log(`[BalanceItemRelationsBackfiller] Updated ${registrations} registration balance items and ${orders} order balance items`);
161
+
162
+ return { registrations, orders };
163
+ }
@@ -115,8 +115,7 @@ export class BuckarooHelper {
115
115
  const status = this.getStatusFromResponse(response);
116
116
 
117
117
  return status === PaymentStatus.Pending || status === PaymentStatus.Created || status === PaymentStatus.Succeeded;
118
- }
119
- catch (e) {
118
+ } catch (e) {
120
119
  console.error(e);
121
120
  }
122
121
  return false;
@@ -205,8 +204,7 @@ export class BuckarooHelper {
205
204
  await dbPayment.save();
206
205
 
207
206
  return response['RequiredAction']?.['RedirectURL'] ?? null;
208
- }
209
- catch (e) {
207
+ } catch (e) {
210
208
  console.error(e);
211
209
  throw new SimpleError({
212
210
  code: 'buckaroo_error',
@@ -39,8 +39,7 @@ export async function checkAllStripePayouts(checkAll = false) {
39
39
  stripeAccount: account.accountId,
40
40
  });
41
41
  await checker.checkSettlements(checkAll);
42
- }
43
- catch (e) {
42
+ } catch (e) {
44
43
  console.error(e);
45
44
  }
46
45
  }
@@ -63,8 +62,7 @@ export async function checkSettlements(checkAll = false) {
63
62
  const token = STAMHOOFD.MOLLIE_ORGANIZATION_TOKEN;
64
63
  if (!token) {
65
64
  console.error('Missing mollie organization token');
66
- }
67
- else {
65
+ } else {
68
66
  await checkMollieSettlementsFor(token, checkAll);
69
67
  }
70
68
 
@@ -77,19 +75,16 @@ export async function checkSettlements(checkAll = false) {
77
75
  for (const token of mollieTokens) {
78
76
  if (token.createdAt < new Date(2021, 8 /* september! */, 8)) {
79
77
  console.log('Skipped mollie token that is too old');
80
- }
81
- else {
78
+ } else {
82
79
  try {
83
80
  await token.refreshIfNeeded();
84
81
  await checkMollieSettlementsFor(token.accessToken, checkAll);
85
- }
86
- catch (e) {
82
+ } catch (e) {
87
83
  console.error(e);
88
84
  }
89
85
  }
90
86
  }
91
- }
92
- catch (e) {
87
+ } catch (e) {
93
88
  console.error(e);
94
89
  }
95
90
  }
@@ -135,22 +130,18 @@ export async function checkMollieSettlementsFor(token: string, checkAll = false)
135
130
  await updateSettlement(token, settlement);
136
131
  }
137
132
  }
138
- }
139
- else {
133
+ } else {
140
134
  console.error('Unreadable settlements');
141
135
  }
142
- }
143
- catch (e) {
136
+ } catch (e) {
144
137
  console.error(request.data);
145
138
  throw e;
146
139
  }
147
- }
148
- else {
140
+ } else {
149
141
  console.error('Failed to fetch settlements');
150
142
  console.error(request.data);
151
143
  }
152
- }
153
- catch (e) {
144
+ } catch (e) {
154
145
  console.error(e);
155
146
  }
156
147
  }
@@ -199,12 +190,10 @@ async function updateSettlement(token: string, settlement: MollieSettlement, fro
199
190
  console.log('Updated settlement of payment ' + payment.id);
200
191
  console.log(payment.settlement);
201
192
  }
202
- }
203
- else {
193
+ } else {
204
194
  console.log('Missing payment ' + mp.paymentId);
205
195
  }
206
- }
207
- else {
196
+ } else {
208
197
  // Probably a payment in a different system/platform
209
198
  // console.log("No mollie payment found for id "+mollie.id)
210
199
  }
@@ -214,8 +203,7 @@ async function updateSettlement(token: string, settlement: MollieSettlement, fro
214
203
  if (request.data._links.next) {
215
204
  await updateSettlement(token, settlement, molliePayments[molliePayments.length - 1].id);
216
205
  }
217
- }
218
- else {
206
+ } else {
219
207
  console.error(request.data);
220
208
  }
221
209
  }
@@ -5,7 +5,7 @@ import type { User } from '@stamhoofd/models';
5
5
  import { Organization, Platform, RateLimiter, Token } from '@stamhoofd/models';
6
6
  import { AsyncLocalStorage } from 'async_hooks';
7
7
 
8
- import type { Decoder} from '@simonbackx/simple-encoding';
8
+ import type { Decoder } from '@simonbackx/simple-encoding';
9
9
  import { AutoEncoder, field, StringDecoder } from '@simonbackx/simple-encoding';
10
10
  import { ApiUserRateLimits } from '@stamhoofd/structures';
11
11
  import { AdminPermissionChecker } from './AdminPermissionChecker.js';
@@ -156,8 +156,7 @@ export class ContextInstance {
156
156
  async setOptionalOrganizationScope(options?: { willAuthenticate?: boolean }) {
157
157
  try {
158
158
  return await this.setOrganizationScope(options);
159
- }
160
- catch (e) {
159
+ } catch (e) {
161
160
  if (isSimpleError(e) && e.hasCode('invalid_host')) {
162
161
  return null;
163
162
  }
@@ -199,11 +198,16 @@ export class ContextInstance {
199
198
  return organization;
200
199
  }
201
200
 
201
+ async setManualOrganizationScope(organization: Organization) {
202
+ this.organization = organization;
203
+ this.i18n.switchToLocale({ country: organization.address.country });
204
+ return organization;
205
+ }
206
+
202
207
  async optionalAuthenticate({ allowWithoutAccount = false }: { allowWithoutAccount?: boolean } = {}): Promise<{ user?: User }> {
203
208
  try {
204
209
  return await this.authenticate({ allowWithoutAccount });
205
- }
206
- catch (e) {
210
+ } catch (e) {
207
211
  if (e.code === 'not_authenticated') {
208
212
  // Do not allow to optional authenticate to inactive organizations
209
213
  if (this.organization && !this.organization.active) {
@@ -226,8 +230,7 @@ export class ContextInstance {
226
230
  try {
227
231
  const decoded = await DecodedRequest.fromRequest(this.request, undefined, undefined, AuthorizationPostBody as Decoder<AuthorizationPostBody>);
228
232
  header = decoded.body.header_authorization;
229
- }
230
- catch (e) {
233
+ } catch (e) {
231
234
  // Ignore: failed to read from body
232
235
  }
233
236
  }
@@ -307,8 +310,12 @@ export class ContextInstance {
307
310
  );
308
311
 
309
312
  // Load member of user
310
- // todo
313
+ await this.insecurelyAuthenticateAs(user);
314
+
315
+ return { user, token };
316
+ }
311
317
 
318
+ async insecurelyAuthenticateAs(user: User) {
312
319
  this.#auth = new AdminPermissionChecker(user, await Platform.getSharedPrivateStruct(), this.organization);
313
320
 
314
321
  if (this.organization && !this.organization.active) {
@@ -322,8 +329,6 @@ export class ContextInstance {
322
329
  });
323
330
  }
324
331
  }
325
-
326
- return { user, token };
327
332
  }
328
333
  }
329
334
 
@@ -38,8 +38,7 @@ export class CookieHelper {
38
38
  response.headers['set-cookie'] = [
39
39
  cookies,
40
40
  ];
41
- }
42
- else {
41
+ } else {
43
42
  if (!Array.isArray(currentCookies)) {
44
43
  currentCookies = [currentCookies.toString()];
45
44
  response.headers['set-cookie'] = currentCookies;
@@ -30,8 +30,7 @@ export async function resumeEmails() {
30
30
  await ContextInstance.startForUser(user, organization, async () => {
31
31
  await email.resumeSending();
32
32
  });
33
- }
34
- catch (e) {
33
+ } catch (e) {
35
34
  console.error('Error resuming email', email.id, e);
36
35
  }
37
36
  }
@@ -111,7 +111,7 @@ export class FileCache {
111
111
  throw new SimpleError({
112
112
  code: 'invalid_file',
113
113
  message: 'Invalid file',
114
- human: $t(`%Fn`),
114
+ human: $t(`%Fm`),
115
115
  statusCode: 400,
116
116
  });
117
117
  }
@@ -136,8 +136,7 @@ export class FileCache {
136
136
  let stat: fs.Stats;
137
137
  try {
138
138
  stat = await fs.promises.stat(filePath);
139
- }
140
- catch (e) {
139
+ } catch (e) {
141
140
  if (e.code == 'ENOENT') {
142
141
  throw new SimpleError({
143
142
  code: 'file_expired',
@@ -3,9 +3,9 @@ import type { FinancialSupportSettings, Organization as OrganizationStruct, Plat
3
3
 
4
4
  /**
5
5
  * Get the financial support settings from the platform if userMode is platform, or from the organization otherwise.
6
- * @param platform
6
+ * @param platform
7
7
  * @param getOrganization callback to prevent fetching the organization if not needed
8
- * @returns
8
+ * @returns
9
9
  */
10
10
  export async function getFinancialSupportSettingsAsync(platform: Platform | PlatformStruct, getOrganization: () => Promise<Organization | OrganizationStruct | null>): Promise<FinancialSupportSettings | null> {
11
11
  if (STAMHOOFD.userMode === 'platform') {
@@ -82,8 +82,7 @@ export class FlagMomentCleanup {
82
82
  ),
83
83
  )
84
84
  .fetch();
85
- }
86
- else {
85
+ } else {
87
86
  return await MemberResponsibilityRecord.select()
88
87
  .join(SQL.innerJoin(
89
88
  SQL.table(Organization.table))
@@ -43,8 +43,7 @@ export class ForwardHandler {
43
43
  }
44
44
  model.unsubscribedAll = true;
45
45
  await model.save();
46
- }
47
- else {
46
+ } else {
48
47
  console.error('[Unsubscribe] Received an unsubscribe request for unknown ID ' + id + ' from ' + from);
49
48
 
50
49
  // Forward
@@ -98,17 +97,14 @@ export class ForwardHandler {
98
97
  if (!organizationEmails) {
99
98
  if (STAMHOOFD.environment === 'test') {
100
99
  // ignore
101
- }
102
- else {
100
+ } else {
103
101
  console.error('Missing reply emails for organization ' + organization.id);
104
102
  }
105
103
  return doBounce();
106
- }
107
- else {
104
+ } else {
108
105
  defaultEmail = organizationEmails;
109
106
  }
110
- }
111
- else {
107
+ } else {
112
108
  return doBounce();
113
109
  }
114
110
 
@@ -123,8 +119,7 @@ export class ForwardHandler {
123
119
  if (body !== -1) {
124
120
  const endTag = parsed.html.indexOf('>', body);
125
121
  html = parsed.html.substring(0, endTag + 1) + '<p><i>' + Formatter.escapeHtml(extraDescription) + '<br><br></i></p>' + parsed.html.substring(endTag + 1);
126
- }
127
- else {
122
+ } else {
128
123
  html = '<p><i>' + Formatter.escapeHtml(extraDescription) + '<br><br></i></p>' + parsed.html;
129
124
  }
130
125
  }
@@ -9,13 +9,13 @@ export class GlobalHelper {
9
9
  await I18n.load();
10
10
  this.loadGlobalTranslateFunction();
11
11
  await FileSignService.load();
12
-
12
+
13
13
  MemberRecordStore.init();
14
-
14
+
15
15
  BalanceItemService.listen();
16
16
  }
17
17
 
18
- private static loadGlobalTranslateFunction() {
18
+ static loadGlobalTranslateFunction() {
19
19
  function getI18n() {
20
20
  return ContextInstance.optional?.i18n ?? new I18n(I18n.defaultLanguage, STAMHOOFD.fixedCountry ?? I18n.defaultCountry);
21
21
  }