@endora-commerce/mod-inventory 0.100.0

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 (223) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/admin/api/warehouses-client.d.ts +22 -0
  4. package/dist/admin/api/warehouses-client.d.ts.map +1 -0
  5. package/dist/admin/api/warehouses-client.js +32 -0
  6. package/dist/admin/api/warehouses-client.js.map +1 -0
  7. package/dist/admin/index.d.ts +43 -0
  8. package/dist/admin/index.d.ts.map +1 -0
  9. package/dist/admin/index.js +190 -0
  10. package/dist/admin/index.js.map +1 -0
  11. package/dist/admin/pages/AvailabilityNotificationsPage.d.ts +15 -0
  12. package/dist/admin/pages/AvailabilityNotificationsPage.d.ts.map +1 -0
  13. package/dist/admin/pages/AvailabilityNotificationsPage.js +111 -0
  14. package/dist/admin/pages/AvailabilityNotificationsPage.js.map +1 -0
  15. package/dist/admin/pages/InventoryPage.d.ts +17 -0
  16. package/dist/admin/pages/InventoryPage.d.ts.map +1 -0
  17. package/dist/admin/pages/InventoryPage.js +135 -0
  18. package/dist/admin/pages/InventoryPage.js.map +1 -0
  19. package/dist/admin/pages/LowStockPage.d.ts +16 -0
  20. package/dist/admin/pages/LowStockPage.d.ts.map +1 -0
  21. package/dist/admin/pages/LowStockPage.js +61 -0
  22. package/dist/admin/pages/LowStockPage.js.map +1 -0
  23. package/dist/admin/pages/StockImportWizard.d.ts +17 -0
  24. package/dist/admin/pages/StockImportWizard.d.ts.map +1 -0
  25. package/dist/admin/pages/StockImportWizard.js +111 -0
  26. package/dist/admin/pages/StockImportWizard.js.map +1 -0
  27. package/dist/admin/pages/WarehouseEditor.d.ts +12 -0
  28. package/dist/admin/pages/WarehouseEditor.d.ts.map +1 -0
  29. package/dist/admin/pages/WarehouseEditor.js +194 -0
  30. package/dist/admin/pages/WarehouseEditor.js.map +1 -0
  31. package/dist/admin/pages/WarehousesList.d.ts +12 -0
  32. package/dist/admin/pages/WarehousesList.d.ts.map +1 -0
  33. package/dist/admin/pages/WarehousesList.js +69 -0
  34. package/dist/admin/pages/WarehousesList.js.map +1 -0
  35. package/dist/admin/zones/ChannelWarehouses.d.ts +49 -0
  36. package/dist/admin/zones/ChannelWarehouses.d.ts.map +1 -0
  37. package/dist/admin/zones/ChannelWarehouses.js +109 -0
  38. package/dist/admin/zones/ChannelWarehouses.js.map +1 -0
  39. package/dist/backend/demo/reset.d.ts +18 -0
  40. package/dist/backend/demo/reset.d.ts.map +1 -0
  41. package/dist/backend/demo/reset.js +20 -0
  42. package/dist/backend/demo/reset.js.map +1 -0
  43. package/dist/backend/demo/rows.d.ts +38 -0
  44. package/dist/backend/demo/rows.d.ts.map +1 -0
  45. package/dist/backend/demo/rows.js +38 -0
  46. package/dist/backend/demo/rows.js.map +1 -0
  47. package/dist/backend/demo/seed.d.ts +26 -0
  48. package/dist/backend/demo/seed.d.ts.map +1 -0
  49. package/dist/backend/demo/seed.js +65 -0
  50. package/dist/backend/demo/seed.js.map +1 -0
  51. package/dist/backend/email-templates/transactional-defaults.d.ts +11 -0
  52. package/dist/backend/email-templates/transactional-defaults.d.ts.map +1 -0
  53. package/dist/backend/email-templates/transactional-defaults.js +49 -0
  54. package/dist/backend/email-templates/transactional-defaults.js.map +1 -0
  55. package/dist/backend/entities/availability-notification.entity.d.ts +49 -0
  56. package/dist/backend/entities/availability-notification.entity.d.ts.map +1 -0
  57. package/dist/backend/entities/availability-notification.entity.js +93 -0
  58. package/dist/backend/entities/availability-notification.entity.js.map +1 -0
  59. package/dist/backend/entities/inventory-threshold.entity.d.ts +24 -0
  60. package/dist/backend/entities/inventory-threshold.entity.d.ts.map +1 -0
  61. package/dist/backend/entities/inventory-threshold.entity.js +61 -0
  62. package/dist/backend/entities/inventory-threshold.entity.js.map +1 -0
  63. package/dist/backend/entities/product-warehouse-low-stock-threshold.entity.d.ts +15 -0
  64. package/dist/backend/entities/product-warehouse-low-stock-threshold.entity.d.ts.map +1 -0
  65. package/dist/backend/entities/product-warehouse-low-stock-threshold.entity.js +51 -0
  66. package/dist/backend/entities/product-warehouse-low-stock-threshold.entity.js.map +1 -0
  67. package/dist/backend/entities/stock-allocation.entity.d.ts +22 -0
  68. package/dist/backend/entities/stock-allocation.entity.d.ts.map +1 -0
  69. package/dist/backend/entities/stock-allocation.entity.js +69 -0
  70. package/dist/backend/entities/stock-allocation.entity.js.map +1 -0
  71. package/dist/backend/entities/stock-level.entity.d.ts +24 -0
  72. package/dist/backend/entities/stock-level.entity.d.ts.map +1 -0
  73. package/dist/backend/entities/stock-level.entity.js +74 -0
  74. package/dist/backend/entities/stock-level.entity.js.map +1 -0
  75. package/dist/backend/entities/warehouse-channel-assignment.entity.d.ts +17 -0
  76. package/dist/backend/entities/warehouse-channel-assignment.entity.d.ts.map +1 -0
  77. package/dist/backend/entities/warehouse-channel-assignment.entity.js +60 -0
  78. package/dist/backend/entities/warehouse-channel-assignment.entity.js.map +1 -0
  79. package/dist/backend/entities/warehouse.entity.d.ts +37 -0
  80. package/dist/backend/entities/warehouse.entity.d.ts.map +1 -0
  81. package/dist/backend/entities/warehouse.entity.js +90 -0
  82. package/dist/backend/entities/warehouse.entity.js.map +1 -0
  83. package/dist/backend/index.d.ts +139 -0
  84. package/dist/backend/index.d.ts.map +1 -0
  85. package/dist/backend/index.js +351 -0
  86. package/dist/backend/index.js.map +1 -0
  87. package/dist/backend/plugin.d.ts +113 -0
  88. package/dist/backend/plugin.d.ts.map +1 -0
  89. package/dist/backend/plugin.js +75 -0
  90. package/dist/backend/plugin.js.map +1 -0
  91. package/dist/backend/prompt-tools.d.ts +23 -0
  92. package/dist/backend/prompt-tools.d.ts.map +1 -0
  93. package/dist/backend/prompt-tools.js +77 -0
  94. package/dist/backend/prompt-tools.js.map +1 -0
  95. package/dist/backend/routes.admin.d.ts +62 -0
  96. package/dist/backend/routes.admin.d.ts.map +1 -0
  97. package/dist/backend/routes.admin.js +383 -0
  98. package/dist/backend/routes.admin.js.map +1 -0
  99. package/dist/backend/routes.d.ts +40 -0
  100. package/dist/backend/routes.d.ts.map +1 -0
  101. package/dist/backend/routes.js +263 -0
  102. package/dist/backend/routes.js.map +1 -0
  103. package/dist/backend/services/audit-references.d.ts +15 -0
  104. package/dist/backend/services/audit-references.d.ts.map +1 -0
  105. package/dist/backend/services/audit-references.js +27 -0
  106. package/dist/backend/services/audit-references.js.map +1 -0
  107. package/dist/backend/services/availability-notification-service.d.ts +155 -0
  108. package/dist/backend/services/availability-notification-service.d.ts.map +1 -0
  109. package/dist/backend/services/availability-notification-service.js +363 -0
  110. package/dist/backend/services/availability-notification-service.js.map +1 -0
  111. package/dist/backend/services/availability-worker.d.ts +57 -0
  112. package/dist/backend/services/availability-worker.d.ts.map +1 -0
  113. package/dist/backend/services/availability-worker.js +135 -0
  114. package/dist/backend/services/availability-worker.js.map +1 -0
  115. package/dist/backend/services/csv-stock-importer.d.ts +52 -0
  116. package/dist/backend/services/csv-stock-importer.d.ts.map +1 -0
  117. package/dist/backend/services/csv-stock-importer.js +154 -0
  118. package/dist/backend/services/csv-stock-importer.js.map +1 -0
  119. package/dist/backend/services/display-band-resolver.d.ts +19 -0
  120. package/dist/backend/services/display-band-resolver.d.ts.map +1 -0
  121. package/dist/backend/services/display-band-resolver.js +21 -0
  122. package/dist/backend/services/display-band-resolver.js.map +1 -0
  123. package/dist/backend/services/effective-fulfilment-strategy.d.ts +16 -0
  124. package/dist/backend/services/effective-fulfilment-strategy.d.ts.map +1 -0
  125. package/dist/backend/services/effective-fulfilment-strategy.js +16 -0
  126. package/dist/backend/services/effective-fulfilment-strategy.js.map +1 -0
  127. package/dist/backend/services/fulfilment-strategy-resolver.d.ts +13 -0
  128. package/dist/backend/services/fulfilment-strategy-resolver.d.ts.map +1 -0
  129. package/dist/backend/services/fulfilment-strategy-resolver.js +13 -0
  130. package/dist/backend/services/fulfilment-strategy-resolver.js.map +1 -0
  131. package/dist/backend/services/inventory-read-port.d.ts +65 -0
  132. package/dist/backend/services/inventory-read-port.d.ts.map +1 -0
  133. package/dist/backend/services/inventory-read-port.js +168 -0
  134. package/dist/backend/services/inventory-read-port.js.map +1 -0
  135. package/dist/backend/services/inventory-reservation-apply-port.d.ts +62 -0
  136. package/dist/backend/services/inventory-reservation-apply-port.d.ts.map +1 -0
  137. package/dist/backend/services/inventory-reservation-apply-port.js +134 -0
  138. package/dist/backend/services/inventory-reservation-apply-port.js.map +1 -0
  139. package/dist/backend/services/low-stock-alert-service.d.ts +87 -0
  140. package/dist/backend/services/low-stock-alert-service.d.ts.map +1 -0
  141. package/dist/backend/services/low-stock-alert-service.js +164 -0
  142. package/dist/backend/services/low-stock-alert-service.js.map +1 -0
  143. package/dist/backend/services/product-threshold-write.service.d.ts +38 -0
  144. package/dist/backend/services/product-threshold-write.service.d.ts.map +1 -0
  145. package/dist/backend/services/product-threshold-write.service.js +80 -0
  146. package/dist/backend/services/product-threshold-write.service.js.map +1 -0
  147. package/dist/backend/services/stock-import.service.d.ts +43 -0
  148. package/dist/backend/services/stock-import.service.d.ts.map +1 -0
  149. package/dist/backend/services/stock-import.service.js +124 -0
  150. package/dist/backend/services/stock-import.service.js.map +1 -0
  151. package/dist/backend/services/stock-level-service.d.ts +146 -0
  152. package/dist/backend/services/stock-level-service.d.ts.map +1 -0
  153. package/dist/backend/services/stock-level-service.js +489 -0
  154. package/dist/backend/services/stock-level-service.js.map +1 -0
  155. package/dist/backend/services/threshold-admin-service.d.ts +73 -0
  156. package/dist/backend/services/threshold-admin-service.d.ts.map +1 -0
  157. package/dist/backend/services/threshold-admin-service.js +167 -0
  158. package/dist/backend/services/threshold-admin-service.js.map +1 -0
  159. package/dist/backend/services/threshold-resolver.d.ts +23 -0
  160. package/dist/backend/services/threshold-resolver.d.ts.map +1 -0
  161. package/dist/backend/services/threshold-resolver.js +29 -0
  162. package/dist/backend/services/threshold-resolver.js.map +1 -0
  163. package/dist/backend/services/threshold-settings-mirror.d.ts +55 -0
  164. package/dist/backend/services/threshold-settings-mirror.d.ts.map +1 -0
  165. package/dist/backend/services/threshold-settings-mirror.js +84 -0
  166. package/dist/backend/services/threshold-settings-mirror.js.map +1 -0
  167. package/dist/backend/services/warehouse-channel-reconciler.d.ts +19 -0
  168. package/dist/backend/services/warehouse-channel-reconciler.d.ts.map +1 -0
  169. package/dist/backend/services/warehouse-channel-reconciler.js +65 -0
  170. package/dist/backend/services/warehouse-channel-reconciler.js.map +1 -0
  171. package/dist/backend/services/warehouse-channel-service.d.ts +57 -0
  172. package/dist/backend/services/warehouse-channel-service.d.ts.map +1 -0
  173. package/dist/backend/services/warehouse-channel-service.js +205 -0
  174. package/dist/backend/services/warehouse-channel-service.js.map +1 -0
  175. package/dist/backend/services/warehouse-country-reference.d.ts +14 -0
  176. package/dist/backend/services/warehouse-country-reference.d.ts.map +1 -0
  177. package/dist/backend/services/warehouse-country-reference.js +27 -0
  178. package/dist/backend/services/warehouse-country-reference.js.map +1 -0
  179. package/dist/backend/services/warehouse-service.d.ts +86 -0
  180. package/dist/backend/services/warehouse-service.d.ts.map +1 -0
  181. package/dist/backend/services/warehouse-service.js +267 -0
  182. package/dist/backend/services/warehouse-service.js.map +1 -0
  183. package/dist/manifest.d.ts +219 -0
  184. package/dist/manifest.d.ts.map +1 -0
  185. package/dist/manifest.js +377 -0
  186. package/dist/manifest.js.map +1 -0
  187. package/dist/migrations/20260503T182812_inventory_workflow.d.ts +39 -0
  188. package/dist/migrations/20260503T182812_inventory_workflow.d.ts.map +1 -0
  189. package/dist/migrations/20260503T182812_inventory_workflow.js +205 -0
  190. package/dist/migrations/20260503T182812_inventory_workflow.js.map +1 -0
  191. package/dist/migrations/20260611T140347_inventory_warehouse_default_low_stock_threshold.d.ts +14 -0
  192. package/dist/migrations/20260611T140347_inventory_warehouse_default_low_stock_threshold.d.ts.map +1 -0
  193. package/dist/migrations/20260611T140347_inventory_warehouse_default_low_stock_threshold.js +18 -0
  194. package/dist/migrations/20260611T140347_inventory_warehouse_default_low_stock_threshold.js.map +1 -0
  195. package/dist/migrations/20260611T140348_inventory_per_warehouse_low_stock_thresholds.d.ts +28 -0
  196. package/dist/migrations/20260611T140348_inventory_per_warehouse_low_stock_thresholds.d.ts.map +1 -0
  197. package/dist/migrations/20260611T140348_inventory_per_warehouse_low_stock_thresholds.js +48 -0
  198. package/dist/migrations/20260611T140348_inventory_per_warehouse_low_stock_thresholds.js.map +1 -0
  199. package/dist/migrations/20260818T081243_inventory_stock_allocation_order_item_fk.d.ts +44 -0
  200. package/dist/migrations/20260818T081243_inventory_stock_allocation_order_item_fk.d.ts.map +1 -0
  201. package/dist/migrations/20260818T081243_inventory_stock_allocation_order_item_fk.js +81 -0
  202. package/dist/migrations/20260818T081243_inventory_stock_allocation_order_item_fk.js.map +1 -0
  203. package/dist/migrations/20260830T182139_inventory_organization_attribution.d.ts +109 -0
  204. package/dist/migrations/20260830T182139_inventory_organization_attribution.d.ts.map +1 -0
  205. package/dist/migrations/20260830T182139_inventory_organization_attribution.js +178 -0
  206. package/dist/migrations/20260830T182139_inventory_organization_attribution.js.map +1 -0
  207. package/dist/migrations/20260912T125716_inventory_organization_warehouses.d.ts +34 -0
  208. package/dist/migrations/20260912T125716_inventory_organization_warehouses.d.ts.map +1 -0
  209. package/dist/migrations/20260912T125716_inventory_organization_warehouses.js +50 -0
  210. package/dist/migrations/20260912T125716_inventory_organization_warehouses.js.map +1 -0
  211. package/dist/migrations/index.d.ts +32 -0
  212. package/dist/migrations/index.d.ts.map +1 -0
  213. package/dist/migrations/index.js +39 -0
  214. package/dist/migrations/index.js.map +1 -0
  215. package/dist/ports/index.d.ts +183 -0
  216. package/dist/ports/index.d.ts.map +1 -0
  217. package/dist/ports/index.js +2 -0
  218. package/dist/ports/index.js.map +1 -0
  219. package/docs/inventory.md +177 -0
  220. package/i18n/en.json +32 -0
  221. package/i18n/pl.json +32 -0
  222. package/package.json +105 -0
  223. package/tailwind.css +14 -0
