@open-mercato/core 0.6.7-develop.6669.1.40b669666b → 0.6.7-develop.6670.1.4efa7961c6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/inventory_balance/index.js +21 -0
  3. package/dist/generated/entities/inventory_balance/index.js.map +7 -0
  4. package/dist/generated/entities/inventory_lot/index.js +19 -0
  5. package/dist/generated/entities/inventory_lot/index.js.map +7 -0
  6. package/dist/generated/entities/inventory_movement/index.js +35 -0
  7. package/dist/generated/entities/inventory_movement/index.js.map +7 -0
  8. package/dist/generated/entities/inventory_reservation/index.js +23 -0
  9. package/dist/generated/entities/inventory_reservation/index.js.map +7 -0
  10. package/dist/generated/entities/product_inventory_profile/index.js +21 -0
  11. package/dist/generated/entities/product_inventory_profile/index.js.map +7 -0
  12. package/dist/generated/entities/sales_order_warehouse_assignment/index.js +11 -0
  13. package/dist/generated/entities/sales_order_warehouse_assignment/index.js.map +7 -0
  14. package/dist/generated/entities/warehouse/index.js +25 -0
  15. package/dist/generated/entities/warehouse/index.js.map +7 -0
  16. package/dist/generated/entities/warehouse_location/index.js +21 -0
  17. package/dist/generated/entities/warehouse_location/index.js.map +7 -0
  18. package/dist/generated/entities/warehouse_zone/index.js +11 -0
  19. package/dist/generated/entities/warehouse_zone/index.js.map +7 -0
  20. package/dist/generated/entities.ids.generated.js +12 -0
  21. package/dist/generated/entities.ids.generated.js.map +2 -2
  22. package/dist/generated/entity-fields-registry.js +98 -0
  23. package/dist/generated/entity-fields-registry.js.map +2 -2
  24. package/dist/modules/auth/backend/roles/page.js +12 -4
  25. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  26. package/dist/modules/auth/lib/backendChrome.js +1 -0
  27. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  28. package/dist/modules/auth/services/rbacService.js +16 -17
  29. package/dist/modules/auth/services/rbacService.js.map +2 -2
  30. package/dist/modules/catalog/api/products/route.js +3 -0
  31. package/dist/modules/catalog/api/products/route.js.map +2 -2
  32. package/dist/modules/catalog/api/variants/route.js +3 -0
  33. package/dist/modules/catalog/api/variants/route.js.map +2 -2
  34. package/dist/modules/query_index/lib/engine.js +6 -6
  35. package/dist/modules/query_index/lib/engine.js.map +2 -2
  36. package/dist/modules/sales/api/documents/factory.js +1 -0
  37. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  38. package/dist/modules/sales/commands/documents.js +53 -0
  39. package/dist/modules/sales/commands/documents.js.map +2 -2
  40. package/dist/modules/sales/components/documents/ItemsSection.js +51 -2
  41. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  42. package/dist/modules/sales/events.js +2 -0
  43. package/dist/modules/sales/events.js.map +2 -2
  44. package/dist/modules/sales/widgets/injection/order-items-context.js +11 -0
  45. package/dist/modules/sales/widgets/injection/order-items-context.js.map +7 -0
  46. package/dist/modules/wms/acl.js +18 -0
  47. package/dist/modules/wms/acl.js.map +7 -0
  48. package/dist/modules/wms/analytics.js +11 -0
  49. package/dist/modules/wms/analytics.js.map +7 -0
  50. package/dist/modules/wms/api/dashboard/operational/route.js +80 -0
  51. package/dist/modules/wms/api/dashboard/operational/route.js.map +7 -0
  52. package/dist/modules/wms/api/interceptors.js +90 -0
  53. package/dist/modules/wms/api/interceptors.js.map +7 -0
  54. package/dist/modules/wms/api/inventory/adjust/route.js +51 -0
  55. package/dist/modules/wms/api/inventory/adjust/route.js.map +7 -0
  56. package/dist/modules/wms/api/inventory/allocate/route.js +51 -0
  57. package/dist/modules/wms/api/inventory/allocate/route.js.map +7 -0
  58. package/dist/modules/wms/api/inventory/balances/route.js +172 -0
  59. package/dist/modules/wms/api/inventory/balances/route.js.map +7 -0
  60. package/dist/modules/wms/api/inventory/cycle-count/route.js +52 -0
  61. package/dist/modules/wms/api/inventory/cycle-count/route.js.map +7 -0
  62. package/dist/modules/wms/api/inventory/helpers.js +113 -0
  63. package/dist/modules/wms/api/inventory/helpers.js.map +7 -0
  64. package/dist/modules/wms/api/inventory/import/apply/route.js +46 -0
  65. package/dist/modules/wms/api/inventory/import/apply/route.js.map +7 -0
  66. package/dist/modules/wms/api/inventory/import/helpers.js +195 -0
  67. package/dist/modules/wms/api/inventory/import/helpers.js.map +7 -0
  68. package/dist/modules/wms/api/inventory/import/template/route.js +32 -0
  69. package/dist/modules/wms/api/inventory/import/template/route.js.map +7 -0
  70. package/dist/modules/wms/api/inventory/import/validate/route.js +54 -0
  71. package/dist/modules/wms/api/inventory/import/validate/route.js.map +7 -0
  72. package/dist/modules/wms/api/inventory/move/route.js +51 -0
  73. package/dist/modules/wms/api/inventory/move/route.js.map +7 -0
  74. package/dist/modules/wms/api/inventory/movements/route.js +164 -0
  75. package/dist/modules/wms/api/inventory/movements/route.js.map +7 -0
  76. package/dist/modules/wms/api/inventory/receive/route.js +50 -0
  77. package/dist/modules/wms/api/inventory/receive/route.js.map +7 -0
  78. package/dist/modules/wms/api/inventory/release/route.js +44 -0
  79. package/dist/modules/wms/api/inventory/release/route.js.map +7 -0
  80. package/dist/modules/wms/api/inventory/reservations/route.js +128 -0
  81. package/dist/modules/wms/api/inventory/reservations/route.js.map +7 -0
  82. package/dist/modules/wms/api/inventory/reserve/route.js +59 -0
  83. package/dist/modules/wms/api/inventory/reserve/route.js.map +7 -0
  84. package/dist/modules/wms/api/inventory-profiles/route.js +178 -0
  85. package/dist/modules/wms/api/inventory-profiles/route.js.map +7 -0
  86. package/dist/modules/wms/api/listEnrichers.js +181 -0
  87. package/dist/modules/wms/api/listEnrichers.js.map +7 -0
  88. package/dist/modules/wms/api/listSearch.js +77 -0
  89. package/dist/modules/wms/api/listSearch.js.map +7 -0
  90. package/dist/modules/wms/api/locations/route.js +172 -0
  91. package/dist/modules/wms/api/locations/route.js.map +7 -0
  92. package/dist/modules/wms/api/lots/route.js +204 -0
  93. package/dist/modules/wms/api/lots/route.js.map +7 -0
  94. package/dist/modules/wms/api/openapi.js +27 -0
  95. package/dist/modules/wms/api/openapi.js.map +7 -0
  96. package/dist/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.js +54 -0
  97. package/dist/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.js.map +7 -0
  98. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js +279 -0
  99. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js.map +7 -0
  100. package/dist/modules/wms/api/sales-orders/assign-warehouse/route.js +56 -0
  101. package/dist/modules/wms/api/sales-orders/assign-warehouse/route.js.map +7 -0
  102. package/dist/modules/wms/api/sales-orders/unassign-warehouse/route.js +43 -0
  103. package/dist/modules/wms/api/sales-orders/unassign-warehouse/route.js.map +7 -0
  104. package/dist/modules/wms/api/warehouses/route.js +181 -0
  105. package/dist/modules/wms/api/warehouses/route.js.map +7 -0
  106. package/dist/modules/wms/api/zones/route.js +159 -0
  107. package/dist/modules/wms/api/zones/route.js.map +7 -0
  108. package/dist/modules/wms/backend/config/wms/page.js +9 -0
  109. package/dist/modules/wms/backend/config/wms/page.js.map +7 -0
  110. package/dist/modules/wms/backend/config/wms/page.meta.js +18 -0
  111. package/dist/modules/wms/backend/config/wms/page.meta.js.map +7 -0
  112. package/dist/modules/wms/backend/page.js +9 -0
  113. package/dist/modules/wms/backend/page.js.map +7 -0
  114. package/dist/modules/wms/backend/page.meta.js +16 -0
  115. package/dist/modules/wms/backend/page.meta.js.map +7 -0
  116. package/dist/modules/wms/backend/wms/inventory/page.js +9 -0
  117. package/dist/modules/wms/backend/wms/inventory/page.js.map +7 -0
  118. package/dist/modules/wms/backend/wms/inventory/page.meta.js +18 -0
  119. package/dist/modules/wms/backend/wms/inventory/page.meta.js.map +7 -0
  120. package/dist/modules/wms/backend/wms/location/[id]/page.js +9 -0
  121. package/dist/modules/wms/backend/wms/location/[id]/page.js.map +7 -0
  122. package/dist/modules/wms/backend/wms/location/[id]/page.meta.js +18 -0
  123. package/dist/modules/wms/backend/wms/location/[id]/page.meta.js.map +7 -0
  124. package/dist/modules/wms/backend/wms/locations/page.js +10 -0
  125. package/dist/modules/wms/backend/wms/locations/page.js.map +7 -0
  126. package/dist/modules/wms/backend/wms/locations/page.meta.js +18 -0
  127. package/dist/modules/wms/backend/wms/locations/page.meta.js.map +7 -0
  128. package/dist/modules/wms/backend/wms/lot/[id]/page.js +9 -0
  129. package/dist/modules/wms/backend/wms/lot/[id]/page.js.map +7 -0
  130. package/dist/modules/wms/backend/wms/lot/[id]/page.meta.js +18 -0
  131. package/dist/modules/wms/backend/wms/lot/[id]/page.meta.js.map +7 -0
  132. package/dist/modules/wms/backend/wms/lots/page.js +9 -0
  133. package/dist/modules/wms/backend/wms/lots/page.js.map +7 -0
  134. package/dist/modules/wms/backend/wms/lots/page.meta.js +18 -0
  135. package/dist/modules/wms/backend/wms/lots/page.meta.js.map +7 -0
  136. package/dist/modules/wms/backend/wms/movements/page.js +22 -0
  137. package/dist/modules/wms/backend/wms/movements/page.js.map +7 -0
  138. package/dist/modules/wms/backend/wms/movements/page.meta.js +18 -0
  139. package/dist/modules/wms/backend/wms/movements/page.meta.js.map +7 -0
  140. package/dist/modules/wms/backend/wms/reservations/page.js +23 -0
  141. package/dist/modules/wms/backend/wms/reservations/page.js.map +7 -0
  142. package/dist/modules/wms/backend/wms/reservations/page.meta.js +18 -0
  143. package/dist/modules/wms/backend/wms/reservations/page.meta.js.map +7 -0
  144. package/dist/modules/wms/backend/wms/sku/[id]/page.js +9 -0
  145. package/dist/modules/wms/backend/wms/sku/[id]/page.js.map +7 -0
  146. package/dist/modules/wms/backend/wms/sku/[id]/page.meta.js +18 -0
  147. package/dist/modules/wms/backend/wms/sku/[id]/page.meta.js.map +7 -0
  148. package/dist/modules/wms/backend/wms/warehouses/page.js +10 -0
  149. package/dist/modules/wms/backend/wms/warehouses/page.js.map +7 -0
  150. package/dist/modules/wms/backend/wms/warehouses/page.meta.js +18 -0
  151. package/dist/modules/wms/backend/wms/warehouses/page.meta.js.map +7 -0
  152. package/dist/modules/wms/backend/wms/zones/page.js +10 -0
  153. package/dist/modules/wms/backend/wms/zones/page.js.map +7 -0
  154. package/dist/modules/wms/backend/wms/zones/page.meta.js +18 -0
  155. package/dist/modules/wms/backend/wms/zones/page.meta.js.map +7 -0
  156. package/dist/modules/wms/ce.js +80 -0
  157. package/dist/modules/wms/ce.js.map +7 -0
  158. package/dist/modules/wms/cli.js +83 -0
  159. package/dist/modules/wms/cli.js.map +7 -0
  160. package/dist/modules/wms/commands/configuration.js +1519 -0
  161. package/dist/modules/wms/commands/configuration.js.map +7 -0
  162. package/dist/modules/wms/commands/index.js +4 -0
  163. package/dist/modules/wms/commands/index.js.map +7 -0
  164. package/dist/modules/wms/commands/inventory-actions.js +1539 -0
  165. package/dist/modules/wms/commands/inventory-actions.js.map +7 -0
  166. package/dist/modules/wms/commands/sales-order-assignment.js +277 -0
  167. package/dist/modules/wms/commands/sales-order-assignment.js.map +7 -0
  168. package/dist/modules/wms/commands/shared.js +82 -0
  169. package/dist/modules/wms/commands/shared.js.map +7 -0
  170. package/dist/modules/wms/components/backend/AdjustInventoryDialog.js +755 -0
  171. package/dist/modules/wms/components/backend/AdjustInventoryDialog.js.map +7 -0
  172. package/dist/modules/wms/components/backend/ChangeLotStatusDialog.js +269 -0
  173. package/dist/modules/wms/components/backend/ChangeLotStatusDialog.js.map +7 -0
  174. package/dist/modules/wms/components/backend/CycleCountWizardDialog.js +1783 -0
  175. package/dist/modules/wms/components/backend/CycleCountWizardDialog.js.map +7 -0
  176. package/dist/modules/wms/components/backend/ImportInventoryDialog.js +766 -0
  177. package/dist/modules/wms/components/backend/ImportInventoryDialog.js.map +7 -0
  178. package/dist/modules/wms/components/backend/InventoryOperationsSection.js +119 -0
  179. package/dist/modules/wms/components/backend/InventoryOperationsSection.js.map +7 -0
  180. package/dist/modules/wms/components/backend/LocationEditDialog.js +140 -0
  181. package/dist/modules/wms/components/backend/LocationEditDialog.js.map +7 -0
  182. package/dist/modules/wms/components/backend/MoveInventoryDialog.js +791 -0
  183. package/dist/modules/wms/components/backend/MoveInventoryDialog.js.map +7 -0
  184. package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js +656 -0
  185. package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js.map +7 -0
  186. package/dist/modules/wms/components/backend/ReleaseReservationDialog.js +344 -0
  187. package/dist/modules/wms/components/backend/ReleaseReservationDialog.js.map +7 -0
  188. package/dist/modules/wms/components/backend/ReserveInventoryDialog.js +475 -0
  189. package/dist/modules/wms/components/backend/ReserveInventoryDialog.js.map +7 -0
  190. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +1112 -0
  191. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +7 -0
  192. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +908 -0
  193. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +7 -0
  194. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +1015 -0
  195. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +7 -0
  196. package/dist/modules/wms/components/backend/WmsLotDetailPage.js +1049 -0
  197. package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +7 -0
  198. package/dist/modules/wms/components/backend/WmsLotsListPage.js +297 -0
  199. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +7 -0
  200. package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js +757 -0
  201. package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js.map +7 -0
  202. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +975 -0
  203. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +7 -0
  204. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +710 -0
  205. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +7 -0
  206. package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js +79 -0
  207. package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js.map +7 -0
  208. package/dist/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.js +24 -0
  209. package/dist/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.js.map +7 -0
  210. package/dist/modules/wms/components/backend/wmsLookupLoaders.js +55 -0
  211. package/dist/modules/wms/components/backend/wmsLookupLoaders.js.map +7 -0
  212. package/dist/modules/wms/data/enrichers.js +501 -0
  213. package/dist/modules/wms/data/enrichers.js.map +7 -0
  214. package/dist/modules/wms/data/entities.js +467 -0
  215. package/dist/modules/wms/data/entities.js.map +7 -0
  216. package/dist/modules/wms/data/validators.js +399 -0
  217. package/dist/modules/wms/data/validators.js.map +7 -0
  218. package/dist/modules/wms/di.js +27 -0
  219. package/dist/modules/wms/di.js.map +7 -0
  220. package/dist/modules/wms/events.js +42 -0
  221. package/dist/modules/wms/events.js.map +7 -0
  222. package/dist/modules/wms/index.js +17 -0
  223. package/dist/modules/wms/index.js.map +7 -0
  224. package/dist/modules/wms/lib/catalogInventoryProfileIntent.js +54 -0
  225. package/dist/modules/wms/lib/catalogInventoryProfileIntent.js.map +7 -0
  226. package/dist/modules/wms/lib/catalogInventoryProfileSync.js +144 -0
  227. package/dist/modules/wms/lib/catalogInventoryProfileSync.js.map +7 -0
  228. package/dist/modules/wms/lib/expiry.js +29 -0
  229. package/dist/modules/wms/lib/expiry.js.map +7 -0
  230. package/dist/modules/wms/lib/flashMutationError.js +51 -0
  231. package/dist/modules/wms/lib/flashMutationError.js.map +7 -0
  232. package/dist/modules/wms/lib/inventoryDisplayUi.js +188 -0
  233. package/dist/modules/wms/lib/inventoryDisplayUi.js.map +7 -0
  234. package/dist/modules/wms/lib/inventoryIdempotency.js +37 -0
  235. package/dist/modules/wms/lib/inventoryIdempotency.js.map +7 -0
  236. package/dist/modules/wms/lib/inventoryImportCsv.js +173 -0
  237. package/dist/modules/wms/lib/inventoryImportCsv.js.map +7 -0
  238. package/dist/modules/wms/lib/inventoryImportService.js +468 -0
  239. package/dist/modules/wms/lib/inventoryImportService.js.map +7 -0
  240. package/dist/modules/wms/lib/inventoryMutationUi.js +25 -0
  241. package/dist/modules/wms/lib/inventoryMutationUi.js.map +7 -0
  242. package/dist/modules/wms/lib/inventoryPolicy.js +61 -0
  243. package/dist/modules/wms/lib/inventoryPolicy.js.map +7 -0
  244. package/dist/modules/wms/lib/inventoryReconciliation.js +193 -0
  245. package/dist/modules/wms/lib/inventoryReconciliation.js.map +7 -0
  246. package/dist/modules/wms/lib/inventoryTrackingValidation.js +13 -0
  247. package/dist/modules/wms/lib/inventoryTrackingValidation.js.map +7 -0
  248. package/dist/modules/wms/lib/loadOperationalDashboard.js +580 -0
  249. package/dist/modules/wms/lib/loadOperationalDashboard.js.map +7 -0
  250. package/dist/modules/wms/lib/lowStockBalanceFilter.js +49 -0
  251. package/dist/modules/wms/lib/lowStockBalanceFilter.js.map +7 -0
  252. package/dist/modules/wms/lib/primaryWarehousePolicy.js +32 -0
  253. package/dist/modules/wms/lib/primaryWarehousePolicy.js.map +7 -0
  254. package/dist/modules/wms/lib/roleFeatures.js +30 -0
  255. package/dist/modules/wms/lib/roleFeatures.js.map +7 -0
  256. package/dist/modules/wms/lib/salesOrderInventoryAutomation.js +291 -0
  257. package/dist/modules/wms/lib/salesOrderInventoryAutomation.js.map +7 -0
  258. package/dist/modules/wms/lib/salesOrderWarehouseAssignment.js +54 -0
  259. package/dist/modules/wms/lib/salesOrderWarehouseAssignment.js.map +7 -0
  260. package/dist/modules/wms/lib/wmsIntegrationToggles.js +71 -0
  261. package/dist/modules/wms/lib/wmsIntegrationToggles.js.map +7 -0
  262. package/dist/modules/wms/migrations/Migration20260428110546.js +78 -0
  263. package/dist/modules/wms/migrations/Migration20260428110546.js.map +7 -0
  264. package/dist/modules/wms/migrations/Migration20260527120000.js +15 -0
  265. package/dist/modules/wms/migrations/Migration20260527120000.js.map +7 -0
  266. package/dist/modules/wms/migrations/Migration20260527140000.js +37 -0
  267. package/dist/modules/wms/migrations/Migration20260527140000.js.map +7 -0
  268. package/dist/modules/wms/migrations/Migration20260613120000.js +23 -0
  269. package/dist/modules/wms/migrations/Migration20260613120000.js.map +7 -0
  270. package/dist/modules/wms/migrations/Migration20260616090000.js +13 -0
  271. package/dist/modules/wms/migrations/Migration20260616090000.js.map +7 -0
  272. package/dist/modules/wms/migrations/Migration20260707180000.js +15 -0
  273. package/dist/modules/wms/migrations/Migration20260707180000.js.map +7 -0
  274. package/dist/modules/wms/notifications.client.js +18 -0
  275. package/dist/modules/wms/notifications.client.js.map +7 -0
  276. package/dist/modules/wms/notifications.js +53 -0
  277. package/dist/modules/wms/notifications.js.map +7 -0
  278. package/dist/modules/wms/search.js +196 -0
  279. package/dist/modules/wms/search.js.map +7 -0
  280. package/dist/modules/wms/setup.js +30 -0
  281. package/dist/modules/wms/setup.js.map +7 -0
  282. package/dist/modules/wms/subscribers/low-stock-notification.js +40 -0
  283. package/dist/modules/wms/subscribers/low-stock-notification.js.map +7 -0
  284. package/dist/modules/wms/subscribers/reservation-shortfall-notification.js +69 -0
  285. package/dist/modules/wms/subscribers/reservation-shortfall-notification.js.map +7 -0
  286. package/dist/modules/wms/subscribers/sales-order-cancelled-release.js +14 -0
  287. package/dist/modules/wms/subscribers/sales-order-cancelled-release.js.map +7 -0
  288. package/dist/modules/wms/subscribers/sales-order-confirmed-reserve.js +14 -0
  289. package/dist/modules/wms/subscribers/sales-order-confirmed-reserve.js.map +7 -0
  290. package/dist/modules/wms/translations.js +10 -0
  291. package/dist/modules/wms/translations.js.map +7 -0
  292. package/dist/modules/wms/vector.js +9 -0
  293. package/dist/modules/wms/vector.js.map +7 -0
  294. package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js +200 -0
  295. package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js.map +7 -0
  296. package/dist/modules/wms/widgets/injection/order-items-stock-column/widget.js +104 -0
  297. package/dist/modules/wms/widgets/injection/order-items-stock-column/widget.js.map +7 -0
  298. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js +389 -0
  299. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js.map +7 -0
  300. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.js +16 -0
  301. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.js.map +7 -0
  302. package/dist/modules/wms/widgets/injection-table.js +36 -0
  303. package/dist/modules/wms/widgets/injection-table.js.map +7 -0
  304. package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js +150 -0
  305. package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js.map +7 -0
  306. package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js +186 -0
  307. package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js.map +7 -0
  308. package/dist/modules/wms/widgets/notifications/index.js +7 -0
  309. package/dist/modules/wms/widgets/notifications/index.js.map +7 -0
  310. package/generated/entities/inventory_balance/index.ts +9 -0
  311. package/generated/entities/inventory_lot/index.ts +8 -0
  312. package/generated/entities/inventory_movement/index.ts +16 -0
  313. package/generated/entities/inventory_reservation/index.ts +10 -0
  314. package/generated/entities/product_inventory_profile/index.ts +9 -0
  315. package/generated/entities/sales_order_warehouse_assignment/index.ts +4 -0
  316. package/generated/entities/warehouse/index.ts +11 -0
  317. package/generated/entities/warehouse_location/index.ts +9 -0
  318. package/generated/entities/warehouse_zone/index.ts +4 -0
  319. package/generated/entities.ids.generated.ts +12 -0
  320. package/generated/entity-fields-registry.ts +98 -0
  321. package/package.json +7 -7
  322. package/src/modules/auth/backend/roles/page.tsx +13 -4
  323. package/src/modules/auth/i18n/de.json +2 -0
  324. package/src/modules/auth/i18n/en.json +2 -0
  325. package/src/modules/auth/i18n/es.json +2 -0
  326. package/src/modules/auth/i18n/pl.json +2 -0
  327. package/src/modules/auth/lib/backendChrome.tsx +1 -0
  328. package/src/modules/auth/services/rbacService.ts +25 -21
  329. package/src/modules/catalog/api/products/route.ts +3 -0
  330. package/src/modules/catalog/api/variants/route.ts +3 -0
  331. package/src/modules/query_index/lib/engine.ts +18 -6
  332. package/src/modules/sales/api/documents/factory.ts +1 -0
  333. package/src/modules/sales/commands/documents.ts +71 -0
  334. package/src/modules/sales/components/documents/ItemsSection.tsx +58 -0
  335. package/src/modules/sales/events.ts +2 -0
  336. package/src/modules/sales/widgets/injection/order-items-context.ts +15 -0
  337. package/src/modules/wms/acl.ts +14 -0
  338. package/src/modules/wms/analytics.ts +9 -0
  339. package/src/modules/wms/api/dashboard/operational/route.ts +83 -0
  340. package/src/modules/wms/api/interceptors.ts +108 -0
  341. package/src/modules/wms/api/inventory/adjust/route.ts +50 -0
  342. package/src/modules/wms/api/inventory/allocate/route.ts +50 -0
  343. package/src/modules/wms/api/inventory/balances/route.ts +178 -0
  344. package/src/modules/wms/api/inventory/cycle-count/route.ts +51 -0
  345. package/src/modules/wms/api/inventory/helpers.ts +128 -0
  346. package/src/modules/wms/api/inventory/import/apply/route.ts +47 -0
  347. package/src/modules/wms/api/inventory/import/helpers.ts +223 -0
  348. package/src/modules/wms/api/inventory/import/template/route.ts +31 -0
  349. package/src/modules/wms/api/inventory/import/validate/route.ts +56 -0
  350. package/src/modules/wms/api/inventory/move/route.ts +50 -0
  351. package/src/modules/wms/api/inventory/movements/route.ts +164 -0
  352. package/src/modules/wms/api/inventory/receive/route.ts +49 -0
  353. package/src/modules/wms/api/inventory/release/route.ts +43 -0
  354. package/src/modules/wms/api/inventory/reservations/route.ts +128 -0
  355. package/src/modules/wms/api/inventory/reserve/route.ts +59 -0
  356. package/src/modules/wms/api/inventory-profiles/route.ts +177 -0
  357. package/src/modules/wms/api/listEnrichers.ts +312 -0
  358. package/src/modules/wms/api/listSearch.ts +121 -0
  359. package/src/modules/wms/api/locations/route.ts +171 -0
  360. package/src/modules/wms/api/lots/route.ts +205 -0
  361. package/src/modules/wms/api/openapi.ts +28 -0
  362. package/src/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.ts +58 -0
  363. package/src/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.ts +306 -0
  364. package/src/modules/wms/api/sales-orders/assign-warehouse/route.ts +57 -0
  365. package/src/modules/wms/api/sales-orders/unassign-warehouse/route.ts +43 -0
  366. package/src/modules/wms/api/warehouses/route.ts +181 -0
  367. package/src/modules/wms/api/zones/route.ts +158 -0
  368. package/src/modules/wms/backend/config/wms/page.meta.ts +14 -0
  369. package/src/modules/wms/backend/config/wms/page.tsx +5 -0
  370. package/src/modules/wms/backend/page.meta.ts +12 -0
  371. package/src/modules/wms/backend/page.tsx +5 -0
  372. package/src/modules/wms/backend/wms/inventory/page.meta.ts +14 -0
  373. package/src/modules/wms/backend/wms/inventory/page.tsx +5 -0
  374. package/src/modules/wms/backend/wms/location/[id]/page.meta.ts +14 -0
  375. package/src/modules/wms/backend/wms/location/[id]/page.tsx +5 -0
  376. package/src/modules/wms/backend/wms/locations/page.meta.ts +14 -0
  377. package/src/modules/wms/backend/wms/locations/page.tsx +12 -0
  378. package/src/modules/wms/backend/wms/lot/[id]/page.meta.ts +14 -0
  379. package/src/modules/wms/backend/wms/lot/[id]/page.tsx +5 -0
  380. package/src/modules/wms/backend/wms/lots/page.meta.ts +14 -0
  381. package/src/modules/wms/backend/wms/lots/page.tsx +5 -0
  382. package/src/modules/wms/backend/wms/movements/page.meta.ts +14 -0
  383. package/src/modules/wms/backend/wms/movements/page.tsx +23 -0
  384. package/src/modules/wms/backend/wms/reservations/page.meta.ts +14 -0
  385. package/src/modules/wms/backend/wms/reservations/page.tsx +24 -0
  386. package/src/modules/wms/backend/wms/sku/[id]/page.meta.ts +14 -0
  387. package/src/modules/wms/backend/wms/sku/[id]/page.tsx +5 -0
  388. package/src/modules/wms/backend/wms/warehouses/page.meta.ts +14 -0
  389. package/src/modules/wms/backend/wms/warehouses/page.tsx +12 -0
  390. package/src/modules/wms/backend/wms/zones/page.meta.ts +14 -0
  391. package/src/modules/wms/backend/wms/zones/page.tsx +12 -0
  392. package/src/modules/wms/ce.ts +76 -0
  393. package/src/modules/wms/cli.ts +96 -0
  394. package/src/modules/wms/commands/configuration.ts +1844 -0
  395. package/src/modules/wms/commands/index.ts +3 -0
  396. package/src/modules/wms/commands/inventory-actions.ts +1866 -0
  397. package/src/modules/wms/commands/sales-order-assignment.ts +346 -0
  398. package/src/modules/wms/commands/shared.ts +90 -0
  399. package/src/modules/wms/components/backend/AdjustInventoryDialog.tsx +820 -0
  400. package/src/modules/wms/components/backend/ChangeLotStatusDialog.tsx +312 -0
  401. package/src/modules/wms/components/backend/CycleCountWizardDialog.tsx +2007 -0
  402. package/src/modules/wms/components/backend/ImportInventoryDialog.tsx +1018 -0
  403. package/src/modules/wms/components/backend/InventoryOperationsSection.tsx +159 -0
  404. package/src/modules/wms/components/backend/LocationEditDialog.tsx +185 -0
  405. package/src/modules/wms/components/backend/MoveInventoryDialog.tsx +907 -0
  406. package/src/modules/wms/components/backend/ReceiveInventoryDialog.tsx +695 -0
  407. package/src/modules/wms/components/backend/ReleaseReservationDialog.tsx +424 -0
  408. package/src/modules/wms/components/backend/ReserveInventoryDialog.tsx +511 -0
  409. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +1340 -0
  410. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +1132 -0
  411. package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +1310 -0
  412. package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +1355 -0
  413. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +359 -0
  414. package/src/modules/wms/components/backend/WmsOperationalDashboardPage.tsx +958 -0
  415. package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +1245 -0
  416. package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +960 -0
  417. package/src/modules/wms/components/backend/useWmsInventoryMutationAccess.ts +89 -0
  418. package/src/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.ts +32 -0
  419. package/src/modules/wms/components/backend/wmsLookupLoaders.ts +78 -0
  420. package/src/modules/wms/data/enrichers.ts +718 -0
  421. package/src/modules/wms/data/entities.ts +436 -0
  422. package/src/modules/wms/data/validators.ts +463 -0
  423. package/src/modules/wms/di.ts +25 -0
  424. package/src/modules/wms/events.ts +41 -0
  425. package/src/modules/wms/i18n/de.json +1051 -0
  426. package/src/modules/wms/i18n/en.json +1051 -0
  427. package/src/modules/wms/i18n/es.json +1051 -0
  428. package/src/modules/wms/i18n/pl.json +1051 -0
  429. package/src/modules/wms/index.ts +15 -0
  430. package/src/modules/wms/lib/catalogInventoryProfileIntent.ts +65 -0
  431. package/src/modules/wms/lib/catalogInventoryProfileSync.ts +199 -0
  432. package/src/modules/wms/lib/expiry.ts +30 -0
  433. package/src/modules/wms/lib/flashMutationError.ts +74 -0
  434. package/src/modules/wms/lib/inventoryDisplayUi.ts +249 -0
  435. package/src/modules/wms/lib/inventoryIdempotency.ts +54 -0
  436. package/src/modules/wms/lib/inventoryImportCsv.ts +212 -0
  437. package/src/modules/wms/lib/inventoryImportService.ts +629 -0
  438. package/src/modules/wms/lib/inventoryMutationUi.ts +21 -0
  439. package/src/modules/wms/lib/inventoryPolicy.ts +111 -0
  440. package/src/modules/wms/lib/inventoryReconciliation.ts +263 -0
  441. package/src/modules/wms/lib/inventoryTrackingValidation.ts +23 -0
  442. package/src/modules/wms/lib/loadOperationalDashboard.ts +776 -0
  443. package/src/modules/wms/lib/lowStockBalanceFilter.ts +74 -0
  444. package/src/modules/wms/lib/primaryWarehousePolicy.ts +46 -0
  445. package/src/modules/wms/lib/roleFeatures.ts +32 -0
  446. package/src/modules/wms/lib/salesOrderInventoryAutomation.ts +390 -0
  447. package/src/modules/wms/lib/salesOrderWarehouseAssignment.ts +78 -0
  448. package/src/modules/wms/lib/wmsIntegrationToggles.ts +81 -0
  449. package/src/modules/wms/migrations/.snapshot-open-mercato.json +2880 -0
  450. package/src/modules/wms/migrations/Migration20260428110546.ts +91 -0
  451. package/src/modules/wms/migrations/Migration20260527120000.ts +15 -0
  452. package/src/modules/wms/migrations/Migration20260527140000.ts +35 -0
  453. package/src/modules/wms/migrations/Migration20260613120000.ts +21 -0
  454. package/src/modules/wms/migrations/Migration20260616090000.ts +11 -0
  455. package/src/modules/wms/migrations/Migration20260707180000.ts +13 -0
  456. package/src/modules/wms/notifications.client.ts +18 -0
  457. package/src/modules/wms/notifications.ts +51 -0
  458. package/src/modules/wms/search.ts +230 -0
  459. package/src/modules/wms/setup.ts +29 -0
  460. package/src/modules/wms/subscribers/low-stock-notification.ts +54 -0
  461. package/src/modules/wms/subscribers/reservation-shortfall-notification.ts +98 -0
  462. package/src/modules/wms/subscribers/sales-order-cancelled-release.ts +21 -0
  463. package/src/modules/wms/subscribers/sales-order-confirmed-reserve.ts +21 -0
  464. package/src/modules/wms/translations.ts +6 -0
  465. package/src/modules/wms/vector.ts +7 -0
  466. package/src/modules/wms/widgets/injection/catalog-inventory-profile/widget.ts +238 -0
  467. package/src/modules/wms/widgets/injection/order-items-stock-column/widget.tsx +153 -0
  468. package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.client.tsx +476 -0
  469. package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.ts +15 -0
  470. package/src/modules/wms/widgets/injection-table.ts +34 -0
  471. package/src/modules/wms/widgets/notifications/WmsLowStockRenderer.tsx +153 -0
  472. package/src/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.tsx +194 -0
  473. package/src/modules/wms/widgets/notifications/index.ts +2 -0
