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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/inventory_balance/index.js +21 -0
  3. package/dist/generated/entities/inventory_balance/index.js.map +7 -0
  4. package/dist/generated/entities/inventory_lot/index.js +19 -0
  5. package/dist/generated/entities/inventory_lot/index.js.map +7 -0
  6. package/dist/generated/entities/inventory_movement/index.js +35 -0
  7. package/dist/generated/entities/inventory_movement/index.js.map +7 -0
  8. package/dist/generated/entities/inventory_reservation/index.js +23 -0
  9. package/dist/generated/entities/inventory_reservation/index.js.map +7 -0
  10. package/dist/generated/entities/product_inventory_profile/index.js +21 -0
  11. package/dist/generated/entities/product_inventory_profile/index.js.map +7 -0
  12. package/dist/generated/entities/sales_order_warehouse_assignment/index.js +11 -0
  13. package/dist/generated/entities/sales_order_warehouse_assignment/index.js.map +7 -0
  14. package/dist/generated/entities/warehouse/index.js +25 -0
  15. package/dist/generated/entities/warehouse/index.js.map +7 -0
  16. package/dist/generated/entities/warehouse_location/index.js +21 -0
  17. package/dist/generated/entities/warehouse_location/index.js.map +7 -0
  18. package/dist/generated/entities/warehouse_zone/index.js +11 -0
  19. package/dist/generated/entities/warehouse_zone/index.js.map +7 -0
  20. package/dist/generated/entities.ids.generated.js +12 -0
  21. package/dist/generated/entities.ids.generated.js.map +2 -2
  22. package/dist/generated/entity-fields-registry.js +98 -0
  23. package/dist/generated/entity-fields-registry.js.map +2 -2
  24. package/dist/modules/auth/backend/roles/page.js +12 -4
  25. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  26. package/dist/modules/auth/lib/backendChrome.js +1 -0
  27. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  28. package/dist/modules/auth/services/rbacService.js +16 -17
  29. package/dist/modules/auth/services/rbacService.js.map +2 -2
  30. package/dist/modules/catalog/api/products/route.js +3 -0
  31. package/dist/modules/catalog/api/products/route.js.map +2 -2
  32. package/dist/modules/catalog/api/variants/route.js +3 -0
  33. package/dist/modules/catalog/api/variants/route.js.map +2 -2
  34. package/dist/modules/query_index/lib/engine.js +6 -6
  35. package/dist/modules/query_index/lib/engine.js.map +2 -2
  36. package/dist/modules/sales/api/documents/factory.js +1 -0
  37. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  38. package/dist/modules/sales/commands/documents.js +53 -0
  39. package/dist/modules/sales/commands/documents.js.map +2 -2
  40. package/dist/modules/sales/components/documents/ItemsSection.js +51 -2
  41. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  42. package/dist/modules/sales/events.js +2 -0
  43. package/dist/modules/sales/events.js.map +2 -2
  44. package/dist/modules/sales/widgets/injection/order-items-context.js +11 -0
  45. package/dist/modules/sales/widgets/injection/order-items-context.js.map +7 -0
  46. package/dist/modules/wms/acl.js +18 -0
  47. package/dist/modules/wms/acl.js.map +7 -0
  48. package/dist/modules/wms/analytics.js +11 -0
  49. package/dist/modules/wms/analytics.js.map +7 -0
  50. package/dist/modules/wms/api/dashboard/operational/route.js +80 -0
  51. package/dist/modules/wms/api/dashboard/operational/route.js.map +7 -0
  52. package/dist/modules/wms/api/interceptors.js +90 -0
  53. package/dist/modules/wms/api/interceptors.js.map +7 -0
  54. package/dist/modules/wms/api/inventory/adjust/route.js +51 -0
  55. package/dist/modules/wms/api/inventory/adjust/route.js.map +7 -0
  56. package/dist/modules/wms/api/inventory/allocate/route.js +51 -0
  57. package/dist/modules/wms/api/inventory/allocate/route.js.map +7 -0
  58. package/dist/modules/wms/api/inventory/balances/route.js +172 -0
  59. package/dist/modules/wms/api/inventory/balances/route.js.map +7 -0
  60. package/dist/modules/wms/api/inventory/cycle-count/route.js +52 -0
  61. package/dist/modules/wms/api/inventory/cycle-count/route.js.map +7 -0
  62. package/dist/modules/wms/api/inventory/helpers.js +113 -0
  63. package/dist/modules/wms/api/inventory/helpers.js.map +7 -0
  64. package/dist/modules/wms/api/inventory/import/apply/route.js +46 -0
  65. package/dist/modules/wms/api/inventory/import/apply/route.js.map +7 -0
  66. package/dist/modules/wms/api/inventory/import/helpers.js +195 -0
  67. package/dist/modules/wms/api/inventory/import/helpers.js.map +7 -0
  68. package/dist/modules/wms/api/inventory/import/template/route.js +32 -0
  69. package/dist/modules/wms/api/inventory/import/template/route.js.map +7 -0
  70. package/dist/modules/wms/api/inventory/import/validate/route.js +54 -0
  71. package/dist/modules/wms/api/inventory/import/validate/route.js.map +7 -0
  72. package/dist/modules/wms/api/inventory/move/route.js +51 -0
  73. package/dist/modules/wms/api/inventory/move/route.js.map +7 -0
  74. package/dist/modules/wms/api/inventory/movements/route.js +164 -0
  75. package/dist/modules/wms/api/inventory/movements/route.js.map +7 -0
  76. package/dist/modules/wms/api/inventory/receive/route.js +50 -0
  77. package/dist/modules/wms/api/inventory/receive/route.js.map +7 -0
  78. package/dist/modules/wms/api/inventory/release/route.js +44 -0
  79. package/dist/modules/wms/api/inventory/release/route.js.map +7 -0
  80. package/dist/modules/wms/api/inventory/reservations/route.js +128 -0
  81. package/dist/modules/wms/api/inventory/reservations/route.js.map +7 -0
  82. package/dist/modules/wms/api/inventory/reserve/route.js +59 -0
  83. package/dist/modules/wms/api/inventory/reserve/route.js.map +7 -0
  84. package/dist/modules/wms/api/inventory-profiles/route.js +178 -0
  85. package/dist/modules/wms/api/inventory-profiles/route.js.map +7 -0
  86. package/dist/modules/wms/api/listEnrichers.js +181 -0
  87. package/dist/modules/wms/api/listEnrichers.js.map +7 -0
  88. package/dist/modules/wms/api/listSearch.js +77 -0
  89. package/dist/modules/wms/api/listSearch.js.map +7 -0
  90. package/dist/modules/wms/api/locations/route.js +172 -0
  91. package/dist/modules/wms/api/locations/route.js.map +7 -0
  92. package/dist/modules/wms/api/lots/route.js +204 -0
  93. package/dist/modules/wms/api/lots/route.js.map +7 -0
  94. package/dist/modules/wms/api/openapi.js +27 -0
  95. package/dist/modules/wms/api/openapi.js.map +7 -0
  96. package/dist/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.js +54 -0
  97. package/dist/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.js.map +7 -0
  98. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js +279 -0
  99. package/dist/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.js.map +7 -0
  100. package/dist/modules/wms/api/sales-orders/assign-warehouse/route.js +56 -0
  101. package/dist/modules/wms/api/sales-orders/assign-warehouse/route.js.map +7 -0
  102. package/dist/modules/wms/api/sales-orders/unassign-warehouse/route.js +43 -0
  103. package/dist/modules/wms/api/sales-orders/unassign-warehouse/route.js.map +7 -0
  104. package/dist/modules/wms/api/warehouses/route.js +181 -0
  105. package/dist/modules/wms/api/warehouses/route.js.map +7 -0
  106. package/dist/modules/wms/api/zones/route.js +159 -0
  107. package/dist/modules/wms/api/zones/route.js.map +7 -0
  108. package/dist/modules/wms/backend/config/wms/page.js +9 -0
  109. package/dist/modules/wms/backend/config/wms/page.js.map +7 -0
  110. package/dist/modules/wms/backend/config/wms/page.meta.js +18 -0
  111. package/dist/modules/wms/backend/config/wms/page.meta.js.map +7 -0
  112. package/dist/modules/wms/backend/page.js +9 -0
  113. package/dist/modules/wms/backend/page.js.map +7 -0
  114. package/dist/modules/wms/backend/page.meta.js +16 -0
  115. package/dist/modules/wms/backend/page.meta.js.map +7 -0
  116. package/dist/modules/wms/backend/wms/inventory/page.js +9 -0
  117. package/dist/modules/wms/backend/wms/inventory/page.js.map +7 -0
  118. package/dist/modules/wms/backend/wms/inventory/page.meta.js +18 -0
  119. package/dist/modules/wms/backend/wms/inventory/page.meta.js.map +7 -0
  120. package/dist/modules/wms/backend/wms/location/[id]/page.js +9 -0
  121. package/dist/modules/wms/backend/wms/location/[id]/page.js.map +7 -0
  122. package/dist/modules/wms/backend/wms/location/[id]/page.meta.js +18 -0
  123. package/dist/modules/wms/backend/wms/location/[id]/page.meta.js.map +7 -0
  124. package/dist/modules/wms/backend/wms/locations/page.js +10 -0
  125. package/dist/modules/wms/backend/wms/locations/page.js.map +7 -0
  126. package/dist/modules/wms/backend/wms/locations/page.meta.js +18 -0
  127. package/dist/modules/wms/backend/wms/locations/page.meta.js.map +7 -0
  128. package/dist/modules/wms/backend/wms/lot/[id]/page.js +9 -0
  129. package/dist/modules/wms/backend/wms/lot/[id]/page.js.map +7 -0
  130. package/dist/modules/wms/backend/wms/lot/[id]/page.meta.js +18 -0
  131. package/dist/modules/wms/backend/wms/lot/[id]/page.meta.js.map +7 -0
  132. package/dist/modules/wms/backend/wms/lots/page.js +9 -0
  133. package/dist/modules/wms/backend/wms/lots/page.js.map +7 -0
  134. package/dist/modules/wms/backend/wms/lots/page.meta.js +18 -0
  135. package/dist/modules/wms/backend/wms/lots/page.meta.js.map +7 -0
  136. package/dist/modules/wms/backend/wms/movements/page.js +22 -0
  137. package/dist/modules/wms/backend/wms/movements/page.js.map +7 -0
  138. package/dist/modules/wms/backend/wms/movements/page.meta.js +18 -0
  139. package/dist/modules/wms/backend/wms/movements/page.meta.js.map +7 -0
  140. package/dist/modules/wms/backend/wms/reservations/page.js +23 -0
  141. package/dist/modules/wms/backend/wms/reservations/page.js.map +7 -0
  142. package/dist/modules/wms/backend/wms/reservations/page.meta.js +18 -0
  143. package/dist/modules/wms/backend/wms/reservations/page.meta.js.map +7 -0
  144. package/dist/modules/wms/backend/wms/sku/[id]/page.js +9 -0
  145. package/dist/modules/wms/backend/wms/sku/[id]/page.js.map +7 -0
  146. package/dist/modules/wms/backend/wms/sku/[id]/page.meta.js +18 -0
  147. package/dist/modules/wms/backend/wms/sku/[id]/page.meta.js.map +7 -0
  148. package/dist/modules/wms/backend/wms/warehouses/page.js +10 -0
  149. package/dist/modules/wms/backend/wms/warehouses/page.js.map +7 -0
  150. package/dist/modules/wms/backend/wms/warehouses/page.meta.js +18 -0
  151. package/dist/modules/wms/backend/wms/warehouses/page.meta.js.map +7 -0
  152. package/dist/modules/wms/backend/wms/zones/page.js +10 -0
  153. package/dist/modules/wms/backend/wms/zones/page.js.map +7 -0
  154. package/dist/modules/wms/backend/wms/zones/page.meta.js +18 -0
  155. package/dist/modules/wms/backend/wms/zones/page.meta.js.map +7 -0
  156. package/dist/modules/wms/ce.js +80 -0
  157. package/dist/modules/wms/ce.js.map +7 -0
  158. package/dist/modules/wms/cli.js +83 -0
  159. package/dist/modules/wms/cli.js.map +7 -0
  160. package/dist/modules/wms/commands/configuration.js +1519 -0
  161. package/dist/modules/wms/commands/configuration.js.map +7 -0
  162. package/dist/modules/wms/commands/index.js +4 -0
  163. package/dist/modules/wms/commands/index.js.map +7 -0
  164. package/dist/modules/wms/commands/inventory-actions.js +1539 -0
  165. package/dist/modules/wms/commands/inventory-actions.js.map +7 -0
  166. package/dist/modules/wms/commands/sales-order-assignment.js +277 -0
  167. package/dist/modules/wms/commands/sales-order-assignment.js.map +7 -0
  168. package/dist/modules/wms/commands/shared.js +82 -0
  169. package/dist/modules/wms/commands/shared.js.map +7 -0
  170. package/dist/modules/wms/components/backend/AdjustInventoryDialog.js +755 -0
  171. package/dist/modules/wms/components/backend/AdjustInventoryDialog.js.map +7 -0
  172. package/dist/modules/wms/components/backend/ChangeLotStatusDialog.js +269 -0
  173. package/dist/modules/wms/components/backend/ChangeLotStatusDialog.js.map +7 -0
  174. package/dist/modules/wms/components/backend/CycleCountWizardDialog.js +1783 -0
  175. package/dist/modules/wms/components/backend/CycleCountWizardDialog.js.map +7 -0
  176. package/dist/modules/wms/components/backend/ImportInventoryDialog.js +766 -0
  177. package/dist/modules/wms/components/backend/ImportInventoryDialog.js.map +7 -0
  178. package/dist/modules/wms/components/backend/InventoryOperationsSection.js +119 -0
  179. package/dist/modules/wms/components/backend/InventoryOperationsSection.js.map +7 -0
  180. package/dist/modules/wms/components/backend/LocationEditDialog.js +140 -0
  181. package/dist/modules/wms/components/backend/LocationEditDialog.js.map +7 -0
  182. package/dist/modules/wms/components/backend/MoveInventoryDialog.js +791 -0
  183. package/dist/modules/wms/components/backend/MoveInventoryDialog.js.map +7 -0
  184. package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js +656 -0
  185. package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js.map +7 -0
  186. package/dist/modules/wms/components/backend/ReleaseReservationDialog.js +344 -0
  187. package/dist/modules/wms/components/backend/ReleaseReservationDialog.js.map +7 -0
  188. package/dist/modules/wms/components/backend/ReserveInventoryDialog.js +475 -0
  189. package/dist/modules/wms/components/backend/ReserveInventoryDialog.js.map +7 -0
  190. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +1112 -0
  191. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +7 -0
  192. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +908 -0
  193. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +7 -0
  194. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +1015 -0
  195. package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +7 -0
  196. package/dist/modules/wms/components/backend/WmsLotDetailPage.js +1049 -0
  197. package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +7 -0
  198. package/dist/modules/wms/components/backend/WmsLotsListPage.js +297 -0
  199. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +7 -0
  200. package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js +757 -0
  201. package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js.map +7 -0
  202. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +975 -0
  203. package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +7 -0
  204. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +710 -0
  205. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +7 -0
  206. package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js +79 -0
  207. package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js.map +7 -0
  208. package/dist/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.js +24 -0
  209. package/dist/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.js.map +7 -0
  210. package/dist/modules/wms/components/backend/wmsLookupLoaders.js +55 -0
  211. package/dist/modules/wms/components/backend/wmsLookupLoaders.js.map +7 -0
  212. package/dist/modules/wms/data/enrichers.js +501 -0
  213. package/dist/modules/wms/data/enrichers.js.map +7 -0
  214. package/dist/modules/wms/data/entities.js +467 -0
  215. package/dist/modules/wms/data/entities.js.map +7 -0
  216. package/dist/modules/wms/data/validators.js +399 -0
  217. package/dist/modules/wms/data/validators.js.map +7 -0
  218. package/dist/modules/wms/di.js +27 -0
  219. package/dist/modules/wms/di.js.map +7 -0
  220. package/dist/modules/wms/events.js +42 -0
  221. package/dist/modules/wms/events.js.map +7 -0
  222. package/dist/modules/wms/index.js +17 -0
  223. package/dist/modules/wms/index.js.map +7 -0
  224. package/dist/modules/wms/lib/catalogInventoryProfileIntent.js +54 -0
  225. package/dist/modules/wms/lib/catalogInventoryProfileIntent.js.map +7 -0
  226. package/dist/modules/wms/lib/catalogInventoryProfileSync.js +144 -0
  227. package/dist/modules/wms/lib/catalogInventoryProfileSync.js.map +7 -0
  228. package/dist/modules/wms/lib/expiry.js +29 -0
  229. package/dist/modules/wms/lib/expiry.js.map +7 -0
  230. package/dist/modules/wms/lib/flashMutationError.js +51 -0
  231. package/dist/modules/wms/lib/flashMutationError.js.map +7 -0
  232. package/dist/modules/wms/lib/inventoryDisplayUi.js +188 -0
  233. package/dist/modules/wms/lib/inventoryDisplayUi.js.map +7 -0
  234. package/dist/modules/wms/lib/inventoryIdempotency.js +37 -0
  235. package/dist/modules/wms/lib/inventoryIdempotency.js.map +7 -0
  236. package/dist/modules/wms/lib/inventoryImportCsv.js +173 -0
  237. package/dist/modules/wms/lib/inventoryImportCsv.js.map +7 -0
  238. package/dist/modules/wms/lib/inventoryImportService.js +468 -0
  239. package/dist/modules/wms/lib/inventoryImportService.js.map +7 -0
  240. package/dist/modules/wms/lib/inventoryMutationUi.js +25 -0
  241. package/dist/modules/wms/lib/inventoryMutationUi.js.map +7 -0
  242. package/dist/modules/wms/lib/inventoryPolicy.js +61 -0
  243. package/dist/modules/wms/lib/inventoryPolicy.js.map +7 -0
  244. package/dist/modules/wms/lib/inventoryReconciliation.js +193 -0
  245. package/dist/modules/wms/lib/inventoryReconciliation.js.map +7 -0
  246. package/dist/modules/wms/lib/inventoryTrackingValidation.js +13 -0
  247. package/dist/modules/wms/lib/inventoryTrackingValidation.js.map +7 -0
  248. package/dist/modules/wms/lib/loadOperationalDashboard.js +580 -0
  249. package/dist/modules/wms/lib/loadOperationalDashboard.js.map +7 -0
  250. package/dist/modules/wms/lib/lowStockBalanceFilter.js +49 -0
  251. package/dist/modules/wms/lib/lowStockBalanceFilter.js.map +7 -0
  252. package/dist/modules/wms/lib/primaryWarehousePolicy.js +32 -0
  253. package/dist/modules/wms/lib/primaryWarehousePolicy.js.map +7 -0
  254. package/dist/modules/wms/lib/roleFeatures.js +30 -0
  255. package/dist/modules/wms/lib/roleFeatures.js.map +7 -0
  256. package/dist/modules/wms/lib/salesOrderInventoryAutomation.js +291 -0
  257. package/dist/modules/wms/lib/salesOrderInventoryAutomation.js.map +7 -0
  258. package/dist/modules/wms/lib/salesOrderWarehouseAssignment.js +54 -0
  259. package/dist/modules/wms/lib/salesOrderWarehouseAssignment.js.map +7 -0
  260. package/dist/modules/wms/lib/wmsIntegrationToggles.js +71 -0
  261. package/dist/modules/wms/lib/wmsIntegrationToggles.js.map +7 -0
  262. package/dist/modules/wms/migrations/Migration20260428110546.js +78 -0
  263. package/dist/modules/wms/migrations/Migration20260428110546.js.map +7 -0
  264. package/dist/modules/wms/migrations/Migration20260527120000.js +15 -0
  265. package/dist/modules/wms/migrations/Migration20260527120000.js.map +7 -0
  266. package/dist/modules/wms/migrations/Migration20260527140000.js +37 -0
  267. package/dist/modules/wms/migrations/Migration20260527140000.js.map +7 -0
  268. package/dist/modules/wms/migrations/Migration20260613120000.js +23 -0
  269. package/dist/modules/wms/migrations/Migration20260613120000.js.map +7 -0
  270. package/dist/modules/wms/migrations/Migration20260616090000.js +13 -0
  271. package/dist/modules/wms/migrations/Migration20260616090000.js.map +7 -0
  272. package/dist/modules/wms/migrations/Migration20260707180000.js +15 -0
  273. package/dist/modules/wms/migrations/Migration20260707180000.js.map +7 -0
  274. package/dist/modules/wms/notifications.client.js +18 -0
  275. package/dist/modules/wms/notifications.client.js.map +7 -0
  276. package/dist/modules/wms/notifications.js +53 -0
  277. package/dist/modules/wms/notifications.js.map +7 -0
  278. package/dist/modules/wms/search.js +196 -0
  279. package/dist/modules/wms/search.js.map +7 -0
  280. package/dist/modules/wms/setup.js +30 -0
  281. package/dist/modules/wms/setup.js.map +7 -0
  282. package/dist/modules/wms/subscribers/low-stock-notification.js +40 -0
  283. package/dist/modules/wms/subscribers/low-stock-notification.js.map +7 -0
  284. package/dist/modules/wms/subscribers/reservation-shortfall-notification.js +69 -0
  285. package/dist/modules/wms/subscribers/reservation-shortfall-notification.js.map +7 -0
  286. package/dist/modules/wms/subscribers/sales-order-cancelled-release.js +14 -0
  287. package/dist/modules/wms/subscribers/sales-order-cancelled-release.js.map +7 -0
  288. package/dist/modules/wms/subscribers/sales-order-confirmed-reserve.js +14 -0
  289. package/dist/modules/wms/subscribers/sales-order-confirmed-reserve.js.map +7 -0
  290. package/dist/modules/wms/translations.js +10 -0
  291. package/dist/modules/wms/translations.js.map +7 -0
  292. package/dist/modules/wms/vector.js +9 -0
  293. package/dist/modules/wms/vector.js.map +7 -0
  294. package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js +200 -0
  295. package/dist/modules/wms/widgets/injection/catalog-inventory-profile/widget.js.map +7 -0
  296. package/dist/modules/wms/widgets/injection/order-items-stock-column/widget.js +104 -0
  297. package/dist/modules/wms/widgets/injection/order-items-stock-column/widget.js.map +7 -0
  298. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js +389 -0
  299. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js.map +7 -0
  300. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.js +16 -0
  301. package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.js.map +7 -0
  302. package/dist/modules/wms/widgets/injection-table.js +36 -0
  303. package/dist/modules/wms/widgets/injection-table.js.map +7 -0
  304. package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js +150 -0
  305. package/dist/modules/wms/widgets/notifications/WmsLowStockRenderer.js.map +7 -0
  306. package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js +186 -0
  307. package/dist/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.js.map +7 -0
  308. package/dist/modules/wms/widgets/notifications/index.js +7 -0
  309. package/dist/modules/wms/widgets/notifications/index.js.map +7 -0
  310. package/generated/entities/inventory_balance/index.ts +9 -0
  311. package/generated/entities/inventory_lot/index.ts +8 -0
  312. package/generated/entities/inventory_movement/index.ts +16 -0
  313. package/generated/entities/inventory_reservation/index.ts +10 -0
  314. package/generated/entities/product_inventory_profile/index.ts +9 -0
  315. package/generated/entities/sales_order_warehouse_assignment/index.ts +4 -0
  316. package/generated/entities/warehouse/index.ts +11 -0
  317. package/generated/entities/warehouse_location/index.ts +9 -0
  318. package/generated/entities/warehouse_zone/index.ts +4 -0
  319. package/generated/entities.ids.generated.ts +12 -0
  320. package/generated/entity-fields-registry.ts +98 -0
  321. package/package.json +7 -7
  322. package/src/modules/auth/backend/roles/page.tsx +13 -4
  323. package/src/modules/auth/i18n/de.json +2 -0
  324. package/src/modules/auth/i18n/en.json +2 -0
  325. package/src/modules/auth/i18n/es.json +2 -0
  326. package/src/modules/auth/i18n/pl.json +2 -0
  327. package/src/modules/auth/lib/backendChrome.tsx +1 -0
  328. package/src/modules/auth/services/rbacService.ts +25 -21
  329. package/src/modules/catalog/api/products/route.ts +3 -0
  330. package/src/modules/catalog/api/variants/route.ts +3 -0
  331. package/src/modules/query_index/lib/engine.ts +18 -6
  332. package/src/modules/sales/api/documents/factory.ts +1 -0
  333. package/src/modules/sales/commands/documents.ts +71 -0
  334. package/src/modules/sales/components/documents/ItemsSection.tsx +58 -0
  335. package/src/modules/sales/events.ts +2 -0
  336. package/src/modules/sales/widgets/injection/order-items-context.ts +15 -0
  337. package/src/modules/wms/acl.ts +14 -0
  338. package/src/modules/wms/analytics.ts +9 -0
  339. package/src/modules/wms/api/dashboard/operational/route.ts +83 -0
  340. package/src/modules/wms/api/interceptors.ts +108 -0
  341. package/src/modules/wms/api/inventory/adjust/route.ts +50 -0
  342. package/src/modules/wms/api/inventory/allocate/route.ts +50 -0
  343. package/src/modules/wms/api/inventory/balances/route.ts +178 -0
  344. package/src/modules/wms/api/inventory/cycle-count/route.ts +51 -0
  345. package/src/modules/wms/api/inventory/helpers.ts +128 -0
  346. package/src/modules/wms/api/inventory/import/apply/route.ts +47 -0
  347. package/src/modules/wms/api/inventory/import/helpers.ts +223 -0
  348. package/src/modules/wms/api/inventory/import/template/route.ts +31 -0
  349. package/src/modules/wms/api/inventory/import/validate/route.ts +56 -0
  350. package/src/modules/wms/api/inventory/move/route.ts +50 -0
  351. package/src/modules/wms/api/inventory/movements/route.ts +164 -0
  352. package/src/modules/wms/api/inventory/receive/route.ts +49 -0
  353. package/src/modules/wms/api/inventory/release/route.ts +43 -0
  354. package/src/modules/wms/api/inventory/reservations/route.ts +128 -0
  355. package/src/modules/wms/api/inventory/reserve/route.ts +59 -0
  356. package/src/modules/wms/api/inventory-profiles/route.ts +177 -0
  357. package/src/modules/wms/api/listEnrichers.ts +312 -0
  358. package/src/modules/wms/api/listSearch.ts +121 -0
  359. package/src/modules/wms/api/locations/route.ts +171 -0
  360. package/src/modules/wms/api/lots/route.ts +205 -0
  361. package/src/modules/wms/api/openapi.ts +28 -0
  362. package/src/modules/wms/api/sales-orders/[salesOrderId]/re-run-reservation/route.ts +58 -0
  363. package/src/modules/wms/api/sales-orders/[salesOrderId]/warehouse-assignment/route.ts +306 -0
  364. package/src/modules/wms/api/sales-orders/assign-warehouse/route.ts +57 -0
  365. package/src/modules/wms/api/sales-orders/unassign-warehouse/route.ts +43 -0
  366. package/src/modules/wms/api/warehouses/route.ts +181 -0
  367. package/src/modules/wms/api/zones/route.ts +158 -0
  368. package/src/modules/wms/backend/config/wms/page.meta.ts +14 -0
  369. package/src/modules/wms/backend/config/wms/page.tsx +5 -0
  370. package/src/modules/wms/backend/page.meta.ts +12 -0
  371. package/src/modules/wms/backend/page.tsx +5 -0
  372. package/src/modules/wms/backend/wms/inventory/page.meta.ts +14 -0
  373. package/src/modules/wms/backend/wms/inventory/page.tsx +5 -0
  374. package/src/modules/wms/backend/wms/location/[id]/page.meta.ts +14 -0
  375. package/src/modules/wms/backend/wms/location/[id]/page.tsx +5 -0
  376. package/src/modules/wms/backend/wms/locations/page.meta.ts +14 -0
  377. package/src/modules/wms/backend/wms/locations/page.tsx +12 -0
  378. package/src/modules/wms/backend/wms/lot/[id]/page.meta.ts +14 -0
  379. package/src/modules/wms/backend/wms/lot/[id]/page.tsx +5 -0
  380. package/src/modules/wms/backend/wms/lots/page.meta.ts +14 -0
  381. package/src/modules/wms/backend/wms/lots/page.tsx +5 -0
  382. package/src/modules/wms/backend/wms/movements/page.meta.ts +14 -0
  383. package/src/modules/wms/backend/wms/movements/page.tsx +23 -0
  384. package/src/modules/wms/backend/wms/reservations/page.meta.ts +14 -0
  385. package/src/modules/wms/backend/wms/reservations/page.tsx +24 -0
  386. package/src/modules/wms/backend/wms/sku/[id]/page.meta.ts +14 -0
  387. package/src/modules/wms/backend/wms/sku/[id]/page.tsx +5 -0
  388. package/src/modules/wms/backend/wms/warehouses/page.meta.ts +14 -0
  389. package/src/modules/wms/backend/wms/warehouses/page.tsx +12 -0
  390. package/src/modules/wms/backend/wms/zones/page.meta.ts +14 -0
  391. package/src/modules/wms/backend/wms/zones/page.tsx +12 -0
  392. package/src/modules/wms/ce.ts +76 -0
  393. package/src/modules/wms/cli.ts +96 -0
  394. package/src/modules/wms/commands/configuration.ts +1844 -0
  395. package/src/modules/wms/commands/index.ts +3 -0
  396. package/src/modules/wms/commands/inventory-actions.ts +1866 -0
  397. package/src/modules/wms/commands/sales-order-assignment.ts +346 -0
  398. package/src/modules/wms/commands/shared.ts +90 -0
  399. package/src/modules/wms/components/backend/AdjustInventoryDialog.tsx +820 -0
  400. package/src/modules/wms/components/backend/ChangeLotStatusDialog.tsx +312 -0
  401. package/src/modules/wms/components/backend/CycleCountWizardDialog.tsx +2007 -0
  402. package/src/modules/wms/components/backend/ImportInventoryDialog.tsx +1018 -0
  403. package/src/modules/wms/components/backend/InventoryOperationsSection.tsx +159 -0
  404. package/src/modules/wms/components/backend/LocationEditDialog.tsx +185 -0
  405. package/src/modules/wms/components/backend/MoveInventoryDialog.tsx +907 -0
  406. package/src/modules/wms/components/backend/ReceiveInventoryDialog.tsx +695 -0
  407. package/src/modules/wms/components/backend/ReleaseReservationDialog.tsx +424 -0
  408. package/src/modules/wms/components/backend/ReserveInventoryDialog.tsx +511 -0
  409. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +1340 -0
  410. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +1132 -0
  411. package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +1310 -0
  412. package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +1355 -0
  413. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +359 -0
  414. package/src/modules/wms/components/backend/WmsOperationalDashboardPage.tsx +958 -0
  415. package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +1245 -0
  416. package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +960 -0
  417. package/src/modules/wms/components/backend/useWmsInventoryMutationAccess.ts +89 -0
  418. package/src/modules/wms/components/backend/useWmsInventoryScopeFromSearchParams.ts +32 -0
  419. package/src/modules/wms/components/backend/wmsLookupLoaders.ts +78 -0
  420. package/src/modules/wms/data/enrichers.ts +718 -0
  421. package/src/modules/wms/data/entities.ts +436 -0
  422. package/src/modules/wms/data/validators.ts +463 -0
  423. package/src/modules/wms/di.ts +25 -0
  424. package/src/modules/wms/events.ts +41 -0
  425. package/src/modules/wms/i18n/de.json +1051 -0
  426. package/src/modules/wms/i18n/en.json +1051 -0
  427. package/src/modules/wms/i18n/es.json +1051 -0
  428. package/src/modules/wms/i18n/pl.json +1051 -0
  429. package/src/modules/wms/index.ts +15 -0
  430. package/src/modules/wms/lib/catalogInventoryProfileIntent.ts +65 -0
  431. package/src/modules/wms/lib/catalogInventoryProfileSync.ts +199 -0
  432. package/src/modules/wms/lib/expiry.ts +30 -0
  433. package/src/modules/wms/lib/flashMutationError.ts +74 -0
  434. package/src/modules/wms/lib/inventoryDisplayUi.ts +249 -0
  435. package/src/modules/wms/lib/inventoryIdempotency.ts +54 -0
  436. package/src/modules/wms/lib/inventoryImportCsv.ts +212 -0
  437. package/src/modules/wms/lib/inventoryImportService.ts +629 -0
  438. package/src/modules/wms/lib/inventoryMutationUi.ts +21 -0
  439. package/src/modules/wms/lib/inventoryPolicy.ts +111 -0
  440. package/src/modules/wms/lib/inventoryReconciliation.ts +263 -0
  441. package/src/modules/wms/lib/inventoryTrackingValidation.ts +23 -0
  442. package/src/modules/wms/lib/loadOperationalDashboard.ts +776 -0
  443. package/src/modules/wms/lib/lowStockBalanceFilter.ts +74 -0
  444. package/src/modules/wms/lib/primaryWarehousePolicy.ts +46 -0
  445. package/src/modules/wms/lib/roleFeatures.ts +32 -0
  446. package/src/modules/wms/lib/salesOrderInventoryAutomation.ts +390 -0
  447. package/src/modules/wms/lib/salesOrderWarehouseAssignment.ts +78 -0
  448. package/src/modules/wms/lib/wmsIntegrationToggles.ts +81 -0
  449. package/src/modules/wms/migrations/.snapshot-open-mercato.json +2880 -0
  450. package/src/modules/wms/migrations/Migration20260428110546.ts +91 -0
  451. package/src/modules/wms/migrations/Migration20260527120000.ts +15 -0
  452. package/src/modules/wms/migrations/Migration20260527140000.ts +35 -0
  453. package/src/modules/wms/migrations/Migration20260613120000.ts +21 -0
  454. package/src/modules/wms/migrations/Migration20260616090000.ts +11 -0
  455. package/src/modules/wms/migrations/Migration20260707180000.ts +13 -0
  456. package/src/modules/wms/notifications.client.ts +18 -0
  457. package/src/modules/wms/notifications.ts +51 -0
  458. package/src/modules/wms/search.ts +230 -0
  459. package/src/modules/wms/setup.ts +29 -0
  460. package/src/modules/wms/subscribers/low-stock-notification.ts +54 -0
  461. package/src/modules/wms/subscribers/reservation-shortfall-notification.ts +98 -0
  462. package/src/modules/wms/subscribers/sales-order-cancelled-release.ts +21 -0
  463. package/src/modules/wms/subscribers/sales-order-confirmed-reserve.ts +21 -0
  464. package/src/modules/wms/translations.ts +6 -0
  465. package/src/modules/wms/vector.ts +7 -0
  466. package/src/modules/wms/widgets/injection/catalog-inventory-profile/widget.ts +238 -0
  467. package/src/modules/wms/widgets/injection/order-items-stock-column/widget.tsx +153 -0
  468. package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.client.tsx +476 -0
  469. package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.ts +15 -0
  470. package/src/modules/wms/widgets/injection-table.ts +34 -0
  471. package/src/modules/wms/widgets/notifications/WmsLowStockRenderer.tsx +153 -0
  472. package/src/modules/wms/widgets/notifications/WmsReservationShortfallRenderer.tsx +194 -0
  473. package/src/modules/wms/widgets/notifications/index.ts +2 -0