@@ -0,0 +1,351 @@
1
+ import { resolveAllocations, resolveEffectiveFulfilmentStrategy } from '@endora-commerce/contracts';
2
+ import { lazyPort } from '@endora-commerce/platform/kernel';
3
+ import { effectiveState } from '@endora-commerce/platform/kernel';
4
+ import { inventoryModule } from './plugin.js';
5
+ import { StockLevelService } from './services/stock-level-service.js';
6
+ import { InventoryStockReadService } from './services/inventory-read-port.js';
7
+ import { InventoryReservationApplyService } from './services/inventory-reservation-apply-port.js';
8
+ import { InventoryStockImportService } from './services/stock-import.service.js';
9
+ import { InventoryProductThresholdWriteService } from './services/product-threshold-write.service.js';
10
+ import { WarehouseChannelService } from './services/warehouse-channel-service.js';
11
+ import { WarehouseChannelReconciler } from './services/warehouse-channel-reconciler.js';
12
+ import { AVAILABILITY_BACK_IN_STOCK_DEFAULT, LOW_STOCK_ALERT_DEFAULT } from './email-templates/transactional-defaults.js';
13
+ import { inventoryPromptTools } from './prompt-tools.js';
14
+ import { registerWarehouseCountryReferences } from './services/warehouse-country-reference.js';
15
+ import { registerInventoryAuditReferences } from './services/audit-references.js';
16
+ import { AvailabilityNotification } from './entities/availability-notification.entity.js';
17
+ import { InventoryThreshold } from './entities/inventory-threshold.entity.js';
18
+ import { ProductWarehouseLowStockThreshold } from './entities/product-warehouse-low-stock-threshold.entity.js';
19
+ import { StockAllocation } from './entities/stock-allocation.entity.js';
20
+ import { StockLevel } from './entities/stock-level.entity.js';
21
+ import { WarehouseChannelAssignment } from './entities/warehouse-channel-assignment.entity.js';
22
+ import { Warehouse } from './entities/warehouse.entity.js';
23
+ export function registerModule(ctx) {
24
+ ctx.di.register({
25
+ inventory: ctx
26
+ .asFunction(({ emFactory, eventBus, auditLogService }) => inventoryModule({
27
+ emFactory,
28
+ eventBus,
29
+ auditLogService,
30
+ settingsService: lazyPort(ctx, 'settingsReadPort'),
31
+ channelResolver: lazyPort(ctx, 'salesChannelResolutionPort'),
32
+ dictionaryValidator: lazyPort(ctx, 'dictionaryValidator'),
33
+ // Feature 075, Phase C — the four reads and one write this module used
34
+ // to take by importing `catalog`'s, `customer_accounts`' and `email`'s
35
+ // files. Every one of them kept answering with its owner switched off.
36
+ catalogProducts: lazyPort(ctx, 'catalogProductReadPort'),
37
+ catalogCategories: lazyPort(ctx, 'catalogCategoryReadPort'),
38
+ catalogCategoryWrites: lazyPort(ctx, 'catalogCategoryWritePort'),
39
+ customerAccounts: lazyPort(ctx, 'customerAccountReadPort'),
40
+ // Issue #259 — the channel assortment gate on the notify-me seam. A
41
+ // kernel registration, not a module's, so there is no edge to declare
42
+ // in the manifest.
43
+ salesChannelMembership: lazyPort(ctx, 'salesChannelMembershipPort'),
44
+ mailer: lazyPort(ctx, 'emailMailer'),
45
+ requireAdmin: (permission) => async (req, reply) => ctx.cradle().requireAdmin(permission)(req, reply),
46
+ requireCustomer: (req, reply) => ctx.cradle().requireCustomer(req, reply),
47
+ resolveCustomerContext: (req) => ctx.cradle().customerContextResolver(req),
48
+ resolveSystemDefaultChannelId: () => ctx.cradle().settingsChannelResolver(),
49
+ resolveAdminAuditContext: (req) => ctx.cradle().inventoryAdminAuditContext(req),
50
+ templateEmail: {
51
+ trySend: (input) => ctx.cradle().templateEmailPort.trySend(input),
52
+ },
53
+ // Composed from the two halves, without a `catch` — the root closure
54
+ // this replaces had one, which would have read a disabled-module
55
+ // throw as "every warehouse is allowed" (T138).
56
+ resolveOrganizationWarehouseAllowList: async (req) => {
57
+ const cradle = ctx.cradle();
58
+ const organizationId = cradle.customerOrganizationIdResolver(req);
59
+ if (organizationId === null)
60
+ return null;
61
+ return cradle.organizationRestrictionPort.allowedIdsFor(organizationId, 'warehouseIds');
62
+ },
63
+ }))
64
+ .singleton(),
65
+ });
66
+ /**
67
+ * Feature 075, Phase P — the stock read model.
68
+ *
69
+ * `orders` assembles candidate warehouses for a line from three of this
70
+ * module's tables today, inside its own transaction, reaching them through a
71
+ * **dynamic** import. `candidatesFor` is that assembly, on this side of the
72
+ * boundary; the three list methods beside it are the transcriptions
73
+ * `import_export` and the dev seed need.
74
+ */
75
+ ctx.di.providePort('inventoryStockReadPort', ctx
76
+ .asFunction(({ emFactory }) => new InventoryStockReadService(emFactory))
77
+ .singleton());
78
+ /**
79
+ * D-94.4 — the warehouse-picking policy, published.
80
+ *
81
+ * `orders` reached both functions through `await import(
82
+ * '../../inventory/services/…')` inside the placement method body. They are
83
+ * pure over their arguments, so nothing here reads a table and nothing takes
84
+ * an `EntityManager`; what the port buys is that the policy is asked of its
85
+ * owner rather than re-implemented by whoever edits the import next.
86
+ *
87
+ * A separate port from `inventoryStockReadPort` on purpose: a read port that
88
+ * also decides policy makes its own name a lie.
89
+ *
90
+ * The gate `providePort` wraps this in is real but never reached from
91
+ * placement: `orders` declares this name `degrades-without` and asks
92
+ * `effectiveState.isPresent('inventory')` before the reservation block, so
93
+ * with this module off there is no plan to compute rather than a 503 in the
94
+ * middle of one.
95
+ */
96
+ ctx.di.providePort('inventoryFulfilmentPlanningPort', ctx
97
+ .asFunction(() => ({
98
+ resolveEffectiveStrategy: resolveEffectiveFulfilmentStrategy,
99
+ planAllocations: resolveAllocations,
100
+ }))
101
+ .singleton());
102
+ /**
103
+ * Feature 080, T048 / D-169 — the stock reservation, published.
104
+ *
105
+ * `orders` reached this module's `StockLevel` and `StockAllocation` classes
106
+ * for it, statically for the reservation and through an `await import()` for
107
+ * the release, and wrote both tables itself: the `FOR UPDATE` read, the
108
+ * `reserved` increment, the allocation insert and the release loop. D-168
109
+ * leaves a packaged `inventory` no entity class for a stranger to name, so
110
+ * the reach had to go before this module moves; the transaction it runs in
111
+ * did not change, and `stock_allocations_order_item_fk` is untouched.
112
+ *
113
+ * A third `inventory` name rather than a widening of either port above, and
114
+ * the three differ in exactly which transaction they run in:
115
+ * `inventoryStockReadPort` reads on this module's own `EntityManager`,
116
+ * `inventoryFulfilmentPlanningPort` opens none at all — it is pure over its
117
+ * arguments — and this one takes placement's, because the
118
+ * `PESSIMISTIC_WRITE` has to be held until the order commits and the
119
+ * allocation rows cannot exist before their order items do.
120
+ *
121
+ * The gate `providePort` wraps this in is real but never reached from
122
+ * placement, for the same reason `inventoryFulfilmentPlanningPort`'s is not:
123
+ * `orders` declares this name `degrades-without` and asks
124
+ * `effectiveState.isPresent('inventory')` before the reservation block and
125
+ * before the cancellation release, so with this module off nothing is
126
+ * reserved and nothing is released — rather than a 503 in the middle of a
127
+ * placement.
128
+ */
129
+ ctx.di.providePort('inventoryReservationApplyPort', ctx.asFunction(() => new InventoryReservationApplyService()).singleton());
130
+ /**
131
+ * D-74 — the bulk stock import. `import_export` wrote `stock_levels` from its
132
+ * own transaction, with no Command, no audit row and the seeded warehouse id
133
+ * pasted in as a literal; all three come back here, where the rows live.
134
+ *
135
+ * `catalogProductReadPort` is resolved lazily and per call: a spreadsheet
136
+ * addresses a product by SKU, and this module already declares `catalog`.
137
+ */
138
+ ctx.di.providePort('inventoryStockImportPort', ctx
139
+ .asFunction(({ commandBus }) => new InventoryStockImportService(commandBus, lazyPort(ctx, 'catalogProductReadPort')))
140
+ .singleton());
141
+ /**
142
+ * Issue #185 — the per-warehouse threshold copy, published.
143
+ *
144
+ * `catalog`'s product duplication wrote these rows itself, with an
145
+ * `insert … select` naming this module's table. It named no import specifier,
146
+ * so `check:module-boundary`'s specifier pass could not see it; it asked no
147
+ * gate, so it kept writing with this module switched off; and it left no
148
+ * audit row here, so the rows arrived with nothing on this side having decided
149
+ * they should. The port is the whole remedy: one Command, one audit row, and
150
+ * the gate `providePort` wraps it in.
151
+ *
152
+ * `catalog` declares this name `degrades-without` and decides presence in
153
+ * front of the gate, so the duplication itself never meets a 503 — see the
154
+ * contract's note on why the copy owns its own transaction.
155
+ */
156
+ ctx.di.providePort('inventoryProductThresholdWritePort', ctx
157
+ .asFunction(({ commandBus }) => new InventoryProductThresholdWriteService(commandBus))
158
+ .singleton());
159
+ ctx.di.providePort('inventoryAvailabilityPort', ctx
160
+ .asFunction(({ emFactory, eventBus, auditLogService }) => {
161
+ const warehouseChannels = new WarehouseChannelService(emFactory, auditLogService);
162
+ const stockLevels = new StockLevelService(emFactory, lazyPort(ctx, 'catalogProductReadPort'), lazyPort(ctx, 'catalogCategoryReadPort'), eventBus, auditLogService);
163
+ return {
164
+ async resolveAvailabilityBands(productIds, salesChannelId) {
165
+ const candidateWarehouseIds = await warehouseChannels.resolveCandidateWarehouseIds(salesChannelId);
166
+ return stockLevels.resolveAvailabilityBands(productIds, candidateWarehouseIds.length > 0 ? candidateWarehouseIds : undefined);
167
+ },
168
+ };
169
+ })
170
+ .singleton());
171
+ /**
172
+ * The three reactors this module owns (issue #107).
173
+ *
174
+ * All three were bare `eventBus.on` calls inside the plugin body, so a
175
+ * switched-off `inventory` still sent back-in-stock mail, still sent low-stock
176
+ * alerts and still wrote the mirrored threshold row — three writes on a module
177
+ * an operator believed was absent. `ctx.subscribe` puts each behind
178
+ * `subscribeForModule`, which reads the effective state per event.
179
+ *
180
+ * The threshold mirror re-reads the changed setting, and reads the value that
181
+ * was just written: `SettingsAdminService` drops the settings cache at the
182
+ * write seam and awaits the drop before it emits (issue #45). This used to
183
+ * depend on the kernel's invalidator being registered ahead of this handler —
184
+ * true, but only by composition order, which nothing preserved.
185
+ */
186
+ const handle = () => ctx.cradle().inventory.handle;
187
+ ctx.subscribe('inventory.adjusted.v1', async (payload) => {
188
+ await handle().availabilityWorker.handleAdjusted(payload);
189
+ });
190
+ ctx.subscribe('inventory.adjusted.v1', async (payload) => {
191
+ await handle().lowStockAlertService.handleAdjusted(payload);
192
+ });
193
+ ctx.subscribe('settings.value_changed', async (payload) => {
194
+ await handle().thresholdSettingsMirror?.onSettingChanged(payload);
195
+ });
196
+ ctx.routes(async (app) => {
197
+ await ctx.cradle().inventory.plugin(app);
198
+ });
199
+ /**
200
+ * Migration 030 seeds the Default warehouse and tries to bind it to every
201
+ * channel, but it runs *before* the default-channel reconciler creates the
202
+ * system channel at boot. This catches up at runtime so a channel is never
203
+ * seen without at least one warehouse assignment (feature 026 US3).
204
+ *
205
+ * It ran from `composition.ts` until T143a — which meant it ran with this
206
+ * module switched off, and did not run in the harness at all
207
+ * (`harness-parity` carried it as a production-only construct). As a boot
208
+ * hook it does neither.
209
+ */
210
+ ctx.onBoot(async () => {
211
+ // Presence is decided here — first, and outside anything that could catch it
212
+ // (issue #146, D-68). The reconciler creates a
213
+ // `warehouse_channel_assignments` row per sales channel, so with the module
214
+ // switched off it wrote this module's tables at every boot. A boot hook has
215
+ // no caller to answer, so the question is asked rather than thrown:
216
+ // `runBootHooks` re-throws as `ModuleCompositionError`, which `index.ts`
217
+ // turns into `process.exit(1)`.
218
+ //
219
+ // The consequence of returning: a sales channel created while `inventory` is
220
+ // off gets its default warehouse assignment at the **next boot** rather than
221
+ // at reactivation. That is acceptable because the reconcile is idempotent
222
+ // and every read of those rows is gated anyway. If it stops being
223
+ // acceptable, the repair is to drive the reconcile from the activation
224
+ // event — not to un-probe this hook.
225
+ if (!effectiveState.isPresent('inventory'))
226
+ return;
227
+ await new WarehouseChannelReconciler(ctx.cradle().emFactory()).run();
228
+ });
229
+ /**
230
+ * The default subject and content for the 2 transactional emails this
231
+ * module declares in its manifest (T143a).
232
+ *
233
+ * These were fourteen `emailDefaultsRegistry.register(...)` calls in
234
+ * `composition.ts`, each importing a template constant out of the module that
235
+ * owns it — a root reaching into seven modules to hand their own content to
236
+ * an eighth. Each module registers its own now.
237
+ *
238
+ * `ctx.onBoot` rather than a registration: the registry is *read* once, by
239
+ * `transactional_emails`' boot reconciler inside its plugin body. Boot hooks
240
+ * run during composition and plugin bodies only when the Fastify app is
241
+ * built, so this always lands first — by construction, not by ordering luck.
242
+ */
243
+ ctx.onBoot(async () => {
244
+ const defaults = lazyPort(ctx, 'emailDefaultsPort');
245
+ defaults.register('low_stock_alert', LOW_STOCK_ALERT_DEFAULT, 'inventory');
246
+ defaults.register('availability_back_in_stock', AVAILABILITY_BACK_IN_STOCK_DEFAULT, 'inventory');
247
+ });
248
+ /**
249
+ * The assistant tools this module contributes (D-44).
250
+ *
251
+ * Both roots built the warehouse resolver and the `set_stock_level` mutation
252
+ * from this module's own services and pushed them into `prompt_actions`'
253
+ * registry, because pushing from here would have made `prompt_actions` a
254
+ * declared dependency — and that declaration is what would have made an
255
+ * optional assistant undeactivatable while `inventory` is present.
256
+ * `nonBindingDependencies` declares the edge without that claim.
257
+ *
258
+ * A push, not a pull. The registry is a plain registration, so this resolves
259
+ * no gate, and the host drops every tool whose recorded owner is not
260
+ * effectively present.
261
+ */
262
+ ctx.onBoot(() => {
263
+ const cradle = ctx.cradle();
264
+ const registry = cradle.promptActionToolRegistry;
265
+ for (const tool of inventoryPromptTools({
266
+ emFactory: cradle.emFactory,
267
+ catalogProducts: lazyPort(ctx, 'catalogProductReadPort'),
268
+ catalogCategories: lazyPort(ctx, 'catalogCategoryReadPort'),
269
+ eventBus: cradle.eventBus,
270
+ auditLogService: cradle.auditLogService,
271
+ })) {
272
+ registry.register(tool);
273
+ }
274
+ });
275
+ /**
276
+ * This module's rows carry a country code, so it answers "who still points at
277
+ * this country?" about its own tables (feature 077, D-87), where the owner used
278
+ * to count them with SQL naming this module's tables.
279
+ *
280
+ * A **contribution** hook: it pushes an inert descriptor into `countryReferenceRegistry`,
281
+ * an ungated registry, and carries no presence probe (D-62/D-68). Probing
282
+ * would be wrong in the dangerous direction — a switched-off module still owns
283
+ * the rows, so its country must still refuse the delete, which is the
284
+ * enumeration policy the registry states.
285
+ */
286
+ ctx.onBoot(() => {
287
+ registerWarehouseCountryReferences(lazyPort(ctx, 'countryReferenceRegistry'), ctx.cradle().emFactory);
288
+ });
289
+ /**
290
+ * What an audit row about a warehouse is called, and where the admin app shows it
291
+ * (feature 075, D-87 drain).
292
+ *
293
+ * `audit_logs` used to answer both by hand — one SQL statement naming this
294
+ * module's table, and this module's admin route spelled into its own switch.
295
+ * A read port would have been the wrong repair: `audit_logs` is a
296
+ * cross-cutting reader, and five ports into it would be five edges pointing
297
+ * from the record towards the things it records. One of the five contributors
298
+ * (`inventory`) is switchable, and `audit_logs` is `nonDeactivatable`, so that
299
+ * edge would also have taken the operator's switch away. A push costs nothing
300
+ * and reads the same for all five.
301
+ *
302
+ * A **contribution** hook: it pushes an inert resolver into
303
+ * `auditReferenceRegistry`, an ungated registry, and carries no presence probe
304
+ * (D-67/D-68). The registry's own enumeration policy is what drops this entry
305
+ * while the module is absent — probing here would make the drop survive a
306
+ * reactivation until the next restart.
307
+ */
308
+ ctx.onBoot(() => {
309
+ registerInventoryAuditReferences(lazyPort(ctx, 'auditReferenceRegistry'), ctx.cradle().emFactory);
310
+ });
311
+ }
312
+ /**
313
+ * The module's persisted entity classes, on the `./backend` subpath, as one
314
+ * array and **no named class export** (D-168).
315
+ *
316
+ * This is the shape the platform reads when the package is *installed*: the
317
+ * boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
318
+ * and the static declaration reader (`scripts/lib/package-declarations.ts`),
319
+ * which is the third source of `check:module-boundary`'s `table->owner` map and
320
+ * the package pass of `check-entity-tenant-classification`. A missing array is
321
+ * answered with `[]` — zero entities registered, no error anywhere.
322
+ *
323
+ * The order is the one `db/entities-registry.generated.ts` declared before this
324
+ * module became a package, so the registered set is the same list in the same
325
+ * sequence.
326
+ */
327
+ export const entities = [
328
+ AvailabilityNotification,
329
+ InventoryThreshold,
330
+ ProductWarehouseLowStockThreshold,
331
+ StockAllocation,
332
+ StockLevel,
333
+ WarehouseChannelAssignment,
334
+ Warehouse,
335
+ ];
336
+ /**
337
+ * The warehouse↔channel reconciler and this module's system warehouse id,
338
+ * published **by name** on `./backend`.
339
+ *
340
+ * The host's demo composition runs the reconciler, and a host program is
341
+ * composed against this package's `dist` while the ORM is registered from the
342
+ * same `entities` array above — so a filesystem path into this file's source
343
+ * would evaluate `warehouse.entity.ts` a second time and the reconciler would
344
+ * `em.create` a `WarehouseChannelAssignment` class the ORM has never heard of
345
+ * (D-160.6.1). D-168 bars an entity class from leaving by this door; a service
346
+ * and a constant are not entities, and `price_lists`' `DefaultPriceListMigrator`
347
+ * / `DEFAULT_PRICE_LIST_ID` pair is the precedent for exactly this shape.
348
+ */
349
+ export { WarehouseChannelReconciler } from './services/warehouse-channel-reconciler.js';
350
+ export { DEFAULT_WAREHOUSE_ID } from './entities/warehouse.entity.js';
351
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ import type { FastifyInstance, FastifyRequest } from 'fastify';
2
+ import type { EntityManager } from '@mikro-orm/postgresql';
3
+ import type { EventBus } from '@endora-commerce/platform/events';
4
+ import { AvailabilityWorker } from './services/availability-worker.js';
5
+ import { ThresholdSettingsMirror } from './services/threshold-settings-mirror.js';
6
+ import { LowStockAlertService, type InventoryTemplateEmailPort } from './services/low-stock-alert-service.js';
7
+ import type { SalesChannelMembershipPort } from '@endora-commerce/platform/kernel';
8
+ import type { SalesChannelResolutionPort } from '@endora-commerce/platform/kernel';
9
+ import type { SettingsReadPort } from '@endora-commerce/platform/kernel';
10
+ import type { AuditPort } from '@endora-commerce/platform/kernel';
11
+ import type { CatalogCategoryReadPort, CatalogCategoryWritePort, CatalogProductReadPort, CustomerAccountReadPort, DictionaryValidator, EmailMailerPort } from '@endora-commerce/contracts';
12
+ import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
13
+ export interface InventoryAuditContext {
14
+ actorAdminUserId: string;
15
+ impersonatedCustomerAccountId?: string | null;
16
+ ipAddress?: string | null;
17
+ userAgent?: string | null;
18
+ requestId?: string | null;
19
+ }
20
+ /**
21
+ * Composition root for the inventory module — feature 010.
22
+ *
23
+ * Adds WarehouseService + StockLevelService alongside the existing
24
+ * AvailabilityNotificationService. Routes are registered via the
25
+ * plug-in factory so test harnesses get the same wiring.
26
+ */
27
+ export interface InventoryModuleOptions {
28
+ emFactory: () => EntityManager;
29
+ /**
30
+ * The three reads and one write this module performs across a boundary
31
+ * (feature 075, Phase C). Required, not optional: `catalog` and
32
+ * `customer_accounts` are declared dependencies, and an optional port is a
33
+ * composition that silently answers without them — which is exactly what an
34
+ * entity import was.
35
+ */
36
+ catalogProducts: CatalogProductReadPort;
37
+ catalogCategories: CatalogCategoryReadPort;
38
+ catalogCategoryWrites: CatalogCategoryWritePort;
39
+ customerAccounts: CustomerAccountReadPort;
40
+ /**
41
+ * `salesChannelMembershipPort` — the sanctioned bridge accessor
42
+ * (Constitution XII) the notify-when-available seam narrows against, through
43
+ * `outOfRequestChannel`. Required for the same reason the four ports above
44
+ * are: an optional channel gate is a composition that answers without one.
45
+ */
46
+ salesChannelMembership: SalesChannelMembershipPort;
47
+ requireCustomer: (req: FastifyRequest, reply: unknown) => Promise<void>;
48
+ resolveCustomerContext: (req: FastifyRequest) => {
49
+ customerAccountId: string;
50
+ organizationId: string;
51
+ };
52
+ /** When supplied, the admin stock-level read + set routes are registered. */
53
+ requireAdmin?: RequireAdminFactory;
54
+ /** Optional event bus for `inventory.adjusted.v1` emission. */
55
+ eventBus?: EventBus;
56
+ /** Optional channel resolver — when supplied, storefront-public stock
57
+ * reads scope cumulative on-hand to the caller's channel binding. */
58
+ channelResolver?: SalesChannelResolutionPort;
59
+ /** Optional settings service used to read the inventory.display_mode key
60
+ * for the storefront-public display-mode endpoint. */
61
+ settingsService?: SettingsReadPort;
62
+ /**
63
+ * `emailMailer`, owned by `email`, as its published contract (feature 075).
64
+ * Required: the `ConsoleMailer` default this used to fall back to was a value
65
+ * import of another module's driver, and it has had no reachable caller since
66
+ * the container started resolving `emailMailer` for every composition.
67
+ */
68
+ mailer: EmailMailerPort;
69
+ /** Feature 047 — optional admin-editable template path for inventory emails. */
70
+ templateEmail?: InventoryTemplateEmailPort;
71
+ /** Channel id used to read inventory.* settings for low-stock alerts. */
72
+ settingsChannelId?: string;
73
+ /** Lazy lookup for the system-default channel id; used by the
74
+ * threshold-settings mirror. Falls back to {@link channelResolver}
75
+ * when omitted. */
76
+ resolveSystemDefaultChannelId?: () => Promise<string | null>;
77
+ dictionaryValidator?: DictionaryValidator;
78
+ /** Feature 024 — optional cross-module hook so warehouse / stock /
79
+ * threshold / CSV-import mutations land in the audit log. Tests that
80
+ * don't care about audit can omit it. */
81
+ auditLogService?: AuditPort;
82
+ /** Feature 024 — resolves the admin actor identity for audit entries. */
83
+ resolveAdminAuditContext?: (request: FastifyRequest) => {
84
+ actorAdminUserId: string;
85
+ impersonatedCustomerAccountId?: string | null;
86
+ };
87
+ /**
88
+ * Feature 026 US4 — when provided, the storefront stock-figure endpoint
89
+ * intersects its candidate warehouse set with the Organization's assigned
90
+ * warehouses. Empty / null ⇒ platform defaults apply.
91
+ */
92
+ resolveOrganizationWarehouseAllowList?: (req: FastifyRequest) => Promise<string[] | null>;
93
+ }
94
+ /**
95
+ * The three event handlers this module owns, exposed so `backend.ts` can
96
+ * register them through `ctx.subscribe` (issue #107).
97
+ *
98
+ * They were attached here with a bare `eventBus.on`, which is why a switched-off
99
+ * `inventory` still mailed back-in-stock notices, still mailed low-stock alerts
100
+ * and still wrote the mirrored threshold row.
101
+ */
102
+ export interface InventoryModuleHandle {
103
+ availabilityWorker: AvailabilityWorker;
104
+ lowStockAlertService: LowStockAlertService;
105
+ /** Absent when this composition wired no settings service. */
106
+ thresholdSettingsMirror: ThresholdSettingsMirror | undefined;
107
+ }
108
+ export interface InventoryModuleResult {
109
+ plugin: (app: FastifyInstance) => Promise<void>;
110
+ handle: InventoryModuleHandle;
111
+ }
112
+ export declare function inventoryModule(options: InventoryModuleOptions): InventoryModuleResult;
113
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/backend/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import { AvailabilityNotificationService } from './services/availability-notification-service.js';
2
+ import { AvailabilityWorker } from './services/availability-worker.js';
3
+ import { CsvStockImporter } from './services/csv-stock-importer.js';
4
+ import { ThresholdSettingsMirror } from './services/threshold-settings-mirror.js';
5
+ import { WarehouseService } from './services/warehouse-service.js';
6
+ import { StockLevelService } from './services/stock-level-service.js';
7
+ import { WarehouseChannelService } from './services/warehouse-channel-service.js';
8
+ import { ThresholdAdminService } from './services/threshold-admin-service.js';
9
+ import { LowStockAlertService } from './services/low-stock-alert-service.js';
10
+ import { registerInventoryRoutes } from './routes.js';
11
+ import { registerInventoryAdminRoutes } from './routes.admin.js';
12
+ export function inventoryModule(options) {
13
+ const mailer = options.mailer;
14
+ const availabilityWorker = new AvailabilityWorker(options.emFactory, mailer, options.catalogProducts, options.customerAccounts);
15
+ const lowStockAlertService = new LowStockAlertService(options.emFactory, mailer, options.catalogProducts, options.settingsService, options.settingsChannelId, options.templateEmail);
16
+ let thresholdSettingsMirror;
17
+ if (options.settingsService) {
18
+ // D-48 — the last branch used to be `sysDefault?.id ?? null`, which
19
+ // mirrored the threshold settings platform-wide on a branch the platform
20
+ // guarantees against. `null` here now means only what it always should
21
+ // have: this composition wired no channel resolver at all.
22
+ const resolveChannelId = options.resolveSystemDefaultChannelId ??
23
+ (async () => {
24
+ if (options.settingsChannelId)
25
+ return options.settingsChannelId;
26
+ if (!options.channelResolver)
27
+ return null;
28
+ return (await options.channelResolver.getSystemDefault()).id;
29
+ });
30
+ thresholdSettingsMirror = new ThresholdSettingsMirror(options.emFactory, options.settingsService, resolveChannelId);
31
+ }
32
+ const plugin = async (app) => {
33
+ const availabilityService = new AvailabilityNotificationService(options.emFactory, options.catalogProducts, options.customerAccounts, options.salesChannelMembership, mailer, options.templateEmail);
34
+ const warehouseChannelService = new WarehouseChannelService(options.emFactory, options.auditLogService);
35
+ const stockLevelService = new StockLevelService(options.emFactory, options.catalogProducts, options.catalogCategories, options.eventBus, options.auditLogService);
36
+ const thresholdAdminService = new ThresholdAdminService(options.emFactory, options.catalogCategories, options.catalogCategoryWrites, options.catalogProducts, options.auditLogService);
37
+ await registerInventoryRoutes(app, {
38
+ emFactory: options.emFactory,
39
+ catalogProducts: options.catalogProducts,
40
+ catalogCategories: options.catalogCategories,
41
+ customerAccounts: options.customerAccounts,
42
+ availabilityService,
43
+ requireCustomer: options.requireCustomer,
44
+ resolveCustomerContext: options.resolveCustomerContext,
45
+ warehouseChannelService,
46
+ stockLevelService,
47
+ ...(options.channelResolver ? { channelResolver: options.channelResolver } : {}),
48
+ ...(options.settingsService ? { settingsService: options.settingsService } : {}),
49
+ ...(options.resolveOrganizationWarehouseAllowList
50
+ ? { resolveOrganizationWarehouseAllowList: options.resolveOrganizationWarehouseAllowList }
51
+ : {}),
52
+ });
53
+ if (options.requireAdmin) {
54
+ const warehouseService = new WarehouseService(options.emFactory, options.dictionaryValidator, options.auditLogService);
55
+ const csvStockImporter = new CsvStockImporter(options.emFactory, options.catalogProducts, options.eventBus, options.auditLogService);
56
+ await registerInventoryAdminRoutes(app, {
57
+ emFactory: options.emFactory,
58
+ catalogProducts: options.catalogProducts,
59
+ warehouseService,
60
+ stockLevelService,
61
+ warehouseChannelService,
62
+ thresholdAdminService,
63
+ lowStockAlertService,
64
+ availabilityNotificationService: availabilityService,
65
+ csvStockImporter,
66
+ requireAdmin: options.requireAdmin,
67
+ ...(options.resolveAdminAuditContext
68
+ ? { resolveAdminAuditContext: options.resolveAdminAuditContext }
69
+ : {}),
70
+ });
71
+ }
72
+ };
73
+ return { plugin, handle: { availabilityWorker, lowStockAlertService, thresholdSettingsMirror } };
74
+ }
75
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/backend/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { type CatalogCategoryReadPort, type CatalogProductReadPort, type PromptActionTool } from '@endora-commerce/contracts';
2
+ import type { EntityManager } from '@mikro-orm/postgresql';
3
+ import type { EventBus } from '@endora-commerce/platform/events';
4
+ import type { AuditPort } from '@endora-commerce/platform/kernel';
5
+ /**
6
+ * Inventory's contribution to the prompt-assistant tool catalogue
7
+ * (feature 043, data-model §4): the warehouse resolver and the flagship
8
+ * `set_stock_level` mutation. The mutation's preview is server-computed
9
+ * from the same rows the execution will touch (FR-004), and execution
10
+ * rides `StockLevelService.setOnHand` — the exact path of the manual
11
+ * inventory screen, including its `stock_level.adjust` audit row.
12
+ */
13
+ export interface InventoryPromptToolsDeps {
14
+ emFactory: () => EntityManager;
15
+ /** `catalogProductReadPort`, owned by `catalog` (feature 075, Phase C). */
16
+ catalogProducts: CatalogProductReadPort;
17
+ /** `catalogCategoryReadPort`, owned by `catalog` — read by the stock service. */
18
+ catalogCategories: CatalogCategoryReadPort;
19
+ eventBus?: EventBus;
20
+ auditLogService?: AuditPort;
21
+ }
22
+ export declare function inventoryPromptTools(deps: InventoryPromptToolsDeps): PromptActionTool[];
23
+ //# sourceMappingURL=prompt-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-tools.d.ts","sourceRoot":"","sources":["../../src/backend/prompt-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EAItB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAMlE;;;;;;;GAOG;AAEH,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B,2EAA2E;IAC3E,eAAe,EAAE,sBAAsB,CAAC;IACxC,iFAAiF;IACjF,iBAAiB,EAAE,uBAAuB,CAAC;IAC3C,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,eAAe,CAAC,EAAE,SAAS,CAAC;CAC7B;AAQD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,wBAAwB,GAAG,gBAAgB,EAAE,CAgFvF"}