@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
@@ -1,9 +1,10 @@
1
- import type { Decoder} from '@simonbackx/simple-encoding';
1
+ import type { Decoder } from '@simonbackx/simple-encoding';
2
2
  import { AutoEncoder, field, StringDecoder } from '@simonbackx/simple-encoding';
3
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
3
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
4
4
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
5
5
  import { Webshop } from '@stamhoofd/models';
6
6
  import { PermissionLevel, WebshopUriAvailabilityResponse } from '@stamhoofd/structures';
7
+ import { isReservedWebshopPathSegment } from '@stamhoofd/utility';
7
8
 
8
9
  import { Context } from '../../../../helpers/Context.js';
9
10
 
@@ -49,6 +50,14 @@ export class GetWebshopUriAvailabilityEndpoint extends Endpoint<Params, Query, B
49
50
  throw Context.auth.notFoundOrNoAccess();
50
51
  }
51
52
 
53
+ if (isReservedWebshopPathSegment(request.query.uri)) {
54
+ return new Response(
55
+ WebshopUriAvailabilityResponse.create({
56
+ available: false,
57
+ }),
58
+ );
59
+ }
60
+
52
61
  const q = await Webshop.where({
53
62
  uri: request.query.uri,
54
63
  id: {
@@ -1,6 +1,6 @@
1
- import type { AutoEncoderPatchType, Decoder, PatchableArrayAutoEncoder} from '@simonbackx/simple-encoding';
1
+ import type { AutoEncoderPatchType, Decoder, PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
2
2
  import { PatchableArrayDecoder, patchObject, StringDecoder } from '@simonbackx/simple-encoding';
3
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
3
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
4
4
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
5
5
  import { SimpleError } from '@simonbackx/simple-errors';
6
6
  import { Webshop, WebshopDiscountCode } from '@stamhoofd/models';
@@ -61,8 +61,7 @@ export class PatchWebshopDiscountCodesEndpoint extends Endpoint<Params, Query, B
61
61
 
62
62
  try {
63
63
  await model.save();
64
- }
65
- catch (e) {
64
+ } catch (e) {
66
65
  // Duplicate key probably
67
66
  if (e.code && e.code == 'ER_DUP_ENTRY') {
68
67
  throw new SimpleError({
@@ -93,8 +92,7 @@ export class PatchWebshopDiscountCodesEndpoint extends Endpoint<Params, Query, B
93
92
 
94
93
  try {
95
94
  await model.save();
96
- }
97
- catch (e) {
95
+ } catch (e) {
98
96
  // Duplicate key probably
99
97
  if (e.code && e.code == 'ER_DUP_ENTRY') {
100
98
  throw new SimpleError({
@@ -1,13 +1,14 @@
1
1
  import type { AutoEncoderPatchType, Decoder } from '@simonbackx/simple-encoding';
2
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
2
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
3
3
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
4
4
  import { SimpleError } from '@simonbackx/simple-errors';
5
5
  import { Webshop } from '@stamhoofd/models';
6
6
  import { QueueHandler } from '@stamhoofd/queues';
7
7
  import { PermissionLevel, PrivateWebshop, WebshopPrivateMetaData } from '@stamhoofd/structures';
8
- import { Formatter } from '@stamhoofd/utility';
8
+ import { Formatter, isReservedWebshopPathSegment } from '@stamhoofd/utility';
9
9
 
10
10
  import { Context } from '../../../../helpers/Context.js';
11
+ import { RecordAnswerHelper } from '../../../../helpers/RecordAnswerHelper.js';
11
12
 
12
13
  type Params = { id: string };
13
14
  type Query = undefined;
@@ -56,6 +57,11 @@ export class PatchWebshopEndpoint extends Endpoint<Params, Query, Body, Response
56
57
  if (request.body.meta.customCode !== undefined && !await Context.auth.hasFullAccess(organization.id)) {
57
58
  throw Context.auth.error($t('%15n'));
58
59
  }
60
+
61
+ if (request.body.meta.recordCategories) {
62
+ RecordAnswerHelper.throwIfPatchOrPutIsInvalid(webshop.meta.recordCategories, request.body.meta.recordCategories);
63
+ }
64
+
59
65
  webshop.meta.patchOrPut(request.body.meta);
60
66
  }
61
67
 
@@ -116,8 +122,7 @@ export class PatchWebshopEndpoint extends Endpoint<Params, Query, Body, Response
116
122
  });
117
123
  }
118
124
  }
119
- }
120
- else {
125
+ } else {
121
126
  webshop.domain = null;
122
127
  webshop.privateMeta.dnsRecords = [];
123
128
  webshop.meta.domainActive = false;
@@ -137,6 +142,15 @@ export class PatchWebshopEndpoint extends Endpoint<Params, Query, Body, Response
137
142
  });
138
143
  }
139
144
 
145
+ if (webshop.domainUri && isReservedWebshopPathSegment(webshop.domainUri)) {
146
+ throw new SimpleError({
147
+ code: 'invalid_field',
148
+ message: 'domainUri is reserved for internal webshop routes',
149
+ human: $t("%1a4"),
150
+ field: 'customUrl',
151
+ });
152
+ }
153
+
140
154
  // Check exists
141
155
  const existing = await Webshop.getByDomain(webshop.domain, webshop.domainUri);
142
156
  if (existing !== undefined) {
@@ -146,8 +160,7 @@ export class PatchWebshopEndpoint extends Endpoint<Params, Query, Body, Response
146
160
  human: $t(`%FP`) + ' ' + existing.meta.name + $t(`%FQ`),
147
161
  });
148
162
  }
149
- }
150
- else {
163
+ } else {
151
164
  webshop.domainUri = null;
152
165
  }
153
166
  }