@@ -0,0 +1,580 @@
1
+ import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
+ import {
3
+ InventoryBalance,
4
+ InventoryLot,
5
+ InventoryMovement,
6
+ InventoryReservation,
7
+ ProductInventoryProfile,
8
+ Warehouse
9
+ } from "../data/entities.js";
10
+ import { evaluateLowStock } from "./inventoryPolicy.js";
11
+ import { addUtcDays, EXPIRING_SOON_DAYS, startOfUtcDay } from "./expiry.js";
12
+ const AGING_RESERVATION_DAYS = 7;
13
+ const TREND_DAYS = 7;
14
+ const MONTHLY_TREND_MONTHS = 6;
15
+ const ACTIVITY_LIMIT = 10;
16
+ const EXPIRY_CARD_LIMIT = 5;
17
+ class OperationalDashboardWarehouseNotFoundError extends Error {
18
+ constructor(warehouseId) {
19
+ super(`Warehouse ${warehouseId} not found`);
20
+ this.name = "OperationalDashboardWarehouseNotFoundError";
21
+ this.warehouseId = warehouseId;
22
+ }
23
+ }
24
+ function toOperationalDashboardNumber(value) {
25
+ if (typeof value === "number") return value;
26
+ if (typeof value === "string" && value.trim().length > 0) return Number(value);
27
+ return 0;
28
+ }
29
+ import { addUtcDays as addUtcDays2, startOfUtcDay as startOfUtcDay2 } from "./expiry.js";
30
+ function formatMonthKey(date) {
31
+ return date.toLocaleString("en-US", { month: "short", timeZone: "UTC" });
32
+ }
33
+ function buildDailyBuckets(days, now) {
34
+ const today = startOfUtcDay(now);
35
+ const buckets = [];
36
+ for (let offset = days - 1; offset >= 0; offset -= 1) {
37
+ buckets.push(addUtcDays(today, -offset));
38
+ }
39
+ return buckets;
40
+ }
41
+ function mapDailyCountsToSparkline(dayBuckets, rows) {
42
+ const counts = /* @__PURE__ */ new Map();
43
+ for (const bucket of dayBuckets) {
44
+ counts.set(bucket.getTime(), 0);
45
+ }
46
+ for (const row of rows) {
47
+ const day = startOfUtcDay(row.day instanceof Date ? row.day : new Date(row.day)).getTime();
48
+ if (counts.has(day)) {
49
+ counts.set(day, toOperationalDashboardNumber(row.count));
50
+ }
51
+ }
52
+ return dayBuckets.map((bucket) => counts.get(bucket.getTime()) ?? 0);
53
+ }
54
+ function resolveLotAvailableQuantity(lotId, balances, warehouseId) {
55
+ let total = 0;
56
+ for (const balance of balances) {
57
+ if (balance.lot?.id !== lotId) continue;
58
+ if (warehouseId && balance.warehouse.id !== warehouseId) continue;
59
+ const available = toOperationalDashboardNumber(balance.quantityOnHand) - toOperationalDashboardNumber(balance.quantityReserved) - toOperationalDashboardNumber(balance.quantityAllocated);
60
+ if (available > 0) total += available;
61
+ }
62
+ return total;
63
+ }
64
+ function buildExpiryLotRows(expiringSoonLots, pastDueLots, balances, warehouseId, limit = EXPIRY_CARD_LIMIT) {
65
+ const expiringRows = expiringSoonLots.map((lot) => ({
66
+ lot,
67
+ availableQuantity: resolveLotAvailableQuantity(lot.id, balances, warehouseId)
68
+ })).filter(({ availableQuantity }) => availableQuantity > 0).sort((left, right) => {
69
+ const leftTime = left.lot.expiresAt?.getTime() ?? 0;
70
+ const rightTime = right.lot.expiresAt?.getTime() ?? 0;
71
+ return leftTime - rightTime;
72
+ }).slice(0, limit).map(({ lot, availableQuantity }) => ({
73
+ id: lot.id,
74
+ lotNumber: lot.lotNumber,
75
+ sku: lot.sku,
76
+ catalogVariantId: lot.catalogVariantId,
77
+ expiresAt: lot.expiresAt.toISOString(),
78
+ availableQuantity,
79
+ status: lot.status,
80
+ updatedAt: lot.updatedAt?.toISOString() ?? null,
81
+ category: "expiringSoon"
82
+ }));
83
+ const pastDueRows = pastDueLots.map((lot) => ({
84
+ lot,
85
+ availableQuantity: resolveLotAvailableQuantity(lot.id, balances, warehouseId)
86
+ })).filter(({ availableQuantity }) => availableQuantity > 0).sort((left, right) => {
87
+ const leftTime = left.lot.expiresAt?.getTime() ?? 0;
88
+ const rightTime = right.lot.expiresAt?.getTime() ?? 0;
89
+ return leftTime - rightTime;
90
+ }).slice(0, limit).map(({ lot, availableQuantity }) => ({
91
+ id: lot.id,
92
+ lotNumber: lot.lotNumber,
93
+ sku: lot.sku,
94
+ catalogVariantId: lot.catalogVariantId,
95
+ expiresAt: lot.expiresAt.toISOString(),
96
+ availableQuantity,
97
+ status: lot.status,
98
+ updatedAt: lot.updatedAt?.toISOString() ?? null,
99
+ category: "pastDue"
100
+ }));
101
+ return [...expiringRows, ...pastDueRows];
102
+ }
103
+ function computeLowStockCounts(profiles, balances, warehouseId) {
104
+ const availableByVariantWarehouse = /* @__PURE__ */ new Map();
105
+ for (const balance of balances) {
106
+ const onHand = toOperationalDashboardNumber(balance.quantityOnHand);
107
+ const reserved = toOperationalDashboardNumber(balance.quantityReserved);
108
+ const allocated = toOperationalDashboardNumber(balance.quantityAllocated);
109
+ const available = onHand - reserved - allocated;
110
+ const key = `${balance.catalogVariantId}::${balance.warehouse.id}`;
111
+ availableByVariantWarehouse.set(key, (availableByVariantWarehouse.get(key) ?? 0) + available);
112
+ }
113
+ let lowStockCount = 0;
114
+ let reorderCriticalCount = 0;
115
+ const seenLowStockKeys = /* @__PURE__ */ new Set();
116
+ for (const profile of profiles) {
117
+ const variantId = profile.catalogVariantId;
118
+ if (!variantId) continue;
119
+ const reorderPoint = toOperationalDashboardNumber(profile.reorderPoint);
120
+ const safetyStock = toOperationalDashboardNumber(profile.safetyStock);
121
+ if (reorderPoint <= 0 && safetyStock <= 0) continue;
122
+ const warehouseIds = warehouseId ? [warehouseId] : Array.from(new Set(balances.map((balance) => balance.warehouse.id)));
123
+ for (const scopedWarehouseId of warehouseIds) {
124
+ const key = `${variantId}::${scopedWarehouseId}`;
125
+ const available = availableByVariantWarehouse.get(key) ?? 0;
126
+ const evaluation = evaluateLowStock(
127
+ { reorderPoint: profile.reorderPoint, safetyStock: profile.safetyStock },
128
+ available
129
+ );
130
+ if (!evaluation) continue;
131
+ if (seenLowStockKeys.has(key)) continue;
132
+ seenLowStockKeys.add(key);
133
+ lowStockCount += 1;
134
+ if (evaluation.state === "below_safety_stock") {
135
+ reorderCriticalCount += 1;
136
+ }
137
+ }
138
+ }
139
+ return { lowStockCount, reorderCriticalCount };
140
+ }
141
+ function resolveWarehouseLabel(warehouse, warehouseId) {
142
+ return warehouse?.code?.trim() || warehouse?.name?.trim() || warehouseId;
143
+ }
144
+ function resolveLocationLabel(warehouseLabel, fromCode, toCode) {
145
+ if (fromCode && toCode) return `${fromCode} \u2192 ${toCode}`;
146
+ if (toCode) return `${warehouseLabel} \xB7 ${toCode}`;
147
+ if (fromCode) return `${warehouseLabel} \xB7 ${fromCode}`;
148
+ return warehouseLabel;
149
+ }
150
+ function resolveDecryptionScope(scope) {
151
+ return {
152
+ tenantId: scope.tenantId,
153
+ organizationId: scope.organizationId
154
+ };
155
+ }
156
+ function appendWarehouseFilter(sql, params, warehouseId) {
157
+ if (!warehouseId) return sql;
158
+ params.push(warehouseId);
159
+ return `${sql} and warehouse_id = ?`;
160
+ }
161
+ async function loadVariantSkus(em, scope, variantIds) {
162
+ if (variantIds.length === 0) return /* @__PURE__ */ new Map();
163
+ const rows = await em.getConnection().execute(
164
+ `select id, sku from catalog_product_variants
165
+ where organization_id = ? and tenant_id = ? and id in (${variantIds.map(() => "?").join(", ")})
166
+ and deleted_at is null`,
167
+ [scope.organizationId, scope.tenantId, ...variantIds]
168
+ );
169
+ const map = /* @__PURE__ */ new Map();
170
+ for (const row of rows) {
171
+ if (row.id && row.sku) map.set(row.id, row.sku);
172
+ }
173
+ return map;
174
+ }
175
+ async function countMovementsBetween(em, scope, start, end, options) {
176
+ const params = [scope.organizationId, scope.tenantId, start, end];
177
+ let sql = `
178
+ select count(*)::int as count
179
+ from wms_inventory_movements
180
+ where organization_id = ? and tenant_id = ? and deleted_at is null
181
+ and performed_at >= ? and performed_at < ?
182
+ `;
183
+ sql = appendWarehouseFilter(sql, params, scope.warehouseId);
184
+ if (options?.types?.length) {
185
+ sql += ` and type in (${options.types.map(() => "?").join(", ")})`;
186
+ params.push(...options.types);
187
+ }
188
+ if (options?.quantitySign === "negative") {
189
+ sql += " and quantity < 0";
190
+ }
191
+ const rows = await em.getConnection().execute(sql, params);
192
+ return toOperationalDashboardNumber(rows[0]?.count);
193
+ }
194
+ async function loadMovementDailyCounts(em, scope, start, options) {
195
+ const params = [scope.organizationId, scope.tenantId, start];
196
+ let sql = `
197
+ select date_trunc('day', performed_at) as day, count(*)::int as count
198
+ from wms_inventory_movements
199
+ where organization_id = ? and tenant_id = ? and deleted_at is null
200
+ and performed_at >= ?
201
+ `;
202
+ sql = appendWarehouseFilter(sql, params, scope.warehouseId);
203
+ if (options?.types?.length) {
204
+ sql += ` and type in (${options.types.map(() => "?").join(", ")})`;
205
+ params.push(...options.types);
206
+ }
207
+ if (options?.quantitySign === "negative") {
208
+ sql += " and quantity < 0";
209
+ }
210
+ sql += " group by 1 order by 1";
211
+ return em.getConnection().execute(sql, params);
212
+ }
213
+ async function loadMonthlyMovementTrends(em, scope, monthlyStart, now) {
214
+ const params = [scope.organizationId, scope.tenantId, monthlyStart];
215
+ let sql = `
216
+ select date_trunc('month', performed_at) as month_start, type, count(*)::int as count
217
+ from wms_inventory_movements
218
+ where organization_id = ? and tenant_id = ? and deleted_at is null
219
+ and performed_at >= ?
220
+ `;
221
+ sql = appendWarehouseFilter(sql, params, scope.warehouseId);
222
+ sql += " group by 1, 2 order by 1";
223
+ const rows = await em.getConnection().execute(sql, params);
224
+ const monthlyTrendMap = /* @__PURE__ */ new Map();
225
+ for (let index = 0; index < MONTHLY_TREND_MONTHS; index += 1) {
226
+ const monthDate = new Date(
227
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (MONTHLY_TREND_MONTHS - 1 - index), 1)
228
+ );
229
+ monthlyTrendMap.set(formatMonthKey(monthDate), { receive: 0, allocate: 0 });
230
+ }
231
+ for (const row of rows) {
232
+ const monthDate = row.month_start instanceof Date ? row.month_start : new Date(row.month_start);
233
+ const key = formatMonthKey(monthDate);
234
+ const bucket = monthlyTrendMap.get(key);
235
+ if (!bucket) continue;
236
+ if (row.type === "receipt" || row.type === "return_receive") {
237
+ bucket.receive += toOperationalDashboardNumber(row.count);
238
+ }
239
+ if (row.type === "pick" || row.type === "pack") {
240
+ bucket.allocate += toOperationalDashboardNumber(row.count);
241
+ }
242
+ }
243
+ return Array.from(monthlyTrendMap.entries()).map(([month, values]) => ({
244
+ month,
245
+ receive: values.receive,
246
+ allocate: values.allocate
247
+ }));
248
+ }
249
+ async function loadExpiringSoonDailyCounts(em, scope, dayBuckets) {
250
+ if (dayBuckets.length === 0) return [];
251
+ const trendStart = dayBuckets[0];
252
+ const trendEnd = dayBuckets[dayBuckets.length - 1];
253
+ const params = [
254
+ trendStart,
255
+ trendEnd,
256
+ scope.organizationId,
257
+ scope.tenantId
258
+ ];
259
+ let sql = `
260
+ select bucket.day as day, count(distinct l.id)::int as count
261
+ from (
262
+ select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day
263
+ ) bucket
264
+ join wms_inventory_lots l
265
+ on l.organization_id = ?
266
+ and l.tenant_id = ?
267
+ and l.deleted_at is null
268
+ and l.status = 'available'
269
+ and l.expires_at is not null
270
+ and l.expires_at >= bucket.day
271
+ and l.expires_at <= bucket.day + interval '${EXPIRING_SOON_DAYS} days'
272
+ `;
273
+ if (scope.warehouseId) {
274
+ sql += `
275
+ join wms_inventory_balances b
276
+ on b.lot_id = l.id
277
+ and b.deleted_at is null
278
+ and b.warehouse_id = ?
279
+ `;
280
+ params.push(scope.warehouseId);
281
+ }
282
+ sql += " group by bucket.day order by bucket.day";
283
+ return em.getConnection().execute(sql, params);
284
+ }
285
+ async function loadPastDueLotCount(em, scope, todayStart) {
286
+ const params = [scope.organizationId, scope.tenantId, todayStart];
287
+ let sql = `
288
+ select count(distinct l.id)::int as count
289
+ from wms_inventory_lots l
290
+ join wms_inventory_balances b
291
+ on b.lot_id = l.id
292
+ and b.deleted_at is null
293
+ and (
294
+ coalesce(b.quantity_on_hand, 0)
295
+ - coalesce(b.quantity_reserved, 0)
296
+ - coalesce(b.quantity_allocated, 0)
297
+ ) > 0
298
+ where l.organization_id = ?
299
+ and l.tenant_id = ?
300
+ and l.deleted_at is null
301
+ and l.status = 'available'
302
+ and l.expires_at is not null
303
+ and l.expires_at < ?
304
+ `;
305
+ if (scope.warehouseId) {
306
+ sql += " and b.warehouse_id = ?";
307
+ params.push(scope.warehouseId);
308
+ }
309
+ const rows = await em.getConnection().execute(sql, params);
310
+ return toOperationalDashboardNumber(rows[0]?.count);
311
+ }
312
+ async function loadPastDueDailyCounts(em, scope, dayBuckets) {
313
+ if (dayBuckets.length === 0) return [];
314
+ const params = [
315
+ dayBuckets[0],
316
+ dayBuckets[dayBuckets.length - 1],
317
+ scope.organizationId,
318
+ scope.tenantId
319
+ ];
320
+ let sql = `
321
+ select bucket.day as day, count(distinct l.id)::int as count
322
+ from (
323
+ select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day
324
+ ) bucket
325
+ join wms_inventory_lots l
326
+ on l.organization_id = ?
327
+ and l.tenant_id = ?
328
+ and l.deleted_at is null
329
+ and l.status = 'available'
330
+ and l.expires_at is not null
331
+ and l.expires_at < bucket.day
332
+ join wms_inventory_balances b
333
+ on b.lot_id = l.id
334
+ and b.deleted_at is null
335
+ and (
336
+ coalesce(b.quantity_on_hand, 0)
337
+ - coalesce(b.quantity_reserved, 0)
338
+ - coalesce(b.quantity_allocated, 0)
339
+ ) > 0
340
+ `;
341
+ if (scope.warehouseId) {
342
+ sql += " and b.warehouse_id = ?";
343
+ params.push(scope.warehouseId);
344
+ }
345
+ sql += " group by bucket.day order by bucket.day";
346
+ return em.getConnection().execute(sql, params);
347
+ }
348
+ async function loadAgingReservationsDailyCounts(em, scope, dayBuckets) {
349
+ if (dayBuckets.length === 0) return [];
350
+ const params = [
351
+ dayBuckets[0],
352
+ dayBuckets[dayBuckets.length - 1],
353
+ scope.organizationId,
354
+ scope.tenantId,
355
+ String(AGING_RESERVATION_DAYS)
356
+ ];
357
+ let sql = `
358
+ select bucket.day as day, count(r.id)::int as count
359
+ from (
360
+ select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day
361
+ ) bucket
362
+ join wms_inventory_reservations r
363
+ on r.organization_id = ?
364
+ and r.tenant_id = ?
365
+ and r.deleted_at is null
366
+ and r.status = 'active'
367
+ and r.created_at <= bucket.day - (?::int * interval '1 day')
368
+ `;
369
+ sql = appendWarehouseFilter(sql, params, scope.warehouseId);
370
+ sql += " group by bucket.day order by bucket.day";
371
+ return em.getConnection().execute(sql, params);
372
+ }
373
+ async function loadOperationalDashboard(em, scope) {
374
+ const now = /* @__PURE__ */ new Date();
375
+ const todayStart = startOfUtcDay(now);
376
+ const tomorrowStart = addUtcDays(todayStart, 1);
377
+ const yesterdayStart = addUtcDays(todayStart, -1);
378
+ const agingCutoff = addUtcDays(todayStart, -AGING_RESERVATION_DAYS);
379
+ const expiringCutoff = addUtcDays(todayStart, EXPIRING_SOON_DAYS);
380
+ const trendStart = addUtcDays(todayStart, -(TREND_DAYS - 1));
381
+ const dayBuckets = buildDailyBuckets(TREND_DAYS, now);
382
+ const decryptionScope = resolveDecryptionScope(scope);
383
+ const baseScope = {
384
+ organizationId: scope.organizationId,
385
+ tenantId: scope.tenantId,
386
+ deletedAt: null
387
+ };
388
+ if (scope.warehouseId) {
389
+ const warehouse = await findOneWithDecryption(
390
+ em,
391
+ Warehouse,
392
+ { id: scope.warehouseId, ...baseScope },
393
+ void 0,
394
+ decryptionScope
395
+ );
396
+ if (!warehouse) {
397
+ throw new OperationalDashboardWarehouseNotFoundError(scope.warehouseId);
398
+ }
399
+ }
400
+ const warehouseFilter = scope.warehouseId ? { warehouse: scope.warehouseId } : {};
401
+ const [profiles, balances, expiringSoonLots, pastDueLots, reservations, activityMovements] = await Promise.all([
402
+ findWithDecryption(em, ProductInventoryProfile, baseScope, void 0, decryptionScope),
403
+ findWithDecryption(
404
+ em,
405
+ InventoryBalance,
406
+ { ...baseScope, ...warehouseFilter },
407
+ { populate: ["warehouse", "location", "lot"] },
408
+ decryptionScope
409
+ ),
410
+ findWithDecryption(
411
+ em,
412
+ InventoryLot,
413
+ {
414
+ ...baseScope,
415
+ status: "available",
416
+ expiresAt: { $ne: null, $gte: todayStart, $lte: expiringCutoff }
417
+ },
418
+ { orderBy: { expiresAt: "ASC" }, limit: 100 },
419
+ decryptionScope
420
+ ),
421
+ findWithDecryption(
422
+ em,
423
+ InventoryLot,
424
+ {
425
+ ...baseScope,
426
+ status: "available",
427
+ expiresAt: { $ne: null, $lt: todayStart }
428
+ },
429
+ { orderBy: { expiresAt: "ASC" }, limit: 100 },
430
+ decryptionScope
431
+ ),
432
+ findWithDecryption(
433
+ em,
434
+ InventoryReservation,
435
+ {
436
+ ...baseScope,
437
+ ...warehouseFilter,
438
+ status: "active",
439
+ createdAt: { $lte: agingCutoff }
440
+ },
441
+ void 0,
442
+ decryptionScope
443
+ ),
444
+ findWithDecryption(
445
+ em,
446
+ InventoryMovement,
447
+ { ...baseScope, ...warehouseFilter },
448
+ {
449
+ populate: ["warehouse", "locationFrom", "locationTo"],
450
+ orderBy: { performedAt: "DESC" },
451
+ limit: ACTIVITY_LIMIT
452
+ },
453
+ decryptionScope
454
+ )
455
+ ]);
456
+ const { lowStockCount, reorderCriticalCount } = computeLowStockCounts(
457
+ profiles,
458
+ balances,
459
+ scope.warehouseId
460
+ );
461
+ const expiringSoonCount = expiringSoonLots.filter(
462
+ (lot) => resolveLotAvailableQuantity(lot.id, balances, scope.warehouseId) > 0
463
+ ).length;
464
+ const agingReservationsCount = reservations.length;
465
+ const [
466
+ todaysMoveCount,
467
+ yesterdaysMoveCount,
468
+ pastDueCount,
469
+ lowStockSparklineRows,
470
+ reorderCriticalSparklineRows,
471
+ expiringSoonSparklineRows,
472
+ pastDueSparklineRows,
473
+ agingReservationsSparklineRows,
474
+ todaysMovesSparklineRows,
475
+ monthlyTrends
476
+ ] = await Promise.all([
477
+ countMovementsBetween(em, scope, todayStart, tomorrowStart),
478
+ countMovementsBetween(em, scope, yesterdayStart, todayStart),
479
+ loadPastDueLotCount(em, scope, todayStart),
480
+ loadMovementDailyCounts(em, scope, trendStart, { types: ["adjust"], quantitySign: "negative" }),
481
+ loadMovementDailyCounts(em, scope, trendStart, { types: ["adjust"], quantitySign: "negative" }),
482
+ loadExpiringSoonDailyCounts(em, scope, dayBuckets),
483
+ loadPastDueDailyCounts(em, scope, dayBuckets),
484
+ loadAgingReservationsDailyCounts(em, scope, dayBuckets),
485
+ loadMovementDailyCounts(em, scope, trendStart),
486
+ loadMonthlyMovementTrends(
487
+ em,
488
+ scope,
489
+ new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (MONTHLY_TREND_MONTHS - 1), 1)),
490
+ now
491
+ )
492
+ ]);
493
+ const kpis = [
494
+ {
495
+ id: "lowStock",
496
+ count: lowStockCount,
497
+ deltaSinceYesterday: null,
498
+ sparkline: mapDailyCountsToSparkline(dayBuckets, lowStockSparklineRows)
499
+ },
500
+ {
501
+ id: "reorderCritical",
502
+ count: reorderCriticalCount,
503
+ deltaSinceYesterday: null,
504
+ sparkline: mapDailyCountsToSparkline(dayBuckets, reorderCriticalSparklineRows)
505
+ },
506
+ {
507
+ id: "expiringSoon",
508
+ count: expiringSoonCount,
509
+ deltaSinceYesterday: null,
510
+ sparkline: mapDailyCountsToSparkline(dayBuckets, expiringSoonSparklineRows)
511
+ },
512
+ {
513
+ id: "pastDue",
514
+ count: pastDueCount,
515
+ deltaSinceYesterday: null,
516
+ sparkline: mapDailyCountsToSparkline(dayBuckets, pastDueSparklineRows)
517
+ },
518
+ {
519
+ id: "agingReservations",
520
+ count: agingReservationsCount,
521
+ deltaSinceYesterday: null,
522
+ sparkline: mapDailyCountsToSparkline(dayBuckets, agingReservationsSparklineRows)
523
+ },
524
+ {
525
+ id: "todaysMoves",
526
+ count: todaysMoveCount,
527
+ deltaSinceYesterday: todaysMoveCount - yesterdaysMoveCount,
528
+ sparkline: mapDailyCountsToSparkline(dayBuckets, todaysMovesSparklineRows)
529
+ }
530
+ ];
531
+ const variantIds = Array.from(new Set(activityMovements.map((movement) => movement.catalogVariantId)));
532
+ const variantSkus = await loadVariantSkus(em, scope, variantIds);
533
+ const recentActivity = activityMovements.map((movement) => {
534
+ const warehouseLabel = resolveWarehouseLabel(movement.warehouse, movement.warehouse.id);
535
+ return {
536
+ id: movement.id,
537
+ movementType: movement.type,
538
+ quantity: toOperationalDashboardNumber(movement.quantity),
539
+ variantSku: variantSkus.get(movement.catalogVariantId) ?? null,
540
+ variantId: movement.catalogVariantId,
541
+ referenceType: movement.referenceType ?? null,
542
+ referenceId: movement.referenceId ?? null,
543
+ reason: movement.reason ?? null,
544
+ reasonCode: movement.reasonCode ?? null,
545
+ locationLabel: resolveLocationLabel(
546
+ warehouseLabel,
547
+ movement.locationFrom?.code,
548
+ movement.locationTo?.code
549
+ ),
550
+ performedAt: movement.performedAt.toISOString()
551
+ };
552
+ });
553
+ const expiryLots = buildExpiryLotRows(
554
+ expiringSoonLots,
555
+ pastDueLots,
556
+ balances,
557
+ scope.warehouseId
558
+ );
559
+ return {
560
+ lastUpdatedAt: now.toISOString(),
561
+ warehouseId: scope.warehouseId ?? null,
562
+ kpis,
563
+ expiryLots,
564
+ monthlyTrends,
565
+ recentActivity
566
+ };
567
+ }
568
+ export {
569
+ OperationalDashboardWarehouseNotFoundError,
570
+ addUtcDays2 as addUtcDays,
571
+ buildDailyBuckets,
572
+ buildExpiryLotRows,
573
+ computeLowStockCounts,
574
+ loadOperationalDashboard,
575
+ mapDailyCountsToSparkline,
576
+ resolveLotAvailableQuantity,
577
+ startOfUtcDay2 as startOfUtcDay,
578
+ toOperationalDashboardNumber
579
+ };
580
+ //# sourceMappingURL=loadOperationalDashboard.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/wms/lib/loadOperationalDashboard.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n InventoryBalance,\n InventoryLot,\n InventoryMovement,\n InventoryReservation,\n ProductInventoryProfile,\n Warehouse,\n} from '../data/entities'\nimport { evaluateLowStock } from './inventoryPolicy'\nimport { addUtcDays, EXPIRING_SOON_DAYS, startOfUtcDay } from './expiry'\n\nconst AGING_RESERVATION_DAYS = 7\nconst TREND_DAYS = 7\nconst MONTHLY_TREND_MONTHS = 6\nconst ACTIVITY_LIMIT = 10\nconst EXPIRY_CARD_LIMIT = 5\n\nexport type OperationalDashboardScope = {\n organizationId: string\n tenantId: string\n warehouseId?: string | null\n}\n\nexport type OperationalDashboardKpiId =\n | 'lowStock'\n | 'reorderCritical'\n | 'expiringSoon'\n | 'pastDue'\n | 'agingReservations'\n | 'todaysMoves'\n\nexport type OperationalDashboardKpi = {\n id: OperationalDashboardKpiId\n count: number\n deltaSinceYesterday: number | null\n sparkline: number[]\n}\n\nexport type OperationalDashboardTrendPoint = {\n month: string\n receive: number\n allocate: number\n}\n\nexport type OperationalDashboardActivityRow = {\n id: string\n movementType: string\n quantity: number\n variantSku: string | null\n variantId: string\n referenceType: string | null\n referenceId: string | null\n reason: string | null\n reasonCode: string | null\n locationLabel: string\n performedAt: string\n}\n\nexport type OperationalDashboardExpiryLotRow = {\n id: string\n lotNumber: string\n sku: string\n catalogVariantId: string\n expiresAt: string\n availableQuantity: number\n status: string\n updatedAt: string | null\n category: 'expiringSoon' | 'pastDue'\n}\n\nexport type OperationalDashboardPayload = {\n lastUpdatedAt: string\n warehouseId: string | null\n kpis: OperationalDashboardKpi[]\n expiryLots: OperationalDashboardExpiryLotRow[]\n monthlyTrends: OperationalDashboardTrendPoint[]\n recentActivity: OperationalDashboardActivityRow[]\n}\n\nexport class OperationalDashboardWarehouseNotFoundError extends Error {\n readonly warehouseId: string\n\n constructor(warehouseId: string) {\n super(`Warehouse ${warehouseId} not found`)\n this.name = 'OperationalDashboardWarehouseNotFoundError'\n this.warehouseId = warehouseId\n }\n}\n\ntype DecryptionScope = {\n tenantId: string\n organizationId: string\n}\n\ntype DailyCountRow = {\n day: Date | string\n count: string | number\n}\n\ntype MonthlyTrendRow = {\n month_start: Date | string\n type: string\n count: string | number\n}\n\nexport function toOperationalDashboardNumber(value: string | number | null | undefined): number {\n if (typeof value === 'number') return value\n if (typeof value === 'string' && value.trim().length > 0) return Number(value)\n return 0\n}\n\nexport { addUtcDays, startOfUtcDay } from './expiry'\n\nfunction formatMonthKey(date: Date): string {\n return date.toLocaleString('en-US', { month: 'short', timeZone: 'UTC' })\n}\n\nexport function buildDailyBuckets(days: number, now: Date): Date[] {\n const today = startOfUtcDay(now)\n const buckets: Date[] = []\n for (let offset = days - 1; offset >= 0; offset -= 1) {\n buckets.push(addUtcDays(today, -offset))\n }\n return buckets\n}\n\nexport function mapDailyCountsToSparkline(\n dayBuckets: Date[],\n rows: Array<{ day: Date | string; count: string | number }>,\n): number[] {\n const counts = new Map<number, number>()\n for (const bucket of dayBuckets) {\n counts.set(bucket.getTime(), 0)\n }\n for (const row of rows) {\n const day = startOfUtcDay(row.day instanceof Date ? row.day : new Date(row.day)).getTime()\n if (counts.has(day)) {\n counts.set(day, toOperationalDashboardNumber(row.count))\n }\n }\n return dayBuckets.map((bucket) => counts.get(bucket.getTime()) ?? 0)\n}\n\nexport function resolveLotAvailableQuantity(\n lotId: string,\n balances: InventoryBalance[],\n warehouseId?: string | null,\n): number {\n let total = 0\n for (const balance of balances) {\n if (balance.lot?.id !== lotId) continue\n if (warehouseId && balance.warehouse.id !== warehouseId) continue\n const available =\n toOperationalDashboardNumber(balance.quantityOnHand)\n - toOperationalDashboardNumber(balance.quantityReserved)\n - toOperationalDashboardNumber(balance.quantityAllocated)\n if (available > 0) total += available\n }\n return total\n}\n\nexport function buildExpiryLotRows(\n expiringSoonLots: InventoryLot[],\n pastDueLots: InventoryLot[],\n balances: InventoryBalance[],\n warehouseId?: string | null,\n limit = EXPIRY_CARD_LIMIT,\n): OperationalDashboardExpiryLotRow[] {\n const expiringRows = expiringSoonLots\n .map((lot) => ({\n lot,\n availableQuantity: resolveLotAvailableQuantity(lot.id, balances, warehouseId),\n }))\n .filter(({ availableQuantity }) => availableQuantity > 0)\n .sort((left, right) => {\n const leftTime = left.lot.expiresAt?.getTime() ?? 0\n const rightTime = right.lot.expiresAt?.getTime() ?? 0\n return leftTime - rightTime\n })\n .slice(0, limit)\n .map(({ lot, availableQuantity }) => ({\n id: lot.id,\n lotNumber: lot.lotNumber,\n sku: lot.sku,\n catalogVariantId: lot.catalogVariantId,\n expiresAt: lot.expiresAt!.toISOString(),\n availableQuantity,\n status: lot.status,\n updatedAt: lot.updatedAt?.toISOString() ?? null,\n category: 'expiringSoon' as const,\n }))\n\n const pastDueRows = pastDueLots\n .map((lot) => ({\n lot,\n availableQuantity: resolveLotAvailableQuantity(lot.id, balances, warehouseId),\n }))\n .filter(({ availableQuantity }) => availableQuantity > 0)\n .sort((left, right) => {\n const leftTime = left.lot.expiresAt?.getTime() ?? 0\n const rightTime = right.lot.expiresAt?.getTime() ?? 0\n return leftTime - rightTime\n })\n .slice(0, limit)\n .map(({ lot, availableQuantity }) => ({\n id: lot.id,\n lotNumber: lot.lotNumber,\n sku: lot.sku,\n catalogVariantId: lot.catalogVariantId,\n expiresAt: lot.expiresAt!.toISOString(),\n availableQuantity,\n status: lot.status,\n updatedAt: lot.updatedAt?.toISOString() ?? null,\n category: 'pastDue' as const,\n }))\n\n return [...expiringRows, ...pastDueRows]\n}\n\nexport function computeLowStockCounts(\n profiles: ProductInventoryProfile[],\n balances: InventoryBalance[],\n warehouseId?: string | null,\n): { lowStockCount: number; reorderCriticalCount: number } {\n const availableByVariantWarehouse = new Map<string, number>()\n for (const balance of balances) {\n const onHand = toOperationalDashboardNumber(balance.quantityOnHand)\n const reserved = toOperationalDashboardNumber(balance.quantityReserved)\n const allocated = toOperationalDashboardNumber(balance.quantityAllocated)\n const available = onHand - reserved - allocated\n const key = `${balance.catalogVariantId}::${balance.warehouse.id}`\n availableByVariantWarehouse.set(key, (availableByVariantWarehouse.get(key) ?? 0) + available)\n }\n\n let lowStockCount = 0\n let reorderCriticalCount = 0\n const seenLowStockKeys = new Set<string>()\n\n for (const profile of profiles) {\n const variantId = profile.catalogVariantId\n if (!variantId) continue\n const reorderPoint = toOperationalDashboardNumber(profile.reorderPoint)\n const safetyStock = toOperationalDashboardNumber(profile.safetyStock)\n if (reorderPoint <= 0 && safetyStock <= 0) continue\n\n const warehouseIds = warehouseId\n ? [warehouseId]\n : Array.from(new Set(balances.map((balance) => balance.warehouse.id)))\n\n for (const scopedWarehouseId of warehouseIds) {\n const key = `${variantId}::${scopedWarehouseId}`\n const available = availableByVariantWarehouse.get(key) ?? 0\n const evaluation = evaluateLowStock(\n { reorderPoint: profile.reorderPoint, safetyStock: profile.safetyStock },\n available,\n )\n if (!evaluation) continue\n if (seenLowStockKeys.has(key)) continue\n seenLowStockKeys.add(key)\n lowStockCount += 1\n if (evaluation.state === 'below_safety_stock') {\n reorderCriticalCount += 1\n }\n }\n }\n\n return { lowStockCount, reorderCriticalCount }\n}\n\nfunction resolveWarehouseLabel(\n warehouse: Warehouse | undefined,\n warehouseId: string,\n): string {\n return warehouse?.code?.trim() || warehouse?.name?.trim() || warehouseId\n}\n\nfunction resolveLocationLabel(\n warehouseLabel: string,\n fromCode?: string | null,\n toCode?: string | null,\n): string {\n if (fromCode && toCode) return `${fromCode} \u2192 ${toCode}`\n if (toCode) return `${warehouseLabel} \u00B7 ${toCode}`\n if (fromCode) return `${warehouseLabel} \u00B7 ${fromCode}`\n return warehouseLabel\n}\n\nfunction resolveDecryptionScope(scope: OperationalDashboardScope): DecryptionScope {\n return {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }\n}\n\nfunction appendWarehouseFilter(\n sql: string,\n params: unknown[],\n warehouseId?: string | null,\n): string {\n if (!warehouseId) return sql\n params.push(warehouseId)\n return `${sql} and warehouse_id = ?`\n}\n\nasync function loadVariantSkus(\n em: EntityManager,\n scope: OperationalDashboardScope,\n variantIds: string[],\n): Promise<Map<string, string>> {\n if (variantIds.length === 0) return new Map()\n const rows = await em.getConnection().execute<Array<{ id: string; sku: string | null }>>(\n `select id, sku from catalog_product_variants\n where organization_id = ? and tenant_id = ? and id in (${variantIds.map(() => '?').join(', ')})\n and deleted_at is null`,\n [scope.organizationId, scope.tenantId, ...variantIds],\n )\n const map = new Map<string, string>()\n for (const row of rows) {\n if (row.id && row.sku) map.set(row.id, row.sku)\n }\n return map\n}\n\nasync function countMovementsBetween(\n em: EntityManager,\n scope: OperationalDashboardScope,\n start: Date,\n end: Date,\n options?: { types?: string[]; quantitySign?: 'negative' },\n): Promise<number> {\n const params: unknown[] = [scope.organizationId, scope.tenantId, start, end]\n let sql = `\n select count(*)::int as count\n from wms_inventory_movements\n where organization_id = ? and tenant_id = ? and deleted_at is null\n and performed_at >= ? and performed_at < ?\n `\n sql = appendWarehouseFilter(sql, params, scope.warehouseId)\n if (options?.types?.length) {\n sql += ` and type in (${options.types.map(() => '?').join(', ')})`\n params.push(...options.types)\n }\n if (options?.quantitySign === 'negative') {\n sql += ' and quantity < 0'\n }\n const rows = await em.getConnection().execute<Array<{ count: string | number }>>(sql, params)\n return toOperationalDashboardNumber(rows[0]?.count)\n}\n\nasync function loadMovementDailyCounts(\n em: EntityManager,\n scope: OperationalDashboardScope,\n start: Date,\n options?: { types?: string[]; quantitySign?: 'negative' },\n): Promise<DailyCountRow[]> {\n const params: unknown[] = [scope.organizationId, scope.tenantId, start]\n let sql = `\n select date_trunc('day', performed_at) as day, count(*)::int as count\n from wms_inventory_movements\n where organization_id = ? and tenant_id = ? and deleted_at is null\n and performed_at >= ?\n `\n sql = appendWarehouseFilter(sql, params, scope.warehouseId)\n if (options?.types?.length) {\n sql += ` and type in (${options.types.map(() => '?').join(', ')})`\n params.push(...options.types)\n }\n if (options?.quantitySign === 'negative') {\n sql += ' and quantity < 0'\n }\n sql += ' group by 1 order by 1'\n return em.getConnection().execute<DailyCountRow[]>(sql, params)\n}\n\nasync function loadMonthlyMovementTrends(\n em: EntityManager,\n scope: OperationalDashboardScope,\n monthlyStart: Date,\n now: Date,\n): Promise<OperationalDashboardTrendPoint[]> {\n const params: unknown[] = [scope.organizationId, scope.tenantId, monthlyStart]\n let sql = `\n select date_trunc('month', performed_at) as month_start, type, count(*)::int as count\n from wms_inventory_movements\n where organization_id = ? and tenant_id = ? and deleted_at is null\n and performed_at >= ?\n `\n sql = appendWarehouseFilter(sql, params, scope.warehouseId)\n sql += ' group by 1, 2 order by 1'\n\n const rows = await em.getConnection().execute<MonthlyTrendRow[]>(sql, params)\n const monthlyTrendMap = new Map<string, { receive: number; allocate: number }>()\n for (let index = 0; index < MONTHLY_TREND_MONTHS; index += 1) {\n const monthDate = new Date(\n Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (MONTHLY_TREND_MONTHS - 1 - index), 1),\n )\n monthlyTrendMap.set(formatMonthKey(monthDate), { receive: 0, allocate: 0 })\n }\n\n for (const row of rows) {\n const monthDate = row.month_start instanceof Date ? row.month_start : new Date(row.month_start)\n const key = formatMonthKey(monthDate)\n const bucket = monthlyTrendMap.get(key)\n if (!bucket) continue\n if (row.type === 'receipt' || row.type === 'return_receive') {\n bucket.receive += toOperationalDashboardNumber(row.count)\n }\n if (row.type === 'pick' || row.type === 'pack') {\n bucket.allocate += toOperationalDashboardNumber(row.count)\n }\n }\n\n return Array.from(monthlyTrendMap.entries()).map(([month, values]) => ({\n month,\n receive: values.receive,\n allocate: values.allocate,\n }))\n}\n\nasync function loadExpiringSoonDailyCounts(\n em: EntityManager,\n scope: OperationalDashboardScope,\n dayBuckets: Date[],\n): Promise<DailyCountRow[]> {\n if (dayBuckets.length === 0) return []\n const trendStart = dayBuckets[0]!\n const trendEnd = dayBuckets[dayBuckets.length - 1]!\n const params: unknown[] = [\n trendStart,\n trendEnd,\n scope.organizationId,\n scope.tenantId,\n ]\n let sql = `\n select bucket.day as day, count(distinct l.id)::int as count\n from (\n select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day\n ) bucket\n join wms_inventory_lots l\n on l.organization_id = ?\n and l.tenant_id = ?\n and l.deleted_at is null\n and l.status = 'available'\n and l.expires_at is not null\n and l.expires_at >= bucket.day\n and l.expires_at <= bucket.day + interval '${EXPIRING_SOON_DAYS} days'\n `\n if (scope.warehouseId) {\n sql += `\n join wms_inventory_balances b\n on b.lot_id = l.id\n and b.deleted_at is null\n and b.warehouse_id = ?\n `\n params.push(scope.warehouseId)\n }\n sql += ' group by bucket.day order by bucket.day'\n return em.getConnection().execute<DailyCountRow[]>(sql, params)\n}\n\nasync function loadPastDueLotCount(\n em: EntityManager,\n scope: OperationalDashboardScope,\n todayStart: Date,\n): Promise<number> {\n const params: unknown[] = [scope.organizationId, scope.tenantId, todayStart]\n let sql = `\n select count(distinct l.id)::int as count\n from wms_inventory_lots l\n join wms_inventory_balances b\n on b.lot_id = l.id\n and b.deleted_at is null\n and (\n coalesce(b.quantity_on_hand, 0)\n - coalesce(b.quantity_reserved, 0)\n - coalesce(b.quantity_allocated, 0)\n ) > 0\n where l.organization_id = ?\n and l.tenant_id = ?\n and l.deleted_at is null\n and l.status = 'available'\n and l.expires_at is not null\n and l.expires_at < ?\n `\n if (scope.warehouseId) {\n sql += ' and b.warehouse_id = ?'\n params.push(scope.warehouseId)\n }\n const rows = await em.getConnection().execute<Array<{ count: string | number }>>(sql, params)\n return toOperationalDashboardNumber(rows[0]?.count)\n}\n\nasync function loadPastDueDailyCounts(\n em: EntityManager,\n scope: OperationalDashboardScope,\n dayBuckets: Date[],\n): Promise<DailyCountRow[]> {\n if (dayBuckets.length === 0) return []\n const params: unknown[] = [\n dayBuckets[0]!,\n dayBuckets[dayBuckets.length - 1]!,\n scope.organizationId,\n scope.tenantId,\n ]\n let sql = `\n select bucket.day as day, count(distinct l.id)::int as count\n from (\n select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day\n ) bucket\n join wms_inventory_lots l\n on l.organization_id = ?\n and l.tenant_id = ?\n and l.deleted_at is null\n and l.status = 'available'\n and l.expires_at is not null\n and l.expires_at < bucket.day\n join wms_inventory_balances b\n on b.lot_id = l.id\n and b.deleted_at is null\n and (\n coalesce(b.quantity_on_hand, 0)\n - coalesce(b.quantity_reserved, 0)\n - coalesce(b.quantity_allocated, 0)\n ) > 0\n `\n if (scope.warehouseId) {\n sql += ' and b.warehouse_id = ?'\n params.push(scope.warehouseId)\n }\n sql += ' group by bucket.day order by bucket.day'\n return em.getConnection().execute<DailyCountRow[]>(sql, params)\n}\n\nasync function loadAgingReservationsDailyCounts(\n em: EntityManager,\n scope: OperationalDashboardScope,\n dayBuckets: Date[],\n): Promise<DailyCountRow[]> {\n if (dayBuckets.length === 0) return []\n const params: unknown[] = [\n dayBuckets[0]!,\n dayBuckets[dayBuckets.length - 1]!,\n scope.organizationId,\n scope.tenantId,\n String(AGING_RESERVATION_DAYS),\n ]\n let sql = `\n select bucket.day as day, count(r.id)::int as count\n from (\n select generate_series(?::timestamptz, ?::timestamptz, interval '1 day') as day\n ) bucket\n join wms_inventory_reservations r\n on r.organization_id = ?\n and r.tenant_id = ?\n and r.deleted_at is null\n and r.status = 'active'\n and r.created_at <= bucket.day - (?::int * interval '1 day')\n `\n sql = appendWarehouseFilter(sql, params, scope.warehouseId)\n sql += ' group by bucket.day order by bucket.day'\n return em.getConnection().execute<DailyCountRow[]>(sql, params)\n}\n\nexport async function loadOperationalDashboard(\n em: EntityManager,\n scope: OperationalDashboardScope,\n): Promise<OperationalDashboardPayload> {\n const now = new Date()\n const todayStart = startOfUtcDay(now)\n const tomorrowStart = addUtcDays(todayStart, 1)\n const yesterdayStart = addUtcDays(todayStart, -1)\n const agingCutoff = addUtcDays(todayStart, -AGING_RESERVATION_DAYS)\n const expiringCutoff = addUtcDays(todayStart, EXPIRING_SOON_DAYS)\n const trendStart = addUtcDays(todayStart, -(TREND_DAYS - 1))\n const dayBuckets = buildDailyBuckets(TREND_DAYS, now)\n const decryptionScope = resolveDecryptionScope(scope)\n\n const baseScope = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null as Date | null,\n }\n\n if (scope.warehouseId) {\n const warehouse = await findOneWithDecryption(\n em,\n Warehouse,\n { id: scope.warehouseId, ...baseScope },\n undefined,\n decryptionScope,\n )\n if (!warehouse) {\n throw new OperationalDashboardWarehouseNotFoundError(scope.warehouseId)\n }\n }\n\n const warehouseFilter = scope.warehouseId ? { warehouse: scope.warehouseId } : {}\n\n const [profiles, balances, expiringSoonLots, pastDueLots, reservations, activityMovements] = await Promise.all([\n findWithDecryption(em, ProductInventoryProfile, baseScope, undefined, decryptionScope),\n findWithDecryption(\n em,\n InventoryBalance,\n { ...baseScope, ...warehouseFilter },\n { populate: ['warehouse', 'location', 'lot'] },\n decryptionScope,\n ),\n findWithDecryption(\n em,\n InventoryLot,\n {\n ...baseScope,\n status: 'available',\n expiresAt: { $ne: null, $gte: todayStart, $lte: expiringCutoff },\n },\n { orderBy: { expiresAt: 'ASC' }, limit: 100 },\n decryptionScope,\n ),\n findWithDecryption(\n em,\n InventoryLot,\n {\n ...baseScope,\n status: 'available',\n expiresAt: { $ne: null, $lt: todayStart },\n },\n { orderBy: { expiresAt: 'ASC' }, limit: 100 },\n decryptionScope,\n ),\n findWithDecryption(\n em,\n InventoryReservation,\n {\n ...baseScope,\n ...warehouseFilter,\n status: 'active',\n createdAt: { $lte: agingCutoff },\n },\n undefined,\n decryptionScope,\n ),\n findWithDecryption(\n em,\n InventoryMovement,\n { ...baseScope, ...warehouseFilter },\n {\n populate: ['warehouse', 'locationFrom', 'locationTo'],\n orderBy: { performedAt: 'DESC' },\n limit: ACTIVITY_LIMIT,\n },\n decryptionScope,\n ),\n ])\n\n const { lowStockCount, reorderCriticalCount } = computeLowStockCounts(\n profiles,\n balances,\n scope.warehouseId,\n )\n\n const expiringSoonCount = expiringSoonLots.filter(\n (lot) => resolveLotAvailableQuantity(lot.id, balances, scope.warehouseId) > 0,\n ).length\n\n const agingReservationsCount = reservations.length\n\n const [\n todaysMoveCount,\n yesterdaysMoveCount,\n pastDueCount,\n lowStockSparklineRows,\n reorderCriticalSparklineRows,\n expiringSoonSparklineRows,\n pastDueSparklineRows,\n agingReservationsSparklineRows,\n todaysMovesSparklineRows,\n monthlyTrends,\n ] = await Promise.all([\n countMovementsBetween(em, scope, todayStart, tomorrowStart),\n countMovementsBetween(em, scope, yesterdayStart, todayStart),\n loadPastDueLotCount(em, scope, todayStart),\n loadMovementDailyCounts(em, scope, trendStart, { types: ['adjust'], quantitySign: 'negative' }),\n loadMovementDailyCounts(em, scope, trendStart, { types: ['adjust'], quantitySign: 'negative' }),\n loadExpiringSoonDailyCounts(em, scope, dayBuckets),\n loadPastDueDailyCounts(em, scope, dayBuckets),\n loadAgingReservationsDailyCounts(em, scope, dayBuckets),\n loadMovementDailyCounts(em, scope, trendStart),\n loadMonthlyMovementTrends(\n em,\n scope,\n new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - (MONTHLY_TREND_MONTHS - 1), 1)),\n now,\n ),\n ])\n\n const kpis: OperationalDashboardKpi[] = [\n {\n id: 'lowStock',\n count: lowStockCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, lowStockSparklineRows),\n },\n {\n id: 'reorderCritical',\n count: reorderCriticalCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, reorderCriticalSparklineRows),\n },\n {\n id: 'expiringSoon',\n count: expiringSoonCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, expiringSoonSparklineRows),\n },\n {\n id: 'pastDue',\n count: pastDueCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, pastDueSparklineRows),\n },\n {\n id: 'agingReservations',\n count: agingReservationsCount,\n deltaSinceYesterday: null,\n sparkline: mapDailyCountsToSparkline(dayBuckets, agingReservationsSparklineRows),\n },\n {\n id: 'todaysMoves',\n count: todaysMoveCount,\n deltaSinceYesterday: todaysMoveCount - yesterdaysMoveCount,\n sparkline: mapDailyCountsToSparkline(dayBuckets, todaysMovesSparklineRows),\n },\n ]\n\n const variantIds = Array.from(new Set(activityMovements.map((movement) => movement.catalogVariantId)))\n const variantSkus = await loadVariantSkus(em, scope, variantIds)\n\n const recentActivity: OperationalDashboardActivityRow[] = activityMovements.map((movement) => {\n const warehouseLabel = resolveWarehouseLabel(movement.warehouse, movement.warehouse.id)\n return {\n id: movement.id,\n movementType: movement.type,\n quantity: toOperationalDashboardNumber(movement.quantity),\n variantSku: variantSkus.get(movement.catalogVariantId) ?? null,\n variantId: movement.catalogVariantId,\n referenceType: movement.referenceType ?? null,\n referenceId: movement.referenceId ?? null,\n reason: movement.reason ?? null,\n reasonCode: movement.reasonCode ?? null,\n locationLabel: resolveLocationLabel(\n warehouseLabel,\n movement.locationFrom?.code,\n movement.locationTo?.code,\n ),\n performedAt: movement.performedAt.toISOString(),\n }\n })\n\n const expiryLots = buildExpiryLotRows(\n expiringSoonLots,\n pastDueLots,\n balances,\n scope.warehouseId,\n )\n\n return {\n lastUpdatedAt: now.toISOString(),\n warehouseId: scope.warehouseId ?? null,\n kpis,\n expiryLots,\n monthlyTrends,\n recentActivity,\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["addUtcDays", "startOfUtcDay"]
7
+ }