@stamhoofd/backend 2.39.0 → 2.40.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 (198) hide show
  1. package/eslint.config.mjs +5 -0
  2. package/index.ts +81 -74
  3. package/jest.config.cjs +10 -0
  4. package/migrations.ts +16 -14
  5. package/package.json +11 -11
  6. package/src/crons/clear-excel-cache.test.ts +48 -50
  7. package/src/crons/clear-excel-cache.ts +18 -18
  8. package/src/crons/setup-steps.ts +2 -2
  9. package/src/crons.ts +325 -306
  10. package/src/decoders/StringArrayDecoder.ts +7 -7
  11. package/src/decoders/StringNullableDecoder.ts +1 -2
  12. package/src/email-recipient-loaders/members.ts +22 -22
  13. package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +8 -9
  14. package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +39 -40
  15. package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +8 -8
  16. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +44 -45
  17. package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +58 -57
  18. package/src/endpoints/auth/CreateAdminEndpoint.ts +48 -45
  19. package/src/endpoints/auth/CreateTokenEndpoint.test.ts +31 -31
  20. package/src/endpoints/auth/CreateTokenEndpoint.ts +146 -147
  21. package/src/endpoints/auth/DeleteTokenEndpoint.ts +7 -7
  22. package/src/endpoints/auth/DeleteUserEndpoint.ts +15 -15
  23. package/src/endpoints/auth/ForgotPasswordEndpoint.ts +17 -18
  24. package/src/endpoints/auth/GetOtherUserEndpoint.ts +9 -10
  25. package/src/endpoints/auth/GetUserEndpoint.test.ts +32 -35
  26. package/src/endpoints/auth/GetUserEndpoint.ts +5 -6
  27. package/src/endpoints/auth/PatchApiUserEndpoint.ts +35 -33
  28. package/src/endpoints/auth/PatchUserEndpoint.ts +55 -52
  29. package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +9 -9
  30. package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +8 -8
  31. package/src/endpoints/auth/SignupEndpoint.ts +37 -36
  32. package/src/endpoints/auth/VerifyEmailEndpoint.ts +29 -28
  33. package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +33 -33
  34. package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +7 -7
  35. package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +37 -37
  36. package/src/endpoints/global/email/CreateEmailEndpoint.ts +30 -30
  37. package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +13 -13
  38. package/src/endpoints/global/email/GetEmailEndpoint.ts +13 -13
  39. package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +16 -16
  40. package/src/endpoints/global/email/PatchEmailEndpoint.ts +25 -25
  41. package/src/endpoints/global/events/GetEventsEndpoint.ts +43 -44
  42. package/src/endpoints/global/events/PatchEventsEndpoint.ts +127 -172
  43. package/src/endpoints/global/files/ExportToExcelEndpoint.ts +49 -50
  44. package/src/endpoints/global/files/GetFileCache.ts +13 -13
  45. package/src/endpoints/global/files/UploadFile.ts +51 -54
  46. package/src/endpoints/global/files/UploadImage.ts +53 -53
  47. package/src/endpoints/global/groups/GetGroupsEndpoint.ts +25 -25
  48. package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +24 -23
  49. package/src/endpoints/global/members/GetMembersCountEndpoint.ts +8 -8
  50. package/src/endpoints/global/members/GetMembersEndpoint.ts +105 -102
  51. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +240 -239
  52. package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +12 -14
  53. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +32 -33
  54. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +48 -57
  55. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +21 -22
  56. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +28 -28
  57. package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +18 -18
  58. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +20 -20
  59. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +17 -17
  60. package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +81 -75
  61. package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +14 -14
  62. package/src/endpoints/global/platform/GetPlatformEnpoint.ts +11 -11
  63. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +71 -68
  64. package/src/endpoints/global/registration/GetPaymentRegistrations.ts +27 -27
  65. package/src/endpoints/global/registration/GetUserBillingStatusEndpoint.ts +30 -30
  66. package/src/endpoints/global/registration/GetUserDetailedBillingStatusEndpoint.ts +34 -34
  67. package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +26 -26
  68. package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +12 -12
  69. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +90 -90
  70. package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +118 -121
  71. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +362 -350
  72. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +8 -9
  73. package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +21 -21
  74. package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +65 -65
  75. package/src/endpoints/organization/dashboard/billing/GetOrganizationBillingStatusEndpoint.ts +9 -9
  76. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedBillingStatusEndpoint.ts +14 -14
  77. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +17 -17
  78. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +21 -21
  79. package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +15 -15
  80. package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +52 -52
  81. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplateEndpoint.ts +37 -37
  82. package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +14 -14
  83. package/src/endpoints/organization/dashboard/email/EmailEndpoint.ts +113 -112
  84. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +29 -29
  85. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +48 -47
  86. package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +22 -21
  87. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +13 -14
  88. package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +12 -13
  89. package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +24 -24
  90. package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +10 -12
  91. package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +14 -14
  92. package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +13 -13
  93. package/src/endpoints/organization/dashboard/organization/GetOrganizationSSOEndpoint.ts +12 -12
  94. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +120 -124
  95. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +172 -173
  96. package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +88 -89
  97. package/src/endpoints/organization/dashboard/organization/SetOrganizationSSOEndpoint.ts +12 -12
  98. package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +17 -17
  99. package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +8 -8
  100. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +66 -67
  101. package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +47 -47
  102. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +93 -91
  103. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +16 -17
  104. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +170 -167
  105. package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +25 -24
  106. package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +22 -23
  107. package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +22 -22
  108. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +17 -18
  109. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +8 -9
  110. package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +17 -18
  111. package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +14 -15
  112. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +19 -19
  113. package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +19 -19
  114. package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +14 -14
  115. package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +12 -12
  116. package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +103 -100
  117. package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +11 -12
  118. package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +15 -15
  119. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +14 -14
  120. package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +14 -14
  121. package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +23 -23
  122. package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +54 -52
  123. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +84 -81
  124. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +120 -111
  125. package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +24 -24
  126. package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +18 -18
  127. package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +141 -130
  128. package/src/endpoints/organization/shared/GetDocumentHtml.ts +25 -25
  129. package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +18 -18
  130. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +36 -37
  131. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +9 -9
  132. package/src/endpoints/organization/shared/auth/OpenIDConnectCallbackEndpoint.ts +11 -11
  133. package/src/endpoints/organization/shared/auth/OpenIDConnectStartEndpoint.ts +28 -27
  134. package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +20 -20
  135. package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +22 -22
  136. package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +14 -14
  137. package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +57 -56
  138. package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +65 -66
  139. package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +18 -17
  140. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +124 -128
  141. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +154 -145
  142. package/src/excel-loaders/members.ts +102 -103
  143. package/src/excel-loaders/payments.ts +155 -156
  144. package/src/helpers/AddressValidator.test.ts +32 -32
  145. package/src/helpers/AddressValidator.ts +128 -122
  146. package/src/helpers/AdminPermissionChecker.ts +339 -236
  147. package/src/helpers/AuthenticatedStructures.ts +233 -134
  148. package/src/helpers/BuckarooHelper.ts +134 -134
  149. package/src/helpers/CheckSettlements.ts +94 -88
  150. package/src/helpers/Context.ts +87 -86
  151. package/src/helpers/CookieHelper.ts +23 -22
  152. package/src/helpers/EmailResumer.ts +10 -10
  153. package/src/helpers/FileCache.ts +62 -62
  154. package/src/helpers/ForwardHandler.test.ts +122 -124
  155. package/src/helpers/ForwardHandler.ts +76 -70
  156. package/src/helpers/MemberUserSyncer.ts +101 -96
  157. package/src/helpers/MembershipCharger.ts +69 -69
  158. package/src/helpers/MembershipHelper.ts +11 -12
  159. package/src/helpers/OpenIDConnectHelper.ts +85 -82
  160. package/src/helpers/PeriodHelper.ts +65 -70
  161. package/src/helpers/StripeHelper.ts +146 -137
  162. package/src/helpers/StripePayoutChecker.ts +51 -52
  163. package/src/helpers/ViesHelper.ts +46 -44
  164. package/src/helpers/fetchToAsyncIterator.ts +14 -14
  165. package/src/helpers/xlsxAddressTransformerColumnFactory.ts +50 -52
  166. package/src/middleware/ContextMiddleware.ts +5 -5
  167. package/src/migrations/1646578856-validate-addresses.ts +6 -9
  168. package/src/seeds/0000000000-example.ts +3 -5
  169. package/src/seeds/1715028563-user-permissions.ts +16 -18
  170. package/src/seeds/1722256498-group-update-occupancy.ts +12 -12
  171. package/src/seeds/1722344162-sync-member-users.ts +14 -15
  172. package/src/seeds/1722344162-update-membership.ts +6 -6
  173. package/src/seeds/1726055544-balance-item-paid.ts +4 -4
  174. package/src/seeds/1726055545-balance-item-pending.ts +4 -4
  175. package/src/seeds/1726494419-update-cached-outstanding-balance.ts +16 -16
  176. package/src/seeds/1726494420-update-cached-outstanding-balance-from-items.ts +12 -12
  177. package/src/seeds/1726572303-schedule-stock-updates.ts +12 -12
  178. package/src/seeds/1726847064-setup-steps.ts +16 -0
  179. package/src/sql-filters/balance-item-payments.ts +7 -7
  180. package/src/sql-filters/events.ts +14 -14
  181. package/src/sql-filters/members.ts +96 -96
  182. package/src/sql-filters/organizations.ts +139 -75
  183. package/src/sql-filters/payments.ts +28 -28
  184. package/src/sql-filters/registrations.ts +14 -14
  185. package/src/sql-sorters/events.ts +25 -25
  186. package/src/sql-sorters/members.ts +26 -26
  187. package/src/sql-sorters/organizations.ts +36 -36
  188. package/src/sql-sorters/payments.ts +26 -26
  189. package/tests/e2e/stock.test.ts +616 -621
  190. package/tests/e2e/tickets.test.ts +255 -260
  191. package/tests/helpers/StripeMocker.ts +177 -179
  192. package/tests/helpers/TestServer.ts +9 -9
  193. package/tests/jest.global.setup.ts +14 -13
  194. package/tests/jest.setup.ts +33 -32
  195. package/.eslintrc.js +0 -61
  196. package/jest.config.js +0 -11
  197. package/src/helpers/SetupStepsUpdater.ts +0 -359
  198. package/src/seeds/1724076679-setup-steps.ts +0 -16