@@ -177,6 +190,15 @@ export class PatchWebshopEndpoint extends Endpoint<Params, Query, Body, Response
177
190
  });
178
191
  }
179
192
 
193
+ if (isReservedWebshopPathSegment(request.body.uri)) {
194
+ throw new SimpleError({
195
+ code: 'invalid_field',
196
+ message: 'Uri is reserved for internal webshop routes',
197
+ human: $t("%1a4"),
198
+ field: 'uri',
199
+ });
200
+ }
201
+
180
202
  webshop.uri = request.body.uri;
181
203
  }
182
204
 
@@ -191,8 +213,7 @@ export class PatchWebshopEndpoint extends Endpoint<Params, Query, Body, Response
191
213
 
192
214
  try {
193
215
  await webshop.save();
194
- }
195
- catch (e) {
216
+ } catch (e) {
196
217
  // Duplicate key probably
197
218
  if (e.code && e.code == 'ER_DUP_ENTRY') {
198
219
  throw new SimpleError({
@@ -1,6 +1,6 @@
1
- import type { AutoEncoderPatchType, Data, Decoder, PatchableArrayAutoEncoder} from '@simonbackx/simple-encoding';
1
+ import type { AutoEncoderPatchType, Data, Decoder, PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
2
2
  import { ArrayDecoder, PatchableArray, PatchableArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
3
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
3
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
4
4
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
5
5
  import { SimpleError } from '@simonbackx/simple-errors';
6
6
  import { BalanceItem, BalanceItemPayment, Order, Payment, Webshop, WebshopCounter } from '@stamhoofd/models';
@@ -65,7 +65,7 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
65
65
 
66
66
  async handle(request: DecodedRequest<Params, Query, Body>) {
67
67
  const organization = await Context.setOrganizationScope();
68
- await Context.authenticate();
68
+ const { user } = await Context.authenticate();
69
69
 
70
70
  // Fast throw first (more in depth checking for patches later)
71
71
  if (!await Context.auth.hasSomeAccess(organization.id)) {
@@ -79,8 +79,7 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
79
79
  for (const p of request.body) {
80
80
  body.addPatch(p);
81
81
  }
82
- }
83
- else {
82
+ } else {
84
83
  body = request.body;
85
84
  }
86
85
 
@@ -99,12 +98,12 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
99
98
 
100
99
  const orders = body.getPatches().length > 0
101
100
  ? await Order.where({
102
- webshopId: webshop.id,
103
- id: {
104
- sign: 'IN',
105
- value: body.getPatches().map(o => o.id),
106
- },
107
- })
101
+ webshopId: webshop.id,
102
+ id: {
103
+ sign: 'IN',
104
+ value: body.getPatches().map(o => o.id),
105
+ },
106
+ })
108
107
  : [];
109
108
 
110
109
  // We use a getter because we need to have an up to date webshop struct
@@ -150,25 +149,25 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
150
149
  // Mark this order as paid
151
150
  await order.markPaid(null, organization, webshop);
152
151
  await order.save();
153
- }
154
- else {
152
+ } else {
155
153
  const payment = new Payment();
156
154
  payment.organizationId = organization.id;
157
155
  payment.method = struct.data.paymentMethod;
158
156
  payment.status = PaymentStatus.Created;
159
157
  payment.price = totalPrice;
160
- PaymentService.round(payment);
158
+ PaymentService.roundPayment(payment);
161
159
  payment.paidAt = null;
160
+ payment.adminUserId = user.id;
162
161
 
163
162
  // Determine the payment provider (always null because no online payments here)
164
163
  payment.provider = null;
165
- ServiceFeeHelper.setServiceFee(
164
+ await ServiceFeeHelper.setServiceFee(
166
165
  payment,
167
166
  organization,
168
167
  webshop.meta.ticketType === WebshopTicketType.None ? 'webshop' : 'tickets',
169
168
  order.data.cart.items.flatMap(i => i.calculatedPrices.map(p => p.discountedPrice)),
170
169
  );
171
-
170
+ await ServiceFeeHelper.setTransferFee({ payment, organization, stripeAccount: null });
172
171
  await payment.save();
173
172
 
174
173
  order.paymentId = payment.id;
@@ -209,22 +208,19 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
209
208
  await order.markValid(payment, []);
210
209
  await payment.save();
211
210
  await order.save();
212
- }
213
- else if (payment.method === PaymentMethod.PointOfSale) {
211
+ } else if (payment.method === PaymentMethod.PointOfSale) {
214
212
  // Not really paid, but needed to create the tickets if needed
215
213
  await order.markPaid(payment, organization, webshop);
216
214
  await payment.save();
217
215
  await order.save();
218
- }
219
- else {
216
+ } else {
220
217
  throw new Error('Unsupported payment method');
221
218
  }
222
219
 
223
220
  balanceItem.description = order.generateBalanceDescription(webshop);
224
221
  await balanceItem.save();
225
222
  }
226
- }
227
- catch (e) {
223
+ } catch (e) {
228
224
  await order.deleteOrderBecauseOfCreationError();
229
225
  throw e;
230
226
  }
@@ -278,8 +274,7 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
278
274
  model.markUpdated();
279
275
  // Cancel payment if still pending
280
276
  await BalanceItem.deleteForDeletedOrders([model.id]);
281
- }
282
- else {
277
+ } else {
283
278
  if (previousStatus === OrderStatus.Canceled || previousStatus === OrderStatus.Deleted) {
284
279
  model.markUpdated();
285
280
  // Undo deletion
@@ -300,8 +295,7 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
300
295
 
301
296
  if (model.isDue) {
302
297
  paidItem.status = BalanceItemStatus.Due;
303
- }
304
- else {
298
+ } else {
305
299
  paidItem.status = BalanceItemStatus.Canceled;
306
300
  }
307
301
  paidItem.description = model.generateBalanceDescription(webshop);
@@ -310,8 +304,7 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
310
304
  // Zero out the other items
311
305
  const otherItems = items.filter(i => i.id !== paidItem.id);
312
306
  await BalanceItem.deleteItems(otherItems);
313
- }
314
- else if (items.length === 0
307
+ } else if (items.length === 0
315
308
  && model.totalToPay > 0) {
316
309
  model.markUpdated();
317
310
  const balanceItem = new BalanceItem();
@@ -1,6 +1,6 @@
1
1
  import type { AutoEncoderPatchType, Decoder } from '@simonbackx/simple-encoding';
2
2
  import { ArrayDecoder } from '@simonbackx/simple-encoding';
3
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
3
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
4
4
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
5
5
  import { SimpleError, SimpleErrors } from '@simonbackx/simple-errors';
6
6
  import { Ticket, Token, Webshop } from '@stamhoofd/models';
@@ -1,7 +1,7 @@
1
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
1
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
2
2
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
3
3
  import { UitpasService } from '../../../../services/uitpas/UitpasService.js';
4
- import type { Decoder} from '@simonbackx/simple-encoding';
4
+ import type { Decoder } from '@simonbackx/simple-encoding';
5
5
  import { AutoEncoder, field, StringDecoder } from '@simonbackx/simple-encoding';
6
6
  import { Context } from '../../../../helpers/Context.js';
7
7
  import type { UitpasEventsResponse } from '@stamhoofd/structures';
@@ -1,4 +1,4 @@
1
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
1
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
2
2
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
3
3
  import { SimpleError } from '@simonbackx/simple-errors';
4
4
  import { Token, Webshop } from '@stamhoofd/models';
@@ -48,8 +48,7 @@ export class VerifyWebshopDomainEndpoint extends Endpoint<Params, Query, Body, R
48
48
  if (webshop.domain !== null) {
49
49
  webshop.privateMeta.dnsRecords = WebshopPrivateMetaData.buildDNSRecords(webshop.domain);
50
50
  await webshop.updateDNSRecords();
51
- }
52
- else {
51
+ } else {
53
52
  webshop.privateMeta.dnsRecords = [];
54
53
  webshop.meta.domainActive = false;
55
54
  }
@@ -0,0 +1,95 @@
1
+ import { Request } from '@simonbackx/simple-endpoints';
2
+ import { OrganizationFactory, Token, UserFactory, Webshop, WebshopFactory } from '@stamhoofd/models';
3
+ import { Permissions, PermissionLevel, PrivateWebshop, WebshopMetaData } from '@stamhoofd/structures';
4
+ import { STExpect, TestUtils } from '@stamhoofd/test-utils';
5
+
6
+ import { testServer } from '../../../../../tests/helpers/TestServer.js';
7
+ import { CreateWebshopEndpoint } from './CreateWebshopEndpoint.js';
8
+ import { GetWebshopUriAvailabilityEndpoint } from './GetWebshopUriAvailabilityEndpoint.js';
9
+ import { PatchWebshopEndpoint } from './PatchWebshopEndpoint.js';
10
+
11
+ describe('Endpoint.WebshopReservedPathSegments', () => {
12
+ const checkUriEndpoint = new GetWebshopUriAvailabilityEndpoint();
13
+ const patchEndpoint = new PatchWebshopEndpoint();
14
+ const createEndpoint = new CreateWebshopEndpoint();
15
+
16
+ beforeEach(async () => {
17
+ TestUtils.setEnvironment('userMode', 'platform');
18
+ });
19
+
20
+ async function createAdminContext() {
21
+ const organization = await new OrganizationFactory({}).create();
22
+ const user = await new UserFactory({
23
+ organization,
24
+ permissions: Permissions.create({
25
+ level: PermissionLevel.Full,
26
+ }),
27
+ }).create();
28
+ const token = await Token.createToken(user);
29
+
30
+ return { organization, token };
31
+ }
32
+
33
+ test('reserved webshop paths are not available as default URI', async () => {
34
+ const { organization, token } = await createAdminContext();
35
+ const webshop = await new WebshopFactory({ organizationId: organization.id }).create();
36
+
37
+ const request = Request.get({
38
+ path: '/webshop/' + webshop.id + '/check-uri',
39
+ host: organization.getApiHost(),
40
+ query: {
41
+ uri: 'tickets',
42
+ },
43
+ headers: { authorization: 'Bearer ' + token.accessToken },
44
+ });
45
+
46
+ const response = await testServer.test(checkUriEndpoint, request);
47
+
48
+ expect(response.body.available).toBe(false);
49
+ });
50
+
51
+ test('reserved webshop paths cannot be saved as default URI', async () => {
52
+ const { organization, token } = await createAdminContext();
53
+ const webshop = await new WebshopFactory({ organizationId: organization.id }).create();
54
+ const patch = PrivateWebshop.patch({ uri: 'tickets' });
55
+ const request = Request.buildJson('PATCH', '/webshop/' + webshop.id, organization.getApiHost(), patch);
56
+ request.headers.authorization = 'Bearer ' + token.accessToken;
57
+
58
+ await expect(testServer.test(patchEndpoint, request)).rejects.toThrow(
59
+ STExpect.simpleError({ code: 'invalid_field', field: 'uri' }),
60
+ );
61
+ });
62
+
63
+ test('reserved webshop paths cannot be saved as custom domain URI', async () => {
64
+ const { organization, token } = await createAdminContext();
65
+ const webshop = await new WebshopFactory({ organizationId: organization.id }).create();
66
+ webshop.domain = 'shop.example.com';
67
+ webshop.domainUri = 'valid';
68
+ await webshop.save();
69
+
70
+ const patch = PrivateWebshop.patch({ domainUri: 'tickets' });
71
+ const request = Request.buildJson('PATCH', '/webshop/' + webshop.id, organization.getApiHost(), patch);
72
+ request.headers.authorization = 'Bearer ' + token.accessToken;
73
+
74
+ await expect(testServer.test(patchEndpoint, request)).rejects.toThrow(
75
+ STExpect.simpleError({ code: 'invalid_field', field: 'customUrl' }),
76
+ );
77
+ });
78
+
79
+ test('generated webshop URIs skip reserved webshop paths', async () => {
80
+ const { organization, token } = await createAdminContext();
81
+ const body = PrivateWebshop.create({
82
+ meta: WebshopMetaData.create({
83
+ name: 'Tickets',
84
+ }),
85
+ });
86
+ const request = Request.buildJson('POST', '/webshop', organization.getApiHost(), body);
87
+ request.headers.authorization = 'Bearer ' + token.accessToken;
88
+
89
+ const response = await testServer.test(createEndpoint, request);
90
+ const webshop = await Webshop.getByID(response.body.id);
91
+
92
+ expect(response.body.uri).not.toBe('tickets');
93
+ expect(webshop?.uri).not.toBe('tickets');
94
+ });
95
+ });
@@ -1,6 +1,6 @@
1
- import type { Decoder} from '@simonbackx/simple-encoding';
1
+ import type { Decoder } from '@simonbackx/simple-encoding';
2
2
  import { AutoEncoder, BooleanDecoder, field } from '@simonbackx/simple-encoding';
3
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
3
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
4
4
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
5
5
  import { SimpleError } from '@simonbackx/simple-errors';
6
6
  import { Order } from '@stamhoofd/models';
@@ -45,10 +45,8 @@ export class ExchangePaymentEndpoint extends Endpoint<Params, Query, Body, Respo
45
45
  }
46
46
 
47
47
  async handle(request: DecodedRequest<Params, Query, Body>) {
48
- const organization = await Context.setOptionalOrganizationScope({ willAuthenticate: false });
49
- if (!request.query.exchange) {
50
- await Context.optionalAuthenticate();
51
- }
48
+ const organization = await Context.setOptionalOrganizationScope({ willAuthenticate: true }); // will authentiate set to true because we allow exchanges for inactive organizations
49
+ await Context.optionalAuthenticate();
52
50
 
53
51
  // Not method on payment because circular references (not supprted in ts)
54
52
  const payment = await PaymentService.pollStatus(request.params.id, organization, request.query.cancel);
@@ -63,19 +61,23 @@ export class ExchangePaymentEndpoint extends Endpoint<Params, Query, Body, Respo
63
61
  return new Response(undefined);
64
62
  }
65
63
 
66
- // #region skip check permissions if order and created less than hour ago
64
+ // Skip check permissions if order and created less than hour ago
67
65
  let checkPermissions = true;
68
66
  const hourAgo = new Date();
69
- hourAgo.setHours(-1);
67
+ hourAgo.setHours(-2);
70
68
 
71
69
  if (payment.createdAt > hourAgo) {
72
- const orders = await Order.where({ paymentId: payment.id }, { limit: 1 });
73
- const isOrder = orders[0] !== undefined;
74
- if (isOrder) {
75
- checkPermissions = false;
70
+ if (payment.payingOrganizationId) {
71
+ // B2B payments always required
72
+ checkPermissions = true;
73
+ } else {
74
+ const orders = await Order.where({ paymentId: payment.id }, { limit: 1 });
75
+ const isOrder = orders[0] !== undefined;
76
+ if (isOrder) {
77
+ checkPermissions = false;
78
+ }
76
79
  }
77
80
  }
78
- // #endregion
79
81
 
80
82
  return new Response(
81
83
  await AuthenticatedStructures.paymentGeneral(payment, checkPermissions),
@@ -1,4 +1,4 @@
1
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
1
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
2
2
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
3
3
  import { SimpleError } from '@simonbackx/simple-errors';
4
4
  import { signInternal } from '@stamhoofd/backend-env';
@@ -1,4 +1,4 @@
1
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
1
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
2
2
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
3
3
  import { SimpleError } from '@simonbackx/simple-errors';
4
4
  import { Payment } from '@stamhoofd/models';
@@ -1,4 +1,4 @@
1
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
1
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
2
2
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
3
3
  import { UitpasNumberDetails, UitpasNumbersGetDetailsRequest } from '@stamhoofd/structures';
4
4
 
@@ -53,14 +53,12 @@ export class GetUitpasNumberDetailsEndpoint extends Endpoint<Params, Query, Body
53
53
  uitpasNumber,
54
54
  socialTariff,
55
55
  }));
56
- }
57
- catch (error) {
56
+ } catch (error) {
58
57
  if (isSimpleError(error) || isSimpleErrors(error)) {
59
58
  error.addNamespace(i.toString());
60
59
  error.addNamespace('uitpasNumbers');
61
60
  simpleErrors.addError(error);
62
- }
63
- else {
61
+ } else {
64
62
  throw error;
65
63
  }
66
64
  }
@@ -1,4 +1,4 @@
1
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
1
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
2
2
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
3
3
  import type { Organization as OrganizationStruct } from '@stamhoofd/structures';
4
4
 
@@ -1,11 +1,12 @@
1
1
  import { ArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
2
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
2
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
3
3
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
4
4
  import { SimpleError } from '@simonbackx/simple-errors';
5
5
  import { Webshop, WebshopDiscountCode } from '@stamhoofd/models';
6
6
  import type { DiscountCode } from '@stamhoofd/structures';
7
7
 
8
8
  import { Context } from '../../../helpers/Context.js';
9
+ import { WebshopAuthHelper } from './WebshopAuthHelper.js';
9
10
 
10
11
  type Params = { id: string };
11
12
  type Query = undefined;
@@ -39,6 +40,8 @@ export class CheckWebshopDiscountCodesEndpoint extends Endpoint<Params, Query, B
39
40
  });
