@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
package/src/migrate.ts CHANGED
@@ -9,6 +9,9 @@ process.env.TZ = 'UTC';
9
9
 
10
10
  // Polyfill require.resolve, since import.meta.resolve is not supported by vitest
11
11
  import { createRequire } from 'node:module';
12
+ import { GlobalHelper } from './helpers/GlobalHelper.js';
13
+ import { I18n } from '@stamhoofd/backend-i18n/I18n';
14
+ import { QueryableModel } from '@stamhoofd/sql';
12
15
  const require = createRequire(import.meta.url);
13
16
 
14
17
  const emailPath = require.resolve('@stamhoofd/email');
@@ -26,13 +29,14 @@ const start = async () => {
26
29
 
27
30
  // Reload database so we are sure we are running on the correct database in the
28
31
  // environment
29
- await Database.reload({})
32
+ await Database.reload({});
30
33
 
31
34
  let killSignalReceived = false;
32
35
  const handler = () => {
33
36
  // Ignore
34
37
  console.error('Ignoring SIGTERM signal during migration');
35
38
  killSignalReceived = true;
39
+ QueryableModel.shutdownMigrations = true;
36
40
  };
37
41
 
38
42
  process.on('SIGTERM', handler);
@@ -50,15 +54,18 @@ const start = async () => {
50
54
 
51
55
  // External migrations
52
56
  if (!await Migration.runAll(path.dirname(modelsPath) + '/migrations')) {
53
- throw new Error('Migrations failed')
57
+ throw new Error('Migrations failed');
54
58
  }
55
59
  if (!await Migration.runAll(path.dirname(emailPath) + '/../migrations')) {
56
- throw new Error('Email migrations failed')
60
+ throw new Error('Email migrations failed');
57
61
  }
58
62
 
59
63
  // Internal
64
+ await I18n.load();
65
+ GlobalHelper.loadGlobalTranslateFunction();
66
+
60
67
  if (!await Migration.runAll(import.meta.dirname + '/migrations')) {
61
- throw new Error('Internal migrations failed')
68
+ throw new Error('Internal migrations failed');
62
69
  }
63
70
 
64
71
  if (killSignalReceived) {
@@ -67,7 +74,7 @@ const start = async () => {
67
74
  }
68
75
 
69
76
  // Reload database to prevent connection state leakage
70
- await Database.reload({})
77
+ await Database.reload({});
71
78
 
72
79
  process.off('SIGTERM', handler);
73
80
  process.off('SIGINT', handler);
@@ -1,5 +1,5 @@
1
1
  import { Migration } from '@simonbackx/simple-database';
2
- import { Organization, RegistrationPeriod } from '@stamhoofd/models';
2
+ import { Organization, Platform, RegistrationPeriod } from '@stamhoofd/models';
3
3
  import { Address } from '@stamhoofd/structures';
4
4
  import { Country } from '@stamhoofd/types/Country';
5
5
  import { Formatter } from '@stamhoofd/utility';
@@ -9,6 +9,10 @@ export default new Migration(async () => {
9
9
  return;
10
10
  }
11
11
 
12
+ if (STAMHOOFD.userMode !== 'platform') {
13
+ throw new Error('singleOrganization should never be combined with userMode organization');
14
+ }
15
+
12
16
  let organization = await Organization.getByID(STAMHOOFD.singleOrganization);
13
17
  if (organization) {
14
18
  console.log('Single organization already created.');
@@ -56,6 +60,11 @@ export default new Migration(async () => {
56
60
 
57
61
  await organization.save();
58
62
 
63
+ // Set as platform organization
64
+ const platform = await Platform.getForEditing();
65
+ platform.membershipOrganizationId = organization.id;
66
+ await platform.save();
67
+
59
68
  // Do something here
60
69
  return Promise.resolve();
61
70
  });
@@ -0,0 +1,139 @@
1
+ import { Migration } from '@simonbackx/simple-database';
2
+ import { Organization, Platform, RegistrationPeriod } from '@stamhoofd/models';
3
+ import { Address, Company, File, Image, PaymentMethod, Resolution } from '@stamhoofd/structures';
4
+ import { Country } from '@stamhoofd/types/Country';
5
+ import { Formatter } from '@stamhoofd/utility';
6
+ import { STPackageService } from '../services/STPackageService.js';
7
+
8
+ export default new Migration(async () => {
9
+ const platform = await Platform.getForEditing();
10
+ if (platform.membershipOrganizationId) {
11
+ console.log('Membership organization already created.');
12
+ return;
13
+ }
14
+
15
+ const registrationPeriod = STAMHOOFD.userMode === 'platform' ? ((await RegistrationPeriod.select().first(false)) ?? new RegistrationPeriod()) : new RegistrationPeriod();
16
+ if (!registrationPeriod.id) {
17
+ const s = Formatter.luxon();
18
+ const startDate = s.set({
19
+ day: 1,
20
+ month: 9,
21
+ hour: 0,
22
+ minute: 0,
23
+ second: 0,
24
+ millisecond: 0,
25
+ });
26
+ const endDate = s.set({
27
+ year: startDate.year + 1,
28
+ day: 31,
29
+ month: 8,
30
+ hour: 23,
31
+ minute: 59,
32
+ second: 59,
33
+ millisecond: 999,
34
+ });
35
+ registrationPeriod.startDate = startDate.toJSDate();
36
+ registrationPeriod.endDate = endDate.toJSDate();
37
+ }
38
+ await registrationPeriod.save();
39
+
40
+ console.log('Creating membership organization...');
41
+ const organization = new Organization();
42
+ organization.name = STAMHOOFD.platformName;
43
+ organization.uri = Formatter.slug(STAMHOOFD.platformName);
44
+ organization.periodId = registrationPeriod.id;
45
+ organization.address = Address.create({
46
+ street: '',
47
+ number: '',
48
+ postalCode: '',
49
+ city: 'Gent',
50
+ country: STAMHOOFD.fixedCountry ?? Country.Belgium,
51
+ });
52
+ organization.privateMeta.featureFlags = ['organization-receivable-balances'];
53
+
54
+ // Setup Codawood credentials if running Stamhoofd
55
+ if (STAMHOOFD.platformName === 'stamhoofd' && STAMHOOFD.userMode === 'organization') {
56
+ organization.id = '57aa0001-0000-4000-8000-000000000001';
57
+ organization.name = 'Stamhoofd';
58
+ organization.meta.companies = [
59
+ Company.create({
60
+ name: 'Codawood BV',
61
+ VATNumber: 'BE0747832683',
62
+ companyNumber: '0747832683',
63
+ address: Address.create({
64
+ street: 'Collegiebaan',
65
+ number: '54',
66
+ postalCode: '9230',
67
+ city: 'Wetteren',
68
+ country: Country.Belgium,
69
+ }),
70
+ administrationEmail: 'hallo@stamhoofd.be',
71
+ }),
72
+ ];
73
+
74
+ organization.address = organization.meta.companies[0].address!;
75
+ organization.meta.registrationPaymentConfiguration.enableMandates = true;
76
+ organization.meta.invoicesEnabled = true;
77
+ organization.meta.registrationPaymentConfiguration.paymentMethods = [
78
+ PaymentMethod.Bancontact,
79
+ PaymentMethod.iDEAL,
80
+ PaymentMethod.CreditCard,
81
+ ];
82
+
83
+ // Logo for invoices + normal icon
84
+ const horizontalLogo = new File({
85
+ id: 'logo',
86
+ size: 0,
87
+ server: 'https://files.stamhoofd.be',
88
+ path: 'fixtures/logo.svg',
89
+ });
90
+
91
+ organization.meta.horizontalLogo = Image.create({
92
+ source: horizontalLogo,
93
+ resolutions: [
94
+ new Resolution({
95
+ file: horizontalLogo,
96
+ width: 1650,
97
+ height: 340,
98
+ }),
99
+ ],
100
+ });
101
+
102
+ const squareLogo = new File({
103
+ id: 'square',
104
+ size: 0,
105
+ server: 'https://files.stamhoofd.be',
106
+ path: 'fixtures/logo-small.svg',
107
+ });
108
+
109
+ organization.meta.squareLogo = Image.create({
110
+ source: squareLogo,
111
+ resolutions: [
112
+ new Resolution({
113
+ file: squareLogo,
114
+ width: 1000,
115
+ height: 1000,
116
+ }),
117
+ ],
118
+ });
119
+
120
+ // Link a mollie token
121
+ }
122
+
123
+ await organization.save();
124
+
125
+ if (STAMHOOFD.userMode === 'organization') {
126
+ registrationPeriod.organizationId = organization.id;
127
+ await registrationPeriod.save();
128
+ }
129
+
130
+ // Set as platform organization
131
+ platform.membershipOrganizationId = organization.id;
132
+ await platform.save();
133
+
134
+ // Make sure default packages are active for this organization
135
+ await STPackageService.updateOrganizationPackages(organization.id);
136
+
137
+ // Do something here
138
+ return Promise.resolve();
139
+ });
@@ -1,6 +1,7 @@
1
1
  import { Migration } from '@simonbackx/simple-database';
2
2
  import { User } from '@stamhoofd/models';
3
3
  import { UserPermissions } from '@stamhoofd/structures';
4
+ import { SeedTools } from '../helpers/SeedTools.js';
4
5
 
5
6
  export default new Migration(async () => {
6
7
  if (STAMHOOFD.environment == 'test') {
@@ -8,42 +9,31 @@ export default new Migration(async () => {
8
9
  return;
9
10
  }
10
11
  process.stdout.write('\n');
11
- let c = 0;
12
- while (true) {
13
- const admins = await User.where({
14
- organizationPermissions: {
15
- value: null,
16
- sign: '!=',
17
- },
18
- organizationId: {
19
- value: null,
20
- sign: '!=',
21
- },
22
- }, { limit: 100 });
23
12
 
24
- for (const admin of admins) {
13
+ let realUpdate = 0;
14
+
15
+ const result = await SeedTools.loop({
16
+ batchSize: 1000,
17
+ query: User.select().whereNot('organizationPermissions', null).whereNot('organizationId', null),
18
+ useTransactionPerBatch: true,
19
+ action: async (admin: User) => {
25
20
  if (!admin.organizationPermissions || !admin.organizationId) {
26
- continue;
21
+ return;
27
22
  }
28
23
  const p = UserPermissions.create({});
29
24
  p.organizationPermissions.set(admin.organizationId, admin.organizationPermissions);
30
25
  admin.permissions = UserPermissions.limitedAdd(admin.permissions, p, admin.organizationId);
31
26
  admin.organizationPermissions = null;
32
- await admin.save();
33
- c++;
34
-
35
- if (c % 1000 === 0) {
36
- process.stdout.write('.');
27
+ if (await admin.save({
28
+ skipMarkSaved: true,
29
+ skipSendEvents: true,
30
+ })) {
31
+ realUpdate++;
37
32
  }
38
- if (c % 10000 === 0) {
39
- process.stdout.write('\n');
40
- }
41
- }
33
+ },
34
+ });
42
35
 
43
- if (admins.length === 0) {
44
- break;
45
- }
46
- }
36
+ console.log('Updated permissions of ' + realUpdate + ' users, looped ' + result.total + ' users');
47
37
 
48
38
  // Do something here
49
39
  return Promise.resolve();
@@ -1,6 +1,7 @@
1
- import type { RegistrationPeriod} from '@stamhoofd/models';
1
+ import type { RegistrationPeriod } from '@stamhoofd/models';
2
2
  import { DocumentTemplate, DocumentTemplateFactory, GroupFactory, OrganizationFactory, RegistrationPeriodFactory } from '@stamhoofd/models';
3
- import { migrateDocumentYears } from './1765896674-document-update-year.js';
3
+ import { migrateDocumentYears } from './1750090029-document-update-year.js';
4
+ import { Formatter } from '@stamhoofd/utility';
4
5
 
5
6
  describe('migration.document-update-year', () => {
6
7
  describe('should use most frequent year of groups', () => {
@@ -9,8 +10,8 @@ describe('migration.document-update-year', () => {
9
10
  }).create();
10
11
 
11
12
  const period1 = await new RegistrationPeriodFactory({
12
- startDate: new Date(2021, 0, 1),
13
- endDate: new Date(2021, 11, 31),
13
+ startDate: Formatter.luxon().set({ day: 1, month: 1, year: 2021 }).toJSDate(),
14
+ endDate: Formatter.luxon().set({ day: 31, month: 12, year: 2021 }).toJSDate(),
14
15
  organization,
15
16
  }).create();
16
17
 
@@ -18,8 +19,8 @@ describe('migration.document-update-year', () => {
18
19
  await organization.save();
19
20
 
20
21
  const period2 = await new RegistrationPeriodFactory({
21
- startDate: new Date(2019, 0, 1),
22
- endDate: new Date(2019, 11, 31),
22
+ startDate: Formatter.luxon().set({ day: 1, month: 1, year: 2019 }).toJSDate(),
23
+ endDate: Formatter.luxon().set({ day: 31, month: 12, year: 2019 }).toJSDate(),
23
24
  organization,
24
25
  }).create();
25
26
 
@@ -32,9 +33,9 @@ describe('migration.document-update-year', () => {
32
33
  };
33
34
 
34
35
  // groups
35
- const group1 = await createGroup(new Date(2021, 0, 1), new Date(2021, 11, 31), period1);
36
- const group2 = await createGroup(new Date(2021, 0, 1), new Date(2021, 11, 31), period1);
37
- const group3 = await createGroup(new Date(2019, 0, 1), new Date(2019, 11, 31), period2);
36
+ const group1 = await createGroup(Formatter.luxon().set({ day: 1, month: 1, year: 2021 }).toJSDate(), Formatter.luxon().set({ day: 31, month: 12, year: 2021 }).toJSDate(), period1);
37
+ const group2 = await createGroup(Formatter.luxon().set({ day: 1, month: 1, year: 2021 }).toJSDate(), Formatter.luxon().set({ day: 31, month: 12, year: 2021 }).toJSDate(), period1);
38
+ const group3 = await createGroup(Formatter.luxon().set({ day: 1, month: 1, year: 2019 }).toJSDate(), Formatter.luxon().set({ day: 31, month: 12, year: 2019 }).toJSDate(), period2);
38
39
 
39
40
  // document created in 2021
40
41
  const document1 = await new DocumentTemplateFactory({
@@ -42,7 +43,7 @@ describe('migration.document-update-year', () => {
42
43
  year: 0,
43
44
  }).create();
44
45
 
45
- document1.createdAt = new Date(2022, 0, 1);
46
+ document1.createdAt = Formatter.luxon().set({ day: 1, month: 1, year: 2022 }).toJSDate();
46
47
  await document1.save();
47
48
 
48
49
  // document created in 2020
@@ -51,7 +52,7 @@ describe('migration.document-update-year', () => {
51
52
  year: 0,
52
53
  }).create();
53
54
 
54
- document2.createdAt = new Date(2021, 0, 1);
55
+ document2.createdAt = Formatter.luxon().set({ day: 1, month: 1, year: 2021 }).toJSDate();
55
56
  await document2.save();
56
57
 
57
58
  // document created in 2019
@@ -60,7 +61,7 @@ describe('migration.document-update-year', () => {
60
61
  year: 0,
61
62
  }).create();
62
63
 
63
- document3.createdAt = new Date(2020, 0, 1);
64
+ document3.createdAt = Formatter.luxon().set({ day: 1, month: 1, year: 2020 }).toJSDate();
64
65
  await document3.save();
65
66
 
66
67
  // act
@@ -74,7 +75,7 @@ describe('migration.document-update-year', () => {
74
75
  // take most frequent year and prefer date of document creation
75
76
  expect(updatedDocument1?.year).toBe(2021);
76
77
  expect(updatedDocument2?.year).toBe(2021);
77
- expect(updatedDocument3?.year).toBe(2021);
78
+ expect(updatedDocument3?.year).toBe(2020); // maxed at creation year
78
79
  });
79
80
 
80
81
  test('groups overlapping period', async () => {
@@ -82,8 +83,8 @@ describe('migration.document-update-year', () => {
82
83
  }).create();
83
84
 
84
85
  const period1 = await new RegistrationPeriodFactory({
85
- startDate: new Date(2021, 0, 1),
86
- endDate: new Date(2021, 11, 31),
86
+ startDate: Formatter.luxon().set({ day: 1, month: 1, year: 2021 }).toJSDate(),
87
+ endDate: Formatter.luxon().set({ day: 31, month: 12, year: 2021 }).toJSDate(),
87
88
  organization,
88
89
  }).create();
89
90
 
@@ -91,14 +92,14 @@ describe('migration.document-update-year', () => {
91
92
  await organization.save();
92
93
 
93
94
  const period2 = await new RegistrationPeriodFactory({
94
- startDate: new Date(2020, 0, 1),
95
- endDate: new Date(2020, 11, 31),
95
+ startDate: Formatter.luxon().set({ day: 1, month: 1, year: 2020 }).toJSDate(),
96
+ endDate: Formatter.luxon().set({ day: 31, month: 12, year: 2020 }).toJSDate(),
96
97
  organization,
97
98
  }).create();
98
99
 
99
100
  const period3 = await new RegistrationPeriodFactory({
100
- startDate: new Date(2019, 0, 1),
101
- endDate: new Date(2019, 11, 31),
101
+ startDate: Formatter.luxon().set({ day: 1, month: 1, year: 2019 }).toJSDate(),
102
+ endDate: Formatter.luxon().set({ day: 31, month: 12, year: 2019 }).toJSDate(),
102
103
  organization,
103
104
  }).create();
104
105
 
@@ -111,9 +112,9 @@ describe('migration.document-update-year', () => {
111
112
  };
112
113
 
113
114
  // groups
114
- const group1 = await createGroup(new Date(2020, 6, 1), new Date(2021, 5, 30), period1);
115
- const group2 = await createGroup(new Date(2020, 7, 5), new Date(2021, 4, 3), period1);
116
- const group3 = await createGroup(new Date(2018, 5, 1), new Date(2019, 10, 14), period3);
115
+ const group1 = await createGroup(Formatter.luxon().set({ day: 1, month: 7, year: 2020 }).toJSDate(), Formatter.luxon().set({ day: 30, month: 6, year: 2021 }).toJSDate(), period1);
116
+ const group2 = await createGroup(Formatter.luxon().set({ day: 5, month: 8, year: 2020 }).toJSDate(), Formatter.luxon().set({ day: 3, month: 5, year: 2021 }).toJSDate(), period1);
117
+ const group3 = await createGroup(Formatter.luxon().set({ day: 1, month: 6, year: 2018 }).toJSDate(), Formatter.luxon().set({ day: 14, month: 11, year: 2019 }).toJSDate(), period3);
117
118
 
118
119
  // document created in 2021
119
120
  const document1 = await new DocumentTemplateFactory({
@@ -121,7 +122,7 @@ describe('migration.document-update-year', () => {
121
122
  year: 0,
122
123
  }).create();
123
124
 
124
- document1.createdAt = new Date(2022, 0, 1);
125
+ document1.createdAt = Formatter.luxon().set({ day: 1, month: 1, year: 2022 }).toJSDate();
125
126
  await document1.save();
126
127
 
127
128
  // document created in 2020
@@ -130,7 +131,7 @@ describe('migration.document-update-year', () => {
130
131
  year: 0,
131
132
  }).create();
132
133
 
133
- document2.createdAt = new Date(2021, 0, 1);
134
+ document2.createdAt = Formatter.luxon().set({ day: 1, month: 1, year: 2021 }).toJSDate();
134
135
  await document2.save();
135
136
 
136
137
  // document created in 2019
@@ -139,7 +140,7 @@ describe('migration.document-update-year', () => {
139
140
  year: 0,
140
141
  }).create();
141
142
 
142
- document3.createdAt = new Date(2020, 0, 1);
143
+ document3.createdAt = Formatter.luxon().set({ day: 1, month: 1, year: 2020 }).toJSDate();
143
144
  await document3.save();
144
145
 
145
146
  // act
@@ -165,7 +166,7 @@ describe('migration.document-update-year', () => {
165
166
  year: 0,
166
167
  }).create();
167
168
 
168
- document.createdAt = new Date(2025, 0, 1);
169
+ document.createdAt = Formatter.luxon().set({ day: 1, month: 1, year: 2025 }).toJSDate();
169
170
  await document.save();
170
171
 
171
172
  // act
@@ -0,0 +1,103 @@
1
+ import { Migration } from '@simonbackx/simple-database';
2
+ import { DocumentTemplate, Group } from '@stamhoofd/models';
3
+ import { SQL } from '@stamhoofd/sql';
4
+ import { Formatter } from '@stamhoofd/utility';
5
+ import { SeedTools } from '../helpers/SeedTools.js';
6
+
7
+ export default new Migration(async () => {
8
+ if (STAMHOOFD.platformName.toLowerCase() !== 'stamhoofd') {
9
+ console.log('skipped for platform (only runs for Stamhoofd): ' + STAMHOOFD.platformName);
10
+ return;
11
+ }
12
+
13
+ process.stdout.write('\n');
14
+ console.log('Start updating year of document templates.');
15
+ await migrateDocumentYears();
16
+
17
+ return Promise.resolve();
18
+ });
19
+
20
+ export async function migrateDocumentYears() {
21
+ let realUpdate = 0;
22
+ const result = await SeedTools.loop({
23
+ query: DocumentTemplate.select(),
24
+ batchSize: 100,
25
+ useTransactionPerBatch: true,
26
+ action: async (document: DocumentTemplate) => {
27
+ // check
28
+ if (!document.year) {
29
+ // by default use the year before creation
30
+ let year: number = document.createdAt.getFullYear() - 1;
31
+
32
+ const groups = document.privateSettings.groups;
33
+ const groupIds: string[] = [...new Set(groups.map(g => g.group.id))];
34
+
35
+ if (groupIds.length > 0) {
36
+ const query = Group.select().where(SQL.where('id', groupIds));
37
+ const groupModels = await query.fetch();
38
+
39
+ // count the number of groups per year
40
+ const yearMap = new Map<number, number>();
41
+
42
+ for (const group of groups) {
43
+ const model = groupModels.find(g => g.id === group.group.id);
44
+ if (!model) {
45
+ continue;
46
+ }
47
+
48
+ // Note: we need to use the cycle settings to find the correct start and end dates
49
+ const info = model.settings.cycleSettings.get(group.cycle);
50
+ if (info && group.cycle !== model.cycle) {
51
+ if (info.startDate) {
52
+ const y = Formatter.luxon(info.startDate).year;
53
+
54
+ const count = yearMap.get(y) ?? 0;
55
+ yearMap.set(y, count + 1);
56
+ } else {
57
+ // Missing info: don't use the wrong year
58
+ }
59
+ } else {
60
+ const y = Formatter.luxon(model.settings.startDate).year;
61
+ const count = yearMap.get(y) ?? 0;
62
+ yearMap.set(y, count + 1);
63
+ }
64
+ }
65
+
66
+ // find the year with the highest count
67
+ let topYear = 0;
68
+ let topCount = 0;
69
+
70
+ for (const [year, count] of yearMap) {
71
+ if (count > topCount) {
72
+ topYear = year;
73
+ topCount = count;
74
+ }
75
+ }
76
+
77
+ // use the year with the highest count
78
+ if (topCount > 0) {
79
+ year = topYear;
80
+ }
81
+ }
82
+
83
+ const creationYear = Formatter.luxon(document.createdAt).year;
84
+ if (creationYear < year) {
85
+ // This should never log: if this logs we should fix the migration
86
+ console.error('FIXME: Unexpected document year ' + year + ' which is larger than creation year ' + creationYear + ' for ' + document.id);
87
+ year = creationYear;
88
+ }
89
+
90
+ document.year = year;
91
+ if (await document.save({
92
+ forceSave: true,
93
+ skipMarkSaved: true,
94
+ skipSendEvents: true,
95
+ })) {
96
+ realUpdate += 1;
97
+ }
98
+ }
99
+ },
100
+ });
101
+
102
+ console.log('Migrated ' + realUpdate + ' document templates of ' + result.total + ' looped document templates');
103
+ };
@@ -1,9 +1,10 @@
1
1
  import { column, Migration } from '@simonbackx/simple-database';
2
2
  import { AutoEncoder, field } from '@simonbackx/simple-encoding';
3
- import { Organization, Webshop } from '@stamhoofd/models';
3
+ import { Organization } from '@stamhoofd/models';
4
4
  import { QueryableModel, SQL } from '@stamhoofd/sql';
5
5
  import { DataPermissionsSettings, FinancialSupportSettings, Version } from '@stamhoofd/structures';
6
6
  import { v4 as uuidv4 } from 'uuid';
7
+ import { SeedTools } from '../helpers/SeedTools.js';
7
8
 
8
9
  class OldOrganizationRecordsConfiguration extends AutoEncoder {
9
10
  /**
@@ -20,10 +21,10 @@ class OldOrganizationRecordsConfiguration extends AutoEncoder {
20
21
  }
21
22
 
22
23
  class OldOrganizationMetaData extends AutoEncoder {
23
- @field({
24
- decoder: OldOrganizationRecordsConfiguration,
24
+ @field({
25
+ decoder: OldOrganizationRecordsConfiguration,
25
26
  version: 53,
26
- defaultValue: () => OldOrganizationRecordsConfiguration.create({})
27
+ defaultValue: () => OldOrganizationRecordsConfiguration.create({}),
27
28
  })
28
29
  recordsConfiguration: OldOrganizationRecordsConfiguration = OldOrganizationRecordsConfiguration.create({});
29
30
  }
@@ -33,9 +34,9 @@ export class OldOrganization extends QueryableModel {
33
34
  static table = 'organizations';
34
35
 
35
36
  @column({
36
- primary: true, type: 'string', beforeSave(value) {
37
- return value ?? uuidv4();
38
- }
37
+ primary: true, type: 'string', beforeSave(value) {
38
+ return value ?? uuidv4();
39
+ },
39
40
  })
40
41
  id!: string;
41
42
 
@@ -47,33 +48,33 @@ export class OldOrganization extends QueryableModel {
47
48
  }
48
49
 
49
50
  export async function startRecordsConfigurationMigration() {
50
-
51
- // migrate recordsConfiguration of organizations
52
- for await (const oldOrganization of OldOrganization.select()
53
- // prevent migrating same organizations twice if something goes wrong
54
- .where(SQL.jsonValue(SQL.column('meta'), '$.version'), '<', Version)
55
- .all()) {
56
- const oldFinancialSupport = oldOrganization.meta.recordsConfiguration.financialSupport;
57
- const oldDataPermission = oldOrganization.meta.recordsConfiguration.dataPermission;
58
-
59
- if (oldFinancialSupport || oldDataPermission) {
60
- const newOrganization = await Organization.getByID(oldOrganization.id);
61
-
62
- if (!newOrganization) {
63
- throw new Error('Organization with id ' + oldOrganization.id + ' not found');
51
+ const result = await SeedTools.loop({
52
+ batchSize: 100,
53
+ query: OldOrganization.select().where(SQL.jsonValue(SQL.column('meta'), '$.version'), '<', Version),
54
+ useTransactionPerBatch: true,
55
+ action: async (oldOrganization: OldOrganization) => {
56
+ const oldFinancialSupport = oldOrganization.meta.recordsConfiguration.financialSupport;
57
+ const oldDataPermission = oldOrganization.meta.recordsConfiguration.dataPermission;
58
+
59
+ if (oldFinancialSupport || oldDataPermission) {
60
+ const newOrganization = await Organization.getByID(oldOrganization.id);
61
+
62
+ if (!newOrganization) {
63
+ throw new Error('Organization with id ' + oldOrganization.id + ' not found');
64
+ }
65
+
66
+ newOrganization.meta.financialSupport = oldFinancialSupport;
67
+ newOrganization.meta.dataPermission = oldDataPermission;
68
+
69
+ await newOrganization.save({
70
+ skipMarkSaved: true,
71
+ skipSendEvents: true,
72
+ });
64
73
  }
74
+ },
75
+ });
65
76
 
66
- newOrganization.meta.financialSupport = oldFinancialSupport;
67
- newOrganization.meta.dataPermission = oldDataPermission;
68
-
69
- await newOrganization.save();
70
- }
71
- }
72
-
73
- // migrate recordsConfiguration of webshops
74
- for await (const webshop of Webshop.select().all()) {
75
- await webshop.save();
76
- }
77
+ console.log('Succesfully migrated financialSupport and dataPermissions for ' + result.total + ' organizations');
77
78
  }
78
79
 
79
80
  export default new Migration(async () => {