@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,15 @@
1
+ import type { ModuleInfo } from '@open-mercato/shared/modules/registry'
2
+ import './commands'
3
+
4
+ export const metadata: ModuleInfo = {
5
+ name: 'wms',
6
+ title: 'Warehouse Management System',
7
+ version: '0.1.0',
8
+ description: 'Warehouse topology, inventory balances, reservations, and movement ledger.',
9
+ author: 'Open Mercato Team',
10
+ license: 'MIT',
11
+ ejectable: true,
12
+ requires: ['catalog', 'sales', 'feature_toggles'],
13
+ }
14
+
15
+ export { features } from './acl'
@@ -0,0 +1,65 @@
1
+ import { z } from 'zod'
2
+
3
+ const inventoryStrategySchema = z.enum(['fifo', 'lifo', 'fefo'])
4
+
5
+ export const catalogInventoryProfileIntentSchema = z.object({
6
+ manageInventory: z.boolean(),
7
+ defaultUom: z.string().trim().max(32).nullable().optional(),
8
+ defaultStrategy: inventoryStrategySchema.optional(),
9
+ trackLot: z.boolean().optional(),
10
+ trackSerial: z.boolean().optional(),
11
+ trackExpiration: z.boolean().optional(),
12
+ reorderPoint: z.coerce.number().finite().min(0).nullable().optional(),
13
+ safetyStock: z.coerce.number().finite().min(0).nullable().optional(),
14
+ }).superRefine((payload, ctx) => {
15
+ if (!payload.manageInventory) return
16
+
17
+ if (!payload.defaultUom || payload.defaultUom.trim().length === 0) {
18
+ ctx.addIssue({
19
+ code: z.ZodIssueCode.custom,
20
+ path: ['defaultUom'],
21
+ message: 'wms.widgets.catalog.inventoryProfile.errors.defaultUomRequired',
22
+ })
23
+ }
24
+
25
+ if (!payload.defaultStrategy) {
26
+ ctx.addIssue({
27
+ code: z.ZodIssueCode.custom,
28
+ path: ['defaultStrategy'],
29
+ message: 'wms.widgets.catalog.inventoryProfile.errors.strategyRequired',
30
+ })
31
+ }
32
+
33
+ if (payload.trackExpiration && payload.defaultStrategy !== 'fefo') {
34
+ ctx.addIssue({
35
+ code: z.ZodIssueCode.custom,
36
+ path: ['defaultStrategy'],
37
+ message: 'wms.widgets.catalog.inventoryProfile.errors.fefoRequired',
38
+ })
39
+ }
40
+ })
41
+
42
+ export type CatalogInventoryProfileIntent = z.infer<
43
+ typeof catalogInventoryProfileIntentSchema
44
+ >
45
+
46
+ export const WMS_CATALOG_PROFILE_HEADER =
47
+ 'x-open-mercato-wms-catalog-profile'
48
+
49
+ export function encodeCatalogInventoryProfileIntent(
50
+ intent: CatalogInventoryProfileIntent,
51
+ ): string {
52
+ return encodeURIComponent(JSON.stringify(intent))
53
+ }
54
+
55
+ export function decodeCatalogInventoryProfileIntent(
56
+ rawHeader: string | null | undefined,
57
+ ): CatalogInventoryProfileIntent | null {
58
+ if (typeof rawHeader !== 'string' || rawHeader.trim().length === 0) {
59
+ return null
60
+ }
61
+
62
+ const decoded = decodeURIComponent(rawHeader)
63
+ const parsed = JSON.parse(decoded) as unknown
64
+ return catalogInventoryProfileIntentSchema.parse(parsed)
65
+ }
@@ -0,0 +1,199 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import type { AwilixContainer } from 'awilix'
3
+ import type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
4
+ import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
5
+ import type { AuthContext } from '@open-mercato/shared/lib/auth/server'
6
+ import type { QueryEngine } from '@open-mercato/shared/lib/query/types'
7
+ import { E } from '#generated/entities.ids.generated'
8
+ import { ProductInventoryProfile } from '../data/entities'
9
+ import {
10
+ catalogInventoryProfileIntentSchema,
11
+ type CatalogInventoryProfileIntent,
12
+ } from './catalogInventoryProfileIntent'
13
+
14
+ type SyncTarget = 'product' | 'variant'
15
+
16
+ type SyncCatalogInventoryProfileInput = {
17
+ intent: CatalogInventoryProfileIntent
18
+ target: SyncTarget
19
+ recordId: string
20
+ organizationId: string
21
+ tenantId: string
22
+ userId: string
23
+ container: AwilixContainer
24
+ }
25
+
26
+ function normalizeOptionalString(value: unknown): string | null {
27
+ if (typeof value !== 'string') return null
28
+ const trimmed = value.trim()
29
+ return trimmed.length > 0 ? trimmed : null
30
+ }
31
+
32
+ function buildCommandContext(params: {
33
+ container: AwilixContainer
34
+ organizationId: string
35
+ tenantId: string
36
+ userId: string
37
+ }): CommandRuntimeContext {
38
+ const auth: AuthContext = {
39
+ sub: params.userId,
40
+ userId: params.userId,
41
+ tenantId: params.tenantId,
42
+ orgId: params.organizationId,
43
+ }
44
+
45
+ return {
46
+ container: params.container,
47
+ auth,
48
+ organizationScope: null,
49
+ selectedOrganizationId: params.organizationId,
50
+ organizationIds: [params.organizationId],
51
+ }
52
+ }
53
+
54
+ async function loadExistingProfile(params: {
55
+ organizationId: string
56
+ tenantId: string
57
+ target: SyncTarget
58
+ recordId: string
59
+ catalogProductId: string
60
+ container: AwilixContainer
61
+ }) {
62
+ const em = params.container.resolve('em') as EntityManager
63
+ const scope = {
64
+ organizationId: params.organizationId,
65
+ tenantId: params.tenantId,
66
+ }
67
+
68
+ if (params.target === 'variant') {
69
+ return findOneWithDecryption(
70
+ em,
71
+ ProductInventoryProfile,
72
+ {
73
+ organizationId: params.organizationId,
74
+ tenantId: params.tenantId,
75
+ deletedAt: null,
76
+ catalogVariantId: params.recordId,
77
+ } as never,
78
+ undefined,
79
+ scope,
80
+ )
81
+ }
82
+
83
+ return findOneWithDecryption(
84
+ em,
85
+ ProductInventoryProfile,
86
+ {
87
+ organizationId: params.organizationId,
88
+ tenantId: params.tenantId,
89
+ deletedAt: null,
90
+ catalogProductId: params.catalogProductId,
91
+ catalogVariantId: null,
92
+ } as never,
93
+ undefined,
94
+ scope,
95
+ )
96
+ }
97
+
98
+ async function resolveCatalogProductId(params: {
99
+ target: SyncTarget
100
+ recordId: string
101
+ organizationId: string
102
+ tenantId: string
103
+ container: AwilixContainer
104
+ }): Promise<string> {
105
+ if (params.target === 'product') return params.recordId
106
+
107
+ // Read the variant -> product_id mapping via QueryEngine so this module does
108
+ // not import the catalog ORM entity directly. queryEngine resolves the
109
+ // base table via Mikro-ORM metadata, so the only cross-module surface we
110
+ // depend on is the public catalog entity id from the `E` registry.
111
+ const queryEngine = params.container.resolve('queryEngine') as QueryEngine
112
+ const result = await queryEngine.query<{ id?: string; product_id?: string }>(
113
+ E.catalog.catalog_product_variant,
114
+ {
115
+ tenantId: params.tenantId,
116
+ organizationId: params.organizationId,
117
+ filters: { id: { $eq: params.recordId } },
118
+ fields: ['id', 'product_id'],
119
+ page: { page: 1, pageSize: 1 },
120
+ },
121
+ )
122
+
123
+ const variantRow = result.items[0]
124
+ if (!variantRow) {
125
+ throw new Error(`Variant ${params.recordId} not found for WMS profile sync`)
126
+ }
127
+
128
+ const productId = typeof variantRow.product_id === 'string' ? variantRow.product_id : null
129
+ if (!productId) {
130
+ throw new Error(
131
+ `Variant ${params.recordId} is missing product context for WMS profile sync`,
132
+ )
133
+ }
134
+
135
+ return productId
136
+ }
137
+
138
+ export async function syncCatalogInventoryProfile(
139
+ input: SyncCatalogInventoryProfileInput,
140
+ ): Promise<void> {
141
+ const intent = catalogInventoryProfileIntentSchema.parse(input.intent)
142
+ const commandBus = input.container.resolve('commandBus') as CommandBus
143
+ const ctx = buildCommandContext(input)
144
+ const catalogProductId = await resolveCatalogProductId({
145
+ target: input.target,
146
+ recordId: input.recordId,
147
+ organizationId: input.organizationId,
148
+ tenantId: input.tenantId,
149
+ container: input.container,
150
+ })
151
+
152
+ const existingProfile = await loadExistingProfile({
153
+ organizationId: input.organizationId,
154
+ tenantId: input.tenantId,
155
+ target: input.target,
156
+ recordId: input.recordId,
157
+ catalogProductId,
158
+ container: input.container,
159
+ })
160
+
161
+ if (!intent.manageInventory) {
162
+ if (!existingProfile) return
163
+ await commandBus.execute('wms.inventoryProfiles.delete', {
164
+ input: { id: existingProfile.id },
165
+ ctx,
166
+ })
167
+ return
168
+ }
169
+
170
+ const profileInput = {
171
+ organizationId: input.organizationId,
172
+ tenantId: input.tenantId,
173
+ catalogProductId,
174
+ catalogVariantId: input.target === 'variant' ? input.recordId : null,
175
+ defaultUom: normalizeOptionalString(intent.defaultUom),
176
+ defaultStrategy: intent.defaultStrategy,
177
+ trackLot: intent.trackLot ?? false,
178
+ trackSerial: intent.trackSerial ?? false,
179
+ trackExpiration: intent.trackExpiration ?? false,
180
+ reorderPoint: intent.reorderPoint ?? 0,
181
+ safetyStock: intent.safetyStock ?? 0,
182
+ }
183
+
184
+ if (existingProfile) {
185
+ await commandBus.execute('wms.inventoryProfiles.update', {
186
+ input: {
187
+ id: existingProfile.id,
188
+ ...profileInput,
189
+ },
190
+ ctx,
191
+ })
192
+ return
193
+ }
194
+
195
+ await commandBus.execute('wms.inventoryProfiles.create', {
196
+ input: profileInput,
197
+ ctx,
198
+ })
199
+ }
@@ -0,0 +1,30 @@
1
+ export const EXPIRING_SOON_DAYS = 30
2
+
3
+ export type ExpiryWindow = 'expiringSoon' | 'pastDue'
4
+
5
+ export function startOfUtcDay(date: Date): Date {
6
+ return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()))
7
+ }
8
+
9
+ export function addUtcDays(date: Date, days: number): Date {
10
+ const next = new Date(date)
11
+ next.setUTCDate(next.getUTCDate() + days)
12
+ return next
13
+ }
14
+
15
+ export function buildExpiryWindowDateFilter(
16
+ expiryWindow: ExpiryWindow,
17
+ now: Date = new Date(),
18
+ ): Record<string, unknown> {
19
+ const today = startOfUtcDay(now)
20
+ if (expiryWindow === 'pastDue') {
21
+ return { expires_at: { $ne: null, $lt: today } }
22
+ }
23
+ return {
24
+ expires_at: {
25
+ $ne: null,
26
+ $gte: today,
27
+ $lte: addUtcDays(today, EXPIRING_SOON_DAYS),
28
+ },
29
+ }
30
+ }
@@ -0,0 +1,74 @@
1
+ import { flash } from '@open-mercato/ui/backend/FlashMessages'
2
+ import type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'
3
+
4
+ /**
5
+ * Maps a `requireFeatures` ACL feature id to the i18n key that names the
6
+ * specific permission a 403 response is missing (#4102 follow-up — the
7
+ * generic "Forbidden" toast didn't say what was denied).
8
+ */
9
+ const FORBIDDEN_FEATURE_MESSAGE_KEYS: Record<string, string> = {
10
+ 'wms.manage_warehouses': 'wms.errors.forbidden.manageWarehouses',
11
+ 'wms.manage_zones': 'wms.errors.forbidden.manageZones',
12
+ 'wms.manage_locations': 'wms.errors.forbidden.manageLocations',
13
+ 'wms.manage_inventory': 'wms.errors.forbidden.manageInventory',
14
+ 'wms.manage_reservations': 'wms.errors.forbidden.manageReservations',
15
+ 'wms.adjust_inventory': 'wms.errors.forbidden.adjustInventory',
16
+ 'wms.receive_inventory': 'wms.errors.forbidden.receiveInventory',
17
+ 'wms.cycle_count': 'wms.errors.forbidden.cycleCount',
18
+ 'wms.import': 'wms.errors.forbidden.import',
19
+ }
20
+
21
+ const FORBIDDEN_FEATURE_MESSAGE_FALLBACKS: Record<string, string> = {
22
+ 'wms.manage_warehouses': "You don't have permission to manage warehouses.",
23
+ 'wms.manage_zones': "You don't have permission to manage warehouse zones.",
24
+ 'wms.manage_locations': "You don't have permission to manage warehouse locations.",
25
+ 'wms.manage_inventory': "You don't have permission to manage inventory profiles.",
26
+ 'wms.manage_reservations': "You don't have permission to manage inventory reservations.",
27
+ 'wms.adjust_inventory': "You don't have permission to adjust or move inventory.",
28
+ 'wms.receive_inventory': "You don't have permission to receive inbound inventory.",
29
+ 'wms.cycle_count': "You don't have permission to run cycle counts.",
30
+ 'wms.import': "You don't have permission to import inventory.",
31
+ }
32
+
33
+ /**
34
+ * Reads the 403 response's `requiredFeatures` (attached to the thrown error
35
+ * by `raiseCrudError`) and, when the missing feature is a known WMS
36
+ * permission, resolves a translated message naming it. Returns `null` when
37
+ * the error isn't a recognized 403-with-features shape so callers can fall
38
+ * back to the generic message.
39
+ */
40
+ function resolveForbiddenFeatureMessage(error: unknown, t?: TranslateFn): string | null {
41
+ if (!error || typeof error !== 'object') return null
42
+ const status = (error as Record<string, unknown>).status
43
+ if (status !== 403) return null
44
+ const requiredFeatures = (error as Record<string, unknown>).requiredFeatures
45
+ if (!Array.isArray(requiredFeatures)) return null
46
+ const knownFeature = requiredFeatures.find(
47
+ (feature): feature is string => typeof feature === 'string' && feature in FORBIDDEN_FEATURE_MESSAGE_KEYS,
48
+ )
49
+ if (!knownFeature) return null
50
+ const key = FORBIDDEN_FEATURE_MESSAGE_KEYS[knownFeature]
51
+ const fallback = FORBIDDEN_FEATURE_MESSAGE_FALLBACKS[knownFeature]
52
+ return t ? t(key, fallback) : fallback
53
+ }
54
+
55
+ /**
56
+ * Surfaces a mutation failure as an error flash toast. Prefers a
57
+ * feature-specific 403 message derived from the server's `requiredFeatures`
58
+ * hint (#4102 follow-up), then the thrown error's own message (already
59
+ * server-derived and translated by `raiseCrudError`/`useGuardedMutation`),
60
+ * and falls back to a translated, dialog-specific message otherwise (#4103).
61
+ */
62
+ export function flashMutationError(error: unknown, fallbackMessage: string, t?: TranslateFn): void {
63
+ const forbiddenMessage = resolveForbiddenFeatureMessage(error, t)
64
+ if (forbiddenMessage) {
65
+ flash(forbiddenMessage, 'error')
66
+ return
67
+ }
68
+ // apiFetch throws ForbiddenError with a bare "Forbidden" message when the
69
+ // ACL body has no mappable feature — prefer the dialog-specific fallback
70
+ // over flashing the untranslated server token.
71
+ const rawMessage = error instanceof Error ? error.message.trim() : ''
72
+ const isGenericForbidden = rawMessage.length === 0 || /^forbidden$/i.test(rawMessage)
73
+ flash(isGenericForbidden ? fallbackMessage : rawMessage, 'error')
74
+ }
@@ -0,0 +1,249 @@
1
+ import type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'
2
+ import { parseInventoryQuantity } from './inventoryMutationUi'
3
+
4
+ export type InventoryDisplayTranslator = TranslateFn
5
+
6
+ const MOVEMENT_TYPE_FALLBACKS: Record<string, string> = {
7
+ receipt: 'Receive',
8
+ return_receive: 'Receive',
9
+ adjust: 'Adjust',
10
+ transfer: 'Move',
11
+ pick: 'Allocate',
12
+ pack: 'Allocate',
13
+ cycle_count: 'Reconcile',
14
+ putaway: 'Putaway',
15
+ ship: 'Ship',
16
+ }
17
+
18
+ const RESERVATION_SOURCE_TYPE_FALLBACKS: Record<string, string> = {
19
+ order: 'Sales order',
20
+ transfer: 'Transfer',
21
+ manual: 'Manual',
22
+ }
23
+
24
+ const REFERENCE_TYPE_FALLBACKS: Record<string, string> = {
25
+ po: 'Purchase order',
26
+ so: 'Sales order',
27
+ transfer: 'Transfer',
28
+ manual: 'Manual',
29
+ qc: 'Quality control',
30
+ rma: 'RMA',
31
+ }
32
+
33
+ const RESERVATION_STATUS_FALLBACKS: Record<string, string> = {
34
+ active: 'Active',
35
+ released: 'Released',
36
+ fulfilled: 'Fulfilled',
37
+ }
38
+
39
+ const ROTATION_STRATEGY_FALLBACKS: Record<string, string> = {
40
+ fifo: 'FIFO',
41
+ lifo: 'LIFO',
42
+ fefo: 'FEFO',
43
+ }
44
+
45
+ const ADJUST_REASON_FALLBACKS: Record<string, string> = {
46
+ damaged: 'Damaged',
47
+ shrinkage: 'Shrinkage',
48
+ found: 'Found stock',
49
+ correction: 'Correction',
50
+ other: 'Other',
51
+ }
52
+
53
+ const MOVE_REASON_FALLBACKS: Record<string, string> = {
54
+ transfer: 'Transfer',
55
+ replenishment: 'Replenishment',
56
+ consolidation: 'Consolidation',
57
+ correction: 'Correction',
58
+ other: 'Other',
59
+ }
60
+
61
+ const RELEASE_REASON_FALLBACKS: Record<string, string> = {
62
+ order_cancelled: 'Order cancelled',
63
+ manual_release: 'Manual release',
64
+ correction: 'Correction',
65
+ other: 'Other',
66
+ }
67
+
68
+ const STABLE_REASON_CODE_PATTERN = /^[a-z][a-z0-9_]*$/
69
+
70
+ export function createInventoryQuantityFormatter(locale: string): Intl.NumberFormat {
71
+ return new Intl.NumberFormat(locale, { maximumFractionDigits: 2 })
72
+ }
73
+
74
+ export function formatInventoryQuantity(
75
+ value: string | number | null | undefined,
76
+ formatter: Intl.NumberFormat,
77
+ ): string {
78
+ return formatter.format(parseInventoryQuantity(value))
79
+ }
80
+
81
+ export function createInventoryDateTimeFormatter(
82
+ locale: string,
83
+ options: Intl.DateTimeFormatOptions = {
84
+ month: '2-digit',
85
+ day: '2-digit',
86
+ hour: '2-digit',
87
+ minute: '2-digit',
88
+ },
89
+ ): Intl.DateTimeFormat {
90
+ return new Intl.DateTimeFormat(locale, options)
91
+ }
92
+
93
+ export function formatInventoryDateTime(
94
+ value: string | null | undefined,
95
+ formatter: Intl.DateTimeFormat,
96
+ ): string {
97
+ if (!value?.trim()) return '—'
98
+ const date = new Date(value)
99
+ if (Number.isNaN(date.getTime())) return '—'
100
+ return formatter.format(date)
101
+ }
102
+
103
+ export function inventoryMovementTypeLabel(type: string, t: InventoryDisplayTranslator): string {
104
+ const normalized = type.trim()
105
+ if (!normalized) return '—'
106
+ return t(
107
+ `wms.backend.dashboard.activity.types.${normalized}`,
108
+ MOVEMENT_TYPE_FALLBACKS[normalized] ?? normalized,
109
+ )
110
+ }
111
+
112
+ export function inventoryReservationSourceTypeLabel(
113
+ sourceType: string,
114
+ t: InventoryDisplayTranslator,
115
+ ): string {
116
+ const normalized = sourceType.trim()
117
+ if (!normalized) return '—'
118
+ return t(
119
+ `wms.backend.inventory.sourceTypes.${normalized}`,
120
+ RESERVATION_SOURCE_TYPE_FALLBACKS[normalized] ?? normalized,
121
+ )
122
+ }
123
+
124
+ export function inventoryReferenceTypeLabel(
125
+ referenceType: string,
126
+ t: InventoryDisplayTranslator,
127
+ ): string {
128
+ const normalized = referenceType.trim()
129
+ if (!normalized) return '—'
130
+ return t(
131
+ `wms.backend.inventory.referenceTypes.${normalized}`,
132
+ REFERENCE_TYPE_FALLBACKS[normalized] ?? normalized,
133
+ )
134
+ }
135
+
136
+ export function inventoryReservationStatusLabel(status: string, t: InventoryDisplayTranslator): string {
137
+ const normalized = status.trim()
138
+ if (!normalized) return '—'
139
+ return t(
140
+ `wms.backend.inventory.reservationStatuses.${normalized}`,
141
+ RESERVATION_STATUS_FALLBACKS[normalized] ?? normalized,
142
+ )
143
+ }
144
+
145
+ export function inventoryRotationStrategyLabel(strategy: string, t: InventoryDisplayTranslator): string {
146
+ const normalized = strategy.trim()
147
+ if (!normalized) return '—'
148
+ return t(
149
+ `wms.widgets.catalog.inventoryProfile.strategy.${normalized}`,
150
+ ROTATION_STRATEGY_FALLBACKS[normalized] ?? normalized,
151
+ )
152
+ }
153
+
154
+ function translateStableReasonCode(
155
+ code: string,
156
+ movementType: string | null | undefined,
157
+ t: InventoryDisplayTranslator,
158
+ ): string | null {
159
+ if (code === 'cycle_count') {
160
+ return t('wms.backend.dashboard.activity.reasons.cycleCount', 'Cycle count')
161
+ }
162
+
163
+ const type = (movementType ?? '').trim()
164
+ if (type === 'transfer' && code in MOVE_REASON_FALLBACKS) {
165
+ return t(`wms.backend.inventory.move.reasons.${code}`, MOVE_REASON_FALLBACKS[code])
166
+ }
167
+ if ((type === 'adjust' || type === 'cycle_count') && code in ADJUST_REASON_FALLBACKS) {
168
+ return t(`wms.backend.inventory.adjust.reasons.${code}`, ADJUST_REASON_FALLBACKS[code])
169
+ }
170
+ if (code in ADJUST_REASON_FALLBACKS) {
171
+ return t(`wms.backend.inventory.adjust.reasons.${code}`, ADJUST_REASON_FALLBACKS[code])
172
+ }
173
+ if (code in MOVE_REASON_FALLBACKS) {
174
+ return t(`wms.backend.inventory.move.reasons.${code}`, MOVE_REASON_FALLBACKS[code])
175
+ }
176
+ if (code in RELEASE_REASON_FALLBACKS) {
177
+ return t(`wms.backend.inventory.release.reasons.${code}`, RELEASE_REASON_FALLBACKS[code])
178
+ }
179
+ return null
180
+ }
181
+
182
+ /**
183
+ * Resolve a movement/activity reason for display. Prefers the stable
184
+ * `reasonCode` (re-translated for the current locale) over a free-text
185
+ * `reason` that may have been baked in a different language at write time.
186
+ */
187
+ export function inventoryMovementReasonLabel(
188
+ input: {
189
+ reasonCode?: string | null
190
+ reason?: string | null
191
+ movementType?: string | null
192
+ },
193
+ t: InventoryDisplayTranslator,
194
+ ): string | null {
195
+ const reasonCode = input.reasonCode?.trim() || null
196
+ const reason = input.reason?.trim() || null
197
+ const candidateCode =
198
+ reasonCode ||
199
+ (reason && STABLE_REASON_CODE_PATTERN.test(reason) ? reason : null)
200
+
201
+ if (candidateCode) {
202
+ const translated = translateStableReasonCode(candidateCode, input.movementType, t)
203
+ if (translated) return translated
204
+ }
205
+
206
+ return reason
207
+ }
208
+
209
+ export function formatCatalogProductLabel(row: {
210
+ product_title?: string | null
211
+ product_sku?: string | null
212
+ catalog_product_id?: string | null
213
+ }): string {
214
+ const title = (row.product_title ?? '').trim()
215
+ const sku = (row.product_sku ?? '').trim()
216
+ if (title && sku) return `${title} (${sku})`
217
+ if (title) return title
218
+ if (sku) return sku
219
+ return row.catalog_product_id?.trim() || '—'
220
+ }
221
+
222
+ export function formatCatalogVariantLabel(row: {
223
+ variant_name?: string | null
224
+ variant_sku?: string | null
225
+ catalog_variant_id?: string | null
226
+ }): string {
227
+ const name = (row.variant_name ?? '').trim()
228
+ const sku = (row.variant_sku ?? '').trim()
229
+ if (name && sku) return `${name} (${sku})`
230
+ if (name) return name
231
+ if (sku) return sku
232
+ return row.catalog_variant_id?.trim() || '—'
233
+ }
234
+
235
+ export function formatReservationSourceLabel(
236
+ row: {
237
+ source_type?: string | null
238
+ source_id?: string | null
239
+ source_label?: string | null
240
+ },
241
+ t: InventoryDisplayTranslator,
242
+ ): string {
243
+ const sourceType = row.source_type?.trim()
244
+ if (!sourceType) return '—'
245
+ const typeLabel = inventoryReservationSourceTypeLabel(sourceType, t)
246
+ const sourceLabel = row.source_label?.trim()
247
+ if (sourceLabel) return `${typeLabel} · ${sourceLabel}`
248
+ return typeLabel
249
+ }
@@ -0,0 +1,54 @@
1
+ import type { InventoryMovementType, InventoryReservationSourceType } from '../data/entities'
2
+
3
+ function normalizeSegment(value: string | null | undefined): string {
4
+ if (typeof value !== 'string' || value.trim().length === 0) return ''
5
+ return value.trim()
6
+ }
7
+
8
+ function normalizeQuantity(value: number): string {
9
+ return String(value)
10
+ }
11
+
12
+ export function buildMovementIdempotencyKey(input: {
13
+ referenceType: string
14
+ referenceId: string
15
+ type: InventoryMovementType
16
+ warehouseId: string
17
+ locationFromId?: string | null
18
+ locationToId?: string | null
19
+ catalogVariantId: string
20
+ lotId?: string | null
21
+ serialNumber?: string | null
22
+ quantity: number
23
+ }): string {
24
+ return [
25
+ 'movement',
26
+ normalizeSegment(input.referenceType),
27
+ normalizeSegment(input.referenceId),
28
+ normalizeSegment(input.type),
29
+ normalizeSegment(input.warehouseId),
30
+ normalizeSegment(input.locationFromId),
31
+ normalizeSegment(input.locationToId),
32
+ normalizeSegment(input.catalogVariantId),
33
+ normalizeSegment(input.lotId),
34
+ normalizeSegment(input.serialNumber),
35
+ normalizeQuantity(input.quantity),
36
+ ].join('|')
37
+ }
38
+
39
+ export function buildReservationIdempotencyKey(input: {
40
+ sourceType: InventoryReservationSourceType
41
+ sourceId: string
42
+ catalogVariantId: string
43
+ warehouseId: string
44
+ quantity: number
45
+ }): string {
46
+ return [
47
+ 'reservation',
48
+ normalizeSegment(input.sourceType),
49
+ normalizeSegment(input.sourceId),
50
+ normalizeSegment(input.catalogVariantId),
51
+ normalizeSegment(input.warehouseId),
52
+ normalizeQuantity(input.quantity),
53
+ ].join('|')
54
+ }