40
41
  }
41
42
 
43
+ await WebshopAuthHelper.optionalAuthenticateForWebshop(webshop);
44
+
42
45
  if (request.body.length > 10) {
43
46
  // Auto limit
44
47
  request.body = request.body.slice(0, 10);
@@ -1,12 +1,12 @@
1
- import { PartialWithoutMethods } from '@simonbackx/simple-encoding';
2
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
1
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
3
2
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
4
3
  import { SimpleError } from '@simonbackx/simple-errors';
5
- import { Order } from '@stamhoofd/models';
4
+ import { Order, Webshop } from '@stamhoofd/models';
6
5
  import { Payment } from '@stamhoofd/models';
7
6
  import type { Order as OrderStruct } from '@stamhoofd/structures';
8
7
 
9
8
  import { Context } from '../../../helpers/Context.js';
9
+ import { WebshopAuthHelper } from './WebshopAuthHelper.js';
10
10
  type Params = { id: string; paymentId: string };
11
11
  type Query = undefined;
12
12
  type Body = undefined;
@@ -46,6 +46,17 @@ export class GetOrderByPaymentEndpoint extends Endpoint<Params, Query, Body, Res
46
46
  });
47
47
  }
48
48
 
49
+ const webshop = await Webshop.getByID(request.params.id);
50
+ if (!webshop || webshop.organizationId !== organization.id) {
51
+ throw new SimpleError({
52
+ code: 'not_found',
53
+ message: 'Webshop not found',
54
+ human: $t(`%FX`),
55
+ });
56
+ }
57
+
58
+ await WebshopAuthHelper.checkOrderAccess(webshop, order);
59
+
49
60
  order.setRelation(Order.payment, payment);
