@open-mercato/core 0.6.7-develop.6669.1.40b669666b → 0.6.7-develop.6670.1.4efa7961c6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/inventory_balance/index.js +21 -0
  3. package/dist/generated/entities/inventory_balance/index.js.map +7 -0
  4. package/dist/generated/entities/inventory_lot/index.js +19 -0
  5. package/dist/generated/entities/inventory_lot/index.js.map +7 -0
  6. package/dist/generated/entities/inventory_movement/index.js +35 -0
  7. package/dist/generated/entities/inventory_movement/index.js.map +7 -0
  8. package/dist/generated/entities/inventory_reservation/index.js +23 -0
  9. package/dist/generated/entities/inventory_reservation/index.js.map +7 -0
  10. package/dist/generated/entities/product_inventory_profile/index.js +21 -0
  11. package/dist/generated/entities/product_inventory_profile/index.js.map +7 -0
  12. package/dist/generated/entities/sales_order_warehouse_assignment/index.js +11 -0
  13. package/dist/generated/entities/sales_order_warehouse_assignment/index.js.map +7 -0
  14. package/dist/generated/entities/warehouse/index.js +25 -0
  15. package/dist/generated/entities/warehouse/index.js.map +7 -0
  16. package/dist/generated/entities/warehouse_location/index.js +21 -0
  17. package/dist/generated/entities/warehouse_location/index.js.map +7 -0
  18. package/dist/generated/entities/warehouse_zone/index.js +11 -0
  19. package/dist/generated/entities/warehouse_zone/index.js.map +7 -0
  20. package/dist/generated/entities.ids.generated.js +12 -0
  21. package/dist/generated/entities.ids.generated.js.map +2 -2
  22. package/dist/generated/entity-fields-registry.js +98 -0
  23. package/dist/generated/entity-fields-registry.js.map +2 -2
  24. package/dist/modules/auth/backend/roles/page.js +12 -4
  25. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  26. package/dist/modules/auth/lib/backendChrome.js +1 -0
  27. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  28. package/dist/modules/auth/services/rbacService.js +16 -17
  29. package/dist/modules/auth/services/rbacService.js.map +2 -2
  30. package/dist/modules/catalog/api/products/route.js +3 -0
  31. package/dist/modules/catalog/api/products/route.js.map +2 -2
  32. package/dist/modules/catalog/api/variants/route.js +3 -0
  33. package/dist/modules/catalog/api/variants/route.js.map +2 -2
  34. package/dist/modules/query_index/lib/engine.js +6 -6
  35. package/dist/modules/query_index/lib/engine.js.map +2 -2
  36. package/dist/modules/sales/api/documents/factory.js +1 -0
  37. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  38. package/dist/modules/sales/commands/documents.js +53 -0
  39. package/dist/modules/sales/commands/documents.js.map +2 -2
  40. package/dist/modules/sales/components/documents/ItemsSection.js +51 -2
  41. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  42. package/dist/modules/sales/events.js +2 -0
  43. package/dist/modules/sales/events.js.map +2 -2
  44. package/dist/modules/sales/widgets/injection/order-items-context.js +11 -0
  45. package/dist/modules/sales/widgets/injection/order-items-context.js.map +7 -0
  46. package/dist/modules/wms/acl.js +18 -0
  47. package/dist/modules/wms/acl.js.map +7 -0
  48. package/dist/modules/wms/analytics.js +11 -0
  49. package/dist/modules/wms/analytics.js.map +7 -0
  50. package/dist/modules/wms/api/dashboard/operational/route.js +80 -0
  51. package/dist/modules/wms/api/dashboard/operational/route.js.map +7 -0
  52. package/dist/modules/wms/api/interceptors.js +90 -0
  53. package/dist/modules/wms/api/interceptors.js.map +7 -0
  54. package/dist/modules/wms/api/inventory/adjust/route.js +51 -0
  55. package/dist/modules/wms/api/inventory/adjust/route.js.map +7 -0
  56. package/dist/modules/wms/api/inventory/allocate/route.js +51 -0
  57. package/dist/modules/wms/api/inventory/allocate/route.js.map +7 -0
  58. package/dist/modules/wms/api/inventory/balances/route.js +172 -0
  59. package/dist/modules/wms/api/inventory/balances/route.js.map +7 -0
  60. package/dist/modules/wms/api/inventory/cycle-count/route.js +52 -0
  61. package/dist/modules/wms/api/inventory/cycle-count/route.js.map +7 -0
  62. package/dist/modules/wms/api/inventory/helpers.js +113 -0
  63. package/dist/modules/wms/api/inventory/helpers.js.map +7 -0
  64. package/dist/modules/wms/api/inventory/import/apply/route.js +46 -0
  65. package/dist/modules/wms/api/inventory/import/apply/route.js.map +7 -0
  66. package/dist/modules/wms/api/inventory/import/helpers.js +195 -0
  67. package/dist/modules/wms/api/inventory/import/helpers.js.map +7 -0
  68. package/dist/modules/wms/api/inventory/import/template/route.js +32 -0
  69. package/dist/modules/wms/api/inventory/import/template/route.js.map +7 -0
  70. package/dist/modules/wms/api/inventory/import/validate/route.js +54 -0
  71. package/dist/modules/wms/api/inventory/import/validate/route.js.map +7 -0
  72. package/dist/modules/wms/api/inventory/move/route.js +51 -0
  73. package/dist/modules/wms/api/inventory/move/route.js.map +7 -0
  74. package/dist/modules/wms/api/inventory/movements/route.js +164 -0
  75. package/dist/modules/wms/api/inventory/movements/route.js.map +7 -0
  76. package/dist/modules/wms/api/inventory/receive/route.js +50 -0
  77. package/dist/modules/wms/api/inventory/receive/route.js.map +7 -0
  78. package/dist/modules/wms/api/inventory/release/route.js +44 -0
  79. package/dist/modules/wms/api/inventory/release/route.js.map +7 -0
  80. package/dist/modules/wms/api/inventory/reservations/route.js +128 -0
  81. package/dist/modules/wms/api/inventory/reservations/route.js.map +7 -0
  82. package/dist/modules/wms/api/inventory/reserve/route.js +59 -0
  83. package/dist/modules/wms/api/inventory/reserve/route.js.map +7 -0
  84. package/dist/modules/wms/api/inventory-profiles/route.js +178 -0
  85. package/dist/modules/wms/api/inventory-profiles/route.js.map +7 -0
  86. package/dist/modules/wms/api/listEnrichers.js +181 -0
  87. package/dist/modules/wms/api/listEnrichers.js.map +7 -0
  88. package/dist/modules/wms/api/listSearch.js +77 -0
  89. package/dist/modules/wms/api/listSearch.js.map +7 -0
  90. package/dist/modules/wms/api/locations/route.js +172 -0
  91. package/dist/modules/wms/api/locations/route.js.map +7 -0
  92. package/dist/modules/wms/api/lots/route.js +204 -0
  93. package/dist/modules/wms/api/lots/route.js.map +7 -0
  94. package/dist/modules/wms/api/openapi.js +27 -0
  95. package/dist/modules/wms/api/openapi.js.map +7 -0
  96. package/dist/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.js +54 -0
  97. package/dist/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.js.map +7 -0
  98. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js +279 -0
  99. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js.map +7 -0
  100. package/dist/modules/wms/api/sales-orders/assign-warehouse/route.js +56 -0
  101. package/dist/modules/wms/api/sales-orders/assign-warehouse/route.js.map +7 -0
  102. package/dist/modules/wms/api/sales-orders/unassign-warehouse/route.js +43 -0
  103. package/dist/modules/wms/api/sales-orders/unassign-warehouse/route.js.map +7 -0
  104. package/dist/modules/wms/api/warehouses/route.js +181 -0
  105. package/dist/modules/wms/api/warehouses/route.js.map +7 -0
  106. package/dist/modules/wms/api/zones/route.js +159 -0
  107. package/dist/modules/wms/api/zones/route.js.map +7 -0
  108. package/dist/modules/wms/backend/config/wms/page.js +9 -0
  109. package/dist/modules/wms/backend/config/wms/page.js.map +7 -0
  110. package/dist/modules/wms/backend/config/wms/page.meta.js +18 -0
  111. package/dist/modules/wms/backend/config/wms/page.meta.js.map +7 -0
  112. package/dist/modules/wms/backend/page.js +9 -0
  113. package/dist/modules/wms/backend/page.js.map +7 -0
  114. package/dist/modules/wms/backend/page.meta.js +16 -0
  115. package/dist/modules/wms/backend/page.meta.js.map +7 -0
  116. package/dist/modules/wms/backend/wms/inventory/page.js +9 -0
  117. package/dist/modules/wms/backend/wms/inventory/page.js.map +7 -0
  118. package/dist/modules/wms/backend/wms/inventory/page.meta.js +18 -0
  119. package/dist/modules/wms/backend/wms/inventory/page.meta.js.map +7 -0
  120. package/dist/modules/wms/backend/wms/location/[id]/page.js +9 -0
  121. package/dist/modules/wms/backend/wms/location/[id]/page.js.map +7 -0
  122. package/dist/modules/wms/backend/wms/location/[id]/page.meta.js +18 -0
  123. package/dist/modules/wms/backend/wms/location/[id]/page.meta.js.map +7 -0
  124. package/dist/modules/wms/backend/wms/locations/page.js +10 -0
  125. package/dist/modules/wms/backend/wms/locations/page.js.map +7 -0
  126. package/dist/modules/wms/backend/wms/locations/page.meta.js +18 -0
  127. package/dist/modules/wms/backend/wms/locations/page.meta.js.map +7 -0
  128. package/dist/modules/wms/backend/wms/lot/[id]/page.js +9 -0
  129. package/dist/modules/wms/backend/wms/lot/[id]/page.js.map +7 -0
  130. package/dist/modules/wms/backend/wms/lot/[id]/page.meta.js +18 -0
  131. package/dist/modules/wms/backend/wms/lot/[id]/page.meta.js.map +7 -0
  132. package/dist/modules/wms/backend/wms/lots/page.js +9 -0
  133. package/dist/modules/wms/backend/wms/lots/page.js.map +7 -0
  134. package/dist/modules/wms/backend/wms/lots/page.meta.js +18 -0
  135. package/dist/modules/wms/backend/wms/lots/page.meta.js.map +7 -0
  136. package/dist/modules/wms/backend/wms/movements/page.js +22 -0
  137. package/dist/modules/wms/backend/wms/movements/page.js.map +7 -0
  138. package/dist/modules/wms/backend/wms/movements/page.meta.js +18 -0
  139. package/dist/modules/wms/backend/wms/movements/page.meta.js.map +7 -0
  140. package/dist/modules/wms/backend/wms/reservations/page.js +23 -0
  141. package/dist/modules/wms/backend/wms/reservations/page.js.map +7 -0
  142. package/dist/modules/wms/backend/wms/reservations/page.meta.js +18 -0
  143. package/dist/modules/wms/backend/wms/reservations/page.meta.js.map +7 -0
  144. package/dist/modules/wms/backend/wms/sku/[id]/page.js +9 -0
  145. package/dist/modules/wms/backend/wms/sku/[id]/page.js.map +7 -0
  146. package/dist/modules/wms/backend/wms/sku/[id]/page.meta.js +18 -0
  147. package/dist/modules/wms/backend/wms/sku/[id]/page.meta.js.map +7 -0
  148. package/dist/modules/wms/backend/wms/warehouses/page.js +10 -0
  149. package/dist/modules/wms/backend/wms/warehouses/page.js.map +7 -0
  150. package/dist/modules/wms/backend/wms/warehouses/page.meta.js +18 -0
  151. package/dist/modules/wms/backend/wms/warehouses/page.meta.js.map +7 -0
  152. package/dist/modules/wms/backend/wms/zones/page.js +10 -0
  153. package/dist/modules/wms/backend/wms/zones/page.js.map +7 -0
  154. package/dist/modules/wms/backend/wms/zones/page.meta.js +18 -0
  155. package/dist/modules/wms/backend/wms/zones/page.meta.js.map +7 -0
  156. package/dist/modules/wms/ce.js +80 -0
  157. package/dist/modules/wms/ce.js.map +7 -0
  158. package/dist/modules/wms/cli.js +83 -0
  159. package/dist/modules/wms/cli.js.map +7 -0
  160. package/dist/modules/wms/commands/configuration.js +1519 -0
  161. package/dist/modules/wms/commands/configuration.js.map +7 -0
  162. package/dist/modules/wms/commands/index.js +4 -0
  163. package/dist/modules/wms/commands/index.js.map +7 -0
  164. package/dist/modules/wms/commands/inventory-actions.js +1539 -0
  165. package/dist/modules/wms/commands/inventory-actions.js.map +7 -0
  166. package/dist/modules/wms/commands/sales-order-assignment.js +277 -0
  167. package/dist/modules/wms/commands/sales-order-assignment.js.map +7 -0
  168. package/dist/modules/wms/commands/shared.js +82 -0
  169. package/dist/modules/wms/commands/shared.js.map +7 -0
  170. package/dist/modules/wms/components/backend/AdjustInventoryDialog.js +755 -0
  171. package/dist/modules/wms/components/backend/AdjustInventoryDialog.js.map +7 -0
  172. package/dist/modules/wms/components/backend/ChangeLotStatusDialog.js +269 -0
  173. package/dist/modules/wms/components/backend/ChangeLotStatusDialog.js.map +7 -0
  174. package/dist/modules/wms/components/backend/CycleCountWizardDialog.js +1783 -0
  175. package/dist/modules/wms/components/backend/CycleCountWizardDialog.js.map +7 -0
  176. package/dist/modules/wms/components/backend/ImportInventoryDialog.js +766 -0
  177. package/dist/modules/wms/components/backend/ImportInventoryDialog.js.map +7 -0
  178. package/dist/modules/wms/components/backend/InventoryOperationsSection.js +119 -0
  179. package/dist/modules/wms/components/backend/InventoryOperationsSection.js.map +7 -0
  180. package/dist/modules/wms/components/backend/LocationEditDialog.js +140 -0
  181. package/dist/modules/wms/components/backend/LocationEditDialog.js.map +7 -0
  182. package/dist/modules/wms/components/backend/MoveInventoryDialog.js +791 -0
  183. package/dist/modules/wms/components/backend/MoveInventoryDialog.js.map +7 -0
  184. package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js +656 -0
  185. package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js.map +7 -0
  186. package/dist/modules/wms/components/backend/ReleaseReservationDialog.js +344 -0
  187. package/dist/modules/wms/components/backend/ReleaseReservationDialog.js.map +7 -0
  188. package/dist/modules/wms/components/backend/ReserveInventoryDialog.js +475 -0
  189. package/dist/modules/wms/components/backend/ReserveInventoryDialog.js.map +7 -0
  190. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +1112 -0
  191. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +7 -0
  192. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +908 -0
  193. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +7 -0
  194. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +1015 -0
  195. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +7 -0
  196. package/dist/modules/wms/components/backend/WmsLotDetailPage.js +1049 -0
  197. package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +7 -0
  198. package/dist/modules/wms/components/backend/WmsLotsListPage.js +297 -0
  199. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +7 -0
  200. package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js +757 -0
  201. package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js.map +7 -0
  202. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +975 -0
  203. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +7 -0
  204. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +710 -0
  205. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +7 -0
  206. package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js +79 -0
  207. package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js.map +7 -0
  208. package/dist/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.js +24 -0
  209. package/dist/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.js.map +7 -0
  210. package/dist/modules/wms/components/backend/wmsLookupLoaders.js +55 -0
  211. package/dist/modules/wms/components/backend/wmsLookupLoaders.js.map +7 -0
  212. package/dist/modules/wms/data/enrichers.js +501 -0
  213. package/dist/modules/wms/data/enrichers.js.map +7 -0
  214. package/dist/modules/wms/data/entities.js +467 -0
  215. package/dist/modules/wms/data/entities.js.map +7 -0
  216. package/dist/modules/wms/data/validators.js +399 -0
  217. package/dist/modules/wms/data/validators.js.map +7 -0
  218. package/dist/modules/wms/di.js +27 -0
  219. package/dist/modules/wms/di.js.map +7 -0
  220. package/dist/modules/wms/events.js +42 -0
  221. package/dist/modules/wms/events.js.map +7 -0
  222. package/dist/modules/wms/index.js +17 -0
  223. package/dist/modules/wms/index.js.map +7 -0
  224. package/dist/modules/wms/lib/catalogInventoryProfileIntent.js +54 -0
  225. package/dist/modules/wms/lib/catalogInventoryProfileIntent.js.map +7 -0
  226. package/dist/modules/wms/lib/catalogInventoryProfileSync.js +144 -0
  227. package/dist/modules/wms/lib/catalogInventoryProfileSync.js.map +7 -0
  228. package/dist/modules/wms/lib/expiry.js +29 -0
  229. package/dist/modules/wms/lib/expiry.js.map +7 -0
  230. package/dist/modules/wms/lib/flashMutationError.js +51 -0
  231. package/dist/modules/wms/lib/flashMutationError.js.map +7 -0
  232. package/dist/modules/wms/lib/inventoryDisplayUi.js +188 -0
  233. package/dist/modules/wms/lib/inventoryDisplayUi.js.map +7 -0
  234. package/dist/modules/wms/lib/inventoryIdempotency.js +37 -0
  235. package/dist/modules/wms/lib/inventoryIdempotency.js.map +7 -0
  236. package/dist/modules/wms/lib/inventoryImportCsv.js +173 -0
  237. package/dist/modules/wms/lib/inventoryImportCsv.js.map +7 -0
  238. package/dist/modules/wms/lib/inventoryImportService.js +468 -0
  239. package/dist/modules/wms/lib/inventoryImportService.js.map +7 -0
  240. package/dist/modules/wms/lib/inventoryMutationUi.js +25 -0
  241. package/dist/modules/wms/lib/inventoryMutationUi.js.map +7 -0
  242. package/dist/modules/wms/lib/inventoryPolicy.js +61 -0
  243. package/dist/modules/wms/lib/inventoryPolicy.js.map +7 -0
  244. package/dist/modules/wms/lib/inventoryReconciliation.js +193 -0
  245. package/dist/modules/wms/lib/inventoryReconciliation.js.map +7 -0
  246. package/dist/modules/wms/lib/inventoryTrackingValidation.js +13 -0
  247. package/dist/modules/wms/lib/inventoryTrackingValidation.js.map +7 -0
  248. package/dist/modules/wms/lib/loadOperationalDashboard.js +580 -0
  249. package/dist/modules/wms/lib/loadOperationalDashboard.js.map +7 -0
  250. package/dist/modules/wms/lib/lowStockBalanceFilter.js +49 -0
  251. package/dist/modules/wms/lib/lowStockBalanceFilter.js.map +7 -0
  252. package/dist/modules/wms/lib/primaryWarehousePolicy.js +32 -0
  253. package/dist/modules/wms/lib/primaryWarehousePolicy.js.map +7 -0
  254. package/dist/modules/wms/lib/roleFeatures.js +30 -0
  255. package/dist/modules/wms/lib/roleFeatures.js.map +7 -0
  256. package/dist/modules/wms/lib/salesOrderInventoryAutomation.js +291 -0
  257. package/dist/modules/wms/lib/salesOrderInventoryAutomation.js.map +7 -0
  258. package/dist/modules/wms/lib/salesOrderWarehouseAssignment.js +54 -0
  259. package/dist/modules/wms/lib/salesOrderWarehouseAssignment.js.map +7 -0
  260. package/dist/modules/wms/lib/wmsIntegrationToggles.js +71 -0
  261. package/dist/modules/wms/lib/wmsIntegrationToggles.js.map +7 -0
  262. package/dist/modules/wms/migrations/Migration20260428110546.js +78 -0
  263. package/dist/modules/wms/migrations/Migration20260428110546.js.map +7 -0
  264. package/dist/modules/wms/migrations/Migration20260527120000.js +15 -0
  265. package/dist/modules/wms/migrations/Migration20260527120000.js.map +7 -0
  266. package/dist/modules/wms/migrations/Migration20260527140000.js +37 -0
  267. package/dist/modules/wms/migrations/Migration20260527140000.js.map +7 -0
  268. package/dist/modules/wms/migrations/Migration20260613120000.js +23 -0
  269. package/dist/modules/wms/migrations/Migration20260613120000.js.map +7 -0
  270. package/dist/modules/wms/migrations/Migration20260616090000.js +13 -0
  271. package/dist/modules/wms/migrations/Migration20260616090000.js.map +7 -0
  272. package/dist/modules/wms/migrations/Migration20260707180000.js +15 -0
  273. package/dist/modules/wms/migrations/Migration20260707180000.js.map +7 -0
  274. package/dist/modules/wms/notifications.client.js +18 -0
  275. package/dist/modules/wms/notifications.client.js.map +7 -0
  276. package/dist/modules/wms/notifications.js +53 -0
  277. package/dist/modules/wms/notifications.js.map +7 -0
  278. package/dist/modules/wms/search.js +196 -0
  279. package/dist/modules/wms/search.js.map +7 -0
  280. package/dist/modules/wms/setup.js +30 -0
  281. package/dist/modules/wms/setup.js.map +7 -0
  282. package/dist/modules/wms/subscribers/low-stock-notification.js +40 -0
  283. package/dist/modules/wms/subscribers/low-stock-notification.js.map +7 -0
  284. package/dist/modules/wms/subscribers/reservation-shortfall-notification.js +69 -0
  285. package/dist/modules/wms/subscribers/reservation-shortfall-notification.js.map +7 -0
  286. package/dist/modules/wms/subscribers/sales-order-cancelled-release.js +14 -0
  287. package/dist/modules/wms/subscribers/sales-order-cancelled-release.js.map +7 -0
  288. package/dist/modules/wms/subscribers/sales-order-confirmed-reserve.js +14 -0
  289. package/dist/modules/wms/subscribers/sales-order-confirmed-reserve.js.map +7 -0
  290. package/dist/modules/wms/translations.js +10 -0
  291. package/dist/modules/wms/translations.js.map +7 -0
  292. package/dist/modules/wms/vector.js +9 -0
  293. package/dist/modules/wms/vector.js.map +7 -0
  294. package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js +200 -0
  295. package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js.map +7 -0
  296. package/dist/modules/wms/widgets/injection/order-items-stock-column/widget.js +104 -0
  297. package/dist/modules/wms/widgets/injection/order-items-stock-column/widget.js.map +7 -0
  298. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js +389 -0
  299. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js.map +7 -0
  300. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.js +16 -0
  301. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.js.map +7 -0
  302. package/dist/modules/wms/widgets/injection-table.js +36 -0
  303. package/dist/modules/wms/widgets/injection-table.js.map +7 -0
  304. package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js +150 -0
  305. package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js.map +7 -0
  306. package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js +186 -0
  307. package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js.map +7 -0
  308. package/dist/modules/wms/widgets/notifications/index.js +7 -0
  309. package/dist/modules/wms/widgets/notifications/index.js.map +7 -0
  310. package/generated/entities/inventory_balance/index.ts +9 -0
  311. package/generated/entities/inventory_lot/index.ts +8 -0
  312. package/generated/entities/inventory_movement/index.ts +16 -0
  313. package/generated/entities/inventory_reservation/index.ts +10 -0
  314. package/generated/entities/product_inventory_profile/index.ts +9 -0
  315. package/generated/entities/sales_order_warehouse_assignment/index.ts +4 -0
  316. package/generated/entities/warehouse/index.ts +11 -0
  317. package/generated/entities/warehouse_location/index.ts +9 -0
  318. package/generated/entities/warehouse_zone/index.ts +4 -0
  319. package/generated/entities.ids.generated.ts +12 -0
  320. package/generated/entity-fields-registry.ts +98 -0
  321. package/package.json +7 -7
  322. package/src/modules/auth/backend/roles/page.tsx +13 -4
  323. package/src/modules/auth/i18n/de.json +2 -0
  324. package/src/modules/auth/i18n/en.json +2 -0
  325. package/src/modules/auth/i18n/es.json +2 -0
  326. package/src/modules/auth/i18n/pl.json +2 -0
  327. package/src/modules/auth/lib/backendChrome.tsx +1 -0
  328. package/src/modules/auth/services/rbacService.ts +25 -21
  329. package/src/modules/catalog/api/products/route.ts +3 -0
  330. package/src/modules/catalog/api/variants/route.ts +3 -0
  331. package/src/modules/query_index/lib/engine.ts +18 -6
  332. package/src/modules/sales/api/documents/factory.ts +1 -0
  333. package/src/modules/sales/commands/documents.ts +71 -0
  334. package/src/modules/sales/components/documents/ItemsSection.tsx +58 -0
  335. package/src/modules/sales/events.ts +2 -0
  336. package/src/modules/sales/widgets/injection/order-items-context.ts +15 -0
  337. package/src/modules/wms/acl.ts +14 -0
  338. package/src/modules/wms/analytics.ts +9 -0
  339. package/src/modules/wms/api/dashboard/operational/route.ts +83 -0
  340. package/src/modules/wms/api/interceptors.ts +108 -0
  341. package/src/modules/wms/api/inventory/adjust/route.ts +50 -0
  342. package/src/modules/wms/api/inventory/allocate/route.ts +50 -0
  343. package/src/modules/wms/api/inventory/balances/route.ts +178 -0
  344. package/src/modules/wms/api/inventory/cycle-count/route.ts +51 -0
  345. package/src/modules/wms/api/inventory/helpers.ts +128 -0
  346. package/src/modules/wms/api/inventory/import/apply/route.ts +47 -0
  347. package/src/modules/wms/api/inventory/import/helpers.ts +223 -0
  348. package/src/modules/wms/api/inventory/import/template/route.ts +31 -0
  349. package/src/modules/wms/api/inventory/import/validate/route.ts +56 -0
  350. package/src/modules/wms/api/inventory/move/route.ts +50 -0
  351. package/src/modules/wms/api/inventory/movements/route.ts +164 -0
  352. package/src/modules/wms/api/inventory/receive/route.ts +49 -0
  353. package/src/modules/wms/api/inventory/release/route.ts +43 -0
  354. package/src/modules/wms/api/inventory/reservations/route.ts +128 -0
  355. package/src/modules/wms/api/inventory/reserve/route.ts +59 -0
  356. package/src/modules/wms/api/inventory-profiles/route.ts +177 -0
  357. package/src/modules/wms/api/listEnrichers.ts +312 -0
  358. package/src/modules/wms/api/listSearch.ts +121 -0
  359. package/src/modules/wms/api/locations/route.ts +171 -0
  360. package/src/modules/wms/api/lots/route.ts +205 -0
  361. package/src/modules/wms/api/openapi.ts +28 -0
  362. package/src/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.ts +58 -0
  363. package/src/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.ts +306 -0
  364. package/src/modules/wms/api/sales-orders/assign-warehouse/route.ts +57 -0
  365. package/src/modules/wms/api/sales-orders/unassign-warehouse/route.ts +43 -0
  366. package/src/modules/wms/api/warehouses/route.ts +181 -0
  367. package/src/modules/wms/api/zones/route.ts +158 -0
  368. package/src/modules/wms/backend/config/wms/page.meta.ts +14 -0
  369. package/src/modules/wms/backend/config/wms/page.tsx +5 -0
  370. package/src/modules/wms/backend/page.meta.ts +12 -0
  371. package/src/modules/wms/backend/page.tsx +5 -0
  372. package/src/modules/wms/backend/wms/inventory/page.meta.ts +14 -0
  373. package/src/modules/wms/backend/wms/inventory/page.tsx +5 -0
  374. package/src/modules/wms/backend/wms/location/[id]/page.meta.ts +14 -0
  375. package/src/modules/wms/backend/wms/location/[id]/page.tsx +5 -0
  376. package/src/modules/wms/backend/wms/locations/page.meta.ts +14 -0
  377. package/src/modules/wms/backend/wms/locations/page.tsx +12 -0
  378. package/src/modules/wms/backend/wms/lot/[id]/page.meta.ts +14 -0
  379. package/src/modules/wms/backend/wms/lot/[id]/page.tsx +5 -0
  380. package/src/modules/wms/backend/wms/lots/page.meta.ts +14 -0
  381. package/src/modules/wms/backend/wms/lots/page.tsx +5 -0
  382. package/src/modules/wms/backend/wms/movements/page.meta.ts +14 -0
  383. package/src/modules/wms/backend/wms/movements/page.tsx +23 -0
  384. package/src/modules/wms/backend/wms/reservations/page.meta.ts +14 -0
  385. package/src/modules/wms/backend/wms/reservations/page.tsx +24 -0
  386. package/src/modules/wms/backend/wms/sku/[id]/page.meta.ts +14 -0
  387. package/src/modules/wms/backend/wms/sku/[id]/page.tsx +5 -0
  388. package/src/modules/wms/backend/wms/warehouses/page.meta.ts +14 -0
  389. package/src/modules/wms/backend/wms/warehouses/page.tsx +12 -0
  390. package/src/modules/wms/backend/wms/zones/page.meta.ts +14 -0
  391. package/src/modules/wms/backend/wms/zones/page.tsx +12 -0
  392. package/src/modules/wms/ce.ts +76 -0
  393. package/src/modules/wms/cli.ts +96 -0
  394. package/src/modules/wms/commands/configuration.ts +1844 -0
  395. package/src/modules/wms/commands/index.ts +3 -0
  396. package/src/modules/wms/commands/inventory-actions.ts +1866 -0
  397. package/src/modules/wms/commands/sales-order-assignment.ts +346 -0
  398. package/src/modules/wms/commands/shared.ts +90 -0
  399. package/src/modules/wms/components/backend/AdjustInventoryDialog.tsx +820 -0
  400. package/src/modules/wms/components/backend/ChangeLotStatusDialog.tsx +312 -0
  401. package/src/modules/wms/components/backend/CycleCountWizardDialog.tsx +2007 -0
  402. package/src/modules/wms/components/backend/ImportInventoryDialog.tsx +1018 -0
  403. package/src/modules/wms/components/backend/InventoryOperationsSection.tsx +159 -0
  404. package/src/modules/wms/components/backend/LocationEditDialog.tsx +185 -0
  405. package/src/modules/wms/components/backend/MoveInventoryDialog.tsx +907 -0
  406. package/src/modules/wms/components/backend/ReceiveInventoryDialog.tsx +695 -0
  407. package/src/modules/wms/components/backend/ReleaseReservationDialog.tsx +424 -0
  408. package/src/modules/wms/components/backend/ReserveInventoryDialog.tsx +511 -0
  409. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +1340 -0
  410. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +1132 -0
  411. package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +1310 -0
  412. package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +1355 -0
  413. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +359 -0
  414. package/src/modules/wms/components/backend/WmsOperationalDashboardPage.tsx +958 -0
  415. package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +1245 -0
  416. package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +960 -0
  417. package/src/modules/wms/components/backend/useWmsInventoryMutationAccess.ts +89 -0
  418. package/src/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.ts +32 -0
  419. package/src/modules/wms/components/backend/wmsLookupLoaders.ts +78 -0
  420. package/src/modules/wms/data/enrichers.ts +718 -0
  421. package/src/modules/wms/data/entities.ts +436 -0
  422. package/src/modules/wms/data/validators.ts +463 -0
  423. package/src/modules/wms/di.ts +25 -0
  424. package/src/modules/wms/events.ts +41 -0
  425. package/src/modules/wms/i18n/de.json +1051 -0
  426. package/src/modules/wms/i18n/en.json +1051 -0
  427. package/src/modules/wms/i18n/es.json +1051 -0
  428. package/src/modules/wms/i18n/pl.json +1051 -0
  429. package/src/modules/wms/index.ts +15 -0
  430. package/src/modules/wms/lib/catalogInventoryProfileIntent.ts +65 -0
  431. package/src/modules/wms/lib/catalogInventoryProfileSync.ts +199 -0
  432. package/src/modules/wms/lib/expiry.ts +30 -0
  433. package/src/modules/wms/lib/flashMutationError.ts +74 -0
  434. package/src/modules/wms/lib/inventoryDisplayUi.ts +249 -0
  435. package/src/modules/wms/lib/inventoryIdempotency.ts +54 -0
  436. package/src/modules/wms/lib/inventoryImportCsv.ts +212 -0
  437. package/src/modules/wms/lib/inventoryImportService.ts +629 -0
  438. package/src/modules/wms/lib/inventoryMutationUi.ts +21 -0
  439. package/src/modules/wms/lib/inventoryPolicy.ts +111 -0
  440. package/src/modules/wms/lib/inventoryReconciliation.ts +263 -0
  441. package/src/modules/wms/lib/inventoryTrackingValidation.ts +23 -0
  442. package/src/modules/wms/lib/loadOperationalDashboard.ts +776 -0
  443. package/src/modules/wms/lib/lowStockBalanceFilter.ts +74 -0
  444. package/src/modules/wms/lib/primaryWarehousePolicy.ts +46 -0
  445. package/src/modules/wms/lib/roleFeatures.ts +32 -0
  446. package/src/modules/wms/lib/salesOrderInventoryAutomation.ts +390 -0
  447. package/src/modules/wms/lib/salesOrderWarehouseAssignment.ts +78 -0
  448. package/src/modules/wms/lib/wmsIntegrationToggles.ts +81 -0
  449. package/src/modules/wms/migrations/.snapshot-open-mercato.json +2880 -0
  450. package/src/modules/wms/migrations/Migration20260428110546.ts +91 -0
  451. package/src/modules/wms/migrations/Migration20260527120000.ts +15 -0
  452. package/src/modules/wms/migrations/Migration20260527140000.ts +35 -0
  453. package/src/modules/wms/migrations/Migration20260613120000.ts +21 -0
  454. package/src/modules/wms/migrations/Migration20260616090000.ts +11 -0
  455. package/src/modules/wms/migrations/Migration20260707180000.ts +13 -0
  456. package/src/modules/wms/notifications.client.ts +18 -0
  457. package/src/modules/wms/notifications.ts +51 -0
  458. package/src/modules/wms/search.ts +230 -0
  459. package/src/modules/wms/setup.ts +29 -0
  460. package/src/modules/wms/subscribers/low-stock-notification.ts +54 -0
  461. package/src/modules/wms/subscribers/reservation-shortfall-notification.ts +98 -0
  462. package/src/modules/wms/subscribers/sales-order-cancelled-release.ts +21 -0
  463. package/src/modules/wms/subscribers/sales-order-confirmed-reserve.ts +21 -0
  464. package/src/modules/wms/translations.ts +6 -0
  465. package/src/modules/wms/vector.ts +7 -0
  466. package/src/modules/wms/widgets/injection/catalog-inventory-profile/widget.ts +238 -0
  467. package/src/modules/wms/widgets/injection/order-items-stock-column/widget.tsx +153 -0
  468. package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.client.tsx +476 -0
  469. package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.ts +15 -0
  470. package/src/modules/wms/widgets/injection-table.ts +34 -0
  471. package/src/modules/wms/widgets/notifications/WmsLowStockRenderer.tsx +153 -0
  472. package/src/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.tsx +194 -0
  473. package/src/modules/wms/widgets/notifications/index.ts +2 -0
