@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,1049 @@
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 {
27
+ Select,
28
+ SelectContent,
29
+ SelectItem,
30
+ SelectTrigger,
31
+ SelectValue
32
+ } from "@open-mercato/ui/primitives/select";
33
+ import { StatusBadge } from "@open-mercato/ui/primitives/status-badge";
34
+ import { Checkbox } from "@open-mercato/ui/primitives/checkbox";
35
+ import { cn } from "@open-mercato/shared/lib/utils";
36
+ import { E } from "../../../../generated/entities.ids.generated.js";
37
+ import {
38
+ inventoryMovementReasonLabel
39
+ } from "../../lib/inventoryDisplayUi.js";
40
+ import { AdjustInventoryDialog } from "./AdjustInventoryDialog.js";
41
+ import { ChangeLotStatusDialog } from "./ChangeLotStatusDialog.js";
42
+ import { CycleCountWizardDialog } from "./CycleCountWizardDialog.js";
43
+ import { useWmsInventoryMutationAccess } from "./useWmsInventoryMutationAccess.js";
44
+ const lotIdSchema = z.string().uuid();
45
+ function extractLotStatusNotes(metadata) {
46
+ if (!metadata || typeof metadata !== "object") return null;
47
+ const notes = metadata.notes;
48
+ return typeof notes === "string" && notes.trim().length > 0 ? notes.trim() : null;
49
+ }
50
+ const NON_SELLABLE_LOCATION_TYPES = /* @__PURE__ */ new Set(["staging", "dock"]);
51
+ const PICKING_LOCATION_TYPES = /* @__PURE__ */ new Set(["staging", "bin", "slot"]);
52
+ const NEAR_EXPIRY_MS = 30 * 24 * 60 * 60 * 1e3;
53
+ const MS_PER_DAY = 24 * 60 * 60 * 1e3;
54
+ function escapeCsvCell(value) {
55
+ const str = String(value ?? "");
56
+ if (/[",\n]/.test(str)) return `"${str.replace(/"/g, '""')}"`;
57
+ return str;
58
+ }
59
+ function downloadCsvFile(filename, rows) {
60
+ const csv = rows.map((row) => row.map(escapeCsvCell).join(",")).join("\n");
61
+ const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
62
+ const url = URL.createObjectURL(blob);
63
+ const anchor = document.createElement("a");
64
+ anchor.href = url;
65
+ anchor.download = filename;
66
+ anchor.click();
67
+ URL.revokeObjectURL(url);
68
+ }
69
+ function toNumber(value) {
70
+ const parsed = Number(value ?? 0);
71
+ return Number.isFinite(parsed) ? parsed : 0;
72
+ }
73
+ function formatWarehouseLabel(row) {
74
+ const code = (row.warehouse_code ?? "").trim();
75
+ const name = (row.warehouse_name ?? "").trim();
76
+ if (code && name) return `${code} \xB7 ${name}`;
77
+ return name || code || row.warehouse_id || "\u2014";
78
+ }
79
+ function formatLocationLabel(code, id) {
80
+ const trimmed = (code ?? "").trim();
81
+ if (trimmed) return trimmed;
82
+ return id || "\u2014";
83
+ }
84
+ function balanceLocationKey(row) {
85
+ return `${row.warehouse_id?.trim() ?? ""}:${row.location_id?.trim() ?? ""}`;
86
+ }
87
+ function movementLocationKey(warehouseId, locationId) {
88
+ return `${warehouseId?.trim() ?? ""}:${locationId?.trim() ?? ""}`;
89
+ }
90
+ function isNearExpiry(expiresAt, nowMs) {
91
+ if (!expiresAt) return false;
92
+ const expires = new Date(expiresAt).getTime();
93
+ if (Number.isNaN(expires)) return false;
94
+ return expires > nowMs && expires - nowMs <= NEAR_EXPIRY_MS;
95
+ }
96
+ function isExpired(expiresAt, nowMs) {
97
+ if (!expiresAt) return false;
98
+ const expires = new Date(expiresAt).getTime();
99
+ return !Number.isNaN(expires) && expires <= nowMs;
100
+ }
101
+ function daysUntilExpiry(expiresAt, nowMs) {
102
+ if (!expiresAt) return null;
103
+ const expires = new Date(expiresAt).getTime();
104
+ if (Number.isNaN(expires)) return null;
105
+ return Math.ceil((expires - nowMs) / MS_PER_DAY);
106
+ }
107
+ function daysSince(value, nowMs) {
108
+ if (!value) return null;
109
+ const ts = new Date(value).getTime();
110
+ if (Number.isNaN(ts)) return null;
111
+ return Math.max(0, Math.floor((nowMs - ts) / MS_PER_DAY));
112
+ }
113
+ function resolveLotQualityStatus(status, expiresAt, nowMs) {
114
+ if (status === "expired" || isExpired(expiresAt, nowMs)) {
115
+ return {
116
+ variant: "error",
117
+ labelKey: "wms.backend.lot.status.expired",
118
+ labelFallback: "Expired",
119
+ value: "Expired"
120
+ };
121
+ }
122
+ if (status === "quarantine") {
123
+ return {
124
+ variant: "warning",
125
+ labelKey: "wms.backend.lot.status.quarantine",
126
+ labelFallback: "Quarantine",
127
+ value: "QC"
128
+ };
129
+ }
130
+ if (status === "hold") {
131
+ return {
132
+ variant: "warning",
133
+ labelKey: "wms.backend.lot.status.hold",
134
+ labelFallback: "Hold",
135
+ value: "Hold"
136
+ };
137
+ }
138
+ if (isNearExpiry(expiresAt, nowMs)) {
139
+ return {
140
+ variant: "warning",
141
+ labelKey: "wms.backend.lot.status.nearExpiry",
142
+ labelFallback: "Near expiry",
143
+ value: "Near expiry"
144
+ };
145
+ }
146
+ return {
147
+ variant: "success",
148
+ labelKey: "wms.backend.lot.status.available",
149
+ labelFallback: "Available",
150
+ value: "OK"
151
+ };
152
+ }
153
+ function resolveBalanceStatus(row, lot, reorderPoint, nowMs) {
154
+ if (lot?.status === "expired" || isExpired(lot?.expires_at, nowMs)) {
155
+ return {
156
+ variant: "error",
157
+ labelKey: "wms.backend.lot.distribution.status.expired",
158
+ labelFallback: "Expired"
159
+ };
160
+ }
161
+ if (isNearExpiry(lot?.expires_at, nowMs)) {
162
+ return {
163
+ variant: "warning",
164
+ labelKey: "wms.backend.lot.distribution.status.nearExpiry",
165
+ labelFallback: "Near expiry"
166
+ };
167
+ }
168
+ const available = row.quantity_available ?? 0;
169
+ if (reorderPoint > 0 && available <= reorderPoint) {
170
+ return {
171
+ variant: "warning",
172
+ labelKey: "wms.backend.lot.distribution.status.lowStock",
173
+ labelFallback: "Low stock"
174
+ };
175
+ }
176
+ const reserved = toNumber(row.quantity_reserved);
177
+ const onHand = toNumber(row.quantity_on_hand);
178
+ if (reserved > 0 && onHand > 0 && reserved >= onHand) {
179
+ return {
180
+ variant: "info",
181
+ labelKey: "wms.backend.lot.distribution.status.reserved",
182
+ labelFallback: "Reserved"
183
+ };
184
+ }
185
+ return {
186
+ variant: "success",
187
+ labelKey: "wms.backend.lot.distribution.status.available",
188
+ labelFallback: "Available"
189
+ };
190
+ }
191
+ function matchesDistributionFilter(row, lot, filter, nowMs) {
192
+ const locationType = (row.location_type ?? "").trim().toLowerCase();
193
+ const locationCode = (row.location_code ?? "").trim().toLowerCase();
194
+ switch (filter) {
195
+ case "all":
196
+ return true;
197
+ case "sellable":
198
+ return !NON_SELLABLE_LOCATION_TYPES.has(locationType) && lot?.status !== "expired";
199
+ case "picking":
200
+ return PICKING_LOCATION_TYPES.has(locationType) || locationCode.includes("pick") || locationCode.includes("staging") || toNumber(row.quantity_reserved) > 0 || toNumber(row.quantity_allocated) > 0;
201
+ case "nearExpiry":
202
+ return isNearExpiry(lot?.expires_at, nowMs) || lot?.status === "expired";
203
+ default:
204
+ return true;
205
+ }
206
+ }
207
+ function movementTypeLabel(type, t) {
208
+ const key = `wms.backend.lot.activity.types.${type}`;
209
+ const fallbacks = {
210
+ receipt: "Receive",
211
+ return_receive: "Receive",
212
+ adjust: "Adjust",
213
+ transfer: "Move",
214
+ pick: "Allocate",
215
+ pack: "Allocate",
216
+ cycle_count: "Reconcile",
217
+ putaway: "Putaway",
218
+ ship: "Ship"
219
+ };
220
+ return t(key, fallbacks[type] ?? type);
221
+ }
222
+ const movementStatusMap = {
223
+ receipt: "success",
224
+ return_receive: "success",
225
+ adjust: "warning",
226
+ transfer: "info",
227
+ pick: "info",
228
+ pack: "info",
229
+ cycle_count: "neutral",
230
+ putaway: "info",
231
+ ship: "success"
232
+ };
233
+ function formatMovementTitle(row, lotLabel, t) {
234
+ const quantity = Math.abs(toNumber(row.quantity));
235
+ const signedQuantity = toNumber(row.quantity);
236
+ switch (row.type) {
237
+ case "receipt":
238
+ case "return_receive":
239
+ return t("wms.backend.lot.activity.titles.received", "Received {quantity}\xD7 {lot}", {
240
+ quantity,
241
+ lot: lotLabel
242
+ });
243
+ case "adjust":
244
+ return t("wms.backend.lot.activity.titles.adjusted", "Adjusted {quantity}\xD7 {lot}", {
245
+ quantity: `${signedQuantity >= 0 ? "+" : ""}${signedQuantity}`,
246
+ lot: lotLabel
247
+ });
248
+ case "transfer":
249
+ return t("wms.backend.lot.activity.titles.moved", "Moved {quantity}\xD7 {lot}", {
250
+ quantity,
251
+ lot: lotLabel
252
+ });
253
+ case "pick":
254
+ case "pack":
255
+ return t("wms.backend.lot.activity.titles.allocated", "Allocated {quantity}\xD7 {lot}", {
256
+ quantity,
257
+ lot: lotLabel
258
+ });
259
+ case "cycle_count":
260
+ return t("wms.backend.lot.activity.titles.reconciled", "Cycle count of {lot}", {
261
+ lot: lotLabel
262
+ });
263
+ default:
264
+ return t("wms.backend.lot.activity.titles.generic", "{type} {quantity}\xD7 {lot}", {
265
+ type: row.type ?? "movement",
266
+ quantity,
267
+ lot: lotLabel
268
+ });
269
+ }
270
+ }
271
+ function formatMovementSubtitle(row, t) {
272
+ const reasonLabel = inventoryMovementReasonLabel(
273
+ {
274
+ reasonCode: row.reason_code,
275
+ reason: row.reason,
276
+ movementType: row.type
277
+ },
278
+ t
279
+ );
280
+ if (reasonLabel) return reasonLabel;
281
+ if (row.reference_type && row.reference_id) return `${row.reference_type} \xB7 ${row.reference_id}`;
282
+ return null;
283
+ }
284
+ function formatMovementLocation(row) {
285
+ const warehouse = formatWarehouseLabel(row);
286
+ const from = formatLocationLabel(row.location_from_code, row.location_from_id);
287
+ const to = formatLocationLabel(row.location_to_code, row.location_to_id);
288
+ if (row.type === "transfer" && from !== "\u2014" && to !== "\u2014") return `${from} \u2192 ${to}`;
289
+ const location = to !== "\u2014" ? to : from;
290
+ if (location !== "\u2014") return `${warehouse} \xB7 ${location}`;
291
+ return warehouse;
292
+ }
293
+ function formatLastMoveLabel(raw, locale, t) {
294
+ if (!raw) return "\u2014";
295
+ const date = new Date(raw);
296
+ if (Number.isNaN(date.getTime())) return raw;
297
+ const diffDays = Math.floor((Date.now() - date.getTime()) / MS_PER_DAY);
298
+ if (diffDays === 0) {
299
+ return t("wms.backend.lot.distribution.lastMove.today", "{time} today", {
300
+ time: new Intl.DateTimeFormat(locale, { hour: "2-digit", minute: "2-digit" }).format(date)
301
+ });
302
+ }
303
+ if (diffDays === 1) {
304
+ return t("wms.backend.lot.distribution.lastMove.yesterday", "Yesterday");
305
+ }
306
+ if (diffDays < 7) {
307
+ return t("wms.backend.lot.distribution.lastMove.daysAgo", "{days} days ago", { days: diffDays });
308
+ }
309
+ return new Intl.DateTimeFormat(locale, { month: "2-digit", day: "2-digit" }).format(date);
310
+ }
311
+ function LotKpiCard({
312
+ title,
313
+ caption,
314
+ value,
315
+ badgeLabel,
316
+ badgeVariant,
317
+ ctaLabel,
318
+ ctaHref,
319
+ onCtaClick
320
+ }) {
321
+ return /* @__PURE__ */ jsxs("section", { className: "flex min-h-52 flex-col rounded-lg border bg-card p-5 text-card-foreground shadow-sm", children: [
322
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: title }),
323
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-xs text-muted-foreground", children: caption }),
324
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-end gap-3", children: [
325
+ /* @__PURE__ */ jsx("p", { className: "text-3xl font-semibold tracking-tight", children: value }),
326
+ badgeLabel ? /* @__PURE__ */ jsx(StatusBadge, { variant: badgeVariant, dot: true, children: badgeLabel }) : null
327
+ ] }),
328
+ 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
329
+ ] });
330
+ }
331
+ function WmsLotDetailPage({ lotId }) {
332
+ const t = useT();
333
+ const locale = useLocale();
334
+ const router = useRouter();
335
+ const access = useWmsInventoryMutationAccess();
336
+ const parsedLotId = lotIdSchema.safeParse(lotId.trim());
337
+ const scopedLotId = parsedLotId.success ? parsedLotId.data : null;
338
+ const [warehouseId, setWarehouseId] = React.useState("all");
339
+ const [distributionFilter, setDistributionFilter] = React.useState("all");
340
+ const [distributionPage, setDistributionPage] = React.useState(1);
341
+ const [selectedBalanceIds, setSelectedBalanceIds] = React.useState(() => /* @__PURE__ */ new Set());
342
+ const [adjustOpen, setAdjustOpen] = React.useState(false);
343
+ const [adjustPreset, setAdjustPreset] = React.useState({});
344
+ const [cycleOpen, setCycleOpen] = React.useState(false);
345
+ const [cyclePreset, setCyclePreset] = React.useState({});
346
+ const [changeStatusOpen, setChangeStatusOpen] = React.useState(false);
347
+ const distributionPageSize = 20;
348
+ const lotsHref = "/backend/wms/lots";
349
+ const inventoryHref = "/backend/wms/inventory";
350
+ const activityTimeFormatter = React.useMemo(
351
+ () => new Intl.DateTimeFormat(locale, {
352
+ month: "2-digit",
353
+ day: "2-digit",
354
+ hour: "2-digit",
355
+ minute: "2-digit"
356
+ }),
357
+ [locale]
358
+ );
359
+ const lotQuery = useQuery({
360
+ queryKey: ["wms-lot-detail", "lot", scopedLotId],
361
+ enabled: Boolean(scopedLotId),
362
+ queryFn: async () => {
363
+ const params = new URLSearchParams({
364
+ ids: scopedLotId,
365
+ page: "1",
366
+ pageSize: "1"
367
+ });
368
+ const call = await apiCall(`/api/wms/lots?${params.toString()}`);
369
+ if (!call.ok) {
370
+ await raiseCrudError(call.response, t("wms.backend.lot.errors.lot", "Failed to load lot."));
371
+ }
372
+ return call.result?.items?.[0] ?? null;
373
+ }
374
+ });
375
+ const catalogVariantId = lotQuery.data?.catalog_variant_id?.trim() ?? null;
376
+ const variantQuery = useQuery({
377
+ queryKey: ["wms-lot-detail", "variant", catalogVariantId],
378
+ enabled: Boolean(catalogVariantId),
379
+ queryFn: async () => {
380
+ const params = new URLSearchParams({
381
+ id: catalogVariantId,
382
+ page: "1",
383
+ pageSize: "1"
384
+ });
385
+ const call = await apiCall(
386
+ `/api/catalog/variants?${params.toString()}`
387
+ );
388
+ if (!call.ok) {
389
+ await raiseCrudError(call.response, t("wms.backend.lot.errors.variant", "Failed to load SKU."));
390
+ }
391
+ return call.result?.items?.[0] ?? null;
392
+ }
393
+ });
394
+ const profileQuery = useQuery({
395
+ queryKey: ["wms-lot-detail", "profile", catalogVariantId],
396
+ enabled: Boolean(catalogVariantId),
397
+ queryFn: async () => {
398
+ const params = new URLSearchParams({
399
+ catalogVariantId,
400
+ page: "1",
401
+ pageSize: "1"
402
+ });
403
+ const call = await apiCall(
404
+ `/api/wms/inventory-profiles?${params.toString()}`
405
+ );
406
+ if (!call.ok) {
407
+ await raiseCrudError(call.response, t("wms.backend.lot.errors.profile", "Failed to load inventory profile."));
408
+ }
409
+ return call.result?.items?.[0] ?? null;
410
+ }
411
+ });
412
+ const warehousesQuery = useQuery({
413
+ queryKey: ["wms-lot-detail", "warehouses"],
414
+ queryFn: async () => {
415
+ const params = new URLSearchParams({ page: "1", pageSize: "100", sortField: "name", sortDir: "asc" });
416
+ const call = await apiCall(`/api/wms/warehouses?${params.toString()}`);
417
+ if (!call.ok) {
418
+ await raiseCrudError(call.response, t("wms.backend.lot.errors.warehouses", "Failed to load warehouses."));
419
+ }
420
+ return call.result?.items ?? [];
421
+ }
422
+ });
423
+ const balancesQuery = useQuery({
424
+ queryKey: ["wms-lot-detail", "balances", scopedLotId, warehouseId],
425
+ enabled: Boolean(scopedLotId),
426
+ queryFn: async () => {
427
+ const params = new URLSearchParams({
428
+ lotId: scopedLotId,
429
+ page: "1",
430
+ pageSize: "100",
431
+ sortField: "updatedAt",
432
+ sortDir: "desc"
433
+ });
434
+ if (warehouseId !== "all") params.set("warehouseId", warehouseId);
435
+ const call = await apiCall(
436
+ `/api/wms/inventory/balances?${params.toString()}`
437
+ );
438
+ if (!call.ok) {
439
+ await raiseCrudError(call.response, t("wms.backend.lot.errors.balances", "Failed to load lot locations."));
440
+ }
441
+ return call.result ?? { items: [], total: 0, totalPages: 1 };
442
+ }
443
+ });
444
+ const movementsQuery = useQuery({
445
+ queryKey: ["wms-lot-detail", "movements", scopedLotId, warehouseId],
446
+ enabled: Boolean(scopedLotId),
447
+ queryFn: async () => {
448
+ const params = new URLSearchParams({
449
+ lotId: scopedLotId,
450
+ page: "1",
451
+ pageSize: "25",
452
+ sortField: "performedAt",
453
+ sortDir: "desc"
454
+ });
455
+ if (warehouseId !== "all") params.set("warehouseId", warehouseId);
456
+ const call = await apiCall(
457
+ `/api/wms/inventory/movements?${params.toString()}`
458
+ );
459
+ if (!call.ok) {
460
+ await raiseCrudError(call.response, t("wms.backend.lot.errors.movements", "Failed to load recent activity."));
461
+ }
462
+ return call.result?.items ?? [];
463
+ }
464
+ });
465
+ const reorderPoint = toNumber(profileQuery.data?.reorder_point);
466
+ const lotData = lotQuery.data;
467
+ const lotLabel = (lotData?.lot_number ?? "").trim() || scopedLotId || "\u2014";
468
+ const skuLabel = (lotData?.sku ?? "").trim() || (variantQuery.data?.sku ?? "").trim() || catalogVariantId || "\u2014";
469
+ const variantName = (variantQuery.data?.name ?? "").trim();
470
+ const pageTitle = lotLabel;
471
+ const nowMs = React.useMemo(() => Date.now(), []);
472
+ const qualityStatus = React.useMemo(
473
+ () => resolveLotQualityStatus(lotData?.status, lotData?.expires_at, nowMs),
474
+ [lotData?.expires_at, lotData?.status, nowMs]
475
+ );
476
+ const statusNotes = React.useMemo(
477
+ () => extractLotStatusNotes(lotData?.metadata),
478
+ [lotData?.metadata]
479
+ );
480
+ const daysToExpiry = daysUntilExpiry(lotData?.expires_at, nowMs);
481
+ const lotAgeDays = daysSince(lotData?.created_at, nowMs);
482
+ const totals = React.useMemo(() => {
483
+ const items = balancesQuery.data?.items ?? [];
484
+ let onHand = 0;
485
+ let reserved = 0;
486
+ let available = 0;
487
+ for (const row of items) {
488
+ onHand += toNumber(row.quantity_on_hand);
489
+ reserved += toNumber(row.quantity_reserved);
490
+ available += row.quantity_available ?? 0;
491
+ }
492
+ return { onHand, reserved, available };
493
+ }, [balancesQuery.data?.items]);
494
+ const lastMoveByLocation = React.useMemo(() => {
495
+ const map = /* @__PURE__ */ new Map();
496
+ for (const row of movementsQuery.data ?? []) {
497
+ const raw = row.performed_at ?? row.received_at;
498
+ if (!raw) continue;
499
+ const keys = [
500
+ movementLocationKey(row.warehouse_id, row.location_to_id),
501
+ movementLocationKey(row.warehouse_id, row.location_from_id)
502
+ ];
503
+ for (const key of keys) {
504
+ if (!key || key === ":") continue;
505
+ const existing = map.get(key);
506
+ if (!existing || new Date(raw).getTime() > new Date(existing).getTime()) {
507
+ map.set(key, raw);
508
+ }
509
+ }
510
+ }
511
+ return map;
512
+ }, [movementsQuery.data]);
513
+ const filteredBalances = React.useMemo(() => {
514
+ const items = balancesQuery.data?.items ?? [];
515
+ return items.filter((row) => matchesDistributionFilter(row, lotData, distributionFilter, nowMs));
516
+ }, [balancesQuery.data?.items, distributionFilter, lotData, nowMs]);
517
+ const distributionTotal = filteredBalances.length;
518
+ const distributionTotalPages = Math.max(1, Math.ceil(distributionTotal / distributionPageSize));
519
+ const pagedBalances = React.useMemo(() => {
520
+ const start = (distributionPage - 1) * distributionPageSize;
521
+ return filteredBalances.slice(start, start + distributionPageSize);
522
+ }, [distributionPage, distributionPageSize, filteredBalances]);
523
+ React.useEffect(() => {
524
+ setDistributionPage(1);
525
+ setSelectedBalanceIds(/* @__PURE__ */ new Set());
526
+ }, [distributionFilter, warehouseId]);
527
+ const selectedBalances = React.useMemo(
528
+ () => filteredBalances.filter((row) => selectedBalanceIds.has(row.id)),
529
+ [filteredBalances, selectedBalanceIds]
530
+ );
531
+ const movementsHref = React.useMemo(() => {
532
+ const params = new URLSearchParams();
533
+ if (scopedLotId) params.set("lotId", scopedLotId);
534
+ if (warehouseId !== "all") params.set("warehouseId", warehouseId);
535
+ const query = params.toString();
536
+ return query ? `/backend/wms/movements?${query}` : "/backend/wms/movements";
537
+ }, [scopedLotId, warehouseId]);
538
+ const inventoryConsoleHref = React.useMemo(() => {
539
+ if (!scopedLotId) return inventoryHref;
540
+ return `${inventoryHref}?lotId=${encodeURIComponent(scopedLotId)}`;
541
+ }, [scopedLotId]);
542
+ const skuDetailHref = catalogVariantId ? `/backend/wms/sku/${encodeURIComponent(catalogVariantId)}` : inventoryHref;
543
+ const openAdjustDialog = React.useCallback((preset = {}) => {
544
+ setAdjustPreset(preset);
545
+ setAdjustOpen(true);
546
+ }, []);
547
+ const openCycleCountDialog = React.useCallback(
548
+ (preset = {}) => {
549
+ setCyclePreset(preset);
550
+ setCycleOpen(true);
551
+ },
552
+ []
553
+ );
554
+ const resolveMutationContext = React.useCallback(() => {
555
+ const firstSelected = selectedBalances[0];
556
+ const scopedWarehouseId = firstSelected?.warehouse_id?.trim() || (warehouseId !== "all" ? warehouseId : void 0);
557
+ const locationId = selectedBalances.length === 1 ? firstSelected?.location_id?.trim() || void 0 : void 0;
558
+ return {
559
+ warehouseId: scopedWarehouseId,
560
+ locationId,
561
+ catalogVariantId: catalogVariantId ?? void 0,
562
+ lotId: scopedLotId ?? void 0
563
+ };
564
+ }, [catalogVariantId, scopedLotId, selectedBalances, warehouseId]);
565
+ const toggleBalanceSelection = React.useCallback((balanceId, selected) => {
566
+ setSelectedBalanceIds((current) => {
567
+ const next = new Set(current);
568
+ if (selected) next.add(balanceId);
569
+ else next.delete(balanceId);
570
+ return next;
571
+ });
572
+ }, []);
573
+ const togglePageSelection = React.useCallback((selected) => {
574
+ setSelectedBalanceIds((current) => {
575
+ const next = new Set(current);
576
+ for (const row of pagedBalances) {
577
+ if (selected) next.add(row.id);
578
+ else next.delete(row.id);
579
+ }
580
+ return next;
581
+ });
582
+ }, [pagedBalances]);
583
+ const pageSelectionState = React.useMemo(() => {
584
+ if (pagedBalances.length === 0) {
585
+ return { checked: false, indeterminate: false };
586
+ }
587
+ const selectedOnPage = pagedBalances.filter((row) => selectedBalanceIds.has(row.id)).length;
588
+ return {
589
+ checked: selectedOnPage === pagedBalances.length,
590
+ indeterminate: selectedOnPage > 0 && selectedOnPage < pagedBalances.length
591
+ };
592
+ }, [pagedBalances, selectedBalanceIds]);
593
+ const handleExportDistributionCsv = React.useCallback(() => {
594
+ const headers = [
595
+ t("wms.backend.lot.distribution.columns.warehouse", "Warehouse"),
596
+ t("wms.backend.lot.distribution.columns.location", "Location"),
597
+ t("wms.backend.lot.distribution.columns.lastMove", "Last move"),
598
+ t("wms.backend.lot.distribution.columns.onHand", "On hand"),
599
+ t("wms.backend.lot.distribution.columns.reserved", "Reserved"),
600
+ t("wms.backend.lot.distribution.columns.status", "Status")
601
+ ];
602
+ const rows = filteredBalances.map((row) => {
603
+ const status = resolveBalanceStatus(row, lotData, reorderPoint, nowMs);
604
+ return [
605
+ formatWarehouseLabel(row),
606
+ formatLocationLabel(row.location_code, row.location_id),
607
+ formatLastMoveLabel(lastMoveByLocation.get(balanceLocationKey(row)), locale, t),
608
+ String(toNumber(row.quantity_on_hand)),
609
+ String(toNumber(row.quantity_reserved)),
610
+ t(status.labelKey, status.labelFallback)
611
+ ];
612
+ });
613
+ const safeLot = pageTitle.replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "") || "lot";
614
+ downloadCsvFile(`${safeLot}-locations.csv`, [headers, ...rows]);
615
+ }, [filteredBalances, lastMoveByLocation, locale, lotData, nowMs, pageTitle, reorderPoint, t]);
616
+ const selectedWarehouse = warehousesQuery.data?.find((warehouse) => warehouse.id === warehouseId);
617
+ const warehouseLabel = warehouseId === "all" ? t("wms.backend.lot.filters.allWarehouses", "All warehouses") : selectedWarehouse?.name || selectedWarehouse?.code || warehouseId;
618
+ const dateFormatter = React.useMemo(
619
+ () => new Intl.DateTimeFormat(locale, { year: "numeric", month: "2-digit", day: "2-digit" }),
620
+ [locale]
621
+ );
622
+ const subtitleParts = [
623
+ skuLabel !== "\u2014" ? skuLabel : null,
624
+ variantName || null,
625
+ lotData?.expires_at ? t("wms.backend.lot.header.expires", "Exp {date}", {
626
+ date: dateFormatter.format(new Date(lotData.expires_at))
627
+ }) : null
628
+ ].filter(Boolean);
629
+ const distributionColumns = React.useMemo(
630
+ () => [
631
+ {
632
+ id: "select",
633
+ header: () => /* @__PURE__ */ jsx(
634
+ Checkbox,
635
+ {
636
+ "aria-label": t("wms.backend.lot.distribution.columns.select", "Select"),
637
+ checked: pageSelectionState.indeterminate ? "indeterminate" : pageSelectionState.checked,
638
+ onCheckedChange: (checked) => togglePageSelection(checked === true)
639
+ }
640
+ ),
641
+ cell: ({ row }) => /* @__PURE__ */ jsx(
642
+ Checkbox,
643
+ {
644
+ "aria-label": t("wms.backend.lot.distribution.columns.select", "Select"),
645
+ checked: selectedBalanceIds.has(row.original.id),
646
+ onCheckedChange: (checked) => toggleBalanceSelection(row.original.id, checked === true)
647
+ }
648
+ ),
649
+ meta: { maxWidth: "2.75rem" }
650
+ },
651
+ {
652
+ accessorKey: "warehouse_id",
653
+ header: t("wms.backend.lot.distribution.columns.warehouse", "Warehouse"),
654
+ cell: ({ row }) => formatWarehouseLabel(row.original)
655
+ },
656
+ {
657
+ accessorKey: "location_id",
658
+ header: t("wms.backend.lot.distribution.columns.location", "Location"),
659
+ cell: ({ row }) => {
660
+ const locationId = row.original.location_id?.trim();
661
+ const label = formatLocationLabel(row.original.location_code, row.original.location_id);
662
+ if (!locationId || label === "\u2014") return label;
663
+ return /* @__PURE__ */ jsx(
664
+ Link,
665
+ {
666
+ href: `/backend/wms/location/${encodeURIComponent(locationId)}`,
667
+ className: "font-medium text-primary hover:underline",
668
+ children: label
669
+ }
670
+ );
671
+ }
672
+ },
673
+ {
674
+ id: "lastMove",
675
+ header: t("wms.backend.lot.distribution.columns.lastMove", "Last move"),
676
+ cell: ({ row }) => formatLastMoveLabel(lastMoveByLocation.get(balanceLocationKey(row.original)), locale, t)
677
+ },
678
+ {
679
+ accessorKey: "quantity_on_hand",
680
+ header: t("wms.backend.lot.distribution.columns.onHand", "On hand"),
681
+ cell: ({ row }) => String(toNumber(row.original.quantity_on_hand))
682
+ },
683
+ {
684
+ accessorKey: "quantity_reserved",
685
+ header: t("wms.backend.lot.distribution.columns.reserved", "Reserved"),
686
+ cell: ({ row }) => String(toNumber(row.original.quantity_reserved))
687
+ },
688
+ {
689
+ id: "status",
690
+ header: t("wms.backend.lot.distribution.columns.status", "Status"),
691
+ cell: ({ row }) => {
692
+ const status = resolveBalanceStatus(row.original, lotData, reorderPoint, nowMs);
693
+ return /* @__PURE__ */ jsx(StatusBadge, { variant: status.variant, dot: true, children: t(status.labelKey, status.labelFallback) });
694
+ }
695
+ }
696
+ ],
697
+ [
698
+ lastMoveByLocation,
699
+ locale,
700
+ lotData,
701
+ nowMs,
702
+ pageSelectionState.checked,
703
+ pageSelectionState.indeterminate,
704
+ reorderPoint,
705
+ selectedBalanceIds,
706
+ t,
707
+ toggleBalanceSelection,
708
+ togglePageSelection
709
+ ]
710
+ );
711
+ const activityColumns = React.useMemo(
712
+ () => [
713
+ {
714
+ accessorKey: "type",
715
+ header: t("wms.backend.lot.activity.columns.event", "Event"),
716
+ cell: ({ row }) => {
717
+ const type = row.original.type ?? "movement";
718
+ return /* @__PURE__ */ jsx(StatusBadge, { variant: movementStatusMap[type] ?? "neutral", children: movementTypeLabel(type, t) });
719
+ }
720
+ },
721
+ {
722
+ id: "details",
723
+ header: t("wms.backend.lot.activity.columns.details", "Details"),
724
+ cell: ({ row }) => {
725
+ const subtitle = formatMovementSubtitle(row.original, t);
726
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
727
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: formatMovementTitle(row.original, lotLabel, t) }),
728
+ subtitle ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: subtitle }) : null
729
+ ] });
730
+ }
731
+ },
732
+ {
733
+ id: "location",
734
+ header: t("wms.backend.lot.activity.columns.location", "Location"),
735
+ cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: formatMovementLocation(row.original) })
736
+ },
737
+ {
738
+ id: "time",
739
+ header: t("wms.backend.lot.activity.columns.time", "Time"),
740
+ cell: ({ row }) => {
741
+ const raw = row.original.performed_at ?? row.original.received_at;
742
+ if (!raw) return "\u2014";
743
+ const date = new Date(raw);
744
+ if (Number.isNaN(date.getTime())) return raw;
745
+ return activityTimeFormatter.format(date);
746
+ },
747
+ meta: { maxWidth: "6rem" }
748
+ }
749
+ ],
750
+ [activityTimeFormatter, lotLabel, t]
751
+ );
752
+ const filterChips = [
753
+ { id: "all", label: t("wms.backend.lot.distribution.filters.all", "All locations") },
754
+ { id: "sellable", label: t("wms.backend.lot.distribution.filters.sellable", "Sellable") },
755
+ { id: "picking", label: t("wms.backend.lot.distribution.filters.picking", "Picking") },
756
+ { id: "nearExpiry", label: t("wms.backend.lot.distribution.filters.nearExpiry", "Near expiry") }
757
+ ];
758
+ const isLoading = lotQuery.isLoading || variantQuery.isLoading || profileQuery.isLoading || balancesQuery.isLoading || movementsQuery.isLoading;
759
+ const hasError = lotQuery.isError || variantQuery.isError || profileQuery.isError || balancesQuery.isError || movementsQuery.isError;
760
+ if (!scopedLotId) {
761
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
762
+ ErrorMessage,
763
+ {
764
+ label: t("wms.backend.lot.errors.invalidId", "Invalid lot identifier."),
765
+ action: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => router.push(lotsHref), children: t("wms.backend.lot.actions.backToLots", "Back to lots") })
766
+ }
767
+ ) }) });
768
+ }
769
+ return /* @__PURE__ */ jsxs(Page, { children: [
770
+ /* @__PURE__ */ jsxs(PageBody, { className: "space-y-6", children: [
771
+ /* @__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: lotsHref, children: [
772
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "size-4" }),
773
+ t("wms.backend.lot.actions.backToLots", "Back to lots")
774
+ ] }) }),
775
+ /* @__PURE__ */ jsx(
776
+ PageHeader,
777
+ {
778
+ title: pageTitle,
779
+ description: subtitleParts.join(" \xB7 "),
780
+ actions: /* @__PURE__ */ jsxs(Fragment, { children: [
781
+ /* @__PURE__ */ jsxs(Select, { value: warehouseId, onValueChange: setWarehouseId, children: [
782
+ /* @__PURE__ */ jsxs(SelectTrigger, { className: "w-full max-w-xs sm:w-56", children: [
783
+ /* @__PURE__ */ jsx(Warehouse, { className: "mr-2 size-4 shrink-0 text-muted-foreground" }),
784
+ /* @__PURE__ */ jsx(SelectValue, { placeholder: warehouseLabel })
785
+ ] }),
786
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
787
+ /* @__PURE__ */ jsx(SelectItem, { value: "all", children: t("wms.backend.lot.filters.allWarehouses", "All warehouses") }),
788
+ (warehousesQuery.data ?? []).map((warehouse) => /* @__PURE__ */ jsx(SelectItem, { value: warehouse.id, children: warehouse.name || warehouse.code || warehouse.id }, warehouse.id))
789
+ ] })
790
+ ] }),
791
+ access.canAdjust ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", onClick: () => openAdjustDialog(resolveMutationContext()), children: [
792
+ /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-4" }),
793
+ t("wms.backend.lot.actions.adjust", "Adjust stock")
794
+ ] }) : null
795
+ ] })
796
+ }
797
+ ),
798
+ isLoading ? /* @__PURE__ */ jsx(LoadingMessage, { label: t("wms.backend.lot.loading", "Loading lot view\u2026") }) : null,
799
+ hasError ? /* @__PURE__ */ jsx(ErrorMessage, { label: t("wms.backend.lot.errors.load", "Failed to load lot view.") }) : null,
800
+ !isLoading && !hasError && lotQuery.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
801
+ /* @__PURE__ */ jsxs("section", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5", children: [
802
+ /* @__PURE__ */ jsx(
803
+ LotKpiCard,
804
+ {
805
+ title: t("wms.backend.lot.kpis.onHand.title", "Total on hand"),
806
+ caption: t("wms.backend.lot.kpis.onHand.caption", "Physical quantity for this lot"),
807
+ value: String(totals.onHand),
808
+ badgeLabel: totals.onHand > 0 ? t("wms.backend.lot.kpis.onHand.badge", "{count} units", { count: totals.onHand }) : null,
809
+ badgeVariant: "info",
810
+ ctaLabel: t("wms.backend.lot.kpis.onHand.cta", "View locations"),
811
+ ctaHref: "#lot-locations"
812
+ }
813
+ ),
814
+ /* @__PURE__ */ jsx(
815
+ LotKpiCard,
816
+ {
817
+ title: t("wms.backend.lot.kpis.reserved.title", "Reserved"),
818
+ caption: t("wms.backend.lot.kpis.reserved.caption", "Committed from this lot"),
819
+ value: String(totals.reserved),
820
+ badgeLabel: totals.reserved > 0 ? t("wms.backend.lot.kpis.reserved.badge", "{count} units held", { count: totals.reserved }) : null,
821
+ badgeVariant: "info",
822
+ ctaLabel: t("wms.backend.lot.kpis.reserved.cta", "View reservations"),
823
+ ctaHref: "/backend/wms/reservations"
824
+ }
825
+ ),
826
+ /* @__PURE__ */ jsx(
827
+ LotKpiCard,
828
+ {
829
+ title: t("wms.backend.lot.kpis.daysToExpiry.title", "Days to expiry"),
830
+ caption: t("wms.backend.lot.kpis.daysToExpiry.caption", "Until expiration date"),
831
+ value: daysToExpiry === null ? "\u2014" : String(daysToExpiry),
832
+ badgeLabel: daysToExpiry !== null && daysToExpiry <= 30 ? t("wms.backend.lot.kpis.daysToExpiry.badgeSoon", "Expiring soon") : daysToExpiry !== null ? t("wms.backend.lot.kpis.daysToExpiry.badgeOk", "Within window") : null,
833
+ badgeVariant: daysToExpiry !== null && daysToExpiry <= 30 ? "warning" : "success",
834
+ ctaLabel: t("wms.backend.lot.kpis.daysToExpiry.cta", "View SKU profile"),
835
+ ctaHref: skuDetailHref
836
+ }
837
+ ),
838
+ /* @__PURE__ */ jsx(
839
+ LotKpiCard,
840
+ {
841
+ title: t("wms.backend.lot.kpis.lotAge.title", "Lot age"),
842
+ caption: t("wms.backend.lot.kpis.lotAge.caption", "Since lot was created"),
843
+ value: lotAgeDays === null ? "\u2014" : t("wms.backend.lot.kpis.lotAge.value", "{days}d", { days: lotAgeDays }),
844
+ badgeLabel: lotAgeDays !== null && lotAgeDays <= 7 ? t("wms.backend.lot.kpis.lotAge.badgeFresh", "Fresh lot") : lotAgeDays !== null ? t("wms.backend.lot.kpis.lotAge.badgeAged", "Aged stock") : null,
845
+ badgeVariant: lotAgeDays !== null && lotAgeDays <= 7 ? "success" : "neutral",
846
+ ctaLabel: t("wms.backend.lot.kpis.lotAge.cta", "View movements"),
847
+ ctaHref: movementsHref
848
+ }
849
+ ),
850
+ /* @__PURE__ */ jsx(
851
+ LotKpiCard,
852
+ {
853
+ title: t("wms.backend.lot.kpis.qualityStatus.title", "Quality status"),
854
+ caption: statusNotes ? t("wms.backend.lot.kpis.qualityStatus.notesCaption", "Note: {notes}", {
855
+ notes: statusNotes
856
+ }) : t("wms.backend.lot.kpis.qualityStatus.caption", "Lot hold and QC state"),
857
+ value: qualityStatus.value,
858
+ badgeLabel: t(qualityStatus.labelKey, qualityStatus.labelFallback),
859
+ badgeVariant: qualityStatus.variant,
860
+ ctaLabel: t("wms.backend.lot.kpis.qualityStatus.cta", "Change status"),
861
+ onCtaClick: access.canManage ? () => setChangeStatusOpen(true) : void 0,
862
+ ctaHref: !access.canManage ? "/backend/config/wms" : void 0
863
+ }
864
+ )
865
+ ] }),
866
+ /* @__PURE__ */ jsxs(
867
+ "section",
868
+ {
869
+ id: "lot-locations",
870
+ className: "rounded-lg border bg-card text-card-foreground shadow-sm",
871
+ children: [
872
+ /* @__PURE__ */ jsx("div", { className: "border-b px-5 py-4", children: /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: t("wms.backend.lot.distribution.title", "Where this lot lives") }) }),
873
+ /* @__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: [
874
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: filterChips.map((chip) => /* @__PURE__ */ jsx(
875
+ Button,
876
+ {
877
+ type: "button",
878
+ size: "sm",
879
+ variant: distributionFilter === chip.id ? "default" : "outline",
880
+ className: cn("rounded-full", distributionFilter === chip.id && "shadow-sm"),
881
+ onClick: () => setDistributionFilter(chip.id),
882
+ children: chip.label
883
+ },
884
+ chip.id
885
+ )) }),
886
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
887
+ /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: handleExportDistributionCsv, children: [
888
+ /* @__PURE__ */ jsx(Download, { className: "size-4" }),
889
+ t("wms.backend.lot.distribution.actions.exportCsv", "Export CSV")
890
+ ] }),
891
+ access.canCycleCount ? /* @__PURE__ */ jsx(
892
+ Button,
893
+ {
894
+ type: "button",
895
+ size: "sm",
896
+ variant: "outline",
897
+ onClick: () => openCycleCountDialog(resolveMutationContext()),
898
+ children: t("wms.backend.lot.distribution.actions.cycleCountZone", "Cycle count zone")
899
+ }
900
+ ) : null,
901
+ access.canAdjust && selectedBalances.length > 0 ? /* @__PURE__ */ jsx(
902
+ Button,
903
+ {
904
+ type: "button",
905
+ size: "sm",
906
+ variant: "default",
907
+ onClick: () => openAdjustDialog(resolveMutationContext()),
908
+ children: t("wms.backend.lot.distribution.actions.adjustSelected", "Adjust selected ({count})", { count: selectedBalances.length })
909
+ }
910
+ ) : null
911
+ ] })
912
+ ] }),
913
+ /* @__PURE__ */ jsx(
914
+ DataTable,
915
+ {
916
+ embedded: true,
917
+ columns: distributionColumns,
918
+ data: pagedBalances,
919
+ disableRowClick: true,
920
+ entityId: E.wms.inventory_balance,
921
+ perspective: { tableId: "wms.lot.distribution" },
922
+ pagination: {
923
+ page: distributionPage,
924
+ pageSize: distributionPageSize,
925
+ total: distributionTotal,
926
+ totalPages: distributionTotalPages,
927
+ onPageChange: setDistributionPage
928
+ },
929
+ emptyState: /* @__PURE__ */ jsx(
930
+ EmptyState,
931
+ {
932
+ title: t("wms.backend.lot.distribution.empty.title", "No locations in this view"),
933
+ description: t(
934
+ "wms.backend.lot.distribution.empty.description",
935
+ "Try another filter or post inventory through receipts or adjustments."
936
+ )
937
+ }
938
+ )
939
+ }
940
+ ),
941
+ distributionTotal > 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: [
942
+ /* @__PURE__ */ jsx("span", { children: t("wms.backend.lot.distribution.footer.showing", "Showing {shown} of {total} locations", {
943
+ shown: pagedBalances.length,
944
+ total: distributionTotal
945
+ }) }),
946
+ /* @__PURE__ */ jsx(LinkButton, { asChild: true, variant: "gray", size: "sm", className: "h-auto px-0", children: /* @__PURE__ */ jsx(Link, { href: movementsHref, children: t("wms.backend.lot.distribution.footer.openLedger", "Open ledger for this lot \u2192") }) })
947
+ ] }) : null
948
+ ]
949
+ }
950
+ ),
951
+ /* @__PURE__ */ jsx(
952
+ DataTable,
953
+ {
954
+ title: t("wms.backend.lot.activity.title", "Recent activity"),
955
+ columns: activityColumns,
956
+ data: movementsQuery.data ?? [],
957
+ disableRowClick: true,
958
+ entityId: E.wms.inventory_movement,
959
+ perspective: { tableId: "wms.lot.activity" },
960
+ emptyState: t("wms.backend.lot.activity.empty", "No recent movements for this lot."),
961
+ actions: /* @__PURE__ */ jsx(Button, { asChild: true, type: "button", variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(Link, { href: movementsHref, children: t("wms.backend.lot.activity.viewAll", "View all movements \u2192") }) })
962
+ }
963
+ ),
964
+ /* @__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: [
965
+ /* @__PURE__ */ jsxs("div", { children: [
966
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: t("wms.backend.lot.quickActions.title", "Quick actions") }),
967
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t(
968
+ "wms.backend.lot.quickActions.description",
969
+ "Run common inventory actions without leaving this lot view"
970
+ ) })
971
+ ] }),
972
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
973
+ access.canAdjust ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "default", onClick: () => openAdjustDialog(resolveMutationContext()), children: [
974
+ /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-4" }),
975
+ t("wms.backend.lot.quickActions.adjust", "Adjust inventory")
976
+ ] }) : null,
977
+ access.canAdjust ? /* @__PURE__ */ jsx(Button, { asChild: true, type: "button", variant: "outline", children: /* @__PURE__ */ jsxs(Link, { href: inventoryConsoleHref, children: [
978
+ /* @__PURE__ */ jsx(ArrowLeftRight, { className: "size-4" }),
979
+ t("wms.backend.lot.quickActions.move", "Move stock")
980
+ ] }) }) : null,
981
+ access.canCycleCount ? /* @__PURE__ */ jsxs(
982
+ Button,
983
+ {
984
+ type: "button",
985
+ variant: "outline",
986
+ onClick: () => openCycleCountDialog(resolveMutationContext()),
987
+ children: [
988
+ /* @__PURE__ */ jsx(ClipboardList, { className: "size-4" }),
989
+ t("wms.backend.lot.quickActions.cycleCount", "Cycle count")
990
+ ]
991
+ }
992
+ ) : null,
993
+ /* @__PURE__ */ jsx(Button, { asChild: true, type: "button", variant: "outline", children: /* @__PURE__ */ jsxs(Link, { href: movementsHref, children: [
994
+ t("wms.backend.lot.quickActions.openLedger", "Open ledger"),
995
+ /* @__PURE__ */ jsx(ExternalLink, { className: "size-4" })
996
+ ] }) })
997
+ ] })
998
+ ] })
999
+ ] }) : null,
1000
+ !isLoading && !hasError && !lotQuery.data ? /* @__PURE__ */ jsx(
1001
+ RecordNotFoundState,
1002
+ {
1003
+ label: t("wms.backend.lot.errors.notFound", "Lot not found."),
1004
+ backHref: lotsHref,
1005
+ backLabel: t("wms.backend.lot.actions.backToLots", "Back to lots")
1006
+ }
1007
+ ) : null
1008
+ ] }),
1009
+ access.canAdjust && scopedLotId ? /* @__PURE__ */ jsx(
1010
+ AdjustInventoryDialog,
1011
+ {
1012
+ open: adjustOpen,
1013
+ onOpenChange: setAdjustOpen,
1014
+ access,
1015
+ initialCatalogVariantId: adjustPreset.catalogVariantId ?? catalogVariantId ?? void 0,
1016
+ initialWarehouseId: adjustPreset.warehouseId,
1017
+ initialLocationId: adjustPreset.locationId,
1018
+ initialLotId: adjustPreset.lotId ?? scopedLotId
1019
+ }
1020
+ ) : null,
1021
+ access.canCycleCount ? /* @__PURE__ */ jsx(
1022
+ CycleCountWizardDialog,
1023
+ {
1024
+ open: cycleOpen,
1025
+ onOpenChange: setCycleOpen,
1026
+ access,
1027
+ initialCatalogVariantId: catalogVariantId ?? void 0,
1028
+ initialWarehouseId: cyclePreset.warehouseId ?? (warehouseId !== "all" ? warehouseId : void 0),
1029
+ initialLocationId: cyclePreset.locationId,
1030
+ initialLotId: scopedLotId ?? void 0
1031
+ }
1032
+ ) : null,
1033
+ access.canAdjust && scopedLotId ? /* @__PURE__ */ jsx(
1034
+ ChangeLotStatusDialog,
1035
+ {
1036
+ open: changeStatusOpen,
1037
+ onOpenChange: setChangeStatusOpen,
1038
+ access,
1039
+ lotId: scopedLotId,
1040
+ currentStatus: lotData?.status,
1041
+ lotUpdatedAt: lotData?.updated_at
1042
+ }
1043
+ ) : null
1044
+ ] });
1045
+ }
1046
+ export {
1047
+ WmsLotDetailPage as default
1048
+ };
1049
+ //# sourceMappingURL=WmsLotDetailPage.js.map