@open-mercato/core 0.10.1-develop.7709.1.046124599c → 0.10.1-develop.7714.1.9dbb8200d8

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 (276) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/asn/index.js +19 -0
  3. package/dist/generated/entities/asn/index.js.map +7 -0
  4. package/dist/generated/entities/putaway_task/index.js +25 -0
  5. package/dist/generated/entities/putaway_task/index.js.map +7 -0
  6. package/dist/generated/entities/receiving_line/index.js +21 -0
  7. package/dist/generated/entities/receiving_line/index.js.map +7 -0
  8. package/dist/generated/entities.ids.generated.js +4 -1
  9. package/dist/generated/entities.ids.generated.js.map +2 -2
  10. package/dist/generated/entity-fields-registry.js +34 -0
  11. package/dist/generated/entity-fields-registry.js.map +2 -2
  12. package/dist/modules/communication_channels/lib/sanitize-channel-html.js +22 -3
  13. package/dist/modules/communication_channels/lib/sanitize-channel-html.js.map +2 -2
  14. package/dist/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.js +40 -11
  15. package/dist/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.js.map +2 -2
  16. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +13 -2
  17. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
  18. package/dist/modules/wms/acl.js +2 -0
  19. package/dist/modules/wms/acl.js.map +2 -2
  20. package/dist/modules/wms/api/asns/[id]/complete/route.js +61 -0
  21. package/dist/modules/wms/api/asns/[id]/complete/route.js.map +7 -0
  22. package/dist/modules/wms/api/asns/[id]/receive/route.js +68 -0
  23. package/dist/modules/wms/api/asns/[id]/receive/route.js.map +7 -0
  24. package/dist/modules/wms/api/asns/route.js +197 -0
  25. package/dist/modules/wms/api/asns/route.js.map +7 -0
  26. package/dist/modules/wms/api/inventory/helpers.js +42 -34
  27. package/dist/modules/wms/api/inventory/helpers.js.map +2 -2
  28. package/dist/modules/wms/api/inventory/receive/route.js +1 -1
  29. package/dist/modules/wms/api/inventory/receive/route.js.map +2 -2
  30. package/dist/modules/wms/api/listEnrichers.js +23 -0
  31. package/dist/modules/wms/api/listEnrichers.js.map +2 -2
  32. package/dist/modules/wms/api/putaway-tasks/[id]/assign/route.js +56 -0
  33. package/dist/modules/wms/api/putaway-tasks/[id]/assign/route.js.map +7 -0
  34. package/dist/modules/wms/api/putaway-tasks/[id]/cancel/route.js +56 -0
  35. package/dist/modules/wms/api/putaway-tasks/[id]/cancel/route.js.map +7 -0
  36. package/dist/modules/wms/api/putaway-tasks/[id]/complete/route.js +65 -0
  37. package/dist/modules/wms/api/putaway-tasks/[id]/complete/route.js.map +7 -0
  38. package/dist/modules/wms/api/putaway-tasks/[id]/start/route.js +56 -0
  39. package/dist/modules/wms/api/putaway-tasks/[id]/start/route.js.map +7 -0
  40. package/dist/modules/wms/api/putaway-tasks/create-from-balance/route.js +51 -0
  41. package/dist/modules/wms/api/putaway-tasks/create-from-balance/route.js.map +7 -0
  42. package/dist/modules/wms/api/putaway-tasks/route.js +192 -0
  43. package/dist/modules/wms/api/putaway-tasks/route.js.map +7 -0
  44. package/dist/modules/wms/api/receiving-lines/route.js +180 -0
  45. package/dist/modules/wms/api/receiving-lines/route.js.map +7 -0
  46. package/dist/modules/wms/api/scan/putaway/route.js +104 -0
  47. package/dist/modules/wms/api/scan/putaway/route.js.map +7 -0
  48. package/dist/modules/wms/api/scan/receive/route.js +109 -0
  49. package/dist/modules/wms/api/scan/receive/route.js.map +7 -0
  50. package/dist/modules/wms/api/scan/resolve-location/route.js +89 -0
  51. package/dist/modules/wms/api/scan/resolve-location/route.js.map +7 -0
  52. package/dist/modules/wms/api/scan/resolve-lot/route.js +89 -0
  53. package/dist/modules/wms/api/scan/resolve-lot/route.js.map +7 -0
  54. package/dist/modules/wms/backend/wms/asns/[id]/page.js +9 -0
  55. package/dist/modules/wms/backend/wms/asns/[id]/page.js.map +7 -0
  56. package/dist/modules/wms/backend/wms/asns/[id]/page.meta.js +18 -0
  57. package/dist/modules/wms/backend/wms/asns/[id]/page.meta.js.map +7 -0
  58. package/dist/modules/wms/backend/wms/asns/page.js +9 -0
  59. package/dist/modules/wms/backend/wms/asns/page.js.map +7 -0
  60. package/dist/modules/wms/backend/wms/asns/page.meta.js +18 -0
  61. package/dist/modules/wms/backend/wms/asns/page.meta.js.map +7 -0
  62. package/dist/modules/wms/backend/wms/putaway/page.js +9 -0
  63. package/dist/modules/wms/backend/wms/putaway/page.js.map +7 -0
  64. package/dist/modules/wms/backend/wms/putaway/page.meta.js +18 -0
  65. package/dist/modules/wms/backend/wms/putaway/page.meta.js.map +7 -0
  66. package/dist/modules/wms/backend/wms/receiving/page.js +8 -0
  67. package/dist/modules/wms/backend/wms/receiving/page.js.map +7 -0
  68. package/dist/modules/wms/backend/wms/receiving/page.meta.js +18 -0
  69. package/dist/modules/wms/backend/wms/receiving/page.meta.js.map +7 -0
  70. package/dist/modules/wms/ce.js +27 -0
  71. package/dist/modules/wms/ce.js.map +2 -2
  72. package/dist/modules/wms/commands/asn.js +1746 -0
  73. package/dist/modules/wms/commands/asn.js.map +7 -0
  74. package/dist/modules/wms/commands/index.js +2 -0
  75. package/dist/modules/wms/commands/index.js.map +2 -2
  76. package/dist/modules/wms/commands/inventory-actions.js +347 -243
  77. package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
  78. package/dist/modules/wms/commands/putaway.js +945 -0
  79. package/dist/modules/wms/commands/putaway.js.map +7 -0
  80. package/dist/modules/wms/commands/shared.js +51 -0
  81. package/dist/modules/wms/commands/shared.js.map +2 -2
  82. package/dist/modules/wms/components/backend/AssignPutawayTaskDialog.js +278 -0
  83. package/dist/modules/wms/components/backend/AssignPutawayTaskDialog.js.map +7 -0
  84. package/dist/modules/wms/components/backend/CompletePutawayTaskDialog.js +327 -0
  85. package/dist/modules/wms/components/backend/CompletePutawayTaskDialog.js.map +7 -0
  86. package/dist/modules/wms/components/backend/CreateAsnDialog.js +404 -0
  87. package/dist/modules/wms/components/backend/CreateAsnDialog.js.map +7 -0
  88. package/dist/modules/wms/components/backend/InventoryOperationsSection.js +16 -3
  89. package/dist/modules/wms/components/backend/InventoryOperationsSection.js.map +2 -2
  90. package/dist/modules/wms/components/backend/ReceiveAsnLineDialog.js +476 -0
  91. package/dist/modules/wms/components/backend/ReceiveAsnLineDialog.js.map +7 -0
  92. package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js +2 -2
  93. package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js.map +2 -2
  94. package/dist/modules/wms/components/backend/WmsAsnDetailPage.js +524 -0
  95. package/dist/modules/wms/components/backend/WmsAsnDetailPage.js.map +7 -0
  96. package/dist/modules/wms/components/backend/WmsAsnsListPage.js +339 -0
  97. package/dist/modules/wms/components/backend/WmsAsnsListPage.js.map +7 -0
  98. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +5 -6
  99. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
  100. package/dist/modules/wms/components/backend/WmsLotDetailPage.js +5 -6
  101. package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
  102. package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js +14 -10
  103. package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js.map +2 -2
  104. package/dist/modules/wms/components/backend/WmsPutawayQueuePage.js +598 -0
  105. package/dist/modules/wms/components/backend/WmsPutawayQueuePage.js.map +7 -0
  106. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +5 -6
  107. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
  108. package/dist/modules/wms/components/backend/asnCompleteOptimisticLock.js +32 -0
  109. package/dist/modules/wms/components/backend/asnCompleteOptimisticLock.js.map +7 -0
  110. package/dist/modules/wms/components/backend/asnReceivingLinesLoader.js +36 -0
  111. package/dist/modules/wms/components/backend/asnReceivingLinesLoader.js.map +7 -0
  112. package/dist/modules/wms/components/backend/inboundStatusUi.js +106 -0
  113. package/dist/modules/wms/components/backend/inboundStatusUi.js.map +7 -0
  114. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +17 -0
  115. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
  116. package/dist/modules/wms/components/backend/putawayQueueOptimisticLock.js +14 -0
  117. package/dist/modules/wms/components/backend/putawayQueueOptimisticLock.js.map +7 -0
  118. package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js +4 -0
  119. package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js.map +2 -2
  120. package/dist/modules/wms/data/enrichers.js +117 -12
  121. package/dist/modules/wms/data/enrichers.js.map +2 -2
  122. package/dist/modules/wms/data/entities.js +150 -1
  123. package/dist/modules/wms/data/entities.js.map +2 -2
  124. package/dist/modules/wms/data/validators.js +214 -0
  125. package/dist/modules/wms/data/validators.js.map +2 -2
  126. package/dist/modules/wms/events.js +12 -1
  127. package/dist/modules/wms/events.js.map +2 -2
  128. package/dist/modules/wms/extension-points.js +3 -1
  129. package/dist/modules/wms/extension-points.js.map +2 -2
  130. package/dist/modules/wms/lib/asnReceiving.js +124 -0
  131. package/dist/modules/wms/lib/asnReceiving.js.map +7 -0
  132. package/dist/modules/wms/lib/asnVendor.js +52 -0
  133. package/dist/modules/wms/lib/asnVendor.js.map +7 -0
  134. package/dist/modules/wms/lib/flashMutationError.js +4 -0
  135. package/dist/modules/wms/lib/flashMutationError.js.map +2 -2
  136. package/dist/modules/wms/lib/inventoryDisplayUi.js +24 -0
  137. package/dist/modules/wms/lib/inventoryDisplayUi.js.map +2 -2
  138. package/dist/modules/wms/lib/inventoryPolicy.js +17 -0
  139. package/dist/modules/wms/lib/inventoryPolicy.js.map +2 -2
  140. package/dist/modules/wms/lib/loadOperationalDashboard.js +67 -1
  141. package/dist/modules/wms/lib/loadOperationalDashboard.js.map +2 -2
  142. package/dist/modules/wms/lib/putaway.js +141 -0
  143. package/dist/modules/wms/lib/putaway.js.map +7 -0
  144. package/dist/modules/wms/lib/roleFeatures.js +3 -1
  145. package/dist/modules/wms/lib/roleFeatures.js.map +2 -2
  146. package/dist/modules/wms/lib/salesOrderInventoryAutomation.js +99 -1
  147. package/dist/modules/wms/lib/salesOrderInventoryAutomation.js.map +2 -2
  148. package/dist/modules/wms/lib/scanResolve.js +147 -0
  149. package/dist/modules/wms/lib/scanResolve.js.map +7 -0
  150. package/dist/modules/wms/lib/wmsIntegrationToggles.js +1 -1
  151. package/dist/modules/wms/lib/wmsIntegrationToggles.js.map +2 -2
  152. package/dist/modules/wms/migrations/Migration20260812120000.js +43 -0
  153. package/dist/modules/wms/migrations/Migration20260812120000.js.map +7 -0
  154. package/dist/modules/wms/migrations/Migration20260812130000.js +30 -0
  155. package/dist/modules/wms/migrations/Migration20260812130000.js.map +7 -0
  156. package/dist/modules/wms/migrations/Migration20260822120000.js +17 -0
  157. package/dist/modules/wms/migrations/Migration20260822120000.js.map +7 -0
  158. package/dist/modules/wms/migrations/Migration20260822130000.js +17 -0
  159. package/dist/modules/wms/migrations/Migration20260822130000.js.map +7 -0
  160. package/dist/modules/wms/migrations/Migration20261029120000.js +13 -0
  161. package/dist/modules/wms/migrations/Migration20261029120000.js.map +7 -0
  162. package/dist/modules/wms/search.js +85 -0
  163. package/dist/modules/wms/search.js.map +2 -2
  164. package/dist/modules/wms/subscribers/asn-line-received-reevaluate-reservations.js +14 -0
  165. package/dist/modules/wms/subscribers/asn-line-received-reevaluate-reservations.js.map +7 -0
  166. package/dist/modules/wms/subscribers/invalidate-enricher-cache-asn.js +12 -0
  167. package/dist/modules/wms/subscribers/invalidate-enricher-cache-asn.js.map +7 -0
  168. package/dist/modules/wms/subscribers/procurement-goods-receipt-created.js +163 -0
  169. package/dist/modules/wms/subscribers/procurement-goods-receipt-created.js.map +7 -0
  170. package/dist/modules/wms/subscribers/putaway-completed-reevaluate-reservations.js +14 -0
  171. package/dist/modules/wms/subscribers/putaway-completed-reevaluate-reservations.js.map +7 -0
  172. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js +37 -8
  173. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js.map +2 -2
  174. package/generated/entities/asn/index.ts +8 -0
  175. package/generated/entities/putaway_task/index.ts +11 -0
  176. package/generated/entities/receiving_line/index.ts +9 -0
  177. package/generated/entities.ids.generated.ts +4 -1
  178. package/generated/entity-fields-registry.ts +34 -0
  179. package/package.json +7 -7
  180. package/src/modules/auth/i18n/de.json +2 -0
  181. package/src/modules/auth/i18n/en.json +2 -0
  182. package/src/modules/auth/i18n/es.json +2 -0
  183. package/src/modules/auth/i18n/ko.json +2 -0
  184. package/src/modules/auth/i18n/pl.json +2 -0
  185. package/src/modules/communication_channels/i18n/de.json +2 -0
  186. package/src/modules/communication_channels/i18n/en.json +2 -0
  187. package/src/modules/communication_channels/i18n/es.json +2 -0
  188. package/src/modules/communication_channels/i18n/ko.json +2 -0
  189. package/src/modules/communication_channels/i18n/pl.json +2 -0
  190. package/src/modules/communication_channels/lib/sanitize-channel-html.ts +23 -3
  191. package/src/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.tsx +44 -12
  192. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +16 -2
  193. package/src/modules/wms/acl.ts +2 -0
  194. package/src/modules/wms/api/asns/[id]/complete/route.ts +62 -0
  195. package/src/modules/wms/api/asns/[id]/receive/route.ts +74 -0
  196. package/src/modules/wms/api/asns/route.ts +200 -0
  197. package/src/modules/wms/api/inventory/helpers.ts +57 -34
  198. package/src/modules/wms/api/inventory/receive/route.ts +2 -1
  199. package/src/modules/wms/api/listEnrichers.ts +38 -0
  200. package/src/modules/wms/api/putaway-tasks/[id]/assign/route.ts +56 -0
  201. package/src/modules/wms/api/putaway-tasks/[id]/cancel/route.ts +56 -0
  202. package/src/modules/wms/api/putaway-tasks/[id]/complete/route.ts +66 -0
  203. package/src/modules/wms/api/putaway-tasks/[id]/start/route.ts +56 -0
  204. package/src/modules/wms/api/putaway-tasks/create-from-balance/route.ts +50 -0
  205. package/src/modules/wms/api/putaway-tasks/route.ts +199 -0
  206. package/src/modules/wms/api/receiving-lines/route.ts +180 -0
  207. package/src/modules/wms/api/scan/putaway/route.ts +108 -0
  208. package/src/modules/wms/api/scan/receive/route.ts +118 -0
  209. package/src/modules/wms/api/scan/resolve-location/route.ts +92 -0
  210. package/src/modules/wms/api/scan/resolve-lot/route.ts +92 -0
  211. package/src/modules/wms/backend/wms/asns/[id]/page.meta.ts +14 -0
  212. package/src/modules/wms/backend/wms/asns/[id]/page.tsx +5 -0
  213. package/src/modules/wms/backend/wms/asns/page.meta.ts +14 -0
  214. package/src/modules/wms/backend/wms/asns/page.tsx +5 -0
  215. package/src/modules/wms/backend/wms/putaway/page.meta.ts +14 -0
  216. package/src/modules/wms/backend/wms/putaway/page.tsx +5 -0
  217. package/src/modules/wms/backend/wms/receiving/page.meta.ts +14 -0
  218. package/src/modules/wms/backend/wms/receiving/page.tsx +5 -0
  219. package/src/modules/wms/ce.ts +27 -0
  220. package/src/modules/wms/commands/asn.ts +2122 -0
  221. package/src/modules/wms/commands/index.ts +2 -0
  222. package/src/modules/wms/commands/inventory-actions.ts +413 -243
  223. package/src/modules/wms/commands/putaway.ts +1169 -0
  224. package/src/modules/wms/commands/shared.ts +51 -0
  225. package/src/modules/wms/components/backend/AssignPutawayTaskDialog.tsx +328 -0
  226. package/src/modules/wms/components/backend/CompletePutawayTaskDialog.tsx +366 -0
  227. package/src/modules/wms/components/backend/CreateAsnDialog.tsx +427 -0
  228. package/src/modules/wms/components/backend/InventoryOperationsSection.tsx +20 -2
  229. package/src/modules/wms/components/backend/ReceiveAsnLineDialog.tsx +535 -0
  230. package/src/modules/wms/components/backend/ReceiveInventoryDialog.tsx +2 -2
  231. package/src/modules/wms/components/backend/WmsAsnDetailPage.tsx +647 -0
  232. package/src/modules/wms/components/backend/WmsAsnsListPage.tsx +407 -0
  233. package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +4 -5
  234. package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +4 -5
  235. package/src/modules/wms/components/backend/WmsOperationalDashboardPage.tsx +12 -8
  236. package/src/modules/wms/components/backend/WmsPutawayQueuePage.tsx +677 -0
  237. package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +4 -5
  238. package/src/modules/wms/components/backend/asnCompleteOptimisticLock.ts +52 -0
  239. package/src/modules/wms/components/backend/asnReceivingLinesLoader.ts +83 -0
  240. package/src/modules/wms/components/backend/inboundStatusUi.ts +154 -0
  241. package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +20 -0
  242. package/src/modules/wms/components/backend/putawayQueueOptimisticLock.ts +20 -0
  243. package/src/modules/wms/components/backend/useWmsInventoryMutationAccess.ts +4 -0
  244. package/src/modules/wms/data/enrichers.ts +175 -13
  245. package/src/modules/wms/data/entities.ts +155 -0
  246. package/src/modules/wms/data/validators.ts +256 -0
  247. package/src/modules/wms/events.ts +11 -0
  248. package/src/modules/wms/extension-points.ts +2 -0
  249. package/src/modules/wms/i18n/de.json +205 -3
  250. package/src/modules/wms/i18n/en.json +205 -3
  251. package/src/modules/wms/i18n/es.json +205 -3
  252. package/src/modules/wms/i18n/ko.json +205 -3
  253. package/src/modules/wms/i18n/pl.json +205 -3
  254. package/src/modules/wms/lib/asnReceiving.ts +226 -0
  255. package/src/modules/wms/lib/asnVendor.ts +80 -0
  256. package/src/modules/wms/lib/flashMutationError.ts +4 -0
  257. package/src/modules/wms/lib/inventoryDisplayUi.ts +46 -0
  258. package/src/modules/wms/lib/inventoryPolicy.ts +31 -1
  259. package/src/modules/wms/lib/loadOperationalDashboard.ts +89 -1
  260. package/src/modules/wms/lib/putaway.ts +210 -0
  261. package/src/modules/wms/lib/roleFeatures.ts +2 -0
  262. package/src/modules/wms/lib/salesOrderInventoryAutomation.ts +150 -1
  263. package/src/modules/wms/lib/scanResolve.ts +185 -0
  264. package/src/modules/wms/lib/wmsIntegrationToggles.ts +2 -1
  265. package/src/modules/wms/migrations/.snapshot-open-mercato.json +1000 -0
  266. package/src/modules/wms/migrations/Migration20260812120000.ts +43 -0
  267. package/src/modules/wms/migrations/Migration20260812130000.ts +28 -0
  268. package/src/modules/wms/migrations/Migration20260822120000.ts +17 -0
  269. package/src/modules/wms/migrations/Migration20260822130000.ts +15 -0
  270. package/src/modules/wms/migrations/Migration20261029120000.ts +11 -0
  271. package/src/modules/wms/search.ts +95 -0
  272. package/src/modules/wms/subscribers/asn-line-received-reevaluate-reservations.ts +21 -0
  273. package/src/modules/wms/subscribers/invalidate-enricher-cache-asn.ts +12 -0
  274. package/src/modules/wms/subscribers/procurement-goods-receipt-created.ts +238 -0
  275. package/src/modules/wms/subscribers/putaway-completed-reevaluate-reservations.ts +21 -0
  276. package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.client.tsx +63 -13
