@stamhoofd/backend 2.121.0 → 2.122.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (429) hide show
  1. package/output-2.txt +1 -0
  2. package/output.txt +1 -0
  3. package/package.json +69 -52
  4. package/src/audit-logs/EventNotificationLogger.ts +40 -0
  5. package/src/audit-logs/ModelLogger.ts +19 -15
  6. package/src/audit-logs/OrganizationLogger.ts +1 -1
  7. package/src/audit-logs/RegistrationInvitationLogger.ts +24 -24
  8. package/src/audit-logs/init.ts +8 -2
  9. package/src/boot.ts +19 -18
  10. package/src/crons/amazon-ses.ts +13 -26
  11. package/src/crons/balance-emails.ts +3 -5
  12. package/src/crons/clearExcelCache.test.ts +1 -1
  13. package/src/crons/clearExcelCache.ts +1 -2
  14. package/src/crons/drip-emails.ts +42 -0
  15. package/src/crons/endFunctionsOfUsersWithoutRegistration.ts +4 -0
  16. package/src/crons/helpers/isOutside.ts +11 -0
  17. package/src/crons/helpers/useSavedIterator.ts +32 -0
  18. package/src/crons/index.ts +5 -0
  19. package/src/crons/invoices.ts +32 -38
  20. package/src/crons/members-fees.ts +50 -0
  21. package/src/crons/mollie-chargebacks.ts +14 -15
  22. package/src/crons/service-fees.ts +152 -0
  23. package/src/crons/stripe-invoices.ts +48 -0
  24. package/src/crons/transfer-fees.ts +176 -0
  25. package/src/crons/update-cached-balances.ts +4 -4
  26. package/src/crons.ts +7 -64
  27. package/src/debug.ts +4 -2
  28. package/src/email-recipient-loaders/documents.ts +1 -1
  29. package/src/email-recipient-loaders/members.ts +1 -1
  30. package/src/email-recipient-loaders/payments.ts +4 -6
  31. package/src/email-recipient-loaders/registrations.ts +1 -1
  32. package/src/email-replacements/getEmailReplacementsForPayment.ts +5 -9
  33. package/src/endpoints/admin/members/ChargeMembersEndpoint.ts +1 -1
  34. package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +1 -1
  35. package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +3 -5
  36. package/src/endpoints/admin/organizations/ChargeOrganizationsEndpoint.ts +1 -1
  37. package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +1 -1
  38. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +13 -7
  39. package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +4 -6
  40. package/src/endpoints/admin/organizations/PatchPackagesEndpoint.test.ts +10 -6
  41. package/src/endpoints/admin/organizations/PatchPackagesEndpoint.ts +39 -21
  42. package/src/endpoints/admin/registrations/ChargeRegistrationsEndpoint.ts +1 -1
  43. package/src/endpoints/auth/CreateAdminEndpoint.ts +23 -5
  44. package/src/endpoints/auth/CreateTokenEndpoint.ts +2 -2
  45. package/src/endpoints/auth/DeleteTokenEndpoint.ts +1 -1
  46. package/src/endpoints/auth/DeleteUserEndpoint.ts +3 -3
  47. package/src/endpoints/auth/ForgotPasswordEndpoint.ts +1 -1
  48. package/src/endpoints/auth/GetOtherUserEndpoint.ts +1 -1
  49. package/src/endpoints/auth/GetUserEndpoint.ts +1 -1
  50. package/src/endpoints/auth/OpenIDConnectAuthTokenEndpoint.ts +1 -1
  51. package/src/endpoints/auth/OpenIDConnectStartEndpoint.ts +1 -1
  52. package/src/endpoints/auth/PatchUserEndpoint.ts +5 -8
  53. package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +1 -1
  54. package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +1 -1
  55. package/src/endpoints/auth/SignupEndpoint.ts +2 -3
  56. package/src/endpoints/auth/VerifyEmailEndpoint.ts +20 -3
  57. package/src/endpoints/frontend/FrontendEnvironmentEndpoint.ts +2 -1
  58. package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +2 -4
  59. package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +1 -1
  60. package/src/endpoints/global/audit-logs/GetAuditLogsEndpoint.ts +5 -7
  61. package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +2 -2
  62. package/src/endpoints/global/email/CreateEmailEndpoint.ts +3 -4
  63. package/src/endpoints/global/email/GetAdminEmailsEndpoint.test.ts +1 -1
  64. package/src/endpoints/global/email/GetAdminEmailsEndpoint.ts +1 -2
  65. package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +4 -6
  66. package/src/endpoints/global/email/GetEmailEndpoint.ts +1 -1
  67. package/src/endpoints/global/email/GetUserEmailsEndpoint.test.ts +1 -1
  68. package/src/endpoints/global/email/GetUserEmailsEndpoint.ts +1 -1
  69. package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +6 -10
  70. package/src/endpoints/global/email/PatchEmailEndpoint.test.ts +4 -7
  71. package/src/endpoints/global/email/PatchEmailEndpoint.ts +6 -9
  72. package/src/endpoints/global/email-recipients/GetEmailRecipientsCountEndpoint.ts +1 -1
  73. package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.test.ts +1 -1
  74. package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.ts +1 -1
  75. package/src/endpoints/global/email-recipients/RetryEmailRecipientEndpoint.ts +2 -2
  76. package/src/endpoints/global/events/GetEventNotificationsCountEndpoint.ts +1 -1
  77. package/src/endpoints/global/events/GetEventNotificationsEndpoint.ts +3 -3
  78. package/src/endpoints/global/events/GetEventsEndpoint.ts +3 -3
  79. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.test.ts +49 -4
  80. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.ts +5 -8
  81. package/src/endpoints/global/events/PatchEventsEndpoint.test.ts +12 -44
  82. package/src/endpoints/global/events/PatchEventsEndpoint.ts +128 -127
  83. package/src/endpoints/global/files/ExportToExcelEndpoint.ts +9 -9
  84. package/src/endpoints/global/files/GetFileCache.ts +3 -4
  85. package/src/endpoints/global/files/UploadFile.ts +3 -4
  86. package/src/endpoints/global/files/UploadImage.ts +3 -4
  87. package/src/endpoints/global/groups/GetGroupsCountEndpoint.ts +1 -1
  88. package/src/endpoints/global/groups/GetGroupsEndpoint.test.ts +1 -1
  89. package/src/endpoints/global/groups/GetGroupsEndpoint.ts +4 -2
  90. package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +2 -3
  91. package/src/endpoints/global/members/GetMembersCountEndpoint.ts +1 -1
  92. package/src/endpoints/global/members/GetMembersEndpoint.test.ts +2 -2
  93. package/src/endpoints/global/members/GetMembersEndpoint.ts +10 -12
  94. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.test.ts +195 -12
  95. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +16 -22
  96. package/src/endpoints/global/members/helpers/validateGroupFilter.ts +6 -30
  97. package/src/endpoints/global/members/shouldCheckIfMemberIsDuplicate.ts +1 -1
  98. package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +1 -1
  99. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +40 -8
  100. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +2 -2
  101. package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +2 -2
  102. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +4 -1
  103. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +4 -5
  104. package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +9 -16
  105. package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +1 -1
  106. package/src/endpoints/global/platform/GetPlatformEndpoint.ts +1 -1
  107. package/src/endpoints/global/platform/PatchPlatformEnpoint.test.ts +1 -1
  108. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +11 -11
  109. package/src/endpoints/global/platform-memberships/GetPlatformMembershipsCountEndpoint.ts +31 -31
  110. package/src/endpoints/global/platform-memberships/GetPlatformMembershipsEndpoint.ts +18 -20
  111. package/src/endpoints/global/registration/GetRegistrationsCountEndpoint.ts +1 -1
  112. package/src/endpoints/global/registration/GetRegistrationsEndpoint.test.ts +1 -1
  113. package/src/endpoints/global/registration/GetRegistrationsEndpoint.ts +6 -10
  114. package/src/endpoints/global/registration/GetUserDetailedPayableBalanceEndpoint.ts +35 -6
  115. package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +2 -2
  116. package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +1 -1
  117. package/src/endpoints/global/registration/GetUserPayableBalanceEndpoint.ts +1 -1
  118. package/src/endpoints/global/registration/PatchUserMembersEndpoint.test.ts +2 -2
  119. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +3 -3
  120. package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +90 -6
  121. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +35 -34
  122. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsCountEndpoint.ts +1 -1
  123. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.test.ts +62 -63
  124. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.ts +6 -9
  125. package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.test.ts +51 -52
  126. package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.ts +6 -7
  127. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsCountEndpoint.ts +43 -0
  128. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +1 -1
  129. package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +13 -5
  130. package/src/endpoints/global/sso/GetSSOEndpoint.ts +2 -3
  131. package/src/endpoints/global/sso/SetSSOEndpoint.ts +1 -1
  132. package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +2 -2
  133. package/src/endpoints/global/webshops/GetWebshopsEndpoint.test.ts +1 -2
  134. package/src/endpoints/global/webshops/GetWebshopsEndpoint.ts +2 -4
  135. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemEndpoint.ts +2 -2
  136. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsCountEndpoint.ts +1 -1
  137. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsEndpoint.ts +3 -4
  138. package/src/endpoints/organization/dashboard/balance-items/PatchBalanceItemsEndpoint.ts +7 -9
  139. package/src/endpoints/organization/dashboard/billing/ApplyRegisterCodeEndpoint.test.ts +73 -0
  140. package/src/endpoints/organization/dashboard/billing/ApplyRegisterCodeEndpoint.ts +89 -0
  141. package/src/endpoints/organization/dashboard/billing/DeactivatePackageEndpoint.ts +1 -5
  142. package/src/endpoints/organization/dashboard/billing/DeleteOrganizationMandateEndpoint.ts +11 -11
  143. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceCollectionEndpoint.ts +2 -2
  144. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceEndpoint.ts +8 -8
  145. package/src/endpoints/organization/dashboard/billing/GetOrganizationMandatesEndpoint.ts +9 -9
  146. package/src/endpoints/organization/dashboard/billing/GetOrganizationPayableBalanceEndpoint.ts +2 -2
  147. package/src/endpoints/organization/dashboard/billing/GetOrganizationPayableInvoicesEndpoint.ts +68 -0
  148. package/src/endpoints/organization/dashboard/billing/GetPackagesEndpoint.ts +4 -4
  149. package/src/endpoints/organization/dashboard/billing/GetRegisterCodeEndpoint.ts +66 -0
  150. package/src/endpoints/organization/dashboard/billing/OrganizationCheckoutEndpoint.test.ts +949 -0
  151. package/src/endpoints/organization/dashboard/billing/OrganizationCheckoutEndpoint.ts +60 -57
  152. package/src/endpoints/organization/dashboard/billing/PatchOrganizationMandatesEndpoint.ts +20 -20
  153. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +1 -1
  154. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesCountEndpoint.ts +1 -1
  155. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +1 -1
  156. package/src/endpoints/organization/dashboard/documents/GetDocumentsCountEndpoint.ts +1 -1
  157. package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +1 -1
  158. package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +10 -2
  159. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.test.ts +2 -2
  160. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.ts +2 -2
  161. package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +1 -1
  162. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.test.ts +1 -1
  163. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +10 -8
  164. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.test.ts +1 -1
  165. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +5 -6
  166. package/src/endpoints/organization/dashboard/invoices/GetInvoicesCountEndpoint.ts +1 -1
  167. package/src/endpoints/organization/dashboard/invoices/GetInvoicesEndpoint.ts +10 -6
  168. package/src/endpoints/organization/dashboard/invoices/PatchInvoicesEndpoint.ts +11 -2
  169. package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +4 -5
  170. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +5 -5
  171. package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +2 -2
  172. package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +7 -7
  173. package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +1 -1
  174. package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +2 -2
  175. package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +1 -1
  176. package/src/endpoints/organization/dashboard/organization/GetUitpasClientIdEndpoint.ts +1 -1
  177. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +2 -2
  178. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +50 -12
  179. package/src/endpoints/organization/dashboard/organization/SearchUitpasOrganizersEndpoint.ts +2 -2
  180. package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +5 -10
  181. package/src/endpoints/organization/dashboard/organization/SetUitpasClientCredentialsEndpoint.ts +1 -1
  182. package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +1 -1
  183. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +3 -4
  184. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +21 -14
  185. package/src/endpoints/organization/dashboard/receivable-balances/ChargeReceivableBalancesEndpoint.ts +35 -28
  186. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint.ts +2 -3
  187. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesCountEndpoint.ts +1 -1
  188. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts +1 -1
  189. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.test.ts +1 -1
  190. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +2 -3
  191. package/src/endpoints/organization/dashboard/registration-periods/MoveRegistrationPeriods.test.ts +1 -1
  192. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.test.ts +1 -1
  193. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +19 -18
  194. package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +4 -5
  195. package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +1 -1
  196. package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +2 -3
  197. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +2 -2
  198. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +1 -1
  199. package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +2 -2
  200. package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +1 -1
  201. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +1 -1
  202. package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +1 -1
  203. package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +1 -1
  204. package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +1 -1
  205. package/src/endpoints/organization/dashboard/users/PatchApiUserEndpoint.ts +4 -6
  206. package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +10 -15
  207. package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +1 -1
  208. package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +2 -2
  209. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersCountEndpoint.ts +1 -1
  210. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +1 -1
  211. package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +1 -1
  212. package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +11 -2
  213. package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +4 -6
  214. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +22 -7
  215. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +20 -27
  216. package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +1 -1
  217. package/src/endpoints/organization/dashboard/webshops/SearchUitpasEventsEndpoint.ts +2 -2
  218. package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +2 -3
  219. package/src/endpoints/organization/dashboard/webshops/WebshopReservedPathSegments.test.ts +95 -0
  220. package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +2 -2
  221. package/src/endpoints/organization/shared/GetDocumentHtml.ts +1 -1
  222. package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +1 -1
  223. package/src/endpoints/organization/shared/GetUitpasNumberDetailsEndpoint.ts +3 -5
  224. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +1 -1
  225. package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +4 -1
  226. package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +14 -3
  227. package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +14 -2
  228. package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +37 -16
  229. package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +34 -2
  230. package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +4 -2
  231. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +74 -3
  232. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +16 -33
  233. package/src/endpoints/organization/webshops/RetrieveUitpasSocialTariffPriceEndpoint.ts +3 -5
  234. package/src/endpoints/organization/webshops/WebshopAuthHelper.ts +36 -0
  235. package/src/endpoints/system/HealthEndpoint.ts +1 -1
  236. package/src/excel-loaders/balance-items.ts +1 -1
  237. package/src/excel-loaders/event-notifications.ts +1 -1
  238. package/src/excel-loaders/members.ts +1 -1
  239. package/src/excel-loaders/organizations.ts +3 -3
  240. package/src/excel-loaders/payments.ts +31 -1
  241. package/src/excel-loaders/platform-memberships.ts +13 -14
  242. package/src/excel-loaders/receivable-balances.ts +2 -2
  243. package/src/excel-loaders/registrations.ts +2 -3
  244. package/src/helpers/AddressValidator.ts +7 -14
  245. package/src/helpers/AdminPermissionChecker.ts +50 -63
  246. package/src/helpers/AuthenticatedStructures.ts +69 -55
  247. package/src/helpers/BalanceItemRelationsBackfiller.test.ts +174 -0
  248. package/src/helpers/BalanceItemRelationsBackfiller.ts +163 -0
  249. package/src/helpers/BuckarooHelper.ts +2 -4
  250. package/src/helpers/CheckSettlements.ts +12 -24
  251. package/src/helpers/Context.ts +15 -10
  252. package/src/helpers/CookieHelper.ts +1 -2
  253. package/src/helpers/EmailResumer.ts +1 -2
  254. package/src/helpers/FileCache.ts +2 -3
  255. package/src/helpers/FinancialSupportHelper.ts +2 -2
  256. package/src/helpers/FlagMomentCleanup.ts +1 -2
  257. package/src/helpers/ForwardHandler.ts +5 -10
  258. package/src/helpers/GlobalHelper.ts +3 -3
  259. package/src/helpers/LegacyBillingConverter.ts +787 -0
  260. package/src/helpers/MemberMerger.test.ts +782 -0
  261. package/src/helpers/MemberMerger.ts +600 -0
  262. package/src/helpers/MemberUserSyncer.ts +6 -12
  263. package/src/helpers/MembershipCharger.ts +2 -4
  264. package/src/helpers/PaymentCustomerResolver.test.ts +203 -0
  265. package/src/helpers/PaymentCustomerResolver.ts +144 -0
  266. package/src/helpers/PeriodHelper.ts +2 -3
  267. package/src/helpers/RecordAnswerHelper.test.ts +105 -110
  268. package/src/helpers/RecordAnswerHelper.ts +7 -7
  269. package/src/helpers/SeedTools.ts +106 -0
  270. package/src/helpers/ServiceFeeHelper.ts +125 -15
  271. package/src/helpers/SetupStepUpdater.ts +38 -32
  272. package/src/helpers/StamhoofdFilterAccessHelper.ts +52 -0
  273. package/src/helpers/StripeHelper.ts +14 -36
  274. package/src/helpers/StripeInvoicer.ts +419 -0
  275. package/src/helpers/StripePayoutChecker.ts +5 -10
  276. package/src/helpers/TagHelper.ts +7 -8
  277. package/src/helpers/TemporaryMemberAccess.ts +1 -2
  278. package/src/helpers/ThrottledQueue.ts +1 -2
  279. package/src/helpers/UitpasTokenRepository.ts +1 -2
  280. package/src/helpers/ViesHelper.ts +7 -11
  281. package/src/helpers/XlsxTransformerColumnHelper.ts +1 -1
  282. package/src/helpers/outstandingBalanceJoin.ts +2 -2
  283. package/src/helpers/updateMemberDetailsUitpasNumber.ts +3 -5
  284. package/src/migrate.ts +12 -5
  285. package/src/{seeds → migrations}/0000000004-single-organization.ts +10 -1
  286. package/src/migrations/0000000006-default-organization.ts +139 -0
  287. package/src/{seeds → migrations}/1715028563-user-permissions.ts +17 -27
  288. package/src/{seeds/1765896674-document-update-year.test.ts → migrations/1750090029-document-update-year.test.ts} +27 -26
  289. package/src/migrations/1750090029-document-update-year.ts +103 -0
  290. package/src/{seeds → migrations}/1750090030-records-configuration.ts +33 -32
  291. package/src/migrations/1750090031-records-configuration-webshops.ts +36 -0
  292. package/src/migrations/1752848540-national-numbers.ts +585 -0
  293. package/src/migrations/1752848550-records-configuration-group-filter.ts +1064 -0
  294. package/src/{seeds → migrations}/1752848561-groups-registration-periods.ts +70 -26
  295. package/src/{seeds → migrations}/1754560914-groups-prices.test.ts +1 -1
  296. package/src/{seeds → migrations}/1754560914-groups-prices.ts +9 -15
  297. package/src/{seeds → migrations}/1756293699-fill-previous-next-period-id.ts +1 -2
  298. package/src/migrations/1761665607-sync-member-users.ts +40 -0
  299. package/src/migrations/1779121240-invoice-email-template.sql +6 -0
  300. package/src/migrations/1779986893-default-payment-failed-email-templates.sql +4 -0
  301. package/src/migrations/1780578166-convert-legacy-billing.ts +13 -0
  302. package/src/{seeds/1755876819-remove-duplicate-members.ts → migrations/1780665426-remove-duplicate-members.ts} +23 -4
  303. package/src/migrations/1780933598-document-groups.ts +88 -0
  304. package/src/migrations/1781692342-balance-item-relations.ts +13 -0
  305. package/src/migrations/1781857866-platform-admins.ts +103 -0
  306. package/src/migrations/1781857867-rm-old-platform-admins.ts +25 -0
  307. package/src/seeds/0000000001-throw.ts +5 -0
  308. package/src/seeds/1760702452-update-balance-price-paid.ts +19 -0
  309. package/src/seeds/1760702453-update-balance-invoiced.ts +19 -0
  310. package/src/seeds/1760702454-update-cached-outstanding-balance-from-items.ts +51 -14
  311. package/src/seeds/1773754928-force-save-members.ts +41 -8
  312. package/src/seeds/1780665427-schedule-stock-updates.ts +45 -0
  313. package/src/seeds/1780665428-group-update-occupancy.ts +31 -0
  314. package/src/seeds/1780915001-fill-payment-customer.ts +70 -0
  315. package/src/seeds/1780915002-update-orders.ts +39 -0
  316. package/src/seeds/1782047708-organization-company-address.ts +44 -0
  317. package/src/seeds-temporary/1769088653-uitpas-status.ts +1 -2
  318. package/src/seeds-temporary/1780416000-migrate-audit-log-legacy-enums.test.ts +69 -0
  319. package/src/seeds-temporary/1780416000-migrate-audit-log-legacy-enums.ts +85 -0
  320. package/src/services/AuditLogService.test.ts +51 -0
  321. package/src/services/AuditLogService.ts +45 -0
  322. package/src/services/BalanceItemService.ts +141 -44
  323. package/src/services/CpuService.ts +3 -6
  324. package/src/services/DatabaseCollationService.test.ts +1 -2
  325. package/src/services/DocumentService.ts +1 -2
  326. package/src/services/EventNotificationService.ts +1 -1
  327. package/src/services/FileSignService.ts +2 -4
  328. package/src/services/InvoicePdfService.ts +286 -0
  329. package/src/services/InvoiceService.ts +204 -251
  330. package/src/services/InvoiceXMLService.ts +424 -0
  331. package/src/services/MemberNumberService.ts +6 -11
  332. package/src/services/MemberRecordStore.ts +8 -10
  333. package/src/services/MollieService.ts +114 -121
  334. package/src/services/PaymentMandateService.ts +45 -45
  335. package/src/services/PaymentReallocationService.test.ts +1 -1
  336. package/src/services/PaymentReallocationService.ts +7 -9
  337. package/src/services/PaymentService.ts +444 -308
  338. package/src/services/PlatformMembershipService.ts +4 -8
  339. package/src/services/ReferralService.ts +223 -0
  340. package/src/services/RegistrationService.ts +63 -53
  341. package/src/services/SSOService.test.ts +119 -0
  342. package/src/services/SSOService.ts +56 -49
  343. package/src/services/STPackageService.ts +97 -61
  344. package/src/services/UniqueMemberNumberService.ts +69 -0
  345. package/src/services/UniqueUserService.ts +3 -6
  346. package/src/services/VATService.ts +85 -0
  347. package/src/services/uitpas/PassholderEndpoints.ts +3 -6
  348. package/src/services/uitpas/UitpasService.ts +6 -10
  349. package/src/services/uitpas/checkUitpasNumbers.ts +2 -4
  350. package/src/services/uitpas/getSocialTariffForUitpasNumbers.ts +3 -6
  351. package/src/services/uitpas/searchUitpasEvents.ts +1 -2
  352. package/src/sql-filters/audit-logs.ts +1 -1
  353. package/src/sql-filters/balance-item-payments.ts +1 -1
  354. package/src/sql-filters/balance-items.ts +1 -1
  355. package/src/sql-filters/base-registration-filter-compilers.ts +5 -33
  356. package/src/sql-filters/document-templates.ts +1 -1
  357. package/src/sql-filters/documents.ts +1 -1
  358. package/src/sql-filters/email-recipients.ts +1 -1
  359. package/src/sql-filters/emails.ts +1 -1
  360. package/src/sql-filters/event-notifications.ts +1 -1
  361. package/src/sql-filters/events.ts +6 -1
  362. package/src/sql-filters/groups.ts +5 -0
  363. package/src/sql-filters/invoiced-balance-items.ts +1 -1
  364. package/src/sql-filters/invoices.ts +1 -1
  365. package/src/sql-filters/member-responsibility-records.ts +1 -1
  366. package/src/sql-filters/members.ts +1 -1
  367. package/src/sql-filters/orders.ts +4 -4
  368. package/src/sql-filters/organization-registration-periods.ts +1 -1
  369. package/src/sql-filters/organizations.ts +1 -1
  370. package/src/sql-filters/platform-memberships.ts +3 -3
  371. package/src/sql-filters/receivable-balances.ts +1 -1
  372. package/src/sql-filters/registration-periods.ts +1 -1
  373. package/src/sql-filters/registrations.ts +1 -1
  374. package/src/sql-filters/tickets.ts +1 -1
  375. package/src/sql-filters/users.ts +1 -1
  376. package/src/sql-sorters/groups.ts +23 -0
  377. package/src/sql-sorters/platform-memberships.ts +16 -16
  378. package/src/sql-sorters/registration-invitations.ts +2 -2
  379. package/tests/actions/patchOrganizationMember.ts +1 -1
  380. package/tests/actions/patchUserMember.ts +1 -1
  381. package/tests/assertions/assertBalances.ts +6 -12
  382. package/tests/e2e/api-rate-limits.test.ts +12 -24
  383. package/tests/e2e/bundle-discounts.test.ts +4 -1
  384. package/tests/e2e/charge-members.test.ts +13 -11
  385. package/tests/e2e/documents.test.ts +4 -1
  386. package/tests/e2e/register.test.ts +7 -9
  387. package/tests/e2e/stock.test.ts +4 -3
  388. package/tests/e2e/tickets.test.ts +1 -1
  389. package/tests/helpers/MollieMocker.ts +462 -0
  390. package/tests/helpers/PayconiqMocker.ts +138 -45
  391. package/tests/helpers/StripeMocker.ts +9 -6
  392. package/tests/helpers/index.ts +4 -0
  393. package/tests/init/initAdmin.ts +2 -2
  394. package/tests/init/initBundleDiscount.ts +1 -1
  395. package/tests/init/initMembershipOrganization.ts +13 -0
  396. package/tests/init/initPermissionRole.ts +3 -4
  397. package/tests/vitest.global.setup.ts +1 -1
  398. package/vitest.config.js +6 -0
  399. package/.nvmrc +0 -1
  400. package/src/helpers/GroupBuilder.ts +0 -418
  401. package/src/seeds/0000000000-example.ts +0 -11
  402. package/src/seeds/1722256498-group-update-occupancy.ts +0 -52
  403. package/src/seeds/1726572303-schedule-stock-updates.ts +0 -52
  404. package/src/seeds/1726847064-setup-steps.ts +0 -16
  405. package/src/seeds/1728928974-update-cached-outstanding-balance-from-items.ts +0 -31
  406. package/src/seeds/1729253172-update-orders.ts +0 -21
  407. package/src/seeds/1733319079-fill-paying-organization-ids.ts +0 -68
  408. package/src/seeds/1733748412-update-deleted-order-numbers.ts +0 -109
  409. package/src/seeds/1733994455-balance-item-status-open.ts +0 -30
  410. package/src/seeds/1740046783-update-membership.ts +0 -17
  411. package/src/seeds/1741008870-fix-auditlog-description.ts +0 -50
  412. package/src/seeds/1741011468-fix-auditlog-description-uft16.ts +0 -88
  413. package/src/seeds/1741268179-fix-group-dates-of-events.ts +0 -32
  414. package/src/seeds/1751445358-upload-email-attachments.ts +0 -106
  415. package/src/seeds/1755532883-update-email-sender-ids.ts +0 -47
  416. package/src/seeds/1755790070-fill-email-recipient-errors.ts +0 -96
  417. package/src/seeds/1756115432-remove-old-drafts.ts +0 -16
  418. package/src/seeds/1756115433-fill-email-recipient-organization-id.ts +0 -30
  419. package/src/seeds/1756303697-update-email-counts.ts +0 -76
  420. package/src/seeds/1761665607-sync-member-users.ts +0 -59
  421. package/src/seeds/1765896674-document-update-year.ts +0 -66
  422. /package/src/{seeds → migrations}/0000000001-development-user.ts +0 -0
  423. /package/src/{seeds → migrations}/0000000002-clear-stamhoofd-email-templates.ts +0 -0
  424. /package/src/{seeds → migrations}/0000000003-default-email-templates.ts +0 -0
  425. /package/src/{seeds → migrations}/1752848561-groups-registration-periods.test.ts +0 -0
  426. /package/src/{seeds → migrations}/1766150402-document-published-at.test.ts +0 -0
  427. /package/src/{seeds → migrations}/1766150402-document-published-at.ts +0 -0
  428. /package/src/{seeds → migrations}/1779121239-default-invoice-email-template.sql +0 -0
  429. /package/src/{seeds → migrations}/data/default-email-templates.sql +0 -0
