@open-mercato/core 0.6.5-develop.4516.1.88e6ab71a9 → 0.6.5-develop.4544.1.71c003c861
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 +2 -2
- package/AGENTS.md +5 -0
- package/dist/generated/entities/role/index.js +3 -1
- package/dist/generated/entities/role/index.js.map +2 -2
- package/dist/generated/entities/step_instance/index.js +2 -0
- package/dist/generated/entities/step_instance/index.js.map +2 -2
- package/dist/generated/entities/user/index.js +3 -1
- package/dist/generated/entities/user/index.js.map +2 -2
- package/dist/generated/entities/user_task/index.js +2 -0
- package/dist/generated/entities/user_task/index.js.map +2 -2
- package/dist/generated/entities/workflow_branch_instance/index.js +39 -0
- package/dist/generated/entities/workflow_branch_instance/index.js.map +7 -0
- package/dist/generated/entities/workflow_event/index.js +2 -0
- package/dist/generated/entities/workflow_event/index.js.map +2 -2
- package/dist/generated/entities/workflow_instance/index.js +2 -0
- package/dist/generated/entities/workflow_instance/index.js.map +2 -2
- package/dist/generated/entities.ids.generated.js +1 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +26 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/optimisticLockUi.js +104 -0
- package/dist/helpers/integration/optimisticLockUi.js.map +7 -0
- package/dist/helpers/integration/salesFixtures.js +17 -0
- package/dist/helpers/integration/salesFixtures.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/page.js +9 -5
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +17 -9
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +32 -13
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/roles/route.js +3 -1
- package/dist/modules/auth/api/roles/route.js.map +2 -2
- package/dist/modules/auth/api/sidebar/preferences/route.js +71 -3
- package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +42 -19
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +3 -1
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.js +24 -4
- package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +8 -4
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +27 -5
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +6 -2
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/components/AclEditor.js +3 -1
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/auth/data/entities.js +6 -0
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/services/sidebarPreferencesService.js +32 -4
- package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +28 -0
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/route.js +28 -0
- package/dist/modules/business_rules/api/sets/route.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/[id]/page.js +11 -4
- package/dist/modules/business_rules/backend/rules/[id]/page.js.map +3 -3
- package/dist/modules/business_rules/backend/rules/page.js +20 -11
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/[id]/page.js +11 -4
- package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +20 -11
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/catalog/api/categories/route.js +2 -0
- package/dist/modules/catalog/api/categories/route.js.map +2 -2
- package/dist/modules/catalog/api/products/route.js +2 -1
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +2 -0
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +94 -40
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +37 -8
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js.map +2 -2
- package/dist/modules/catalog/commands/variants.js +32 -31
- package/dist/modules/catalog/commands/variants.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +12 -5
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductMediaManager.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +5 -3
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/catalog/components/products/variantForm.js +2 -1
- package/dist/modules/catalog/components/products/variantForm.js.map +2 -2
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +5 -0
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/[id]/page.js +6 -3
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +18 -11
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +1 -0
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +10 -6
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/currencies/commands/currencies.js +7 -5
- package/dist/modules/currencies/commands/currencies.js.map +2 -2
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js +26 -19
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id].js +28 -5
- package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles.js +4 -2
- package/dist/modules/customer_accounts/api/admin/roles.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users/[id].js +28 -5
- package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users.js +2 -0
- package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +16 -8
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +8 -4
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js +8 -4
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +29 -18
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +18 -11
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customers/api/companies/route.js +13 -2
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +2 -0
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +11 -2
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +1 -0
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +34 -21
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/[id]/page.js +45 -27
- package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +22 -5
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js +30 -8
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -0
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +16 -6
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +62 -39
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js +41 -26
- package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +50 -23
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/addresses.js +16 -14
- package/dist/modules/customers/commands/addresses.js.map +2 -2
- package/dist/modules/customers/commands/companies.js +1 -1
- package/dist/modules/customers/commands/companies.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +41 -4
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/people.js +1 -1
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/dist/modules/customers/commands/personCompanyLinks.js +8 -5
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/commands/pipeline-stages.js +13 -11
- package/dist/modules/customers/commands/pipeline-stages.js.map +3 -3
- package/dist/modules/customers/components/AddressFormatSettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySettings.js +20 -13
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySortSettings.js +4 -0
- package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
- package/dist/modules/customers/components/PipelineSettings.js +38 -23
- package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityTimeline.js +1 -1
- package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
- package/dist/modules/customers/components/detail/AddressesSection.js +4 -0
- package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +28 -22
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealsSection.js +36 -24
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/EmailCardActions.js +5 -0
- package/dist/modules/customers/components/detail/EmailCardActions.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +7 -0
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/ManageTagsDialog.js +34 -22
- package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +41 -29
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js +14 -8
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +14 -6
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +29 -13
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/useInteractions.js +77 -35
- package/dist/modules/customers/components/detail/hooks/useInteractions.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +25 -17
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/data/guards.js +66 -0
- package/dist/modules/customers/data/guards.js.map +7 -0
- package/dist/modules/customers/di.js +37 -0
- package/dist/modules/customers/di.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +11 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/data_sync/api/options.js +4 -4
- package/dist/modules/data_sync/api/options.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/route.js +9 -1
- package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +17 -8
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js +43 -22
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-schedule-service.js +9 -0
- package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +8 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js +17 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +31 -10
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +28 -15
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/directory/api/organizations/route.js +3 -0
- package/dist/modules/directory/api/organizations/route.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +2 -0
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +9 -5
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +7 -3
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +8 -4
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/directory/commands/organizations.js +7 -2
- package/dist/modules/directory/commands/organizations.js.map +2 -2
- package/dist/modules/entities/api/records.js +66 -0
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js +1 -0
- package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +8 -4
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/entities/lib/helpers.js +17 -0
- package/dist/modules/entities/lib/helpers.js.map +2 -2
- package/dist/modules/feature_toggles/api/global/[id]/override/route.js +2 -1
- package/dist/modules/feature_toggles/api/global/[id]/override/route.js.map +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js +15 -0
- package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
- package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js +15 -14
- package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js +20 -12
- package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +6 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/formConfig.js +2 -1
- package/dist/modules/feature_toggles/components/formConfig.js.map +2 -2
- package/dist/modules/feature_toggles/components/overrideFormConfig.js +5 -1
- package/dist/modules/feature_toggles/components/overrideFormConfig.js.map +2 -2
- package/dist/modules/feature_toggles/data/validators.js +7 -4
- package/dist/modules/feature_toggles/data/validators.js.map +2 -2
- package/dist/modules/inbox_ops/api/settings/route.js +17 -2
- package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +13 -8
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +9 -4
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +18 -11
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/page.js +12 -8
- package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +13 -10
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/perspectives/api/[tableId]/route.js +39 -30
- package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +7 -0
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +6 -14
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +3 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +4 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js +2 -0
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +36 -11
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/planner/components/AvailabilitySchedule.js +9 -5
- package/dist/modules/planner/components/AvailabilitySchedule.js.map +2 -2
- package/dist/modules/progress/api/jobs/[id]/route.js +7 -1
- package/dist/modules/progress/api/jobs/[id]/route.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +19 -0
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +1 -0
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +4 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +14 -3
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +8 -4
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/resources/components/ResourceCrudForm.js +2 -0
- package/dist/modules/resources/components/ResourceCrudForm.js.map +2 -2
- package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -0
- package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
- package/dist/modules/sales/api/documents/factory.js +7 -2
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +3 -1
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +13 -4
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +16 -4
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +68 -22
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/create/page.js.map +2 -2
- package/dist/modules/sales/commands/documentAddresses.js +181 -2
- package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +29 -1
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +12 -2
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/commands/shared.js +15 -0
- package/dist/modules/sales/commands/shared.js.map +2 -2
- package/dist/modules/sales/commands/shipments.js +4 -1
- package/dist/modules/sales/commands/shipments.js.map +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js +19 -11
- package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
- package/dist/modules/sales/components/DocumentNumberSettings.js.map +2 -2
- package/dist/modules/sales/components/OrderEditingSettings.js.map +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js +12 -4
- package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js +12 -4
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/StatusSettings.js +18 -11
- package/dist/modules/sales/components/StatusSettings.js.map +2 -2
- package/dist/modules/sales/components/TaxRatesSettings.js +12 -4
- package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
- package/dist/modules/sales/components/channels/ChannelOfferForm.js +47 -16
- package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +8 -4
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +44 -25
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +43 -23
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +22 -13
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +23 -10
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentDialog.js +29 -14
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +20 -10
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnDialog.js +26 -17
- package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +3 -1
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +10 -5
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +21 -7
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +19 -10
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/optimisticLock.js +27 -0
- package/dist/modules/sales/components/documents/optimisticLock.js.map +7 -0
- package/dist/modules/sales/di.js +18 -0
- package/dist/modules/sales/di.js.map +2 -2
- package/dist/modules/shipping_carriers/api/cancel/route.js +2 -2
- package/dist/modules/shipping_carriers/api/cancel/route.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/status-sync.js +8 -1
- package/dist/modules/shipping_carriers/lib/status-sync.js.map +2 -2
- package/dist/modules/staff/api/job-histories.js +11 -2
- package/dist/modules/staff/api/job-histories.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/route.js +11 -4
- package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +13 -8
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +2 -1
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +7 -4
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +4 -2
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +1 -0
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +4 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +5 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +12 -3
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +4 -1
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +12 -3
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/staff/commands/job-histories.js +40 -3
- package/dist/modules/staff/commands/job-histories.js.map +2 -2
- package/dist/modules/staff/components/LeaveRequestForm.js +1 -0
- package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
- package/dist/modules/staff/components/TeamForm.js +1 -0
- package/dist/modules/staff/components/TeamForm.js.map +2 -2
- package/dist/modules/staff/components/TeamMemberForm.js +1 -0
- package/dist/modules/staff/components/TeamMemberForm.js.map +2 -2
- package/dist/modules/staff/components/TeamRoleForm.js +1 -0
- package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
- package/dist/modules/staff/components/detail/JobHistorySection.js +20 -7
- package/dist/modules/staff/components/detail/JobHistorySection.js.map +2 -2
- package/dist/modules/staff/data/validators.js +7 -1
- package/dist/modules/staff/data/validators.js.map +2 -2
- package/dist/modules/staff/lib/leaveRequestHelpers.js +2 -1
- package/dist/modules/staff/lib/leaveRequestHelpers.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +12 -8
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js +106 -0
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +11 -3
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/page.js +19 -8
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +29 -16
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialog.js +3 -1
- package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowGraphImpl.js +4 -2
- package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
- package/dist/modules/workflows/components/formConfig.js +4 -1
- package/dist/modules/workflows/components/formConfig.js.map +2 -2
- package/dist/modules/workflows/components/nodes/ParallelForkNode.js +49 -0
- package/dist/modules/workflows/components/nodes/ParallelForkNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/ParallelJoinNode.js +49 -0
- package/dist/modules/workflows/components/nodes/ParallelJoinNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/index.js +4 -0
- package/dist/modules/workflows/components/nodes/index.js.map +2 -2
- package/dist/modules/workflows/data/entities.js +81 -0
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/data/validators.js +146 -1
- package/dist/modules/workflows/data/validators.js.map +2 -2
- package/dist/modules/workflows/di.js +12 -0
- package/dist/modules/workflows/di.js.map +2 -2
- package/dist/modules/workflows/events.js +7 -1
- package/dist/modules/workflows/events.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +4 -2
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/activity-queue-types.js.map +2 -2
- package/dist/modules/workflows/lib/event-logger.js +2 -0
- package/dist/modules/workflows/lib/event-logger.js.map +2 -2
- package/dist/modules/workflows/lib/execution-token.js +98 -0
- package/dist/modules/workflows/lib/execution-token.js.map +7 -0
- package/dist/modules/workflows/lib/node-type-icons.js +14 -5
- package/dist/modules/workflows/lib/node-type-icons.js.map +2 -2
- package/dist/modules/workflows/lib/parallel-handler.js +364 -0
- package/dist/modules/workflows/lib/parallel-handler.js.map +7 -0
- package/dist/modules/workflows/lib/signal-handler.js +63 -1
- package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +74 -30
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +26 -0
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/timer-handler.js +26 -1
- package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +33 -21
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +39 -1
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/migrations/Migration20260602120000.js +24 -0
- package/dist/modules/workflows/migrations/Migration20260602120000.js.map +7 -0
- package/dist/modules/workflows/workers/workflow-activities.worker.js +8 -4
- package/dist/modules/workflows/workers/workflow-activities.worker.js.map +2 -2
- package/generated/entities/role/index.ts +1 -0
- package/generated/entities/step_instance/index.ts +1 -0
- package/generated/entities/user/index.ts +1 -0
- package/generated/entities/user_task/index.ts +1 -0
- package/generated/entities/workflow_branch_instance/index.ts +18 -0
- package/generated/entities/workflow_event/index.ts +1 -0
- package/generated/entities/workflow_instance/index.ts +1 -0
- package/generated/entities.ids.generated.ts +1 -0
- package/generated/entity-fields-registry.ts +26 -0
- package/jest.setup.ts +17 -0
- package/package.json +8 -7
- package/src/helpers/integration/optimisticLockUi.ts +172 -0
- package/src/helpers/integration/salesFixtures.ts +29 -0
- package/src/modules/api_keys/backend/api-keys/page.tsx +10 -5
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +19 -9
- package/src/modules/auth/api/roles/acl/route.ts +37 -11
- package/src/modules/auth/api/roles/route.ts +2 -0
- package/src/modules/auth/api/sidebar/preferences/route.ts +73 -0
- package/src/modules/auth/api/users/acl/route.ts +46 -18
- package/src/modules/auth/api/users/route.ts +2 -0
- package/src/modules/auth/backend/roles/[id]/edit/page.tsx +29 -4
- package/src/modules/auth/backend/roles/page.tsx +9 -4
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +37 -4
- package/src/modules/auth/backend/users/page.tsx +7 -2
- package/src/modules/auth/components/AclEditor.tsx +10 -1
- package/src/modules/auth/data/entities.ts +7 -1
- package/src/modules/auth/services/sidebarPreferencesService.ts +38 -4
- package/src/modules/business_rules/api/rules/route.ts +30 -0
- package/src/modules/business_rules/api/sets/route.ts +30 -0
- package/src/modules/business_rules/backend/rules/[id]/page.tsx +16 -4
- package/src/modules/business_rules/backend/rules/page.tsx +20 -11
- package/src/modules/business_rules/backend/sets/[id]/page.tsx +16 -4
- package/src/modules/business_rules/backend/sets/page.tsx +20 -11
- package/src/modules/catalog/api/categories/route.ts +3 -0
- package/src/modules/catalog/api/products/route.ts +4 -0
- package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +5 -0
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +112 -35
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +56 -7
- package/src/modules/catalog/backend/catalog/products/optionSchemaClient.ts +2 -0
- package/src/modules/catalog/commands/variants.ts +32 -32
- package/src/modules/catalog/components/PriceKindSettings.tsx +20 -7
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +1 -0
- package/src/modules/catalog/components/products/ProductMediaManager.tsx +2 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +8 -4
- package/src/modules/catalog/components/products/productForm.ts +3 -0
- package/src/modules/catalog/components/products/variantForm.ts +9 -0
- package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +5 -0
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +13 -6
- package/src/modules/currencies/backend/currencies/page.tsx +18 -11
- package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +3 -0
- package/src/modules/currencies/backend/exchange-rates/page.tsx +10 -6
- package/src/modules/currencies/commands/currencies.ts +10 -5
- package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +31 -21
- package/src/modules/customer_accounts/api/admin/roles/[id].ts +35 -5
- package/src/modules/customer_accounts/api/admin/roles.ts +2 -0
- package/src/modules/customer_accounts/api/admin/users/[id].ts +38 -5
- package/src/modules/customer_accounts/api/admin/users.ts +2 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +34 -20
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +9 -4
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.tsx +11 -4
- package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +28 -17
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +19 -11
- package/src/modules/customers/AGENTS.md +2 -2
- package/src/modules/customers/api/companies/route.ts +14 -1
- package/src/modules/customers/api/deals/route.ts +3 -0
- package/src/modules/customers/api/people/route.ts +12 -1
- package/src/modules/customers/api/todos/route.ts +1 -0
- package/src/modules/customers/backend/config/customers/deals/page.tsx +1 -0
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +36 -21
- package/src/modules/customers/backend/customers/companies/[id]/page.tsx +52 -27
- package/src/modules/customers/backend/customers/companies/page.tsx +2 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +27 -5
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.ts +39 -7
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -0
- package/src/modules/customers/backend/customers/deals/page.tsx +18 -6
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +64 -39
- package/src/modules/customers/backend/customers/people/[id]/page.tsx +46 -26
- package/src/modules/customers/backend/customers/people/page.tsx +2 -0
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +84 -24
- package/src/modules/customers/commands/addresses.ts +16 -14
- package/src/modules/customers/commands/companies.ts +3 -1
- package/src/modules/customers/commands/interactions.ts +50 -4
- package/src/modules/customers/commands/people.ts +2 -1
- package/src/modules/customers/commands/personCompanyLinks.ts +8 -5
- package/src/modules/customers/commands/pipeline-stages.ts +16 -16
- package/src/modules/customers/components/AddressFormatSettings.tsx +1 -0
- package/src/modules/customers/components/DictionarySettings.tsx +18 -13
- package/src/modules/customers/components/DictionarySortSettings.tsx +4 -0
- package/src/modules/customers/components/PipelineSettings.tsx +42 -21
- package/src/modules/customers/components/detail/ActivityTimeline.tsx +3 -3
- package/src/modules/customers/components/detail/AddressesSection.tsx +4 -0
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +2 -0
- package/src/modules/customers/components/detail/DealsSection.tsx +4 -0
- package/src/modules/customers/components/detail/EmailCardActions.tsx +5 -0
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +7 -0
- package/src/modules/customers/components/detail/ManageTagsDialog.tsx +4 -0
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +4 -0
- package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +2 -0
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +23 -7
- package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +25 -15
- package/src/modules/customers/components/detail/hooks/useInteractions.ts +76 -35
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +30 -17
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +2 -0
- package/src/modules/customers/components/detail/types.ts +1 -0
- package/src/modules/customers/components/formConfig.tsx +2 -0
- package/src/modules/customers/data/guards.ts +67 -0
- package/src/modules/customers/di.ts +66 -0
- package/src/modules/customers/i18n/de.json +2 -0
- package/src/modules/customers/i18n/en.json +2 -0
- package/src/modules/customers/i18n/es.json +2 -0
- package/src/modules/customers/i18n/pl.json +2 -0
- package/src/modules/customers/lib/todoCompatibility.ts +14 -0
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +2 -0
- package/src/modules/data_sync/api/options.ts +7 -4
- package/src/modules/data_sync/api/schedules/route.ts +9 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +18 -5
- package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +46 -19
- package/src/modules/data_sync/lib/sync-schedule-service.ts +11 -0
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +8 -1
- package/src/modules/dictionaries/api/[dictionaryId]/route.ts +23 -0
- package/src/modules/dictionaries/components/DictionariesManager.tsx +32 -9
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +30 -14
- package/src/modules/dictionaries/i18n/de.json +1 -0
- package/src/modules/dictionaries/i18n/en.json +1 -0
- package/src/modules/dictionaries/i18n/es.json +1 -0
- package/src/modules/dictionaries/i18n/pl.json +1 -0
- package/src/modules/directory/api/organizations/route.ts +3 -0
- package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +8 -0
- package/src/modules/directory/backend/directory/organizations/page.tsx +10 -5
- package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +16 -5
- package/src/modules/directory/backend/directory/tenants/page.tsx +8 -4
- package/src/modules/directory/commands/organizations.ts +7 -4
- package/src/modules/entities/api/records.ts +99 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.tsx +7 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +8 -4
- package/src/modules/entities/lib/helpers.ts +17 -0
- package/src/modules/feature_toggles/api/global/[id]/override/route.ts +1 -0
- package/src/modules/feature_toggles/api/overrides/route.ts +19 -0
- package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +19 -13
- package/src/modules/feature_toggles/components/FeatureToggleOverrideCard.tsx +22 -12
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +7 -2
- package/src/modules/feature_toggles/components/formConfig.tsx +2 -1
- package/src/modules/feature_toggles/components/overrideFormConfig.tsx +10 -1
- package/src/modules/feature_toggles/data/validators.ts +11 -3
- package/src/modules/inbox_ops/api/settings/route.ts +18 -0
- package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +15 -10
- package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +9 -4
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +20 -11
- package/src/modules/integrations/backend/integrations/page.tsx +13 -8
- package/src/modules/messages/commands/messages.ts +27 -15
- package/src/modules/perspectives/api/[tableId]/route.ts +11 -2
- package/src/modules/perspectives/services/perspectiveService.ts +13 -1
- package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +16 -14
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +6 -3
- package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +3 -0
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +58 -15
- package/src/modules/planner/components/AvailabilitySchedule.tsx +22 -7
- package/src/modules/progress/api/jobs/[id]/route.ts +7 -0
- package/src/modules/query_index/lib/engine.ts +34 -0
- package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +7 -1
- package/src/modules/resources/backend/resources/resource-types/page.tsx +6 -3
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +23 -3
- package/src/modules/resources/backend/resources/resources/page.tsx +15 -4
- package/src/modules/resources/components/ResourceCrudForm.tsx +3 -0
- package/src/modules/resources/components/ResourceTypeCrudForm.tsx +2 -0
- package/src/modules/sales/api/documents/factory.ts +13 -1
- package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +6 -0
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +10 -4
- package/src/modules/sales/backend/sales/channels/page.tsx +19 -4
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +73 -20
- package/src/modules/sales/backend/sales/documents/create/page.tsx +2 -0
- package/src/modules/sales/commands/documentAddresses.ts +226 -4
- package/src/modules/sales/commands/documents.ts +28 -0
- package/src/modules/sales/commands/returns.ts +12 -3
- package/src/modules/sales/commands/shared.ts +36 -0
- package/src/modules/sales/commands/shipments.ts +17 -1
- package/src/modules/sales/components/AdjustmentKindSettings.tsx +20 -11
- package/src/modules/sales/components/DocumentNumberSettings.tsx +1 -0
- package/src/modules/sales/components/OrderEditingSettings.tsx +1 -0
- package/src/modules/sales/components/PaymentMethodsSettings.tsx +12 -4
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +12 -4
- package/src/modules/sales/components/StatusSettings.tsx +20 -11
- package/src/modules/sales/components/TaxRatesSettings.tsx +12 -5
- package/src/modules/sales/components/channels/ChannelOfferForm.tsx +67 -14
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +7 -4
- package/src/modules/sales/components/documents/AddressesSection.tsx +35 -25
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +50 -25
- package/src/modules/sales/components/documents/ItemsSection.tsx +24 -13
- package/src/modules/sales/components/documents/LineItemDialog.tsx +26 -9
- package/src/modules/sales/components/documents/PaymentDialog.tsx +33 -14
- package/src/modules/sales/components/documents/PaymentsSection.tsx +22 -10
- package/src/modules/sales/components/documents/ReturnDialog.tsx +28 -17
- package/src/modules/sales/components/documents/ReturnsSection.tsx +4 -1
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +11 -4
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +23 -8
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +20 -10
- package/src/modules/sales/components/documents/optimisticLock.ts +34 -0
- package/src/modules/sales/components/documents/shipmentTypes.ts +1 -0
- package/src/modules/sales/di.ts +35 -0
- package/src/modules/sales/i18n/de.json +3 -0
- package/src/modules/sales/i18n/en.json +3 -0
- package/src/modules/sales/i18n/es.json +3 -0
- package/src/modules/sales/i18n/pl.json +3 -0
- package/src/modules/shipping_carriers/api/cancel/route.ts +2 -2
- package/src/modules/shipping_carriers/lib/status-sync.ts +19 -0
- package/src/modules/staff/api/job-histories.ts +12 -2
- package/src/modules/staff/api/timesheets/time-entries/route.ts +16 -4
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +12 -7
- package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +2 -0
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +16 -5
- package/src/modules/staff/backend/staff/team-members/page.tsx +6 -2
- package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +8 -0
- package/src/modules/staff/backend/staff/team-roles/page.tsx +6 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +13 -3
- package/src/modules/staff/backend/staff/teams/page.tsx +9 -3
- package/src/modules/staff/backend/staff/timesheets/page.tsx +10 -1
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -0
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +9 -3
- package/src/modules/staff/commands/job-histories.ts +42 -3
- package/src/modules/staff/components/LeaveRequestForm.tsx +2 -0
- package/src/modules/staff/components/TeamForm.tsx +2 -0
- package/src/modules/staff/components/TeamMemberForm.tsx +2 -0
- package/src/modules/staff/components/TeamRoleForm.tsx +2 -0
- package/src/modules/staff/components/detail/JobHistorySection.tsx +28 -6
- package/src/modules/staff/data/validators.ts +6 -0
- package/src/modules/staff/i18n/de.json +1 -0
- package/src/modules/staff/i18n/en.json +1 -0
- package/src/modules/staff/i18n/es.json +1 -0
- package/src/modules/staff/i18n/pl.json +1 -0
- package/src/modules/staff/lib/leaveRequestHelpers.ts +4 -0
- package/src/modules/translations/components/TranslationManager.tsx +13 -8
- package/src/modules/workflows/api/definitions/[id]/route.ts +112 -0
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +20 -4
- package/src/modules/workflows/backend/definitions/page.tsx +20 -9
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +29 -16
- package/src/modules/workflows/components/NodeEditDialog.tsx +2 -0
- package/src/modules/workflows/components/WorkflowGraphImpl.tsx +3 -1
- package/src/modules/workflows/components/formConfig.tsx +5 -0
- package/src/modules/workflows/components/nodes/ParallelForkNode.tsx +66 -0
- package/src/modules/workflows/components/nodes/ParallelJoinNode.tsx +66 -0
- package/src/modules/workflows/components/nodes/index.ts +6 -0
- package/src/modules/workflows/data/entities.ts +109 -0
- package/src/modules/workflows/data/validators.ts +223 -0
- package/src/modules/workflows/di.ts +20 -0
- package/src/modules/workflows/events.ts +7 -0
- package/src/modules/workflows/i18n/de.json +13 -0
- package/src/modules/workflows/i18n/en.json +13 -0
- package/src/modules/workflows/i18n/es.json +13 -0
- package/src/modules/workflows/i18n/pl.json +13 -0
- package/src/modules/workflows/lib/activity-executor.ts +8 -2
- package/src/modules/workflows/lib/activity-queue-types.ts +3 -0
- package/src/modules/workflows/lib/event-logger.ts +3 -0
- package/src/modules/workflows/lib/execution-token.ts +166 -0
- package/src/modules/workflows/lib/node-type-icons.ts +11 -2
- package/src/modules/workflows/lib/parallel-handler.ts +575 -0
- package/src/modules/workflows/lib/signal-handler.ts +72 -1
- package/src/modules/workflows/lib/step-handler.ts +94 -34
- package/src/modules/workflows/lib/task-handler.ts +32 -0
- package/src/modules/workflows/lib/timer-handler.ts +30 -1
- package/src/modules/workflows/lib/transition-handler.ts +56 -24
- package/src/modules/workflows/lib/workflow-executor.ts +53 -1
- package/src/modules/workflows/migrations/.snapshot-open-mercato.json +263 -0
- package/src/modules/workflows/migrations/Migration20260602120000.ts +25 -0
- package/src/modules/workflows/workers/workflow-activities.worker.ts +9 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/catalog/api/products/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from \"zod\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport { makeCrudRoute } from \"@open-mercato/shared/lib/crud/factory\";\nimport { CrudHttpError } from \"@open-mercato/shared/lib/crud/errors\";\nimport {\n buildCustomFieldFiltersFromQuery,\n extractAllCustomFieldEntries,\n} from \"@open-mercato/shared/lib/crud/custom-fields\";\nimport { resolveTranslations } from \"@open-mercato/shared/lib/i18n/server\";\nimport {\n CatalogOffer,\n CatalogProduct,\n CatalogProductCategory,\n CatalogProductCategoryAssignment,\n CatalogProductPrice,\n CatalogProductUnitConversion,\n CatalogProductVariant,\n CatalogProductTagAssignment,\n} from \"../../data/entities\";\nimport { CATALOG_PRODUCT_TYPES } from \"../../data/types\";\nimport type { CatalogProductType } from \"../../data/types\";\nimport {\n productCreateSchema,\n productUpdateSchema,\n} from \"../../data/validators\";\nimport { parseScopedCommandInput, resolveCrudRecordId } from \"../utils\";\nimport { splitCustomFieldPayload } from \"@open-mercato/shared/lib/crud/custom-fields\";\nimport { E } from \"#generated/entities.ids.generated\";\nimport * as F from \"#generated/entities/catalog_product\";\nimport { parseBooleanFlag, sanitizeSearchTerm } from \"../helpers\";\nimport { escapeLikePattern } from \"@open-mercato/shared/lib/db/escapeLikePattern\";\nimport type { CrudCtx } from \"@open-mercato/shared/lib/crud/factory\";\nimport { buildScopedWhere } from \"@open-mercato/shared/lib/api/crud\";\nimport {\n resolvePriceChannelId,\n resolvePriceOfferId,\n resolvePriceVariantId,\n resolvePriceKindCode,\n type PricingContext,\n type PriceRow,\n} from \"../../lib/pricing\";\nimport type { CatalogPricingService } from \"../../services/catalogPricingService\";\nimport { fieldsetCodeRegex } from \"@open-mercato/core/modules/entities/data/validators\";\nimport { SalesChannel } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from \"../openapi\";\nimport { findWithDecryption } from \"@open-mercato/shared/lib/encryption/find\";\nimport { canonicalizeUnitCode, toUnitLookupKey } from \"../../lib/unitCodes\";\nconst rawBodySchema = z.object({}).passthrough();\n\nconst UUID_REGEX =\n /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n status: z.string().optional(),\n isActive: z.string().optional(),\n configurable: z.string().optional(),\n productType: z.enum(CATALOG_PRODUCT_TYPES).optional(),\n channelIds: z.string().optional(),\n channelId: z.string().uuid().optional(),\n categoryIds: z.string().optional(),\n tagIds: z.string().optional(),\n offerId: z.string().uuid().optional(),\n userId: z.string().uuid().optional(),\n userGroupId: z.string().uuid().optional(),\n customerId: z.string().uuid().optional(),\n customerGroupId: z.string().uuid().optional(),\n quantity: z.coerce.number().min(1).max(100000).optional(),\n quantityUnit: z.string().trim().max(50).optional(),\n priceDate: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum([\"asc\", \"desc\"]).optional(),\n withDeleted: z.coerce.boolean().optional(),\n customFieldset: z.string().regex(fieldsetCodeRegex).optional(),\n })\n .passthrough();\n\ntype ProductsQuery = z.infer<typeof listSchema>;\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: [\"catalog.products.view\"] },\n POST: { requireAuth: true, requireFeatures: [\"catalog.products.manage\"] },\n PUT: { requireAuth: true, requireFeatures: [\"catalog.products.manage\"] },\n DELETE: { requireAuth: true, requireFeatures: [\"catalog.products.manage\"] },\n};\n\nexport const metadata = routeMetadata;\n\nexport function parseIdList(raw?: string): string[] {\n if (!raw) return [];\n return raw\n .split(\",\")\n .map((value) => value.trim())\n .filter((value) => UUID_REGEX.test(value));\n}\n\nexport async function buildProductFilters(\n query: ProductsQuery,\n ctx: CrudCtx,\n): Promise<Record<string, unknown>> {\n const filters: Record<string, unknown> = {};\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const restrictedProductIds: { value: Set<string> | null } = { value: null };\n\n const intersectProductIds = (ids: string[]) => {\n const normalized = ids.filter(\n (id): id is string => typeof id === \"string\" && id.trim().length > 0,\n );\n const current = new Set(normalized);\n if (!current.size) {\n restrictedProductIds.value = new Set();\n return;\n }\n if (!restrictedProductIds.value) {\n restrictedProductIds.value = current;\n return;\n }\n restrictedProductIds.value = new Set(\n Array.from(restrictedProductIds.value).filter((id) => current.has(id)),\n );\n };\n\n const applyRestrictedProducts = () => {\n if (!restrictedProductIds.value) return;\n if (restrictedProductIds.value.size === 0) {\n filters.id = { $eq: \"00000000-0000-0000-0000-000000000000\" };\n return;\n }\n const ids = Array.from(restrictedProductIds.value);\n const existing = filters.id as Record<string, unknown> | undefined;\n if (existing && typeof existing === \"object\") {\n if (\n \"$eq\" in existing &&\n typeof (existing as { $eq?: unknown }).$eq === \"string\"\n ) {\n const target = (existing as { $eq: string }).$eq;\n if (!restrictedProductIds.value.has(target)) {\n filters.id = { $eq: \"00000000-0000-0000-0000-000000000000\" };\n }\n return;\n }\n if (\n \"$in\" in existing &&\n Array.isArray((existing as { $in?: unknown }).$in)\n ) {\n const subset = (existing as { $in: string[] }).$in.filter((id) =>\n restrictedProductIds.value!.has(id),\n );\n filters.id = subset.length\n ? { $in: subset }\n : { $eq: \"00000000-0000-0000-0000-000000000000\" };\n return;\n }\n }\n filters.id = ids.length === 1 ? { $eq: ids[0] } : { $in: ids };\n };\n if (query.id) {\n filters.id = { $eq: query.id };\n }\n if (query.status && query.status.trim()) {\n filters.status_entry_id = { $eq: query.status.trim() };\n }\n const active = parseBooleanFlag(query.isActive);\n if (active !== undefined) {\n filters.is_active = active;\n }\n const configurable = parseBooleanFlag(query.configurable);\n if (configurable !== undefined) {\n filters.is_configurable = configurable;\n }\n if (query.productType) {\n filters.product_type = { $eq: query.productType };\n }\n const scope = {\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n tenantId: ctx.auth?.tenantId ?? null,\n };\n const term = sanitizeSearchTerm(query.search);\n if (term) {\n const like = `%${escapeLikePattern(term)}%`;\n const searchMatches = await findWithDecryption(\n em,\n CatalogProduct,\n {\n ...scope,\n ...(query.withDeleted ? {} : { deletedAt: null }),\n $or: [\n { title: { $ilike: like } },\n { subtitle: { $ilike: like } },\n { description: { $ilike: like } },\n { sku: { $ilike: like } },\n { handle: { $ilike: like } },\n ],\n },\n { fields: [\"id\"] },\n scope,\n );\n const productIds = searchMatches\n .map((product) => product.id)\n .filter((id): id is string => typeof id === \"string\" && id.length > 0);\n intersectProductIds(productIds);\n }\n\n const channelFilterIds = parseIdList(query.channelIds);\n if (channelFilterIds.length) {\n const offerRows = await findWithDecryption(\n em,\n CatalogOffer,\n {\n channelId: { $in: channelFilterIds },\n deletedAt: null,\n ...scope,\n },\n { fields: [\"id\", \"product\"] },\n scope,\n );\n const productIds = offerRows\n .map((offer) =>\n typeof offer.product === \"string\"\n ? offer.product\n : (offer.product?.id ?? null),\n )\n .filter((id): id is string => !!id);\n intersectProductIds(productIds);\n }\n\n const categoryFilterIds = parseIdList(query.categoryIds);\n if (categoryFilterIds.length) {\n const assignments = await findWithDecryption(\n em,\n CatalogProductCategoryAssignment,\n { category: { $in: categoryFilterIds }, ...scope },\n { fields: [\"id\", \"product\"] },\n scope,\n );\n const productIds = assignments\n .map((assignment) =>\n typeof assignment.product === \"string\"\n ? assignment.product\n : (assignment.product?.id ?? null),\n )\n .filter((id): id is string => !!id);\n intersectProductIds(productIds);\n }\n\n const tagFilterIds = parseIdList(query.tagIds);\n if (tagFilterIds.length) {\n const assignments = await findWithDecryption(\n em,\n CatalogProductTagAssignment,\n { tag: { $in: tagFilterIds }, ...scope },\n { fields: [\"id\", \"product\"] },\n scope,\n );\n const productIds = assignments\n .map((assignment) =>\n typeof assignment.product === \"string\"\n ? assignment.product\n : (assignment.product?.id ?? null),\n )\n .filter((id): id is string => !!id);\n intersectProductIds(productIds);\n }\n const customFieldset =\n typeof query.customFieldset === \"string\" &&\n query.customFieldset.trim().length\n ? query.customFieldset.trim()\n : null;\n const tenantId = ctx.auth?.tenantId ?? null;\n try {\n const scopedEm = ctx.container.resolve(\"em\") as EntityManager;\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.catalog.catalog_product],\n query,\n em: scopedEm,\n tenantId,\n fieldset: customFieldset ?? undefined,\n });\n Object.assign(filters, cfFilters);\n } catch (err) {\n // Custom field filter parsing may fail for non-existent or misconfigured fields.\n // Fall back to base filters to avoid blocking the product listing.\n if (process.env.NODE_ENV === 'development') console.warn('[catalog:products] custom field filter error', err);\n }\n applyRestrictedProducts();\n return filters;\n}\n\nexport function buildPricingContext(\n query: ProductsQuery,\n channelFallback: string | null,\n): PricingContext {\n const quantity = Number.isFinite(Number(query.quantity))\n ? Number(query.quantity)\n : 1;\n const parsedDate = query.priceDate ? new Date(query.priceDate) : new Date();\n const channelId = query.channelId ?? channelFallback ?? null;\n return {\n channelId,\n offerId: query.offerId ?? null,\n userId: query.userId ?? null,\n userGroupId: query.userGroupId ?? null,\n customerId: query.customerId ?? null,\n customerGroupId: query.customerGroupId ?? null,\n quantity: Number.isFinite(quantity) && quantity > 0 ? quantity : 1,\n date: Number.isNaN(parsedDate.getTime()) ? new Date() : parsedDate,\n };\n}\n\ntype ProductListItem = Record<string, unknown> & {\n id?: string;\n title?: string | null;\n subtitle?: string | null;\n description?: string | null;\n sku?: string | null;\n handle?: string | null;\n product_type?: CatalogProductType | null;\n primary_currency_code?: string | null;\n default_unit?: string | null;\n default_sales_unit?: string | null;\n default_sales_unit_quantity?: number | null;\n uom_rounding_scale?: number | null;\n uom_rounding_mode?: \"half_up\" | \"down\" | \"up\" | null;\n unit_price_enabled?: boolean | null;\n unit_price_reference_unit?: \"kg\" | \"l\" | \"m2\" | \"m3\" | \"pc\" | null;\n unit_price_base_quantity?: number | null;\n default_media_id?: string | null;\n default_media_url?: string | null;\n weight_value?: string | null;\n weightValue?: string | null;\n weight_unit?: string | null;\n weightUnit?: string | null;\n dimensions?: Record<string, unknown> | null;\n custom_fieldset_code?: string | null;\n option_schema_id?: string | null;\n offers?: Array<Record<string, unknown>>;\n channelIds?: string[];\n categories?: Array<Record<string, unknown>>;\n categoryIds?: string[];\n tags?: string[];\n};\n\nasync function decorateProductsAfterList(\n payload: { items?: ProductListItem[] },\n ctx: CrudCtx & { query: ProductsQuery },\n): Promise<void> {\n const items = Array.isArray(payload?.items) ? payload.items : [];\n if (!items.length) return;\n const productIds = items\n .map((item) => (typeof item.id === \"string\" ? item.id : null))\n .filter((id): id is string => !!id);\n if (!productIds.length) return;\n try {\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const scope = {\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n tenantId: ctx.auth?.tenantId ?? null,\n };\n const offers = await findWithDecryption(\n em,\n CatalogOffer,\n { product: { $in: productIds }, deletedAt: null, ...scope },\n { orderBy: { createdAt: \"asc\" } },\n scope,\n );\n const channelIds = Array.from(\n new Set(\n offers\n .map((offer) => offer.channelId)\n .filter(\n (id): id is string => typeof id === \"string\" && id.length > 0,\n ),\n ),\n );\n const channelLookup = new Map<\n string,\n { name?: string | null; code?: string | null }\n >();\n if (channelIds.length) {\n const scopedChannelsWhere = buildScopedWhere(\n { id: { $in: channelIds } },\n {\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n organizationIds: Array.isArray(ctx.organizationIds)\n ? ctx.organizationIds\n : undefined,\n tenantId: ctx.auth?.tenantId ?? null,\n },\n );\n const channels = await findWithDecryption(em, SalesChannel, scopedChannelsWhere, {\n fields: [\"id\", \"name\", \"code\"],\n });\n for (const channel of channels) {\n channelLookup.set(channel.id, {\n name: channel.name,\n code: channel.code ?? null,\n });\n }\n }\n const offersByProduct = new Map<string, Array<Record<string, unknown>>>();\n for (const offer of offers) {\n const productId =\n typeof offer.product === \"string\"\n ? offer.product\n : (offer.product?.id ?? null);\n if (!productId) continue;\n const channelInfo = channelLookup.get(offer.channelId);\n const entry = offersByProduct.get(productId) ?? [];\n entry.push({\n id: offer.id,\n channelId: offer.channelId,\n channelName: channelInfo?.name ?? null,\n channelCode: channelInfo?.code ?? null,\n title: offer.title,\n description: offer.description ?? null,\n isActive: offer.isActive,\n defaultMediaId: offer.defaultMediaId ?? null,\n defaultMediaUrl: offer.defaultMediaUrl ?? null,\n metadata: offer.metadata ?? null,\n });\n offersByProduct.set(productId, entry);\n }\n\n const categoryAssignments = await findWithDecryption(\n em,\n CatalogProductCategoryAssignment,\n { product: { $in: productIds }, ...scope },\n { populate: [\"category\"], orderBy: { position: \"asc\" } },\n scope,\n );\n const parentIds = new Set<string>();\n for (const assignment of categoryAssignments) {\n const category =\n typeof assignment.category === \"string\"\n ? null\n : (assignment.category ?? null);\n if (!category) continue;\n const parentId = category.parentId ?? null;\n if (parentId) parentIds.add(parentId);\n }\n const parentCategories = parentIds.size\n ? await findWithDecryption(\n em,\n CatalogProductCategory,\n { id: { $in: Array.from(parentIds) }, ...scope },\n { fields: [\"id\", \"name\"] },\n scope,\n )\n : [];\n const parentNameById = new Map<string, string | null>();\n for (const parent of parentCategories) {\n parentNameById.set(parent.id, parent.name ?? null);\n }\n const categoriesByProduct = new Map<\n string,\n Array<{\n id: string;\n name: string | null;\n treePath: string | null;\n parentId: string | null;\n parentName: string | null;\n }>\n >();\n for (const assignment of categoryAssignments) {\n const productId =\n typeof assignment.product === \"string\"\n ? assignment.product\n : (assignment.product?.id ?? null);\n if (!productId) continue;\n const category =\n typeof assignment.category === \"string\"\n ? null\n : (assignment.category ?? null);\n if (!category) continue;\n const parentId = category.parentId ?? null;\n const parentName = parentId\n ? (parentNameById.get(parentId) ?? null)\n : null;\n const bucket = categoriesByProduct.get(productId) ?? [];\n bucket.push({\n id: category.id,\n name: category.name ?? null,\n treePath: category.treePath ?? null,\n parentId,\n parentName,\n });\n categoriesByProduct.set(productId, bucket);\n }\n\n const tagAssignments = await findWithDecryption(\n em,\n CatalogProductTagAssignment,\n { product: { $in: productIds } },\n { populate: [\"tag\"] },\n {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.auth?.orgId ?? null,\n },\n );\n const tagsByProduct = new Map<string, string[]>();\n for (const assignment of tagAssignments) {\n const productId =\n typeof assignment.product === \"string\"\n ? assignment.product\n : (assignment.product?.id ?? null);\n if (!productId) continue;\n const tag =\n typeof assignment.tag === \"string\" ? null : (assignment.tag ?? null);\n if (!tag) continue;\n const label =\n typeof tag.label === \"string\" && tag.label.trim().length\n ? tag.label\n : null;\n if (!label) continue;\n const bucket = tagsByProduct.get(productId) ?? [];\n bucket.push(label);\n tagsByProduct.set(productId, bucket);\n }\n\n const variants = await findWithDecryption(\n em,\n CatalogProductVariant,\n { product: { $in: productIds }, deletedAt: null, ...scope },\n { fields: [\"id\", \"product\"] },\n scope,\n );\n const variantToProduct = new Map<string, string>();\n for (const variant of variants) {\n const productId =\n typeof variant.product === \"string\"\n ? variant.product\n : (variant.product?.id ?? null);\n if (!productId) continue;\n variantToProduct.set(variant.id, productId);\n }\n const variantIds = Array.from(variantToProduct.keys());\n const priceWhere =\n variantIds.length > 0\n ? {\n $or: [\n { product: { $in: productIds } },\n { variant: { $in: variantIds } },\n ],\n }\n : { product: { $in: productIds } };\n const priceRows = await findWithDecryption(\n em,\n CatalogProductPrice,\n { ...priceWhere, ...scope },\n { populate: [\"offer\", \"variant\", \"product\", \"priceKind\"] },\n scope,\n );\n const pricesByProduct = new Map<string, PriceRow[]>();\n for (const price of priceRows) {\n let productId: string | null = null;\n if (price.product) {\n productId =\n typeof price.product === \"string\"\n ? price.product\n : (price.product?.id ?? null);\n } else if (price.variant) {\n const variantId =\n typeof price.variant === \"string\" ? price.variant : price.variant.id;\n productId = variantToProduct.get(variantId) ?? null;\n }\n if (!productId) continue;\n const entry = pricesByProduct.get(productId) ?? [];\n entry.push(price);\n pricesByProduct.set(productId, entry);\n }\n\n const requestQuantityUnitKey = toUnitLookupKey(\n ctx.query.quantityUnit,\n );\n const conversionsByProduct = new Map<string, Map<string, number>>();\n const conversionOrganizationId =\n ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;\n const conversionTenantId = ctx.auth?.tenantId ?? null;\n if (\n requestQuantityUnitKey &&\n productIds.length &&\n conversionOrganizationId &&\n conversionTenantId\n ) {\n const conversionRows = await findWithDecryption(\n em,\n CatalogProductUnitConversion,\n {\n product: { $in: productIds },\n organizationId: conversionOrganizationId,\n tenantId: conversionTenantId,\n deletedAt: null,\n isActive: true,\n },\n { fields: [\"id\", \"product\", \"unitCode\", \"toBaseFactor\"] },\n { organizationId: conversionOrganizationId, tenantId: conversionTenantId },\n );\n for (const row of conversionRows) {\n const productId =\n typeof row.product === \"string\"\n ? row.product\n : (row.product?.id ?? null);\n const unitKey = toUnitLookupKey(row.unitCode);\n const factor = Number(row.toBaseFactor);\n if (!productId || !unitKey || !Number.isFinite(factor) || factor <= 0)\n continue;\n const bucket =\n conversionsByProduct.get(productId) ?? new Map<string, number>();\n bucket.set(unitKey, factor);\n conversionsByProduct.set(productId, bucket);\n }\n }\n\n const channelFilterIds = parseIdList(ctx.query.channelIds);\n const channelContext =\n ctx.query.channelId ??\n (channelFilterIds.length === 1 ? channelFilterIds[0] : null);\n const pricingContext = buildPricingContext(ctx.query, channelContext);\n const pricingService = ctx.container.resolve<CatalogPricingService>(\n \"catalogPricingService\",\n );\n\n const pricingEntries: Array<{ rows: PriceRow[]; context: PricingContext } | null> = [];\n for (const item of items) {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (!id) {\n pricingEntries.push(null);\n continue;\n }\n const offerEntries = offersByProduct.get(id) ?? [];\n item.offers = offerEntries;\n const channelIds = Array.from(\n new Set(\n offerEntries\n .map((offer) =>\n typeof offer.channelId === \"string\" ? offer.channelId : null,\n )\n .filter((channelId): channelId is string => !!channelId),\n ),\n );\n item.channelIds = channelIds;\n const categories = categoriesByProduct.get(id) ?? [];\n item.categories = categories;\n item.categoryIds = categories.map((category) => category.id);\n item.tags = tagsByProduct.get(id) ?? [];\n const priceCandidates = pricesByProduct.get(id) ?? [];\n const normalizedQuantityForPricing = (() => {\n if (!requestQuantityUnitKey) return pricingContext.quantity;\n const baseUnit = toUnitLookupKey(item.default_unit);\n if (!baseUnit || requestQuantityUnitKey === baseUnit)\n return pricingContext.quantity;\n const productConversions = conversionsByProduct.get(id);\n const factor = productConversions?.get(requestQuantityUnitKey) ?? null;\n if (!factor || !Number.isFinite(factor) || factor <= 0) {\n if (process.env.NODE_ENV === 'development') console.warn(`[catalog.products] Invalid conversion factor for product=${id} unit=${requestQuantityUnitKey} factor=${factor}`);\n return pricingContext.quantity;\n }\n const normalized = pricingContext.quantity * factor;\n return Number.isFinite(normalized) && normalized > 0\n ? normalized\n : pricingContext.quantity;\n })();\n const channelScopedContext =\n pricingContext.channelId || channelIds.length !== 1\n ? pricingContext\n : { ...pricingContext, channelId: channelIds[0] };\n pricingEntries.push({\n rows: priceCandidates,\n context: { ...channelScopedContext, quantity: normalizedQuantityForPricing },\n });\n }\n\n const resolveInputs: Array<{ rows: PriceRow[]; context: PricingContext }> = [];\n const resolveIndices: number[] = [];\n for (let i = 0; i < pricingEntries.length; i++) {\n if (pricingEntries[i] !== null) {\n resolveInputs.push(pricingEntries[i]!);\n resolveIndices.push(i);\n }\n }\n const priceResults = await pricingService.resolvePriceMany(resolveInputs);\n\n for (let i = 0; i < resolveIndices.length; i++) {\n const item = items[resolveIndices[i]];\n const best = priceResults[i];\n if (best) {\n item.pricing = {\n kind: resolvePriceKindCode(best),\n price_kind_id:\n typeof best.priceKind === \"string\"\n ? best.priceKind\n : (best.priceKind?.id ?? null),\n price_kind_code: resolvePriceKindCode(best),\n currency_code: best.currencyCode,\n unit_price_net: best.unitPriceNet,\n unit_price_gross: best.unitPriceGross,\n min_quantity: best.minQuantity,\n max_quantity: best.maxQuantity ?? null,\n tax_rate: best.taxRate ?? null,\n tax_amount: best.taxAmount ?? null,\n scope: {\n variant_id: resolvePriceVariantId(best),\n offer_id: resolvePriceOfferId(best),\n channel_id: resolvePriceChannelId(best),\n user_id: best.userId ?? null,\n user_group_id: best.userGroupId ?? null,\n customer_id: best.customerId ?? null,\n customer_group_id: best.customerGroupId ?? null,\n },\n };\n } else {\n item.pricing = null;\n }\n }\n } catch (error) {\n console.error(\"[decorateProductsAfterList] Failed to load unit conversions\", error);\n }\n\n const searchTerm = ctx.query.search ? sanitizeSearchTerm(ctx.query.search) : null;\n if (searchTerm && !ctx.query.sortField && Array.isArray(payload.items)) {\n const needle = searchTerm.toLowerCase();\n payload.items.sort((a, b) => {\n const scoreA = scoreProductSearchRelevance(needle, a.title, a.sku);\n const scoreB = scoreProductSearchRelevance(needle, b.title, b.sku);\n if (scoreA !== scoreB) return scoreA - scoreB;\n return (a.title ?? \"\").localeCompare(b.title ?? \"\");\n });\n }\n}\n\nexport function scoreProductSearchRelevance(\n needle: string,\n title: string | null | undefined,\n sku: string | null | undefined,\n): number {\n const t = (title ?? \"\").toLowerCase();\n const s = (sku ?? \"\").toLowerCase();\n if (t === needle) return 0;\n if (s === needle) return 1;\n if (t.startsWith(needle)) return 2;\n if (s.startsWith(needle)) return 3;\n if (t.includes(needle)) return 4;\n if (s.includes(needle)) return 5;\n return 6;\n}\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogProduct,\n idField: \"id\",\n orgField: \"organizationId\",\n tenantField: \"tenantId\",\n softDeleteField: \"deletedAt\",\n },\n indexer: {\n entityType: E.catalog.catalog_product,\n },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_product,\n fields: [\n F.id,\n F.title,\n F.subtitle,\n F.description,\n F.sku,\n F.handle,\n \"tax_rate_id\",\n \"tax_rate\",\n F.product_type,\n F.status_entry_id,\n F.primary_currency_code,\n F.default_unit,\n \"default_sales_unit\",\n \"default_sales_unit_quantity\",\n \"uom_rounding_scale\",\n \"uom_rounding_mode\",\n \"unit_price_enabled\",\n \"unit_price_reference_unit\",\n \"unit_price_base_quantity\",\n F.default_media_id,\n F.default_media_url,\n F.weight_value,\n F.weight_unit,\n F.dimensions,\n F.is_configurable,\n F.is_active,\n F.metadata,\n \"custom_fieldset_code\",\n \"option_schema_id\",\n F.created_at,\n F.updated_at,\n ],\n decorateCustomFields: { entityIds: [E.catalog.catalog_product] },\n sortFieldMap: {\n title: F.title,\n sku: F.sku,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n buildFilters: buildProductFilters,\n transformItem: (item: ProductListItem | null | undefined) => {\n if (!item) return item;\n const normalized = { ...item };\n const cfEntries = extractAllCustomFieldEntries(item);\n for (const key of Object.keys(normalized)) {\n if (key.startsWith(\"cf:\")) {\n delete normalized[key];\n }\n }\n const defaultUnit = canonicalizeUnitCode(normalized.default_unit) ?? null;\n const defaultSalesUnit =\n canonicalizeUnitCode(normalized.default_sales_unit) ?? null;\n const unitPriceReferenceUnit =\n canonicalizeUnitCode(normalized.unit_price_reference_unit) ?? null;\n return {\n ...normalized,\n default_unit: defaultUnit,\n default_sales_unit: defaultSalesUnit,\n unit_price_reference_unit: unitPriceReferenceUnit,\n ...cfEntries,\n unit_price: {\n enabled: Boolean(normalized.unit_price_enabled),\n reference_unit: unitPriceReferenceUnit,\n base_quantity: normalized.unit_price_base_quantity ?? null,\n },\n };\n },\n },\n hooks: {\n afterList: decorateProductsAfterList,\n },\n actions: {\n create: {\n commandId: \"catalog.products.create\",\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations();\n const parsed = parseScopedCommandInput(\n productCreateSchema,\n raw ?? {},\n ctx,\n translate,\n );\n const { base, custom } = splitCustomFieldPayload(parsed);\n return Object.keys(custom).length\n ? { ...base, customFields: custom }\n : base;\n },\n response: ({ result }) => ({\n id: result?.productId ?? result?.id ?? null,\n }),\n status: 201,\n },\n update: {\n commandId: \"catalog.products.update\",\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations();\n const parsed = parseScopedCommandInput(\n productUpdateSchema,\n raw ?? {},\n ctx,\n translate,\n );\n const { base, custom } = splitCustomFieldPayload(parsed);\n return Object.keys(custom).length\n ? { ...base, customFields: custom }\n : base;\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: \"catalog.products.delete\",\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations();\n const id = resolveCrudRecordId(parsed, ctx, translate);\n if (!id)\n throw new CrudHttpError(400, {\n error: translate(\n \"catalog.errors.id_required\",\n \"Product id is required.\",\n ),\n });\n return { id };\n },\n response: () => ({ ok: true }),\n },\n },\n});\n\nexport const GET = crud.GET;\nexport const POST = crud.POST;\nexport const PUT = crud.PUT;\nexport const DELETE = crud.DELETE;\n\nconst productListItemSchema = z.object({\n id: z.string().uuid(),\n title: z.string().nullable().optional(),\n subtitle: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n sku: z.string().nullable().optional(),\n handle: z.string().nullable().optional(),\n product_type: z.string().nullable().optional(),\n status_entry_id: z.string().uuid().nullable().optional(),\n primary_currency_code: z.string().nullable().optional(),\n default_unit: z.string().nullable().optional(),\n default_sales_unit: z.string().nullable().optional(),\n default_sales_unit_quantity: z.number().nullable().optional(),\n uom_rounding_scale: z.number().nullable().optional(),\n uom_rounding_mode: z.enum([\"half_up\", \"down\", \"up\"]).nullable().optional(),\n unit_price_enabled: z.boolean().nullable().optional(),\n unit_price_reference_unit: z\n .enum([\"kg\", \"l\", \"m2\", \"m3\", \"pc\"])\n .nullable()\n .optional(),\n unit_price_base_quantity: z.number().nullable().optional(),\n unit_price: z\n .object({\n enabled: z.boolean(),\n reference_unit: z.enum([\"kg\", \"l\", \"m2\", \"m3\", \"pc\"]).nullable(),\n base_quantity: z.number().nullable(),\n })\n .optional(),\n default_media_id: z.string().uuid().nullable().optional(),\n default_media_url: z.string().nullable().optional(),\n weight_value: z.number().nullable().optional(),\n weight_unit: z.string().nullable().optional(),\n dimensions: z.record(z.string(), z.unknown()).nullable().optional(),\n is_configurable: z.boolean().nullable().optional(),\n is_active: z.boolean().nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n custom_fieldset_code: z.string().nullable().optional(),\n option_schema_id: z.string().uuid().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n offers: z.array(z.record(z.string(), z.unknown())).optional(),\n channelIds: z.array(z.string()).optional(),\n categories: z.array(z.record(z.string(), z.unknown())).optional(),\n categoryIds: z.array(z.string()).optional(),\n tags: z.array(z.string()).optional(),\n pricing: z.record(z.string(), z.unknown()).nullable().optional(),\n});\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: \"Product\",\n pluralName: \"Products\",\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(productListItemSchema),\n create: {\n schema: productCreateSchema,\n description: \"Creates a new product in the catalog.\",\n },\n update: {\n schema: productUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: \"Updates an existing product by id.\",\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: \"Deletes a product by id.\",\n },\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { z } from \"zod\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport { makeCrudRoute } from \"@open-mercato/shared/lib/crud/factory\";\nimport { CrudHttpError } from \"@open-mercato/shared/lib/crud/errors\";\nimport {\n buildCustomFieldFiltersFromQuery,\n extractAllCustomFieldEntries,\n} from \"@open-mercato/shared/lib/crud/custom-fields\";\nimport { resolveTranslations } from \"@open-mercato/shared/lib/i18n/server\";\nimport {\n CatalogOffer,\n CatalogProduct,\n CatalogProductCategory,\n CatalogProductCategoryAssignment,\n CatalogProductPrice,\n CatalogProductUnitConversion,\n CatalogProductVariant,\n CatalogProductTagAssignment,\n} from \"../../data/entities\";\nimport { CATALOG_PRODUCT_TYPES } from \"../../data/types\";\nimport type { CatalogProductType } from \"../../data/types\";\nimport {\n productCreateSchema,\n productUpdateSchema,\n} from \"../../data/validators\";\nimport { parseScopedCommandInput, resolveCrudRecordId } from \"../utils\";\nimport { splitCustomFieldPayload } from \"@open-mercato/shared/lib/crud/custom-fields\";\nimport { E } from \"#generated/entities.ids.generated\";\nimport * as F from \"#generated/entities/catalog_product\";\nimport { parseBooleanFlag, sanitizeSearchTerm } from \"../helpers\";\nimport { escapeLikePattern } from \"@open-mercato/shared/lib/db/escapeLikePattern\";\nimport type { CrudCtx } from \"@open-mercato/shared/lib/crud/factory\";\nimport { buildScopedWhere } from \"@open-mercato/shared/lib/api/crud\";\nimport {\n resolvePriceChannelId,\n resolvePriceOfferId,\n resolvePriceVariantId,\n resolvePriceKindCode,\n type PricingContext,\n type PriceRow,\n} from \"../../lib/pricing\";\nimport type { CatalogPricingService } from \"../../services/catalogPricingService\";\nimport { fieldsetCodeRegex } from \"@open-mercato/core/modules/entities/data/validators\";\nimport { SalesChannel } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from \"../openapi\";\nimport { findWithDecryption } from \"@open-mercato/shared/lib/encryption/find\";\nimport { canonicalizeUnitCode, toUnitLookupKey } from \"../../lib/unitCodes\";\nconst rawBodySchema = z.object({}).passthrough();\n\nconst UUID_REGEX =\n /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n status: z.string().optional(),\n isActive: z.string().optional(),\n configurable: z.string().optional(),\n productType: z.enum(CATALOG_PRODUCT_TYPES).optional(),\n channelIds: z.string().optional(),\n channelId: z.string().uuid().optional(),\n categoryIds: z.string().optional(),\n tagIds: z.string().optional(),\n offerId: z.string().uuid().optional(),\n userId: z.string().uuid().optional(),\n userGroupId: z.string().uuid().optional(),\n customerId: z.string().uuid().optional(),\n customerGroupId: z.string().uuid().optional(),\n quantity: z.coerce.number().min(1).max(100000).optional(),\n quantityUnit: z.string().trim().max(50).optional(),\n priceDate: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum([\"asc\", \"desc\"]).optional(),\n withDeleted: z.coerce.boolean().optional(),\n customFieldset: z.string().regex(fieldsetCodeRegex).optional(),\n })\n .passthrough();\n\ntype ProductsQuery = z.infer<typeof listSchema>;\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: [\"catalog.products.view\"] },\n POST: { requireAuth: true, requireFeatures: [\"catalog.products.manage\"] },\n PUT: { requireAuth: true, requireFeatures: [\"catalog.products.manage\"] },\n DELETE: { requireAuth: true, requireFeatures: [\"catalog.products.manage\"] },\n};\n\nexport const metadata = routeMetadata;\n\nexport function parseIdList(raw?: string): string[] {\n if (!raw) return [];\n return raw\n .split(\",\")\n .map((value) => value.trim())\n .filter((value) => UUID_REGEX.test(value));\n}\n\nexport async function buildProductFilters(\n query: ProductsQuery,\n ctx: CrudCtx,\n): Promise<Record<string, unknown>> {\n const filters: Record<string, unknown> = {};\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const restrictedProductIds: { value: Set<string> | null } = { value: null };\n\n const intersectProductIds = (ids: string[]) => {\n const normalized = ids.filter(\n (id): id is string => typeof id === \"string\" && id.trim().length > 0,\n );\n const current = new Set(normalized);\n if (!current.size) {\n restrictedProductIds.value = new Set();\n return;\n }\n if (!restrictedProductIds.value) {\n restrictedProductIds.value = current;\n return;\n }\n restrictedProductIds.value = new Set(\n Array.from(restrictedProductIds.value).filter((id) => current.has(id)),\n );\n };\n\n const applyRestrictedProducts = () => {\n if (!restrictedProductIds.value) return;\n if (restrictedProductIds.value.size === 0) {\n filters.id = { $eq: \"00000000-0000-0000-0000-000000000000\" };\n return;\n }\n const ids = Array.from(restrictedProductIds.value);\n const existing = filters.id as Record<string, unknown> | undefined;\n if (existing && typeof existing === \"object\") {\n if (\n \"$eq\" in existing &&\n typeof (existing as { $eq?: unknown }).$eq === \"string\"\n ) {\n const target = (existing as { $eq: string }).$eq;\n if (!restrictedProductIds.value.has(target)) {\n filters.id = { $eq: \"00000000-0000-0000-0000-000000000000\" };\n }\n return;\n }\n if (\n \"$in\" in existing &&\n Array.isArray((existing as { $in?: unknown }).$in)\n ) {\n const subset = (existing as { $in: string[] }).$in.filter((id) =>\n restrictedProductIds.value!.has(id),\n );\n filters.id = subset.length\n ? { $in: subset }\n : { $eq: \"00000000-0000-0000-0000-000000000000\" };\n return;\n }\n }\n filters.id = ids.length === 1 ? { $eq: ids[0] } : { $in: ids };\n };\n if (query.id) {\n filters.id = { $eq: query.id };\n }\n if (query.status && query.status.trim()) {\n filters.status_entry_id = { $eq: query.status.trim() };\n }\n const active = parseBooleanFlag(query.isActive);\n if (active !== undefined) {\n filters.is_active = active;\n }\n const configurable = parseBooleanFlag(query.configurable);\n if (configurable !== undefined) {\n filters.is_configurable = configurable;\n }\n if (query.productType) {\n filters.product_type = { $eq: query.productType };\n }\n const scope = {\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n tenantId: ctx.auth?.tenantId ?? null,\n };\n const term = sanitizeSearchTerm(query.search);\n if (term) {\n const like = `%${escapeLikePattern(term)}%`;\n const searchMatches = await findWithDecryption(\n em,\n CatalogProduct,\n {\n ...scope,\n ...(query.withDeleted ? {} : { deletedAt: null }),\n $or: [\n { title: { $ilike: like } },\n { subtitle: { $ilike: like } },\n { description: { $ilike: like } },\n { sku: { $ilike: like } },\n { handle: { $ilike: like } },\n ],\n },\n { fields: [\"id\"] },\n scope,\n );\n const productIds = searchMatches\n .map((product) => product.id)\n .filter((id): id is string => typeof id === \"string\" && id.length > 0);\n intersectProductIds(productIds);\n }\n\n const channelFilterIds = parseIdList(query.channelIds);\n if (channelFilterIds.length) {\n const offerRows = await findWithDecryption(\n em,\n CatalogOffer,\n {\n channelId: { $in: channelFilterIds },\n deletedAt: null,\n ...scope,\n },\n { fields: [\"id\", \"product\"] },\n scope,\n );\n const productIds = offerRows\n .map((offer) =>\n typeof offer.product === \"string\"\n ? offer.product\n : (offer.product?.id ?? null),\n )\n .filter((id): id is string => !!id);\n intersectProductIds(productIds);\n }\n\n const categoryFilterIds = parseIdList(query.categoryIds);\n if (categoryFilterIds.length) {\n const assignments = await findWithDecryption(\n em,\n CatalogProductCategoryAssignment,\n { category: { $in: categoryFilterIds }, ...scope },\n { fields: [\"id\", \"product\"] },\n scope,\n );\n const productIds = assignments\n .map((assignment) =>\n typeof assignment.product === \"string\"\n ? assignment.product\n : (assignment.product?.id ?? null),\n )\n .filter((id): id is string => !!id);\n intersectProductIds(productIds);\n }\n\n const tagFilterIds = parseIdList(query.tagIds);\n if (tagFilterIds.length) {\n const assignments = await findWithDecryption(\n em,\n CatalogProductTagAssignment,\n { tag: { $in: tagFilterIds }, ...scope },\n { fields: [\"id\", \"product\"] },\n scope,\n );\n const productIds = assignments\n .map((assignment) =>\n typeof assignment.product === \"string\"\n ? assignment.product\n : (assignment.product?.id ?? null),\n )\n .filter((id): id is string => !!id);\n intersectProductIds(productIds);\n }\n const customFieldset =\n typeof query.customFieldset === \"string\" &&\n query.customFieldset.trim().length\n ? query.customFieldset.trim()\n : null;\n const tenantId = ctx.auth?.tenantId ?? null;\n try {\n const scopedEm = ctx.container.resolve(\"em\") as EntityManager;\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.catalog.catalog_product],\n query,\n em: scopedEm,\n tenantId,\n fieldset: customFieldset ?? undefined,\n });\n Object.assign(filters, cfFilters);\n } catch (err) {\n // Custom field filter parsing may fail for non-existent or misconfigured fields.\n // Fall back to base filters to avoid blocking the product listing.\n if (process.env.NODE_ENV === 'development') console.warn('[catalog:products] custom field filter error', err);\n }\n applyRestrictedProducts();\n return filters;\n}\n\nexport function buildPricingContext(\n query: ProductsQuery,\n channelFallback: string | null,\n): PricingContext {\n const quantity = Number.isFinite(Number(query.quantity))\n ? Number(query.quantity)\n : 1;\n const parsedDate = query.priceDate ? new Date(query.priceDate) : new Date();\n const channelId = query.channelId ?? channelFallback ?? null;\n return {\n channelId,\n offerId: query.offerId ?? null,\n userId: query.userId ?? null,\n userGroupId: query.userGroupId ?? null,\n customerId: query.customerId ?? null,\n customerGroupId: query.customerGroupId ?? null,\n quantity: Number.isFinite(quantity) && quantity > 0 ? quantity : 1,\n date: Number.isNaN(parsedDate.getTime()) ? new Date() : parsedDate,\n };\n}\n\ntype ProductListItem = Record<string, unknown> & {\n id?: string;\n title?: string | null;\n subtitle?: string | null;\n description?: string | null;\n sku?: string | null;\n handle?: string | null;\n product_type?: CatalogProductType | null;\n primary_currency_code?: string | null;\n default_unit?: string | null;\n default_sales_unit?: string | null;\n default_sales_unit_quantity?: number | null;\n uom_rounding_scale?: number | null;\n uom_rounding_mode?: \"half_up\" | \"down\" | \"up\" | null;\n unit_price_enabled?: boolean | null;\n unit_price_reference_unit?: \"kg\" | \"l\" | \"m2\" | \"m3\" | \"pc\" | null;\n unit_price_base_quantity?: number | null;\n default_media_id?: string | null;\n default_media_url?: string | null;\n weight_value?: string | null;\n weightValue?: string | null;\n weight_unit?: string | null;\n weightUnit?: string | null;\n dimensions?: Record<string, unknown> | null;\n custom_fieldset_code?: string | null;\n option_schema_id?: string | null;\n offers?: Array<Record<string, unknown>>;\n channelIds?: string[];\n categories?: Array<Record<string, unknown>>;\n categoryIds?: string[];\n tags?: string[];\n};\n\nasync function decorateProductsAfterList(\n payload: { items?: ProductListItem[] },\n ctx: CrudCtx & { query: ProductsQuery },\n): Promise<void> {\n const items = Array.isArray(payload?.items) ? payload.items : [];\n if (!items.length) return;\n const productIds = items\n .map((item) => (typeof item.id === \"string\" ? item.id : null))\n .filter((id): id is string => !!id);\n if (!productIds.length) return;\n try {\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const scope = {\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n tenantId: ctx.auth?.tenantId ?? null,\n };\n const offers = await findWithDecryption(\n em,\n CatalogOffer,\n { product: { $in: productIds }, deletedAt: null, ...scope },\n { orderBy: { createdAt: \"asc\" } },\n scope,\n );\n const channelIds = Array.from(\n new Set(\n offers\n .map((offer) => offer.channelId)\n .filter(\n (id): id is string => typeof id === \"string\" && id.length > 0,\n ),\n ),\n );\n const channelLookup = new Map<\n string,\n { name?: string | null; code?: string | null }\n >();\n if (channelIds.length) {\n const scopedChannelsWhere = buildScopedWhere(\n { id: { $in: channelIds } },\n {\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n organizationIds: Array.isArray(ctx.organizationIds)\n ? ctx.organizationIds\n : undefined,\n tenantId: ctx.auth?.tenantId ?? null,\n },\n );\n const channels = await findWithDecryption(em, SalesChannel, scopedChannelsWhere, {\n fields: [\"id\", \"name\", \"code\"],\n });\n for (const channel of channels) {\n channelLookup.set(channel.id, {\n name: channel.name,\n code: channel.code ?? null,\n });\n }\n }\n const offersByProduct = new Map<string, Array<Record<string, unknown>>>();\n for (const offer of offers) {\n const productId =\n typeof offer.product === \"string\"\n ? offer.product\n : (offer.product?.id ?? null);\n if (!productId) continue;\n const channelInfo = channelLookup.get(offer.channelId);\n const entry = offersByProduct.get(productId) ?? [];\n entry.push({\n id: offer.id,\n channelId: offer.channelId,\n channelName: channelInfo?.name ?? null,\n channelCode: channelInfo?.code ?? null,\n title: offer.title,\n description: offer.description ?? null,\n isActive: offer.isActive,\n defaultMediaId: offer.defaultMediaId ?? null,\n defaultMediaUrl: offer.defaultMediaUrl ?? null,\n metadata: offer.metadata ?? null,\n updatedAt:\n offer.updatedAt instanceof Date\n ? offer.updatedAt.toISOString()\n : (typeof offer.updatedAt === \"string\" ? offer.updatedAt : null),\n });\n offersByProduct.set(productId, entry);\n }\n\n const categoryAssignments = await findWithDecryption(\n em,\n CatalogProductCategoryAssignment,\n { product: { $in: productIds }, ...scope },\n { populate: [\"category\"], orderBy: { position: \"asc\" } },\n scope,\n );\n const parentIds = new Set<string>();\n for (const assignment of categoryAssignments) {\n const category =\n typeof assignment.category === \"string\"\n ? null\n : (assignment.category ?? null);\n if (!category) continue;\n const parentId = category.parentId ?? null;\n if (parentId) parentIds.add(parentId);\n }\n const parentCategories = parentIds.size\n ? await findWithDecryption(\n em,\n CatalogProductCategory,\n { id: { $in: Array.from(parentIds) }, ...scope },\n { fields: [\"id\", \"name\"] },\n scope,\n )\n : [];\n const parentNameById = new Map<string, string | null>();\n for (const parent of parentCategories) {\n parentNameById.set(parent.id, parent.name ?? null);\n }\n const categoriesByProduct = new Map<\n string,\n Array<{\n id: string;\n name: string | null;\n treePath: string | null;\n parentId: string | null;\n parentName: string | null;\n }>\n >();\n for (const assignment of categoryAssignments) {\n const productId =\n typeof assignment.product === \"string\"\n ? assignment.product\n : (assignment.product?.id ?? null);\n if (!productId) continue;\n const category =\n typeof assignment.category === \"string\"\n ? null\n : (assignment.category ?? null);\n if (!category) continue;\n const parentId = category.parentId ?? null;\n const parentName = parentId\n ? (parentNameById.get(parentId) ?? null)\n : null;\n const bucket = categoriesByProduct.get(productId) ?? [];\n bucket.push({\n id: category.id,\n name: category.name ?? null,\n treePath: category.treePath ?? null,\n parentId,\n parentName,\n });\n categoriesByProduct.set(productId, bucket);\n }\n\n const tagAssignments = await findWithDecryption(\n em,\n CatalogProductTagAssignment,\n { product: { $in: productIds } },\n { populate: [\"tag\"] },\n {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.auth?.orgId ?? null,\n },\n );\n const tagsByProduct = new Map<string, string[]>();\n for (const assignment of tagAssignments) {\n const productId =\n typeof assignment.product === \"string\"\n ? assignment.product\n : (assignment.product?.id ?? null);\n if (!productId) continue;\n const tag =\n typeof assignment.tag === \"string\" ? null : (assignment.tag ?? null);\n if (!tag) continue;\n const label =\n typeof tag.label === \"string\" && tag.label.trim().length\n ? tag.label\n : null;\n if (!label) continue;\n const bucket = tagsByProduct.get(productId) ?? [];\n bucket.push(label);\n tagsByProduct.set(productId, bucket);\n }\n\n const variants = await findWithDecryption(\n em,\n CatalogProductVariant,\n { product: { $in: productIds }, deletedAt: null, ...scope },\n { fields: [\"id\", \"product\"] },\n scope,\n );\n const variantToProduct = new Map<string, string>();\n for (const variant of variants) {\n const productId =\n typeof variant.product === \"string\"\n ? variant.product\n : (variant.product?.id ?? null);\n if (!productId) continue;\n variantToProduct.set(variant.id, productId);\n }\n const variantIds = Array.from(variantToProduct.keys());\n const priceWhere =\n variantIds.length > 0\n ? {\n $or: [\n { product: { $in: productIds } },\n { variant: { $in: variantIds } },\n ],\n }\n : { product: { $in: productIds } };\n const priceRows = await findWithDecryption(\n em,\n CatalogProductPrice,\n { ...priceWhere, ...scope },\n { populate: [\"offer\", \"variant\", \"product\", \"priceKind\"] },\n scope,\n );\n const pricesByProduct = new Map<string, PriceRow[]>();\n for (const price of priceRows) {\n let productId: string | null = null;\n if (price.product) {\n productId =\n typeof price.product === \"string\"\n ? price.product\n : (price.product?.id ?? null);\n } else if (price.variant) {\n const variantId =\n typeof price.variant === \"string\" ? price.variant : price.variant.id;\n productId = variantToProduct.get(variantId) ?? null;\n }\n if (!productId) continue;\n const entry = pricesByProduct.get(productId) ?? [];\n entry.push(price);\n pricesByProduct.set(productId, entry);\n }\n\n const requestQuantityUnitKey = toUnitLookupKey(\n ctx.query.quantityUnit,\n );\n const conversionsByProduct = new Map<string, Map<string, number>>();\n const conversionOrganizationId =\n ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;\n const conversionTenantId = ctx.auth?.tenantId ?? null;\n if (\n requestQuantityUnitKey &&\n productIds.length &&\n conversionOrganizationId &&\n conversionTenantId\n ) {\n const conversionRows = await findWithDecryption(\n em,\n CatalogProductUnitConversion,\n {\n product: { $in: productIds },\n organizationId: conversionOrganizationId,\n tenantId: conversionTenantId,\n deletedAt: null,\n isActive: true,\n },\n { fields: [\"id\", \"product\", \"unitCode\", \"toBaseFactor\"] },\n { organizationId: conversionOrganizationId, tenantId: conversionTenantId },\n );\n for (const row of conversionRows) {\n const productId =\n typeof row.product === \"string\"\n ? row.product\n : (row.product?.id ?? null);\n const unitKey = toUnitLookupKey(row.unitCode);\n const factor = Number(row.toBaseFactor);\n if (!productId || !unitKey || !Number.isFinite(factor) || factor <= 0)\n continue;\n const bucket =\n conversionsByProduct.get(productId) ?? new Map<string, number>();\n bucket.set(unitKey, factor);\n conversionsByProduct.set(productId, bucket);\n }\n }\n\n const channelFilterIds = parseIdList(ctx.query.channelIds);\n const channelContext =\n ctx.query.channelId ??\n (channelFilterIds.length === 1 ? channelFilterIds[0] : null);\n const pricingContext = buildPricingContext(ctx.query, channelContext);\n const pricingService = ctx.container.resolve<CatalogPricingService>(\n \"catalogPricingService\",\n );\n\n const pricingEntries: Array<{ rows: PriceRow[]; context: PricingContext } | null> = [];\n for (const item of items) {\n const id = typeof item.id === \"string\" ? item.id : null;\n if (!id) {\n pricingEntries.push(null);\n continue;\n }\n const offerEntries = offersByProduct.get(id) ?? [];\n item.offers = offerEntries;\n const channelIds = Array.from(\n new Set(\n offerEntries\n .map((offer) =>\n typeof offer.channelId === \"string\" ? offer.channelId : null,\n )\n .filter((channelId): channelId is string => !!channelId),\n ),\n );\n item.channelIds = channelIds;\n const categories = categoriesByProduct.get(id) ?? [];\n item.categories = categories;\n item.categoryIds = categories.map((category) => category.id);\n item.tags = tagsByProduct.get(id) ?? [];\n const priceCandidates = pricesByProduct.get(id) ?? [];\n const normalizedQuantityForPricing = (() => {\n if (!requestQuantityUnitKey) return pricingContext.quantity;\n const baseUnit = toUnitLookupKey(item.default_unit);\n if (!baseUnit || requestQuantityUnitKey === baseUnit)\n return pricingContext.quantity;\n const productConversions = conversionsByProduct.get(id);\n const factor = productConversions?.get(requestQuantityUnitKey) ?? null;\n if (!factor || !Number.isFinite(factor) || factor <= 0) {\n if (process.env.NODE_ENV === 'development') console.warn(`[catalog.products] Invalid conversion factor for product=${id} unit=${requestQuantityUnitKey} factor=${factor}`);\n return pricingContext.quantity;\n }\n const normalized = pricingContext.quantity * factor;\n return Number.isFinite(normalized) && normalized > 0\n ? normalized\n : pricingContext.quantity;\n })();\n const channelScopedContext =\n pricingContext.channelId || channelIds.length !== 1\n ? pricingContext\n : { ...pricingContext, channelId: channelIds[0] };\n pricingEntries.push({\n rows: priceCandidates,\n context: { ...channelScopedContext, quantity: normalizedQuantityForPricing },\n });\n }\n\n const resolveInputs: Array<{ rows: PriceRow[]; context: PricingContext }> = [];\n const resolveIndices: number[] = [];\n for (let i = 0; i < pricingEntries.length; i++) {\n if (pricingEntries[i] !== null) {\n resolveInputs.push(pricingEntries[i]!);\n resolveIndices.push(i);\n }\n }\n const priceResults = await pricingService.resolvePriceMany(resolveInputs);\n\n for (let i = 0; i < resolveIndices.length; i++) {\n const item = items[resolveIndices[i]];\n const best = priceResults[i];\n if (best) {\n item.pricing = {\n kind: resolvePriceKindCode(best),\n price_kind_id:\n typeof best.priceKind === \"string\"\n ? best.priceKind\n : (best.priceKind?.id ?? null),\n price_kind_code: resolvePriceKindCode(best),\n currency_code: best.currencyCode,\n unit_price_net: best.unitPriceNet,\n unit_price_gross: best.unitPriceGross,\n min_quantity: best.minQuantity,\n max_quantity: best.maxQuantity ?? null,\n tax_rate: best.taxRate ?? null,\n tax_amount: best.taxAmount ?? null,\n scope: {\n variant_id: resolvePriceVariantId(best),\n offer_id: resolvePriceOfferId(best),\n channel_id: resolvePriceChannelId(best),\n user_id: best.userId ?? null,\n user_group_id: best.userGroupId ?? null,\n customer_id: best.customerId ?? null,\n customer_group_id: best.customerGroupId ?? null,\n },\n };\n } else {\n item.pricing = null;\n }\n }\n } catch (error) {\n console.error(\"[decorateProductsAfterList] Failed to load unit conversions\", error);\n }\n\n const searchTerm = ctx.query.search ? sanitizeSearchTerm(ctx.query.search) : null;\n if (searchTerm && !ctx.query.sortField && Array.isArray(payload.items)) {\n const needle = searchTerm.toLowerCase();\n payload.items.sort((a, b) => {\n const scoreA = scoreProductSearchRelevance(needle, a.title, a.sku);\n const scoreB = scoreProductSearchRelevance(needle, b.title, b.sku);\n if (scoreA !== scoreB) return scoreA - scoreB;\n return (a.title ?? \"\").localeCompare(b.title ?? \"\");\n });\n }\n}\n\nexport function scoreProductSearchRelevance(\n needle: string,\n title: string | null | undefined,\n sku: string | null | undefined,\n): number {\n const t = (title ?? \"\").toLowerCase();\n const s = (sku ?? \"\").toLowerCase();\n if (t === needle) return 0;\n if (s === needle) return 1;\n if (t.startsWith(needle)) return 2;\n if (s.startsWith(needle)) return 3;\n if (t.includes(needle)) return 4;\n if (s.includes(needle)) return 5;\n return 6;\n}\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogProduct,\n idField: \"id\",\n orgField: \"organizationId\",\n tenantField: \"tenantId\",\n softDeleteField: \"deletedAt\",\n },\n indexer: {\n entityType: E.catalog.catalog_product,\n },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_product,\n fields: [\n F.id,\n F.title,\n F.subtitle,\n F.description,\n F.sku,\n F.handle,\n \"tax_rate_id\",\n \"tax_rate\",\n F.product_type,\n F.status_entry_id,\n F.primary_currency_code,\n F.default_unit,\n \"default_sales_unit\",\n \"default_sales_unit_quantity\",\n \"uom_rounding_scale\",\n \"uom_rounding_mode\",\n \"unit_price_enabled\",\n \"unit_price_reference_unit\",\n \"unit_price_base_quantity\",\n F.default_media_id,\n F.default_media_url,\n F.weight_value,\n F.weight_unit,\n F.dimensions,\n F.is_configurable,\n F.is_active,\n F.metadata,\n \"custom_fieldset_code\",\n \"option_schema_id\",\n F.created_at,\n F.updated_at,\n ],\n decorateCustomFields: { entityIds: [E.catalog.catalog_product] },\n sortFieldMap: {\n title: F.title,\n sku: F.sku,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n buildFilters: buildProductFilters,\n transformItem: (item: ProductListItem | null | undefined) => {\n if (!item) return item;\n const normalized = { ...item };\n const cfEntries = extractAllCustomFieldEntries(item);\n for (const key of Object.keys(normalized)) {\n if (key.startsWith(\"cf:\")) {\n delete normalized[key];\n }\n }\n const defaultUnit = canonicalizeUnitCode(normalized.default_unit) ?? null;\n const defaultSalesUnit =\n canonicalizeUnitCode(normalized.default_sales_unit) ?? null;\n const unitPriceReferenceUnit =\n canonicalizeUnitCode(normalized.unit_price_reference_unit) ?? null;\n return {\n ...normalized,\n default_unit: defaultUnit,\n default_sales_unit: defaultSalesUnit,\n unit_price_reference_unit: unitPriceReferenceUnit,\n ...cfEntries,\n unit_price: {\n enabled: Boolean(normalized.unit_price_enabled),\n reference_unit: unitPriceReferenceUnit,\n base_quantity: normalized.unit_price_base_quantity ?? null,\n },\n };\n },\n },\n hooks: {\n afterList: decorateProductsAfterList,\n },\n actions: {\n create: {\n commandId: \"catalog.products.create\",\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations();\n const parsed = parseScopedCommandInput(\n productCreateSchema,\n raw ?? {},\n ctx,\n translate,\n );\n const { base, custom } = splitCustomFieldPayload(parsed);\n return Object.keys(custom).length\n ? { ...base, customFields: custom }\n : base;\n },\n response: ({ result }) => ({\n id: result?.productId ?? result?.id ?? null,\n }),\n status: 201,\n },\n update: {\n commandId: \"catalog.products.update\",\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations();\n const parsed = parseScopedCommandInput(\n productUpdateSchema,\n raw ?? {},\n ctx,\n translate,\n );\n const { base, custom } = splitCustomFieldPayload(parsed);\n return Object.keys(custom).length\n ? { ...base, customFields: custom }\n : base;\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: \"catalog.products.delete\",\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations();\n const id = resolveCrudRecordId(parsed, ctx, translate);\n if (!id)\n throw new CrudHttpError(400, {\n error: translate(\n \"catalog.errors.id_required\",\n \"Product id is required.\",\n ),\n });\n return { id };\n },\n response: () => ({ ok: true }),\n },\n },\n});\n\nexport const GET = crud.GET;\nexport const POST = crud.POST;\nexport const PUT = crud.PUT;\nexport const DELETE = crud.DELETE;\n\nconst productListItemSchema = z.object({\n id: z.string().uuid(),\n title: z.string().nullable().optional(),\n subtitle: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n sku: z.string().nullable().optional(),\n handle: z.string().nullable().optional(),\n product_type: z.string().nullable().optional(),\n status_entry_id: z.string().uuid().nullable().optional(),\n primary_currency_code: z.string().nullable().optional(),\n default_unit: z.string().nullable().optional(),\n default_sales_unit: z.string().nullable().optional(),\n default_sales_unit_quantity: z.number().nullable().optional(),\n uom_rounding_scale: z.number().nullable().optional(),\n uom_rounding_mode: z.enum([\"half_up\", \"down\", \"up\"]).nullable().optional(),\n unit_price_enabled: z.boolean().nullable().optional(),\n unit_price_reference_unit: z\n .enum([\"kg\", \"l\", \"m2\", \"m3\", \"pc\"])\n .nullable()\n .optional(),\n unit_price_base_quantity: z.number().nullable().optional(),\n unit_price: z\n .object({\n enabled: z.boolean(),\n reference_unit: z.enum([\"kg\", \"l\", \"m2\", \"m3\", \"pc\"]).nullable(),\n base_quantity: z.number().nullable(),\n })\n .optional(),\n default_media_id: z.string().uuid().nullable().optional(),\n default_media_url: z.string().nullable().optional(),\n weight_value: z.number().nullable().optional(),\n weight_unit: z.string().nullable().optional(),\n dimensions: z.record(z.string(), z.unknown()).nullable().optional(),\n is_configurable: z.boolean().nullable().optional(),\n is_active: z.boolean().nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n custom_fieldset_code: z.string().nullable().optional(),\n option_schema_id: z.string().uuid().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n offers: z.array(z.record(z.string(), z.unknown())).optional(),\n channelIds: z.array(z.string()).optional(),\n categories: z.array(z.record(z.string(), z.unknown())).optional(),\n categoryIds: z.array(z.string()).optional(),\n tags: z.array(z.string()).optional(),\n pricing: z.record(z.string(), z.unknown()).nullable().optional(),\n});\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: \"Product\",\n pluralName: \"Products\",\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(productListItemSchema),\n create: {\n schema: productCreateSchema,\n description: \"Creates a new product in the catalog.\",\n },\n update: {\n schema: productUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: \"Updates an existing product by id.\",\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: \"Deletes a product by id.\",\n },\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["channelIds"]
|
|
7
7
|
}
|
|
@@ -80,6 +80,7 @@ function EditCatalogCategoryPage({ params }) {
|
|
|
80
80
|
description: record.description ?? "",
|
|
81
81
|
parentId: record.parentId ?? "",
|
|
82
82
|
isActive: record.isActive,
|
|
83
|
+
updatedAt: record.updatedAt ?? record.updated_at ?? null,
|
|
83
84
|
...customValues
|
|
84
85
|
});
|
|
85
86
|
setPathLabel(record.pathLabel ?? "");
|
|
@@ -179,6 +180,7 @@ function EditCatalogCategoryPage({ params }) {
|
|
|
179
180
|
groups,
|
|
180
181
|
entityId: E.catalog.catalog_product_category,
|
|
181
182
|
initialValues: initialValues ?? { id: categoryId, name: "", slug: "", description: "", parentId: "", isActive: true },
|
|
183
|
+
optimisticLockUpdatedAt: initialValues?.updatedAt,
|
|
182
184
|
isLoading: loading,
|
|
183
185
|
loadingMessage: t("catalog.categories.form.loading", "Loading category..."),
|
|
184
186
|
submitLabel: t("catalog.categories.form.action.save", "Save"),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../../src/modules/catalog/backend/catalog/categories/%5Bid%5D/edit/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { E } from '#generated/entities.ids.generated'\nimport { CategorySelect } from '../../../../../components/categories/CategorySelect'\nimport { CategorySlugFieldSync } from '../../../../../components/categories/CategorySlugFieldSync'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\n\ntype CategoryRow = {\n id: string\n name: string\n slug: string | null\n description: string | null\n parentId: string | null\n isActive: boolean\n pathLabel?: string\n}\n\ntype CategoryResponse = {\n items?: CategoryRow[]\n}\n\ntype CategoryFormValues = {\n id?: string\n name: string\n slug?: string\n description?: string\n parentId?: string | null\n isActive?: boolean\n}\n\nasync function submitCategoryUpdate(\n categoryId: string,\n values: CategoryFormValues,\n t: (key: string, fallback?: string) => string,\n) {\n const resolvedId = typeof values.id === 'string' && values.id.length ? values.id : categoryId\n if (!resolvedId) {\n const message = t('catalog.categories.form.errors.idRequired', 'Category identifier is required.')\n throw createCrudFormError(message, { id: message })\n }\n const name = typeof values.name === 'string' ? values.name.trim() : ''\n if (!name) {\n const message = t('catalog.categories.form.errors.name', 'Provide the category name.')\n throw createCrudFormError(message, { name: message })\n }\n const slug = typeof values.slug === 'string' && values.slug.trim().length ? values.slug.trim() : undefined\n const description =\n typeof values.description === 'string' && values.description.trim().length\n ? values.description.trim()\n : undefined\n const parentId =\n typeof values.parentId === 'string' && values.parentId.trim().length\n ? values.parentId.trim()\n : null\n const customFields = collectCustomFieldValues(values as Record<string, unknown>)\n const payload: Record<string, unknown> = {\n id: resolvedId,\n name,\n slug,\n description,\n parentId,\n isActive: values.isActive !== false,\n }\n if (Object.keys(customFields).length > 0) payload.customFields = customFields\n await updateCrud('catalog/categories', payload)\n}\n\nexport default function EditCatalogCategoryPage({ params }: { params?: { id?: string } }) {\n const categoryId = params?.id ?? ''\n const t = useT()\n const [initialValues, setInitialValues] = React.useState<CategoryFormValues | null>(null)\n const [pathLabel, setPathLabel] = React.useState<string>('')\n const [loading, setLoading] = React.useState<boolean>(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState<boolean>(false)\n\n React.useEffect(() => {\n if (!categoryId) return\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n try {\n const { ok, status, result } = await apiCall<CategoryResponse>(\n `/api/catalog/categories?view=manage&ids=${encodeURIComponent(categoryId)}&status=all&page=1&pageSize=1`,\n )\n if (!ok) {\n if (status === 404) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n throw new Error(t('catalog.categories.form.errors.load', 'Failed to load category'))\n }\n const record = Array.isArray(result?.items) ? result.items?.[0] : null\n if (!record) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n if (cancelled) return\n const customValues = extractCustomFieldEntries(record as Record<string, unknown>)\n setInitialValues({\n id: record.id,\n name: record.name,\n slug: record.slug ?? '',\n description: record.description ?? '',\n parentId: record.parentId ?? '',\n isActive: record.isActive,\n ...customValues,\n })\n setPathLabel(record.pathLabel ?? '')\n } catch (err) {\n if (!cancelled) {\n const fallback = t('catalog.categories.form.errors.load', 'Failed to load category')\n const message = err instanceof Error ? err.message : fallback\n setError(message)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => {\n cancelled = true\n }\n }, [categoryId, t])\n\n const fields = React.useMemo<CrudField[]>(() => [\n {\n id: 'name',\n label: t('catalog.categories.form.field.name', 'Name'),\n type: 'text',\n required: true,\n placeholder: t('catalog.categories.form.field.namePlaceholder', 'e.g., Footwear'),\n },\n {\n id: 'slug',\n label: t('catalog.categories.form.field.slug', 'Slug'),\n type: 'text',\n description: t('catalog.categories.form.field.slugHelp', 'Lowercase identifier for URLs or imports.'),\n },\n {\n id: 'description',\n label: t('catalog.categories.form.field.description', 'Description'),\n type: 'textarea',\n },\n {\n id: 'parentId',\n label: t('catalog.categories.form.field.parent', 'Parent'),\n type: 'custom',\n component: ({ id, value, setValue }) => (\n <CategorySelect\n id={id}\n value={typeof value === 'string' ? value : null}\n onChange={(next) => setValue(next ?? '')}\n includeEmptyOption\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n },\n {\n id: 'isActive',\n label: t('catalog.categories.form.field.isActive', 'Active'),\n type: 'checkbox',\n },\n ], [t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => [\n {\n id: 'details',\n title: t('catalog.categories.form.group.details', 'Details'),\n column: 1,\n fields: ['name', 'slug', 'description', 'parentId', 'isActive'],\n component: (ctx) => <CategorySlugFieldSync {...ctx} />,\n },\n {\n id: 'custom',\n title: t('catalog.categories.form.group.custom', 'Custom data'),\n column: 2,\n kind: 'customFields',\n },\n ], [t])\n\n if (!categoryId) {\n return (\n <Page>\n <PageBody>\n <p className=\"text-sm text-destructive\">\n {t('catalog.categories.form.errors.idRequired', 'Category identifier is required.')}\n </p>\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('catalog.categories.form.errors.notFound', 'Category not found')}\n backHref=\"/backend/catalog/categories\"\n backLabel={t('catalog.categories.form.actions.backToList', 'Back to categories')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<CategoryFormValues>\n title={t('catalog.categories.form.editTitle', 'Edit category')}\n backHref=\"/backend/catalog/categories\"\n versionHistory={{ resourceKind: 'catalog.category', resourceId: categoryId ? String(categoryId) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.catalog.catalog_product_category}\n initialValues={initialValues ?? { id: categoryId, name: '', slug: '', description: '', parentId: '', isActive: true }}\n isLoading={loading}\n loadingMessage={t('catalog.categories.form.loading', 'Loading category...')}\n submitLabel={t('catalog.categories.form.action.save', 'Save')}\n cancelHref=\"/backend/catalog/categories\"\n successRedirect={`/backend/catalog/categories?flash=${encodeURIComponent(t('catalog.categories.flash.updated', 'Category updated'))}&type=success`}\n extraActions={(\n <>\n <SendObjectMessageDialog\n object={{\n entityModule: 'catalog',\n entityType: 'category',\n entityId: categoryId,\n previewData: { title: initialValues?.name ?? categoryId },\n }}\n viewHref={`/backend/catalog/categories/${categoryId}/edit`}\n />\n {pathLabel ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('catalog.categories.form.pathLabel', { path: pathLabel })}\n </span>\n ) : null}\n </>\n )}\n onSubmit={async (values) => {\n await submitCategoryUpdate(categoryId, values, t)\n }}\n onDelete={async () => {\n await deleteCrud('catalog/categories', categoryId, {\n errorMessage: t('catalog.categories.form.errors.delete', 'Failed to delete category'),\n })\n }}\n deleteRedirect={`/backend/catalog/categories?flash=${encodeURIComponent(t('catalog.categories.flash.deleted', 'Category archived'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { E } from '#generated/entities.ids.generated'\nimport { CategorySelect } from '../../../../../components/categories/CategorySelect'\nimport { CategorySlugFieldSync } from '../../../../../components/categories/CategorySlugFieldSync'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\n\ntype CategoryRow = {\n id: string\n name: string\n slug: string | null\n description: string | null\n parentId: string | null\n isActive: boolean\n updatedAt?: string | null\n updated_at?: string | null\n pathLabel?: string\n}\n\ntype CategoryResponse = {\n items?: CategoryRow[]\n}\n\ntype CategoryFormValues = {\n id?: string\n name: string\n slug?: string\n description?: string\n parentId?: string | null\n isActive?: boolean\n updatedAt?: string | null\n}\n\nasync function submitCategoryUpdate(\n categoryId: string,\n values: CategoryFormValues,\n t: (key: string, fallback?: string) => string,\n) {\n const resolvedId = typeof values.id === 'string' && values.id.length ? values.id : categoryId\n if (!resolvedId) {\n const message = t('catalog.categories.form.errors.idRequired', 'Category identifier is required.')\n throw createCrudFormError(message, { id: message })\n }\n const name = typeof values.name === 'string' ? values.name.trim() : ''\n if (!name) {\n const message = t('catalog.categories.form.errors.name', 'Provide the category name.')\n throw createCrudFormError(message, { name: message })\n }\n const slug = typeof values.slug === 'string' && values.slug.trim().length ? values.slug.trim() : undefined\n const description =\n typeof values.description === 'string' && values.description.trim().length\n ? values.description.trim()\n : undefined\n const parentId =\n typeof values.parentId === 'string' && values.parentId.trim().length\n ? values.parentId.trim()\n : null\n const customFields = collectCustomFieldValues(values as Record<string, unknown>)\n const payload: Record<string, unknown> = {\n id: resolvedId,\n name,\n slug,\n description,\n parentId,\n isActive: values.isActive !== false,\n }\n if (Object.keys(customFields).length > 0) payload.customFields = customFields\n await updateCrud('catalog/categories', payload)\n}\n\nexport default function EditCatalogCategoryPage({ params }: { params?: { id?: string } }) {\n const categoryId = params?.id ?? ''\n const t = useT()\n const [initialValues, setInitialValues] = React.useState<CategoryFormValues | null>(null)\n const [pathLabel, setPathLabel] = React.useState<string>('')\n const [loading, setLoading] = React.useState<boolean>(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState<boolean>(false)\n\n React.useEffect(() => {\n if (!categoryId) return\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n try {\n const { ok, status, result } = await apiCall<CategoryResponse>(\n `/api/catalog/categories?view=manage&ids=${encodeURIComponent(categoryId)}&status=all&page=1&pageSize=1`,\n )\n if (!ok) {\n if (status === 404) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n throw new Error(t('catalog.categories.form.errors.load', 'Failed to load category'))\n }\n const record = Array.isArray(result?.items) ? result.items?.[0] : null\n if (!record) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n if (cancelled) return\n const customValues = extractCustomFieldEntries(record as Record<string, unknown>)\n setInitialValues({\n id: record.id,\n name: record.name,\n slug: record.slug ?? '',\n description: record.description ?? '',\n parentId: record.parentId ?? '',\n isActive: record.isActive,\n updatedAt: record.updatedAt ?? record.updated_at ?? null,\n ...customValues,\n })\n setPathLabel(record.pathLabel ?? '')\n } catch (err) {\n if (!cancelled) {\n const fallback = t('catalog.categories.form.errors.load', 'Failed to load category')\n const message = err instanceof Error ? err.message : fallback\n setError(message)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => {\n cancelled = true\n }\n }, [categoryId, t])\n\n const fields = React.useMemo<CrudField[]>(() => [\n {\n id: 'name',\n label: t('catalog.categories.form.field.name', 'Name'),\n type: 'text',\n required: true,\n placeholder: t('catalog.categories.form.field.namePlaceholder', 'e.g., Footwear'),\n },\n {\n id: 'slug',\n label: t('catalog.categories.form.field.slug', 'Slug'),\n type: 'text',\n description: t('catalog.categories.form.field.slugHelp', 'Lowercase identifier for URLs or imports.'),\n },\n {\n id: 'description',\n label: t('catalog.categories.form.field.description', 'Description'),\n type: 'textarea',\n },\n {\n id: 'parentId',\n label: t('catalog.categories.form.field.parent', 'Parent'),\n type: 'custom',\n component: ({ id, value, setValue }) => (\n <CategorySelect\n id={id}\n value={typeof value === 'string' ? value : null}\n onChange={(next) => setValue(next ?? '')}\n includeEmptyOption\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n },\n {\n id: 'isActive',\n label: t('catalog.categories.form.field.isActive', 'Active'),\n type: 'checkbox',\n },\n ], [t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => [\n {\n id: 'details',\n title: t('catalog.categories.form.group.details', 'Details'),\n column: 1,\n fields: ['name', 'slug', 'description', 'parentId', 'isActive'],\n component: (ctx) => <CategorySlugFieldSync {...ctx} />,\n },\n {\n id: 'custom',\n title: t('catalog.categories.form.group.custom', 'Custom data'),\n column: 2,\n kind: 'customFields',\n },\n ], [t])\n\n if (!categoryId) {\n return (\n <Page>\n <PageBody>\n <p className=\"text-sm text-destructive\">\n {t('catalog.categories.form.errors.idRequired', 'Category identifier is required.')}\n </p>\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('catalog.categories.form.errors.notFound', 'Category not found')}\n backHref=\"/backend/catalog/categories\"\n backLabel={t('catalog.categories.form.actions.backToList', 'Back to categories')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<CategoryFormValues>\n title={t('catalog.categories.form.editTitle', 'Edit category')}\n backHref=\"/backend/catalog/categories\"\n versionHistory={{ resourceKind: 'catalog.category', resourceId: categoryId ? String(categoryId) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.catalog.catalog_product_category}\n initialValues={initialValues ?? { id: categoryId, name: '', slug: '', description: '', parentId: '', isActive: true }}\n optimisticLockUpdatedAt={initialValues?.updatedAt}\n isLoading={loading}\n loadingMessage={t('catalog.categories.form.loading', 'Loading category...')}\n submitLabel={t('catalog.categories.form.action.save', 'Save')}\n cancelHref=\"/backend/catalog/categories\"\n successRedirect={`/backend/catalog/categories?flash=${encodeURIComponent(t('catalog.categories.flash.updated', 'Category updated'))}&type=success`}\n extraActions={(\n <>\n <SendObjectMessageDialog\n object={{\n entityModule: 'catalog',\n entityType: 'category',\n entityId: categoryId,\n previewData: { title: initialValues?.name ?? categoryId },\n }}\n viewHref={`/backend/catalog/categories/${categoryId}/edit`}\n />\n {pathLabel ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('catalog.categories.form.pathLabel', { path: pathLabel })}\n </span>\n ) : null}\n </>\n )}\n onSubmit={async (values) => {\n await submitCategoryUpdate(categoryId, values, t)\n }}\n onDelete={async () => {\n await deleteCrud('catalog/categories', categoryId, {\n errorMessage: t('catalog.categories.form.errors.delete', 'Failed to delete category'),\n })\n }}\n deleteRedirect={`/backend/catalog/categories?flash=${encodeURIComponent(t('catalog.categories.flash.deleted', 'Category archived'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -33,8 +33,11 @@ import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-
|
|
|
33
33
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
34
34
|
import {
|
|
35
35
|
apiCall,
|
|
36
|
-
readApiResultOrThrow
|
|
36
|
+
readApiResultOrThrow,
|
|
37
|
+
withScopedApiRequestHeaders
|
|
37
38
|
} from "@open-mercato/ui/backend/utils/apiCall";
|
|
39
|
+
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
|
|
40
|
+
import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
|
|
38
41
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
39
42
|
import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
|
|
40
43
|
import { E } from "../../../../../../generated/entities.ids.generated.js";
|
|
@@ -164,7 +167,8 @@ function readProductConversionRows(items) {
|
|
|
164
167
|
unitCode,
|
|
165
168
|
toBaseFactor: String(factor),
|
|
166
169
|
sortOrder: String(sortOrderRaw),
|
|
167
|
-
isActive
|
|
170
|
+
isActive,
|
|
171
|
+
updatedAt: typeof item.updated_at === "string" ? item.updated_at : typeof item.updatedAt === "string" ? item.updatedAt : null
|
|
168
172
|
};
|
|
169
173
|
}).filter((entry) => Boolean(entry));
|
|
170
174
|
}
|
|
@@ -239,7 +243,8 @@ function EditCatalogProductPage({
|
|
|
239
243
|
isDefault: Boolean(variant.is_default ?? variant.isDefault),
|
|
240
244
|
defaultMediaId: typeof variant.default_media_id === "string" ? variant.default_media_id : typeof variant.defaultMediaId === "string" ? variant.defaultMediaId : null,
|
|
241
245
|
prices: priceMap[variantId] ?? [],
|
|
242
|
-
optionValues
|
|
246
|
+
optionValues,
|
|
247
|
+
updatedAt: typeof variant.updatedAt === "string" ? variant.updatedAt : typeof variant.updated_at === "string" ? variant.updated_at : null
|
|
243
248
|
};
|
|
244
249
|
}).filter((entry) => Boolean(entry));
|
|
245
250
|
setVariants(mapped);
|
|
@@ -468,7 +473,8 @@ function EditCatalogProductPage({
|
|
|
468
473
|
customFieldsetCode: typeof record.custom_fieldset_code === "string" ? record.custom_fieldset_code : typeof record.customFieldsetCode === "string" ? record.customFieldsetCode : null,
|
|
469
474
|
categoryIds,
|
|
470
475
|
channelIds,
|
|
471
|
-
tags: tagValues
|
|
476
|
+
tags: tagValues,
|
|
477
|
+
updatedAt: typeof record.updatedAt === "string" ? record.updatedAt : typeof record.updated_at === "string" ? record.updated_at : null
|
|
472
478
|
};
|
|
473
479
|
if (!cancelled) {
|
|
474
480
|
setInitialValues({ ...initial, ...customValues });
|
|
@@ -926,12 +932,16 @@ function EditCatalogProductPage({
|
|
|
926
932
|
try {
|
|
927
933
|
for (const offer of removedOffers) {
|
|
928
934
|
if (!offer.id) continue;
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
+
const offerId = offer.id;
|
|
936
|
+
await withScopedApiRequestHeaders(
|
|
937
|
+
buildOptimisticLockHeader(offer.updatedAt),
|
|
938
|
+
() => deleteCrud("catalog/offers", offerId, {
|
|
939
|
+
errorMessage: t(
|
|
940
|
+
"catalog.products.edit.offers.deleteError",
|
|
941
|
+
"Failed to remove sales channel offer."
|
|
942
|
+
)
|
|
943
|
+
})
|
|
944
|
+
);
|
|
935
945
|
}
|
|
936
946
|
} catch (err) {
|
|
937
947
|
console.error("catalog.products.edit.offers.delete", err);
|
|
@@ -947,6 +957,11 @@ function EditCatalogProductPage({
|
|
|
947
957
|
const previousConversionIds = new Set(
|
|
948
958
|
initialConversionsRef.current.map((entry) => toTrimmedOrNull(entry.id)).filter((id) => Boolean(id))
|
|
949
959
|
);
|
|
960
|
+
const conversionVersions = /* @__PURE__ */ new Map();
|
|
961
|
+
for (const entry of initialConversionsRef.current) {
|
|
962
|
+
const cid = toTrimmedOrNull(entry.id);
|
|
963
|
+
if (cid) conversionVersions.set(cid, entry.updatedAt ?? null);
|
|
964
|
+
}
|
|
950
965
|
const nextConversionIds = new Set(
|
|
951
966
|
conversionInputs.map(
|
|
952
967
|
(entry) => entry.id && entry.id.trim().length ? entry.id : null
|
|
@@ -956,23 +971,30 @@ function EditCatalogProductPage({
|
|
|
956
971
|
(id) => !nextConversionIds.has(id)
|
|
957
972
|
);
|
|
958
973
|
for (const conversionId of removedConversionIds) {
|
|
959
|
-
await
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
974
|
+
await withScopedApiRequestHeaders(
|
|
975
|
+
buildOptimisticLockHeader(conversionVersions.get(conversionId) ?? null),
|
|
976
|
+
() => deleteCrud("catalog/product-unit-conversions", conversionId, {
|
|
977
|
+
errorMessage: t(
|
|
978
|
+
"catalog.products.uom.errors.sync",
|
|
979
|
+
"Failed to synchronize product conversions."
|
|
980
|
+
)
|
|
981
|
+
})
|
|
982
|
+
);
|
|
965
983
|
}
|
|
966
984
|
const persistedConversions = [];
|
|
967
985
|
for (const conversion of conversionInputs) {
|
|
968
986
|
if (conversion.id) {
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
987
|
+
const conversionId = conversion.id;
|
|
988
|
+
await withScopedApiRequestHeaders(
|
|
989
|
+
buildOptimisticLockHeader(conversionVersions.get(conversionId) ?? null),
|
|
990
|
+
() => updateCrud("catalog/product-unit-conversions", {
|
|
991
|
+
id: conversionId,
|
|
992
|
+
unitCode: conversion.unitCode,
|
|
993
|
+
toBaseFactor: conversion.toBaseFactor,
|
|
994
|
+
sortOrder: conversion.sortOrder,
|
|
995
|
+
isActive: conversion.isActive
|
|
996
|
+
})
|
|
997
|
+
);
|
|
976
998
|
persistedConversions.push({
|
|
977
999
|
id: conversion.id,
|
|
978
1000
|
unitCode: conversion.unitCode,
|
|
@@ -1384,23 +1406,32 @@ function ProductOptionsSection({ values, setValue }) {
|
|
|
1384
1406
|
}, []);
|
|
1385
1407
|
const handleDeleteSchema = React.useCallback(
|
|
1386
1408
|
async (id) => {
|
|
1409
|
+
const target = schemaTemplates.find((entry) => entry.id === id);
|
|
1410
|
+
const lockVersion = target?.updatedAt ?? target?.updated_at ?? null;
|
|
1387
1411
|
try {
|
|
1388
|
-
await
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1412
|
+
await withScopedApiRequestHeaders(
|
|
1413
|
+
buildOptimisticLockHeader(lockVersion),
|
|
1414
|
+
() => deleteCrud("catalog/option-schemas", id, {
|
|
1415
|
+
errorMessage: t(
|
|
1416
|
+
"catalog.products.edit.schemas.deleteError",
|
|
1417
|
+
"Failed to delete schema."
|
|
1418
|
+
)
|
|
1419
|
+
})
|
|
1420
|
+
);
|
|
1394
1421
|
flash(
|
|
1395
1422
|
t("catalog.products.edit.schemas.deleted", "Schema deleted."),
|
|
1396
1423
|
"success"
|
|
1397
1424
|
);
|
|
1398
1425
|
void loadSchemas();
|
|
1399
1426
|
} catch (err) {
|
|
1427
|
+
if (surfaceRecordConflict(err, t)) {
|
|
1428
|
+
void loadSchemas();
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1400
1431
|
console.error("catalog.option-schemas.delete failed", err);
|
|
1401
1432
|
}
|
|
1402
1433
|
},
|
|
1403
|
-
[loadSchemas, t]
|
|
1434
|
+
[loadSchemas, schemaTemplates, t]
|
|
1404
1435
|
);
|
|
1405
1436
|
const handleSaveSchema = React.useCallback(
|
|
1406
1437
|
async (name) => {
|
|
@@ -1431,8 +1462,25 @@ function ProductOptionsSection({ values, setValue }) {
|
|
|
1431
1462
|
isActive: true
|
|
1432
1463
|
};
|
|
1433
1464
|
if (schemaToEdit?.id) payload.id = schemaToEdit.id;
|
|
1434
|
-
|
|
1435
|
-
|
|
1465
|
+
try {
|
|
1466
|
+
if (schemaToEdit?.id) {
|
|
1467
|
+
const lockVersion = schemaToEdit.updatedAt ?? schemaToEdit.updated_at ?? null;
|
|
1468
|
+
await withScopedApiRequestHeaders(
|
|
1469
|
+
buildOptimisticLockHeader(lockVersion),
|
|
1470
|
+
() => updateCrud("catalog/option-schemas", payload)
|
|
1471
|
+
);
|
|
1472
|
+
} else {
|
|
1473
|
+
await createCrud("catalog/option-schemas", payload);
|
|
1474
|
+
}
|
|
1475
|
+
} catch (err) {
|
|
1476
|
+
if (surfaceRecordConflict(err, t)) {
|
|
1477
|
+
setSaveSchemaOpen(false);
|
|
1478
|
+
setSchemaToEdit(null);
|
|
1479
|
+
void loadSchemas();
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
throw err;
|
|
1483
|
+
}
|
|
1436
1484
|
flash(
|
|
1437
1485
|
t("catalog.products.edit.schemas.saved", "Schema saved."),
|
|
1438
1486
|
"success"
|
|
@@ -1738,18 +1786,22 @@ function ProductVariantsSection({
|
|
|
1738
1786
|
if (!confirmed) return;
|
|
1739
1787
|
setDeletingId(variant.id);
|
|
1740
1788
|
try {
|
|
1741
|
-
await
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1789
|
+
await withScopedApiRequestHeaders(
|
|
1790
|
+
buildOptimisticLockHeader(variant.updatedAt),
|
|
1791
|
+
() => deleteCrud("catalog/variants", variant.id, {
|
|
1792
|
+
errorMessage: t(
|
|
1793
|
+
"catalog.variants.form.deleteError",
|
|
1794
|
+
"Failed to delete variant."
|
|
1795
|
+
)
|
|
1796
|
+
})
|
|
1797
|
+
);
|
|
1747
1798
|
flash(
|
|
1748
1799
|
t("catalog.variants.form.deleted", "Variant deleted."),
|
|
1749
1800
|
"success"
|
|
1750
1801
|
);
|
|
1751
1802
|
onVariantDeleted(variant.id);
|
|
1752
1803
|
} catch (err) {
|
|
1804
|
+
if (surfaceRecordConflict(err, t)) return;
|
|
1753
1805
|
console.error("catalog.products.edit.variants.delete", err);
|
|
1754
1806
|
flash(
|
|
1755
1807
|
t("catalog.variants.form.deleteError", "Failed to delete variant."),
|
|
@@ -2208,7 +2260,8 @@ function readOfferSnapshots(record) {
|
|
|
2208
2260
|
metadata: isRecord(offer.metadata) ? offer.metadata : null,
|
|
2209
2261
|
isActive: offer.isActive !== false,
|
|
2210
2262
|
channelName: getString(offer.channelName) ?? getString(offer.channel_name),
|
|
2211
|
-
channelCode: getString(offer.channelCode) ?? getString(offer.channel_code)
|
|
2263
|
+
channelCode: getString(offer.channelCode) ?? getString(offer.channel_code),
|
|
2264
|
+
updatedAt: getString(offer.updatedAt) ?? getString(offer.updated_at) ?? null
|
|
2212
2265
|
});
|
|
2213
2266
|
}
|
|
2214
2267
|
return snapshots;
|
|
@@ -2272,7 +2325,8 @@ function mergeOfferSnapshots(current, payloads) {
|
|
|
2272
2325
|
metadata: entry.metadata ?? previous?.metadata ?? null,
|
|
2273
2326
|
isActive: entry.isActive ?? previous?.isActive ?? true,
|
|
2274
2327
|
channelName: previous?.channelName ?? null,
|
|
2275
|
-
channelCode: previous?.channelCode ?? null
|
|
2328
|
+
channelCode: previous?.channelCode ?? null,
|
|
2329
|
+
updatedAt: previous?.updatedAt ?? null
|
|
2276
2330
|
};
|
|
2277
2331
|
});
|
|
2278
2332
|
}
|