@open-mercato/core 0.6.7-develop.6669.1.40b669666b → 0.6.7-develop.6670.1.4efa7961c6
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/dist/generated/entities/inventory_balance/index.js +21 -0
- package/dist/generated/entities/inventory_balance/index.js.map +7 -0
- package/dist/generated/entities/inventory_lot/index.js +19 -0
- package/dist/generated/entities/inventory_lot/index.js.map +7 -0
- package/dist/generated/entities/inventory_movement/index.js +35 -0
- package/dist/generated/entities/inventory_movement/index.js.map +7 -0
- package/dist/generated/entities/inventory_reservation/index.js +23 -0
- package/dist/generated/entities/inventory_reservation/index.js.map +7 -0
- package/dist/generated/entities/product_inventory_profile/index.js +21 -0
- package/dist/generated/entities/product_inventory_profile/index.js.map +7 -0
- package/dist/generated/entities/sales_order_warehouse_assignment/index.js +11 -0
- package/dist/generated/entities/sales_order_warehouse_assignment/index.js.map +7 -0
- package/dist/generated/entities/warehouse/index.js +25 -0
- package/dist/generated/entities/warehouse/index.js.map +7 -0
- package/dist/generated/entities/warehouse_location/index.js +21 -0
- package/dist/generated/entities/warehouse_location/index.js.map +7 -0
- package/dist/generated/entities/warehouse_zone/index.js +11 -0
- package/dist/generated/entities/warehouse_zone/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +12 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +98 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +12 -4
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/lib/backendChrome.js +1 -0
- package/dist/modules/auth/lib/backendChrome.js.map +2 -2
- package/dist/modules/auth/services/rbacService.js +16 -17
- package/dist/modules/auth/services/rbacService.js.map +2 -2
- package/dist/modules/catalog/api/products/route.js +3 -0
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/api/variants/route.js +3 -0
- package/dist/modules/catalog/api/variants/route.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +6 -6
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/sales/api/documents/factory.js +1 -0
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +53 -0
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +51 -2
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/events.js +2 -0
- package/dist/modules/sales/events.js.map +2 -2
- package/dist/modules/sales/widgets/injection/order-items-context.js +11 -0
- package/dist/modules/sales/widgets/injection/order-items-context.js.map +7 -0
- package/dist/modules/wms/acl.js +18 -0
- package/dist/modules/wms/acl.js.map +7 -0
- package/dist/modules/wms/analytics.js +11 -0
- package/dist/modules/wms/analytics.js.map +7 -0
- package/dist/modules/wms/api/dashboard/operational/route.js +80 -0
- package/dist/modules/wms/api/dashboard/operational/route.js.map +7 -0
- package/dist/modules/wms/api/interceptors.js +90 -0
- package/dist/modules/wms/api/interceptors.js.map +7 -0
- package/dist/modules/wms/api/inventory/adjust/route.js +51 -0
- package/dist/modules/wms/api/inventory/adjust/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/allocate/route.js +51 -0
- package/dist/modules/wms/api/inventory/allocate/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/balances/route.js +172 -0
- package/dist/modules/wms/api/inventory/balances/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/cycle-count/route.js +52 -0
- package/dist/modules/wms/api/inventory/cycle-count/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/helpers.js +113 -0
- package/dist/modules/wms/api/inventory/helpers.js.map +7 -0
- package/dist/modules/wms/api/inventory/import/apply/route.js +46 -0
- package/dist/modules/wms/api/inventory/import/apply/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/import/helpers.js +195 -0
- package/dist/modules/wms/api/inventory/import/helpers.js.map +7 -0
- package/dist/modules/wms/api/inventory/import/template/route.js +32 -0
- package/dist/modules/wms/api/inventory/import/template/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/import/validate/route.js +54 -0
- package/dist/modules/wms/api/inventory/import/validate/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/move/route.js +51 -0
- package/dist/modules/wms/api/inventory/move/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/movements/route.js +164 -0
- package/dist/modules/wms/api/inventory/movements/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/receive/route.js +50 -0
- package/dist/modules/wms/api/inventory/receive/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/release/route.js +44 -0
- package/dist/modules/wms/api/inventory/release/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/reservations/route.js +128 -0
- package/dist/modules/wms/api/inventory/reservations/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/reserve/route.js +59 -0
- package/dist/modules/wms/api/inventory/reserve/route.js.map +7 -0
- package/dist/modules/wms/api/inventory-profiles/route.js +178 -0
- package/dist/modules/wms/api/inventory-profiles/route.js.map +7 -0
- package/dist/modules/wms/api/listEnrichers.js +181 -0
- package/dist/modules/wms/api/listEnrichers.js.map +7 -0
- package/dist/modules/wms/api/listSearch.js +77 -0
- package/dist/modules/wms/api/listSearch.js.map +7 -0
- package/dist/modules/wms/api/locations/route.js +172 -0
- package/dist/modules/wms/api/locations/route.js.map +7 -0
- package/dist/modules/wms/api/lots/route.js +204 -0
- package/dist/modules/wms/api/lots/route.js.map +7 -0
- package/dist/modules/wms/api/openapi.js +27 -0
- package/dist/modules/wms/api/openapi.js.map +7 -0
- package/dist/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.js +54 -0
- package/dist/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.js.map +7 -0
- package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js +279 -0
- package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js.map +7 -0
- package/dist/modules/wms/api/sales-orders/assign-warehouse/route.js +56 -0
- package/dist/modules/wms/api/sales-orders/assign-warehouse/route.js.map +7 -0
- package/dist/modules/wms/api/sales-orders/unassign-warehouse/route.js +43 -0
- package/dist/modules/wms/api/sales-orders/unassign-warehouse/route.js.map +7 -0
- package/dist/modules/wms/api/warehouses/route.js +181 -0
- package/dist/modules/wms/api/warehouses/route.js.map +7 -0
- package/dist/modules/wms/api/zones/route.js +159 -0
- package/dist/modules/wms/api/zones/route.js.map +7 -0
- package/dist/modules/wms/backend/config/wms/page.js +9 -0
- package/dist/modules/wms/backend/config/wms/page.js.map +7 -0
- package/dist/modules/wms/backend/config/wms/page.meta.js +18 -0
- package/dist/modules/wms/backend/config/wms/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/page.js +9 -0
- package/dist/modules/wms/backend/page.js.map +7 -0
- package/dist/modules/wms/backend/page.meta.js +16 -0
- package/dist/modules/wms/backend/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/inventory/page.js +9 -0
- package/dist/modules/wms/backend/wms/inventory/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/inventory/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/inventory/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/location/[id]/page.js +9 -0
- package/dist/modules/wms/backend/wms/location/[id]/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/location/[id]/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/location/[id]/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/locations/page.js +10 -0
- package/dist/modules/wms/backend/wms/locations/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/locations/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/locations/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/lot/[id]/page.js +9 -0
- package/dist/modules/wms/backend/wms/lot/[id]/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/lot/[id]/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/lot/[id]/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/lots/page.js +9 -0
- package/dist/modules/wms/backend/wms/lots/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/lots/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/lots/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/movements/page.js +22 -0
- package/dist/modules/wms/backend/wms/movements/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/movements/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/movements/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/reservations/page.js +23 -0
- package/dist/modules/wms/backend/wms/reservations/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/reservations/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/reservations/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/sku/[id]/page.js +9 -0
- package/dist/modules/wms/backend/wms/sku/[id]/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/sku/[id]/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/sku/[id]/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/warehouses/page.js +10 -0
- package/dist/modules/wms/backend/wms/warehouses/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/warehouses/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/warehouses/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/zones/page.js +10 -0
- package/dist/modules/wms/backend/wms/zones/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/zones/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/zones/page.meta.js.map +7 -0
- package/dist/modules/wms/ce.js +80 -0
- package/dist/modules/wms/ce.js.map +7 -0
- package/dist/modules/wms/cli.js +83 -0
- package/dist/modules/wms/cli.js.map +7 -0
- package/dist/modules/wms/commands/configuration.js +1519 -0
- package/dist/modules/wms/commands/configuration.js.map +7 -0
- package/dist/modules/wms/commands/index.js +4 -0
- package/dist/modules/wms/commands/index.js.map +7 -0
- package/dist/modules/wms/commands/inventory-actions.js +1539 -0
- package/dist/modules/wms/commands/inventory-actions.js.map +7 -0
- package/dist/modules/wms/commands/sales-order-assignment.js +277 -0
- package/dist/modules/wms/commands/sales-order-assignment.js.map +7 -0
- package/dist/modules/wms/commands/shared.js +82 -0
- package/dist/modules/wms/commands/shared.js.map +7 -0
- package/dist/modules/wms/components/backend/AdjustInventoryDialog.js +755 -0
- package/dist/modules/wms/components/backend/AdjustInventoryDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/ChangeLotStatusDialog.js +269 -0
- package/dist/modules/wms/components/backend/ChangeLotStatusDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/CycleCountWizardDialog.js +1783 -0
- package/dist/modules/wms/components/backend/CycleCountWizardDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/ImportInventoryDialog.js +766 -0
- package/dist/modules/wms/components/backend/ImportInventoryDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/InventoryOperationsSection.js +119 -0
- package/dist/modules/wms/components/backend/InventoryOperationsSection.js.map +7 -0
- package/dist/modules/wms/components/backend/LocationEditDialog.js +140 -0
- package/dist/modules/wms/components/backend/LocationEditDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/MoveInventoryDialog.js +791 -0
- package/dist/modules/wms/components/backend/MoveInventoryDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js +656 -0
- package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/ReleaseReservationDialog.js +344 -0
- package/dist/modules/wms/components/backend/ReleaseReservationDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/ReserveInventoryDialog.js +475 -0
- package/dist/modules/wms/components/backend/ReserveInventoryDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js +1112 -0
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +908 -0
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +1015 -0
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js +1049 -0
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsLotsListPage.js +297 -0
- package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js +757 -0
- package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +975 -0
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +7 -0
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +710 -0
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +7 -0
- package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js +79 -0
- package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js.map +7 -0
- package/dist/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.js +24 -0
- package/dist/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.js.map +7 -0
- package/dist/modules/wms/components/backend/wmsLookupLoaders.js +55 -0
- package/dist/modules/wms/components/backend/wmsLookupLoaders.js.map +7 -0
- package/dist/modules/wms/data/enrichers.js +501 -0
- package/dist/modules/wms/data/enrichers.js.map +7 -0
- package/dist/modules/wms/data/entities.js +467 -0
- package/dist/modules/wms/data/entities.js.map +7 -0
- package/dist/modules/wms/data/validators.js +399 -0
- package/dist/modules/wms/data/validators.js.map +7 -0
- package/dist/modules/wms/di.js +27 -0
- package/dist/modules/wms/di.js.map +7 -0
- package/dist/modules/wms/events.js +42 -0
- package/dist/modules/wms/events.js.map +7 -0
- package/dist/modules/wms/index.js +17 -0
- package/dist/modules/wms/index.js.map +7 -0
- package/dist/modules/wms/lib/catalogInventoryProfileIntent.js +54 -0
- package/dist/modules/wms/lib/catalogInventoryProfileIntent.js.map +7 -0
- package/dist/modules/wms/lib/catalogInventoryProfileSync.js +144 -0
- package/dist/modules/wms/lib/catalogInventoryProfileSync.js.map +7 -0
- package/dist/modules/wms/lib/expiry.js +29 -0
- package/dist/modules/wms/lib/expiry.js.map +7 -0
- package/dist/modules/wms/lib/flashMutationError.js +51 -0
- package/dist/modules/wms/lib/flashMutationError.js.map +7 -0
- package/dist/modules/wms/lib/inventoryDisplayUi.js +188 -0
- package/dist/modules/wms/lib/inventoryDisplayUi.js.map +7 -0
- package/dist/modules/wms/lib/inventoryIdempotency.js +37 -0
- package/dist/modules/wms/lib/inventoryIdempotency.js.map +7 -0
- package/dist/modules/wms/lib/inventoryImportCsv.js +173 -0
- package/dist/modules/wms/lib/inventoryImportCsv.js.map +7 -0
- package/dist/modules/wms/lib/inventoryImportService.js +468 -0
- package/dist/modules/wms/lib/inventoryImportService.js.map +7 -0
- package/dist/modules/wms/lib/inventoryMutationUi.js +25 -0
- package/dist/modules/wms/lib/inventoryMutationUi.js.map +7 -0
- package/dist/modules/wms/lib/inventoryPolicy.js +61 -0
- package/dist/modules/wms/lib/inventoryPolicy.js.map +7 -0
- package/dist/modules/wms/lib/inventoryReconciliation.js +193 -0
- package/dist/modules/wms/lib/inventoryReconciliation.js.map +7 -0
- package/dist/modules/wms/lib/inventoryTrackingValidation.js +13 -0
- package/dist/modules/wms/lib/inventoryTrackingValidation.js.map +7 -0
- package/dist/modules/wms/lib/loadOperationalDashboard.js +580 -0
- package/dist/modules/wms/lib/loadOperationalDashboard.js.map +7 -0
- package/dist/modules/wms/lib/lowStockBalanceFilter.js +49 -0
- package/dist/modules/wms/lib/lowStockBalanceFilter.js.map +7 -0
- package/dist/modules/wms/lib/primaryWarehousePolicy.js +32 -0
- package/dist/modules/wms/lib/primaryWarehousePolicy.js.map +7 -0
- package/dist/modules/wms/lib/roleFeatures.js +30 -0
- package/dist/modules/wms/lib/roleFeatures.js.map +7 -0
- package/dist/modules/wms/lib/salesOrderInventoryAutomation.js +291 -0
- package/dist/modules/wms/lib/salesOrderInventoryAutomation.js.map +7 -0
- package/dist/modules/wms/lib/salesOrderWarehouseAssignment.js +54 -0
- package/dist/modules/wms/lib/salesOrderWarehouseAssignment.js.map +7 -0
- package/dist/modules/wms/lib/wmsIntegrationToggles.js +71 -0
- package/dist/modules/wms/lib/wmsIntegrationToggles.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20260428110546.js +78 -0
- package/dist/modules/wms/migrations/Migration20260428110546.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20260527120000.js +15 -0
- package/dist/modules/wms/migrations/Migration20260527120000.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20260527140000.js +37 -0
- package/dist/modules/wms/migrations/Migration20260527140000.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20260613120000.js +23 -0
- package/dist/modules/wms/migrations/Migration20260613120000.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20260616090000.js +13 -0
- package/dist/modules/wms/migrations/Migration20260616090000.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20260707180000.js +15 -0
- package/dist/modules/wms/migrations/Migration20260707180000.js.map +7 -0
- package/dist/modules/wms/notifications.client.js +18 -0
- package/dist/modules/wms/notifications.client.js.map +7 -0
- package/dist/modules/wms/notifications.js +53 -0
- package/dist/modules/wms/notifications.js.map +7 -0
- package/dist/modules/wms/search.js +196 -0
- package/dist/modules/wms/search.js.map +7 -0
- package/dist/modules/wms/setup.js +30 -0
- package/dist/modules/wms/setup.js.map +7 -0
- package/dist/modules/wms/subscribers/low-stock-notification.js +40 -0
- package/dist/modules/wms/subscribers/low-stock-notification.js.map +7 -0
- package/dist/modules/wms/subscribers/reservation-shortfall-notification.js +69 -0
- package/dist/modules/wms/subscribers/reservation-shortfall-notification.js.map +7 -0
- package/dist/modules/wms/subscribers/sales-order-cancelled-release.js +14 -0
- package/dist/modules/wms/subscribers/sales-order-cancelled-release.js.map +7 -0
- package/dist/modules/wms/subscribers/sales-order-confirmed-reserve.js +14 -0
- package/dist/modules/wms/subscribers/sales-order-confirmed-reserve.js.map +7 -0
- package/dist/modules/wms/translations.js +10 -0
- package/dist/modules/wms/translations.js.map +7 -0
- package/dist/modules/wms/vector.js +9 -0
- package/dist/modules/wms/vector.js.map +7 -0
- package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js +200 -0
- package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js.map +7 -0
- package/dist/modules/wms/widgets/injection/order-items-stock-column/widget.js +104 -0
- package/dist/modules/wms/widgets/injection/order-items-stock-column/widget.js.map +7 -0
- package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js +389 -0
- package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js.map +7 -0
- package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.js +16 -0
- package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.js.map +7 -0
- package/dist/modules/wms/widgets/injection-table.js +36 -0
- package/dist/modules/wms/widgets/injection-table.js.map +7 -0
- package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js +150 -0
- package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js.map +7 -0
- package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js +186 -0
- package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js.map +7 -0
- package/dist/modules/wms/widgets/notifications/index.js +7 -0
- package/dist/modules/wms/widgets/notifications/index.js.map +7 -0
- package/generated/entities/inventory_balance/index.ts +9 -0
- package/generated/entities/inventory_lot/index.ts +8 -0
- package/generated/entities/inventory_movement/index.ts +16 -0
- package/generated/entities/inventory_reservation/index.ts +10 -0
- package/generated/entities/product_inventory_profile/index.ts +9 -0
- package/generated/entities/sales_order_warehouse_assignment/index.ts +4 -0
- package/generated/entities/warehouse/index.ts +11 -0
- package/generated/entities/warehouse_location/index.ts +9 -0
- package/generated/entities/warehouse_zone/index.ts +4 -0
- package/generated/entities.ids.generated.ts +12 -0
- package/generated/entity-fields-registry.ts +98 -0
- package/package.json +7 -7
- package/src/modules/auth/backend/roles/page.tsx +13 -4
- package/src/modules/auth/i18n/de.json +2 -0
- package/src/modules/auth/i18n/en.json +2 -0
- package/src/modules/auth/i18n/es.json +2 -0
- package/src/modules/auth/i18n/pl.json +2 -0
- package/src/modules/auth/lib/backendChrome.tsx +1 -0
- package/src/modules/auth/services/rbacService.ts +25 -21
- package/src/modules/catalog/api/products/route.ts +3 -0
- package/src/modules/catalog/api/variants/route.ts +3 -0
- package/src/modules/query_index/lib/engine.ts +18 -6
- package/src/modules/sales/api/documents/factory.ts +1 -0
- package/src/modules/sales/commands/documents.ts +71 -0
- package/src/modules/sales/components/documents/ItemsSection.tsx +58 -0
- package/src/modules/sales/events.ts +2 -0
- package/src/modules/sales/widgets/injection/order-items-context.ts +15 -0
- package/src/modules/wms/acl.ts +14 -0
- package/src/modules/wms/analytics.ts +9 -0
- package/src/modules/wms/api/dashboard/operational/route.ts +83 -0
- package/src/modules/wms/api/interceptors.ts +108 -0
- package/src/modules/wms/api/inventory/adjust/route.ts +50 -0
- package/src/modules/wms/api/inventory/allocate/route.ts +50 -0
- package/src/modules/wms/api/inventory/balances/route.ts +178 -0
- package/src/modules/wms/api/inventory/cycle-count/route.ts +51 -0
- package/src/modules/wms/api/inventory/helpers.ts +128 -0
- package/src/modules/wms/api/inventory/import/apply/route.ts +47 -0
- package/src/modules/wms/api/inventory/import/helpers.ts +223 -0
- package/src/modules/wms/api/inventory/import/template/route.ts +31 -0
- package/src/modules/wms/api/inventory/import/validate/route.ts +56 -0
- package/src/modules/wms/api/inventory/move/route.ts +50 -0
- package/src/modules/wms/api/inventory/movements/route.ts +164 -0
- package/src/modules/wms/api/inventory/receive/route.ts +49 -0
- package/src/modules/wms/api/inventory/release/route.ts +43 -0
- package/src/modules/wms/api/inventory/reservations/route.ts +128 -0
- package/src/modules/wms/api/inventory/reserve/route.ts +59 -0
- package/src/modules/wms/api/inventory-profiles/route.ts +177 -0
- package/src/modules/wms/api/listEnrichers.ts +312 -0
- package/src/modules/wms/api/listSearch.ts +121 -0
- package/src/modules/wms/api/locations/route.ts +171 -0
- package/src/modules/wms/api/lots/route.ts +205 -0
- package/src/modules/wms/api/openapi.ts +28 -0
- package/src/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.ts +58 -0
- package/src/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.ts +306 -0
- package/src/modules/wms/api/sales-orders/assign-warehouse/route.ts +57 -0
- package/src/modules/wms/api/sales-orders/unassign-warehouse/route.ts +43 -0
- package/src/modules/wms/api/warehouses/route.ts +181 -0
- package/src/modules/wms/api/zones/route.ts +158 -0
- package/src/modules/wms/backend/config/wms/page.meta.ts +14 -0
- package/src/modules/wms/backend/config/wms/page.tsx +5 -0
- package/src/modules/wms/backend/page.meta.ts +12 -0
- package/src/modules/wms/backend/page.tsx +5 -0
- package/src/modules/wms/backend/wms/inventory/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/inventory/page.tsx +5 -0
- package/src/modules/wms/backend/wms/location/[id]/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/location/[id]/page.tsx +5 -0
- package/src/modules/wms/backend/wms/locations/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/locations/page.tsx +12 -0
- package/src/modules/wms/backend/wms/lot/[id]/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/lot/[id]/page.tsx +5 -0
- package/src/modules/wms/backend/wms/lots/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/lots/page.tsx +5 -0
- package/src/modules/wms/backend/wms/movements/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/movements/page.tsx +23 -0
- package/src/modules/wms/backend/wms/reservations/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/reservations/page.tsx +24 -0
- package/src/modules/wms/backend/wms/sku/[id]/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/sku/[id]/page.tsx +5 -0
- package/src/modules/wms/backend/wms/warehouses/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/warehouses/page.tsx +12 -0
- package/src/modules/wms/backend/wms/zones/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/zones/page.tsx +12 -0
- package/src/modules/wms/ce.ts +76 -0
- package/src/modules/wms/cli.ts +96 -0
- package/src/modules/wms/commands/configuration.ts +1844 -0
- package/src/modules/wms/commands/index.ts +3 -0
- package/src/modules/wms/commands/inventory-actions.ts +1866 -0
- package/src/modules/wms/commands/sales-order-assignment.ts +346 -0
- package/src/modules/wms/commands/shared.ts +90 -0
- package/src/modules/wms/components/backend/AdjustInventoryDialog.tsx +820 -0
- package/src/modules/wms/components/backend/ChangeLotStatusDialog.tsx +312 -0
- package/src/modules/wms/components/backend/CycleCountWizardDialog.tsx +2007 -0
- package/src/modules/wms/components/backend/ImportInventoryDialog.tsx +1018 -0
- package/src/modules/wms/components/backend/InventoryOperationsSection.tsx +159 -0
- package/src/modules/wms/components/backend/LocationEditDialog.tsx +185 -0
- package/src/modules/wms/components/backend/MoveInventoryDialog.tsx +907 -0
- package/src/modules/wms/components/backend/ReceiveInventoryDialog.tsx +695 -0
- package/src/modules/wms/components/backend/ReleaseReservationDialog.tsx +424 -0
- package/src/modules/wms/components/backend/ReserveInventoryDialog.tsx +511 -0
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +1340 -0
- package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +1132 -0
- package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +1310 -0
- package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +1355 -0
- package/src/modules/wms/components/backend/WmsLotsListPage.tsx +359 -0
- package/src/modules/wms/components/backend/WmsOperationalDashboardPage.tsx +958 -0
- package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +1245 -0
- package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +960 -0
- package/src/modules/wms/components/backend/useWmsInventoryMutationAccess.ts +89 -0
- package/src/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.ts +32 -0
- package/src/modules/wms/components/backend/wmsLookupLoaders.ts +78 -0
- package/src/modules/wms/data/enrichers.ts +718 -0
- package/src/modules/wms/data/entities.ts +436 -0
- package/src/modules/wms/data/validators.ts +463 -0
- package/src/modules/wms/di.ts +25 -0
- package/src/modules/wms/events.ts +41 -0
- package/src/modules/wms/i18n/de.json +1051 -0
- package/src/modules/wms/i18n/en.json +1051 -0
- package/src/modules/wms/i18n/es.json +1051 -0
- package/src/modules/wms/i18n/pl.json +1051 -0
- package/src/modules/wms/index.ts +15 -0
- package/src/modules/wms/lib/catalogInventoryProfileIntent.ts +65 -0
- package/src/modules/wms/lib/catalogInventoryProfileSync.ts +199 -0
- package/src/modules/wms/lib/expiry.ts +30 -0
- package/src/modules/wms/lib/flashMutationError.ts +74 -0
- package/src/modules/wms/lib/inventoryDisplayUi.ts +249 -0
- package/src/modules/wms/lib/inventoryIdempotency.ts +54 -0
- package/src/modules/wms/lib/inventoryImportCsv.ts +212 -0
- package/src/modules/wms/lib/inventoryImportService.ts +629 -0
- package/src/modules/wms/lib/inventoryMutationUi.ts +21 -0
- package/src/modules/wms/lib/inventoryPolicy.ts +111 -0
- package/src/modules/wms/lib/inventoryReconciliation.ts +263 -0
- package/src/modules/wms/lib/inventoryTrackingValidation.ts +23 -0
- package/src/modules/wms/lib/loadOperationalDashboard.ts +776 -0
- package/src/modules/wms/lib/lowStockBalanceFilter.ts +74 -0
- package/src/modules/wms/lib/primaryWarehousePolicy.ts +46 -0
- package/src/modules/wms/lib/roleFeatures.ts +32 -0
- package/src/modules/wms/lib/salesOrderInventoryAutomation.ts +390 -0
- package/src/modules/wms/lib/salesOrderWarehouseAssignment.ts +78 -0
- package/src/modules/wms/lib/wmsIntegrationToggles.ts +81 -0
- package/src/modules/wms/migrations/.snapshot-open-mercato.json +2880 -0
- package/src/modules/wms/migrations/Migration20260428110546.ts +91 -0
- package/src/modules/wms/migrations/Migration20260527120000.ts +15 -0
- package/src/modules/wms/migrations/Migration20260527140000.ts +35 -0
- package/src/modules/wms/migrations/Migration20260613120000.ts +21 -0
- package/src/modules/wms/migrations/Migration20260616090000.ts +11 -0
- package/src/modules/wms/migrations/Migration20260707180000.ts +13 -0
- package/src/modules/wms/notifications.client.ts +18 -0
- package/src/modules/wms/notifications.ts +51 -0
- package/src/modules/wms/search.ts +230 -0
- package/src/modules/wms/setup.ts +29 -0
- package/src/modules/wms/subscribers/low-stock-notification.ts +54 -0
- package/src/modules/wms/subscribers/reservation-shortfall-notification.ts +98 -0
- package/src/modules/wms/subscribers/sales-order-cancelled-release.ts +21 -0
- package/src/modules/wms/subscribers/sales-order-confirmed-reserve.ts +21 -0
- package/src/modules/wms/translations.ts +6 -0
- package/src/modules/wms/vector.ts +7 -0
- package/src/modules/wms/widgets/injection/catalog-inventory-profile/widget.ts +238 -0
- package/src/modules/wms/widgets/injection/order-items-stock-column/widget.tsx +153 -0
- package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.client.tsx +476 -0
- package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.ts +15 -0
- package/src/modules/wms/widgets/injection-table.ts +34 -0
- package/src/modules/wms/widgets/notifications/WmsLowStockRenderer.tsx +153 -0
- package/src/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.tsx +194 -0
- package/src/modules/wms/widgets/notifications/index.ts +2 -0
|
@@ -1453,6 +1453,57 @@ export const entityFieldsRegistry: Record<string, Record<string, string>> = {
|
|
|
1453
1453
|
"updated_at": "updated_at",
|
|
1454
1454
|
"deleted_at": "deleted_at"
|
|
1455
1455
|
},
|
|
1456
|
+
"inventory_balance": {
|
|
1457
|
+
"warehouse": "warehouse",
|
|
1458
|
+
"location": "location",
|
|
1459
|
+
"catalog_variant_id": "catalog_variant_id",
|
|
1460
|
+
"lot": "lot",
|
|
1461
|
+
"serial_number": "serial_number",
|
|
1462
|
+
"quantity_on_hand": "quantity_on_hand",
|
|
1463
|
+
"quantity_reserved": "quantity_reserved",
|
|
1464
|
+
"quantity_allocated": "quantity_allocated",
|
|
1465
|
+
"quantity_available": "quantity_available"
|
|
1466
|
+
},
|
|
1467
|
+
"inventory_lot": {
|
|
1468
|
+
"catalog_variant_id": "catalog_variant_id",
|
|
1469
|
+
"sku": "sku",
|
|
1470
|
+
"lot_number": "lot_number",
|
|
1471
|
+
"batch_number": "batch_number",
|
|
1472
|
+
"manufactured_at": "manufactured_at",
|
|
1473
|
+
"best_before_at": "best_before_at",
|
|
1474
|
+
"expires_at": "expires_at",
|
|
1475
|
+
"status": "status"
|
|
1476
|
+
},
|
|
1477
|
+
"inventory_movement": {
|
|
1478
|
+
"warehouse": "warehouse",
|
|
1479
|
+
"location_from": "location_from",
|
|
1480
|
+
"location_to": "location_to",
|
|
1481
|
+
"catalog_variant_id": "catalog_variant_id",
|
|
1482
|
+
"lot": "lot",
|
|
1483
|
+
"serial_number": "serial_number",
|
|
1484
|
+
"quantity": "quantity",
|
|
1485
|
+
"type": "type",
|
|
1486
|
+
"reference_type": "reference_type",
|
|
1487
|
+
"reference_id": "reference_id",
|
|
1488
|
+
"performed_by": "performed_by",
|
|
1489
|
+
"performed_at": "performed_at",
|
|
1490
|
+
"received_at": "received_at",
|
|
1491
|
+
"reason": "reason",
|
|
1492
|
+
"reason_code": "reason_code",
|
|
1493
|
+
"idempotency_key": "idempotency_key"
|
|
1494
|
+
},
|
|
1495
|
+
"inventory_reservation": {
|
|
1496
|
+
"warehouse": "warehouse",
|
|
1497
|
+
"catalog_variant_id": "catalog_variant_id",
|
|
1498
|
+
"lot": "lot",
|
|
1499
|
+
"serial_number": "serial_number",
|
|
1500
|
+
"quantity": "quantity",
|
|
1501
|
+
"source_type": "source_type",
|
|
1502
|
+
"source_id": "source_id",
|
|
1503
|
+
"expires_at": "expires_at",
|
|
1504
|
+
"status": "status",
|
|
1505
|
+
"idempotency_key": "idempotency_key"
|
|
1506
|
+
},
|
|
1456
1507
|
"message": {
|
|
1457
1508
|
"id": "id",
|
|
1458
1509
|
"type": "type",
|
|
@@ -1674,6 +1725,17 @@ export const entityFieldsRegistry: Record<string, Record<string, string>> = {
|
|
|
1674
1725
|
"updated_at": "updated_at",
|
|
1675
1726
|
"deleted_at": "deleted_at"
|
|
1676
1727
|
},
|
|
1728
|
+
"product_inventory_profile": {
|
|
1729
|
+
"catalog_product_id": "catalog_product_id",
|
|
1730
|
+
"catalog_variant_id": "catalog_variant_id",
|
|
1731
|
+
"default_uom": "default_uom",
|
|
1732
|
+
"track_lot": "track_lot",
|
|
1733
|
+
"track_serial": "track_serial",
|
|
1734
|
+
"track_expiration": "track_expiration",
|
|
1735
|
+
"default_strategy": "default_strategy",
|
|
1736
|
+
"reorder_point": "reorder_point",
|
|
1737
|
+
"safety_stock": "safety_stock"
|
|
1738
|
+
},
|
|
1677
1739
|
"progress_job": {
|
|
1678
1740
|
"id": "id",
|
|
1679
1741
|
"job_type": "job_type",
|
|
@@ -2228,6 +2290,12 @@ export const entityFieldsRegistry: Record<string, Record<string, string>> = {
|
|
|
2228
2290
|
"invoice_lines": "invoice_lines",
|
|
2229
2291
|
"credit_memo_lines": "credit_memo_lines"
|
|
2230
2292
|
},
|
|
2293
|
+
"sales_order_warehouse_assignment": {
|
|
2294
|
+
"sales_order_id": "sales_order_id",
|
|
2295
|
+
"warehouse": "warehouse",
|
|
2296
|
+
"assigned_by": "assigned_by",
|
|
2297
|
+
"notes": "notes"
|
|
2298
|
+
},
|
|
2231
2299
|
"sales_payment": {
|
|
2232
2300
|
"id": "id",
|
|
2233
2301
|
"order": "order",
|
|
@@ -2956,6 +3024,36 @@ export const entityFieldsRegistry: Record<string, Record<string, string>> = {
|
|
|
2956
3024
|
"created_at": "created_at",
|
|
2957
3025
|
"updated_at": "updated_at"
|
|
2958
3026
|
},
|
|
3027
|
+
"warehouse": {
|
|
3028
|
+
"name": "name",
|
|
3029
|
+
"code": "code",
|
|
3030
|
+
"is_active": "is_active",
|
|
3031
|
+
"is_primary": "is_primary",
|
|
3032
|
+
"address_line1": "address_line1",
|
|
3033
|
+
"city": "city",
|
|
3034
|
+
"postal_code": "postal_code",
|
|
3035
|
+
"country": "country",
|
|
3036
|
+
"timezone": "timezone",
|
|
3037
|
+
"zones": "zones",
|
|
3038
|
+
"locations": "locations"
|
|
3039
|
+
},
|
|
3040
|
+
"warehouse_location": {
|
|
3041
|
+
"warehouse": "warehouse",
|
|
3042
|
+
"code": "code",
|
|
3043
|
+
"type": "type",
|
|
3044
|
+
"parent": "parent",
|
|
3045
|
+
"children": "children",
|
|
3046
|
+
"is_active": "is_active",
|
|
3047
|
+
"capacity_units": "capacity_units",
|
|
3048
|
+
"capacity_weight": "capacity_weight",
|
|
3049
|
+
"constraints": "constraints"
|
|
3050
|
+
},
|
|
3051
|
+
"warehouse_zone": {
|
|
3052
|
+
"warehouse": "warehouse",
|
|
3053
|
+
"code": "code",
|
|
3054
|
+
"name": "name",
|
|
3055
|
+
"priority": "priority"
|
|
3056
|
+
},
|
|
2959
3057
|
"webhook_processed_event": {
|
|
2960
3058
|
"id": "id",
|
|
2961
3059
|
"provider_key": "provider_key",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.6.7-develop.
|
|
3
|
+
"version": "0.6.7-develop.6670.1.4efa7961c6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -254,16 +254,16 @@
|
|
|
254
254
|
"zod": "^4.4.3"
|
|
255
255
|
},
|
|
256
256
|
"peerDependencies": {
|
|
257
|
-
"@open-mercato/ai-assistant": "0.6.7-develop.
|
|
258
|
-
"@open-mercato/shared": "0.6.7-develop.
|
|
259
|
-
"@open-mercato/ui": "0.6.7-develop.
|
|
257
|
+
"@open-mercato/ai-assistant": "0.6.7-develop.6670.1.4efa7961c6",
|
|
258
|
+
"@open-mercato/shared": "0.6.7-develop.6670.1.4efa7961c6",
|
|
259
|
+
"@open-mercato/ui": "0.6.7-develop.6670.1.4efa7961c6",
|
|
260
260
|
"react": "^19.0.0",
|
|
261
261
|
"react-dom": "^19.0.0"
|
|
262
262
|
},
|
|
263
263
|
"devDependencies": {
|
|
264
|
-
"@open-mercato/ai-assistant": "0.6.7-develop.
|
|
265
|
-
"@open-mercato/shared": "0.6.7-develop.
|
|
266
|
-
"@open-mercato/ui": "0.6.7-develop.
|
|
264
|
+
"@open-mercato/ai-assistant": "0.6.7-develop.6670.1.4efa7961c6",
|
|
265
|
+
"@open-mercato/shared": "0.6.7-develop.6670.1.4efa7961c6",
|
|
266
|
+
"@open-mercato/ui": "0.6.7-develop.6670.1.4efa7961c6",
|
|
267
267
|
"@testing-library/dom": "^10.4.1",
|
|
268
268
|
"@testing-library/jest-dom": "^6.9.1",
|
|
269
269
|
"@testing-library/react": "^16.3.1",
|
|
@@ -73,9 +73,14 @@ export default function RolesListPage() {
|
|
|
73
73
|
return () => { cancelled = true }
|
|
74
74
|
}, [page, search, reloadToken, scopeVersion, t])
|
|
75
75
|
|
|
76
|
+
const formatRoleName = React.useCallback(
|
|
77
|
+
(name: string) => t(`auth.roles.${name}`, name),
|
|
78
|
+
[t],
|
|
79
|
+
)
|
|
80
|
+
|
|
76
81
|
const handleDelete = React.useCallback(async (row: Row) => {
|
|
77
82
|
const confirmed = await confirm({
|
|
78
|
-
title: t('auth.roles.list.confirmDelete', 'Delete role "{{name}}"?').replace('{{name}}', row.name),
|
|
83
|
+
title: t('auth.roles.list.confirmDelete', 'Delete role "{{name}}"?').replace('{{name}}', formatRoleName(row.name)),
|
|
79
84
|
variant: 'destructive',
|
|
80
85
|
})
|
|
81
86
|
if (!confirmed) return
|
|
@@ -96,7 +101,7 @@ export default function RolesListPage() {
|
|
|
96
101
|
const message = error instanceof Error ? error.message : t('auth.roles.list.error.delete', 'Failed to delete role')
|
|
97
102
|
flash(message, 'error')
|
|
98
103
|
}
|
|
99
|
-
}, [confirm, t])
|
|
104
|
+
}, [confirm, formatRoleName, t])
|
|
100
105
|
|
|
101
106
|
const showTenantColumn = React.useMemo(
|
|
102
107
|
() => isSuperAdmin && rows.some((row) => row.tenantName),
|
|
@@ -104,14 +109,18 @@ export default function RolesListPage() {
|
|
|
104
109
|
)
|
|
105
110
|
const columns = React.useMemo<ColumnDef<Row>[]>(() => {
|
|
106
111
|
const base: ColumnDef<Row>[] = [
|
|
107
|
-
{
|
|
112
|
+
{
|
|
113
|
+
accessorKey: 'name',
|
|
114
|
+
header: t('auth.roles.list.columns.role', 'Role'),
|
|
115
|
+
cell: ({ row }) => formatRoleName(row.original.name),
|
|
116
|
+
},
|
|
108
117
|
{ accessorKey: 'usersCount', header: t('auth.roles.list.columns.users', 'Users') },
|
|
109
118
|
]
|
|
110
119
|
if (showTenantColumn) {
|
|
111
120
|
base.splice(1, 0, { accessorKey: 'tenantName', header: t('auth.roles.list.columns.tenant', 'Tenant') })
|
|
112
121
|
}
|
|
113
122
|
return base
|
|
114
|
-
}, [showTenantColumn, t])
|
|
123
|
+
}, [formatRoleName, showTenantColumn, t])
|
|
115
124
|
|
|
116
125
|
return (
|
|
117
126
|
<Page>
|
|
@@ -140,7 +140,9 @@
|
|
|
140
140
|
"auth.roles.list.error.load": "Rollen konnten nicht geladen werden",
|
|
141
141
|
"auth.roles.list.success.delete": "Rolle gelöscht",
|
|
142
142
|
"auth.roles.list.title": "Rollen",
|
|
143
|
+
"auth.roles.operator": "Lageroperator",
|
|
143
144
|
"auth.roles.superadmin": "Superadministrator",
|
|
145
|
+
"auth.roles.supervisor": "Lagerleiter",
|
|
144
146
|
"auth.sendResetLink": "Link zum Zurücksetzen senden",
|
|
145
147
|
"auth.session.refresh.errors.invalidPayload": "Fehlendes oder ungültiges Refresh-Token",
|
|
146
148
|
"auth.session.refresh.errors.invalidToken": "Ungültiges oder abgelaufenes Refresh-Token",
|
|
@@ -140,7 +140,9 @@
|
|
|
140
140
|
"auth.roles.list.error.load": "Failed to load roles",
|
|
141
141
|
"auth.roles.list.success.delete": "Role deleted",
|
|
142
142
|
"auth.roles.list.title": "Roles",
|
|
143
|
+
"auth.roles.operator": "Warehouse Operator",
|
|
143
144
|
"auth.roles.superadmin": "Super Admin",
|
|
145
|
+
"auth.roles.supervisor": "Warehouse Supervisor",
|
|
144
146
|
"auth.sendResetLink": "Send reset link",
|
|
145
147
|
"auth.session.refresh.errors.invalidPayload": "Missing or invalid refresh token",
|
|
146
148
|
"auth.session.refresh.errors.invalidToken": "Invalid or expired refresh token",
|
|
@@ -140,7 +140,9 @@
|
|
|
140
140
|
"auth.roles.list.error.load": "No se pudieron cargar los roles",
|
|
141
141
|
"auth.roles.list.success.delete": "Rol eliminado",
|
|
142
142
|
"auth.roles.list.title": "Roles",
|
|
143
|
+
"auth.roles.operator": "Operador de almacén",
|
|
143
144
|
"auth.roles.superadmin": "Superadministrador",
|
|
145
|
+
"auth.roles.supervisor": "Supervisor de almacén",
|
|
144
146
|
"auth.sendResetLink": "Enviar enlace de restablecimiento",
|
|
145
147
|
"auth.session.refresh.errors.invalidPayload": "Falta el token de actualización o no es válido",
|
|
146
148
|
"auth.session.refresh.errors.invalidToken": "El token de actualización no es válido o ha expirado",
|
|
@@ -140,7 +140,9 @@
|
|
|
140
140
|
"auth.roles.list.error.load": "Nie udało się wczytać ról",
|
|
141
141
|
"auth.roles.list.success.delete": "Rola usunięta",
|
|
142
142
|
"auth.roles.list.title": "Role",
|
|
143
|
+
"auth.roles.operator": "Operator magazynowy",
|
|
143
144
|
"auth.roles.superadmin": "Superadministrator",
|
|
145
|
+
"auth.roles.supervisor": "Kierownik magazynu",
|
|
144
146
|
"auth.sendResetLink": "Wyślij link resetujący",
|
|
145
147
|
"auth.session.refresh.errors.invalidPayload": "Brak tokenu odświeżania lub token jest nieprawidłowy",
|
|
146
148
|
"auth.session.refresh.errors.invalidToken": "Token odświeżania jest nieprawidłowy lub wygasł",
|
|
@@ -152,6 +152,7 @@ function normalizeGroupWeights(groups: NavGroupWithWeight[]): NavGroupWithWeight
|
|
|
152
152
|
'customers.nav.group',
|
|
153
153
|
'catalog.nav.group',
|
|
154
154
|
'customers~sales.nav.group',
|
|
155
|
+
'wms.nav.group',
|
|
155
156
|
'resources.nav.group',
|
|
156
157
|
'staff.nav.group',
|
|
157
158
|
'entities.nav.group',
|
|
@@ -367,27 +367,6 @@ export class RbacService {
|
|
|
367
367
|
return result
|
|
368
368
|
}
|
|
369
369
|
|
|
370
|
-
/**
|
|
371
|
-
* Returns the user's granted feature strings for a given scope.
|
|
372
|
-
*
|
|
373
|
-
* Used by infrastructure that needs the raw grant list rather than a yes/no
|
|
374
|
-
* authorization check (for example response enrichers gating themselves with
|
|
375
|
-
* `features: [...]`). Callers MUST apply wildcard-aware matching against the
|
|
376
|
-
* returned array — grants like `module.*` or `*` are part of the ACL contract.
|
|
377
|
-
*
|
|
378
|
-
* @param userId - The ID of the user
|
|
379
|
-
* @param scope - The tenant and organization context for ACL evaluation
|
|
380
|
-
* @returns Array of feature strings (may include wildcards); empty array when
|
|
381
|
-
* the user has no grants in scope
|
|
382
|
-
*/
|
|
383
|
-
async getGrantedFeatures(
|
|
384
|
-
userId: string,
|
|
385
|
-
scope: { tenantId: string | null; organizationId: string | null },
|
|
386
|
-
): Promise<string[]> {
|
|
387
|
-
const acl = await this.loadAcl(userId, scope)
|
|
388
|
-
return Array.isArray(acl.features) ? acl.features : []
|
|
389
|
-
}
|
|
390
|
-
|
|
391
370
|
/**
|
|
392
371
|
* Checks whether any tenant role grants a feature.
|
|
393
372
|
*
|
|
@@ -466,4 +445,29 @@ export class RbacService {
|
|
|
466
445
|
if (acl.organizations && scope.organizationId && !acl.organizations.includes(scope.organizationId) && !acl.organizations.includes('__all__')) return false
|
|
467
446
|
return this.hasAllFeatures(required, filterGrantsByEnabledModules(acl.features))
|
|
468
447
|
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Returns the effective feature grant list for a user within a scope,
|
|
451
|
+
* filtered to enabled modules only. Super admins receive `['*']` expanded
|
|
452
|
+
* to per-module wildcards via `filterGrantsByEnabledModules` — consistent
|
|
453
|
+
* with `userHasAllFeatures` which also enforces disabled-module boundaries
|
|
454
|
+
* for super admins. Returns `[]` when the requested organization is outside
|
|
455
|
+
* the user's visibility list, or when the user does not exist.
|
|
456
|
+
*/
|
|
457
|
+
async getGrantedFeatures(
|
|
458
|
+
userId: string,
|
|
459
|
+
scope: { tenantId: string | null; organizationId: string | null },
|
|
460
|
+
): Promise<string[]> {
|
|
461
|
+
const acl = await this.loadAcl(userId, scope)
|
|
462
|
+
if (acl.isSuperAdmin) return filterGrantsByEnabledModules(['*'])
|
|
463
|
+
if (
|
|
464
|
+
acl.organizations &&
|
|
465
|
+
scope.organizationId &&
|
|
466
|
+
!acl.organizations.includes(scope.organizationId) &&
|
|
467
|
+
!acl.organizations.includes('__all__')
|
|
468
|
+
) {
|
|
469
|
+
return []
|
|
470
|
+
}
|
|
471
|
+
return filterGrantsByEnabledModules(acl.features)
|
|
472
|
+
}
|
|
469
473
|
}
|
|
@@ -104,6 +104,9 @@ const crud = makeCrudRoute({
|
|
|
104
104
|
softDeleteField: 'deletedAt',
|
|
105
105
|
},
|
|
106
106
|
indexer: { entityType: E.catalog.catalog_product_variant },
|
|
107
|
+
enrichers: {
|
|
108
|
+
entityId: E.catalog.catalog_product_variant,
|
|
109
|
+
},
|
|
107
110
|
list: {
|
|
108
111
|
schema: listSchema,
|
|
109
112
|
entityId: E.catalog.catalog_product_variant,
|
|
@@ -707,8 +707,14 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
707
707
|
|
|
708
708
|
const applyJoinFilterOpFn = (target: AnyBuilder, column: string, op: FilterOp, value?: unknown): AnyBuilder => {
|
|
709
709
|
switch (op) {
|
|
710
|
-
case 'eq':
|
|
711
|
-
|
|
710
|
+
case 'eq':
|
|
711
|
+
return value === null
|
|
712
|
+
? target.where(column, 'is', null)
|
|
713
|
+
: target.where(column, '=', value as any)
|
|
714
|
+
case 'ne':
|
|
715
|
+
return value === null
|
|
716
|
+
? target.where(column, 'is not', null)
|
|
717
|
+
: target.where(column, '!=', value as any)
|
|
712
718
|
case 'gt': return target.where(column, '>', value as any)
|
|
713
719
|
case 'gte': return target.where(column, '>=', value as any)
|
|
714
720
|
case 'lt': return target.where(column, '<', value as any)
|
|
@@ -1570,8 +1576,8 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
1570
1576
|
value: unknown,
|
|
1571
1577
|
): any {
|
|
1572
1578
|
switch (op) {
|
|
1573
|
-
case 'eq': return eb(column, '=', value)
|
|
1574
|
-
case 'ne': return eb(column, '!=', value)
|
|
1579
|
+
case 'eq': return value === null ? eb(column, 'is', null) : eb(column, '=', value)
|
|
1580
|
+
case 'ne': return value === null ? eb(column, 'is not', null) : eb(column, '!=', value)
|
|
1575
1581
|
case 'gt': return eb(column, '>', value)
|
|
1576
1582
|
case 'gte': return eb(column, '>=', value)
|
|
1577
1583
|
case 'lt': return eb(column, '<', value)
|
|
@@ -2235,8 +2241,14 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
2235
2241
|
}
|
|
2236
2242
|
const col: any = column
|
|
2237
2243
|
switch (filter.op) {
|
|
2238
|
-
case 'eq':
|
|
2239
|
-
|
|
2244
|
+
case 'eq':
|
|
2245
|
+
return filter.value === null
|
|
2246
|
+
? q.where(col, 'is', null)
|
|
2247
|
+
: q.where(col, '=', filter.value as any)
|
|
2248
|
+
case 'ne':
|
|
2249
|
+
return filter.value === null
|
|
2250
|
+
? q.where(col, 'is not', null)
|
|
2251
|
+
: q.where(col, '!=', filter.value as any)
|
|
2240
2252
|
case 'gt':
|
|
2241
2253
|
case 'gte':
|
|
2242
2254
|
case 'lt':
|
|
@@ -377,6 +377,7 @@ export function buildDocumentCrudOptions(binding: DocumentBinding) {
|
|
|
377
377
|
indexer: {
|
|
378
378
|
entityType: binding.entityId,
|
|
379
379
|
},
|
|
380
|
+
enrichers: binding.kind === 'order' ? { entityId: binding.entityId } : undefined,
|
|
380
381
|
list: {
|
|
381
382
|
schema: listSchema,
|
|
382
383
|
entityId: binding.entityId,
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
24
24
|
import { resolveNotificationService } from "../../notifications/lib/notificationService";
|
|
25
25
|
import { buildFeatureNotificationFromType } from "../../notifications/lib/notificationBuilder";
|
|
26
|
+
import { emitSalesEvent } from "../events";
|
|
26
27
|
import { setRecordCustomFields } from "@open-mercato/core/modules/entities/lib/helpers";
|
|
27
28
|
import { loadCustomFieldValues } from "@open-mercato/shared/lib/crud/custom-fields";
|
|
28
29
|
import { normalizeCustomFieldValues } from "@open-mercato/shared/lib/custom-fields/normalize";
|
|
@@ -858,6 +859,70 @@ function normalizeStatusValue(raw: unknown): string | null {
|
|
|
858
859
|
return trimmed.length ? trimmed : null;
|
|
859
860
|
}
|
|
860
861
|
|
|
862
|
+
function isConfirmedOrderStatus(status: string | null): boolean {
|
|
863
|
+
return status === "confirmed";
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
function isCancelledOrderStatus(status: string | null): boolean {
|
|
867
|
+
return status === "canceled" || status === "cancelled";
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
async function emitOrderLifecycleEvent(input: {
|
|
871
|
+
eventId: "sales.order.confirmed" | "sales.order.cancelled";
|
|
872
|
+
order: SalesOrder;
|
|
873
|
+
previousStatus: string | null;
|
|
874
|
+
}): Promise<void> {
|
|
875
|
+
await emitSalesEvent(input.eventId, {
|
|
876
|
+
id: input.order.id,
|
|
877
|
+
orderId: input.order.id,
|
|
878
|
+
orderNumber: input.order.orderNumber,
|
|
879
|
+
previousStatus: input.previousStatus,
|
|
880
|
+
status: normalizeStatusValue(input.order.status),
|
|
881
|
+
tenantId: input.order.tenantId,
|
|
882
|
+
organizationId: input.order.organizationId,
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
function emitOrderLifecycleEventsForTransition(input: {
|
|
887
|
+
order: SalesOrder;
|
|
888
|
+
previousStatus: string | null;
|
|
889
|
+
}): void {
|
|
890
|
+
const nextStatus = normalizeStatusValue(input.order.status);
|
|
891
|
+
if (input.previousStatus === nextStatus) return;
|
|
892
|
+
|
|
893
|
+
if (isConfirmedOrderStatus(nextStatus)) {
|
|
894
|
+
void emitOrderLifecycleEvent({
|
|
895
|
+
eventId: "sales.order.confirmed",
|
|
896
|
+
order: input.order,
|
|
897
|
+
previousStatus: input.previousStatus,
|
|
898
|
+
}).catch((err) => {
|
|
899
|
+
// Surface as warning so downstream automations (e.g. WMS reservation
|
|
900
|
+
// subscriber) failing to register/persist their own follow-up state is
|
|
901
|
+
// observable in logs instead of being silently dropped. The order
|
|
902
|
+
// status transition itself is already committed at this point.
|
|
903
|
+
logger.warn("order lifecycle event emit failed", {
|
|
904
|
+
eventId: "sales.order.confirmed",
|
|
905
|
+
orderId: input.order.id,
|
|
906
|
+
err,
|
|
907
|
+
});
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
if (isCancelledOrderStatus(nextStatus)) {
|
|
912
|
+
void emitOrderLifecycleEvent({
|
|
913
|
+
eventId: "sales.order.cancelled",
|
|
914
|
+
order: input.order,
|
|
915
|
+
previousStatus: input.previousStatus,
|
|
916
|
+
}).catch((err) => {
|
|
917
|
+
logger.warn("order lifecycle event emit failed", {
|
|
918
|
+
eventId: "sales.order.cancelled",
|
|
919
|
+
orderId: input.order.id,
|
|
920
|
+
err,
|
|
921
|
+
});
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
861
926
|
function resolveNoteAuthorFromAuth(auth: AuthContext | null): string | null {
|
|
862
927
|
if (!auth || auth.isApiKey) return null;
|
|
863
928
|
const sub = typeof auth.sub === "string" ? auth.sub.trim() : "";
|
|
@@ -5359,6 +5424,7 @@ const updateOrderCommand: CommandHandler<
|
|
|
5359
5424
|
],
|
|
5360
5425
|
{ transaction: true },
|
|
5361
5426
|
);
|
|
5427
|
+
emitOrderLifecycleEventsForTransition({ order, previousStatus });
|
|
5362
5428
|
if (statusChangeNote) {
|
|
5363
5429
|
const dataEngine = ctx.container.resolve("dataEngine");
|
|
5364
5430
|
await emitCrudSideEffects({
|
|
@@ -5800,6 +5866,11 @@ const createOrderCommand: CommandHandler<
|
|
|
5800
5866
|
"created",
|
|
5801
5867
|
);
|
|
5802
5868
|
|
|
5869
|
+
emitOrderLifecycleEventsForTransition({
|
|
5870
|
+
order,
|
|
5871
|
+
previousStatus: null,
|
|
5872
|
+
});
|
|
5873
|
+
|
|
5803
5874
|
return { orderId: order.id };
|
|
5804
5875
|
},
|
|
5805
5876
|
captureAfter: async (_input, result, ctx) => {
|
|
@@ -27,6 +27,9 @@ import type { SectionAction } from "@open-mercato/ui/backend/detail";
|
|
|
27
27
|
import { extractCustomFieldValues } from "./customFieldHelpers";
|
|
28
28
|
import { canonicalizeUnitCode } from "@open-mercato/shared/lib/units/unitCodes";
|
|
29
29
|
import type { SalesLineUomSnapshot } from "../../lib/types";
|
|
30
|
+
import { useInjectionDataWidgets } from "@open-mercato/ui/backend/injection/useInjectionDataWidgets";
|
|
31
|
+
import type { InjectionColumnDefinition } from "@open-mercato/shared/modules/widgets/injection";
|
|
32
|
+
import { OrderItemsInjectionContext } from "../../widgets/injection/order-items-context";
|
|
30
33
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
31
34
|
|
|
32
35
|
const logger = createLogger('sales')
|
|
@@ -110,6 +113,19 @@ function getUomFields(item: Record<string, unknown>) {
|
|
|
110
113
|
};
|
|
111
114
|
}
|
|
112
115
|
|
|
116
|
+
function resolveInjectedColumnValue(
|
|
117
|
+
row: Record<string, unknown>,
|
|
118
|
+
accessorKey: string,
|
|
119
|
+
): unknown {
|
|
120
|
+
const segments = accessorKey.split(".").filter(Boolean);
|
|
121
|
+
let current: unknown = row;
|
|
122
|
+
for (const segment of segments) {
|
|
123
|
+
if (!current || typeof current !== "object") return undefined;
|
|
124
|
+
current = (current as Record<string, unknown>)[segment];
|
|
125
|
+
}
|
|
126
|
+
return current;
|
|
127
|
+
}
|
|
128
|
+
|
|
113
129
|
type SalesDocumentItemsSectionProps = {
|
|
114
130
|
documentId: string;
|
|
115
131
|
kind: "order" | "quote";
|
|
@@ -148,6 +164,22 @@ export function SalesDocumentItemsSection({
|
|
|
148
164
|
new Map(),
|
|
149
165
|
);
|
|
150
166
|
|
|
167
|
+
const { widgets: allColumnWidgets } = useInjectionDataWidgets(
|
|
168
|
+
"data-table:sales.order.items:columns",
|
|
169
|
+
);
|
|
170
|
+
const columnWidgets = kind === "order" ? allColumnWidgets : [];
|
|
171
|
+
const injectedColumns = React.useMemo<InjectionColumnDefinition[]>(() => {
|
|
172
|
+
const cols: InjectionColumnDefinition[] = [];
|
|
173
|
+
for (const widget of columnWidgets) {
|
|
174
|
+
if (!("columns" in widget)) continue;
|
|
175
|
+
for (const def of (widget as { columns?: InjectionColumnDefinition[] })
|
|
176
|
+
.columns ?? []) {
|
|
177
|
+
cols.push(def);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return cols;
|
|
181
|
+
}, [columnWidgets]);
|
|
182
|
+
|
|
151
183
|
const resourcePath = React.useMemo(
|
|
152
184
|
() => (kind === "order" ? "sales/order-lines" : "sales/quote-lines"),
|
|
153
185
|
[kind],
|
|
@@ -575,6 +607,7 @@ export function SalesDocumentItemsSection({
|
|
|
575
607
|
};
|
|
576
608
|
|
|
577
609
|
return (
|
|
610
|
+
<OrderItemsInjectionContext.Provider value={{ documentId, kind }}>
|
|
578
611
|
<div className="space-y-4">
|
|
579
612
|
{loading ? (
|
|
580
613
|
<LoadingMessage
|
|
@@ -615,6 +648,14 @@ export function SalesDocumentItemsSection({
|
|
|
615
648
|
<th className="px-3 py-2 font-medium">
|
|
616
649
|
{t("sales.documents.items.table.total", "Total")}
|
|
617
650
|
</th>
|
|
651
|
+
{injectedColumns.map((col) => (
|
|
652
|
+
<th
|
|
653
|
+
key={col.id}
|
|
654
|
+
className="px-3 py-2 font-medium whitespace-nowrap"
|
|
655
|
+
>
|
|
656
|
+
{col.headerKey ? t(col.headerKey, col.header) : col.header}
|
|
657
|
+
</th>
|
|
658
|
+
))}
|
|
618
659
|
<th className="px-3 py-2 font-medium sr-only">
|
|
619
660
|
{t("sales.documents.items.table.actions", "Actions")}
|
|
620
661
|
</th>
|
|
@@ -770,6 +811,22 @@ export function SalesDocumentItemsSection({
|
|
|
770
811
|
</span>
|
|
771
812
|
</div>
|
|
772
813
|
</td>
|
|
814
|
+
{injectedColumns.map((col) => {
|
|
815
|
+
const colValue = resolveInjectedColumnValue(
|
|
816
|
+
item as unknown as Record<string, unknown>,
|
|
817
|
+
col.accessorKey,
|
|
818
|
+
);
|
|
819
|
+
const Cell = col.cell;
|
|
820
|
+
return (
|
|
821
|
+
<td
|
|
822
|
+
key={col.id}
|
|
823
|
+
className="px-3 py-3"
|
|
824
|
+
onClick={(e) => e.stopPropagation()}
|
|
825
|
+
>
|
|
826
|
+
{Cell ? <Cell getValue={() => colValue} /> : null}
|
|
827
|
+
</td>
|
|
828
|
+
);
|
|
829
|
+
})}
|
|
773
830
|
<td className="px-3 py-3">
|
|
774
831
|
<div className="flex items-center gap-2 justify-end">
|
|
775
832
|
<Button
|
|
@@ -829,5 +886,6 @@ export function SalesDocumentItemsSection({
|
|
|
829
886
|
/>
|
|
830
887
|
{ConfirmDialogElement}
|
|
831
888
|
</div>
|
|
889
|
+
</OrderItemsInjectionContext.Provider>
|
|
832
890
|
);
|
|
833
891
|
}
|
|
@@ -10,6 +10,8 @@ const events = [
|
|
|
10
10
|
{ id: 'sales.order.created', label: 'Sales Order Created', entity: 'order', category: 'crud' },
|
|
11
11
|
{ id: 'sales.order.updated', label: 'Sales Order Updated', entity: 'order', category: 'crud' },
|
|
12
12
|
{ id: 'sales.order.deleted', label: 'Sales Order Deleted', entity: 'order', category: 'crud' },
|
|
13
|
+
{ id: 'sales.order.confirmed', label: 'Sales Order Confirmed', entity: 'order', category: 'lifecycle' },
|
|
14
|
+
{ id: 'sales.order.cancelled', label: 'Sales Order Cancelled', entity: 'order', category: 'lifecycle' },
|
|
13
15
|
|
|
14
16
|
// Quotes
|
|
15
17
|
{ id: 'sales.quote.created', label: 'Quote Created', entity: 'quote', category: 'crud' },
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
export type OrderItemsInjectionContextValue = {
|
|
6
|
+
documentId: string
|
|
7
|
+
kind: 'order' | 'quote'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const OrderItemsInjectionContext =
|
|
11
|
+
React.createContext<OrderItemsInjectionContextValue | null>(null)
|
|
12
|
+
|
|
13
|
+
export function useOrderItemsInjectionContext(): OrderItemsInjectionContextValue | null {
|
|
14
|
+
return React.useContext(OrderItemsInjectionContext)
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const features = [
|
|
2
|
+
{ id: 'wms.view', title: 'View WMS data', module: 'wms' },
|
|
3
|
+
{ id: 'wms.manage_warehouses', title: 'Manage warehouses', module: 'wms' },
|
|
4
|
+
{ id: 'wms.manage_zones', title: 'Manage warehouse zones', module: 'wms' },
|
|
5
|
+
{ id: 'wms.manage_locations', title: 'Manage warehouse locations', module: 'wms' },
|
|
6
|
+
{ id: 'wms.manage_inventory', title: 'Manage inventory profiles and stock state', module: 'wms' },
|
|
7
|
+
{ id: 'wms.manage_reservations', title: 'Manage inventory reservations', module: 'wms' },
|
|
8
|
+
{ id: 'wms.adjust_inventory', title: 'Adjust and move inventory', module: 'wms' },
|
|
9
|
+
{ id: 'wms.receive_inventory', title: 'Receive inbound inventory', module: 'wms' },
|
|
10
|
+
{ id: 'wms.cycle_count', title: 'Run cycle counts', module: 'wms' },
|
|
11
|
+
{ id: 'wms.import', title: 'Import inventory from CSV', module: 'wms' },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
export default features
|