@endora-commerce/mod-organizations 0.100.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 (288) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/dist/admin/components/OrganizationSalesRepsTab.d.ts +27 -0
  4. package/dist/admin/components/OrganizationSalesRepsTab.d.ts.map +1 -0
  5. package/dist/admin/components/OrganizationSalesRepsTab.js +170 -0
  6. package/dist/admin/components/OrganizationSalesRepsTab.js.map +1 -0
  7. package/dist/admin/index.d.ts +30 -0
  8. package/dist/admin/index.d.ts.map +1 -0
  9. package/dist/admin/index.js +59 -0
  10. package/dist/admin/index.js.map +1 -0
  11. package/dist/admin/pages/OrganizationDetail.d.ts +9 -0
  12. package/dist/admin/pages/OrganizationDetail.d.ts.map +1 -0
  13. package/dist/admin/pages/OrganizationDetail.js +247 -0
  14. package/dist/admin/pages/OrganizationDetail.js.map +1 -0
  15. package/dist/admin/pages/OrganizationsList.d.ts +9 -0
  16. package/dist/admin/pages/OrganizationsList.d.ts.map +1 -0
  17. package/dist/admin/pages/OrganizationsList.js +73 -0
  18. package/dist/admin/pages/OrganizationsList.js.map +1 -0
  19. package/dist/admin/panels/ApplicablePriceListsPanel.d.ts +12 -0
  20. package/dist/admin/panels/ApplicablePriceListsPanel.d.ts.map +1 -0
  21. package/dist/admin/panels/ApplicablePriceListsPanel.js +49 -0
  22. package/dist/admin/panels/ApplicablePriceListsPanel.js.map +1 -0
  23. package/dist/admin/panels/FulfilmentStrategyPanel.d.ts +16 -0
  24. package/dist/admin/panels/FulfilmentStrategyPanel.d.ts.map +1 -0
  25. package/dist/admin/panels/FulfilmentStrategyPanel.js +29 -0
  26. package/dist/admin/panels/FulfilmentStrategyPanel.js.map +1 -0
  27. package/dist/admin/panels/HierarchyPanel.d.ts +15 -0
  28. package/dist/admin/panels/HierarchyPanel.d.ts.map +1 -0
  29. package/dist/admin/panels/HierarchyPanel.js +65 -0
  30. package/dist/admin/panels/HierarchyPanel.js.map +1 -0
  31. package/dist/admin/panels/ModerationActionsPanel.d.ts +28 -0
  32. package/dist/admin/panels/ModerationActionsPanel.d.ts.map +1 -0
  33. package/dist/admin/panels/ModerationActionsPanel.js +111 -0
  34. package/dist/admin/panels/ModerationActionsPanel.js.map +1 -0
  35. package/dist/admin/panels/RestrictionsPanel.d.ts +24 -0
  36. package/dist/admin/panels/RestrictionsPanel.d.ts.map +1 -0
  37. package/dist/admin/panels/RestrictionsPanel.js +121 -0
  38. package/dist/admin/panels/RestrictionsPanel.js.map +1 -0
  39. package/dist/admin/panels/VatValidationPanel.d.ts +28 -0
  40. package/dist/admin/panels/VatValidationPanel.d.ts.map +1 -0
  41. package/dist/admin/panels/VatValidationPanel.js +79 -0
  42. package/dist/admin/panels/VatValidationPanel.js.map +1 -0
  43. package/dist/backend/commands/move.command.d.ts +11 -0
  44. package/dist/backend/commands/move.command.d.ts.map +1 -0
  45. package/dist/backend/commands/move.command.js +11 -0
  46. package/dist/backend/commands/move.command.js.map +1 -0
  47. package/dist/backend/commands/set-cart-approval-policy.command.d.ts +31 -0
  48. package/dist/backend/commands/set-cart-approval-policy.command.d.ts.map +1 -0
  49. package/dist/backend/commands/set-cart-approval-policy.command.js +56 -0
  50. package/dist/backend/commands/set-cart-approval-policy.command.js.map +1 -0
  51. package/dist/backend/commands/set-credit-mode.command.d.ts +16 -0
  52. package/dist/backend/commands/set-credit-mode.command.d.ts.map +1 -0
  53. package/dist/backend/commands/set-credit-mode.command.js +25 -0
  54. package/dist/backend/commands/set-credit-mode.command.js.map +1 -0
  55. package/dist/backend/commands/set-parent.command.d.ts +26 -0
  56. package/dist/backend/commands/set-parent.command.d.ts.map +1 -0
  57. package/dist/backend/commands/set-parent.command.js +51 -0
  58. package/dist/backend/commands/set-parent.command.js.map +1 -0
  59. package/dist/backend/demo/reset.d.ts +20 -0
  60. package/dist/backend/demo/reset.d.ts.map +1 -0
  61. package/dist/backend/demo/reset.js +11 -0
  62. package/dist/backend/demo/reset.js.map +1 -0
  63. package/dist/backend/demo/rows.d.ts +44 -0
  64. package/dist/backend/demo/rows.d.ts.map +1 -0
  65. package/dist/backend/demo/rows.js +44 -0
  66. package/dist/backend/demo/rows.js.map +1 -0
  67. package/dist/backend/demo/seed.d.ts +20 -0
  68. package/dist/backend/demo/seed.d.ts.map +1 -0
  69. package/dist/backend/demo/seed.js +28 -0
  70. package/dist/backend/demo/seed.js.map +1 -0
  71. package/dist/backend/email-templates/invitation.d.ts +23 -0
  72. package/dist/backend/email-templates/invitation.d.ts.map +1 -0
  73. package/dist/backend/email-templates/invitation.js +35 -0
  74. package/dist/backend/email-templates/invitation.js.map +1 -0
  75. package/dist/backend/email-templates/transactional-defaults.d.ts +54 -0
  76. package/dist/backend/email-templates/transactional-defaults.d.ts.map +1 -0
  77. package/dist/backend/email-templates/transactional-defaults.js +242 -0
  78. package/dist/backend/email-templates/transactional-defaults.js.map +1 -0
  79. package/dist/backend/email-templates/verification.d.ts +14 -0
  80. package/dist/backend/email-templates/verification.d.ts.map +1 -0
  81. package/dist/backend/email-templates/verification.js +34 -0
  82. package/dist/backend/email-templates/verification.js.map +1 -0
  83. package/dist/backend/entities/email-verification-token.entity.d.ts +17 -0
  84. package/dist/backend/entities/email-verification-token.entity.d.ts.map +1 -0
  85. package/dist/backend/entities/email-verification-token.entity.js +60 -0
  86. package/dist/backend/entities/email-verification-token.entity.js.map +1 -0
  87. package/dist/backend/entities/organization-delivery-method-link.entity.d.ts +14 -0
  88. package/dist/backend/entities/organization-delivery-method-link.entity.d.ts.map +1 -0
  89. package/dist/backend/entities/organization-delivery-method-link.entity.js +41 -0
  90. package/dist/backend/entities/organization-delivery-method-link.entity.js.map +1 -0
  91. package/dist/backend/entities/organization-invitation.entity.d.ts +21 -0
  92. package/dist/backend/entities/organization-invitation.entity.d.ts.map +1 -0
  93. package/dist/backend/entities/organization-invitation.entity.js +85 -0
  94. package/dist/backend/entities/organization-invitation.entity.js.map +1 -0
  95. package/dist/backend/entities/organization-payment-method-link.entity.d.ts +14 -0
  96. package/dist/backend/entities/organization-payment-method-link.entity.d.ts.map +1 -0
  97. package/dist/backend/entities/organization-payment-method-link.entity.js +41 -0
  98. package/dist/backend/entities/organization-payment-method-link.entity.js.map +1 -0
  99. package/dist/backend/entities/organization-sales-rep-assignment.entity.d.ts +17 -0
  100. package/dist/backend/entities/organization-sales-rep-assignment.entity.d.ts.map +1 -0
  101. package/dist/backend/entities/organization-sales-rep-assignment.entity.js +56 -0
  102. package/dist/backend/entities/organization-sales-rep-assignment.entity.js.map +1 -0
  103. package/dist/backend/entities/organization-tax-id-validation.entity.d.ts +29 -0
  104. package/dist/backend/entities/organization-tax-id-validation.entity.d.ts.map +1 -0
  105. package/dist/backend/entities/organization-tax-id-validation.entity.js +78 -0
  106. package/dist/backend/entities/organization-tax-id-validation.entity.js.map +1 -0
  107. package/dist/backend/entities/organization-warehouse-link.entity.d.ts +15 -0
  108. package/dist/backend/entities/organization-warehouse-link.entity.d.ts.map +1 -0
  109. package/dist/backend/entities/organization-warehouse-link.entity.js +42 -0
  110. package/dist/backend/entities/organization-warehouse-link.entity.js.map +1 -0
  111. package/dist/backend/entities/organization.entity.d.ts +125 -0
  112. package/dist/backend/entities/organization.entity.d.ts.map +1 -0
  113. package/dist/backend/entities/organization.entity.js +282 -0
  114. package/dist/backend/entities/organization.entity.js.map +1 -0
  115. package/dist/backend/index.d.ts +250 -0
  116. package/dist/backend/index.d.ts.map +1 -0
  117. package/dist/backend/index.js +506 -0
  118. package/dist/backend/index.js.map +1 -0
  119. package/dist/backend/integrations/ministerstwo-finansow-client.d.ts +22 -0
  120. package/dist/backend/integrations/ministerstwo-finansow-client.d.ts.map +1 -0
  121. package/dist/backend/integrations/ministerstwo-finansow-client.js +172 -0
  122. package/dist/backend/integrations/ministerstwo-finansow-client.js.map +1 -0
  123. package/dist/backend/integrations/vies-client.d.ts +18 -0
  124. package/dist/backend/integrations/vies-client.d.ts.map +1 -0
  125. package/dist/backend/integrations/vies-client.js +133 -0
  126. package/dist/backend/integrations/vies-client.js.map +1 -0
  127. package/dist/backend/plugin.d.ts +126 -0
  128. package/dist/backend/plugin.d.ts.map +1 -0
  129. package/dist/backend/plugin.js +139 -0
  130. package/dist/backend/plugin.js.map +1 -0
  131. package/dist/backend/routes.admin.d.ts +66 -0
  132. package/dist/backend/routes.admin.d.ts.map +1 -0
  133. package/dist/backend/routes.admin.js +711 -0
  134. package/dist/backend/routes.admin.js.map +1 -0
  135. package/dist/backend/routes.customer.d.ts +33 -0
  136. package/dist/backend/routes.customer.d.ts.map +1 -0
  137. package/dist/backend/routes.customer.js +139 -0
  138. package/dist/backend/routes.customer.js.map +1 -0
  139. package/dist/backend/routes.members.d.ts +31 -0
  140. package/dist/backend/routes.members.d.ts.map +1 -0
  141. package/dist/backend/routes.members.js +109 -0
  142. package/dist/backend/routes.members.js.map +1 -0
  143. package/dist/backend/routes.public.d.ts +49 -0
  144. package/dist/backend/routes.public.d.ts.map +1 -0
  145. package/dist/backend/routes.public.js +220 -0
  146. package/dist/backend/routes.public.js.map +1 -0
  147. package/dist/backend/routes.sales-reps.d.ts +46 -0
  148. package/dist/backend/routes.sales-reps.d.ts.map +1 -0
  149. package/dist/backend/routes.sales-reps.js +114 -0
  150. package/dist/backend/routes.sales-reps.js.map +1 -0
  151. package/dist/backend/routes.storefront.d.ts +25 -0
  152. package/dist/backend/routes.storefront.d.ts.map +1 -0
  153. package/dist/backend/routes.storefront.js +65 -0
  154. package/dist/backend/routes.storefront.js.map +1 -0
  155. package/dist/backend/schemas/organization.d.ts +59 -0
  156. package/dist/backend/schemas/organization.d.ts.map +1 -0
  157. package/dist/backend/schemas/organization.js +55 -0
  158. package/dist/backend/schemas/organization.js.map +1 -0
  159. package/dist/backend/schemas/settings.d.ts +30 -0
  160. package/dist/backend/schemas/settings.d.ts.map +1 -0
  161. package/dist/backend/schemas/settings.js +35 -0
  162. package/dist/backend/schemas/settings.js.map +1 -0
  163. package/dist/backend/services/email-verification-service.d.ts +45 -0
  164. package/dist/backend/services/email-verification-service.d.ts.map +1 -0
  165. package/dist/backend/services/email-verification-service.js +95 -0
  166. package/dist/backend/services/email-verification-service.js.map +1 -0
  167. package/dist/backend/services/invitation-service.d.ts +85 -0
  168. package/dist/backend/services/invitation-service.d.ts.map +1 -0
  169. package/dist/backend/services/invitation-service.js +266 -0
  170. package/dist/backend/services/invitation-service.js.map +1 -0
  171. package/dist/backend/services/normalize-name.d.ts +14 -0
  172. package/dist/backend/services/normalize-name.d.ts.map +1 -0
  173. package/dist/backend/services/normalize-name.js +14 -0
  174. package/dist/backend/services/normalize-name.js.map +1 -0
  175. package/dist/backend/services/org-registration-notifier.d.ts +36 -0
  176. package/dist/backend/services/org-registration-notifier.d.ts.map +1 -0
  177. package/dist/backend/services/org-registration-notifier.js +109 -0
  178. package/dist/backend/services/org-registration-notifier.js.map +1 -0
  179. package/dist/backend/services/org-template-email.d.ts +18 -0
  180. package/dist/backend/services/org-template-email.d.ts.map +1 -0
  181. package/dist/backend/services/org-template-email.js +16 -0
  182. package/dist/backend/services/org-template-email.js.map +1 -0
  183. package/dist/backend/services/organization-context-service.d.ts +52 -0
  184. package/dist/backend/services/organization-context-service.d.ts.map +1 -0
  185. package/dist/backend/services/organization-context-service.js +70 -0
  186. package/dist/backend/services/organization-context-service.js.map +1 -0
  187. package/dist/backend/services/organization-country-reference.d.ts +11 -0
  188. package/dist/backend/services/organization-country-reference.d.ts.map +1 -0
  189. package/dist/backend/services/organization-country-reference.js +24 -0
  190. package/dist/backend/services/organization-country-reference.js.map +1 -0
  191. package/dist/backend/services/organization-details-port.d.ts +33 -0
  192. package/dist/backend/services/organization-details-port.d.ts.map +1 -0
  193. package/dist/backend/services/organization-details-port.js +95 -0
  194. package/dist/backend/services/organization-details-port.js.map +1 -0
  195. package/dist/backend/services/organization-effective-pricelists-service.d.ts +50 -0
  196. package/dist/backend/services/organization-effective-pricelists-service.d.ts.map +1 -0
  197. package/dist/backend/services/organization-effective-pricelists-service.js +68 -0
  198. package/dist/backend/services/organization-effective-pricelists-service.js.map +1 -0
  199. package/dist/backend/services/organization-inheritance-service.d.ts +73 -0
  200. package/dist/backend/services/organization-inheritance-service.d.ts.map +1 -0
  201. package/dist/backend/services/organization-inheritance-service.js +63 -0
  202. package/dist/backend/services/organization-inheritance-service.js.map +1 -0
  203. package/dist/backend/services/organization-moderation-service.d.ts +124 -0
  204. package/dist/backend/services/organization-moderation-service.d.ts.map +1 -0
  205. package/dist/backend/services/organization-moderation-service.js +337 -0
  206. package/dist/backend/services/organization-moderation-service.js.map +1 -0
  207. package/dist/backend/services/organization-restriction-service.d.ts +70 -0
  208. package/dist/backend/services/organization-restriction-service.d.ts.map +1 -0
  209. package/dist/backend/services/organization-restriction-service.js +210 -0
  210. package/dist/backend/services/organization-restriction-service.js.map +1 -0
  211. package/dist/backend/services/organization-tax-id-validation-service.d.ts +59 -0
  212. package/dist/backend/services/organization-tax-id-validation-service.d.ts.map +1 -0
  213. package/dist/backend/services/organization-tax-id-validation-service.js +115 -0
  214. package/dist/backend/services/organization-tax-id-validation-service.js.map +1 -0
  215. package/dist/backend/services/organization-tree-service.d.ts +102 -0
  216. package/dist/backend/services/organization-tree-service.d.ts.map +1 -0
  217. package/dist/backend/services/organization-tree-service.js +184 -0
  218. package/dist/backend/services/organization-tree-service.js.map +1 -0
  219. package/dist/backend/services/personal-organization-service.d.ts +130 -0
  220. package/dist/backend/services/personal-organization-service.d.ts.map +1 -0
  221. package/dist/backend/services/personal-organization-service.js +207 -0
  222. package/dist/backend/services/personal-organization-service.js.map +1 -0
  223. package/dist/backend/services/registration-service.d.ts +80 -0
  224. package/dist/backend/services/registration-service.d.ts.map +1 -0
  225. package/dist/backend/services/registration-service.js +126 -0
  226. package/dist/backend/services/registration-service.js.map +1 -0
  227. package/dist/backend/services/sales-rep-assignment-service.d.ts +89 -0
  228. package/dist/backend/services/sales-rep-assignment-service.d.ts.map +1 -0
  229. package/dist/backend/services/sales-rep-assignment-service.js +176 -0
  230. package/dist/backend/services/sales-rep-assignment-service.js.map +1 -0
  231. package/dist/backend/services/vat-validator-port.d.ts +20 -0
  232. package/dist/backend/services/vat-validator-port.d.ts.map +1 -0
  233. package/dist/backend/services/vat-validator-port.js +2 -0
  234. package/dist/backend/services/vat-validator-port.js.map +1 -0
  235. package/dist/manifest.d.ts +176 -0
  236. package/dist/manifest.d.ts.map +1 -0
  237. package/dist/manifest.js +503 -0
  238. package/dist/manifest.js.map +1 -0
  239. package/dist/migrations/20260424T205317_organizations_init.d.ts +13 -0
  240. package/dist/migrations/20260424T205317_organizations_init.d.ts.map +1 -0
  241. package/dist/migrations/20260424T205317_organizations_init.js +100 -0
  242. package/dist/migrations/20260424T205317_organizations_init.js.map +1 -0
  243. package/dist/migrations/20260425T051700_organizations_invitations_init.d.ts +13 -0
  244. package/dist/migrations/20260425T051700_organizations_invitations_init.d.ts.map +1 -0
  245. package/dist/migrations/20260425T051700_organizations_invitations_init.js +39 -0
  246. package/dist/migrations/20260425T051700_organizations_invitations_init.js.map +1 -0
  247. package/dist/migrations/20260611T140349_organizations_consolidation.d.ts +35 -0
  248. package/dist/migrations/20260611T140349_organizations_consolidation.d.ts.map +1 -0
  249. package/dist/migrations/20260611T140349_organizations_consolidation.js +180 -0
  250. package/dist/migrations/20260611T140349_organizations_consolidation.js.map +1 -0
  251. package/dist/migrations/20260611T140358_organizations_org_order_confirmation_emails.d.ts +10 -0
  252. package/dist/migrations/20260611T140358_organizations_org_order_confirmation_emails.d.ts.map +1 -0
  253. package/dist/migrations/20260611T140358_organizations_org_order_confirmation_emails.js +14 -0
  254. package/dist/migrations/20260611T140358_organizations_org_order_confirmation_emails.js.map +1 -0
  255. package/dist/migrations/20260611T140402_organizations_org_fulfilment_strategy.d.ts +14 -0
  256. package/dist/migrations/20260611T140402_organizations_org_fulfilment_strategy.d.ts.map +1 -0
  257. package/dist/migrations/20260611T140402_organizations_org_fulfilment_strategy.js +20 -0
  258. package/dist/migrations/20260611T140402_organizations_org_fulfilment_strategy.js.map +1 -0
  259. package/dist/migrations/20260717T151403_organizations_personal_organizations.d.ts +24 -0
  260. package/dist/migrations/20260717T151403_organizations_personal_organizations.d.ts.map +1 -0
  261. package/dist/migrations/20260717T151403_organizations_personal_organizations.js +63 -0
  262. package/dist/migrations/20260717T151403_organizations_personal_organizations.js.map +1 -0
  263. package/dist/migrations/20260718T200340_organizations_organization_custom_field_values.d.ts +12 -0
  264. package/dist/migrations/20260718T200340_organizations_organization_custom_field_values.d.ts.map +1 -0
  265. package/dist/migrations/20260718T200340_organizations_organization_custom_field_values.js +16 -0
  266. package/dist/migrations/20260718T200340_organizations_organization_custom_field_values.js.map +1 -0
  267. package/dist/migrations/20260720T044254_organizations_org_hierarchy.d.ts +23 -0
  268. package/dist/migrations/20260720T044254_organizations_org_hierarchy.d.ts.map +1 -0
  269. package/dist/migrations/20260720T044254_organizations_org_hierarchy.js +37 -0
  270. package/dist/migrations/20260720T044254_organizations_org_hierarchy.js.map +1 -0
  271. package/dist/migrations/20260912T094646_organizations_sales_channel_organizations.d.ts +27 -0
  272. package/dist/migrations/20260912T094646_organizations_sales_channel_organizations.d.ts.map +1 -0
  273. package/dist/migrations/20260912T094646_organizations_sales_channel_organizations.js +44 -0
  274. package/dist/migrations/20260912T094646_organizations_sales_channel_organizations.js.map +1 -0
  275. package/dist/migrations/index.d.ts +35 -0
  276. package/dist/migrations/index.d.ts.map +1 -0
  277. package/dist/migrations/index.js +45 -0
  278. package/dist/migrations/index.js.map +1 -0
  279. package/dist/ports/index.d.ts +53 -0
  280. package/dist/ports/index.d.ts.map +1 -0
  281. package/dist/ports/index.js +2 -0
  282. package/dist/ports/index.js.map +1 -0
  283. package/docs/organization-hierarchy.md +117 -0
  284. package/docs/organizations.md +312 -0
  285. package/i18n/en.json +17 -0
  286. package/i18n/pl.json +17 -0
  287. package/package.json +107 -0
  288. package/tailwind.css +14 -0
