@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.
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/dist/admin/components/OrganizationSalesRepsTab.d.ts +27 -0
- package/dist/admin/components/OrganizationSalesRepsTab.d.ts.map +1 -0
- package/dist/admin/components/OrganizationSalesRepsTab.js +170 -0
- package/dist/admin/components/OrganizationSalesRepsTab.js.map +1 -0
- package/dist/admin/index.d.ts +30 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +59 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/OrganizationDetail.d.ts +9 -0
- package/dist/admin/pages/OrganizationDetail.d.ts.map +1 -0
- package/dist/admin/pages/OrganizationDetail.js +247 -0
- package/dist/admin/pages/OrganizationDetail.js.map +1 -0
- package/dist/admin/pages/OrganizationsList.d.ts +9 -0
- package/dist/admin/pages/OrganizationsList.d.ts.map +1 -0
- package/dist/admin/pages/OrganizationsList.js +73 -0
- package/dist/admin/pages/OrganizationsList.js.map +1 -0
- package/dist/admin/panels/ApplicablePriceListsPanel.d.ts +12 -0
- package/dist/admin/panels/ApplicablePriceListsPanel.d.ts.map +1 -0
- package/dist/admin/panels/ApplicablePriceListsPanel.js +49 -0
- package/dist/admin/panels/ApplicablePriceListsPanel.js.map +1 -0
- package/dist/admin/panels/FulfilmentStrategyPanel.d.ts +16 -0
- package/dist/admin/panels/FulfilmentStrategyPanel.d.ts.map +1 -0
- package/dist/admin/panels/FulfilmentStrategyPanel.js +29 -0
- package/dist/admin/panels/FulfilmentStrategyPanel.js.map +1 -0
- package/dist/admin/panels/HierarchyPanel.d.ts +15 -0
- package/dist/admin/panels/HierarchyPanel.d.ts.map +1 -0
- package/dist/admin/panels/HierarchyPanel.js +65 -0
- package/dist/admin/panels/HierarchyPanel.js.map +1 -0
- package/dist/admin/panels/ModerationActionsPanel.d.ts +28 -0
- package/dist/admin/panels/ModerationActionsPanel.d.ts.map +1 -0
- package/dist/admin/panels/ModerationActionsPanel.js +111 -0
- package/dist/admin/panels/ModerationActionsPanel.js.map +1 -0
- package/dist/admin/panels/RestrictionsPanel.d.ts +24 -0
- package/dist/admin/panels/RestrictionsPanel.d.ts.map +1 -0
- package/dist/admin/panels/RestrictionsPanel.js +121 -0
- package/dist/admin/panels/RestrictionsPanel.js.map +1 -0
- package/dist/admin/panels/VatValidationPanel.d.ts +28 -0
- package/dist/admin/panels/VatValidationPanel.d.ts.map +1 -0
- package/dist/admin/panels/VatValidationPanel.js +79 -0
- package/dist/admin/panels/VatValidationPanel.js.map +1 -0
- package/dist/backend/commands/move.command.d.ts +11 -0
- package/dist/backend/commands/move.command.d.ts.map +1 -0
- package/dist/backend/commands/move.command.js +11 -0
- package/dist/backend/commands/move.command.js.map +1 -0
- package/dist/backend/commands/set-cart-approval-policy.command.d.ts +31 -0
- package/dist/backend/commands/set-cart-approval-policy.command.d.ts.map +1 -0
- package/dist/backend/commands/set-cart-approval-policy.command.js +56 -0
- package/dist/backend/commands/set-cart-approval-policy.command.js.map +1 -0
- package/dist/backend/commands/set-credit-mode.command.d.ts +16 -0
- package/dist/backend/commands/set-credit-mode.command.d.ts.map +1 -0
- package/dist/backend/commands/set-credit-mode.command.js +25 -0
- package/dist/backend/commands/set-credit-mode.command.js.map +1 -0
- package/dist/backend/commands/set-parent.command.d.ts +26 -0
- package/dist/backend/commands/set-parent.command.d.ts.map +1 -0
- package/dist/backend/commands/set-parent.command.js +51 -0
- package/dist/backend/commands/set-parent.command.js.map +1 -0
- package/dist/backend/demo/reset.d.ts +20 -0
- package/dist/backend/demo/reset.d.ts.map +1 -0
- package/dist/backend/demo/reset.js +11 -0
- package/dist/backend/demo/reset.js.map +1 -0
- package/dist/backend/demo/rows.d.ts +44 -0
- package/dist/backend/demo/rows.d.ts.map +1 -0
- package/dist/backend/demo/rows.js +44 -0
- package/dist/backend/demo/rows.js.map +1 -0
- package/dist/backend/demo/seed.d.ts +20 -0
- package/dist/backend/demo/seed.d.ts.map +1 -0
- package/dist/backend/demo/seed.js +28 -0
- package/dist/backend/demo/seed.js.map +1 -0
- package/dist/backend/email-templates/invitation.d.ts +23 -0
- package/dist/backend/email-templates/invitation.d.ts.map +1 -0
- package/dist/backend/email-templates/invitation.js +35 -0
- package/dist/backend/email-templates/invitation.js.map +1 -0
- package/dist/backend/email-templates/transactional-defaults.d.ts +54 -0
- package/dist/backend/email-templates/transactional-defaults.d.ts.map +1 -0
- package/dist/backend/email-templates/transactional-defaults.js +242 -0
- package/dist/backend/email-templates/transactional-defaults.js.map +1 -0
- package/dist/backend/email-templates/verification.d.ts +14 -0
- package/dist/backend/email-templates/verification.d.ts.map +1 -0
- package/dist/backend/email-templates/verification.js +34 -0
- package/dist/backend/email-templates/verification.js.map +1 -0
- package/dist/backend/entities/email-verification-token.entity.d.ts +17 -0
- package/dist/backend/entities/email-verification-token.entity.d.ts.map +1 -0
- package/dist/backend/entities/email-verification-token.entity.js +60 -0
- package/dist/backend/entities/email-verification-token.entity.js.map +1 -0
- package/dist/backend/entities/organization-delivery-method-link.entity.d.ts +14 -0
- package/dist/backend/entities/organization-delivery-method-link.entity.d.ts.map +1 -0
- package/dist/backend/entities/organization-delivery-method-link.entity.js +41 -0
- package/dist/backend/entities/organization-delivery-method-link.entity.js.map +1 -0
- package/dist/backend/entities/organization-invitation.entity.d.ts +21 -0
- package/dist/backend/entities/organization-invitation.entity.d.ts.map +1 -0
- package/dist/backend/entities/organization-invitation.entity.js +85 -0
- package/dist/backend/entities/organization-invitation.entity.js.map +1 -0
- package/dist/backend/entities/organization-payment-method-link.entity.d.ts +14 -0
- package/dist/backend/entities/organization-payment-method-link.entity.d.ts.map +1 -0
- package/dist/backend/entities/organization-payment-method-link.entity.js +41 -0
- package/dist/backend/entities/organization-payment-method-link.entity.js.map +1 -0
- package/dist/backend/entities/organization-sales-rep-assignment.entity.d.ts +17 -0
- package/dist/backend/entities/organization-sales-rep-assignment.entity.d.ts.map +1 -0
- package/dist/backend/entities/organization-sales-rep-assignment.entity.js +56 -0
- package/dist/backend/entities/organization-sales-rep-assignment.entity.js.map +1 -0
- package/dist/backend/entities/organization-tax-id-validation.entity.d.ts +29 -0
- package/dist/backend/entities/organization-tax-id-validation.entity.d.ts.map +1 -0
- package/dist/backend/entities/organization-tax-id-validation.entity.js +78 -0
- package/dist/backend/entities/organization-tax-id-validation.entity.js.map +1 -0
- package/dist/backend/entities/organization-warehouse-link.entity.d.ts +15 -0
- package/dist/backend/entities/organization-warehouse-link.entity.d.ts.map +1 -0
- package/dist/backend/entities/organization-warehouse-link.entity.js +42 -0
- package/dist/backend/entities/organization-warehouse-link.entity.js.map +1 -0
- package/dist/backend/entities/organization.entity.d.ts +125 -0
- package/dist/backend/entities/organization.entity.d.ts.map +1 -0
- package/dist/backend/entities/organization.entity.js +282 -0
- package/dist/backend/entities/organization.entity.js.map +1 -0
- package/dist/backend/index.d.ts +250 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +506 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/integrations/ministerstwo-finansow-client.d.ts +22 -0
- package/dist/backend/integrations/ministerstwo-finansow-client.d.ts.map +1 -0
- package/dist/backend/integrations/ministerstwo-finansow-client.js +172 -0
- package/dist/backend/integrations/ministerstwo-finansow-client.js.map +1 -0
- package/dist/backend/integrations/vies-client.d.ts +18 -0
- package/dist/backend/integrations/vies-client.d.ts.map +1 -0
- package/dist/backend/integrations/vies-client.js +133 -0
- package/dist/backend/integrations/vies-client.js.map +1 -0
- package/dist/backend/plugin.d.ts +126 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +139 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +66 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +711 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.customer.d.ts +33 -0
- package/dist/backend/routes.customer.d.ts.map +1 -0
- package/dist/backend/routes.customer.js +139 -0
- package/dist/backend/routes.customer.js.map +1 -0
- package/dist/backend/routes.members.d.ts +31 -0
- package/dist/backend/routes.members.d.ts.map +1 -0
- package/dist/backend/routes.members.js +109 -0
- package/dist/backend/routes.members.js.map +1 -0
- package/dist/backend/routes.public.d.ts +49 -0
- package/dist/backend/routes.public.d.ts.map +1 -0
- package/dist/backend/routes.public.js +220 -0
- package/dist/backend/routes.public.js.map +1 -0
- package/dist/backend/routes.sales-reps.d.ts +46 -0
- package/dist/backend/routes.sales-reps.d.ts.map +1 -0
- package/dist/backend/routes.sales-reps.js +114 -0
- package/dist/backend/routes.sales-reps.js.map +1 -0
- package/dist/backend/routes.storefront.d.ts +25 -0
- package/dist/backend/routes.storefront.d.ts.map +1 -0
- package/dist/backend/routes.storefront.js +65 -0
- package/dist/backend/routes.storefront.js.map +1 -0
- package/dist/backend/schemas/organization.d.ts +59 -0
- package/dist/backend/schemas/organization.d.ts.map +1 -0
- package/dist/backend/schemas/organization.js +55 -0
- package/dist/backend/schemas/organization.js.map +1 -0
- package/dist/backend/schemas/settings.d.ts +30 -0
- package/dist/backend/schemas/settings.d.ts.map +1 -0
- package/dist/backend/schemas/settings.js +35 -0
- package/dist/backend/schemas/settings.js.map +1 -0
- package/dist/backend/services/email-verification-service.d.ts +45 -0
- package/dist/backend/services/email-verification-service.d.ts.map +1 -0
- package/dist/backend/services/email-verification-service.js +95 -0
- package/dist/backend/services/email-verification-service.js.map +1 -0
- package/dist/backend/services/invitation-service.d.ts +85 -0
- package/dist/backend/services/invitation-service.d.ts.map +1 -0
- package/dist/backend/services/invitation-service.js +266 -0
- package/dist/backend/services/invitation-service.js.map +1 -0
- package/dist/backend/services/normalize-name.d.ts +14 -0
- package/dist/backend/services/normalize-name.d.ts.map +1 -0
- package/dist/backend/services/normalize-name.js +14 -0
- package/dist/backend/services/normalize-name.js.map +1 -0
- package/dist/backend/services/org-registration-notifier.d.ts +36 -0
- package/dist/backend/services/org-registration-notifier.d.ts.map +1 -0
- package/dist/backend/services/org-registration-notifier.js +109 -0
- package/dist/backend/services/org-registration-notifier.js.map +1 -0
- package/dist/backend/services/org-template-email.d.ts +18 -0
- package/dist/backend/services/org-template-email.d.ts.map +1 -0
- package/dist/backend/services/org-template-email.js +16 -0
- package/dist/backend/services/org-template-email.js.map +1 -0
- package/dist/backend/services/organization-context-service.d.ts +52 -0
- package/dist/backend/services/organization-context-service.d.ts.map +1 -0
- package/dist/backend/services/organization-context-service.js +70 -0
- package/dist/backend/services/organization-context-service.js.map +1 -0
- package/dist/backend/services/organization-country-reference.d.ts +11 -0
- package/dist/backend/services/organization-country-reference.d.ts.map +1 -0
- package/dist/backend/services/organization-country-reference.js +24 -0
- package/dist/backend/services/organization-country-reference.js.map +1 -0
- package/dist/backend/services/organization-details-port.d.ts +33 -0
- package/dist/backend/services/organization-details-port.d.ts.map +1 -0
- package/dist/backend/services/organization-details-port.js +95 -0
- package/dist/backend/services/organization-details-port.js.map +1 -0
- package/dist/backend/services/organization-effective-pricelists-service.d.ts +50 -0
- package/dist/backend/services/organization-effective-pricelists-service.d.ts.map +1 -0
- package/dist/backend/services/organization-effective-pricelists-service.js +68 -0
- package/dist/backend/services/organization-effective-pricelists-service.js.map +1 -0
- package/dist/backend/services/organization-inheritance-service.d.ts +73 -0
- package/dist/backend/services/organization-inheritance-service.d.ts.map +1 -0
- package/dist/backend/services/organization-inheritance-service.js +63 -0
- package/dist/backend/services/organization-inheritance-service.js.map +1 -0
- package/dist/backend/services/organization-moderation-service.d.ts +124 -0
- package/dist/backend/services/organization-moderation-service.d.ts.map +1 -0
- package/dist/backend/services/organization-moderation-service.js +337 -0
- package/dist/backend/services/organization-moderation-service.js.map +1 -0
- package/dist/backend/services/organization-restriction-service.d.ts +70 -0
- package/dist/backend/services/organization-restriction-service.d.ts.map +1 -0
- package/dist/backend/services/organization-restriction-service.js +210 -0
- package/dist/backend/services/organization-restriction-service.js.map +1 -0
- package/dist/backend/services/organization-tax-id-validation-service.d.ts +59 -0
- package/dist/backend/services/organization-tax-id-validation-service.d.ts.map +1 -0
- package/dist/backend/services/organization-tax-id-validation-service.js +115 -0
- package/dist/backend/services/organization-tax-id-validation-service.js.map +1 -0
- package/dist/backend/services/organization-tree-service.d.ts +102 -0
- package/dist/backend/services/organization-tree-service.d.ts.map +1 -0
- package/dist/backend/services/organization-tree-service.js +184 -0
- package/dist/backend/services/organization-tree-service.js.map +1 -0
- package/dist/backend/services/personal-organization-service.d.ts +130 -0
- package/dist/backend/services/personal-organization-service.d.ts.map +1 -0
- package/dist/backend/services/personal-organization-service.js +207 -0
- package/dist/backend/services/personal-organization-service.js.map +1 -0
- package/dist/backend/services/registration-service.d.ts +80 -0
- package/dist/backend/services/registration-service.d.ts.map +1 -0
- package/dist/backend/services/registration-service.js +126 -0
- package/dist/backend/services/registration-service.js.map +1 -0
- package/dist/backend/services/sales-rep-assignment-service.d.ts +89 -0
- package/dist/backend/services/sales-rep-assignment-service.d.ts.map +1 -0
- package/dist/backend/services/sales-rep-assignment-service.js +176 -0
- package/dist/backend/services/sales-rep-assignment-service.js.map +1 -0
- package/dist/backend/services/vat-validator-port.d.ts +20 -0
- package/dist/backend/services/vat-validator-port.d.ts.map +1 -0
- package/dist/backend/services/vat-validator-port.js +2 -0
- package/dist/backend/services/vat-validator-port.js.map +1 -0
- package/dist/manifest.d.ts +176 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +503 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260424T205317_organizations_init.d.ts +13 -0
- package/dist/migrations/20260424T205317_organizations_init.d.ts.map +1 -0
- package/dist/migrations/20260424T205317_organizations_init.js +100 -0
- package/dist/migrations/20260424T205317_organizations_init.js.map +1 -0
- package/dist/migrations/20260425T051700_organizations_invitations_init.d.ts +13 -0
- package/dist/migrations/20260425T051700_organizations_invitations_init.d.ts.map +1 -0
- package/dist/migrations/20260425T051700_organizations_invitations_init.js +39 -0
- package/dist/migrations/20260425T051700_organizations_invitations_init.js.map +1 -0
- package/dist/migrations/20260611T140349_organizations_consolidation.d.ts +35 -0
- package/dist/migrations/20260611T140349_organizations_consolidation.d.ts.map +1 -0
- package/dist/migrations/20260611T140349_organizations_consolidation.js +180 -0
- package/dist/migrations/20260611T140349_organizations_consolidation.js.map +1 -0
- package/dist/migrations/20260611T140358_organizations_org_order_confirmation_emails.d.ts +10 -0
- package/dist/migrations/20260611T140358_organizations_org_order_confirmation_emails.d.ts.map +1 -0
- package/dist/migrations/20260611T140358_organizations_org_order_confirmation_emails.js +14 -0
- package/dist/migrations/20260611T140358_organizations_org_order_confirmation_emails.js.map +1 -0
- package/dist/migrations/20260611T140402_organizations_org_fulfilment_strategy.d.ts +14 -0
- package/dist/migrations/20260611T140402_organizations_org_fulfilment_strategy.d.ts.map +1 -0
- package/dist/migrations/20260611T140402_organizations_org_fulfilment_strategy.js +20 -0
- package/dist/migrations/20260611T140402_organizations_org_fulfilment_strategy.js.map +1 -0
- package/dist/migrations/20260717T151403_organizations_personal_organizations.d.ts +24 -0
- package/dist/migrations/20260717T151403_organizations_personal_organizations.d.ts.map +1 -0
- package/dist/migrations/20260717T151403_organizations_personal_organizations.js +63 -0
- package/dist/migrations/20260717T151403_organizations_personal_organizations.js.map +1 -0
- package/dist/migrations/20260718T200340_organizations_organization_custom_field_values.d.ts +12 -0
- package/dist/migrations/20260718T200340_organizations_organization_custom_field_values.d.ts.map +1 -0
- package/dist/migrations/20260718T200340_organizations_organization_custom_field_values.js +16 -0
- package/dist/migrations/20260718T200340_organizations_organization_custom_field_values.js.map +1 -0
- package/dist/migrations/20260720T044254_organizations_org_hierarchy.d.ts +23 -0
- package/dist/migrations/20260720T044254_organizations_org_hierarchy.d.ts.map +1 -0
- package/dist/migrations/20260720T044254_organizations_org_hierarchy.js +37 -0
- package/dist/migrations/20260720T044254_organizations_org_hierarchy.js.map +1 -0
- package/dist/migrations/20260912T094646_organizations_sales_channel_organizations.d.ts +27 -0
- package/dist/migrations/20260912T094646_organizations_sales_channel_organizations.d.ts.map +1 -0
- package/dist/migrations/20260912T094646_organizations_sales_channel_organizations.js +44 -0
- package/dist/migrations/20260912T094646_organizations_sales_channel_organizations.js.map +1 -0
- package/dist/migrations/index.d.ts +35 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +45 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/ports/index.d.ts +53 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +2 -0
- package/dist/ports/index.js.map +1 -0
- package/docs/organization-hierarchy.md +117 -0
- package/docs/organizations.md +312 -0
- package/i18n/en.json +17 -0
- package/i18n/pl.json +17 -0
- package/package.json +107 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { AdminNotificationRecordPort, EmailMailerPort } from '@endora-commerce/contracts';
|
|
3
|
+
import { type OrgTemplateEmail } from './org-template-email.js';
|
|
4
|
+
/**
|
|
5
|
+
* OrgRegistrationNotifier — subscribes to `organization.registered.v1` and
|
|
6
|
+
* dispatches two side effects:
|
|
7
|
+
*
|
|
8
|
+
* 1. Writes one `admin_notifications` row (audience='all_admins',
|
|
9
|
+
* kind='organization.registered') so the admin bell + feed pick it up.
|
|
10
|
+
* 2. Reads the `organizations.notifications.new_registration_recipients`
|
|
11
|
+
* setting (a list of e-mail addresses) and sends one notification e-mail
|
|
12
|
+
* per recipient. Empty / unset list ⇒ no e-mails (the admin bell still
|
|
13
|
+
* fires).
|
|
14
|
+
*
|
|
15
|
+
* The notifier is best-effort by design — a downstream failure never
|
|
16
|
+
* poisons the registration itself, which has already committed before the
|
|
17
|
+
* event was emitted.
|
|
18
|
+
*/
|
|
19
|
+
export interface OrgRegistrationNotifierDeps {
|
|
20
|
+
emFactory: () => EntityManager;
|
|
21
|
+
adminNotificationService: AdminNotificationRecordPort;
|
|
22
|
+
mailer: EmailMailerPort;
|
|
23
|
+
resolveRecipients: () => Promise<string[]>;
|
|
24
|
+
onError?: (err: unknown) => void;
|
|
25
|
+
/** Feature 047 — optional admin-editable template path. */
|
|
26
|
+
templateEmail?: OrgTemplateEmail;
|
|
27
|
+
}
|
|
28
|
+
export declare class OrgRegistrationNotifier {
|
|
29
|
+
private readonly deps;
|
|
30
|
+
constructor(deps: OrgRegistrationNotifierDeps);
|
|
31
|
+
handleRegistered(organizationId: string): Promise<void>;
|
|
32
|
+
private writeAdminNotification;
|
|
33
|
+
private dispatchRecipientEmails;
|
|
34
|
+
private composeBody;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=org-registration-notifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-registration-notifier.d.ts","sourceRoot":"","sources":["../../../src/backend/services/org-registration-notifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,OAAO,KAAK,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,EAAwB,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEtF;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B,wBAAwB,EAAE,2BAA2B,CAAC;IACtD,MAAM,EAAE,eAAe,CAAC;IACxB,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,2DAA2D;IAC3D,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC;AAED,qBAAa,uBAAuB;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,2BAA2B;IAExD,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAuB/C,sBAAsB;YAetB,uBAAuB;IAmDrC,OAAO,CAAC,WAAW;CAWpB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { rethrowIfModuleDisabled } from '@endora-commerce/platform/kernel';
|
|
2
|
+
import { Organization } from '../entities/organization.entity.js';
|
|
3
|
+
import { noopOrgTemplateEmail } from './org-template-email.js';
|
|
4
|
+
export class OrgRegistrationNotifier {
|
|
5
|
+
deps;
|
|
6
|
+
constructor(deps) {
|
|
7
|
+
this.deps = deps;
|
|
8
|
+
}
|
|
9
|
+
async handleRegistered(organizationId) {
|
|
10
|
+
try {
|
|
11
|
+
const em = this.deps.emFactory();
|
|
12
|
+
const org = await em.findOne(Organization, { id: organizationId, deletedAt: null });
|
|
13
|
+
if (!org)
|
|
14
|
+
return;
|
|
15
|
+
await this.writeAdminNotification(org);
|
|
16
|
+
await this.dispatchRecipientEmails(org);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
// `writeAdminNotification` reaches `admin_notifications` through a gated
|
|
20
|
+
// port, and that module declares no `activation.nonDeactivatable`: switch
|
|
21
|
+
// it off and every organization registration went silently un-notified,
|
|
22
|
+
// with `onError` absorbing the 503 (D-88). A registration nobody was told
|
|
23
|
+
// about is not a degrade `organizations` may choose on
|
|
24
|
+
// `admin_notifications`' behalf — if that module is off, the answer
|
|
25
|
+
// belongs in its own port's return type, decided by its owner. The rest
|
|
26
|
+
// of the tolerance stays: the registration itself has already committed,
|
|
27
|
+
// so an ordinary downstream failure must not poison it.
|
|
28
|
+
rethrowIfModuleDisabled(err);
|
|
29
|
+
this.deps.onError?.(err);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async writeAdminNotification(org) {
|
|
33
|
+
await this.deps.adminNotificationService.record({
|
|
34
|
+
audience: 'all_admins',
|
|
35
|
+
kind: 'organization.registered',
|
|
36
|
+
subjectType: 'organization',
|
|
37
|
+
subjectId: org.id,
|
|
38
|
+
title: `Nowa Organizacja: ${org.name}`,
|
|
39
|
+
body: org.status === 'pending_verification'
|
|
40
|
+
? 'Oczekuje na weryfikację.'
|
|
41
|
+
: 'Zarejestrowana automatycznie.',
|
|
42
|
+
linkPath: `/organizations/${org.id}`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async dispatchRecipientEmails(org) {
|
|
46
|
+
let recipients = [];
|
|
47
|
+
try {
|
|
48
|
+
recipients = await this.deps.resolveRecipients();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Setting unreachable — degrade to "no email recipients".
|
|
52
|
+
}
|
|
53
|
+
if (recipients.length === 0)
|
|
54
|
+
return;
|
|
55
|
+
const template = this.deps.templateEmail ?? noopOrgTemplateEmail;
|
|
56
|
+
const statusLabel = org.status === 'pending_verification' ? 'Oczekuje na weryfikację' : 'Aktywna';
|
|
57
|
+
for (const to of recipients) {
|
|
58
|
+
const messageId = `organization.registered.${org.id}.${to.toLowerCase()}`;
|
|
59
|
+
try {
|
|
60
|
+
const sentViaTemplate = await template.trySend({
|
|
61
|
+
code: 'new_org_registration',
|
|
62
|
+
to,
|
|
63
|
+
messageId,
|
|
64
|
+
variables: {
|
|
65
|
+
organizationName: org.name,
|
|
66
|
+
taxId: org.taxId,
|
|
67
|
+
statusLabel,
|
|
68
|
+
linkPath: `/organizations/${org.id}`,
|
|
69
|
+
},
|
|
70
|
+
meta: { organizationId: org.id, kind: 'organization.registered' },
|
|
71
|
+
});
|
|
72
|
+
if (!sentViaTemplate) {
|
|
73
|
+
const outcome = await this.deps.mailer.send({
|
|
74
|
+
messageId,
|
|
75
|
+
to,
|
|
76
|
+
subject: `Nowa Organizacja: ${org.name}`,
|
|
77
|
+
text: this.composeBody(org),
|
|
78
|
+
meta: { organizationId: org.id, kind: 'organization.registered' },
|
|
79
|
+
});
|
|
80
|
+
if (outcome.status !== 'sent') {
|
|
81
|
+
// `onError` is for a throw; a suppression is not one. Each
|
|
82
|
+
// recipient is independent, so it is named on its own — and D-59's
|
|
83
|
+
// record holds the same fact per recipient.
|
|
84
|
+
console.warn('[organizations] the new-organization e-mail was not sent', {
|
|
85
|
+
organizationId: org.id,
|
|
86
|
+
to,
|
|
87
|
+
reason: outcome.reason,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
this.deps.onError?.(err);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
composeBody(org) {
|
|
98
|
+
return [
|
|
99
|
+
`Zarejestrowała się nowa Organizacja na platformie B2B.`,
|
|
100
|
+
``,
|
|
101
|
+
` Nazwa: ${org.name}`,
|
|
102
|
+
` NIP/VAT: ${org.taxId}`,
|
|
103
|
+
` Status: ${org.status === 'pending_verification' ? 'Oczekuje na weryfikację' : 'Aktywna'}`,
|
|
104
|
+
``,
|
|
105
|
+
`Otwórz w Panelu Administracyjnym: /organizations/${org.id}`,
|
|
106
|
+
].join('\n');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=org-registration-notifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-registration-notifier.js","sourceRoot":"","sources":["../../../src/backend/services/org-registration-notifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface OrgTemplateEmail {
|
|
2
|
+
/**
|
|
3
|
+
* `true` means "handled — do not use the legacy in-code builder", which
|
|
4
|
+
* includes an email the operator deactivated: off must stay off rather than
|
|
5
|
+
* silently degrade to the in-code version. Only a code with no definition at
|
|
6
|
+
* all answers `false`.
|
|
7
|
+
*/
|
|
8
|
+
trySend(input: {
|
|
9
|
+
code: string;
|
|
10
|
+
to: string;
|
|
11
|
+
messageId: string;
|
|
12
|
+
variables: Record<string, unknown>;
|
|
13
|
+
meta?: Record<string, unknown> | undefined;
|
|
14
|
+
}): Promise<boolean>;
|
|
15
|
+
}
|
|
16
|
+
/** No-op helper (sender not wired) — always falls back to the legacy builder. */
|
|
17
|
+
export declare const noopOrgTemplateEmail: OrgTemplateEmail;
|
|
18
|
+
//# sourceMappingURL=org-template-email.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-template-email.d.ts","sourceRoot":"","sources":["../../../src/backend/services/org-template-email.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,OAAO,CAAC,KAAK,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;KAC5C,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtB;AAED,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,EAAE,gBAIlC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Feature 047 — the shape an organizations email takes when it routes through
|
|
2
|
+
// the admin-editable transactional template, and the no-op that makes the
|
|
3
|
+
// caller fall back to its legacy in-code builder.
|
|
4
|
+
//
|
|
5
|
+
// The implementation left in T120: it was pure sender-plus-channel logic, so it
|
|
6
|
+
// belongs to `transactional_emails`, which offers it as `templateEmailPort`.
|
|
7
|
+
// What stays here is the *shape this module needs*, declared locally so
|
|
8
|
+
// resolving the port crosses no boundary — the port pattern, rather than an
|
|
9
|
+
// import of another module's helper.
|
|
10
|
+
/** No-op helper (sender not wired) — always falls back to the legacy builder. */
|
|
11
|
+
export const noopOrgTemplateEmail = {
|
|
12
|
+
async trySend() {
|
|
13
|
+
return false;
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=org-template-email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-template-email.js","sourceRoot":"","sources":["../../../src/backend/services/org-template-email.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAC1E,kDAAkD;AAClD,EAAE;AACF,gFAAgF;AAChF,6EAA6E;AAC7E,wEAAwE;AACxE,4EAA4E;AAC5E,qCAAqC;AAkBrC,iFAAiF;AACjF,MAAM,CAAC,MAAM,oBAAoB,GAAqB;IACpD,KAAK,CAAC,OAAO;QACX,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { OrganizationCannotTransactError, OrganizationNotFoundError } from '@endora-commerce/contracts';
|
|
3
|
+
import { Organization } from '../entities/organization.entity.js';
|
|
4
|
+
/**
|
|
5
|
+
* Lightweight read-side service that exposes "what's the effective state of
|
|
6
|
+
* this Customer's Organization?" without forcing every caller to write the
|
|
7
|
+
* `findOne` boilerplate.
|
|
8
|
+
*
|
|
9
|
+
* Two responsibilities only:
|
|
10
|
+
*
|
|
11
|
+
* 1. `loadEffectiveOrganization(organizationId)` — returns the Organization
|
|
12
|
+
* or `null` if it doesn't exist / is soft-deleted. Cheap (single PK
|
|
13
|
+
* lookup; MikroORM caches per request).
|
|
14
|
+
*
|
|
15
|
+
* 2. `assertCanTransact(orgId | org)` — throws `OrganizationCannotTransactError`
|
|
16
|
+
* when the status is anything other than `active`. The error carries a
|
|
17
|
+
* localized-message key and the current status so route handlers can map
|
|
18
|
+
* it to HTTP 423 with a Customer-friendly body.
|
|
19
|
+
*
|
|
20
|
+
* The service is consumed by cart-line-add, checkout-submit, and
|
|
21
|
+
* quote-request-submit route handlers. Read-only flows (browse, view-cart,
|
|
22
|
+
* order-history) do NOT call `assertCanTransact` — pending / blocked /
|
|
23
|
+
* rejected Organizations may still see the storefront.
|
|
24
|
+
*/
|
|
25
|
+
export declare class OrganizationContextService {
|
|
26
|
+
private readonly emFactory;
|
|
27
|
+
constructor(emFactory: () => EntityManager);
|
|
28
|
+
loadEffectiveOrganization(organizationId: string): Promise<Organization | null>;
|
|
29
|
+
/**
|
|
30
|
+
* @throws {OrganizationNotFoundError} when the org doesn't exist.
|
|
31
|
+
* @throws {OrganizationCannotTransactError} when status ≠ `active`.
|
|
32
|
+
*/
|
|
33
|
+
assertCanTransact(organizationId: string): Promise<Organization>;
|
|
34
|
+
/**
|
|
35
|
+
* Feature 027 §R2 — single-boolean lookup driving the per-Organization
|
|
36
|
+
* cart-approval policy. Returns `false` when the Organization is
|
|
37
|
+
* missing or soft-deleted (the gate is off by definition in that case
|
|
38
|
+
* — a Customer with no Organization uses platform defaults).
|
|
39
|
+
*/
|
|
40
|
+
loadCartApprovalPolicy(organizationId: string | null): Promise<boolean>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Both error classes moved to `@endora-commerce/contracts` in feature 075's Phase P. An
|
|
44
|
+
* error is a shape, not behaviour — four modules catch `instanceof` on the
|
|
45
|
+
* second one to turn it into a 409 envelope, and the kernel's
|
|
46
|
+
* `OrganizationReadPort` has documented both as `assertCanTransact`'s failure
|
|
47
|
+
* modes since D-32 while the classes themselves lived in this file.
|
|
48
|
+
*
|
|
49
|
+
* Re-exported here for the length of Phase P, which cuts no consumer.
|
|
50
|
+
*/
|
|
51
|
+
export { OrganizationNotFoundError, OrganizationCannotTransactError };
|
|
52
|
+
//# sourceMappingURL=organization-context-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization-context-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/organization-context-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EACL,+BAA+B,EAC/B,yBAAyB,EAC1B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,0BAA0B;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,aAAa;IAErD,yBAAyB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAKrF;;;OAGG;IACG,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAWtE;;;;;OAKG;IACG,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;CAK9E;AAED;;;;;;;;GAQG;AACH,OAAO,EAAE,yBAAyB,EAAE,+BAA+B,EAAE,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OrganizationCannotTransactError, OrganizationNotFoundError, } from '@endora-commerce/contracts';
|
|
2
|
+
import { Organization } from '../entities/organization.entity.js';
|
|
3
|
+
/**
|
|
4
|
+
* Lightweight read-side service that exposes "what's the effective state of
|
|
5
|
+
* this Customer's Organization?" without forcing every caller to write the
|
|
6
|
+
* `findOne` boilerplate.
|
|
7
|
+
*
|
|
8
|
+
* Two responsibilities only:
|
|
9
|
+
*
|
|
10
|
+
* 1. `loadEffectiveOrganization(organizationId)` — returns the Organization
|
|
11
|
+
* or `null` if it doesn't exist / is soft-deleted. Cheap (single PK
|
|
12
|
+
* lookup; MikroORM caches per request).
|
|
13
|
+
*
|
|
14
|
+
* 2. `assertCanTransact(orgId | org)` — throws `OrganizationCannotTransactError`
|
|
15
|
+
* when the status is anything other than `active`. The error carries a
|
|
16
|
+
* localized-message key and the current status so route handlers can map
|
|
17
|
+
* it to HTTP 423 with a Customer-friendly body.
|
|
18
|
+
*
|
|
19
|
+
* The service is consumed by cart-line-add, checkout-submit, and
|
|
20
|
+
* quote-request-submit route handlers. Read-only flows (browse, view-cart,
|
|
21
|
+
* order-history) do NOT call `assertCanTransact` — pending / blocked /
|
|
22
|
+
* rejected Organizations may still see the storefront.
|
|
23
|
+
*/
|
|
24
|
+
export class OrganizationContextService {
|
|
25
|
+
emFactory;
|
|
26
|
+
constructor(emFactory) {
|
|
27
|
+
this.emFactory = emFactory;
|
|
28
|
+
}
|
|
29
|
+
async loadEffectiveOrganization(organizationId) {
|
|
30
|
+
const em = this.emFactory();
|
|
31
|
+
return em.findOne(Organization, { id: organizationId, deletedAt: null });
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* @throws {OrganizationNotFoundError} when the org doesn't exist.
|
|
35
|
+
* @throws {OrganizationCannotTransactError} when status ≠ `active`.
|
|
36
|
+
*/
|
|
37
|
+
async assertCanTransact(organizationId) {
|
|
38
|
+
const org = await this.loadEffectiveOrganization(organizationId);
|
|
39
|
+
if (!org) {
|
|
40
|
+
throw new OrganizationNotFoundError(organizationId);
|
|
41
|
+
}
|
|
42
|
+
if (org.status !== 'active') {
|
|
43
|
+
throw new OrganizationCannotTransactError(org.id, org.status);
|
|
44
|
+
}
|
|
45
|
+
return org;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Feature 027 §R2 — single-boolean lookup driving the per-Organization
|
|
49
|
+
* cart-approval policy. Returns `false` when the Organization is
|
|
50
|
+
* missing or soft-deleted (the gate is off by definition in that case
|
|
51
|
+
* — a Customer with no Organization uses platform defaults).
|
|
52
|
+
*/
|
|
53
|
+
async loadCartApprovalPolicy(organizationId) {
|
|
54
|
+
if (!organizationId)
|
|
55
|
+
return false;
|
|
56
|
+
const org = await this.loadEffectiveOrganization(organizationId);
|
|
57
|
+
return org?.requiresCartApproval ?? false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Both error classes moved to `@endora-commerce/contracts` in feature 075's Phase P. An
|
|
62
|
+
* error is a shape, not behaviour — four modules catch `instanceof` on the
|
|
63
|
+
* second one to turn it into a 409 envelope, and the kernel's
|
|
64
|
+
* `OrganizationReadPort` has documented both as `assertCanTransact`'s failure
|
|
65
|
+
* modes since D-32 while the classes themselves lived in this file.
|
|
66
|
+
*
|
|
67
|
+
* Re-exported here for the length of Phase P, which cuts no consumer.
|
|
68
|
+
*/
|
|
69
|
+
export { OrganizationNotFoundError, OrganizationCannotTransactError };
|
|
70
|
+
//# sourceMappingURL=organization-context-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization-context-service.js","sourceRoot":"","sources":["../../../src/backend/services/organization-context-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,+BAA+B,EAC/B,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,0BAA0B;IACR;IAA7B,YAA6B,SAA8B;QAA9B,cAAS,GAAT,SAAS,CAAqB;IAAG,CAAC;IAE/D,KAAK,CAAC,yBAAyB,CAAC,cAAsB;QACpD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,iBAAiB,CAAC,cAAsB;QAC5C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,cAAc,CAAC,CAAC;QACjE,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,yBAAyB,CAAC,cAAc,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,IAAI,+BAA+B,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,sBAAsB,CAAC,cAA6B;QACxD,IAAI,CAAC,cAAc;YAAE,OAAO,KAAK,CAAC;QAClC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,cAAc,CAAC,CAAC;QACjE,OAAO,GAAG,EAAE,oBAAoB,IAAI,KAAK,CAAC;IAC5C,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,OAAO,EAAE,yBAAyB,EAAE,+BAA+B,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DictionaryReferenceRegistryPort } from '@endora-commerce/contracts';
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
3
|
+
/**
|
|
4
|
+
* Who in `organizations` still points at a country (feature 077, D-87).
|
|
5
|
+
*
|
|
6
|
+
* The country sits inside the `registered_address` JSONB column, which is
|
|
7
|
+
* why `dictionaries` used to reach for `->>'country'` against this module's
|
|
8
|
+
* table directly. The path lives here now, next to the column it is about.
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerOrganizationCountryReferences(registry: DictionaryReferenceRegistryPort, emFactory: () => EntityManager): void;
|
|
11
|
+
//# sourceMappingURL=organization-country-reference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization-country-reference.d.ts","sourceRoot":"","sources":["../../../src/backend/services/organization-country-reference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;;;GAMG;AACH,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,+BAA+B,EACzC,SAAS,EAAE,MAAM,aAAa,GAC7B,IAAI,CAqBN"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who in `organizations` still points at a country (feature 077, D-87).
|
|
3
|
+
*
|
|
4
|
+
* The country sits inside the `registered_address` JSONB column, which is
|
|
5
|
+
* why `dictionaries` used to reach for `->>'country'` against this module's
|
|
6
|
+
* table directly. The path lives here now, next to the column it is about.
|
|
7
|
+
*/
|
|
8
|
+
export function registerOrganizationCountryReferences(registry, emFactory) {
|
|
9
|
+
registry.register({
|
|
10
|
+
ownerModuleId: 'organizations',
|
|
11
|
+
consumer: 'organizations',
|
|
12
|
+
tableName: 'organizations',
|
|
13
|
+
columnName: 'registered_address.country',
|
|
14
|
+
blocking: true,
|
|
15
|
+
countReferences: async (code) => {
|
|
16
|
+
const rows = (await emFactory().execute(`select count(*)::int as n from "organizations" where "registered_address"->>'country' = ?`, [code]));
|
|
17
|
+
return rows[0]?.n ?? 0;
|
|
18
|
+
},
|
|
19
|
+
usedCodes: async () => (await emFactory().execute(`select "registered_address"->>'country' as code, count(*)::int as count
|
|
20
|
+
from "organizations" where "registered_address"->>'country' is not null
|
|
21
|
+
group by "registered_address"->>'country'`)),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=organization-country-reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization-country-reference.js","sourceRoot":"","sources":["../../../src/backend/services/organization-country-reference.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,MAAM,UAAU,qCAAqC,CACnD,QAAyC,EACzC,SAA8B;IAE9B,QAAQ,CAAC,QAAQ,CAAC;QAChB,aAAa,EAAE,eAAe;QAC9B,QAAQ,EAAE,eAAe;QACzB,SAAS,EAAE,eAAe;QAC1B,UAAU,EAAE,4BAA4B;QACxC,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YAC9B,MAAM,IAAI,GAAG,CAAC,MAAM,SAAS,EAAE,CAAC,OAAO,CACrC,2FAA2F,EAC3F,CAAC,IAAI,CAAC,CACP,CAAyB,CAAC;YAC3B,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,SAAS,EAAE,KAAK,IAAI,EAAE,CACpB,CAAC,MAAM,SAAS,EAAE,CAAC,OAAO,CACxB;;oDAE4C,CAC7C,CAA2C;KAC/C,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { OrganizationDetailsPort, OrganizationRecord } from '@endora-commerce/contracts';
|
|
3
|
+
import { Organization } from '../entities/organization.entity.js';
|
|
4
|
+
/**
|
|
5
|
+
* The row-level read model `organizations` publishes (feature 075, Phase P).
|
|
6
|
+
*
|
|
7
|
+
* Eleven modules read this table; 24 of the 47 inbound import sites are a
|
|
8
|
+
* direct `em.findOne` / `em.find` on the entity class, spread across carts,
|
|
9
|
+
* orders, pricing, quotes, push messages and two admin pickers. This service
|
|
10
|
+
* is the union of what they ask for, and the mapping into
|
|
11
|
+
* `OrganizationRecord` is what keeps the entity on this side of the boundary.
|
|
12
|
+
*
|
|
13
|
+
* It is a **second** port beside the kernel's `organizationReadPort`, not a
|
|
14
|
+
* replacement: that one is the tenancy projection (`{ id, status }` plus
|
|
15
|
+
* `assertCanTransact`), and D-55 settled it at that. See the contract's note.
|
|
16
|
+
*
|
|
17
|
+
* One behaviour deliberately changes as callers move onto it. Two of the three
|
|
18
|
+
* name pickers query `name` with `$ilike`, so a search for "lodz" misses
|
|
19
|
+
* "Łódź"; `searchByName` queries the diacritic-folded `nameSearch` column that
|
|
20
|
+
* exists for precisely this, as `orders`' list filter already does.
|
|
21
|
+
*/
|
|
22
|
+
export declare class OrganizationDetailsService implements OrganizationDetailsPort {
|
|
23
|
+
#private;
|
|
24
|
+
private readonly emFactory;
|
|
25
|
+
constructor(emFactory: () => EntityManager);
|
|
26
|
+
findById(id: string): Promise<OrganizationRecord | null>;
|
|
27
|
+
findByIds(ids: readonly string[]): Promise<OrganizationRecord[]>;
|
|
28
|
+
countByIds(ids: readonly string[]): Promise<number>;
|
|
29
|
+
searchByName(query: string, limit: number): Promise<OrganizationRecord[]>;
|
|
30
|
+
searchIdsByName(query: string): Promise<string[]>;
|
|
31
|
+
}
|
|
32
|
+
export declare function toOrganizationRecord(organization: Organization): OrganizationRecord;
|
|
33
|
+
//# sourceMappingURL=organization-details-port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization-details-port.d.ts","sourceRoot":"","sources":["../../../src/backend/services/organization-details-port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAE9F,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAElE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,0BAA2B,YAAW,uBAAuB;;IAC5D,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,aAAa;IAErD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAKxD,SAAS,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAMhE,UAAU,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAKnD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAQzE,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAYxD;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,YAAY,GAAG,kBAAkB,CAiCnF"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { normalizeOrganizationName } from '@endora-commerce/contracts';
|
|
2
|
+
import { Organization } from '../entities/organization.entity.js';
|
|
3
|
+
/**
|
|
4
|
+
* The row-level read model `organizations` publishes (feature 075, Phase P).
|
|
5
|
+
*
|
|
6
|
+
* Eleven modules read this table; 24 of the 47 inbound import sites are a
|
|
7
|
+
* direct `em.findOne` / `em.find` on the entity class, spread across carts,
|
|
8
|
+
* orders, pricing, quotes, push messages and two admin pickers. This service
|
|
9
|
+
* is the union of what they ask for, and the mapping into
|
|
10
|
+
* `OrganizationRecord` is what keeps the entity on this side of the boundary.
|
|
11
|
+
*
|
|
12
|
+
* It is a **second** port beside the kernel's `organizationReadPort`, not a
|
|
13
|
+
* replacement: that one is the tenancy projection (`{ id, status }` plus
|
|
14
|
+
* `assertCanTransact`), and D-55 settled it at that. See the contract's note.
|
|
15
|
+
*
|
|
16
|
+
* One behaviour deliberately changes as callers move onto it. Two of the three
|
|
17
|
+
* name pickers query `name` with `$ilike`, so a search for "lodz" misses
|
|
18
|
+
* "Łódź"; `searchByName` queries the diacritic-folded `nameSearch` column that
|
|
19
|
+
* exists for precisely this, as `orders`' list filter already does.
|
|
20
|
+
*/
|
|
21
|
+
export class OrganizationDetailsService {
|
|
22
|
+
emFactory;
|
|
23
|
+
constructor(emFactory) {
|
|
24
|
+
this.emFactory = emFactory;
|
|
25
|
+
}
|
|
26
|
+
async findById(id) {
|
|
27
|
+
const organization = await this.emFactory().findOne(Organization, { id });
|
|
28
|
+
return organization ? toOrganizationRecord(organization) : null;
|
|
29
|
+
}
|
|
30
|
+
async findByIds(ids) {
|
|
31
|
+
if (ids.length === 0)
|
|
32
|
+
return [];
|
|
33
|
+
const organizations = await this.emFactory().find(Organization, { id: { $in: [...ids] } });
|
|
34
|
+
return organizations.map(toOrganizationRecord);
|
|
35
|
+
}
|
|
36
|
+
async countByIds(ids) {
|
|
37
|
+
if (ids.length === 0)
|
|
38
|
+
return 0;
|
|
39
|
+
return this.emFactory().count(Organization, { id: { $in: [...ids] } });
|
|
40
|
+
}
|
|
41
|
+
async searchByName(query, limit) {
|
|
42
|
+
const organizations = await this.emFactory().find(Organization, this.#where(query), {
|
|
43
|
+
orderBy: { name: 'asc' },
|
|
44
|
+
limit,
|
|
45
|
+
});
|
|
46
|
+
return organizations.map(toOrganizationRecord);
|
|
47
|
+
}
|
|
48
|
+
async searchIdsByName(query) {
|
|
49
|
+
const rows = await this.emFactory().find(Organization, this.#where(query), {
|
|
50
|
+
fields: ['id'],
|
|
51
|
+
});
|
|
52
|
+
return rows.map((row) => row.id);
|
|
53
|
+
}
|
|
54
|
+
#where(query) {
|
|
55
|
+
const trimmed = query.trim();
|
|
56
|
+
if (!trimmed)
|
|
57
|
+
return {};
|
|
58
|
+
return { nameSearch: { $like: `%${normalizeOrganizationName(trimmed)}%` } };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function toOrganizationRecord(organization) {
|
|
62
|
+
return {
|
|
63
|
+
id: organization.id,
|
|
64
|
+
name: organization.name,
|
|
65
|
+
legalName: organization.legalName ?? null,
|
|
66
|
+
taxId: organization.taxId,
|
|
67
|
+
status: organization.status,
|
|
68
|
+
vatStatus: organization.vatStatus,
|
|
69
|
+
isPersonal: organization.isPersonal,
|
|
70
|
+
customerGroupId: organization.customerGroupId ?? null,
|
|
71
|
+
registeredAddress: organization.registeredAddress,
|
|
72
|
+
orderConfirmationEmails: organization.orderConfirmationEmails ?? [],
|
|
73
|
+
vatValidatedAt: organization.vatValidatedAt ?? null,
|
|
74
|
+
vatValidationProvider: organization.vatValidationProvider ?? null,
|
|
75
|
+
vatValidationOutcome: organization.vatValidationOutcome ?? null,
|
|
76
|
+
blockedReason: organization.blockedReason ?? null,
|
|
77
|
+
blockedAt: organization.blockedAt ?? null,
|
|
78
|
+
rejectedReason: organization.rejectedReason ?? null,
|
|
79
|
+
rejectedAt: organization.rejectedAt ?? null,
|
|
80
|
+
approvedAt: organization.approvedAt ?? null,
|
|
81
|
+
approvedByAdminUserId: organization.approvedByAdminUserId ?? null,
|
|
82
|
+
requiresCartApproval: organization.requiresCartApproval,
|
|
83
|
+
fulfilmentStrategy: organization.fulfilmentStrategy ?? null,
|
|
84
|
+
fulfilmentStrategyWarehouseOrder: organization.fulfilmentStrategyWarehouseOrder ?? null,
|
|
85
|
+
parentId: organization.parentId ?? null,
|
|
86
|
+
path: organization.path,
|
|
87
|
+
creditInheritanceMode: organization.creditInheritanceMode ?? null,
|
|
88
|
+
customFieldValues: organization.customFieldValues ?? {},
|
|
89
|
+
version: organization.version,
|
|
90
|
+
createdAt: organization.createdAt,
|
|
91
|
+
updatedAt: organization.updatedAt,
|
|
92
|
+
deletedAt: organization.deletedAt ?? null,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=organization-details-port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization-details-port.js","sourceRoot":"","sources":["../../../src/backend/services/organization-details-port.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { type PriceListReadPort } from '@endora-commerce/contracts';
|
|
3
|
+
/**
|
|
4
|
+
* Maps the application-rule-evaluator's `RuleCriterionType` tags to the
|
|
5
|
+
* customer-facing "reason" labels surfaced by the Organization detail
|
|
6
|
+
* panel (feature 026 US5). The Organization detail page reads
|
|
7
|
+
* `reasons[]` and renders one chip per entry.
|
|
8
|
+
*
|
|
9
|
+
* The category criterion is mapped to `segment_rule_match` because in
|
|
10
|
+
* practice a category-scoped price list functions as a segment rule
|
|
11
|
+
* from the operator's perspective.
|
|
12
|
+
*/
|
|
13
|
+
export type ApplicablePriceListReason = 'direct_organization_match' | 'customer_group_match' | 'sales_channel_inheritance' | 'segment_rule_match';
|
|
14
|
+
export interface ApplicablePriceListEntry {
|
|
15
|
+
priceListId: string;
|
|
16
|
+
name: string;
|
|
17
|
+
priority: number;
|
|
18
|
+
reasons: ApplicablePriceListReason[];
|
|
19
|
+
}
|
|
20
|
+
export interface OrganizationEffectivePriceListsDeps {
|
|
21
|
+
emFactory: () => EntityManager;
|
|
22
|
+
/**
|
|
23
|
+
* Sales-channel id used to evaluate channel-bound rules. The org-detail
|
|
24
|
+
* panel is read-only; passing the platform's system-default channel is
|
|
25
|
+
* sufficient because the panel surfaces what applies "to this
|
|
26
|
+
* Organization broadly" — channel-specific overrides are visible when
|
|
27
|
+
* an admin opens the relevant Sales Channel.
|
|
28
|
+
*/
|
|
29
|
+
resolveDefaultSalesChannelId: () => Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* `price_lists`' own answer to "which lists are active", rather than this
|
|
32
|
+
* module's copy of the status filter (feature 075, Phase C). With
|
|
33
|
+
* `price_lists` off the call fails closed and the panel refuses: an empty
|
|
34
|
+
* list here reads as "no price list applies to this organisation", which is
|
|
35
|
+
* a plausible answer and the wrong one.
|
|
36
|
+
*/
|
|
37
|
+
priceListRead: PriceListReadPort;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Returns the set of Price Lists currently applicable to a given
|
|
41
|
+
* Organization, each tagged with the reasons it applies. Implementation
|
|
42
|
+
* reuses the existing application-rule evaluator (no new persistence
|
|
43
|
+
* surface) — see research.md R6.
|
|
44
|
+
*/
|
|
45
|
+
export declare class OrganizationEffectivePriceListsService {
|
|
46
|
+
private readonly deps;
|
|
47
|
+
constructor(deps: OrganizationEffectivePriceListsDeps);
|
|
48
|
+
listApplicable(organizationId: string): Promise<ApplicablePriceListEntry[]>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=organization-effective-pricelists-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organization-effective-pricelists-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/organization-effective-pricelists-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAEL,KAAK,iBAAiB,EAEvB,MAAM,4BAA4B,CAAC;AAGpC;;;;;;;;;GASG;AACH,MAAM,MAAM,yBAAyB,GACjC,2BAA2B,GAC3B,sBAAsB,GACtB,2BAA2B,GAC3B,oBAAoB,CAAC;AAEzB,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,yBAAyB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,mCAAmC;IAClD,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B;;;;;;OAMG;IACH,4BAA4B,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD;;;;;;OAMG;IACH,aAAa,EAAE,iBAAiB,CAAC;CAClC;AAED;;;;;GAKG;AACH,qBAAa,sCAAsC;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,mCAAmC;IAEhE,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC;CAoDlF"}
|