@open-mercato/core 0.7.0 → 0.7.1-develop.7103.1.41ff100d93
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/.turbo/turbo-build.log +1 -1
- package/dist/helpers/integration/api.js +13 -1
- package/dist/helpers/integration/api.js.map +2 -2
- package/dist/helpers/integration/communicationChannelsFixtures.js +19 -0
- package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
- package/dist/modules/api_keys/api/keys/route.js +1 -1
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/page.js +3 -1
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/api_keys/di.js +9 -0
- package/dist/modules/api_keys/di.js.map +7 -0
- package/dist/modules/api_keys/services/principalService.js +31 -0
- package/dist/modules/api_keys/services/principalService.js.map +7 -0
- package/dist/modules/attachments/api/route.js +2 -2
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +2 -0
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/di.js +11 -1
- package/dist/modules/attachments/di.js.map +2 -2
- package/dist/modules/attachments/index.js.map +1 -1
- package/dist/modules/attachments/lib/attachment-service.js +313 -0
- package/dist/modules/attachments/lib/attachment-service.js.map +7 -0
- package/dist/modules/attachments/lib/scoped-upload-service.js +15 -2
- package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
- package/dist/modules/attachments/lib/upload-limits.js +6 -2
- package/dist/modules/attachments/lib/upload-limits.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +6 -0
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/audit_logs/lib/display-helpers.js +19 -11
- package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
- package/dist/modules/audit_logs/services/actionLogService.js +57 -12
- package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
- package/dist/modules/auth/acl.js +30 -5
- package/dist/modules/auth/acl.js.map +2 -2
- package/dist/modules/auth/api/feature-check.js +8 -2
- package/dist/modules/auth/api/feature-check.js.map +2 -2
- package/dist/modules/auth/api/login.js +4 -1
- package/dist/modules/auth/api/login.js.map +2 -2
- package/dist/modules/auth/api/reset/validate.js +55 -0
- package/dist/modules/auth/api/reset/validate.js.map +7 -0
- package/dist/modules/auth/api/roles/acl/route.js +28 -33
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/session/refresh.js +25 -1
- package/dist/modules/auth/api/session/refresh.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +96 -51
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +13 -5
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js +5 -1
- package/dist/modules/auth/backend/roles/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +3 -1
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js +5 -1
- package/dist/modules/auth/backend/users/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +2 -1
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/commands/acl.js +254 -0
- package/dist/modules/auth/commands/acl.js.map +7 -0
- package/dist/modules/auth/components/AclEditor.js +39 -30
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/data/validators.js +5 -1
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/auth/di.js +35 -9
- package/dist/modules/auth/di.js.map +2 -2
- package/dist/modules/auth/frontend/reset/[token]/page.js +46 -0
- package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
- package/dist/modules/auth/lib/grantChecks.js.map +2 -2
- package/dist/modules/auth/lib/userIdFilter.js +16 -0
- package/dist/modules/auth/lib/userIdFilter.js.map +7 -0
- package/dist/modules/auth/services/authService.js +16 -2
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/auth/services/principalService.js +200 -0
- package/dist/modules/auth/services/principalService.js.map +7 -0
- package/dist/modules/auth/services/rbacService.js +67 -24
- package/dist/modules/auth/services/rbacService.js.map +3 -3
- package/dist/modules/auth/services/roleOrganizationScope.js +41 -0
- package/dist/modules/auth/services/roleOrganizationScope.js.map +7 -0
- package/dist/modules/business_rules/backend/logs/page.js +3 -1
- package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +3 -1
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +3 -1
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/business_rules/lib/expression-evaluator.js +9 -9
- package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-evaluator.js +10 -9
- package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
- package/dist/modules/catalog/ai-agents.js +1 -1
- package/dist/modules/catalog/ai-agents.js.map +1 -1
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +2 -2
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +5 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -0
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +7 -1
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +2 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +9 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/test-seed/route.js +95 -10
- package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +3 -0
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js +14 -1
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
- package/dist/modules/communication_channels/di.js +7 -1
- package/dist/modules/communication_channels/di.js.map +2 -2
- package/dist/modules/communication_channels/lib/email-capabilities.js +4 -1
- package/dist/modules/communication_channels/lib/email-capabilities.js.map +2 -2
- package/dist/modules/communication_channels/lib/outbound-recipient.js +33 -0
- package/dist/modules/communication_channels/lib/outbound-recipient.js.map +7 -0
- package/dist/modules/communication_channels/lib/resolve-channel-type.js +51 -0
- package/dist/modules/communication_channels/lib/resolve-channel-type.js.map +7 -0
- package/dist/modules/communication_channels/lib/test-seed.js +41 -2
- package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
- package/dist/modules/configs/lib/system-status.js +9 -0
- package/dist/modules/configs/lib/system-status.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +3 -1
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +3 -1
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/currencies/services/rateFetchingService.js +6 -1
- package/dist/modules/currencies/services/rateFetchingService.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js +9 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
- package/dist/modules/customer_accounts/services/domainMappingService.js +10 -0
- package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
- package/dist/modules/customers/ai-tools/companies-pack.js +4 -1
- package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js +13 -2
- package/dist/modules/customers/ai-tools/deal-analyzer-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deals-pack.js +52 -6
- package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/people-pack.js +4 -1
- package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +48 -6
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/people/route.js +20 -64
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +17 -94
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +8 -5
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/companies/route.js +1 -1
- package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js +1 -1
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/route.js +8 -25
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/stats/route.js +3 -22
- package/dist/modules/customers/api/deals/[id]/stats/route.js.map +2 -2
- package/dist/modules/customers/api/deals/aggregate/route.js +14 -9
- package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
- package/dist/modules/customers/api/deals/map/route.js +5 -5
- package/dist/modules/customers/api/deals/map/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +38 -1
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/entity-roles-factory.js +4 -4
- package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +3 -1
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/tasks/route.js +27 -4
- package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +4 -3
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/context.js +1 -1
- package/dist/modules/customers/api/people/[id]/companies/context.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +1 -1
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +11 -10
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/check-phone/route.js +51 -9
- package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +30 -5
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +4 -2
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +6 -1
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +5 -2
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js +4 -13
- package/dist/modules/customers/backend/customers/deals/pipeline/components/Lane.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js +85 -14
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js +18 -0
- package/dist/modules/customers/backend/customers/deals/pipeline/components/toneClasses.js.map +7 -0
- package/dist/modules/customers/backend/customers/people/page.js +4 -2
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js +9 -3
- package/dist/modules/customers/backend/hooks/useEmailDuplicateCheck.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +21 -34
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js.map +1 -1
- package/dist/modules/customers/commands/personCompanyLinks.js +131 -2
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/customers/components/DealsKpiStrip.js +7 -6
- package/dist/modules/customers/components/DealsKpiStrip.js.map +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarScreen.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +1 -1
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
- package/dist/modules/customers/components/calendar/EventBlock.js +1 -1
- package/dist/modules/customers/components/calendar/EventBlock.js.map +2 -2
- package/dist/modules/customers/components/calendar/EventPeekPopover.js +3 -2
- package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +40 -5
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js +2 -1
- package/dist/modules/customers/components/calendar/editor/hooks.js.map +2 -2
- package/dist/modules/customers/components/calendar/types.js +1 -1
- package/dist/modules/customers/components/calendar/types.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyKpiBar.js +5 -4
- package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +3 -1
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +19 -7
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealsSection.js +6 -5
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +35 -11
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +3 -1
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +19 -13
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +4 -4
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +3 -3
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/detail/utils.js +5 -5
- package/dist/modules/customers/components/detail/utils.js.map +2 -2
- package/dist/modules/customers/data/entities.js.map +1 -1
- package/dist/modules/customers/data/validators.js +32 -3
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/events.js +5 -0
- package/dist/modules/customers/events.js.map +2 -2
- package/dist/modules/customers/lib/calendar/conflicts.js +8 -2
- package/dist/modules/customers/lib/calendar/conflicts.js.map +2 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js +3 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
- package/dist/modules/customers/lib/calendar/mapItem.js +8 -3
- package/dist/modules/customers/lib/calendar/mapItem.js.map +2 -2
- package/dist/modules/customers/lib/calendar/participantIdentity.js +9 -0
- package/dist/modules/customers/lib/calendar/participantIdentity.js.map +7 -0
- package/dist/modules/customers/lib/closureStage.js +45 -0
- package/dist/modules/customers/lib/closureStage.js.map +7 -0
- package/dist/modules/customers/lib/dealStatus.js +30 -0
- package/dist/modules/customers/lib/dealStatus.js.map +2 -2
- package/dist/modules/customers/lib/detailReadAccess.js +12 -0
- package/dist/modules/customers/lib/detailReadAccess.js.map +7 -0
- package/dist/modules/customers/lib/findPeopleByAddresses.js +1 -0
- package/dist/modules/customers/lib/findPeopleByAddresses.js.map +2 -2
- package/dist/modules/customers/lib/personCompanies.js +100 -2
- package/dist/modules/customers/lib/personCompanies.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +12 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetScope.js +6 -1
- package/dist/modules/dashboards/lib/widgetScope.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/lib/abandoned-run.js +19 -0
- package/dist/modules/data_sync/lib/abandoned-run.js.map +7 -0
- package/dist/modules/data_sync/lib/sync-engine.js +72 -6
- package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-export.js +5 -1
- package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-import.js +5 -1
- package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
- package/dist/modules/devices/acl.js +9 -1
- package/dist/modules/devices/acl.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/[id]/route.js +5 -32
- package/dist/modules/devices/api/admin/devices/[id]/route.js.map +2 -2
- package/dist/modules/devices/api/admin/devices/route.js +14 -1
- package/dist/modules/devices/api/admin/devices/route.js.map +2 -2
- package/dist/modules/devices/api/deviceList.js +99 -12
- package/dist/modules/devices/api/deviceList.js.map +2 -2
- package/dist/modules/devices/api/deviceSerialization.js +46 -0
- package/dist/modules/devices/api/deviceSerialization.js.map +7 -0
- package/dist/modules/devices/api/openapi.js +3 -1
- package/dist/modules/devices/api/openapi.js.map +2 -2
- package/dist/modules/devices/api/route.js +9 -1
- package/dist/modules/devices/api/route.js.map +2 -2
- package/dist/modules/devices/backend/devices/[id]/page.js +10 -26
- package/dist/modules/devices/backend/devices/[id]/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/create/page.js +17 -1
- package/dist/modules/devices/backend/devices/create/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/page.js +28 -34
- package/dist/modules/devices/backend/devices/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js +34 -0
- package/dist/modules/devices/backend/devices/useDeviceUserLabels.js.map +7 -0
- package/dist/modules/devices/backend/devices/userOptions.js +52 -0
- package/dist/modules/devices/backend/devices/userOptions.js.map +7 -0
- package/dist/modules/devices/setup.js +6 -2
- package/dist/modules/devices/setup.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/directory/di.js +9 -0
- package/dist/modules/directory/di.js.map +2 -2
- package/dist/modules/directory/services/organizationHierarchyService.js +29 -0
- package/dist/modules/directory/services/organizationHierarchyService.js.map +7 -0
- package/dist/modules/directory/services/organizationScopeService.js +56 -0
- package/dist/modules/directory/services/organizationScopeService.js.map +7 -0
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -2
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +3 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/eudr/api/plots/route.js +5 -1
- package/dist/modules/eudr/api/plots/route.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
- package/dist/modules/eudr/commands/statements.js +0 -3
- package/dist/modules/eudr/commands/statements.js.map +2 -2
- package/dist/modules/eudr/data/validators.js +4 -1
- package/dist/modules/eudr/data/validators.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +1 -0
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/OverridesTable.js +1 -0
- package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
- package/dist/modules/feature_toggles/defaults.json +0 -8
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js +1 -12
- package/dist/modules/inbox_ops/lib/htmlToPlainText.js.map +2 -2
- package/dist/modules/integrations/api/[id]/credentials/route.js +6 -1
- package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +38 -29
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +36 -9
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js +55 -0
- package/dist/modules/integrations/backend/integrations/credential-secret-fields.js.map +7 -0
- package/dist/modules/integrations/data/validators.js +11 -3
- package/dist/modules/integrations/data/validators.js.map +2 -2
- package/dist/modules/integrations/lib/credentials-masking.js +6 -2
- package/dist/modules/integrations/lib/credentials-masking.js.map +2 -2
- package/dist/modules/messages/api/[id]/route.js +29 -1
- package/dist/modules/messages/api/[id]/route.js.map +2 -2
- package/dist/modules/messages/api/openapi.js +17 -2
- package/dist/modules/messages/api/openapi.js.map +2 -2
- package/dist/modules/messages/api/route.js +17 -2
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +7 -14
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/components/inboxFilters.js +15 -0
- package/dist/modules/messages/components/inboxFilters.js.map +2 -2
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +11 -1
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +3 -1
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js +2 -1
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
- package/dist/modules/messages/components/messageListLabels.js +14 -2
- package/dist/modules/messages/components/messageListLabels.js.map +2 -2
- package/dist/modules/messages/data/validators.js +18 -4
- package/dist/modules/messages/data/validators.js.map +2 -2
- package/dist/modules/messages/lib/channel-sender-identity.js +26 -0
- package/dist/modules/messages/lib/channel-sender-identity.js.map +7 -0
- package/dist/modules/messages/lib/composeSourceChannelType.js +41 -0
- package/dist/modules/messages/lib/composeSourceChannelType.js.map +7 -0
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +4 -6
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -1
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/payment_gateways/lib/webhook-processor.js +7 -0
- package/dist/modules/payment_gateways/lib/webhook-processor.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -0
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/page.js +3 -1
- package/dist/modules/push_notifications/backend/push_notifications/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js +1 -1
- package/dist/modules/push_notifications/backend/push_notifications/send/page.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +150 -51
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/search-entity-policy.js +14 -0
- package/dist/modules/query_index/lib/search-entity-policy.js.map +7 -0
- package/dist/modules/query_index/lib/search-tokens.js +79 -3
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +3 -1
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +3 -1
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +10 -8
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +79 -1
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/PriceWithCurrency.js +7 -5
- package/dist/modules/sales/components/PriceWithCurrency.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +3 -0
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +8 -6
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +51 -22
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +83 -18
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +23 -9
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +8 -6
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +68 -14
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +6 -5
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +5 -4
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +8 -6
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js +54 -0
- package/dist/modules/sales/components/documents/lineItemShipmentLock.js.map +7 -0
- package/dist/modules/sales/components/documents/lineItemUtils.js +2 -2
- package/dist/modules/sales/components/documents/lineItemUtils.js.map +2 -2
- package/dist/modules/sales/data/entities.js +8 -2
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/extension-points.js +1 -0
- package/dist/modules/sales/extension-points.js.map +2 -2
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js +33 -0
- package/dist/modules/sales/lib/salesChannelsToggleSeed.js.map +7 -0
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js +32 -0
- package/dist/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.js.map +7 -0
- package/dist/modules/sales/setup.js +2 -0
- package/dist/modules/sales/setup.js.map +2 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +10 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +2 -2
- package/dist/modules/sales/widgets/injection-table.js +4 -7
- package/dist/modules/sales/widgets/injection-table.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +29 -18
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +3 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +1 -0
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/dist/modules/warranty_claims/api/assignees/route.js +3 -3
- package/dist/modules/warranty_claims/api/assignees/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js +12 -9
- package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/backend/page.js +3 -0
- package/dist/modules/warranty_claims/backend/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -0
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
- package/dist/modules/wms/api/warehouseSearch.js +21 -0
- package/dist/modules/wms/api/warehouseSearch.js.map +7 -0
- package/dist/modules/wms/api/warehouses/route.js +13 -9
- package/dist/modules/wms/api/warehouses/route.js.map +2 -2
- package/dist/modules/wms/api/zones/route.js +15 -2
- package/dist/modules/wms/api/zones/route.js.map +2 -2
- package/dist/modules/wms/commands/configuration.js +121 -9
- package/dist/modules/wms/commands/configuration.js.map +2 -2
- package/dist/modules/wms/commands/inventory-actions.js +3 -0
- package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
- package/dist/modules/wms/commands/shared.js +9 -1
- package/dist/modules/wms/commands/shared.js.map +2 -2
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js +158 -0
- package/dist/modules/wms/components/backend/WarehouseEditDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js +76 -111
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +3 -3
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +1 -0
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotsListPage.js +1 -0
- package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +27 -20
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
- package/dist/modules/wms/components/backend/warehouseFormOptions.js +66 -0
- package/dist/modules/wms/components/backend/warehouseFormOptions.js.map +7 -0
- package/dist/modules/workflows/backend/definitions/page.js +3 -1
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/page.js +3 -1
- package/dist/modules/workflows/backend/events/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +3 -1
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +3 -1
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +4 -0
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/package.json +9 -10
- package/src/helpers/integration/api.ts +33 -1
- package/src/helpers/integration/communicationChannelsFixtures.ts +69 -1
- package/src/modules/api_keys/api/keys/route.ts +3 -1
- package/src/modules/api_keys/backend/api-keys/page.tsx +4 -1
- package/src/modules/api_keys/di.ts +7 -0
- package/src/modules/api_keys/services/principalService.ts +33 -0
- package/src/modules/attachments/AGENTS.md +15 -0
- package/src/modules/attachments/api/route.ts +2 -2
- package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -0
- package/src/modules/attachments/di.ts +16 -0
- package/src/modules/attachments/i18n/de.json +5 -0
- package/src/modules/attachments/i18n/en.json +5 -0
- package/src/modules/attachments/i18n/es.json +5 -0
- package/src/modules/attachments/i18n/ko.json +5 -0
- package/src/modules/attachments/i18n/pl.json +5 -0
- package/src/modules/attachments/index.ts +10 -0
- package/src/modules/attachments/lib/attachment-service.ts +468 -0
- package/src/modules/attachments/lib/scoped-upload-service.ts +46 -0
- package/src/modules/attachments/lib/upload-limits.ts +6 -2
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +8 -0
- package/src/modules/audit_logs/lib/display-helpers.tsx +42 -32
- package/src/modules/audit_logs/services/actionLogService.ts +74 -11
- package/src/modules/auth/acl.ts +30 -6
- package/src/modules/auth/api/feature-check.ts +10 -3
- package/src/modules/auth/api/login.ts +9 -1
- package/src/modules/auth/api/reset/validate.ts +57 -0
- package/src/modules/auth/api/roles/acl/route.ts +42 -39
- package/src/modules/auth/api/session/refresh.ts +32 -1
- package/src/modules/auth/api/users/acl/route.ts +177 -53
- package/src/modules/auth/api/users/route.ts +18 -5
- package/src/modules/auth/backend/roles/[id]/edit/page.meta.ts +5 -2
- package/src/modules/auth/backend/roles/page.tsx +4 -2
- package/src/modules/auth/backend/users/[id]/edit/page.meta.ts +5 -2
- package/src/modules/auth/backend/users/page.tsx +3 -2
- package/src/modules/auth/commands/acl.ts +495 -0
- package/src/modules/auth/components/AclEditor.tsx +63 -33
- package/src/modules/auth/data/entities.ts +4 -1
- package/src/modules/auth/data/validators.ts +5 -0
- package/src/modules/auth/di.ts +46 -16
- package/src/modules/auth/frontend/reset/[token]/page.tsx +74 -0
- package/src/modules/auth/i18n/de.json +389 -0
- package/src/modules/auth/i18n/en.json +389 -0
- package/src/modules/auth/i18n/es.json +389 -0
- package/src/modules/auth/i18n/ko.json +389 -0
- package/src/modules/auth/i18n/pl.json +391 -2
- package/src/modules/auth/lib/grantChecks.ts +6 -0
- package/src/modules/auth/lib/userIdFilter.ts +31 -0
- package/src/modules/auth/services/authService.ts +18 -2
- package/src/modules/auth/services/principalService.ts +266 -0
- package/src/modules/auth/services/rbacService.ts +110 -24
- package/src/modules/auth/services/roleOrganizationScope.ts +70 -0
- package/src/modules/business_rules/backend/logs/page.tsx +4 -1
- package/src/modules/business_rules/backend/rules/page.tsx +4 -1
- package/src/modules/business_rules/backend/sets/page.tsx +4 -1
- package/src/modules/business_rules/lib/expression-evaluator.ts +9 -9
- package/src/modules/business_rules/lib/rule-evaluator.ts +10 -9
- package/src/modules/catalog/ai-agents.ts +1 -1
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +2 -2
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +12 -5
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +3 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +7 -0
- package/src/modules/catalog/i18n/de.json +1 -0
- package/src/modules/catalog/i18n/en.json +1 -0
- package/src/modules/catalog/i18n/es.json +1 -0
- package/src/modules/catalog/i18n/ko.json +1 -0
- package/src/modules/catalog/i18n/pl.json +1 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +4 -0
- package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +17 -1
- package/src/modules/communication_channels/api/post/test-seed/route.ts +155 -16
- package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +4 -0
- package/src/modules/communication_channels/commands/ingest-inbound-message.ts +38 -1
- package/src/modules/communication_channels/di.ts +7 -0
- package/src/modules/communication_channels/lib/adapter.ts +14 -0
- package/src/modules/communication_channels/lib/email-capabilities.ts +4 -0
- package/src/modules/communication_channels/lib/outbound-recipient.ts +71 -0
- package/src/modules/communication_channels/lib/resolve-channel-type.ts +99 -0
- package/src/modules/communication_channels/lib/test-seed.ts +64 -4
- package/src/modules/configs/i18n/de.json +2 -0
- package/src/modules/configs/i18n/en.json +2 -0
- package/src/modules/configs/i18n/es.json +2 -0
- package/src/modules/configs/i18n/ko.json +2 -0
- package/src/modules/configs/i18n/pl.json +2 -0
- package/src/modules/configs/lib/system-status.ts +9 -0
- package/src/modules/currencies/AGENTS.md +3 -0
- package/src/modules/currencies/backend/currencies/page.tsx +4 -1
- package/src/modules/currencies/backend/exchange-rates/page.tsx +4 -1
- package/src/modules/currencies/services/README.md +45 -0
- package/src/modules/currencies/services/rateFetchingService.ts +6 -1
- package/src/modules/customer_accounts/api/admin/domain-mappings.ts +7 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +4 -1
- package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +4 -1
- package/src/modules/customer_accounts/services/domainMappingService.ts +10 -0
- package/src/modules/customers/ai-tools/companies-pack.ts +4 -1
- package/src/modules/customers/ai-tools/deal-analyzer-pack.ts +17 -2
- package/src/modules/customers/ai-tools/deals-pack.ts +66 -1
- package/src/modules/customers/ai-tools/people-pack.ts +4 -1
- package/src/modules/customers/api/activities/route.ts +45 -0
- package/src/modules/customers/api/companies/[id]/people/route.ts +24 -73
- package/src/modules/customers/api/companies/[id]/route.ts +24 -107
- package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +16 -8
- package/src/modules/customers/api/deals/[id]/companies/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/people/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/route.ts +17 -28
- package/src/modules/customers/api/deals/[id]/stats/route.ts +10 -25
- package/src/modules/customers/api/deals/aggregate/route.ts +17 -9
- package/src/modules/customers/api/deals/map/route.ts +4 -4
- package/src/modules/customers/api/deals/route.ts +50 -1
- package/src/modules/customers/api/entity-roles-factory.ts +8 -4
- package/src/modules/customers/api/interactions/route.ts +8 -2
- package/src/modules/customers/api/interactions/tasks/route.ts +24 -1
- package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +12 -4
- package/src/modules/customers/api/people/[id]/companies/context.ts +4 -1
- package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +4 -1
- package/src/modules/customers/api/people/[id]/route.ts +16 -11
- package/src/modules/customers/api/people/check-phone/route.ts +75 -10
- package/src/modules/customers/api/todos/route.ts +27 -2
- package/src/modules/customers/backend/customers/companies/page.tsx +5 -2
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +7 -2
- package/src/modules/customers/backend/customers/deals/page.tsx +8 -2
- package/src/modules/customers/backend/customers/deals/pipeline/components/Lane.tsx +5 -14
- package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +109 -27
- package/src/modules/customers/backend/customers/deals/pipeline/components/toneClasses.ts +21 -0
- package/src/modules/customers/backend/customers/people/page.tsx +5 -2
- package/src/modules/customers/backend/hooks/useEmailDuplicateCheck.ts +12 -4
- package/src/modules/customers/commands/deals.ts +34 -59
- package/src/modules/customers/commands/interactions.ts +1 -1
- package/src/modules/customers/commands/personCompanyLinks.ts +224 -8
- package/src/modules/customers/components/CustomerTodosTable.tsx +2 -0
- package/src/modules/customers/components/DealsKpiStrip.tsx +7 -7
- package/src/modules/customers/components/calendar/AgendaList.tsx +3 -3
- package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +1 -1
- package/src/modules/customers/components/calendar/CalendarScreen.tsx +1 -1
- package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +1 -1
- package/src/modules/customers/components/calendar/EventBlock.tsx +2 -2
- package/src/modules/customers/components/calendar/EventPeekPopover.tsx +4 -2
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +61 -5
- package/src/modules/customers/components/calendar/editor/hooks.ts +7 -1
- package/src/modules/customers/components/calendar/types.ts +2 -2
- package/src/modules/customers/components/detail/CompanyKpiBar.tsx +5 -4
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +8 -1
- package/src/modules/customers/components/detail/DealForm.tsx +22 -2
- package/src/modules/customers/components/detail/DealsSection.tsx +11 -5
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +58 -12
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +8 -1
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +23 -14
- package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +5 -5
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +5 -5
- package/src/modules/customers/components/detail/types.ts +1 -1
- package/src/modules/customers/components/detail/utils.ts +15 -5
- package/src/modules/customers/data/entities.ts +1 -1
- package/src/modules/customers/data/validators.ts +50 -9
- package/src/modules/customers/events.ts +5 -0
- package/src/modules/customers/i18n/de.json +9 -1
- package/src/modules/customers/i18n/en.json +9 -1
- package/src/modules/customers/i18n/es.json +9 -1
- package/src/modules/customers/i18n/ko.json +9 -1
- package/src/modules/customers/i18n/pl.json +9 -1
- package/src/modules/customers/lib/calendar/conflicts.ts +10 -2
- package/src/modules/customers/lib/calendar/editorPayload.ts +4 -3
- package/src/modules/customers/lib/calendar/mapItem.ts +8 -3
- package/src/modules/customers/lib/calendar/participantIdentity.ts +17 -0
- package/src/modules/customers/lib/closureStage.ts +76 -0
- package/src/modules/customers/lib/dealStatus.ts +42 -0
- package/src/modules/customers/lib/detailReadAccess.ts +35 -0
- package/src/modules/customers/lib/findPeopleByAddresses.ts +8 -6
- package/src/modules/customers/lib/personCompanies.ts +136 -1
- package/src/modules/customers/lib/todoCompatibility.ts +19 -1
- package/src/modules/dashboards/i18n/es.json +4 -4
- package/src/modules/dashboards/i18n/pl.json +7 -7
- package/src/modules/dashboards/lib/widgetScope.ts +6 -0
- package/src/modules/data_sync/AGENTS.md +1 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +4 -1
- package/src/modules/data_sync/lib/abandoned-run.ts +56 -0
- package/src/modules/data_sync/lib/adapter.ts +36 -0
- package/src/modules/data_sync/lib/sync-engine.ts +113 -5
- package/src/modules/data_sync/workers/sync-export.ts +4 -0
- package/src/modules/data_sync/workers/sync-import.ts +4 -0
- package/src/modules/devices/AGENTS.md +20 -1
- package/src/modules/devices/acl.ts +9 -1
- package/src/modules/devices/api/admin/devices/[id]/route.ts +5 -34
- package/src/modules/devices/api/admin/devices/route.ts +14 -1
- package/src/modules/devices/api/deviceList.ts +135 -11
- package/src/modules/devices/api/deviceSerialization.ts +50 -0
- package/src/modules/devices/api/openapi.ts +9 -1
- package/src/modules/devices/api/route.ts +9 -1
- package/src/modules/devices/backend/devices/[id]/page.tsx +18 -32
- package/src/modules/devices/backend/devices/create/page.tsx +17 -1
- package/src/modules/devices/backend/devices/page.tsx +44 -45
- package/src/modules/devices/backend/devices/useDeviceUserLabels.ts +45 -0
- package/src/modules/devices/backend/devices/userOptions.ts +99 -0
- package/src/modules/devices/i18n/de.json +3 -2
- package/src/modules/devices/i18n/en.json +3 -2
- package/src/modules/devices/i18n/es.json +3 -2
- package/src/modules/devices/i18n/ko.json +3 -2
- package/src/modules/devices/i18n/pl.json +3 -2
- package/src/modules/devices/setup.ts +6 -2
- package/src/modules/directory/backend/directory/organizations/page.tsx +3 -1
- package/src/modules/directory/backend/directory/tenants/page.tsx +3 -1
- package/src/modules/directory/di.ts +14 -2
- package/src/modules/directory/services/organizationHierarchyService.ts +34 -0
- package/src/modules/directory/services/organizationScopeService.ts +85 -0
- package/src/modules/directory/utils/organizationScope.ts +4 -15
- package/src/modules/entities/api/records.ts +2 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +4 -1
- package/src/modules/eudr/api/plots/route.ts +4 -0
- package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/plots/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/statements/page.tsx +4 -0
- package/src/modules/eudr/commands/statements.ts +0 -3
- package/src/modules/eudr/data/validators.ts +16 -1
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +2 -1
- package/src/modules/feature_toggles/components/OverridesTable.tsx +2 -1
- package/src/modules/feature_toggles/defaults.json +0 -8
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +4 -0
- package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +4 -0
- package/src/modules/inbox_ops/lib/htmlToPlainText.ts +1 -17
- package/src/modules/integrations/api/[id]/credentials/route.ts +6 -4
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +61 -31
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +44 -9
- package/src/modules/integrations/backend/integrations/credential-secret-fields.ts +84 -0
- package/src/modules/integrations/data/validators.ts +12 -2
- package/src/modules/integrations/i18n/de.json +1 -0
- package/src/modules/integrations/i18n/en.json +1 -0
- package/src/modules/integrations/i18n/es.json +1 -0
- package/src/modules/integrations/i18n/ko.json +1 -0
- package/src/modules/integrations/i18n/pl.json +1 -0
- package/src/modules/integrations/lib/credentials-masking.ts +10 -6
- package/src/modules/messages/api/[id]/route.ts +55 -1
- package/src/modules/messages/api/openapi.ts +20 -0
- package/src/modules/messages/api/route.ts +31 -2
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +9 -16
- package/src/modules/messages/components/inboxFilters.ts +36 -0
- package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +14 -1
- package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +3 -1
- package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +2 -1
- package/src/modules/messages/components/message-detail/types.ts +3 -0
- package/src/modules/messages/components/messageListLabels.ts +52 -3
- package/src/modules/messages/data/validators.ts +43 -4
- package/src/modules/messages/lib/channel-sender-identity.ts +55 -0
- package/src/modules/messages/lib/composeSourceChannelType.ts +95 -0
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +4 -6
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +4 -1
- package/src/modules/payment_gateways/lib/webhook-processor.ts +11 -0
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -0
- package/src/modules/push_notifications/backend/push_notifications/page.tsx +4 -1
- package/src/modules/push_notifications/backend/push_notifications/send/page.tsx +4 -4
- package/src/modules/query_index/lib/engine.ts +249 -61
- package/src/modules/query_index/lib/search-entity-policy.ts +46 -0
- package/src/modules/query_index/lib/search-tokens.ts +135 -3
- package/src/modules/resources/backend/resources/resource-types/page.tsx +4 -1
- package/src/modules/resources/backend/resources/resources/page.tsx +4 -1
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +4 -0
- package/src/modules/sales/backend/sales/channels/page.tsx +4 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +14 -8
- package/src/modules/sales/commands/documents.ts +93 -0
- package/src/modules/sales/components/PriceWithCurrency.tsx +17 -5
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +4 -0
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +6 -5
- package/src/modules/sales/components/documents/ItemsSection.tsx +56 -18
- package/src/modules/sales/components/documents/LineItemDialog.tsx +137 -20
- package/src/modules/sales/components/documents/PaymentsSection.tsx +20 -9
- package/src/modules/sales/components/documents/ReturnsSection.tsx +6 -5
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +106 -14
- package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +6 -5
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +5 -4
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +6 -5
- package/src/modules/sales/components/documents/lineItemShipmentLock.ts +74 -0
- package/src/modules/sales/components/documents/lineItemUtils.ts +7 -2
- package/src/modules/sales/data/entities.ts +6 -0
- package/src/modules/sales/extension-points.ts +1 -0
- package/src/modules/sales/i18n/de.json +8 -0
- package/src/modules/sales/i18n/en.json +8 -0
- package/src/modules/sales/i18n/es.json +8 -0
- package/src/modules/sales/i18n/ko.json +8 -0
- package/src/modules/sales/i18n/pl.json +8 -0
- package/src/modules/sales/lib/salesChannelsToggleSeed.ts +42 -0
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +60 -0
- package/src/modules/sales/migrations/Migration20260821120000_sales_notes_addresses_context_idx.ts +87 -0
- package/src/modules/sales/setup.ts +2 -0
- package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +9 -1
- package/src/modules/sales/widgets/injection-table.ts +4 -7
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/team-members/page.tsx +6 -0
- package/src/modules/staff/backend/staff/team-roles/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/page.tsx +4 -0
- package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +4 -0
- package/src/modules/sync_excel/lib/adapters/customers.ts +5 -0
- package/src/modules/warranty_claims/api/assignees/route.ts +3 -3
- package/src/modules/warranty_claims/api/portal/attachments/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/claims/route.ts +12 -9
- package/src/modules/warranty_claims/backend/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +4 -0
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +4 -0
- package/src/modules/wms/api/warehouseSearch.ts +23 -0
- package/src/modules/wms/api/warehouses/route.ts +13 -9
- package/src/modules/wms/api/zones/route.ts +16 -0
- package/src/modules/wms/commands/configuration.ts +159 -10
- package/src/modules/wms/commands/inventory-actions.ts +3 -0
- package/src/modules/wms/commands/shared.ts +17 -0
- package/src/modules/wms/components/backend/WarehouseEditDialog.tsx +216 -0
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +95 -141
- package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +2 -0
- package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -0
- package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +36 -20
- package/src/modules/wms/components/backend/warehouseFormOptions.ts +72 -0
- package/src/modules/wms/i18n/de.json +2 -0
- package/src/modules/wms/i18n/en.json +2 -0
- package/src/modules/wms/i18n/es.json +2 -0
- package/src/modules/wms/i18n/ko.json +2 -0
- package/src/modules/wms/i18n/pl.json +2 -0
- package/src/modules/workflows/backend/definitions/page.tsx +4 -1
- package/src/modules/workflows/backend/events/page.tsx +4 -1
- package/src/modules/workflows/backend/instances/page.tsx +4 -1
- package/src/modules/workflows/backend/tasks/page.tsx +4 -1
- package/src/modules/workflows/lib/activity-executor.ts +9 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/lib/calendar/mapItem.ts"],
|
|
4
|
-
"sourcesContent": ["import { addMinutes } from 'date-fns/addMinutes'\nimport { endOfDay } from 'date-fns/endOfDay'\nimport { startOfDay } from 'date-fns/startOfDay'\nimport type {\n CalendarInteractionPayload,\n CalendarItem,\n CalendarItemStatus,\n CalendarLocationKind,\n CalendarParticipant,\n CalendarPlatform,\n} from '../../components/calendar/types'\nimport { categoryOf } from './categories'\n\nconst DEFAULT_DURATION_MINUTES = 30\n\nfunction narrowStatus(status: string): CalendarItemStatus {\n if (status === 'done') return 'done'\n if (status === 'canceled') return 'canceled'\n return 'planned'\n}\n\nexport function detectPlatform(location: string | null): CalendarPlatform | null {\n if (!location) return null\n const normalized = location.toLowerCase()\n if (normalized.includes('zoom.us') || normalized.includes('zoom')) return 'zoom'\n if (normalized.includes('meet.google') || normalized.includes('on meet')) return 'meet'\n if (normalized.includes('slack')) return 'slack'\n if (normalized.includes('teams')) return 'teams'\n return null\n}\n\nfunction detectLocationKind(location: string | null, platform: CalendarPlatform | null): CalendarLocationKind | null {\n if (!location) return null\n const normalized = location.trim().toLowerCase()\n if (normalized.startsWith('http') || normalized.startsWith('www')) return 'url'\n if (platform) return 'platform'\n return 'venue'\n}\n\nfunction mapParticipants(payload: CalendarInteractionPayload): CalendarParticipant[] {\n const participants = payload.participants\n if (!Array.isArray(participants)) return []\n const seen = new Set<string>()\n const mapped: CalendarParticipant[] = []\n for (const participant of participants) {\n if (seen.has(
|
|
5
|
-
"mappings": "AAAA,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAS3B,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["import { addMinutes } from 'date-fns/addMinutes'\nimport { endOfDay } from 'date-fns/endOfDay'\nimport { startOfDay } from 'date-fns/startOfDay'\nimport type {\n CalendarInteractionPayload,\n CalendarItem,\n CalendarItemStatus,\n CalendarLocationKind,\n CalendarParticipant,\n CalendarPlatform,\n} from '../../components/calendar/types'\nimport { categoryOf } from './categories'\nimport { participantActorKey } from './participantIdentity'\n\nconst DEFAULT_DURATION_MINUTES = 30\n\nfunction narrowStatus(status: string): CalendarItemStatus {\n if (status === 'done') return 'done'\n if (status === 'canceled') return 'canceled'\n return 'planned'\n}\n\nexport function detectPlatform(location: string | null): CalendarPlatform | null {\n if (!location) return null\n const normalized = location.toLowerCase()\n if (normalized.includes('zoom.us') || normalized.includes('zoom')) return 'zoom'\n if (normalized.includes('meet.google') || normalized.includes('on meet')) return 'meet'\n if (normalized.includes('slack')) return 'slack'\n if (normalized.includes('teams')) return 'teams'\n return null\n}\n\nfunction detectLocationKind(location: string | null, platform: CalendarPlatform | null): CalendarLocationKind | null {\n if (!location) return null\n const normalized = location.trim().toLowerCase()\n if (normalized.startsWith('http') || normalized.startsWith('www')) return 'url'\n if (platform) return 'platform'\n return 'venue'\n}\n\nfunction mapParticipants(payload: CalendarInteractionPayload): CalendarParticipant[] {\n const participants = payload.participants\n if (!Array.isArray(participants)) return []\n const seen = new Set<string>()\n const mapped: CalendarParticipant[] = []\n for (const participant of participants) {\n const dedupeKey = participantActorKey(participant)\n if (dedupeKey) {\n if (seen.has(dedupeKey)) continue\n seen.add(dedupeKey)\n }\n const entry: CalendarParticipant = {}\n if (typeof participant.userId === 'string') entry.userId = participant.userId\n if (typeof participant.name === 'string') entry.name = participant.name\n if (typeof participant.email === 'string') entry.email = participant.email\n mapped.push(entry)\n }\n return mapped\n}\n\nexport function mapInteractionToCalendarItem(\n payload: CalendarInteractionPayload,\n typeColorByType: Record<string, string | null>,\n): CalendarItem | null {\n const effectiveStartRaw = payload.occurredAt ?? payload.scheduledAt ?? null\n if (!effectiveStartRaw) return null\n const parsedStart = new Date(effectiveStartRaw)\n if (Number.isNaN(parsedStart.getTime())) return null\n\n const allDay = payload.allDay === true\n const durationMinutes = payload.durationMinutes ?? DEFAULT_DURATION_MINUTES\n const start = allDay ? startOfDay(parsedStart) : parsedStart\n const end = allDay ? endOfDay(parsedStart) : addMinutes(parsedStart, durationMinutes)\n\n const location = payload.location ?? null\n const platform = detectPlatform(location)\n\n return {\n id: payload.id,\n title: payload.title ?? '',\n interactionType: payload.interactionType,\n category: categoryOf(payload.interactionType),\n status: narrowStatus(payload.status),\n start,\n end,\n allDay,\n location,\n platform,\n locationKind: detectLocationKind(location, platform),\n participants: mapParticipants(payload),\n ownerUserId: payload.ownerUserId ?? null,\n entityId: payload.entityId ?? null,\n dealId: payload.dealId ?? null,\n color: payload.appearanceColor ?? typeColorByType[payload.interactionType] ?? null,\n isRecurringOccurrence: false,\n updatedAt: payload.updatedAt ?? null,\n raw: payload,\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAS3B,SAAS,kBAAkB;AAC3B,SAAS,2BAA2B;AAEpC,MAAM,2BAA2B;AAEjC,SAAS,aAAa,QAAoC;AACxD,MAAI,WAAW,OAAQ,QAAO;AAC9B,MAAI,WAAW,WAAY,QAAO;AAClC,SAAO;AACT;AAEO,SAAS,eAAe,UAAkD;AAC/E,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,aAAa,SAAS,YAAY;AACxC,MAAI,WAAW,SAAS,SAAS,KAAK,WAAW,SAAS,MAAM,EAAG,QAAO;AAC1E,MAAI,WAAW,SAAS,aAAa,KAAK,WAAW,SAAS,SAAS,EAAG,QAAO;AACjF,MAAI,WAAW,SAAS,OAAO,EAAG,QAAO;AACzC,MAAI,WAAW,SAAS,OAAO,EAAG,QAAO;AACzC,SAAO;AACT;AAEA,SAAS,mBAAmB,UAAyB,UAAgE;AACnH,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,aAAa,SAAS,KAAK,EAAE,YAAY;AAC/C,MAAI,WAAW,WAAW,MAAM,KAAK,WAAW,WAAW,KAAK,EAAG,QAAO;AAC1E,MAAI,SAAU,QAAO;AACrB,SAAO;AACT;AAEA,SAAS,gBAAgB,SAA4D;AACnF,QAAM,eAAe,QAAQ;AAC7B,MAAI,CAAC,MAAM,QAAQ,YAAY,EAAG,QAAO,CAAC;AAC1C,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAAgC,CAAC;AACvC,aAAW,eAAe,cAAc;AACtC,UAAM,YAAY,oBAAoB,WAAW;AACjD,QAAI,WAAW;AACb,UAAI,KAAK,IAAI,SAAS,EAAG;AACzB,WAAK,IAAI,SAAS;AAAA,IACpB;AACA,UAAM,QAA6B,CAAC;AACpC,QAAI,OAAO,YAAY,WAAW,SAAU,OAAM,SAAS,YAAY;AACvE,QAAI,OAAO,YAAY,SAAS,SAAU,OAAM,OAAO,YAAY;AACnE,QAAI,OAAO,YAAY,UAAU,SAAU,OAAM,QAAQ,YAAY;AACrE,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,SAAO;AACT;AAEO,SAAS,6BACd,SACA,iBACqB;AACrB,QAAM,oBAAoB,QAAQ,cAAc,QAAQ,eAAe;AACvE,MAAI,CAAC,kBAAmB,QAAO;AAC/B,QAAM,cAAc,IAAI,KAAK,iBAAiB;AAC9C,MAAI,OAAO,MAAM,YAAY,QAAQ,CAAC,EAAG,QAAO;AAEhD,QAAM,SAAS,QAAQ,WAAW;AAClC,QAAM,kBAAkB,QAAQ,mBAAmB;AACnD,QAAM,QAAQ,SAAS,WAAW,WAAW,IAAI;AACjD,QAAM,MAAM,SAAS,SAAS,WAAW,IAAI,WAAW,aAAa,eAAe;AAEpF,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,WAAW,eAAe,QAAQ;AAExC,SAAO;AAAA,IACL,IAAI,QAAQ;AAAA,IACZ,OAAO,QAAQ,SAAS;AAAA,IACxB,iBAAiB,QAAQ;AAAA,IACzB,UAAU,WAAW,QAAQ,eAAe;AAAA,IAC5C,QAAQ,aAAa,QAAQ,MAAM;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,mBAAmB,UAAU,QAAQ;AAAA,IACnD,cAAc,gBAAgB,OAAO;AAAA,IACrC,aAAa,QAAQ,eAAe;AAAA,IACpC,UAAU,QAAQ,YAAY;AAAA,IAC9B,QAAQ,QAAQ,UAAU;AAAA,IAC1B,OAAO,QAAQ,mBAAmB,gBAAgB,QAAQ,eAAe,KAAK;AAAA,IAC9E,uBAAuB;AAAA,IACvB,WAAW,QAAQ,aAAa;AAAA,IAChC,KAAK;AAAA,EACP;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
function participantActorKey(participant) {
|
|
2
|
+
if (participant.userId) return `user:${participant.userId}`;
|
|
3
|
+
const email = participant.email?.trim().toLowerCase();
|
|
4
|
+
return email ? `email:${email}` : null;
|
|
5
|
+
}
|
|
6
|
+
export {
|
|
7
|
+
participantActorKey
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=participantIdentity.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/customers/lib/calendar/participantIdentity.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The one canonical actor key for a calendar participant.\n *\n * A staff/customer attendee is identified by `userId`. An external guest has no\n * record in the system, so the normalized email is the only stable identity it\n * carries. Mapping, dedupe, conflict detection and the editor's conflict-probe\n * dependency key all derive their key from here, so a guest is treated as the\n * same actor across events instead of dropping out of actor comparisons.\n *\n * Returns `null` for a participant with neither \u2014 such a participant cannot be\n * compared to any other and must never collide with one that can.\n */\nexport function participantActorKey(participant: { userId?: string; email?: string }): string | null {\n if (participant.userId) return `user:${participant.userId}`\n const email = participant.email?.trim().toLowerCase()\n return email ? `email:${email}` : null\n}\n"],
|
|
5
|
+
"mappings": "AAYO,SAAS,oBAAoB,aAAiE;AACnG,MAAI,YAAY,OAAQ,QAAO,QAAQ,YAAY,MAAM;AACzD,QAAM,QAAQ,YAAY,OAAO,KAAK,EAAE,YAAY;AACpD,SAAO,QAAQ,SAAS,KAAK,KAAK;AACpC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
2
|
+
import { CustomerPipelineStage } from "../data/entities.js";
|
|
3
|
+
const TERMINAL_PIPELINE_STAGE_LABELS = {
|
|
4
|
+
won: /* @__PURE__ */ new Set(["won", "win", "closed won", "closed win"]),
|
|
5
|
+
lost: /* @__PURE__ */ new Set(["lost", "loose", "closed lost", "closed loose"])
|
|
6
|
+
};
|
|
7
|
+
function dealClosureOutcomeFromStatus(status) {
|
|
8
|
+
const normalized = typeof status === "string" ? status.trim().toLowerCase() : status;
|
|
9
|
+
if (normalized === "win" || normalized === "won") return "won";
|
|
10
|
+
if (normalized === "loose" || normalized === "lost") return "lost";
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
function normalizePipelineStageLabel(value) {
|
|
14
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
15
|
+
}
|
|
16
|
+
async function loadClosurePipelineStageSnapshot(em, input) {
|
|
17
|
+
if (!input.pipelineId) return null;
|
|
18
|
+
const stages = await findWithDecryption(
|
|
19
|
+
em,
|
|
20
|
+
CustomerPipelineStage,
|
|
21
|
+
{
|
|
22
|
+
pipelineId: input.pipelineId,
|
|
23
|
+
tenantId: input.tenantId,
|
|
24
|
+
organizationId: input.organizationId
|
|
25
|
+
},
|
|
26
|
+
{ orderBy: { order: "ASC" } },
|
|
27
|
+
{ tenantId: input.tenantId, organizationId: input.organizationId }
|
|
28
|
+
);
|
|
29
|
+
const aliases = TERMINAL_PIPELINE_STAGE_LABELS[input.closureOutcome];
|
|
30
|
+
const stage = stages.find((candidate) => aliases.has(normalizePipelineStageLabel(candidate.label)));
|
|
31
|
+
if (!stage) return null;
|
|
32
|
+
return {
|
|
33
|
+
id: stage.id,
|
|
34
|
+
pipelineId: stage.pipelineId,
|
|
35
|
+
label: stage.label,
|
|
36
|
+
order: stage.order
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
TERMINAL_PIPELINE_STAGE_LABELS,
|
|
41
|
+
dealClosureOutcomeFromStatus,
|
|
42
|
+
loadClosurePipelineStageSnapshot,
|
|
43
|
+
normalizePipelineStageLabel
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=closureStage.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/customers/lib/closureStage.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerPipelineStage } from '../data/entities'\n\nexport type DealClosureOutcome = 'won' | 'lost'\n\nexport type PipelineStageSnapshot = {\n id: string\n pipelineId: string\n label: string\n order: number\n}\n\n// Stage labels that mark a pipeline as terminal for a given closure outcome. Matching is\n// label-based because stages are tenant-configurable rows; see #5107.\nexport const TERMINAL_PIPELINE_STAGE_LABELS: Record<DealClosureOutcome, ReadonlySet<string>> = {\n won: new Set(['won', 'win', 'closed won', 'closed win']),\n lost: new Set(['lost', 'loose', 'closed lost', 'closed loose']),\n}\n\n/**\n * Map a deal status spelling (UI `win`/`loose` or AI `won`/`lost`) to its closure\n * outcome. Case-insensitive because callers such as the AI tool pass free-form model\n * text through, while every persisted status is lower-case.\n */\nexport function dealClosureOutcomeFromStatus(status: string | null | undefined): DealClosureOutcome | null {\n const normalized = typeof status === 'string' ? status.trim().toLowerCase() : status\n if (normalized === 'win' || normalized === 'won') return 'won'\n if (normalized === 'loose' || normalized === 'lost') return 'lost'\n return null\n}\n\nexport function normalizePipelineStageLabel(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, ' ')\n .trim()\n}\n\n/**\n * Resolve the terminal stage of the deal's pipeline for a closure outcome, so every\n * writer (command, AI tool preview) agrees on where a closed deal lands (#5107).\n */\nexport async function loadClosurePipelineStageSnapshot(\n em: EntityManager,\n input: {\n pipelineId: string | null\n closureOutcome: DealClosureOutcome\n tenantId: string\n organizationId: string\n },\n): Promise<PipelineStageSnapshot | null> {\n if (!input.pipelineId) return null\n\n const stages = await findWithDecryption(\n em,\n CustomerPipelineStage,\n {\n pipelineId: input.pipelineId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n { orderBy: { order: 'ASC' } },\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n const aliases = TERMINAL_PIPELINE_STAGE_LABELS[input.closureOutcome]\n const stage = stages.find((candidate) => aliases.has(normalizePipelineStageLabel(candidate.label)))\n if (!stage) return null\n return {\n id: stage.id,\n pipelineId: stage.pipelineId,\n label: stage.label,\n order: stage.order,\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AAa/B,MAAM,iCAAkF;AAAA,EAC7F,KAAK,oBAAI,IAAI,CAAC,OAAO,OAAO,cAAc,YAAY,CAAC;AAAA,EACvD,MAAM,oBAAI,IAAI,CAAC,QAAQ,SAAS,eAAe,cAAc,CAAC;AAChE;AAOO,SAAS,6BAA6B,QAA8D;AACzG,QAAM,aAAa,OAAO,WAAW,WAAW,OAAO,KAAK,EAAE,YAAY,IAAI;AAC9E,MAAI,eAAe,SAAS,eAAe,MAAO,QAAO;AACzD,MAAI,eAAe,WAAW,eAAe,OAAQ,QAAO;AAC5D,SAAO;AACT;AAEO,SAAS,4BAA4B,OAAuB;AACjE,SAAO,MACJ,KAAK,EACL,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,KAAK;AACV;AAMA,eAAsB,iCACpB,IACA,OAMuC;AACvC,MAAI,CAAC,MAAM,WAAY,QAAO;AAE9B,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,MACE,YAAY,MAAM;AAAA,MAClB,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,IACxB;AAAA,IACA,EAAE,SAAS,EAAE,OAAO,MAAM,EAAE;AAAA,IAC5B,EAAE,UAAU,MAAM,UAAU,gBAAgB,MAAM,eAAe;AAAA,EACnE;AACA,QAAM,UAAU,+BAA+B,MAAM,cAAc;AACnE,QAAM,QAAQ,OAAO,KAAK,CAAC,cAAc,QAAQ,IAAI,4BAA4B,UAAU,KAAK,CAAC,CAAC;AAClG,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,IAAI,MAAM;AAAA,IACV,YAAY,MAAM;AAAA,IAClB,OAAO,MAAM;AAAA,IACb,OAAO,MAAM;AAAA,EACf;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -23,6 +23,34 @@ function isClosedDealStatus(value) {
|
|
|
23
23
|
function isOpenDealStatus(value) {
|
|
24
24
|
return !isClosedDealStatus(value);
|
|
25
25
|
}
|
|
26
|
+
function canonicalDealStatus(value) {
|
|
27
|
+
const lower = value.toLowerCase();
|
|
28
|
+
if (lower === "won") return DEAL_STATUS_WIN;
|
|
29
|
+
if (lower === "lost") return DEAL_STATUS_LOSE;
|
|
30
|
+
if (lower === "win" || lower === "loose" || lower === "open" || lower === "closed") return lower;
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
function expandDealStatusAliases(values) {
|
|
34
|
+
const out = /* @__PURE__ */ new Set();
|
|
35
|
+
for (const value of values) {
|
|
36
|
+
const trimmed = value.trim();
|
|
37
|
+
const lower = trimmed.toLowerCase();
|
|
38
|
+
if (lower === "win" || lower === "won") {
|
|
39
|
+
WON_DEAL_STATUS_LIST.forEach((entry) => out.add(entry));
|
|
40
|
+
out.add(trimmed);
|
|
41
|
+
} else if (lower === "loose" || lower === "lost") {
|
|
42
|
+
LOST_DEAL_STATUS_LIST.forEach((entry) => out.add(entry));
|
|
43
|
+
out.add(trimmed);
|
|
44
|
+
} else if (lower === "closed") {
|
|
45
|
+
CLOSED_DEAL_STATUS_LIST.forEach((entry) => out.add(entry));
|
|
46
|
+
out.add(trimmed);
|
|
47
|
+
} else {
|
|
48
|
+
out.add(trimmed);
|
|
49
|
+
out.add(lower);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return Array.from(out);
|
|
53
|
+
}
|
|
26
54
|
export {
|
|
27
55
|
CLOSED_DEAL_STATUS_LIST,
|
|
28
56
|
DEAL_STATUS_CLOSED,
|
|
@@ -30,6 +58,8 @@ export {
|
|
|
30
58
|
DEAL_STATUS_WIN,
|
|
31
59
|
LOST_DEAL_STATUS_LIST,
|
|
32
60
|
WON_DEAL_STATUS_LIST,
|
|
61
|
+
canonicalDealStatus,
|
|
62
|
+
expandDealStatusAliases,
|
|
33
63
|
isClosedDealStatus,
|
|
34
64
|
isLostDealStatus,
|
|
35
65
|
isOpenDealStatus,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/lib/dealStatus.ts"],
|
|
4
|
-
"sourcesContent": ["// Single source of truth for deal open/closed (terminal) semantics.\n//\n// `customer_deals.status` is a lenient text column and the supported writers do not agree on\n// one spelling: the closure hooks and the kanban board persist `win` / `loose`, the AI tool\n// `customers.update_deal_stage` persists `won` / `lost`, and the seeded vocabulary also carries\n// `closed`. The terminal set below therefore covers every spelling a status writer persists, so\n// status-based readers can share one classification. `closureOutcome` is a separate signal and\n// callers that combine both columns must handle it explicitly.\n//\n// A status not known to code counts as OPEN. Deal stages are configurable per tenant, so the\n// lenient column can hold values this module has never seen \u2014 treating them as open keeps them\n// visible in active-deal counts instead of silently reclassifying them as closed.\n\nexport const DEAL_STATUS_WIN = 'win' as const\nexport const DEAL_STATUS_LOSE = 'loose' as const\nexport const DEAL_STATUS_CLOSED = 'closed' as const\n\n// `won` / `lost` are the spellings the AI stage tool writes; `win` / `loose` are what the UI\n// closure flows persist. Both are accepted so neither writer produces an unreadable status.\nexport const WON_DEAL_STATUS_LIST: readonly string[] = [DEAL_STATUS_WIN, 'won']\n\nexport const LOST_DEAL_STATUS_LIST: readonly string[] = [DEAL_STATUS_LOSE, 'lost']\n\nexport const CLOSED_DEAL_STATUS_LIST: readonly string[] = [\n ...WON_DEAL_STATUS_LIST,\n ...LOST_DEAL_STATUS_LIST,\n DEAL_STATUS_CLOSED,\n]\n\nconst WON_DEAL_STATUSES = new Set<string>(WON_DEAL_STATUS_LIST)\nconst LOST_DEAL_STATUSES = new Set<string>(LOST_DEAL_STATUS_LIST)\nconst CLOSED_DEAL_STATUSES = new Set<string>(CLOSED_DEAL_STATUS_LIST)\n\nexport function isWonDealStatus(value: string | null | undefined): boolean {\n return value != null && WON_DEAL_STATUSES.has(value)\n}\n\nexport function isLostDealStatus(value: string | null | undefined): boolean {\n return value != null && LOST_DEAL_STATUSES.has(value)\n}\n\nexport function isClosedDealStatus(value: string | null | undefined): boolean {\n return value != null && CLOSED_DEAL_STATUSES.has(value)\n}\n\nexport function isOpenDealStatus(value: string | null | undefined): boolean {\n return !isClosedDealStatus(value)\n}\n"],
|
|
5
|
-
"mappings": "AAaO,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;AAI3B,MAAM,uBAA0C,CAAC,iBAAiB,KAAK;AAEvE,MAAM,wBAA2C,CAAC,kBAAkB,MAAM;AAE1E,MAAM,0BAA6C;AAAA,EACxD,GAAG;AAAA,EACH,GAAG;AAAA,EACH;AACF;AAEA,MAAM,oBAAoB,IAAI,IAAY,oBAAoB;AAC9D,MAAM,qBAAqB,IAAI,IAAY,qBAAqB;AAChE,MAAM,uBAAuB,IAAI,IAAY,uBAAuB;AAE7D,SAAS,gBAAgB,OAA2C;AACzE,SAAO,SAAS,QAAQ,kBAAkB,IAAI,KAAK;AACrD;AAEO,SAAS,iBAAiB,OAA2C;AAC1E,SAAO,SAAS,QAAQ,mBAAmB,IAAI,KAAK;AACtD;AAEO,SAAS,mBAAmB,OAA2C;AAC5E,SAAO,SAAS,QAAQ,qBAAqB,IAAI,KAAK;AACxD;AAEO,SAAS,iBAAiB,OAA2C;AAC1E,SAAO,CAAC,mBAAmB,KAAK;AAClC;",
|
|
4
|
+
"sourcesContent": ["// Single source of truth for deal open/closed (terminal) semantics.\n//\n// `customer_deals.status` is a lenient text column and the supported writers do not agree on\n// one spelling: the closure hooks and the kanban board persist `win` / `loose`, the AI tool\n// `customers.update_deal_stage` persists `won` / `lost`, and the seeded vocabulary also carries\n// `closed`. The terminal set below therefore covers every spelling a status writer persists, so\n// status-based readers can share one classification. `closureOutcome` is a separate signal and\n// callers that combine both columns must handle it explicitly.\n//\n// A status not known to code counts as OPEN. Deal stages are configurable per tenant, so the\n// lenient column can hold values this module has never seen \u2014 treating them as open keeps them\n// visible in active-deal counts instead of silently reclassifying them as closed.\n\nexport const DEAL_STATUS_WIN = 'win' as const\nexport const DEAL_STATUS_LOSE = 'loose' as const\nexport const DEAL_STATUS_CLOSED = 'closed' as const\n\n// `won` / `lost` are the spellings the AI stage tool writes; `win` / `loose` are what the UI\n// closure flows persist. Both are accepted so neither writer produces an unreadable status.\nexport const WON_DEAL_STATUS_LIST: readonly string[] = [DEAL_STATUS_WIN, 'won']\n\nexport const LOST_DEAL_STATUS_LIST: readonly string[] = [DEAL_STATUS_LOSE, 'lost']\n\nexport const CLOSED_DEAL_STATUS_LIST: readonly string[] = [\n ...WON_DEAL_STATUS_LIST,\n ...LOST_DEAL_STATUS_LIST,\n DEAL_STATUS_CLOSED,\n]\n\nconst WON_DEAL_STATUSES = new Set<string>(WON_DEAL_STATUS_LIST)\nconst LOST_DEAL_STATUSES = new Set<string>(LOST_DEAL_STATUS_LIST)\nconst CLOSED_DEAL_STATUSES = new Set<string>(CLOSED_DEAL_STATUS_LIST)\n\nexport function isWonDealStatus(value: string | null | undefined): boolean {\n return value != null && WON_DEAL_STATUSES.has(value)\n}\n\nexport function isLostDealStatus(value: string | null | undefined): boolean {\n return value != null && LOST_DEAL_STATUSES.has(value)\n}\n\nexport function isClosedDealStatus(value: string | null | undefined): boolean {\n return value != null && CLOSED_DEAL_STATUSES.has(value)\n}\n\nexport function isOpenDealStatus(value: string | null | undefined): boolean {\n return !isClosedDealStatus(value)\n}\n\nexport function canonicalDealStatus(value: string): string {\n const lower = value.toLowerCase()\n if (lower === 'won') return DEAL_STATUS_WIN\n if (lower === 'lost') return DEAL_STATUS_LOSE\n // Canonical spellings normalize to lower-case too, so an upper-case selection still\n // matches the lower-case persisted values and dictionary options.\n if (lower === 'win' || lower === 'loose' || lower === 'open' || lower === 'closed') return lower\n return value\n}\n\n/**\n * Expand operator-selected status filter values into the canonical vocabulary so a\n * single selection matches every spelling the supported writers persist (#5107).\n *\n * Alias groups (`win`/`won`, `loose`/`lost`, `closed`) are matched case-insensitively,\n * expanded to their canonical spellings, and also keep the caller's original token so\n * the result is always a strict superset of a verbatim match. Unknown values emit both\n * the trimmed original and its lower-case form \u2014 mixed-case tenant dictionary statuses\n * match exactly while `?status=Open` still hits lower-case stored rows.\n */\nexport function expandDealStatusAliases(values: string[]): string[] {\n const out = new Set<string>()\n for (const value of values) {\n const trimmed = value.trim()\n const lower = trimmed.toLowerCase()\n if (lower === 'win' || lower === 'won') {\n WON_DEAL_STATUS_LIST.forEach((entry) => out.add(entry))\n out.add(trimmed)\n } else if (lower === 'loose' || lower === 'lost') {\n LOST_DEAL_STATUS_LIST.forEach((entry) => out.add(entry))\n out.add(trimmed)\n } else if (lower === 'closed') {\n CLOSED_DEAL_STATUS_LIST.forEach((entry) => out.add(entry))\n out.add(trimmed)\n } else {\n out.add(trimmed)\n out.add(lower)\n }\n }\n return Array.from(out)\n}\n"],
|
|
5
|
+
"mappings": "AAaO,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;AAI3B,MAAM,uBAA0C,CAAC,iBAAiB,KAAK;AAEvE,MAAM,wBAA2C,CAAC,kBAAkB,MAAM;AAE1E,MAAM,0BAA6C;AAAA,EACxD,GAAG;AAAA,EACH,GAAG;AAAA,EACH;AACF;AAEA,MAAM,oBAAoB,IAAI,IAAY,oBAAoB;AAC9D,MAAM,qBAAqB,IAAI,IAAY,qBAAqB;AAChE,MAAM,uBAAuB,IAAI,IAAY,uBAAuB;AAE7D,SAAS,gBAAgB,OAA2C;AACzE,SAAO,SAAS,QAAQ,kBAAkB,IAAI,KAAK;AACrD;AAEO,SAAS,iBAAiB,OAA2C;AAC1E,SAAO,SAAS,QAAQ,mBAAmB,IAAI,KAAK;AACtD;AAEO,SAAS,mBAAmB,OAA2C;AAC5E,SAAO,SAAS,QAAQ,qBAAqB,IAAI,KAAK;AACxD;AAEO,SAAS,iBAAiB,OAA2C;AAC1E,SAAO,CAAC,mBAAmB,KAAK;AAClC;AAEO,SAAS,oBAAoB,OAAuB;AACzD,QAAM,QAAQ,MAAM,YAAY;AAChC,MAAI,UAAU,MAAO,QAAO;AAC5B,MAAI,UAAU,OAAQ,QAAO;AAG7B,MAAI,UAAU,SAAS,UAAU,WAAW,UAAU,UAAU,UAAU,SAAU,QAAO;AAC3F,SAAO;AACT;AAYO,SAAS,wBAAwB,QAA4B;AAClE,QAAM,MAAM,oBAAI,IAAY;AAC5B,aAAW,SAAS,QAAQ;AAC1B,UAAM,UAAU,MAAM,KAAK;AAC3B,UAAM,QAAQ,QAAQ,YAAY;AAClC,QAAI,UAAU,SAAS,UAAU,OAAO;AACtC,2BAAqB,QAAQ,CAAC,UAAU,IAAI,IAAI,KAAK,CAAC;AACtD,UAAI,IAAI,OAAO;AAAA,IACjB,WAAW,UAAU,WAAW,UAAU,QAAQ;AAChD,4BAAsB,QAAQ,CAAC,UAAU,IAAI,IAAI,KAAK,CAAC;AACvD,UAAI,IAAI,OAAO;AAAA,IACjB,WAAW,UAAU,UAAU;AAC7B,8BAAwB,QAAQ,CAAC,UAAU,IAAI,IAAI,KAAK,CAAC;AACzD,UAAI,IAAI,OAAO;AAAA,IACjB,OAAO;AACL,UAAI,IAAI,OAAO;AACf,UAAI,IAAI,KAAK;AAAA,IACf;AAAA,EACF;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import {
|
|
3
|
+
isOrganizationReadAccessAllowed
|
|
4
|
+
} from "@open-mercato/core/modules/directory/utils/organizationScopeGuard";
|
|
5
|
+
function denyCustomerDetailReadAsNotFound(input, notFoundMessage) {
|
|
6
|
+
if (isOrganizationReadAccessAllowed(input)) return null;
|
|
7
|
+
return NextResponse.json({ error: notFoundMessage }, { status: 404 });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
denyCustomerDetailReadAsNotFound
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=detailReadAccess.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/customers/lib/detailReadAccess.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport {\n isOrganizationReadAccessAllowed,\n type OrganizationReadAccessInput,\n} from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\n\n/**\n * Single-record customers detail routes (person / company / deal) must not leak\n * whether a record exists through the organization-scope check.\n *\n * The API dispatcher already enforces each route's `metadata.requireFeatures`\n * before the handler runs, returning a uniform `403` for callers who lack the\n * grant \u2014 so that path never distinguishes an existing id from a missing one.\n * The only remaining existence signal is the *post-load* organization guard: a\n * caller who holds the feature but whose scope excludes the record's\n * organization previously received `403` (record exists in another org) while a\n * non-existent id received `404`. That 403-vs-404 split is an existence oracle\n * (issue #5504).\n *\n * Collapse the organization-scope denial into the route's own not-found\n * response so an out-of-scope caller cannot tell \"exists in an organization you\n * cannot see\" from \"does not exist\" \u2014 the shape the api_keys hardening\n * (#4033 / PR-4051) established. Sharing this decision keeps the three customers\n * detail routes from drifting apart again.\n *\n * @returns the `404` response to return when read access is denied, or `null`\n * when the caller may read the record.\n */\nexport function denyCustomerDetailReadAsNotFound(\n input: OrganizationReadAccessInput,\n notFoundMessage: string,\n): NextResponse | null {\n if (isOrganizationReadAccessAllowed(input)) return null\n return NextResponse.json({ error: notFoundMessage }, { status: 404 })\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,OAEK;AAwBA,SAAS,iCACd,OACA,iBACqB;AACrB,MAAI,gCAAgC,KAAK,EAAG,QAAO;AACnD,SAAO,aAAa,KAAK,EAAE,OAAO,gBAAgB,GAAG,EAAE,QAAQ,IAAI,CAAC;AACtE;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/lib/findPeopleByAddresses.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerEntity } from '../data/entities'\n\n/**\n * Lower-cases, trims, and dedupes a list of email-shaped strings.\n * Rejects anything that doesn't look like `x@y` (single `@`, not at the start\n * or end, no consecutive `@`).\n */\nexport function normalizeAddresses(input: unknown): string[] {\n if (!Array.isArray(input)) return []\n const seen = new Set<string>()\n const out: string[] = []\n for (const value of input) {\n if (typeof value !== 'string') continue\n const trimmed = value.trim().toLowerCase()\n if (!trimmed) continue\n const at = trimmed.indexOf('@')\n if (at <= 0 || at === trimmed.length - 1 || trimmed.lastIndexOf('@') !== at) continue\n if (seen.has(trimmed)) continue\n seen.add(trimmed)\n out.push(trimmed)\n }\n return out\n}\n\nexport interface MatchedPerson {\n /** customer_entities.id (the anchor for customer_interactions.entity_id). */\n id: string\n /** Lowercased email address. */\n email: string\n}\n\n/**\n * Max
|
|
5
|
-
"mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAOxB,SAAS,mBAAmB,OAA0B;AAC3D,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAgB,CAAC;AACvB,aAAW,SAAS,OAAO;AACzB,QAAI,OAAO,UAAU,SAAU;AAC/B,UAAM,UAAU,MAAM,KAAK,EAAE,YAAY;AACzC,QAAI,CAAC,QAAS;AACd,UAAM,KAAK,QAAQ,QAAQ,GAAG;AAC9B,QAAI,MAAM,KAAK,OAAO,QAAQ,SAAS,KAAK,QAAQ,YAAY,GAAG,MAAM,GAAI;AAC7E,QAAI,KAAK,IAAI,OAAO,EAAG;AACvB,SAAK,IAAI,OAAO;AAChB,QAAI,KAAK,OAAO;AAAA,EAClB;AACA,SAAO;AACT;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerEntity } from '../data/entities'\n\n/**\n * Lower-cases, trims, and dedupes a list of email-shaped strings.\n * Rejects anything that doesn't look like `x@y` (single `@`, not at the start\n * or end, no consecutive `@`).\n */\nexport function normalizeAddresses(input: unknown): string[] {\n if (!Array.isArray(input)) return []\n const seen = new Set<string>()\n const out: string[] = []\n for (const value of input) {\n if (typeof value !== 'string') continue\n const trimmed = value.trim().toLowerCase()\n if (!trimmed) continue\n const at = trimmed.indexOf('@')\n if (at <= 0 || at === trimmed.length - 1 || trimmed.lastIndexOf('@') !== at) continue\n if (seen.has(trimmed)) continue\n seen.add(trimmed)\n out.push(trimmed)\n }\n return out\n}\n\nexport interface MatchedPerson {\n /** customer_entities.id (the anchor for customer_interactions.entity_id). */\n id: string\n /** Lowercased email address. */\n email: string\n}\n\n/**\n * Max rows scanned by in-memory fallback matches over encrypted contact\n * columns (`primary_email` here, `primary_phone` in the check-phone route).\n * These columns are GDPR-encrypted with a random IV (see\n * `customers/encryption.ts`), so they cannot be filtered by value in SQL when\n * tenant data encryption is on \u2014 fallbacks decrypt recent rows and compare in\n * memory instead. Bounded to keep interactive lookups cheap; a blind-index\n * (hash) column per field is the follow-up if tenants outgrow it (#5515).\n */\nexport const MATCH_CANDIDATE_LIMIT = 500\n\n/**\n * Batch lookup of CustomerEntity rows (kind='person') whose `primaryEmail`\n * matches any of the given addresses (case-insensitive), scoped to the tenant\n * and organization. Returns at most one MatchedPerson per resolved person.\n *\n * `primary_email` is encrypted with a non-deterministic IV, so a `WHERE\n * primary_email = ?` filter silently matches nothing when encryption is on. We\n * therefore try a direct equality match first (the fast path when encryption is\n * off) and, for any address it leaves unresolved, fall back to scanning recent\n * decrypted person rows and comparing in memory \u2014 the same dual-mode pattern as\n * `inbox-actions.ts`.\n */\nexport async function findPeopleByAddresses(\n em: EntityManager,\n addresses: string[],\n tenantId: string,\n organizationId: string | null = null,\n): Promise<MatchedPerson[]> {\n const normalized = normalizeAddresses(addresses)\n if (normalized.length === 0) return []\n if (!organizationId) return []\n const dscope = { tenantId, organizationId }\n const resolved = new Map<string, string>()\n\n // Fast path: direct equality match. Matches exactly when tenant data encryption\n // is off; returns nothing against encrypted (random-IV) ciphertext, which the\n // in-memory fallback below covers.\n const direct = (await findWithDecryption(\n em,\n CustomerEntity,\n { primaryEmail: { $in: normalized }, kind: 'person', tenantId, organizationId, deletedAt: null },\n undefined,\n dscope,\n )) as Array<{ id: string; primaryEmail?: string | null }>\n for (const row of direct) {\n const rowEmail = row.primaryEmail?.trim().toLowerCase()\n if (rowEmail && !resolved.has(rowEmail)) resolved.set(rowEmail, row.id)\n }\n\n // Fallback for unresolved addresses (the encryption-on path): scan recent person\n // rows and compare decrypted emails in memory.\n if (normalized.some((email) => !resolved.has(email))) {\n const candidates = (await findWithDecryption(\n em,\n CustomerEntity,\n { kind: 'person', tenantId, organizationId, deletedAt: null },\n { limit: MATCH_CANDIDATE_LIMIT, orderBy: { createdAt: 'DESC' } },\n dscope,\n )) as Array<{ id: string; primaryEmail?: string | null }>\n for (const row of candidates) {\n const rowEmail = row.primaryEmail?.trim().toLowerCase()\n if (rowEmail && !resolved.has(rowEmail)) resolved.set(rowEmail, row.id)\n }\n }\n\n const seen = new Set<string>()\n const out: MatchedPerson[] = []\n for (const email of normalized) {\n const id = resolved.get(email)\n if (!id || seen.has(id)) continue\n seen.add(id)\n out.push({ id, email })\n }\n return out\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAOxB,SAAS,mBAAmB,OAA0B;AAC3D,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAgB,CAAC;AACvB,aAAW,SAAS,OAAO;AACzB,QAAI,OAAO,UAAU,SAAU;AAC/B,UAAM,UAAU,MAAM,KAAK,EAAE,YAAY;AACzC,QAAI,CAAC,QAAS;AACd,UAAM,KAAK,QAAQ,QAAQ,GAAG;AAC9B,QAAI,MAAM,KAAK,OAAO,QAAQ,SAAS,KAAK,QAAQ,YAAY,GAAG,MAAM,GAAI;AAC7E,QAAI,KAAK,IAAI,OAAO,EAAG;AACvB,SAAK,IAAI,OAAO;AAChB,QAAI,KAAK,OAAO;AAAA,EAClB;AACA,SAAO;AACT;AAkBO,MAAM,wBAAwB;AAcrC,eAAsB,sBACpB,IACA,WACA,UACA,iBAAgC,MACN;AAC1B,QAAM,aAAa,mBAAmB,SAAS;AAC/C,MAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AACrC,MAAI,CAAC,eAAgB,QAAO,CAAC;AAC7B,QAAM,SAAS,EAAE,UAAU,eAAe;AAC1C,QAAM,WAAW,oBAAI,IAAoB;AAKzC,QAAM,SAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,EAAE,cAAc,EAAE,KAAK,WAAW,GAAG,MAAM,UAAU,UAAU,gBAAgB,WAAW,KAAK;AAAA,IAC/F;AAAA,IACA;AAAA,EACF;AACA,aAAW,OAAO,QAAQ;AACxB,UAAM,WAAW,IAAI,cAAc,KAAK,EAAE,YAAY;AACtD,QAAI,YAAY,CAAC,SAAS,IAAI,QAAQ,EAAG,UAAS,IAAI,UAAU,IAAI,EAAE;AAAA,EACxE;AAIA,MAAI,WAAW,KAAK,CAAC,UAAU,CAAC,SAAS,IAAI,KAAK,CAAC,GAAG;AACpD,UAAM,aAAc,MAAM;AAAA,MACxB;AAAA,MACA;AAAA,MACA,EAAE,MAAM,UAAU,UAAU,gBAAgB,WAAW,KAAK;AAAA,MAC5D,EAAE,OAAO,uBAAuB,SAAS,EAAE,WAAW,OAAO,EAAE;AAAA,MAC/D;AAAA,IACF;AACA,eAAW,OAAO,YAAY;AAC5B,YAAM,WAAW,IAAI,cAAc,KAAK,EAAE,YAAY;AACtD,UAAI,YAAY,CAAC,SAAS,IAAI,QAAQ,EAAG,UAAS,IAAI,UAAU,IAAI,EAAE;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAuB,CAAC;AAC9B,aAAW,SAAS,YAAY;AAC9B,UAAM,KAAK,SAAS,IAAI,KAAK;AAC7B,QAAI,CAAC,MAAM,KAAK,IAAI,EAAE,EAAG;AACzB,SAAK,IAAI,EAAE;AACX,QAAI,KAAK,EAAE,IAAI,MAAM,CAAC;AAAA,EACxB;AACA,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,7 +2,8 @@ import { CrudHttpError, notFound } from "@open-mercato/shared/lib/crud/errors";
|
|
|
2
2
|
import { findWithDecryption, findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
3
3
|
import {
|
|
4
4
|
CustomerEntity,
|
|
5
|
-
CustomerPersonCompanyLink
|
|
5
|
+
CustomerPersonCompanyLink,
|
|
6
|
+
CustomerPersonProfile
|
|
6
7
|
} from "../data/entities.js";
|
|
7
8
|
import {
|
|
8
9
|
filterActivePersonCompanyLinks,
|
|
@@ -34,6 +35,99 @@ async function requireCompany(em, companyId, organizationId, tenantId) {
|
|
|
34
35
|
}
|
|
35
36
|
return company;
|
|
36
37
|
}
|
|
38
|
+
async function loadCompanyPeopleUnion(em, company, scope) {
|
|
39
|
+
const decryptionScope = {
|
|
40
|
+
tenantId: scope.tenantId ?? company.tenantId ?? null,
|
|
41
|
+
organizationId: scope.organizationId ?? company.organizationId ?? null
|
|
42
|
+
};
|
|
43
|
+
const relatedPeopleById = /* @__PURE__ */ new Map();
|
|
44
|
+
const companyLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(
|
|
45
|
+
em,
|
|
46
|
+
{ company: company.id, organizationId: company.organizationId, tenantId: company.tenantId },
|
|
47
|
+
"customers.companies.loadCompanyPeopleUnion"
|
|
48
|
+
);
|
|
49
|
+
const companyLinks = filterActivePersonCompanyLinks(
|
|
50
|
+
await findWithDecryption(
|
|
51
|
+
em,
|
|
52
|
+
CustomerPersonCompanyLink,
|
|
53
|
+
companyLinkWhere,
|
|
54
|
+
{ populate: ["person", "person.personProfile"], orderBy: { isPrimary: "desc", createdAt: "asc" } },
|
|
55
|
+
decryptionScope
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
companyLinks.forEach((link) => {
|
|
59
|
+
const entity = typeof link.person === "string" ? null : link.person;
|
|
60
|
+
if (!entity || entity.kind !== "person" || entity.deletedAt) return;
|
|
61
|
+
const personProfile = entity.personProfile && typeof entity.personProfile !== "string" ? entity.personProfile : null;
|
|
62
|
+
relatedPeopleById.set(entity.id, {
|
|
63
|
+
entity,
|
|
64
|
+
profile: personProfile,
|
|
65
|
+
linkedAt: link.createdAt instanceof Date ? link.createdAt.toISOString() : null
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
const profiles = await findWithDecryption(
|
|
69
|
+
em,
|
|
70
|
+
CustomerPersonProfile,
|
|
71
|
+
{
|
|
72
|
+
company: company.id,
|
|
73
|
+
tenantId: company.tenantId,
|
|
74
|
+
organizationId: company.organizationId,
|
|
75
|
+
entity: { deletedAt: null }
|
|
76
|
+
},
|
|
77
|
+
{ populate: ["entity"] },
|
|
78
|
+
decryptionScope
|
|
79
|
+
);
|
|
80
|
+
profiles.forEach((entry) => {
|
|
81
|
+
const entity = entry.entity;
|
|
82
|
+
if (!entity || entity.kind !== "person" || entity.deletedAt) return;
|
|
83
|
+
if (!relatedPeopleById.has(entity.id)) {
|
|
84
|
+
relatedPeopleById.set(entity.id, {
|
|
85
|
+
entity,
|
|
86
|
+
profile: entry ?? null,
|
|
87
|
+
linkedAt: entry.createdAt instanceof Date ? entry.createdAt.toISOString() : null
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return Array.from(relatedPeopleById.values());
|
|
92
|
+
}
|
|
93
|
+
async function countCompanyPeopleUnion(em, company) {
|
|
94
|
+
const personIds = /* @__PURE__ */ new Set();
|
|
95
|
+
const companyLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(
|
|
96
|
+
em,
|
|
97
|
+
{
|
|
98
|
+
company: company.id,
|
|
99
|
+
organizationId: company.organizationId,
|
|
100
|
+
tenantId: company.tenantId,
|
|
101
|
+
person: { kind: "person", deletedAt: null }
|
|
102
|
+
},
|
|
103
|
+
"customers.companies.countCompanyPeopleUnion"
|
|
104
|
+
);
|
|
105
|
+
const companyLinks = filterActivePersonCompanyLinks(
|
|
106
|
+
await em.find(CustomerPersonCompanyLink, companyLinkWhere, {
|
|
107
|
+
fields: ["person", "deletedAt"]
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
companyLinks.forEach((link) => {
|
|
111
|
+
const personId = typeof link.person === "string" ? link.person : link.person?.id;
|
|
112
|
+
if (personId) personIds.add(personId);
|
|
113
|
+
});
|
|
114
|
+
const profiles = await em.find(
|
|
115
|
+
CustomerPersonProfile,
|
|
116
|
+
{
|
|
117
|
+
company: company.id,
|
|
118
|
+
tenantId: company.tenantId,
|
|
119
|
+
organizationId: company.organizationId,
|
|
120
|
+
entity: { kind: "person", deletedAt: null }
|
|
121
|
+
},
|
|
122
|
+
{ fields: ["entity"] }
|
|
123
|
+
);
|
|
124
|
+
profiles.forEach((entry) => {
|
|
125
|
+
const entity = entry.entity;
|
|
126
|
+
const entityId = typeof entity === "string" ? entity : entity?.id;
|
|
127
|
+
if (entityId) personIds.add(entityId);
|
|
128
|
+
});
|
|
129
|
+
return personIds.size;
|
|
130
|
+
}
|
|
37
131
|
async function loadPersonCompanyLinks(em, person) {
|
|
38
132
|
const where = await withActiveCustomerPersonCompanyLinkFilter(
|
|
39
133
|
em,
|
|
@@ -207,7 +301,9 @@ async function removePersonCompanyLink(em, person, profile, linkId) {
|
|
|
207
301
|
const link = existingLinks.find((entry) => entry.id === linkId) ?? existingLinks.find((entry) => (typeof entry.company === "string" ? entry.company : entry.company.id) === linkId) ?? null;
|
|
208
302
|
if (!link) {
|
|
209
303
|
if (profile.company && typeof profile.company !== "string" && profile.company.id === linkId) {
|
|
210
|
-
|
|
304
|
+
const primary = existingLinks.find((entry) => entry.isPrimary) ?? null;
|
|
305
|
+
const primaryCompany = primary ? resolveLinkedCompany(primary) : null;
|
|
306
|
+
profile.company = primaryCompany ?? null;
|
|
211
307
|
return;
|
|
212
308
|
}
|
|
213
309
|
throw notFound("Company link not found");
|
|
@@ -229,7 +325,9 @@ async function removePersonCompanyLink(em, person, profile, linkId) {
|
|
|
229
325
|
}
|
|
230
326
|
export {
|
|
231
327
|
addPersonCompanyLink,
|
|
328
|
+
countCompanyPeopleUnion,
|
|
232
329
|
findDeletedPersonCompanyLink,
|
|
330
|
+
loadCompanyPeopleUnion,
|
|
233
331
|
loadPersonCompanyLinks,
|
|
234
332
|
promoteFallbackPrimaryLink,
|
|
235
333
|
removePersonCompanyLink,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/lib/personCompanies.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n CustomerEntity,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n} from '../data/entities'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from './personCompanyLinkTable'\n\nexport type PersonCompanySummary = {\n linkId: string | null\n companyId: string\n displayName: string\n isPrimary: boolean\n synthetic?: boolean\n}\n\nexport async function findDeletedPersonCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n company: CustomerEntity,\n): Promise<CustomerPersonCompanyLink | null> {\n const link = await findOneWithDecryption(\n em,\n CustomerPersonCompanyLink,\n {\n person,\n company,\n organizationId: person.organizationId,\n tenantId: person.tenantId,\n deletedAt: { $ne: null },\n } as any,\n {},\n { tenantId: person.tenantId, organizationId: person.organizationId },\n )\n return link ?? null\n}\n\nasync function requireCompany(\n em: EntityManager,\n companyId: string,\n organizationId: string,\n tenantId: string,\n): Promise<CustomerEntity> {\n const company = await findOneWithDecryption(em, CustomerEntity, { id: companyId, kind: 'company', deletedAt: null }, {}, { tenantId, organizationId })\n if (!company) {\n throw notFound('Company not found')\n }\n if (company.organizationId !== organizationId || company.tenantId !== tenantId) {\n throw new CrudHttpError(403, { error: 'Cannot link company outside current scope' })\n }\n return company\n}\n\nexport async function loadPersonCompanyLinks(\n em: EntityManager,\n person: CustomerEntity,\n): Promise<CustomerPersonCompanyLink[]> {\n const where = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n { person, organizationId: person.organizationId, tenantId: person.tenantId },\n 'customers.personCompanies.loadPersonCompanyLinks',\n )\n return filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n where,\n { populate: ['company'], orderBy: { isPrimary: 'desc', createdAt: 'asc' } },\n { tenantId: person.tenantId, organizationId: person.organizationId },\n ),\n )\n}\n\nexport function summarizePersonCompanies(\n profile: CustomerPersonProfile | null,\n links: CustomerPersonCompanyLink[],\n): PersonCompanySummary[] {\n if (links.length > 0) {\n const items: PersonCompanySummary[] = []\n links.forEach((link) => {\n const company = typeof link.company === 'string' ? null : link.company\n if (!company) return\n items.push({\n linkId: link.id,\n companyId: company.id,\n displayName: company.displayName,\n isPrimary: Boolean(link.isPrimary),\n })\n })\n return items\n }\n\n const fallbackCompany = profile?.company && typeof profile.company !== 'string' ? profile.company : null\n if (!fallbackCompany) return []\n\n return [\n {\n linkId: fallbackCompany.id,\n companyId: fallbackCompany.id,\n displayName: fallbackCompany.displayName,\n isPrimary: true,\n synthetic: true,\n },\n ]\n}\n\nasync function clearPrimaryFlags(em: EntityManager, person: CustomerEntity): Promise<void> {\n await em.nativeUpdate(\n CustomerPersonCompanyLink,\n { person, organizationId: person.organizationId, tenantId: person.tenantId, isPrimary: true },\n { isPrimary: false },\n )\n}\n\nfunction resolveLinkedCompany(link: CustomerPersonCompanyLink): CustomerEntity | null {\n return typeof link.company === 'string' ? null : link.company\n}\n\nexport async function promoteFallbackPrimaryLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n links: CustomerPersonCompanyLink[],\n removedCompanyId?: string | null,\n): Promise<void> {\n const nextPrimary = links[0] ?? null\n if (!nextPrimary) {\n if (\n !removedCompanyId\n || (profile.company && typeof profile.company !== 'string' && profile.company.id === removedCompanyId)\n || profile.company == null\n ) {\n profile.company = null\n }\n return\n }\n\n await clearPrimaryFlags(em, person)\n nextPrimary.isPrimary = true\n const nextCompany = resolveLinkedCompany(nextPrimary)\n if (nextCompany) {\n profile.company = nextCompany\n }\n}\n\nexport async function syncLegacyPrimaryCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n companyId: string | null | undefined,\n): Promise<void> {\n const normalizedCompanyId = typeof companyId === 'string' && companyId.trim().length > 0 ? companyId.trim() : null\n const existingLinks = await loadPersonCompanyLinks(em, person)\n\n if (!normalizedCompanyId) {\n if (existingLinks.some((link) => link.isPrimary)) {\n await clearPrimaryFlags(em, person)\n }\n profile.company = null\n return\n }\n\n const company = await requireCompany(em, normalizedCompanyId, person.organizationId, person.tenantId)\n const currentLink =\n existingLinks.find((link) => (typeof link.company === 'string' ? link.company : link.company.id) === company.id) ?? null\n\n if (currentLink) {\n if (!currentLink.isPrimary) {\n await clearPrimaryFlags(em, person)\n currentLink.isPrimary = true\n } else if (existingLinks.some((link) => link.id !== currentLink.id && link.isPrimary)) {\n await clearPrimaryFlags(em, person)\n currentLink.isPrimary = true\n }\n } else {\n await clearPrimaryFlags(em, person)\n const link = em.create(CustomerPersonCompanyLink, {\n organizationId: person.organizationId,\n tenantId: person.tenantId,\n person,\n company,\n isPrimary: true,\n })\n em.persist(link)\n }\n\n profile.company = company\n}\n\nexport async function addPersonCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n companyId: string,\n options?: { isPrimary?: boolean },\n): Promise<CustomerPersonCompanyLink> {\n const company = await requireCompany(em, companyId, person.organizationId, person.tenantId)\n const existingLinks = await loadPersonCompanyLinks(em, person)\n const makePrimary = Boolean(options?.isPrimary) || existingLinks.length === 0\n const existing =\n existingLinks.find((link) => (typeof link.company === 'string' ? link.company : link.company.id) === company.id) ?? null\n\n if (existing) {\n if (makePrimary && !existing.isPrimary) {\n await clearPrimaryFlags(em, person)\n existing.isPrimary = true\n profile.company = company\n }\n return existing\n }\n\n if (makePrimary) {\n await clearPrimaryFlags(em, person)\n }\n\n const deletedLink = await findDeletedPersonCompanyLink(em, person, company)\n const link = deletedLink ?? em.create(CustomerPersonCompanyLink, {\n organizationId: person.organizationId,\n tenantId: person.tenantId,\n person,\n company,\n isPrimary: makePrimary,\n })\n if (deletedLink) {\n deletedLink.deletedAt = null\n deletedLink.isPrimary = makePrimary\n }\n em.persist(link)\n\n if (makePrimary) {\n profile.company = company\n } else if (!profile.company && existingLinks.length === 0) {\n profile.company = company\n link.isPrimary = true\n }\n\n return link\n}\n\nexport async function updatePersonCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n linkId: string,\n patch: { isPrimary?: boolean },\n): Promise<CustomerPersonCompanyLink | null> {\n const existingLinks = await loadPersonCompanyLinks(em, person)\n const link = existingLinks.find((entry) => entry.id === linkId)\n ?? existingLinks.find((entry) => (typeof entry.company === 'string' ? entry.company : entry.company.id) === linkId)\n ?? null\n\n if (!link && profile.company && typeof profile.company !== 'string' && profile.company.id === linkId && patch.isPrimary === false) {\n profile.company = null\n return null\n }\n\n if (!link) {\n throw notFound('Company link not found')\n }\n\n if (patch.isPrimary === true) {\n await clearPrimaryFlags(em, person)\n link.isPrimary = true\n const company = resolveLinkedCompany(link)\n if (company) {\n profile.company = company\n }\n } else if (patch.isPrimary === false) {\n const linkWasPrimary = link.isPrimary\n const removedCompanyId = typeof link.company === 'string' ? link.company : link.company.id\n link.isPrimary = false\n if (linkWasPrimary) {\n const remainingLinks = existingLinks.filter((entry) => entry.id !== link.id)\n await promoteFallbackPrimaryLink(em, person, profile, remainingLinks, removedCompanyId)\n } else if (profile.company && typeof profile.company !== 'string' && profile.company.id === removedCompanyId) {\n profile.company = null\n }\n }\n\n return link\n}\n\nexport async function removePersonCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n linkId: string,\n): Promise<void> {\n const existingLinks = await loadPersonCompanyLinks(em, person)\n const link = existingLinks.find((entry) => entry.id === linkId)\n ?? existingLinks.find((entry) => (typeof entry.company === 'string' ? entry.company : entry.company.id) === linkId)\n ?? null\n\n if (!link) {\n if (profile.company && typeof profile.company !== 'string' && profile.company.id === linkId) {\n profile.company = null\n return\n }\n throw notFound('Company link not found')\n }\n\n const removedCompanyId = typeof link.company === 'string' ? link.company : link.company.id\n const removedWasPrimary = link.isPrimary\n link.isPrimary = false\n link.deletedAt = new Date()\n const remainingLinks = existingLinks.filter((entry) => entry.id !== link.id)\n\n if (removedWasPrimary) {\n await promoteFallbackPrimaryLink(em, person, profile, remainingLinks, removedCompanyId)\n } else if (profile.company && typeof profile.company !== 'string' && profile.company.id === removedCompanyId) {\n const primary = remainingLinks.find((entry) => entry.isPrimary) ?? null\n const primaryCompany = primary ? resolveLinkedCompany(primary) : null\n if (primaryCompany) {\n profile.company = primaryCompany\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,eAAe,gBAAgB;AACxC,SAAS,oBAAoB,6BAA6B;AAC1D;AAAA,EACE;AAAA,EACA;AAAA,
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n CustomerEntity,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n} from '../data/entities'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from './personCompanyLinkTable'\n\nexport type PersonCompanySummary = {\n linkId: string | null\n companyId: string\n displayName: string\n isPrimary: boolean\n synthetic?: boolean\n}\n\nexport async function findDeletedPersonCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n company: CustomerEntity,\n): Promise<CustomerPersonCompanyLink | null> {\n const link = await findOneWithDecryption(\n em,\n CustomerPersonCompanyLink,\n {\n person,\n company,\n organizationId: person.organizationId,\n tenantId: person.tenantId,\n deletedAt: { $ne: null },\n } as any,\n {},\n { tenantId: person.tenantId, organizationId: person.organizationId },\n )\n return link ?? null\n}\n\nasync function requireCompany(\n em: EntityManager,\n companyId: string,\n organizationId: string,\n tenantId: string,\n): Promise<CustomerEntity> {\n const company = await findOneWithDecryption(em, CustomerEntity, { id: companyId, kind: 'company', deletedAt: null }, {}, { tenantId, organizationId })\n if (!company) {\n throw notFound('Company not found')\n }\n if (company.organizationId !== organizationId || company.tenantId !== tenantId) {\n throw new CrudHttpError(403, { error: 'Cannot link company outside current scope' })\n }\n return company\n}\n\nexport type CompanyPersonUnionEntry = {\n entity: CustomerEntity\n profile: CustomerPersonProfile | null\n linkedAt: string | null\n}\n\n/**\n * Resolve \"people belonging to this company\" as the union of active\n * `CustomerPersonCompanyLink` rows and `CustomerPersonProfile.company`\n * profile-only assignments (data that never got a link row, e.g. from\n * migrated CRM imports). This is the single source of truth for both the\n * company People tab list and its badge count \u2014 see #5114.\n */\nexport async function loadCompanyPeopleUnion(\n em: EntityManager,\n company: CustomerEntity,\n scope: { tenantId?: string | null; organizationId?: string | null },\n): Promise<CompanyPersonUnionEntry[]> {\n const decryptionScope = {\n tenantId: scope.tenantId ?? company.tenantId ?? null,\n organizationId: scope.organizationId ?? company.organizationId ?? null,\n }\n const relatedPeopleById = new Map<string, CompanyPersonUnionEntry>()\n\n const companyLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n { company: company.id, organizationId: company.organizationId, tenantId: company.tenantId },\n 'customers.companies.loadCompanyPeopleUnion',\n )\n const companyLinks = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n companyLinkWhere,\n { populate: ['person', 'person.personProfile'], orderBy: { isPrimary: 'desc', createdAt: 'asc' } },\n decryptionScope,\n ),\n )\n companyLinks.forEach((link) => {\n const entity = typeof link.person === 'string' ? null : link.person\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n const personProfile =\n entity.personProfile && typeof entity.personProfile !== 'string' ? entity.personProfile : null\n relatedPeopleById.set(entity.id, {\n entity,\n profile: personProfile,\n linkedAt: link.createdAt instanceof Date ? link.createdAt.toISOString() : null,\n })\n })\n\n const profiles = await findWithDecryption(\n em,\n CustomerPersonProfile,\n {\n company: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n entity: { deletedAt: null },\n },\n { populate: ['entity'] },\n decryptionScope,\n )\n profiles.forEach((entry) => {\n const entity = entry.entity as CustomerEntity | null\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n if (!relatedPeopleById.has(entity.id)) {\n relatedPeopleById.set(entity.id, {\n entity,\n profile: entry ?? null,\n linkedAt: entry.createdAt instanceof Date ? entry.createdAt.toISOString() : null,\n })\n }\n })\n\n return Array.from(relatedPeopleById.values())\n}\n\n/**\n * Count-only sibling of `loadCompanyPeopleUnion` for the company People badge, which\n * needs the size of the union and nothing else. Both queries project just the foreign\n * key column and push the `kind: 'person'` / `deletedAt: null` predicates into the\n * WHERE clause, so no person row is hydrated and no PII is decrypted to produce a\n * number \u2014 `findWithDecryption` is deliberately not used here because the projections\n * select no encrypted column.\n */\nexport async function countCompanyPeopleUnion(\n em: EntityManager,\n company: CustomerEntity,\n): Promise<number> {\n const personIds = new Set<string>()\n\n const companyLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n person: { kind: 'person', deletedAt: null },\n },\n 'customers.companies.countCompanyPeopleUnion',\n )\n const companyLinks = filterActivePersonCompanyLinks(\n await em.find(CustomerPersonCompanyLink, companyLinkWhere as any, {\n fields: ['person', 'deletedAt'],\n } as any),\n )\n companyLinks.forEach((link) => {\n const personId = typeof link.person === 'string' ? link.person : link.person?.id\n if (personId) personIds.add(personId)\n })\n\n const profiles = await em.find(\n CustomerPersonProfile,\n {\n company: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n entity: { kind: 'person', deletedAt: null },\n } as any,\n { fields: ['entity'] } as any,\n )\n profiles.forEach((entry) => {\n const entity = entry.entity as CustomerEntity | string | null\n const entityId = typeof entity === 'string' ? entity : entity?.id\n if (entityId) personIds.add(entityId)\n })\n\n return personIds.size\n}\n\nexport async function loadPersonCompanyLinks(\n em: EntityManager,\n person: CustomerEntity,\n): Promise<CustomerPersonCompanyLink[]> {\n const where = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n { person, organizationId: person.organizationId, tenantId: person.tenantId },\n 'customers.personCompanies.loadPersonCompanyLinks',\n )\n return filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n where,\n { populate: ['company'], orderBy: { isPrimary: 'desc', createdAt: 'asc' } },\n { tenantId: person.tenantId, organizationId: person.organizationId },\n ),\n )\n}\n\nexport function summarizePersonCompanies(\n profile: CustomerPersonProfile | null,\n links: CustomerPersonCompanyLink[],\n): PersonCompanySummary[] {\n if (links.length > 0) {\n const items: PersonCompanySummary[] = []\n links.forEach((link) => {\n const company = typeof link.company === 'string' ? null : link.company\n if (!company) return\n items.push({\n linkId: link.id,\n companyId: company.id,\n displayName: company.displayName,\n isPrimary: Boolean(link.isPrimary),\n })\n })\n return items\n }\n\n const fallbackCompany = profile?.company && typeof profile.company !== 'string' ? profile.company : null\n if (!fallbackCompany) return []\n\n return [\n {\n linkId: fallbackCompany.id,\n companyId: fallbackCompany.id,\n displayName: fallbackCompany.displayName,\n isPrimary: true,\n synthetic: true,\n },\n ]\n}\n\nasync function clearPrimaryFlags(em: EntityManager, person: CustomerEntity): Promise<void> {\n await em.nativeUpdate(\n CustomerPersonCompanyLink,\n { person, organizationId: person.organizationId, tenantId: person.tenantId, isPrimary: true },\n { isPrimary: false },\n )\n}\n\nfunction resolveLinkedCompany(link: CustomerPersonCompanyLink): CustomerEntity | null {\n return typeof link.company === 'string' ? null : link.company\n}\n\nexport async function promoteFallbackPrimaryLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n links: CustomerPersonCompanyLink[],\n removedCompanyId?: string | null,\n): Promise<void> {\n const nextPrimary = links[0] ?? null\n if (!nextPrimary) {\n if (\n !removedCompanyId\n || (profile.company && typeof profile.company !== 'string' && profile.company.id === removedCompanyId)\n || profile.company == null\n ) {\n profile.company = null\n }\n return\n }\n\n await clearPrimaryFlags(em, person)\n nextPrimary.isPrimary = true\n const nextCompany = resolveLinkedCompany(nextPrimary)\n if (nextCompany) {\n profile.company = nextCompany\n }\n}\n\nexport async function syncLegacyPrimaryCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n companyId: string | null | undefined,\n): Promise<void> {\n const normalizedCompanyId = typeof companyId === 'string' && companyId.trim().length > 0 ? companyId.trim() : null\n const existingLinks = await loadPersonCompanyLinks(em, person)\n\n if (!normalizedCompanyId) {\n if (existingLinks.some((link) => link.isPrimary)) {\n await clearPrimaryFlags(em, person)\n }\n profile.company = null\n return\n }\n\n const company = await requireCompany(em, normalizedCompanyId, person.organizationId, person.tenantId)\n const currentLink =\n existingLinks.find((link) => (typeof link.company === 'string' ? link.company : link.company.id) === company.id) ?? null\n\n if (currentLink) {\n if (!currentLink.isPrimary) {\n await clearPrimaryFlags(em, person)\n currentLink.isPrimary = true\n } else if (existingLinks.some((link) => link.id !== currentLink.id && link.isPrimary)) {\n await clearPrimaryFlags(em, person)\n currentLink.isPrimary = true\n }\n } else {\n await clearPrimaryFlags(em, person)\n const link = em.create(CustomerPersonCompanyLink, {\n organizationId: person.organizationId,\n tenantId: person.tenantId,\n person,\n company,\n isPrimary: true,\n })\n em.persist(link)\n }\n\n profile.company = company\n}\n\nexport async function addPersonCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n companyId: string,\n options?: { isPrimary?: boolean },\n): Promise<CustomerPersonCompanyLink> {\n const company = await requireCompany(em, companyId, person.organizationId, person.tenantId)\n const existingLinks = await loadPersonCompanyLinks(em, person)\n const makePrimary = Boolean(options?.isPrimary) || existingLinks.length === 0\n const existing =\n existingLinks.find((link) => (typeof link.company === 'string' ? link.company : link.company.id) === company.id) ?? null\n\n if (existing) {\n if (makePrimary && !existing.isPrimary) {\n await clearPrimaryFlags(em, person)\n existing.isPrimary = true\n profile.company = company\n }\n return existing\n }\n\n if (makePrimary) {\n await clearPrimaryFlags(em, person)\n }\n\n const deletedLink = await findDeletedPersonCompanyLink(em, person, company)\n const link = deletedLink ?? em.create(CustomerPersonCompanyLink, {\n organizationId: person.organizationId,\n tenantId: person.tenantId,\n person,\n company,\n isPrimary: makePrimary,\n })\n if (deletedLink) {\n deletedLink.deletedAt = null\n deletedLink.isPrimary = makePrimary\n }\n em.persist(link)\n\n if (makePrimary) {\n profile.company = company\n } else if (!profile.company && existingLinks.length === 0) {\n profile.company = company\n link.isPrimary = true\n }\n\n return link\n}\n\nexport async function updatePersonCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n linkId: string,\n patch: { isPrimary?: boolean },\n): Promise<CustomerPersonCompanyLink | null> {\n const existingLinks = await loadPersonCompanyLinks(em, person)\n const link = existingLinks.find((entry) => entry.id === linkId)\n ?? existingLinks.find((entry) => (typeof entry.company === 'string' ? entry.company : entry.company.id) === linkId)\n ?? null\n\n if (!link && profile.company && typeof profile.company !== 'string' && profile.company.id === linkId && patch.isPrimary === false) {\n profile.company = null\n return null\n }\n\n if (!link) {\n throw notFound('Company link not found')\n }\n\n if (patch.isPrimary === true) {\n await clearPrimaryFlags(em, person)\n link.isPrimary = true\n const company = resolveLinkedCompany(link)\n if (company) {\n profile.company = company\n }\n } else if (patch.isPrimary === false) {\n const linkWasPrimary = link.isPrimary\n const removedCompanyId = typeof link.company === 'string' ? link.company : link.company.id\n link.isPrimary = false\n if (linkWasPrimary) {\n const remainingLinks = existingLinks.filter((entry) => entry.id !== link.id)\n await promoteFallbackPrimaryLink(em, person, profile, remainingLinks, removedCompanyId)\n } else if (profile.company && typeof profile.company !== 'string' && profile.company.id === removedCompanyId) {\n profile.company = null\n }\n }\n\n return link\n}\n\nexport async function removePersonCompanyLink(\n em: EntityManager,\n person: CustomerEntity,\n profile: CustomerPersonProfile,\n linkId: string,\n): Promise<void> {\n const existingLinks = await loadPersonCompanyLinks(em, person)\n const link = existingLinks.find((entry) => entry.id === linkId)\n ?? existingLinks.find((entry) => (typeof entry.company === 'string' ? entry.company : entry.company.id) === linkId)\n ?? null\n\n if (!link) {\n if (profile.company && typeof profile.company !== 'string' && profile.company.id === linkId) {\n // Profile-only assignment: no link row backs it, so only the legacy field is\n // cleared. It must keep mirroring the primary link the way every other detach\n // path leaves it, so promote a remaining primary link instead of nulling blindly.\n const primary = existingLinks.find((entry) => entry.isPrimary) ?? null\n const primaryCompany = primary ? resolveLinkedCompany(primary) : null\n profile.company = primaryCompany ?? null\n return\n }\n throw notFound('Company link not found')\n }\n\n const removedCompanyId = typeof link.company === 'string' ? link.company : link.company.id\n const removedWasPrimary = link.isPrimary\n link.isPrimary = false\n link.deletedAt = new Date()\n const remainingLinks = existingLinks.filter((entry) => entry.id !== link.id)\n\n if (removedWasPrimary) {\n await promoteFallbackPrimaryLink(em, person, profile, remainingLinks, removedCompanyId)\n } else if (profile.company && typeof profile.company !== 'string' && profile.company.id === removedCompanyId) {\n const primary = remainingLinks.find((entry) => entry.isPrimary) ?? null\n const primaryCompany = primary ? resolveLinkedCompany(primary) : null\n if (primaryCompany) {\n profile.company = primaryCompany\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["link"]
|
|
7
7
|
}
|
|
@@ -11,6 +11,12 @@ import {
|
|
|
11
11
|
import { hydrateCanonicalInteractions, loadCustomerSummaries } from "./interactionReadModel.js";
|
|
12
12
|
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
13
13
|
const logger = createLogger("customers");
|
|
14
|
+
function emptyCanonicalTodoList() {
|
|
15
|
+
return { items: [], bridgeIds: /* @__PURE__ */ new Set(), total: 0 };
|
|
16
|
+
}
|
|
17
|
+
function isCollapsedRestrictedOrganizationScope(organizationIds, isUnrestricted) {
|
|
18
|
+
return isUnrestricted !== true && (!organizationIds || organizationIds.length === 0);
|
|
19
|
+
}
|
|
14
20
|
function resolveLegacyTodoSource(source) {
|
|
15
21
|
return typeof source === "string" && source.trim().length > 0 ? source : EXAMPLE_TODO_SOURCE;
|
|
16
22
|
}
|
|
@@ -258,6 +264,9 @@ async function resolveLegacyTodoDetails(queryEngine, links, tenantId, organizati
|
|
|
258
264
|
return details;
|
|
259
265
|
}
|
|
260
266
|
async function listLegacyTodoRows(em, queryEngine, tenantId, organizationIds, entityId, options) {
|
|
267
|
+
if (isCollapsedRestrictedOrganizationScope(organizationIds, options?.isUnrestricted)) {
|
|
268
|
+
return [];
|
|
269
|
+
}
|
|
261
270
|
const where = { tenantId };
|
|
262
271
|
if (organizationIds && organizationIds.length > 0) {
|
|
263
272
|
where.organizationId = { $in: organizationIds };
|
|
@@ -288,6 +297,9 @@ async function listLegacyTodoRows(em, queryEngine, tenantId, organizationIds, en
|
|
|
288
297
|
});
|
|
289
298
|
}
|
|
290
299
|
async function listCanonicalTodoRows(em, container, auth, selectedOrganizationId, organizationIds, options) {
|
|
300
|
+
if (isCollapsedRestrictedOrganizationScope(organizationIds, options?.isUnrestricted)) {
|
|
301
|
+
return emptyCanonicalTodoList();
|
|
302
|
+
}
|
|
291
303
|
const where = {
|
|
292
304
|
tenantId: auth.tenantId,
|
|
293
305
|
interactionType: "task"
|