@@ -1,14 +1,13 @@
1
1
  import { AutoEncoderPatchType, Decoder, isPatchableArray, ObjectData, PatchableArrayAutoEncoder, patchObject } from '@simonbackx/simple-encoding';
2
- import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
2
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
3
3
  import { SimpleError, SimpleErrors } from '@simonbackx/simple-errors';
4
- import { Organization, OrganizationRegistrationPeriod, PayconiqPayment, Platform, RegistrationPeriod, StripeAccount, Webshop } from '@stamhoofd/models';
5
- import { BuckarooSettings, Company, OrganizationMetaData, OrganizationPatch, Organization as OrganizationStruct, PayconiqAccount, PaymentMethod, PaymentMethodHelper, PermissionLevel } from "@stamhoofd/structures";
4
+ import { Organization, OrganizationRegistrationPeriod, PayconiqPayment, Platform, RegistrationPeriod, SetupStepUpdater, StripeAccount, Webshop } from '@stamhoofd/models';
5
+ import { BuckarooSettings, Company, OrganizationMetaData, OrganizationPatch, Organization as OrganizationStruct, PayconiqAccount, PaymentMethod, PaymentMethodHelper, PermissionLevel } from '@stamhoofd/structures';
6
6
  import { Formatter } from '@stamhoofd/utility';