@@ -0,0 +1,337 @@
1
+ import { OptimisticLockError } from '@mikro-orm/core';
2
+ import { Organization } from '../entities/organization.entity.js';
3
+ import { withSystemScope } from '@endora-commerce/platform/tenancy';
4
+ import { noopOrgTemplateEmail } from './org-template-email.js';
5
+ export class OrganizationModerationService {
6
+ emFactory;
7
+ auditLogService;
8
+ events;
9
+ mailer;
10
+ customerAccounts;
11
+ resolveModerationMode;
12
+ templateEmail;
13
+ constructor(emFactory, auditLogService, events, mailer,
14
+ /**
15
+ * `customer_accounts`' published read, for the one question this service
16
+ * asks it: who receives the approval or rejection message.
17
+ */
18
+ customerAccounts,
19
+ /** Resolver for the moderation-mode setting. Returns 'auto' or 'manual'. */
20
+ resolveModerationMode,
21
+ /**
22
+ * The transactional-template seam, which is where the language comes from.
23
+ *
24
+ * Defaulted to the no-op rather than made required so a composition that
25
+ * does not wire it keeps sending — silence would be worse than the
26
+ * fallback language, which is the whole argument for keeping the in-code
27
+ * builders below.
28
+ */
29
+ templateEmail = noopOrgTemplateEmail) {
30
+ this.emFactory = emFactory;
31
+ this.auditLogService = auditLogService;
32
+ this.events = events;
33
+ this.mailer = mailer;
34
+ this.customerAccounts = customerAccounts;
35
+ this.resolveModerationMode = resolveModerationMode;
36
+ this.templateEmail = templateEmail;
37
+ }
38
+ /**
39
+ * Invoked by the `organization.registered.v1` subscriber. When the
40
+ * setting is `auto`, the freshly created org is approved immediately
41
+ * (system actor = null adminUserId). When `manual`, this is a no-op
42
+ * — the org stays in `pending_verification` until an admin acts.
43
+ */
44
+ async handleNewlyRegistered(organizationId) {
45
+ let mode = 'manual';
46
+ try {
47
+ mode = await this.resolveModerationMode();
48
+ }
49
+ catch {
50
+ // Settings not yet seeded or unreachable — degrade safely to manual.
51
+ }
52
+ if (mode !== 'auto')
53
+ return;
54
+ const em = this.emFactory();
55
+ const org = await em.findOne(Organization, { id: organizationId, deletedAt: null });
56
+ if (!org)
57
+ return;
58
+ if (org.status !== 'pending_verification')
59
+ return;
60
+ await this.approve(organizationId, {
61
+ expectedVersion: org.version,
62
+ actorAdminUserId: null,
63
+ });
64
+ }
65
+ async approve(organizationId, options) {
66
+ return this.transition({
67
+ organizationId,
68
+ expectedVersion: options.expectedVersion,
69
+ requireStatus: 'pending_verification',
70
+ mutate: (org) => {
71
+ org.status = 'active';
72
+ org.approvedAt = new Date();
73
+ org.approvedByAdminUserId = options.actorAdminUserId ?? null;
74
+ },
75
+ action: 'organization.approved',
76
+ actorAdminUserId: options.actorAdminUserId ?? null,
77
+ requestId: options.requestId ?? null,
78
+ eventNewStatus: 'active',
79
+ afterCommit: async (org) => {
80
+ await this.notifyCustomer(org, {
81
+ code: 'organization_approved',
82
+ variables: { organizationName: org.name },
83
+ fallbackSubject: 'Your organization has been verified',
84
+ fallbackText: `Hi,\n\nOrganization "${org.name}" has been verified successfully and can now place Orders and Requests for Quotation.\n\nThank you.`,
85
+ messageIdSuffix: 'approved',
86
+ });
87
+ },
88
+ });
89
+ }
90
+ async reject(organizationId, options) {
91
+ if (!options.reason || options.reason.trim().length === 0) {
92
+ throw new Error('OrganizationModerationService.reject: reason is required.');
93
+ }
94
+ return this.transition({
95
+ organizationId,
96
+ expectedVersion: options.expectedVersion,
97
+ requireStatus: 'pending_verification',
98
+ mutate: (org) => {
99
+ org.status = 'rejected';
100
+ org.rejectedAt = new Date();
101
+ org.rejectedReason = options.reason;
102
+ },
103
+ action: 'organization.rejected',
104
+ actorAdminUserId: options.actorAdminUserId ?? null,
105
+ requestId: options.requestId ?? null,
106
+ eventNewStatus: 'rejected',
107
+ reason: options.reason,
108
+ afterCommit: async (org) => {
109
+ if (options.notifyCustomerEmail === false)
110
+ return;
111
+ await this.notifyCustomer(org, {
112
+ code: 'organization_rejected',
113
+ variables: { organizationName: org.name, reason: options.reason },
114
+ fallbackSubject: 'Organization registration rejected',
115
+ fallbackText: `Hi,\n\nUnfortunately, the registration of organization "${org.name}" was rejected for the following reason:\n\n${options.reason}\n\nIf you have any questions, please contact the platform administrators.`,
116
+ messageIdSuffix: 'rejected',
117
+ });
118
+ },
119
+ });
120
+ }
121
+ async block(organizationId, options) {
122
+ return this.transition({
123
+ organizationId,
124
+ expectedVersion: options.expectedVersion,
125
+ requireStatus: 'active',
126
+ mutate: (org) => {
127
+ org.status = 'blocked';
128
+ org.blockedAt = new Date();
129
+ org.blockedReason = options.reason ?? null;
130
+ },
131
+ action: 'organization.blocked',
132
+ actorAdminUserId: options.actorAdminUserId ?? null,
133
+ requestId: options.requestId ?? null,
134
+ eventNewStatus: 'blocked',
135
+ reason: options.reason ?? null,
136
+ });
137
+ }
138
+ async unblock(organizationId, options) {
139
+ return this.transition({
140
+ organizationId,
141
+ expectedVersion: options.expectedVersion,
142
+ requireStatus: 'blocked',
143
+ mutate: (org) => {
144
+ org.status = 'active';
145
+ org.blockedAt = null;
146
+ org.blockedReason = null;
147
+ },
148
+ action: 'organization.unblocked',
149
+ actorAdminUserId: options.actorAdminUserId ?? null,
150
+ requestId: options.requestId ?? null,
151
+ eventNewStatus: 'active',
152
+ });
153
+ }
154
+ // ── internals ──────────────────────────────────────────────────────────
155
+ async transition(input) {
156
+ const em = this.emFactory();
157
+ const captured = { snapshotBefore: null, snapshotAfter: null, org: null };
158
+ try {
159
+ await em.transactional(async (tem) => {
160
+ const org = await tem.findOne(Organization, { id: input.organizationId, deletedAt: null });
161
+ if (!org) {
162
+ throw new OrganizationNotFoundError(input.organizationId);
163
+ }
164
+ if (org.version !== input.expectedVersion) {
165
+ throw new OrganizationVersionMismatchError(org.id, input.expectedVersion, org.version);
166
+ }
167
+ if (org.status !== input.requireStatus) {
168
+ throw new OrganizationStatusGuardError(org.id, org.status, input.requireStatus);
169
+ }
170
+ captured.snapshotBefore = snapshot(org);
171
+ input.mutate(org);
172
+ await tem.flush();
173
+ captured.snapshotAfter = snapshot(org);
174
+ captured.org = org;
175
+ });
176
+ }
177
+ catch (err) {
178
+ if (err instanceof OptimisticLockError) {
179
+ throw new OrganizationVersionMismatchError(input.organizationId, input.expectedVersion, -1);
180
+ }
181
+ throw err;
182
+ }
183
+ const { snapshotBefore, snapshotAfter, org: approvedOrg } = captured;
184
+ // Audit + event + email run AFTER the DB commit so a downstream failure
185
+ // never poisons the status transition. We accept best-effort semantics
186
+ // for those (mailer is idempotent via messageId).
187
+ await this.auditLogService.record({
188
+ actorAdminUserId: input.actorAdminUserId,
189
+ action: input.action,
190
+ objectType: 'organization',
191
+ objectId: input.organizationId,
192
+ stateBefore: snapshotBefore ? { ...snapshotBefore } : null,
193
+ stateAfter: snapshotAfter ? { ...snapshotAfter } : null,
194
+ requestId: input.requestId,
195
+ });
196
+ this.events.emit('organization.status_changed.v1', {
197
+ eventId: crypto.randomUUID(),
198
+ occurredAt: new Date().toISOString(),
199
+ organizationId: input.organizationId,
200
+ newStatus: input.eventNewStatus,
201
+ });
202
+ if (input.afterCommit && approvedOrg) {
203
+ try {
204
+ await input.afterCommit(approvedOrg);
205
+ }
206
+ catch {
207
+ // Customer email is best-effort. The transition has already happened.
208
+ }
209
+ }
210
+ return approvedOrg;
211
+ }
212
+ async notifyCustomer(org, input) {
213
+ /**
214
+ * Feature 075 (D-87) — `customer_accounts`' port, where this was a
215
+ * `getConnection().getKnex().raw('select "email" from "customer_accounts" …')`.
216
+ * Raw SQL names no import specifier, so the reach compiled and returned
217
+ * rows while every boundary check read clean.
218
+ *
219
+ * **The system scope is load-bearing and is not incidental to the port.**
220
+ * `CustomerAccount` is `@OrgScoped`, so the read carries the acting
221
+ * admin's tenant filter, and a moderator with an `allowed-set` context has
222
+ * by definition not been assigned the organisation they are approving —
223
+ * it is still `pending_verification`. Filtered, the lookup would find no
224
+ * recipient and the approval mail would silently not go out. The raw
225
+ * statement crossed organisations by bypassing the filter entirely and
226
+ * telling nobody; `withSystemScope` crosses them the sanctioned way
227
+ * (Constitution XI, FR-005), with a reason and one audit record.
228
+ *
229
+ * `listByOrganization` orders by role then creation date, so the first
230
+ * `organization_admin` in the result is the row the `order by
231
+ * "created_at" asc limit 1` picked.
232
+ */
233
+ const members = await withSystemScope('organizations: notify the moderated organisation of its status change', () => this.customerAccounts.listByOrganization(org.id, { activeOnly: true }));
234
+ const recipient = members.find((m) => m.role === 'organization_admin')?.email;
235
+ if (!recipient)
236
+ return;
237
+ const messageId = `organization.${input.messageIdSuffix}.${org.id}.${org.version}`;
238
+ const meta = { organizationId: org.id, kind: input.messageIdSuffix };
239
+ /**
240
+ * The language this message is written in, and where it comes from
241
+ * (`specs/093-backend-delivered-prose/` § Out of scope — the seam-B
242
+ * carve-out).
243
+ *
244
+ * Both of these messages were finished Polish sentences composed right
245
+ * here and handed straight to the transport, so a buyer on an English
246
+ * sales channel was sent Polish unconditionally. They carry a code now,
247
+ * and `templateEmailPort` resolves the language from the **system-default
248
+ * sales channel's `defaultLanguage`**, falling back to `en-US`.
249
+ *
250
+ * That is the honest derivation available at this call site and not a
251
+ * convenience. There is no per-buyer language to read: neither
252
+ * `CustomerAccountRecord` nor `Organization` carries one, and
253
+ * `specs/083-buyer-language-resolution/` records the reserved rung for it
254
+ * as deliberately absent. Nor is the request's language usable — this runs
255
+ * `afterCommit`, and on the two paths that reach it the request either
256
+ * belongs to the moderating **administrator**, whose language is not the
257
+ * recipient's, or does not exist at all, `handleNewlyRegistered` being
258
+ * driven by an event subscriber.
259
+ *
260
+ * `trySend` answers `false` only for a code with no definition, and then
261
+ * the English builders below send. A message that silently fails to go out
262
+ * is worse than one in a language the recipient did not choose.
263
+ */
264
+ const sentViaTemplate = await this.templateEmail.trySend({
265
+ code: input.code,
266
+ to: recipient,
267
+ messageId,
268
+ variables: input.variables,
269
+ meta,
270
+ });
271
+ if (sentViaTemplate)
272
+ return;
273
+ const outcome = await this.mailer.send({
274
+ messageId,
275
+ to: recipient,
276
+ subject: input.fallbackSubject,
277
+ text: input.fallbackText,
278
+ meta,
279
+ });
280
+ if (outcome.status !== 'sent') {
281
+ // The moderation transition has committed and this notification runs
282
+ // after it, so the non-send is named rather than raised — D-59's record
283
+ // is what survives to answer "was the customer told".
284
+ console.warn('[organizations] the moderation e-mail was not sent', {
285
+ organizationId: org.id,
286
+ kind: input.messageIdSuffix,
287
+ reason: outcome.reason,
288
+ });
289
+ }
290
+ }
291
+ }
292
+ function snapshot(org) {
293
+ return {
294
+ id: org.id,
295
+ status: org.status,
296
+ approvedAt: org.approvedAt ? org.approvedAt.toISOString() : null,
297
+ approvedByAdminUserId: org.approvedByAdminUserId ?? null,
298
+ blockedAt: org.blockedAt ? org.blockedAt.toISOString() : null,
299
+ blockedReason: org.blockedReason ?? null,
300
+ rejectedAt: org.rejectedAt ? org.rejectedAt.toISOString() : null,
301
+ rejectedReason: org.rejectedReason ?? null,
302
+ version: org.version,
303
+ };
304
+ }
305
+ export class OrganizationNotFoundError extends Error {
306
+ organizationId;
307
+ constructor(organizationId) {
308
+ super(`Organization ${organizationId} not found.`);
309
+ this.organizationId = organizationId;
310
+ this.name = 'OrganizationNotFoundError';
311
+ }
312
+ }
313
+ export class OrganizationVersionMismatchError extends Error {
314
+ organizationId;
315
+ expectedVersion;
316
+ currentVersion;
317
+ constructor(organizationId, expectedVersion, currentVersion) {
318
+ super(`Organization ${organizationId} version mismatch (expected ${expectedVersion}, currently ${currentVersion}).`);
319
+ this.organizationId = organizationId;
320
+ this.expectedVersion = expectedVersion;
321
+ this.currentVersion = currentVersion;
322
+ this.name = 'OrganizationVersionMismatchError';
323
+ }
324
+ }
325
+ export class OrganizationStatusGuardError extends Error {
326
+ organizationId;
327
+ currentStatus;
328
+ requiredStatus;
329
+ constructor(organizationId, currentStatus, requiredStatus) {
330
+ super(`Organization ${organizationId} is in status '${currentStatus}', cannot perform an action that requires '${requiredStatus}'.`);
331
+ this.organizationId = organizationId;
332
+ this.currentStatus = currentStatus;
333
+ this.requiredStatus = requiredStatus;
334
+ this.name = 'OrganizationStatusGuardError';
335
+ }
336
+ }
337
+ //# sourceMappingURL=organization-moderation-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization-moderation-service.js","sourceRoot":"","sources":["../../../src/backend/services/organization-moderation-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { AuditPort } from '@endora-commerce/platform/kernel';
3
+ export interface AllowLists {
4
+ paymentMethodIds: string[];
5
+ deliveryMethodIds: string[];
6
+ warehouseIds: string[];
7
+ }
8
+ export interface AllowListsRead extends AllowLists {
9
+ organizationId: string;
10
+ /** Organization's optimistic-lock version after the read. Pass this on the next write. */
11
+ version: number;
12
+ }
13
+ export interface ReplaceAllowListsInput extends AllowLists {
14
+ expectedVersion: number;
15
+ }
16
+ export type RestrictionKind = 'payment_method' | 'delivery_method' | 'warehouse';
17
+ export interface PatchAllowListInput {
18
+ expectedVersion: number;
19
+ add?: string[] | undefined;
20
+ remove?: string[] | undefined;
21
+ }
22
+ /**
23
+ * Owns the three per-Organization allow-list bridges:
24
+ * - `organization_payment_methods`
25
+ * - `organization_delivery_methods`
26
+ * - `organization_warehouses`
27
+ *
28
+ * Empty allow-list ⇒ "platform defaults apply" (FR-014 / FR-015 / FR-016).
29
+ *
30
+ * Every write is gated by the Organization's `version` column (optimistic
31
+ * lock per research R7). Mismatch raises `OrganizationVersionMismatchError`
32
+ * which the route handler maps to HTTP 409.
33
+ *
34
+ * Storefront-side cache invalidation is layered on top by US4 — this
35
+ * foundational service only owns the persisted state.
36
+ */
37
+ export declare class OrganizationRestrictionService {
38
+ private readonly emFactory;
39
+ private readonly auditLog?;
40
+ constructor(emFactory: () => EntityManager, auditLog?: AuditPort | undefined);
41
+ readAllowLists(organizationId: string): Promise<AllowListsRead>;
42
+ /**
43
+ * The allow-list for one restriction kind, or `null` for "no restriction".
44
+ *
45
+ * Feature 072 (T138). Three composition roots' worth of callers —
46
+ * `payment_methods`, `delivery_methods` and `inventory` — used to reach this
47
+ * service through a root closure that wrapped {@link readAllowLists} in a
48
+ * bare `catch` and read "organization not found" as "unrestricted". That is
49
+ * the right policy and the wrong place for it: a `catch` around a *port* call
50
+ * also swallows `ModuleDisabledError`, turning a fail-closed gate into a
51
+ * fail-open restriction check — on the one code path whose entire job is to
52
+ * restrict.
53
+ *
54
+ * So the degrade is expressed here, in the return type, by the module that
55
+ * owns the policy. A caller needs no `catch`, and a genuine module-disabled
56
+ * error propagates as the 503 it is.
57
+ */
58
+ allowedIdsFor(organizationId: string, kind: 'paymentMethodIds' | 'deliveryMethodIds' | 'warehouseIds'): Promise<string[] | null>;
59
+ replaceAllowLists(organizationId: string, input: ReplaceAllowListsInput): Promise<AllowListsRead>;
60
+ patchAllowList(organizationId: string, kind: RestrictionKind, input: PatchAllowListInput): Promise<AllowListsRead>;
61
+ private guardVersion;
62
+ private translateOptimisticLockError;
63
+ }
64
+ export declare class OrganizationVersionMismatchError extends Error {
65
+ readonly organizationId: string;
66
+ readonly expectedVersion: number;
67
+ readonly currentVersion: number;
68
+ constructor(organizationId: string, expectedVersion: number, currentVersion: number);
69
+ }
70
+ //# sourceMappingURL=organization-restriction-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization-restriction-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/organization-restriction-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAO3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,cAAc,EAAE,MAAM,CAAC;IACvB,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAuB,SAAQ,UAAU;IACxD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,WAAW,CAAC;AAEjF,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CAC/B;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,8BAA8B;IAEvC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBADT,SAAS,EAAE,MAAM,aAAa,EAC9B,QAAQ,CAAC,EAAE,SAAS,YAAA;IAGjC,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAmBrE;;;;;;;;;;;;;;;OAeG;IACG,aAAa,CACjB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,kBAAkB,GAAG,mBAAmB,GAAG,cAAc,GAC9D,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IAcrB,iBAAiB,CACrB,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,cAAc,CAAC;IAiDpB,cAAc,CAClB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,cAAc,CAAC;IAgE1B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,4BAA4B;CAMrC;AAED,qBAAa,gCAAiC,SAAQ,KAAK;aAEvC,cAAc,EAAE,MAAM;aACtB,eAAe,EAAE,MAAM;aACvB,cAAc,EAAE,MAAM;gBAFtB,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,MAAM;CAOzC"}
@@ -0,0 +1,210 @@
1
+ import { NotFoundError, OptimisticLockError } from '@mikro-orm/core';
2
+ import { Organization } from '../entities/organization.entity.js';
3
+ import { OrganizationPaymentMethodLink } from '../entities/organization-payment-method-link.entity.js';
4
+ import { OrganizationDeliveryMethodLink } from '../entities/organization-delivery-method-link.entity.js';
5
+ import { OrganizationWarehouseLink } from '../entities/organization-warehouse-link.entity.js';
6
+ import { recordAuditFromContext } from '@endora-commerce/platform/commands';
7
+ /**
8
+ * Owns the three per-Organization allow-list bridges:
9
+ * - `organization_payment_methods`
10
+ * - `organization_delivery_methods`
11
+ * - `organization_warehouses`
12
+ *
13
+ * Empty allow-list ⇒ "platform defaults apply" (FR-014 / FR-015 / FR-016).
14
+ *
15
+ * Every write is gated by the Organization's `version` column (optimistic
16
+ * lock per research R7). Mismatch raises `OrganizationVersionMismatchError`
17
+ * which the route handler maps to HTTP 409.
18
+ *
19
+ * Storefront-side cache invalidation is layered on top by US4 — this
20
+ * foundational service only owns the persisted state.
21
+ */
22
+ export class OrganizationRestrictionService {
23
+ emFactory;
24
+ auditLog;
25
+ constructor(emFactory, auditLog) {
26
+ this.emFactory = emFactory;
27
+ this.auditLog = auditLog;
28
+ }
29
+ async readAllowLists(organizationId) {
30
+ const em = this.emFactory();
31
+ const org = await em.findOneOrFail(Organization, { id: organizationId, deletedAt: null });
32
+ const [payment, delivery, warehouses] = await Promise.all([
33
+ em.find(OrganizationPaymentMethodLink, { organizationId }),
34
+ em.find(OrganizationDeliveryMethodLink, { organizationId }),
35
+ em.find(OrganizationWarehouseLink, { organizationId }),
36
+ ]);
37
+ return {
38
+ organizationId,
39
+ paymentMethodIds: payment.map((r) => r.paymentMethodId).sort(),
40
+ deliveryMethodIds: delivery.map((r) => r.deliveryMethodId).sort(),
41
+ warehouseIds: warehouses.map((r) => r.warehouseId).sort(),
42
+ version: org.version,
43
+ };
44
+ }
45
+ /**
46
+ * The allow-list for one restriction kind, or `null` for "no restriction".
47
+ *
48
+ * Feature 072 (T138). Three composition roots' worth of callers —
49
+ * `payment_methods`, `delivery_methods` and `inventory` — used to reach this
50
+ * service through a root closure that wrapped {@link readAllowLists} in a
51
+ * bare `catch` and read "organization not found" as "unrestricted". That is
52
+ * the right policy and the wrong place for it: a `catch` around a *port* call
53
+ * also swallows `ModuleDisabledError`, turning a fail-closed gate into a
54
+ * fail-open restriction check — on the one code path whose entire job is to
55
+ * restrict.
56
+ *
57
+ * So the degrade is expressed here, in the return type, by the module that
58
+ * owns the policy. A caller needs no `catch`, and a genuine module-disabled
59
+ * error propagates as the 503 it is.
60
+ */
61
+ async allowedIdsFor(organizationId, kind) {
62
+ let lists;
63
+ try {
64
+ lists = await this.readAllowLists(organizationId);
65
+ }
66
+ catch (err) {
67
+ // The one condition this may absorb: the Organization is unknown or
68
+ // soft-deleted, which `readAllowLists` reports as a `findOneOrFail`
69
+ // rejection. Anything else is a real failure and must surface.
70
+ if (err instanceof NotFoundError)
71
+ return null;
72
+ throw err;
73
+ }
74
+ return lists[kind];
75
+ }
76
+ async replaceAllowLists(organizationId, input) {
77
+ const em = this.emFactory();
78
+ try {
79
+ await em.transactional(async (tem) => {
80
+ const org = await tem.findOneOrFail(Organization, {
81
+ id: organizationId,
82
+ deletedAt: null,
83
+ });
84
+ this.guardVersion(org, input.expectedVersion);
85
+ await tem.nativeDelete(OrganizationPaymentMethodLink, { organizationId });
86
+ await tem.nativeDelete(OrganizationDeliveryMethodLink, { organizationId });
87
+ await tem.nativeDelete(OrganizationWarehouseLink, { organizationId });
88
+ for (const paymentMethodId of dedupe(input.paymentMethodIds)) {
89
+ tem.persist(tem.create(OrganizationPaymentMethodLink, { organizationId, paymentMethodId }));
90
+ }
91
+ for (const deliveryMethodId of dedupe(input.deliveryMethodIds)) {
92
+ tem.persist(tem.create(OrganizationDeliveryMethodLink, { organizationId, deliveryMethodId }));
93
+ }
94
+ for (const warehouseId of dedupe(input.warehouseIds)) {
95
+ tem.persist(tem.create(OrganizationWarehouseLink, { organizationId, warehouseId }));
96
+ }
97
+ // Touch the Organization so the version column advances. MikroORM's
98
+ // optimistic-lock semantics bump `version` automatically on flush.
99
+ org.updatedAt = new Date();
100
+ if (this.auditLog) {
101
+ recordAuditFromContext(this.auditLog, tem, {
102
+ action: 'organization.allow_lists_replace',
103
+ objectType: 'organization',
104
+ objectId: organizationId,
105
+ stateBefore: null,
106
+ stateAfter: {
107
+ paymentMethodIds: dedupe(input.paymentMethodIds),
108
+ deliveryMethodIds: dedupe(input.deliveryMethodIds),
109
+ warehouseIds: dedupe(input.warehouseIds),
110
+ },
111
+ });
112
+ }
113
+ await tem.flush();
114
+ });
115
+ }
116
+ catch (err) {
117
+ throw this.translateOptimisticLockError(err, organizationId);
118
+ }
119
+ return this.readAllowLists(organizationId);
120
+ }
121
+ async patchAllowList(organizationId, kind, input) {
122
+ const em = this.emFactory();
123
+ try {
124
+ await em.transactional(async (tem) => {
125
+ const org = await tem.findOneOrFail(Organization, {
126
+ id: organizationId,
127
+ deletedAt: null,
128
+ });
129
+ this.guardVersion(org, input.expectedVersion);
130
+ const add = dedupe(input.add ?? []);
131
+ const remove = dedupe(input.remove ?? []);
132
+ if (kind === 'payment_method') {
133
+ if (remove.length) {
134
+ await tem.nativeDelete(OrganizationPaymentMethodLink, {
135
+ organizationId,
136
+ paymentMethodId: { $in: remove },
137
+ });
138
+ }
139
+ for (const id of add) {
140
+ tem.persist(tem.create(OrganizationPaymentMethodLink, { organizationId, paymentMethodId: id }));
141
+ }
142
+ }
143
+ else if (kind === 'delivery_method') {
144
+ if (remove.length) {
145
+ await tem.nativeDelete(OrganizationDeliveryMethodLink, {
146
+ organizationId,
147
+ deliveryMethodId: { $in: remove },
148
+ });
149
+ }
150
+ for (const id of add) {
151
+ tem.persist(tem.create(OrganizationDeliveryMethodLink, { organizationId, deliveryMethodId: id }));
152
+ }
153
+ }
154
+ else {
155
+ if (remove.length) {
156
+ await tem.nativeDelete(OrganizationWarehouseLink, {
157
+ organizationId,
158
+ warehouseId: { $in: remove },
159
+ });
160
+ }
161
+ for (const id of add) {
162
+ tem.persist(tem.create(OrganizationWarehouseLink, { organizationId, warehouseId: id }));
163
+ }
164
+ }
165
+ org.updatedAt = new Date();
166
+ if (this.auditLog) {
167
+ recordAuditFromContext(this.auditLog, tem, {
168
+ action: 'organization.allow_list_patch',
169
+ objectType: 'organization',
170
+ objectId: organizationId,
171
+ stateBefore: null,
172
+ stateAfter: { kind, add: dedupe(input.add ?? []), remove: dedupe(input.remove ?? []) },
173
+ });
174
+ }
175
+ await tem.flush();
176
+ });
177
+ }
178
+ catch (err) {
179
+ throw this.translateOptimisticLockError(err, organizationId);
180
+ }
181
+ return this.readAllowLists(organizationId);
182
+ }
183
+ guardVersion(org, expected) {
184
+ if (org.version !== expected) {
185
+ throw new OrganizationVersionMismatchError(org.id, expected, org.version);
186
+ }
187
+ }
188
+ translateOptimisticLockError(err, organizationId) {
189
+ if (err instanceof OptimisticLockError) {
190
+ return new OrganizationVersionMismatchError(organizationId, -1, -1);
191
+ }
192
+ return err;
193
+ }
194
+ }
195
+ export class OrganizationVersionMismatchError extends Error {
196
+ organizationId;
197
+ expectedVersion;
198
+ currentVersion;
199
+ constructor(organizationId, expectedVersion, currentVersion) {
200
+ super(`Organization ${organizationId} version mismatch (expected ${expectedVersion}, currently ${currentVersion}).`);
201
+ this.organizationId = organizationId;
202
+ this.expectedVersion = expectedVersion;
203
+ this.currentVersion = currentVersion;
204
+ this.name = 'OrganizationVersionMismatchError';
205
+ }
206
+ }
207
+ function dedupe(arr) {
208
+ return Array.from(new Set(arr));
209
+ }
210
+ //# sourceMappingURL=organization-restriction-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization-restriction-service.js","sourceRoot":"","sources":["../../../src/backend/services/organization-restriction-service.ts"],"names":[],"mappings":"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"}