@@ -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,8 +149,7 @@ 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;
@@ -159,16 +157,17 @@ export class PatchWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Re
159
157
  payment.price = totalPrice;
160
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';
@@ -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
  }
@@ -1,12 +1,13 @@
1
- import type { Decoder} from '@simonbackx/simple-encoding';
1
+ import type { Decoder } from '@simonbackx/simple-encoding';
2
2
  import { AutoEncoder, field, StringDecoder } from '@simonbackx/simple-encoding';
3
- import type { DecodedRequest, Request} from '@simonbackx/simple-endpoints';
3
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
4
4
  import { Endpoint, Response } from '@simonbackx/simple-endpoints';
5
5
  import { SimpleError } from '@simonbackx/simple-errors';
6
- import { Order, Ticket } from '@stamhoofd/models';
6
+ import { Order, Ticket, Webshop } from '@stamhoofd/models';
7
7
  import { TicketOrder, TicketPublic } from '@stamhoofd/structures';
8
8
 
9
9
  import { Context } from '../../../helpers/Context.js';
10
+ import { WebshopAuthHelper } from './WebshopAuthHelper.js';
10
11
  type Params = { id: string };
11
12
 
12
13
  class Query extends AutoEncoder {
@@ -45,6 +46,14 @@ export class GetTicketsEndpoint extends Endpoint<Params, Query, Body, ResponseBo
45
46
 
46
47
  async handle(request: DecodedRequest<Params, Query, Body>) {
47
48
  const organization = await Context.setOrganizationScope({ willAuthenticate: false });
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
+ }
48
57
 
49
58
  if (request.query.secret) {
50
59
  const [ticket] = await Ticket.where({
@@ -61,17 +70,20 @@ export class GetTicketsEndpoint extends Endpoint<Params, Query, Body, ResponseBo
61
70
  });
62
71
  }
63
72
 
73
+ const order = await Order.getByID(ticket.orderId);
74
+ if (!order || order.webshopId !== request.params.id || order.organizationId !== organization.id) {
75
+ console.error('Error: missing order ' + ticket.orderId + ' for ticket ' + ticket.id);
76
+ throw new SimpleError({
77
+ code: 'not_found',
78
+ message: 'Ticket not found',
79
+ human: $t(`%FZ`),
80
+ });
81
+ }
82
+
83
+ await WebshopAuthHelper.checkOrderAccess(webshop, order);
84
+
64
85
  if (!request.query.orderId) {
65
86
  // Include item data
66
- const order = await Order.getByID(ticket.orderId);
67
- if (!order || order.webshopId !== request.params.id) {
68
- console.error('Error: missing order ' + ticket.orderId + ' for ticket ' + ticket.id);
69
- throw new SimpleError({
70
- code: 'not_found',
71
- message: 'Ticket not found',
72
- human: $t(`%FZ`),
73
- });
74
- }
75
87
 
76
88
  if (ticket.itemId) {
77
89
  const item = order.data.cart.items.find(i => i.id === ticket.itemId);
@@ -91,8 +103,7 @@ export class GetTicketsEndpoint extends Endpoint<Params, Query, Body, ResponseBo
91
103
  items: [item],
92
104
  }),
93
105
  ]);