7
7
 
8
8
  import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
9
9
  import { BuckarooHelper } from '../../../../helpers/BuckarooHelper';
10
10
  import { Context } from '../../../../helpers/Context';
11
- import { SetupStepUpdater } from '../../../../helpers/SetupStepsUpdater';
12
11
  import { ViesHelper } from '../../../../helpers/ViesHelper';
13
12
 
14
13
  type Params = Record<string, never>;
@@ -21,14 +20,14 @@ type ResponseBody = OrganizationStruct;
21
20
  */
22
21
 
23
22
  export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
24
- bodyDecoder = OrganizationPatch as Decoder<AutoEncoderPatchType<OrganizationStruct>>
23
+ bodyDecoder = OrganizationPatch as Decoder<AutoEncoderPatchType<OrganizationStruct>>;
25
24
 
26
25
  protected doesMatch(request: Request): [true, Params] | [false] {
27
- if (request.method != "PATCH") {
26
+ if (request.method !== 'PATCH') {
28
27
  return [false];
29
28
  }
30
29
 
31
- const params = Endpoint.parseParameters(request.url, "/organization", {});
30
+ const params = Endpoint.parseParameters(request.url, '/organization', {});
32
31
 
33
32
  if (params) {
34
33
  return [true, params as Params];
@@ -37,116 +36,115 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
37
36
  }
38
37
 
39
38
  async handle(request: DecodedRequest<Params, Query, Body>) {
40
- const organization = await Context.setOrganizationScope({allowInactive: true});
41
- await Context.authenticate()
39
+ const organization = await Context.setOrganizationScope({ allowInactive: true });
40
+ await Context.authenticate();
42
41
 
43
42
  if (!await Context.auth.hasSomeAccess(organization.id)) {
44
- throw Context.auth.error()
43
+ throw Context.auth.error();
45
44
  }
46
45
 
47
46
  if (!organization.active && !Context.auth.hasPlatformFullAccess()) {
48
47
  throw new SimpleError({
49
- code: "permission_denied",
50
- message: "You do not have permissions to edit an inactive organization",
48
+ code: 'permission_denied',
49
+ message: 'You do not have permissions to edit an inactive organization',
51
50
  human: 'Je hebt geen toegangsrechten om een inactieve groep te bewerken',
52
- statusCode: 403
53
- })
54
-
51
+ statusCode: 403,
52
+ });
55
53
  }
56
-
54
+
57
55
  // check if organization ID matches
58
56
  if (request.body.id !== organization.id) {
59
57
  throw new SimpleError({
60
- code: "invalid_id",
61
- message: "You cannot modify an organization with a different ID than the organization you are signed in for",
62
- statusCode: 403
63
- })
58
+ code: 'invalid_id',
59
+ message: 'You cannot modify an organization with a different ID than the organization you are signed in for',
60
+ statusCode: 403,
61
+ });
64
62
  }
65
63
 
66
- const errors = new SimpleErrors()
64
+ const errors = new SimpleErrors();
67
65
  let shouldUpdateSetupSteps = false;
68
66
 
