@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
@@ -27,6 +27,7 @@ import {
27
27
  } from "../data/validators.js";
28
28
  import {
29
29
  evaluateLowStock,
30
+ isBalanceLocationReservable,
30
31
  isLotEligible,
31
32
  resolveReservationStrategyFromProfile,
32
33
  sortBucketsForStrategy
@@ -359,11 +360,14 @@ async function listCandidateBalances(em, ctx, input, scope) {
359
360
  },
360
361
  scope
361
362
  );
363
+ const reservable = [];
362
364
  for (const balance of balances) {
363
365
  ensureTenantScope(ctx, balance.tenantId);
364
366
  ensureOrganizationScope(ctx, balance.organizationId);
367
+ if (!isBalanceLocationReservable(balance)) continue;
368
+ reservable.push(balance);
365
369
  }
366
- return balances;
370
+ return reservable;
367
371
  }
368
372
  async function listBalancesForVariant(em, ctx, catalogVariantId, scope) {
369
373
  const balances = await findWithDecryption(
@@ -1093,12 +1097,26 @@ const adjustInventoryCommand = {
1093
1097
  if (delta < 0 && getAvailableQuantity(balance) < Math.abs(delta) - 1e-6) {
1094
1098
  throw new CrudHttpError(409, { error: "insufficient_stock" });
1095
1099
  }
1100
+ const { movement, idempotentReplay } = await persistMovementWithIdempotency(trx, scope, movementInput);
1101
+ if (idempotentReplay) {
1102
+ return {
1103
+ movementId: movement.id,
1104
+ warehouseId: input.warehouseId,
1105
+ catalogVariantId: input.catalogVariantId,
1106
+ quantity: delta,
1107
+ tenantId: scope.tenantId,
1108
+ organizationId: scope.organizationId,
1109
+ movementEntity: movement,
1110
+ balanceEntity: balance,
1111
+ balanceAction: "updated",
1112
+ idempotentReplay: true
1113
+ };
1114
+ }
1096
1115
  setNumeric(
1097
1116
  balance,
1098
1117
  "quantityOnHand",
1099
1118
  toNumber(balance.quantityOnHand) + delta
1100
1119
  );
1101
- const { movement } = await persistMovementWithIdempotency(trx, scope, movementInput);
1102
1120
  await trx.flush();
1103
1121
  return {
1104
1122
  movementId: movement.id,
@@ -1147,6 +1165,138 @@ const adjustInventoryCommand = {
1147
1165
  cacheAliases: [WMS_INVENTORY_BALANCE_RESOURCE]
1148
1166
  })
1149
1167
  };
1168
+ async function applyInventoryReceiveInTransaction(trx, ctx, input) {
1169
+ const scope = resolveScope(ctx, input);
1170
+ await requireWarehouse(trx, ctx, input.warehouseId, scope);
1171
+ const location = await requireLocation(trx, ctx, input.locationId, scope);
1172
+ const locationWarehouseId = typeof location.warehouse === "string" ? location.warehouse : location.warehouse.id;
1173
+ if (locationWarehouseId !== input.warehouseId) {
1174
+ throw new CrudHttpError(422, { error: "invalid_location" });
1175
+ }
1176
+ const profile = await loadProfileForVariant(trx, ctx, input.catalogVariantId, scope);
1177
+ const resolvedLotId = await resolveReceiveLotId(trx, ctx, scope, input);
1178
+ enforceInventoryTrackingRequirements(profile, {
1179
+ lotId: resolvedLotId ?? null,
1180
+ serialNumber: input.serialNumber ?? null
1181
+ });
1182
+ const { balance, created: balanceWasNew } = await upsertBalanceBucket(trx, scope, {
1183
+ warehouseId: input.warehouseId,
1184
+ locationId: input.locationId,
1185
+ catalogVariantId: input.catalogVariantId,
1186
+ lotId: resolvedLotId,
1187
+ serialNumber: input.serialNumber
1188
+ });
1189
+ const receivedAt = input.receivedAt ?? input.performedAt ?? /* @__PURE__ */ new Date();
1190
+ const performedAt = input.performedAt ?? receivedAt;
1191
+ const movementInput = {
1192
+ warehouseId: input.warehouseId,
1193
+ locationToId: input.locationId,
1194
+ catalogVariantId: input.catalogVariantId,
1195
+ lotId: resolvedLotId ?? null,
1196
+ serialNumber: input.serialNumber ?? null,
1197
+ quantity: input.quantity,
1198
+ type: "receipt",
1199
+ referenceType: input.referenceType,
1200
+ referenceId: input.referenceId,
1201
+ performedBy: input.performedBy,
1202
+ performedAt,
1203
+ receivedAt,
1204
+ reason: input.reason,
1205
+ reasonCode: input.reasonCode ?? null,
1206
+ metadata: input.metadata ?? null
1207
+ };
1208
+ const idempotencyKey = buildMovementIdempotencyKey({
1209
+ referenceType: movementInput.referenceType,
1210
+ referenceId: movementInput.referenceId,
1211
+ type: movementInput.type,
1212
+ warehouseId: movementInput.warehouseId,
1213
+ locationFromId: movementInput.locationFromId,
1214
+ locationToId: movementInput.locationToId,
1215
+ catalogVariantId: movementInput.catalogVariantId,
1216
+ lotId: movementInput.lotId,
1217
+ serialNumber: movementInput.serialNumber,
1218
+ quantity: movementInput.quantity
1219
+ });
1220
+ const existingMovement = await findExistingMovementByIdempotencyKey(trx, scope, idempotencyKey);
1221
+ if (existingMovement) {
1222
+ const existingLotRaw = existingMovement.lot ?? null;
1223
+ const existingLotId = typeof existingLotRaw === "string" ? existingLotRaw : existingLotRaw?.id ?? resolvedLotId ?? null;
1224
+ return {
1225
+ movementId: existingMovement.id,
1226
+ warehouseId: input.warehouseId,
1227
+ locationId: input.locationId,
1228
+ catalogVariantId: input.catalogVariantId,
1229
+ quantity: input.quantity,
1230
+ lotId: existingLotId,
1231
+ tenantId: scope.tenantId,
1232
+ organizationId: scope.organizationId,
1233
+ movementEntity: existingMovement,
1234
+ balanceEntity: balance,
1235
+ balanceAction: "updated",
1236
+ idempotentReplay: true
1237
+ };
1238
+ }
1239
+ const { movement, idempotentReplay } = await persistMovementWithIdempotency(trx, scope, movementInput);
1240
+ if (idempotentReplay) {
1241
+ return {
1242
+ movementId: movement.id,
1243
+ warehouseId: input.warehouseId,
1244
+ locationId: input.locationId,
1245
+ catalogVariantId: input.catalogVariantId,
1246
+ quantity: input.quantity,
1247
+ lotId: resolvedLotId ?? null,
1248
+ tenantId: scope.tenantId,
1249
+ organizationId: scope.organizationId,
1250
+ movementEntity: movement,
1251
+ balanceEntity: balance,
1252
+ balanceAction: "updated",
1253
+ idempotentReplay: true
1254
+ };
1255
+ }
1256
+ setNumeric(
1257
+ balance,
1258
+ "quantityOnHand",
1259
+ toNumber(balance.quantityOnHand) + input.quantity
1260
+ );
1261
+ await trx.flush();
1262
+ return {
1263
+ movementId: movement.id,
1264
+ warehouseId: input.warehouseId,
1265
+ locationId: input.locationId,
1266
+ catalogVariantId: input.catalogVariantId,
1267
+ quantity: input.quantity,
1268
+ lotId: resolvedLotId ?? null,
1269
+ tenantId: scope.tenantId,
1270
+ organizationId: scope.organizationId,
1271
+ movementEntity: movement,
1272
+ balanceEntity: balance,
1273
+ balanceAction: balanceWasNew ? "created" : "updated",
1274
+ idempotentReplay: false
1275
+ };
1276
+ }
1277
+ async function emitInventoryReceiveSideEffects(ctx, result) {
1278
+ if (result.idempotentReplay) return;
1279
+ await emitInventorySideEffects(ctx, {
1280
+ movements: [{ entity: result.movementEntity, action: "created" }],
1281
+ balances: [{ entity: result.balanceEntity, action: result.balanceAction }]
1282
+ });
1283
+ void emitWmsEvent("wms.inventory.received", {
1284
+ id: result.movementId,
1285
+ movementId: result.movementId,
1286
+ warehouseId: result.warehouseId,
1287
+ locationId: result.locationId,
1288
+ catalogVariantId: result.catalogVariantId,
1289
+ quantity: toNumericString(result.quantity),
1290
+ tenantId: result.tenantId,
1291
+ organizationId: result.organizationId
1292
+ }).catch(() => void 0);
1293
+ void emitLowStockEventIfNeeded(
1294
+ resolveEm(ctx),
1295
+ ctx,
1296
+ { tenantId: result.tenantId, organizationId: result.organizationId },
1297
+ result.catalogVariantId
1298
+ ).catch(() => void 0);
1299
+ }
1150
1300
  const receiveInventoryCommand = {
1151
1301
  id: "wms.inventory.receive",
1152
1302
  // See "WMS Inventory Mutation Commands — Undo Policy" at top of file.
@@ -1156,116 +1306,11 @@ const receiveInventoryCommand = {
1156
1306
  ensureTenantScope(ctx, input.tenantId);
1157
1307
  ensureOrganizationScope(ctx, input.organizationId);
1158
1308
  const em = resolveEm(ctx);
1159
- const result = await runInTransaction(em, async (trx) => {
1160
- const scope = resolveScope(ctx, input);
1161
- await requireWarehouse(trx, ctx, input.warehouseId, scope);
1162
- const location = await requireLocation(trx, ctx, input.locationId, scope);
1163
- const locationWarehouseId = typeof location.warehouse === "string" ? location.warehouse : location.warehouse.id;
1164
- if (locationWarehouseId !== input.warehouseId) {
1165
- throw new CrudHttpError(422, { error: "invalid_location" });
1166
- }
1167
- const profile = await loadProfileForVariant(trx, ctx, input.catalogVariantId, scope);
1168
- const resolvedLotId = await resolveReceiveLotId(trx, ctx, scope, input);
1169
- enforceInventoryTrackingRequirements(profile, {
1170
- lotId: resolvedLotId ?? null,
1171
- serialNumber: input.serialNumber ?? null
1172
- });
1173
- const { balance, created: balanceWasNew } = await upsertBalanceBucket(trx, scope, {
1174
- warehouseId: input.warehouseId,
1175
- locationId: input.locationId,
1176
- catalogVariantId: input.catalogVariantId,
1177
- lotId: resolvedLotId,
1178
- serialNumber: input.serialNumber
1179
- });
1180
- const receivedAt = input.receivedAt ?? input.performedAt ?? /* @__PURE__ */ new Date();
1181
- const performedAt = input.performedAt ?? receivedAt;
1182
- const movementInput = {
1183
- warehouseId: input.warehouseId,
1184
- locationToId: input.locationId,
1185
- catalogVariantId: input.catalogVariantId,
1186
- lotId: resolvedLotId ?? null,
1187
- serialNumber: input.serialNumber ?? null,
1188
- quantity: input.quantity,
1189
- type: "receipt",
1190
- referenceType: input.referenceType,
1191
- referenceId: input.referenceId,
1192
- performedBy: input.performedBy,
1193
- performedAt,
1194
- receivedAt,
1195
- reason: input.reason,
1196
- metadata: input.metadata ?? null
1197
- };
1198
- const idempotencyKey = buildMovementIdempotencyKey({
1199
- referenceType: movementInput.referenceType,
1200
- referenceId: movementInput.referenceId,
1201
- type: movementInput.type,
1202
- warehouseId: movementInput.warehouseId,
1203
- locationFromId: movementInput.locationFromId,
1204
- locationToId: movementInput.locationToId,
1205
- catalogVariantId: movementInput.catalogVariantId,
1206
- lotId: movementInput.lotId,
1207
- serialNumber: movementInput.serialNumber,
1208
- quantity: movementInput.quantity
1209
- });
1210
- const existingMovement = await findExistingMovementByIdempotencyKey(trx, scope, idempotencyKey);
1211
- if (existingMovement) {
1212
- return {
1213
- movementId: existingMovement.id,
1214
- warehouseId: input.warehouseId,
1215
- locationId: input.locationId,
1216
- catalogVariantId: input.catalogVariantId,
1217
- quantity: input.quantity,
1218
- tenantId: scope.tenantId,
1219
- organizationId: scope.organizationId,
1220
- movementEntity: existingMovement,
1221
- balanceEntity: balance,
1222
- balanceAction: "updated",
1223
- idempotentReplay: true
1224
- };
1225
- }
1226
- setNumeric(
1227
- balance,
1228
- "quantityOnHand",
1229
- toNumber(balance.quantityOnHand) + input.quantity
1230
- );
1231
- const { movement } = await persistMovementWithIdempotency(trx, scope, movementInput);
1232
- await trx.flush();
1233
- return {
1234
- movementId: movement.id,
1235
- warehouseId: input.warehouseId,
1236
- locationId: input.locationId,
1237
- catalogVariantId: input.catalogVariantId,
1238
- quantity: input.quantity,
1239
- tenantId: scope.tenantId,
1240
- organizationId: scope.organizationId,
1241
- movementEntity: movement,
1242
- balanceEntity: balance,
1243
- balanceAction: balanceWasNew ? "created" : "updated",
1244
- idempotentReplay: false
1245
- };
1246
- });
1247
- if (!result.idempotentReplay) {
1248
- await emitInventorySideEffects(ctx, {
1249
- movements: [{ entity: result.movementEntity, action: "created" }],
1250
- balances: [{ entity: result.balanceEntity, action: result.balanceAction }]
1251
- });
1252
- void emitWmsEvent("wms.inventory.received", {
1253
- id: result.movementId,
1254
- movementId: result.movementId,
1255
- warehouseId: result.warehouseId,
1256
- locationId: result.locationId,
1257
- catalogVariantId: result.catalogVariantId,
1258
- quantity: toNumericString(result.quantity),
1259
- tenantId: result.tenantId,
1260
- organizationId: result.organizationId
1261
- }).catch(() => void 0);
1262
- void emitLowStockEventIfNeeded(
1263
- resolveEm(ctx),
1264
- ctx,
1265
- { tenantId: result.tenantId, organizationId: result.organizationId },
1266
- result.catalogVariantId
1267
- ).catch(() => void 0);
1268
- }
1309
+ const result = await runInTransaction(
1310
+ em,
1311
+ async (trx) => applyInventoryReceiveInTransaction(trx, ctx, input)
1312
+ );
1313
+ await emitInventoryReceiveSideEffects(ctx, result);
1269
1314
  return { movementId: result.movementId };
1270
1315
  },
1271
1316
  buildLog: async ({ input, result, ctx }) => buildMutationLog({
@@ -1279,6 +1324,169 @@ const receiveInventoryCommand = {
1279
1324
  cacheAliases: [WMS_INVENTORY_BALANCE_RESOURCE]
1280
1325
  })
1281
1326
  };
1327
+ async function applyInventoryMoveInTransaction(trx, ctx, input) {
1328
+ const scope = resolveScope(ctx, input);
1329
+ await requireWarehouse(trx, ctx, input.warehouseId, scope);
1330
+ const sourceLocation = await requireLocation(trx, ctx, input.fromLocationId, scope);
1331
+ const targetLocation = await requireLocation(trx, ctx, input.toLocationId, scope);
1332
+ const sourceWarehouseId = typeof sourceLocation.warehouse === "string" ? sourceLocation.warehouse : sourceLocation.warehouse.id;
1333
+ const targetWarehouseId = typeof targetLocation.warehouse === "string" ? targetLocation.warehouse : targetLocation.warehouse.id;
1334
+ if (sourceWarehouseId !== input.warehouseId || targetWarehouseId !== input.warehouseId) {
1335
+ throw new CrudHttpError(422, { error: "invalid_location" });
1336
+ }
1337
+ const sourceBalance = await findExactBalanceForUpdate(trx, scope, {
1338
+ warehouseId: input.warehouseId,
1339
+ locationId: input.fromLocationId,
1340
+ catalogVariantId: input.catalogVariantId,
1341
+ lotId: input.lotId,
1342
+ serialNumber: input.serialNumber
1343
+ });
1344
+ if (!sourceBalance) {
1345
+ throw new CrudHttpError(409, { error: "insufficient_stock" });
1346
+ }
1347
+ const sourceBalanceAction = "updated";
1348
+ const targetResult = await upsertBalanceBucket(trx, scope, {
1349
+ warehouseId: input.warehouseId,
1350
+ locationId: input.toLocationId,
1351
+ catalogVariantId: input.catalogVariantId,
1352
+ lotId: input.lotId,
1353
+ serialNumber: input.serialNumber
1354
+ });
1355
+ const targetBalance = targetResult.balance;
1356
+ const targetBalanceAction = targetResult.created ? "created" : "updated";
1357
+ const performedAt = input.performedAt ?? /* @__PURE__ */ new Date();
1358
+ const receivedAt = await resolveReceivedAtForBalance(trx, sourceBalance, scope, performedAt);
1359
+ const movementInput = {
1360
+ warehouseId: input.warehouseId,
1361
+ locationFromId: input.fromLocationId,
1362
+ locationToId: input.toLocationId,
1363
+ catalogVariantId: input.catalogVariantId,
1364
+ lotId: input.lotId ?? null,
1365
+ serialNumber: input.serialNumber ?? null,
1366
+ quantity: input.quantity,
1367
+ type: input.type ?? "transfer",
1368
+ referenceType: input.referenceType,
1369
+ referenceId: input.referenceId,
1370
+ performedBy: input.performedBy,
1371
+ performedAt,
1372
+ receivedAt,
1373
+ reason: input.reason,
1374
+ reasonCode: input.reasonCode ?? null,
1375
+ metadata: input.metadata ?? null
1376
+ };
1377
+ const idempotencyKey = buildMovementIdempotencyKey({
1378
+ referenceType: movementInput.referenceType,
1379
+ referenceId: movementInput.referenceId,
1380
+ type: movementInput.type,
1381
+ warehouseId: movementInput.warehouseId,
1382
+ locationFromId: movementInput.locationFromId,
1383
+ locationToId: movementInput.locationToId,
1384
+ catalogVariantId: movementInput.catalogVariantId,
1385
+ lotId: movementInput.lotId,
1386
+ serialNumber: movementInput.serialNumber,
1387
+ quantity: movementInput.quantity
1388
+ });
1389
+ const existingMovement = await findExistingMovementByIdempotencyKey(trx, scope, idempotencyKey);
1390
+ if (existingMovement) {
1391
+ return {
1392
+ movementId: existingMovement.id,
1393
+ warehouseId: input.warehouseId,
1394
+ catalogVariantId: input.catalogVariantId,
1395
+ quantity: input.quantity,
1396
+ tenantId: scope.tenantId,
1397
+ organizationId: scope.organizationId,
1398
+ movementEntity: existingMovement,
1399
+ balances: [
1400
+ { entity: sourceBalance, action: sourceBalanceAction },
1401
+ { entity: targetBalance, action: targetBalanceAction }
1402
+ ],
1403
+ idempotentReplay: true
1404
+ };
1405
+ }
1406
+ const { movement, idempotentReplay } = await persistMovementWithIdempotency(trx, scope, movementInput);
1407
+ if (idempotentReplay) {
1408
+ return {
1409
+ movementId: movement.id,
1410
+ warehouseId: input.warehouseId,
1411
+ catalogVariantId: input.catalogVariantId,
1412
+ quantity: input.quantity,
1413
+ tenantId: scope.tenantId,
1414
+ organizationId: scope.organizationId,
1415
+ movementEntity: movement,
1416
+ balances: [
1417
+ { entity: sourceBalance, action: sourceBalanceAction },
1418
+ { entity: targetBalance, action: targetBalanceAction }
1419
+ ],
1420
+ idempotentReplay: true
1421
+ };
1422
+ }
1423
+ if (getAvailableQuantity(sourceBalance) < input.quantity - 1e-6) {
1424
+ throw new CrudHttpError(409, { error: "insufficient_stock" });
1425
+ }
1426
+ setNumeric(
1427
+ sourceBalance,
1428
+ "quantityOnHand",
1429
+ toNumber(sourceBalance.quantityOnHand) - input.quantity
1430
+ );
1431
+ setNumeric(
1432
+ targetBalance,
1433
+ "quantityOnHand",
1434
+ toNumber(targetBalance.quantityOnHand) + input.quantity
1435
+ );
1436
+ await trx.flush();
1437
+ return {
1438
+ movementId: movement.id,
1439
+ warehouseId: input.warehouseId,
1440
+ catalogVariantId: input.catalogVariantId,
1441
+ quantity: input.quantity,
1442
+ tenantId: scope.tenantId,
1443
+ organizationId: scope.organizationId,
1444
+ movementEntity: movement,
1445
+ balances: [
1446
+ { entity: sourceBalance, action: sourceBalanceAction },
1447
+ { entity: targetBalance, action: targetBalanceAction }
1448
+ ],
1449
+ idempotentReplay: false
1450
+ };
1451
+ }
1452
+ async function emitInventoryMoveSideEffects(ctx, result) {
1453
+ if (result.idempotentReplay) return;
1454
+ await emitInventorySideEffects(ctx, {
1455
+ movements: [{ entity: result.movementEntity, action: "created" }],
1456
+ balances: result.balances
1457
+ });
1458
+ void emitWmsEvent("wms.inventory.moved", {
1459
+ id: result.movementId,
1460
+ movementId: result.movementId,
1461
+ warehouseId: result.warehouseId,
1462
+ catalogVariantId: result.catalogVariantId,
1463
+ quantity: toNumericString(result.quantity),
1464
+ tenantId: result.tenantId,
1465
+ organizationId: result.organizationId
1466
+ }).catch(() => void 0);
1467
+ void emitLowStockEventIfNeeded(
1468
+ resolveEm(ctx),
1469
+ ctx,
1470
+ { tenantId: result.tenantId, organizationId: result.organizationId },
1471
+ result.catalogVariantId
1472
+ ).catch(() => void 0);
1473
+ }
1474
+ async function findPutawayCompleteMovementByReference(em, scope, referenceId) {
1475
+ return findOneWithDecryption(
1476
+ em,
1477
+ InventoryMovement,
1478
+ {
1479
+ organizationId: scope.organizationId,
1480
+ tenantId: scope.tenantId,
1481
+ referenceType: "manual",
1482
+ referenceId,
1483
+ type: "putaway",
1484
+ deletedAt: null
1485
+ },
1486
+ void 0,
1487
+ scope
1488
+ );
1489
+ }
1282
1490
  const moveInventoryCommand = {
1283
1491
  id: "wms.inventory.move",
1284
1492
  // See "WMS Inventory Mutation Commands — Undo Policy" at top of file.
@@ -1288,136 +1496,11 @@ const moveInventoryCommand = {
1288
1496
  ensureTenantScope(ctx, input.tenantId);
1289
1497
  ensureOrganizationScope(ctx, input.organizationId);
1290
1498
  const em = resolveEm(ctx);
1291
- const result = await runInTransaction(em, async (trx) => {
1292
- const scope = resolveScope(ctx, input);
1293
- await requireWarehouse(trx, ctx, input.warehouseId, scope);
1294
- const sourceLocation = await requireLocation(trx, ctx, input.fromLocationId, scope);
1295
- const targetLocation = await requireLocation(trx, ctx, input.toLocationId, scope);
1296
- const sourceWarehouseId = typeof sourceLocation.warehouse === "string" ? sourceLocation.warehouse : sourceLocation.warehouse.id;
1297
- const targetWarehouseId = typeof targetLocation.warehouse === "string" ? targetLocation.warehouse : targetLocation.warehouse.id;
1298
- if (sourceWarehouseId !== input.warehouseId || targetWarehouseId !== input.warehouseId) {
1299
- throw new CrudHttpError(422, { error: "invalid_location" });
1300
- }
1301
- const sourceBalance = await findExactBalanceForUpdate(trx, scope, {
1302
- warehouseId: input.warehouseId,
1303
- locationId: input.fromLocationId,
1304
- catalogVariantId: input.catalogVariantId,
1305
- lotId: input.lotId,
1306
- serialNumber: input.serialNumber
1307
- });
1308
- if (!sourceBalance) {
1309
- throw new CrudHttpError(409, { error: "insufficient_stock" });
1310
- }
1311
- const sourceBalanceAction = "updated";
1312
- const targetResult = await upsertBalanceBucket(trx, scope, {
1313
- warehouseId: input.warehouseId,
1314
- locationId: input.toLocationId,
1315
- catalogVariantId: input.catalogVariantId,
1316
- lotId: input.lotId,
1317
- serialNumber: input.serialNumber
1318
- });
1319
- const targetBalance = targetResult.balance;
1320
- const targetBalanceAction = targetResult.created ? "created" : "updated";
1321
- const performedAt = input.performedAt ?? /* @__PURE__ */ new Date();
1322
- const receivedAt = await resolveReceivedAtForBalance(trx, sourceBalance, scope, performedAt);
1323
- const movementInput = {
1324
- warehouseId: input.warehouseId,
1325
- locationFromId: input.fromLocationId,
1326
- locationToId: input.toLocationId,
1327
- catalogVariantId: input.catalogVariantId,
1328
- lotId: input.lotId ?? null,
1329
- serialNumber: input.serialNumber ?? null,
1330
- quantity: input.quantity,
1331
- type: input.type ?? "transfer",
1332
- referenceType: input.referenceType,
1333
- referenceId: input.referenceId,
1334
- performedBy: input.performedBy,
1335
- performedAt,
1336
- receivedAt,
1337
- reason: input.reason,
1338
- reasonCode: input.reasonCode ?? null,
1339
- metadata: input.metadata ?? null
1340
- };
1341
- const idempotencyKey = buildMovementIdempotencyKey({
1342
- referenceType: movementInput.referenceType,
1343
- referenceId: movementInput.referenceId,
1344
- type: movementInput.type,
1345
- warehouseId: movementInput.warehouseId,
1346
- locationFromId: movementInput.locationFromId,
1347
- locationToId: movementInput.locationToId,
1348
- catalogVariantId: movementInput.catalogVariantId,
1349
- lotId: movementInput.lotId,
1350
- serialNumber: movementInput.serialNumber,
1351
- quantity: movementInput.quantity
1352
- });
1353
- const existingMovement = await findExistingMovementByIdempotencyKey(trx, scope, idempotencyKey);
1354
- if (existingMovement) {
1355
- return {
1356
- movementId: existingMovement.id,
1357
- warehouseId: input.warehouseId,
1358
- catalogVariantId: input.catalogVariantId,
1359
- quantity: input.quantity,
1360
- tenantId: scope.tenantId,
1361
- organizationId: scope.organizationId,
1362
- movementEntity: existingMovement,
1363
- balances: [
1364
- { entity: sourceBalance, action: sourceBalanceAction },
1365
- { entity: targetBalance, action: targetBalanceAction }
1366
- ],
1367
- idempotentReplay: true
1368
- };
1369
- }
1370
- if (getAvailableQuantity(sourceBalance) < input.quantity - 1e-6) {
1371
- throw new CrudHttpError(409, { error: "insufficient_stock" });
1372
- }
1373
- setNumeric(
1374
- sourceBalance,
1375
- "quantityOnHand",
1376
- toNumber(sourceBalance.quantityOnHand) - input.quantity
1377
- );
1378
- setNumeric(
1379
- targetBalance,
1380
- "quantityOnHand",
1381
- toNumber(targetBalance.quantityOnHand) + input.quantity
1382
- );
1383
- const { movement } = await persistMovementWithIdempotency(trx, scope, movementInput);
1384
- await trx.flush();
1385
- return {
1386
- movementId: movement.id,
1387
- warehouseId: input.warehouseId,
1388
- catalogVariantId: input.catalogVariantId,
1389
- quantity: input.quantity,
1390
- tenantId: scope.tenantId,
1391
- organizationId: scope.organizationId,
1392
- movementEntity: movement,
1393
- balances: [
1394
- { entity: sourceBalance, action: sourceBalanceAction },
1395
- { entity: targetBalance, action: targetBalanceAction }
1396
- ],
1397
- idempotentReplay: false
1398
- };
1399
- });
1400
- if (!result.idempotentReplay) {
1401
- await emitInventorySideEffects(ctx, {
1402
- movements: [{ entity: result.movementEntity, action: "created" }],
1403
- balances: result.balances
1404
- });
1405
- void emitWmsEvent("wms.inventory.moved", {
1406
- id: result.movementId,
1407
- movementId: result.movementId,
1408
- warehouseId: result.warehouseId,
1409
- catalogVariantId: result.catalogVariantId,
1410
- quantity: toNumericString(result.quantity),
1411
- tenantId: result.tenantId,
1412
- organizationId: result.organizationId
1413
- }).catch(() => void 0);
1414
- void emitLowStockEventIfNeeded(
1415
- resolveEm(ctx),
1416
- ctx,
1417
- { tenantId: result.tenantId, organizationId: result.organizationId },
1418
- result.catalogVariantId
1419
- ).catch(() => void 0);
1420
- }
1499
+ const result = await runInTransaction(
1500
+ em,
1501
+ async (trx) => applyInventoryMoveInTransaction(trx, ctx, input)
1502
+ );
1503
+ await emitInventoryMoveSideEffects(ctx, result);
1421
1504
  return { movementId: result.movementId };
1422
1505
  },
1423
1506
  buildLog: async ({ input, result, ctx }) => buildMutationLog({
@@ -1527,12 +1610,26 @@ const cycleCountInventoryCommand = {
1527
1610
  )
1528
1611
  });
1529
1612
  }
1613
+ const { movement, idempotentReplay } = await persistMovementWithIdempotency(trx, scope, movementInput);
1614
+ if (idempotentReplay) {
1615
+ return {
1616
+ adjustmentDelta: toNumericString(delta),
1617
+ movementId: movement.id,
1618
+ warehouseId: input.warehouseId,
1619
+ catalogVariantId: input.catalogVariantId,
1620
+ tenantId: scope.tenantId,
1621
+ organizationId: scope.organizationId,
1622
+ movementEntity: movement,
1623
+ balanceEntity: balance,
1624
+ balanceAction: "updated",
1625
+ idempotentReplay: true
1626
+ };
1627
+ }
1530
1628
  setNumeric(
1531
1629
  balance,
1532
1630
  "quantityOnHand",
1533
1631
  input.countedQuantity
1534
1632
  );
1535
- const { movement } = await persistMovementWithIdempotency(trx, scope, movementInput);
1536
1633
  await trx.flush();
1537
1634
  return {
1538
1635
  adjustmentDelta: toNumericString(delta),
@@ -1593,4 +1690,11 @@ registerCommand(adjustInventoryCommand);
1593
1690
  registerCommand(receiveInventoryCommand);
1594
1691
  registerCommand(moveInventoryCommand);
1595
1692
  registerCommand(cycleCountInventoryCommand);
1693
+ export {
1694
+ applyInventoryMoveInTransaction,
1695
+ applyInventoryReceiveInTransaction,
1696
+ emitInventoryMoveSideEffects,
1697
+ emitInventoryReceiveSideEffects,
1698
+ findPutawayCompleteMovementByReference
1699
+ };
1596
1700
  //# sourceMappingURL=inventory-actions.js.map