@open-mercato/core 0.6.7-develop.6661.1.0043ed1d03 → 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/customer_accounts/migrations/Migration20260724120000_customer_accounts.js +56 -0
- package/dist/modules/customer_accounts/migrations/Migration20260724120000_customer_accounts.js.map +7 -0
- package/dist/modules/directory/api/organizations/route.js +1 -1
- package/dist/modules/directory/api/organizations/route.js.map +1 -1
- package/dist/modules/entities/api/definitions.js +2 -0
- package/dist/modules/entities/api/definitions.js.map +2 -2
- package/dist/modules/entities/lib/helpers.js +1 -0
- package/dist/modules/entities/lib/helpers.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/api/quotes/accept/route.js +7 -2
- package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/public/[token]/route.js +2 -1
- package/dist/modules/sales/api/quotes/public/[token]/route.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/lib/publicQuoteTenantScope.js +24 -0
- package/dist/modules/sales/lib/publicQuoteTenantScope.js.map +7 -0
- 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/customer_accounts/migrations/Migration20260724120000_customer_accounts.ts +96 -0
- package/src/modules/directory/api/organizations/route.ts +1 -1
- package/src/modules/entities/api/definitions.ts +2 -0
- package/src/modules/entities/lib/helpers.ts +1 -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/api/quotes/accept/route.ts +9 -2
- package/src/modules/sales/api/quotes/public/[token]/route.ts +2 -1
- 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/lib/publicQuoteTenantScope.ts +49 -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,580 @@
|
|
|
1
|
+
import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
2
|
+
import {
|
|
3
|
+
InventoryBalance,
|
|
4
|
+
InventoryLot,
|
|
5
|
+
InventoryMovement,
|
|
6
|
+
InventoryReservation,
|
|
7
|
+
ProductInventoryProfile,
|
|
8
|
+
Warehouse
|
|
9
|
+
} from "../data/entities.js";
|
|
10
|
+
import { evaluateLowStock } from "./inventoryPolicy.js";
|
|
11
|
+
import { addUtcDays, EXPIRING_SOON_DAYS, startOfUtcDay } from "./expiry.js";
|
|
12
|
+
const AGING_RESERVATION_DAYS = 7;
|
|
13
|
+
const TREND_DAYS = 7;
|
|
14
|
+
const MONTHLY_TREND_MONTHS = 6;
|
|
15
|
+
const ACTIVITY_LIMIT = 10;
|
|
16
|
+
const EXPIRY_CARD_LIMIT = 5;
|
|
17
|
+
class OperationalDashboardWarehouseNotFoundError extends Error {
|
|
18
|
+
constructor(warehouseId) {
|
|
19
|
+
super(`Warehouse ${warehouseId} not found`);
|
|
20
|
+
this.name = "OperationalDashboardWarehouseNotFoundError";
|
|
21
|
+
this.warehouseId = warehouseId;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function toOperationalDashboardNumber(value) {
|
|
25
|
+
if (typeof value === "number") return value;
|
|
26
|
+
if (typeof value === "string" && value.trim().length > 0) return Number(value);
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
import { addUtcDays as addUtcDays2, startOfUtcDay as startOfUtcDay2 } from "./expiry.js";
|
|
30
|
+
function formatMonthKey(date) {
|
|
31
|
+
return date.toLocaleString("en-US", { month: "short", timeZone: "UTC" });
|
|
32
|
+
}
|
|
33
|
+
function buildDailyBuckets(days, now) {
|
|
34
|
+
const today = startOfUtcDay(now);
|
|
35
|
+
const buckets = [];
|
|
36
|
+
for (let offset = days - 1; offset >= 0; offset -= 1) {
|
|
37
|
+
buckets.push(addUtcDays(today, -offset));
|
|
38
|
+
}
|
|
39
|
+
return buckets;
|
|
40
|
+
}
|
|
41
|
+
function mapDailyCountsToSparkline(dayBuckets, rows) {
|
|
42
|
+
const counts = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const bucket of dayBuckets) {
|
|
44
|
+
counts.set(bucket.getTime(), 0);
|
|
45
|
+
}
|
|
46
|
+
for (const row of rows) {
|
|
47
|
+
const day = startOfUtcDay(row.day instanceof Date ? row.day : new Date(row.day)).getTime();
|
|
48
|
+
if (counts.has(day)) {
|
|
49
|
+
counts.set(day, toOperationalDashboardNumber(row.count));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return dayBuckets.map((bucket) => counts.get(bucket.getTime()) ?? 0);
|
|
53
|
+
}
|
|
54
|
+
function resolveLotAvailableQuantity(lotId, balances, warehouseId) {
|
|
55
|
+
let total = 0;
|
|
56
|
+
for (const balance of balances) {
|
|
57
|
+
if (balance.lot?.id !== lotId) continue;
|
|
58
|
+
if (warehouseId && balance.warehouse.id !== warehouseId) continue;
|
|
59
|
+
const available = toOperationalDashboardNumber(balance.quantityOnHand) - toOperationalDashboardNumber(balance.quantityReserved) - toOperationalDashboardNumber(balance.quantityAllocated);
|
|
60
|
+
if (available > 0) total += available;
|
|
61
|
+
}
|
|
62
|
+
return total;
|
|
63
|
+
}
|
|
64
|
+
function buildExpiryLotRows(expiringSoonLots, pastDueLots, balances, warehouseId, limit = EXPIRY_CARD_LIMIT) {
|
|
65
|
+
const expiringRows = expiringSoonLots.map((lot) => ({
|
|
66
|
+
lot,
|
|
67
|
+
availableQuantity: resolveLotAvailableQuantity(lot.id, balances, warehouseId)
|
|
68
|
+
})).filter(({ availableQuantity }) => availableQuantity > 0).sort((left, right) => {
|
|
69
|
+
const leftTime = left.lot.expiresAt?.getTime() ?? 0;
|
|
70
|
+
const rightTime = right.lot.expiresAt?.getTime() ?? 0;
|
|
71
|
+
return leftTime - rightTime;
|
|
72
|
+
}).slice(0, limit).map(({ lot, availableQuantity }) => ({
|
|
73
|
+
id: lot.id,
|
|
74
|
+
lotNumber: lot.lotNumber,
|
|
75
|
+
sku: lot.sku,
|
|
76
|
+
catalogVariantId: lot.catalogVariantId,
|
|
77
|
+
expiresAt: lot.expiresAt.toISOString(),
|
|
78
|
+
availableQuantity,
|
|
79
|
+
status: lot.status,
|
|
80
|
+
updatedAt: lot.updatedAt?.toISOString() ?? null,
|
|
81
|
+
category: "expiringSoon"
|
|
82
|
+
}));
|
|
83
|
+
const pastDueRows = pastDueLots.map((lot) => ({
|
|
84
|
+
lot,
|
|
85
|
+
availableQuantity: resolveLotAvailableQuantity(lot.id, balances, warehouseId)
|
|
86
|
+
})).filter(({ availableQuantity }) => availableQuantity > 0).sort((left, right) => {
|
|
87
|
+
const leftTime = left.lot.expiresAt?.getTime() ?? 0;
|
|
88
|
+
const rightTime = right.lot.expiresAt?.getTime() ?? 0;
|
|
89
|
+
return leftTime - rightTime;
|
|
90
|
+
}).slice(0, limit).map(({ lot, availableQuantity }) => ({
|
|
91
|
+
id: lot.id,
|
|
92
|
+
lotNumber: lot.lotNumber,
|
|
93
|
+
sku: lot.sku,
|
|
94
|
+
catalogVariantId: lot.catalogVariantId,
|
|
95
|
+
expiresAt: lot.expiresAt.toISOString(),
|
|
96
|
+
availableQuantity,
|
|
97
|
+
status: lot.status,
|
|
98
|
+
updatedAt: lot.updatedAt?.toISOString() ?? null,
|
|
99
|
+
category: "pastDue"
|
|
100
|
+
}));
|
|
101
|
+
return [...expiringRows, ...pastDueRows];
|
|
102
|
+
}
|
|
103
|
+
function computeLowStockCounts(profiles, balances, warehouseId) {
|
|
104
|
+
const availableByVariantWarehouse = /* @__PURE__ */ new Map();
|
|
105
|
+
for (const balance of balances) {
|
|
106
|
+
const onHand = toOperationalDashboardNumber(balance.quantityOnHand);
|
|
107
|
+
const reserved = toOperationalDashboardNumber(balance.quantityReserved);
|
|
108
|
+
const allocated = toOperationalDashboardNumber(balance.quantityAllocated);
|
|
109
|
+
const available = onHand - reserved - allocated;
|
|
110
|
+
const key = `${balance.catalogVariantId}::${balance.warehouse.id}`;
|
|
111
|
+
availableByVariantWarehouse.set(key, (availableByVariantWarehouse.get(key) ?? 0) + available);
|
|
112
|
+
}
|
|
113
|
+
let lowStockCount = 0;
|
|
114
|
+
let reorderCriticalCount = 0;
|
|
115
|
+
const seenLowStockKeys = /* @__PURE__ */ new Set();
|
|
116
|
+
for (const profile of profiles) {
|
|
117
|
+
const variantId = profile.catalogVariantId;
|
|
118
|
+
if (!variantId) continue;
|
|
119
|
+
const reorderPoint = toOperationalDashboardNumber(profile.reorderPoint);
|
|
120
|
+
const safetyStock = toOperationalDashboardNumber(profile.safetyStock);
|
|
121
|
+
if (reorderPoint <= 0 && safetyStock <= 0) continue;
|
|
122
|
+
const warehouseIds = warehouseId ? [warehouseId] : Array.from(new Set(balances.map((balance) => balance.warehouse.id)));
|
|
123
|
+
for (const scopedWarehouseId of warehouseIds) {
|
|
124
|
+
const key = `${variantId}::${scopedWarehouseId}`;
|
|
125
|
+
const available = availableByVariantWarehouse.get(key) ?? 0;
|
|
126
|
+
const evaluation = evaluateLowStock(
|
|
127
|
+
{ reorderPoint: profile.reorderPoint, safetyStock: profile.safetyStock },
|
|
128
|
+
available
|
|
129
|
+
);
|
|
130
|
+
if (!evaluation) continue;
|
|
131
|
+
if (seenLowStockKeys.has(key)) continue;
|
|
132
|
+
seenLowStockKeys.add(key);
|
|
133
|
+
lowStockCount += 1;
|
|
134
|
+
if (evaluation.state === "below_safety_stock") {
|
|
135
|
+
reorderCriticalCount += 1;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return { lowStockCount, reorderCriticalCount };
|
|
140
|
+
}
|
|
141
|
+
function resolveWarehouseLabel(warehouse, warehouseId) {
|
|
142
|
+
return warehouse?.code?.trim() || warehouse?.name?.trim() || warehouseId;
|
|
143
|
+
}
|
|
144
|
+
function resolveLocationLabel(warehouseLabel, fromCode, toCode) {
|
|
145
|
+
if (fromCode && toCode) return `${fromCode} \u2192 ${toCode}`;
|
|
146
|
+
if (toCode) return `${warehouseLabel} \xB7 ${toCode}`;
|
|
147
|
+
if (fromCode) return `${warehouseLabel} \xB7 ${fromCode}`;
|
|
148
|
+
return warehouseLabel;
|
|
149
|
+
}
|
|
150
|
+
function resolveDecryptionScope(scope) {
|
|
151
|
+
return {
|
|
152
|
+
tenantId: scope.tenantId,
|
|
153
|
+
organizationId: scope.organizationId
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function appendWarehouseFilter(sql, params, warehouseId) {
|
|
157
|
+
if (!warehouseId) return sql;
|
|
158
|
+
params.push(warehouseId);
|
|
159
|
+
return `${sql} and warehouse_id = ?`;
|
|
160
|
+
}
|
|
161
|
+
async function loadVariantSkus(em, scope, variantIds) {
|
|
162
|
+
if (variantIds.length === 0) return /* @__PURE__ */ new Map();
|
|
163
|
+
const rows = await em.getConnection().execute(
|
|
164
|
+
`select id, sku from catalog_product_variants
|
|
165
|
+
where organization_id = ? and tenant_id = ? and id in (${variantIds.map(() => "?").join(", ")})
|
|
166
|
+
and deleted_at is null`,
|
|
167
|
+
[scope.organizationId, scope.tenantId, ...variantIds]
|
|
168
|
+
);
|
|
169
|
+
const map = /* @__PURE__ */ new Map();
|
|
170
|
+
for (const row of rows) {
|
|
171
|
+
if (row.id && row.sku) map.set(row.id, row.sku);
|
|
172
|
+
}
|
|
173
|
+
return map;
|
|
174
|
+
}
|
|
175
|
+
async function countMovementsBetween(em, scope, start, end, options) {
|
|
176
|
+
const params = [scope.organizationId, scope.tenantId, start, end];
|
|
177
|
+
let sql = `
|
|
178
|
+
select count(*)::int as count
|
|
179
|
+
from wms_inventory_movements
|
|
180
|
+
where organization_id = ? and tenant_id = ? and deleted_at is null
|
|
181
|
+
and performed_at >= ? and performed_at < ?
|
|
182
|
+
`;
|
|
183
|
+
sql = appendWarehouseFilter(sql, params, scope.warehouseId);
|
|
184
|
+
if (options?.types?.length) {
|
|
185
|
+
sql += ` and type in (${options.types.map(() => "?").join(", ")})`;
|
|
186
|
+
params.push(...options.types);
|
|
187
|
+
}
|
|
188
|
+
if (options?.quantitySign === "negative") {
|
|
189
|
+
sql += " and quantity < 0";
|
|
190
|
+
}
|
|
191
|
+
const rows = await em.getConnection().execute(sql, params);
|
|
192
|
+
return toOperationalDashboardNumber(rows[0]?.count);
|
|
193
|
+
}
|
|
194
|
+
async function loadMovementDailyCounts(em, scope, start, options) {
|
|
195
|
+
const params = [scope.organizationId, scope.tenantId, start];
|
|
196
|
+
let sql = `
|
|
197
|
+
select date_trunc('day', performed_at) as day, count(*)::int as count
|
|
198
|
+
from wms_inventory_movements
|
|
199
|
+
where organization_id = ? and tenant_id = ? and deleted_at is null
|
|
200
|
+
and performed_at >= ?
|
|
201
|
+
`;
|
|
202
|
+
sql = appendWarehouseFilter(sql, params, scope.warehouseId);
|
|
203
|
+
if (options?.types?.length) {
|
|
204
|
+
sql += ` and type in (${options.types.map(() => "?").join(", ")})`;
|
|
205
|
+
params.push(...options.types);
|
|
206
|
+
}
|
|
207
|
+
if (options?.quantitySign === "negative") {
|
|
208
|
+
sql += " and quantity < 0";
|
|
209
|
+
}
|
|
210
|
+
sql += " group by 1 order by 1";
|
|
211
|
+
return em.getConnection().execute(sql, params);
|
|
212
|
+
}
|
|
213
|
+
async function loadMonthlyMovementTrends(em, scope, monthlyStart, now) {
|
|
214
|
+
const params = [scope.organizationId, scope.tenantId, monthlyStart];
|
|
215
|
+
let sql = `
|
|
216
|
+
select date_trunc('month', performed_at) as month_start, type, count(*)::int as count
|
|
217
|
+
from wms_inventory_movements
|
|
218
|
+
where organization_id = ? and tenant_id = ? and deleted_at is null
|
|
219
|
+
and performed_at >= ?
|
|
220
|
+
`;
|
|
221
|
+
sql = appendWarehouseFilter(sql, params, scope.warehouseId);
|
|
222
|
+
sql += " group by 1, 2 order by 1";
|
|
223
|
+
const rows = await em.getConnection().execute(sql, params);
|
|
224
|
+
const monthlyTrendMap = /* @__PURE__ */ new Map();
|
|
225
|
+
for (let index = 0; index < MONTHLY_TREND_MONTHS; index += 1) {
|
|
226
|
+
const monthDate = new Date(
|
|
227
|
+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (MONTHLY_TREND_MONTHS - 1 - index), 1)
|
|
228
|
+
);
|
|
229
|
+
monthlyTrendMap.set(formatMonthKey(monthDate), { receive: 0, allocate: 0 });
|
|
230
|
+
}
|
|
231
|
+
for (const row of rows) {
|
|
232
|
+
const monthDate = row.month_start instanceof Date ? row.month_start : new Date(row.month_start);
|
|
233
|
+
const key = formatMonthKey(monthDate);
|
|
234
|
+
const bucket = monthlyTrendMap.get(key);
|
|
235
|
+
if (!bucket) continue;
|
|
236
|
+
if (row.type === "receipt" || row.type === "return_receive") {
|
|
237
|
+
bucket.receive += toOperationalDashboardNumber(row.count);
|
|
238
|
+
}
|
|
239
|
+
if (row.type === "pick" || row.type === "pack") {
|
|
240
|
+
bucket.allocate += toOperationalDashboardNumber(row.count);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return Array.from(monthlyTrendMap.entries()).map(([month, values]) => ({
|
|
244
|
+
month,
|
|
245
|
+
receive: values.receive,
|
|
246
|
+
allocate: values.allocate
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
async function loadExpiringSoonDailyCounts(em, scope, dayBuckets) {
|
|
250
|
+
if (dayBuckets.length === 0) return [];
|
|
251
|
+
const trendStart = dayBuckets[0];
|
|
252
|
+
const trendEnd = dayBuckets[dayBuckets.length - 1];
|
|
253
|
+
const params = [
|
|
254
|
+
trendStart,
|
|
255
|
+
trendEnd,
|
|
256
|
+
scope.organizationId,
|
|
257
|
+
scope.tenantId
|
|
258
|
+
];
|
|
259
|
+
let sql = `
|
|
260
|
+
select bucket.day as day, count(distinct l.id)::int as count
|
|
261
|
+
from (
|
|
262
|
+
select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day
|
|
263
|
+
) bucket
|
|
264
|
+
join wms_inventory_lots l
|
|
265
|
+
on l.organization_id = ?
|
|
266
|
+
and l.tenant_id = ?
|
|
267
|
+
and l.deleted_at is null
|
|
268
|
+
and l.status = 'available'
|
|
269
|
+
and l.expires_at is not null
|
|
270
|
+
and l.expires_at >= bucket.day
|
|
271
|
+
and l.expires_at <= bucket.day + interval '${EXPIRING_SOON_DAYS} days'
|
|
272
|
+
`;
|
|
273
|
+
if (scope.warehouseId) {
|
|
274
|
+
sql += `
|
|
275
|
+
join wms_inventory_balances b
|
|
276
|
+
on b.lot_id = l.id
|
|
277
|
+
and b.deleted_at is null
|
|
278
|
+
and b.warehouse_id = ?
|
|
279
|
+
`;
|
|
280
|
+
params.push(scope.warehouseId);
|
|
281
|
+
}
|
|
282
|
+
sql += " group by bucket.day order by bucket.day";
|
|
283
|
+
return em.getConnection().execute(sql, params);
|
|
284
|
+
}
|
|
285
|
+
async function loadPastDueLotCount(em, scope, todayStart) {
|
|
286
|
+
const params = [scope.organizationId, scope.tenantId, todayStart];
|
|
287
|
+
let sql = `
|
|
288
|
+
select count(distinct l.id)::int as count
|
|
289
|
+
from wms_inventory_lots l
|
|
290
|
+
join wms_inventory_balances b
|
|
291
|
+
on b.lot_id = l.id
|
|
292
|
+
and b.deleted_at is null
|
|
293
|
+
and (
|
|
294
|
+
coalesce(b.quantity_on_hand, 0)
|
|
295
|
+
- coalesce(b.quantity_reserved, 0)
|
|
296
|
+
- coalesce(b.quantity_allocated, 0)
|
|
297
|
+
) > 0
|
|
298
|
+
where l.organization_id = ?
|
|
299
|
+
and l.tenant_id = ?
|
|
300
|
+
and l.deleted_at is null
|
|
301
|
+
and l.status = 'available'
|
|
302
|
+
and l.expires_at is not null
|
|
303
|
+
and l.expires_at < ?
|
|
304
|
+
`;
|
|
305
|
+
if (scope.warehouseId) {
|
|
306
|
+
sql += " and b.warehouse_id = ?";
|
|
307
|
+
params.push(scope.warehouseId);
|
|
308
|
+
}
|
|
309
|
+
const rows = await em.getConnection().execute(sql, params);
|
|
310
|
+
return toOperationalDashboardNumber(rows[0]?.count);
|
|
311
|
+
}
|
|
312
|
+
async function loadPastDueDailyCounts(em, scope, dayBuckets) {
|
|
313
|
+
if (dayBuckets.length === 0) return [];
|
|
314
|
+
const params = [
|
|
315
|
+
dayBuckets[0],
|
|
316
|
+
dayBuckets[dayBuckets.length - 1],
|
|
317
|
+
scope.organizationId,
|
|
318
|
+
scope.tenantId
|
|
319
|
+
];
|
|
320
|
+
let sql = `
|
|
321
|
+
select bucket.day as day, count(distinct l.id)::int as count
|
|
322
|
+
from (
|
|
323
|
+
select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day
|
|
324
|
+
) bucket
|
|
325
|
+
join wms_inventory_lots l
|
|
326
|
+
on l.organization_id = ?
|
|
327
|
+
and l.tenant_id = ?
|
|
328
|
+
and l.deleted_at is null
|
|
329
|
+
and l.status = 'available'
|
|
330
|
+
and l.expires_at is not null
|
|
331
|
+
and l.expires_at < bucket.day
|
|
332
|
+
join wms_inventory_balances b
|
|
333
|
+
on b.lot_id = l.id
|
|
334
|
+
and b.deleted_at is null
|
|
335
|
+
and (
|
|
336
|
+
coalesce(b.quantity_on_hand, 0)
|
|
337
|
+
- coalesce(b.quantity_reserved, 0)
|
|
338
|
+
- coalesce(b.quantity_allocated, 0)
|
|
339
|
+
) > 0
|
|
340
|
+
`;
|
|
341
|
+
if (scope.warehouseId) {
|
|
342
|
+
sql += " and b.warehouse_id = ?";
|
|
343
|
+
params.push(scope.warehouseId);
|
|
344
|
+
}
|
|
345
|
+
sql += " group by bucket.day order by bucket.day";
|
|
346
|
+
return em.getConnection().execute(sql, params);
|
|
347
|
+
}
|
|
348
|
+
async function loadAgingReservationsDailyCounts(em, scope, dayBuckets) {
|
|
349
|
+
if (dayBuckets.length === 0) return [];
|
|
350
|
+
const params = [
|
|
351
|
+
dayBuckets[0],
|
|
352
|
+
dayBuckets[dayBuckets.length - 1],
|
|
353
|
+
scope.organizationId,
|
|
354
|
+
scope.tenantId,
|
|
355
|
+
String(AGING_RESERVATION_DAYS)
|
|
356
|
+
];
|
|
357
|
+
let sql = `
|
|
358
|
+
select bucket.day as day, count(r.id)::int as count
|
|
359
|
+
from (
|
|
360
|
+
select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day
|
|
361
|
+
) bucket
|
|
362
|
+
join wms_inventory_reservations r
|
|
363
|
+
on r.organization_id = ?
|
|
364
|
+
and r.tenant_id = ?
|
|
365
|
+
and r.deleted_at is null
|
|
366
|
+
and r.status = 'active'
|
|
367
|
+
and r.created_at <= bucket.day - (?::int * interval '1 day')
|
|
368
|
+
`;
|
|
369
|
+
sql = appendWarehouseFilter(sql, params, scope.warehouseId);
|
|
370
|
+
sql += " group by bucket.day order by bucket.day";
|
|
371
|
+
return em.getConnection().execute(sql, params);
|
|
372
|
+
}
|
|
373
|
+
async function loadOperationalDashboard(em, scope) {
|
|
374
|
+
const now = /* @__PURE__ */ new Date();
|
|
375
|
+
const todayStart = startOfUtcDay(now);
|
|
376
|
+
const tomorrowStart = addUtcDays(todayStart, 1);
|
|
377
|
+
const yesterdayStart = addUtcDays(todayStart, -1);
|
|
378
|
+
const agingCutoff = addUtcDays(todayStart, -AGING_RESERVATION_DAYS);
|
|
379
|
+
const expiringCutoff = addUtcDays(todayStart, EXPIRING_SOON_DAYS);
|
|
380
|
+
const trendStart = addUtcDays(todayStart, -(TREND_DAYS - 1));
|
|
381
|
+
const dayBuckets = buildDailyBuckets(TREND_DAYS, now);
|
|
382
|
+
const decryptionScope = resolveDecryptionScope(scope);
|
|
383
|
+
const baseScope = {
|
|
384
|
+
organizationId: scope.organizationId,
|
|
385
|
+
tenantId: scope.tenantId,
|
|
386
|
+
deletedAt: null
|
|
387
|
+
};
|
|
388
|
+
if (scope.warehouseId) {
|
|
389
|
+
const warehouse = await findOneWithDecryption(
|
|
390
|
+
em,
|
|
391
|
+
Warehouse,
|
|
392
|
+
{ id: scope.warehouseId, ...baseScope },
|
|
393
|
+
void 0,
|
|
394
|
+
decryptionScope
|
|
395
|
+
);
|
|
396
|
+
if (!warehouse) {
|
|
397
|
+
throw new OperationalDashboardWarehouseNotFoundError(scope.warehouseId);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
const warehouseFilter = scope.warehouseId ? { warehouse: scope.warehouseId } : {};
|
|
401
|
+
const [profiles, balances, expiringSoonLots, pastDueLots, reservations, activityMovements] = await Promise.all([
|
|
402
|
+
findWithDecryption(em, ProductInventoryProfile, baseScope, void 0, decryptionScope),
|
|
403
|
+
findWithDecryption(
|
|
404
|
+
em,
|
|
405
|
+
InventoryBalance,
|
|
406
|
+
{ ...baseScope, ...warehouseFilter },
|
|
407
|
+
{ populate: ["warehouse", "location", "lot"] },
|
|
408
|
+
decryptionScope
|
|
409
|
+
),
|
|
410
|
+
findWithDecryption(
|
|
411
|
+
em,
|
|
412
|
+
InventoryLot,
|
|
413
|
+
{
|
|
414
|
+
...baseScope,
|
|
415
|
+
status: "available",
|
|
416
|
+
expiresAt: { $ne: null, $gte: todayStart, $lte: expiringCutoff }
|
|
417
|
+
},
|
|
418
|
+
{ orderBy: { expiresAt: "ASC" }, limit: 100 },
|
|
419
|
+
decryptionScope
|
|
420
|
+
),
|
|
421
|
+
findWithDecryption(
|
|
422
|
+
em,
|
|
423
|
+
InventoryLot,
|
|
424
|
+
{
|
|
425
|
+
...baseScope,
|
|
426
|
+
status: "available",
|
|
427
|
+
expiresAt: { $ne: null, $lt: todayStart }
|
|
428
|
+
},
|
|
429
|
+
{ orderBy: { expiresAt: "ASC" }, limit: 100 },
|
|
430
|
+
decryptionScope
|
|
431
|
+
),
|
|
432
|
+
findWithDecryption(
|
|
433
|
+
em,
|
|
434
|
+
InventoryReservation,
|
|
435
|
+
{
|
|
436
|
+
...baseScope,
|
|
437
|
+
...warehouseFilter,
|
|
438
|
+
status: "active",
|
|
439
|
+
createdAt: { $lte: agingCutoff }
|
|
440
|
+
},
|
|
441
|
+
void 0,
|
|
442
|
+
decryptionScope
|
|
443
|
+
),
|
|
444
|
+
findWithDecryption(
|
|
445
|
+
em,
|
|
446
|
+
InventoryMovement,
|
|
447
|
+
{ ...baseScope, ...warehouseFilter },
|
|
448
|
+
{
|
|
449
|
+
populate: ["warehouse", "locationFrom", "locationTo"],
|
|
450
|
+
orderBy: { performedAt: "DESC" },
|
|
451
|
+
limit: ACTIVITY_LIMIT
|
|
452
|
+
},
|
|
453
|
+
decryptionScope
|
|
454
|
+
)
|
|
455
|
+
]);
|
|
456
|
+
const { lowStockCount, reorderCriticalCount } = computeLowStockCounts(
|
|
457
|
+
profiles,
|
|
458
|
+
balances,
|
|
459
|
+
scope.warehouseId
|
|
460
|
+
);
|
|
461
|
+
const expiringSoonCount = expiringSoonLots.filter(
|
|
462
|
+
(lot) => resolveLotAvailableQuantity(lot.id, balances, scope.warehouseId) > 0
|
|
463
|
+
).length;
|
|
464
|
+
const agingReservationsCount = reservations.length;
|
|
465
|
+
const [
|
|
466
|
+
todaysMoveCount,
|
|
467
|
+
yesterdaysMoveCount,
|
|
468
|
+
pastDueCount,
|
|
469
|
+
lowStockSparklineRows,
|
|
470
|
+
reorderCriticalSparklineRows,
|
|
471
|
+
expiringSoonSparklineRows,
|
|
472
|
+
pastDueSparklineRows,
|
|
473
|
+
agingReservationsSparklineRows,
|
|
474
|
+
todaysMovesSparklineRows,
|
|
475
|
+
monthlyTrends
|
|
476
|
+
] = await Promise.all([
|
|
477
|
+
countMovementsBetween(em, scope, todayStart, tomorrowStart),
|
|
478
|
+
countMovementsBetween(em, scope, yesterdayStart, todayStart),
|
|
479
|
+
loadPastDueLotCount(em, scope, todayStart),
|
|
480
|
+
loadMovementDailyCounts(em, scope, trendStart, { types: ["adjust"], quantitySign: "negative" }),
|
|
481
|
+
loadMovementDailyCounts(em, scope, trendStart, { types: ["adjust"], quantitySign: "negative" }),
|
|
482
|
+
loadExpiringSoonDailyCounts(em, scope, dayBuckets),
|
|
483
|
+
loadPastDueDailyCounts(em, scope, dayBuckets),
|
|
484
|
+
loadAgingReservationsDailyCounts(em, scope, dayBuckets),
|
|
485
|
+
loadMovementDailyCounts(em, scope, trendStart),
|
|
486
|
+
loadMonthlyMovementTrends(
|
|
487
|
+
em,
|
|
488
|
+
scope,
|
|
489
|
+
new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (MONTHLY_TREND_MONTHS - 1), 1)),
|
|
490
|
+
now
|
|
491
|
+
)
|
|
492
|
+
]);
|
|
493
|
+
const kpis = [
|
|
494
|
+
{
|
|
495
|
+
id: "lowStock",
|
|
496
|
+
count: lowStockCount,
|
|
497
|
+
deltaSinceYesterday: null,
|
|
498
|
+
sparkline: mapDailyCountsToSparkline(dayBuckets, lowStockSparklineRows)
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
id: "reorderCritical",
|
|
502
|
+
count: reorderCriticalCount,
|
|
503
|
+
deltaSinceYesterday: null,
|
|
504
|
+
sparkline: mapDailyCountsToSparkline(dayBuckets, reorderCriticalSparklineRows)
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
id: "expiringSoon",
|
|
508
|
+
count: expiringSoonCount,
|
|
509
|
+
deltaSinceYesterday: null,
|
|
510
|
+
sparkline: mapDailyCountsToSparkline(dayBuckets, expiringSoonSparklineRows)
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
id: "pastDue",
|
|
514
|
+
count: pastDueCount,
|
|
515
|
+
deltaSinceYesterday: null,
|
|
516
|
+
sparkline: mapDailyCountsToSparkline(dayBuckets, pastDueSparklineRows)
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
id: "agingReservations",
|
|
520
|
+
count: agingReservationsCount,
|
|
521
|
+
deltaSinceYesterday: null,
|
|
522
|
+
sparkline: mapDailyCountsToSparkline(dayBuckets, agingReservationsSparklineRows)
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
id: "todaysMoves",
|
|
526
|
+
count: todaysMoveCount,
|
|
527
|
+
deltaSinceYesterday: todaysMoveCount - yesterdaysMoveCount,
|
|
528
|
+
sparkline: mapDailyCountsToSparkline(dayBuckets, todaysMovesSparklineRows)
|
|
529
|
+
}
|
|
530
|
+
];
|
|
531
|
+
const variantIds = Array.from(new Set(activityMovements.map((movement) => movement.catalogVariantId)));
|
|
532
|
+
const variantSkus = await loadVariantSkus(em, scope, variantIds);
|
|
533
|
+
const recentActivity = activityMovements.map((movement) => {
|
|
534
|
+
const warehouseLabel = resolveWarehouseLabel(movement.warehouse, movement.warehouse.id);
|
|
535
|
+
return {
|
|
536
|
+
id: movement.id,
|
|
537
|
+
movementType: movement.type,
|
|
538
|
+
quantity: toOperationalDashboardNumber(movement.quantity),
|
|
539
|
+
variantSku: variantSkus.get(movement.catalogVariantId) ?? null,
|
|
540
|
+
variantId: movement.catalogVariantId,
|
|
541
|
+
referenceType: movement.referenceType ?? null,
|
|
542
|
+
referenceId: movement.referenceId ?? null,
|
|
543
|
+
reason: movement.reason ?? null,
|
|
544
|
+
reasonCode: movement.reasonCode ?? null,
|
|
545
|
+
locationLabel: resolveLocationLabel(
|
|
546
|
+
warehouseLabel,
|
|
547
|
+
movement.locationFrom?.code,
|
|
548
|
+
movement.locationTo?.code
|
|
549
|
+
),
|
|
550
|
+
performedAt: movement.performedAt.toISOString()
|
|
551
|
+
};
|
|
552
|
+
});
|
|
553
|
+
const expiryLots = buildExpiryLotRows(
|
|
554
|
+
expiringSoonLots,
|
|
555
|
+
pastDueLots,
|
|
556
|
+
balances,
|
|
557
|
+
scope.warehouseId
|
|
558
|
+
);
|
|
559
|
+
return {
|
|
560
|
+
lastUpdatedAt: now.toISOString(),
|
|
561
|
+
warehouseId: scope.warehouseId ?? null,
|
|
562
|
+
kpis,
|
|
563
|
+
expiryLots,
|
|
564
|
+
monthlyTrends,
|
|
565
|
+
recentActivity
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
export {
|
|
569
|
+
OperationalDashboardWarehouseNotFoundError,
|
|
570
|
+
addUtcDays2 as addUtcDays,
|
|
571
|
+
buildDailyBuckets,
|
|
572
|
+
buildExpiryLotRows,
|
|
573
|
+
computeLowStockCounts,
|
|
574
|
+
loadOperationalDashboard,
|
|
575
|
+
mapDailyCountsToSparkline,
|
|
576
|
+
resolveLotAvailableQuantity,
|
|
577
|
+
startOfUtcDay2 as startOfUtcDay,
|
|
578
|
+
toOperationalDashboardNumber
|
|
579
|
+
};
|
|
580
|
+
//# sourceMappingURL=loadOperationalDashboard.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/wms/lib/loadOperationalDashboard.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n InventoryBalance,\n InventoryLot,\n InventoryMovement,\n InventoryReservation,\n ProductInventoryProfile,\n Warehouse,\n} from '../data/entities'\nimport { evaluateLowStock } from './inventoryPolicy'\nimport { addUtcDays, EXPIRING_SOON_DAYS, startOfUtcDay } from './expiry'\n\nconst AGING_RESERVATION_DAYS = 7\nconst TREND_DAYS = 7\nconst MONTHLY_TREND_MONTHS = 6\nconst ACTIVITY_LIMIT = 10\nconst EXPIRY_CARD_LIMIT = 5\n\nexport type OperationalDashboardScope = {\n organizationId: string\n tenantId: string\n warehouseId?: string | null\n}\n\nexport type OperationalDashboardKpiId =\n | 'lowStock'\n | 'reorderCritical'\n | 'expiringSoon'\n | 'pastDue'\n | 'agingReservations'\n | 'todaysMoves'\n\nexport type OperationalDashboardKpi = {\n id: OperationalDashboardKpiId\n count: number\n deltaSinceYesterday: number | null\n sparkline: number[]\n}\n\nexport type OperationalDashboardTrendPoint = {\n month: string\n receive: number\n allocate: number\n}\n\nexport type OperationalDashboardActivityRow = {\n id: string\n movementType: string\n quantity: number\n variantSku: string | null\n variantId: string\n referenceType: string | null\n referenceId: string | null\n reason: string | null\n reasonCode: string | null\n locationLabel: string\n performedAt: string\n}\n\nexport type OperationalDashboardExpiryLotRow = {\n id: string\n lotNumber: string\n sku: string\n catalogVariantId: string\n expiresAt: string\n availableQuantity: number\n status: string\n updatedAt: string | null\n category: 'expiringSoon' | 'pastDue'\n}\n\nexport type OperationalDashboardPayload = {\n lastUpdatedAt: string\n warehouseId: string | null\n kpis: OperationalDashboardKpi[]\n expiryLots: OperationalDashboardExpiryLotRow[]\n monthlyTrends: OperationalDashboardTrendPoint[]\n recentActivity: OperationalDashboardActivityRow[]\n}\n\nexport class OperationalDashboardWarehouseNotFoundError extends Error {\n readonly warehouseId: string\n\n constructor(warehouseId: string) {\n super(`Warehouse ${warehouseId} not found`)\n this.name = 'OperationalDashboardWarehouseNotFoundError'\n this.warehouseId = warehouseId\n }\n}\n\ntype DecryptionScope = {\n tenantId: string\n organizationId: string\n}\n\ntype DailyCountRow = {\n day: Date | string\n count: string | number\n}\n\ntype MonthlyTrendRow = {\n month_start: Date | string\n type: string\n count: string | number\n}\n\nexport function toOperationalDashboardNumber(value: string | number | null | undefined): number {\n if (typeof value === 'number') return value\n if (typeof value === 'string' && value.trim().length > 0) return Number(value)\n return 0\n}\n\nexport { addUtcDays, startOfUtcDay } from './expiry'\n\nfunction formatMonthKey(date: Date): string {\n return date.toLocaleString('en-US', { month: 'short', timeZone: 'UTC' })\n}\n\nexport function buildDailyBuckets(days: number, now: Date): Date[] {\n const today = startOfUtcDay(now)\n const buckets: Date[] = []\n for (let offset = days - 1; offset >= 0; offset -= 1) {\n buckets.push(addUtcDays(today, -offset))\n }\n return buckets\n}\n\nexport function mapDailyCountsToSparkline(\n dayBuckets: Date[],\n rows: Array<{ day: Date | string; count: string | number }>,\n): number[] {\n const counts = new Map<number, number>()\n for (const bucket of dayBuckets) {\n counts.set(bucket.getTime(), 0)\n }\n for (const row of rows) {\n const day = startOfUtcDay(row.day instanceof Date ? row.day : new Date(row.day)).getTime()\n if (counts.has(day)) {\n counts.set(day, toOperationalDashboardNumber(row.count))\n }\n }\n return dayBuckets.map((bucket) => counts.get(bucket.getTime()) ?? 0)\n}\n\nexport function resolveLotAvailableQuantity(\n lotId: string,\n balances: InventoryBalance[],\n warehouseId?: string | null,\n): number {\n let total = 0\n for (const balance of balances) {\n if (balance.lot?.id !== lotId) continue\n if (warehouseId && balance.warehouse.id !== warehouseId) continue\n const available =\n toOperationalDashboardNumber(balance.quantityOnHand)\n - toOperationalDashboardNumber(balance.quantityReserved)\n - toOperationalDashboardNumber(balance.quantityAllocated)\n if (available > 0) total += available\n }\n return total\n}\n\nexport function buildExpiryLotRows(\n expiringSoonLots: InventoryLot[],\n pastDueLots: InventoryLot[],\n balances: InventoryBalance[],\n warehouseId?: string | null,\n limit = EXPIRY_CARD_LIMIT,\n): OperationalDashboardExpiryLotRow[] {\n const expiringRows = expiringSoonLots\n .map((lot) => ({\n lot,\n availableQuantity: resolveLotAvailableQuantity(lot.id, balances, warehouseId),\n }))\n .filter(({ availableQuantity }) => availableQuantity > 0)\n .sort((left, right) => {\n const leftTime = left.lot.expiresAt?.getTime() ?? 0\n const rightTime = right.lot.expiresAt?.getTime() ?? 0\n return leftTime - rightTime\n })\n .slice(0, limit)\n .map(({ lot, availableQuantity }) => ({\n id: lot.id,\n lotNumber: lot.lotNumber,\n sku: lot.sku,\n catalogVariantId: lot.catalogVariantId,\n expiresAt: lot.expiresAt!.toISOString(),\n availableQuantity,\n status: lot.status,\n updatedAt: lot.updatedAt?.toISOString() ?? null,\n category: 'expiringSoon' as const,\n }))\n\n const pastDueRows = pastDueLots\n .map((lot) => ({\n lot,\n availableQuantity: resolveLotAvailableQuantity(lot.id, balances, warehouseId),\n }))\n .filter(({ availableQuantity }) => availableQuantity > 0)\n .sort((left, right) => {\n const leftTime = left.lot.expiresAt?.getTime() ?? 0\n const rightTime = right.lot.expiresAt?.getTime() ?? 0\n return leftTime - rightTime\n })\n .slice(0, limit)\n .map(({ lot, availableQuantity }) => ({\n id: lot.id,\n lotNumber: lot.lotNumber,\n sku: lot.sku,\n catalogVariantId: lot.catalogVariantId,\n expiresAt: lot.expiresAt!.toISOString(),\n availableQuantity,\n status: lot.status,\n updatedAt: lot.updatedAt?.toISOString() ?? null,\n category: 'pastDue' as const,\n }))\n\n return [...expiringRows, ...pastDueRows]\n}\n\nexport function computeLowStockCounts(\n profiles: ProductInventoryProfile[],\n balances: InventoryBalance[],\n warehouseId?: string | null,\n): { lowStockCount: number; reorderCriticalCount: number } {\n const availableByVariantWarehouse = new Map<string, number>()\n for (const balance of balances) {\n const onHand = toOperationalDashboardNumber(balance.quantityOnHand)\n const reserved = toOperationalDashboardNumber(balance.quantityReserved)\n const allocated = toOperationalDashboardNumber(balance.quantityAllocated)\n const available = onHand - reserved - allocated\n const key = `${balance.catalogVariantId}::${balance.warehouse.id}`\n availableByVariantWarehouse.set(key, (availableByVariantWarehouse.get(key) ?? 0) + available)\n }\n\n let lowStockCount = 0\n let reorderCriticalCount = 0\n const seenLowStockKeys = new Set<string>()\n\n for (const profile of profiles) {\n const variantId = profile.catalogVariantId\n if (!variantId) continue\n const reorderPoint = toOperationalDashboardNumber(profile.reorderPoint)\n const safetyStock = toOperationalDashboardNumber(profile.safetyStock)\n if (reorderPoint <= 0 && safetyStock <= 0) continue\n\n const warehouseIds = warehouseId\n ? [warehouseId]\n : Array.from(new Set(balances.map((balance) => balance.warehouse.id)))\n\n for (const scopedWarehouseId of warehouseIds) {\n const key = `${variantId}::${scopedWarehouseId}`\n const available = availableByVariantWarehouse.get(key) ?? 0\n const evaluation = evaluateLowStock(\n { reorderPoint: profile.reorderPoint, safetyStock: profile.safetyStock },\n available,\n )\n if (!evaluation) continue\n if (seenLowStockKeys.has(key)) continue\n seenLowStockKeys.add(key)\n lowStockCount += 1\n if (evaluation.state === 'below_safety_stock') {\n reorderCriticalCount += 1\n }\n }\n }\n\n return { lowStockCount, reorderCriticalCount }\n}\n\nfunction resolveWarehouseLabel(\n warehouse: Warehouse | undefined,\n warehouseId: string,\n): string {\n return warehouse?.code?.trim() || warehouse?.name?.trim() || warehouseId\n}\n\nfunction resolveLocationLabel(\n warehouseLabel: string,\n fromCode?: string | null,\n toCode?: string | null,\n): string {\n if (fromCode && toCode) return `${fromCode} \u2192 ${toCode}`\n if (toCode) return `${warehouseLabel} \u00B7 ${toCode}`\n if (fromCode) return `${warehouseLabel} \u00B7 ${fromCode}`\n return warehouseLabel\n}\n\nfunction resolveDecryptionScope(scope: OperationalDashboardScope): DecryptionScope {\n return {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }\n}\n\nfunction appendWarehouseFilter(\n sql: string,\n params: unknown[],\n warehouseId?: string | null,\n): string {\n if (!warehouseId) return sql\n params.push(warehouseId)\n return `${sql} and warehouse_id = ?`\n}\n\nasync function loadVariantSkus(\n em: EntityManager,\n scope: OperationalDashboardScope,\n variantIds: string[],\n): Promise<Map<string, string>> {\n if (variantIds.length === 0) return new Map()\n const rows = await em.getConnection().execute<Array<{ id: string; sku: string | null }>>(\n `select id, sku from catalog_product_variants\n where organization_id = ? and tenant_id = ? and id in (${variantIds.map(() => '?').join(', ')})\n and deleted_at is null`,\n [scope.organizationId, scope.tenantId, ...variantIds],\n )\n const map = new Map<string, string>()\n for (const row of rows) {\n if (row.id && row.sku) map.set(row.id, row.sku)\n }\n return map\n}\n\nasync function countMovementsBetween(\n em: EntityManager,\n scope: OperationalDashboardScope,\n start: Date,\n end: Date,\n options?: { types?: string[]; quantitySign?: 'negative' },\n): Promise<number> {\n const params: unknown[] = [scope.organizationId, scope.tenantId, start, end]\n let sql = `\n select count(*)::int as count\n from wms_inventory_movements\n where organization_id = ? and tenant_id = ? and deleted_at is null\n and performed_at >= ? and performed_at < ?\n `\n sql = appendWarehouseFilter(sql, params, scope.warehouseId)\n if (options?.types?.length) {\n sql += ` and type in (${options.types.map(() => '?').join(', ')})`\n params.push(...options.types)\n }\n if (options?.quantitySign === 'negative') {\n sql += ' and quantity < 0'\n }\n const rows = await em.getConnection().execute<Array<{ count: string | number }>>(sql, params)\n return toOperationalDashboardNumber(rows[0]?.count)\n}\n\nasync function loadMovementDailyCounts(\n em: EntityManager,\n scope: OperationalDashboardScope,\n start: Date,\n options?: { types?: string[]; quantitySign?: 'negative' },\n): Promise<DailyCountRow[]> {\n const params: unknown[] = [scope.organizationId, scope.tenantId, start]\n let sql = `\n select date_trunc('day', performed_at) as day, count(*)::int as count\n from wms_inventory_movements\n where organization_id = ? and tenant_id = ? and deleted_at is null\n and performed_at >= ?\n `\n sql = appendWarehouseFilter(sql, params, scope.warehouseId)\n if (options?.types?.length) {\n sql += ` and type in (${options.types.map(() => '?').join(', ')})`\n params.push(...options.types)\n }\n if (options?.quantitySign === 'negative') {\n sql += ' and quantity < 0'\n }\n sql += ' group by 1 order by 1'\n return em.getConnection().execute<DailyCountRow[]>(sql, params)\n}\n\nasync function loadMonthlyMovementTrends(\n em: EntityManager,\n scope: OperationalDashboardScope,\n monthlyStart: Date,\n now: Date,\n): Promise<OperationalDashboardTrendPoint[]> {\n const params: unknown[] = [scope.organizationId, scope.tenantId, monthlyStart]\n let sql = `\n select date_trunc('month', performed_at) as month_start, type, count(*)::int as count\n from wms_inventory_movements\n where organization_id = ? and tenant_id = ? and deleted_at is null\n and performed_at >= ?\n `\n sql = appendWarehouseFilter(sql, params, scope.warehouseId)\n sql += ' group by 1, 2 order by 1'\n\n const rows = await em.getConnection().execute<MonthlyTrendRow[]>(sql, params)\n const monthlyTrendMap = new Map<string, { receive: number; allocate: number }>()\n for (let index = 0; index < MONTHLY_TREND_MONTHS; index += 1) {\n const monthDate = new Date(\n Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (MONTHLY_TREND_MONTHS - 1 - index), 1),\n )\n monthlyTrendMap.set(formatMonthKey(monthDate), { receive: 0, allocate: 0 })\n }\n\n for (const row of rows) {\n const monthDate = row.month_start instanceof Date ? row.month_start : new Date(row.month_start)\n const key = formatMonthKey(monthDate)\n const bucket = monthlyTrendMap.get(key)\n if (!bucket) continue\n if (row.type === 'receipt' || row.type === 'return_receive') {\n bucket.receive += toOperationalDashboardNumber(row.count)\n }\n if (row.type === 'pick' || row.type === 'pack') {\n bucket.allocate += toOperationalDashboardNumber(row.count)\n }\n }\n\n return Array.from(monthlyTrendMap.entries()).map(([month, values]) => ({\n month,\n receive: values.receive,\n allocate: values.allocate,\n }))\n}\n\nasync function loadExpiringSoonDailyCounts(\n em: EntityManager,\n scope: OperationalDashboardScope,\n dayBuckets: Date[],\n): Promise<DailyCountRow[]> {\n if (dayBuckets.length === 0) return []\n const trendStart = dayBuckets[0]!\n const trendEnd = dayBuckets[dayBuckets.length - 1]!\n const params: unknown[] = [\n trendStart,\n trendEnd,\n scope.organizationId,\n scope.tenantId,\n ]\n let sql = `\n select bucket.day as day, count(distinct l.id)::int as count\n from (\n select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day\n ) bucket\n join wms_inventory_lots l\n on l.organization_id = ?\n and l.tenant_id = ?\n and l.deleted_at is null\n and l.status = 'available'\n and l.expires_at is not null\n and l.expires_at >= bucket.day\n and l.expires_at <= bucket.day + interval '${EXPIRING_SOON_DAYS} days'\n `\n if (scope.warehouseId) {\n sql += `\n join wms_inventory_balances b\n on b.lot_id = l.id\n and b.deleted_at is null\n and b.warehouse_id = ?\n `\n params.push(scope.warehouseId)\n }\n sql += ' group by bucket.day order by bucket.day'\n return em.getConnection().execute<DailyCountRow[]>(sql, params)\n}\n\nasync function loadPastDueLotCount(\n em: EntityManager,\n scope: OperationalDashboardScope,\n todayStart: Date,\n): Promise<number> {\n const params: unknown[] = [scope.organizationId, scope.tenantId, todayStart]\n let sql = `\n select count(distinct l.id)::int as count\n from wms_inventory_lots l\n join wms_inventory_balances b\n on b.lot_id = l.id\n and b.deleted_at is null\n and (\n coalesce(b.quantity_on_hand, 0)\n - coalesce(b.quantity_reserved, 0)\n - coalesce(b.quantity_allocated, 0)\n ) > 0\n where l.organization_id = ?\n and l.tenant_id = ?\n and l.deleted_at is null\n and l.status = 'available'\n and l.expires_at is not null\n and l.expires_at < ?\n `\n if (scope.warehouseId) {\n sql += ' and b.warehouse_id = ?'\n params.push(scope.warehouseId)\n }\n const rows = await em.getConnection().execute<Array<{ count: string | number }>>(sql, params)\n return toOperationalDashboardNumber(rows[0]?.count)\n}\n\nasync function loadPastDueDailyCounts(\n em: EntityManager,\n scope: OperationalDashboardScope,\n dayBuckets: Date[],\n): Promise<DailyCountRow[]> {\n if (dayBuckets.length === 0) return []\n const params: unknown[] = [\n dayBuckets[0]!,\n dayBuckets[dayBuckets.length - 1]!,\n scope.organizationId,\n scope.tenantId,\n ]\n let sql = `\n select bucket.day as day, count(distinct l.id)::int as count\n from (\n select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day\n ) bucket\n join wms_inventory_lots l\n on l.organization_id = ?\n and l.tenant_id = ?\n and l.deleted_at is null\n and l.status = 'available'\n and l.expires_at is not null\n and l.expires_at < bucket.day\n join wms_inventory_balances b\n on b.lot_id = l.id\n and b.deleted_at is null\n and (\n coalesce(b.quantity_on_hand, 0)\n - coalesce(b.quantity_reserved, 0)\n - coalesce(b.quantity_allocated, 0)\n ) > 0\n `\n if (scope.warehouseId) {\n sql += ' and b.warehouse_id = ?'\n params.push(scope.warehouseId)\n }\n sql += ' group by bucket.day order by bucket.day'\n return em.getConnection().execute<DailyCountRow[]>(sql, params)\n}\n\nasync function loadAgingReservationsDailyCounts(\n em: EntityManager,\n scope: OperationalDashboardScope,\n dayBuckets: Date[],\n): Promise<DailyCountRow[]> {\n if (dayBuckets.length === 0) return []\n const params: unknown[] = [\n dayBuckets[0]!,\n dayBuckets[dayBuckets.length - 1]!,\n scope.organizationId,\n scope.tenantId,\n String(AGING_RESERVATION_DAYS),\n ]\n let sql = `\n select bucket.day as day, count(r.id)::int as count\n from (\n select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day\n ) bucket\n join wms_inventory_reservations r\n on r.organization_id = ?\n and r.tenant_id = ?\n and r.deleted_at is null\n and r.status = 'active'\n and r.created_at <= bucket.day - (?::int * interval '1 day')\n `\n sql = appendWarehouseFilter(sql, params, scope.warehouseId)\n sql += ' group by bucket.day order by bucket.day'\n return em.getConnection().execute<DailyCountRow[]>(sql, params)\n}\n\nexport async function loadOperationalDashboard(\n em: EntityManager,\n scope: OperationalDashboardScope,\n): Promise<OperationalDashboardPayload> {\n const now = new Date()\n const todayStart = startOfUtcDay(now)\n const tomorrowStart = addUtcDays(todayStart, 1)\n const yesterdayStart = addUtcDays(todayStart, -1)\n const agingCutoff = addUtcDays(todayStart, -AGING_RESERVATION_DAYS)\n const expiringCutoff = addUtcDays(todayStart, EXPIRING_SOON_DAYS)\n const trendStart = addUtcDays(todayStart, -(TREND_DAYS - 1))\n const dayBuckets = buildDailyBuckets(TREND_DAYS, now)\n const decryptionScope = resolveDecryptionScope(scope)\n\n const baseScope = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null as Date | null,\n }\n\n if (scope.warehouseId) {\n const warehouse = await findOneWithDecryption(\n em,\n Warehouse,\n { id: scope.warehouseId, ...baseScope },\n undefined,\n decryptionScope,\n )\n if (!warehouse) {\n throw new OperationalDashboardWarehouseNotFoundError(scope.warehouseId)\n }\n }\n\n const warehouseFilter = scope.warehouseId ? { warehouse: scope.warehouseId } : {}\n\n const [profiles, balances, expiringSoonLots, pastDueLots, reservations, activityMovements] = await Promise.all([\n findWithDecryption(em, ProductInventoryProfile, baseScope, undefined, decryptionScope),\n findWithDecryption(\n em,\n InventoryBalance,\n { ...baseScope, ...warehouseFilter },\n { populate: ['warehouse', 'location', 'lot'] },\n decryptionScope,\n ),\n findWithDecryption(\n em,\n InventoryLot,\n {\n ...baseScope,\n status: 'available',\n expiresAt: { $ne: null, $gte: todayStart, $lte: expiringCutoff },\n },\n { orderBy: { expiresAt: 'ASC' }, limit: 100 },\n decryptionScope,\n ),\n findWithDecryption(\n em,\n InventoryLot,\n {\n ...baseScope,\n status: 'available',\n expiresAt: { $ne: null, $lt: todayStart },\n },\n { orderBy: { expiresAt: 'ASC' }, limit: 100 },\n decryptionScope,\n ),\n findWithDecryption(\n em,\n InventoryReservation,\n {\n ...baseScope,\n ...warehouseFilter,\n status: 'active',\n createdAt: { $lte: agingCutoff },\n },\n undefined,\n decryptionScope,\n ),\n findWithDecryption(\n em,\n InventoryMovement,\n { ...baseScope, ...warehouseFilter },\n {\n populate: ['warehouse', 'locationFrom', 'locationTo'],\n orderBy: { performedAt: 'DESC' },\n limit: ACTIVITY_LIMIT,\n },\n decryptionScope,\n ),\n ])\n\n const { lowStockCount, reorderCriticalCount } = computeLowStockCounts(\n profiles,\n balances,\n scope.warehouseId,\n )\n\n const expiringSoonCount = expiringSoonLots.filter(\n (lot) => resolveLotAvailableQuantity(lot.id, balances, scope.warehouseId) > 0,\n ).length\n\n const agingReservationsCount = reservations.length\n\n const [\n todaysMoveCount,\n yesterdaysMoveCount,\n pastDueCount,\n lowStockSparklineRows,\n reorderCriticalSparklineRows,\n expiringSoonSparklineRows,\n pastDueSparklineRows,\n agingReservationsSparklineRows,\n todaysMovesSparklineRows,\n monthlyTrends,\n ] = await Promise.all([\n countMovementsBetween(em, scope, todayStart, tomorrowStart),\n countMovementsBetween(em, scope, yesterdayStart, todayStart),\n loadPastDueLotCount(em, scope, todayStart),\n loadMovementDailyCounts(em, scope, trendStart, { types: ['adjust'], quantitySign: 'negative' }),\n loadMovementDailyCounts(em, scope, trendStart, { types: ['adjust'], quantitySign: 'negative' }),\n loadExpiringSoonDailyCounts(em, scope, dayBuckets),\n loadPastDueDailyCounts(em, scope, dayBuckets),\n loadAgingReservationsDailyCounts(em, scope, dayBuckets),\n loadMovementDailyCounts(em, scope, trendStart),\n loadMonthlyMovementTrends(\n em,\n scope,\n new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (MONTHLY_TREND_MONTHS - 1), 1)),\n now,\n ),\n ])\n\n const kpis: OperationalDashboardKpi[] = [\n {\n id: 'lowStock',\n count: lowStockCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, lowStockSparklineRows),\n },\n {\n id: 'reorderCritical',\n count: reorderCriticalCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, reorderCriticalSparklineRows),\n },\n {\n id: 'expiringSoon',\n count: expiringSoonCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, expiringSoonSparklineRows),\n },\n {\n id: 'pastDue',\n count: pastDueCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, pastDueSparklineRows),\n },\n {\n id: 'agingReservations',\n count: agingReservationsCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, agingReservationsSparklineRows),\n },\n {\n id: 'todaysMoves',\n count: todaysMoveCount,\n deltaSinceYesterday: todaysMoveCount - yesterdaysMoveCount,\n sparkline: mapDailyCountsToSparkline(dayBuckets, todaysMovesSparklineRows),\n },\n ]\n\n const variantIds = Array.from(new Set(activityMovements.map((movement) => movement.catalogVariantId)))\n const variantSkus = await loadVariantSkus(em, scope, variantIds)\n\n const recentActivity: OperationalDashboardActivityRow[] = activityMovements.map((movement) => {\n const warehouseLabel = resolveWarehouseLabel(movement.warehouse, movement.warehouse.id)\n return {\n id: movement.id,\n movementType: movement.type,\n quantity: toOperationalDashboardNumber(movement.quantity),\n variantSku: variantSkus.get(movement.catalogVariantId) ?? null,\n variantId: movement.catalogVariantId,\n referenceType: movement.referenceType ?? null,\n referenceId: movement.referenceId ?? null,\n reason: movement.reason ?? null,\n reasonCode: movement.reasonCode ?? null,\n locationLabel: resolveLocationLabel(\n warehouseLabel,\n movement.locationFrom?.code,\n movement.locationTo?.code,\n ),\n performedAt: movement.performedAt.toISOString(),\n }\n })\n\n const expiryLots = buildExpiryLotRows(\n expiringSoonLots,\n pastDueLots,\n balances,\n scope.warehouseId,\n )\n\n return {\n lastUpdatedAt: now.toISOString(),\n warehouseId: scope.warehouseId ?? null,\n kpis,\n expiryLots,\n monthlyTrends,\n recentActivity,\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,uBAAuB,0BAA0B;AAC1D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,wBAAwB;AACjC,SAAS,YAAY,oBAAoB,qBAAqB;AAE9D,MAAM,yBAAyB;AAC/B,MAAM,aAAa;AACnB,MAAM,uBAAuB;AAC7B,MAAM,iBAAiB;AACvB,MAAM,oBAAoB;AAgEnB,MAAM,mDAAmD,MAAM;AAAA,EAGpE,YAAY,aAAqB;AAC/B,UAAM,aAAa,WAAW,YAAY;AAC1C,SAAK,OAAO;AACZ,SAAK,cAAc;AAAA,EACrB;AACF;AAkBO,SAAS,6BAA6B,OAAmD;AAC9F,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,EAAG,QAAO,OAAO,KAAK;AAC7E,SAAO;AACT;AAEA,SAAS,cAAAA,aAAY,iBAAAC,sBAAqB;AAE1C,SAAS,eAAe,MAAoB;AAC1C,SAAO,KAAK,eAAe,SAAS,EAAE,OAAO,SAAS,UAAU,MAAM,CAAC;AACzE;AAEO,SAAS,kBAAkB,MAAc,KAAmB;AACjE,QAAM,QAAQ,cAAc,GAAG;AAC/B,QAAM,UAAkB,CAAC;AACzB,WAAS,SAAS,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG;AACpD,YAAQ,KAAK,WAAW,OAAO,CAAC,MAAM,CAAC;AAAA,EACzC;AACA,SAAO;AACT;AAEO,SAAS,0BACd,YACA,MACU;AACV,QAAM,SAAS,oBAAI,IAAoB;AACvC,aAAW,UAAU,YAAY;AAC/B,WAAO,IAAI,OAAO,QAAQ,GAAG,CAAC;AAAA,EAChC;AACA,aAAW,OAAO,MAAM;AACtB,UAAM,MAAM,cAAc,IAAI,eAAe,OAAO,IAAI,MAAM,IAAI,KAAK,IAAI,GAAG,CAAC,EAAE,QAAQ;AACzF,QAAI,OAAO,IAAI,GAAG,GAAG;AACnB,aAAO,IAAI,KAAK,6BAA6B,IAAI,KAAK,CAAC;AAAA,IACzD;AAAA,EACF;AACA,SAAO,WAAW,IAAI,CAAC,WAAW,OAAO,IAAI,OAAO,QAAQ,CAAC,KAAK,CAAC;AACrE;AAEO,SAAS,4BACd,OACA,UACA,aACQ;AACR,MAAI,QAAQ;AACZ,aAAW,WAAW,UAAU;AAC9B,QAAI,QAAQ,KAAK,OAAO,MAAO;AAC/B,QAAI,eAAe,QAAQ,UAAU,OAAO,YAAa;AACzD,UAAM,YACJ,6BAA6B,QAAQ,cAAc,IACjD,6BAA6B,QAAQ,gBAAgB,IACrD,6BAA6B,QAAQ,iBAAiB;AAC1D,QAAI,YAAY,EAAG,UAAS;AAAA,EAC9B;AACA,SAAO;AACT;AAEO,SAAS,mBACd,kBACA,aACA,UACA,aACA,QAAQ,mBAC4B;AACpC,QAAM,eAAe,iBAClB,IAAI,CAAC,SAAS;AAAA,IACb;AAAA,IACA,mBAAmB,4BAA4B,IAAI,IAAI,UAAU,WAAW;AAAA,EAC9E,EAAE,EACD,OAAO,CAAC,EAAE,kBAAkB,MAAM,oBAAoB,CAAC,EACvD,KAAK,CAAC,MAAM,UAAU;AACrB,UAAM,WAAW,KAAK,IAAI,WAAW,QAAQ,KAAK;AAClD,UAAM,YAAY,MAAM,IAAI,WAAW,QAAQ,KAAK;AACpD,WAAO,WAAW;AAAA,EACpB,CAAC,EACA,MAAM,GAAG,KAAK,EACd,IAAI,CAAC,EAAE,KAAK,kBAAkB,OAAO;AAAA,IACpC,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,KAAK,IAAI;AAAA,IACT,kBAAkB,IAAI;AAAA,IACtB,WAAW,IAAI,UAAW,YAAY;AAAA,IACtC;AAAA,IACA,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI,WAAW,YAAY,KAAK;AAAA,IAC3C,UAAU;AAAA,EACZ,EAAE;AAEJ,QAAM,cAAc,YACjB,IAAI,CAAC,SAAS;AAAA,IACb;AAAA,IACA,mBAAmB,4BAA4B,IAAI,IAAI,UAAU,WAAW;AAAA,EAC9E,EAAE,EACD,OAAO,CAAC,EAAE,kBAAkB,MAAM,oBAAoB,CAAC,EACvD,KAAK,CAAC,MAAM,UAAU;AACrB,UAAM,WAAW,KAAK,IAAI,WAAW,QAAQ,KAAK;AAClD,UAAM,YAAY,MAAM,IAAI,WAAW,QAAQ,KAAK;AACpD,WAAO,WAAW;AAAA,EACpB,CAAC,EACA,MAAM,GAAG,KAAK,EACd,IAAI,CAAC,EAAE,KAAK,kBAAkB,OAAO;AAAA,IACpC,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,KAAK,IAAI;AAAA,IACT,kBAAkB,IAAI;AAAA,IACtB,WAAW,IAAI,UAAW,YAAY;AAAA,IACtC;AAAA,IACA,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI,WAAW,YAAY,KAAK;AAAA,IAC3C,UAAU;AAAA,EACZ,EAAE;AAEJ,SAAO,CAAC,GAAG,cAAc,GAAG,WAAW;AACzC;AAEO,SAAS,sBACd,UACA,UACA,aACyD;AACzD,QAAM,8BAA8B,oBAAI,IAAoB;AAC5D,aAAW,WAAW,UAAU;AAC9B,UAAM,SAAS,6BAA6B,QAAQ,cAAc;AAClE,UAAM,WAAW,6BAA6B,QAAQ,gBAAgB;AACtE,UAAM,YAAY,6BAA6B,QAAQ,iBAAiB;AACxE,UAAM,YAAY,SAAS,WAAW;AACtC,UAAM,MAAM,GAAG,QAAQ,gBAAgB,KAAK,QAAQ,UAAU,EAAE;AAChE,gCAA4B,IAAI,MAAM,4BAA4B,IAAI,GAAG,KAAK,KAAK,SAAS;AAAA,EAC9F;AAEA,MAAI,gBAAgB;AACpB,MAAI,uBAAuB;AAC3B,QAAM,mBAAmB,oBAAI,IAAY;AAEzC,aAAW,WAAW,UAAU;AAC9B,UAAM,YAAY,QAAQ;AAC1B,QAAI,CAAC,UAAW;AAChB,UAAM,eAAe,6BAA6B,QAAQ,YAAY;AACtE,UAAM,cAAc,6BAA6B,QAAQ,WAAW;AACpE,QAAI,gBAAgB,KAAK,eAAe,EAAG;AAE3C,UAAM,eAAe,cACjB,CAAC,WAAW,IACZ,MAAM,KAAK,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY,QAAQ,UAAU,EAAE,CAAC,CAAC;AAEvE,eAAW,qBAAqB,cAAc;AAC5C,YAAM,MAAM,GAAG,SAAS,KAAK,iBAAiB;AAC9C,YAAM,YAAY,4BAA4B,IAAI,GAAG,KAAK;AAC1D,YAAM,aAAa;AAAA,QACjB,EAAE,cAAc,QAAQ,cAAc,aAAa,QAAQ,YAAY;AAAA,QACvE;AAAA,MACF;AACA,UAAI,CAAC,WAAY;AACjB,UAAI,iBAAiB,IAAI,GAAG,EAAG;AAC/B,uBAAiB,IAAI,GAAG;AACxB,uBAAiB;AACjB,UAAI,WAAW,UAAU,sBAAsB;AAC7C,gCAAwB;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,eAAe,qBAAqB;AAC/C;AAEA,SAAS,sBACP,WACA,aACQ;AACR,SAAO,WAAW,MAAM,KAAK,KAAK,WAAW,MAAM,KAAK,KAAK;AAC/D;AAEA,SAAS,qBACP,gBACA,UACA,QACQ;AACR,MAAI,YAAY,OAAQ,QAAO,GAAG,QAAQ,WAAM,MAAM;AACtD,MAAI,OAAQ,QAAO,GAAG,cAAc,SAAM,MAAM;AAChD,MAAI,SAAU,QAAO,GAAG,cAAc,SAAM,QAAQ;AACpD,SAAO;AACT;AAEA,SAAS,uBAAuB,OAAmD;AACjF,SAAO;AAAA,IACL,UAAU,MAAM;AAAA,IAChB,gBAAgB,MAAM;AAAA,EACxB;AACF;AAEA,SAAS,sBACP,KACA,QACA,aACQ;AACR,MAAI,CAAC,YAAa,QAAO;AACzB,SAAO,KAAK,WAAW;AACvB,SAAO,GAAG,GAAG;AACf;AAEA,eAAe,gBACb,IACA,OACA,YAC8B;AAC9B,MAAI,WAAW,WAAW,EAAG,QAAO,oBAAI,IAAI;AAC5C,QAAM,OAAO,MAAM,GAAG,cAAc,EAAE;AAAA,IACpC;AAAA,8DAC0D,WAAW,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,IAE9F,CAAC,MAAM,gBAAgB,MAAM,UAAU,GAAG,UAAU;AAAA,EACtD;AACA,QAAM,MAAM,oBAAI,IAAoB;AACpC,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,MAAM,IAAI,IAAK,KAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAAA,EAChD;AACA,SAAO;AACT;AAEA,eAAe,sBACb,IACA,OACA,OACA,KACA,SACiB;AACjB,QAAM,SAAoB,CAAC,MAAM,gBAAgB,MAAM,UAAU,OAAO,GAAG;AAC3E,MAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAMV,QAAM,sBAAsB,KAAK,QAAQ,MAAM,WAAW;AAC1D,MAAI,SAAS,OAAO,QAAQ;AAC1B,WAAO,iBAAiB,QAAQ,MAAM,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI,CAAC;AAC/D,WAAO,KAAK,GAAG,QAAQ,KAAK;AAAA,EAC9B;AACA,MAAI,SAAS,iBAAiB,YAAY;AACxC,WAAO;AAAA,EACT;AACA,QAAM,OAAO,MAAM,GAAG,cAAc,EAAE,QAA2C,KAAK,MAAM;AAC5F,SAAO,6BAA6B,KAAK,CAAC,GAAG,KAAK;AACpD;AAEA,eAAe,wBACb,IACA,OACA,OACA,SAC0B;AAC1B,QAAM,SAAoB,CAAC,MAAM,gBAAgB,MAAM,UAAU,KAAK;AACtE,MAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAMV,QAAM,sBAAsB,KAAK,QAAQ,MAAM,WAAW;AAC1D,MAAI,SAAS,OAAO,QAAQ;AAC1B,WAAO,iBAAiB,QAAQ,MAAM,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI,CAAC;AAC/D,WAAO,KAAK,GAAG,QAAQ,KAAK;AAAA,EAC9B;AACA,MAAI,SAAS,iBAAiB,YAAY;AACxC,WAAO;AAAA,EACT;AACA,SAAO;AACP,SAAO,GAAG,cAAc,EAAE,QAAyB,KAAK,MAAM;AAChE;AAEA,eAAe,0BACb,IACA,OACA,cACA,KAC2C;AAC3C,QAAM,SAAoB,CAAC,MAAM,gBAAgB,MAAM,UAAU,YAAY;AAC7E,MAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAMV,QAAM,sBAAsB,KAAK,QAAQ,MAAM,WAAW;AAC1D,SAAO;AAEP,QAAM,OAAO,MAAM,GAAG,cAAc,EAAE,QAA2B,KAAK,MAAM;AAC5E,QAAM,kBAAkB,oBAAI,IAAmD;AAC/E,WAAS,QAAQ,GAAG,QAAQ,sBAAsB,SAAS,GAAG;AAC5D,UAAM,YAAY,IAAI;AAAA,MACpB,KAAK,IAAI,IAAI,eAAe,GAAG,IAAI,YAAY,KAAK,uBAAuB,IAAI,QAAQ,CAAC;AAAA,IAC1F;AACA,oBAAgB,IAAI,eAAe,SAAS,GAAG,EAAE,SAAS,GAAG,UAAU,EAAE,CAAC;AAAA,EAC5E;AAEA,aAAW,OAAO,MAAM;AACtB,UAAM,YAAY,IAAI,uBAAuB,OAAO,IAAI,cAAc,IAAI,KAAK,IAAI,WAAW;AAC9F,UAAM,MAAM,eAAe,SAAS;AACpC,UAAM,SAAS,gBAAgB,IAAI,GAAG;AACtC,QAAI,CAAC,OAAQ;AACb,QAAI,IAAI,SAAS,aAAa,IAAI,SAAS,kBAAkB;AAC3D,aAAO,WAAW,6BAA6B,IAAI,KAAK;AAAA,IAC1D;AACA,QAAI,IAAI,SAAS,UAAU,IAAI,SAAS,QAAQ;AAC9C,aAAO,YAAY,6BAA6B,IAAI,KAAK;AAAA,IAC3D;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,gBAAgB,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,MAAM,OAAO;AAAA,IACrE;AAAA,IACA,SAAS,OAAO;AAAA,IAChB,UAAU,OAAO;AAAA,EACnB,EAAE;AACJ;AAEA,eAAe,4BACb,IACA,OACA,YAC0B;AAC1B,MAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AACrC,QAAM,aAAa,WAAW,CAAC;AAC/B,QAAM,WAAW,WAAW,WAAW,SAAS,CAAC;AACjD,QAAM,SAAoB;AAAA,IACxB;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACA,MAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kDAYsC,kBAAkB;AAAA;AAElE,MAAI,MAAM,aAAa;AACrB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAMP,WAAO,KAAK,MAAM,WAAW;AAAA,EAC/B;AACA,SAAO;AACP,SAAO,GAAG,cAAc,EAAE,QAAyB,KAAK,MAAM;AAChE;AAEA,eAAe,oBACb,IACA,OACA,YACiB;AACjB,QAAM,SAAoB,CAAC,MAAM,gBAAgB,MAAM,UAAU,UAAU;AAC3E,MAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBV,MAAI,MAAM,aAAa;AACrB,WAAO;AACP,WAAO,KAAK,MAAM,WAAW;AAAA,EAC/B;AACA,QAAM,OAAO,MAAM,GAAG,cAAc,EAAE,QAA2C,KAAK,MAAM;AAC5F,SAAO,6BAA6B,KAAK,CAAC,GAAG,KAAK;AACpD;AAEA,eAAe,uBACb,IACA,OACA,YAC0B;AAC1B,MAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AACrC,QAAM,SAAoB;AAAA,IACxB,WAAW,CAAC;AAAA,IACZ,WAAW,WAAW,SAAS,CAAC;AAAA,IAChC,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACA,MAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBV,MAAI,MAAM,aAAa;AACrB,WAAO;AACP,WAAO,KAAK,MAAM,WAAW;AAAA,EAC/B;AACA,SAAO;AACP,SAAO,GAAG,cAAc,EAAE,QAAyB,KAAK,MAAM;AAChE;AAEA,eAAe,iCACb,IACA,OACA,YAC0B;AAC1B,MAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AACrC,QAAM,SAAoB;AAAA,IACxB,WAAW,CAAC;AAAA,IACZ,WAAW,WAAW,SAAS,CAAC;AAAA,IAChC,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO,sBAAsB;AAAA,EAC/B;AACA,MAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYV,QAAM,sBAAsB,KAAK,QAAQ,MAAM,WAAW;AAC1D,SAAO;AACP,SAAO,GAAG,cAAc,EAAE,QAAyB,KAAK,MAAM;AAChE;AAEA,eAAsB,yBACpB,IACA,OACsC;AACtC,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,aAAa,cAAc,GAAG;AACpC,QAAM,gBAAgB,WAAW,YAAY,CAAC;AAC9C,QAAM,iBAAiB,WAAW,YAAY,EAAE;AAChD,QAAM,cAAc,WAAW,YAAY,CAAC,sBAAsB;AAClE,QAAM,iBAAiB,WAAW,YAAY,kBAAkB;AAChE,QAAM,aAAa,WAAW,YAAY,EAAE,aAAa,EAAE;AAC3D,QAAM,aAAa,kBAAkB,YAAY,GAAG;AACpD,QAAM,kBAAkB,uBAAuB,KAAK;AAEpD,QAAM,YAAY;AAAA,IAChB,gBAAgB,MAAM;AAAA,IACtB,UAAU,MAAM;AAAA,IAChB,WAAW;AAAA,EACb;AAEA,MAAI,MAAM,aAAa;AACrB,UAAM,YAAY,MAAM;AAAA,MACtB;AAAA,MACA;AAAA,MACA,EAAE,IAAI,MAAM,aAAa,GAAG,UAAU;AAAA,MACtC;AAAA,MACA;AAAA,IACF;AACA,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,2CAA2C,MAAM,WAAW;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,kBAAkB,MAAM,cAAc,EAAE,WAAW,MAAM,YAAY,IAAI,CAAC;AAEhF,QAAM,CAAC,UAAU,UAAU,kBAAkB,aAAa,cAAc,iBAAiB,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC7G,mBAAmB,IAAI,yBAAyB,WAAW,QAAW,eAAe;AAAA,IACrF;AAAA,MACE;AAAA,MACA;AAAA,MACA,EAAE,GAAG,WAAW,GAAG,gBAAgB;AAAA,MACnC,EAAE,UAAU,CAAC,aAAa,YAAY,KAAK,EAAE;AAAA,MAC7C;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,WAAW,EAAE,KAAK,MAAM,MAAM,YAAY,MAAM,eAAe;AAAA,MACjE;AAAA,MACA,EAAE,SAAS,EAAE,WAAW,MAAM,GAAG,OAAO,IAAI;AAAA,MAC5C;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,WAAW,EAAE,KAAK,MAAM,KAAK,WAAW;AAAA,MAC1C;AAAA,MACA,EAAE,SAAS,EAAE,WAAW,MAAM,GAAG,OAAO,IAAI;AAAA,MAC5C;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,GAAG;AAAA,QACH,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,WAAW,EAAE,MAAM,YAAY;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA,EAAE,GAAG,WAAW,GAAG,gBAAgB;AAAA,MACnC;AAAA,QACE,UAAU,CAAC,aAAa,gBAAgB,YAAY;AAAA,QACpD,SAAS,EAAE,aAAa,OAAO;AAAA,QAC/B,OAAO;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,EAAE,eAAe,qBAAqB,IAAI;AAAA,IAC9C;AAAA,IACA;AAAA,IACA,MAAM;AAAA,EACR;AAEA,QAAM,oBAAoB,iBAAiB;AAAA,IACzC,CAAC,QAAQ,4BAA4B,IAAI,IAAI,UAAU,MAAM,WAAW,IAAI;AAAA,EAC9E,EAAE;AAEF,QAAM,yBAAyB,aAAa;AAE5C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,MAAM,QAAQ,IAAI;AAAA,IACpB,sBAAsB,IAAI,OAAO,YAAY,aAAa;AAAA,IAC1D,sBAAsB,IAAI,OAAO,gBAAgB,UAAU;AAAA,IAC3D,oBAAoB,IAAI,OAAO,UAAU;AAAA,IACzC,wBAAwB,IAAI,OAAO,YAAY,EAAE,OAAO,CAAC,QAAQ,GAAG,cAAc,WAAW,CAAC;AAAA,IAC9F,wBAAwB,IAAI,OAAO,YAAY,EAAE,OAAO,CAAC,QAAQ,GAAG,cAAc,WAAW,CAAC;AAAA,IAC9F,4BAA4B,IAAI,OAAO,UAAU;AAAA,IACjD,uBAAuB,IAAI,OAAO,UAAU;AAAA,IAC5C,iCAAiC,IAAI,OAAO,UAAU;AAAA,IACtD,wBAAwB,IAAI,OAAO,UAAU;AAAA,IAC7C;AAAA,MACE;AAAA,MACA;AAAA,MACA,IAAI,KAAK,KAAK,IAAI,IAAI,eAAe,GAAG,IAAI,YAAY,KAAK,uBAAuB,IAAI,CAAC,CAAC;AAAA,MAC1F;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,OAAkC;AAAA,IACtC;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,qBAAqB;AAAA,MACrB,WAAW,0BAA0B,YAAY,qBAAqB;AAAA,IACxE;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,qBAAqB;AAAA,MACrB,WAAW,0BAA0B,YAAY,4BAA4B;AAAA,IAC/E;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,qBAAqB;AAAA,MACrB,WAAW,0BAA0B,YAAY,yBAAyB;AAAA,IAC5E;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,qBAAqB;AAAA,MACrB,WAAW,0BAA0B,YAAY,oBAAoB;AAAA,IACvE;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,qBAAqB;AAAA,MACrB,WAAW,0BAA0B,YAAY,8BAA8B;AAAA,IACjF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,qBAAqB,kBAAkB;AAAA,MACvC,WAAW,0BAA0B,YAAY,wBAAwB;AAAA,IAC3E;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,KAAK,IAAI,IAAI,kBAAkB,IAAI,CAAC,aAAa,SAAS,gBAAgB,CAAC,CAAC;AACrG,QAAM,cAAc,MAAM,gBAAgB,IAAI,OAAO,UAAU;AAE/D,QAAM,iBAAoD,kBAAkB,IAAI,CAAC,aAAa;AAC5F,UAAM,iBAAiB,sBAAsB,SAAS,WAAW,SAAS,UAAU,EAAE;AACtF,WAAO;AAAA,MACL,IAAI,SAAS;AAAA,MACb,cAAc,SAAS;AAAA,MACvB,UAAU,6BAA6B,SAAS,QAAQ;AAAA,MACxD,YAAY,YAAY,IAAI,SAAS,gBAAgB,KAAK;AAAA,MAC1D,WAAW,SAAS;AAAA,MACpB,eAAe,SAAS,iBAAiB;AAAA,MACzC,aAAa,SAAS,eAAe;AAAA,MACrC,QAAQ,SAAS,UAAU;AAAA,MAC3B,YAAY,SAAS,cAAc;AAAA,MACnC,eAAe;AAAA,QACb;AAAA,QACA,SAAS,cAAc;AAAA,QACvB,SAAS,YAAY;AAAA,MACvB;AAAA,MACA,aAAa,SAAS,YAAY,YAAY;AAAA,IAChD;AAAA,EACF,CAAC;AAED,QAAM,aAAa;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,EACR;AAEA,SAAO;AAAA,IACL,eAAe,IAAI,YAAY;AAAA,IAC/B,aAAa,MAAM,eAAe;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
|
|
6
|
+
"names": ["addUtcDays", "startOfUtcDay"]
|
|
7
|
+
}
|