69
67
  if (await Context.auth.hasFullAccess(organization.id)) {
70
- organization.name = request.body.name ?? organization.name
68
+ organization.name = request.body.name ?? organization.name;
71
69
  if (request.body.website !== undefined) {
72
70
  organization.website = request.body.website;
73
71
  }
74
72
 
75
73
  if (request.body.address) {
76
- organization.address = organization.address.patch(request.body.address)
74
+ organization.address = organization.address.patch(request.body.address);
77
75
  }
78
76
 
79
77
  if (request.body.uri && request.body.uri !== organization.uri) {
80
78
  const slugified = Formatter.slug(request.body.uri);
81
79
  if (slugified.length > 100) {
82
80
  throw new SimpleError({
83
- code: "invalid_field",
84
- message: "Field is too long",
85
- human: "De URI van de vereniging is te lang",
86
- field: "uri"
87
- })
81
+ code: 'invalid_field',
82
+ message: 'Field is too long',
83
+ human: 'De URI van de vereniging is te lang',
84
+ field: 'uri',
85
+ });
88
86
  }
89
87
 
90
88
  if (slugified.length < 3) {
91
89
  throw new SimpleError({
92
- code: "invalid_field",
93
- message: "Field is too short",
94
- human: "De URI van de vereniging is te kort",
95
- field: "uri"
96
- })
90
+ code: 'invalid_field',
91
+ message: 'Field is too short',
92
+ human: 'De URI van de vereniging is te kort',
93
+ field: 'uri',
94
+ });
97
95
  }
98
96
  const alreadyExists = await Organization.getByURI(slugified);
99
97
 
100
98
  if (alreadyExists) {
101
99
  throw new SimpleError({
102
- code: "name_taken",
103
- message: "An organization with the same URI already exists",
104
- human: "Er bestaat al een vereniging met dezelfde URI. Voeg bijvoorbeeld de naam van je gemeente toe.",
105
- field: "uri",
100
+ code: 'name_taken',
101
+ message: 'An organization with the same URI already exists',
102
+ human: 'Er bestaat al een vereniging met dezelfde URI. Voeg bijvoorbeeld de naam van je gemeente toe.',
103
+ field: 'uri',
106
104
  });
107
105
  }
108
106
 
109
- organization.uri = slugified
107
+ organization.uri = slugified;
110
108
  }
111
109
 
112
110
  if (request.body.privateMeta && request.body.privateMeta.isPatch()) {
113
- organization.privateMeta.emails = request.body.privateMeta.emails.applyTo(organization.privateMeta.emails)
114
- if(request.body.privateMeta.emails) {
111
+ organization.privateMeta.emails = request.body.privateMeta.emails.applyTo(organization.privateMeta.emails);
112
+ if (request.body.privateMeta.emails) {
115
113
  shouldUpdateSetupSteps = true;
116
114
  }
117
115
 
118
116
  organization.privateMeta.premises = patchObject(organization.privateMeta.premises, request.body.privateMeta.premises);
119
- if(request.body.privateMeta.premises) {
117
+ if (request.body.privateMeta.premises) {
120
118
  shouldUpdateSetupSteps = true;
121
119
  }
122
- organization.privateMeta.roles = request.body.privateMeta.roles.applyTo(organization.privateMeta.roles)
123
- organization.privateMeta.responsibilities = request.body.privateMeta.responsibilities.applyTo(organization.privateMeta.responsibilities)
124
- organization.privateMeta.inheritedResponsibilityRoles = request.body.privateMeta.inheritedResponsibilityRoles.applyTo(organization.privateMeta.inheritedResponsibilityRoles)
125
- organization.privateMeta.privateKey = request.body.privateMeta.privateKey ?? organization.privateMeta.privateKey
120
+ organization.privateMeta.roles = request.body.privateMeta.roles.applyTo(organization.privateMeta.roles);
121
+ organization.privateMeta.responsibilities = request.body.privateMeta.responsibilities.applyTo(organization.privateMeta.responsibilities);
122
+ organization.privateMeta.inheritedResponsibilityRoles = request.body.privateMeta.inheritedResponsibilityRoles.applyTo(organization.privateMeta.inheritedResponsibilityRoles);
123
+ organization.privateMeta.privateKey = request.body.privateMeta.privateKey ?? organization.privateMeta.privateKey;
126
124
  organization.privateMeta.featureFlags = patchObject(organization.privateMeta.featureFlags, request.body.privateMeta.featureFlags);
127
125
 
128
126
  if (request.body.privateMeta.mollieProfile !== undefined) {
129
- organization.privateMeta.mollieProfile = patchObject(organization.privateMeta.mollieProfile, request.body.privateMeta.mollieProfile)
127
+ organization.privateMeta.mollieProfile = patchObject(organization.privateMeta.mollieProfile, request.body.privateMeta.mollieProfile);
130
128
  }
131
129
 
132
130
  if (request.body.privateMeta.useTestPayments !== undefined) {
133
- organization.privateMeta.useTestPayments = request.body.privateMeta.useTestPayments
131
+ organization.privateMeta.useTestPayments = request.body.privateMeta.useTestPayments;
134
132
  }
135
133
 
136
134
  // Apply payconiq patch
137
135
  if (request.body.privateMeta.payconiqAccounts !== undefined) {
138
- organization.privateMeta.payconiqAccounts = patchObject(organization.privateMeta.payconiqAccounts, request.body.privateMeta.payconiqAccounts)
136
+ organization.privateMeta.payconiqAccounts = patchObject(organization.privateMeta.payconiqAccounts, request.body.privateMeta.payconiqAccounts);
139
137
 
140
138
  for (const account of organization.privateMeta.payconiqAccounts) {
141
139
  if (account.merchantId === null) {
142
- const payment = await PayconiqPayment.createTest(organization, account)
143
-
140
+ const payment = await PayconiqPayment.createTest(organization, account);
141
+
144
142
  if (!payment) {
145
143
  throw new SimpleError({
146
- code: "invalid_field",
147
- message: "De API-key voor Payconiq is niet geldig. Kijk eens na of je wel de juiste key hebt ingevuld.",
148
- field: "payconiqAccounts"
149
- })
144
+ code: 'invalid_field',
145
+ message: 'De API-key voor Payconiq is niet geldig. Kijk eens na of je wel de juiste key hebt ingevuld.',
146
+ field: 'payconiqAccounts',
147
+ });
150
148
  }
151
149
 
152
150
  // Save merchant id
@@ -155,14 +153,14 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
155
153
  ...(payment as any).creditor,
156
154
  id: account.id,
157
155
  apiKey: account.apiKey,
158
- }, {version: 0})
159
- )
160
-
161
- account.merchantId = decoded.merchantId
162
- account.callbackUrl = decoded.callbackUrl
163
- account.profileId = decoded.profileId
164
- account.name = decoded.name
165
- account.iban = decoded.iban
156
+ }, { version: 0 }),
157
+ );
158
+
159
+ account.merchantId = decoded.merchantId;
160
+ account.callbackUrl = decoded.callbackUrl;
161
+ account.profileId = decoded.profileId;
162
+ account.name = decoded.name;
163
+ account.iban = decoded.iban;
166
164
  }
