@open-mercato/core 0.6.7-develop.6669.1.40b669666b → 0.6.7-develop.6671.1.4b925c5096
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
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ModuleInfo } from '@open-mercato/shared/modules/registry'
|
|
2
|
+
import './commands'
|
|
3
|
+
|
|
4
|
+
export const metadata: ModuleInfo = {
|
|
5
|
+
name: 'wms',
|
|
6
|
+
title: 'Warehouse Management System',
|
|
7
|
+
version: '0.1.0',
|
|
8
|
+
description: 'Warehouse topology, inventory balances, reservations, and movement ledger.',
|
|
9
|
+
author: 'Open Mercato Team',
|
|
10
|
+
license: 'MIT',
|
|
11
|
+
ejectable: true,
|
|
12
|
+
requires: ['catalog', 'sales', 'feature_toggles'],
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { features } from './acl'
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
const inventoryStrategySchema = z.enum(['fifo', 'lifo', 'fefo'])
|
|
4
|
+
|
|
5
|
+
export const catalogInventoryProfileIntentSchema = z.object({
|
|
6
|
+
manageInventory: z.boolean(),
|
|
7
|
+
defaultUom: z.string().trim().max(32).nullable().optional(),
|
|
8
|
+
defaultStrategy: inventoryStrategySchema.optional(),
|
|
9
|
+
trackLot: z.boolean().optional(),
|
|
10
|
+
trackSerial: z.boolean().optional(),
|
|
11
|
+
trackExpiration: z.boolean().optional(),
|
|
12
|
+
reorderPoint: z.coerce.number().finite().min(0).nullable().optional(),
|
|
13
|
+
safetyStock: z.coerce.number().finite().min(0).nullable().optional(),
|
|
14
|
+
}).superRefine((payload, ctx) => {
|
|
15
|
+
if (!payload.manageInventory) return
|
|
16
|
+
|
|
17
|
+
if (!payload.defaultUom || payload.defaultUom.trim().length === 0) {
|
|
18
|
+
ctx.addIssue({
|
|
19
|
+
code: z.ZodIssueCode.custom,
|
|
20
|
+
path: ['defaultUom'],
|
|
21
|
+
message: 'wms.widgets.catalog.inventoryProfile.errors.defaultUomRequired',
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!payload.defaultStrategy) {
|
|
26
|
+
ctx.addIssue({
|
|
27
|
+
code: z.ZodIssueCode.custom,
|
|
28
|
+
path: ['defaultStrategy'],
|
|
29
|
+
message: 'wms.widgets.catalog.inventoryProfile.errors.strategyRequired',
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (payload.trackExpiration && payload.defaultStrategy !== 'fefo') {
|
|
34
|
+
ctx.addIssue({
|
|
35
|
+
code: z.ZodIssueCode.custom,
|
|
36
|
+
path: ['defaultStrategy'],
|
|
37
|
+
message: 'wms.widgets.catalog.inventoryProfile.errors.fefoRequired',
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
export type CatalogInventoryProfileIntent = z.infer<
|
|
43
|
+
typeof catalogInventoryProfileIntentSchema
|
|
44
|
+
>
|
|
45
|
+
|
|
46
|
+
export const WMS_CATALOG_PROFILE_HEADER =
|
|
47
|
+
'x-open-mercato-wms-catalog-profile'
|
|
48
|
+
|
|
49
|
+
export function encodeCatalogInventoryProfileIntent(
|
|
50
|
+
intent: CatalogInventoryProfileIntent,
|
|
51
|
+
): string {
|
|
52
|
+
return encodeURIComponent(JSON.stringify(intent))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function decodeCatalogInventoryProfileIntent(
|
|
56
|
+
rawHeader: string | null | undefined,
|
|
57
|
+
): CatalogInventoryProfileIntent | null {
|
|
58
|
+
if (typeof rawHeader !== 'string' || rawHeader.trim().length === 0) {
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const decoded = decodeURIComponent(rawHeader)
|
|
63
|
+
const parsed = JSON.parse(decoded) as unknown
|
|
64
|
+
return catalogInventoryProfileIntentSchema.parse(parsed)
|
|
65
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import type { AwilixContainer } from 'awilix'
|
|
3
|
+
import type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
|
|
4
|
+
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
5
|
+
import type { AuthContext } from '@open-mercato/shared/lib/auth/server'
|
|
6
|
+
import type { QueryEngine } from '@open-mercato/shared/lib/query/types'
|
|
7
|
+
import { E } from '#generated/entities.ids.generated'
|
|
8
|
+
import { ProductInventoryProfile } from '../data/entities'
|
|
9
|
+
import {
|
|
10
|
+
catalogInventoryProfileIntentSchema,
|
|
11
|
+
type CatalogInventoryProfileIntent,
|
|
12
|
+
} from './catalogInventoryProfileIntent'
|
|
13
|
+
|
|
14
|
+
type SyncTarget = 'product' | 'variant'
|
|
15
|
+
|
|
16
|
+
type SyncCatalogInventoryProfileInput = {
|
|
17
|
+
intent: CatalogInventoryProfileIntent
|
|
18
|
+
target: SyncTarget
|
|
19
|
+
recordId: string
|
|
20
|
+
organizationId: string
|
|
21
|
+
tenantId: string
|
|
22
|
+
userId: string
|
|
23
|
+
container: AwilixContainer
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeOptionalString(value: unknown): string | null {
|
|
27
|
+
if (typeof value !== 'string') return null
|
|
28
|
+
const trimmed = value.trim()
|
|
29
|
+
return trimmed.length > 0 ? trimmed : null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function buildCommandContext(params: {
|
|
33
|
+
container: AwilixContainer
|
|
34
|
+
organizationId: string
|
|
35
|
+
tenantId: string
|
|
36
|
+
userId: string
|
|
37
|
+
}): CommandRuntimeContext {
|
|
38
|
+
const auth: AuthContext = {
|
|
39
|
+
sub: params.userId,
|
|
40
|
+
userId: params.userId,
|
|
41
|
+
tenantId: params.tenantId,
|
|
42
|
+
orgId: params.organizationId,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
container: params.container,
|
|
47
|
+
auth,
|
|
48
|
+
organizationScope: null,
|
|
49
|
+
selectedOrganizationId: params.organizationId,
|
|
50
|
+
organizationIds: [params.organizationId],
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function loadExistingProfile(params: {
|
|
55
|
+
organizationId: string
|
|
56
|
+
tenantId: string
|
|
57
|
+
target: SyncTarget
|
|
58
|
+
recordId: string
|
|
59
|
+
catalogProductId: string
|
|
60
|
+
container: AwilixContainer
|
|
61
|
+
}) {
|
|
62
|
+
const em = params.container.resolve('em') as EntityManager
|
|
63
|
+
const scope = {
|
|
64
|
+
organizationId: params.organizationId,
|
|
65
|
+
tenantId: params.tenantId,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (params.target === 'variant') {
|
|
69
|
+
return findOneWithDecryption(
|
|
70
|
+
em,
|
|
71
|
+
ProductInventoryProfile,
|
|
72
|
+
{
|
|
73
|
+
organizationId: params.organizationId,
|
|
74
|
+
tenantId: params.tenantId,
|
|
75
|
+
deletedAt: null,
|
|
76
|
+
catalogVariantId: params.recordId,
|
|
77
|
+
} as never,
|
|
78
|
+
undefined,
|
|
79
|
+
scope,
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return findOneWithDecryption(
|
|
84
|
+
em,
|
|
85
|
+
ProductInventoryProfile,
|
|
86
|
+
{
|
|
87
|
+
organizationId: params.organizationId,
|
|
88
|
+
tenantId: params.tenantId,
|
|
89
|
+
deletedAt: null,
|
|
90
|
+
catalogProductId: params.catalogProductId,
|
|
91
|
+
catalogVariantId: null,
|
|
92
|
+
} as never,
|
|
93
|
+
undefined,
|
|
94
|
+
scope,
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function resolveCatalogProductId(params: {
|
|
99
|
+
target: SyncTarget
|
|
100
|
+
recordId: string
|
|
101
|
+
organizationId: string
|
|
102
|
+
tenantId: string
|
|
103
|
+
container: AwilixContainer
|
|
104
|
+
}): Promise<string> {
|
|
105
|
+
if (params.target === 'product') return params.recordId
|
|
106
|
+
|
|
107
|
+
// Read the variant -> product_id mapping via QueryEngine so this module does
|
|
108
|
+
// not import the catalog ORM entity directly. queryEngine resolves the
|
|
109
|
+
// base table via Mikro-ORM metadata, so the only cross-module surface we
|
|
110
|
+
// depend on is the public catalog entity id from the `E` registry.
|
|
111
|
+
const queryEngine = params.container.resolve('queryEngine') as QueryEngine
|
|
112
|
+
const result = await queryEngine.query<{ id?: string; product_id?: string }>(
|
|
113
|
+
E.catalog.catalog_product_variant,
|
|
114
|
+
{
|
|
115
|
+
tenantId: params.tenantId,
|
|
116
|
+
organizationId: params.organizationId,
|
|
117
|
+
filters: { id: { $eq: params.recordId } },
|
|
118
|
+
fields: ['id', 'product_id'],
|
|
119
|
+
page: { page: 1, pageSize: 1 },
|
|
120
|
+
},
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
const variantRow = result.items[0]
|
|
124
|
+
if (!variantRow) {
|
|
125
|
+
throw new Error(`Variant ${params.recordId} not found for WMS profile sync`)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const productId = typeof variantRow.product_id === 'string' ? variantRow.product_id : null
|
|
129
|
+
if (!productId) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
`Variant ${params.recordId} is missing product context for WMS profile sync`,
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return productId
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function syncCatalogInventoryProfile(
|
|
139
|
+
input: SyncCatalogInventoryProfileInput,
|
|
140
|
+
): Promise<void> {
|
|
141
|
+
const intent = catalogInventoryProfileIntentSchema.parse(input.intent)
|
|
142
|
+
const commandBus = input.container.resolve('commandBus') as CommandBus
|
|
143
|
+
const ctx = buildCommandContext(input)
|
|
144
|
+
const catalogProductId = await resolveCatalogProductId({
|
|
145
|
+
target: input.target,
|
|
146
|
+
recordId: input.recordId,
|
|
147
|
+
organizationId: input.organizationId,
|
|
148
|
+
tenantId: input.tenantId,
|
|
149
|
+
container: input.container,
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
const existingProfile = await loadExistingProfile({
|
|
153
|
+
organizationId: input.organizationId,
|
|
154
|
+
tenantId: input.tenantId,
|
|
155
|
+
target: input.target,
|
|
156
|
+
recordId: input.recordId,
|
|
157
|
+
catalogProductId,
|
|
158
|
+
container: input.container,
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
if (!intent.manageInventory) {
|
|
162
|
+
if (!existingProfile) return
|
|
163
|
+
await commandBus.execute('wms.inventoryProfiles.delete', {
|
|
164
|
+
input: { id: existingProfile.id },
|
|
165
|
+
ctx,
|
|
166
|
+
})
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const profileInput = {
|
|
171
|
+
organizationId: input.organizationId,
|
|
172
|
+
tenantId: input.tenantId,
|
|
173
|
+
catalogProductId,
|
|
174
|
+
catalogVariantId: input.target === 'variant' ? input.recordId : null,
|
|
175
|
+
defaultUom: normalizeOptionalString(intent.defaultUom),
|
|
176
|
+
defaultStrategy: intent.defaultStrategy,
|
|
177
|
+
trackLot: intent.trackLot ?? false,
|
|
178
|
+
trackSerial: intent.trackSerial ?? false,
|
|
179
|
+
trackExpiration: intent.trackExpiration ?? false,
|
|
180
|
+
reorderPoint: intent.reorderPoint ?? 0,
|
|
181
|
+
safetyStock: intent.safetyStock ?? 0,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (existingProfile) {
|
|
185
|
+
await commandBus.execute('wms.inventoryProfiles.update', {
|
|
186
|
+
input: {
|
|
187
|
+
id: existingProfile.id,
|
|
188
|
+
...profileInput,
|
|
189
|
+
},
|
|
190
|
+
ctx,
|
|
191
|
+
})
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
await commandBus.execute('wms.inventoryProfiles.create', {
|
|
196
|
+
input: profileInput,
|
|
197
|
+
ctx,
|
|
198
|
+
})
|
|
199
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const EXPIRING_SOON_DAYS = 30
|
|
2
|
+
|
|
3
|
+
export type ExpiryWindow = 'expiringSoon' | 'pastDue'
|
|
4
|
+
|
|
5
|
+
export function startOfUtcDay(date: Date): Date {
|
|
6
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()))
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function addUtcDays(date: Date, days: number): Date {
|
|
10
|
+
const next = new Date(date)
|
|
11
|
+
next.setUTCDate(next.getUTCDate() + days)
|
|
12
|
+
return next
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function buildExpiryWindowDateFilter(
|
|
16
|
+
expiryWindow: ExpiryWindow,
|
|
17
|
+
now: Date = new Date(),
|
|
18
|
+
): Record<string, unknown> {
|
|
19
|
+
const today = startOfUtcDay(now)
|
|
20
|
+
if (expiryWindow === 'pastDue') {
|
|
21
|
+
return { expires_at: { $ne: null, $lt: today } }
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
expires_at: {
|
|
25
|
+
$ne: null,
|
|
26
|
+
$gte: today,
|
|
27
|
+
$lte: addUtcDays(today, EXPIRING_SOON_DAYS),
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
2
|
+
import type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Maps a `requireFeatures` ACL feature id to the i18n key that names the
|
|
6
|
+
* specific permission a 403 response is missing (#4102 follow-up — the
|
|
7
|
+
* generic "Forbidden" toast didn't say what was denied).
|
|
8
|
+
*/
|
|
9
|
+
const FORBIDDEN_FEATURE_MESSAGE_KEYS: Record<string, string> = {
|
|
10
|
+
'wms.manage_warehouses': 'wms.errors.forbidden.manageWarehouses',
|
|
11
|
+
'wms.manage_zones': 'wms.errors.forbidden.manageZones',
|
|
12
|
+
'wms.manage_locations': 'wms.errors.forbidden.manageLocations',
|
|
13
|
+
'wms.manage_inventory': 'wms.errors.forbidden.manageInventory',
|
|
14
|
+
'wms.manage_reservations': 'wms.errors.forbidden.manageReservations',
|
|
15
|
+
'wms.adjust_inventory': 'wms.errors.forbidden.adjustInventory',
|
|
16
|
+
'wms.receive_inventory': 'wms.errors.forbidden.receiveInventory',
|
|
17
|
+
'wms.cycle_count': 'wms.errors.forbidden.cycleCount',
|
|
18
|
+
'wms.import': 'wms.errors.forbidden.import',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const FORBIDDEN_FEATURE_MESSAGE_FALLBACKS: Record<string, string> = {
|
|
22
|
+
'wms.manage_warehouses': "You don't have permission to manage warehouses.",
|
|
23
|
+
'wms.manage_zones': "You don't have permission to manage warehouse zones.",
|
|
24
|
+
'wms.manage_locations': "You don't have permission to manage warehouse locations.",
|
|
25
|
+
'wms.manage_inventory': "You don't have permission to manage inventory profiles.",
|
|
26
|
+
'wms.manage_reservations': "You don't have permission to manage inventory reservations.",
|
|
27
|
+
'wms.adjust_inventory': "You don't have permission to adjust or move inventory.",
|
|
28
|
+
'wms.receive_inventory': "You don't have permission to receive inbound inventory.",
|
|
29
|
+
'wms.cycle_count': "You don't have permission to run cycle counts.",
|
|
30
|
+
'wms.import': "You don't have permission to import inventory.",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Reads the 403 response's `requiredFeatures` (attached to the thrown error
|
|
35
|
+
* by `raiseCrudError`) and, when the missing feature is a known WMS
|
|
36
|
+
* permission, resolves a translated message naming it. Returns `null` when
|
|
37
|
+
* the error isn't a recognized 403-with-features shape so callers can fall
|
|
38
|
+
* back to the generic message.
|
|
39
|
+
*/
|
|
40
|
+
function resolveForbiddenFeatureMessage(error: unknown, t?: TranslateFn): string | null {
|
|
41
|
+
if (!error || typeof error !== 'object') return null
|
|
42
|
+
const status = (error as Record<string, unknown>).status
|
|
43
|
+
if (status !== 403) return null
|
|
44
|
+
const requiredFeatures = (error as Record<string, unknown>).requiredFeatures
|
|
45
|
+
if (!Array.isArray(requiredFeatures)) return null
|
|
46
|
+
const knownFeature = requiredFeatures.find(
|
|
47
|
+
(feature): feature is string => typeof feature === 'string' && feature in FORBIDDEN_FEATURE_MESSAGE_KEYS,
|
|
48
|
+
)
|
|
49
|
+
if (!knownFeature) return null
|
|
50
|
+
const key = FORBIDDEN_FEATURE_MESSAGE_KEYS[knownFeature]
|
|
51
|
+
const fallback = FORBIDDEN_FEATURE_MESSAGE_FALLBACKS[knownFeature]
|
|
52
|
+
return t ? t(key, fallback) : fallback
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Surfaces a mutation failure as an error flash toast. Prefers a
|
|
57
|
+
* feature-specific 403 message derived from the server's `requiredFeatures`
|
|
58
|
+
* hint (#4102 follow-up), then the thrown error's own message (already
|
|
59
|
+
* server-derived and translated by `raiseCrudError`/`useGuardedMutation`),
|
|
60
|
+
* and falls back to a translated, dialog-specific message otherwise (#4103).
|
|
61
|
+
*/
|
|
62
|
+
export function flashMutationError(error: unknown, fallbackMessage: string, t?: TranslateFn): void {
|
|
63
|
+
const forbiddenMessage = resolveForbiddenFeatureMessage(error, t)
|
|
64
|
+
if (forbiddenMessage) {
|
|
65
|
+
flash(forbiddenMessage, 'error')
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
// apiFetch throws ForbiddenError with a bare "Forbidden" message when the
|
|
69
|
+
// ACL body has no mappable feature — prefer the dialog-specific fallback
|
|
70
|
+
// over flashing the untranslated server token.
|
|
71
|
+
const rawMessage = error instanceof Error ? error.message.trim() : ''
|
|
72
|
+
const isGenericForbidden = rawMessage.length === 0 || /^forbidden$/i.test(rawMessage)
|
|
73
|
+
flash(isGenericForbidden ? fallbackMessage : rawMessage, 'error')
|
|
74
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'
|
|
2
|
+
import { parseInventoryQuantity } from './inventoryMutationUi'
|
|
3
|
+
|
|
4
|
+
export type InventoryDisplayTranslator = TranslateFn
|
|
5
|
+
|
|
6
|
+
const MOVEMENT_TYPE_FALLBACKS: Record<string, string> = {
|
|
7
|
+
receipt: 'Receive',
|
|
8
|
+
return_receive: 'Receive',
|
|
9
|
+
adjust: 'Adjust',
|
|
10
|
+
transfer: 'Move',
|
|
11
|
+
pick: 'Allocate',
|
|
12
|
+
pack: 'Allocate',
|
|
13
|
+
cycle_count: 'Reconcile',
|
|
14
|
+
putaway: 'Putaway',
|
|
15
|
+
ship: 'Ship',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const RESERVATION_SOURCE_TYPE_FALLBACKS: Record<string, string> = {
|
|
19
|
+
order: 'Sales order',
|
|
20
|
+
transfer: 'Transfer',
|
|
21
|
+
manual: 'Manual',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const REFERENCE_TYPE_FALLBACKS: Record<string, string> = {
|
|
25
|
+
po: 'Purchase order',
|
|
26
|
+
so: 'Sales order',
|
|
27
|
+
transfer: 'Transfer',
|
|
28
|
+
manual: 'Manual',
|
|
29
|
+
qc: 'Quality control',
|
|
30
|
+
rma: 'RMA',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const RESERVATION_STATUS_FALLBACKS: Record<string, string> = {
|
|
34
|
+
active: 'Active',
|
|
35
|
+
released: 'Released',
|
|
36
|
+
fulfilled: 'Fulfilled',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const ROTATION_STRATEGY_FALLBACKS: Record<string, string> = {
|
|
40
|
+
fifo: 'FIFO',
|
|
41
|
+
lifo: 'LIFO',
|
|
42
|
+
fefo: 'FEFO',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const ADJUST_REASON_FALLBACKS: Record<string, string> = {
|
|
46
|
+
damaged: 'Damaged',
|
|
47
|
+
shrinkage: 'Shrinkage',
|
|
48
|
+
found: 'Found stock',
|
|
49
|
+
correction: 'Correction',
|
|
50
|
+
other: 'Other',
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const MOVE_REASON_FALLBACKS: Record<string, string> = {
|
|
54
|
+
transfer: 'Transfer',
|
|
55
|
+
replenishment: 'Replenishment',
|
|
56
|
+
consolidation: 'Consolidation',
|
|
57
|
+
correction: 'Correction',
|
|
58
|
+
other: 'Other',
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const RELEASE_REASON_FALLBACKS: Record<string, string> = {
|
|
62
|
+
order_cancelled: 'Order cancelled',
|
|
63
|
+
manual_release: 'Manual release',
|
|
64
|
+
correction: 'Correction',
|
|
65
|
+
other: 'Other',
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const STABLE_REASON_CODE_PATTERN = /^[a-z][a-z0-9_]*$/
|
|
69
|
+
|
|
70
|
+
export function createInventoryQuantityFormatter(locale: string): Intl.NumberFormat {
|
|
71
|
+
return new Intl.NumberFormat(locale, { maximumFractionDigits: 2 })
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function formatInventoryQuantity(
|
|
75
|
+
value: string | number | null | undefined,
|
|
76
|
+
formatter: Intl.NumberFormat,
|
|
77
|
+
): string {
|
|
78
|
+
return formatter.format(parseInventoryQuantity(value))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function createInventoryDateTimeFormatter(
|
|
82
|
+
locale: string,
|
|
83
|
+
options: Intl.DateTimeFormatOptions = {
|
|
84
|
+
month: '2-digit',
|
|
85
|
+
day: '2-digit',
|
|
86
|
+
hour: '2-digit',
|
|
87
|
+
minute: '2-digit',
|
|
88
|
+
},
|
|
89
|
+
): Intl.DateTimeFormat {
|
|
90
|
+
return new Intl.DateTimeFormat(locale, options)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function formatInventoryDateTime(
|
|
94
|
+
value: string | null | undefined,
|
|
95
|
+
formatter: Intl.DateTimeFormat,
|
|
96
|
+
): string {
|
|
97
|
+
if (!value?.trim()) return '—'
|
|
98
|
+
const date = new Date(value)
|
|
99
|
+
if (Number.isNaN(date.getTime())) return '—'
|
|
100
|
+
return formatter.format(date)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function inventoryMovementTypeLabel(type: string, t: InventoryDisplayTranslator): string {
|
|
104
|
+
const normalized = type.trim()
|
|
105
|
+
if (!normalized) return '—'
|
|
106
|
+
return t(
|
|
107
|
+
`wms.backend.dashboard.activity.types.${normalized}`,
|
|
108
|
+
MOVEMENT_TYPE_FALLBACKS[normalized] ?? normalized,
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function inventoryReservationSourceTypeLabel(
|
|
113
|
+
sourceType: string,
|
|
114
|
+
t: InventoryDisplayTranslator,
|
|
115
|
+
): string {
|
|
116
|
+
const normalized = sourceType.trim()
|
|
117
|
+
if (!normalized) return '—'
|
|
118
|
+
return t(
|
|
119
|
+
`wms.backend.inventory.sourceTypes.${normalized}`,
|
|
120
|
+
RESERVATION_SOURCE_TYPE_FALLBACKS[normalized] ?? normalized,
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function inventoryReferenceTypeLabel(
|
|
125
|
+
referenceType: string,
|
|
126
|
+
t: InventoryDisplayTranslator,
|
|
127
|
+
): string {
|
|
128
|
+
const normalized = referenceType.trim()
|
|
129
|
+
if (!normalized) return '—'
|
|
130
|
+
return t(
|
|
131
|
+
`wms.backend.inventory.referenceTypes.${normalized}`,
|
|
132
|
+
REFERENCE_TYPE_FALLBACKS[normalized] ?? normalized,
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function inventoryReservationStatusLabel(status: string, t: InventoryDisplayTranslator): string {
|
|
137
|
+
const normalized = status.trim()
|
|
138
|
+
if (!normalized) return '—'
|
|
139
|
+
return t(
|
|
140
|
+
`wms.backend.inventory.reservationStatuses.${normalized}`,
|
|
141
|
+
RESERVATION_STATUS_FALLBACKS[normalized] ?? normalized,
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function inventoryRotationStrategyLabel(strategy: string, t: InventoryDisplayTranslator): string {
|
|
146
|
+
const normalized = strategy.trim()
|
|
147
|
+
if (!normalized) return '—'
|
|
148
|
+
return t(
|
|
149
|
+
`wms.widgets.catalog.inventoryProfile.strategy.${normalized}`,
|
|
150
|
+
ROTATION_STRATEGY_FALLBACKS[normalized] ?? normalized,
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function translateStableReasonCode(
|
|
155
|
+
code: string,
|
|
156
|
+
movementType: string | null | undefined,
|
|
157
|
+
t: InventoryDisplayTranslator,
|
|
158
|
+
): string | null {
|
|
159
|
+
if (code === 'cycle_count') {
|
|
160
|
+
return t('wms.backend.dashboard.activity.reasons.cycleCount', 'Cycle count')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const type = (movementType ?? '').trim()
|
|
164
|
+
if (type === 'transfer' && code in MOVE_REASON_FALLBACKS) {
|
|
165
|
+
return t(`wms.backend.inventory.move.reasons.${code}`, MOVE_REASON_FALLBACKS[code])
|
|
166
|
+
}
|
|
167
|
+
if ((type === 'adjust' || type === 'cycle_count') && code in ADJUST_REASON_FALLBACKS) {
|
|
168
|
+
return t(`wms.backend.inventory.adjust.reasons.${code}`, ADJUST_REASON_FALLBACKS[code])
|
|
169
|
+
}
|
|
170
|
+
if (code in ADJUST_REASON_FALLBACKS) {
|
|
171
|
+
return t(`wms.backend.inventory.adjust.reasons.${code}`, ADJUST_REASON_FALLBACKS[code])
|
|
172
|
+
}
|
|
173
|
+
if (code in MOVE_REASON_FALLBACKS) {
|
|
174
|
+
return t(`wms.backend.inventory.move.reasons.${code}`, MOVE_REASON_FALLBACKS[code])
|
|
175
|
+
}
|
|
176
|
+
if (code in RELEASE_REASON_FALLBACKS) {
|
|
177
|
+
return t(`wms.backend.inventory.release.reasons.${code}`, RELEASE_REASON_FALLBACKS[code])
|
|
178
|
+
}
|
|
179
|
+
return null
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Resolve a movement/activity reason for display. Prefers the stable
|
|
184
|
+
* `reasonCode` (re-translated for the current locale) over a free-text
|
|
185
|
+
* `reason` that may have been baked in a different language at write time.
|
|
186
|
+
*/
|
|
187
|
+
export function inventoryMovementReasonLabel(
|
|
188
|
+
input: {
|
|
189
|
+
reasonCode?: string | null
|
|
190
|
+
reason?: string | null
|
|
191
|
+
movementType?: string | null
|
|
192
|
+
},
|
|
193
|
+
t: InventoryDisplayTranslator,
|
|
194
|
+
): string | null {
|
|
195
|
+
const reasonCode = input.reasonCode?.trim() || null
|
|
196
|
+
const reason = input.reason?.trim() || null
|
|
197
|
+
const candidateCode =
|
|
198
|
+
reasonCode ||
|
|
199
|
+
(reason && STABLE_REASON_CODE_PATTERN.test(reason) ? reason : null)
|
|
200
|
+
|
|
201
|
+
if (candidateCode) {
|
|
202
|
+
const translated = translateStableReasonCode(candidateCode, input.movementType, t)
|
|
203
|
+
if (translated) return translated
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return reason
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function formatCatalogProductLabel(row: {
|
|
210
|
+
product_title?: string | null
|
|
211
|
+
product_sku?: string | null
|
|
212
|
+
catalog_product_id?: string | null
|
|
213
|
+
}): string {
|
|
214
|
+
const title = (row.product_title ?? '').trim()
|
|
215
|
+
const sku = (row.product_sku ?? '').trim()
|
|
216
|
+
if (title && sku) return `${title} (${sku})`
|
|
217
|
+
if (title) return title
|
|
218
|
+
if (sku) return sku
|
|
219
|
+
return row.catalog_product_id?.trim() || '—'
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function formatCatalogVariantLabel(row: {
|
|
223
|
+
variant_name?: string | null
|
|
224
|
+
variant_sku?: string | null
|
|
225
|
+
catalog_variant_id?: string | null
|
|
226
|
+
}): string {
|
|
227
|
+
const name = (row.variant_name ?? '').trim()
|
|
228
|
+
const sku = (row.variant_sku ?? '').trim()
|
|
229
|
+
if (name && sku) return `${name} (${sku})`
|
|
230
|
+
if (name) return name
|
|
231
|
+
if (sku) return sku
|
|
232
|
+
return row.catalog_variant_id?.trim() || '—'
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function formatReservationSourceLabel(
|
|
236
|
+
row: {
|
|
237
|
+
source_type?: string | null
|
|
238
|
+
source_id?: string | null
|
|
239
|
+
source_label?: string | null
|
|
240
|
+
},
|
|
241
|
+
t: InventoryDisplayTranslator,
|
|
242
|
+
): string {
|
|
243
|
+
const sourceType = row.source_type?.trim()
|
|
244
|
+
if (!sourceType) return '—'
|
|
245
|
+
const typeLabel = inventoryReservationSourceTypeLabel(sourceType, t)
|
|
246
|
+
const sourceLabel = row.source_label?.trim()
|
|
247
|
+
if (sourceLabel) return `${typeLabel} · ${sourceLabel}`
|
|
248
|
+
return typeLabel
|
|
249
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { InventoryMovementType, InventoryReservationSourceType } from '../data/entities'
|
|
2
|
+
|
|
3
|
+
function normalizeSegment(value: string | null | undefined): string {
|
|
4
|
+
if (typeof value !== 'string' || value.trim().length === 0) return ''
|
|
5
|
+
return value.trim()
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function normalizeQuantity(value: number): string {
|
|
9
|
+
return String(value)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function buildMovementIdempotencyKey(input: {
|
|
13
|
+
referenceType: string
|
|
14
|
+
referenceId: string
|
|
15
|
+
type: InventoryMovementType
|
|
16
|
+
warehouseId: string
|
|
17
|
+
locationFromId?: string | null
|
|
18
|
+
locationToId?: string | null
|
|
19
|
+
catalogVariantId: string
|
|
20
|
+
lotId?: string | null
|
|
21
|
+
serialNumber?: string | null
|
|
22
|
+
quantity: number
|
|
23
|
+
}): string {
|
|
24
|
+
return [
|
|
25
|
+
'movement',
|
|
26
|
+
normalizeSegment(input.referenceType),
|
|
27
|
+
normalizeSegment(input.referenceId),
|
|
28
|
+
normalizeSegment(input.type),
|
|
29
|
+
normalizeSegment(input.warehouseId),
|
|
30
|
+
normalizeSegment(input.locationFromId),
|
|
31
|
+
normalizeSegment(input.locationToId),
|
|
32
|
+
normalizeSegment(input.catalogVariantId),
|
|
33
|
+
normalizeSegment(input.lotId),
|
|
34
|
+
normalizeSegment(input.serialNumber),
|
|
35
|
+
normalizeQuantity(input.quantity),
|
|
36
|
+
].join('|')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function buildReservationIdempotencyKey(input: {
|
|
40
|
+
sourceType: InventoryReservationSourceType
|
|
41
|
+
sourceId: string
|
|
42
|
+
catalogVariantId: string
|
|
43
|
+
warehouseId: string
|
|
44
|
+
quantity: number
|
|
45
|
+
}): string {
|
|
46
|
+
return [
|
|
47
|
+
'reservation',
|
|
48
|
+
normalizeSegment(input.sourceType),
|
|
49
|
+
normalizeSegment(input.sourceId),
|
|
50
|
+
normalizeSegment(input.catalogVariantId),
|
|
51
|
+
normalizeSegment(input.warehouseId),
|
|
52
|
+
normalizeQuantity(input.quantity),
|
|
53
|
+
].join('|')
|
|
54
|
+
}
|