@open-mercato/core 0.6.7-develop.6669.1.40b669666b → 0.6.7-develop.6671.1.4b925c5096

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,975 @@
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
+ ArrowDown,
10
+ ArrowLeft,
11
+ ArrowLeftRight,
12
+ ClipboardList,
13
+ Download,
14
+ ExternalLink,
15
+ SlidersHorizontal,
16
+ Warehouse
17
+ } from "lucide-react";
18
+ import { Page, PageBody, PageHeader } from "@open-mercato/ui/backend/Page";
19
+ import { DataTable } from "@open-mercato/ui/backend/DataTable";
20
+ import { EmptyState } from "@open-mercato/ui/backend/EmptyState";
21
+ import { ErrorMessage, LoadingMessage, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
22
+ import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
23
+ import { raiseCrudError } from "@open-mercato/ui/backend/utils/serverErrors";
24
+ import { useLocale, useT } from "@open-mercato/shared/lib/i18n/context";
25
+ import { Button } from "@open-mercato/ui/primitives/button";
26
+ import { LinkButton } from "@open-mercato/ui/primitives/link-button";
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 { ReceiveInventoryDialog } from "./ReceiveInventoryDialog.js";
44
+ import { useWmsInventoryMutationAccess } from "./useWmsInventoryMutationAccess.js";
45
+ const variantIdSchema = z.string().uuid();
46
+ function escapeCsvCell(value) {
47
+ const str = String(value ?? "");
48
+ if (/[",\n]/.test(str)) return `"${str.replace(/"/g, '""')}"`;
49
+ return str;
50
+ }
51
+ function downloadCsvFile(filename, rows) {
52
+ const csv = rows.map((row) => row.map(escapeCsvCell).join(",")).join("\n");
53
+ const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
54
+ const url = URL.createObjectURL(blob);
55
+ const anchor = document.createElement("a");
56
+ anchor.href = url;
57
+ anchor.download = filename;
58
+ anchor.click();
59
+ URL.revokeObjectURL(url);
60
+ }
61
+ const NON_SELLABLE_LOCATION_TYPES = /* @__PURE__ */ new Set(["staging", "dock"]);
62
+ const PICKING_LOCATION_TYPES = /* @__PURE__ */ new Set(["staging", "bin", "slot"]);
63
+ const NEAR_EXPIRY_MS = 30 * 24 * 60 * 60 * 1e3;
64
+ const USAGE_WINDOW_DAYS = 14;
65
+ function toNumber(value) {
66
+ const parsed = Number(value ?? 0);
67
+ return Number.isFinite(parsed) ? parsed : 0;
68
+ }
69
+ function formatWarehouseLabel(row) {
70
+ const code = (row.warehouse_code ?? "").trim();
71
+ const name = (row.warehouse_name ?? "").trim();
72
+ if (code && name) return `${code} \xB7 ${name}`;
73
+ return name || code || row.warehouse_id || "\u2014";
74
+ }
75
+ function formatLocationLabel(code, id) {
76
+ const trimmed = (code ?? "").trim();
77
+ if (trimmed) return trimmed;
78
+ return id || "\u2014";
79
+ }
80
+ function formatLotLabel(lot, locale) {
81
+ if (!lot) return "\u2014";
82
+ const number = (lot.lot_number ?? "").trim() || lot.id;
83
+ if (!lot.expires_at) return number;
84
+ const expires = new Date(lot.expires_at);
85
+ if (Number.isNaN(expires.getTime())) return number;
86
+ const expLabel = new Intl.DateTimeFormat(locale, { month: "2-digit", year: "2-digit" }).format(expires);
87
+ return `${number} \xB7 exp ${expLabel}`;
88
+ }
89
+ function isNearExpiry(expiresAt, nowMs) {
90
+ if (!expiresAt) return false;
91
+ const expires = new Date(expiresAt).getTime();
92
+ if (Number.isNaN(expires)) return false;
93
+ return expires > nowMs && expires - nowMs <= NEAR_EXPIRY_MS;
94
+ }
95
+ function isExpired(expiresAt, nowMs) {
96
+ if (!expiresAt) return false;
97
+ const expires = new Date(expiresAt).getTime();
98
+ return !Number.isNaN(expires) && expires <= nowMs;
99
+ }
100
+ function resolveBalanceStatus(row, lot, reorderPoint, nowMs) {
101
+ if (lot?.status === "expired" || isExpired(lot?.expires_at, nowMs)) {
102
+ return {
103
+ variant: "error",
104
+ labelKey: "wms.backend.sku.distribution.status.expired",
105
+ labelFallback: "Expired"
106
+ };
107
+ }
108
+ if (isNearExpiry(lot?.expires_at, nowMs)) {
109
+ return {
110
+ variant: "warning",
111
+ labelKey: "wms.backend.sku.distribution.status.nearExpiry",
112
+ labelFallback: "Near expiry"
113
+ };
114
+ }
115
+ const available = row.quantity_available ?? 0;
116
+ if (reorderPoint > 0 && available <= reorderPoint) {
117
+ return {
118
+ variant: "warning",
119
+ labelKey: "wms.backend.sku.distribution.status.lowStock",
120
+ labelFallback: "Low stock"
121
+ };
122
+ }
123
+ const reserved = toNumber(row.quantity_reserved);
124
+ const onHand = toNumber(row.quantity_on_hand);
125
+ if (reserved > 0 && onHand > 0 && reserved >= onHand) {
126
+ return {
127
+ variant: "info",
128
+ labelKey: "wms.backend.sku.distribution.status.reserved",
129
+ labelFallback: "Reserved"
130
+ };
131
+ }
132
+ return {
133
+ variant: "success",
134
+ labelKey: "wms.backend.sku.distribution.status.available",
135
+ labelFallback: "Available"
136
+ };
137
+ }
138
+ function matchesDistributionFilter(row, lot, filter, nowMs) {
139
+ const locationType = (row.location_type ?? "").trim().toLowerCase();
140
+ const locationCode = (row.location_code ?? "").trim().toLowerCase();
141
+ switch (filter) {
142
+ case "all":
143
+ return true;
144
+ case "sellable":
145
+ return !NON_SELLABLE_LOCATION_TYPES.has(locationType);
146
+ case "picking":
147
+ return PICKING_LOCATION_TYPES.has(locationType) || locationCode.includes("pick") || locationCode.includes("staging");
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.sku.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) {
232
+ const warehouse = formatWarehouseLabel(row);
233
+ const from = formatLocationLabel(row.location_from_code, row.location_from_id);
234
+ const to = formatLocationLabel(row.location_to_code, row.location_to_id);
235
+ if (row.type === "transfer" && from !== "\u2014" && to !== "\u2014") return `${from} \u2192 ${to}`;
236
+ const location = to !== "\u2014" ? to : from;
237
+ if (location !== "\u2014") return `${warehouse} \xB7 ${location}`;
238
+ return warehouse;
239
+ }
240
+ function SkuKpiCard({
241
+ title,
242
+ caption,
243
+ value,
244
+ badgeLabel,
245
+ badgeVariant,
246
+ ctaLabel,
247
+ ctaHref
248
+ }) {
249
+ return /* @__PURE__ */ jsxs("section", { className: "flex min-h-52 flex-col rounded-lg border bg-card p-5 text-card-foreground shadow-sm", children: [
250
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: title }),
251
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-xs text-muted-foreground", children: caption }),
252
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-end gap-3", children: [
253
+ /* @__PURE__ */ jsx("p", { className: "text-3xl font-semibold tracking-tight", children: value }),
254
+ badgeLabel ? /* @__PURE__ */ jsx(StatusBadge, { variant: badgeVariant, dot: true, children: badgeLabel }) : null
255
+ ] }),
256
+ /* @__PURE__ */ jsx(LinkButton, { asChild: true, variant: "primary", size: "sm", className: "mt-auto pt-4 w-fit", children: /* @__PURE__ */ jsx(Link, { href: ctaHref, children: ctaLabel }) })
257
+ ] });
258
+ }
259
+ function WmsSkuDetailPage({ variantId }) {
260
+ const t = useT();
261
+ const locale = useLocale();
262
+ const router = useRouter();
263
+ const access = useWmsInventoryMutationAccess();
264
+ const parsedVariantId = variantIdSchema.safeParse(variantId.trim());
265
+ const catalogVariantId = parsedVariantId.success ? parsedVariantId.data : null;
266
+ const [warehouseId, setWarehouseId] = React.useState("all");
267
+ const [distributionFilter, setDistributionFilter] = React.useState("all");
268
+ const [distributionPage, setDistributionPage] = React.useState(1);
269
+ const [selectedBalanceIds, setSelectedBalanceIds] = React.useState(() => /* @__PURE__ */ new Set());
270
+ const [adjustOpen, setAdjustOpen] = React.useState(false);
271
+ const [adjustPreset, setAdjustPreset] = React.useState({});
272
+ const [receiveOpen, setReceiveOpen] = React.useState(false);
273
+ const [cycleOpen, setCycleOpen] = React.useState(false);
274
+ const [cyclePreset, setCyclePreset] = React.useState({});
275
+ const distributionPageSize = 20;
276
+ const activityTimeFormatter = React.useMemo(
277
+ () => new Intl.DateTimeFormat(locale, {
278
+ month: "2-digit",
279
+ day: "2-digit",
280
+ hour: "2-digit",
281
+ minute: "2-digit"
282
+ }),
283
+ [locale]
284
+ );
285
+ const variantQuery = useQuery({
286
+ queryKey: ["wms-sku-detail", "variant", catalogVariantId],
287
+ enabled: Boolean(catalogVariantId),
288
+ queryFn: async () => {
289
+ const params = new URLSearchParams({
290
+ id: catalogVariantId,
291
+ page: "1",
292
+ pageSize: "1"
293
+ });
294
+ const call = await apiCall(
295
+ `/api/catalog/variants?${params.toString()}`
296
+ );
297
+ if (!call.ok) {
298
+ await raiseCrudError(call.response, t("wms.backend.sku.errors.variant", "Failed to load SKU."));
299
+ }
300
+ return call.result?.items?.[0] ?? null;
301
+ }
302
+ });
303
+ const profileQuery = useQuery({
304
+ queryKey: ["wms-sku-detail", "profile", catalogVariantId],
305
+ enabled: Boolean(catalogVariantId),
306
+ queryFn: async () => {
307
+ const params = new URLSearchParams({
308
+ catalogVariantId,
309
+ page: "1",
310
+ pageSize: "1"
311
+ });
312
+ const call = await apiCall(
313
+ `/api/wms/inventory-profiles?${params.toString()}`
314
+ );
315
+ if (!call.ok) {
316
+ await raiseCrudError(call.response, t("wms.backend.sku.errors.profile", "Failed to load inventory profile."));
317
+ }
318
+ return call.result?.items?.[0] ?? null;
319
+ }
320
+ });
321
+ const warehousesQuery = useQuery({
322
+ queryKey: ["wms-sku-detail", "warehouses"],
323
+ queryFn: async () => {
324
+ const params = new URLSearchParams({ page: "1", pageSize: "100", sortField: "name", sortDir: "asc" });
325
+ const call = await apiCall(`/api/wms/warehouses?${params.toString()}`);
326
+ if (!call.ok) {
327
+ await raiseCrudError(call.response, t("wms.backend.sku.errors.warehouses", "Failed to load warehouses."));
328
+ }
329
+ return call.result?.items ?? [];
330
+ }
331
+ });
332
+ const balancesQuery = useQuery({
333
+ queryKey: ["wms-sku-detail", "balances", catalogVariantId, warehouseId],
334
+ enabled: Boolean(catalogVariantId),
335
+ queryFn: async () => {
336
+ const params = new URLSearchParams({
337
+ catalogVariantId,
338
+ page: "1",
339
+ pageSize: "100",
340
+ sortField: "updatedAt",
341
+ sortDir: "desc"
342
+ });
343
+ if (warehouseId !== "all") params.set("warehouseId", warehouseId);
344
+ const call = await apiCall(
345
+ `/api/wms/inventory/balances?${params.toString()}`
346
+ );
347
+ if (!call.ok) {
348
+ await raiseCrudError(call.response, t("wms.backend.sku.errors.balances", "Failed to load stock distribution."));
349
+ }
350
+ return call.result ?? { items: [], total: 0, totalPages: 1 };
351
+ }
352
+ });
353
+ const lotsQuery = useQuery({
354
+ queryKey: ["wms-sku-detail", "lots", catalogVariantId],
355
+ enabled: Boolean(catalogVariantId),
356
+ queryFn: async () => {
357
+ const params = new URLSearchParams({
358
+ catalogVariantId,
359
+ page: "1",
360
+ pageSize: "100"
361
+ });
362
+ const call = await apiCall(`/api/wms/lots?${params.toString()}`);
363
+ if (!call.ok) {
364
+ await raiseCrudError(call.response, t("wms.backend.sku.errors.lots", "Failed to load lots."));
365
+ }
366
+ return call.result?.items ?? [];
367
+ }
368
+ });
369
+ const movementsQuery = useQuery({
370
+ queryKey: ["wms-sku-detail", "movements", catalogVariantId, warehouseId],
371
+ enabled: Boolean(catalogVariantId),
372
+ queryFn: async () => {
373
+ const params = new URLSearchParams({
374
+ catalogVariantId,
375
+ page: "1",
376
+ pageSize: "25",
377
+ sortField: "performedAt",
378
+ sortDir: "desc"
379
+ });
380
+ if (warehouseId !== "all") params.set("warehouseId", warehouseId);
381
+ const call = await apiCall(
382
+ `/api/wms/inventory/movements?${params.toString()}`
383
+ );
384
+ if (!call.ok) {
385
+ await raiseCrudError(call.response, t("wms.backend.sku.errors.movements", "Failed to load recent activity."));
386
+ }
387
+ return call.result?.items ?? [];
388
+ }
389
+ });
390
+ const lotById = React.useMemo(() => {
391
+ const map = /* @__PURE__ */ new Map();
392
+ for (const lot of lotsQuery.data ?? []) {
393
+ if (lot.id) map.set(lot.id, lot);
394
+ }
395
+ return map;
396
+ }, [lotsQuery.data]);
397
+ const reorderPoint = toNumber(profileQuery.data?.reorder_point);
398
+ const safetyStock = toNumber(profileQuery.data?.safety_stock);
399
+ const skuLabel = (variantQuery.data?.sku ?? "").trim() || (variantQuery.data?.name ?? "").trim() || catalogVariantId || "\u2014";
400
+ const variantName = (variantQuery.data?.name ?? "").trim();
401
+ const pageTitle = (variantQuery.data?.sku ?? "").trim() || skuLabel;
402
+ const totals = React.useMemo(() => {
403
+ const items = balancesQuery.data?.items ?? [];
404
+ let onHand = 0;
405
+ let reserved = 0;
406
+ let available = 0;
407
+ for (const row of items) {
408
+ onHand += toNumber(row.quantity_on_hand);
409
+ reserved += toNumber(row.quantity_reserved);
410
+ available += row.quantity_available ?? 0;
411
+ }
412
+ return { onHand, reserved, available };
413
+ }, [balancesQuery.data?.items]);
414
+ const daysOfSupply = React.useMemo(() => {
415
+ const movements = movementsQuery.data ?? [];
416
+ const windowStart = Date.now() - USAGE_WINDOW_DAYS * 24 * 60 * 60 * 1e3;
417
+ let outbound = 0;
418
+ for (const row of movements) {
419
+ const at = row.performed_at ?? row.received_at;
420
+ if (!at) continue;
421
+ const ts = new Date(at).getTime();
422
+ if (Number.isNaN(ts) || ts < windowStart) continue;
423
+ if (row.type === "pick" || row.type === "pack" || row.type === "ship") {
424
+ outbound += Math.abs(toNumber(row.quantity));
425
+ }
426
+ }
427
+ const daily = outbound / USAGE_WINDOW_DAYS;
428
+ if (daily <= 0 || totals.available <= 0) return null;
429
+ return Math.round(totals.available / daily);
430
+ }, [movementsQuery.data, totals.available]);
431
+ const nowMs = React.useMemo(() => Date.now(), []);
432
+ const filteredBalances = React.useMemo(() => {
433
+ const items = balancesQuery.data?.items ?? [];
434
+ return items.filter(
435
+ (row) => matchesDistributionFilter(row, row.lot_id ? lotById.get(row.lot_id) : void 0, distributionFilter, nowMs)
436
+ );
437
+ }, [balancesQuery.data?.items, distributionFilter, lotById, nowMs]);
438
+ const distributionTotal = filteredBalances.length;
439
+ const distributionTotalPages = Math.max(1, Math.ceil(distributionTotal / distributionPageSize));
440
+ const pagedBalances = React.useMemo(() => {
441
+ const start = (distributionPage - 1) * distributionPageSize;
442
+ return filteredBalances.slice(start, start + distributionPageSize);
443
+ }, [distributionPage, distributionPageSize, filteredBalances]);
444
+ React.useEffect(() => {
445
+ setDistributionPage(1);
446
+ setSelectedBalanceIds(/* @__PURE__ */ new Set());
447
+ }, [distributionFilter, warehouseId]);
448
+ const selectedBalances = React.useMemo(
449
+ () => filteredBalances.filter((row) => selectedBalanceIds.has(row.id)),
450
+ [filteredBalances, selectedBalanceIds]
451
+ );
452
+ const movementsHref = React.useMemo(() => {
453
+ const params = new URLSearchParams();
454
+ if (catalogVariantId) params.set("catalogVariantId", catalogVariantId);
455
+ if (warehouseId !== "all") params.set("warehouseId", warehouseId);
456
+ const query = params.toString();
457
+ return query ? `/backend/wms/movements?${query}` : "/backend/wms/movements";
458
+ }, [catalogVariantId, warehouseId]);
459
+ const inventoryConsoleHref = React.useMemo(() => {
460
+ if (!catalogVariantId) return "/backend/wms/inventory";
461
+ return `/backend/wms/inventory?catalogVariantId=${encodeURIComponent(catalogVariantId)}`;
462
+ }, [catalogVariantId]);
463
+ const openAdjustDialog = React.useCallback((preset = {}) => {
464
+ setAdjustPreset(preset);
465
+ setAdjustOpen(true);
466
+ }, []);
467
+ const openCycleCountDialog = React.useCallback(
468
+ (preset = {}) => {
469
+ setCyclePreset(preset);
470
+ setCycleOpen(true);
471
+ },
472
+ []
473
+ );
474
+ const resolveMutationContext = React.useCallback(() => {
475
+ const firstSelected = selectedBalances[0];
476
+ const scopedWarehouseId = firstSelected?.warehouse_id?.trim() || (warehouseId !== "all" ? warehouseId : void 0);
477
+ const locationId = selectedBalances.length === 1 ? firstSelected?.location_id?.trim() || void 0 : void 0;
478
+ const lotId = selectedBalances.length === 1 ? firstSelected?.lot_id?.trim() || void 0 : void 0;
479
+ return {
480
+ warehouseId: scopedWarehouseId,
481
+ locationId,
482
+ lotId
483
+ };
484
+ }, [selectedBalances, warehouseId]);
485
+ const toggleBalanceSelection = React.useCallback((balanceId, selected) => {
486
+ setSelectedBalanceIds((current) => {
487
+ const next = new Set(current);
488
+ if (selected) next.add(balanceId);
489
+ else next.delete(balanceId);
490
+ return next;
491
+ });
492
+ }, []);
493
+ const togglePageSelection = React.useCallback((selected) => {
494
+ setSelectedBalanceIds((current) => {
495
+ const next = new Set(current);
496
+ for (const row of pagedBalances) {
497
+ if (selected) next.add(row.id);
498
+ else next.delete(row.id);
499
+ }
500
+ return next;
501
+ });
502
+ }, [pagedBalances]);
503
+ const pageSelectionState = React.useMemo(() => {
504
+ if (pagedBalances.length === 0) {
505
+ return { checked: false, indeterminate: false };
506
+ }
507
+ const selectedOnPage = pagedBalances.filter((row) => selectedBalanceIds.has(row.id)).length;
508
+ return {
509
+ checked: selectedOnPage === pagedBalances.length,
510
+ indeterminate: selectedOnPage > 0 && selectedOnPage < pagedBalances.length
511
+ };
512
+ }, [pagedBalances, selectedBalanceIds]);
513
+ const handleExportDistributionCsv = React.useCallback(() => {
514
+ const headers = [
515
+ t("wms.backend.sku.distribution.columns.warehouse", "Warehouse"),
516
+ t("wms.backend.sku.distribution.columns.location", "Location"),
517
+ t("wms.backend.sku.distribution.columns.lot", "Lot"),
518
+ t("wms.backend.sku.distribution.columns.onHand", "On hand"),
519
+ t("wms.backend.sku.distribution.columns.reserved", "Reserved"),
520
+ t("wms.backend.sku.distribution.columns.status", "Status")
521
+ ];
522
+ const rows = filteredBalances.map((row) => {
523
+ const lot = row.lot_id ? lotById.get(row.lot_id) : void 0;
524
+ const status = resolveBalanceStatus(row, lot, reorderPoint, nowMs);
525
+ return [
526
+ formatWarehouseLabel(row),
527
+ formatLocationLabel(row.location_code, row.location_id),
528
+ formatLotLabel(lot, locale),
529
+ String(toNumber(row.quantity_on_hand)),
530
+ String(toNumber(row.quantity_reserved)),
531
+ t(status.labelKey, status.labelFallback)
532
+ ];
533
+ });
534
+ const safeSku = pageTitle.replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "") || "sku";
535
+ downloadCsvFile(`${safeSku}-distribution.csv`, [headers, ...rows]);
536
+ }, [filteredBalances, locale, lotById, nowMs, pageTitle, reorderPoint, t]);
537
+ const inventoryHref = "/backend/wms/inventory";
538
+ const selectedWarehouse = warehousesQuery.data?.find((warehouse) => warehouse.id === warehouseId);
539
+ const warehouseLabel = warehouseId === "all" ? t("wms.backend.sku.filters.allWarehouses", "All warehouses") : selectedWarehouse?.name || selectedWarehouse?.code || warehouseId;
540
+ const subtitleParts = [
541
+ variantName || null,
542
+ variantQuery.data?.is_active === false ? t("wms.backend.sku.header.inactive", "Inactive") : null
543
+ ].filter(Boolean);
544
+ const distributionColumns = React.useMemo(
545
+ () => [
546
+ {
547
+ id: "select",
548
+ header: () => /* @__PURE__ */ jsx(
549
+ Checkbox,
550
+ {
551
+ "aria-label": t("wms.backend.sku.distribution.columns.select", "Select"),
552
+ checked: pageSelectionState.indeterminate ? "indeterminate" : pageSelectionState.checked,
553
+ onCheckedChange: (checked) => togglePageSelection(checked === true)
554
+ }
555
+ ),
556
+ cell: ({ row }) => /* @__PURE__ */ jsx(
557
+ Checkbox,
558
+ {
559
+ "aria-label": t("wms.backend.sku.distribution.columns.select", "Select"),
560
+ checked: selectedBalanceIds.has(row.original.id),
561
+ onCheckedChange: (checked) => toggleBalanceSelection(row.original.id, checked === true)
562
+ }
563
+ ),
564
+ meta: { maxWidth: "2.75rem" }
565
+ },
566
+ {
567
+ accessorKey: "warehouse_id",
568
+ header: t("wms.backend.sku.distribution.columns.warehouse", "Warehouse"),
569
+ cell: ({ row }) => formatWarehouseLabel(row.original)
570
+ },
571
+ {
572
+ accessorKey: "location_id",
573
+ header: t("wms.backend.sku.distribution.columns.location", "Location"),
574
+ cell: ({ row }) => {
575
+ const locationId = row.original.location_id?.trim();
576
+ const label = formatLocationLabel(row.original.location_code, row.original.location_id);
577
+ if (!locationId || label === "\u2014") return label;
578
+ return /* @__PURE__ */ jsx(
579
+ Link,
580
+ {
581
+ href: `/backend/wms/location/${encodeURIComponent(locationId)}`,
582
+ className: "font-medium text-primary hover:underline",
583
+ children: label
584
+ }
585
+ );
586
+ }
587
+ },
588
+ {
589
+ accessorKey: "lot_id",
590
+ header: t("wms.backend.sku.distribution.columns.lot", "Lot"),
591
+ cell: ({ row }) => {
592
+ const lotId = row.original.lot_id?.trim();
593
+ const lot = lotId ? lotById.get(lotId) : void 0;
594
+ const label = formatLotLabel(lot, locale);
595
+ if (!lotId || label === "\u2014") return label;
596
+ return /* @__PURE__ */ jsx(
597
+ Link,
598
+ {
599
+ href: `/backend/wms/lot/${encodeURIComponent(lotId)}`,
600
+ className: "font-medium text-primary hover:underline",
601
+ children: label
602
+ }
603
+ );
604
+ }
605
+ },
606
+ {
607
+ accessorKey: "quantity_on_hand",
608
+ header: t("wms.backend.sku.distribution.columns.onHand", "On hand"),
609
+ cell: ({ row }) => String(toNumber(row.original.quantity_on_hand))
610
+ },
611
+ {
612
+ accessorKey: "quantity_reserved",
613
+ header: t("wms.backend.sku.distribution.columns.reserved", "Reserved"),
614
+ cell: ({ row }) => String(toNumber(row.original.quantity_reserved))
615
+ },
616
+ {
617
+ id: "status",
618
+ header: t("wms.backend.sku.distribution.columns.status", "Status"),
619
+ cell: ({ row }) => {
620
+ const lot = row.original.lot_id ? lotById.get(row.original.lot_id) : void 0;
621
+ const status = resolveBalanceStatus(row.original, lot, reorderPoint, nowMs);
622
+ return /* @__PURE__ */ jsx(StatusBadge, { variant: status.variant, dot: true, children: t(status.labelKey, status.labelFallback) });
623
+ }
624
+ }
625
+ ],
626
+ [
627
+ locale,
628
+ lotById,
629
+ nowMs,
630
+ pageSelectionState.checked,
631
+ pageSelectionState.indeterminate,
632
+ reorderPoint,
633
+ selectedBalanceIds,
634
+ t,
635
+ toggleBalanceSelection,
636
+ togglePageSelection
637
+ ]
638
+ );
639
+ const activityColumns = React.useMemo(
640
+ () => [
641
+ {
642
+ accessorKey: "type",
643
+ header: t("wms.backend.sku.activity.columns.event", "Event"),
644
+ cell: ({ row }) => {
645
+ const type = row.original.type ?? "movement";
646
+ return /* @__PURE__ */ jsx(StatusBadge, { variant: movementStatusMap[type] ?? "neutral", children: movementTypeLabel(type, t) });
647
+ }
648
+ },
649
+ {
650
+ id: "details",
651
+ header: t("wms.backend.sku.activity.columns.details", "Details"),
652
+ cell: ({ row }) => {
653
+ const subtitle = formatMovementSubtitle(row.original, t);
654
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
655
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: formatMovementTitle(row.original, skuLabel, t) }),
656
+ subtitle ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: subtitle }) : null
657
+ ] });
658
+ }
659
+ },
660
+ {
661
+ id: "location",
662
+ header: t("wms.backend.sku.activity.columns.location", "Location"),
663
+ cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: formatMovementLocation(row.original) })
664
+ },
665
+ {
666
+ id: "time",
667
+ header: t("wms.backend.sku.activity.columns.time", "Time"),
668
+ cell: ({ row }) => {
669
+ const raw = row.original.performed_at ?? row.original.received_at;
670
+ if (!raw) return "\u2014";
671
+ const date = new Date(raw);
672
+ if (Number.isNaN(date.getTime())) return raw;
673
+ return activityTimeFormatter.format(date);
674
+ },
675
+ meta: { maxWidth: "6rem" }
676
+ }
677
+ ],
678
+ [activityTimeFormatter, skuLabel, t]
679
+ );
680
+ const filterChips = [
681
+ { id: "all", label: t("wms.backend.sku.distribution.filters.all", "All bins") },
682
+ { id: "sellable", label: t("wms.backend.sku.distribution.filters.sellable", "Sellable") },
683
+ { id: "picking", label: t("wms.backend.sku.distribution.filters.picking", "Picking") },
684
+ { id: "nearExpiry", label: t("wms.backend.sku.distribution.filters.nearExpiry", "Near expiry") }
685
+ ];
686
+ const isLoading = variantQuery.isLoading || profileQuery.isLoading || balancesQuery.isLoading || lotsQuery.isLoading || movementsQuery.isLoading;
687
+ const hasError = variantQuery.isError || profileQuery.isError || balancesQuery.isError || lotsQuery.isError || movementsQuery.isError;
688
+ if (!catalogVariantId) {
689
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
690
+ ErrorMessage,
691
+ {
692
+ label: t("wms.backend.sku.errors.invalidId", "Invalid SKU identifier."),
693
+ action: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => router.push(inventoryHref), children: t("wms.backend.sku.actions.backToInventory", "Back to inventory") })
694
+ }
695
+ ) }) });
696
+ }
697
+ return /* @__PURE__ */ jsxs(Page, { children: [
698
+ /* @__PURE__ */ jsxs(PageBody, { className: "space-y-6", children: [
699
+ /* @__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: inventoryHref, children: [
700
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "size-4" }),
701
+ t("wms.backend.sku.actions.backToInventory", "Back to inventory")
702
+ ] }) }),
703
+ /* @__PURE__ */ jsx(
704
+ PageHeader,
705
+ {
706
+ title: pageTitle,
707
+ description: subtitleParts.join(" \xB7 "),
708
+ actions: /* @__PURE__ */ jsxs(Fragment, { children: [
709
+ /* @__PURE__ */ jsxs(Select, { value: warehouseId, onValueChange: setWarehouseId, children: [
710
+ /* @__PURE__ */ jsxs(SelectTrigger, { className: "w-full max-w-xs sm:w-56", children: [
711
+ /* @__PURE__ */ jsx(Warehouse, { className: "mr-2 size-4 shrink-0 text-muted-foreground" }),
712
+ /* @__PURE__ */ jsx(SelectValue, { placeholder: warehouseLabel })
713
+ ] }),
714
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
715
+ /* @__PURE__ */ jsx(SelectItem, { value: "all", children: t("wms.backend.sku.filters.allWarehouses", "All warehouses") }),
716
+ (warehousesQuery.data ?? []).map((warehouse) => /* @__PURE__ */ jsx(SelectItem, { value: warehouse.id, children: warehouse.name || warehouse.code || warehouse.id }, warehouse.id))
717
+ ] })
718
+ ] }),
719
+ access.canAdjust ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", onClick: () => openAdjustDialog(), children: [
720
+ /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-4" }),
721
+ t("wms.backend.sku.actions.adjust", "Adjust stock")
722
+ ] }) : null
723
+ ] })
724
+ }
725
+ ),
726
+ isLoading ? /* @__PURE__ */ jsx(LoadingMessage, { label: t("wms.backend.sku.loading", "Loading SKU view\u2026") }) : null,
727
+ hasError ? /* @__PURE__ */ jsx(ErrorMessage, { label: t("wms.backend.sku.errors.load", "Failed to load SKU view.") }) : null,
728
+ !isLoading && !hasError && variantQuery.data ? /* @__PURE__ */ jsxs(Fragment, { children: [
729
+ /* @__PURE__ */ jsxs("section", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5", children: [
730
+ /* @__PURE__ */ jsx(
731
+ SkuKpiCard,
732
+ {
733
+ title: t("wms.backend.sku.kpis.onHand.title", "On hand"),
734
+ caption: t("wms.backend.sku.kpis.onHand.caption", "Total physical quantity"),
735
+ value: String(totals.onHand),
736
+ badgeLabel: reorderPoint > 0 && totals.onHand <= reorderPoint ? t("wms.backend.sku.kpis.onHand.badgeLow", "Below reorder") : null,
737
+ badgeVariant: "warning",
738
+ ctaLabel: t("wms.backend.sku.kpis.onHand.cta", "View distribution"),
739
+ ctaHref: "#stock-distribution"
740
+ }
741
+ ),
742
+ /* @__PURE__ */ jsx(
743
+ SkuKpiCard,
744
+ {
745
+ title: t("wms.backend.sku.kpis.reserved.title", "Reserved"),
746
+ caption: t("wms.backend.sku.kpis.reserved.caption", "Committed to orders"),
747
+ value: String(totals.reserved),
748
+ badgeLabel: totals.reserved > 0 ? t("wms.backend.sku.kpis.reserved.badge", "{count} units held", { count: totals.reserved }) : null,
749
+ badgeVariant: "info",
750
+ ctaLabel: t("wms.backend.sku.kpis.reserved.cta", "View reservations"),
751
+ ctaHref: "/backend/wms/reservations"
752
+ }
753
+ ),
754
+ /* @__PURE__ */ jsx(
755
+ SkuKpiCard,
756
+ {
757
+ title: t("wms.backend.sku.kpis.available.title", "Available"),
758
+ caption: t("wms.backend.sku.kpis.available.caption", "Ready to allocate"),
759
+ value: String(totals.available),
760
+ badgeLabel: totals.available > 0 ? t("wms.backend.sku.kpis.available.badge", "Sellable") : t("wms.backend.sku.kpis.available.badgeEmpty", "None"),
761
+ badgeVariant: totals.available > 0 ? "success" : "neutral",
762
+ ctaLabel: t("wms.backend.sku.kpis.available.cta", "Adjust stock"),
763
+ ctaHref: access.canAdjust ? "#stock-distribution" : inventoryHref
764
+ }
765
+ ),
766
+ /* @__PURE__ */ jsx(
767
+ SkuKpiCard,
768
+ {
769
+ title: t("wms.backend.sku.kpis.reorderPoint.title", "Reorder point"),
770
+ caption: t("wms.backend.sku.kpis.reorderPoint.caption", "From inventory profile"),
771
+ value: String(reorderPoint),
772
+ badgeLabel: safetyStock > 0 ? t("wms.backend.sku.kpis.reorderPoint.badgeSafety", "Safety {count}", { count: safetyStock }) : null,
773
+ badgeVariant: totals.available <= reorderPoint && reorderPoint > 0 ? "error" : "neutral",
774
+ ctaLabel: t("wms.backend.sku.kpis.reorderPoint.cta", "Edit profile"),
775
+ ctaHref: "/backend/config/wms"
776
+ }
777
+ ),
778
+ /* @__PURE__ */ jsx(
779
+ SkuKpiCard,
780
+ {
781
+ title: t("wms.backend.sku.kpis.daysOfSupply.title", "Days of supply"),
782
+ caption: t("wms.backend.sku.kpis.daysOfSupply.caption", "Based on last {days} days outbound", {
783
+ days: USAGE_WINDOW_DAYS
784
+ }),
785
+ value: daysOfSupply === null ? "\u2014" : String(daysOfSupply),
786
+ badgeLabel: daysOfSupply !== null && daysOfSupply <= 7 ? t("wms.backend.sku.kpis.daysOfSupply.badgeShort", "Short runway") : null,
787
+ badgeVariant: "warning",
788
+ ctaLabel: t("wms.backend.sku.kpis.daysOfSupply.cta", "View movements"),
789
+ ctaHref: movementsHref
790
+ }
791
+ )
792
+ ] }),
793
+ /* @__PURE__ */ jsxs(
794
+ "section",
795
+ {
796
+ id: "stock-distribution",
797
+ className: "rounded-lg border bg-card text-card-foreground shadow-sm",
798
+ children: [
799
+ /* @__PURE__ */ jsx("div", { className: "border-b px-5 py-4", children: /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: t("wms.backend.sku.distribution.title", "Stock distribution") }) }),
800
+ /* @__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: [
801
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: filterChips.map((chip) => /* @__PURE__ */ jsx(
802
+ Button,
803
+ {
804
+ type: "button",
805
+ size: "sm",
806
+ variant: distributionFilter === chip.id ? "default" : "outline",
807
+ className: cn("rounded-full", distributionFilter === chip.id && "shadow-sm"),
808
+ onClick: () => setDistributionFilter(chip.id),
809
+ children: chip.label
810
+ },
811
+ chip.id
812
+ )) }),
813
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
814
+ /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", onClick: handleExportDistributionCsv, children: [
815
+ /* @__PURE__ */ jsx(Download, { className: "size-4" }),
816
+ t("wms.backend.sku.distribution.actions.exportCsv", "Export CSV")
817
+ ] }),
818
+ access.canCycleCount ? /* @__PURE__ */ jsx(
819
+ Button,
820
+ {
821
+ type: "button",
822
+ variant: "outline",
823
+ onClick: () => openCycleCountDialog(resolveMutationContext()),
824
+ children: t("wms.backend.sku.distribution.actions.cycleCountZone", "Cycle count zone")
825
+ }
826
+ ) : null,
827
+ access.canAdjust && selectedBalances.length > 0 ? /* @__PURE__ */ jsx(
828
+ Button,
829
+ {
830
+ type: "button",
831
+ variant: "default",
832
+ onClick: () => openAdjustDialog(resolveMutationContext()),
833
+ children: t("wms.backend.sku.distribution.actions.adjustSelected", "Adjust selected ({count})", { count: selectedBalances.length })
834
+ }
835
+ ) : null
836
+ ] })
837
+ ] }),
838
+ /* @__PURE__ */ jsx(
839
+ DataTable,
840
+ {
841
+ embedded: true,
842
+ columns: distributionColumns,
843
+ data: pagedBalances,
844
+ disableRowClick: true,
845
+ entityId: E.wms.inventory_balance,
846
+ perspective: { tableId: "wms.sku.distribution" },
847
+ pagination: {
848
+ page: distributionPage,
849
+ pageSize: distributionPageSize,
850
+ total: distributionTotal,
851
+ totalPages: distributionTotalPages,
852
+ onPageChange: setDistributionPage
853
+ },
854
+ emptyState: /* @__PURE__ */ jsx(
855
+ EmptyState,
856
+ {
857
+ title: t("wms.backend.sku.distribution.empty.title", "No locations in this view"),
858
+ description: t(
859
+ "wms.backend.sku.distribution.empty.description",
860
+ "Try another filter or post inventory through receipts or adjustments."
861
+ )
862
+ }
863
+ )
864
+ }
865
+ ),
866
+ 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: [
867
+ /* @__PURE__ */ jsx("span", { children: t("wms.backend.sku.distribution.footer.showing", "Showing {shown} of {total} locations", {
868
+ shown: pagedBalances.length,
869
+ total: distributionTotal
870
+ }) }),
871
+ balancesQuery.data && balancesQuery.data.total > distributionTotal ? /* @__PURE__ */ jsx(LinkButton, { asChild: true, variant: "gray", size: "sm", className: "h-auto px-0", children: /* @__PURE__ */ jsx(Link, { href: inventoryHref, children: t("wms.backend.sku.distribution.footer.viewAll", "View all locations \u2192") }) }) : null
872
+ ] }) : null
873
+ ]
874
+ }
875
+ ),
876
+ /* @__PURE__ */ jsx(
877
+ DataTable,
878
+ {
879
+ title: t("wms.backend.sku.activity.title", "Recent activity"),
880
+ columns: activityColumns,
881
+ data: movementsQuery.data ?? [],
882
+ disableRowClick: true,
883
+ entityId: E.wms.inventory_movement,
884
+ perspective: { tableId: "wms.sku.activity" },
885
+ emptyState: t("wms.backend.sku.activity.empty", "No recent movements for this SKU."),
886
+ actions: /* @__PURE__ */ jsx(Button, { asChild: true, type: "button", variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(Link, { href: movementsHref, children: t("wms.backend.sku.activity.viewAll", "View all movements \u2192") }) })
887
+ }
888
+ ),
889
+ /* @__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: [
890
+ /* @__PURE__ */ jsxs("div", { children: [
891
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: t("wms.backend.sku.quickActions.title", "Quick actions") }),
892
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t(
893
+ "wms.backend.sku.quickActions.description",
894
+ "Run common inventory actions without leaving this SKU view"
895
+ ) })
896
+ ] }),
897
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
898
+ access.canReceive ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "default", onClick: () => setReceiveOpen(true), children: [
899
+ /* @__PURE__ */ jsx(ArrowDown, { className: "size-4" }),
900
+ t("wms.backend.sku.quickActions.receive", "Receive stock")
901
+ ] }) : null,
902
+ access.canAdjust ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", onClick: () => openAdjustDialog(), children: [
903
+ /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-4" }),
904
+ t("wms.backend.sku.quickActions.adjust", "Adjust inventory")
905
+ ] }) : null,
906
+ access.canAdjust ? /* @__PURE__ */ jsx(Button, { asChild: true, type: "button", variant: "outline", children: /* @__PURE__ */ jsxs(Link, { href: inventoryConsoleHref, children: [
907
+ /* @__PURE__ */ jsx(ArrowLeftRight, { className: "size-4" }),
908
+ t("wms.backend.sku.quickActions.move", "Move stock")
909
+ ] }) }) : null,
910
+ access.canCycleCount ? /* @__PURE__ */ jsxs(
911
+ Button,
912
+ {
913
+ type: "button",
914
+ variant: "outline",
915
+ onClick: () => openCycleCountDialog(resolveMutationContext()),
916
+ children: [
917
+ /* @__PURE__ */ jsx(ClipboardList, { className: "size-4" }),
918
+ t("wms.backend.sku.quickActions.cycleCount", "Cycle count")
919
+ ]
920
+ }
921
+ ) : null,
922
+ /* @__PURE__ */ jsx(Button, { asChild: true, type: "button", variant: "outline", children: /* @__PURE__ */ jsxs(Link, { href: movementsHref, children: [
923
+ t("wms.backend.sku.quickActions.openLedger", "Open ledger"),
924
+ /* @__PURE__ */ jsx(ExternalLink, { className: "size-4" })
925
+ ] }) })
926
+ ] })
927
+ ] })
928
+ ] }) : null,
929
+ !isLoading && !hasError && !variantQuery.data ? /* @__PURE__ */ jsx(
930
+ RecordNotFoundState,
931
+ {
932
+ label: t("wms.backend.sku.errors.notFound", "SKU not found."),
933
+ backHref: inventoryHref,
934
+ backLabel: t("wms.backend.sku.actions.backToInventory", "Back to inventory")
935
+ }
936
+ ) : null
937
+ ] }),
938
+ access.canReceive && catalogVariantId ? /* @__PURE__ */ jsx(
939
+ ReceiveInventoryDialog,
940
+ {
941
+ open: receiveOpen,
942
+ onOpenChange: setReceiveOpen,
943
+ access,
944
+ initialCatalogVariantId: catalogVariantId
945
+ }
946
+ ) : null,
947
+ access.canAdjust && catalogVariantId ? /* @__PURE__ */ jsx(
948
+ AdjustInventoryDialog,
949
+ {
950
+ open: adjustOpen,
951
+ onOpenChange: setAdjustOpen,
952
+ access,
953
+ initialCatalogVariantId: catalogVariantId,
954
+ initialWarehouseId: adjustPreset.warehouseId,
955
+ initialLocationId: adjustPreset.locationId,
956
+ initialLotId: adjustPreset.lotId
957
+ }
958
+ ) : null,
959
+ access.canCycleCount ? /* @__PURE__ */ jsx(
960
+ CycleCountWizardDialog,
961
+ {
962
+ open: cycleOpen,
963
+ onOpenChange: setCycleOpen,
964
+ access,
965
+ initialCatalogVariantId: catalogVariantId ?? void 0,
966
+ initialWarehouseId: cyclePreset.warehouseId,
967
+ initialLocationId: cyclePreset.locationId
968
+ }
969
+ ) : null
970
+ ] });
971
+ }
972
+ export {
973
+ WmsSkuDetailPage as default
974
+ };
975
+ //# sourceMappingURL=WmsSkuDetailPage.js.map