167
165
  }
168
166
  }
@@ -170,41 +168,42 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
170
168
  if (request.body.privateMeta.buckarooSettings !== undefined) {
171
169
  if (request.body.privateMeta.buckarooSettings === null) {
172
170
  organization.privateMeta.buckarooSettings = null;
173
- } else {
174
- organization.privateMeta.buckarooSettings = organization.privateMeta.buckarooSettings ?? BuckarooSettings.create({})
175
- organization.privateMeta.buckarooSettings.patchOrPut(request.body.privateMeta.buckarooSettings)
171
+ }
172
+ else {
173
+ organization.privateMeta.buckarooSettings = organization.privateMeta.buckarooSettings ?? BuckarooSettings.create({});
174
+ organization.privateMeta.buckarooSettings.patchOrPut(request.body.privateMeta.buckarooSettings);
176
175
 
177
176
  // Validate buckaroo settings
178
- const buckaroo = new BuckarooHelper(organization.privateMeta.buckarooSettings.key, organization.privateMeta.buckarooSettings.secret, organization.privateMeta.useTestPayments ?? STAMHOOFD.environment != 'production')
177
+ const buckaroo = new BuckarooHelper(organization.privateMeta.buckarooSettings.key, organization.privateMeta.buckarooSettings.secret, organization.privateMeta.useTestPayments ?? STAMHOOFD.environment !== 'production');
179
178
 
180
179
  if (!(await buckaroo.createTest())) {
181
180
  throw new SimpleError({
182
- code: "invalid_field",
183
- message: "De key of secret voor Buckaroo is niet geldig. Kijk eens na of je wel de juiste key hebt ingevuld.",
184
- field: "buckarooSettings"
185
- })
181
+ code: 'invalid_field',
182
+ message: 'De key of secret voor Buckaroo is niet geldig. Kijk eens na of je wel de juiste key hebt ingevuld.',
183
+ field: 'buckarooSettings',
184
+ });
186
185
  }
187
186
  }
188
187
  }
189
188
 
190
189
  if (request.body.privateMeta.registrationPaymentConfiguration?.stripeAccountId !== undefined) {
191
190
  if (request.body.privateMeta.registrationPaymentConfiguration.stripeAccountId !== null) {
192
- const account = await StripeAccount.getByID(request.body.privateMeta.registrationPaymentConfiguration.stripeAccountId)
191
+ const account = await StripeAccount.getByID(request.body.privateMeta.registrationPaymentConfiguration.stripeAccountId);
193
192
  if (!account || account.organizationId !== organization.id) {
194
193
  throw new SimpleError({
195
- code: "invalid_field",
196
- message: "Het Stripe account dat je hebt gekozen bestaat niet (meer)",
197
- field: "registrationPaymentConfiguration.stripeAccountId"
198
- })
194
+ code: 'invalid_field',
195
+ message: 'Het Stripe account dat je hebt gekozen bestaat niet (meer)',
196
+ field: 'registrationPaymentConfiguration.stripeAccountId',
197
+ });
199
198
  }
