@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,118 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { z } from 'zod'
3
+ import type { EntityManager } from '@mikro-orm/postgresql'
4
+ import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
5
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
6
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
7
+ import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
8
+ import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
9
+ import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
10
+ import { createLogger } from '@open-mercato/shared/lib/logger'
11
+ import { asnReceiveLineSchema, scanReceiveSchema } from '../../../data/validators'
12
+ import { resolveScanReceiveCommandInput } from '../../../lib/scanResolve'
13
+ import { executeWmsCustomPostRoute } from '../../inventory/helpers'
14
+
15
+ const logger = createLogger('wms')
16
+
17
+ export const metadata = {
18
+ POST: { requireAuth: true, requireFeatures: ['wms.receive_inventory'] },
19
+ }
20
+
21
+ const successSchema = z.object({
22
+ ok: z.literal(true),
23
+ movementIds: z.array(z.string().uuid()),
24
+ putawayTaskIds: z.array(z.string().uuid()),
25
+ receivedQty: z.number().optional(),
26
+ asnUpdatedAt: z.string().datetime().optional(),
27
+ })
28
+ const errorSchema = z.object({ error: z.string() })
29
+
30
+ export async function POST(request: Request) {
31
+ try {
32
+ const container = await createRequestContainer()
33
+ const auth = await getAuthFromRequest(request)
34
+ if (!auth?.tenantId) {
35
+ throw new CrudHttpError(401, { error: 'Unauthorized' })
36
+ }
37
+ const organizationScope = await resolveOrganizationScopeForRequest({
38
+ container,
39
+ auth,
40
+ request,
41
+ })
42
+ const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null
43
+ if (!organizationId) {
44
+ throw new CrudHttpError(400, { error: 'organization_scope_required' })
45
+ }
46
+ const body = await readJsonSafe<Record<string, unknown>>(request, {})
47
+ const parsed = scanReceiveSchema.parse(body)
48
+ if (parsed.tenantId !== auth.tenantId && !auth.isSuperAdmin) {
49
+ throw new CrudHttpError(403, { error: 'Forbidden' })
50
+ }
51
+ // Scope organization from auth/session — never trust body organizationId for
52
+ // ASN/location resolve (same contract as resolve-location / resolve-lot).
53
+ const scoped = {
54
+ ...parsed,
55
+ tenantId: auth.tenantId,
56
+ organizationId,
57
+ }
58
+ const em = (container.resolve('em') as EntityManager).fork()
59
+ const commandInput = await resolveScanReceiveCommandInput(em, scoped)
60
+ const scopedRequest = new Request(request.url, {
61
+ method: 'POST',
62
+ headers: request.headers,
63
+ body: JSON.stringify(commandInput),
64
+ })
65
+ return executeWmsCustomPostRoute({
66
+ request: scopedRequest,
67
+ routePath: 'wms/scan/receive',
68
+ inputSchema: asnReceiveLineSchema,
69
+ commandId: 'wms.asns.receive-line',
70
+ describeResource: (input) => ({
71
+ resourceKind: 'wms.asn',
72
+ resourceId: input.asnId,
73
+ }),
74
+ mapSuccess: (result: {
75
+ movementIds: string[]
76
+ putawayTaskIds: string[]
77
+ receivedQty?: number
78
+ asnUpdatedAt?: string
79
+ }) => ({
80
+ ok: true,
81
+ movementIds: result.movementIds,
82
+ putawayTaskIds: result.putawayTaskIds,
83
+ receivedQty: result.receivedQty,
84
+ asnUpdatedAt: result.asnUpdatedAt,
85
+ }),
86
+ })
87
+ } catch (error) {
88
+ if (error instanceof CrudHttpError) {
89
+ return NextResponse.json(error.body, { status: error.status })
90
+ }
91
+ if (error instanceof z.ZodError) {
92
+ return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })
93
+ }
94
+ logger.error('scan receive failed', { err: error })
95
+ return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
96
+ }
97
+ }
98
+
99
+ export const openApi: OpenApiRouteDoc = {
100
+ tag: 'WMS',
101
+ summary: 'Scan-assisted ASN receive',
102
+ methods: {
103
+ POST: {
104
+ summary: 'Receive ASN line from scanned location/lot codes',
105
+ description:
106
+ 'Resolves scanned location (and optional lot) codes, then executes the same command path as POST /api/wms/asns/:id/receive. Organization is taken from the authenticated session scope, not the request body. Both QC-pass and QC-fail require absolute targetReceivedQty for retry-safe attempts (optional idempotencyKey is an extra stabilizer only).',
107
+ requestBody: { contentType: 'application/json', schema: scanReceiveSchema },
108
+ responses: [{ status: 200, description: 'ASN line received', schema: successSchema }],
109
+ errors: [
110
+ { status: 400, description: 'Validation failed', schema: errorSchema },
111
+ { status: 401, description: 'Unauthorized', schema: errorSchema },
112
+ { status: 404, description: 'ASN or location not found', schema: errorSchema },
113
+ { status: 409, description: 'Invalid receipt state', schema: errorSchema },
114
+ { status: 422, description: 'Tracking or QC transition invalid', schema: errorSchema },
115
+ ],
116
+ },
117
+ },
118
+ }
@@ -0,0 +1,92 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { z } from 'zod'
3
+ import type { EntityManager } from '@mikro-orm/postgresql'
4
+ import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
5
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
6
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
7
+ import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
8
+ import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
9
+ import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
10
+ import { createLogger } from '@open-mercato/shared/lib/logger'
11
+ import { scanResolveLocationSchema } from '../../../data/validators'
12
+ import { resolveLocationByCode } from '../../../lib/scanResolve'
13
+
14
+ const logger = createLogger('wms')
15
+
16
+ export const metadata = {
17
+ POST: { requireAuth: true, requireFeatures: ['wms.view'] },
18
+ }
19
+
20
+ const successSchema = z.object({
21
+ ok: z.literal(true),
22
+ locationId: z.string().uuid(),
23
+ code: z.string(),
24
+ type: z.string(),
25
+ })
26
+ const errorSchema = z.object({ error: z.string() })
27
+
28
+ export async function POST(request: Request) {
29
+ try {
30
+ const container = await createRequestContainer()
31
+ const auth = await getAuthFromRequest(request)
32
+ if (!auth?.tenantId) {
33
+ throw new CrudHttpError(401, { error: 'Unauthorized' })
34
+ }
35
+ const organizationScope = await resolveOrganizationScopeForRequest({
36
+ container,
37
+ auth,
38
+ request,
39
+ })
40
+ const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null
41
+ if (!organizationId) {
42
+ throw new CrudHttpError(400, { error: 'organization_scope_required' })
43
+ }
44
+ const body = await readJsonSafe<Record<string, unknown>>(request, {})
45
+ const parsed = scanResolveLocationSchema.parse(body)
46
+ if (parsed.tenantId !== auth.tenantId && !auth.isSuperAdmin) {
47
+ throw new CrudHttpError(403, { error: 'Forbidden' })
48
+ }
49
+ // Scope organization from auth/session — never trust body organizationId for cross-org reads.
50
+ const scoped = {
51
+ ...parsed,
52
+ tenantId: auth.tenantId,
53
+ organizationId,
54
+ }
55
+ const em = (container.resolve('em') as EntityManager).fork()
56
+ const resolved = await resolveLocationByCode(em, scoped)
57
+ return NextResponse.json({
58
+ ok: true as const,
59
+ locationId: resolved.locationId,
60
+ code: resolved.code,
61
+ type: resolved.type,
62
+ })
63
+ } catch (error) {
64
+ if (error instanceof CrudHttpError) {
65
+ return NextResponse.json(error.body, { status: error.status })
66
+ }
67
+ if (error instanceof z.ZodError) {
68
+ return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })
69
+ }
70
+ logger.error('scan resolve-location failed', { err: error })
71
+ return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
72
+ }
73
+ }
74
+
75
+ export const openApi: OpenApiRouteDoc = {
76
+ tag: 'WMS',
77
+ summary: 'Resolve scanned location code',
78
+ methods: {
79
+ POST: {
80
+ summary: 'Resolve location by warehouse + barcode/code',
81
+ description:
82
+ 'Returns the canonical location id and type for a scanned warehouse location code. Organization is taken from the authenticated session scope, not the request body.',
83
+ requestBody: { contentType: 'application/json', schema: scanResolveLocationSchema },
84
+ responses: [{ status: 200, description: 'Location resolved', schema: successSchema }],
85
+ errors: [
86
+ { status: 400, description: 'Validation failed', schema: errorSchema },
87
+ { status: 401, description: 'Unauthorized', schema: errorSchema },
88
+ { status: 404, description: 'Location not found', schema: errorSchema },
89
+ ],
90
+ },
91
+ },
92
+ }
@@ -0,0 +1,92 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { z } from 'zod'
3
+ import type { EntityManager } from '@mikro-orm/postgresql'
4
+ import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
5
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
6
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
7
+ import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
8
+ import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
9
+ import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
10
+ import { createLogger } from '@open-mercato/shared/lib/logger'
11
+ import { scanResolveLotSchema } from '../../../data/validators'
12
+ import { resolveLotByNumber } from '../../../lib/scanResolve'
13
+
14
+ const logger = createLogger('wms')
15
+
16
+ export const metadata = {
17
+ POST: { requireAuth: true, requireFeatures: ['wms.view'] },
18
+ }
19
+
20
+ const successSchema = z.object({
21
+ ok: z.literal(true),
22
+ lotId: z.string().uuid(),
23
+ lotNumber: z.string(),
24
+ expiresAt: z.string().nullable(),
25
+ })
26
+ const errorSchema = z.object({ error: z.string() })
27
+
28
+ export async function POST(request: Request) {
29
+ try {
30
+ const container = await createRequestContainer()
31
+ const auth = await getAuthFromRequest(request)
32
+ if (!auth?.tenantId) {
33
+ throw new CrudHttpError(401, { error: 'Unauthorized' })
34
+ }
35
+ const organizationScope = await resolveOrganizationScopeForRequest({
36
+ container,
37
+ auth,
38
+ request,
39
+ })
40
+ const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null
41
+ if (!organizationId) {
42
+ throw new CrudHttpError(400, { error: 'organization_scope_required' })
43
+ }
44
+ const body = await readJsonSafe<Record<string, unknown>>(request, {})
45
+ const parsed = scanResolveLotSchema.parse(body)
46
+ if (parsed.tenantId !== auth.tenantId && !auth.isSuperAdmin) {
47
+ throw new CrudHttpError(403, { error: 'Forbidden' })
48
+ }
49
+ // Scope organization from auth/session — never trust body organizationId for cross-org reads.
50
+ const scoped = {
51
+ ...parsed,
52
+ tenantId: auth.tenantId,
53
+ organizationId,
54
+ }
55
+ const em = (container.resolve('em') as EntityManager).fork()
56
+ const resolved = await resolveLotByNumber(em, scoped)
57
+ return NextResponse.json({
58
+ ok: true as const,
59
+ lotId: resolved.lotId,
60
+ lotNumber: resolved.lotNumber,
61
+ expiresAt: resolved.expiresAt,
62
+ })
63
+ } catch (error) {
64
+ if (error instanceof CrudHttpError) {
65
+ return NextResponse.json(error.body, { status: error.status })
66
+ }
67
+ if (error instanceof z.ZodError) {
68
+ return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })
69
+ }
70
+ logger.error('scan resolve-lot failed', { err: error })
71
+ return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
72
+ }
73
+ }
74
+
75
+ export const openApi: OpenApiRouteDoc = {
76
+ tag: 'WMS',
77
+ summary: 'Resolve scanned lot number',
78
+ methods: {
79
+ POST: {
80
+ summary: 'Resolve lot by catalog variant + lot number',
81
+ description:
82
+ 'Returns the canonical lot id and expiry for a scanned lot number. Organization is taken from the authenticated session scope, not the request body.',
83
+ requestBody: { contentType: 'application/json', schema: scanResolveLotSchema },
84
+ responses: [{ status: 200, description: 'Lot resolved', schema: successSchema }],
85
+ errors: [
86
+ { status: 400, description: 'Validation failed', schema: errorSchema },
87
+ { status: 401, description: 'Unauthorized', schema: errorSchema },
88
+ { status: 404, description: 'Lot not found', schema: errorSchema },
89
+ ],
90
+ },
91
+ },
92
+ }
@@ -0,0 +1,14 @@
1
+ export const metadata = {
2
+ requireAuth: true,
3
+ requireFeatures: ['wms.view'],
4
+ pageTitle: 'ASN detail',
5
+ pageTitleKey: 'wms.backend.asns.detail.nav.title',
6
+ pageGroup: 'WMS',
7
+ pageGroupKey: 'wms.nav.group',
8
+ navHidden: true,
9
+ breadcrumb: [
10
+ { label: 'WMS', labelKey: 'wms.backend.nav.title', href: '/backend/wms' },
11
+ { label: 'ASNs', labelKey: 'wms.backend.asns.nav.title', href: '/backend/wms/asns' },
12
+ { label: 'ASN', labelKey: 'wms.backend.asns.detail.nav.title' },
13
+ ],
14
+ } as const
@@ -0,0 +1,5 @@
1
+ import WmsAsnDetailPage from '../../../../components/backend/WmsAsnDetailPage'
2
+
3
+ export default function WmsAsnDetailRoutePage({ params }: { params?: { id?: string } }) {
4
+ return <WmsAsnDetailPage asnId={params?.id ?? ''} />
5
+ }
@@ -0,0 +1,14 @@
1
+ export const metadata = {
2
+ requireAuth: true,
3
+ requireFeatures: ['wms.view'],
4
+ pageTitle: 'ASNs',
5
+ pageTitleKey: 'wms.backend.asns.nav.title',
6
+ pageGroup: 'WMS',
7
+ pageGroupKey: 'wms.nav.group',
8
+ pageOrder: 90,
9
+ breadcrumb: [
10
+ { label: 'WMS', labelKey: 'wms.backend.nav.title', href: '/backend/wms' },
11
+ { label: 'ASNs', labelKey: 'wms.backend.asns.nav.title' },
12
+ ],
13
+ icon: 'clipboard-list',
14
+ } as const
@@ -0,0 +1,5 @@
1
+ import WmsAsnsListPage from '../../../components/backend/WmsAsnsListPage'
2
+
3
+ export default function WmsAsnsPage() {
4
+ return <WmsAsnsListPage />
5
+ }
@@ -0,0 +1,14 @@
1
+ export const metadata = {
2
+ requireAuth: true,
3
+ requireFeatures: ['wms.view'],
4
+ pageTitle: 'Putaway',
5
+ pageTitleKey: 'wms.backend.putaway.nav.title',
6
+ pageGroup: 'WMS',
7
+ pageGroupKey: 'wms.nav.group',
8
+ pageOrder: 95,
9
+ breadcrumb: [
10
+ { label: 'WMS', labelKey: 'wms.backend.nav.title', href: '/backend/wms' },
11
+ { label: 'Putaway', labelKey: 'wms.backend.putaway.nav.title' },
12
+ ],
13
+ icon: 'package',
14
+ } as const
@@ -0,0 +1,5 @@
1
+ import WmsPutawayQueuePage from '../../../components/backend/WmsPutawayQueuePage'
2
+
3
+ export default function WmsPutawayPage() {
4
+ return <WmsPutawayQueuePage />
5
+ }
@@ -0,0 +1,14 @@
1
+ export const metadata = {
2
+ requireAuth: true,
3
+ requireFeatures: ['wms.view'],
4
+ pageTitle: 'Receiving',
5
+ pageTitleKey: 'wms.backend.receiving.nav.title',
6
+ pageGroup: 'WMS',
7
+ pageGroupKey: 'wms.nav.group',
8
+ pageOrder: 92,
9
+ breadcrumb: [
10
+ { label: 'WMS', labelKey: 'wms.backend.nav.title', href: '/backend/wms' },
11
+ { label: 'Receiving', labelKey: 'wms.backend.receiving.nav.title' },
12
+ ],
13
+ icon: 'inbox',
14
+ } as const
@@ -0,0 +1,5 @@
1
+ import { redirect } from 'next/navigation'
2
+
3
+ export default function WmsReceivingPage() {
4
+ redirect('/backend/wms/asns?queue=open')
5
+ }
@@ -71,6 +71,33 @@ export const entities = [
71
71
  defaultEditor: false,
72
72
  fields: [],
73
73
  },
74
+ {
75
+ id: 'wms:asn',
76
+ label: 'ASN',
77
+ description: 'Advanced shipping notice for structured inbound receiving.',
78
+ labelField: 'referenceNumber',
79
+ showInSidebar: false,
80
+ defaultEditor: false,
81
+ fields: [],
82
+ },
83
+ {
84
+ id: 'wms:receiving_line',
85
+ label: 'Receiving Line',
86
+ description: 'Expected/received line against an ASN with QC outcome.',
87
+ labelField: 'catalogVariantId',
88
+ showInSidebar: false,
89
+ defaultEditor: false,
90
+ fields: [],
91
+ },
92
+ {
93
+ id: 'wms:putaway_task',
94
+ label: 'Putaway Task',
95
+ description: 'Directed putaway task moving accepted stock from staging into storage.',
96
+ labelField: 'catalogVariantId',
97
+ showInSidebar: false,
98
+ defaultEditor: false,
99
+ fields: [],
100
+ },
74
101
  ]
75
102
 
76
103
  export default entities