50
61
  return new Response(await order.getStructure());
51
62
  }
@@ -1,10 +1,11 @@
1
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
1
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
2
2
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
3
3
  import { SimpleError } from '@simonbackx/simple-errors';
4
- import { Order } from '@stamhoofd/models';
4
+ import { Order, Webshop } from '@stamhoofd/models';
5
5
  import type { Order as OrderStruct } from '@stamhoofd/structures';
6
6
 
7
7
  import { Context } from '../../../helpers/Context.js';
8
+ import { WebshopAuthHelper } from './WebshopAuthHelper.js';
8
9
  type Params = { id: string; orderId: string };
9
10
  type Query = undefined;
10
11
  type Body = undefined;
@@ -36,6 +37,17 @@ export class GetOrderEndpoint extends Endpoint<Params, Query, Body, ResponseBody
36
37
  });
37
38
  }
38
39
 
40
+ const webshop = await Webshop.getByID(request.params.id);
41
+ if (!webshop || webshop.organizationId !== organization.id) {
42
+ throw new SimpleError({
43
+ code: 'not_found',
44
+ message: 'Webshop not found',
45
+ human: $t(`%FX`),
46
+ });
47
+ }
48
+
49
+ await WebshopAuthHelper.checkOrderAccess(webshop, order);
50
+
39
51
  return new Response(await order.getStructure());
40
52
  }
41
53
  }