200
199
  }
201
- organization.privateMeta.registrationPaymentConfiguration.stripeAccountId = request.body.privateMeta.registrationPaymentConfiguration.stripeAccountId
200
+ organization.privateMeta.registrationPaymentConfiguration.stripeAccountId = request.body.privateMeta.registrationPaymentConfiguration.stripeAccountId;
202
201
  }
203
202
  }
204
203
 
205
204
  // Allow admin patches (permissions only atm). No put atm
206
205
  if (request.body.admins) {
207
- throw new Error("Temporary removed to keep code cleaner. Please use different endpoints.")
206
+ throw new Error('Temporary removed to keep code cleaner. Please use different endpoints.');
208
207
  // for (const patch of request.body.admins.getPatches()) {
209
208
  // if (patch.permissions) {
210
209
  // const admin = await User.getByID(patch.id)
@@ -229,227 +228,227 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
229
228
 
230
229
  if (request.body.meta) {
231
230
  if (request.body.meta.companies) {
232
- await this.validateCompanies(organization, request.body.meta.companies)
233
- shouldUpdateSetupSteps = true
231
+ await this.validateCompanies(organization, request.body.meta.companies);
232
+ shouldUpdateSetupSteps = true;
234
233
  }
235
234
 
236
- const savedPackages = organization.meta.packages
237
- organization.meta.patchOrPut(request.body.meta)
238
- organization.meta.packages = savedPackages
235
+ const savedPackages = organization.meta.packages;
236
+ organization.meta.patchOrPut(request.body.meta);
237
+ organization.meta.packages = savedPackages;
239
238
 
240
239
  // check payconiq + mollie
241
240
  if (request.body.meta.registrationPaymentConfiguration) {
242
241
  if (!organization.privateMeta.payconiqApiKey && !organization.privateMeta.buckarooSettings?.paymentMethods.includes(PaymentMethod.Payconiq)) {
243
- const i = organization.meta.paymentMethods.findIndex(p => p == PaymentMethod.Payconiq)
244
- if (i != -1) {
242
+ const i = organization.meta.paymentMethods.findIndex(p => p == PaymentMethod.Payconiq);
243
+ if (i !== -1) {
245
244
  throw new SimpleError({
246
- code: "invalid_field",
247
- message: "Je kan Payconiq niet activeren omdat je geen Payconiq API Key hebt ingesteld. Schakel Payconiq uit voor je verder gaat.",
248
- field: "paymentMethods"
249
- })
245
+ code: 'invalid_field',
246
+ message: 'Je kan Payconiq niet activeren omdat je geen Payconiq API Key hebt ingesteld. Schakel Payconiq uit voor je verder gaat.',
247
+ field: 'paymentMethods',
248
+ });
250
249
  }
251
250
  }
252
251
 
253
252
  // check payconiq + mollie
254
253
  if (!organization.privateMeta.mollieOnboarding || !organization.privateMeta.mollieOnboarding.canReceivePayments) {
255
- let stripe: StripeAccount | undefined = undefined
254
+ let stripe: StripeAccount | undefined = undefined;
256
255
  if (organization.privateMeta.registrationPaymentConfiguration.stripeAccountId) {
257
- stripe = await StripeAccount.getByID(organization.privateMeta.registrationPaymentConfiguration.stripeAccountId)
256
+ stripe = await StripeAccount.getByID(organization.privateMeta.registrationPaymentConfiguration.stripeAccountId);
258
257
  }
259
258
 
260
- const i = organization.meta.paymentMethods.findIndex(p => {
261
- if (p === PaymentMethod.Payconiq) return
262
- if (p === PaymentMethod.Transfer) return
263
- if (p === PaymentMethod.PointOfSale) return
259
+ const i = organization.meta.paymentMethods.findIndex((p) => {
260
+ if (p === PaymentMethod.Payconiq) return;
261
+ if (p === PaymentMethod.Transfer) return;
262
+ if (p === PaymentMethod.PointOfSale) return;
264
263
 
265
264
  if (!organization.privateMeta.buckarooSettings?.paymentMethods.includes(p)) {
266
265
  if (!stripe?.meta.paymentMethods.includes(p)) {
267
- return true
266
+ return true;
268
267
  }
269
268
  }
270
- })
271
- if (i != -1) {
269
+ });
270
+ if (i !== -1) {
272
271
  throw new SimpleError({
273
- code: "invalid_field",
274
- message: "Je kan "+PaymentMethodHelper.getName(organization.meta.paymentMethods[i])+" niet activeren omdat je daarvoor nog niet aangesloten bent bij een betaalpartner. Schakel "+PaymentMethodHelper.getName(organization.meta.paymentMethods[i])+" uit voor je verder gaat.",
275
- field: "paymentMethods"
276
- })
272
+ code: 'invalid_field',
273
+ message: 'Je kan ' + PaymentMethodHelper.getName(organization.meta.paymentMethods[i]) + ' niet activeren omdat je daarvoor nog niet aangesloten bent bij een betaalpartner. Schakel ' + PaymentMethodHelper.getName(organization.meta.paymentMethods[i]) + ' uit voor je verder gaat.',
274
+ field: 'paymentMethods',
275
+ });
277
276
  }
278
277
  }
279
278
  }
