@stamhoofd/backend 2.120.6 → 2.122.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/output-2.txt +1 -0
  2. package/output.txt +1 -0
  3. package/package.json +70 -53
  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 +46 -0
  8. package/src/audit-logs/init.ts +9 -1
  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 +7 -0
  19. package/src/crons/invoices.ts +160 -0
  20. package/src/crons/members-fees.ts +50 -0
  21. package/src/crons/mollie-chargebacks.ts +86 -0
  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 +54 -74
  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 +87 -46
  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 +51 -0
  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 +32 -13
  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 +38 -33
  122. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsCountEndpoint.ts +45 -0
  123. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.test.ts +494 -0
  124. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.ts +213 -0
  125. package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.test.ts +404 -0
  126. package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.ts +167 -0
  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 +19 -6
  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/{global → organization/dashboard}/billing/DeactivatePackageEndpoint.ts +4 -9
  142. package/src/endpoints/organization/dashboard/billing/DeleteOrganizationMandateEndpoint.ts +62 -0
  143. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceCollectionEndpoint.ts +56 -0
  144. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceEndpoint.ts +41 -18
  145. package/src/endpoints/organization/dashboard/billing/GetOrganizationMandatesEndpoint.ts +64 -0
  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 +12 -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 +311 -0
  152. package/src/endpoints/organization/dashboard/billing/PatchOrganizationMandatesEndpoint.ts +94 -0
  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 +15 -4
  168. package/src/endpoints/organization/dashboard/invoices/PatchInvoicesEndpoint.ts +11 -2
  169. package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +8 -8
  170. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +10 -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 +67 -20
  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 +24 -17
  185. package/src/endpoints/organization/dashboard/receivable-balances/ChargeReceivableBalancesEndpoint.ts +134 -0
  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 +32 -22
  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 +29 -8
  215. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +21 -28
  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 +15 -13
  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 +28 -50
  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 +60 -65
  246. package/src/helpers/AuthenticatedStructures.ts +153 -51
  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 +21 -0
  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 +741 -0
  268. package/src/helpers/RecordAnswerHelper.ts +116 -0
  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 +15 -38
  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 +11 -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/migrations/1750090030-records-configuration.ts +92 -0
  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 +95 -27
  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/1779121239-default-invoice-email-template.sql +3 -0
  300. package/src/migrations/1779121240-invoice-email-template.sql +6 -0
  301. package/src/migrations/1779986893-default-payment-failed-email-templates.sql +4 -0
  302. package/src/migrations/1780578166-convert-legacy-billing.ts +13 -0
  303. package/src/{seeds/1755876819-remove-duplicate-members.ts → migrations/1780665426-remove-duplicate-members.ts} +23 -4
  304. package/src/migrations/1780933598-document-groups.ts +88 -0
  305. package/src/migrations/1781692342-balance-item-relations.ts +13 -0
  306. package/src/migrations/1781857866-platform-admins.ts +103 -0
  307. package/src/migrations/1781857867-rm-old-platform-admins.ts +25 -0
  308. package/src/seeds/0000000001-throw.ts +5 -0
  309. package/src/seeds/1760702452-update-balance-price-paid.ts +19 -0
  310. package/src/seeds/1760702453-update-balance-invoiced.ts +19 -0
  311. package/src/seeds/1760702454-update-cached-outstanding-balance-from-items.ts +51 -14
  312. package/src/seeds/1773754928-force-save-members.ts +41 -8
  313. package/src/seeds/1780665427-schedule-stock-updates.ts +45 -0
  314. package/src/seeds/1780665428-group-update-occupancy.ts +31 -0
  315. package/src/seeds/1780915001-fill-payment-customer.ts +70 -0
  316. package/src/seeds/1780915002-update-orders.ts +39 -0
  317. package/src/seeds/1782047708-organization-company-address.ts +44 -0
  318. package/src/seeds-temporary/1769088653-uitpas-status.ts +1 -2
  319. package/src/seeds-temporary/1780416000-migrate-audit-log-legacy-enums.test.ts +69 -0
  320. package/src/seeds-temporary/1780416000-migrate-audit-log-legacy-enums.ts +85 -0
  321. package/src/services/AuditLogService.test.ts +51 -0
  322. package/src/services/AuditLogService.ts +45 -0
  323. package/src/services/BalanceItemService.ts +148 -55
  324. package/src/services/CpuService.ts +3 -6
  325. package/src/services/DatabaseCollationService.test.ts +1 -2
  326. package/src/services/DocumentService.ts +1 -2
  327. package/src/services/EventNotificationService.ts +1 -1
  328. package/src/services/FileSignService.ts +2 -4
  329. package/src/services/InvoicePdfService.ts +286 -0
  330. package/src/services/InvoiceService.ts +330 -77
  331. package/src/services/InvoiceXMLService.ts +424 -0
  332. package/src/services/MemberNumberService.ts +6 -11
  333. package/src/services/MemberRecordStore.ts +8 -10
  334. package/src/services/MollieService.ts +530 -0
  335. package/src/services/PaymentMandateService.ts +214 -0
  336. package/src/services/PaymentReallocationService.test.ts +1 -1
  337. package/src/services/PaymentReallocationService.ts +7 -9
  338. package/src/services/PaymentService.ts +820 -328
  339. package/src/services/PlatformMembershipService.ts +5 -9
  340. package/src/services/ReferralService.ts +223 -0
  341. package/src/services/RegistrationService.ts +125 -54
  342. package/src/services/SSOService.test.ts +119 -0
  343. package/src/services/SSOService.ts +56 -49
  344. package/src/services/STPackageService.ts +97 -68
  345. package/src/services/UniqueMemberNumberService.ts +69 -0
  346. package/src/services/UniqueUserService.ts +3 -6
  347. package/src/services/VATService.ts +85 -0
  348. package/src/services/data/invoice.hbs.html +686 -0
  349. package/src/services/uitpas/PassholderEndpoints.ts +3 -6
  350. package/src/services/uitpas/UitpasService.ts +6 -10
  351. package/src/services/uitpas/checkUitpasNumbers.ts +2 -4
  352. package/src/services/uitpas/getSocialTariffForUitpasNumbers.ts +3 -6
  353. package/src/services/uitpas/searchUitpasEvents.ts +1 -2
  354. package/src/sql-filters/audit-logs.ts +1 -1
  355. package/src/sql-filters/balance-item-payments.ts +1 -1
  356. package/src/sql-filters/balance-items.ts +1 -1
  357. package/src/sql-filters/base-registration-filter-compilers.ts +5 -33
  358. package/src/sql-filters/document-templates.ts +1 -1
  359. package/src/sql-filters/documents.ts +1 -1
  360. package/src/sql-filters/email-recipients.ts +1 -1
  361. package/src/sql-filters/emails.ts +1 -1
  362. package/src/sql-filters/event-notifications.ts +1 -1
  363. package/src/sql-filters/events.ts +6 -1
  364. package/src/sql-filters/groups.ts +16 -1
  365. package/src/sql-filters/invoiced-balance-items.ts +1 -1
  366. package/src/sql-filters/invoices.ts +1 -1
  367. package/src/sql-filters/member-responsibility-records.ts +1 -1
  368. package/src/sql-filters/members.ts +1 -1
  369. package/src/sql-filters/orders.ts +4 -4
  370. package/src/sql-filters/organization-registration-periods.ts +1 -1
  371. package/src/sql-filters/organizations.ts +1 -1
  372. package/src/sql-filters/payments.ts +5 -0
  373. package/src/sql-filters/platform-memberships.ts +3 -3
  374. package/src/sql-filters/receivable-balances.ts +1 -1
  375. package/src/sql-filters/registration-invitations.ts +90 -0
  376. package/src/sql-filters/registration-periods.ts +1 -1
  377. package/src/sql-filters/registrations.ts +1 -1
  378. package/src/sql-filters/tickets.ts +1 -1
  379. package/src/sql-filters/users.ts +1 -1
  380. package/src/sql-sorters/groups.ts +23 -0
  381. package/src/sql-sorters/platform-memberships.ts +16 -16
  382. package/src/sql-sorters/registration-invitations.ts +36 -0
  383. package/tests/actions/patchOrganizationMember.ts +1 -1
  384. package/tests/actions/patchUserMember.ts +1 -1
  385. package/tests/assertions/assertBalances.ts +6 -12
  386. package/tests/e2e/api-rate-limits.test.ts +12 -24
  387. package/tests/e2e/bundle-discounts.test.ts +4 -1
  388. package/tests/e2e/charge-members.test.ts +13 -11
  389. package/tests/e2e/documents.test.ts +4 -1
  390. package/tests/e2e/register.test.ts +7 -9
  391. package/tests/e2e/stock.test.ts +4 -3
  392. package/tests/e2e/tickets.test.ts +1 -1
  393. package/tests/helpers/MollieMocker.ts +462 -0
  394. package/tests/helpers/PayconiqMocker.ts +138 -45
  395. package/tests/helpers/StripeMocker.ts +9 -6
  396. package/tests/helpers/index.ts +4 -0
  397. package/tests/init/initAdmin.ts +2 -2
  398. package/tests/init/initBundleDiscount.ts +1 -1
  399. package/tests/init/initMembershipOrganization.ts +13 -0
  400. package/tests/init/initPermissionRole.ts +3 -4
  401. package/tests/vitest.global.setup.ts +1 -1
  402. package/vitest.config.js +7 -0
  403. package/.nvmrc +0 -1
  404. package/src/endpoints/global/billing/ActivatePackagesEndpoint.ts +0 -216
  405. package/src/helpers/GroupBuilder.ts +0 -418
  406. package/src/seeds/0000000000-example.ts +0 -11
  407. package/src/seeds/1722256498-group-update-occupancy.ts +0 -52
  408. package/src/seeds/1726572303-schedule-stock-updates.ts +0 -52
  409. package/src/seeds/1726847064-setup-steps.ts +0 -16
  410. package/src/seeds/1728928974-update-cached-outstanding-balance-from-items.ts +0 -31
  411. package/src/seeds/1729253172-update-orders.ts +0 -21
  412. package/src/seeds/1733319079-fill-paying-organization-ids.ts +0 -68
  413. package/src/seeds/1733748412-update-deleted-order-numbers.ts +0 -109
  414. package/src/seeds/1733994455-balance-item-status-open.ts +0 -30
  415. package/src/seeds/1740046783-update-membership.ts +0 -17
  416. package/src/seeds/1741008870-fix-auditlog-description.ts +0 -50
  417. package/src/seeds/1741011468-fix-auditlog-description-uft16.ts +0 -88
  418. package/src/seeds/1741268179-fix-group-dates-of-events.ts +0 -32
  419. package/src/seeds/1750090030-records-configuration.ts +0 -26
  420. package/src/seeds/1751445358-upload-email-attachments.ts +0 -106
  421. package/src/seeds/1755532883-update-email-sender-ids.ts +0 -47
  422. package/src/seeds/1755790070-fill-email-recipient-errors.ts +0 -96
  423. package/src/seeds/1756115432-remove-old-drafts.ts +0 -16
  424. package/src/seeds/1756115433-fill-email-recipient-organization-id.ts +0 -30
  425. package/src/seeds/1756303697-update-email-counts.ts +0 -76
  426. package/src/seeds/1761665607-sync-member-users.ts +0 -59
  427. package/src/seeds/1765896674-document-update-year.ts +0 -66
  428. /package/src/{seeds → migrations}/0000000001-development-user.ts +0 -0
  429. /package/src/{seeds → migrations}/0000000002-clear-stamhoofd-email-templates.ts +0 -0
  430. /package/src/{seeds → migrations}/0000000003-default-email-templates.ts +0 -0
  431. /package/src/{seeds → migrations}/1752848561-groups-registration-periods.test.ts +0 -0
  432. /package/src/{seeds → migrations}/1766150402-document-published-at.test.ts +0 -0
  433. /package/src/{seeds → migrations}/1766150402-document-published-at.ts +0 -0
  434. /package/src/{seeds → migrations}/data/default-email-templates.sql +0 -0