94
- }
95
- else {
106
+ } else {
96
107
  return new Response([
97
108
  TicketPublic.create({
98
109
  ...ticket,
@@ -104,8 +115,7 @@ export class GetTicketsEndpoint extends Endpoint<Params, Query, Body, ResponseBo
104
115
  return new Response([
105
116
  TicketOrder.create(ticket),
106
117
  ]);
107
- }
108
- else {
118
+ } else {
109
119
  if (!request.query.orderId) {
110
120
  throw new SimpleError({
111
121
  code: 'not_found',
@@ -119,6 +129,17 @@ export class GetTicketsEndpoint extends Endpoint<Params, Query, Body, ResponseBo
119
129
  organizationId: organization.id,
120
130
  deletedAt: null,
121
131
  });
132
+
133
+ const order = await Order.getByID(request.query.orderId);
134
+ if (!order || order.webshopId !== request.params.id || order.organizationId !== organization.id) {
135
+ throw new SimpleError({
136
+ code: 'not_found',
137
+ message: 'Ticket not found',
138
+ human: $t(`%FZ`),
139
+ });
140
+ }
141
+
142
+ await WebshopAuthHelper.checkOrderAccess(webshop, order);
122
143
  return new Response(
123
144
  tickets.map(ticket => TicketOrder.create(ticket)),
124
145
  );
@@ -1,8 +1,8 @@
1
1
  import { Request } from '@simonbackx/simple-endpoints';
2
2
  import { OrganizationFactory, Token, UserFactory, WebshopFactory } from '@stamhoofd/models';
3
- import { PermissionLevel, Permissions } from '@stamhoofd/structures';
3
+ import { PermissionLevel, Permissions, WebshopAuthType, WebshopMetaData } from '@stamhoofd/structures';
4
4
 
5
- import { TestUtils } from '@stamhoofd/test-utils';
5
+ import { STExpect, TestUtils } from '@stamhoofd/test-utils';
6
6
  import { testServer } from '../../../../tests/helpers/TestServer.js';
7
7
  import { GetWebshopEndpoint } from './GetWebshopEndpoint.js';
8
8
 
@@ -43,6 +43,38 @@ describe('Endpoint.GetWebshop', () => {
43
43
  expect((response.body as any).privateMeta).toBeUndefined();
44
44
  });
45
45
 
46
+ test('Reject anonymous access for required-auth webshop', async () => {
47
+ const organization = await new OrganizationFactory({}).create();
48
+ const webshop = await new WebshopFactory({
49
+ organizationId: organization.id,
50
+ meta: WebshopMetaData.create({
51
+ authType: WebshopAuthType.Required,
52
+ }),
53
+ }).create();
54
+
55
+ const r = Request.buildJson('GET', '/webshop/' + webshop.id, organization.getApiHost());
56
+
57
+ await expect(testServer.test(endpoint, r)).rejects.toThrow(STExpect.errorWithCode('not_authenticated'));
58
+ });
59
+
60
+ test('Allow signed in user access for required-auth webshop', async () => {
61
+ const organization = await new OrganizationFactory({}).create();
62
+ const user = await new UserFactory({ organization }).create();
63
+ const token = await Token.createToken(user);
64
+ const webshop = await new WebshopFactory({
65
+ organizationId: organization.id,
66
+ meta: WebshopMetaData.create({
67
+ authType: WebshopAuthType.Required,
68
+ }),
69
+ }).create();
70
+
71
+ const r = Request.buildJson('GET', '/webshop/' + webshop.id, organization.getApiHost());
72
+ r.headers.authorization = 'Bearer ' + token.accessToken;
73
+
74
+ const response = await testServer.test(endpoint, r);
75
+ expect(response.body.id).toEqual(webshop.id);
76
+ });
77
+
46
78
  test('Get webshop as admin', async () => {
47
79
  const organization = await new OrganizationFactory({}).create();
48
80
  const user = await new UserFactory({
@@ -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 { Webshop } from '@stamhoofd/models';
@@ -6,6 +6,7 @@ import type { PrivateWebshop, Webshop as WebshopStruct } from '@stamhoofd/struct
6
6
 
7
7
  import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures.js';
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;
@@ -28,7 +29,6 @@ export class GetWebshopEndpoint extends Endpoint<Params, Query, Body, ResponseBo
28
29
 
29
30
  async handle(request: DecodedRequest<Params, Query, Body>) {
30
31
  await Context.setOptionalOrganizationScope(); // editing webshop from the admin panel -> no scope
31
- await Context.optionalAuthenticate();
32
32
 
33
33
  const webshop = await Webshop.getByID(request.params.id);
34
34
  if (!webshop) {
@@ -39,6 +39,8 @@ export class GetWebshopEndpoint extends Endpoint<Params, Query, Body, ResponseBo
39
39
  });
40
40
  }
41
41
 
42
+ await WebshopAuthHelper.optionalAuthenticateForWebshop(webshop);
43
+
42
44
  return new Response(
43
45
  await AuthenticatedStructures.webshop(webshop),
44
46
  );