280
279
 
281
280
  if (request.body.meta?.tags && (Array.isArray(request.body.meta?.tags) || request.body.meta?.tags.changes.length > 0)) {
282
281
  if (!Context.auth.hasPlatformFullAccess()) {
283
- throw Context.auth.error()
282
+ throw Context.auth.error();
284
283
  }
285
284
 
286
285
  const cleanedPatch = OrganizationMetaData.patch({
287
- tags: request.body.meta.tags as any
288
- })
289
- const platform = await Platform.getShared()
286
+ tags: request.body.meta.tags as any,
287
+ });
288
+ const platform = await Platform.getShared();
290
289
  const patchedMeta = organization.meta.patch(cleanedPatch);
291
290
  for (const tag of patchedMeta.tags) {
292
291
  if (!platform.config.tags.find(t => t.id === tag)) {
293
- throw new SimpleError({ code: "invalid_tag", message: "Invalid tag", statusCode: 400 });
292
+ throw new SimpleError({ code: 'invalid_tag', message: 'Invalid tag', statusCode: 400 });
294
293
  }
295
294
  }
296
-
295
+
297
296
  // Sort tags based on platform config order
298
297
  patchedMeta.tags.sort((a, b) => {
299
298
  const aIndex = platform.config.tags.findIndex(t => t.id === a);
300
299
  const bIndex = platform.config.tags.findIndex(t => t.id === b);
301
300
  return aIndex - bIndex;
302
- })
303
-
301
+ });
302
+
304
303
  organization.meta.tags = patchedMeta.tags;
305
304
  }
306
305
  }
307
306
 
308
307
  if (request.body.active !== undefined) {
309
308
  if (!Context.auth.hasPlatformFullAccess()) {
310
- throw Context.auth.error('Enkel een platform hoofdbeheerder kan een groep (in)actief maken')
309
+ throw Context.auth.error('Enkel een platform hoofdbeheerder kan een groep (in)actief maken');
311
310
  }
312
311
  organization.active = request.body.active;
313
312
  }
314
313
 
315
314
  if (request.body.uri) {
316
315
  if (!Context.auth.hasPlatformFullAccess()) {
317
- throw Context.auth.error()
316
+ throw Context.auth.error();
318
317
  }
319
-
318
+
320
319
  const uriExists = await Organization.getByURI(request.body.uri);
321
-
320
+
322
321
  if (uriExists && uriExists.id !== organization.id) {
323
322
  throw new SimpleError({
324
- code: "name_taken",
325
- message: "An organization with the same name already exists",
326
- human: "Er bestaat al een vereniging met dezelfde URI. Pas deze aan zodat deze uniek is, en controleer of deze vereniging niet al bestaat.",
327
- field: "name",
323
+ code: 'name_taken',
324
+ message: 'An organization with the same name already exists',
325
+ human: 'Er bestaat al een vereniging met dezelfde URI. Pas deze aan zodat deze uniek is, en controleer of deze vereniging niet al bestaat.',
326
+ field: 'name',
328
327
  });
329
328
  }
330
329
 
331
- organization.uri = request.body.uri
330
+ organization.uri = request.body.uri;
332
331
  }
333
332
 
334
333
  if (request.body.period && request.body.period.id !== organization.periodId) {
335
- const organizationPeriod = await OrganizationRegistrationPeriod.getByID(request.body.period.id)
334
+ const organizationPeriod = await OrganizationRegistrationPeriod.getByID(request.body.period.id);
336
335
  if (!organizationPeriod || organizationPeriod.organizationId !== organization.id) {
337
336
  throw new SimpleError({
338
- code: "invalid_field",
339
- message: "De periode die je wilt instellen bestaat niet (meer)",
340
- field: "period"
341
- })
337
+ code: 'invalid_field',
338
+ message: 'De periode die je wilt instellen bestaat niet (meer)',
339
+ field: 'period',
340
+ });
342
341
  }
343
342
 
344
- const period = await RegistrationPeriod.getByID(organizationPeriod.periodId)
343
+ const period = await RegistrationPeriod.getByID(organizationPeriod.periodId);
345
344
  if (!period || (period.organizationId && period.organizationId !== organization.id)) {
346
345
  throw new SimpleError({
347
- code: "invalid_field",
348
- message: "De periode die je wilt instellen bestaat niet (meer)",
349
- field: "period"
350
- })
346
+ code: 'invalid_field',
347
+ message: 'De periode die je wilt instellen bestaat niet (meer)',
348
+ field: 'period',
349
+ });
351
350
  }
352
351
 
353
352
  if (period.locked) {
354
353
  throw new SimpleError({
355
- code: "invalid_field",
356
- message: "De periode die je wilt instellen is reeds afgesloten",
357
- field: "period"
358
- })
354
+ code: 'invalid_field',
355
+ message: 'De periode die je wilt instellen is reeds afgesloten',
356
+ field: 'period',
357
+ });
359
358
  }
