@open-mercato/core 0.6.5-develop.4534.1.b459babe6d → 0.6.5-develop.4559.1.839e136509
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/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/user/index.js +3 -1
- package/dist/generated/entities/user/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
- package/dist/helpers/integration/dbFixtures.js +2 -1
- package/dist/helpers/integration/dbFixtures.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/api/post/test-seed/route.js +23 -2
- package/dist/modules/communication_channels/api/post/test-seed/route.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/communication_channels/commands/set-primary-channel.js +2 -1
- package/dist/modules/communication_channels/commands/set-primary-channel.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/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/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/formConfig.js +4 -1
- package/dist/modules/workflows/components/formConfig.js.map +2 -2
- package/dist/modules/workflows/di.js +12 -0
- package/dist/modules/workflows/di.js.map +2 -2
- package/generated/entities/role/index.ts +1 -0
- package/generated/entities/user/index.ts +1 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/jest.setup.ts +17 -0
- package/package.json +8 -7
- package/src/helpers/integration/communicationChannelsFixtures.ts +6 -0
- package/src/helpers/integration/dbFixtures.ts +1 -1
- 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/api/post/test-seed/route.ts +28 -1
- package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +5 -0
- package/src/modules/communication_channels/commands/set-primary-channel.ts +10 -7
- 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/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/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/formConfig.tsx +5 -0
- package/src/modules/workflows/di.ts +20 -0
- package/src/modules/workflows/i18n/de.json +1 -0
- package/src/modules/workflows/i18n/en.json +1 -0
- package/src/modules/workflows/i18n/es.json +1 -0
- package/src/modules/workflows/i18n/pl.json +1 -0
|
@@ -12,7 +12,7 @@ import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/
|
|
|
12
12
|
import { SalesDocumentNumberGenerator } from '../services/salesDocumentNumberGenerator'
|
|
13
13
|
import type { SalesCalculationService } from '../services/salesCalculationService'
|
|
14
14
|
import type { SalesAdjustmentDraft, SalesLineSnapshot, SalesDocumentCalculationResult } from '../lib/types'
|
|
15
|
-
import { cloneJson, ensureOrganizationScope, ensureSameScope, ensureTenantScope, extractUndoPayload, toNumericString } from './shared'
|
|
15
|
+
import { cloneJson, ensureOrganizationScope, ensureSameScope, ensureTenantScope, extractUndoPayload, toNumericString, enforceSalesDocumentOptimisticLock, SALES_RESOURCE_KIND_ORDER } from './shared'
|
|
16
16
|
import { SalesOrder, SalesOrderAdjustment, SalesOrderLine, SalesReturn, SalesReturnLine } from '../data/entities'
|
|
17
17
|
import { returnCreateSchema, type ReturnCreateInput } from '../data/validators'
|
|
18
18
|
import { E } from '#generated/entities.ids.generated'
|
|
@@ -286,6 +286,7 @@ const createReturnCommand: CommandHandler<ReturnCreateInput, { returnId: string
|
|
|
286
286
|
throw new CrudHttpError(404, { error: translate('sales.returns.orderMissing', 'Order not found.') })
|
|
287
287
|
}
|
|
288
288
|
ensureSameScope(order, input.organizationId, input.tenantId)
|
|
289
|
+
enforceSalesDocumentOptimisticLock(ctx, order, SALES_RESOURCE_KIND_ORDER)
|
|
289
290
|
|
|
290
291
|
const orderLines = await findWithDecryption(
|
|
291
292
|
tx,
|
|
@@ -476,11 +477,12 @@ const createReturnCommand: CommandHandler<ReturnCreateInput, { returnId: string
|
|
|
476
477
|
// Line reversals, adjustment/return removals, and the order-total recompute
|
|
477
478
|
// interleave queries on the same EntityManager with scalar mutations, so they
|
|
478
479
|
// must run inside an atomic flush to avoid lost updates and partial commits.
|
|
480
|
+
let lines: SalesOrderLine[] = []
|
|
479
481
|
await withAtomicFlush(
|
|
480
482
|
em,
|
|
481
483
|
[
|
|
482
484
|
async () => {
|
|
483
|
-
|
|
485
|
+
lines = await findWithDecryption(
|
|
484
486
|
em,
|
|
485
487
|
SalesOrderLine,
|
|
486
488
|
{ order: order.id, deletedAt: null },
|
|
@@ -496,7 +498,14 @@ const createReturnCommand: CommandHandler<ReturnCreateInput, { returnId: string
|
|
|
496
498
|
line.updatedAt = new Date()
|
|
497
499
|
em.persist(line)
|
|
498
500
|
})
|
|
499
|
-
|
|
501
|
+
},
|
|
502
|
+
// The line returnedQuantity reversals above are persisted by
|
|
503
|
+
// withAtomicFlush's per-phase flush boundary before the adjustment /
|
|
504
|
+
// header / return-line lookups below run any query on this
|
|
505
|
+
// EntityManager. MikroORM v7 would otherwise silently discard the pending
|
|
506
|
+
// scalar changes on the managed `lines` when the next read resets the
|
|
507
|
+
// changeset (see SPEC-018).
|
|
508
|
+
async () => {
|
|
500
509
|
if (after.adjustmentIds.length) {
|
|
501
510
|
const adjustments = await findWithDecryption(
|
|
502
511
|
em,
|
|
@@ -2,10 +2,46 @@ import type { EntityManager } from '@mikro-orm/postgresql'
|
|
|
2
2
|
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
3
3
|
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
4
4
|
import type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
|
|
5
|
+
import { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
|
|
5
6
|
export { assertFound } from '@open-mercato/shared/lib/crud/errors'
|
|
6
7
|
export { ensureOrganizationScope, ensureSameScope, ensureTenantScope } from '@open-mercato/shared/lib/commands/scope'
|
|
7
8
|
export { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'
|
|
8
9
|
|
|
10
|
+
/** Resource kinds used by the document-aggregate optimistic-lock check. */
|
|
11
|
+
export const SALES_RESOURCE_KIND_ORDER = 'sales.order'
|
|
12
|
+
export const SALES_RESOURCE_KIND_QUOTE = 'sales.quote'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Enforce the document-aggregate OSS optimistic lock for a sales sub-resource
|
|
16
|
+
* command (lines, adjustments, shipments, payments, returns, quote
|
|
17
|
+
* conversion). The client sends the parent order/quote's expected `updated_at`
|
|
18
|
+
* via the optimistic-lock extension header; this compares it against the
|
|
19
|
+
* already-loaded document and throws the structured 409 on mismatch.
|
|
20
|
+
*
|
|
21
|
+
* The parent document is the consistency boundary: sub-resource mutations
|
|
22
|
+
* recalculate document totals (or transition the document), which dirties the
|
|
23
|
+
* parent so its `updated_at` advances on flush — meaning concurrent sub-edits
|
|
24
|
+
* observe each other and conflict. Call this AFTER loading + scope-checking the
|
|
25
|
+
* document and BEFORE mutating, so `document.updatedAt` is the pre-mutation
|
|
26
|
+
* version.
|
|
27
|
+
*
|
|
28
|
+
* Strictly additive: when the client sends no header the check is a no-op, so
|
|
29
|
+
* existing API consumers are unaffected. Respects `OM_OPTIMISTIC_LOCK`.
|
|
30
|
+
*/
|
|
31
|
+
export function enforceSalesDocumentOptimisticLock(
|
|
32
|
+
ctx: CommandRuntimeContext,
|
|
33
|
+
document: { id: string; updatedAt?: Date | string | null } | null | undefined,
|
|
34
|
+
resourceKind: string,
|
|
35
|
+
): void {
|
|
36
|
+
if (!document) return
|
|
37
|
+
enforceCommandOptimisticLock({
|
|
38
|
+
resourceKind,
|
|
39
|
+
resourceId: document.id,
|
|
40
|
+
current: document.updatedAt ?? null,
|
|
41
|
+
request: ctx.request ?? null,
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
9
45
|
export function cloneJson<T>(value: T): T {
|
|
10
46
|
if (value === null || value === undefined) return value
|
|
11
47
|
return JSON.parse(JSON.stringify(value)) as T
|
|
@@ -657,11 +657,17 @@ const updateShipmentCommand: CommandHandler<ShipmentUpdateInput, { shipmentId: s
|
|
|
657
657
|
: null
|
|
658
658
|
const normalizedItems = validatedItems?.items ?? null
|
|
659
659
|
const lineMap = validatedItems?.lineMap ?? new Map<string, SalesOrderLine>()
|
|
660
|
+
// Resolve the status label BEFORE mutating shipment scalars so this
|
|
661
|
+
// dictionary read does not interleave with (and drop) the pending
|
|
662
|
+
// shipment changeset under MikroORM v7 (SPEC-018 / #2453 class).
|
|
663
|
+
const resolvedShipmentStatus = input.statusEntryId !== undefined
|
|
664
|
+
? await resolveDictionaryEntryValue(tx, input.statusEntryId ?? null)
|
|
665
|
+
: undefined
|
|
660
666
|
if (input.shipmentNumber !== undefined) shipmentEntity.shipmentNumber = input.shipmentNumber ?? null
|
|
661
667
|
if (input.shippingMethodId !== undefined) shipmentEntity.shippingMethodId = input.shippingMethodId ?? null
|
|
662
668
|
if (input.statusEntryId !== undefined) {
|
|
663
669
|
shipmentEntity.statusEntryId = input.statusEntryId ?? null
|
|
664
|
-
shipmentEntity.status =
|
|
670
|
+
shipmentEntity.status = resolvedShipmentStatus ?? null
|
|
665
671
|
}
|
|
666
672
|
if (input.carrierName !== undefined) shipmentEntity.carrierName = input.carrierName ?? null
|
|
667
673
|
if (input.trackingNumbers !== undefined) shipmentEntity.trackingNumbers = parseTrackingNumbers(input.trackingNumbers)
|
|
@@ -685,6 +691,13 @@ const updateShipmentCommand: CommandHandler<ShipmentUpdateInput, { shipmentId: s
|
|
|
685
691
|
}
|
|
686
692
|
shipmentEntity.updatedAt = new Date()
|
|
687
693
|
|
|
694
|
+
// Persist the shipment scalar mutations before the item reads below run on
|
|
695
|
+
// the same EntityManager. Under MikroORM v7 an interleaved query (the
|
|
696
|
+
// findWithDecryption on SalesShipmentItem here and in the snapshot step)
|
|
697
|
+
// resets the identity-map changeset, so shippingMethodId/status/carrier/etc.
|
|
698
|
+
// would silently not persist even though the write returns 200 (#2453).
|
|
699
|
+
await tx.flush()
|
|
700
|
+
|
|
688
701
|
const shouldLoadItems = Boolean(normalizedItems || input.lineStatusEntryId !== undefined)
|
|
689
702
|
const existingItems = shouldLoadItems ? await findWithDecryption(tx, SalesShipmentItem, { shipment: shipmentEntity }, {}, { tenantId: shipmentEntity.tenantId, organizationId: shipmentEntity.organizationId }) : []
|
|
690
703
|
const newItems: SalesShipmentItem[] = []
|
|
@@ -758,6 +771,9 @@ const updateShipmentCommand: CommandHandler<ShipmentUpdateInput, { shipmentId: s
|
|
|
758
771
|
}
|
|
759
772
|
}
|
|
760
773
|
|
|
774
|
+
// Flush any order/line status mutations applied above before the snapshot
|
|
775
|
+
// read below queries the same EntityManager (same interleaved-read hazard).
|
|
776
|
+
await tx.flush()
|
|
761
777
|
const itemsForSnapshot =
|
|
762
778
|
normalizedItems || shouldLoadItems
|
|
763
779
|
? (normalizedItems ? newItems : existingItems)
|
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
17
17
|
import { Label } from '@open-mercato/ui/primitives/label'
|
|
18
18
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
19
|
-
import { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
19
|
+
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
20
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
20
21
|
import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
21
22
|
import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
|
|
22
23
|
import { AppearanceSelector } from '@open-mercato/core/modules/dictionaries/components/AppearanceSelector'
|
|
@@ -219,11 +220,15 @@ export function AdjustmentKindSettings() {
|
|
|
219
220
|
? JSON.stringify(payload)
|
|
220
221
|
: JSON.stringify({ id: dialog.entry.id, ...payload })
|
|
221
222
|
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
223
|
+
const lockHeader =
|
|
224
|
+
dialog.mode === 'edit' ? buildOptimisticLockHeader(dialog.entry.updatedAt) : {}
|
|
225
|
+
const call = await withScopedApiRequestHeaders(lockHeader, () =>
|
|
226
|
+
apiCall('/api/sales/adjustment-kinds', {
|
|
227
|
+
method,
|
|
228
|
+
headers: { 'content-type': 'application/json' },
|
|
229
|
+
body,
|
|
230
|
+
})
|
|
231
|
+
)
|
|
227
232
|
if (!call.ok) {
|
|
228
233
|
await raiseCrudError(call.response, labels.saveError)
|
|
229
234
|
}
|
|
@@ -248,11 +253,15 @@ export function AdjustmentKindSettings() {
|
|
|
248
253
|
})
|
|
249
254
|
if (!confirmed) return
|
|
250
255
|
try {
|
|
251
|
-
const call = await
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
+
const call = await withScopedApiRequestHeaders(
|
|
257
|
+
buildOptimisticLockHeader(entry.updatedAt),
|
|
258
|
+
() =>
|
|
259
|
+
apiCall('/api/sales/adjustment-kinds', {
|
|
260
|
+
method: 'DELETE',
|
|
261
|
+
headers: { 'content-type': 'application/json' },
|
|
262
|
+
body: JSON.stringify({ id: entry.id }),
|
|
263
|
+
})
|
|
264
|
+
)
|
|
256
265
|
if (!call.ok) {
|
|
257
266
|
await raiseCrudError(call.response, labels.deleteError)
|
|
258
267
|
}
|
|
@@ -128,6 +128,7 @@ export function DocumentNumberSettings() {
|
|
|
128
128
|
orderNextNumber: Number.parseInt(formState.orderNextNumber, 10) || undefined,
|
|
129
129
|
quoteNextNumber: Number.parseInt(formState.quoteNextNumber, 10) || undefined,
|
|
130
130
|
}
|
|
131
|
+
// optimistic-lock-exempt: single-row tenant numbering settings blob — no per-record version / concurrent record edit
|
|
131
132
|
const call = await apiCall<SettingsResponse>('/api/sales/settings/document-numbers', {
|
|
132
133
|
method: 'PUT',
|
|
133
134
|
headers: { 'content-type': 'application/json' },
|
|
@@ -121,6 +121,7 @@ export function OrderEditingSettings() {
|
|
|
121
121
|
orderCustomerEditableStatuses: customerStatuses,
|
|
122
122
|
orderAddressEditableStatuses: addressStatuses,
|
|
123
123
|
}
|
|
124
|
+
// optimistic-lock-exempt: single-row tenant order-editing settings blob — no per-record version / concurrent record edit
|
|
124
125
|
const call = await apiCall<SettingsResponse>('/api/sales/settings/order-editing', {
|
|
125
126
|
method: 'PUT',
|
|
126
127
|
headers: { 'content-type': 'application/json' },
|
|
@@ -15,7 +15,9 @@ import {
|
|
|
15
15
|
import { Label } from '@open-mercato/ui/primitives/label'
|
|
16
16
|
import { CrudForm, type CrudField, type CrudCustomFieldRenderProps } from '@open-mercato/ui/backend/CrudForm'
|
|
17
17
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
18
|
-
import { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
18
|
+
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
19
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
20
|
+
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
19
21
|
import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
20
22
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
21
23
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -291,12 +293,14 @@ export function PaymentMethodsSettings() {
|
|
|
291
293
|
})
|
|
292
294
|
if (!confirmed) return
|
|
293
295
|
try {
|
|
294
|
-
const
|
|
296
|
+
const headers = buildOptimisticLockHeader(entry.updatedAt)
|
|
297
|
+
const call = await withScopedApiRequestHeaders(headers, () => apiCall('/api/sales/payment-methods', {
|
|
295
298
|
method: 'DELETE',
|
|
296
299
|
headers: { 'content-type': 'application/json' },
|
|
297
300
|
body: JSON.stringify({ id: entry.id }),
|
|
298
|
-
})
|
|
301
|
+
}))
|
|
299
302
|
if (!call.ok) {
|
|
303
|
+
if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return
|
|
300
304
|
await raiseCrudError(call.response, translations.errors.delete)
|
|
301
305
|
}
|
|
302
306
|
flash(translations.messages.deleted, 'success')
|
|
@@ -325,12 +329,15 @@ export function PaymentMethodsSettings() {
|
|
|
325
329
|
const method = dialog.mode === 'create' ? 'POST' : 'PUT'
|
|
326
330
|
if (dialog.mode === 'edit') payload.id = dialog.entry.id
|
|
327
331
|
try {
|
|
328
|
-
const
|
|
332
|
+
const savePaymentMethod = () => apiCall(path, {
|
|
329
333
|
method,
|
|
330
334
|
headers: { 'content-type': 'application/json' },
|
|
331
335
|
body: JSON.stringify(payload),
|
|
332
336
|
})
|
|
337
|
+
const headers = buildOptimisticLockHeader(dialog.mode === 'edit' ? dialog.entry.updatedAt : null)
|
|
338
|
+
const call = await withScopedApiRequestHeaders(headers, savePaymentMethod)
|
|
333
339
|
if (!call.ok) {
|
|
340
|
+
if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return
|
|
334
341
|
await raiseCrudError(call.response, translations.errors.save)
|
|
335
342
|
}
|
|
336
343
|
flash(translations.messages.saved, 'success')
|
|
@@ -466,6 +473,7 @@ export function PaymentMethodsSettings() {
|
|
|
466
473
|
schema={paymentFormSchema}
|
|
467
474
|
fields={fields}
|
|
468
475
|
initialValues={formValues}
|
|
476
|
+
optimisticLockUpdatedAt={dialog?.mode === 'edit' ? dialog.entry.updatedAt : null}
|
|
469
477
|
submitLabel={translations.form.save}
|
|
470
478
|
onSubmit={handleSubmit}
|
|
471
479
|
cancelHref={undefined}
|
|
@@ -24,7 +24,9 @@ import { Label } from '@open-mercato/ui/primitives/label'
|
|
|
24
24
|
import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
|
|
25
25
|
import { CrudForm, type CrudCustomFieldRenderProps, type CrudField } from '@open-mercato/ui/backend/CrudForm'
|
|
26
26
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
27
|
-
import { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
27
|
+
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
28
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
29
|
+
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
28
30
|
import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
29
31
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
30
32
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -549,12 +551,14 @@ export function ShippingMethodsSettings() {
|
|
|
549
551
|
})
|
|
550
552
|
if (!confirmed) return
|
|
551
553
|
try {
|
|
552
|
-
const
|
|
554
|
+
const headers = buildOptimisticLockHeader(entry.updatedAt)
|
|
555
|
+
const call = await withScopedApiRequestHeaders(headers, () => apiCall('/api/sales/shipping-methods', {
|
|
553
556
|
method: 'DELETE',
|
|
554
557
|
headers: { 'content-type': 'application/json' },
|
|
555
558
|
body: JSON.stringify({ id: entry.id }),
|
|
556
|
-
})
|
|
559
|
+
}))
|
|
557
560
|
if (!call.ok) {
|
|
561
|
+
if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return
|
|
558
562
|
await raiseCrudError(call.response, translations.errors.delete)
|
|
559
563
|
}
|
|
560
564
|
flash(translations.messages.deleted, 'success')
|
|
@@ -642,12 +646,15 @@ export function ShippingMethodsSettings() {
|
|
|
642
646
|
const method = dialog.mode === 'create' ? 'POST' : 'PUT'
|
|
643
647
|
if (dialog.mode === 'edit') payload.id = dialog.entry.id
|
|
644
648
|
try {
|
|
645
|
-
const
|
|
649
|
+
const saveShippingMethod = () => apiCall(path, {
|
|
646
650
|
method,
|
|
647
651
|
headers: { 'content-type': 'application/json' },
|
|
648
652
|
body: JSON.stringify(payload),
|
|
649
653
|
})
|
|
654
|
+
const headers = buildOptimisticLockHeader(dialog.mode === 'edit' ? dialog.entry.updatedAt : null)
|
|
655
|
+
const call = await withScopedApiRequestHeaders(headers, saveShippingMethod)
|
|
650
656
|
if (!call.ok) {
|
|
657
|
+
if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return
|
|
651
658
|
await raiseCrudError(call.response, translations.errors.save)
|
|
652
659
|
}
|
|
653
660
|
flash(translations.messages.saved, 'success')
|
|
@@ -770,6 +777,7 @@ export function ShippingMethodsSettings() {
|
|
|
770
777
|
schema={shippingFormSchema}
|
|
771
778
|
fields={fields}
|
|
772
779
|
initialValues={formValues}
|
|
780
|
+
optimisticLockUpdatedAt={dialog?.mode === 'edit' ? dialog.entry.updatedAt : null}
|
|
773
781
|
submitLabel={translations.form.save}
|
|
774
782
|
cancelHref={undefined}
|
|
775
783
|
embedded
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
DialogTitle,
|
|
9
9
|
} from '@open-mercato/ui/primitives/dialog'
|
|
10
10
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
11
|
-
import { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
11
|
+
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
12
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
12
13
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
13
14
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
14
15
|
import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
|
|
@@ -197,11 +198,15 @@ export function StatusSettings() {
|
|
|
197
198
|
})
|
|
198
199
|
if (!confirmed) return
|
|
199
200
|
try {
|
|
200
|
-
const call = await
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
const call = await withScopedApiRequestHeaders(
|
|
202
|
+
buildOptimisticLockHeader(entry.updatedAt),
|
|
203
|
+
() =>
|
|
204
|
+
apiCall(apiPaths[kind], {
|
|
205
|
+
method: 'DELETE',
|
|
206
|
+
headers: { 'content-type': 'application/json' },
|
|
207
|
+
body: JSON.stringify({ id: entry.id }),
|
|
208
|
+
})
|
|
209
|
+
)
|
|
205
210
|
if (!call.ok) {
|
|
206
211
|
await raiseCrudError(call.response, translate('sales.config.statuses.error.delete', 'Failed to delete status.'))
|
|
207
212
|
}
|
|
@@ -238,11 +243,15 @@ export function StatusSettings() {
|
|
|
238
243
|
if (nextColor !== (entry.color ?? null)) body.color = nextColor
|
|
239
244
|
const nextIcon = values.icon ?? null
|
|
240
245
|
if (nextIcon !== (entry.icon ?? null)) body.icon = nextIcon
|
|
241
|
-
const call = await
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
+
const call = await withScopedApiRequestHeaders(
|
|
247
|
+
buildOptimisticLockHeader(entry.updatedAt),
|
|
248
|
+
() =>
|
|
249
|
+
apiCall(path, {
|
|
250
|
+
method: 'PUT',
|
|
251
|
+
headers: { 'content-type': 'application/json' },
|
|
252
|
+
body: JSON.stringify(body),
|
|
253
|
+
})
|
|
254
|
+
)
|
|
246
255
|
if (!call.ok) {
|
|
247
256
|
await raiseCrudError(call.response, translate('sales.config.statuses.error.save', 'Failed to save status.'))
|
|
248
257
|
}
|
|
@@ -10,7 +10,9 @@ import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
|
10
10
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'
|
|
11
11
|
import { CrudForm, type CrudField } from '@open-mercato/ui/backend/CrudForm'
|
|
12
12
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
13
|
-
import { readApiResultOrThrow, apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
13
|
+
import { readApiResultOrThrow, apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
14
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
15
|
+
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
14
16
|
import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
15
17
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
16
18
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -206,12 +208,15 @@ export function TaxRatesSettings() {
|
|
|
206
208
|
payload.id = dialog.entry.id
|
|
207
209
|
}
|
|
208
210
|
try {
|
|
209
|
-
const
|
|
211
|
+
const saveTaxRate = () => apiCall('/api/sales/tax-rates', {
|
|
210
212
|
method,
|
|
211
213
|
headers: { 'content-type': 'application/json' },
|
|
212
214
|
body: JSON.stringify(payload),
|
|
213
215
|
})
|
|
216
|
+
const headers = buildOptimisticLockHeader(dialog.mode === 'edit' ? dialog.entry.updatedAt : null)
|
|
217
|
+
const call = await withScopedApiRequestHeaders(headers, saveTaxRate)
|
|
214
218
|
if (!call.ok) {
|
|
219
|
+
if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return
|
|
215
220
|
await raiseCrudError(call.response, translations.errors.save)
|
|
216
221
|
return
|
|
217
222
|
}
|
|
@@ -232,12 +237,14 @@ export function TaxRatesSettings() {
|
|
|
232
237
|
})
|
|
233
238
|
if (!confirmed) return
|
|
234
239
|
try {
|
|
235
|
-
const
|
|
240
|
+
const headers = buildOptimisticLockHeader(entry.updatedAt)
|
|
241
|
+
const call = await withScopedApiRequestHeaders(headers, () => apiCall('/api/sales/tax-rates', {
|
|
236
242
|
method: 'DELETE',
|
|
237
243
|
headers: { 'content-type': 'application/json' },
|
|
238
244
|
body: JSON.stringify({ id: entry.id }),
|
|
239
|
-
})
|
|
245
|
+
}))
|
|
240
246
|
if (!call.ok) {
|
|
247
|
+
if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return
|
|
241
248
|
await raiseCrudError(call.response, translations.errors.delete)
|
|
242
249
|
return
|
|
243
250
|
}
|
|
@@ -361,6 +368,7 @@ export function TaxRatesSettings() {
|
|
|
361
368
|
schema={taxRateFormSchema}
|
|
362
369
|
fields={fields}
|
|
363
370
|
initialValues={dialogValues}
|
|
371
|
+
optimisticLockUpdatedAt={dialog?.mode === 'edit' ? dialog.entry.updatedAt : null}
|
|
364
372
|
submitLabel={translations.form.save}
|
|
365
373
|
cancelHref={undefined}
|
|
366
374
|
embedded
|
|
@@ -387,4 +395,3 @@ function formatLocation(entry: TaxRateRow): string {
|
|
|
387
395
|
return parts.length ? parts.join(', ') : '—'
|
|
388
396
|
}
|
|
389
397
|
|
|
390
|
-
|
|
@@ -7,7 +7,9 @@ import { CrudForm, type CrudField, type CrudFormGroup, type CrudFormGroupCompone
|
|
|
7
7
|
import { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'
|
|
8
8
|
import { createCrud, updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
|
|
9
9
|
import { createCrudFormError, type CrudServerFieldErrors } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
10
|
-
import { readApiResultOrThrow, apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
10
|
+
import { readApiResultOrThrow, apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
11
|
+
import { buildOptimisticLockHeader, extractOptimisticLockConflict } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
12
|
+
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
11
13
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
12
14
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
13
15
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
@@ -41,6 +43,8 @@ type PriceOverrideDraft = {
|
|
|
41
43
|
currencyCode?: string | null
|
|
42
44
|
displayMode?: 'including-tax' | 'excluding-tax' | null
|
|
43
45
|
amount?: string
|
|
46
|
+
/** The price row's version, for the per-price optimistic-lock header (#2332). */
|
|
47
|
+
updatedAt?: string | null
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
export type OfferFormValues = {
|
|
@@ -51,6 +55,7 @@ export type OfferFormValues = {
|
|
|
51
55
|
defaultMediaId?: string | null
|
|
52
56
|
isActive: boolean
|
|
53
57
|
priceOverrides: PriceOverrideDraft[]
|
|
58
|
+
updatedAt?: string | null
|
|
54
59
|
} & Record<string, unknown>
|
|
55
60
|
|
|
56
61
|
type ChannelOfferFormProps = {
|
|
@@ -141,13 +146,15 @@ export function ChannelOfferForm({ channelId: lockedChannelId, offerId, mode }:
|
|
|
141
146
|
const variantMediaCache = React.useRef<Map<string, VariantThumbnailInfo>>(new Map())
|
|
142
147
|
const [selectedChannelId, setSelectedChannelId] = React.useState<string | null>(lockedChannelId ?? null)
|
|
143
148
|
const manualMediaSelections = React.useRef<Set<string>>(new Set())
|
|
144
|
-
|
|
149
|
+
// Map of the loaded price-override id → its `updatedAt`, so deletes during the
|
|
150
|
+
// offer save can send the price's own optimistic-lock version (#2332).
|
|
151
|
+
const initialPriceVersionsRef = React.useRef<Map<string, string | null>>(new Map())
|
|
145
152
|
const [currentProductId, setCurrentProductId] = React.useState<string | null>(null)
|
|
146
153
|
React.useEffect(() => {
|
|
147
154
|
if (initialValues) {
|
|
148
|
-
|
|
155
|
+
initialPriceVersionsRef.current = collectPriceVersions(initialValues.priceOverrides)
|
|
149
156
|
} else {
|
|
150
|
-
|
|
157
|
+
initialPriceVersionsRef.current = new Map()
|
|
151
158
|
}
|
|
152
159
|
}, [initialValues])
|
|
153
160
|
const channelOffersHref = React.useMemo(
|
|
@@ -438,12 +445,16 @@ export function ChannelOfferForm({ channelId: lockedChannelId, offerId, mode }:
|
|
|
438
445
|
if (!priceId) return true
|
|
439
446
|
if (mode !== 'edit') return true
|
|
440
447
|
try {
|
|
441
|
-
await
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
448
|
+
await withScopedApiRequestHeaders(
|
|
449
|
+
buildOptimisticLockHeader(draft.updatedAt),
|
|
450
|
+
() => deleteCrud('catalog/prices', priceId, {
|
|
451
|
+
errorMessage: t('sales.channels.offers.errors.removePrice', 'Failed to remove price override.'),
|
|
452
|
+
}),
|
|
453
|
+
)
|
|
454
|
+
initialPriceVersionsRef.current.delete(priceId)
|
|
445
455
|
return true
|
|
446
456
|
} catch (err) {
|
|
457
|
+
if (surfaceRecordConflict(err, t)) return false
|
|
447
458
|
console.error('sales.channels.pricing.remove', err)
|
|
448
459
|
flash(t('sales.channels.offers.errors.removePrice', 'Failed to remove price override.'), 'error')
|
|
449
460
|
return false
|
|
@@ -594,10 +605,11 @@ export function ChannelOfferForm({ channelId: lockedChannelId, offerId, mode }:
|
|
|
594
605
|
}
|
|
595
606
|
const submittedPriceIds = collectPriceIds(overrides)
|
|
596
607
|
const deletedIdSet = new Set<string>()
|
|
597
|
-
|
|
608
|
+
initialPriceVersionsRef.current.forEach((_version, id) => {
|
|
598
609
|
if (!submittedPriceIds.has(id)) deletedIdSet.add(id)
|
|
599
610
|
})
|
|
600
611
|
const deletedIds = Array.from(deletedIdSet)
|
|
612
|
+
const deletedVersions = new Map(deletedIds.map((id) => [id, initialPriceVersionsRef.current.get(id) ?? null]))
|
|
601
613
|
let savedId = offerId ?? null
|
|
602
614
|
try {
|
|
603
615
|
if (mode === 'create') {
|
|
@@ -612,6 +624,13 @@ export function ChannelOfferForm({ channelId: lockedChannelId, offerId, mode }:
|
|
|
612
624
|
savedId = offerId
|
|
613
625
|
}
|
|
614
626
|
} catch (err) {
|
|
627
|
+
// Let an optimistic-lock 409 propagate untouched so CrudForm's
|
|
628
|
+
// extractOptimisticLockConflict still sees the top-level `code` /
|
|
629
|
+
// `currentUpdatedAt` / `expectedUpdatedAt` and surfaces the unified
|
|
630
|
+
// conflict bar. Re-wrapping via createCrudFormError below would drop them.
|
|
631
|
+
if (extractOptimisticLockConflict(err)) {
|
|
632
|
+
throw err
|
|
633
|
+
}
|
|
615
634
|
const details = (err as { details?: unknown })?.details
|
|
616
635
|
const rawFieldErrors = (err as { fieldErrors?: unknown })?.fieldErrors
|
|
617
636
|
const fieldErrors = rawFieldErrors && typeof rawFieldErrors === 'object'
|
|
@@ -634,15 +653,16 @@ export function ChannelOfferForm({ channelId: lockedChannelId, offerId, mode }:
|
|
|
634
653
|
await syncPriceOverrides({
|
|
635
654
|
overrides,
|
|
636
655
|
deletedIds,
|
|
656
|
+
deletedVersions,
|
|
637
657
|
offerId: savedId,
|
|
638
658
|
channelId,
|
|
639
659
|
productId,
|
|
640
660
|
})
|
|
641
|
-
|
|
661
|
+
initialPriceVersionsRef.current = collectPriceVersions(overrides)
|
|
642
662
|
}
|
|
643
663
|
flash(t('sales.channels.offers.messages.saved', 'Offer saved.'), 'success')
|
|
644
664
|
router.push(buildChannelOffersHref(channelId))
|
|
645
|
-
}, [attachmentCache,
|
|
665
|
+
}, [attachmentCache, lockedChannelId, mode, offerId, router, selectedChannelId, t])
|
|
646
666
|
|
|
647
667
|
const handleDelete = React.useCallback(async () => {
|
|
648
668
|
if (!offerId) return
|
|
@@ -669,6 +689,7 @@ export function ChannelOfferForm({ channelId: lockedChannelId, offerId, mode }:
|
|
|
669
689
|
fields={fields}
|
|
670
690
|
groups={groups}
|
|
671
691
|
initialValues={initialValues ?? undefined}
|
|
692
|
+
optimisticLockUpdatedAt={initialValues?.updatedAt}
|
|
672
693
|
isLoading={loading}
|
|
673
694
|
loadingMessage={t('sales.channels.offers.form.loading', 'Loading offer…')}
|
|
674
695
|
submitLabel={mode === 'create'
|
|
@@ -706,6 +727,11 @@ function mapOfferToFormValues(item: Record<string, unknown>, lockedChannelId?: s
|
|
|
706
727
|
: null,
|
|
707
728
|
isActive: item.isActive === true || item.is_active === true,
|
|
708
729
|
priceOverrides: [],
|
|
730
|
+
updatedAt: typeof item.updatedAt === 'string'
|
|
731
|
+
? item.updatedAt
|
|
732
|
+
: typeof item.updated_at === 'string'
|
|
733
|
+
? item.updated_at
|
|
734
|
+
: null,
|
|
709
735
|
}
|
|
710
736
|
mergeCustomFieldValues(values, item)
|
|
711
737
|
return values
|
|
@@ -742,6 +768,11 @@ function mapPriceRow(row: Record<string, unknown>): PriceOverrideDraft {
|
|
|
742
768
|
: typeof row.unit_price_gross === 'string'
|
|
743
769
|
? row.unit_price_gross
|
|
744
770
|
: '',
|
|
771
|
+
updatedAt: typeof row.updatedAt === 'string'
|
|
772
|
+
? row.updatedAt
|
|
773
|
+
: typeof row.updated_at === 'string'
|
|
774
|
+
? row.updated_at
|
|
775
|
+
: null,
|
|
745
776
|
}
|
|
746
777
|
}
|
|
747
778
|
|
|
@@ -753,6 +784,17 @@ function collectPriceIds(source: PriceOverrideDraft[] | null | undefined): Set<s
|
|
|
753
784
|
return new Set(ids)
|
|
754
785
|
}
|
|
755
786
|
|
|
787
|
+
function collectPriceVersions(source: PriceOverrideDraft[] | null | undefined): Map<string, string | null> {
|
|
788
|
+
const versions = new Map<string, string | null>()
|
|
789
|
+
if (!Array.isArray(source)) return versions
|
|
790
|
+
for (const entry of source) {
|
|
791
|
+
if (typeof entry?.priceId === 'string' && entry.priceId) {
|
|
792
|
+
versions.set(entry.priceId, typeof entry.updatedAt === 'string' ? entry.updatedAt : null)
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return versions
|
|
796
|
+
}
|
|
797
|
+
|
|
756
798
|
function mergeCustomFieldValues(target: Record<string, unknown>, source: Record<string, unknown> | null | undefined) {
|
|
757
799
|
Object.assign(target, extractCustomFieldEntries(source ?? {}))
|
|
758
800
|
}
|
|
@@ -766,11 +808,12 @@ function buildChannelOffersHref(channelId?: string | null): string {
|
|
|
766
808
|
async function syncPriceOverrides(params: {
|
|
767
809
|
overrides: PriceOverrideDraft[]
|
|
768
810
|
deletedIds: string[]
|
|
811
|
+
deletedVersions: Map<string, string | null>
|
|
769
812
|
offerId: string
|
|
770
813
|
channelId: string
|
|
771
814
|
productId: string
|
|
772
815
|
}) {
|
|
773
|
-
const { overrides, deletedIds, offerId, channelId, productId } = params
|
|
816
|
+
const { overrides, deletedIds, deletedVersions, offerId, channelId, productId } = params
|
|
774
817
|
for (const draft of overrides) {
|
|
775
818
|
if (!draft.priceKindId || !draft.amount) continue
|
|
776
819
|
const amount = Number(draft.amount)
|
|
@@ -788,7 +831,14 @@ async function syncPriceOverrides(params: {
|
|
|
788
831
|
payload.unitPriceNet = amount
|
|
789
832
|
}
|
|
790
833
|
if (draft.priceId) {
|
|
791
|
-
|
|
834
|
+
// Send the PRICE's own version, overriding the offer header the parent
|
|
835
|
+
// CrudForm submit scope put on the stack (otherwise the price guard would
|
|
836
|
+
// compare the offer's `updated_at` and 409 falsely). #2332.
|
|
837
|
+
const priceId = draft.priceId
|
|
838
|
+
await withScopedApiRequestHeaders(
|
|
839
|
+
buildOptimisticLockHeader(draft.updatedAt),
|
|
840
|
+
() => updateCrud('catalog/prices', { id: priceId, ...payload }),
|
|
841
|
+
)
|
|
792
842
|
} else {
|
|
793
843
|
await createCrud('catalog/prices', payload)
|
|
794
844
|
}
|
|
@@ -799,7 +849,10 @@ async function syncPriceOverrides(params: {
|
|
|
799
849
|
for (const id of uniqueDeletedIds) {
|
|
800
850
|
if (!id) continue
|
|
801
851
|
try {
|
|
802
|
-
await
|
|
852
|
+
await withScopedApiRequestHeaders(
|
|
853
|
+
buildOptimisticLockHeader(deletedVersions.get(id) ?? null),
|
|
854
|
+
() => deleteCrud('catalog/prices', id),
|
|
855
|
+
)
|
|
803
856
|
} catch (err) {
|
|
804
857
|
console.error('catalog.prices.delete', err)
|
|
805
858
|
}
|