@open-mercato/core 0.6.7-develop.6669.1.40b669666b → 0.6.7-develop.6671.1.4b925c5096

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,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/wms/lib/inventoryImportService.ts"],
4
+ "sourcesContent": ["import { randomUUID } from 'node:crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n InventoryBalance,\n InventoryLot,\n Warehouse,\n WarehouseLocation,\n} from '../data/entities'\nimport type {\n InventoryImportApplyInput,\n InventoryImportApplyRowInput,\n InventoryImportMode,\n InventoryImportValidateInput,\n} from '../data/validators'\nimport { ensureOrganizationScope, ensureTenantScope } from '../commands/shared'\nimport type { InventoryImportRawRow } from './inventoryImportCsv'\n\ntype ImportScope = {\n tenantId: string\n organizationId: string\n}\n\ntype ResolvedImportRow = {\n rowNumber: number\n warehouseId: string\n warehouseCode: string\n locationId: string\n locationCode: string\n catalogVariantId: string\n sku: string\n quantity: number\n lotId?: string\n lotNumber?: string\n serialNumber?: string\n currentOnHand: number\n delta: number\n}\n\nexport type InventoryImportRowResult = {\n rowNumber: number\n status: 'valid' | 'error' | 'warning' | 'skip'\n errors: string[]\n warnings: string[]\n input: InventoryImportRawRow\n resolved?: ResolvedImportRow\n}\n\nexport type InventoryImportValidationResult = {\n ok: boolean\n importBatchId: string\n summary: {\n totalRows: number\n validRows: number\n errorRows: number\n warningRows: number\n skipRows: number\n }\n rows: InventoryImportRowResult[]\n}\n\nexport type InventoryImportApplyResult = {\n ok: boolean\n importBatchId: string\n summary: {\n applied: number\n skipped: number\n failed: number\n }\n rows: Array<{\n rowNumber: number\n status: 'applied' | 'skipped' | 'failed'\n movementId?: string\n error?: string\n }>\n}\n\nfunction toNumber(value: unknown): number {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length > 0) {\n const parsed = Number(value)\n if (Number.isFinite(parsed)) return parsed\n }\n return 0\n}\n\nfunction buildBucketKey(input: {\n warehouseId: string\n locationId: string\n catalogVariantId: string\n lotId?: string | null\n serialNumber?: string | null\n}): string {\n return [\n input.warehouseId,\n input.locationId,\n input.catalogVariantId,\n input.lotId ?? '',\n input.serialNumber ?? '',\n ].join('::')\n}\n\nasync function resolveWarehouse(\n em: EntityManager,\n scope: ImportScope,\n row: InventoryImportRawRow,\n): Promise<{ id: string; code: string } | null> {\n if (row.warehouseId) {\n const warehouse = await findOneWithDecryption(\n em,\n Warehouse,\n { id: row.warehouseId, deletedAt: null },\n undefined,\n scope,\n )\n if (!warehouse) return null\n return { id: warehouse.id, code: warehouse.code }\n }\n const code = row.warehouseCode?.trim()\n if (!code) return null\n const warehouse = await findOneWithDecryption(\n em,\n Warehouse,\n { code, deletedAt: null },\n undefined,\n scope,\n )\n if (!warehouse) return null\n return { id: warehouse.id, code: warehouse.code }\n}\n\nasync function resolveLocation(\n em: EntityManager,\n scope: ImportScope,\n warehouseId: string,\n row: InventoryImportRawRow,\n): Promise<{ id: string; code: string } | null> {\n if (row.locationId) {\n const location = await findOneWithDecryption(\n em,\n WarehouseLocation,\n { id: row.locationId, deletedAt: null },\n undefined,\n scope,\n )\n if (!location) return null\n const locationWarehouseId =\n typeof location.warehouse === 'string' ? location.warehouse : location.warehouse.id\n if (locationWarehouseId !== warehouseId) return null\n return { id: location.id, code: location.code }\n }\n const code = row.locationCode?.trim()\n if (!code) return null\n const location = await findOneWithDecryption(\n em,\n WarehouseLocation,\n { warehouse: warehouseId, code, deletedAt: null },\n undefined,\n scope,\n )\n if (!location) return null\n return { id: location.id, code: location.code }\n}\n\ntype ResolvedCatalogVariant = { id: string; sku: string }\n\ntype VariantResolveResult =\n | { status: 'found'; variant: ResolvedCatalogVariant }\n | { status: 'failed'; code: 'catalog_variant_not_found' | 'sku_not_found' | 'sku_ambiguous' }\n\nasync function resolveVariantBySku(\n queryEngine: QueryEngine,\n scope: ImportScope,\n sku: string,\n): Promise<VariantResolveResult> {\n const normalizedSku = sku.trim()\n if (!normalizedSku) return { status: 'failed', code: 'sku_not_found' }\n const result = await queryEngine.query<{ id?: string | null; sku?: string | null }>(\n E.catalog.catalog_product_variant,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n filters: { sku: { $eq: normalizedSku } },\n fields: ['id', 'sku'],\n page: { page: 1, pageSize: 2 },\n },\n )\n const items = result.items ?? []\n if (items.length === 0) return { status: 'failed', code: 'sku_not_found' }\n if (items.length > 1) return { status: 'failed', code: 'sku_ambiguous' }\n const id = items[0]?.id\n if (typeof id !== 'string' || !id) return { status: 'failed', code: 'sku_not_found' }\n return {\n status: 'found',\n variant: { id, sku: items[0]?.sku?.trim() || normalizedSku },\n }\n}\n\nasync function resolveVariant(\n queryEngine: QueryEngine,\n scope: ImportScope,\n row: InventoryImportRawRow,\n): Promise<VariantResolveResult> {\n if (row.catalogVariantId?.trim()) {\n const result = await queryEngine.query<{ id?: string | null; sku?: string | null }>(\n E.catalog.catalog_product_variant,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n filters: { id: { $eq: row.catalogVariantId.trim() } },\n fields: ['id', 'sku'],\n page: { page: 1, pageSize: 1 },\n },\n )\n const item = result.items?.[0]\n if (!item?.id) return { status: 'failed', code: 'catalog_variant_not_found' }\n return {\n status: 'found',\n variant: { id: item.id, sku: item.sku?.trim() || row.sku?.trim() || item.id },\n }\n }\n const sku = row.sku?.trim()\n if (!sku) return { status: 'failed', code: 'sku_not_found' }\n return resolveVariantBySku(queryEngine, scope, sku)\n}\n\nasync function resolveLot(\n em: EntityManager,\n scope: ImportScope,\n catalogVariantId: string,\n row: InventoryImportRawRow,\n): Promise<{ id: string; lotNumber: string } | null> {\n if (row.lotId) {\n const lot = await findOneWithDecryption(\n em,\n InventoryLot,\n { id: row.lotId, deletedAt: null },\n undefined,\n scope,\n )\n if (!lot || lot.catalogVariantId !== catalogVariantId) return null\n return { id: lot.id, lotNumber: lot.lotNumber }\n }\n const lotNumber = row.lotNumber?.trim()\n if (!lotNumber) return null\n const lot = await findOneWithDecryption(\n em,\n InventoryLot,\n { catalogVariantId, lotNumber, deletedAt: null },\n undefined,\n scope,\n )\n if (!lot) return null\n return { id: lot.id, lotNumber: lot.lotNumber }\n}\n\nasync function loadCurrentOnHand(\n em: EntityManager,\n scope: ImportScope,\n input: {\n warehouseId: string\n locationId: string\n catalogVariantId: string\n lotId?: string\n serialNumber?: string\n },\n): Promise<number> {\n const balance = await findOneWithDecryption(\n em,\n InventoryBalance,\n {\n warehouse: input.warehouseId,\n location: input.locationId,\n catalogVariantId: input.catalogVariantId,\n lot: input.lotId ?? null,\n serialNumber: input.serialNumber ?? null,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n return balance ? toNumber(balance.quantityOnHand) : 0\n}\n\nasync function verifyApplyRowDeltas(\n em: EntityManager,\n scope: ImportScope,\n mode: InventoryImportMode,\n rows: InventoryImportApplyRowInput[],\n): Promise<InventoryImportApplyRowInput[]> {\n if (mode === 'additive') {\n // Additive mode: the delta posted to the ledger always equals the row's\n // quantity (the amount received), regardless of the current on-hand balance.\n return rows.map((row) => {\n if (Math.abs(row.quantity - row.delta) > 0.000001) {\n throw new CrudHttpError(400, {\n error: 'import_delta_tampering',\n rowNumber: row.rowNumber,\n expectedDelta: row.quantity,\n providedDelta: row.delta,\n })\n }\n return row\n })\n }\n // Reconcile mode (opt-in, requires the \"reconcile to exact balance\" checkbox):\n // quantity is the target on-hand balance, so the delta must be recalculated\n // against the current balance to guard against staleness between validate/apply.\n const recalculated: InventoryImportApplyRowInput[] = []\n for (const row of rows) {\n const currentOnHand = await loadCurrentOnHand(em, scope, {\n warehouseId: row.warehouseId,\n locationId: row.locationId,\n catalogVariantId: row.catalogVariantId,\n lotId: row.lotId,\n serialNumber: row.serialNumber,\n })\n const serverDelta = row.quantity - currentOnHand\n if (Math.abs(serverDelta - row.delta) > 0.000001) {\n throw new CrudHttpError(400, {\n error: 'import_delta_tampering',\n rowNumber: row.rowNumber,\n expectedDelta: serverDelta,\n providedDelta: row.delta,\n })\n }\n recalculated.push({ ...row, delta: serverDelta })\n }\n return recalculated\n}\n\nexport async function validateInventoryImport(\n ctx: CommandRuntimeContext,\n input: InventoryImportValidateInput,\n): Promise<InventoryImportValidationResult> {\n ensureTenantScope(ctx, input.tenantId)\n ensureOrganizationScope(ctx, input.organizationId)\n const mode: InventoryImportMode = input.mode ?? 'additive'\n const scope: ImportScope = {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n }\n const em = ctx.container.resolve('em') as EntityManager\n const queryEngine = ctx.container.resolve('queryEngine') as QueryEngine\n const importBatchId = input.importBatchId ?? randomUUID()\n const seenBuckets = new Map<string, number>()\n const rows: InventoryImportRowResult[] = []\n\n for (let index = 0; index < input.rows.length; index += 1) {\n const raw = input.rows[index]\n const rowNumber = index + 1\n const errors: string[] = []\n const warnings: string[] = []\n\n const quantity = toNumber(raw.quantity)\n if (raw.quantity === undefined || raw.quantity.trim().length === 0) {\n errors.push('quantity_required')\n } else if (!Number.isFinite(quantity) || quantity < 0) {\n errors.push('quantity_invalid')\n }\n\n const hasWarehouse = Boolean(raw.warehouseId?.trim() || raw.warehouseCode?.trim())\n const hasLocation = Boolean(raw.locationId?.trim() || raw.locationCode?.trim())\n const hasVariant = Boolean(raw.catalogVariantId?.trim() || raw.sku?.trim())\n\n if (!hasWarehouse) errors.push('warehouse_required')\n if (!hasLocation) errors.push('location_required')\n if (!hasVariant) errors.push('sku_required')\n\n if (errors.length > 0) {\n rows.push({ rowNumber, status: 'error', errors, warnings, input: raw })\n continue\n }\n\n const warehouse = await resolveWarehouse(em, scope, raw)\n if (!warehouse) {\n errors.push('warehouse_not_found')\n rows.push({ rowNumber, status: 'error', errors, warnings, input: raw })\n continue\n }\n\n const location = await resolveLocation(em, scope, warehouse.id, raw)\n if (!location) {\n errors.push('location_not_found')\n rows.push({ rowNumber, status: 'error', errors, warnings, input: raw })\n continue\n }\n\n const variantResult = await resolveVariant(queryEngine, scope, raw)\n if (variantResult.status === 'failed') {\n errors.push(variantResult.code)\n rows.push({ rowNumber, status: 'error', errors, warnings, input: raw })\n continue\n }\n const variant = variantResult.variant\n\n let lot: { id: string; lotNumber: string } | null = null\n if (raw.lotId?.trim() || raw.lotNumber?.trim()) {\n lot = await resolveLot(em, scope, variant.id, raw)\n if (!lot) {\n errors.push('lot_not_found')\n rows.push({ rowNumber, status: 'error', errors, warnings, input: raw })\n continue\n }\n }\n\n const serialNumber = raw.serialNumber?.trim() || undefined\n const currentOnHand = await loadCurrentOnHand(em, scope, {\n warehouseId: warehouse.id,\n locationId: location.id,\n catalogVariantId: variant.id,\n lotId: lot?.id,\n serialNumber,\n })\n const bucketKey = buildBucketKey({\n warehouseId: warehouse.id,\n locationId: location.id,\n catalogVariantId: variant.id,\n lotId: lot?.id,\n serialNumber,\n })\n const duplicateRow = seenBuckets.get(bucketKey)\n if (duplicateRow) {\n if (input.skipDuplicates) {\n warnings.push('duplicate_row')\n warnings.push(`duplicate_of_row_${duplicateRow}`)\n rows.push({\n rowNumber,\n status: 'skip',\n errors,\n warnings,\n input: raw,\n resolved: {\n rowNumber,\n warehouseId: warehouse.id,\n warehouseCode: warehouse.code,\n locationId: location.id,\n locationCode: location.code,\n catalogVariantId: variant.id,\n sku: variant.sku,\n quantity,\n lotId: lot?.id,\n lotNumber: lot?.lotNumber,\n serialNumber,\n currentOnHand,\n delta: 0,\n },\n })\n continue\n }\n errors.push('duplicate_row')\n warnings.push(`duplicate_of_row_${duplicateRow}`)\n rows.push({ rowNumber, status: 'error', errors, warnings, input: raw })\n continue\n }\n seenBuckets.set(bucketKey, rowNumber)\n\n // Additive mode (default): quantity is the amount to receive into this bucket,\n // so the delta never depends on currentOnHand. Reconcile mode (opt-in) treats\n // quantity as the target on-hand balance instead, so it can also reduce stock.\n const delta = mode === 'additive' ? quantity : quantity - currentOnHand\n\n if (mode === 'reconcile') {\n if (delta < 0 && currentOnHand < Math.abs(delta) - 0.000001) {\n warnings.push('insufficient_available_for_negative_delta')\n }\n if (currentOnHand > 0 && Math.sign(delta) !== 0) {\n warnings.push('overwriting_existing_balance')\n }\n }\n\n if (Math.abs(delta) < 0.000001) {\n rows.push({\n rowNumber,\n status: 'skip',\n errors,\n warnings,\n input: raw,\n resolved: {\n rowNumber,\n warehouseId: warehouse.id,\n warehouseCode: warehouse.code,\n locationId: location.id,\n locationCode: location.code,\n catalogVariantId: variant.id,\n sku: variant.sku,\n quantity,\n lotId: lot?.id,\n lotNumber: lot?.lotNumber,\n serialNumber,\n currentOnHand,\n delta: 0,\n },\n })\n continue\n }\n\n rows.push({\n rowNumber,\n status: warnings.length > 0 ? 'warning' : 'valid',\n errors,\n warnings,\n input: raw,\n resolved: {\n rowNumber,\n warehouseId: warehouse.id,\n warehouseCode: warehouse.code,\n locationId: location.id,\n locationCode: location.code,\n catalogVariantId: variant.id,\n sku: variant.sku,\n quantity,\n lotId: lot?.id,\n lotNumber: lot?.lotNumber,\n serialNumber,\n currentOnHand,\n delta,\n },\n })\n }\n\n const errorRows = rows.filter((row) => row.status === 'error').length\n const warningRows = rows.filter((row) => row.status === 'warning').length\n const skipRows = rows.filter((row) => row.status === 'skip').length\n const validRows = rows.filter((row) => row.status === 'valid' || row.status === 'warning').length\n\n return {\n ok: errorRows === 0,\n importBatchId,\n summary: {\n totalRows: rows.length,\n validRows,\n errorRows,\n warningRows,\n skipRows,\n },\n rows,\n }\n}\n\nexport async function applyInventoryImport(\n ctx: CommandRuntimeContext,\n input: InventoryImportApplyInput,\n): Promise<InventoryImportApplyResult> {\n ensureTenantScope(ctx, input.tenantId)\n ensureOrganizationScope(ctx, input.organizationId)\n const mode: InventoryImportMode = input.mode ?? 'additive'\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const em = ctx.container.resolve('em') as EntityManager\n const scope: ImportScope = {\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n }\n const applyRows = await verifyApplyRowDeltas(em, scope, mode, input.rows)\n const resultRows: InventoryImportApplyResult['rows'] = []\n let applied = 0\n let skipped = 0\n let failed = 0\n\n for (const row of applyRows) {\n if (Math.abs(row.delta) < 0.000001) {\n skipped += 1\n resultRows.push({ rowNumber: row.rowNumber, status: 'skipped' })\n continue\n }\n\n try {\n const execution = await commandBus.execute('wms.inventory.adjust', {\n input: {\n organizationId: input.organizationId,\n tenantId: input.tenantId,\n warehouseId: row.warehouseId,\n locationId: row.locationId,\n catalogVariantId: row.catalogVariantId,\n lotId: row.lotId,\n serialNumber: row.serialNumber,\n delta: row.delta,\n reason: input.reason,\n referenceType: 'manual' as const,\n referenceId: randomUUID(),\n performedBy: input.performedBy,\n metadata: {\n importBatchId: input.importBatchId,\n importRowNumber: row.rowNumber,\n source: 'csv_import',\n ...(mode === 'reconcile' ? { targetQuantity: row.quantity } : {}),\n },\n },\n ctx,\n })\n applied += 1\n resultRows.push({\n rowNumber: row.rowNumber,\n status: 'applied',\n movementId: (execution.result as { movementId?: string }).movementId,\n })\n } catch (error) {\n failed += 1\n const message =\n error instanceof CrudHttpError\n ? String((error.body as { error?: unknown })?.error ?? 'apply_failed')\n : 'apply_failed'\n resultRows.push({\n rowNumber: row.rowNumber,\n status: 'failed',\n error: message,\n })\n if (!input.continueOnError) {\n throw new CrudHttpError(409, {\n error: 'import_apply_partial_failure',\n importBatchId: input.importBatchId,\n summary: { applied, skipped, failed },\n rows: resultRows,\n })\n }\n }\n }\n\n return {\n ok: failed === 0,\n importBatchId: input.importBatchId,\n summary: { applied, skipped, failed },\n rows: resultRows,\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["warehouse", "location", "lot"]
7
+ }
@@ -0,0 +1,25 @@
1
+ function parseInventoryQuantity(value) {
2
+ if (value == null || value === "") return 0;
3
+ const parsed = typeof value === "number" ? value : Number(value);
4
+ return Number.isFinite(parsed) ? parsed : 0;
5
+ }
6
+ function computeCycleCountVariance(systemOnHand, countedQuantity) {
7
+ return countedQuantity - systemOnHand;
8
+ }
9
+ function formatSignedQuantity(value) {
10
+ if (value > 0) return `+${value}`;
11
+ return String(value);
12
+ }
13
+ function buildInventoryMutationReferenceId() {
14
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
15
+ return crypto.randomUUID();
16
+ }
17
+ return `00000000-0000-4000-8000-${Date.now().toString(16).padStart(12, "0").slice(-12)}`;
18
+ }
19
+ export {
20
+ buildInventoryMutationReferenceId,
21
+ computeCycleCountVariance,
22
+ formatSignedQuantity,
23
+ parseInventoryQuantity
24
+ };
25
+ //# sourceMappingURL=inventoryMutationUi.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/wms/lib/inventoryMutationUi.ts"],
4
+ "sourcesContent": ["export function parseInventoryQuantity(value: string | number | null | undefined): number {\n if (value == null || value === '') return 0\n const parsed = typeof value === 'number' ? value : Number(value)\n return Number.isFinite(parsed) ? parsed : 0\n}\n\nexport function computeCycleCountVariance(systemOnHand: number, countedQuantity: number): number {\n return countedQuantity - systemOnHand\n}\n\nexport function formatSignedQuantity(value: number): string {\n if (value > 0) return `+${value}`\n return String(value)\n}\n\nexport function buildInventoryMutationReferenceId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n return `00000000-0000-4000-8000-${Date.now().toString(16).padStart(12, '0').slice(-12)}`\n}\n"],
5
+ "mappings": "AAAO,SAAS,uBAAuB,OAAmD;AACxF,MAAI,SAAS,QAAQ,UAAU,GAAI,QAAO;AAC1C,QAAM,SAAS,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK;AAC/D,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC5C;AAEO,SAAS,0BAA0B,cAAsB,iBAAiC;AAC/F,SAAO,kBAAkB;AAC3B;AAEO,SAAS,qBAAqB,OAAuB;AAC1D,MAAI,QAAQ,EAAG,QAAO,IAAI,KAAK;AAC/B,SAAO,OAAO,KAAK;AACrB;AAEO,SAAS,oCAA4C;AAC1D,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E,WAAO,OAAO,WAAW;AAAA,EAC3B;AACA,SAAO,2BAA2B,KAAK,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,IAAI,GAAG,EAAE,MAAM,GAAG,CAAC;AACxF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,61 @@
1
+ function isLotEligible(lot, now = /* @__PURE__ */ new Date()) {
2
+ if (!lot) return true;
3
+ if (lot.status !== "available") return false;
4
+ if (lot.expiresAt && lot.expiresAt.getTime() <= now.getTime()) return false;
5
+ return true;
6
+ }
7
+ function toNumber(value) {
8
+ if (typeof value === "number") return value;
9
+ if (typeof value === "string" && value.trim().length > 0) {
10
+ return Number(value);
11
+ }
12
+ return 0;
13
+ }
14
+ function buildBucketKey(bucket) {
15
+ return [
16
+ bucket.warehouseId,
17
+ bucket.locationId,
18
+ bucket.catalogVariantId,
19
+ bucket.lotId ?? "",
20
+ bucket.serialNumber ?? ""
21
+ ].join("::");
22
+ }
23
+ function resolveBucketSortValue(bucket, strategy, receiptMap) {
24
+ const receiptAt = receiptMap.get(buildBucketKey(bucket));
25
+ if (strategy === "fefo") {
26
+ return bucket.lotExpiresAt?.getTime() ?? Number.MAX_SAFE_INTEGER;
27
+ }
28
+ return receiptAt?.getTime() ?? bucket.createdAt.getTime();
29
+ }
30
+ function sortBucketsForStrategy(buckets, strategy, receiptMap) {
31
+ return [...buckets].sort((left, right) => {
32
+ const leftValue = resolveBucketSortValue(left, strategy, receiptMap);
33
+ const rightValue = resolveBucketSortValue(right, strategy, receiptMap);
34
+ if (leftValue === rightValue) {
35
+ return left.createdAt.getTime() - right.createdAt.getTime();
36
+ }
37
+ return strategy === "lifo" ? rightValue - leftValue : leftValue - rightValue;
38
+ });
39
+ }
40
+ function resolveReservationStrategyFromProfile(profile, requestedStrategy) {
41
+ if (profile?.trackExpiration) return "fefo";
42
+ return requestedStrategy ?? profile?.defaultStrategy ?? "fifo";
43
+ }
44
+ function evaluateLowStock(profile, availableQuantity) {
45
+ const reorderPoint = toNumber(profile.reorderPoint);
46
+ if (availableQuantity > reorderPoint) return null;
47
+ const safetyStock = toNumber(profile.safetyStock);
48
+ return {
49
+ state: availableQuantity <= safetyStock ? "below_safety_stock" : "below_reorder_point",
50
+ reorderPoint: profile.reorderPoint,
51
+ safetyStock: profile.safetyStock,
52
+ availableQuantity: String(availableQuantity)
53
+ };
54
+ }
55
+ export {
56
+ evaluateLowStock,
57
+ isLotEligible,
58
+ resolveReservationStrategyFromProfile,
59
+ sortBucketsForStrategy
60
+ };
61
+ //# sourceMappingURL=inventoryPolicy.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/wms/lib/inventoryPolicy.ts"],
4
+ "sourcesContent": ["import type { InventoryLotStatus, InventoryStrategy } from '../data/entities'\n\ntype LotEligibilityInput = {\n status?: InventoryLotStatus | null\n expiresAt?: Date | null\n} | null | undefined\n\nexport function isLotEligible(lot: LotEligibilityInput, now: Date = new Date()): boolean {\n if (!lot) return true\n if (lot.status !== 'available') return false\n if (lot.expiresAt && lot.expiresAt.getTime() <= now.getTime()) return false\n return true\n}\n\ntype NumericLike = string | number | null | undefined\n\ntype StrategyProfile = {\n trackExpiration?: boolean | null\n defaultStrategy?: InventoryStrategy | null\n}\n\ntype LowStockProfile = {\n reorderPoint?: NumericLike\n safetyStock?: NumericLike\n}\n\nexport type InventoryStrategyBucket = {\n warehouseId: string\n locationId: string\n catalogVariantId: string\n createdAt: Date\n lotId?: string | null\n lotExpiresAt?: Date | null\n serialNumber?: string | null\n}\n\nfunction toNumber(value: NumericLike): number {\n if (typeof value === 'number') return value\n if (typeof value === 'string' && value.trim().length > 0) {\n return Number(value)\n }\n return 0\n}\n\nfunction buildBucketKey(bucket: InventoryStrategyBucket): string {\n return [\n bucket.warehouseId,\n bucket.locationId,\n bucket.catalogVariantId,\n bucket.lotId ?? '',\n bucket.serialNumber ?? '',\n ].join('::')\n}\n\nfunction resolveBucketSortValue(\n bucket: InventoryStrategyBucket,\n strategy: InventoryStrategy,\n receiptMap: Map<string, Date>,\n): number {\n const receiptAt = receiptMap.get(buildBucketKey(bucket))\n if (strategy === 'fefo') {\n return bucket.lotExpiresAt?.getTime() ?? Number.MAX_SAFE_INTEGER\n }\n return receiptAt?.getTime() ?? bucket.createdAt.getTime()\n}\n\nexport function sortBucketsForStrategy<T extends InventoryStrategyBucket>(\n buckets: T[],\n strategy: InventoryStrategy,\n receiptMap: Map<string, Date>,\n): T[] {\n return [...buckets].sort((left, right) => {\n const leftValue = resolveBucketSortValue(left, strategy, receiptMap)\n const rightValue = resolveBucketSortValue(right, strategy, receiptMap)\n if (leftValue === rightValue) {\n return left.createdAt.getTime() - right.createdAt.getTime()\n }\n return strategy === 'lifo' ? rightValue - leftValue : leftValue - rightValue\n })\n}\n\nexport function resolveReservationStrategyFromProfile(\n profile: StrategyProfile | null | undefined,\n requestedStrategy?: InventoryStrategy | null,\n): InventoryStrategy {\n if (profile?.trackExpiration) return 'fefo'\n return requestedStrategy ?? profile?.defaultStrategy ?? 'fifo'\n}\n\nexport function evaluateLowStock(\n profile: LowStockProfile,\n availableQuantity: number,\n):\n | {\n state: 'below_safety_stock' | 'below_reorder_point'\n reorderPoint: NumericLike\n safetyStock: NumericLike\n availableQuantity: string\n }\n | null {\n const reorderPoint = toNumber(profile.reorderPoint)\n if (availableQuantity > reorderPoint) return null\n\n const safetyStock = toNumber(profile.safetyStock)\n return {\n state: availableQuantity <= safetyStock ? 'below_safety_stock' : 'below_reorder_point',\n reorderPoint: profile.reorderPoint,\n safetyStock: profile.safetyStock,\n availableQuantity: String(availableQuantity),\n }\n}\n"],
5
+ "mappings": "AAOO,SAAS,cAAc,KAA0B,MAAY,oBAAI,KAAK,GAAY;AACvF,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,YAAa,QAAO;AACvC,MAAI,IAAI,aAAa,IAAI,UAAU,QAAQ,KAAK,IAAI,QAAQ,EAAG,QAAO;AACtE,SAAO;AACT;AAwBA,SAAS,SAAS,OAA4B;AAC5C,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,GAAG;AACxD,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,eAAe,QAAyC;AAC/D,SAAO;AAAA,IACL,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO,SAAS;AAAA,IAChB,OAAO,gBAAgB;AAAA,EACzB,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,uBACP,QACA,UACA,YACQ;AACR,QAAM,YAAY,WAAW,IAAI,eAAe,MAAM,CAAC;AACvD,MAAI,aAAa,QAAQ;AACvB,WAAO,OAAO,cAAc,QAAQ,KAAK,OAAO;AAAA,EAClD;AACA,SAAO,WAAW,QAAQ,KAAK,OAAO,UAAU,QAAQ;AAC1D;AAEO,SAAS,uBACd,SACA,UACA,YACK;AACL,SAAO,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,MAAM,UAAU;AACxC,UAAM,YAAY,uBAAuB,MAAM,UAAU,UAAU;AACnE,UAAM,aAAa,uBAAuB,OAAO,UAAU,UAAU;AACrE,QAAI,cAAc,YAAY;AAC5B,aAAO,KAAK,UAAU,QAAQ,IAAI,MAAM,UAAU,QAAQ;AAAA,IAC5D;AACA,WAAO,aAAa,SAAS,aAAa,YAAY,YAAY;AAAA,EACpE,CAAC;AACH;AAEO,SAAS,sCACd,SACA,mBACmB;AACnB,MAAI,SAAS,gBAAiB,QAAO;AACrC,SAAO,qBAAqB,SAAS,mBAAmB;AAC1D;AAEO,SAAS,iBACd,SACA,mBAQO;AACP,QAAM,eAAe,SAAS,QAAQ,YAAY;AAClD,MAAI,oBAAoB,aAAc,QAAO;AAE7C,QAAM,cAAc,SAAS,QAAQ,WAAW;AAChD,SAAO;AAAA,IACL,OAAO,qBAAqB,cAAc,uBAAuB;AAAA,IACjE,cAAc,QAAQ;AAAA,IACtB,aAAa,QAAQ;AAAA,IACrB,mBAAmB,OAAO,iBAAiB;AAAA,EAC7C;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,193 @@
1
+ import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
+ import {
3
+ InventoryBalance,
4
+ InventoryMovement,
5
+ InventoryReservation
6
+ } from "../data/entities.js";
7
+ function toNumber(value) {
8
+ if (typeof value === "number" && Number.isFinite(value)) return value;
9
+ if (typeof value === "string" && value.trim().length > 0) {
10
+ const parsed = Number(value);
11
+ if (Number.isFinite(parsed)) return parsed;
12
+ }
13
+ return 0;
14
+ }
15
+ function buildBucketKey(bucket) {
16
+ return [
17
+ bucket.warehouseId,
18
+ bucket.locationId,
19
+ bucket.catalogVariantId,
20
+ bucket.lotId ?? "",
21
+ bucket.serialNumber ?? ""
22
+ ].join("::");
23
+ }
24
+ function resolveRelationId(value) {
25
+ if (typeof value === "string") return value;
26
+ return typeof value?.id === "string" ? value.id : null;
27
+ }
28
+ function extractReservationMetadata(reservation) {
29
+ if (!reservation.metadata || typeof reservation.metadata !== "object" || Array.isArray(reservation.metadata)) {
30
+ return {};
31
+ }
32
+ return { ...reservation.metadata };
33
+ }
34
+ function recomputeBalanceFromMovements(movements) {
35
+ const onHandByBucket = /* @__PURE__ */ new Map();
36
+ for (const movement of movements) {
37
+ const warehouseId = resolveRelationId(movement.warehouse);
38
+ if (!warehouseId) continue;
39
+ const catalogVariantId = movement.catalogVariantId;
40
+ const lotId = resolveRelationId(movement.lot);
41
+ const serialNumber = movement.serialNumber ?? null;
42
+ const quantity = toNumber(movement.quantity);
43
+ const locationToId = resolveRelationId(movement.locationTo);
44
+ const locationFromId = resolveRelationId(movement.locationFrom);
45
+ if (locationToId) {
46
+ const key = buildBucketKey({
47
+ warehouseId,
48
+ locationId: locationToId,
49
+ catalogVariantId,
50
+ lotId,
51
+ serialNumber
52
+ });
53
+ onHandByBucket.set(key, (onHandByBucket.get(key) ?? 0) + quantity);
54
+ }
55
+ if (locationFromId) {
56
+ const key = buildBucketKey({
57
+ warehouseId,
58
+ locationId: locationFromId,
59
+ catalogVariantId,
60
+ lotId,
61
+ serialNumber
62
+ });
63
+ onHandByBucket.set(key, (onHandByBucket.get(key) ?? 0) - quantity);
64
+ }
65
+ }
66
+ return onHandByBucket;
67
+ }
68
+ function recomputeReservedAllocatedFromReservations(reservations) {
69
+ const reservedByBucket = /* @__PURE__ */ new Map();
70
+ const allocatedByBucket = /* @__PURE__ */ new Map();
71
+ for (const reservation of reservations) {
72
+ if (reservation.status !== "active") continue;
73
+ const warehouseId = resolveRelationId(reservation.warehouse);
74
+ if (!warehouseId) continue;
75
+ const metadata = extractReservationMetadata(reservation);
76
+ const buckets = Array.isArray(metadata.allocatedBuckets) ? metadata.allocatedBuckets : [];
77
+ const allocationState = metadata.allocationState ?? "reserved";
78
+ for (const bucket of buckets) {
79
+ const key = buildBucketKey({
80
+ warehouseId,
81
+ locationId: bucket.locationId,
82
+ catalogVariantId: reservation.catalogVariantId,
83
+ lotId: bucket.lotId ?? null,
84
+ serialNumber: bucket.serialNumber ?? null
85
+ });
86
+ if (allocationState === "allocated") {
87
+ allocatedByBucket.set(key, (allocatedByBucket.get(key) ?? 0) + toNumber(bucket.quantity));
88
+ } else {
89
+ reservedByBucket.set(key, (reservedByBucket.get(key) ?? 0) + toNumber(bucket.quantity));
90
+ }
91
+ }
92
+ }
93
+ return { reservedByBucket, allocatedByBucket };
94
+ }
95
+ async function verifyBalances(em, scope, filters) {
96
+ const balanceWhere = {
97
+ organizationId: scope.organizationId,
98
+ tenantId: scope.tenantId,
99
+ deletedAt: null
100
+ };
101
+ if (filters?.warehouseId) balanceWhere.warehouse = filters.warehouseId;
102
+ if (filters?.catalogVariantId) balanceWhere.catalogVariantId = filters.catalogVariantId;
103
+ const movementWhere = {
104
+ organizationId: scope.organizationId,
105
+ tenantId: scope.tenantId,
106
+ deletedAt: null
107
+ };
108
+ if (filters?.warehouseId) movementWhere.warehouse = filters.warehouseId;
109
+ if (filters?.catalogVariantId) movementWhere.catalogVariantId = filters.catalogVariantId;
110
+ const reservationWhere = {
111
+ organizationId: scope.organizationId,
112
+ tenantId: scope.tenantId,
113
+ status: "active",
114
+ deletedAt: null
115
+ };
116
+ if (filters?.warehouseId) reservationWhere.warehouse = filters.warehouseId;
117
+ if (filters?.catalogVariantId) reservationWhere.catalogVariantId = filters.catalogVariantId;
118
+ const [balances, movements, reservations] = await Promise.all([
119
+ findWithDecryption(em, InventoryBalance, balanceWhere, void 0, scope),
120
+ findWithDecryption(em, InventoryMovement, movementWhere, void 0, scope),
121
+ findWithDecryption(em, InventoryReservation, reservationWhere, void 0, scope)
122
+ ]);
123
+ const onHandByBucket = recomputeBalanceFromMovements(movements);
124
+ const { reservedByBucket, allocatedByBucket } = recomputeReservedAllocatedFromReservations(reservations);
125
+ const driftRows = [];
126
+ for (const balance of balances) {
127
+ const warehouseId = resolveRelationId(balance.warehouse);
128
+ const locationId = resolveRelationId(balance.location);
129
+ if (!warehouseId || !locationId) continue;
130
+ const lotId = resolveRelationId(balance.lot);
131
+ const bucket = {
132
+ warehouseId,
133
+ locationId,
134
+ catalogVariantId: balance.catalogVariantId,
135
+ lotId,
136
+ serialNumber: balance.serialNumber ?? null
137
+ };
138
+ const key = buildBucketKey(bucket);
139
+ const expectedOnHand = onHandByBucket.get(key) ?? 0;
140
+ const expectedReserved = reservedByBucket.get(key) ?? 0;
141
+ const expectedAllocated = allocatedByBucket.get(key) ?? 0;
142
+ const storedOnHand = toNumber(balance.quantityOnHand);
143
+ const storedReserved = toNumber(balance.quantityReserved);
144
+ const storedAllocated = toNumber(balance.quantityAllocated);
145
+ const onHandDrift = Math.abs(storedOnHand - expectedOnHand) > 1e-6;
146
+ const reservedDrift = Math.abs(storedReserved - expectedReserved) > 1e-6;
147
+ const allocatedDrift = Math.abs(storedAllocated - expectedAllocated) > 1e-6;
148
+ if (!onHandDrift && !reservedDrift && !allocatedDrift) continue;
149
+ driftRows.push({
150
+ balanceId: balance.id,
151
+ bucket,
152
+ storedOnHand,
153
+ expectedOnHand,
154
+ storedReserved,
155
+ expectedReserved,
156
+ storedAllocated,
157
+ expectedAllocated
158
+ });
159
+ }
160
+ return driftRows;
161
+ }
162
+ async function repairBalanceDrift(em, scope, driftRows) {
163
+ let repaired = 0;
164
+ for (const row of driftRows) {
165
+ const balance = await findOneWithDecryption(
166
+ em,
167
+ InventoryBalance,
168
+ {
169
+ id: row.balanceId,
170
+ organizationId: scope.organizationId,
171
+ tenantId: scope.tenantId,
172
+ deletedAt: null
173
+ },
174
+ void 0,
175
+ scope
176
+ );
177
+ if (!balance) continue;
178
+ balance.quantityOnHand = String(row.expectedOnHand);
179
+ balance.quantityReserved = String(row.expectedReserved);
180
+ balance.quantityAllocated = String(row.expectedAllocated);
181
+ repaired += 1;
182
+ }
183
+ if (repaired > 0) {
184
+ await em.flush();
185
+ }
186
+ return repaired;
187
+ }
188
+ export {
189
+ recomputeBalanceFromMovements,
190
+ repairBalanceDrift,
191
+ verifyBalances
192
+ };
193
+ //# sourceMappingURL=inventoryReconciliation.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/wms/lib/inventoryReconciliation.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n InventoryBalance,\n InventoryMovement,\n InventoryReservation,\n type InventoryLot,\n} from '../data/entities'\n\ntype Scope = {\n tenantId: string\n organizationId: string\n}\n\ntype AllocationBucket = {\n balanceId?: string\n locationId: string\n lotId: string | null\n serialNumber: string | null\n quantity: number\n}\n\ntype ReservationMetadata = {\n allocatedBuckets?: AllocationBucket[]\n allocationState?: 'reserved' | 'allocated'\n}\n\nexport type BalanceBucketKey = {\n warehouseId: string\n locationId: string\n catalogVariantId: string\n lotId: string | null\n serialNumber: string | null\n}\n\nexport type BalanceDriftRow = {\n balanceId: string\n bucket: BalanceBucketKey\n storedOnHand: number\n expectedOnHand: number\n storedReserved: number\n expectedReserved: number\n storedAllocated: number\n expectedAllocated: number\n}\n\nfunction toNumber(value: unknown): number {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length > 0) {\n const parsed = Number(value)\n if (Number.isFinite(parsed)) return parsed\n }\n return 0\n}\n\nfunction buildBucketKey(bucket: BalanceBucketKey): string {\n return [\n bucket.warehouseId,\n bucket.locationId,\n bucket.catalogVariantId,\n bucket.lotId ?? '',\n bucket.serialNumber ?? '',\n ].join('::')\n}\n\nfunction resolveRelationId(value: { id?: string } | string | null | undefined): string | null {\n if (typeof value === 'string') return value\n return typeof value?.id === 'string' ? value.id : null\n}\n\nfunction extractReservationMetadata(reservation: InventoryReservation): ReservationMetadata {\n if (!reservation.metadata || typeof reservation.metadata !== 'object' || Array.isArray(reservation.metadata)) {\n return {}\n }\n return { ...(reservation.metadata as Record<string, unknown>) }\n}\n\nexport function recomputeBalanceFromMovements(\n movements: InventoryMovement[],\n): Map<string, number> {\n const onHandByBucket = new Map<string, number>()\n for (const movement of movements) {\n const warehouseId = resolveRelationId(movement.warehouse)\n if (!warehouseId) continue\n const catalogVariantId = movement.catalogVariantId\n const lotId = resolveRelationId(movement.lot)\n const serialNumber = movement.serialNumber ?? null\n const quantity = toNumber(movement.quantity)\n const locationToId = resolveRelationId(movement.locationTo)\n const locationFromId = resolveRelationId(movement.locationFrom)\n\n if (locationToId) {\n const key = buildBucketKey({\n warehouseId,\n locationId: locationToId,\n catalogVariantId,\n lotId,\n serialNumber,\n })\n onHandByBucket.set(key, (onHandByBucket.get(key) ?? 0) + quantity)\n }\n if (locationFromId) {\n const key = buildBucketKey({\n warehouseId,\n locationId: locationFromId,\n catalogVariantId,\n lotId,\n serialNumber,\n })\n onHandByBucket.set(key, (onHandByBucket.get(key) ?? 0) - quantity)\n }\n }\n return onHandByBucket\n}\n\nfunction recomputeReservedAllocatedFromReservations(\n reservations: InventoryReservation[],\n): {\n reservedByBucket: Map<string, number>\n allocatedByBucket: Map<string, number>\n} {\n const reservedByBucket = new Map<string, number>()\n const allocatedByBucket = new Map<string, number>()\n for (const reservation of reservations) {\n if (reservation.status !== 'active') continue\n const warehouseId = resolveRelationId(reservation.warehouse)\n if (!warehouseId) continue\n const metadata = extractReservationMetadata(reservation)\n const buckets = Array.isArray(metadata.allocatedBuckets) ? metadata.allocatedBuckets : []\n const allocationState = metadata.allocationState ?? 'reserved'\n for (const bucket of buckets) {\n const key = buildBucketKey({\n warehouseId,\n locationId: bucket.locationId,\n catalogVariantId: reservation.catalogVariantId,\n lotId: bucket.lotId ?? null,\n serialNumber: bucket.serialNumber ?? null,\n })\n if (allocationState === 'allocated') {\n allocatedByBucket.set(key, (allocatedByBucket.get(key) ?? 0) + toNumber(bucket.quantity))\n } else {\n reservedByBucket.set(key, (reservedByBucket.get(key) ?? 0) + toNumber(bucket.quantity))\n }\n }\n }\n return { reservedByBucket, allocatedByBucket }\n}\n\nexport async function verifyBalances(\n em: EntityManager,\n scope: Scope,\n filters?: {\n warehouseId?: string\n catalogVariantId?: string\n },\n): Promise<BalanceDriftRow[]> {\n const balanceWhere: Record<string, unknown> = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }\n if (filters?.warehouseId) balanceWhere.warehouse = filters.warehouseId\n if (filters?.catalogVariantId) balanceWhere.catalogVariantId = filters.catalogVariantId\n\n const movementWhere: Record<string, unknown> = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }\n if (filters?.warehouseId) movementWhere.warehouse = filters.warehouseId\n if (filters?.catalogVariantId) movementWhere.catalogVariantId = filters.catalogVariantId\n\n const reservationWhere: Record<string, unknown> = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n status: 'active',\n deletedAt: null,\n }\n if (filters?.warehouseId) reservationWhere.warehouse = filters.warehouseId\n if (filters?.catalogVariantId) reservationWhere.catalogVariantId = filters.catalogVariantId\n\n const [balances, movements, reservations] = await Promise.all([\n findWithDecryption(em, InventoryBalance, balanceWhere, undefined, scope),\n findWithDecryption(em, InventoryMovement, movementWhere, undefined, scope),\n findWithDecryption(em, InventoryReservation, reservationWhere, undefined, scope),\n ])\n\n const onHandByBucket = recomputeBalanceFromMovements(movements)\n const { reservedByBucket, allocatedByBucket } = recomputeReservedAllocatedFromReservations(reservations)\n\n const driftRows: BalanceDriftRow[] = []\n for (const balance of balances) {\n const warehouseId = resolveRelationId(balance.warehouse)\n const locationId = resolveRelationId(balance.location)\n if (!warehouseId || !locationId) continue\n const lotId = resolveRelationId(balance.lot)\n const bucket: BalanceBucketKey = {\n warehouseId,\n locationId,\n catalogVariantId: balance.catalogVariantId,\n lotId,\n serialNumber: balance.serialNumber ?? null,\n }\n const key = buildBucketKey(bucket)\n const expectedOnHand = onHandByBucket.get(key) ?? 0\n const expectedReserved = reservedByBucket.get(key) ?? 0\n const expectedAllocated = allocatedByBucket.get(key) ?? 0\n const storedOnHand = toNumber(balance.quantityOnHand)\n const storedReserved = toNumber(balance.quantityReserved)\n const storedAllocated = toNumber(balance.quantityAllocated)\n\n const onHandDrift = Math.abs(storedOnHand - expectedOnHand) > 0.000001\n const reservedDrift = Math.abs(storedReserved - expectedReserved) > 0.000001\n const allocatedDrift = Math.abs(storedAllocated - expectedAllocated) > 0.000001\n if (!onHandDrift && !reservedDrift && !allocatedDrift) continue\n\n driftRows.push({\n balanceId: balance.id,\n bucket,\n storedOnHand,\n expectedOnHand,\n storedReserved,\n expectedReserved,\n storedAllocated,\n expectedAllocated,\n })\n }\n\n return driftRows\n}\n\nexport async function repairBalanceDrift(\n em: EntityManager,\n scope: Scope,\n driftRows: BalanceDriftRow[],\n): Promise<number> {\n let repaired = 0\n for (const row of driftRows) {\n const balance = await findOneWithDecryption(\n em,\n InventoryBalance,\n {\n id: row.balanceId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (!balance) continue\n balance.quantityOnHand = String(row.expectedOnHand)\n balance.quantityReserved = String(row.expectedReserved)\n balance.quantityAllocated = String(row.expectedAllocated)\n repaired += 1\n }\n if (repaired > 0) {\n await em.flush()\n }\n return repaired\n}\n\nexport type { InventoryLot }\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,13 @@
1
+ import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
2
+ function enforceInventoryTrackingRequirements(profile, input) {
3
+ if (profile?.trackLot && !input.lotId?.trim()) {
4
+ throw new CrudHttpError(422, { error: "lot_required" });
5
+ }
6
+ if (profile?.trackSerial && !input.serialNumber?.trim()) {
7
+ throw new CrudHttpError(422, { error: "serial_required" });
8
+ }
9
+ }
10
+ export {
11
+ enforceInventoryTrackingRequirements
12
+ };
13
+ //# sourceMappingURL=inventoryTrackingValidation.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/wms/lib/inventoryTrackingValidation.ts"],
4
+ "sourcesContent": ["import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\n\ntype InventoryTrackingProfile = {\n trackLot?: boolean | null\n trackSerial?: boolean | null\n} | null\n\ntype InventoryTrackingInput = {\n lotId?: string | null\n serialNumber?: string | null\n}\n\nexport function enforceInventoryTrackingRequirements(\n profile: InventoryTrackingProfile,\n input: InventoryTrackingInput,\n): void {\n if (profile?.trackLot && !input.lotId?.trim()) {\n throw new CrudHttpError(422, { error: 'lot_required' })\n }\n if (profile?.trackSerial && !input.serialNumber?.trim()) {\n throw new CrudHttpError(422, { error: 'serial_required' })\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,qBAAqB;AAYvB,SAAS,qCACd,SACA,OACM;AACN,MAAI,SAAS,YAAY,CAAC,MAAM,OAAO,KAAK,GAAG;AAC7C,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,EACxD;AACA,MAAI,SAAS,eAAe,CAAC,MAAM,cAAc,KAAK,GAAG;AACvD,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,EAC3D;AACF;",
6
+ "names": []
7
+ }