360
359
 
361
- organization.periodId = period.id
360
+ organization.periodId = period.id;
362
361
  shouldUpdateSetupSteps = true;
363
362
  }
364
363
 
365
364
  // Save the organization
366
- await organization.save()
367
- } else {
365
+ await organization.save();
366
+ }
367
+ else {
368
368
  if (request.body.name || request.body.address) {
369
369
  throw new SimpleError({
370
- code: "permission_denied",
371
- message: "You do not have permissions to edit the organization settings",
372
- statusCode: 403
373
- })
370
+ code: 'permission_denied',
371
+ message: 'You do not have permissions to edit the organization settings',
372
+ statusCode: 403,
373
+ });
374
374
  }
375
375
  }
376
376
 
377
377
  // Only needed for permissions atm, so no put or delete here
378
378
  for (const struct of request.body.webshops.getPatches()) {
379
- const model = await Webshop.getByID(struct.id)
379
+ const model = await Webshop.getByID(struct.id);
380
380
 
381
381
  if (!model || !await Context.auth.canAccessWebshop(model, PermissionLevel.Full)) {
382
382
  errors.addError(
383
- Context.auth.error('Je hebt geen toegangsrechten om deze webshop te wijzigen')
384
- )
383
+ Context.auth.error('Je hebt geen toegangsrechten om deze webshop te wijzigen'),
384
+ );
385
385
  continue;
386
386
  }
387
387
 
388
388
  if (struct.meta) {
389
- model.meta.patchOrPut(struct.meta)
389
+ model.meta.patchOrPut(struct.meta);
390
390
  }
391
-
391
+
392
392
  if (struct.privateMeta) {
393
- model.privateMeta.patchOrPut(struct.privateMeta)
393
+ model.privateMeta.patchOrPut(struct.privateMeta);
394
394
  }
395
-
395
+
396
396
  await model.save();
397
- }
397
+ }
398
398
 
399
- errors.throwIfNotEmpty()
399
+ errors.throwIfNotEmpty();
400
400
 
401
- if(shouldUpdateSetupSteps) {
401
+ if (shouldUpdateSetupSteps) {
402
402
  await SetupStepUpdater.updateForOrganization(organization);
403
403
  }
404
-
404
+
405
405
  return new Response(await AuthenticatedStructures.organization(organization));
406
406
  }
407
407
 
408
- async validateCompanies(organization: Organization, companies: PatchableArrayAutoEncoder<Company>|Company[]) {
408
+ async validateCompanies(organization: Organization, companies: PatchableArrayAutoEncoder<Company> | Company[]) {
409
409
  if (isPatchableArray(companies)) {
410
410
  for (const patch of companies.getPatches()) {
411
411
  // Changed VAT number
412
- const original = organization.meta.companies.find(c => c.id === patch.id)
412
+ const original = organization.meta.companies.find(c => c.id === patch.id);
413
413
 
414
414
  if (!original) {
415
- throw new Error('Could not find company')
415
+ throw new Error('Could not find company');
416
416
  }
417
-
417
+
418
418
  // Changed VAT number
419
- const prepatched = original.patch(patch)
420
- await ViesHelper.checkCompany(prepatched, patch)
419
+ const prepatched = original.patch(patch);
420
+ await ViesHelper.checkCompany(prepatched, patch);
421
421
  }
422
422
 
423
423
  let c = 0;
424
- for (const {put} of companies.getPuts()) {
424
+ for (const { put } of companies.getPuts()) {
425
425
  c++;
426
-
426
+
427
427
  if ((organization.meta.companies.length + c) > 5) {
428
428
  throw new SimpleError({
429
- code: "invalid_field",
430
- message: "Too many companies",
431
- human: "Je kan maximaal 5 bedrijven toevoegen",
432
- field: "companies"
433
- })
429
+ code: 'invalid_field',
430
+ message: 'Too many companies',
431
+ human: 'Je kan maximaal 5 bedrijven toevoegen',
432
+ field: 'companies',
433
+ });
434
434
  }
435
435
 
436
- await ViesHelper.checkCompany(put, put)
436
+ await ViesHelper.checkCompany(put, put);
437
437
  }
438
-
439
- } else {
438
+ }
439
+ else {
440
440
  if (companies.length > 5) {
441
441
  throw new SimpleError({
442
- code: "invalid_field",
443
- message: "Too many companies",
444
- human: "Je kan maximaal 5 bedrijven toevoegen",
445
- field: "companies"
446
- })
442
+ code: 'invalid_field',
443
+ message: 'Too many companies',
444
+ human: 'Je kan maximaal 5 bedrijven toevoegen',
445
+ field: 'companies',
446
+ });
447
447
  }
448
448
 
449
449
  for (const company of companies) {
450
- await ViesHelper.checkCompany(company, company)
450
+ await ViesHelper.checkCompany(company, company);
451
451
  }
452
452
  }
453
453
  }
454
454
  }
455
-