@happyvertical/smrt-inventory 0.57.17 → 0.57.18

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 (45) hide show
  1. package/AGENTS.md +19 -1
  2. package/README.md +32 -2
  3. package/dist/collections/LotCollection.d.ts +22 -0
  4. package/dist/collections/LotCollection.d.ts.map +1 -0
  5. package/dist/collections/LotCorrectionCollection.d.ts +12 -0
  6. package/dist/collections/LotCorrectionCollection.d.ts.map +1 -0
  7. package/dist/collections/LotDocumentCollection.d.ts +12 -0
  8. package/dist/collections/LotDocumentCollection.d.ts.map +1 -0
  9. package/dist/collections/LotStockLevelCollection.d.ts +21 -0
  10. package/dist/collections/LotStockLevelCollection.d.ts.map +1 -0
  11. package/dist/collections/LotUsageCollection.d.ts +18 -0
  12. package/dist/collections/LotUsageCollection.d.ts.map +1 -0
  13. package/dist/collections/index.d.ts +5 -0
  14. package/dist/collections/index.d.ts.map +1 -1
  15. package/dist/index.d.ts +4 -4
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1168 -31
  18. package/dist/index.js.map +1 -1
  19. package/dist/manifest.json +2921 -288
  20. package/dist/models/Lot.d.ts +96 -0
  21. package/dist/models/Lot.d.ts.map +1 -0
  22. package/dist/models/LotCorrection.d.ts +55 -0
  23. package/dist/models/LotCorrection.d.ts.map +1 -0
  24. package/dist/models/LotDocument.d.ts +45 -0
  25. package/dist/models/LotDocument.d.ts.map +1 -0
  26. package/dist/models/LotStockLevel.d.ts +43 -0
  27. package/dist/models/LotStockLevel.d.ts.map +1 -0
  28. package/dist/models/LotUsage.d.ts +64 -0
  29. package/dist/models/LotUsage.d.ts.map +1 -0
  30. package/dist/models/StockMovement.d.ts +7 -0
  31. package/dist/models/StockMovement.d.ts.map +1 -1
  32. package/dist/models/index.d.ts +5 -0
  33. package/dist/models/index.d.ts.map +1 -1
  34. package/dist/services/LotService.d.ts +258 -0
  35. package/dist/services/LotService.d.ts.map +1 -0
  36. package/dist/services/StockService.d.ts +25 -2
  37. package/dist/services/StockService.d.ts.map +1 -1
  38. package/dist/services/index.d.ts +2 -0
  39. package/dist/services/index.d.ts.map +1 -1
  40. package/dist/services/lot-errors.d.ts +44 -0
  41. package/dist/services/lot-errors.d.ts.map +1 -0
  42. package/dist/smrt-knowledge.json +1333 -76
  43. package/dist/types.d.ts +6 -0
  44. package/dist/types.d.ts.map +1 -1
  45. package/package.json +6 -6
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/__smrt-register__.ts","../src/models/InventoryLocation.ts","../src/collections/InventoryLocationCollection.ts","../src/models/StockLevel.ts","../src/collections/StockLevelCollection.ts","../src/models/StockMovement.ts","../src/collections/StockMovementCollection.ts","../src/recipes.ts","../src/services/StockService.ts","../src/services/dispatch-handlers.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"packageVersion\\\":\\\"0.57.17\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-inventory:InventoryLocationCollection\\\":{\\\"name\\\":\\\"inventorylocationcollection\\\",\\\"className\\\":\\\"InventoryLocationCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:InventoryLocationCollection\\\",\\\"collection\\\":\\\"inventorylocations\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/InventoryLocationCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByCode\\\":{\\\"name\\\":\\\"findByCode\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"code\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<InventoryLocation | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByKind\\\":{\\\"name\\\":\\\"findByKind\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"InventoryLocationKind\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<InventoryLocation[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByPlace\\\":{\\\"name\\\":\\\"findByPlace\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<InventoryLocation[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findActive\\\":{\\\"name\\\":\\\"findActive\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"InventoryLocationKind\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<InventoryLocation[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_locations\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"InventoryLocation\\\",\\\"exportName\\\":\\\"InventoryLocationCollection\\\",\\\"collectionExportName\\\":\\\"InventoryLocationCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_locations\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_locations\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"code\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"kind\\\\\\\" TEXT DEFAULT 'warehouse',\\\\n \\\\\\\"place_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"active\\\\\\\" BOOLEAN DEFAULT TRUE\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"warehouse\\\"},\\\"place_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"active\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":true}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_locations_code_tenant_id_idx\\\",\\\"columns\\\":[\\\"code\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_locations_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_locations_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"401c28a1\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:StockLevelCollection\\\":{\\\"name\\\":\\\"stocklevelcollection\\\",\\\"className\\\":\\\"StockLevelCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:StockLevelCollection\\\",\\\"collection\\\":\\\"stocklevels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/StockLevelCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"getLevel\\\":{\\\"name\\\":\\\"getLevel\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"skuId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"state\\\",\\\"type\\\":\\\"StockState\\\",\\\"optional\\\":true,\\\"default\\\":\\\"available\\\"}],\\\"returnType\\\":\\\"Promise<StockLevel | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBySku\\\":{\\\"name\\\":\\\"findBySku\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"skuId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockLevel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByLocation\\\":{\\\"name\\\":\\\"findByLocation\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockLevel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBelowReorderPoint\\\":{\\\"name\\\":\\\"findBelowReorderPoint\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<StockLevel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"totalForSku\\\":{\\\"name\\\":\\\"totalForSku\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"skuId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"state\\\",\\\"type\\\":\\\"StockState\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"totalForLocation\\\":{\\\"name\\\":\\\"totalForLocation\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"state\\\",\\\"type\\\":\\\"StockState\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_stock_levels\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"StockLevel\\\",\\\"exportName\\\":\\\"StockLevelCollection\\\",\\\"collectionExportName\\\":\\\"StockLevelCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_stock_levels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_stock_levels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"state\\\\\\\" TEXT NOT NULL DEFAULT 'available',\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"reorder_point\\\\\\\" REAL,\\\\n \\\\\\\"reorder_quantity\\\\\\\" REAL\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"available\\\"},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reorder_point\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reorder_quantity\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_stock_levels_sku_id_location_id_idx\\\",\\\"columns\\\":[\\\"sku_id\\\",\\\"location_id\\\",\\\"state\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_stock_levels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_stock_levels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"02387935\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:StockMovementCollection\\\":{\\\"name\\\":\\\"stockmovementcollection\\\",\\\"className\\\":\\\"StockMovementCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:StockMovementCollection\\\",\\\"collection\\\":\\\"stockmovements\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/StockMovementCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findBySku\\\":{\\\"name\\\":\\\"findBySku\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"skuId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByLocation\\\":{\\\"name\\\":\\\"findByLocation\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBySource\\\":{\\\"name\\\":\\\"findBySource\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"sourceType\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"sourceId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByReason\\\":{\\\"name\\\":\\\"findByReason\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"reasonCode\\\",\\\"type\\\":\\\"StockMovementReason\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_stock_movements\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"StockMovement\\\",\\\"exportName\\\":\\\"StockMovementCollection\\\",\\\"collectionExportName\\\":\\\"StockMovementCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_stock_movements\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_stock_movements\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"from_state\\\\\\\" TEXT,\\\\n \\\\\\\"to_state\\\\\\\" TEXT,\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"reason_code\\\\\\\" TEXT NOT NULL DEFAULT 'adjustment',\\\\n \\\\\\\"source_type\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"actor_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"note\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"occurred_at\\\\\\\" TIMESTAMP\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"from_state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"to_state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"adjustment\\\"},\\\"source_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"actor_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"note\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"occurred_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_stock_movements_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_actor_profile_id_idx\\\",\\\"columns\\\":[\\\"actor_profile_id\\\"]}],\\\"version\\\":\\\"eff1027e\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:InventoryLocation\\\":{\\\"name\\\":\\\"inventorylocation\\\",\\\"className\\\":\\\"InventoryLocation\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:InventoryLocation\\\",\\\"collection\\\":\\\"inventorylocations\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/InventoryLocation.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"code\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"A short code for the place stock is kept, for example MAIN.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"A short code for the place stock is kept, for example MAIN.\\\"}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What you call the place, for example Main warehouse.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What you call the place, for example Main warehouse.\\\"}},\\\"kind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"warehouse\\\",\\\"description\\\":\\\"What sort of place it is, for example a warehouse or a shop floor.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What sort of place it is, for example a warehouse or a shop floor.\\\"}},\\\"placeId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"active\\\":{\\\"type\\\":\\\"boolean\\\",\\\"required\\\":false,\\\"default\\\":true}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_locations\\\",\\\"conflictColumns\\\":[\\\"code\\\",\\\"tenant_id\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":true,\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"InventoryLocation\\\",\\\"collectionExportName\\\":\\\"InventoryLocationCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"code\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_locations\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_locations\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"code\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"kind\\\\\\\" TEXT DEFAULT 'warehouse',\\\\n \\\\\\\"place_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"active\\\\\\\" BOOLEAN DEFAULT TRUE\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"warehouse\\\"},\\\"place_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"active\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":true}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_locations_code_tenant_id_idx\\\",\\\"columns\\\":[\\\"code\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_locations_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_locations_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"401c28a1\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:StockLevel\\\":{\\\"name\\\":\\\"stocklevel\\\",\\\"className\\\":\\\"StockLevel\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:StockLevel\\\",\\\"collection\\\":\\\"stocklevels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/StockLevel.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"skuId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The item being counted.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The item being counted.\\\"}},\\\"locationId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"Where the stock is kept.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"Where the stock is kept.\\\"}},\\\"state\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"available\\\",\\\"description\\\":\\\"The state of this stock: available, allocated, wip, qc_hold or damaged.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The state of this stock: available, allocated, wip, qc_hold or damaged.\\\"},\\\"enum\\\":[\\\"available\\\",\\\"allocated\\\",\\\"wip\\\",\\\"qc_hold\\\",\\\"damaged\\\"]},\\\"qty\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How many are on hand.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How many are on hand.\\\"}},\\\"reorderPoint\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"reorderQuantity\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_stock_levels\\\",\\\"conflictColumns\\\":[\\\"sku_id\\\",\\\"location_id\\\",\\\"state\\\",\\\"tenant_id\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"StockLevel\\\",\\\"collectionExportName\\\":\\\"StockLevelCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"skuId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"locationId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"state\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_stock_levels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_stock_levels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"state\\\\\\\" TEXT NOT NULL DEFAULT 'available',\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"reorder_point\\\\\\\" REAL,\\\\n \\\\\\\"reorder_quantity\\\\\\\" REAL\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"available\\\"},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reorder_point\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reorder_quantity\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_stock_levels_sku_id_location_id_idx\\\",\\\"columns\\\":[\\\"sku_id\\\",\\\"location_id\\\",\\\"state\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_stock_levels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_stock_levels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"02387935\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:StockMovement\\\":{\\\"name\\\":\\\"stockmovement\\\",\\\"className\\\":\\\"StockMovement\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:StockMovement\\\",\\\"collection\\\":\\\"stockmovements\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/StockMovement.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"skuId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The item that moved.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The item that moved.\\\"}},\\\"locationId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The place it moved at.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The place it moved at.\\\"}},\\\"fromState\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"What it was before, for example available or damaged.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What it was before, for example available or damaged.\\\"},\\\"enum\\\":[\\\"available\\\",\\\"allocated\\\",\\\"wip\\\",\\\"qc_hold\\\",\\\"damaged\\\"]},\\\"toState\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"What it became.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What it became.\\\"},\\\"enum\\\":[\\\"available\\\",\\\"allocated\\\",\\\"wip\\\",\\\"qc_hold\\\",\\\"damaged\\\"]},\\\"qty\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How many moved.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How many moved.\\\"}},\\\"reasonCode\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"adjustment\\\",\\\"description\\\":\\\"Why it moved, for example adjustment, sale or return.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"Why it moved, for example adjustment, sale or return.\\\"}},\\\"sourceType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"sourceId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"actorProfileId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-profiles:Profile\\\"},\\\"note\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"Anything worth remembering about this movement.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Anything worth remembering about this movement.\\\"}},\\\"occurredAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When it happened.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When it happened.\\\"}}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_stock_movements\\\",\\\"conflictColumns\\\":[\\\"id\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"StockMovement\\\",\\\"collectionExportName\\\":\\\"StockMovementCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"skuId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"locationId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"reasonCode\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_stock_movements\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_stock_movements\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"from_state\\\\\\\" TEXT,\\\\n \\\\\\\"to_state\\\\\\\" TEXT,\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"reason_code\\\\\\\" TEXT NOT NULL DEFAULT 'adjustment',\\\\n \\\\\\\"source_type\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"actor_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"note\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"occurred_at\\\\\\\" TIMESTAMP\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"from_state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"to_state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"adjustment\\\"},\\\"source_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"actor_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"note\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"occurred_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_stock_movements_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_actor_profile_id_idx\\\",\\\"columns\\\":[\\\"actor_profile_id\\\"]}],\\\"version\\\":\\\"eff1027e\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"recipes\\\":[{\\\"id\\\":\\\"inventory.stock\\\",\\\"className\\\":\\\"StockRecipe\\\",\\\"label\\\":\\\"Inventory\\\",\\\"summary\\\":\\\"Keep count of how many of each product you have.\\\",\\\"synonyms\\\":[\\\"stock\\\",\\\"quantity\\\",\\\"on hand\\\"],\\\"models\\\":[\\\"@happyvertical/smrt-inventory:StockLevel\\\",\\\"@happyvertical/smrt-inventory:InventoryLocation\\\",\\\"@happyvertical/smrt-inventory:StockMovement\\\"],\\\"nav\\\":[{\\\"label\\\":\\\"Stock levels\\\",\\\"model\\\":\\\"@happyvertical/smrt-inventory:StockLevel\\\",\\\"icon\\\":\\\"archive\\\",\\\"description\\\":\\\"How much of each item you have on hand right now.\\\",\\\"noun\\\":\\\"stock entry\\\"},{\\\"label\\\":\\\"Locations\\\",\\\"model\\\":\\\"@happyvertical/smrt-inventory:InventoryLocation\\\",\\\"icon\\\":\\\"home\\\",\\\"description\\\":\\\"The places you keep stock, like shelves, rooms or vans.\\\"},{\\\"label\\\":\\\"Stock movements\\\",\\\"model\\\":\\\"@happyvertical/smrt-inventory:StockMovement\\\",\\\"icon\\\":\\\"truck\\\",\\\"description\\\":\\\"Every time stock came in, went out or moved.\\\"}],\\\"requires\\\":[],\\\"requiresAny\\\":[[\\\"products.simple\\\",\\\"products.clothing\\\"]],\\\"section\\\":{\\\"id\\\":\\\"catalog\\\",\\\"label\\\":\\\"Catalog\\\",\\\"icon\\\":\\\"package\\\",\\\"description\\\":\\\"Products, ingredients and the stock you hold.\\\"},\\\"options\\\":{\\\"@happyvertical/smrt-inventory:StockLevel\\\":{\\\"fields\\\":{\\\"reorderPoint\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"reorderQuantity\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-inventory:InventoryLocation\\\":{\\\"fields\\\":{\\\"placeId\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"active\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-inventory:StockMovement\\\":{\\\"fields\\\":{\\\"sourceType\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"sourceId\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"actorProfileId\\\":{\\\"visibility\\\":\\\"hidden\\\"}}}},\\\"help\\\":{\\\"markdown\\\":\\\"## Overview\\\\n\\\\nInventory keeps count of how many of each product you have. Each count is a\\\\nstock level: an item, the place it is kept and how many are on hand. Stock can\\\\nsit in more than one place, and every change is recorded as a stock movement so\\\\nthere is a trail.\\\\n\\\\n## Tasks\\\\n\\\\n### Count what you have\\\\n\\\\n1. Create a stock level for the item and the place it is kept.\\\\n2. Set **{field:qty}** to how many you have on hand.\\\\n3. Set **{field:state}** if the stock is not available to sell, for example\\\\n allocated or on quality hold.\\\\n\\\\n### Correct a count\\\\n\\\\n1. Find the stock level for the item.\\\\n2. Set **{field:qty}** to what you really have. Record why as a stock movement.\\\\n\\\\n### Keep stock in more than one place\\\\n\\\\n1. Add a location with a **{field:code}** and a **{field:name}**, and say what\\\\n sort it is in **{field:kind}**.\\\\n2. Create stock levels against that location.\\\\n\\\",\\\"fieldRefs\\\":[\\\"code\\\",\\\"kind\\\",\\\"name\\\",\\\"qty\\\",\\\"state\\\"]},\\\"demo\\\":{\\\"mode\\\":\\\"server\\\",\\\"reasons\\\":[\\\"Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624).\\\"]}}],\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\"],\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","/**\n * InventoryLocation — a physical or virtual place where stock can sit.\n *\n * `kind` is intentionally a free-form string (see\n * {@link InventoryLocationKind}). Common values are `'warehouse'`,\n * `'factory'`, `'retail'`, `'in_transit'`, or `'virtual'`, but the\n * framework does not special-case any of them. Each application is free\n * to extend the vocabulary.\n *\n * Locations may optionally point at a place row in\n * `@happyvertical/smrt-places` via the plain-string `placeId` — useful\n * when an InventoryLocation maps to a real-world address or POI. The\n * reference is a plain string id, not a `@foreignKey()`, to avoid a\n * cross-package dependency on `smrt-places`.\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { InventoryLocationKind } from '../types.js';\n\n/**\n * Options accepted by the {@link InventoryLocation} constructor.\n */\nexport interface InventoryLocationOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n code?: string;\n name?: string;\n kind?: InventoryLocationKind;\n placeId?: string;\n active?: boolean;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_locations',\n conflictColumns: ['code', 'tenant_id'],\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class InventoryLocation extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the location record is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Short stable identifier (`'WH-EAST'`, `'STORE-42'`, `'IN-TRANSIT'`).\n * Together with `tenantId` this is the natural key.\n */\n @field({\n required: true,\n description: 'A short code for the place stock is kept, for example MAIN.',\n })\n code: string = '';\n\n /** Display name for UIs. */\n @field({\n description: 'What you call the place, for example Main warehouse.',\n })\n name: string = '';\n\n /**\n * Open-ended classifier (`'warehouse'`, `'factory'`, `'retail'`,\n * `'in_transit'`, `'virtual'`, or anything else your domain needs).\n * The framework never branches on this value.\n */\n @field({\n description:\n 'What sort of place it is, for example a warehouse or a shop floor.',\n })\n kind: InventoryLocationKind = 'warehouse';\n\n /**\n * Optional plain-string reference to a `Place.id` in\n * `@happyvertical/smrt-places`. Cross-package id; intentionally not a\n * `@foreignKey()` so this package can be used without `smrt-places`\n * installed.\n */\n placeId: string = '';\n\n /** Soft-active flag — inactive locations stay queryable for history. */\n active: boolean = true;\n\n constructor(options: InventoryLocationOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.code !== undefined) this.code = options.code;\n if (options.name !== undefined) this.name = options.name;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.placeId !== undefined) this.placeId = options.placeId;\n if (options.active !== undefined) this.active = options.active;\n }\n}\n","/**\n * InventoryLocationCollection — query helpers for {@link InventoryLocation}.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { InventoryLocation } from '../models/InventoryLocation.js';\nimport type { InventoryLocationKind } from '../types.js';\n\nexport class InventoryLocationCollection extends SmrtCollection<InventoryLocation> {\n static readonly _itemClass = InventoryLocation;\n\n /**\n * Look up a location by its tenant-scoped `code`. Returns `null` when\n * no row matches.\n */\n async findByCode(code: string): Promise<InventoryLocation | null> {\n const matches = await this.list({ where: { code }, limit: 1 });\n return matches[0] ?? null;\n }\n\n /**\n * Find every location classified as the given kind (`'warehouse'`,\n * `'factory'`, `'retail'`, `'in_transit'`, …).\n */\n async findByKind(kind: InventoryLocationKind): Promise<InventoryLocation[]> {\n return this.list({ where: { kind }, orderBy: 'code ASC' });\n }\n\n /**\n * Find every location linked to a particular `Place.id` from\n * `@happyvertical/smrt-places`. Returns an empty array when no row\n * references the place.\n */\n async findByPlace(placeId: string): Promise<InventoryLocation[]> {\n if (!placeId) return [];\n return this.list({ where: { placeId }, orderBy: 'code ASC' });\n }\n\n /** Find every active location, optionally narrowed by kind. */\n async findActive(kind?: InventoryLocationKind): Promise<InventoryLocation[]> {\n const where: Record<string, unknown> = { active: true };\n if (kind) where.kind = kind;\n return this.list({ where, orderBy: 'code ASC' });\n }\n}\n","/**\n * StockLevel — materialized quantity at a `(skuId, locationId, state)` tuple.\n *\n * StockLevel is the live, mutable view of on-hand stock. There is at most\n * one row per `(skuId, locationId, state)` per tenant; the natural key\n * (`conflictColumns`) gives us idempotent upserts. Each row's `qty`\n * floats up and down as the {@link StockService} processes\n * receive/reserve/release/fulfill/transfer/adjust calls.\n *\n * **Do not call `create()` or `save()` on StockLevel directly.** All\n * mutations must go through {@link StockService}, which guarantees that\n * the level change and the corresponding append-only StockMovement land\n * together. Direct writes will silently desync the audit ledger and make\n * cycle counts unreliable.\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { StockState } from '../types.js';\n\n/**\n * Options accepted by the {@link StockLevel} constructor.\n */\nexport interface StockLevelOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n skuId?: string;\n locationId?: string;\n state?: StockState;\n qty?: number;\n reorderPoint?: number | null;\n reorderQuantity?: number | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_stock_levels',\n conflictColumns: ['sku_id', 'location_id', 'state', 'tenant_id'],\n // StockLevel is materialized state, written only by StockService.\n // Mirror the read-only api/mcp posture on the CLI — `cli: true` would\n // generate create/update/delete subcommands that let a CLI user\n // mutate `qty` (or delete a row) without writing a paired\n // StockMovement, silently desyncing the audit ledger from the\n // materialized balance. The Gotchas section in CLAUDE.md spells out\n // the \"never call StockLevel.save() directly\" rule; the CLI must\n // follow the same constraint.\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class StockLevel extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the level row is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Plain string reference to the {@link Sku} this row tracks. */\n @field({\n required: true,\n description: 'The item being counted.',\n })\n skuId: string = '';\n\n /** Plain string reference to the {@link InventoryLocation} this row tracks. */\n @field({\n required: true,\n description: 'Where the stock is kept.',\n })\n locationId: string = '';\n\n /** Logical state — `available`, `allocated`, `wip`, `qc_hold`, `damaged`. */\n @field({\n required: true,\n description:\n 'The state of this stock: available, allocated, wip, qc_hold or damaged.',\n })\n state: StockState = 'available';\n\n /**\n * Current quantity. Fractional values are allowed (`= 0.0`) for\n * domains that count in units of measure other than whole pieces\n * (kilograms, litres, metres).\n */\n @field({ type: 'decimal', description: 'How many are on hand.' })\n qty: number = 0.0;\n\n /** Available-stock threshold; null disables reorder monitoring. */\n @field({ type: 'decimal', nullable: true })\n reorderPoint: number | null = null;\n\n /** Optional suggested replenishment quantity, independent of stock balance. */\n @field({ type: 'decimal', nullable: true })\n reorderQuantity: number | null = null;\n\n constructor(options: StockLevelOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.skuId !== undefined) this.skuId = options.skuId;\n if (options.locationId !== undefined) this.locationId = options.locationId;\n if (options.state !== undefined) this.state = options.state;\n if (options.qty !== undefined) this.qty = options.qty;\n if (options.reorderPoint !== undefined)\n this.reorderPoint = options.reorderPoint;\n if (options.reorderQuantity !== undefined)\n this.reorderQuantity = options.reorderQuantity;\n }\n}\n","/**\n * StockLevelCollection — read helpers and balance aggregations.\n *\n * Mutations live in {@link StockService}. The collection here is for\n * reading the materialized view only; callers that want to change\n * `qty` must go through the service so the StockMovement audit row is\n * also written.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { StockLevel } from '../models/StockLevel.js';\nimport type { StockState } from '../types.js';\n\nexport class StockLevelCollection extends SmrtCollection<StockLevel> {\n static readonly _itemClass = StockLevel;\n\n /**\n * Fetch the level row for a `(skuId, locationId, state)` tuple, or\n * `null` when the row has never been written. State defaults to\n * `'available'` because that is the common case (selling / picking\n * decisions are driven by available stock).\n */\n async getLevel(\n skuId: string,\n locationId: string,\n state: StockState = 'available',\n ): Promise<StockLevel | null> {\n const matches = await this.list({\n where: { skuId, locationId, state },\n limit: 1,\n });\n return matches[0] ?? null;\n }\n\n /**\n * Return every level row for the given SKU across all locations and\n * states. Useful for \"where is this SKU?\" admin screens.\n */\n async findBySku(skuId: string): Promise<StockLevel[]> {\n return this.list({ where: { skuId } });\n }\n\n /**\n * Return every level row at the given location. Useful for \"what is\n * in this warehouse?\" reports.\n */\n async findByLocation(locationId: string): Promise<StockLevel[]> {\n return this.list({ where: { locationId } });\n }\n\n /**\n * Available rows strictly below their configured reorder point.\n * Reads use the public collection pipeline to preserve tenant filtering.\n */\n async findBelowReorderPoint(locationId?: string): Promise<StockLevel[]> {\n const where: Record<string, unknown> = { state: 'available' };\n if (locationId !== undefined) where.locationId = locationId;\n const levels = await this.list({ where });\n return levels.filter(\n (level) =>\n level.reorderPoint !== null &&\n Number(level.qty) < Number(level.reorderPoint),\n );\n }\n\n /**\n * Sum `qty` across all level rows for the given SKU. Pass `state` to\n * narrow the sum to one logical state (e.g. only `available`);\n * omit it for grand total across all states.\n */\n async totalForSku(skuId: string, state?: StockState): Promise<number> {\n const where: Record<string, unknown> = { skuId };\n if (state) where.state = state;\n const levels = await this.list({ where });\n return levels.reduce((sum, row) => sum + Number(row.qty ?? 0), 0);\n }\n\n /**\n * Sum `qty` across all level rows at the given location, optionally\n * narrowed by state.\n */\n async totalForLocation(\n locationId: string,\n state?: StockState,\n ): Promise<number> {\n const where: Record<string, unknown> = { locationId };\n if (state) where.state = state;\n const levels = await this.list({ where });\n return levels.reduce((sum, row) => sum + Number(row.qty ?? 0), 0);\n }\n}\n","/**\n * StockMovement — append-only audit row written for every stock mutation.\n *\n * Every call into {@link StockService} produces exactly one StockMovement\n * row (or two for `transfer`, one per leg). These rows are the ledger of\n * record: balances on {@link StockLevel} are derived state that could\n * always, in principle, be reconstructed by replaying movements in\n * order.\n *\n * **Movements are append-only.** The package treats updates as a bug and\n * relies on this for cycle-count reconciliation, audit, and source-system\n * attribution. Never call `save()` on a previously-persisted StockMovement\n * with mutated fields, and never let CRUD UIs expose update/delete on the\n * table.\n *\n * Cross-package attribution lives in `sourceType` + `sourceId` so a\n * downstream package can write `'Contract'` + the contract id when it\n * reserves stock, then later query \"which movements were caused by\n * contract X?\" without joining across the framework.\n *\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { StockMovementReason, StockState } from '../types.js';\n\n/**\n * Options accepted by the {@link StockMovement} constructor.\n */\nexport interface StockMovementOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n skuId?: string;\n locationId?: string;\n fromState?: StockState | null;\n toState?: StockState | null;\n qty?: number;\n reasonCode?: StockMovementReason;\n sourceType?: string;\n sourceId?: string;\n actorProfileId?: string | null;\n note?: string;\n occurredAt?: Date | string;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_stock_movements',\n // Append-only: the natural key is the surrogate id, so updates can\n // never collide on conflictColumns. Setting `id` explicitly here\n // documents the intent and prevents future contributors from\n // accidentally adding a \"domain natural key\" that would let upserts\n // overwrite history.\n conflictColumns: ['id'],\n // Movements are an audit log — never mutate or delete via generated\n // CRUD. Reads are fine for reporting and admin tooling. CLI follows\n // the same posture as api/mcp; `cli: true` would generate\n // create/update/delete subcommands that could rewrite or remove\n // audit rows from the shell, defeating the append-only invariant\n // documented in CLAUDE.md.\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class StockMovement extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the movement is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Plain string reference to the {@link Sku} being moved. */\n @field({ required: true, description: 'The item that moved.' })\n skuId: string = '';\n\n /** Plain string reference to the {@link InventoryLocation} being mutated. */\n @field({ required: true, description: 'The place it moved at.' })\n locationId: string = '';\n\n /**\n * Origin state for transitions (e.g. `available` → `allocated` for a\n * reservation). `null` indicates \"no origin\" — used when stock enters\n * the system fresh via {@link StockService.receive} or production.\n */\n @field({\n description: 'What it was before, for example available or damaged.',\n })\n fromState: StockState | null = null;\n\n /**\n * Destination state. `null` indicates \"no destination\" — used for\n * fulfilment, where stock leaves the building entirely.\n */\n @field({ description: 'What it became.' })\n toState: StockState | null = null;\n\n /** Quantity moved. Always positive; the direction is encoded by from/to. */\n @field({ type: 'decimal', description: 'How many moved.' })\n qty: number = 0.0;\n\n /**\n * Why the movement happened (see {@link StockMovementReason}). Drawn\n * from the canonical list when emitted by {@link StockService}; free-form\n * strings are allowed for vertical-specific reasons.\n */\n @field({\n required: true,\n description: 'Why it moved, for example adjustment, sale or return.',\n })\n reasonCode: StockMovementReason = 'adjustment';\n\n /**\n * Cross-package attribution tag — e.g. `'Contract'`, `'Fulfillment'`,\n * `'ProductionOrder'`, `'CycleCount'`. The package writing the\n * movement decides what tag makes sense; readers can group by\n * `(sourceType, sourceId)` to reconstruct \"what caused this\".\n */\n sourceType: string = '';\n\n /**\n * Cross-package id of the row that caused this movement. Plain string;\n * the framework never dereferences it.\n */\n sourceId: string = '';\n\n /** Profile responsible for this movement; null for unattributed automation. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n actorProfileId: string | null = null;\n\n /** Optional free-form note shown in audit UIs. */\n @field({ description: 'Anything worth remembering about this movement.' })\n note: string = '';\n\n /**\n * When the movement happened. Set to `now` at write time; explicit\n * values are allowed when back-dating an import.\n */\n @field({ description: 'When it happened.' })\n occurredAt: Date = new Date();\n\n constructor(options: StockMovementOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.skuId !== undefined) this.skuId = options.skuId;\n if (options.locationId !== undefined) this.locationId = options.locationId;\n if (options.fromState !== undefined) this.fromState = options.fromState;\n if (options.toState !== undefined) this.toState = options.toState;\n if (options.qty !== undefined) this.qty = options.qty;\n if (options.reasonCode !== undefined) this.reasonCode = options.reasonCode;\n if (options.sourceType !== undefined) this.sourceType = options.sourceType;\n if (options.sourceId !== undefined) this.sourceId = options.sourceId;\n if (options.actorProfileId !== undefined)\n this.actorProfileId = options.actorProfileId;\n if (options.note !== undefined) this.note = options.note;\n if (options.occurredAt !== undefined) {\n this.occurredAt =\n options.occurredAt instanceof Date\n ? options.occurredAt\n : new Date(options.occurredAt);\n }\n }\n}\n","/**\n * StockMovementCollection — read-only access to the append-only audit log.\n *\n * Treat this collection as a ledger. The `StockService` is the only\n * sanctioned writer; query helpers here exist so reporting code, audit\n * UIs, and cycle-count tooling can reconstruct history.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { StockMovement } from '../models/StockMovement.js';\nimport type { StockMovementReason } from '../types.js';\n\nexport class StockMovementCollection extends SmrtCollection<StockMovement> {\n static readonly _itemClass = StockMovement;\n\n /**\n * Return every movement for the given SKU, newest first. Useful for a\n * per-SKU audit trail.\n */\n async findBySku(skuId: string): Promise<StockMovement[]> {\n return this.list({ where: { skuId }, orderBy: 'occurredAt DESC' });\n }\n\n /**\n * Return every movement at the given location, newest first. Useful\n * for a per-warehouse audit trail.\n */\n async findByLocation(locationId: string): Promise<StockMovement[]> {\n return this.list({\n where: { locationId },\n orderBy: 'occurredAt DESC',\n });\n }\n\n /**\n * Return every movement attributed to the given upstream source — for\n * example `findBySource('Contract', contract.id)` returns every\n * movement caused by the reservation/fulfilment/release of that\n * contract. Newest first.\n */\n async findBySource(\n sourceType: string,\n sourceId: string,\n ): Promise<StockMovement[]> {\n return this.list({\n where: { sourceType, sourceId },\n orderBy: 'occurredAt DESC',\n });\n }\n\n /**\n * Return every movement with the given reason code (`'receipt'`,\n * `'reservation'`, `'adjustment'`, …). Newest first.\n */\n async findByReason(\n reasonCode: StockMovementReason,\n ): Promise<StockMovement[]> {\n return this.list({\n where: { reasonCode },\n orderBy: 'occurredAt DESC',\n });\n }\n}\n","/**\n * Declared recipes for smrt-inventory (#3590, #3604): user-facing units of\n * functionality an app or agent can pick instead of the whole package.\n * The scanner reads these statics into the `recipes` array of `manifest.json`\n * and `smrt-knowledge.json`; nothing here runs at that point.\n *\n * @packageDocumentation\n */\n\nimport { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { InventoryLocation } from './models/InventoryLocation.js';\nimport { StockLevel } from './models/StockLevel.js';\nimport { StockMovement } from './models/StockMovement.js';\n\n/** Inventory: Keep count of how many of each product you have. */\nexport class StockRecipe extends SmrtRecipe {\n static id = 'inventory.stock';\n static help = './stock.recipe.md';\n static label = 'Inventory';\n static summary = 'Keep count of how many of each product you have.';\n static synonyms = ['stock', 'quantity', 'on hand'];\n static section = {\n id: 'catalog',\n label: 'Catalog',\n icon: 'package',\n description: 'Products, ingredients and the stock you hold.',\n };\n static models = [StockLevel, InventoryLocation, StockMovement];\n static nav = [\n {\n label: 'Stock levels',\n model: StockLevel,\n icon: 'archive',\n description: 'How much of each item you have on hand right now.',\n noun: 'stock entry',\n },\n {\n label: 'Locations',\n model: InventoryLocation,\n icon: 'home',\n description: 'The places you keep stock, like shelves, rooms or vans.',\n },\n {\n label: 'Stock movements',\n model: StockMovement,\n icon: 'truck',\n description: 'Every time stock came in, went out or moved.',\n },\n ];\n static requiresAny = [['products.simple', 'products.clothing']];\n static options = {\n StockLevel: {\n fields: {\n reorderPoint: { visibility: 'hidden' },\n reorderQuantity: { visibility: 'hidden' },\n },\n },\n InventoryLocation: {\n fields: {\n placeId: { visibility: 'hidden' },\n active: { visibility: 'hidden' },\n },\n },\n StockMovement: {\n fields: {\n sourceType: { visibility: 'hidden' },\n sourceId: { visibility: 'hidden' },\n actorProfileId: { visibility: 'hidden' },\n },\n },\n } as const;\n}\n","/**\n * StockService — the only sanctioned way to mutate stock.\n *\n * Every mutation goes through one of six methods (`receive`, `reserve`,\n * `release`, `fulfill`, `transfer`, `adjust`). Each one:\n *\n * 1. Updates the materialized {@link StockLevel} row(s) for the affected\n * `(skuId, locationId, state)` tuples via the collection's upsert path.\n * 2. Writes exactly one append-only {@link StockMovement} (or two for\n * `transfer`, one per leg) carrying the reason, source attribution,\n * quantity, and from/to state transition.\n *\n * **Atomicity**: each method runs every write inside a single database\n * transaction (`db.transaction(...)` on `@happyvertical/sql >= 0.74.0`).\n * Partial failure — e.g. the level write succeeds but the movement\n * write throws — rolls the entire mutation back, so the materialized\n * balance and the audit ledger never disagree. `transfer` writes both\n * legs (source out, destination in) plus both movement rows in one tx,\n * so a failure mid-`transfer` is also fully rolled back.\n *\n * If the underlying adapter does not expose `transaction()` (rare —\n * sqlite, postgres, and duckdb all do as of 0.74.0; the JSON adapter\n * does too), the service degrades to serial writes and emits a one-time\n * `console.warn`. Tests and consumers that observe that warning should\n * upgrade their adapter.\n *\n * Callers should never reach into the level or movement collections\n * directly to mutate balances — doing so silently desyncs the audit\n * ledger and breaks cycle counts.\n *\n * Concurrency: each method is a read-modify-write on the underlying\n * StockLevel row. Awaited (serial) callers always see a consistent\n * balance. Unawaited `Promise.all([reserve, reserve, ...])` against the\n * same `(skuId, locationId)` can still over-allocate — the per-tx\n * locking guarantees atomicity of each individual call, not isolation\n * across concurrent transactions. Callers that need hard atomicity\n * across concurrent reservations should serialise upstream (e.g. via\n * the job runner from `@happyvertical/smrt-jobs`).\n *\n * @packageDocumentation\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport { type DatabaseConfig, resolveDatabase } from '@happyvertical/smrt-core';\nimport {\n InventoryLocationCollection,\n StockLevelCollection,\n StockMovementCollection,\n} from '../collections/index.js';\nimport type { StockLevel } from '../models/StockLevel.js';\nimport type { StockMovementReason, StockState } from '../types.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Thrown by {@link StockService.reserve} (and {@link StockService.fulfill},\n * {@link StockService.transfer}) when the caller asks to move more stock\n * than the source state currently holds. Carries enough context for a\n * caller to surface a meaningful UI message and decide whether to retry,\n * backorder, or cancel.\n */\nexport class InsufficientStockError extends Error {\n override name = 'InsufficientStockError';\n\n constructor(\n public readonly skuId: string,\n public readonly locationId: string,\n public readonly state: StockState,\n public readonly requested: number,\n public readonly available: number,\n ) {\n super(\n `Insufficient stock: sku=${skuId} location=${locationId} state=${state} ` +\n `requested=${requested} available=${available}`,\n );\n }\n}\n\n/**\n * Options shared by every {@link StockService} method that wants to leave\n * an audit attribution behind. Pairs neatly with the cross-package\n * pattern in {@link StockMovement.sourceType} / {@link StockMovement.sourceId}.\n */\nexport interface StockMutationOptions {\n /** Cross-package tag, e.g. `'Contract'`, `'Fulfillment'`, `'CycleCount'`. */\n sourceType?: string;\n /** Cross-package id of the row that caused this mutation. */\n sourceId?: string;\n /** Trusted actor attribution; null for unattended or legacy callers. */\n actorProfileId?: string | null;\n /** Free-form note shown in audit UIs. */\n note?: string;\n /**\n * Override the reason code stamped on the {@link StockMovement}. Each\n * method picks a sensible default; explicit overrides are useful when a\n * vertical wants to flag a more specific reason (e.g. `'return'`\n * instead of `'receipt'`).\n */\n reasonCode?: StockMovementReason;\n}\n\n/**\n * Options accepted by the {@link StockService} factory.\n */\nexport interface StockServiceOptions {\n /**\n * Database to read/write through. Accepts the same shapes that\n * `SmrtCollection.create({ db })` accepts — a `DatabaseInterface`, a\n * connection-string URL, or a `{ type, url }` config object. Reused by\n * the internal collections so the service, level reads, and movement\n * writes always hit the same connection / pool.\n */\n db: DatabaseConfig;\n}\n\ninterface AdjustLevelOptions {\n skuId: string;\n locationId: string;\n state: StockState;\n delta: number;\n enforceNonNegative?: boolean;\n}\n\ninterface WriteMovementOptions {\n skuId: string;\n locationId: string;\n fromState: StockState | null;\n toState: StockState | null;\n qty: number;\n reasonCode: StockMovementReason;\n sourceType?: string;\n sourceId?: string;\n actorProfileId?: string | null;\n note?: string;\n}\n\n/**\n * Sanctioned stock-mutation surface.\n *\n * Construct via {@link createStockService} — the static factory wires up\n * the underlying collections and shares one database connection across\n * level reads and movement writes.\n *\n * @example\n * ```typescript\n * const service = await createStockService({ db });\n * await service.receive(sku.id, warehouse.id, 100, {\n * sourceType: 'PurchaseOrder',\n * sourceId: po.id,\n * });\n * await service.reserve(sku.id, warehouse.id, 10, {\n * sourceType: 'Contract',\n * sourceId: order.id,\n * });\n * await service.fulfill(sku.id, warehouse.id, 10, {\n * sourceType: 'Fulfillment',\n * sourceId: fulfillment.id,\n * });\n * ```\n */\nexport class StockService {\n private constructor(\n /**\n * The database config this service was bound to (URL string, config\n * object, or already-resolved `DatabaseInterface`). Exposed so\n * downstream services that compose StockService (e.g. BomService,\n * ProductionService in `@happyvertical/smrt-manufacturing`) can pass\n * the same value to their own collection factories without reaching\n * into private fields on the collections.\n */\n public readonly db: DatabaseConfig,\n public readonly levels: StockLevelCollection,\n public readonly movements: StockMovementCollection,\n public readonly locations: InventoryLocationCollection,\n /**\n * Marks a service instance handed to a {@link withTransaction}\n * callback. Public mutation methods on a tx-bound instance skip\n * opening a nested transaction and just execute against the already-\n * bound collections; outer (non-tx) instances open a fresh\n * transaction per mutation. Internal flag — consumers never set it.\n */\n private readonly inTransaction: boolean = false,\n ) {}\n\n /** Internal factory — prefer {@link createStockService}. */\n static async create(options: StockServiceOptions): Promise<StockService> {\n // Resolve the caller's `DatabaseConfig` to a single\n // `DatabaseInterface` instance FIRST, then construct every internal\n // collection on that shared instance. Without this step, passing\n // `{ type: 'sqlite', url: ':memory:' }` would make\n // `SmrtCollection.create({ db: config })` materialize a *fresh*\n // in-memory database per collection — `levels`, `movements`, and\n // `locations` would each point at their own empty DB. The runtime\n // ledger then desyncs: `adjust()` writes a movement to\n // `movements.db` while balance reads go through `levels.db`, and\n // audit queries on `movements` miss the row that was just written.\n // Resolving once means every collection (and the public `db` field\n // exposed for downstream composition) share the same handle.\n const resolved = await resolveDatabase(options.db);\n // Schema probes share one connection; do not interleave their initialization.\n const levels = await StockLevelCollection.create({ db: resolved });\n const movements = await StockMovementCollection.create({ db: resolved });\n const locations = await InventoryLocationCollection.create({\n db: resolved,\n });\n return new StockService(\n resolved as unknown as DatabaseConfig,\n levels,\n movements,\n locations,\n );\n }\n\n /**\n * Run `work` inside a single database transaction with a tx-bound\n * {@link StockService} instance. All mutation calls on `tx` commit\n * atomically when `work` resolves and roll back if it throws.\n *\n * Use this when you need atomicity ACROSS multiple stock-service\n * calls — e.g. consuming materials for every line of a production\n * order in `@happyvertical/smrt-manufacturing`'s `ProductionService`,\n * or a custom workflow that reserves + fulfills + writes a custom\n * audit comment in one indivisible step. Individual mutation methods\n * (`receive`, `reserve`, etc.) are already atomic on their own — you\n * only need `withTransaction` for cross-call composition.\n *\n * Nesting is safe: calling `tx.withTransaction(...)` inside an\n * already-tx-bound callback simply runs the inner `work` on the same\n * transaction without opening a savepoint.\n *\n * When the underlying adapter does not expose `transaction()`, falls\n * through to a serial run on the regular collections with a one-time\n * warning. All four built-in adapters in `@happyvertical/sql >= 0.74.0`\n * support it; only test stubs would hit this branch.\n */\n async withTransaction<T>(work: (tx: StockService) => Promise<T>): Promise<T> {\n if (this.inTransaction) return work(this);\n\n const underlying = (this.levels as unknown as { db?: unknown }).db as\n | { transaction?: (cb: (txDb: unknown) => Promise<T>) => Promise<T> }\n | undefined;\n\n if (typeof underlying?.transaction !== 'function') {\n warnNonTransactional();\n return work(this);\n }\n\n return underlying.transaction(async (txDb) => {\n // The transaction handle also shares a single connection for schema probes.\n const levels = await StockLevelCollection.create({\n db: txDb as DatabaseConfig,\n });\n const movements = await StockMovementCollection.create({\n db: txDb as DatabaseConfig,\n });\n const locations = await InventoryLocationCollection.create({\n db: txDb as DatabaseConfig,\n });\n // Expose the tx-scoped db (not `this.db`) as the tx instance's\n // public `db` field. Callers compose this through `tx.db` when\n // spinning up adjacent services that should also write in the same\n // transaction — e.g. `BomService.create({ db: tx.db })` or\n // `MyCollection.create({ db: tx.db })`. If we leaked the outer db\n // here, those companion writes would commit independently of the\n // stock mutations, defeating the documented \"everything-in-one-tx\"\n // guarantee. Internal mutation methods don't read `tx.db`; they\n // use the tx-scoped collections passed alongside.\n const tx = new StockService(\n txDb as DatabaseConfig,\n levels,\n movements,\n locations,\n /* inTransaction */ true,\n );\n return work(tx);\n });\n }\n\n /**\n * Internal: run a single-method mutation in a transaction. If we're\n * already inside one (the instance was handed to a `withTransaction`\n * callback), reuse it; otherwise open a fresh one.\n */\n private async runAtomically<T>(\n work: (tx: {\n levels: StockLevelCollection;\n movements: StockMovementCollection;\n }) => Promise<T>,\n ): Promise<T> {\n if (this.inTransaction) {\n return work({ levels: this.levels, movements: this.movements });\n }\n return this.withTransaction(async (tx) =>\n work({ levels: tx.levels, movements: tx.movements }),\n );\n }\n\n /**\n * Add `qty` to available stock at the given location. Used for\n * purchase-order receipts, customer returns going back into available\n * inventory, and the \"produce\" leg of a production order.\n */\n async receive(\n skuId: string,\n locationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'receive');\n await this.runAtomically(async (tx) => {\n await adjustLevel(tx.levels, {\n skuId,\n locationId,\n state: 'available',\n delta: qty,\n });\n await writeMovement(tx.movements, {\n skuId,\n locationId,\n fromState: null,\n toState: 'available',\n qty,\n reasonCode: options.reasonCode ?? 'receipt',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Move `qty` from `available` to `allocated` at the given location.\n * Throws {@link InsufficientStockError} if available stock would go\n * negative.\n */\n async reserve(\n skuId: string,\n locationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'reserve');\n await this.runAtomically(async (tx) => {\n await transitionState(tx, {\n skuId,\n locationId,\n fromState: 'available',\n toState: 'allocated',\n qty,\n reasonCode: options.reasonCode ?? 'reservation',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Move `qty` from `allocated` back to `available`. Used when a\n * reservation is cancelled and the previously-reserved stock should\n * go back into the available pool.\n */\n async release(\n skuId: string,\n locationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'release');\n await this.runAtomically(async (tx) => {\n await transitionState(tx, {\n skuId,\n locationId,\n fromState: 'allocated',\n toState: 'available',\n qty,\n reasonCode: options.reasonCode ?? 'release',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Remove `qty` from `allocated` at the given location. Stock leaves\n * the building entirely (shipped, picked up, consumed). Throws\n * {@link InsufficientStockError} if allocated stock would go negative.\n */\n async fulfill(\n skuId: string,\n locationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'fulfill');\n await this.runAtomically(async (tx) => {\n await assertAvailable(tx.levels, skuId, locationId, 'allocated', qty);\n await adjustLevel(tx.levels, {\n skuId,\n locationId,\n state: 'allocated',\n delta: -qty,\n // Already enforced via assertAvailable; skipping the second check\n // avoids a needless extra DB round-trip in the hot path.\n enforceNonNegative: false,\n });\n await writeMovement(tx.movements, {\n skuId,\n locationId,\n fromState: 'allocated',\n toState: null,\n qty,\n reasonCode: options.reasonCode ?? 'fulfillment',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Move `qty` of `available` stock from `fromLocationId` to\n * `toLocationId`. Writes two movement rows — one for the `transfer_out`\n * leg, one for the `transfer_in` leg — so the audit log preserves the\n * lineage in both directions. Throws {@link InsufficientStockError} if\n * source available stock would go negative.\n *\n * Both legs (level writes + movement rows) run inside one transaction\n * — a failure mid-`transfer` rolls back the source debit so there's no\n * \"ghost stock disappearance\" (source decremented, destination never\n * credited).\n */\n async transfer(\n skuId: string,\n fromLocationId: string,\n toLocationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'transfer');\n if (fromLocationId === toLocationId) {\n throw new Error(\n `transfer: fromLocationId and toLocationId must differ (got ${fromLocationId})`,\n );\n }\n await this.runAtomically(async (tx) => {\n await assertAvailable(tx.levels, skuId, fromLocationId, 'available', qty);\n\n // Source leg: decrement available at origin.\n await adjustLevel(tx.levels, {\n skuId,\n locationId: fromLocationId,\n state: 'available',\n delta: -qty,\n enforceNonNegative: false,\n });\n await writeMovement(tx.movements, {\n skuId,\n locationId: fromLocationId,\n fromState: 'available',\n toState: null,\n qty,\n reasonCode: options.reasonCode ?? 'transfer_out',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n\n // Destination leg: increment available at destination.\n await adjustLevel(tx.levels, {\n skuId,\n locationId: toLocationId,\n state: 'available',\n delta: qty,\n });\n await writeMovement(tx.movements, {\n skuId,\n locationId: toLocationId,\n fromState: null,\n toState: 'available',\n qty,\n reasonCode: options.reasonCode ?? 'transfer_in',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Configure replenishment for the available row at a SKU/location.\n * Null disables the threshold. Metadata changes never fabricate movements.\n * The optional quantity is replaced (omitting it clears the suggestion).\n */\n async setReorderPolicy(\n skuId: string,\n locationId: string,\n reorderPoint: number | null,\n reorderQuantity: number | null = null,\n ): Promise<StockLevel> {\n for (const [name, value] of Object.entries({\n reorderPoint,\n reorderQuantity,\n })) {\n if (value !== null && (!Number.isFinite(value) || value < 0)) {\n throw new Error(`${name} must be null or a non-negative finite number`);\n }\n }\n return this.withTransaction(async (tx) => {\n const level = await tx.levels.getLevel(skuId, locationId);\n if (!level) {\n return tx.levels.create({\n skuId,\n locationId,\n state: 'available',\n qty: 0,\n reorderPoint,\n reorderQuantity,\n });\n }\n level.reorderPoint = reorderPoint;\n level.reorderQuantity = reorderQuantity;\n await level.save();\n return level;\n });\n }\n\n /**\n * Apply a positive or negative `delta` to a level row. Used for cycle\n * counts and one-off corrections; `delta=+5` adds five units,\n * `delta=-2` removes two. By default the adjustment targets\n * `available` stock; pass an explicit `state` to adjust a different\n * bucket (e.g. `'damaged'` after a quality-control reclassification).\n *\n * Adjusting by `0` is rejected as a probable programming error — the\n * caller almost always meant a non-zero delta and a no-op write would\n * still cost an audit row.\n */\n async adjust(\n skuId: string,\n locationId: string,\n delta: number,\n options: StockMutationOptions & { state?: StockState } = {},\n ): Promise<void> {\n if (!Number.isFinite(delta) || delta === 0) {\n throw new Error(\n `adjust: delta must be a non-zero finite number (got ${delta})`,\n );\n }\n const state = options.state ?? 'available';\n await this.runAtomically(async (tx) => {\n if (delta < 0) {\n await assertAvailable(tx.levels, skuId, locationId, state, -delta);\n }\n await adjustLevel(tx.levels, {\n skuId,\n locationId,\n state,\n delta,\n enforceNonNegative: false,\n });\n await writeMovement(tx.movements, {\n skuId,\n locationId,\n fromState: delta < 0 ? state : null,\n toState: delta > 0 ? state : null,\n qty: Math.abs(delta),\n reasonCode: options.reasonCode ?? 'adjustment',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Tx-scoped helpers\n//\n// These are module-level functions rather than instance methods so each\n// call site can pass tx-scoped collections through cleanly. The previous\n// versions read `this.levels` / `this.movements` directly which bypassed\n// the transaction. Public methods now wrap everything in\n// `runAtomically` and call these helpers with the tx-scoped pair.\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Read the current level row, sanity-check the result, and throw\n * {@link InsufficientStockError} when the requested quantity is not\n * available.\n */\nasync function assertAvailable(\n levels: StockLevelCollection,\n skuId: string,\n locationId: string,\n state: StockState,\n requested: number,\n): Promise<void> {\n const level = await levels.getLevel(skuId, locationId, state);\n const available = level ? Number(level.qty ?? 0) : 0;\n if (available < requested) {\n throw new InsufficientStockError(\n skuId,\n locationId,\n state,\n requested,\n available,\n );\n }\n}\n\n/**\n * Atomically transition `qty` from one state to another at a single\n * location. Used by `reserve` and `release`.\n */\nasync function transitionState(\n tx: { levels: StockLevelCollection; movements: StockMovementCollection },\n args: {\n skuId: string;\n locationId: string;\n fromState: StockState;\n toState: StockState;\n qty: number;\n reasonCode: StockMovementReason;\n sourceType?: string;\n sourceId?: string;\n actorProfileId?: string | null;\n note?: string;\n },\n): Promise<void> {\n await assertAvailable(\n tx.levels,\n args.skuId,\n args.locationId,\n args.fromState,\n args.qty,\n );\n await adjustLevel(tx.levels, {\n skuId: args.skuId,\n locationId: args.locationId,\n state: args.fromState,\n delta: -args.qty,\n enforceNonNegative: false,\n });\n await adjustLevel(tx.levels, {\n skuId: args.skuId,\n locationId: args.locationId,\n state: args.toState,\n delta: args.qty,\n });\n await writeMovement(tx.movements, {\n skuId: args.skuId,\n locationId: args.locationId,\n fromState: args.fromState,\n toState: args.toState,\n qty: args.qty,\n reasonCode: args.reasonCode,\n sourceType: args.sourceType,\n sourceId: args.sourceId,\n actorProfileId: args.actorProfileId,\n note: args.note,\n });\n}\n\n/**\n * Read-modify-write a level row by `delta`. Creates the row when it\n * doesn't exist yet. When `enforceNonNegative` is set, refuses to\n * write a negative `qty` and throws {@link InsufficientStockError}\n * with the original (non-decremented) balance.\n */\nasync function adjustLevel(\n levels: StockLevelCollection,\n options: AdjustLevelOptions,\n): Promise<StockLevel> {\n const enforce = options.enforceNonNegative ?? options.delta < 0;\n const existing = await levels.getLevel(\n options.skuId,\n options.locationId,\n options.state,\n );\n const previous = existing ? Number(existing.qty ?? 0) : 0;\n const next = previous + options.delta;\n\n if (enforce && next < 0) {\n throw new InsufficientStockError(\n options.skuId,\n options.locationId,\n options.state,\n Math.abs(options.delta),\n previous,\n );\n }\n\n if (existing) {\n existing.qty = next;\n await existing.save();\n return existing;\n }\n\n // SmrtCollection.create() saves the row before returning, so no further\n // save() is needed here. The first row is insert-only: as an upsert, a\n // concurrent first write that also read \"no row\" overwrote this qty with\n // its own delta on PostgreSQL. Now the loser hits the unique key and its\n // transaction rolls back, like a revision conflict on the update path\n // (#3204).\n const level = await levels.create({\n skuId: options.skuId,\n locationId: options.locationId,\n state: options.state,\n qty: next,\n _insertOnly: true,\n });\n return level;\n}\n\n/**\n * Append a movement to the audit log. Never updates an existing row —\n * the natural key is the surrogate id, so each call writes a fresh\n * append-only entry.\n */\nasync function writeMovement(\n movements: StockMovementCollection,\n options: WriteMovementOptions,\n): Promise<void> {\n // SmrtCollection.create() persists the row before returning. A\n // follow-up save() would emit a redundant upsert round-trip on every\n // single stock mutation (one or two per service call) — and the\n // movement table is append-only, so there's nothing to re-save.\n await movements.create({\n skuId: options.skuId,\n locationId: options.locationId,\n fromState: options.fromState,\n toState: options.toState,\n qty: options.qty,\n reasonCode: options.reasonCode,\n sourceType: options.sourceType ?? '',\n sourceId: options.sourceId ?? '',\n actorProfileId: options.actorProfileId ?? null,\n note: options.note ?? '',\n occurredAt: new Date(),\n });\n}\n\n/**\n * Reject zero / negative / non-finite quantities up front. Most stock\n * mutation methods accept positive quantities only; {@link StockService.adjust}\n * is the exception (it accepts signed deltas) and validates separately.\n */\nfunction assertPositiveQty(qty: number, op: string): void {\n if (!Number.isFinite(qty) || qty <= 0) {\n throw new Error(`${op}: qty must be a positive finite number (got ${qty})`);\n }\n}\n\nlet warnedNonTransactional = false;\n\n/**\n * Emit a one-time `console.warn` when the underlying SQL adapter does\n * not expose `transaction()`. All four `@happyvertical/sql >= 0.74.0`\n * adapters implement it — only test stubs or third-party adapters would\n * trip this branch.\n */\nfunction warnNonTransactional(): void {\n if (warnedNonTransactional) return;\n warnedNonTransactional = true;\n logger.warn(\n '[@happyvertical/smrt-inventory] StockService: underlying SQL adapter ' +\n 'does not expose `transaction()`. Stock mutations are degrading to ' +\n 'non-atomic serial writes — partial failures may leave the materialized ' +\n 'level and the audit ledger out of sync. Upgrade @happyvertical/sql to ' +\n '>= 0.74.0 or use one of its built-in adapters.',\n );\n}\n\n/**\n * Convenience factory. Returns a fully-initialized {@link StockService}\n * sharing the given database with its internal collections.\n */\nexport async function createStockService(\n options: StockServiceOptions,\n): Promise<StockService> {\n return StockService.create(options);\n}\n","/**\n * Opt-in DispatchBus subscribers that bridge upstream packages to the\n * {@link StockService}.\n *\n * **Off by default.** The package never auto-subscribes — consumer apps\n * call {@link installInventoryDispatchHandlers} from their `smrt.ts`\n * wiring once they have decided they want automatic stock motion when\n * contracts are created and fulfilments ship.\n *\n * The production-order leg (`production_order:posted` → consume\n * materials + produce SKUs) is deliberately *not* installed here; that\n * subscriber lives in `@happyvertical/smrt-manufacturing` (see issue\n * #1250) and depends on the BOM model that ships alongside it.\n *\n * @packageDocumentation\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport type {\n DatabaseConfig,\n DispatchBus,\n DispatchHandler,\n DispatchMetadata,\n} from '@happyvertical/smrt-core';\nimport type { StockMutationOptions } from './StockService.js';\nimport { createStockService, type StockService } from './StockService.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Shape of a single reserved line in a `contract:created` payload. The\n * producer (typically `@happyvertical/smrt-commerce`) packs one entry\n * per line that needs stock motion; everything else (taxes, fees,\n * non-physical items) should be filtered upstream.\n */\nexport interface ContractCreatedLine {\n skuId: string;\n locationId: string;\n qty: number;\n}\n\n/**\n * Shape of the `contract:created` payload this handler expects. Carries\n * the contract id (used for source attribution on the audit row) and\n * the list of line items to reserve.\n */\nexport interface ContractCreatedPayload {\n contractId: string;\n lines: ContractCreatedLine[];\n}\n\n/**\n * Shape of a single shipped line in a `fulfillment:shipped` payload.\n */\nexport interface FulfillmentShippedLine {\n skuId: string;\n locationId: string;\n qty: number;\n}\n\n/**\n * Shape of the `fulfillment:shipped` payload this handler expects.\n * Producers emit one per shipped fulfilment; the handler fulfils each\n * line against the level created by the matching `contract:created`\n * reservation.\n */\nexport interface FulfillmentShippedPayload {\n fulfillmentId: string;\n lines: FulfillmentShippedLine[];\n}\n\n/**\n * Options accepted by {@link installInventoryDispatchHandlers}.\n *\n * Provide either a pre-built {@link StockService} (when sharing one\n * across multiple subsystems) or a `db` for the helper to construct one\n * on first use.\n */\nexport type InstallInventoryDispatchHandlersOptions = {\n /**\n * Bus to subscribe on. Typically the app-wide `DispatchBus` created in\n * the application's `smrt.ts`.\n */\n dispatchBus: DispatchBus;\n /**\n * When `true` (default), install the `contract:created` handler.\n * Producers should publish a {@link ContractCreatedPayload}.\n */\n installContractReserved?: boolean;\n /**\n * When `true` (default), install the `fulfillment:shipped` handler.\n * Producers should publish a {@link FulfillmentShippedPayload}.\n */\n installFulfillmentShipped?: boolean;\n} & (\n | { stockService: StockService; db?: DatabaseConfig }\n | { db: DatabaseConfig; stockService?: undefined }\n);\n\n/**\n * Result handle returned by {@link installInventoryDispatchHandlers}.\n * Call `dispose()` to detach the subscribers (mainly useful in tests\n * and on graceful shutdown).\n */\nexport interface InstalledInventoryDispatchHandlers {\n /** Resolved StockService — useful for follow-up writes in the same scope. */\n stockService: StockService;\n /** Detach every installed subscriber. Idempotent. */\n dispose(): void;\n}\n\n/**\n * Subscribe a {@link StockService}-driven handler to the relevant signals\n * on the given {@link DispatchBus}. Returns a disposer for tests and\n * shutdown hooks.\n *\n * @example\n * ```typescript\n * import { createDispatchBus } from '@happyvertical/smrt-core';\n * import { installInventoryDispatchHandlers } from '@happyvertical/smrt-inventory';\n *\n * const bus = await createDispatchBus({ db });\n * const handlers = await installInventoryDispatchHandlers({\n * dispatchBus: bus,\n * db,\n * });\n * ```\n */\nexport async function installInventoryDispatchHandlers(\n options: InstallInventoryDispatchHandlersOptions,\n): Promise<InstalledInventoryDispatchHandlers> {\n const {\n dispatchBus,\n installContractReserved = true,\n installFulfillmentShipped = true,\n } = options;\n\n const stockService =\n options.stockService ?? (await buildStockService(options));\n\n const installed: Array<{ pattern: string; handler: DispatchHandler }> = [];\n\n if (installContractReserved) {\n const handler: DispatchHandler = async (payload, metadata) => {\n await handleContractCreated(\n stockService,\n payload as ContractCreatedPayload,\n metadata,\n );\n };\n dispatchBus.on('contract:created', handler);\n installed.push({ pattern: 'contract:created', handler });\n }\n\n if (installFulfillmentShipped) {\n const handler: DispatchHandler = async (payload, metadata) => {\n await handleFulfillmentShipped(\n stockService,\n payload as FulfillmentShippedPayload,\n metadata,\n );\n };\n dispatchBus.on('fulfillment:shipped', handler);\n installed.push({ pattern: 'fulfillment:shipped', handler });\n }\n\n return {\n stockService,\n dispose() {\n for (const entry of installed) {\n dispatchBus.off(entry.pattern, entry.handler);\n }\n installed.length = 0;\n },\n };\n}\n\nasync function handleContractCreated(\n stockService: StockService,\n payload: ContractCreatedPayload | null | undefined,\n metadata: DispatchMetadata,\n): Promise<void> {\n // Silent return on any of these would hide upstream contract drift —\n // producers emitting the wrong shape never get feedback. Source id\n // (`contractId`) is required: without it the resulting StockMovements\n // carry empty `sourceId`, breaking the audit trail back to the\n // originating contract. Each branch reports its specific reason so\n // the emitter can be diagnosed quickly.\n const reason = malformedContractPayloadReason(payload);\n if (reason || !payload) {\n warnMalformedPayload(\n 'contract:created',\n payload,\n metadata,\n reason ?? 'payload is null/undefined',\n );\n return;\n }\n // Validate every line BEFORE opening a transaction. A silent skip on\n // a null/undefined / shape-broken entry would look like a successful\n // commit while only reserving part of the contract — defeating the\n // \"atomic across lines\" guarantee just below. Fail the whole event\n // instead so producers get feedback and downstream observers see no\n // partial state.\n if (!areLinesWellFormed(payload.lines)) {\n warnMalformedPayload(\n 'contract:created',\n payload,\n metadata,\n 'one or more entries in `lines` are null/undefined or missing required fields (skuId: string, locationId: string, qty: finite number)',\n );\n return;\n }\n const baseOptions: StockMutationOptions = {\n sourceType: 'Contract',\n sourceId: payload.contractId,\n note: metadata.source ? `auto-reserve via ${metadata.source}` : undefined,\n };\n // Atomic across lines: a shortfall on line N rolls back lines 1..N-1.\n // Without this wrapper, an `InsufficientStockError` mid-loop would leave\n // a partially-reserved contract, and `DispatchBus` would only log the\n // async handler error — no compensating release would ever fire.\n await stockService.withTransaction(async (tx) => {\n for (const line of payload.lines) {\n await tx.reserve(line.skuId, line.locationId, line.qty, baseOptions);\n }\n });\n}\n\nasync function handleFulfillmentShipped(\n stockService: StockService,\n payload: FulfillmentShippedPayload | null | undefined,\n metadata: DispatchMetadata,\n): Promise<void> {\n // Same rationale as `handleContractCreated`: reject when the\n // source id (`fulfillmentId`) is missing rather than emit\n // StockMovements with no audit attribution; surface the specific\n // failure so producers can diagnose quickly.\n const reason = malformedFulfillmentPayloadReason(payload);\n if (reason || !payload) {\n warnMalformedPayload(\n 'fulfillment:shipped',\n payload,\n metadata,\n reason ?? 'payload is null/undefined',\n );\n return;\n }\n // Validate lines up front for the same reason as\n // `handleContractCreated`: a silent skip would partially fulfill the\n // shipment while looking successful.\n if (!areLinesWellFormed(payload.lines)) {\n warnMalformedPayload(\n 'fulfillment:shipped',\n payload,\n metadata,\n 'one or more entries in `lines` are null/undefined or missing required fields (skuId: string, locationId: string, qty: finite number)',\n );\n return;\n }\n const baseOptions: StockMutationOptions = {\n sourceType: 'Fulfillment',\n sourceId: payload.fulfillmentId,\n note: metadata.source ? `auto-fulfill via ${metadata.source}` : undefined,\n };\n // Atomic across lines: a shortfall on line N rolls back lines 1..N-1.\n // Same rationale as `handleContractCreated` above — without the tx\n // wrapper, a failing fulfilment leg would leave the audit ledger\n // inconsistent and no compensating reservation-restore would ever fire.\n await stockService.withTransaction(async (tx) => {\n for (const line of payload.lines) {\n await tx.fulfill(line.skuId, line.locationId, line.qty, baseOptions);\n }\n });\n}\n\n/**\n * Determine whether a `contract:created` payload is structurally\n * unusable and, if so, return a single human-readable reason naming\n * the specific field that failed. Returns `null` when the top-level\n * shape is acceptable. Line-level validation is a separate step.\n */\nfunction malformedContractPayloadReason(\n payload: ContractCreatedPayload | null | undefined,\n): string | null {\n if (!payload || typeof payload !== 'object') {\n return 'payload is null/undefined or not an object';\n }\n if (!payload.contractId || typeof payload.contractId !== 'string') {\n return 'missing or non-string `contractId` (required for audit-trail source attribution)';\n }\n if (!Array.isArray(payload.lines)) {\n return 'missing or non-array `lines`';\n }\n return null;\n}\n\n/**\n * Same shape as {@link malformedContractPayloadReason} but for\n * `fulfillment:shipped` events. The required source id field is\n * `fulfillmentId` here.\n */\nfunction malformedFulfillmentPayloadReason(\n payload: FulfillmentShippedPayload | null | undefined,\n): string | null {\n if (!payload || typeof payload !== 'object') {\n return 'payload is null/undefined or not an object';\n }\n if (!payload.fulfillmentId || typeof payload.fulfillmentId !== 'string') {\n return 'missing or non-string `fulfillmentId` (required for audit-trail source attribution)';\n }\n if (!Array.isArray(payload.lines)) {\n return 'missing or non-array `lines`';\n }\n return null;\n}\n\n/**\n * Validate that every entry in a dispatch `lines` array is a usable\n * line shape. Returns `false` as soon as it sees a null/undefined entry\n * (e.g. a serialized sparse array hole), a missing/non-string\n * `skuId` / `locationId`, or a non-finite `qty`. Used by both contract\n * and fulfilment handlers to fail-fast before opening a transaction —\n * a silent `continue` over a bad entry would partially mutate state\n * while making the malformed event look successful.\n */\nfunction areLinesWellFormed(\n lines: ReadonlyArray<\n ContractCreatedLine | FulfillmentShippedLine | null | undefined\n >,\n): boolean {\n for (const line of lines) {\n if (!line) return false;\n if (typeof line.skuId !== 'string' || !line.skuId) return false;\n if (typeof line.locationId !== 'string' || !line.locationId) return false;\n if (typeof line.qty !== 'number' || !Number.isFinite(line.qty))\n return false;\n }\n return true;\n}\n\n/**\n * Surface dispatch payloads that don't match the documented shape. The\n * subscribers used to silently return on a missing `lines` array, which\n * hid producer drift — emitters using stale shapes never got feedback\n * and the resulting \"stock didn't move\" bugs were a long way from the\n * dispatch layer. The warning carries the source attribution AND the\n * specific reason the payload was rejected so producers can fix the\n * emitter quickly. Each call site supplies its own `reason` string;\n * the generic shell wraps it with the signal name and payload-key\n * summary for forensic logging.\n */\nfunction warnMalformedPayload(\n signal: string,\n payload: unknown,\n metadata: DispatchMetadata,\n reason: string,\n): void {\n logger.warn(\n `[@happyvertical/smrt-inventory] dispatch handler ignored a ${signal} ` +\n `event with a malformed payload (${reason}). ` +\n `Source: ${metadata.source ?? '<unknown>'}; payload keys: ` +\n `${payload && typeof payload === 'object' ? Object.keys(payload).join(',') : typeof payload}`,\n );\n}\n\n/**\n * Build a `StockService` when no pre-built one was supplied. The option\n * union guarantees `db` is present in that branch, but TypeScript can't\n * narrow from a `??` value check, so this helper validates at runtime\n * with a clear error message.\n */\nasync function buildStockService(\n options: InstallInventoryDispatchHandlersOptions,\n): Promise<StockService> {\n if (!options.db) {\n throw new Error(\n 'installInventoryDispatchHandlers: either `stockService` or `db` is required',\n );\n }\n return createStockService({ db: options.db });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["usage"],"sources":["../src/__smrt-register__.ts","../src/models/InventoryLocation.ts","../src/collections/InventoryLocationCollection.ts","../src/models/Lot.ts","../src/collections/LotCollection.ts","../src/models/LotCorrection.ts","../src/collections/LotCorrectionCollection.ts","../src/models/LotDocument.ts","../src/collections/LotDocumentCollection.ts","../src/models/LotStockLevel.ts","../src/collections/LotStockLevelCollection.ts","../src/models/LotUsage.ts","../src/collections/LotUsageCollection.ts","../src/models/StockLevel.ts","../src/collections/StockLevelCollection.ts","../src/models/StockMovement.ts","../src/collections/StockMovementCollection.ts","../src/recipes.ts","../src/services/lot-errors.ts","../src/services/StockService.ts","../src/services/dispatch-handlers.ts","../src/services/LotService.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"packageVersion\\\":\\\"0.57.18\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-inventory:InventoryLocationCollection\\\":{\\\"name\\\":\\\"inventorylocationcollection\\\",\\\"className\\\":\\\"InventoryLocationCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:InventoryLocationCollection\\\",\\\"collection\\\":\\\"inventorylocations\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/InventoryLocationCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByCode\\\":{\\\"name\\\":\\\"findByCode\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"code\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<InventoryLocation | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByKind\\\":{\\\"name\\\":\\\"findByKind\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"InventoryLocationKind\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<InventoryLocation[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByPlace\\\":{\\\"name\\\":\\\"findByPlace\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"placeId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<InventoryLocation[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findActive\\\":{\\\"name\\\":\\\"findActive\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"InventoryLocationKind\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<InventoryLocation[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_locations\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"InventoryLocation\\\",\\\"exportName\\\":\\\"InventoryLocationCollection\\\",\\\"collectionExportName\\\":\\\"InventoryLocationCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_locations\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_locations\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"code\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"kind\\\\\\\" TEXT DEFAULT 'warehouse',\\\\n \\\\\\\"place_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"active\\\\\\\" BOOLEAN DEFAULT TRUE\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"warehouse\\\"},\\\"place_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"active\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":true}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_locations_code_tenant_id_idx\\\",\\\"columns\\\":[\\\"code\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_locations_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_locations_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"401c28a1\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:LotCollection\\\":{\\\"name\\\":\\\"lotcollection\\\",\\\"className\\\":\\\"LotCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:LotCollection\\\",\\\"collection\\\":\\\"lots\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/LotCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByLotNumber\\\":{\\\"name\\\":\\\"findByLotNumber\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"lotNumber\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"object\\\",\\\"optional\\\":true,\\\"memberTypes\\\":[\\\"string | null\\\"]}],\\\"returnType\\\":\\\"Promise<Lot[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lots\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Lot\\\",\\\"exportName\\\":\\\"LotCollection\\\",\\\"collectionExportName\\\":\\\"LotCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lots\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lots\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT,\\\\n \\\\\\\"kind\\\\\\\" TEXT DEFAULT 'lot',\\\\n \\\\\\\"lot_number\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"search_key\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"identity_key\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"unique_number\\\\\\\" BOOLEAN DEFAULT FALSE,\\\\n \\\\\\\"received_qty\\\\\\\" REAL,\\\\n \\\\\\\"unit\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_type\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"attributes\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'active',\\\\n \\\\\\\"received_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"received_by_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"last_used_at\\\\\\\" TIMESTAMP\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"lot\\\"},\\\"lot_number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"search_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"identity_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"unique_number\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":false},\\\"received_qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unit\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"attributes\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"active\\\"},\\\"received_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"received_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"last_used_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lots_identity_key_tenant_id_idx\\\",\\\"columns\\\":[\\\"identity_key\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_lots_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_lots_search_key_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"search_key\\\"]},{\\\"name\\\":\\\"inventory_lots_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_lots_received_by_profile_id_idx\\\",\\\"columns\\\":[\\\"received_by_profile_id\\\"]}],\\\"version\\\":\\\"eb959677\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:LotCorrectionCollection\\\":{\\\"name\\\":\\\"lotcorrectioncollection\\\",\\\"className\\\":\\\"LotCorrectionCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:LotCorrectionCollection\\\",\\\"collection\\\":\\\"lotcorrections\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/LotCorrectionCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lot_corrections\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"LotCorrection\\\",\\\"exportName\\\":\\\"LotCorrectionCollection\\\",\\\"collectionExportName\\\":\\\"LotCorrectionCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lot_corrections\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lot_corrections\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"lot_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL DEFAULT 'attribute',\\\\n \\\\\\\"field\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"old_value\\\\\\\" TEXT,\\\\n \\\\\\\"new_value\\\\\\\" TEXT,\\\\n \\\\\\\"reason\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"usage_id\\\\\\\" TEXT,\\\\n \\\\\\\"document_id\\\\\\\" TEXT,\\\\n \\\\\\\"actor_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"corrected_at\\\\\\\" TIMESTAMP\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"lot_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"inventory_lots\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"attribute\\\"},\\\"field\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"old_value\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"new_value\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"usage_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"document_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"actor_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"corrected_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_corrections_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_lot_corrections_lot_idx\\\",\\\"columns\\\":[\\\"lot_id\\\"]},{\\\"name\\\":\\\"inventory_lot_corrections_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_lot_corrections_actor_profile_id_idx\\\",\\\"columns\\\":[\\\"actor_profile_id\\\"]}],\\\"version\\\":\\\"d903252e\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:LotDocumentCollection\\\":{\\\"name\\\":\\\"lotdocumentcollection\\\",\\\"className\\\":\\\"LotDocumentCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:LotDocumentCollection\\\",\\\"collection\\\":\\\"lotdocuments\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/LotDocumentCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lot_documents\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"LotDocument\\\",\\\"exportName\\\":\\\"LotDocumentCollection\\\",\\\"collectionExportName\\\":\\\"LotDocumentCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lot_documents\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lot_documents\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"lot_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"asset_id\\\\\\\" UUID,\\\\n \\\\\\\"role\\\\\\\" TEXT DEFAULT 'certificate',\\\\n \\\\\\\"attached_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"attached_by_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"detached_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"detached_by_profile_id\\\\\\\" UUID\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"lot_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"inventory_lots\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"asset_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"role\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"certificate\\\"},\\\"attached_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"attached_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"detached_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"detached_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_documents_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_lot_documents_lot_idx\\\",\\\"columns\\\":[\\\"lot_id\\\"]},{\\\"name\\\":\\\"inventory_lot_documents_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_lot_documents_asset_id_idx\\\",\\\"columns\\\":[\\\"asset_id\\\"]},{\\\"name\\\":\\\"inventory_lot_documents_attached_by_profile_id_idx\\\",\\\"columns\\\":[\\\"attached_by_profile_id\\\"]},{\\\"name\\\":\\\"inventory_lot_documents_detached_by_profile_id_idx\\\",\\\"columns\\\":[\\\"detached_by_profile_id\\\"]}],\\\"version\\\":\\\"076940be\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:LotStockLevelCollection\\\":{\\\"name\\\":\\\"lotstocklevelcollection\\\",\\\"className\\\":\\\"LotStockLevelCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:LotStockLevelCollection\\\",\\\"collection\\\":\\\"lotstocklevels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/LotStockLevelCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"getLevel\\\":{\\\"name\\\":\\\"getLevel\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"lotId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"state\\\",\\\"type\\\":\\\"StockState\\\",\\\"optional\\\":true,\\\"default\\\":\\\"available\\\"}],\\\"returnType\\\":\\\"Promise<LotStockLevel | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"onHand\\\":{\\\"name\\\":\\\"onHand\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"lotId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"state\\\",\\\"type\\\":\\\"StockState\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lot_stock_levels\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"LotStockLevel\\\",\\\"exportName\\\":\\\"LotStockLevelCollection\\\",\\\"collectionExportName\\\":\\\"LotStockLevelCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lot_stock_levels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lot_stock_levels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"lot_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"state\\\\\\\" TEXT NOT NULL DEFAULT 'available',\\\\n \\\\\\\"qty\\\\\\\" REAL\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"lot_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"inventory_lots\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"available\\\"},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_stock_levels_lot_id_location_id_idx\\\",\\\"columns\\\":[\\\"lot_id\\\",\\\"location_id\\\",\\\"state\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_lot_stock_levels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_lot_stock_levels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"6f6becfa\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:LotUsageCollection\\\":{\\\"name\\\":\\\"lotusagecollection\\\",\\\"className\\\":\\\"LotUsageCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:LotUsageCollection\\\",\\\"collection\\\":\\\"lotusages\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/LotUsageCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findActiveForLot\\\":{\\\"name\\\":\\\"findActiveForLot\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"lotId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<LotUsage[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findForConsumer\\\":{\\\"name\\\":\\\"findForConsumer\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"consumerType\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"consumerId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"object\\\",\\\"optional\\\":true,\\\"memberTypes\\\":[\\\"boolean\\\"]}],\\\"returnType\\\":\\\"Promise<LotUsage[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lot_usages\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"LotUsage\\\",\\\"exportName\\\":\\\"LotUsageCollection\\\",\\\"collectionExportName\\\":\\\"LotUsageCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lot_usages\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lot_usages\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"lot_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"consumer_type\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"consumer_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"unit\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'active',\\\\n \\\\\\\"linked_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"linked_by_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"unlinked_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"unlinked_by_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"unlink_reason\\\\\\\" TEXT,\\\\n \\\\\\\"movement_id\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"lot_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"inventory_lots\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"consumer_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"consumer_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unit\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"active\\\"},\\\"linked_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"linked_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unlinked_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unlinked_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unlink_reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"movement_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_usages_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_lot_usages_consumer_idx\\\",\\\"columns\\\":[\\\"consumer_type\\\",\\\"consumer_id\\\"]},{\\\"name\\\":\\\"inventory_lot_usages_lot_status_idx\\\",\\\"columns\\\":[\\\"lot_id\\\",\\\"status\\\"]},{\\\"name\\\":\\\"inventory_lot_usages_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_lot_usages_linked_by_profile_id_idx\\\",\\\"columns\\\":[\\\"linked_by_profile_id\\\"]},{\\\"name\\\":\\\"inventory_lot_usages_unlinked_by_profile_id_idx\\\",\\\"columns\\\":[\\\"unlinked_by_profile_id\\\"]}],\\\"version\\\":\\\"c106a419\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:StockLevelCollection\\\":{\\\"name\\\":\\\"stocklevelcollection\\\",\\\"className\\\":\\\"StockLevelCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:StockLevelCollection\\\",\\\"collection\\\":\\\"stocklevels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/StockLevelCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"getLevel\\\":{\\\"name\\\":\\\"getLevel\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"skuId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"state\\\",\\\"type\\\":\\\"StockState\\\",\\\"optional\\\":true,\\\"default\\\":\\\"available\\\"}],\\\"returnType\\\":\\\"Promise<StockLevel | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBySku\\\":{\\\"name\\\":\\\"findBySku\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"skuId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockLevel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByLocation\\\":{\\\"name\\\":\\\"findByLocation\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockLevel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBelowReorderPoint\\\":{\\\"name\\\":\\\"findBelowReorderPoint\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<StockLevel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"totalForSku\\\":{\\\"name\\\":\\\"totalForSku\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"skuId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"state\\\",\\\"type\\\":\\\"StockState\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"totalForLocation\\\":{\\\"name\\\":\\\"totalForLocation\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"state\\\",\\\"type\\\":\\\"StockState\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_stock_levels\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"StockLevel\\\",\\\"exportName\\\":\\\"StockLevelCollection\\\",\\\"collectionExportName\\\":\\\"StockLevelCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_stock_levels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_stock_levels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"state\\\\\\\" TEXT NOT NULL DEFAULT 'available',\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"reorder_point\\\\\\\" REAL,\\\\n \\\\\\\"reorder_quantity\\\\\\\" REAL\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"available\\\"},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reorder_point\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reorder_quantity\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_stock_levels_sku_id_location_id_idx\\\",\\\"columns\\\":[\\\"sku_id\\\",\\\"location_id\\\",\\\"state\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_stock_levels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_stock_levels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"02387935\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:StockMovementCollection\\\":{\\\"name\\\":\\\"stockmovementcollection\\\",\\\"className\\\":\\\"StockMovementCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:StockMovementCollection\\\",\\\"collection\\\":\\\"stockmovements\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/collections/StockMovementCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findBySku\\\":{\\\"name\\\":\\\"findBySku\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"skuId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByLocation\\\":{\\\"name\\\":\\\"findByLocation\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"locationId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBySource\\\":{\\\"name\\\":\\\"findBySource\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"sourceType\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"sourceId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByReason\\\":{\\\"name\\\":\\\"findByReason\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"reasonCode\\\",\\\"type\\\":\\\"StockMovementReason\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<StockMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_stock_movements\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"StockMovement\\\",\\\"exportName\\\":\\\"StockMovementCollection\\\",\\\"collectionExportName\\\":\\\"StockMovementCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_stock_movements\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_stock_movements\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"lot_id\\\\\\\" TEXT,\\\\n \\\\\\\"from_state\\\\\\\" TEXT,\\\\n \\\\\\\"to_state\\\\\\\" TEXT,\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"reason_code\\\\\\\" TEXT NOT NULL DEFAULT 'adjustment',\\\\n \\\\\\\"source_type\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"actor_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"note\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"occurred_at\\\\\\\" TIMESTAMP\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"lot_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"from_state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"to_state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"adjustment\\\"},\\\"source_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"actor_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"note\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"occurred_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_stock_movements_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_lot_idx\\\",\\\"columns\\\":[\\\"lot_id\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_actor_profile_id_idx\\\",\\\"columns\\\":[\\\"actor_profile_id\\\"]}],\\\"version\\\":\\\"b426c2c5\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:InventoryLocation\\\":{\\\"name\\\":\\\"inventorylocation\\\",\\\"className\\\":\\\"InventoryLocation\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:InventoryLocation\\\",\\\"collection\\\":\\\"inventorylocations\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/InventoryLocation.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"code\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"A short code for the place stock is kept, for example MAIN.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"A short code for the place stock is kept, for example MAIN.\\\"}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What you call the place, for example Main warehouse.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What you call the place, for example Main warehouse.\\\"}},\\\"kind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"warehouse\\\",\\\"description\\\":\\\"What sort of place it is, for example a warehouse or a shop floor.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What sort of place it is, for example a warehouse or a shop floor.\\\"}},\\\"placeId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"active\\\":{\\\"type\\\":\\\"boolean\\\",\\\"required\\\":false,\\\"default\\\":true}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_locations\\\",\\\"conflictColumns\\\":[\\\"code\\\",\\\"tenant_id\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":true,\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"InventoryLocation\\\",\\\"collectionExportName\\\":\\\"InventoryLocationCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"code\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_locations\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_locations\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"code\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"kind\\\\\\\" TEXT DEFAULT 'warehouse',\\\\n \\\\\\\"place_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"active\\\\\\\" BOOLEAN DEFAULT TRUE\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"warehouse\\\"},\\\"place_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"active\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":true}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_locations_code_tenant_id_idx\\\",\\\"columns\\\":[\\\"code\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_locations_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_locations_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"401c28a1\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:Lot\\\":{\\\"name\\\":\\\"lot\\\",\\\"className\\\":\\\"Lot\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:Lot\\\",\\\"collection\\\":\\\"lots\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/Lot.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"skuId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The item this lot is of, if catalogued.\\\",\\\"_meta\\\":{\\\"nullable\\\":true,\\\"description\\\":\\\"The item this lot is of, if catalogued.\\\"}},\\\"kind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"lot\\\",\\\"description\\\":\\\"Whether this is a batch (lot) or a single unit (serial).\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Whether this is a batch (lot) or a single unit (serial).\\\"},\\\"enum\\\":[\\\"lot\\\",\\\"serial\\\"]},\\\"lotNumber\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The batch code, supplier lot or serial number.\\\",\\\"maxLength\\\":128,\\\"_meta\\\":{\\\"required\\\":true,\\\"maxLength\\\":128,\\\"description\\\":\\\"The batch code, supplier lot or serial number.\\\"}},\\\"searchKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The number in normal form, used for lookup.\\\",\\\"maxLength\\\":160,\\\"_meta\\\":{\\\"maxLength\\\":160,\\\"description\\\":\\\"The number in normal form, used for lookup.\\\"}},\\\"identityKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"Internal identity that keeps lots from being created twice.\\\",\\\"maxLength\\\":160,\\\"_meta\\\":{\\\"required\\\":true,\\\"maxLength\\\":160,\\\"description\\\":\\\"Internal identity that keeps lots from being created twice.\\\"}},\\\"uniqueNumber\\\":{\\\"type\\\":\\\"boolean\\\",\\\"required\\\":false,\\\"default\\\":false,\\\"description\\\":\\\"Whether the number must be unique for this item.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Whether the number must be unique for this item.\\\"}},\\\"receivedQty\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How many came in on the receipt.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How many came in on the receipt.\\\"}},\\\"unit\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The unit of measure.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The unit of measure.\\\"}},\\\"sourceType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What kind of record received this lot.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What kind of record received this lot.\\\"}},\\\"sourceId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The record that received this lot.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The record that received this lot.\\\"}},\\\"attributes\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"Anything else worth knowing about this lot, stored as JSON.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Anything else worth knowing about this lot, stored as JSON.\\\"}},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"active\\\",\\\"description\\\":\\\"Where the lot stands: active, quarantined, consumed or void.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Where the lot stands: active, quarantined, consumed or void.\\\"}},\\\"receivedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When the lot was received.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When the lot was received.\\\"}},\\\"receivedByProfileId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-profiles:Profile\\\"},\\\"lastUsedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}}},\\\"methods\\\":{\\\"getAttributes\\\":{\\\"name\\\":\\\"getAttributes\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Record<string, unknown>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"setAttributes\\\":{\\\"name\\\":\\\"setAttributes\\\",\\\"async\\\":false,\\\"parameters\\\":[{\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"Record<string, unknown> | string\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"Record<string, unknown>\\\"},{\\\"type\\\":\\\"string\\\"}]}],\\\"returnType\\\":\\\"void\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lots\\\",\\\"conflictColumns\\\":[\\\"identity_key\\\",\\\"tenant_id\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lots_search_key_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"searchKey\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"Lot\\\",\\\"collectionExportName\\\":\\\"LotCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"lotNumber\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"lotNumber\\\",\\\"rule\\\":\\\"maxLength\\\",\\\"value\\\":128,\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"searchKey\\\",\\\"rule\\\":\\\"maxLength\\\",\\\"value\\\":160,\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"identityKey\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"identityKey\\\",\\\"rule\\\":\\\"maxLength\\\",\\\"value\\\":160,\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lots\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lots\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT,\\\\n \\\\\\\"kind\\\\\\\" TEXT DEFAULT 'lot',\\\\n \\\\\\\"lot_number\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"search_key\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"identity_key\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"unique_number\\\\\\\" BOOLEAN DEFAULT FALSE,\\\\n \\\\\\\"received_qty\\\\\\\" REAL,\\\\n \\\\\\\"unit\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_type\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"attributes\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'active',\\\\n \\\\\\\"received_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"received_by_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"last_used_at\\\\\\\" TIMESTAMP\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"lot\\\"},\\\"lot_number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"search_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"identity_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"unique_number\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":false},\\\"received_qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unit\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"attributes\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"active\\\"},\\\"received_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"received_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"last_used_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lots_identity_key_tenant_id_idx\\\",\\\"columns\\\":[\\\"identity_key\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_lots_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_lots_search_key_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"search_key\\\"]},{\\\"name\\\":\\\"inventory_lots_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_lots_received_by_profile_id_idx\\\",\\\"columns\\\":[\\\"received_by_profile_id\\\"]}],\\\"version\\\":\\\"eb959677\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:LotCorrection\\\":{\\\"name\\\":\\\"lotcorrection\\\",\\\"className\\\":\\\"LotCorrection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:LotCorrection\\\",\\\"collection\\\":\\\"lotcorrections\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/LotCorrection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"lotId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Lot\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"constraint\\\":{\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]},\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\"}},\\\"kind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"attribute\\\",\\\"description\\\":\\\"What was corrected.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"What was corrected.\\\"},\\\"enum\\\":[\\\"lot_number\\\",\\\"attribute\\\",\\\"status\\\",\\\"unlink\\\",\\\"document_detach\\\"]},\\\"field\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"Which attribute changed, if one did.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Which attribute changed, if one did.\\\"}},\\\"oldValue\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"What it was.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What it was.\\\"}},\\\"newValue\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"What it is now.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What it is now.\\\"}},\\\"reason\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"description\\\":\\\"Why it was corrected.\\\",\\\"maxLength\\\":1000,\\\"_meta\\\":{\\\"required\\\":true,\\\"maxLength\\\":1000,\\\"description\\\":\\\"Why it was corrected.\\\"}},\\\"usageId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"documentId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"actorProfileId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-profiles:Profile\\\"},\\\"correctedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When it was corrected.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When it was corrected.\\\"}}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lot_corrections\\\",\\\"conflictColumns\\\":[\\\"id\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_corrections_lot_idx\\\",\\\"columns\\\":[\\\"lotId\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"LotCorrection\\\",\\\"collectionExportName\\\":\\\"LotCorrectionCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"lotId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"kind\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"reason\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"reason\\\",\\\"rule\\\":\\\"maxLength\\\",\\\"value\\\":1000,\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lot_corrections\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lot_corrections\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"lot_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"kind\\\\\\\" TEXT NOT NULL DEFAULT 'attribute',\\\\n \\\\\\\"field\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"old_value\\\\\\\" TEXT,\\\\n \\\\\\\"new_value\\\\\\\" TEXT,\\\\n \\\\\\\"reason\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"usage_id\\\\\\\" TEXT,\\\\n \\\\\\\"document_id\\\\\\\" TEXT,\\\\n \\\\\\\"actor_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"corrected_at\\\\\\\" TIMESTAMP\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"lot_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"inventory_lots\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"attribute\\\"},\\\"field\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"old_value\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"new_value\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"usage_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"document_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"actor_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"corrected_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_corrections_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_lot_corrections_lot_idx\\\",\\\"columns\\\":[\\\"lot_id\\\"]},{\\\"name\\\":\\\"inventory_lot_corrections_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_lot_corrections_actor_profile_id_idx\\\",\\\"columns\\\":[\\\"actor_profile_id\\\"]}],\\\"version\\\":\\\"d903252e\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:LotDocument\\\":{\\\"name\\\":\\\"lotdocument\\\",\\\"className\\\":\\\"LotDocument\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:LotDocument\\\",\\\"collection\\\":\\\"lotdocuments\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/LotDocument.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"lotId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Lot\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"constraint\\\":{\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]},\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\"}},\\\"assetId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-assets:Asset\\\"},\\\"role\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"certificate\\\",\\\"description\\\":\\\"What the document is for, for example certificate.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What the document is for, for example certificate.\\\"}},\\\"attachedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When it was attached.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When it was attached.\\\"}},\\\"attachedByProfileId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-profiles:Profile\\\"},\\\"detachedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"detachedByProfileId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-profiles:Profile\\\"}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lot_documents\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_documents_lot_idx\\\",\\\"columns\\\":[\\\"lotId\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"LotDocument\\\",\\\"collectionExportName\\\":\\\"LotDocumentCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"lotId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lot_documents\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lot_documents\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"lot_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"asset_id\\\\\\\" UUID,\\\\n \\\\\\\"role\\\\\\\" TEXT DEFAULT 'certificate',\\\\n \\\\\\\"attached_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"attached_by_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"detached_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"detached_by_profile_id\\\\\\\" UUID\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"lot_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"inventory_lots\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"asset_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"role\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"certificate\\\"},\\\"attached_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"attached_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"detached_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"detached_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_documents_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_lot_documents_lot_idx\\\",\\\"columns\\\":[\\\"lot_id\\\"]},{\\\"name\\\":\\\"inventory_lot_documents_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_lot_documents_asset_id_idx\\\",\\\"columns\\\":[\\\"asset_id\\\"]},{\\\"name\\\":\\\"inventory_lot_documents_attached_by_profile_id_idx\\\",\\\"columns\\\":[\\\"attached_by_profile_id\\\"]},{\\\"name\\\":\\\"inventory_lot_documents_detached_by_profile_id_idx\\\",\\\"columns\\\":[\\\"detached_by_profile_id\\\"]}],\\\"version\\\":\\\"076940be\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:LotStockLevel\\\":{\\\"name\\\":\\\"lotstocklevel\\\",\\\"className\\\":\\\"LotStockLevel\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:LotStockLevel\\\",\\\"collection\\\":\\\"lotstocklevels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/LotStockLevel.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"lotId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Lot\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"constraint\\\":{\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]},\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\"}},\\\"skuId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The item the lot is of.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The item the lot is of.\\\"}},\\\"locationId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"Where the lot is kept.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"Where the lot is kept.\\\"}},\\\"state\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"available\\\",\\\"description\\\":\\\"The state of this stock: available, allocated, wip, qc_hold or damaged.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The state of this stock: available, allocated, wip, qc_hold or damaged.\\\"},\\\"enum\\\":[\\\"available\\\",\\\"allocated\\\",\\\"wip\\\",\\\"qc_hold\\\",\\\"damaged\\\"]},\\\"qty\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How many are on hand.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How many are on hand.\\\"}}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lot_stock_levels\\\",\\\"conflictColumns\\\":[\\\"lot_id\\\",\\\"location_id\\\",\\\"state\\\",\\\"tenant_id\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"LotStockLevel\\\",\\\"collectionExportName\\\":\\\"LotStockLevelCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"lotId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"locationId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"state\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lot_stock_levels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lot_stock_levels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"lot_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"state\\\\\\\" TEXT NOT NULL DEFAULT 'available',\\\\n \\\\\\\"qty\\\\\\\" REAL\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"lot_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"inventory_lots\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"available\\\"},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_stock_levels_lot_id_location_id_idx\\\",\\\"columns\\\":[\\\"lot_id\\\",\\\"location_id\\\",\\\"state\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_lot_stock_levels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_lot_stock_levels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"6f6becfa\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:LotUsage\\\":{\\\"name\\\":\\\"lotusage\\\",\\\"className\\\":\\\"LotUsage\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:LotUsage\\\",\\\"collection\\\":\\\"lotusages\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/LotUsage.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"lotId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Lot\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"constraint\\\":{\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]},\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\"}},\\\"consumerType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What kind of record used the lot.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"What kind of record used the lot.\\\"}},\\\"consumerId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The record that used the lot.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The record that used the lot.\\\"}},\\\"qty\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How much was used.\\\",\\\"_meta\\\":{\\\"nullable\\\":true,\\\"description\\\":\\\"How much was used.\\\"}},\\\"unit\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The unit of measure.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The unit of measure.\\\"}},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"active\\\",\\\"description\\\":\\\"Whether the link still stands: active or unlinked.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Whether the link still stands: active or unlinked.\\\"},\\\"enum\\\":[\\\"active\\\",\\\"unlinked\\\"]},\\\"linkedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When the lot was linked.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When the lot was linked.\\\"}},\\\"linkedByProfileId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-profiles:Profile\\\"},\\\"unlinkedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"unlinkedByProfileId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-profiles:Profile\\\"},\\\"unlinkReason\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"Why the link was removed.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Why the link was removed.\\\"}},\\\"movementId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The stock movement for this use, if any.\\\",\\\"_meta\\\":{\\\"nullable\\\":true,\\\"description\\\":\\\"The stock movement for this use, if any.\\\"}}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_lot_usages\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_usages_consumer_idx\\\",\\\"columns\\\":[\\\"consumerType\\\",\\\"consumerId\\\"]},{\\\"name\\\":\\\"inventory_lot_usages_lot_status_idx\\\",\\\"columns\\\":[\\\"lotId\\\",\\\"status\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"LotUsage\\\",\\\"collectionExportName\\\":\\\"LotUsageCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"lotId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"consumerType\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"consumerId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_lot_usages\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_lot_usages\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"lot_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"consumer_type\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"consumer_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"unit\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'active',\\\\n \\\\\\\"linked_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"linked_by_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"unlinked_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"unlinked_by_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"unlink_reason\\\\\\\" TEXT,\\\\n \\\\\\\"movement_id\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"lot_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"inventory_lots\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"RESTRICT\\\",\\\"onUpdate\\\":\\\"RESTRICT\\\",\\\"engines\\\":[\\\"postgres\\\",\\\"sqlite\\\"]}},\\\"consumer_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"consumer_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unit\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"active\\\"},\\\"linked_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"linked_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unlinked_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unlinked_by_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"unlink_reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"movement_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_lot_usages_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_lot_usages_consumer_idx\\\",\\\"columns\\\":[\\\"consumer_type\\\",\\\"consumer_id\\\"]},{\\\"name\\\":\\\"inventory_lot_usages_lot_status_idx\\\",\\\"columns\\\":[\\\"lot_id\\\",\\\"status\\\"]},{\\\"name\\\":\\\"inventory_lot_usages_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_lot_usages_linked_by_profile_id_idx\\\",\\\"columns\\\":[\\\"linked_by_profile_id\\\"]},{\\\"name\\\":\\\"inventory_lot_usages_unlinked_by_profile_id_idx\\\",\\\"columns\\\":[\\\"unlinked_by_profile_id\\\"]}],\\\"version\\\":\\\"c106a419\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:StockLevel\\\":{\\\"name\\\":\\\"stocklevel\\\",\\\"className\\\":\\\"StockLevel\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:StockLevel\\\",\\\"collection\\\":\\\"stocklevels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/StockLevel.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"skuId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The item being counted.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The item being counted.\\\"}},\\\"locationId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"Where the stock is kept.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"Where the stock is kept.\\\"}},\\\"state\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"available\\\",\\\"description\\\":\\\"The state of this stock: available, allocated, wip, qc_hold or damaged.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The state of this stock: available, allocated, wip, qc_hold or damaged.\\\"},\\\"enum\\\":[\\\"available\\\",\\\"allocated\\\",\\\"wip\\\",\\\"qc_hold\\\",\\\"damaged\\\"]},\\\"qty\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How many are on hand.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How many are on hand.\\\"}},\\\"reorderPoint\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"reorderQuantity\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_stock_levels\\\",\\\"conflictColumns\\\":[\\\"sku_id\\\",\\\"location_id\\\",\\\"state\\\",\\\"tenant_id\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"StockLevel\\\",\\\"collectionExportName\\\":\\\"StockLevelCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"skuId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"locationId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"state\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_stock_levels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_stock_levels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"state\\\\\\\" TEXT NOT NULL DEFAULT 'available',\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"reorder_point\\\\\\\" REAL,\\\\n \\\\\\\"reorder_quantity\\\\\\\" REAL\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"available\\\"},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reorder_point\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reorder_quantity\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_stock_levels_sku_id_location_id_idx\\\",\\\"columns\\\":[\\\"sku_id\\\",\\\"location_id\\\",\\\"state\\\",\\\"tenant_id\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"inventory_stock_levels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_stock_levels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"02387935\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"},\\\"@happyvertical/smrt-inventory:StockMovement\\\":{\\\"name\\\":\\\"stockmovement\\\",\\\"className\\\":\\\"StockMovement\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-inventory:StockMovement\\\",\\\"collection\\\":\\\"stockmovements\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/inventory/src/models/StockMovement.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-inventory\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"skuId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The item that moved.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The item that moved.\\\"}},\\\"locationId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The place it moved at.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"The place it moved at.\\\"}},\\\"lotId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The lot that moved, when tracked by lot.\\\",\\\"_meta\\\":{\\\"nullable\\\":true,\\\"description\\\":\\\"The lot that moved, when tracked by lot.\\\"}},\\\"fromState\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"What it was before, for example available or damaged.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What it was before, for example available or damaged.\\\"},\\\"enum\\\":[\\\"available\\\",\\\"allocated\\\",\\\"wip\\\",\\\"qc_hold\\\",\\\"damaged\\\"]},\\\"toState\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"What it became.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What it became.\\\"},\\\"enum\\\":[\\\"available\\\",\\\"allocated\\\",\\\"wip\\\",\\\"qc_hold\\\",\\\"damaged\\\"]},\\\"qty\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"description\\\":\\\"How many moved.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"How many moved.\\\"}},\\\"reasonCode\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"adjustment\\\",\\\"description\\\":\\\"Why it moved, for example adjustment, sale or return.\\\",\\\"_meta\\\":{\\\"required\\\":true,\\\"description\\\":\\\"Why it moved, for example adjustment, sale or return.\\\"}},\\\"sourceType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"sourceId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"actorProfileId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-profiles:Profile\\\"},\\\"note\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"Anything worth remembering about this movement.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Anything worth remembering about this movement.\\\"}},\\\"occurredAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When it happened.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When it happened.\\\"}}},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"inventory_stock_movements\\\",\\\"conflictColumns\\\":[\\\"id\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_stock_movements_lot_idx\\\",\\\"columns\\\":[\\\"lotId\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"StockMovement\\\",\\\"collectionExportName\\\":\\\"StockMovementCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"skuId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"locationId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"reasonCode\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"inventory_stock_movements\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"inventory_stock_movements\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"sku_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"location_id\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"lot_id\\\\\\\" TEXT,\\\\n \\\\\\\"from_state\\\\\\\" TEXT,\\\\n \\\\\\\"to_state\\\\\\\" TEXT,\\\\n \\\\\\\"qty\\\\\\\" REAL,\\\\n \\\\\\\"reason_code\\\\\\\" TEXT NOT NULL DEFAULT 'adjustment',\\\\n \\\\\\\"source_type\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_id\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"actor_profile_id\\\\\\\" UUID,\\\\n \\\\\\\"note\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"occurred_at\\\\\\\" TIMESTAMP\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"sku_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"location_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"lot_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"from_state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"to_state\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"qty\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"reason_code\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"adjustment\\\"},\\\"source_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"actor_profile_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"note\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"occurred_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"inventory_stock_movements_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_lot_idx\\\",\\\"columns\\\":[\\\"lot_id\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"inventory_stock_movements_actor_profile_id_idx\\\",\\\"columns\\\":[\\\"actor_profile_id\\\"]}],\\\"version\\\":\\\"b426c2c5\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-inventory\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"recipes\\\":[{\\\"id\\\":\\\"inventory.stock\\\",\\\"className\\\":\\\"StockRecipe\\\",\\\"label\\\":\\\"Inventory\\\",\\\"summary\\\":\\\"Keep count of how many of each product you have.\\\",\\\"synonyms\\\":[\\\"stock\\\",\\\"quantity\\\",\\\"on hand\\\"],\\\"models\\\":[\\\"@happyvertical/smrt-inventory:StockLevel\\\",\\\"@happyvertical/smrt-inventory:InventoryLocation\\\",\\\"@happyvertical/smrt-inventory:StockMovement\\\"],\\\"nav\\\":[{\\\"label\\\":\\\"Stock levels\\\",\\\"model\\\":\\\"@happyvertical/smrt-inventory:StockLevel\\\",\\\"icon\\\":\\\"archive\\\",\\\"description\\\":\\\"How much of each item you have on hand right now.\\\",\\\"noun\\\":\\\"stock entry\\\"},{\\\"label\\\":\\\"Locations\\\",\\\"model\\\":\\\"@happyvertical/smrt-inventory:InventoryLocation\\\",\\\"icon\\\":\\\"home\\\",\\\"description\\\":\\\"The places you keep stock, like shelves, rooms or vans.\\\"},{\\\"label\\\":\\\"Stock movements\\\",\\\"model\\\":\\\"@happyvertical/smrt-inventory:StockMovement\\\",\\\"icon\\\":\\\"truck\\\",\\\"description\\\":\\\"Every time stock came in, went out or moved.\\\"}],\\\"requires\\\":[],\\\"requiresAny\\\":[[\\\"products.simple\\\",\\\"products.clothing\\\"]],\\\"section\\\":{\\\"id\\\":\\\"catalog\\\",\\\"label\\\":\\\"Catalog\\\",\\\"icon\\\":\\\"package\\\",\\\"description\\\":\\\"Products, ingredients and the stock you hold.\\\"},\\\"options\\\":{\\\"@happyvertical/smrt-inventory:StockLevel\\\":{\\\"fields\\\":{\\\"reorderPoint\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"reorderQuantity\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-inventory:InventoryLocation\\\":{\\\"fields\\\":{\\\"placeId\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"active\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-inventory:StockMovement\\\":{\\\"fields\\\":{\\\"sourceType\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"sourceId\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"actorProfileId\\\":{\\\"visibility\\\":\\\"hidden\\\"}}}},\\\"help\\\":{\\\"markdown\\\":\\\"## Overview\\\\n\\\\nInventory keeps count of how many of each product you have. Each count is a\\\\nstock level: an item, the place it is kept and how many are on hand. Stock can\\\\nsit in more than one place, and every change is recorded as a stock movement so\\\\nthere is a trail.\\\\n\\\\n## Tasks\\\\n\\\\n### Count what you have\\\\n\\\\n1. Create a stock level for the item and the place it is kept.\\\\n2. Set **{field:qty}** to how many you have on hand.\\\\n3. Set **{field:state}** if the stock is not available to sell, for example\\\\n allocated or on quality hold.\\\\n\\\\n### Correct a count\\\\n\\\\n1. Find the stock level for the item.\\\\n2. Set **{field:qty}** to what you really have. Record why as a stock movement.\\\\n\\\\n### Keep stock in more than one place\\\\n\\\\n1. Add a location with a **{field:code}** and a **{field:name}**, and say what\\\\n sort it is in **{field:kind}**.\\\\n2. Create stock levels against that location.\\\\n\\\",\\\"fieldRefs\\\":[\\\"code\\\",\\\"kind\\\",\\\"name\\\",\\\"qty\\\",\\\"state\\\"]},\\\"demo\\\":{\\\"mode\\\":\\\"server\\\",\\\"reasons\\\":[\\\"Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624).\\\"]}}],\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\"],\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","/**\n * InventoryLocation — a physical or virtual place where stock can sit.\n *\n * `kind` is intentionally a free-form string (see\n * {@link InventoryLocationKind}). Common values are `'warehouse'`,\n * `'factory'`, `'retail'`, `'in_transit'`, or `'virtual'`, but the\n * framework does not special-case any of them. Each application is free\n * to extend the vocabulary.\n *\n * Locations may optionally point at a place row in\n * `@happyvertical/smrt-places` via the plain-string `placeId` — useful\n * when an InventoryLocation maps to a real-world address or POI. The\n * reference is a plain string id, not a `@foreignKey()`, to avoid a\n * cross-package dependency on `smrt-places`.\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { InventoryLocationKind } from '../types.js';\n\n/**\n * Options accepted by the {@link InventoryLocation} constructor.\n */\nexport interface InventoryLocationOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n code?: string;\n name?: string;\n kind?: InventoryLocationKind;\n placeId?: string;\n active?: boolean;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_locations',\n conflictColumns: ['code', 'tenant_id'],\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class InventoryLocation extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the location record is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Short stable identifier (`'WH-EAST'`, `'STORE-42'`, `'IN-TRANSIT'`).\n * Together with `tenantId` this is the natural key.\n */\n @field({\n required: true,\n description: 'A short code for the place stock is kept, for example MAIN.',\n })\n code: string = '';\n\n /** Display name for UIs. */\n @field({\n description: 'What you call the place, for example Main warehouse.',\n })\n name: string = '';\n\n /**\n * Open-ended classifier (`'warehouse'`, `'factory'`, `'retail'`,\n * `'in_transit'`, `'virtual'`, or anything else your domain needs).\n * The framework never branches on this value.\n */\n @field({\n description:\n 'What sort of place it is, for example a warehouse or a shop floor.',\n })\n kind: InventoryLocationKind = 'warehouse';\n\n /**\n * Optional plain-string reference to a `Place.id` in\n * `@happyvertical/smrt-places`. Cross-package id; intentionally not a\n * `@foreignKey()` so this package can be used without `smrt-places`\n * installed.\n */\n placeId: string = '';\n\n /** Soft-active flag — inactive locations stay queryable for history. */\n active: boolean = true;\n\n constructor(options: InventoryLocationOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.code !== undefined) this.code = options.code;\n if (options.name !== undefined) this.name = options.name;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.placeId !== undefined) this.placeId = options.placeId;\n if (options.active !== undefined) this.active = options.active;\n }\n}\n","/**\n * InventoryLocationCollection — query helpers for {@link InventoryLocation}.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { InventoryLocation } from '../models/InventoryLocation.js';\nimport type { InventoryLocationKind } from '../types.js';\n\nexport class InventoryLocationCollection extends SmrtCollection<InventoryLocation> {\n static readonly _itemClass = InventoryLocation;\n\n /**\n * Look up a location by its tenant-scoped `code`. Returns `null` when\n * no row matches.\n */\n async findByCode(code: string): Promise<InventoryLocation | null> {\n const matches = await this.list({ where: { code }, limit: 1 });\n return matches[0] ?? null;\n }\n\n /**\n * Find every location classified as the given kind (`'warehouse'`,\n * `'factory'`, `'retail'`, `'in_transit'`, …).\n */\n async findByKind(kind: InventoryLocationKind): Promise<InventoryLocation[]> {\n return this.list({ where: { kind }, orderBy: 'code ASC' });\n }\n\n /**\n * Find every location linked to a particular `Place.id` from\n * `@happyvertical/smrt-places`. Returns an empty array when no row\n * references the place.\n */\n async findByPlace(placeId: string): Promise<InventoryLocation[]> {\n if (!placeId) return [];\n return this.list({ where: { placeId }, orderBy: 'code ASC' });\n }\n\n /** Find every active location, optionally narrowed by kind. */\n async findActive(kind?: InventoryLocationKind): Promise<InventoryLocation[]> {\n const where: Record<string, unknown> = { active: true };\n if (kind) where.kind = kind;\n return this.list({ where, orderBy: 'code ASC' });\n }\n}\n","/**\n * Lot — a traceable batch of material, or a single serialized unit.\n *\n * A lot is the identity that stock carries when it must be traced back to\n * where it came from (a supplier batch code, a serial number, any\n * caller-defined identifier). Stock on hand per lot lives in\n * {@link LotStockLevel}; who consumed the lot lives in {@link LotUsage};\n * every after-the-fact change is a {@link LotCorrection}.\n *\n * **Write only through {@link LotService}.** The service keeps `searchKey`\n * and `identityKey` in sync with `lotNumber`, records the correction trail,\n * and enforces exclusivity for serials. Direct `save()` calls bypass all of\n * that.\n *\n * `lotNumber` is not unique by default: one supplier lot can legitimately\n * arrive on two receipts. `identityKey` is what the database enforces, and\n * it derives from the number only for unique lots and serials (see\n * {@link LotService.receiveLot}).\n *\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { LotKind } from '../types.js';\n\n/**\n * Options accepted by the {@link Lot} constructor.\n */\nexport interface LotOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n skuId?: string | null;\n kind?: LotKind;\n lotNumber?: string;\n searchKey?: string;\n identityKey?: string;\n uniqueNumber?: boolean;\n receivedQty?: number;\n unit?: string;\n sourceType?: string;\n sourceId?: string;\n attributes?: Record<string, unknown> | string;\n status?: string;\n receivedAt?: Date | string;\n receivedByProfileId?: string | null;\n lastUsedAt?: Date | string | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_lots',\n // The database-enforced identity. Every create is insert-only, so a\n // duplicate identityKey fails instead of silently overwriting the lot.\n conflictColumns: ['identity_key', 'tenant_id'],\n // Writes go through LotService only (number sync, correction trail).\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n indexes: [\n {\n name: 'inventory_lots_search_key_idx',\n columns: ['tenantId', 'searchKey'],\n },\n ],\n})\nexport class Lot extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the lot is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Plain string reference to the catalog Sku. Null when the lot covers\n * uncatalogued material.\n */\n @field({\n nullable: true,\n description: 'The item this lot is of, if catalogued.',\n })\n skuId: string | null = null;\n\n /** `lot` for a quantity of material, `serial` for one unit. */\n @field({\n description: 'Whether this is a batch (lot) or a single unit (serial).',\n })\n kind: LotKind = 'lot';\n\n /** The identifier as the caller wrote it: batch code, supplier lot, serial number. */\n @field({\n required: true,\n maxLength: 128,\n description: 'The batch code, supplier lot or serial number.',\n })\n lotNumber: string = '';\n\n /** `lotNumber` trimmed and upper-cased, for case-insensitive lookup. Service-maintained. */\n @field({\n maxLength: 160,\n description: 'The number in normal form, used for lookup.',\n })\n searchKey: string = '';\n\n /** What the database keeps unique. Service-maintained; never write it directly. */\n @field({\n required: true,\n maxLength: 160,\n description: 'Internal identity that keeps lots from being created twice.',\n })\n identityKey: string = '';\n\n /** Whether `identityKey` derives from the number (true for serials). */\n @field({ description: 'Whether the number must be unique for this item.' })\n uniqueNumber: boolean = false;\n\n /** Quantity on the receipt that created the lot (1 for a serial). */\n @field({ type: 'decimal', description: 'How many came in on the receipt.' })\n receivedQty: number = 0.0;\n\n /** Unit of measure for `receivedQty`, free text. */\n @field({ description: 'The unit of measure.' })\n unit: string = '';\n\n /** Receipt attribution, same convention as {@link StockMovement.sourceType}. */\n @field({ description: 'What kind of record received this lot.' })\n sourceType: string = '';\n\n /** Id of the record that received this lot. */\n @field({ description: 'The record that received this lot.' })\n sourceId: string = '';\n\n /** Free-form properties as a JSON string; see {@link getAttributes}. */\n @field({\n type: 'text',\n description: 'Anything else worth knowing about this lot, stored as JSON.',\n })\n attributes: string = '{}';\n\n /**\n * Open string. Documented values: `active`, `quarantined`, `consumed`,\n * `void`.\n */\n @field({\n description: 'Where the lot stands: active, quarantined, consumed or void.',\n })\n status: string = 'active';\n\n /** When the lot arrived. */\n @field({ description: 'When the lot was received.' })\n receivedAt: Date = new Date();\n\n /** Profile that received the lot. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n receivedByProfileId: string | null = null;\n\n /**\n * Touched by {@link LotService.recordUsage} and `unlinkUsage` so that\n * concurrent changes to a lot's usage conflict on its revision.\n */\n @field({ type: 'datetime', nullable: true })\n lastUsedAt: Date | null = null;\n\n constructor(options: LotOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.skuId !== undefined) this.skuId = options.skuId;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.lotNumber !== undefined) this.lotNumber = options.lotNumber;\n if (options.searchKey !== undefined) this.searchKey = options.searchKey;\n if (options.identityKey !== undefined)\n this.identityKey = options.identityKey;\n if (options.uniqueNumber !== undefined)\n this.uniqueNumber = options.uniqueNumber;\n if (options.receivedQty !== undefined)\n this.receivedQty = options.receivedQty;\n if (options.unit !== undefined) this.unit = options.unit;\n if (options.sourceType !== undefined) this.sourceType = options.sourceType;\n if (options.sourceId !== undefined) this.sourceId = options.sourceId;\n if (options.attributes !== undefined)\n this.setAttributes(options.attributes);\n if (options.status !== undefined) this.status = options.status;\n if (options.receivedAt !== undefined) {\n this.receivedAt =\n options.receivedAt instanceof Date\n ? options.receivedAt\n : new Date(options.receivedAt);\n }\n if (options.receivedByProfileId !== undefined)\n this.receivedByProfileId = options.receivedByProfileId;\n if (options.lastUsedAt !== undefined) {\n this.lastUsedAt =\n options.lastUsedAt === null || options.lastUsedAt instanceof Date\n ? options.lastUsedAt\n : new Date(options.lastUsedAt);\n }\n }\n\n /**\n * Parse {@link attributes}. Returns an empty object for invalid JSON so\n * callers need no try/catch.\n */\n getAttributes(): Record<string, unknown> {\n if (!this.attributes) return {};\n try {\n const parsed = JSON.parse(this.attributes);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n }\n\n /** Store attributes from an object or an already-serialized JSON string. */\n setAttributes(value: Record<string, unknown> | string): void {\n this.attributes =\n typeof value === 'string' ? value : JSON.stringify(value ?? {});\n }\n}\n","/**\n * LotCollection — read helpers for lots. Writes go through\n * {@link LotService}.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Lot } from '../models/Lot.js';\n\n/** Normal form of a lot number used for lookup: trimmed and upper-cased. */\nexport function lotSearchKey(lotNumber: string): string {\n return lotNumber.trim().toUpperCase();\n}\n\nexport class LotCollection extends SmrtCollection<Lot> {\n static readonly _itemClass = Lot;\n\n /**\n * Find lots by number, case-insensitively and ignoring surrounding\n * whitespace. A number can match several lots (one supplier lot received\n * twice); pass `skuId` to narrow. Oldest receipt first.\n */\n async findByLotNumber(\n lotNumber: string,\n options: { skuId?: string | null } = {},\n ): Promise<Lot[]> {\n const where: Record<string, unknown> = {\n searchKey: lotSearchKey(lotNumber),\n };\n if (options.skuId !== undefined) where.skuId = options.skuId;\n return this.list({ where, orderBy: 'receivedAt ASC' });\n }\n}\n","/**\n * LotCorrection — append-only record of an after-the-fact change to a lot.\n *\n * Fixing a mistyped lot number, editing an attribute, changing status,\n * unlinking a usage or detaching a document each write exactly one\n * correction with the old value, the new value, who did it and why. The\n * reason is mandatory. Like {@link StockMovement}, rows are never updated\n * or deleted. Write only through {@link LotService}.\n *\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { LotCorrectionKind } from '../types.js';\nimport { Lot } from './Lot.js';\n\n/**\n * Options accepted by the {@link LotCorrection} constructor.\n */\nexport interface LotCorrectionOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n lotId?: string;\n kind?: LotCorrectionKind;\n field?: string;\n oldValue?: string;\n newValue?: string;\n reason?: string;\n usageId?: string | null;\n documentId?: string | null;\n actorProfileId?: string | null;\n correctedAt?: Date | string;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_lot_corrections',\n // Append-only: the surrogate id is the only key, as for StockMovement.\n conflictColumns: ['id'],\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n indexes: [{ name: 'inventory_lot_corrections_lot_idx', columns: ['lotId'] }],\n})\nexport class LotCorrection extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the correction is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** The lot that was corrected. */\n @foreignKey(Lot, {\n required: true,\n onDelete: 'RESTRICT',\n onUpdate: 'RESTRICT',\n // DuckDB cannot enforce the constraint; the id is never rewritten.\n constraint: { engines: ['postgres', 'sqlite'] },\n })\n lotId: string = '';\n\n /** What was corrected. */\n @field({ required: true, description: 'What was corrected.' })\n kind: LotCorrectionKind = 'attribute';\n\n /** The attribute key for `attribute` corrections; empty otherwise. */\n @field({ description: 'Which attribute changed, if one did.' })\n field: string = '';\n\n /** The value before the correction. */\n @field({ type: 'text', description: 'What it was.' })\n oldValue: string = '';\n\n /** The value after the correction. */\n @field({ type: 'text', description: 'What it is now.' })\n newValue: string = '';\n\n /** Why the correction was made. Required, at most 1000 characters. */\n @field({\n type: 'text',\n required: true,\n maxLength: 1000,\n description: 'Why it was corrected.',\n })\n reason: string = '';\n\n /** The {@link LotUsage} unlinked, for `unlink` corrections. */\n @field({ nullable: true })\n usageId: string | null = null;\n\n /** The {@link LotDocument} detached, for `document_detach` corrections. */\n @field({ nullable: true })\n documentId: string | null = null;\n\n /** Profile that made the correction. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n actorProfileId: string | null = null;\n\n /** When the correction was made. */\n @field({ description: 'When it was corrected.' })\n correctedAt: Date = new Date();\n\n constructor(options: LotCorrectionOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.lotId !== undefined) this.lotId = options.lotId;\n if (options.kind !== undefined) this.kind = options.kind;\n if (options.field !== undefined) this.field = options.field;\n if (options.oldValue !== undefined) this.oldValue = options.oldValue;\n if (options.newValue !== undefined) this.newValue = options.newValue;\n if (options.reason !== undefined) this.reason = options.reason;\n if (options.usageId !== undefined) this.usageId = options.usageId;\n if (options.documentId !== undefined) this.documentId = options.documentId;\n if (options.actorProfileId !== undefined)\n this.actorProfileId = options.actorProfileId;\n if (options.correctedAt !== undefined) {\n this.correctedAt =\n options.correctedAt instanceof Date\n ? options.correctedAt\n : new Date(options.correctedAt);\n }\n }\n}\n","/**\n * LotCorrectionCollection — read access to the append-only correction\n * trail. Writes go through {@link LotService}.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { LotCorrection } from '../models/LotCorrection.js';\n\nexport class LotCorrectionCollection extends SmrtCollection<LotCorrection> {\n static readonly _itemClass = LotCorrection;\n}\n","/**\n * LotDocument — a document attached to a lot (a certificate, a test\n * report, a delivery note).\n *\n * The file itself is an Asset from `@happyvertical/smrt-assets`, referenced\n * by id; this package takes no dependency on it. Detaching sets\n * `detachedAt` and writes a {@link LotCorrection}; the row stays. Write\n * only through {@link LotService}.\n *\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport { Lot } from './Lot.js';\n\n/**\n * Options accepted by the {@link LotDocument} constructor.\n */\nexport interface LotDocumentOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n lotId?: string;\n assetId?: string;\n role?: string;\n attachedAt?: Date | string;\n attachedByProfileId?: string | null;\n detachedAt?: Date | string | null;\n detachedByProfileId?: string | null;\n}\n\nconst toDate = (value: Date | string) =>\n value instanceof Date ? value : new Date(value);\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_lot_documents',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n indexes: [{ name: 'inventory_lot_documents_lot_idx', columns: ['lotId'] }],\n})\nexport class LotDocument extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the document link is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** The lot the document belongs to. */\n @foreignKey(Lot, {\n required: true,\n onDelete: 'RESTRICT',\n onUpdate: 'RESTRICT',\n // DuckDB cannot enforce the constraint; the id is never rewritten.\n constraint: { engines: ['postgres', 'sqlite'] },\n })\n lotId: string = '';\n\n /** The stored file. */\n @crossPackageRef('@happyvertical/smrt-assets:Asset')\n assetId: string = '';\n\n /** What the document is for, free text, for example `certificate`. */\n @field({ description: 'What the document is for, for example certificate.' })\n role: string = 'certificate';\n\n /** When the document was attached. */\n @field({ description: 'When it was attached.' })\n attachedAt: Date = new Date();\n\n /** Profile that attached it. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n attachedByProfileId: string | null = null;\n\n /** When it was detached, if it was. */\n @field({ type: 'datetime', nullable: true })\n detachedAt: Date | null = null;\n\n /** Profile that detached it. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n detachedByProfileId: string | null = null;\n\n constructor(options: LotDocumentOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.lotId !== undefined) this.lotId = options.lotId;\n if (options.assetId !== undefined) this.assetId = options.assetId;\n if (options.role !== undefined) this.role = options.role;\n if (options.attachedAt !== undefined)\n this.attachedAt = toDate(options.attachedAt);\n if (options.attachedByProfileId !== undefined)\n this.attachedByProfileId = options.attachedByProfileId;\n if (options.detachedAt !== undefined)\n this.detachedAt =\n options.detachedAt === null ? null : toDate(options.detachedAt);\n if (options.detachedByProfileId !== undefined)\n this.detachedByProfileId = options.detachedByProfileId;\n }\n}\n","/**\n * LotDocumentCollection — read access to documents attached to lots.\n * Writes go through {@link LotService}.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { LotDocument } from '../models/LotDocument.js';\n\nexport class LotDocumentCollection extends SmrtCollection<LotDocument> {\n static readonly _itemClass = LotDocument;\n}\n","/**\n * LotStockLevel — materialized quantity at a `(lotId, locationId, state)`\n * tuple.\n *\n * The per-lot companion to {@link StockLevel}: when a {@link StockService}\n * mutation is given a `lotId`, it applies the same deltas here as it does\n * to the SKU-level row. It is a separate table so `StockLevel`'s unique\n * key never changes.\n *\n * **Do not call `create()` or `save()` on LotStockLevel directly.** Only\n * {@link StockService} writes it, in the same transaction as the movement.\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { StockState } from '../types.js';\nimport { Lot } from './Lot.js';\n\n/**\n * Options accepted by the {@link LotStockLevel} constructor.\n */\nexport interface LotStockLevelOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n lotId?: string;\n skuId?: string;\n locationId?: string;\n state?: StockState;\n qty?: number;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_lot_stock_levels',\n conflictColumns: ['lot_id', 'location_id', 'state', 'tenant_id'],\n // Materialized state written only by StockService; see StockLevel.\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class LotStockLevel extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the level row is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** The {@link Lot} this row tracks. */\n @foreignKey(Lot, {\n required: true,\n onDelete: 'RESTRICT',\n onUpdate: 'RESTRICT',\n // DuckDB cannot enforce the constraint; the id is never rewritten.\n constraint: { engines: ['postgres', 'sqlite'] },\n })\n lotId: string = '';\n\n /** Plain string reference to the Sku, copied from the movement. */\n @field({ description: 'The item the lot is of.' })\n skuId: string = '';\n\n /** Plain string reference to the {@link InventoryLocation}. */\n @field({ required: true, description: 'Where the lot is kept.' })\n locationId: string = '';\n\n /** Logical state, same vocabulary as {@link StockLevel.state}. */\n @field({\n required: true,\n description:\n 'The state of this stock: available, allocated, wip, qc_hold or damaged.',\n })\n state: StockState = 'available';\n\n /** Current quantity of the lot in this state at this location. */\n @field({ type: 'decimal', description: 'How many are on hand.' })\n qty: number = 0.0;\n\n constructor(options: LotStockLevelOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.lotId !== undefined) this.lotId = options.lotId;\n if (options.skuId !== undefined) this.skuId = options.skuId;\n if (options.locationId !== undefined) this.locationId = options.locationId;\n if (options.state !== undefined) this.state = options.state;\n if (options.qty !== undefined) this.qty = options.qty;\n }\n}\n","/**\n * LotStockLevelCollection — read helpers for per-lot balances.\n *\n * Mutations live in {@link StockService}; see {@link StockLevelCollection}.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { LotStockLevel } from '../models/LotStockLevel.js';\nimport type { StockState } from '../types.js';\n\nexport class LotStockLevelCollection extends SmrtCollection<LotStockLevel> {\n static readonly _itemClass = LotStockLevel;\n\n /** The level row for a `(lotId, locationId, state)` tuple, or `null`. */\n async getLevel(\n lotId: string,\n locationId: string,\n state: StockState = 'available',\n ): Promise<LotStockLevel | null> {\n const matches = await this.list({\n where: { lotId, locationId, state },\n limit: 1,\n });\n return matches[0] ?? null;\n }\n\n /**\n * Sum of the lot's quantity across locations. Pass `state` to narrow\n * to one state; omit it for the total across all states.\n */\n async onHand(lotId: string, state?: StockState): Promise<number> {\n const where: Record<string, unknown> = { lotId };\n if (state) where.state = state;\n const rows = await this.list({ where });\n return rows.reduce((sum, row) => sum + Number(row.qty ?? 0), 0);\n }\n}\n","/**\n * LotUsage — one edge of the trace graph: a lot used by a consumer.\n *\n * The consumer is cross-package attribution (`consumerType` +\n * `consumerId`, for example `'ProductionOrder'` and its id). When the\n * consumer is itself another lot (an assembly), use `consumerType: 'Lot'`\n * so forward and backward traces can walk the lineage.\n *\n * Rows are never deleted. Correcting a mistaken link flips `status` to\n * `unlinked` and writes a {@link LotCorrection}; the original edge stays\n * on record. Write only through {@link LotService}.\n *\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { LotUsageStatus } from '../types.js';\nimport { Lot } from './Lot.js';\n\n/**\n * Options accepted by the {@link LotUsage} constructor.\n */\nexport interface LotUsageOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n lotId?: string;\n consumerType?: string;\n consumerId?: string;\n qty?: number | null;\n unit?: string;\n status?: LotUsageStatus;\n linkedAt?: Date | string;\n linkedByProfileId?: string | null;\n unlinkedAt?: Date | string | null;\n unlinkedByProfileId?: string | null;\n unlinkReason?: string;\n movementId?: string | null;\n}\n\nconst toDate = (value: Date | string) =>\n value instanceof Date ? value : new Date(value);\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_lot_usages',\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n indexes: [\n {\n name: 'inventory_lot_usages_consumer_idx',\n columns: ['consumerType', 'consumerId'],\n },\n {\n name: 'inventory_lot_usages_lot_status_idx',\n columns: ['lotId', 'status'],\n },\n ],\n})\nexport class LotUsage extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the usage is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** The lot that was used. */\n @foreignKey(Lot, {\n required: true,\n onDelete: 'RESTRICT',\n onUpdate: 'RESTRICT',\n // DuckDB cannot enforce the constraint; the id is never rewritten.\n constraint: { engines: ['postgres', 'sqlite'] },\n })\n lotId: string = '';\n\n /** Kind of consumer, for example `'ProductionOrder'`; `'Lot'` for an assembly. */\n @field({ required: true, description: 'What kind of record used the lot.' })\n consumerType: string = '';\n\n /** Id of the consumer. */\n @field({ required: true, description: 'The record that used the lot.' })\n consumerId: string = '';\n\n /** Quantity used; null means unspecified (the whole lot, or not tracked). */\n @field({ type: 'decimal', nullable: true, description: 'How much was used.' })\n qty: number | null = null;\n\n /** Unit of measure for `qty`. */\n @field({ description: 'The unit of measure.' })\n unit: string = '';\n\n /** `active`, or `unlinked` once a correction removed the link. */\n @field({ description: 'Whether the link still stands: active or unlinked.' })\n status: LotUsageStatus = 'active';\n\n /** When the usage was recorded. */\n @field({ description: 'When the lot was linked.' })\n linkedAt: Date = new Date();\n\n /** Profile that recorded the usage. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n linkedByProfileId: string | null = null;\n\n /** When the link was removed, if it was. */\n @field({ type: 'datetime', nullable: true })\n unlinkedAt: Date | null = null;\n\n /** Profile that removed the link. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n unlinkedByProfileId: string | null = null;\n\n /** Why the link was removed. */\n @field({ type: 'text', description: 'Why the link was removed.' })\n unlinkReason: string = '';\n\n /** Optional StockMovement that took this quantity out. */\n @field({\n nullable: true,\n description: 'The stock movement for this use, if any.',\n })\n movementId: string | null = null;\n\n constructor(options: LotUsageOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.lotId !== undefined) this.lotId = options.lotId;\n if (options.consumerType !== undefined)\n this.consumerType = options.consumerType;\n if (options.consumerId !== undefined) this.consumerId = options.consumerId;\n if (options.qty !== undefined) this.qty = options.qty;\n if (options.unit !== undefined) this.unit = options.unit;\n if (options.status !== undefined) this.status = options.status;\n if (options.linkedAt !== undefined)\n this.linkedAt = toDate(options.linkedAt);\n if (options.linkedByProfileId !== undefined)\n this.linkedByProfileId = options.linkedByProfileId;\n if (options.unlinkedAt !== undefined)\n this.unlinkedAt =\n options.unlinkedAt === null ? null : toDate(options.unlinkedAt);\n if (options.unlinkedByProfileId !== undefined)\n this.unlinkedByProfileId = options.unlinkedByProfileId;\n if (options.unlinkReason !== undefined)\n this.unlinkReason = options.unlinkReason;\n if (options.movementId !== undefined) this.movementId = options.movementId;\n }\n}\n","/**\n * LotUsageCollection — read helpers for lot usage edges. Writes go\n * through {@link LotService}.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { LotUsage } from '../models/LotUsage.js';\n\nexport class LotUsageCollection extends SmrtCollection<LotUsage> {\n static readonly _itemClass = LotUsage;\n\n /** Usages of the lot that have not been unlinked, oldest first. */\n async findActiveForLot(lotId: string): Promise<LotUsage[]> {\n return this.list({\n where: { lotId, status: 'active' },\n orderBy: 'linkedAt ASC',\n });\n }\n\n /** Every usage by one consumer, oldest first. Active only unless asked. */\n async findForConsumer(\n consumerType: string,\n consumerId: string,\n options: { includeUnlinked?: boolean } = {},\n ): Promise<LotUsage[]> {\n const where: Record<string, unknown> = { consumerType, consumerId };\n if (!options.includeUnlinked) where.status = 'active';\n return this.list({ where, orderBy: 'linkedAt ASC' });\n }\n}\n","/**\n * StockLevel — materialized quantity at a `(skuId, locationId, state)` tuple.\n *\n * StockLevel is the live, mutable view of on-hand stock. There is at most\n * one row per `(skuId, locationId, state)` per tenant; the natural key\n * (`conflictColumns`) gives us idempotent upserts. Each row's `qty`\n * floats up and down as the {@link StockService} processes\n * receive/reserve/release/fulfill/transfer/adjust calls.\n *\n * **Do not call `create()` or `save()` on StockLevel directly.** All\n * mutations must go through {@link StockService}, which guarantees that\n * the level change and the corresponding append-only StockMovement land\n * together. Direct writes will silently desync the audit ledger and make\n * cycle counts unreliable.\n *\n * @packageDocumentation\n */\n\nimport {\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { StockState } from '../types.js';\n\n/**\n * Options accepted by the {@link StockLevel} constructor.\n */\nexport interface StockLevelOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n skuId?: string;\n locationId?: string;\n state?: StockState;\n qty?: number;\n reorderPoint?: number | null;\n reorderQuantity?: number | null;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_stock_levels',\n conflictColumns: ['sku_id', 'location_id', 'state', 'tenant_id'],\n // StockLevel is materialized state, written only by StockService.\n // Mirror the read-only api/mcp posture on the CLI — `cli: true` would\n // generate create/update/delete subcommands that let a CLI user\n // mutate `qty` (or delete a row) without writing a paired\n // StockMovement, silently desyncing the audit ledger from the\n // materialized balance. The Gotchas section in CLAUDE.md spells out\n // the \"never call StockLevel.save() directly\" rule; the CLI must\n // follow the same constraint.\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n})\nexport class StockLevel extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the level row is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Plain string reference to the {@link Sku} this row tracks. */\n @field({\n required: true,\n description: 'The item being counted.',\n })\n skuId: string = '';\n\n /** Plain string reference to the {@link InventoryLocation} this row tracks. */\n @field({\n required: true,\n description: 'Where the stock is kept.',\n })\n locationId: string = '';\n\n /** Logical state — `available`, `allocated`, `wip`, `qc_hold`, `damaged`. */\n @field({\n required: true,\n description:\n 'The state of this stock: available, allocated, wip, qc_hold or damaged.',\n })\n state: StockState = 'available';\n\n /**\n * Current quantity. Fractional values are allowed (`= 0.0`) for\n * domains that count in units of measure other than whole pieces\n * (kilograms, litres, metres).\n */\n @field({ type: 'decimal', description: 'How many are on hand.' })\n qty: number = 0.0;\n\n /** Available-stock threshold; null disables reorder monitoring. */\n @field({ type: 'decimal', nullable: true })\n reorderPoint: number | null = null;\n\n /** Optional suggested replenishment quantity, independent of stock balance. */\n @field({ type: 'decimal', nullable: true })\n reorderQuantity: number | null = null;\n\n constructor(options: StockLevelOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.skuId !== undefined) this.skuId = options.skuId;\n if (options.locationId !== undefined) this.locationId = options.locationId;\n if (options.state !== undefined) this.state = options.state;\n if (options.qty !== undefined) this.qty = options.qty;\n if (options.reorderPoint !== undefined)\n this.reorderPoint = options.reorderPoint;\n if (options.reorderQuantity !== undefined)\n this.reorderQuantity = options.reorderQuantity;\n }\n}\n","/**\n * StockLevelCollection — read helpers and balance aggregations.\n *\n * Mutations live in {@link StockService}. The collection here is for\n * reading the materialized view only; callers that want to change\n * `qty` must go through the service so the StockMovement audit row is\n * also written.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { StockLevel } from '../models/StockLevel.js';\nimport type { StockState } from '../types.js';\n\nexport class StockLevelCollection extends SmrtCollection<StockLevel> {\n static readonly _itemClass = StockLevel;\n\n /**\n * Fetch the level row for a `(skuId, locationId, state)` tuple, or\n * `null` when the row has never been written. State defaults to\n * `'available'` because that is the common case (selling / picking\n * decisions are driven by available stock).\n */\n async getLevel(\n skuId: string,\n locationId: string,\n state: StockState = 'available',\n ): Promise<StockLevel | null> {\n const matches = await this.list({\n where: { skuId, locationId, state },\n limit: 1,\n });\n return matches[0] ?? null;\n }\n\n /**\n * Return every level row for the given SKU across all locations and\n * states. Useful for \"where is this SKU?\" admin screens.\n */\n async findBySku(skuId: string): Promise<StockLevel[]> {\n return this.list({ where: { skuId } });\n }\n\n /**\n * Return every level row at the given location. Useful for \"what is\n * in this warehouse?\" reports.\n */\n async findByLocation(locationId: string): Promise<StockLevel[]> {\n return this.list({ where: { locationId } });\n }\n\n /**\n * Available rows strictly below their configured reorder point.\n * Reads use the public collection pipeline to preserve tenant filtering.\n */\n async findBelowReorderPoint(locationId?: string): Promise<StockLevel[]> {\n const where: Record<string, unknown> = { state: 'available' };\n if (locationId !== undefined) where.locationId = locationId;\n const levels = await this.list({ where });\n return levels.filter(\n (level) =>\n level.reorderPoint !== null &&\n Number(level.qty) < Number(level.reorderPoint),\n );\n }\n\n /**\n * Sum `qty` across all level rows for the given SKU. Pass `state` to\n * narrow the sum to one logical state (e.g. only `available`);\n * omit it for grand total across all states.\n */\n async totalForSku(skuId: string, state?: StockState): Promise<number> {\n const where: Record<string, unknown> = { skuId };\n if (state) where.state = state;\n const levels = await this.list({ where });\n return levels.reduce((sum, row) => sum + Number(row.qty ?? 0), 0);\n }\n\n /**\n * Sum `qty` across all level rows at the given location, optionally\n * narrowed by state.\n */\n async totalForLocation(\n locationId: string,\n state?: StockState,\n ): Promise<number> {\n const where: Record<string, unknown> = { locationId };\n if (state) where.state = state;\n const levels = await this.list({ where });\n return levels.reduce((sum, row) => sum + Number(row.qty ?? 0), 0);\n }\n}\n","/**\n * StockMovement — append-only audit row written for every stock mutation.\n *\n * Every call into {@link StockService} produces exactly one StockMovement\n * row (or two for `transfer`, one per leg). These rows are the ledger of\n * record: balances on {@link StockLevel} are derived state that could\n * always, in principle, be reconstructed by replaying movements in\n * order.\n *\n * **Movements are append-only.** The package treats updates as a bug and\n * relies on this for cycle-count reconciliation, audit, and source-system\n * attribution. Never call `save()` on a previously-persisted StockMovement\n * with mutated fields, and never let CRUD UIs expose update/delete on the\n * table.\n *\n * Cross-package attribution lives in `sourceType` + `sourceId` so a\n * downstream package can write `'Contract'` + the contract id when it\n * reserves stock, then later query \"which movements were caused by\n * contract X?\" without joining across the framework.\n *\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n type SmrtObjectOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { StockMovementReason, StockState } from '../types.js';\n\n/**\n * Options accepted by the {@link StockMovement} constructor.\n */\nexport interface StockMovementOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n skuId?: string;\n locationId?: string;\n lotId?: string | null;\n fromState?: StockState | null;\n toState?: StockState | null;\n qty?: number;\n reasonCode?: StockMovementReason;\n sourceType?: string;\n sourceId?: string;\n actorProfileId?: string | null;\n note?: string;\n occurredAt?: Date | string;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'inventory_stock_movements',\n // Append-only: the natural key is the surrogate id, so updates can\n // never collide on conflictColumns. Setting `id` explicitly here\n // documents the intent and prevents future contributors from\n // accidentally adding a \"domain natural key\" that would let upserts\n // overwrite history.\n conflictColumns: ['id'],\n // Movements are an audit log — never mutate or delete via generated\n // CRUD. Reads are fine for reporting and admin tooling. CLI follows\n // the same posture as api/mcp; `cli: true` would generate\n // create/update/delete subcommands that could rewrite or remove\n // audit rows from the shell, defeating the append-only invariant\n // documented in CLAUDE.md.\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n indexes: [{ name: 'inventory_stock_movements_lot_idx', columns: ['lotId'] }],\n})\nexport class StockMovement extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-inventory\";\n /** Tenant scope. `null` means the movement is global. */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Plain string reference to the {@link Sku} being moved. */\n @field({ required: true, description: 'The item that moved.' })\n skuId: string = '';\n\n /** Plain string reference to the {@link InventoryLocation} being mutated. */\n @field({ required: true, description: 'The place it moved at.' })\n locationId: string = '';\n\n /**\n * Plain string reference to the {@link Lot} that moved; null when the\n * movement is not tracked by lot. Nullable and additive: existing rows\n * and SKU-level callers are unaffected.\n */\n @field({\n nullable: true,\n description: 'The lot that moved, when tracked by lot.',\n })\n lotId: string | null = null;\n\n /**\n * Origin state for transitions (e.g. `available` → `allocated` for a\n * reservation). `null` indicates \"no origin\" — used when stock enters\n * the system fresh via {@link StockService.receive} or production.\n */\n @field({\n description: 'What it was before, for example available or damaged.',\n })\n fromState: StockState | null = null;\n\n /**\n * Destination state. `null` indicates \"no destination\" — used for\n * fulfilment, where stock leaves the building entirely.\n */\n @field({ description: 'What it became.' })\n toState: StockState | null = null;\n\n /** Quantity moved. Always positive; the direction is encoded by from/to. */\n @field({ type: 'decimal', description: 'How many moved.' })\n qty: number = 0.0;\n\n /**\n * Why the movement happened (see {@link StockMovementReason}). Drawn\n * from the canonical list when emitted by {@link StockService}; free-form\n * strings are allowed for vertical-specific reasons.\n */\n @field({\n required: true,\n description: 'Why it moved, for example adjustment, sale or return.',\n })\n reasonCode: StockMovementReason = 'adjustment';\n\n /**\n * Cross-package attribution tag — e.g. `'Contract'`, `'Fulfillment'`,\n * `'ProductionOrder'`, `'CycleCount'`. The package writing the\n * movement decides what tag makes sense; readers can group by\n * `(sourceType, sourceId)` to reconstruct \"what caused this\".\n */\n sourceType: string = '';\n\n /**\n * Cross-package id of the row that caused this movement. Plain string;\n * the framework never dereferences it.\n */\n sourceId: string = '';\n\n /** Profile responsible for this movement; null for unattributed automation. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n actorProfileId: string | null = null;\n\n /** Optional free-form note shown in audit UIs. */\n @field({ description: 'Anything worth remembering about this movement.' })\n note: string = '';\n\n /**\n * When the movement happened. Set to `now` at write time; explicit\n * values are allowed when back-dating an import.\n */\n @field({ description: 'When it happened.' })\n occurredAt: Date = new Date();\n\n constructor(options: StockMovementOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.skuId !== undefined) this.skuId = options.skuId;\n if (options.locationId !== undefined) this.locationId = options.locationId;\n if (options.lotId !== undefined) this.lotId = options.lotId;\n if (options.fromState !== undefined) this.fromState = options.fromState;\n if (options.toState !== undefined) this.toState = options.toState;\n if (options.qty !== undefined) this.qty = options.qty;\n if (options.reasonCode !== undefined) this.reasonCode = options.reasonCode;\n if (options.sourceType !== undefined) this.sourceType = options.sourceType;\n if (options.sourceId !== undefined) this.sourceId = options.sourceId;\n if (options.actorProfileId !== undefined)\n this.actorProfileId = options.actorProfileId;\n if (options.note !== undefined) this.note = options.note;\n if (options.occurredAt !== undefined) {\n this.occurredAt =\n options.occurredAt instanceof Date\n ? options.occurredAt\n : new Date(options.occurredAt);\n }\n }\n}\n","/**\n * StockMovementCollection — read-only access to the append-only audit log.\n *\n * Treat this collection as a ledger. The `StockService` is the only\n * sanctioned writer; query helpers here exist so reporting code, audit\n * UIs, and cycle-count tooling can reconstruct history.\n *\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { StockMovement } from '../models/StockMovement.js';\nimport type { StockMovementReason } from '../types.js';\n\nexport class StockMovementCollection extends SmrtCollection<StockMovement> {\n static readonly _itemClass = StockMovement;\n\n /**\n * Return every movement for the given SKU, newest first. Useful for a\n * per-SKU audit trail.\n */\n async findBySku(skuId: string): Promise<StockMovement[]> {\n return this.list({ where: { skuId }, orderBy: 'occurredAt DESC' });\n }\n\n /**\n * Return every movement at the given location, newest first. Useful\n * for a per-warehouse audit trail.\n */\n async findByLocation(locationId: string): Promise<StockMovement[]> {\n return this.list({\n where: { locationId },\n orderBy: 'occurredAt DESC',\n });\n }\n\n /**\n * Return every movement attributed to the given upstream source — for\n * example `findBySource('Contract', contract.id)` returns every\n * movement caused by the reservation/fulfilment/release of that\n * contract. Newest first.\n */\n async findBySource(\n sourceType: string,\n sourceId: string,\n ): Promise<StockMovement[]> {\n return this.list({\n where: { sourceType, sourceId },\n orderBy: 'occurredAt DESC',\n });\n }\n\n /**\n * Return every movement with the given reason code (`'receipt'`,\n * `'reservation'`, `'adjustment'`, …). Newest first.\n */\n async findByReason(\n reasonCode: StockMovementReason,\n ): Promise<StockMovement[]> {\n return this.list({\n where: { reasonCode },\n orderBy: 'occurredAt DESC',\n });\n }\n}\n","/**\n * Declared recipes for smrt-inventory (#3590, #3604): user-facing units of\n * functionality an app or agent can pick instead of the whole package.\n * The scanner reads these statics into the `recipes` array of `manifest.json`\n * and `smrt-knowledge.json`; nothing here runs at that point.\n *\n * @packageDocumentation\n */\n\nimport { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { InventoryLocation } from './models/InventoryLocation.js';\nimport { StockLevel } from './models/StockLevel.js';\nimport { StockMovement } from './models/StockMovement.js';\n\n/** Inventory: Keep count of how many of each product you have. */\nexport class StockRecipe extends SmrtRecipe {\n static id = 'inventory.stock';\n static help = './stock.recipe.md';\n static label = 'Inventory';\n static summary = 'Keep count of how many of each product you have.';\n static synonyms = ['stock', 'quantity', 'on hand'];\n static section = {\n id: 'catalog',\n label: 'Catalog',\n icon: 'package',\n description: 'Products, ingredients and the stock you hold.',\n };\n static models = [StockLevel, InventoryLocation, StockMovement];\n static nav = [\n {\n label: 'Stock levels',\n model: StockLevel,\n icon: 'archive',\n description: 'How much of each item you have on hand right now.',\n noun: 'stock entry',\n },\n {\n label: 'Locations',\n model: InventoryLocation,\n icon: 'home',\n description: 'The places you keep stock, like shelves, rooms or vans.',\n },\n {\n label: 'Stock movements',\n model: StockMovement,\n icon: 'truck',\n description: 'Every time stock came in, went out or moved.',\n },\n ];\n static requiresAny = [['products.simple', 'products.clothing']];\n static options = {\n StockLevel: {\n fields: {\n reorderPoint: { visibility: 'hidden' },\n reorderQuantity: { visibility: 'hidden' },\n },\n },\n InventoryLocation: {\n fields: {\n placeId: { visibility: 'hidden' },\n active: { visibility: 'hidden' },\n },\n },\n StockMovement: {\n fields: {\n sourceType: { visibility: 'hidden' },\n sourceId: { visibility: 'hidden' },\n actorProfileId: { visibility: 'hidden' },\n },\n },\n } as const;\n}\n","/**\n * Errors thrown by {@link LotService} and by {@link StockService} when a\n * mutation names a lot. Kept in their own module so both services can\n * import them without a cycle.\n *\n * @packageDocumentation\n */\n\n/** The lot id does not exist (or belongs to another tenant). */\nexport class LotNotFoundError extends Error {\n override name = 'LotNotFoundError';\n\n constructor(public readonly lotId: string) {\n super(`Lot not found: ${lotId}`);\n }\n}\n\n/** A stock mutation named a lot that belongs to a different SKU. */\nexport class LotMismatchError extends Error {\n override name = 'LotMismatchError';\n\n constructor(\n public readonly lotId: string,\n public readonly lotSkuId: string,\n public readonly skuId: string,\n ) {\n super(`Lot ${lotId} is of sku ${lotSkuId}, not ${skuId}`);\n }\n}\n\n/**\n * A unique lot or serial with this number already exists. Carries the\n * existing lot's id so the caller can link to it.\n */\nexport class DuplicateLotError extends Error {\n override name = 'DuplicateLotError';\n\n constructor(\n public readonly lotNumber: string,\n public readonly existingLotId: string | null,\n ) {\n super(`A lot with number \"${lotNumber}\" already exists`);\n }\n}\n\n/** An exclusive lot is already in use by a different consumer. */\nexport class LotInUseError extends Error {\n override name = 'LotInUseError';\n\n constructor(\n public readonly lotId: string,\n public readonly consumerType: string,\n public readonly consumerId: string,\n ) {\n super(`Lot ${lotId} is already in use by ${consumerType}:${consumerId}`);\n }\n}\n\n/** A correction was refused: missing or oversized reason, or nothing changes. */\nexport class LotCorrectionError extends Error {\n override name = 'LotCorrectionError';\n}\n","/**\n * StockService — the only sanctioned way to mutate stock.\n *\n * Every mutation goes through one of six methods (`receive`, `reserve`,\n * `release`, `fulfill`, `transfer`, `adjust`). Each one:\n *\n * 1. Updates the materialized {@link StockLevel} row(s) for the affected\n * `(skuId, locationId, state)` tuples via the collection's upsert path.\n * 2. Writes exactly one append-only {@link StockMovement} (or two for\n * `transfer`, one per leg) carrying the reason, source attribution,\n * quantity, and from/to state transition.\n *\n * **Atomicity**: each method runs every write inside a single database\n * transaction (`db.transaction(...)` on `@happyvertical/sql >= 0.74.0`).\n * Partial failure — e.g. the level write succeeds but the movement\n * write throws — rolls the entire mutation back, so the materialized\n * balance and the audit ledger never disagree. `transfer` writes both\n * legs (source out, destination in) plus both movement rows in one tx,\n * so a failure mid-`transfer` is also fully rolled back.\n *\n * If the underlying adapter does not expose `transaction()` (rare —\n * sqlite, postgres, and duckdb all do as of 0.74.0; the JSON adapter\n * does too), the service degrades to serial writes and emits a one-time\n * `console.warn`. Tests and consumers that observe that warning should\n * upgrade their adapter.\n *\n * **Lots**: pass `lotId` in the options of any mutation and the same deltas\n * are applied to {@link LotStockLevel} rows keyed by\n * `(lotId, locationId, state)`, with the same non-negative rule, and the\n * lot is stamped on every movement written. SKU-level balances behave\n * exactly as without a lot. Create lots with {@link LotService}; compose\n * both through a shared transaction (`stock.withTransaction`, then\n * `createLotService({ db: tx.db })`) to receive a lot and its stock\n * atomically.\n *\n * Callers should never reach into the level or movement collections\n * directly to mutate balances — doing so silently desyncs the audit\n * ledger and breaks cycle counts.\n *\n * Concurrency: each method is a read-modify-write on the underlying\n * StockLevel row. Awaited (serial) callers always see a consistent\n * balance. Unawaited `Promise.all([reserve, reserve, ...])` against the\n * same `(skuId, locationId)` can still over-allocate — the per-tx\n * locking guarantees atomicity of each individual call, not isolation\n * across concurrent transactions. Callers that need hard atomicity\n * across concurrent reservations should serialise upstream (e.g. via\n * the job runner from `@happyvertical/smrt-jobs`).\n *\n * @packageDocumentation\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport { type DatabaseConfig, resolveDatabase } from '@happyvertical/smrt-core';\nimport {\n InventoryLocationCollection,\n LotCollection,\n LotStockLevelCollection,\n StockLevelCollection,\n StockMovementCollection,\n} from '../collections/index.js';\nimport type { Lot } from '../models/Lot.js';\nimport type { StockLevel } from '../models/StockLevel.js';\nimport type { StockMovementReason, StockState } from '../types.js';\nimport { LotMismatchError, LotNotFoundError } from './lot-errors.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Thrown by {@link StockService.reserve} (and {@link StockService.fulfill},\n * {@link StockService.transfer}) when the caller asks to move more stock\n * than the source state currently holds. Carries enough context for a\n * caller to surface a meaningful UI message and decide whether to retry,\n * backorder, or cancel.\n */\nexport class InsufficientStockError extends Error {\n override name = 'InsufficientStockError';\n\n constructor(\n public readonly skuId: string,\n public readonly locationId: string,\n public readonly state: StockState,\n public readonly requested: number,\n public readonly available: number,\n /** Set when the shortfall is in a lot's balance rather than the SKU's. */\n public readonly lotId?: string,\n ) {\n super(\n `Insufficient stock: sku=${skuId} location=${locationId} state=${state} ` +\n `${lotId ? `lot=${lotId} ` : ''}requested=${requested} available=${available}`,\n );\n }\n}\n\n/**\n * Options shared by every {@link StockService} method that wants to leave\n * an audit attribution behind. Pairs neatly with the cross-package\n * pattern in {@link StockMovement.sourceType} / {@link StockMovement.sourceId}.\n */\nexport interface StockMutationOptions {\n /**\n * Track this mutation against a {@link Lot}. The lot must exist and, when\n * it names a SKU, that SKU must match (else {@link LotMismatchError}).\n */\n lotId?: string | null;\n /** Cross-package tag, e.g. `'Contract'`, `'Fulfillment'`, `'CycleCount'`. */\n sourceType?: string;\n /** Cross-package id of the row that caused this mutation. */\n sourceId?: string;\n /** Trusted actor attribution; null for unattended or legacy callers. */\n actorProfileId?: string | null;\n /** Free-form note shown in audit UIs. */\n note?: string;\n /**\n * Override the reason code stamped on the {@link StockMovement}. Each\n * method picks a sensible default; explicit overrides are useful when a\n * vertical wants to flag a more specific reason (e.g. `'return'`\n * instead of `'receipt'`).\n */\n reasonCode?: StockMovementReason;\n}\n\n/**\n * Options accepted by the {@link StockService} factory.\n */\nexport interface StockServiceOptions {\n /**\n * Database to read/write through. Accepts the same shapes that\n * `SmrtCollection.create({ db })` accepts — a `DatabaseInterface`, a\n * connection-string URL, or a `{ type, url }` config object. Reused by\n * the internal collections so the service, level reads, and movement\n * writes always hit the same connection / pool.\n */\n db: DatabaseConfig;\n}\n\ninterface TxCollections {\n levels: StockLevelCollection;\n movements: StockMovementCollection;\n lotLevels: LotStockLevelCollection;\n lots: LotCollection;\n}\n\ninterface AdjustLevelOptions {\n skuId: string;\n locationId: string;\n state: StockState;\n delta: number;\n enforceNonNegative?: boolean;\n}\n\ninterface WriteMovementOptions {\n skuId: string;\n lotId?: string | null;\n locationId: string;\n fromState: StockState | null;\n toState: StockState | null;\n qty: number;\n reasonCode: StockMovementReason;\n sourceType?: string;\n sourceId?: string;\n actorProfileId?: string | null;\n note?: string;\n}\n\n/**\n * Sanctioned stock-mutation surface.\n *\n * Construct via {@link createStockService} — the static factory wires up\n * the underlying collections and shares one database connection across\n * level reads and movement writes.\n *\n * @example\n * ```typescript\n * const service = await createStockService({ db });\n * await service.receive(sku.id, warehouse.id, 100, {\n * sourceType: 'PurchaseOrder',\n * sourceId: po.id,\n * });\n * await service.reserve(sku.id, warehouse.id, 10, {\n * sourceType: 'Contract',\n * sourceId: order.id,\n * });\n * await service.fulfill(sku.id, warehouse.id, 10, {\n * sourceType: 'Fulfillment',\n * sourceId: fulfillment.id,\n * });\n * ```\n */\nexport class StockService {\n private constructor(\n /**\n * The database config this service was bound to (URL string, config\n * object, or already-resolved `DatabaseInterface`). Exposed so\n * downstream services that compose StockService (e.g. BomService,\n * ProductionService in `@happyvertical/smrt-manufacturing`) can pass\n * the same value to their own collection factories without reaching\n * into private fields on the collections.\n */\n public readonly db: DatabaseConfig,\n public readonly levels: StockLevelCollection,\n public readonly movements: StockMovementCollection,\n public readonly locations: InventoryLocationCollection,\n /** Per-lot balances, mutated only by this service. */\n public readonly lotLevels: LotStockLevelCollection,\n /** Lookup of lots for validation; created through {@link LotService}. */\n public readonly lots: LotCollection,\n /**\n * Marks a service instance handed to a {@link withTransaction}\n * callback. Public mutation methods on a tx-bound instance skip\n * opening a nested transaction and just execute against the already-\n * bound collections; outer (non-tx) instances open a fresh\n * transaction per mutation. Internal flag — consumers never set it.\n */\n private readonly inTransaction: boolean = false,\n ) {}\n\n /** Internal factory — prefer {@link createStockService}. */\n static async create(options: StockServiceOptions): Promise<StockService> {\n // Resolve the caller's `DatabaseConfig` to a single\n // `DatabaseInterface` instance FIRST, then construct every internal\n // collection on that shared instance. Without this step, passing\n // `{ type: 'sqlite', url: ':memory:' }` would make\n // `SmrtCollection.create({ db: config })` materialize a *fresh*\n // in-memory database per collection — `levels`, `movements`, and\n // `locations` would each point at their own empty DB. The runtime\n // ledger then desyncs: `adjust()` writes a movement to\n // `movements.db` while balance reads go through `levels.db`, and\n // audit queries on `movements` miss the row that was just written.\n // Resolving once means every collection (and the public `db` field\n // exposed for downstream composition) share the same handle.\n const resolved = await resolveDatabase(options.db);\n // Schema probes share one connection; do not interleave their initialization.\n const levels = await StockLevelCollection.create({ db: resolved });\n const movements = await StockMovementCollection.create({ db: resolved });\n const locations = await InventoryLocationCollection.create({\n db: resolved,\n });\n const lotLevels = await LotStockLevelCollection.create({ db: resolved });\n const lots = await LotCollection.create({ db: resolved });\n return new StockService(\n resolved as unknown as DatabaseConfig,\n levels,\n movements,\n locations,\n lotLevels,\n lots,\n );\n }\n\n /**\n * Run `work` inside a single database transaction with a tx-bound\n * {@link StockService} instance. All mutation calls on `tx` commit\n * atomically when `work` resolves and roll back if it throws.\n *\n * Use this when you need atomicity ACROSS multiple stock-service\n * calls — e.g. consuming materials for every line of a production\n * order in `@happyvertical/smrt-manufacturing`'s `ProductionService`,\n * or a custom workflow that reserves + fulfills + writes a custom\n * audit comment in one indivisible step. Individual mutation methods\n * (`receive`, `reserve`, etc.) are already atomic on their own — you\n * only need `withTransaction` for cross-call composition.\n *\n * Nesting is safe: calling `tx.withTransaction(...)` inside an\n * already-tx-bound callback simply runs the inner `work` on the same\n * transaction without opening a savepoint.\n *\n * When the underlying adapter does not expose `transaction()`, falls\n * through to a serial run on the regular collections with a one-time\n * warning. All four built-in adapters in `@happyvertical/sql >= 0.74.0`\n * support it; only test stubs would hit this branch.\n */\n async withTransaction<T>(work: (tx: StockService) => Promise<T>): Promise<T> {\n if (this.inTransaction) return work(this);\n\n const underlying = (this.levels as unknown as { db?: unknown }).db as\n | { transaction?: (cb: (txDb: unknown) => Promise<T>) => Promise<T> }\n | undefined;\n\n if (typeof underlying?.transaction !== 'function') {\n warnNonTransactional();\n return work(this);\n }\n\n return underlying.transaction(async (txDb) => {\n // The transaction handle also shares a single connection for schema probes.\n const levels = await StockLevelCollection.create({\n db: txDb as DatabaseConfig,\n });\n const movements = await StockMovementCollection.create({\n db: txDb as DatabaseConfig,\n });\n const locations = await InventoryLocationCollection.create({\n db: txDb as DatabaseConfig,\n });\n const lotLevels = await LotStockLevelCollection.create({\n db: txDb as DatabaseConfig,\n });\n const lots = await LotCollection.create({ db: txDb as DatabaseConfig });\n // Expose the tx-scoped db (not `this.db`) as the tx instance's\n // public `db` field. Callers compose this through `tx.db` when\n // spinning up adjacent services that should also write in the same\n // transaction — e.g. `BomService.create({ db: tx.db })` or\n // `MyCollection.create({ db: tx.db })`. If we leaked the outer db\n // here, those companion writes would commit independently of the\n // stock mutations, defeating the documented \"everything-in-one-tx\"\n // guarantee. Internal mutation methods don't read `tx.db`; they\n // use the tx-scoped collections passed alongside.\n const tx = new StockService(\n txDb as DatabaseConfig,\n levels,\n movements,\n locations,\n lotLevels,\n lots,\n /* inTransaction */ true,\n );\n return work(tx);\n });\n }\n\n /**\n * Internal: run a single-method mutation in a transaction. If we're\n * already inside one (the instance was handed to a `withTransaction`\n * callback), reuse it; otherwise open a fresh one.\n */\n private async runAtomically<T>(\n work: (tx: TxCollections) => Promise<T>,\n ): Promise<T> {\n if (this.inTransaction) return work(this.txCollections());\n return this.withTransaction(async (tx) => work(tx.txCollections()));\n }\n\n private txCollections(): TxCollections {\n return {\n levels: this.levels,\n movements: this.movements,\n lotLevels: this.lotLevels,\n lots: this.lots,\n };\n }\n\n /**\n * Add `qty` to available stock at the given location. Used for\n * purchase-order receipts, customer returns going back into available\n * inventory, and the \"produce\" leg of a production order.\n */\n async receive(\n skuId: string,\n locationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'receive');\n await this.runAtomically(async (tx) => {\n const lotId = await requireLot(tx, skuId, options.lotId);\n await adjustLevel(tx.levels, {\n skuId,\n locationId,\n state: 'available',\n delta: qty,\n });\n await adjustLotLevel(tx, lotId, skuId, locationId, 'available', qty);\n await writeMovement(tx.movements, {\n skuId,\n lotId,\n locationId,\n fromState: null,\n toState: 'available',\n qty,\n reasonCode: options.reasonCode ?? 'receipt',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Move `qty` from `available` to `allocated` at the given location.\n * Throws {@link InsufficientStockError} if available stock would go\n * negative.\n */\n async reserve(\n skuId: string,\n locationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'reserve');\n await this.runAtomically(async (tx) => {\n await transitionState(tx, {\n skuId,\n lotId: options.lotId,\n locationId,\n fromState: 'available',\n toState: 'allocated',\n qty,\n reasonCode: options.reasonCode ?? 'reservation',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Move `qty` from `allocated` back to `available`. Used when a\n * reservation is cancelled and the previously-reserved stock should\n * go back into the available pool.\n */\n async release(\n skuId: string,\n locationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'release');\n await this.runAtomically(async (tx) => {\n await transitionState(tx, {\n skuId,\n lotId: options.lotId,\n locationId,\n fromState: 'allocated',\n toState: 'available',\n qty,\n reasonCode: options.reasonCode ?? 'release',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Remove `qty` from `allocated` at the given location. Stock leaves\n * the building entirely (shipped, picked up, consumed). Throws\n * {@link InsufficientStockError} if allocated stock would go negative.\n */\n async fulfill(\n skuId: string,\n locationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'fulfill');\n await this.runAtomically(async (tx) => {\n const lotId = await requireLot(tx, skuId, options.lotId);\n await assertAvailable(tx.levels, skuId, locationId, 'allocated', qty);\n await assertLotAvailable(tx, lotId, skuId, locationId, 'allocated', qty);\n await adjustLevel(tx.levels, {\n skuId,\n locationId,\n state: 'allocated',\n delta: -qty,\n // Already enforced via assertAvailable; skipping the second check\n // avoids a needless extra DB round-trip in the hot path.\n enforceNonNegative: false,\n });\n await adjustLotLevel(tx, lotId, skuId, locationId, 'allocated', -qty);\n await writeMovement(tx.movements, {\n skuId,\n lotId,\n locationId,\n fromState: 'allocated',\n toState: null,\n qty,\n reasonCode: options.reasonCode ?? 'fulfillment',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Move `qty` of `available` stock from `fromLocationId` to\n * `toLocationId`. Writes two movement rows — one for the `transfer_out`\n * leg, one for the `transfer_in` leg — so the audit log preserves the\n * lineage in both directions. Throws {@link InsufficientStockError} if\n * source available stock would go negative.\n *\n * Both legs (level writes + movement rows) run inside one transaction\n * — a failure mid-`transfer` rolls back the source debit so there's no\n * \"ghost stock disappearance\" (source decremented, destination never\n * credited).\n */\n async transfer(\n skuId: string,\n fromLocationId: string,\n toLocationId: string,\n qty: number,\n options: StockMutationOptions = {},\n ): Promise<void> {\n assertPositiveQty(qty, 'transfer');\n if (fromLocationId === toLocationId) {\n throw new Error(\n `transfer: fromLocationId and toLocationId must differ (got ${fromLocationId})`,\n );\n }\n await this.runAtomically(async (tx) => {\n const lotId = await requireLot(tx, skuId, options.lotId);\n await assertAvailable(tx.levels, skuId, fromLocationId, 'available', qty);\n await assertLotAvailable(\n tx,\n lotId,\n skuId,\n fromLocationId,\n 'available',\n qty,\n );\n\n // Source leg: decrement available at origin.\n await adjustLevel(tx.levels, {\n skuId,\n locationId: fromLocationId,\n state: 'available',\n delta: -qty,\n enforceNonNegative: false,\n });\n await adjustLotLevel(tx, lotId, skuId, fromLocationId, 'available', -qty);\n await writeMovement(tx.movements, {\n skuId,\n lotId,\n locationId: fromLocationId,\n fromState: 'available',\n toState: null,\n qty,\n reasonCode: options.reasonCode ?? 'transfer_out',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n\n // Destination leg: increment available at destination.\n await adjustLevel(tx.levels, {\n skuId,\n locationId: toLocationId,\n state: 'available',\n delta: qty,\n });\n await adjustLotLevel(tx, lotId, skuId, toLocationId, 'available', qty);\n await writeMovement(tx.movements, {\n skuId,\n lotId,\n locationId: toLocationId,\n fromState: null,\n toState: 'available',\n qty,\n reasonCode: options.reasonCode ?? 'transfer_in',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n\n /**\n * Configure replenishment for the available row at a SKU/location.\n * Null disables the threshold. Metadata changes never fabricate movements.\n * The optional quantity is replaced (omitting it clears the suggestion).\n */\n async setReorderPolicy(\n skuId: string,\n locationId: string,\n reorderPoint: number | null,\n reorderQuantity: number | null = null,\n ): Promise<StockLevel> {\n for (const [name, value] of Object.entries({\n reorderPoint,\n reorderQuantity,\n })) {\n if (value !== null && (!Number.isFinite(value) || value < 0)) {\n throw new Error(`${name} must be null or a non-negative finite number`);\n }\n }\n return this.withTransaction(async (tx) => {\n const level = await tx.levels.getLevel(skuId, locationId);\n if (!level) {\n return tx.levels.create({\n skuId,\n locationId,\n state: 'available',\n qty: 0,\n reorderPoint,\n reorderQuantity,\n });\n }\n level.reorderPoint = reorderPoint;\n level.reorderQuantity = reorderQuantity;\n await level.save();\n return level;\n });\n }\n\n /**\n * Apply a positive or negative `delta` to a level row. Used for cycle\n * counts and one-off corrections; `delta=+5` adds five units,\n * `delta=-2` removes two. By default the adjustment targets\n * `available` stock; pass an explicit `state` to adjust a different\n * bucket (e.g. `'damaged'` after a quality-control reclassification).\n *\n * Adjusting by `0` is rejected as a probable programming error — the\n * caller almost always meant a non-zero delta and a no-op write would\n * still cost an audit row.\n */\n async adjust(\n skuId: string,\n locationId: string,\n delta: number,\n options: StockMutationOptions & { state?: StockState } = {},\n ): Promise<void> {\n if (!Number.isFinite(delta) || delta === 0) {\n throw new Error(\n `adjust: delta must be a non-zero finite number (got ${delta})`,\n );\n }\n const state = options.state ?? 'available';\n await this.runAtomically(async (tx) => {\n const lotId = await requireLot(tx, skuId, options.lotId);\n if (delta < 0) {\n await assertAvailable(tx.levels, skuId, locationId, state, -delta);\n await assertLotAvailable(tx, lotId, skuId, locationId, state, -delta);\n }\n await adjustLevel(tx.levels, {\n skuId,\n locationId,\n state,\n delta,\n enforceNonNegative: false,\n });\n await adjustLotLevel(tx, lotId, skuId, locationId, state, delta);\n await writeMovement(tx.movements, {\n skuId,\n lotId,\n locationId,\n fromState: delta < 0 ? state : null,\n toState: delta > 0 ? state : null,\n qty: Math.abs(delta),\n reasonCode: options.reasonCode ?? 'adjustment',\n sourceType: options.sourceType,\n sourceId: options.sourceId,\n actorProfileId: options.actorProfileId,\n note: options.note,\n });\n });\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Tx-scoped helpers\n//\n// These are module-level functions rather than instance methods so each\n// call site can pass tx-scoped collections through cleanly. The previous\n// versions read `this.levels` / `this.movements` directly which bypassed\n// the transaction. Public methods now wrap everything in\n// `runAtomically` and call these helpers with the tx-scoped pair.\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Read the current level row, sanity-check the result, and throw\n * {@link InsufficientStockError} when the requested quantity is not\n * available.\n */\nasync function assertAvailable(\n levels: StockLevelCollection,\n skuId: string,\n locationId: string,\n state: StockState,\n requested: number,\n): Promise<void> {\n const level = await levels.getLevel(skuId, locationId, state);\n const available = level ? Number(level.qty ?? 0) : 0;\n if (available < requested) {\n throw new InsufficientStockError(\n skuId,\n locationId,\n state,\n requested,\n available,\n );\n }\n}\n\n/**\n * Resolve the `lotId` option: null when absent, otherwise the id of a lot\n * that exists and, if it names a SKU, belongs to `skuId`.\n */\nasync function requireLot(\n tx: TxCollections,\n skuId: string,\n lotId: string | null | undefined,\n): Promise<string | null> {\n if (!lotId) return null;\n const lot: Lot | null = await tx.lots.get(lotId);\n if (!lot) throw new LotNotFoundError(lotId);\n if (lot.skuId && lot.skuId !== skuId) {\n throw new LotMismatchError(lotId, lot.skuId, skuId);\n }\n return lotId;\n}\n\n/** Lot-level counterpart of {@link assertAvailable}. */\nasync function assertLotAvailable(\n tx: TxCollections,\n lotId: string | null,\n skuId: string,\n locationId: string,\n state: StockState,\n requested: number,\n): Promise<void> {\n if (!lotId) return;\n const level = await tx.lotLevels.getLevel(lotId, locationId, state);\n const available = level ? Number(level.qty ?? 0) : 0;\n if (available < requested) {\n throw new InsufficientStockError(\n skuId,\n locationId,\n state,\n requested,\n available,\n lotId,\n );\n }\n}\n\n/**\n * Lot-level counterpart of {@link adjustLevel}: read-modify-write of the\n * `(lotId, locationId, state)` row, refusing a negative result. A no-op\n * when the mutation is not tracked by lot.\n */\nasync function adjustLotLevel(\n tx: TxCollections,\n lotId: string | null,\n skuId: string,\n locationId: string,\n state: StockState,\n delta: number,\n): Promise<void> {\n if (!lotId) return;\n const existing = await tx.lotLevels.getLevel(lotId, locationId, state);\n const previous = existing ? Number(existing.qty ?? 0) : 0;\n const next = previous + delta;\n if (next < 0) {\n throw new InsufficientStockError(\n skuId,\n locationId,\n state,\n Math.abs(delta),\n previous,\n lotId,\n );\n }\n if (existing) {\n existing.qty = next;\n await existing.save();\n return;\n }\n // Insert-only for the same reason as the SKU-level row (#3204).\n await tx.lotLevels.create({\n lotId,\n skuId,\n locationId,\n state,\n qty: next,\n _insertOnly: true,\n });\n}\n\n/**\n * Atomically transition `qty` from one state to another at a single\n * location. Used by `reserve` and `release`.\n */\nasync function transitionState(\n tx: TxCollections,\n args: {\n skuId: string;\n lotId?: string | null;\n locationId: string;\n fromState: StockState;\n toState: StockState;\n qty: number;\n reasonCode: StockMovementReason;\n sourceType?: string;\n sourceId?: string;\n actorProfileId?: string | null;\n note?: string;\n },\n): Promise<void> {\n const lotId = await requireLot(tx, args.skuId, args.lotId);\n await assertAvailable(\n tx.levels,\n args.skuId,\n args.locationId,\n args.fromState,\n args.qty,\n );\n await assertLotAvailable(\n tx,\n lotId,\n args.skuId,\n args.locationId,\n args.fromState,\n args.qty,\n );\n await adjustLevel(tx.levels, {\n skuId: args.skuId,\n locationId: args.locationId,\n state: args.fromState,\n delta: -args.qty,\n enforceNonNegative: false,\n });\n await adjustLevel(tx.levels, {\n skuId: args.skuId,\n locationId: args.locationId,\n state: args.toState,\n delta: args.qty,\n });\n await adjustLotLevel(\n tx,\n lotId,\n args.skuId,\n args.locationId,\n args.fromState,\n -args.qty,\n );\n await adjustLotLevel(\n tx,\n lotId,\n args.skuId,\n args.locationId,\n args.toState,\n args.qty,\n );\n await writeMovement(tx.movements, {\n skuId: args.skuId,\n lotId,\n locationId: args.locationId,\n fromState: args.fromState,\n toState: args.toState,\n qty: args.qty,\n reasonCode: args.reasonCode,\n sourceType: args.sourceType,\n sourceId: args.sourceId,\n actorProfileId: args.actorProfileId,\n note: args.note,\n });\n}\n\n/**\n * Read-modify-write a level row by `delta`. Creates the row when it\n * doesn't exist yet. When `enforceNonNegative` is set, refuses to\n * write a negative `qty` and throws {@link InsufficientStockError}\n * with the original (non-decremented) balance.\n */\nasync function adjustLevel(\n levels: StockLevelCollection,\n options: AdjustLevelOptions,\n): Promise<StockLevel> {\n const enforce = options.enforceNonNegative ?? options.delta < 0;\n const existing = await levels.getLevel(\n options.skuId,\n options.locationId,\n options.state,\n );\n const previous = existing ? Number(existing.qty ?? 0) : 0;\n const next = previous + options.delta;\n\n if (enforce && next < 0) {\n throw new InsufficientStockError(\n options.skuId,\n options.locationId,\n options.state,\n Math.abs(options.delta),\n previous,\n );\n }\n\n if (existing) {\n existing.qty = next;\n await existing.save();\n return existing;\n }\n\n // SmrtCollection.create() saves the row before returning, so no further\n // save() is needed here. The first row is insert-only: as an upsert, a\n // concurrent first write that also read \"no row\" overwrote this qty with\n // its own delta on PostgreSQL. Now the loser hits the unique key and its\n // transaction rolls back, like a revision conflict on the update path\n // (#3204).\n const level = await levels.create({\n skuId: options.skuId,\n locationId: options.locationId,\n state: options.state,\n qty: next,\n _insertOnly: true,\n });\n return level;\n}\n\n/**\n * Append a movement to the audit log. Never updates an existing row —\n * the natural key is the surrogate id, so each call writes a fresh\n * append-only entry.\n */\nasync function writeMovement(\n movements: StockMovementCollection,\n options: WriteMovementOptions,\n): Promise<void> {\n // SmrtCollection.create() persists the row before returning. A\n // follow-up save() would emit a redundant upsert round-trip on every\n // single stock mutation (one or two per service call) — and the\n // movement table is append-only, so there's nothing to re-save.\n await movements.create({\n skuId: options.skuId,\n lotId: options.lotId ?? null,\n locationId: options.locationId,\n fromState: options.fromState,\n toState: options.toState,\n qty: options.qty,\n reasonCode: options.reasonCode,\n sourceType: options.sourceType ?? '',\n sourceId: options.sourceId ?? '',\n actorProfileId: options.actorProfileId ?? null,\n note: options.note ?? '',\n occurredAt: new Date(),\n });\n}\n\n/**\n * Reject zero / negative / non-finite quantities up front. Most stock\n * mutation methods accept positive quantities only; {@link StockService.adjust}\n * is the exception (it accepts signed deltas) and validates separately.\n */\nfunction assertPositiveQty(qty: number, op: string): void {\n if (!Number.isFinite(qty) || qty <= 0) {\n throw new Error(`${op}: qty must be a positive finite number (got ${qty})`);\n }\n}\n\nlet warnedNonTransactional = false;\n\n/**\n * Emit a one-time `console.warn` when the underlying SQL adapter does\n * not expose `transaction()`. All four `@happyvertical/sql >= 0.74.0`\n * adapters implement it — only test stubs or third-party adapters would\n * trip this branch.\n */\nfunction warnNonTransactional(): void {\n if (warnedNonTransactional) return;\n warnedNonTransactional = true;\n logger.warn(\n '[@happyvertical/smrt-inventory] StockService: underlying SQL adapter ' +\n 'does not expose `transaction()`. Stock mutations are degrading to ' +\n 'non-atomic serial writes — partial failures may leave the materialized ' +\n 'level and the audit ledger out of sync. Upgrade @happyvertical/sql to ' +\n '>= 0.74.0 or use one of its built-in adapters.',\n );\n}\n\n/**\n * Convenience factory. Returns a fully-initialized {@link StockService}\n * sharing the given database with its internal collections.\n */\nexport async function createStockService(\n options: StockServiceOptions,\n): Promise<StockService> {\n return StockService.create(options);\n}\n","/**\n * Opt-in DispatchBus subscribers that bridge upstream packages to the\n * {@link StockService}.\n *\n * **Off by default.** The package never auto-subscribes — consumer apps\n * call {@link installInventoryDispatchHandlers} from their `smrt.ts`\n * wiring once they have decided they want automatic stock motion when\n * contracts are created and fulfilments ship.\n *\n * The production-order leg (`production_order:posted` → consume\n * materials + produce SKUs) is deliberately *not* installed here; that\n * subscriber lives in `@happyvertical/smrt-manufacturing` (see issue\n * #1250) and depends on the BOM model that ships alongside it.\n *\n * @packageDocumentation\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport type {\n DatabaseConfig,\n DispatchBus,\n DispatchHandler,\n DispatchMetadata,\n} from '@happyvertical/smrt-core';\nimport type { StockMutationOptions } from './StockService.js';\nimport { createStockService, type StockService } from './StockService.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Shape of a single reserved line in a `contract:created` payload. The\n * producer (typically `@happyvertical/smrt-commerce`) packs one entry\n * per line that needs stock motion; everything else (taxes, fees,\n * non-physical items) should be filtered upstream.\n */\nexport interface ContractCreatedLine {\n skuId: string;\n locationId: string;\n qty: number;\n}\n\n/**\n * Shape of the `contract:created` payload this handler expects. Carries\n * the contract id (used for source attribution on the audit row) and\n * the list of line items to reserve.\n */\nexport interface ContractCreatedPayload {\n contractId: string;\n lines: ContractCreatedLine[];\n}\n\n/**\n * Shape of a single shipped line in a `fulfillment:shipped` payload.\n */\nexport interface FulfillmentShippedLine {\n skuId: string;\n locationId: string;\n qty: number;\n}\n\n/**\n * Shape of the `fulfillment:shipped` payload this handler expects.\n * Producers emit one per shipped fulfilment; the handler fulfils each\n * line against the level created by the matching `contract:created`\n * reservation.\n */\nexport interface FulfillmentShippedPayload {\n fulfillmentId: string;\n lines: FulfillmentShippedLine[];\n}\n\n/**\n * Options accepted by {@link installInventoryDispatchHandlers}.\n *\n * Provide either a pre-built {@link StockService} (when sharing one\n * across multiple subsystems) or a `db` for the helper to construct one\n * on first use.\n */\nexport type InstallInventoryDispatchHandlersOptions = {\n /**\n * Bus to subscribe on. Typically the app-wide `DispatchBus` created in\n * the application's `smrt.ts`.\n */\n dispatchBus: DispatchBus;\n /**\n * When `true` (default), install the `contract:created` handler.\n * Producers should publish a {@link ContractCreatedPayload}.\n */\n installContractReserved?: boolean;\n /**\n * When `true` (default), install the `fulfillment:shipped` handler.\n * Producers should publish a {@link FulfillmentShippedPayload}.\n */\n installFulfillmentShipped?: boolean;\n} & (\n | { stockService: StockService; db?: DatabaseConfig }\n | { db: DatabaseConfig; stockService?: undefined }\n);\n\n/**\n * Result handle returned by {@link installInventoryDispatchHandlers}.\n * Call `dispose()` to detach the subscribers (mainly useful in tests\n * and on graceful shutdown).\n */\nexport interface InstalledInventoryDispatchHandlers {\n /** Resolved StockService — useful for follow-up writes in the same scope. */\n stockService: StockService;\n /** Detach every installed subscriber. Idempotent. */\n dispose(): void;\n}\n\n/**\n * Subscribe a {@link StockService}-driven handler to the relevant signals\n * on the given {@link DispatchBus}. Returns a disposer for tests and\n * shutdown hooks.\n *\n * @example\n * ```typescript\n * import { createDispatchBus } from '@happyvertical/smrt-core';\n * import { installInventoryDispatchHandlers } from '@happyvertical/smrt-inventory';\n *\n * const bus = await createDispatchBus({ db });\n * const handlers = await installInventoryDispatchHandlers({\n * dispatchBus: bus,\n * db,\n * });\n * ```\n */\nexport async function installInventoryDispatchHandlers(\n options: InstallInventoryDispatchHandlersOptions,\n): Promise<InstalledInventoryDispatchHandlers> {\n const {\n dispatchBus,\n installContractReserved = true,\n installFulfillmentShipped = true,\n } = options;\n\n const stockService =\n options.stockService ?? (await buildStockService(options));\n\n const installed: Array<{ pattern: string; handler: DispatchHandler }> = [];\n\n if (installContractReserved) {\n const handler: DispatchHandler = async (payload, metadata) => {\n await handleContractCreated(\n stockService,\n payload as ContractCreatedPayload,\n metadata,\n );\n };\n dispatchBus.on('contract:created', handler);\n installed.push({ pattern: 'contract:created', handler });\n }\n\n if (installFulfillmentShipped) {\n const handler: DispatchHandler = async (payload, metadata) => {\n await handleFulfillmentShipped(\n stockService,\n payload as FulfillmentShippedPayload,\n metadata,\n );\n };\n dispatchBus.on('fulfillment:shipped', handler);\n installed.push({ pattern: 'fulfillment:shipped', handler });\n }\n\n return {\n stockService,\n dispose() {\n for (const entry of installed) {\n dispatchBus.off(entry.pattern, entry.handler);\n }\n installed.length = 0;\n },\n };\n}\n\nasync function handleContractCreated(\n stockService: StockService,\n payload: ContractCreatedPayload | null | undefined,\n metadata: DispatchMetadata,\n): Promise<void> {\n // Silent return on any of these would hide upstream contract drift —\n // producers emitting the wrong shape never get feedback. Source id\n // (`contractId`) is required: without it the resulting StockMovements\n // carry empty `sourceId`, breaking the audit trail back to the\n // originating contract. Each branch reports its specific reason so\n // the emitter can be diagnosed quickly.\n const reason = malformedContractPayloadReason(payload);\n if (reason || !payload) {\n warnMalformedPayload(\n 'contract:created',\n payload,\n metadata,\n reason ?? 'payload is null/undefined',\n );\n return;\n }\n // Validate every line BEFORE opening a transaction. A silent skip on\n // a null/undefined / shape-broken entry would look like a successful\n // commit while only reserving part of the contract — defeating the\n // \"atomic across lines\" guarantee just below. Fail the whole event\n // instead so producers get feedback and downstream observers see no\n // partial state.\n if (!areLinesWellFormed(payload.lines)) {\n warnMalformedPayload(\n 'contract:created',\n payload,\n metadata,\n 'one or more entries in `lines` are null/undefined or missing required fields (skuId: string, locationId: string, qty: finite number)',\n );\n return;\n }\n const baseOptions: StockMutationOptions = {\n sourceType: 'Contract',\n sourceId: payload.contractId,\n note: metadata.source ? `auto-reserve via ${metadata.source}` : undefined,\n };\n // Atomic across lines: a shortfall on line N rolls back lines 1..N-1.\n // Without this wrapper, an `InsufficientStockError` mid-loop would leave\n // a partially-reserved contract, and `DispatchBus` would only log the\n // async handler error — no compensating release would ever fire.\n await stockService.withTransaction(async (tx) => {\n for (const line of payload.lines) {\n await tx.reserve(line.skuId, line.locationId, line.qty, baseOptions);\n }\n });\n}\n\nasync function handleFulfillmentShipped(\n stockService: StockService,\n payload: FulfillmentShippedPayload | null | undefined,\n metadata: DispatchMetadata,\n): Promise<void> {\n // Same rationale as `handleContractCreated`: reject when the\n // source id (`fulfillmentId`) is missing rather than emit\n // StockMovements with no audit attribution; surface the specific\n // failure so producers can diagnose quickly.\n const reason = malformedFulfillmentPayloadReason(payload);\n if (reason || !payload) {\n warnMalformedPayload(\n 'fulfillment:shipped',\n payload,\n metadata,\n reason ?? 'payload is null/undefined',\n );\n return;\n }\n // Validate lines up front for the same reason as\n // `handleContractCreated`: a silent skip would partially fulfill the\n // shipment while looking successful.\n if (!areLinesWellFormed(payload.lines)) {\n warnMalformedPayload(\n 'fulfillment:shipped',\n payload,\n metadata,\n 'one or more entries in `lines` are null/undefined or missing required fields (skuId: string, locationId: string, qty: finite number)',\n );\n return;\n }\n const baseOptions: StockMutationOptions = {\n sourceType: 'Fulfillment',\n sourceId: payload.fulfillmentId,\n note: metadata.source ? `auto-fulfill via ${metadata.source}` : undefined,\n };\n // Atomic across lines: a shortfall on line N rolls back lines 1..N-1.\n // Same rationale as `handleContractCreated` above — without the tx\n // wrapper, a failing fulfilment leg would leave the audit ledger\n // inconsistent and no compensating reservation-restore would ever fire.\n await stockService.withTransaction(async (tx) => {\n for (const line of payload.lines) {\n await tx.fulfill(line.skuId, line.locationId, line.qty, baseOptions);\n }\n });\n}\n\n/**\n * Determine whether a `contract:created` payload is structurally\n * unusable and, if so, return a single human-readable reason naming\n * the specific field that failed. Returns `null` when the top-level\n * shape is acceptable. Line-level validation is a separate step.\n */\nfunction malformedContractPayloadReason(\n payload: ContractCreatedPayload | null | undefined,\n): string | null {\n if (!payload || typeof payload !== 'object') {\n return 'payload is null/undefined or not an object';\n }\n if (!payload.contractId || typeof payload.contractId !== 'string') {\n return 'missing or non-string `contractId` (required for audit-trail source attribution)';\n }\n if (!Array.isArray(payload.lines)) {\n return 'missing or non-array `lines`';\n }\n return null;\n}\n\n/**\n * Same shape as {@link malformedContractPayloadReason} but for\n * `fulfillment:shipped` events. The required source id field is\n * `fulfillmentId` here.\n */\nfunction malformedFulfillmentPayloadReason(\n payload: FulfillmentShippedPayload | null | undefined,\n): string | null {\n if (!payload || typeof payload !== 'object') {\n return 'payload is null/undefined or not an object';\n }\n if (!payload.fulfillmentId || typeof payload.fulfillmentId !== 'string') {\n return 'missing or non-string `fulfillmentId` (required for audit-trail source attribution)';\n }\n if (!Array.isArray(payload.lines)) {\n return 'missing or non-array `lines`';\n }\n return null;\n}\n\n/**\n * Validate that every entry in a dispatch `lines` array is a usable\n * line shape. Returns `false` as soon as it sees a null/undefined entry\n * (e.g. a serialized sparse array hole), a missing/non-string\n * `skuId` / `locationId`, or a non-finite `qty`. Used by both contract\n * and fulfilment handlers to fail-fast before opening a transaction —\n * a silent `continue` over a bad entry would partially mutate state\n * while making the malformed event look successful.\n */\nfunction areLinesWellFormed(\n lines: ReadonlyArray<\n ContractCreatedLine | FulfillmentShippedLine | null | undefined\n >,\n): boolean {\n for (const line of lines) {\n if (!line) return false;\n if (typeof line.skuId !== 'string' || !line.skuId) return false;\n if (typeof line.locationId !== 'string' || !line.locationId) return false;\n if (typeof line.qty !== 'number' || !Number.isFinite(line.qty))\n return false;\n }\n return true;\n}\n\n/**\n * Surface dispatch payloads that don't match the documented shape. The\n * subscribers used to silently return on a missing `lines` array, which\n * hid producer drift — emitters using stale shapes never got feedback\n * and the resulting \"stock didn't move\" bugs were a long way from the\n * dispatch layer. The warning carries the source attribution AND the\n * specific reason the payload was rejected so producers can fix the\n * emitter quickly. Each call site supplies its own `reason` string;\n * the generic shell wraps it with the signal name and payload-key\n * summary for forensic logging.\n */\nfunction warnMalformedPayload(\n signal: string,\n payload: unknown,\n metadata: DispatchMetadata,\n reason: string,\n): void {\n logger.warn(\n `[@happyvertical/smrt-inventory] dispatch handler ignored a ${signal} ` +\n `event with a malformed payload (${reason}). ` +\n `Source: ${metadata.source ?? '<unknown>'}; payload keys: ` +\n `${payload && typeof payload === 'object' ? Object.keys(payload).join(',') : typeof payload}`,\n );\n}\n\n/**\n * Build a `StockService` when no pre-built one was supplied. The option\n * union guarantees `db` is present in that branch, but TypeScript can't\n * narrow from a `??` value check, so this helper validates at runtime\n * with a clear error message.\n */\nasync function buildStockService(\n options: InstallInventoryDispatchHandlersOptions,\n): Promise<StockService> {\n if (!options.db) {\n throw new Error(\n 'installInventoryDispatchHandlers: either `stockService` or `db` is required',\n );\n }\n return createStockService({ db: options.db });\n}\n","/**\n * LotService — the only sanctioned way to create and change lots.\n *\n * A lot is an identity for traceable stock: a batch code, a supplier lot, a\n * serial number. This service records lots as they arrive, links them to\n * what consumed them, keeps documents (certificates, reports) attached, and\n * answers \"where did this come from, and where did it go\". Every\n * after-the-fact change is a {@link LotCorrection} with a mandatory reason,\n * so a wrong number or a wrong link is fixed on the record, not erased.\n *\n * **Stock is separate.** Receiving a lot creates the identity only; it moves\n * no quantity. Compose the two in one transaction so the lot and its stock\n * land together or not at all:\n *\n * ```typescript\n * await stock.withTransaction(async (tx) => {\n * const lots = await createLotService({ db: tx.db });\n * const lot = await lots.receiveLot({ lotNumber: 'B-1042', skuId });\n * await tx.receive(skuId, locationId, 40, { lotId: lot.id });\n * });\n * ```\n *\n * **Authorization is the caller's.** Nothing here checks who may receive,\n * correct or unlink; pass `actorProfileId` so the trail says who did.\n *\n * **Concurrency.** Changes that matter to a lot (usage, unlink, number,\n * attribute and status corrections) `save()` the lot row, so two concurrent\n * changes to one lot conflict on its revision and the loser's transaction\n * rolls back; retry it.\n *\n * @packageDocumentation\n */\n\nimport {\n type DatabaseConfig,\n isUniqueViolationError,\n resolveDatabase,\n} from '@happyvertical/smrt-core';\nimport { getCurrentTenant } from '@happyvertical/smrt-tenancy';\nimport { NestedTransactionError } from '@happyvertical/sql/query';\nimport {\n LotCollection,\n LotCorrectionCollection,\n LotDocumentCollection,\n LotUsageCollection,\n lotSearchKey,\n StockMovementCollection,\n} from '../collections/index.js';\nimport type { Lot } from '../models/Lot.js';\nimport type { LotCorrection } from '../models/LotCorrection.js';\nimport type { LotDocument } from '../models/LotDocument.js';\nimport type { LotUsage } from '../models/LotUsage.js';\nimport type { StockMovement } from '../models/StockMovement.js';\nimport type { LotCorrectionKind, LotKind } from '../types.js';\nimport {\n DuplicateLotError,\n LotCorrectionError,\n LotInUseError,\n LotNotFoundError,\n} from './lot-errors.js';\n\nconst MAX_LOT_NUMBER = 128;\nconst MAX_IDENTITY_KEY = 160;\nconst MAX_REASON = 1000;\nconst DEFAULT_TRACE_DEPTH = 10;\n\n/** Options accepted by the {@link LotService} factory. */\nexport interface LotServiceOptions {\n /** Same shapes as {@link StockServiceOptions.db}; pass `tx.db` to join a transaction. */\n db: DatabaseConfig;\n}\n\n/** Input to {@link LotService.receiveLot}. */\nexport interface ReceiveLotInput {\n /** Batch code, supplier lot or serial number as the caller has it. */\n lotNumber: string;\n /** Catalog Sku the lot is of; omit for uncatalogued material. */\n skuId?: string | null;\n /** `lot` (default) or `serial`. A serial is always unique with quantity 1. */\n kind?: LotKind;\n /**\n * Make the number unique per SKU: a second receipt of the same number\n * throws {@link DuplicateLotError}. Default false for lots, always true\n * for serials. Without it one supplier lot may be received more than once.\n */\n unique?: boolean;\n /**\n * Makes the receipt retry-safe: repeating a call with the same key\n * returns the lot the first call made instead of creating another.\n * Ignored for unique lots and serials, whose number is the identity. A\n * repeated key returns the first lot as it was, even when the other fields\n * of the repeat differ.\n */\n idempotencyKey?: string;\n receivedQty?: number;\n unit?: string;\n sourceType?: string;\n sourceId?: string;\n attributes?: Record<string, unknown>;\n /** Default `active`. */\n status?: string;\n receivedAt?: Date;\n actorProfileId?: string | null;\n}\n\n/** Who made a correction, and why. `reason` is required. */\nexport interface LotChangeOptions {\n reason: string;\n actorProfileId?: string | null;\n}\n\n/** Input to {@link LotService.recordUsage}. */\nexport interface RecordUsageInput {\n /** What used the lot, e.g. `'ProductionOrder'`; `'Lot'` for an assembly. */\n consumerType: string;\n consumerId: string;\n /** Quantity used; omit when unspecified or the whole lot. */\n qty?: number | null;\n unit?: string;\n /**\n * Refuse when a different consumer already has an active usage\n * ({@link LotInUseError}). Default true for serials, false for lots.\n */\n exclusive?: boolean;\n /** Optional StockMovement that took the quantity out. */\n movementId?: string | null;\n actorProfileId?: string | null;\n}\n\n/** Input to {@link LotService.attachDocument}. */\nexport interface AttachDocumentInput {\n /** Id of the stored file (an Asset from `@happyvertical/smrt-assets`). */\n assetId: string;\n /** Default `certificate`. */\n role?: string;\n actorProfileId?: string | null;\n}\n\n/** Options for {@link LotService.traceForward} and {@link LotService.traceBack}. */\nexport interface TraceOptions {\n /** Include usages that were unlinked, and detached documents. Default false. */\n includeUnlinked?: boolean;\n /** How many levels of assembly to follow. Default 10. */\n depth?: number;\n}\n\n/**\n * One lot in a trace.\n *\n * In {@link LotService.traceForward}, `usages` are every use of `lot` and\n * `children` are the lots that consumed it (consumer type `Lot`). In\n * {@link LotService.traceBack}, `usages` are the edges from the queried\n * consumer to `lot` and `children` are the lots that went into `lot`.\n */\nexport interface TraceNode {\n lot: Lot;\n usages: LotUsage[];\n /** Stock movements that carried this lot, oldest first. */\n movements: StockMovement[];\n documents: LotDocument[];\n children: TraceNode[];\n}\n\nlet lastCorrectionMs = 0;\n\n/**\n * A timestamp that never repeats within this process, so corrections made\n * in the same millisecond still sort in the order they were written.\n */\nfunction nextCorrectionTime(): Date {\n lastCorrectionMs = Math.max(Date.now(), lastCorrectionMs + 1);\n return new Date(lastCorrectionMs);\n}\n\nfunction requireReason(reason: string | undefined): string {\n const text = (reason ?? '').trim();\n if (!text) throw new LotCorrectionError('A reason is required');\n if (text.length > MAX_REASON) {\n throw new LotCorrectionError(`Reason is over ${MAX_REASON} characters`);\n }\n return text;\n}\n\nfunction normalizeLotNumber(lotNumber: string | undefined): string {\n const text = (lotNumber ?? '').trim();\n if (!text) throw new Error('lotNumber is required');\n if (text.length > MAX_LOT_NUMBER) {\n throw new Error(`lotNumber is over ${MAX_LOT_NUMBER} characters`);\n }\n return text;\n}\n\n/** The database-enforced identity for a lot; see {@link Lot.identityKey}. */\nfunction numberIdentity(\n kind: LotKind,\n skuId: string | null,\n searchKey: string,\n): Promise<string> {\n return boundedIdentity(`u:${kind}:${skuId ?? ''}:${searchKey}`, 'uh:');\n}\n\n/**\n * Keep an identity within the column: one that is too long is replaced by a\n * SHA-256 digest. Web Crypto, not `node:crypto`, so the package root stays\n * importable in the browser.\n */\nasync function boundedIdentity(\n key: string,\n hashPrefix: string,\n): Promise<string> {\n if (key.length <= MAX_IDENTITY_KEY) return key;\n const digest = await globalThis.crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(key),\n );\n const hex = Array.from(new Uint8Array(digest), (byte) =>\n byte.toString(16).padStart(2, '0'),\n ).join('');\n return `${hashPrefix}${hex}`;\n}\n\nfunction jsonOrEmpty(value: unknown): string {\n return value === undefined ? '' : JSON.stringify(value);\n}\n\nexport class LotService {\n private constructor(\n /** The database this service is bound to; `tx.db` inside {@link withTransaction}. */\n public readonly db: DatabaseConfig,\n public readonly lots: LotCollection,\n public readonly usages: LotUsageCollection,\n public readonly corrections: LotCorrectionCollection,\n public readonly documents: LotDocumentCollection,\n public readonly movements: StockMovementCollection,\n private readonly inTransaction: boolean = false,\n ) {}\n\n /** Internal factory — prefer {@link createLotService}. */\n static async create(options: LotServiceOptions): Promise<LotService> {\n // Resolve once so every collection shares one connection (see StockService.create).\n const resolved = await resolveDatabase(options.db);\n return new LotService(\n resolved as unknown as DatabaseConfig,\n await LotCollection.create({ db: resolved }),\n await LotUsageCollection.create({ db: resolved }),\n await LotCorrectionCollection.create({ db: resolved }),\n await LotDocumentCollection.create({ db: resolved }),\n await StockMovementCollection.create({ db: resolved }),\n );\n }\n\n /**\n * Run `work` in one database transaction with a tx-bound service. Nested\n * calls join the outer transaction. Same pattern as\n * {@link StockService.withTransaction}.\n *\n * A service built on a transaction handle (`createLotService({ db: tx.db })`)\n * opens a savepoint where the engine has them (PostgreSQL, SQLite). Where it\n * does not (DuckDB) the handle refuses with `NestedTransactionError` before\n * running anything, and `work` runs on the current handle instead, still\n * inside the caller's transaction.\n */\n async withTransaction<T>(work: (tx: LotService) => Promise<T>): Promise<T> {\n if (this.inTransaction) return work(this);\n return this.scoped(work);\n }\n\n /**\n * Open a transaction (or savepoint) on this service's handle and run `work`\n * in it, even when already tx-bound. Falls back to the current handle when\n * the engine cannot nest.\n */\n private async scoped<T>(work: (tx: LotService) => Promise<T>): Promise<T> {\n const underlying = (this.lots as unknown as { db?: unknown }).db as\n | { transaction?: (cb: (txDb: unknown) => Promise<T>) => Promise<T> }\n | undefined;\n if (typeof underlying?.transaction !== 'function') return work(this);\n\n let entered = false;\n try {\n return await underlying.transaction(async (txDb) => {\n entered = true;\n const db = txDb as DatabaseConfig;\n return work(\n new LotService(\n db,\n await LotCollection.create({ db }),\n await LotUsageCollection.create({ db }),\n await LotCorrectionCollection.create({ db }),\n await LotDocumentCollection.create({ db }),\n await StockMovementCollection.create({ db }),\n /* inTransaction */ true,\n ),\n );\n });\n } catch (error) {\n // Refused before the callback ran, so nothing is replayed.\n if (!entered && error instanceof NestedTransactionError) {\n return work(this);\n }\n throw error;\n }\n }\n\n // ───────────────────────────────────────────────────────────────────────\n // Receiving\n // ───────────────────────────────────────────────────────────────────────\n\n /**\n * Record a lot or serial. Creates the identity only; it moves no stock\n * (see the module notes for composing with {@link StockService}).\n *\n * - Unique lots and all serials are keyed by SKU and number: receiving the\n * same number again throws {@link DuplicateLotError}.\n * - Otherwise a repeated `idempotencyKey` returns the lot already made.\n * - With neither, every call makes a new lot, even for a number already\n * seen: one supplier lot can arrive on two receipts.\n */\n async receiveLot(input: ReceiveLotInput): Promise<Lot> {\n const kind: LotKind = input.kind ?? 'lot';\n const lotNumber = normalizeLotNumber(input.lotNumber);\n const skuId = input.skuId ?? null;\n const unique = kind === 'serial' ? true : (input.unique ?? false);\n const searchKey = lotSearchKey(lotNumber);\n\n let identityKey: string;\n if (unique) identityKey = await numberIdentity(kind, skuId, searchKey);\n else if (input.idempotencyKey) {\n identityKey = await boundedIdentity(`k:${input.idempotencyKey}`, 'kh:');\n } else identityKey = `r:${globalThis.crypto.randomUUID()}`;\n\n // Look first: a unique violation aborts a Postgres transaction we may be\n // joined to, so the race below is the exception, not the normal path.\n const existing = await this.findByIdentity(identityKey);\n if (existing) return this.resolveExisting(existing, unique, lotNumber);\n\n try {\n // Own savepoint: joined to a Postgres transaction, a unique violation\n // aborts the transaction unless it is contained, and the re-query below\n // must still be able to run.\n return await this.scoped((scope) =>\n scope.lots.create({\n skuId,\n kind,\n lotNumber,\n searchKey,\n identityKey,\n uniqueNumber: unique,\n receivedQty: kind === 'serial' ? 1 : (input.receivedQty ?? 0),\n unit: input.unit ?? '',\n sourceType: input.sourceType ?? '',\n sourceId: input.sourceId ?? '',\n attributes: JSON.stringify(input.attributes ?? {}),\n status: input.status ?? 'active',\n receivedAt: input.receivedAt ?? new Date(),\n receivedByProfileId: input.actorProfileId ?? null,\n _insertOnly: true,\n }),\n );\n } catch (error) {\n if (!isUniqueViolationError(error)) throw error;\n const winner = await this.findByIdentity(identityKey);\n if (winner) return this.resolveExisting(winner, unique, lotNumber);\n throw error;\n }\n }\n\n private resolveExisting(existing: Lot, unique: boolean, lotNumber: string) {\n if (unique) throw new DuplicateLotError(lotNumber, existing.id ?? null);\n return existing;\n }\n\n private async findByIdentity(identityKey: string): Promise<Lot | null> {\n // Identity is unique per tenant. A caller outside any tenant context sees\n // every tenant's rows, so match the caller's tenant explicitly.\n const tenantId = getCurrentTenant()?.tenantId ?? null;\n const rows = await this.lots.list({ where: { identityKey } });\n return rows.find((row) => (row.tenantId ?? null) === tenantId) ?? null;\n }\n\n // ───────────────────────────────────────────────────────────────────────\n // Corrections\n // ───────────────────────────────────────────────────────────────────────\n\n /**\n * Fix a mistyped lot number. Recomputes the lookup key and, for unique\n * lots and serials, the identity (a clash throws\n * {@link DuplicateLotError}). Refuses a change to the same number.\n */\n async correctLotNumber(\n lotId: string,\n lotNumber: string,\n options: LotChangeOptions,\n ): Promise<{ lot: Lot; correction: LotCorrection }> {\n const reason = requireReason(options.reason);\n const next = normalizeLotNumber(lotNumber);\n return this.atomically(async (tx) => {\n const lot = await tx.requireLot(lotId);\n if (next === lot.lotNumber) {\n throw new LotCorrectionError('The lot number is unchanged');\n }\n const previous = lot.lotNumber;\n lot.lotNumber = next;\n lot.searchKey = lotSearchKey(next);\n if (lot.uniqueNumber) {\n lot.identityKey = await numberIdentity(\n lot.kind,\n lot.skuId,\n lot.searchKey,\n );\n const clash = await tx.findByIdentity(lot.identityKey);\n if (clash && clash.id !== lot.id) {\n throw new DuplicateLotError(next, clash.id ?? null);\n }\n }\n try {\n await lot.save();\n } catch (error) {\n if (isUniqueViolationError(error)) {\n throw new DuplicateLotError(next, null);\n }\n throw error;\n }\n const correction = await tx.writeCorrection(lot, 'lot_number', reason, {\n oldValue: previous,\n newValue: next,\n actorProfileId: options.actorProfileId,\n });\n return { lot, correction };\n });\n }\n\n /**\n * Change attributes. Each key in `patch` is set to its value, or removed\n * when `null`. One correction is written per key that actually changes;\n * refuses when none does. Values are stored as JSON.\n */\n async correctAttributes(\n lotId: string,\n patch: Record<string, unknown | null>,\n options: LotChangeOptions,\n ): Promise<{ lot: Lot; corrections: LotCorrection[] }> {\n const reason = requireReason(options.reason);\n return this.atomically(async (tx) => {\n const lot = await tx.requireLot(lotId);\n const attributes = lot.getAttributes();\n const changes: Array<{ key: string; before: string; after: string }> = [];\n for (const [key, value] of Object.entries(patch)) {\n const before = jsonOrEmpty(attributes[key]);\n const after = value === null ? '' : jsonOrEmpty(value);\n if (before === after) continue;\n changes.push({ key, before, after });\n if (value === null) delete attributes[key];\n else attributes[key] = value;\n }\n if (changes.length === 0) {\n throw new LotCorrectionError('No attribute changes');\n }\n lot.setAttributes(attributes);\n await lot.save();\n const corrections: LotCorrection[] = [];\n for (const change of changes) {\n corrections.push(\n await tx.writeCorrection(lot, 'attribute', reason, {\n field: change.key,\n oldValue: change.before,\n newValue: change.after,\n actorProfileId: options.actorProfileId,\n }),\n );\n }\n return { lot, corrections };\n });\n }\n\n /** Change status (for example to `quarantined`). Refuses an unchanged status. */\n async setStatus(\n lotId: string,\n status: string,\n options: LotChangeOptions,\n ): Promise<{ lot: Lot; correction: LotCorrection }> {\n const reason = requireReason(options.reason);\n const next = status.trim();\n if (!next) throw new LotCorrectionError('A status is required');\n return this.atomically(async (tx) => {\n const lot = await tx.requireLot(lotId);\n if (lot.status === next) {\n throw new LotCorrectionError('The status is unchanged');\n }\n const previous = lot.status;\n lot.status = next;\n await lot.save();\n const correction = await tx.writeCorrection(lot, 'status', reason, {\n oldValue: previous,\n newValue: next,\n actorProfileId: options.actorProfileId,\n });\n return { lot, correction };\n });\n }\n\n // ───────────────────────────────────────────────────────────────────────\n // Usage\n // ───────────────────────────────────────────────────────────────────────\n\n /**\n * Record that a consumer used the lot. Repeating the call for the same\n * consumer returns the active usage already on record, unchanged: a\n * different `qty` or `movementId` on the repeat is ignored. For an exclusive\n * lot (serials by default) a second consumer throws\n * {@link LotInUseError}. The lot row is saved so two concurrent usages\n * conflict on its revision instead of both landing.\n */\n async recordUsage(lotId: string, input: RecordUsageInput): Promise<LotUsage> {\n const consumerType = (input.consumerType ?? '').trim();\n const consumerId = (input.consumerId ?? '').trim();\n if (!consumerType || !consumerId) {\n throw new Error('recordUsage: consumerType and consumerId are required');\n }\n if (consumerType === 'Lot' && consumerId === lotId) {\n throw new Error('recordUsage: a lot cannot be used by itself');\n }\n return this.atomically(async (tx) => {\n const lot = await tx.requireLot(lotId);\n const active = await tx.usages.findActiveForLot(lotId);\n const same = active.find(\n (usage) =>\n usage.consumerType === consumerType &&\n usage.consumerId === consumerId,\n );\n if (same) return same;\n const exclusive = input.exclusive ?? lot.kind === 'serial';\n const other = active[0];\n if (exclusive && other) {\n throw new LotInUseError(lotId, other.consumerType, other.consumerId);\n }\n const usage = await tx.usages.create({\n lotId,\n consumerType,\n consumerId,\n qty: input.qty ?? null,\n unit: input.unit ?? '',\n status: 'active',\n linkedAt: new Date(),\n linkedByProfileId: input.actorProfileId ?? null,\n movementId: input.movementId ?? null,\n });\n lot.lastUsedAt = new Date();\n await lot.save();\n return usage;\n });\n }\n\n /**\n * Remove a mistaken usage. The row stays, marked `unlinked`, and a\n * correction records who removed it and why. Refuses a usage that is\n * already unlinked.\n */\n async unlinkUsage(\n usageId: string,\n options: LotChangeOptions,\n ): Promise<{ usage: LotUsage; correction: LotCorrection }> {\n const reason = requireReason(options.reason);\n return this.atomically(async (tx) => {\n const usage = await tx.usages.get(usageId);\n if (!usage) throw new LotCorrectionError(`Usage not found: ${usageId}`);\n if (usage.status === 'unlinked') {\n throw new LotCorrectionError('The usage is already unlinked');\n }\n const lot = await tx.requireLot(usage.lotId);\n usage.status = 'unlinked';\n usage.unlinkedAt = new Date();\n usage.unlinkedByProfileId = options.actorProfileId ?? null;\n usage.unlinkReason = reason;\n await usage.save();\n lot.lastUsedAt = new Date();\n await lot.save();\n const correction = await tx.writeCorrection(lot, 'unlink', reason, {\n oldValue: `${usage.consumerType}:${usage.consumerId}`,\n newValue: '',\n usageId: usage.id ?? undefined,\n actorProfileId: options.actorProfileId,\n });\n return { usage, correction };\n });\n }\n\n // ───────────────────────────────────────────────────────────────────────\n // Documents\n // ───────────────────────────────────────────────────────────────────────\n\n /** Attach a stored file to the lot. Repeating the same asset and role returns the active link. */\n async attachDocument(\n lotId: string,\n input: AttachDocumentInput,\n ): Promise<LotDocument> {\n const assetId = (input.assetId ?? '').trim();\n if (!assetId) throw new Error('attachDocument: assetId is required');\n const role = input.role ?? 'certificate';\n return this.atomically(async (tx) => {\n const lot = await tx.requireLot(lotId);\n const current = await tx.documents.list({\n where: { lotId, assetId, role },\n });\n const active = current.find((doc) => !doc.detachedAt);\n if (active) return active;\n const document = await tx.documents.create({\n lotId,\n assetId,\n role,\n attachedAt: new Date(),\n attachedByProfileId: input.actorProfileId ?? null,\n });\n await lot.save();\n return document;\n });\n }\n\n /** Detach a document. The link stays on record with `detachedAt` set. */\n async detachDocument(\n documentId: string,\n options: LotChangeOptions,\n ): Promise<{ document: LotDocument; correction: LotCorrection }> {\n const reason = requireReason(options.reason);\n return this.atomically(async (tx) => {\n const document = await tx.documents.get(documentId);\n if (!document) {\n throw new LotCorrectionError(`Document not found: ${documentId}`);\n }\n if (document.detachedAt) {\n throw new LotCorrectionError('The document is already detached');\n }\n const lot = await tx.requireLot(document.lotId);\n document.detachedAt = new Date();\n document.detachedByProfileId = options.actorProfileId ?? null;\n await document.save();\n const correction = await tx.writeCorrection(\n lot,\n 'document_detach',\n reason,\n {\n oldValue: document.assetId,\n newValue: '',\n documentId: document.id ?? undefined,\n actorProfileId: options.actorProfileId,\n },\n );\n return { document, correction };\n });\n }\n\n // ───────────────────────────────────────────────────────────────────────\n // Reads\n // ───────────────────────────────────────────────────────────────────────\n\n /** Every correction to the lot, oldest first. */\n async history(lotId: string): Promise<LotCorrection[]> {\n return this.corrections.list({\n where: { lotId },\n orderBy: 'correctedAt ASC',\n });\n }\n\n /**\n * Where a lot went: its usages, movements and documents, plus (as\n * `children`) the lots that consumed it, followed up to `depth` levels.\n *\n * Cost: each distinct lot in the trace takes four queries (usages,\n * movements, documents, and the lot itself). A lot reached by two paths\n * (a diamond) is expanded once and the same node object appears under both\n * parents. Bound large graphs with `depth`.\n */\n async traceForward(\n lotId: string,\n options: TraceOptions = {},\n ): Promise<TraceNode> {\n const depth = options.depth ?? DEFAULT_TRACE_DEPTH;\n const lot = await this.requireLot(lotId);\n return this.forwardNode(lot, options, depth, new Set([lotId]), new Map());\n }\n\n private async forwardNode(\n lot: Lot,\n options: TraceOptions,\n depth: number,\n path: Set<string>,\n memo: Map<string, Promise<TraceNode>>,\n ): Promise<TraceNode> {\n const lotId = lot.id as string;\n const key = `${lotId}:${depth}`;\n const known = memo.get(key);\n if (known) return known;\n const node = this.expandForward(lot, options, depth, path, memo);\n memo.set(key, node);\n return node;\n }\n\n private async expandForward(\n lot: Lot,\n options: TraceOptions,\n depth: number,\n path: Set<string>,\n memo: Map<string, Promise<TraceNode>>,\n ): Promise<TraceNode> {\n const lotId = lot.id as string;\n const usages = await this.usages.list({\n where: options.includeUnlinked ? { lotId } : { lotId, status: 'active' },\n orderBy: 'linkedAt ASC',\n });\n const children: TraceNode[] = [];\n if (depth > 0) {\n for (const usage of usages) {\n if (usage.consumerType !== 'Lot' || path.has(usage.consumerId)) {\n continue;\n }\n const child = await this.lots.get(usage.consumerId);\n if (!child) continue;\n children.push(\n await this.forwardNode(\n child,\n options,\n depth - 1,\n new Set([...path, usage.consumerId]),\n memo,\n ),\n );\n }\n }\n return { ...(await this.nodeBase(lot, usages, options)), children };\n }\n\n /**\n * Where a consumer's material came from: one node per lot it used, each\n * with (as `children`) the lots that went into that lot when it was\n * itself an assembly (consumer `('Lot', lotId)`), up to `depth` levels.\n *\n * Cost: one usage query per consumer visited plus, per lot, the lot,\n * movements and documents queries. A lot reached by two paths is expanded\n * once and shared. Bound large graphs with `depth`.\n */\n async traceBack(\n consumerType: string,\n consumerId: string,\n options: TraceOptions = {},\n ): Promise<TraceNode[]> {\n const depth = options.depth ?? DEFAULT_TRACE_DEPTH;\n return this.backNodes(\n consumerType,\n consumerId,\n options,\n depth,\n consumerType === 'Lot' ? new Set([consumerId]) : new Set(),\n new Map(),\n );\n }\n\n private async backNodes(\n consumerType: string,\n consumerId: string,\n options: TraceOptions,\n depth: number,\n path: Set<string>,\n memo: Map<string, Promise<TraceNode | null>>,\n ): Promise<TraceNode[]> {\n const edges = await this.usages.findForConsumer(consumerType, consumerId, {\n includeUnlinked: options.includeUnlinked,\n });\n const byLot = new Map<string, LotUsage[]>();\n for (const edge of edges) {\n byLot.set(edge.lotId, [...(byLot.get(edge.lotId) ?? []), edge]);\n }\n const nodes: TraceNode[] = [];\n for (const [lotId, usages] of byLot) {\n if (path.has(lotId)) continue;\n // Edges differ per consumer, so key on the edges too.\n const key = `${lotId}:${depth}:${usages.map((u) => u.id).join(',')}`;\n let node = memo.get(key);\n if (!node) {\n node = this.expandBack(lotId, usages, options, depth, path, memo);\n memo.set(key, node);\n }\n const resolved = await node;\n if (resolved) nodes.push(resolved);\n }\n return nodes;\n }\n\n private async expandBack(\n lotId: string,\n usages: LotUsage[],\n options: TraceOptions,\n depth: number,\n path: Set<string>,\n memo: Map<string, Promise<TraceNode | null>>,\n ): Promise<TraceNode | null> {\n const lot = await this.lots.get(lotId);\n if (!lot) return null;\n const children =\n depth > 0\n ? await this.backNodes(\n 'Lot',\n lotId,\n options,\n depth - 1,\n new Set([...path, lotId]),\n memo,\n )\n : [];\n return { ...(await this.nodeBase(lot, usages, options)), children };\n }\n\n private async nodeBase(\n lot: Lot,\n usages: LotUsage[],\n options: TraceOptions,\n ): Promise<Omit<TraceNode, 'children'>> {\n const lotId = lot.id as string;\n const [movements, documents] = await Promise.all([\n this.movements.list({ where: { lotId }, orderBy: 'occurredAt ASC' }),\n this.documents.list({ where: { lotId } }),\n ]);\n return {\n lot,\n usages,\n movements,\n documents: options.includeUnlinked\n ? documents\n : documents.filter((doc) => !doc.detachedAt),\n };\n }\n\n // ───────────────────────────────────────────────────────────────────────\n // Internals\n // ───────────────────────────────────────────────────────────────────────\n\n private atomically<T>(work: (tx: LotService) => Promise<T>): Promise<T> {\n return this.withTransaction(work);\n }\n\n private async requireLot(lotId: string): Promise<Lot> {\n const lot = await this.lots.get(lotId);\n if (!lot) throw new LotNotFoundError(lotId);\n return lot;\n }\n\n private writeCorrection(\n lot: Lot,\n kind: LotCorrectionKind,\n reason: string,\n details: {\n field?: string;\n oldValue: string;\n newValue: string;\n usageId?: string;\n documentId?: string;\n actorProfileId?: string | null;\n },\n ): Promise<LotCorrection> {\n return this.corrections.create({\n lotId: lot.id as string,\n kind,\n field: details.field ?? '',\n oldValue: details.oldValue,\n newValue: details.newValue,\n reason,\n usageId: details.usageId ?? null,\n documentId: details.documentId ?? null,\n actorProfileId: details.actorProfileId ?? null,\n correctedAt: nextCorrectionTime(),\n });\n }\n}\n\n/**\n * Convenience factory. Returns a {@link LotService} sharing the given\n * database with its internal collections.\n */\nexport async function createLotService(\n options: LotServiceOptions,\n): Promise<LotService> {\n return LotService.create(options);\n}\n"],"mappings":"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"}