@@ -0,0 +1,530 @@
1
+ import type { Mandate, Payment as MolliePaymentType } from '@mollie/api-client';
2
+ import { ApiMode, createMollieClient, MandateMethod, MandateStatus, PaymentMethod as molliePaymentMethod, PaymentStatus as molliePaymentStatus, OnboardingStatus, ProfileStatus, SequenceType } from '@mollie/api-client';
3
+ import { SimpleError } from '@simonbackx/simple-errors';
4
+ import type { Payment, User } from '@stamhoofd/models';
5
+ import type { Organization } from '@stamhoofd/models';
6
+ import { MolliePayment, MollieToken, Platform } from '@stamhoofd/models';
7
+ import type { PaymentCustomer } from '@stamhoofd/structures';
8
+ import { MollieOnboarding, MollieProfile, MollieProfileMode, MollieProfileStatus, MollieStatus, PaymentMethod, PaymentMethodHelper, PaymentProvider, PaymentStatus } from '@stamhoofd/structures';
9
+ import { PaymentMandate, PaymentMandateDetails, PaymentMandateStatus, PaymentMandateType } from '@stamhoofd/structures/PaymentMandate.js';
10
+ import { Formatter } from '@stamhoofd/utility';
11
+ import { DateTime } from 'luxon';
12
+ import { Context } from '../helpers/Context.js';
13
+
14
+ export class MollieService {
15
+ client: ReturnType<typeof createMollieClient>;
16
+ sellingOrganization: Organization;
17
+ createdAt: Date;
18
+
19
+ private constructor({ sellingOrganization, accessToken }: { sellingOrganization: Organization; accessToken: string }) {
20
+ this.sellingOrganization = sellingOrganization;
21
+ this.client = createMollieClient({ accessToken });
22
+ this.createdAt = new Date();
23
+ }
24
+
25
+ static #cachedServices: Map<string, MollieService> = new Map();
26
+
27
+ /**
28
+ * Cached instances can be used for maximum 30 seconds
29
+ */
30
+ isOutdated() {
31
+ return this.createdAt.getTime() < Date.now() - 30_000;
32
+ }
33
+
34
+ static async create({ sellingOrganization }: { sellingOrganization: Organization }) {
35
+ const cached = this.#cachedServices.get(sellingOrganization.id);
36
+ if (cached && !cached.isOutdated()) {
37
+ return cached;
38
+ }
39
+ const token = await MollieToken.getTokenFor(sellingOrganization.id);
40
+ if (!token) {
41
+ if (cached) {
42
+ this.#cachedServices.delete(sellingOrganization.id);
43
+ }
44
+ return null;
45
+ }
46
+ const service = new MollieService({ sellingOrganization, accessToken: await token.getAccessToken() });
47
+ this.#cachedServices.set(sellingOrganization.id, service);
48
+ return service;
49
+ }
50
+
51
+ /**
52
+ * Set initial onboarding values + enable bancontact
53
+ */
54
+ async setupOnboarding() {
55
+ // Submit onboarding data
56
+ this.sellingOrganization.privateMeta.mollieOnboarding = await this.getOnboardingStatus();
57
+
58
+ if (this.sellingOrganization.privateMeta.mollieOnboarding && this.sellingOrganization.privateMeta.mollieOnboarding.status === MollieStatus.NeedsData) {
59
+ try {
60
+ await this.client.onboarding.submit({
61
+ organization: {
62
+ name: this.sellingOrganization.name,
63
+ address: {
64
+ streetAndNumber: this.sellingOrganization.address.street + ' ' + this.sellingOrganization.address.number,
65
+ postalCode: this.sellingOrganization.address.postalCode,
66
+ city: this.sellingOrganization.address.city,
67
+ country: this.sellingOrganization.address.country,
68
+ },
69
+
70
+ vatRegulation: 'shifted',
71
+ },
72
+ profile: {
73
+ name: this.sellingOrganization.name + ' via Stamhoofd',
74
+ description: $t(`%x1`),
75
+ categoryCode: 8398,
76
+ },
77
+ });
78
+ } catch (e) {
79
+ console.error('Failed to submit onboarding data', e);
80
+ }
81
+ }
82
+ }
83
+
84
+ #verifiedCustomerIds: Set<string> = new Set();
85
+
86
+ /**
87
+ * Gets the customer id for a given payingOrganization or user.
88
+ * If no customer exists, it will create a new mollie customer if customer (payment customer) is set as parameter
89
+ */
90
+ async getCustomerId({ payingOrganization, user, customer }: {
91
+ payingOrganization: Organization | null;
92
+ user: User | null;
93
+
94
+ /**
95
+ * Required to be able to create a new customer
96
+ */
97
+ customer?: PaymentCustomer;
98
+ }): Promise<string | null> {
99
+ if (!payingOrganization) {
100
+ // Not yet supported for users
101
+ return null;
102
+ }
103
+
104
+ if (this.sellingOrganization.id !== (await Platform.getShared()).membershipOrganizationId) {
105
+ // Not yet supported
106
+ return null;
107
+ }
108
+
109
+ if (payingOrganization.serverMeta.mollieCustomerId) {
110
+ const customerId = payingOrganization.serverMeta.mollieCustomerId;
111
+ if (this.#verifiedCustomerIds.has(customerId)) {
112
+ return customerId;
113
+ }
114
+
115
+ // check still valid
116
+ try {
117
+ const c = await this.client.customers.get(customerId, { testmode: this.testMode });
118
+
119
+ if ((c.mode === ApiMode.test) === this.testMode) {
120
+ this.#verifiedCustomerIds.add(customerId);
121
+ return customerId;
122
+ }
123
+ } catch (e) {
124
+ console.error('Error getting customer', e);
125
+ // Customer is not valid anymore, we need to create a new one
126
+ }
127
+ }
128
+
129
+ if (!customer) {
130
+ // No existing customer exists
131
+ // won't create a new one if customer is not set
132
+ return null;
133
+ }
134
+
135
+ const mollieCustomer = await this.client.customers.create({
136
+ name: payingOrganization.name,
137
+ email: customer.email ?? undefined,
138
+ metadata: {
139
+ organizationId: payingOrganization.id,
140
+ userId: user?.id,
141
+ },
142
+ testmode: this.testMode,
143
+ });
144
+
145
+ const customerId = mollieCustomer.id;
146
+ this.#verifiedCustomerIds.add(customerId);
147
+
148
+ payingOrganization.serverMeta.mollieCustomerId = mollieCustomer.id;
149
+ console.log('Saving new mollie customer', mollieCustomer, 'for organization', payingOrganization.id);
150
+ await payingOrganization.save();
151
+
152
+ return customerId;
153
+ }
154
+
155
+ #cachedMandates: Map<string, PaymentMandate[]> = new Map();
156
+
157
+ async getMandates({ payingOrganization, user }: {
158
+ payingOrganization: Organization | null;
159
+ user: User | null;
160
+ }): Promise<PaymentMandate[]> {
161
+ const customerId = await this.getCustomerId({ payingOrganization, user });
162
+ if (!customerId) {
163
+ return [];
164
+ }
165
+
166
+ const cached = this.#cachedMandates.get(customerId);
167
+ if (cached) {
168
+ // return cached;
169
+ }
170
+
171
+ // Poll mollie status
172
+ // Mollie payment is required
173
+ const mandates: PaymentMandate[] = [];
174
+
175
+ try {
176
+ const m = await this.client.customerMandates.page({
177
+ customerId,
178
+ limit: 250,
179
+ testmode: this.testMode,
180
+ });
181
+
182
+ for (const mandate of m) {
183
+ const paymentMandate = MollieService.mollieManateToStamhoofd({ mandate, payingOrganization, user });
184
+ if (paymentMandate) {
185
+ mandates.push(paymentMandate);
186
+ }
187
+ }
188
+ } catch (e) {
189
+ console.error(e);
190
+ }
191
+
192
+ // todo: remove duplicate mandates?
193
+ return mandates;
194
+ }
195
+
196
+ async deleteMandate({ mandateId, payingOrganization, user }: {
197
+ mandateId: string;
198
+ payingOrganization: Organization | null;
199
+ user: User | null;
200
+ }) {
201
+ const customerId = await this.getCustomerId({ payingOrganization, user });
202
+ if (!customerId) {
203
+ return;
204
+ }
205
+
206
+ await this.client.customerMandates.revoke(
207
+ mandateId,
208
+ {
209
+ customerId,
210
+ testmode: this.testMode,
211
+ },
212
+ );
213
+ }
214
+
215
+ private static mollieManateToStamhoofd({ mandate, payingOrganization, user }: {
216
+ mandate: Mandate;
217
+ payingOrganization: Organization | null;
218
+ user: User | null;
219
+ }): PaymentMandate | null {
220
+ let type: PaymentMandateType;
221
+ switch (mandate.method) {
222
+ case MandateMethod.creditcard: {
223
+ type = PaymentMandateType.CreditCard;
224
+ break;
225
+ }
226
+
227
+ case MandateMethod.directdebit: {
228
+ type = PaymentMandateType.DirectDebit;
229
+ break;
230
+ }
231
+
232
+ default: {
233
+ // Not supported
234
+ return null;
235
+ }
236
+ }
237
+ const details = mandate.details;
238
+ return PaymentMandate.create({
239
+ id: mandate.id,
240
+ status: MollieService.mollieMandateStatusToStamhoofd(mandate),
241
+
242
+ // Todo: support for user default mandates
243
+ isDefault: mandate.id === payingOrganization?.serverMeta.mollieMandateId,
244
+
245
+ createdAt: new Date(mandate.createdAt),
246
+
247
+ provider: PaymentProvider.Mollie,
248
+
249
+ type,
250
+
251
+ details: PaymentMandateDetails.create({
252
+ name: ('consumerName' in details ? details.consumerName : details.cardHolder) ?? undefined,
253
+ cardNumber: 'cardNumber' in details ? details.cardNumber : null,
254
+ iban: 'consumerAccount' in details ? details.consumerAccount : null,
255
+ bic: ('consumerBic' in details ? details.consumerBic : undefined),
256
+ expiryDate: ('cardExpiryDate' in details ? DateTime.fromISO(details.cardExpiryDate, { zone: Formatter.timezone }).toJSDate() : null), // todo: parse date correctly in Brussels timezone!
257
+ brand: ('cardLabel' in details ? details.cardLabel : null),
258
+ }),
259
+ });
260
+ }
261
+
262
+ private static mollieMandateStatusToStamhoofd(mandate: Mandate): PaymentMandateStatus {
263
+ switch (mandate.status) {
264
+ case MandateStatus.valid: {
265
+ return PaymentMandateStatus.Valid;
266
+ }
267
+ case MandateStatus.invalid: {
268
+ return PaymentMandateStatus.Invalid;
269
+ }
270
+ case MandateStatus.pending: {
271
+ return PaymentMandateStatus.Pending;
272
+ }
273
+ }
274
+ }
275
+
276
+ private static paymentMethodToMollie(method: PaymentMethod) {
277
+ switch (method) {
278
+ case PaymentMethod.Bancontact:
279
+ return molliePaymentMethod.bancontact;
280
+ case PaymentMethod.CreditCard:
281
+ return molliePaymentMethod.creditcard;
282
+ case PaymentMethod.DirectDebit:
283
+ return molliePaymentMethod.directdebit;
284
+ case PaymentMethod.iDEAL:
285
+ return molliePaymentMethod.ideal;
286
+ case PaymentMethod.Transfer:
287
+ return molliePaymentMethod.banktransfer;
288
+ }
289
+
290
+ return null;
291
+ }
292
+
293
+ async getProfiles(): Promise<MollieProfile[]> {
294
+ try {
295
+ const response = await this.client.profiles.page({
296
+ limit: 250,
297
+ });
298
+ return response.map(p => MollieProfile.create({
299
+ ...p,
300
+ mode: p.mode === ApiMode.live ? MollieProfileMode.Live : MollieProfileMode.Test,
301
+ status: p.status === ProfileStatus.unverified ? MollieProfileStatus.Unverified : (p.status === ProfileStatus.blocked ? MollieProfileStatus.Blocked : MollieProfileStatus.Verified),
302
+ }));
303
+ } catch (e) {
304
+ console.error('Failed to parse mollie profiles', e);
305
+ return [];
306
+ }
307
+ }
308
+
309
+ async getOnboardingStatus() {
310
+ try {
311
+ const response = await this.client.onboarding.get();
312
+ return MollieOnboarding.create({
313
+ canReceivePayments: !!response.canReceivePayments,
314
+ canReceiveSettlements: !!response.canReceiveSettlements,
315
+ status: response.status === OnboardingStatus.needsData ? MollieStatus.NeedsData : (response.status === OnboardingStatus.inReview ? MollieStatus.InReview : (MollieStatus.Completed)),
316
+ });
317
+ } catch (e) {
318
+ console.error('Error when requesting Mollie onboarding status:');
319
+ console.error(e);
320
+ return null;
321
+ }
322
+ }
323
+
324
+ async getProfileId(website?: string): Promise<string | undefined> {
325
+ if (this.sellingOrganization.privateMeta.mollieProfile?.id) {
326
+ return this.sellingOrganization.privateMeta.mollieProfile.id;
327
+ }
328
+
329
+ try {
330
+ const profiles = await this.client.profiles.page({
331
+ limit: 250,
332
+ });
333
+
334
+ // Search profile with Stamhoofd as name
335
+ if (website) {
336
+ for (const profile of profiles) {
337
+ if (profile.website.toLowerCase().includes(website)) {
338
+ return profile.id;
339
+ }
340
+ }
341
+ }
342
+
343
+ // Search profile with Stamhoofd as name
344
+ for (const profile of profiles) {
345
+ if (profile.name.toLowerCase().includes('stamhoofd')) {
346
+ return profile.id;
347
+ }
348
+ }
349
+
350
+ return profiles[0]?.id ?? undefined;
351
+ } catch (e) {
352
+ console.error('Error when requesting Mollie profile id:');
353
+ console.error(e);
354
+ return undefined;
355
+ }
356
+ }
357
+
358
+ get locale() {
359
+ const preferredLocale = Context.i18n.locale.replace('-', '_');
360
+ return ['en_US', 'en_GB', 'nl_NL', 'nl_BE', 'fr_FR', 'fr_BE', 'de_DE', 'de_AT', 'de_CH', 'es_ES', 'ca_ES', 'pt_PT', 'it_IT', 'nb_NO', 'sv_SE', 'fi_FI', 'da_DK', 'is_IS', 'hu_HU', 'pl_PL', 'lv_LV', 'lt_LT'].includes(preferredLocale) ? (preferredLocale as any) : null;
361
+ }
362
+
363
+ get testMode() {
364
+ return this.sellingOrganization.privateMeta.useTestPayments ?? STAMHOOFD.environment !== 'production';
365
+ }
366
+
367
+ static async createPayment(
368
+ { sellingOrganization, payment, mandate, redirectUrl, webhookUrl, cancelUrl, description, metadata, payingOrganization, user, customer }: {
369
+ payment: Payment;
370
+ mandate: PaymentMandate | null;
371
+ redirectUrl: string;
372
+ cancelUrl: string;
373
+ webhookUrl: string;
374
+ description: string;
375
+ metadata: { [key: string]: string | undefined };
376
+ sellingOrganization: Organization;
377
+ payingOrganization: Organization | null;
378
+ user: User | null;
379
+ customer: PaymentCustomer;
380
+ },
381
+ ): Promise<{ paymentUrl: string | null }> {
382
+ const mollieService = await MollieService.create({ sellingOrganization });
383
+ const profileId = await mollieService?.getProfileId();
384
+ const method = MollieService.paymentMethodToMollie(payment.method);
385
+
386
+ if (!mollieService || !profileId || !method) {
387
+ throw new SimpleError({
388
+ code: '',
389
+ message: $t(`%w3`, { method: PaymentMethodHelper.getName(payment.method) }),
390
+ });
391
+ }
392
+
393
+ const customerId = await mollieService.getCustomerId({
394
+ payingOrganization: payingOrganization ?? null,
395
+ user,
396
+ customer,
397
+ }) ?? undefined;
398
+
399
+ const data: Parameters<typeof mollieService.client.payments.create>[0] = {
400
+ amount: {
401
+ currency: 'EUR',
402
+ value: (Math.round(payment.price / 100) / 100).toFixed(2),
403
+ },
404
+ method,
405
+ testmode: mollieService.testMode,
406
+ mandateId: mandate?.id,
407
+ sequenceType: mandate ? SequenceType.recurring : (payment.createMandate ? SequenceType.first : SequenceType.oneoff),
408
+ customerId,
409
+ profileId,
410
+ description,
411
+ redirectUrl,
412
+ cancelUrl,
413
+ webhookUrl,
414
+ metadata: {
415
+ paymentId: payment.id,
416
+ ...metadata,
417
+ },
418
+ locale: mollieService.locale,
419
+ };
420
+ console.log('Creating payment', data);
421
+ const molliePayment = await mollieService.client.payments.create(data);
422
+ console.log('Payment response', molliePayment);
423
+
424
+ const paymentUrl = molliePayment.getCheckoutUrl();
425
+
426
+ // Save payment
427
+ const dbPayment = new MolliePayment();
428
+ dbPayment.paymentId = payment.id;
429
+ dbPayment.mollieId = molliePayment.id;
430
+ await dbPayment.save();
431
+
432
+ const { status } = await mollieService.getStatusFor(molliePayment, payment, false);
433
+ payment.status = status;
434
+
435
+ return {
436
+ paymentUrl: paymentUrl,
437
+ };
438
+ }
439
+
440
+ static async saveChargeInfo(mollieData: MolliePaymentType, payment: Payment) {
441
+ try {
442
+ const details = mollieData.details;
443
+ if (details) {
444
+ if ('consumerName' in details) {
445
+ payment.ibanName = details.consumerName;
446
+ }
447
+ if ('consumerAccount' in details) {
448
+ payment.iban = details.consumerAccount;
449
+ }
450
+ if ('cardHolder' in details) {
451
+ payment.ibanName = details.cardHolder;
452
+ }
453
+ if ('cardNumber' in details) {
454
+ payment.iban = '•••• ' + details.cardNumber;
455
+ }
456
+
457
+ payment.mandateId = mollieData.mandateId ?? null;
458
+ await payment.save();
459
+ }
460
+ } catch (e) {
461
+ console.error('Failed processing charge', e);
462
+ }
463
+ }
464
+
465
+ async getStatusFor(mollieData: MolliePaymentType, payment: Payment, cancel = false): Promise<{ status: PaymentStatus }> {
466
+ await MollieService.saveChargeInfo(mollieData, payment);
467
+
468
+ if (mollieData.status === molliePaymentStatus.paid) {
469
+ return {
470
+ status: PaymentStatus.Succeeded,
471
+ };
472
+ } else if (mollieData.status === molliePaymentStatus.failed) {
473
+ return {
474
+ status: PaymentStatus.Failed,
475
+ };
476
+ } else if (mollieData.status === molliePaymentStatus.expired) {
477
+ return {
478
+ status: PaymentStatus.Failed,
479
+ };
480
+ } else if (mollieData.status === molliePaymentStatus.canceled) {
481
+ return {
482
+ status: PaymentStatus.Failed,
483
+ };
484
+ }
485
+
486
+ // Pending payments should be cancellable
487
+ if (cancel && mollieData.isCancelable) {
488
+ console.log('Cancelling Mollie Payment ' + payment.id);
489
+
490
+ // Try to cancel
491
+ try {
492
+ const newData = await this.client.payments.cancel(mollieData.id, {
493
+ testmode: this.testMode,
494
+ });
495
+ console.log('Cancelled Mollie Payment ' + payment.id);
496
+ return await this.getStatusFor(newData, payment, false);
497
+ } catch (e) {
498
+ console.error('Failed to cancel Mollie Payment ' + payment.id, { cause: e });
499
+ }
500
+ } else if (cancel) {
501
+ console.log('Cannot cancel Mollie Payment ' + payment.id);
502
+ }
503
+
504
+ if (mollieData.status === molliePaymentStatus.open) {
505
+ // Nothink happend yet
506
+ return {
507
+ status: PaymentStatus.Created,
508
+ };
509
+ }
510
+
511
+ return {
512
+ status: PaymentStatus.Pending,
513
+ };
514
+ }
515
+
516
+ async getStatus(payment: Payment, cancel = false) {
517
+ const molliePayment = await MolliePayment.select().where('paymentId', payment.id).first(false);
518
+ if (!molliePayment) {
519
+ throw new Error('Mollie Payment not found for payment ' + payment.id);
520
+ }
521
+
522
+ const mollieData = await this.client.payments.get(molliePayment.mollieId, {
523
+ testmode: this.testMode,
524
+ });
525
+
526
+ console.log(mollieData);
527
+
528
+ return this.getStatusFor(mollieData, payment, cancel);
529
+ }
530
+ }