@@ -0,0 +1,1015 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import Link from "next/link";
5
+ import { useRouter } from "next/navigation";
6
+ import { z } from "zod";
7
+ import { useQuery } from "@tanstack/react-query";
8
+ import {
9
+ ArrowLeft,
10
+ ArrowLeftRight,
11
+ ClipboardList,
12
+ Download,
13
+ ExternalLink,
14
+ SlidersHorizontal,
15
+ Warehouse
16
+ } from "lucide-react";
17
+ import { Page, PageBody, PageHeader } from "@open-mercato/ui/backend/Page";
18
+ import { DataTable } from "@open-mercato/ui/backend/DataTable";
19
+ import { EmptyState } from "@open-mercato/ui/backend/EmptyState";
20
+ import { ErrorMessage, LoadingMessage, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
21
+ import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
22
+ import { raiseCrudError } from "@open-mercato/ui/backend/utils/serverErrors";
23
+ import { useLocale, useT } from "@open-mercato/shared/lib/i18n/context";
24
+ import { Button } from "@open-mercato/ui/primitives/button";
25
+ import { LinkButton } from "@open-mercato/ui/primitives/link-button";
26
+ import { Progress } from "@open-mercato/ui/primitives/progress";
27
+ import {
28
+ Select,
29
+ SelectContent,
30
+ SelectItem,
31
+ SelectTrigger,
32
+ SelectValue
33
+ } from "@open-mercato/ui/primitives/select";
34
+ import { StatusBadge } from "@open-mercato/ui/primitives/status-badge";
35
+ import { Checkbox } from "@open-mercato/ui/primitives/checkbox";
36
+ import { cn } from "@open-mercato/shared/lib/utils";
37
+ import { E } from "../../../../generated/entities.ids.generated.js";
38
+ import {
39
+ inventoryMovementReasonLabel
40
+ } from "../../lib/inventoryDisplayUi.js";
41
+ import { AdjustInventoryDialog } from "./AdjustInventoryDialog.js";
42
+ import { CycleCountWizardDialog } from "./CycleCountWizardDialog.js";
43
+ import { LocationEditDialog } from "./LocationEditDialog.js";
44
+ import { useWmsInventoryMutationAccess } from "./useWmsInventoryMutationAccess.js";
45
+ const locationIdSchema = z.string().uuid();
46
+ const NEAR_EXPIRY_MS = 30 * 24 * 60 * 60 * 1e3;
47
+ function escapeCsvCell(value) {
48
+ const str = String(value ?? "");
49
+ if (/[",\n]/.test(str)) return `"${str.replace(/"/g, '""')}"`;
50
+ return str;
51
+ }
52
+ function downloadCsvFile(filename, rows) {
53
+ const csv = rows.map((row) => row.map(escapeCsvCell).join(",")).join("\n");
54
+ const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
55
+ const url = URL.createObjectURL(blob);
56
+ const anchor = document.createElement("a");
57
+ anchor.href = url;
58
+ anchor.download = filename;
59
+ anchor.click();
60
+ URL.revokeObjectURL(url);
61
+ }
62
+ function toNumber(value) {
63
+ const parsed = Number(value ?? 0);
64
+ return Number.isFinite(parsed) ? parsed : 0;
65
+ }
66
+ function formatWarehouseLabel(row) {
67
+ const code = (row.warehouse_code ?? "").trim();
68
+ const name = (row.warehouse_name ?? "").trim();
69
+ if (code && name) return `${code} \xB7 ${name}`;
70
+ return name || code || row.warehouse_id || "\u2014";
71
+ }
72
+ function formatSkuLabel(row) {
73
+ const sku = (row.variant_sku ?? "").trim();
74
+ const name = (row.variant_name ?? "").trim();
75
+ if (sku) return sku;
76
+ if (name) return name;
77
+ return row.catalog_variant_id || "\u2014";
78
+ }
79
+ function formatVariantName(row) {
80
+ return (row.variant_name ?? "").trim() || "\u2014";
81
+ }
82
+ function formatLotLabel(lot, locale) {
83
+ if (!lot) return "\u2014";
84
+ const number = (lot.lot_number ?? "").trim() || lot.id;
85
+ if (!lot.expires_at) return number;
86
+ const expires = new Date(lot.expires_at);
87
+ if (Number.isNaN(expires.getTime())) return number;
88
+ const expLabel = new Intl.DateTimeFormat(locale, { month: "2-digit", year: "2-digit" }).format(expires);
89
+ return `${number} \xB7 exp ${expLabel}`;
90
+ }
91
+ function isNearExpiry(expiresAt, nowMs) {
92
+ if (!expiresAt) return false;
93
+ const expires = new Date(expiresAt).getTime();
94
+ if (Number.isNaN(expires)) return false;
95
+ return expires > nowMs && expires - nowMs <= NEAR_EXPIRY_MS;
96
+ }
97
+ function isExpired(expiresAt, nowMs) {
98
+ if (!expiresAt) return false;
99
+ const expires = new Date(expiresAt).getTime();
100
+ return !Number.isNaN(expires) && expires <= nowMs;
101
+ }
102
+ function resolveItemStatus(row, lot, reorderPoint, nowMs) {
103
+ if (lot?.status === "expired" || isExpired(lot?.expires_at, nowMs)) {
104
+ return {
105
+ variant: "error",
106
+ labelKey: "wms.backend.location.items.status.expired",
107
+ labelFallback: "Expired"
108
+ };
109
+ }
110
+ if (isNearExpiry(lot?.expires_at, nowMs)) {
111
+ return {
112
+ variant: "warning",
113
+ labelKey: "wms.backend.location.items.status.nearExpiry",
114
+ labelFallback: "Near expiry"
115
+ };
116
+ }
117
+ const available = row.quantity_available ?? 0;
118
+ if (reorderPoint > 0 && available <= reorderPoint) {
119
+ return {
120
+ variant: "warning",
121
+ labelKey: "wms.backend.location.items.status.lowStock",
122
+ labelFallback: "Low stock"
123
+ };
124
+ }
125
+ const reserved = toNumber(row.quantity_reserved);
126
+ const allocated = toNumber(row.quantity_allocated);
127
+ if (reserved > 0 || allocated > 0) {
128
+ return {
129
+ variant: "info",
130
+ labelKey: "wms.backend.location.items.status.reserved",
131
+ labelFallback: "Reserved"
132
+ };
133
+ }
134
+ return {
135
+ variant: "success",
136
+ labelKey: "wms.backend.location.items.status.available",
137
+ labelFallback: "Available"
138
+ };
139
+ }
140
+ function matchesItemFilter(row, lot, filter, nowMs) {
141
+ switch (filter) {
142
+ case "all":
143
+ return true;
144
+ case "sellable":
145
+ return (row.quantity_available ?? 0) > 0 && !isExpired(lot?.expires_at, nowMs) && lot?.status !== "expired";
146
+ case "picking":
147
+ return toNumber(row.quantity_reserved) > 0 || toNumber(row.quantity_allocated) > 0;
148
+ case "nearExpiry":
149
+ return isNearExpiry(lot?.expires_at, nowMs) || lot?.status === "expired";
150
+ default:
151
+ return true;
152
+ }
153
+ }
154
+ function movementTypeLabel(type, t) {
155
+ const key = `wms.backend.location.activity.types.${type}`;
156
+ const fallbacks = {
157
+ receipt: "Receive",
158
+ return_receive: "Receive",
159
+ adjust: "Adjust",
160
+ transfer: "Move",
161
+ pick: "Allocate",
162
+ pack: "Allocate",
163
+ cycle_count: "Reconcile",
164
+ putaway: "Putaway",
165
+ ship: "Ship"
166
+ };
167
+ return t(key, fallbacks[type] ?? type);
168
+ }
169
+ const movementStatusMap = {
170
+ receipt: "success",
171
+ return_receive: "success",
172
+ adjust: "warning",
173
+ transfer: "info",
174
+ pick: "info",
175
+ pack: "info",
176
+ cycle_count: "neutral",
177
+ putaway: "info",
178
+ ship: "success"
179
+ };
180
+ function formatMovementTitle(row, skuLabel, t) {
181
+ const quantity = Math.abs(toNumber(row.quantity));
182
+ const signedQuantity = toNumber(row.quantity);
183
+ switch (row.type) {
184
+ case "receipt":
185
+ case "return_receive":
186
+ return t("wms.backend.dashboard.activity.titles.received", "Received {quantity}\xD7 {sku}", {
187
+ quantity,
188
+ sku: skuLabel
189
+ });
190
+ case "adjust":
191
+ return t("wms.backend.dashboard.activity.titles.adjusted", "Adjusted {quantity}\xD7 {sku}", {
192
+ quantity: `${signedQuantity >= 0 ? "+" : ""}${signedQuantity}`,
193
+ sku: skuLabel
194
+ });
195
+ case "transfer":
196
+ return t("wms.backend.dashboard.activity.titles.moved", "Moved {quantity}\xD7 {sku}", {
197
+ quantity,
198
+ sku: skuLabel
199
+ });
200
+ case "pick":
201
+ case "pack":
202
+ return t("wms.backend.dashboard.activity.titles.allocated", "Allocated {quantity}\xD7 {sku}", {
203
+ quantity,
204
+ sku: skuLabel
205
+ });
206
+ case "cycle_count":
207
+ return t("wms.backend.dashboard.activity.titles.reconciled", "Inventory reconciled \u2014 {sku}", {
208
+ sku: skuLabel
209
+ });
210
+ default:
211
+ return t("wms.backend.dashboard.activity.titles.generic", "{type} {quantity}\xD7 {sku}", {
212
+ type: row.type ?? "movement",
213
+ quantity,
214
+ sku: skuLabel
215
+ });
216
+ }
217
+ }
218
+ function formatMovementSubtitle(row, t) {
219
+ const reasonLabel = inventoryMovementReasonLabel(
220
+ {
221
+ reasonCode: row.reason_code,
222
+ reason: row.reason,
223
+ movementType: row.type
224
+ },
225
+ t
226
+ );
227
+ if (reasonLabel) return reasonLabel;
228
+ if (row.reference_type && row.reference_id) return `${row.reference_type} \xB7 ${row.reference_id}`;
229
+ return null;
230
+ }
231
+ function formatMovementLocation(row, locationId, locationCode) {
232
+ const fromId = row.location_from_id?.trim();
233
+ const toId = row.location_to_id?.trim();
234
+ const from = (row.location_from_code ?? "").trim() || fromId || "\u2014";
235
+ const to = (row.location_to_code ?? "").trim() || toId || "\u2014";
236
+ if (row.type === "transfer" && from !== "\u2014" && to !== "\u2014") return `${from} \u2192 ${to}`;
237
+ if (fromId === locationId || toId === locationId) return locationCode || locationId;
238
+ return from !== "\u2014" ? from : to;
239
+ }
240
+ function formatRelativeDays(valueMs, t) {
241
+ const days = Math.max(0, Math.floor((Date.now() - valueMs) / (24 * 60 * 60 * 1e3)));
242
+ if (days === 0) return t("wms.backend.location.kpis.lastCounted.today", "Today");
243
+ return t("wms.backend.location.kpis.lastCounted.daysAgo", "{days}d ago", { days });
244
+ }
245
+ function LocationKpiCard({
246
+ title,
247
+ caption,
248
+ value,
249
+ badgeLabel,
250
+ badgeVariant,
251
+ ctaLabel,
252
+ ctaHref,
253
+ onCtaClick,
254
+ progress
255
+ }) {
256
+ return /* @__PURE__ */ jsxs("section", { className: "flex min-h-52 flex-col rounded-lg border bg-card p-5 text-card-foreground shadow-sm", children: [
257
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: title }),
258
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-xs text-muted-foreground", children: caption }),
259
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-end gap-3", children: [
260
+ /* @__PURE__ */ jsx("p", { className: "text-3xl font-semibold tracking-tight", children: value }),
261
+ badgeLabel ? /* @__PURE__ */ jsx(StatusBadge, { variant: badgeVariant, dot: true, children: badgeLabel }) : null
262
+ ] }),
263
+ progress != null ? /* @__PURE__ */ jsx(
264
+ Progress,
265
+ {
266
+ value: progress,
267
+ max: 100,
268
+ tone: progress >= 80 ? "warning" : "accent",
269
+ size: "sm",
270
+ className: "mt-3"
271
+ }
272
+ ) : null,
273
+ onCtaClick ? /* @__PURE__ */ jsx(LinkButton, { variant: "primary", size: "sm", className: "mt-auto pt-4 w-fit", onClick: onCtaClick, children: ctaLabel }) : ctaHref ? /* @__PURE__ */ jsx(LinkButton, { asChild: true, variant: "primary", size: "sm", className: "mt-auto pt-4 w-fit", children: /* @__PURE__ */ jsx(Link, { href: ctaHref, children: ctaLabel }) }) : null
274
+ ] });
275
+ }
276
+ function WmsLocationDetailPage({ locationId }) {
277
+ const t = useT();
278
+ const locale = useLocale();
279
+ const router = useRouter();
280
+ const access = useWmsInventoryMutationAccess();
281
+ const parsedLocationId = locationIdSchema.safeParse(locationId.trim());
282
+ const scopedLocationId = parsedLocationId.success ? parsedLocationId.data : null;
283
+ const [itemFilter, setItemFilter] = React.useState("all");
284
+ const [itemsPage, setItemsPage] = React.useState(1);
285
+ const [selectedBalanceIds, setSelectedBalanceIds] = React.useState(() => /* @__PURE__ */ new Set());
286
+ const [adjustOpen, setAdjustOpen] = React.useState(false);
287
+ const [adjustPreset, setAdjustPreset] = React.useState({});
288
+ const [cycleOpen, setCycleOpen] = React.useState(false);
289
+ const [cyclePreset, setCyclePreset] = React.useState({});
290
+ const [editOpen, setEditOpen] = React.useState(false);
291
+ const itemsPageSize = 20;
292
+ const activityTimeFormatter = React.useMemo(
293
+ () => new Intl.DateTimeFormat(locale, {
294
+ month: "2-digit",
295
+ day: "2-digit",
296
+ hour: "2-digit",
297
+ minute: "2-digit"
298
+ }),
299
+ [locale]
300
+ );
301
+ const locationQuery = useQuery({
302
+ queryKey: ["wms-location-detail", "location", scopedLocationId],
303
+ enabled: Boolean(scopedLocationId),
304
+ queryFn: async () => {
305
+ const params = new URLSearchParams({
306
+ ids: scopedLocationId,
307
+ page: "1",
308
+ pageSize: "1"
309
+ });
310
+ const call = await apiCall(`/api/wms/locations?${params.toString()}`);
311
+ if (!call.ok) {
312
+ await raiseCrudError(call.response, t("wms.backend.location.errors.location", "Failed to load location."));
313
+ }
314
+ return call.result?.items?.[0] ?? null;
315
+ }
316
+ });
317
+ const parentLocationQuery = useQuery({
318
+ queryKey: ["wms-location-detail", "parent", locationQuery.data?.parent_id],
319
+ enabled: Boolean(locationQuery.data?.parent_id),
320
+ queryFn: async () => {
321
+ const parentId = locationQuery.data?.parent_id?.trim();
322
+ if (!parentId) return null;
323
+ const params = new URLSearchParams({ ids: parentId, page: "1", pageSize: "1" });
324
+ const call = await apiCall(`/api/wms/locations?${params.toString()}`);
325
+ if (!call.ok) return null;
326
+ return call.result?.items?.[0] ?? null;
327
+ }
328
+ });
329
+ const balancesQuery = useQuery({
330
+ queryKey: ["wms-location-detail", "balances", scopedLocationId],
331
+ enabled: Boolean(scopedLocationId),
332
+ queryFn: async () => {
333
+ const params = new URLSearchParams({
334
+ locationId: scopedLocationId,
335
+ page: "1",
336
+ pageSize: "100",
337
+ sortField: "updatedAt",
338
+ sortDir: "desc"
339
+ });
340
+ const call = await apiCall(
341
+ `/api/wms/inventory/balances?${params.toString()}`
342
+ );
343
+ if (!call.ok) {
344
+ await raiseCrudError(call.response, t("wms.backend.location.errors.balances", "Failed to load items in location."));
345
+ }
346
+ return call.result ?? { items: [], total: 0, totalPages: 1 };
347
+ }
348
+ });
349
+ const variantIds = React.useMemo(() => {
350
+ const ids = /* @__PURE__ */ new Set();
351
+ for (const row of balancesQuery.data?.items ?? []) {
352
+ const variantId = row.catalog_variant_id?.trim();
353
+ if (variantId) ids.add(variantId);
354
+ }
355
+ return Array.from(ids);
356
+ }, [balancesQuery.data?.items]);
357
+ const profilesQuery = useQuery({
358
+ queryKey: ["wms-location-detail", "profiles", variantIds],
359
+ enabled: variantIds.length > 0,
360
+ queryFn: async () => {
361
+ const params = new URLSearchParams({ page: "1", pageSize: "100" });
362
+ const call = await apiCall(
363
+ `/api/wms/inventory-profiles?${params.toString()}`
364
+ );
365
+ if (!call.ok) return [];
366
+ return call.result?.items ?? [];
367
+ }
368
+ });
369
+ const lotsQuery = useQuery({
370
+ queryKey: ["wms-location-detail", "lots", variantIds],
371
+ enabled: variantIds.length > 0,
372
+ queryFn: async () => {
373
+ const params = new URLSearchParams({ page: "1", pageSize: "100" });
374
+ const call = await apiCall(`/api/wms/lots?${params.toString()}`);
375
+ if (!call.ok) {
376
+ await raiseCrudError(call.response, t("wms.backend.location.errors.lots", "Failed to load lots."));
377
+ }
378
+ return call.result?.items ?? [];
379
+ }
380
+ });
381
+ const warehouseId = locationQuery.data?.warehouse_id?.trim() ?? "";
382
+ const movementsQuery = useQuery({
383
+ queryKey: ["wms-location-detail", "movements", scopedLocationId, warehouseId],
384
+ enabled: Boolean(scopedLocationId && warehouseId),
385
+ queryFn: async () => {
386
+ const params = new URLSearchParams({
387
+ warehouseId,
388
+ locationId: scopedLocationId,
389
+ page: "1",
390
+ pageSize: "50",
391
+ sortField: "performedAt",
392
+ sortDir: "desc"
393
+ });
394
+ const call = await apiCall(
395
+ `/api/wms/inventory/movements?${params.toString()}`
396
+ );
397
+ if (!call.ok) {
398
+ await raiseCrudError(call.response, t("wms.backend.location.errors.movements", "Failed to load recent activity."));
399
+ }
400
+ return call.result?.items ?? [];
401
+ }
402
+ });
403
+ const lotById = React.useMemo(() => {
404
+ const map = /* @__PURE__ */ new Map();
405
+ for (const lot of lotsQuery.data ?? []) {
406
+ if (lot.id) map.set(lot.id, lot);
407
+ }
408
+ return map;
409
+ }, [lotsQuery.data]);
410
+ const reorderPointByVariant = React.useMemo(() => {
411
+ const map = /* @__PURE__ */ new Map();
412
+ for (const profile of profilesQuery.data ?? []) {
413
+ const variantId = profile.catalog_variant_id?.trim();
414
+ if (!variantId) continue;
415
+ map.set(variantId, toNumber(profile.reorder_point));
416
+ }
417
+ return map;
418
+ }, [profilesQuery.data]);
419
+ const locationCode = (locationQuery.data?.code ?? "").trim() || scopedLocationId || "\u2014";
420
+ const pageTitle = locationCode;
421
+ const locationTypeLabel = React.useMemo(() => {
422
+ const type = (locationQuery.data?.type ?? "").trim();
423
+ if (!type) return null;
424
+ return t(`wms.backend.location.types.${type}`, type);
425
+ }, [locationQuery.data?.type, t]);
426
+ const nowMs = React.useMemo(() => Date.now(), []);
427
+ const totals = React.useMemo(() => {
428
+ const items = balancesQuery.data?.items ?? [];
429
+ let onHand = 0;
430
+ let reserved = 0;
431
+ let allocated = 0;
432
+ const skuIds = /* @__PURE__ */ new Set();
433
+ const lotIds = /* @__PURE__ */ new Set();
434
+ for (const row of items) {
435
+ onHand += toNumber(row.quantity_on_hand);
436
+ reserved += toNumber(row.quantity_reserved);
437
+ allocated += toNumber(row.quantity_allocated);
438
+ const variantId = row.catalog_variant_id?.trim();
439
+ if (variantId && toNumber(row.quantity_on_hand) > 0) skuIds.add(variantId);
440
+ const lotId = row.lot_id?.trim();
441
+ if (lotId && toNumber(row.quantity_on_hand) > 0) lotIds.add(lotId);
442
+ }
443
+ return {
444
+ onHand,
445
+ reserved,
446
+ allocated,
447
+ pendingPicks: reserved + allocated,
448
+ skuCount: skuIds.size,
449
+ lotCount: lotIds.size
450
+ };
451
+ }, [balancesQuery.data?.items]);
452
+ const capacityUsedPercent = React.useMemo(() => {
453
+ const capacity = toNumber(locationQuery.data?.capacity_units);
454
+ if (capacity <= 0) return null;
455
+ return Math.min(100, Math.round(totals.onHand / capacity * 100));
456
+ }, [locationQuery.data?.capacity_units, totals.onHand]);
457
+ const lastCounted = React.useMemo(() => {
458
+ const cycleMovements = (movementsQuery.data ?? []).filter((row) => row.type === "cycle_count");
459
+ if (cycleMovements.length === 0) return null;
460
+ const latest = cycleMovements[0];
461
+ const raw = latest.performed_at ?? latest.received_at;
462
+ if (!raw) return null;
463
+ const ts = new Date(raw).getTime();
464
+ if (Number.isNaN(ts)) return null;
465
+ return { ts, label: formatRelativeDays(ts, t) };
466
+ }, [movementsQuery.data, t]);
467
+ const filteredBalances = React.useMemo(() => {
468
+ const items = balancesQuery.data?.items ?? [];
469
+ return items.filter(
470
+ (row) => matchesItemFilter(row, row.lot_id ? lotById.get(row.lot_id) : void 0, itemFilter, nowMs)
471
+ );
472
+ }, [balancesQuery.data?.items, itemFilter, lotById, nowMs]);
473
+ const itemsTotal = filteredBalances.length;
474
+ const itemsTotalPages = Math.max(1, Math.ceil(itemsTotal / itemsPageSize));
475
+ const pagedBalances = React.useMemo(() => {
476
+ const start = (itemsPage - 1) * itemsPageSize;
477
+ return filteredBalances.slice(start, start + itemsPageSize);
478
+ }, [filteredBalances, itemsPage, itemsPageSize]);
479
+ React.useEffect(() => {
480
+ setItemsPage(1);
481
+ setSelectedBalanceIds(/* @__PURE__ */ new Set());
482
+ }, [itemFilter]);
483
+ const selectedBalances = React.useMemo(
484
+ () => filteredBalances.filter((row) => selectedBalanceIds.has(row.id)),
485
+ [filteredBalances, selectedBalanceIds]
486
+ );
487
+ const movementsHref = React.useMemo(() => {
488
+ const params = new URLSearchParams();
489
+ if (warehouseId) params.set("warehouseId", warehouseId);
490
+ const query = params.toString();
491
+ return query ? `/backend/wms/movements?${query}` : "/backend/wms/movements";
492
+ }, [warehouseId]);
493
+ const inventoryConsoleHref = React.useMemo(() => {
494
+ if (!scopedLocationId) return "/backend/wms/inventory";
495
+ return `/backend/wms/inventory?locationId=${encodeURIComponent(scopedLocationId)}`;
496
+ }, [scopedLocationId]);
497
+ const locationsHref = "/backend/wms/locations";
498
+ const openAdjustDialog = React.useCallback((preset = {}) => {
499
+ setAdjustPreset(preset);
500
+ setAdjustOpen(true);
501
+ }, []);
502
+ const openCycleCountDialog = React.useCallback(
503
+ (preset = {}) => {
504
+ setCyclePreset(preset);
505
+ setCycleOpen(true);
506
+ },
507
+ []
508
+ );
509
+ const resolveMutationContext = React.useCallback(() => {
510
+ const firstSelected = selectedBalances[0];
511
+ const lotId = selectedBalances.length === 1 ? firstSelected?.lot_id?.trim() || void 0 : void 0;
512
+ const catalogVariantId = selectedBalances.length === 1 ? firstSelected?.catalog_variant_id?.trim() || void 0 : void 0;
513
+ return {
514
+ warehouseId: warehouseId || void 0,
515
+ locationId: scopedLocationId || void 0,
516
+ catalogVariantId,
517
+ lotId
518
+ };
519
+ }, [scopedLocationId, selectedBalances, warehouseId]);
520
+ const toggleBalanceSelection = React.useCallback((balanceId, selected) => {
521
+ setSelectedBalanceIds((current) => {
522
+ const next = new Set(current);
523
+ if (selected) next.add(balanceId);
524
+ else next.delete(balanceId);
525
+ return next;
526
+ });
527
+ }, []);
528
+ const togglePageSelection = React.useCallback((selected) => {
529
+ setSelectedBalanceIds((current) => {
530
+ const next = new Set(current);
531
+ for (const row of pagedBalances) {
532
+ if (selected) next.add(row.id);
533
+ else next.delete(row.id);
534
+ }
535
+ return next;
536
+ });
537
+ }, [pagedBalances]);
538
+ const pageSelectionState = React.useMemo(() => {
539
+ if (pagedBalances.length === 0) {
540
+ return { checked: false, indeterminate: false };
541
+ }
542
+ const selectedOnPage = pagedBalances.filter((row) => selectedBalanceIds.has(row.id)).length;
543
+ return {
544
+ checked: selectedOnPage === pagedBalances.length,
545
+ indeterminate: selectedOnPage > 0 && selectedOnPage < pagedBalances.length
546
+ };
547
+ }, [pagedBalances, selectedBalanceIds]);
548
+ const handleExportItemsCsv = React.useCallback(() => {
549
+ const headers = [
550
+ t("wms.backend.location.items.columns.sku", "SKU"),
551
+ t("wms.backend.location.items.columns.variant", "Variant name"),
552
+ t("wms.backend.location.items.columns.lot", "Lot"),
553
+ t("wms.backend.location.items.columns.onHand", "On hand"),
554
+ t("wms.backend.location.items.columns.reserved", "Reserved"),
555
+ t("wms.backend.location.items.columns.status", "Status")
556
+ ];
557
+ const rows = filteredBalances.map((row) => {
558
+ const lot = row.lot_id ? lotById.get(row.lot_id) : void 0;
559
+ const reorderPoint = reorderPointByVariant.get(row.catalog_variant_id?.trim() ?? "") ?? 0;
560
+ const status = resolveItemStatus(row, lot, reorderPoint, nowMs);
561
+ return [
562
+ formatSkuLabel(row),
563
+ formatVariantName(row),
564
+ formatLotLabel(lot, locale),
565
+ String(toNumber(row.quantity_on_hand)),
566
+ String(toNumber(row.quantity_reserved)),
567
+ t(status.labelKey, status.labelFallback)
568
+ ];
569
+ });
570
+ const safeCode = pageTitle.replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "") || "location";
571
+ downloadCsvFile(`${safeCode}-items.csv`, [headers, ...rows]);
572
+ }, [filteredBalances, locale, lotById, nowMs, pageTitle, reorderPointByVariant, t]);
573
+ const warehouseLabel = formatWarehouseLabel(locationQuery.data ?? {});
574
+ const subtitleParts = [
575
+ locationTypeLabel ? `${locationTypeLabel} ${locationCode}` : null,
576
+ parentLocationQuery.data?.code?.trim() ? t("wms.backend.location.header.zone", "Zone {code}", {
577
+ code: parentLocationQuery.data.code.trim()
578
+ }) : null,
579
+ warehouseLabel !== "\u2014" ? warehouseLabel : null,
580
+ locationQuery.data?.is_active === false ? t("wms.backend.location.header.inactive", "Inactive") : null
581
+ ].filter(Boolean);
582
+ const itemColumns = React.useMemo(
583
+ () => [
584
+ {
585
+ id: "select",
586
+ header: () => /* @__PURE__ */ jsx(
587
+ Checkbox,
588
+ {
589
+ "aria-label": t("wms.backend.location.items.columns.select", "Select"),
590
+ checked: pageSelectionState.indeterminate ? "indeterminate" : pageSelectionState.checked,
591
+ onCheckedChange: (checked) => togglePageSelection(checked === true)
592
+ }
593
+ ),
594
+ cell: ({ row }) => /* @__PURE__ */ jsx(
595
+ Checkbox,
596
+ {
597
+ "aria-label": t("wms.backend.location.items.columns.select", "Select"),
598
+ checked: selectedBalanceIds.has(row.original.id),
599
+ onCheckedChange: (checked) => toggleBalanceSelection(row.original.id, checked === true)
600
+ }
601
+ ),
602
+ meta: { maxWidth: "2.75rem" }
603
+ },
604
+ {
605
+ accessorKey: "variant_sku",
606
+ header: t("wms.backend.location.items.columns.sku", "SKU"),
607
+ cell: ({ row }) => {
608
+ const variantId = row.original.catalog_variant_id?.trim();
609
+ const label = formatSkuLabel(row.original);
610
+ if (!variantId) return label;
611
+ return /* @__PURE__ */ jsx(
612
+ Link,
613
+ {
614
+ href: `/backend/wms/sku/${encodeURIComponent(variantId)}`,
615
+ className: "font-medium text-primary hover:underline",
616
+ children: label
617
+ }
618
+ );
619
+ }
620
+ },
621
+ {
622
+ accessorKey: "variant_name",
623
+ header: t("wms.backend.location.items.columns.variant", "Variant name"),
624
+ cell: ({ row }) => formatVariantName(row.original)
625
+ },
626
+ {
627
+ accessorKey: "lot_id",
628
+ header: t("wms.backend.location.items.columns.lot", "Lot"),
629
+ cell: ({ row }) => {
630
+ const lotId = row.original.lot_id?.trim();
631
+ const lot = lotId ? lotById.get(lotId) : void 0;
632
+ const label = formatLotLabel(lot, locale);
633
+ if (!lotId || label === "\u2014") return label;
634
+ return /* @__PURE__ */ jsx(
635
+ Link,
636
+ {
637
+ href: `/backend/wms/lot/${encodeURIComponent(lotId)}`,
638
+ className: "font-medium text-primary hover:underline",
639
+ children: label
640
+ }
641
+ );
642
+ }
643
+ },
644
+ {
645
+ accessorKey: "quantity_on_hand",
646
+ header: t("wms.backend.location.items.columns.onHand", "On hand"),
647
+ cell: ({ row }) => String(toNumber(row.original.quantity_on_hand))
648
+ },
649
+ {
650
+ accessorKey: "quantity_reserved",
651
+ header: t("wms.backend.location.items.columns.reserved", "Reserved"),
652
+ cell: ({ row }) => String(toNumber(row.original.quantity_reserved))
653
+ },
654
+ {
655
+ id: "status",
656
+ header: t("wms.backend.location.items.columns.status", "Status"),
657
+ cell: ({ row }) => {
658
+ const lot = row.original.lot_id ? lotById.get(row.original.lot_id) : void 0;
659
+ const reorderPoint = reorderPointByVariant.get(row.original.catalog_variant_id?.trim() ?? "") ?? 0;
660
+ const status = resolveItemStatus(row.original, lot, reorderPoint, nowMs);
661
+ return /* @__PURE__ */ jsx(StatusBadge, { variant: status.variant, dot: true, children: t(status.labelKey, status.labelFallback) });
662
+ }
663
+ }
664
+ ],
665
+ [
666
+ locale,
667
+ lotById,
668
+ nowMs,
669
+ pageSelectionState.checked,
670
+ pageSelectionState.indeterminate,
671
+ reorderPointByVariant,
672
+ selectedBalanceIds,
673
+ t,
674
+ toggleBalanceSelection,
675
+ togglePageSelection
676
+ ]
677
+ );
678
+ const activityColumns = React.useMemo(
679
+ () => [
680
+ {
681
+ accessorKey: "type",
682
+ header: t("wms.backend.location.activity.columns.event", "Event"),
683
+ cell: ({ row }) => {
684
+ const type = row.original.type ?? "movement";
685
+ return /* @__PURE__ */ jsx(StatusBadge, { variant: movementStatusMap[type] ?? "neutral", children: movementTypeLabel(type, t) });
686
+ }
687
+ },
688
+ {
689
+ id: "details",
690
+ header: t("wms.backend.location.activity.columns.details", "Details"),
691
+ cell: ({ row }) => {
692
+ const skuLabel = (row.original.variant_sku ?? "").trim() || (row.original.variant_name ?? "").trim() || row.original.catalog_variant_id || "\u2014";
693
+ const subtitle = formatMovementSubtitle(row.original, t);
694
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
695
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: formatMovementTitle(row.original, skuLabel, t) }),
696
+ subtitle ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: subtitle }) : null
697
+ ] });
698
+ }
699
+ },
700
+ {
701
+ id: "location",
702
+ header: t("wms.backend.location.activity.columns.location", "Location"),
703
+ cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: formatMovementLocation(row.original, scopedLocationId ?? "", locationCode) })
704
+ },
705
+ {
706
+ id: "time",
707
+ header: t("wms.backend.location.activity.columns.time", "Time"),
708
+ cell: ({ row }) => {
709
+ const raw = row.original.performed_at ?? row.original.received_at;
710
+ if (!raw) return "\u2014";
711
+ const date = new Date(raw);
712
+ if (Number.isNaN(date.getTime())) return raw;
713
+ return activityTimeFormatter.format(date);
714
+ },
715
+ meta: { maxWidth: "6rem" }
716
+ }
717
+ ],
718
+ [activityTimeFormatter, locationCode, scopedLocationId, t]
719
+ );
720
+ const filterChips = [
721
+ { id: "all", label: t("wms.backend.location.items.filters.all", "All items") },
722
+ { id: "sellable", label: t("wms.backend.location.items.filters.sellable", "Sellable") },
723
+ { id: "picking", label: t("wms.backend.location.items.filters.picking", "Picking") },
724
+ { id: "nearExpiry", label: t("wms.backend.location.items.filters.nearExpiry", "Near expiry") }
725
+ ];
726
+ const isLoading = locationQuery.isLoading || balancesQuery.isLoading || lotsQuery.isLoading || movementsQuery.isLoading || parentLocationQuery.isLoading;
727
+ const hasError = locationQuery.isError || balancesQuery.isError || lotsQuery.isError || movementsQuery.isError;
728
+ if (!scopedLocationId) {
729
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
730
+ ErrorMessage,
731
+ {
732
+ label: t("wms.backend.location.errors.invalidId", "Invalid location identifier."),
733
+ action: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => router.push(locationsHref), children: t("wms.backend.location.actions.backToLocations", "Back to locations") })
734
+ }
735
+ ) }) });
736
+ }
737
+ return /* @__PURE__ */ jsxs(Page, { children: [
738
+ /* @__PURE__ */ jsxs(PageBody, { className: "space-y-6", children: [
739
+ /* @__PURE__ */ jsx(LinkButton, { asChild: true, variant: "gray", size: "sm", className: "w-fit px-0 text-muted-foreground hover:text-foreground", children: /* @__PURE__ */ jsxs(Link, { href: locationsHref, children: [
740
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "size-4" }),
741
+ t("wms.backend.location.actions.backToLocations", "Back to locations")
742
+ ] }) }),
743
+ /* @__PURE__ */ jsx(
744
+ PageHeader,
745
+ {
746
+ title: pageTitle,
747
+ description: subtitleParts.join(" \xB7 "),
748
+ actions: /* @__PURE__ */ jsxs(Fragment, { children: [
749
+ warehouseId ? /* @__PURE__ */ jsxs(Select, { value: warehouseId, disabled: true, children: [
750
+ /* @__PURE__ */ jsxs(SelectTrigger, { className: "w-full max-w-xs sm:w-56", children: [
751
+ /* @__PURE__ */ jsx(Warehouse, { className: "mr-2 size-4 shrink-0 text-muted-foreground" }),
752
+ /* @__PURE__ */ jsx(SelectValue, { placeholder: warehouseLabel })
753
+ ] }),
754
+ /* @__PURE__ */ jsx(SelectContent, { children: /* @__PURE__ */ jsx(SelectItem, { value: warehouseId, children: warehouseLabel }) })
755
+ ] }) : null,
756
+ access.canAdjust ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", onClick: () => openAdjustDialog(resolveMutationContext()), children: [
757
+ /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-4" }),
758
+ t("wms.backend.location.actions.adjust", "Adjust stock")
759
+ ] }) : null
760
+ ] })
761
+ }
762
+ ),
763
+ isLoading ? /* @__PURE__ */ jsx(LoadingMessage, { label: t("wms.backend.location.loading", "Loading location view\u2026") }) : null,
764
+ hasError ? /* @__PURE__ */ jsx(ErrorMessage, { label: t("wms.backend.location.errors.load", "Failed to load location view.") }) : null,
765
+ !isLoading && !hasError && locationQuery.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
766
+ /* @__PURE__ */ jsxs("section", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5", children: [
767
+ /* @__PURE__ */ jsx(
768
+ LocationKpiCard,
769
+ {
770
+ title: t("wms.backend.location.kpis.skusOccupied.title", "SKUs occupied"),
771
+ caption: t("wms.backend.location.kpis.skusOccupied.caption", "Distinct variants with stock"),
772
+ value: String(totals.skuCount),
773
+ badgeLabel: totals.skuCount > 0 ? t("wms.backend.location.kpis.skusOccupied.badge", "{count} active", { count: totals.skuCount }) : null,
774
+ badgeVariant: "info",
775
+ ctaLabel: t("wms.backend.location.kpis.skusOccupied.cta", "View items"),
776
+ ctaHref: "#location-items"
777
+ }
778
+ ),
779
+ /* @__PURE__ */ jsx(
780
+ LocationKpiCard,
781
+ {
782
+ title: t("wms.backend.location.kpis.capacityUsed.title", "Capacity used"),
783
+ caption: t("wms.backend.location.kpis.capacityUsed.caption", "On hand vs location capacity"),
784
+ value: capacityUsedPercent === null ? "\u2014" : `${capacityUsedPercent}%`,
785
+ badgeLabel: capacityUsedPercent !== null && capacityUsedPercent >= 80 ? t("wms.backend.location.kpis.capacityUsed.badgeHigh", "Near limit") : capacityUsedPercent !== null ? t("wms.backend.location.kpis.capacityUsed.badgeOk", "Within capacity") : null,
786
+ badgeVariant: capacityUsedPercent !== null && capacityUsedPercent >= 80 ? "warning" : "success",
787
+ ctaLabel: t("wms.backend.location.kpis.capacityUsed.cta", "Edit location"),
788
+ onCtaClick: access.canManageLocations ? () => setEditOpen(true) : void 0,
789
+ progress: capacityUsedPercent
790
+ }
791
+ ),
792
+ /* @__PURE__ */ jsx(
793
+ LocationKpiCard,
794
+ {
795
+ title: t("wms.backend.location.kpis.activeLots.title", "Active lots"),
796
+ caption: t("wms.backend.location.kpis.activeLots.caption", "Lots with on-hand quantity"),
797
+ value: String(totals.lotCount),
798
+ badgeLabel: totals.lotCount > 0 ? t("wms.backend.location.kpis.activeLots.badge", "{count} lots", { count: totals.lotCount }) : null,
799
+ badgeVariant: "neutral",
800
+ ctaLabel: t("wms.backend.location.kpis.activeLots.cta", "View items"),
801
+ ctaHref: "#location-items"
802
+ }
803
+ ),
804
+ /* @__PURE__ */ jsx(
805
+ LocationKpiCard,
806
+ {
807
+ title: t("wms.backend.location.kpis.pendingPicks.title", "Pending picks"),
808
+ caption: t("wms.backend.location.kpis.pendingPicks.caption", "Reserved and allocated units"),
809
+ value: String(totals.pendingPicks),
810
+ badgeLabel: totals.pendingPicks > 0 ? t("wms.backend.location.kpis.pendingPicks.badge", "{count} units", { count: totals.pendingPicks }) : null,
811
+ badgeVariant: "info",
812
+ ctaLabel: t("wms.backend.location.kpis.pendingPicks.cta", "View reservations"),
813
+ ctaHref: "/backend/wms/reservations"
814
+ }
815
+ ),
816
+ /* @__PURE__ */ jsx(
817
+ LocationKpiCard,
818
+ {
819
+ title: t("wms.backend.location.kpis.lastCounted.title", "Last counted"),
820
+ caption: t("wms.backend.location.kpis.lastCounted.caption", "Most recent cycle count"),
821
+ value: lastCounted?.label ?? "\u2014",
822
+ badgeLabel: lastCounted && nowMs - lastCounted.ts > 14 * 24 * 60 * 60 * 1e3 ? t("wms.backend.location.kpis.lastCounted.badgeStale", "Due soon") : lastCounted ? t("wms.backend.location.kpis.lastCounted.badgeRecent", "Recent") : t("wms.backend.location.kpis.lastCounted.badgeNever", "Never"),
823
+ badgeVariant: !lastCounted || nowMs - (lastCounted?.ts ?? 0) > 14 * 24 * 60 * 60 * 1e3 ? "warning" : "success",
824
+ ctaLabel: t("wms.backend.location.kpis.lastCounted.cta", "Start cycle count"),
825
+ ctaHref: "#location-items"
826
+ }
827
+ )
828
+ ] }),
829
+ /* @__PURE__ */ jsxs(
830
+ "section",
831
+ {
832
+ id: "location-items",
833
+ className: "rounded-lg border bg-card text-card-foreground shadow-sm",
834
+ children: [
835
+ /* @__PURE__ */ jsx("div", { className: "border-b px-5 py-4", children: /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: t("wms.backend.location.items.title", "Items in this location") }) }),
836
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 border-b px-5 py-3 lg:flex-row lg:items-center lg:justify-between", children: [
837
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: filterChips.map((chip) => /* @__PURE__ */ jsx(
838
+ Button,
839
+ {
840
+ type: "button",
841
+ size: "sm",
842
+ variant: itemFilter === chip.id ? "default" : "outline",
843
+ className: cn("rounded-full", itemFilter === chip.id && "shadow-sm"),
844
+ onClick: () => setItemFilter(chip.id),
845
+ children: chip.label
846
+ },
847
+ chip.id
848
+ )) }),
849
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
850
+ /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", onClick: handleExportItemsCsv, children: [
851
+ /* @__PURE__ */ jsx(Download, { className: "size-4" }),
852
+ t("wms.backend.location.items.actions.exportCsv", "Export CSV")
853
+ ] }),
854
+ access.canCycleCount ? /* @__PURE__ */ jsx(
855
+ Button,
856
+ {
857
+ type: "button",
858
+ variant: "outline",
859
+ onClick: () => openCycleCountDialog({
860
+ warehouseId: warehouseId || void 0,
861
+ locationId: scopedLocationId
862
+ }),
863
+ children: t("wms.backend.location.items.actions.cycleCountZone", "Cycle count zone")
864
+ }
865
+ ) : null,
866
+ access.canAdjust && selectedBalances.length > 0 ? /* @__PURE__ */ jsx(
867
+ Button,
868
+ {
869
+ type: "button",
870
+ variant: "default",
871
+ onClick: () => openAdjustDialog(resolveMutationContext()),
872
+ children: t("wms.backend.location.items.actions.adjustSelected", "Adjust selected ({count})", { count: selectedBalances.length })
873
+ }
874
+ ) : null
875
+ ] })
876
+ ] }),
877
+ /* @__PURE__ */ jsx(
878
+ DataTable,
879
+ {
880
+ embedded: true,
881
+ columns: itemColumns,
882
+ data: pagedBalances,
883
+ disableRowClick: true,
884
+ entityId: E.wms.inventory_balance,
885
+ perspective: { tableId: "wms.location.items" },
886
+ pagination: {
887
+ page: itemsPage,
888
+ pageSize: itemsPageSize,
889
+ total: itemsTotal,
890
+ totalPages: itemsTotalPages,
891
+ onPageChange: setItemsPage
892
+ },
893
+ emptyState: /* @__PURE__ */ jsx(
894
+ EmptyState,
895
+ {
896
+ title: t("wms.backend.location.items.empty.title", "No items in this view"),
897
+ description: t(
898
+ "wms.backend.location.items.empty.description",
899
+ "Try another filter or post inventory through receipts or adjustments."
900
+ )
901
+ }
902
+ )
903
+ }
904
+ ),
905
+ itemsTotal > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t px-5 py-3 text-sm text-muted-foreground sm:flex-row sm:items-center sm:justify-between", children: [
906
+ /* @__PURE__ */ jsx("span", { children: t("wms.backend.location.items.footer.showing", "Showing {shown} of {total} items", {
907
+ shown: pagedBalances.length,
908
+ total: itemsTotal
909
+ }) }),
910
+ balancesQuery.data && balancesQuery.data.total > itemsTotal ? /* @__PURE__ */ jsx(LinkButton, { asChild: true, variant: "gray", size: "sm", className: "h-auto px-0", children: /* @__PURE__ */ jsx(Link, { href: inventoryConsoleHref, children: t("wms.backend.location.items.footer.viewAll", "View all items \u2192") }) }) : null
911
+ ] }) : null
912
+ ]
913
+ }
914
+ ),
915
+ /* @__PURE__ */ jsx(
916
+ DataTable,
917
+ {
918
+ title: t("wms.backend.location.activity.title", "Recent activity"),
919
+ columns: activityColumns,
920
+ data: movementsQuery.data ?? [],
921
+ disableRowClick: true,
922
+ entityId: E.wms.inventory_movement,
923
+ perspective: { tableId: "wms.location.activity" },
924
+ emptyState: t("wms.backend.location.activity.empty", "No recent movements for this location."),
925
+ actions: /* @__PURE__ */ jsx(Button, { asChild: true, type: "button", variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(Link, { href: movementsHref, children: t("wms.backend.location.activity.viewAll", "View all movements \u2192") }) })
926
+ }
927
+ ),
928
+ /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-4 rounded-lg border bg-card px-5 py-4 shadow-sm lg:flex-row lg:items-center lg:justify-between", children: [
929
+ /* @__PURE__ */ jsxs("div", { children: [
930
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: t("wms.backend.location.quickActions.title", "Quick actions") }),
931
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t(
932
+ "wms.backend.location.quickActions.description",
933
+ "Run common inventory actions without leaving this location view"
934
+ ) })
935
+ ] }),
936
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
937
+ access.canAdjust ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "default", onClick: () => openAdjustDialog(resolveMutationContext()), children: [
938
+ /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-4" }),
939
+ t("wms.backend.location.quickActions.adjust", "Adjust inventory")
940
+ ] }) : null,
941
+ access.canAdjust ? /* @__PURE__ */ jsx(Button, { asChild: true, type: "button", variant: "outline", children: /* @__PURE__ */ jsxs(Link, { href: inventoryConsoleHref, children: [
942
+ /* @__PURE__ */ jsx(ArrowLeftRight, { className: "size-4" }),
943
+ t("wms.backend.location.quickActions.move", "Move stock")
944
+ ] }) }) : null,
945
+ access.canCycleCount ? /* @__PURE__ */ jsxs(
946
+ Button,
947
+ {
948
+ type: "button",
949
+ variant: "outline",
950
+ onClick: () => openCycleCountDialog({
951
+ warehouseId: warehouseId || void 0,
952
+ locationId: scopedLocationId
953
+ }),
954
+ children: [
955
+ /* @__PURE__ */ jsx(ClipboardList, { className: "size-4" }),
956
+ t("wms.backend.location.quickActions.cycleCount", "Cycle count")
957
+ ]
958
+ }
959
+ ) : null,
960
+ /* @__PURE__ */ jsx(Button, { asChild: true, type: "button", variant: "outline", children: /* @__PURE__ */ jsxs(Link, { href: movementsHref, children: [
961
+ t("wms.backend.location.quickActions.openLedger", "Open ledger"),
962
+ /* @__PURE__ */ jsx(ExternalLink, { className: "size-4" })
963
+ ] }) })
964
+ ] })
965
+ ] })
966
+ ] }) : null,
967
+ !isLoading && !hasError && !locationQuery.data ? /* @__PURE__ */ jsx(
968
+ RecordNotFoundState,
969
+ {
970
+ label: t("wms.backend.location.errors.notFound", "Location not found."),
971
+ backHref: locationsHref,
972
+ backLabel: t("wms.backend.location.actions.backToLocations", "Back to locations")
973
+ }
974
+ ) : null
975
+ ] }),
976
+ access.canAdjust && scopedLocationId ? /* @__PURE__ */ jsx(
977
+ AdjustInventoryDialog,
978
+ {
979
+ open: adjustOpen,
980
+ onOpenChange: setAdjustOpen,
981
+ access,
982
+ initialWarehouseId: adjustPreset.warehouseId ?? warehouseId,
983
+ initialLocationId: adjustPreset.locationId ?? scopedLocationId,
984
+ initialCatalogVariantId: adjustPreset.catalogVariantId,
985
+ initialLotId: adjustPreset.lotId
986
+ }
987
+ ) : null,
988
+ access.canCycleCount ? /* @__PURE__ */ jsx(
989
+ CycleCountWizardDialog,
990
+ {
991
+ open: cycleOpen,
992
+ onOpenChange: setCycleOpen,
993
+ access,
994
+ initialWarehouseId: cyclePreset.warehouseId ?? warehouseId,
995
+ initialLocationId: cyclePreset.locationId ?? scopedLocationId ?? void 0
996
+ }
997
+ ) : null,
998
+ access.canManageLocations && locationQuery.data ? /* @__PURE__ */ jsx(
999
+ LocationEditDialog,
1000
+ {
1001
+ open: editOpen,
1002
+ onOpenChange: setEditOpen,
1003
+ mode: "edit",
1004
+ row: locationQuery.data,
1005
+ onSaved: async () => {
1006
+ await locationQuery.refetch();
1007
+ }
1008
+ }
1009
+ ) : null
1010
+ ] });
1011
+ }
1012
+ export {
1013
+ WmsLocationDetailPage as default
1014
+ };
1015
+ //# sourceMappingURL=WmsLocationDetailPage.js.map