@@ -0,0 +1,74 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+
3
+ export type LowStockBalanceFilterMode = 'belowReorder' | 'belowSafety'
4
+
5
+ type LowStockScope = {
6
+ organizationId: string
7
+ tenantId: string
8
+ warehouseId?: string | null
9
+ }
10
+
11
+ export async function resolveLowStockVariantIds(
12
+ em: EntityManager,
13
+ scope: LowStockScope,
14
+ mode: LowStockBalanceFilterMode,
15
+ ): Promise<string[]> {
16
+ const params: unknown[] = [scope.organizationId, scope.tenantId]
17
+ let warehouseJoin = ''
18
+ if (scope.warehouseId) {
19
+ warehouseJoin = ' and b.warehouse_id = ?'
20
+ params.push(scope.warehouseId)
21
+ }
22
+
23
+ const thresholdExpr =
24
+ mode === 'belowSafety'
25
+ ? 'coalesce(p.safety_stock, 0)'
26
+ : 'coalesce(p.reorder_point, 0)'
27
+
28
+ const thresholdGuard =
29
+ mode === 'belowSafety'
30
+ ? 'coalesce(p.safety_stock, 0) > 0'
31
+ : '(coalesce(p.reorder_point, 0) > 0 or coalesce(p.safety_stock, 0) > 0)'
32
+
33
+ params.push(scope.organizationId, scope.tenantId)
34
+
35
+ const sql = `
36
+ select distinct p.catalog_variant_id as catalog_variant_id
37
+ from wms_product_inventory_profiles p
38
+ join (
39
+ select
40
+ b.catalog_variant_id,
41
+ b.warehouse_id,
42
+ sum(
43
+ coalesce(b.quantity_on_hand, 0)
44
+ - coalesce(b.quantity_reserved, 0)
45
+ - coalesce(b.quantity_allocated, 0)
46
+ ) as available
47
+ from wms_inventory_balances b
48
+ where b.organization_id = ?
49
+ and b.tenant_id = ?
50
+ and b.deleted_at is null
51
+ ${warehouseJoin}
52
+ group by b.catalog_variant_id, b.warehouse_id
53
+ ) availability
54
+ on availability.catalog_variant_id = p.catalog_variant_id
55
+ where p.organization_id = ?
56
+ and p.tenant_id = ?
57
+ and p.deleted_at is null
58
+ and p.catalog_variant_id is not null
59
+ and ${thresholdGuard}
60
+ and availability.available <= ${thresholdExpr}
61
+ `
62
+
63
+ const rows = await em.getConnection().execute<Array<{ catalog_variant_id: string }>>(sql, params)
64
+ return rows
65
+ .map((row) => row.catalog_variant_id?.trim())
66
+ .filter((value): value is string => Boolean(value))
67
+ }
68
+
69
+ /** Sentinel UUID that never matches a real entity — forces zero results when a low-stock filter returns an empty variant set. */
70
+ const NO_MATCH_UUID = '00000000-0000-4000-8000-000000000000'
71
+
72
+ export function formatLowStockVariantIdsForFilter(variantIds: string[]): string[] {
73
+ return variantIds.length > 0 ? variantIds : [NO_MATCH_UUID]
74
+ }
@@ -0,0 +1,46 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
3
+ import { Warehouse } from '../data/entities'
4
+
5
+ type Scope = {
6
+ tenantId: string
7
+ organizationId: string
8
+ }
9
+
10
+ export type WarehouseAvailability = {
11
+ warehouseId: string
12
+ available: number
13
+ }
14
+
15
+ export async function resolvePrimaryWarehouseId(
16
+ em: EntityManager,
17
+ scope: Scope,
18
+ ): Promise<string | null> {
19
+ const warehouse = await findOneWithDecryption(
20
+ em,
21
+ Warehouse,
22
+ {
23
+ organizationId: scope.organizationId,
24
+ isPrimary: true,
25
+ isActive: true,
26
+ deletedAt: null,
27
+ },
28
+ undefined,
29
+ scope,
30
+ )
31
+ return warehouse?.id ?? null
32
+ }
33
+
34
+ export function sortWarehouseAvailabilityForReservation(
35
+ warehouses: WarehouseAvailability[],
36
+ primaryWarehouseId: string | null,
37
+ ): WarehouseAvailability[] {
38
+ return [...warehouses].sort((left, right) => {
39
+ if (primaryWarehouseId) {
40
+ const leftPrimary = left.warehouseId === primaryWarehouseId ? 1 : 0
41
+ const rightPrimary = right.warehouseId === primaryWarehouseId ? 1 : 0
42
+ if (leftPrimary !== rightPrimary) return rightPrimary - leftPrimary
43
+ }
44
+ return right.available - left.available
45
+ })
46
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Reserved tenant role names seeded by WMS `setup.ts` via `ensureRoles`.
3
+ * Other modules MUST NOT reuse `operator` or `supervisor` without coordinating ACL grants and i18n labels.
4
+ */
5
+ export const WMS_OPERATOR_ROLE = 'operator' as const
6
+ export const WMS_SUPERVISOR_ROLE = 'supervisor' as const
7
+
8
+ export const WMS_CUSTOM_ROLE_NAMES = [WMS_OPERATOR_ROLE, WMS_SUPERVISOR_ROLE] as const
9
+
10
+ export const WMS_OPERATOR_FEATURES = [
11
+ 'wms.view',
12
+ 'wms.adjust_inventory',
13
+ 'wms.receive_inventory',
14
+ 'wms.cycle_count',
15
+ ] as const
16
+
17
+ export const WMS_MANAGE_FEATURES = [
18
+ 'wms.manage_warehouses',
19
+ 'wms.manage_zones',
20
+ 'wms.manage_locations',
21
+ 'wms.manage_inventory',
22
+ 'wms.manage_reservations',
23
+ ] as const
24
+
25
+ export const WMS_SUPERVISOR_FEATURES = [
26
+ ...WMS_OPERATOR_FEATURES,
27
+ 'wms.import',
28
+ ...WMS_MANAGE_FEATURES,
29
+ ] as const
30
+
31
+ export type WmsOperatorFeature = (typeof WMS_OPERATOR_FEATURES)[number]
32
+ export type WmsSupervisorFeature = (typeof WMS_SUPERVISOR_FEATURES)[number]
@@ -0,0 +1,390 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
3
+ import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
4
+ import { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
5
+ import type { FeatureTogglesService } from '@open-mercato/core/modules/feature_toggles/lib/feature-flag-check'
6
+ import type { QueryEngine } from '@open-mercato/shared/lib/query/types'
7
+ import { E } from '#generated/entities.ids.generated'
8
+ import { InventoryBalance, InventoryReservation } from '../data/entities'
9
+ import { emitWmsEvent } from '../events'
10
+ import { loadExplicitWarehouseIdForOrder } from './salesOrderWarehouseAssignment'
11
+ import {
12
+ resolvePrimaryWarehouseId,
13
+ sortWarehouseAvailabilityForReservation,
14
+ type WarehouseAvailability,
15
+ } from './primaryWarehousePolicy'
16
+ import { resolveWmsIntegrationToggleEnabled } from './wmsIntegrationToggles'
17
+
18
+ type EventContext = {
19
+ resolve: <T = unknown>(name: string) => T
20
+ }
21
+
22
+ type SalesOrderLifecyclePayload = {
23
+ orderId?: string | null
24
+ tenantId?: string | null
25
+ organizationId?: string | null
26
+ }
27
+
28
+ type Scope = {
29
+ tenantId: string
30
+ organizationId: string
31
+ }
32
+
33
+ type ReservationShortfallLine = {
34
+ catalogVariantId: string
35
+ requiredQuantity: number
36
+ reservedQuantity: number
37
+ shortfallQuantity: number
38
+ }
39
+
40
+ function isInsufficientStockError(error: unknown): boolean {
41
+ return error instanceof CrudHttpError && error.status === 409 && error.body?.error === 'insufficient_stock'
42
+ }
43
+
44
+ function isBalanceIntegrityViolationError(error: unknown): boolean {
45
+ return error instanceof CrudHttpError && error.status === 409 && error.body?.error === 'balance_integrity_violation'
46
+ }
47
+
48
+ type SalesOrderRow = {
49
+ id?: string
50
+ order_number?: string | null
51
+ tenant_id?: string | null
52
+ organization_id?: string | null
53
+ }
54
+
55
+ type SalesOrderLineRow = {
56
+ id?: string
57
+ kind?: string | null
58
+ product_variant_id?: string | null
59
+ quantity?: string | number | null
60
+ line_number?: number | null
61
+ }
62
+
63
+ function toNumber(value: unknown): number {
64
+ if (typeof value === 'number' && Number.isFinite(value)) return value
65
+ if (typeof value === 'string' && value.trim().length > 0) {
66
+ const parsed = Number(value)
67
+ if (Number.isFinite(parsed)) return parsed
68
+ }
69
+ return 0
70
+ }
71
+
72
+ function getWarehouseId(balance: InventoryBalance): string | null {
73
+ const relation = balance.warehouse as { id?: string } | string | undefined
74
+ if (typeof relation === 'string') return relation
75
+ return typeof relation?.id === 'string' ? relation.id : null
76
+ }
77
+
78
+ function buildCommandContext(ctx: EventContext, scope: Scope): CommandRuntimeContext {
79
+ return {
80
+ container: {
81
+ resolve: ctx.resolve,
82
+ } as CommandRuntimeContext['container'],
83
+ auth: null,
84
+ organizationScope: null,
85
+ selectedOrganizationId: scope.organizationId,
86
+ organizationIds: [scope.organizationId],
87
+ }
88
+ }
89
+
90
+ async function isInventoryAutomationEnabled(ctx: EventContext, tenantId: string): Promise<boolean> {
91
+ try {
92
+ const featureTogglesService = ctx.resolve<FeatureTogglesService>('featureTogglesService')
93
+ const em = ctx.resolve<EntityManager>('em')
94
+ return resolveWmsIntegrationToggleEnabled(
95
+ featureTogglesService,
96
+ em,
97
+ 'wms_integration_sales_order_inventory',
98
+ tenantId,
99
+ )
100
+ } catch {
101
+ return true
102
+ }
103
+ }
104
+
105
+ async function loadOrderViaQueryEngine(
106
+ ctx: EventContext,
107
+ orderId: string,
108
+ scope: Scope,
109
+ ): Promise<SalesOrderRow | null> {
110
+ // Read sales orders/lines via QueryEngine instead of importing the sales ORM
111
+ // entity classes — keeps the WMS module decoupled from sales internals.
112
+ // Sales mutations also flush their CRUD side effects synchronously through
113
+ // the command bus before this subscriber fires, so the query_index/base
114
+ // table is consistent at this point.
115
+ const queryEngine = ctx.resolve<QueryEngine>('queryEngine')
116
+ const result = await queryEngine.query<SalesOrderRow>(E.sales.sales_order, {
117
+ tenantId: scope.tenantId,
118
+ organizationId: scope.organizationId,
119
+ filters: { id: { $eq: orderId } },
120
+ fields: ['id', 'order_number', 'tenant_id', 'organization_id'],
121
+ page: { page: 1, pageSize: 1 },
122
+ })
123
+ return result.items[0] ?? null
124
+ }
125
+
126
+ async function loadOrderLinesViaQueryEngine(
127
+ ctx: EventContext,
128
+ orderId: string,
129
+ scope: Scope,
130
+ ): Promise<SalesOrderLineRow[]> {
131
+ const queryEngine = ctx.resolve<QueryEngine>('queryEngine')
132
+ const result = await queryEngine.query<SalesOrderLineRow>(E.sales.sales_order_line, {
133
+ tenantId: scope.tenantId,
134
+ organizationId: scope.organizationId,
135
+ filters: { order_id: { $eq: orderId } },
136
+ fields: ['id', 'kind', 'product_variant_id', 'quantity', 'line_number'],
137
+ sort: [{ field: 'line_number', dir: 'asc' as never }],
138
+ page: { page: 1, pageSize: 1000 },
139
+ })
140
+ return result.items
141
+ }
142
+
143
+ async function loadActiveReservations(
144
+ em: EntityManager,
145
+ orderId: string,
146
+ scope: Scope,
147
+ ): Promise<InventoryReservation[]> {
148
+ return findWithDecryption(
149
+ em,
150
+ InventoryReservation,
151
+ {
152
+ sourceType: 'order',
153
+ sourceId: orderId,
154
+ status: 'active',
155
+ tenantId: scope.tenantId,
156
+ organizationId: scope.organizationId,
157
+ deletedAt: null,
158
+ },
159
+ { orderBy: { createdAt: 'asc' } },
160
+ scope,
161
+ )
162
+ }
163
+
164
+ async function loadBalances(
165
+ em: EntityManager,
166
+ variantIds: string[],
167
+ scope: Scope,
168
+ ): Promise<InventoryBalance[]> {
169
+ if (variantIds.length === 0) return []
170
+ return findWithDecryption(
171
+ em,
172
+ InventoryBalance,
173
+ {
174
+ catalogVariantId: { $in: variantIds },
175
+ tenantId: scope.tenantId,
176
+ organizationId: scope.organizationId,
177
+ deletedAt: null,
178
+ },
179
+ undefined,
180
+ scope,
181
+ )
182
+ }
183
+
184
+ function buildRequiredQuantityByVariant(lines: SalesOrderLineRow[]): Map<string, number> {
185
+ const quantities = new Map<string, number>()
186
+ for (const line of lines) {
187
+ if (line.kind !== 'product' || !line.product_variant_id) continue
188
+ const quantity = toNumber(line.quantity)
189
+ if (quantity <= 0) continue
190
+ quantities.set(
191
+ line.product_variant_id,
192
+ (quantities.get(line.product_variant_id) ?? 0) + quantity,
193
+ )
194
+ }
195
+ return quantities
196
+ }
197
+
198
+ function buildReservedQuantityByVariant(reservations: InventoryReservation[]): Map<string, number> {
199
+ const quantities = new Map<string, number>()
200
+ for (const reservation of reservations) {
201
+ quantities.set(
202
+ reservation.catalogVariantId,
203
+ (quantities.get(reservation.catalogVariantId) ?? 0) + toNumber(reservation.quantity),
204
+ )
205
+ }
206
+ return quantities
207
+ }
208
+
209
+ function buildWarehouseAvailability(
210
+ balances: InventoryBalance[],
211
+ ): Map<string, WarehouseAvailability[]> {
212
+ const byVariant = new Map<string, Map<string, number>>()
213
+ for (const balance of balances) {
214
+ const warehouseId = getWarehouseId(balance)
215
+ if (!warehouseId) continue
216
+ const available =
217
+ toNumber(balance.quantityOnHand) -
218
+ toNumber(balance.quantityReserved) -
219
+ toNumber(balance.quantityAllocated)
220
+ if (available <= 0) continue
221
+
222
+ const warehouseMap = byVariant.get(balance.catalogVariantId) ?? new Map<string, number>()
223
+ warehouseMap.set(warehouseId, (warehouseMap.get(warehouseId) ?? 0) + available)
224
+ byVariant.set(balance.catalogVariantId, warehouseMap)
225
+ }
226
+
227
+ const result = new Map<string, WarehouseAvailability[]>()
228
+ for (const [variantId, warehouseMap] of byVariant.entries()) {
229
+ result.set(
230
+ variantId,
231
+ Array.from(warehouseMap.entries()).map(([warehouseId, available]) => ({ warehouseId, available })),
232
+ )
233
+ }
234
+ return result
235
+ }
236
+
237
+ export async function reserveInventoryForConfirmedOrder(
238
+ payload: SalesOrderLifecyclePayload,
239
+ ctx: EventContext,
240
+ ): Promise<void> {
241
+ if (!payload.orderId || !payload.tenantId || !payload.organizationId) return
242
+ if (!(await isInventoryAutomationEnabled(ctx, payload.tenantId))) return
243
+
244
+ const scope: Scope = {
245
+ tenantId: payload.tenantId,
246
+ organizationId: payload.organizationId,
247
+ }
248
+ const em = ctx.resolve<EntityManager>('em').fork()
249
+ const commandBus = ctx.resolve<CommandBus>('commandBus')
250
+ const commandCtx = buildCommandContext(ctx, scope)
251
+ const order = await loadOrderViaQueryEngine(ctx, payload.orderId, scope)
252
+ if (!order || typeof order.id !== 'string') return
253
+
254
+ const orderId = order.id
255
+ const orderNumber = typeof order.order_number === 'string' ? order.order_number : null
256
+
257
+ const [lines, activeReservations] = await Promise.all([
258
+ loadOrderLinesViaQueryEngine(ctx, orderId, scope),
259
+ loadActiveReservations(em, orderId, scope),
260
+ ])
261
+ const requiredByVariant = buildRequiredQuantityByVariant(lines)
262
+ if (requiredByVariant.size === 0) return
263
+
264
+ const reservedByVariant = buildReservedQuantityByVariant(activeReservations)
265
+ const balances = await loadBalances(em, Array.from(requiredByVariant.keys()), scope)
266
+ const availabilityByVariant = buildWarehouseAvailability(balances)
267
+ const [primaryWarehouseId, assignedWarehouseId] = await Promise.all([
268
+ resolvePrimaryWarehouseId(em, scope),
269
+ loadExplicitWarehouseIdForOrder(em, orderId, scope),
270
+ ])
271
+ const preferredWarehouseId = assignedWarehouseId ?? primaryWarehouseId
272
+ const shortfalls: ReservationShortfallLine[] = []
273
+
274
+ for (const [variantId, requiredQuantity] of requiredByVariant.entries()) {
275
+ let remainingQuantity = requiredQuantity - (reservedByVariant.get(variantId) ?? 0)
276
+ if (remainingQuantity <= 0) continue
277
+
278
+ let variantBuckets = availabilityByVariant.get(variantId) ?? []
279
+ if (assignedWarehouseId) {
280
+ variantBuckets = variantBuckets.filter(
281
+ (bucket) => bucket.warehouseId === assignedWarehouseId,
282
+ )
283
+ }
284
+
285
+ const warehouseAvailability = sortWarehouseAvailabilityForReservation(
286
+ variantBuckets,
287
+ preferredWarehouseId,
288
+ )
289
+ let reservedForVariant = 0
290
+ try {
291
+ for (const bucket of warehouseAvailability) {
292
+ if (remainingQuantity <= 0) break
293
+ const reserveQuantity = Math.min(remainingQuantity, bucket.available)
294
+ if (reserveQuantity <= 0) continue
295
+
296
+ await commandBus.execute('wms.inventory.reserve', {
297
+ input: {
298
+ tenantId: scope.tenantId,
299
+ organizationId: scope.organizationId,
300
+ warehouseId: bucket.warehouseId,
301
+ catalogVariantId: variantId,
302
+ quantity: reserveQuantity,
303
+ sourceType: 'order',
304
+ sourceId: orderId,
305
+ metadata: {
306
+ automation: 'sales.order.confirmed',
307
+ orderId,
308
+ orderNumber,
309
+ catalogVariantId: variantId,
310
+ },
311
+ },
312
+ ctx: commandCtx,
313
+ })
314
+
315
+ remainingQuantity -= reserveQuantity
316
+ reservedForVariant += reserveQuantity
317
+ bucket.available -= reserveQuantity
318
+ }
319
+ } catch (error) {
320
+ if (!isInsufficientStockError(error)) throw error
321
+ }
322
+
323
+ if (remainingQuantity > 0.000001) {
324
+ shortfalls.push({
325
+ catalogVariantId: variantId,
326
+ requiredQuantity,
327
+ reservedQuantity: reservedForVariant + (reservedByVariant.get(variantId) ?? 0),
328
+ shortfallQuantity: remainingQuantity,
329
+ })
330
+ }
331
+ }
332
+
333
+ if (shortfalls.length > 0) {
334
+ await emitWmsEvent('wms.inventory.reservation_shortfall', {
335
+ id: orderId,
336
+ orderId,
337
+ orderNumber,
338
+ shortfalls,
339
+ tenantId: scope.tenantId,
340
+ organizationId: scope.organizationId,
341
+ })
342
+ }
343
+ }
344
+
345
+ export async function releaseInventoryForCancelledOrder(
346
+ payload: SalesOrderLifecyclePayload,
347
+ ctx: EventContext,
348
+ ): Promise<void> {
349
+ if (!payload.orderId || !payload.tenantId || !payload.organizationId) return
350
+ if (!(await isInventoryAutomationEnabled(ctx, payload.tenantId))) return
351
+
352
+ const scope: Scope = {
353
+ tenantId: payload.tenantId,
354
+ organizationId: payload.organizationId,
355
+ }
356
+ const em = ctx.resolve<EntityManager>('em').fork()
357
+ const commandBus = ctx.resolve<CommandBus>('commandBus')
358
+ const commandCtx = buildCommandContext(ctx, scope)
359
+ const activeReservations = await loadActiveReservations(em, payload.orderId, scope)
360
+
361
+ for (const reservation of activeReservations) {
362
+ try {
363
+ await commandBus.execute('wms.inventory.release', {
364
+ input: {
365
+ tenantId: scope.tenantId,
366
+ organizationId: scope.organizationId,
367
+ reservationId: reservation.id,
368
+ reason: 'sales.order.cancelled',
369
+ metadata: {
370
+ automation: 'sales.order.cancelled',
371
+ orderId: payload.orderId,
372
+ },
373
+ },
374
+ ctx: commandCtx,
375
+ })
376
+ } catch (error) {
377
+ if (!isBalanceIntegrityViolationError(error)) throw error
378
+ void emitWmsEvent('wms.inventory.balance_drift', {
379
+ id: reservation.id,
380
+ balanceId: reservation.id,
381
+ reservationId: reservation.id,
382
+ field: 'quantityReserved',
383
+ attemptedValue: null,
384
+ clampedValue: null,
385
+ tenantId: scope.tenantId,
386
+ organizationId: scope.organizationId,
387
+ }).catch(() => undefined)
388
+ }
389
+ }
390
+ }
@@ -0,0 +1,78 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
3
+ import { SalesOrderWarehouseAssignment, Warehouse } from '../data/entities'
4
+
5
+ type Scope = {
6
+ tenantId: string
7
+ organizationId: string
8
+ }
9
+
10
+ export type SalesOrderWarehouseAssignmentView = {
11
+ id: string
12
+ salesOrderId: string
13
+ warehouseId: string
14
+ warehouseName: string | null
15
+ warehouseCode: string | null
16
+ notes: string | null
17
+ assignedBy: string | null
18
+ }
19
+
20
+ function resolveWarehouseId(assignment: SalesOrderWarehouseAssignment): string | null {
21
+ const warehouseRel = assignment.warehouse as { id?: string } | undefined
22
+ return typeof warehouseRel?.id === 'string' ? warehouseRel.id : null
23
+ }
24
+
25
+ export async function loadExplicitWarehouseIdForOrder(
26
+ em: EntityManager,
27
+ salesOrderId: string,
28
+ scope: Scope,
29
+ ): Promise<string | null> {
30
+ const assignment = await findOneWithDecryption(
31
+ em,
32
+ SalesOrderWarehouseAssignment,
33
+ {
34
+ salesOrderId,
35
+ organizationId: scope.organizationId,
36
+ tenantId: scope.tenantId,
37
+ deletedAt: null,
38
+ },
39
+ { populate: ['warehouse'] },
40
+ scope,
41
+ )
42
+ if (!assignment) return null
43
+ return resolveWarehouseId(assignment)
44
+ }
45
+
46
+ export async function loadSalesOrderWarehouseAssignmentView(
47
+ em: EntityManager,
48
+ salesOrderId: string,
49
+ scope: Scope,
50
+ ): Promise<SalesOrderWarehouseAssignmentView | null> {
51
+ const assignment = await findOneWithDecryption(
52
+ em,
53
+ SalesOrderWarehouseAssignment,
54
+ {
55
+ salesOrderId,
56
+ organizationId: scope.organizationId,
57
+ tenantId: scope.tenantId,
58
+ deletedAt: null,
59
+ },
60
+ { populate: ['warehouse'] },
61
+ scope,
62
+ )
63
+ if (!assignment) return null
64
+
65
+ const warehouseId = resolveWarehouseId(assignment)
66
+ if (!warehouseId) return null
67
+
68
+ const warehouse = assignment.warehouse as Warehouse | undefined
69
+ return {
70
+ id: assignment.id,
71
+ salesOrderId: assignment.salesOrderId,
72
+ warehouseId,
73
+ warehouseName: warehouse?.name ?? null,
74
+ warehouseCode: warehouse?.code ?? null,
75
+ notes: assignment.notes ?? null,
76
+ assignedBy: assignment.assignedBy ?? null,
77
+ }
78
+ }
@@ -0,0 +1,81 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
3
+ import { FeatureToggle } from '@open-mercato/core/modules/feature_toggles/data/entities'
4
+ import type { FeatureTogglesService } from '@open-mercato/core/modules/feature_toggles/lib/feature-flag-check'
5
+
6
+ export const WMS_INTEGRATION_TOGGLES = [
7
+ {
8
+ identifier: 'wms_integration_sales_order_inventory',
9
+ name: 'Sales Order Inventory Reservation',
10
+ description: 'Allows WMS to reserve and release inventory from sales order lifecycle events.',
11
+ category: 'wms',
12
+ type: 'boolean' as const,
13
+ defaultValue: true,
14
+ },
15
+ {
16
+ identifier: 'wms_integration_shipping_shipments',
17
+ name: 'Shipping Shipment Coordination',
18
+ description: 'Allows WMS to react to shipping shipment lifecycle events when shipment orchestration is enabled.',
19
+ category: 'wms',
20
+ type: 'boolean' as const,
21
+ defaultValue: true,
22
+ },
23
+ {
24
+ identifier: 'wms_integration_procurement_goods_receipt',
25
+ name: 'Procurement Goods Receipt Bridge',
26
+ description: 'Reserved toggle for future procurement-driven receiving integration.',
27
+ category: 'wms',
28
+ type: 'boolean' as const,
29
+ defaultValue: false,
30
+ },
31
+ ] as const
32
+
33
+ export type WmsIntegrationToggleIdentifier = (typeof WMS_INTEGRATION_TOGGLES)[number]['identifier']
34
+
35
+ export function findWmsIntegrationToggleDefinition(identifier: string) {
36
+ return WMS_INTEGRATION_TOGGLES.find((toggle) => toggle.identifier === identifier) ?? null
37
+ }
38
+
39
+ export async function seedWmsIntegrationToggles(em: EntityManager): Promise<void> {
40
+ for (const toggle of WMS_INTEGRATION_TOGGLES) {
41
+ const existing = await findOneWithDecryption(em, FeatureToggle, {
42
+ identifier: toggle.identifier,
43
+ deletedAt: null,
44
+ })
45
+ if (existing) continue
46
+ em.persist(
47
+ em.create(FeatureToggle, {
48
+ identifier: toggle.identifier,
49
+ name: toggle.name,
50
+ description: toggle.description,
51
+ category: toggle.category,
52
+ type: toggle.type,
53
+ defaultValue: toggle.defaultValue,
54
+ }),
55
+ )
56
+ }
57
+ await em.flush()
58
+ }
59
+
60
+ export async function resolveWmsIntegrationToggleEnabled(
61
+ featureTogglesService: FeatureTogglesService,
62
+ em: EntityManager,
63
+ identifier: WmsIntegrationToggleIdentifier,
64
+ tenantId: string,
65
+ ): Promise<boolean> {
66
+ const definition = findWmsIntegrationToggleDefinition(identifier)
67
+ const fallback = definition?.defaultValue ?? true
68
+
69
+ const result = await featureTogglesService.getBoolConfig(identifier, tenantId)
70
+ if (result.ok) return result.value
71
+
72
+ if (result.error?.code !== 'MISSING_TOGGLE' || !definition) {
73
+ return fallback
74
+ }
75
+
76
+ await seedWmsIntegrationToggles(em)
77
+ await featureTogglesService.invalidateIsEnabledCacheByKey(identifier, tenantId)
78
+
79
+ const retried = await featureTogglesService.getBoolConfig(identifier, tenantId)
80
+ return retried.ok ? retried.value : fallback
81
+ }