@@ -0,0 +1,407 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import Link from 'next/link'
5
+ import { useRouter, useSearchParams } from 'next/navigation'
6
+ import type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'
7
+ import type { SortingState } from '@tanstack/react-table'
8
+ import { useQuery } from '@tanstack/react-query'
9
+ import { ClipboardList, PackagePlus } from 'lucide-react'
10
+ import { Page, PageBody, PageHeader } from '@open-mercato/ui/backend/Page'
11
+ import { DataTable } from '@open-mercato/ui/backend/DataTable'
12
+ import { EmptyState } from '@open-mercato/ui/backend/EmptyState'
13
+ import { RowActions } from '@open-mercato/ui/backend/RowActions'
14
+ import { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'
15
+ import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
16
+ import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
17
+ import { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'
18
+ import { Button } from '@open-mercato/ui/primitives/button'
19
+ import {
20
+ Select,
21
+ SelectContent,
22
+ SelectItem,
23
+ SelectTrigger,
24
+ SelectValue,
25
+ } from '@open-mercato/ui/primitives/select'
26
+ import { StatusBadge } from '@open-mercato/ui/primitives/status-badge'
27
+ import { E } from '#generated/entities.ids.generated'
28
+ import { extensionPoints } from '@open-mercato/core/modules/wms/extension-points'
29
+ import { CreateAsnDialog } from './CreateAsnDialog'
30
+ import { asnStatusVariant } from './inboundStatusUi'
31
+ import { useWmsInventoryMutationAccess } from './useWmsInventoryMutationAccess'
32
+ import { loadWarehouseOptions, resolveWarehouseLabel } from './inventoryMutationLoaders'
33
+
34
+ type AsnRow = {
35
+ id: string
36
+ warehouse_id?: string | null
37
+ vendor_id?: string | null
38
+ status?: string | null
39
+ expected_at?: string | null
40
+ reference_number?: string | null
41
+ notes?: string | null
42
+ created_at?: string | null
43
+ updated_at?: string | null
44
+ }
45
+
46
+ type PagedResponse<T> = {
47
+ items: T[]
48
+ total: number
49
+ totalPages: number
50
+ totalIsCapped?: boolean
51
+ }
52
+
53
+ /** Server-side multi-status for `?queue=open` (mirrors putaway `open,in_progress`). */
54
+ const OPEN_QUEUE_STATUS_PARAM = 'draft,in_transit'
55
+
56
+ export default function WmsAsnsListPage() {
57
+ const t = useT()
58
+ const locale = useLocale()
59
+ const router = useRouter()
60
+ const searchParams = useSearchParams()
61
+ const access = useWmsInventoryMutationAccess()
62
+ const queueOpen = searchParams.get('queue') === 'open'
63
+ const statusFromUrl = searchParams.get('status')?.trim() || ''
64
+
65
+ const [page, setPage] = React.useState(1)
66
+ const [search, setSearch] = React.useState('')
67
+ const [statusFilter, setStatusFilter] = React.useState(statusFromUrl || (queueOpen ? '' : ''))
68
+ const [warehouseId, setWarehouseId] = React.useState('')
69
+ const [warehouseOptions, setWarehouseOptions] = React.useState<Array<{ value: string; label: string }>>([])
70
+ const [warehouseLabels, setWarehouseLabels] = React.useState<Record<string, string>>({})
71
+ const [sorting, setSorting] = React.useState<SortingState>([{ id: 'expectedAt', desc: false }])
72
+ const [createOpen, setCreateOpen] = React.useState(false)
73
+
74
+ React.useEffect(() => {
75
+ setStatusFilter(statusFromUrl)
76
+ }, [statusFromUrl])
77
+
78
+ React.useEffect(() => {
79
+ let cancelled = false
80
+ void loadWarehouseOptions().then((options) => {
81
+ if (!cancelled) setWarehouseOptions(options)
82
+ })
83
+ return () => {
84
+ cancelled = true
85
+ }
86
+ }, [])
87
+
88
+ const dateFormatter = React.useMemo(
89
+ () =>
90
+ new Intl.DateTimeFormat(locale, {
91
+ year: 'numeric',
92
+ month: '2-digit',
93
+ day: '2-digit',
94
+ }),
95
+ [locale],
96
+ )
97
+
98
+ const queryKey = React.useMemo(
99
+ () => ['wms-asns-list', page, search, statusFilter, warehouseId, sorting, queueOpen],
100
+ [page, queueOpen, search, sorting, statusFilter, warehouseId],
101
+ )
102
+
103
+ const asnsQuery = useQuery({
104
+ queryKey,
105
+ queryFn: async () => {
106
+ const sortCol = sorting[0]
107
+ const params = new URLSearchParams({
108
+ page: String(page),
109
+ pageSize: '50',
110
+ sortField: sortCol ? sortCol.id : 'expectedAt',
111
+ sortDir: sortCol ? (sortCol.desc ? 'desc' : 'asc') : 'asc',
112
+ })
113
+ if (search.trim()) params.set('search', search.trim())
114
+ if (statusFilter) params.set('status', statusFilter)
115
+ else if (queueOpen) params.set('status', OPEN_QUEUE_STATUS_PARAM)
116
+ if (warehouseId) params.set('warehouseId', warehouseId)
117
+ const call = await apiCall<PagedResponse<AsnRow>>(`/api/wms/asns?${params.toString()}`)
118
+ if (!call.ok) {
119
+ await raiseCrudError(call.response, t('wms.backend.asns.errors.load', 'Failed to load ASNs.'))
120
+ }
121
+ return call.result ?? { items: [], total: 0, totalPages: 1 }
122
+ },
123
+ })
124
+
125
+ React.useEffect(() => {
126
+ const ids = Array.from(
127
+ new Set(
128
+ (asnsQuery.data?.items ?? [])
129
+ .map((row) => row.warehouse_id)
130
+ .filter((id): id is string => typeof id === 'string' && id.length > 0),
131
+ ),
132
+ )
133
+ if (ids.length === 0) return
134
+ let cancelled = false
135
+ void Promise.all(ids.map(async (id) => [id, await resolveWarehouseLabel(id)] as const)).then(
136
+ (entries) => {
137
+ if (cancelled) return
138
+ setWarehouseLabels((prev) => {
139
+ const next = { ...prev }
140
+ for (const [id, label] of entries) {
141
+ if (label) next[id] = label
142
+ }
143
+ return next
144
+ })
145
+ },
146
+ )
147
+ return () => {
148
+ cancelled = true
149
+ }
150
+ }, [asnsQuery.data?.items])
151
+
152
+ const statusLabel = React.useCallback(
153
+ (status: string) => t(`wms.backend.asns.status.${status}`, status),
154
+ [t],
155
+ )
156
+
157
+ const columns = React.useMemo<ColumnDef<AsnRow>[]>(
158
+ () => [
159
+ {
160
+ accessorKey: 'reference_number',
161
+ id: 'referenceNumber',
162
+ header: t('wms.backend.asns.columns.reference', 'Reference'),
163
+ enableSorting: true,
164
+ cell: ({ row }) => {
165
+ const label = row.original.reference_number?.trim() || row.original.id.slice(0, 8)
166
+ return (
167
+ <Link
168
+ href={`/backend/wms/asns/${encodeURIComponent(row.original.id)}`}
169
+ className="font-medium text-primary hover:underline"
170
+ >
171
+ {label}
172
+ </Link>
173
+ )
174
+ },
175
+ },
176
+ {
177
+ accessorKey: 'status',
178
+ id: 'status',
179
+ header: t('wms.backend.asns.columns.status', 'Status'),
180
+ enableSorting: true,
181
+ cell: ({ row }) => {
182
+ const status = row.original.status?.trim()
183
+ if (!status) return '—'
184
+ return (
185
+ <StatusBadge variant={asnStatusVariant(status)} dot>
186
+ {statusLabel(status)}
187
+ </StatusBadge>
188
+ )
189
+ },
190
+ },
191
+ {
192
+ accessorKey: 'warehouse_id',
193
+ id: 'warehouse',
194
+ header: t('wms.backend.asns.columns.warehouse', 'Warehouse'),
195
+ enableSorting: false,
196
+ cell: ({ row }) => {
197
+ const id = row.original.warehouse_id
198
+ if (!id) return '—'
199
+ return warehouseLabels[id] || id.slice(0, 8)
200
+ },
201
+ },
202
+ {
203
+ accessorKey: 'expected_at',
204
+ id: 'expectedAt',
205
+ header: t('wms.backend.asns.columns.expectedAt', 'Expected'),
206
+ enableSorting: true,
207
+ cell: ({ row }) => {
208
+ const value = row.original.expected_at
209
+ if (!value) return '—'
210
+ const date = new Date(value)
211
+ if (Number.isNaN(date.getTime())) return '—'
212
+ return dateFormatter.format(date)
213
+ },
214
+ },
215
+ ],
216
+ [dateFormatter, statusLabel, t, warehouseLabels],
217
+ )
218
+
219
+ const rowActions = React.useCallback(
220
+ (row: AsnRow) => (
221
+ <RowActions
222
+ items={[
223
+ {
224
+ id: 'open',
225
+ label: t('wms.backend.asns.actions.open', 'Open receiving'),
226
+ onSelect: () => router.push(`/backend/wms/asns/${encodeURIComponent(row.id)}`),
227
+ },
228
+ ]}
229
+ />
230
+ ),
231
+ [router, t],
232
+ )
233
+
234
+ const title = queueOpen
235
+ ? t('wms.backend.receiving.title', 'Receiving queue')
236
+ : t('wms.backend.asns.title', 'ASNs')
237
+ const description = queueOpen
238
+ ? t(
239
+ 'wms.backend.receiving.description',
240
+ 'Open and in-transit ASNs ready for receiving.',
241
+ )
242
+ : t('wms.backend.asns.description', 'Advance shipping notices and inbound receiving.')
243
+
244
+ return (
245
+ <Page>
246
+ <PageBody className="space-y-6">
247
+ <PageHeader
248
+ title={title}
249
+ description={description}
250
+ actions={
251
+ <div className="flex flex-wrap gap-2">
252
+ {access.canManagePutaway ? (
253
+ <Button type="button" variant="outline" asChild>
254
+ <Link href="/backend/wms/putaway">
255
+ {t('wms.backend.asns.actions.putawayQueue', 'Putaway queue')}
256
+ </Link>
257
+ </Button>
258
+ ) : null}
259
+ {access.canManageAsn ? (
260
+ <Button type="button" onClick={() => setCreateOpen(true)}>
261
+ <PackagePlus className="size-4" />
262
+ {t('wms.backend.asns.actions.create', 'Create ASN')}
263
+ </Button>
264
+ ) : null}
265
+ </div>
266
+ }
267
+ />
268
+
269
+ {asnsQuery.isLoading ? (
270
+ <LoadingMessage label={t('wms.backend.asns.loading', 'Loading ASNs…')} />
271
+ ) : null}
272
+ {asnsQuery.isError ? (
273
+ <ErrorMessage label={t('wms.backend.asns.errors.load', 'Failed to load ASNs.')} />
274
+ ) : null}
275
+
276
+ {asnsQuery.data ? (
277
+ <section className="rounded-lg border bg-card p-5 text-card-foreground shadow-sm">
278
+ <div className="mb-4 flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
279
+ <div className="flex items-start gap-3">
280
+ <div className="rounded-md border bg-muted/40 p-2 text-muted-foreground">
281
+ <ClipboardList className="size-5" />
282
+ </div>
283
+ <div className="space-y-1">
284
+ <h2 className="text-xl font-semibold">{title}</h2>
285
+ <p className="text-sm text-muted-foreground">{description}</p>
286
+ </div>
287
+ </div>
288
+ <div className="flex flex-wrap gap-2">
289
+ <Select
290
+ value={statusFilter || (queueOpen ? 'queue-open' : 'all')}
291
+ onValueChange={(value) => {
292
+ setPage(1)
293
+ if (value === 'queue-open') {
294
+ setStatusFilter('')
295
+ router.replace('/backend/wms/asns?queue=open')
296
+ return
297
+ }
298
+ if (value === 'all') {
299
+ setStatusFilter('')
300
+ router.replace('/backend/wms/asns')
301
+ return
302
+ }
303
+ setStatusFilter(value)
304
+ router.replace(`/backend/wms/asns?status=${encodeURIComponent(value)}`)
305
+ }}
306
+ >
307
+ <SelectTrigger className="w-[180px]" data-testid="asn-status-filter">
308
+ <SelectValue />
309
+ </SelectTrigger>
310
+ <SelectContent>
311
+ <SelectItem value="all">{t('wms.backend.asns.filters.statusAll', 'All statuses')}</SelectItem>
312
+ <SelectItem value="queue-open">
313
+ {t('wms.backend.asns.filters.statusOpen', 'Open receiving')}
314
+ </SelectItem>
315
+ <SelectItem value="draft">{statusLabel('draft')}</SelectItem>
316
+ <SelectItem value="in_transit">{statusLabel('in_transit')}</SelectItem>
317
+ <SelectItem value="received">{statusLabel('received')}</SelectItem>
318
+ <SelectItem value="closed">{statusLabel('closed')}</SelectItem>
319
+ </SelectContent>
320
+ </Select>
321
+ <Select
322
+ value={warehouseId || 'all'}
323
+ onValueChange={(value) => {
324
+ setPage(1)
325
+ setWarehouseId(value === 'all' ? '' : value)
326
+ }}
327
+ >
328
+ <SelectTrigger className="w-[200px]" data-testid="asn-warehouse-filter">
329
+ <SelectValue placeholder={t('wms.backend.asns.filters.warehouse', 'Warehouse')} />
330
+ </SelectTrigger>
331
+ <SelectContent>
332
+ <SelectItem value="all">
333
+ {t('wms.backend.asns.filters.warehouseAll', 'All warehouses')}
334
+ </SelectItem>
335
+ {warehouseOptions.map((option) => (
336
+ <SelectItem key={option.value} value={option.value}>
337
+ {option.label}
338
+ </SelectItem>
339
+ ))}
340
+ </SelectContent>
341
+ </Select>
342
+ </div>
343
+ </div>
344
+
345
+ <DataTable
346
+ embedded
347
+ title={title}
348
+ columns={columns}
349
+ data={asnsQuery.data.items}
350
+ isLoading={asnsQuery.isFetching}
351
+ entityId={E.wms.asn}
352
+ searchValue={search}
353
+ onSearchChange={(value) => {
354
+ setSearch(value)
355
+ setPage(1)
356
+ }}
357
+ searchPlaceholder={t('wms.backend.asns.search', 'Search ASNs')}
358
+ sortable
359
+ manualSorting
360
+ sorting={sorting}
361
+ onSortingChange={(next) => {
362
+ setSorting(next)
363
+ setPage(1)
364
+ }}
365
+ rowActions={rowActions}
366
+ onRowClick={(row) => router.push(`/backend/wms/asns/${encodeURIComponent(row.id)}`)}
367
+ pagination={{
368
+ page,
369
+ pageSize: 50,
370
+ total: asnsQuery.data.total,
371
+ totalPages: asnsQuery.data.totalPages,
372
+ totalIsCapped: asnsQuery.data?.totalIsCapped === true,
373
+ onPageChange: setPage,
374
+ }}
375
+ perspective={{ tableId: extensionPoints.hosts.asnsTable.tableId }}
376
+ emptyState={
377
+ <EmptyState
378
+ title={t('wms.backend.asns.empty.title', 'No ASNs')}
379
+ description={t(
380
+ 'wms.backend.asns.empty.description',
381
+ 'Create an ASN to start expected inbound receiving.',
382
+ )}
383
+ actions={
384
+ access.canManageAsn ? (
385
+ <Button type="button" size="sm" onClick={() => setCreateOpen(true)}>
386
+ {t('wms.backend.asns.actions.create', 'Create ASN')}
387
+ </Button>
388
+ ) : null
389
+ }
390
+ />
391
+ }
392
+ />
393
+ </section>
394
+ ) : null}
395
+ </PageBody>
396
+
397
+ {access.canManageAsn ? (
398
+ <CreateAsnDialog
399
+ open={createOpen}
400
+ onOpenChange={setCreateOpen}
401
+ access={access}
402
+ onCreated={(asnId) => router.push(`/backend/wms/asns/${encodeURIComponent(asnId)}`)}
403
+ />
404
+ ) : null}
405
+ </Page>
406
+ )
407
+ }
@@ -38,7 +38,7 @@ import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
38
38
  import { cn } from '@open-mercato/shared/lib/utils'
39
39
  import { E } from '#generated/entities.ids.generated'
40
40
  import {
41
- inventoryMovementReasonLabel,
41
+ formatInventoryMovementActivitySubtitle,
42
42
  type InventoryDisplayTranslator,
43
43
  } from '../../lib/inventoryDisplayUi'
44
44
  import { AdjustInventoryDialog } from './AdjustInventoryDialog'
@@ -340,17 +340,16 @@ function formatMovementSubtitle(
340
340
  row: InventoryMovementRow,
341
341
  t: InventoryDisplayTranslator,
342
342
  ): string | null {
343
- const reasonLabel = inventoryMovementReasonLabel(
343
+ return formatInventoryMovementActivitySubtitle(
344
344
  {
345
345
  reasonCode: row.reason_code,
346
346
  reason: row.reason,
347
347
  movementType: row.type,
348
+ referenceType: row.reference_type,
349
+ referenceId: row.reference_id,
348
350
  },
349
351
  t,
350
352
  )
351
- if (reasonLabel) return reasonLabel
352
- if (row.reference_type && row.reference_id) return `${row.reference_type} · ${row.reference_id}`
353
- return null
354
353
  }
355
354
 
356
355
  function formatMovementLocation(
@@ -37,7 +37,7 @@ import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
37
37
  import { cn } from '@open-mercato/shared/lib/utils'
38
38
  import { E } from '#generated/entities.ids.generated'
39
39
  import {
40
- inventoryMovementReasonLabel,
40
+ formatInventoryMovementActivitySubtitle,
41
41
  type InventoryDisplayTranslator,
42
42
  } from '../../lib/inventoryDisplayUi'
43
43
  import { AdjustInventoryDialog } from './AdjustInventoryDialog'
@@ -411,17 +411,16 @@ function formatMovementSubtitle(
411
411
  row: InventoryMovementRow,
412
412
  t: InventoryDisplayTranslator,
413
413
  ): string | null {
414
- const reasonLabel = inventoryMovementReasonLabel(
414
+ return formatInventoryMovementActivitySubtitle(
415
415
  {
416
416
  reasonCode: row.reason_code,
417
417
  reason: row.reason,
418
418
  movementType: row.type,
419
+ referenceType: row.reference_type,
420
+ referenceId: row.reference_id,
419
421
  },
420
422
  t,
421
423
  )
422
- if (reasonLabel) return reasonLabel
423
- if (row.reference_type && row.reference_id) return `${row.reference_type} · ${row.reference_id}`
424
- return null
425
424
  }
426
425
 
427
426
  function formatMovementLocation(row: InventoryMovementRow): string {
@@ -39,7 +39,7 @@ import type {
39
39
  OperationalDashboardPayload,
40
40
  } from '../../lib/loadOperationalDashboard'
41
41
  import {
42
- inventoryMovementReasonLabel,
42
+ formatInventoryMovementActivitySubtitle,
43
43
  type InventoryDisplayTranslator,
44
44
  } from '../../lib/inventoryDisplayUi'
45
45
  import { AdjustInventoryDialog } from './AdjustInventoryDialog'
@@ -138,17 +138,18 @@ function formatActivitySubtitle(
138
138
  row: OperationalDashboardActivityRow,
139
139
  t: InventoryDisplayTranslator,
140
140
  ): string | null {
141
- const reasonLabel = inventoryMovementReasonLabel(
141
+ return formatInventoryMovementActivitySubtitle(
142
142
  {
143
143
  reasonCode: row.reasonCode,
144
144
  reason: row.reason,
145
145
  movementType: row.movementType,
146
+ referenceType: row.referenceType,
147
+ referenceId: row.referenceId,
148
+ referenceLabel: row.referenceLabel,
149
+ source: row.source,
146
150
  },
147
151
  t,
148
152
  )
149
- if (reasonLabel) return reasonLabel
150
- if (row.referenceType && row.referenceId) return `${row.referenceType} · ${row.referenceId}`
151
- return null
152
153
  }
153
154
 
154
155
  function createDateTimeFormatter(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {
@@ -586,16 +587,19 @@ export default function WmsOperationalDashboardPage() {
586
587
  id: 'details',
587
588
  header: t('wms.backend.dashboard.activity.columns.details', 'Details'),
588
589
  cell: ({ row }) => {
590
+ const title = formatActivityTitle(row.original, t)
589
591
  const subtitle = formatActivitySubtitle(row.original, t)
592
+ const fullDetails = subtitle ? `${title} · ${subtitle}` : title
590
593
  return (
591
- <div className="min-w-0">
592
- <p className="truncate text-sm font-medium">{formatActivityTitle(row.original, t)}</p>
594
+ <div className="min-w-0 max-w-xs" title={fullDetails}>
595
+ <p className="truncate text-sm font-medium">{title}</p>
593
596
  {subtitle ? (
594
- <p className="truncate text-sm text-muted-foreground">{subtitle}</p>
597
+ <p className="line-clamp-2 text-sm text-muted-foreground">{subtitle}</p>
595
598
  ) : null}
596
599
  </div>
597
600
  )
598
601
  },
602
+ meta: { maxWidth: '20rem', truncate: false },
599
603
  },
600
604
  {
601
605
  id: 'location',