@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,647 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import Link from 'next/link'
5
+ import { z } from 'zod'
6
+ import type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'
7
+ import { useQuery, useQueryClient } from '@tanstack/react-query'
8
+ import { ArrowLeft, CheckCircle2, PackageCheck } from 'lucide-react'
9
+ import { Page, PageBody, PageHeader } from '@open-mercato/ui/backend/Page'
10
+ import { DataTable } from '@open-mercato/ui/backend/DataTable'
11
+ import { EmptyState } from '@open-mercato/ui/backend/EmptyState'
12
+ import { RowActions } from '@open-mercato/ui/backend/RowActions'
13
+ import {
14
+ ErrorMessage,
15
+ LoadingMessage,
16
+ RecordNotFoundState,
17
+ } from '@open-mercato/ui/backend/detail'
18
+ import { flash } from '@open-mercato/ui/backend/FlashMessages'
19
+ import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
20
+ import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
21
+ import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
22
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
23
+ import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
24
+ import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
25
+ import { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'
26
+ import { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'
27
+ import { Button } from '@open-mercato/ui/primitives/button'
28
+ import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
29
+ import { StatusBadge } from '@open-mercato/ui/primitives/status-badge'
30
+ import { flashMutationError } from '../../lib/flashMutationError'
31
+ import {
32
+ applyAsnCompleteLockTokenFromConflict,
33
+ applyAsnReceiveLockTokenFromSuccess,
34
+ resolveAsnReceiveLockToken,
35
+ } from './asnCompleteOptimisticLock'
36
+ import {
37
+ loadAllAsnReceivingLines,
38
+ type AsnReceivingLineRow,
39
+ } from './asnReceivingLinesLoader'
40
+ import {
41
+ asnStatusVariant,
42
+ lineHasDiscrepancy,
43
+ qcStatusVariant,
44
+ resolveAsnCompleteGate,
45
+ } from './inboundStatusUi'
46
+ import { ReceiveAsnLineDialog, type ReceiveAsnLineTarget } from './ReceiveAsnLineDialog'
47
+ import { useWmsInventoryMutationAccess } from './useWmsInventoryMutationAccess'
48
+ import {
49
+ resolveCatalogVariantLabel,
50
+ resolveLocationLabel,
51
+ resolveWarehouseLabel,
52
+ } from './inventoryMutationLoaders'
53
+
54
+ const asnIdSchema = z.string().uuid()
55
+
56
+ type PagedResponse<T> = {
57
+ items: T[]
58
+ total: number
59
+ totalPages: number
60
+ }
61
+
62
+ type AsnRow = {
63
+ id: string
64
+ warehouse_id?: string | null
65
+ vendor_id?: string | null
66
+ status?: string | null
67
+ expected_at?: string | null
68
+ reference_number?: string | null
69
+ notes?: string | null
70
+ updated_at?: string | null
71
+ }
72
+
73
+ type ReceivingLineRow = AsnReceivingLineRow
74
+
75
+ function toNumber(value: string | number | null | undefined): number {
76
+ const parsed = Number(value ?? 0)
77
+ return Number.isFinite(parsed) ? parsed : 0
78
+ }
79
+
80
+ export default function WmsAsnDetailPage({ asnId }: { asnId: string }) {
81
+ const t = useT()
82
+ const locale = useLocale()
83
+ const queryClient = useQueryClient()
84
+ const access = useWmsInventoryMutationAccess()
85
+ const { confirm, ConfirmDialogElement } = useConfirmDialog()
86
+ const { runMutation, retryLastMutation } = useGuardedMutation<{
87
+ retryLastMutation: () => Promise<boolean>
88
+ }>({
89
+ contextId: 'wms-asn-complete',
90
+ })
91
+ const mutationContext = React.useMemo(
92
+ () => ({ retryLastMutation }),
93
+ [retryLastMutation],
94
+ )
95
+
96
+ const parsedId = asnIdSchema.safeParse(asnId)
97
+ const [receiveOpen, setReceiveOpen] = React.useState(false)
98
+ const [activeLine, setActiveLine] = React.useState<ReceiveAsnLineTarget | null>(null)
99
+ const [closeWhenShort, setCloseWhenShort] = React.useState(false)
100
+ const [labelCache, setLabelCache] = React.useState<Record<string, string>>({})
101
+ const asnCompleteLockRef = React.useRef<string | null>(null)
102
+ // Fresh ASN If-Match across receives — query refetch is async after onSuccess.
103
+ const asnReceiveLockRef = React.useRef<string | null>(null)
104
+
105
+ const dateFormatter = React.useMemo(
106
+ () =>
107
+ new Intl.DateTimeFormat(locale, {
108
+ year: 'numeric',
109
+ month: '2-digit',
110
+ day: '2-digit',
111
+ }),
112
+ [locale],
113
+ )
114
+
115
+ const asnQuery = useQuery({
116
+ queryKey: ['wms-asn-detail', asnId, 'header'],
117
+ enabled: parsedId.success,
118
+ queryFn: async () => {
119
+ const call = await apiCall<PagedResponse<AsnRow>>(
120
+ `/api/wms/asns?ids=${encodeURIComponent(asnId)}&page=1&pageSize=1`,
121
+ )
122
+ if (!call.ok) {
123
+ await raiseCrudError(call.response, t('wms.backend.asns.detail.errors.load', 'Failed to load ASN.'))
124
+ }
125
+ return call.result?.items?.[0] ?? null
126
+ },
127
+ })
128
+
129
+ const linesQuery = useQuery({
130
+ queryKey: ['wms-asn-detail', asnId, 'lines'],
131
+ enabled: parsedId.success,
132
+ queryFn: async () => {
133
+ // Load-all for detail console: QC alerts, receive actions, and Complete ASN
134
+ // must see every line — never truncate at the first page.
135
+ const loaded = await loadAllAsnReceivingLines(asnId)
136
+ if (loaded.ok) {
137
+ return loaded.items
138
+ }
139
+ await raiseCrudError(
140
+ loaded.response,
141
+ t('wms.backend.asns.detail.errors.loadLines', 'Failed to load receiving lines.'),
142
+ )
143
+ },
144
+ })
145
+
146
+ const asn = asnQuery.data
147
+ const lines = linesQuery.data ?? []
148
+
149
+ React.useEffect(() => {
150
+ if (typeof asn?.updated_at !== 'string' || !asn.updated_at.trim()) return
151
+ const fromQuery = asn.updated_at.trim()
152
+ // Prefer newer ISO tokens so a lagging refetch cannot demote a success token.
153
+ if (!asnReceiveLockRef.current || fromQuery > asnReceiveLockRef.current) {
154
+ asnReceiveLockRef.current = fromQuery
155
+ }
156
+ }, [asn?.updated_at])
157
+
158
+ React.useEffect(() => {
159
+ const ids = new Set<string>()
160
+ if (asn?.warehouse_id) ids.add(asn.warehouse_id)
161
+ for (const line of lines) {
162
+ if (line.catalog_variant_id) ids.add(line.catalog_variant_id)
163
+ if (line.target_staging_location_id) ids.add(line.target_staging_location_id)
164
+ }
165
+ const missing = [...ids].filter((id) => !labelCache[id])
166
+ if (missing.length === 0) return
167
+ let cancelled = false
168
+ void Promise.all(
169
+ missing.map(async (id) => {
170
+ const [warehouse, variant, location] = await Promise.all([
171
+ resolveWarehouseLabel(id),
172
+ resolveCatalogVariantLabel(id),
173
+ resolveLocationLabel(id),
174
+ ])
175
+ return [id, warehouse || variant || location] as const
176
+ }),
177
+ ).then((entries) => {
178
+ if (cancelled) return
179
+ setLabelCache((prev) => {
180
+ const next = { ...prev }
181
+ for (const [id, label] of entries) {
182
+ if (label) next[id] = label
183
+ }
184
+ return next
185
+ })
186
+ })
187
+ return () => {
188
+ cancelled = true
189
+ }
190
+ }, [asn?.warehouse_id, labelCache, lines])
191
+
192
+ const discrepancyLines = lines.filter((line) =>
193
+ lineHasDiscrepancy(line.expected_qty, line.received_qty),
194
+ )
195
+ const failedLines = lines.filter((line) => line.qc_status === 'failed')
196
+ const canReceiveMore = asn?.status === 'draft' || asn?.status === 'in_transit'
197
+ const completeGate = resolveAsnCompleteGate({
198
+ canManageAsn: access.canManageAsn,
199
+ asnStatus: asn?.status,
200
+ lines,
201
+ closeWhenShort,
202
+ })
203
+ const { canShowComplete, canSubmitComplete, showCloseWhenShort } = completeGate
204
+
205
+ const openReceive = React.useCallback((line: ReceivingLineRow) => {
206
+ setActiveLine({
207
+ lineId: line.id,
208
+ catalogVariantId: line.catalog_variant_id ?? '',
209
+ expectedQty: toNumber(line.expected_qty),
210
+ receivedQty: toNumber(line.received_qty),
211
+ lotNumber: line.lot_number,
212
+ serialNumbers: line.serial_numbers,
213
+ targetStagingLocationId: line.target_staging_location_id,
214
+ variantLabel: line.catalog_variant_id
215
+ ? labelCache[line.catalog_variant_id] ?? line.catalog_variant_id
216
+ : null,
217
+ updatedAt: line.updated_at ?? null,
218
+ asnUpdatedAt: resolveAsnReceiveLockToken(asnReceiveLockRef, asn?.updated_at),
219
+ })
220
+ setReceiveOpen(true)
221
+ }, [asn?.updated_at, labelCache])
222
+
223
+ const applyAsnCompleteLockFromConflict = React.useCallback(
224
+ (status: number, body: unknown) => {
225
+ const refreshed = applyAsnCompleteLockTokenFromConflict(asnCompleteLockRef, {
226
+ status,
227
+ body,
228
+ })
229
+ if (!refreshed) return
230
+ queryClient.setQueryData<AsnRow | null>(
231
+ ['wms-asn-detail', asnId, 'header'],
232
+ (previous) => (previous ? { ...previous, updated_at: refreshed } : previous),
233
+ )
234
+ },
235
+ [asnId, queryClient],
236
+ )
237
+
238
+ const handleComplete = React.useCallback(async () => {
239
+ if (!asn || !access.organizationId || !access.tenantId || !canSubmitComplete) return
240
+ const confirmed = await confirm({
241
+ title: t('wms.backend.asns.complete.confirm.title', 'Complete ASN?'),
242
+ description: closeWhenShort
243
+ ? t(
244
+ 'wms.backend.asns.complete.confirm.descriptionShort',
245
+ 'Close this ASN even if some lines are short of expected quantity.',
246
+ )
247
+ : t(
248
+ 'wms.backend.asns.complete.confirm.description',
249
+ 'Mark this ASN as received when receiving is finished.',
250
+ ),
251
+ confirmText: t('wms.backend.asns.complete.confirm.submit', 'Complete ASN'),
252
+ cancelText: t('wms.backend.asns.complete.confirm.cancel', 'Cancel'),
253
+ })
254
+ if (!confirmed) return
255
+
256
+ // Seed once per user action (outside operation) so guarded retry keeps the
257
+ // refreshed token after a 409 instead of re-binding the original row version.
258
+ if (typeof asn.updated_at === 'string' && asn.updated_at.trim()) {
259
+ asnCompleteLockRef.current = asn.updated_at.trim()
260
+ } else {
261
+ asnCompleteLockRef.current = asn.updated_at ?? null
262
+ }
263
+
264
+ const payload = {
265
+ organizationId: access.organizationId,
266
+ tenantId: access.tenantId,
267
+ closeWhenShort,
268
+ }
269
+ try {
270
+ let conflictHandled = false
271
+ await runMutation({
272
+ operation: async () => {
273
+ const call = await apiCall<{ ok?: boolean; status?: string }>(
274
+ `/api/wms/asns/${encodeURIComponent(asn.id)}/complete`,
275
+ {
276
+ method: 'POST',
277
+ headers: {
278
+ 'content-type': 'application/json',
279
+ ...buildOptimisticLockHeader(asnCompleteLockRef.current ?? undefined),
280
+ },
281
+ body: JSON.stringify(payload),
282
+ },
283
+ )
284
+ if (!call.ok) {
285
+ const refreshLockFromConflict = () => {
286
+ applyAsnCompleteLockFromConflict(call.status, call.result)
287
+ void queryClient.invalidateQueries({ queryKey: ['wms-asn-detail', asnId] })
288
+ void queryClient.invalidateQueries({ queryKey: ['wms-asns-list'] })
289
+ }
290
+ if (
291
+ surfaceRecordConflict({ status: call.status, body: call.result }, t, {
292
+ onRefresh: refreshLockFromConflict,
293
+ })
294
+ ) {
295
+ refreshLockFromConflict()
296
+ conflictHandled = true
297
+ return {}
298
+ }
299
+ await raiseCrudError(
300
+ call.response,
301
+ t('wms.backend.asns.complete.errors.submit', 'Failed to complete ASN.'),
302
+ )
303
+ }
304
+ return call.result ?? {}
305
+ },
306
+ context: mutationContext,
307
+ mutationPayload: payload,
308
+ })
309
+ if (conflictHandled) return
310
+ flash(t('wms.backend.asns.complete.flash.success', 'ASN completed'), 'success')
311
+ await Promise.all([
312
+ queryClient.invalidateQueries({ queryKey: ['wms-asn-detail', asnId] }),
313
+ queryClient.invalidateQueries({ queryKey: ['wms-asns-list'] }),
314
+ ])
315
+ } catch (error) {
316
+ flashMutationError(
317
+ error,
318
+ t('wms.backend.asns.complete.errors.submit', 'Failed to complete ASN.'),
319
+ t,
320
+ )
321
+ }
322
+ }, [
323
+ access.organizationId,
324
+ access.tenantId,
325
+ applyAsnCompleteLockFromConflict,
326
+ asn,
327
+ asnId,
328
+ canSubmitComplete,
329
+ closeWhenShort,
330
+ confirm,
331
+ mutationContext,
332
+ queryClient,
333
+ runMutation,
334
+ t,
335
+ ])
336
+
337
+ const columns = React.useMemo<ColumnDef<ReceivingLineRow>[]>(
338
+ () => [
339
+ {
340
+ id: 'variant',
341
+ header: t('wms.backend.asns.detail.columns.variant', 'Variant'),
342
+ cell: ({ row }) => {
343
+ const id = row.original.catalog_variant_id
344
+ if (!id) return '—'
345
+ return labelCache[id] || id.slice(0, 8)
346
+ },
347
+ },
348
+ {
349
+ id: 'expected',
350
+ header: t('wms.backend.asns.detail.columns.expected', 'Expected'),
351
+ cell: ({ row }) => toNumber(row.original.expected_qty),
352
+ },
353
+ {
354
+ id: 'received',
355
+ header: t('wms.backend.asns.detail.columns.received', 'Received'),
356
+ cell: ({ row }) => {
357
+ const expected = toNumber(row.original.expected_qty)
358
+ const received = toNumber(row.original.received_qty)
359
+ const discrepant = lineHasDiscrepancy(expected, received)
360
+ return (
361
+ <span className={discrepant ? 'font-medium text-status-warning-text' : undefined}>
362
+ {received}
363
+ </span>
364
+ )
365
+ },
366
+ },
367
+ {
368
+ id: 'qc',
369
+ header: t('wms.backend.asns.detail.columns.qc', 'QC'),
370
+ cell: ({ row }) => {
371
+ const status = row.original.qc_status?.trim()
372
+ if (!status) return '—'
373
+ return (
374
+ <StatusBadge variant={qcStatusVariant(status)} dot>
375
+ {t(`wms.backend.asns.qc.${status}`, status)}
376
+ </StatusBadge>
377
+ )
378
+ },
379
+ },
380
+ {
381
+ id: 'staging',
382
+ header: t('wms.backend.asns.detail.columns.staging', 'Staging'),
383
+ cell: ({ row }) => {
384
+ const id = row.original.target_staging_location_id
385
+ if (!id) return '—'
386
+ return labelCache[id] || id.slice(0, 8)
387
+ },
388
+ },
389
+ ],
390
+ [labelCache, t],
391
+ )
392
+
393
+ const rowActions = React.useCallback(
394
+ (row: ReceivingLineRow) => {
395
+ if (!access.canReceive || !canReceiveMore) return null
396
+ return (
397
+ <RowActions
398
+ items={[
399
+ {
400
+ id: 'receive',
401
+ label: t('wms.backend.asns.detail.actions.receive', 'Receive line'),
402
+ onSelect: () => openReceive(row),
403
+ },
404
+ ]}
405
+ />
406
+ )
407
+ },
408
+ [access.canReceive, canReceiveMore, openReceive, t],
409
+ )
410
+
411
+ if (!parsedId.success) {
412
+ return (
413
+ <Page>
414
+ <PageBody>
415
+ <RecordNotFoundState
416
+ label={t('wms.backend.asns.detail.notFound', 'ASN not found.')}
417
+ backHref="/backend/wms/asns"
418
+ backLabel={t('wms.backend.asns.detail.back', 'Back to ASNs')}
419
+ />
420
+ </PageBody>
421
+ </Page>
422
+ )
423
+ }
424
+
425
+ if (asnQuery.isLoading || linesQuery.isLoading) {
426
+ return (
427
+ <Page>
428
+ <PageBody>
429
+ <LoadingMessage label={t('wms.backend.asns.detail.loading', 'Loading ASN…')} />
430
+ </PageBody>
431
+ </Page>
432
+ )
433
+ }
434
+
435
+ if (asnQuery.isError || linesQuery.isError) {
436
+ return (
437
+ <Page>
438
+ <PageBody>
439
+ <ErrorMessage label={t('wms.backend.asns.detail.errors.load', 'Failed to load ASN.')} />
440
+ </PageBody>
441
+ </Page>
442
+ )
443
+ }
444
+
445
+ if (!asn) {
446
+ return (
447
+ <Page>
448
+ <PageBody>
449
+ <RecordNotFoundState
450
+ label={t('wms.backend.asns.detail.notFound', 'ASN not found.')}
451
+ backHref="/backend/wms/asns"
452
+ backLabel={t('wms.backend.asns.detail.back', 'Back to ASNs')}
453
+ />
454
+ </PageBody>
455
+ </Page>
456
+ )
457
+ }
458
+
459
+ const title =
460
+ asn.reference_number?.trim() ||
461
+ t('wms.backend.asns.detail.untitled', 'ASN {id}', { id: asn.id.slice(0, 8) })
462
+
463
+ return (
464
+ <Page>
465
+ <PageBody className="space-y-6">
466
+ <PageHeader
467
+ title={title}
468
+ description={t(
469
+ 'wms.backend.asns.detail.description',
470
+ 'Primary receiving console for ASN lines, QC, and discrepancies.',
471
+ )}
472
+ actions={
473
+ <div className="flex flex-wrap gap-2">
474
+ <Button type="button" variant="outline" asChild>
475
+ <Link href="/backend/wms/asns">
476
+ <ArrowLeft className="size-4" />
477
+ {t('wms.backend.asns.detail.back', 'Back to ASNs')}
478
+ </Link>
479
+ </Button>
480
+ {access.canManagePutaway ? (
481
+ <Button type="button" variant="outline" asChild>
482
+ <Link href="/backend/wms/putaway">
483
+ {t('wms.backend.asns.actions.putawayQueue', 'Putaway queue')}
484
+ </Link>
485
+ </Button>
486
+ ) : null}
487
+ {canShowComplete ? (
488
+ <Button
489
+ type="button"
490
+ onClick={() => void handleComplete()}
491
+ disabled={!canSubmitComplete}
492
+ data-testid="asn-complete"
493
+ >
494
+ <CheckCircle2 className="size-4" />
495
+ {t('wms.backend.asns.detail.actions.complete', 'Complete ASN')}
496
+ </Button>
497
+ ) : null}
498
+ </div>
499
+ }
500
+ />
501
+
502
+ <section className="rounded-lg border bg-card p-5 text-card-foreground shadow-sm">
503
+ <div className="flex flex-wrap items-start justify-between gap-4">
504
+ <div className="space-y-2">
505
+ <div className="flex flex-wrap items-center gap-2">
506
+ <StatusBadge variant={asnStatusVariant(asn.status)} dot>
507
+ {t(`wms.backend.asns.status.${asn.status ?? 'draft'}`, asn.status ?? 'draft')}
508
+ </StatusBadge>
509
+ <span className="text-sm text-muted-foreground">
510
+ {asn.warehouse_id
511
+ ? labelCache[asn.warehouse_id] || asn.warehouse_id.slice(0, 8)
512
+ : '—'}
513
+ </span>
514
+ </div>
515
+ <dl className="grid gap-2 text-sm sm:grid-cols-2">
516
+ <div>
517
+ <dt className="text-muted-foreground">
518
+ {t('wms.backend.asns.columns.expectedAt', 'Expected')}
519
+ </dt>
520
+ <dd>
521
+ {asn.expected_at && !Number.isNaN(new Date(asn.expected_at).getTime())
522
+ ? dateFormatter.format(new Date(asn.expected_at))
523
+ : '—'}
524
+ </dd>
525
+ </div>
526
+ <div>
527
+ <dt className="text-muted-foreground">
528
+ {t('wms.backend.asns.columns.reference', 'Reference')}
529
+ </dt>
530
+ <dd>{asn.reference_number?.trim() || '—'}</dd>
531
+ </div>
532
+ </dl>
533
+ {asn.notes?.trim() ? (
534
+ <p className="text-sm text-muted-foreground">{asn.notes}</p>
535
+ ) : null}
536
+ </div>
537
+ {showCloseWhenShort ? (
538
+ <label className="flex items-center gap-2 text-sm">
539
+ <Checkbox
540
+ checked={closeWhenShort}
541
+ onCheckedChange={(checked) => setCloseWhenShort(checked === true)}
542
+ data-testid="asn-close-when-short"
543
+ />
544
+ {t('wms.backend.asns.complete.closeWhenShort', 'Allow close when short')}
545
+ </label>
546
+ ) : null}
547
+ </div>
548
+ </section>
549
+
550
+ {failedLines.length > 0 ? (
551
+ <Alert status="error" style="light">
552
+ <AlertTitle>{t('wms.backend.asns.detail.qcFailed.title', 'QC failed lines')}</AlertTitle>
553
+ <AlertDescription>
554
+ {t(
555
+ 'wms.backend.asns.detail.qcFailed.description',
556
+ '{count} line(s) failed QC and did not increase available stock.',
557
+ { count: failedLines.length },
558
+ )}
559
+ </AlertDescription>
560
+ </Alert>
561
+ ) : null}
562
+
563
+ {discrepancyLines.length > 0 ? (
564
+ <Alert status="warning" style="light">
565
+ <AlertTitle>
566
+ {t('wms.backend.asns.detail.discrepancy.title', 'Quantity discrepancies')}
567
+ </AlertTitle>
568
+ <AlertDescription>
569
+ {t(
570
+ 'wms.backend.asns.detail.discrepancy.description',
571
+ '{count} line(s) have received quantity different from expected.',
572
+ { count: discrepancyLines.length },
573
+ )}
574
+ </AlertDescription>
575
+ </Alert>
576
+ ) : null}
577
+
578
+ <section className="rounded-lg border bg-card p-5 text-card-foreground shadow-sm">
579
+ <div className="mb-4 flex items-start gap-3">
580
+ <div className="rounded-md border bg-muted/40 p-2 text-muted-foreground">
581
+ <PackageCheck className="size-5" />
582
+ </div>
583
+ <div className="space-y-1">
584
+ <h2 className="text-xl font-semibold">
585
+ {t('wms.backend.asns.detail.linesTitle', 'Receiving lines')}
586
+ </h2>
587
+ <p className="text-sm text-muted-foreground">
588
+ {t(
589
+ 'wms.backend.asns.detail.linesDescription',
590
+ 'Receive against expected quantities with QC pass or fail.',
591
+ )}
592
+ </p>
593
+ </div>
594
+ </div>
595
+ <DataTable
596
+ embedded
597
+ columns={columns}
598
+ data={lines}
599
+ rowActions={rowActions}
600
+ emptyState={
601
+ <EmptyState
602
+ title={t('wms.backend.asns.detail.emptyLines.title', 'No receiving lines')}
603
+ description={t(
604
+ 'wms.backend.asns.detail.emptyLines.description',
605
+ 'This ASN has no expected lines yet.',
606
+ )}
607
+ />
608
+ }
609
+ />
610
+ </section>
611
+ </PageBody>
612
+
613
+ {access.canReceive ? (
614
+ <ReceiveAsnLineDialog
615
+ open={receiveOpen}
616
+ onOpenChange={setReceiveOpen}
617
+ access={access}
618
+ asnId={asn.id}
619
+ warehouseId={asn.warehouse_id ?? ''}
620
+ line={activeLine}
621
+ onSuccess={(result) => {
622
+ const refreshed = applyAsnReceiveLockTokenFromSuccess(
623
+ asnReceiveLockRef,
624
+ result?.asnUpdatedAt,
625
+ )
626
+ if (refreshed) {
627
+ queryClient.setQueryData<AsnRow | null>(
628
+ ['wms-asn-detail', asnId, 'header'],
629
+ (previous) => (previous ? { ...previous, updated_at: refreshed } : previous),
630
+ )
631
+ }
632
+ if (result && activeLine) {
633
+ setActiveLine({
634
+ ...activeLine,
635
+ receivedQty: result.receivedQty,
636
+ asnUpdatedAt: refreshed ?? result.asnUpdatedAt ?? activeLine.asnUpdatedAt,
637
+ })
638
+ }
639
+ void linesQuery.refetch()
640
+ void asnQuery.refetch()
641
+ }}
642
+ />
643
+ ) : null}
644
+ {ConfirmDialogElement}
645
+ </Page>
646
+ )
647
+ }