@fayz-ai/shop 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/{chunk-IL6GA4ER.js → chunk-2WACO2TG.js} +3 -3
  2. package/dist/{chunk-IL6GA4ER.js.map → chunk-2WACO2TG.js.map} +1 -1
  3. package/dist/{chunk-RGTIJQJL.js → chunk-6BO2TMZ5.js} +3 -3
  4. package/dist/{chunk-RGTIJQJL.js.map → chunk-6BO2TMZ5.js.map} +1 -1
  5. package/dist/{chunk-XOP6SHPB.js → chunk-NWW3WJ7Y.js} +4 -10
  6. package/dist/chunk-NWW3WJ7Y.js.map +1 -0
  7. package/dist/{chunk-XERLK5LD.js → chunk-STRNMFC4.js} +28 -5
  8. package/dist/chunk-STRNMFC4.js.map +1 -0
  9. package/dist/{chunk-U3O2I3RM.js → chunk-U6HV3LVP.js} +385 -23
  10. package/dist/chunk-U6HV3LVP.js.map +1 -0
  11. package/dist/data/checkout-gateways.d.ts +28 -0
  12. package/dist/data/checkout-gateways.d.ts.map +1 -0
  13. package/dist/data/customer-search.d.ts +3 -0
  14. package/dist/data/customer-search.d.ts.map +1 -0
  15. package/dist/data/functions.d.ts +9 -0
  16. package/dist/data/functions.d.ts.map +1 -0
  17. package/dist/data/media.d.ts +37 -0
  18. package/dist/data/media.d.ts.map +1 -0
  19. package/dist/data/mock-provider.d.ts +40 -8
  20. package/dist/data/mock-provider.d.ts.map +1 -1
  21. package/dist/data/provider.d.ts +205 -7
  22. package/dist/data/provider.d.ts.map +1 -1
  23. package/dist/data/supabase-provider.d.ts +118 -5
  24. package/dist/data/supabase-provider.d.ts.map +1 -1
  25. package/dist/data/tables.d.ts +3 -0
  26. package/dist/data/tables.d.ts.map +1 -1
  27. package/dist/entities/index.d.ts +0 -1
  28. package/dist/entities/index.d.ts.map +1 -1
  29. package/dist/entities.js +2 -2
  30. package/dist/index.d.ts +16 -5
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +925 -60
  33. package/dist/index.js.map +1 -1
  34. package/dist/inventory/index.d.ts +2 -2
  35. package/dist/inventory/index.d.ts.map +1 -1
  36. package/dist/inventory/stock-types.d.ts +60 -1
  37. package/dist/inventory/stock-types.d.ts.map +1 -1
  38. package/dist/inventory/supabase-stock-store.d.ts +1 -0
  39. package/dist/inventory/supabase-stock-store.d.ts.map +1 -1
  40. package/dist/inventory.js +1 -1
  41. package/dist/lib/commerce.d.ts.map +1 -1
  42. package/dist/lib/document.d.ts +13 -0
  43. package/dist/lib/document.d.ts.map +1 -0
  44. package/dist/lib/variant-matrix.d.ts +120 -0
  45. package/dist/lib/variant-matrix.d.ts.map +1 -0
  46. package/dist/mock.js +2 -2
  47. package/dist/providers/checkout.d.ts +129 -0
  48. package/dist/providers/checkout.d.ts.map +1 -0
  49. package/dist/providers/index.d.ts +5 -0
  50. package/dist/providers/index.d.ts.map +1 -0
  51. package/dist/providers/shipping.d.ts +43 -0
  52. package/dist/providers/shipping.d.ts.map +1 -0
  53. package/dist/providers.js +70 -0
  54. package/dist/providers.js.map +1 -0
  55. package/dist/runtime.js +3 -3
  56. package/dist/shipping/label-provider.d.ts +43 -0
  57. package/dist/shipping/label-provider.d.ts.map +1 -0
  58. package/dist/types.d.ts +475 -0
  59. package/dist/types.d.ts.map +1 -1
  60. package/package.json +8 -4
  61. package/dist/chunk-U3O2I3RM.js.map +0 -1
  62. package/dist/chunk-XERLK5LD.js.map +0 -1
  63. package/dist/chunk-XOP6SHPB.js.map +0 -1
  64. package/dist/entities/sidecar.d.ts +0 -9
  65. package/dist/entities/sidecar.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/inventory/stock-store.ts","../src/inventory/stock-types.ts","../src/inventory/vocabulary.ts","../src/inventory/allocation.ts","../src/inventory/shopify-mapping.ts","../src/data/tables.ts","../src/inventory/supabase-stock-store.ts","../src/inventory/mock-stock-store.ts"],"names":["Registry","coreRegistered","error"],"mappings":"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","file":"chunk-STRNMFC4.js","sourcesContent":["import type {\n ListStockBalancesOptions,\n ListStockLotsOptions,\n ListStockMovementsOptions,\n RecordStockMovementInput,\n ReserveStockInput,\n StockAllocation,\n StockAllocationRequest,\n StockBalance,\n StockLocation,\n StockLot,\n StockMovement,\n StockReservation,\n StockReservationStatus,\n} from './stock-types'\n\n// ---------------------------------------------------------------------------\n// StockStore — the read/append surface over the inventory ledger, and the I5\n// storage indirection for it.\n//\n// Deliberately NOT wired into ShopProvider or shop_place_order. Allocation and\n// the place_order rewrite are §9 step 4 and they rewrite the SECURITY DEFINER\n// trust boundary; stock that can be allocated from the client is stock that can\n// be lied about. What ships here is the honest half: reading balances and lots,\n// and APPENDING movements — which is exactly the surface a receiving screen, a\n// CSV import and an ERP connector need, and §10 q4 names receiving as the first\n// thing a real store touches.\n//\n// Two implementations, the same shape as the M4 EntityStore: the Supabase one\n// over migrations 0034–0036, and an in-memory mock. Both run the SAME\n// validator (validateStockMovement) and the same ledger→balance arithmetic, so\n// a test that passes against the mock is asserting the real semantics and not a\n// convenient imitation.\n// ---------------------------------------------------------------------------\n\n/** Thrown when the ledger refuses a movement. Carries the input for logging. */\nexport class StockMovementError extends Error {\n constructor(\n message: string,\n readonly input: RecordStockMovementInput,\n ) {\n super(message)\n this.name = 'StockMovementError'\n }\n}\n\nexport interface StockStore {\n /** Every location, default first. Single-location stores see exactly one. */\n listLocations(): Promise<StockLocation[]>\n /** The tenant's default location, created on demand server-side. */\n getDefaultLocation(): Promise<StockLocation | null>\n\n /** Balance rows per (variant, lot, location). */\n listBalances(options?: ListStockBalancesOptions): Promise<StockBalance[]>\n /**\n * `available` for one variant, summed over sellable active locations — the\n * same number the 0036 mirror publishes to inventory_count, so a caller can\n * check the two agree without knowing how the mirror works.\n */\n getAvailable(variantId: string): Promise<number>\n\n listLots(options?: ListStockLotsOptions): Promise<StockLot[]>\n listMovements(options?: ListStockMovementsOptions): Promise<StockMovement[]>\n\n /**\n * Append to the ledger. Never an update: a mistake is corrected by an\n * opposing movement. An `idempotencyKey` that has already been used returns\n * the EXISTING movement rather than writing a second one, so a retry is safe.\n */\n recordMovement(input: RecordStockMovementInput): Promise<StockMovement>\n\n listReservations(variantId?: string): Promise<StockReservation[]>\n\n // --- §9 step 4: allocation and the reservation lifecycle --------------------\n // These three verbs did not exist while the ledger was read-only. The contract\n // suite carried them \"out of band\" through the harness with a comment saying\n // \"the port has no verb for this until §9 step 4 lands\". It has landed, so\n // they are promoted into the port and the harness keeps only the one thing a\n // port genuinely cannot expose — the raw row count behind it.\n\n /**\n * Which lots cover a quantity, in the strategy's picking order (§4).\n *\n * ALLOCATES ONLY: no movement, no hold, no balance write. That separation is\n * what lets shop_place_order decide what to do with the answer inside its own\n * transaction, and what lets a picking screen show the merchant what WOULD be\n * taken. Throws on a shortfall rather than answering short — backorder is\n * §10 q3, answered no.\n */\n allocate(request: Omit<StockAllocationRequest, 'tracking'>): Promise<StockAllocation[]>\n\n /**\n * Place a hold (§5). Add-to-cart NEVER calls this — carts are abandoned\n * constantly and reserving there converts an abandoned cart into a phantom\n * stockout. Checkout holds, payment consumes, the TTL releases.\n */\n reserve(input: ReserveStockInput): Promise<StockReservation>\n\n /**\n * Move a hold through its lifecycle. `consumed` is what payment confirmation\n * does; `released` is what a cancel or the sweeper does. Neither writes a\n * movement here — consuming a hold into a `sale` is the trust boundary's job\n * (shop_place_order / the order lifecycle trigger), not a client's.\n */\n setReservationStatus(reservationId: string, status: StockReservationStatus): Promise<void>\n\n /**\n * Release every hold whose TTL has passed, and answer how many. Runs\n * opportunistically at allocation time as well, so correctness never depends\n * on a scheduler being alive (§5).\n */\n sweepExpiredReservations(variantId?: string): Promise<number>\n}\n\n// --- Shared arithmetic --------------------------------------------------------\n// The ledger→balance reduction, written once so the mock cannot drift from the\n// SQL trigger it stands in for.\n\n/** Identity of a balance row. The `-` sentinel stands for \"no lot\". */\nexport function stockBalanceKey(variantId: string, locationId: string, lotId: string | null): string {\n return `${variantId}::${locationId}::${lotId ?? '-'}`\n}\n\n/**\n * Replay a ledger into balances — the operation that makes \"the balance is only\n * a cache\" a checkable claim rather than a slogan. Mirrors\n * `shop_rebuild_stock_balances()` in migration 0034.\n *\n * Held reservations subtract from `available` and nothing else; consumed and\n * released ones do not, because a consumed hold has already become a `sale`\n * movement and counting it twice is how phantom stockouts are made.\n */\nexport function replayStockLedger(\n movements: readonly Pick<StockMovement, 'tenantId' | 'variantId' | 'locationId' | 'lotId' | 'quantity'>[],\n reservations: readonly Pick<\n StockReservation,\n 'variantId' | 'locationId' | 'lotId' | 'quantity' | 'status'\n >[] = [],\n): Map<string, { tenantId: string; variantId: string; locationId: string; lotId: string | null; onHand: number; reserved: number }> {\n const balances = new Map<\n string,\n { tenantId: string; variantId: string; locationId: string; lotId: string | null; onHand: number; reserved: number }\n >()\n\n for (const movement of movements) {\n // A movement whose variant was deleted keeps its history but has no\n // balance to belong to — the balance CASCADEd away with the variant.\n if (!movement.variantId) continue\n const key = stockBalanceKey(movement.variantId, movement.locationId, movement.lotId)\n const row = balances.get(key) ?? {\n tenantId: movement.tenantId,\n variantId: movement.variantId,\n locationId: movement.locationId,\n lotId: movement.lotId,\n onHand: 0,\n reserved: 0,\n }\n row.onHand += movement.quantity\n balances.set(key, row)\n }\n\n for (const reservation of reservations) {\n if (reservation.status !== 'held') continue\n const key = stockBalanceKey(reservation.variantId, reservation.locationId, reservation.lotId)\n const row = balances.get(key)\n if (row) {\n row.reserved += reservation.quantity\n continue\n }\n // A hold placed before any receipt is legitimate (backorder). The row is\n // created so `available` reads -N rather than nothing at all.\n balances.set(key, {\n tenantId: '',\n variantId: reservation.variantId,\n locationId: reservation.locationId,\n lotId: reservation.lotId,\n onHand: 0,\n reserved: reservation.quantity,\n })\n }\n\n return balances\n}\n\n/**\n * What the 0036 mirror writes to `plg_shop_product_variants.inventory_count`:\n * available over SELLABLE ACTIVE locations, each row clamped at zero because\n * 0028 declares `CHECK (inventory_count >= 0)` while the ledger deliberately\n * permits a negative balance.\n */\nexport function mirroredInventoryCount(\n balances: readonly Pick<StockBalance, 'locationId' | 'onHand' | 'reserved'>[],\n sellableLocationIds: ReadonlySet<string>,\n): number {\n let total = 0\n for (const balance of balances) {\n if (!sellableLocationIds.has(balance.locationId)) continue\n total += Math.max(balance.onHand - balance.reserved, 0)\n }\n return Math.max(total, 0)\n}\n\n// --- Per-tenant store resolution (the promotion seam, I5) ---------------------\n\nconst storeOverrides = new Map<string, StockStore>()\n\n/**\n * Replace the stock store for one tenant — the seam an ERP connector uses when\n * `plg_shop_settings.stock_ownership = 'external'` and Bling, not our ledger,\n * owns the numbers. Callers are untouched; only the implementation changes.\n */\nexport function registerStockStore(tenantId: string, store: StockStore): void {\n storeOverrides.set(tenantId, store)\n}\n\nexport function getRegisteredStockStore(tenantId: string): StockStore | undefined {\n return storeOverrides.get(tenantId)\n}\n\n/** Resolve a tenant's stock store: the registered override, else the fallback. */\nexport function resolveStockStore(tenantId: string, fallback: () => StockStore): StockStore {\n return storeOverrides.get(tenantId) ?? fallback()\n}\n\n/** Test seam. */\nexport function clearStockStores(): void {\n storeOverrides.clear()\n}\n","// ---------------------------------------------------------------------------\n// The inventory model as serializable, engine-independent types.\n//\n// Stock stops being a number that is EDITED and becomes a number that is\n// DERIVED (docs/storefront/inventory-model.md §1):\n//\n// movements (append-only, signed) ──▶ balances (variant × lot × location)\n// │\n// reservations ─────┤\n// ▼\n// available = onHand − reserved\n//\n// These types mirror migrations 0034–0036 one-for-one. They carry no evaluator\n// and no transport: the portable artifact is the SHAPE, never the engine (I11),\n// which is what lets the same model be served by Postgres today, by a mock in\n// tests, and by a second backend later.\n// ---------------------------------------------------------------------------\n\n/**\n * The per-variant tracking policy — a closed set, deliberately (§3).\n *\n * Unlike movement kinds and reason codes, these are NOT rows: each value\n * changes what the engine does, so a tenant-invented mode would be data no\n * code could honour. Widening this is a model change — this union, the\n * `plg_shop_product_variants_tracking_check` CHECK, and the validator, together.\n *\n * - `none` — never depletes. Made-to-order, digital, services.\n * - `quantity` — one implicit lot. THE DEFAULT, so existing stores are unchanged.\n * - `lot` — batches with expiry; allocation is FEFO.\n * - `serial` — every unit is unique; a serial is a lot whose quantity is 1.\n */\nexport const STOCK_TRACKING_MODES = ['none', 'quantity', 'lot', 'serial'] as const\nexport type StockTrackingMode = (typeof STOCK_TRACKING_MODES)[number]\n\n/** The default every variant gets, so adopting the ledger costs a simple store nothing. */\nexport const DEFAULT_STOCK_TRACKING: StockTrackingMode = 'quantity'\n\n/** Closed set: allocation branches on it (transit stock cannot be promised). */\nexport const STOCK_LOCATION_KINDS = ['store', 'warehouse', 'transit', 'virtual'] as const\nexport type StockLocationKind = (typeof STOCK_LOCATION_KINDS)[number]\n\n/** Closed set: the §5 reservation lifecycle. */\nexport const STOCK_RESERVATION_STATUSES = ['held', 'consumed', 'released'] as const\nexport type StockReservationStatus = (typeof STOCK_RESERVATION_STATUSES)[number]\n\nexport const STOCK_LOT_STATUSES = ['active', 'quarantined', 'expired', 'consumed'] as const\nexport type StockLotStatus = (typeof STOCK_LOT_STATUSES)[number]\n\n/**\n * The sign contract a movement kind carries. It lives in the VOCABULARY ROW,\n * not in the validator, which is precisely what lets a tenant add a kind.\n */\nexport const STOCK_MOVEMENT_DIRECTIONS = ['in', 'out', 'either'] as const\nexport type StockMovementDirection = (typeof STOCK_MOVEMENT_DIRECTIONS)[number]\n\n/** One movement-kind vocabulary row (plg_shop_stock_movement_kinds). */\nexport interface StockMovementKind {\n key: string\n label: string\n direction: StockMovementDirection\n}\n\n/**\n * One reason-code vocabulary row (plg_shop_stock_reason_codes).\n *\n * `movementKind` null means \"valid for any kind\"; naming one makes the pair\n * checkable, so 'breakage' can never be recorded as a receipt.\n */\nexport interface StockReasonCode {\n key: string\n label: string\n movementKind: string | null\n}\n\n/**\n * `fulfillment_provider` when the merchant dispatches by hand — a decision, not\n * an absent one, which is why it is stored instead of inferred from \"no gateway\".\n */\nexport const OWN_FULFILLMENT = 'own'\n\n/** Where stock sits, and — since 0058 — what ships from there. */\nexport interface StockLocation {\n id: string\n tenantId: string\n code: string\n name: string\n kind: StockLocationKind\n /** Stock here can be promised to a shopper. Transit stock cannot. */\n isSellable: boolean\n isDefault: boolean\n status: 'active' | 'archived'\n /** 8 bare digits. The origin a freight gateway quotes from. */\n postalCode?: string | null\n city?: string | null\n state?: string | null\n street?: string | null\n number?: string | null\n district?: string | null\n complement?: string | null\n /** CNPJ/CPF, digits only — the carrier prints it on the label (0061). */\n document?: string | null\n phone?: string | null\n email?: string | null\n /**\n * Where THIS place drops its parcels, per carrier (0062):\n * `{ 'melhor-envio': { id: '49276', name: 'Jadlog Barra' } }`.\n *\n * Per carrier because the choice is: the same warehouse can drop one\n * carrier's parcels downtown and another's next door. Empty means \"the\n * nearest agency that accepts the service\", which is what dispatch does.\n */\n carrierAgencies?: Record<string, { id: string; name?: string }> | null\n /** Online orders may be dispatched from here. */\n shipsOnline?: boolean\n /** null follows the store, `OWN_FULFILLMENT` is by hand, else a connector id. */\n fulfillmentProvider?: string | null\n createdAt: string\n updatedAt: string\n}\n\nexport interface CreateStockLocationInput {\n name: string\n /** Stable handle for a CSV import or an ERP connector. Defaults to a slug of the name. */\n code?: string\n kind?: StockLocationKind\n isSellable?: boolean\n isDefault?: boolean\n status?: 'active' | 'archived'\n postalCode?: string | null\n city?: string | null\n state?: string | null\n street?: string | null\n number?: string | null\n district?: string | null\n complement?: string | null\n document?: string | null\n phone?: string | null\n email?: string | null\n carrierAgencies?: Record<string, { id: string; name?: string }> | null\n shipsOnline?: boolean\n fulfillmentProvider?: string | null\n}\n\nexport type UpdateStockLocationInput = Partial<CreateStockLocationInput>\n\n/** A batch. A serial-tracked unit is a lot whose quantity is 1. */\nexport interface StockLot {\n id: string\n tenantId: string\n variantId: string\n lotCode: string\n serial: string | null\n /** Calendar dates, not timestamps: FEFO order must not depend on a time zone. */\n manufacturedAt: string | null\n expiresAt: string | null\n receivedAt: string\n unitCost: number | null\n supplierRef: string | null\n status: StockLotStatus\n createdAt: string\n updatedAt: string\n}\n\n/**\n * One ledger row. Append-only and signed: a mistake is corrected by an\n * OPPOSING movement, never by an edit, which is what makes the ledger\n * auditable.\n */\nexport interface StockMovement {\n id: string\n tenantId: string\n /** Null only after the variant row was deleted — the history survives it. */\n variantId: string | null\n productId: string | null\n locationId: string\n lotId: string | null\n kind: string\n reasonCode: string | null\n /** Signed. The kind's `direction` decides which signs are legal. */\n quantity: number\n unitCost: number | null\n orderId: string | null\n reservationId: string | null\n idempotencyKey: string | null\n /** WHEN it happened, which is not when it was recorded. */\n occurredAt: string\n createdBy: string | null\n note: string | null\n createdAt: string\n}\n\n/** What a caller supplies to append to the ledger. */\nexport interface RecordStockMovementInput {\n variantId: string\n kind: string\n quantity: number\n reasonCode?: string | null\n /** Omitted ⇒ the tenant's default location, created on demand. */\n locationId?: string | null\n lotId?: string | null\n unitCost?: number | null\n orderId?: string | null\n reservationId?: string | null\n /** A retried write must not decrement twice. */\n idempotencyKey?: string | null\n occurredAt?: string\n note?: string | null\n}\n\n/**\n * The materialised answer per (variant, lot, location) — an index over the\n * ledger, not a second truth. `onHand` may be NEGATIVE: an over-recorded loss\n * must stay visible rather than be refused, because refusing it would make the\n * LEDGER lie. The clamp happens once, at the inventory_count mirror.\n *\n * ---------------------------------------------------------------------------\n * NAME MAPPING TO SHOPIFY, so a connector never needs a translation table.\n *\n * Shopify's quantity states are `available`, `committed`, `on_hand`,\n * `incoming`, plus `damaged`, `safety_stock` and `quality_control`. Ours:\n *\n * ours Shopify note\n * ──────────── ───────────── ──────────────────────────────────────────────\n * onHand on_hand identical\n * available available identical (onHand − reserved)\n * reserved committed SAME CONCEPT, different word. Ours is the\n * schema name (0034, landed and green); theirs\n * is published beside it by the\n * plg_shop_stock_levels view, which exposes both\n * `reserved` and `committed` columns. Renaming\n * the column instead would have churned an\n * already-green contract suite, the SQL\n * regression, the mirror and the mock for a\n * synonym.\n * (a non-sellable location's\n * balance) incoming we model it as a PLACE (`kind = 'transit'`,\n * `is_sellable = false`) rather than as a fourth\n * number, which is strictly more expressive:\n * two warehouses in transit are two rows.\n * (a `loss` movement with\n * reason `damaged`) damaged ours is a ledger entry with a reason code, so\n * it carries when, who and how many; Shopify's\n * is a bucket.\n * — safety_stock NOT MODELLED. Reorder point and low-stock\n * threshold are §8's \"forecasting\", deliberately\n * out of scope.\n * (a `lot` with status\n * 'quarantined') quality_control ours is a lot state, which is more precise:\n * it is a BATCH that is under inspection, not a\n * quantity.\n *\n * Where we go BEYOND Shopify we keep it: lots, `expiresAt`, FEFO and serial\n * tracking have no native Shopify equivalent (merchants buy apps for both), and\n * they are exactly what artorious and cristinarotondaro need. \"Padrão Shopify\"\n * means compatible-by-default, never limited-to. The machine-readable form of\n * this table is packages/shop/src/inventory/shopify-mapping.ts.\n */\nexport interface StockBalance {\n id: string\n tenantId: string\n variantId: string\n locationId: string\n lotId: string | null\n onHand: number\n reserved: number\n /** onHand − reserved. What the mirror publishes to the storefront. */\n available: number\n updatedAt: string\n}\n\n/** A hold. Add-to-cart does NOT reserve; checkout start does (§5). */\nexport interface StockReservation {\n id: string\n tenantId: string\n variantId: string\n locationId: string\n lotId: string | null\n quantity: number\n status: StockReservationStatus\n orderId: string | null\n cartToken: string | null\n /** The TTL that makes pix and boleto honest. */\n expiresAt: string | null\n idempotencyKey: string | null\n createdBy: string | null\n createdAt: string\n updatedAt: string\n}\n\n// --- Allocation (§4) ----------------------------------------------------------\n\n/**\n * One allocation-strategy vocabulary row\n * (plg_shop_stock_allocation_strategies). The three behavioural fields are the\n * ORDERING CONTRACT the engine reads — the same discipline as\n * StockMovementKind.direction. Widening the vocabulary is a row, not a fork.\n */\nexport interface StockAllocationStrategy {\n key: string\n label: string\n /** Order by expiry first, nulls last. FEFO. */\n expiresFirst: boolean\n /** 'asc' = oldest receipt first (FIFO), 'desc' = newest first (LIFO). */\n receivedOrder: 'asc' | 'desc'\n /** Nothing is picked automatically; the caller names the lot. */\n isManual: boolean\n}\n\n/** One (lot, location) position allocation may draw from. */\nexport interface StockAllocationCandidate {\n /** null for a quantity-tracked variant's one implicit lot. */\n lotId: string | null\n locationId: string\n /** onHand − reserved for this position. */\n available: number\n /** Calendar date, so FEFO order cannot depend on a reader's time zone. */\n expiresAt: string | null\n receivedAt: string\n /** Transit stock exists but cannot be promised. Default true. */\n isSellableLocation?: boolean\n /** Breaks ties so the answer is reproducible, not merely correct. */\n isDefaultLocation?: boolean\n}\n\nexport interface StockAllocationRequest {\n variantId: string\n quantity: number\n tracking: StockTrackingMode\n /** Narrow to one location. Omitted, the default location leads. */\n locationId?: string | null\n /** Narrow to one lot — required by the `manual` strategy. */\n lotId?: string | null\n /** Most specific first: explicit, then variant, then store, then derived. */\n strategy?: string | null\n variantStrategy?: string | null\n tenantStrategy?: string | null\n}\n\n/** One lot chosen, in picking order. They sum to the requested quantity. */\nexport interface StockAllocation {\n lotId: string | null\n locationId: string\n quantity: number\n}\n\n/** What a caller supplies to place a hold. Add-to-cart never calls this (§5). */\nexport interface ReserveStockInput {\n variantId: string\n quantity: number\n locationId: string\n lotId?: string | null\n orderId?: string | null\n cartToken?: string | null\n /** The TTL that makes pix and boleto honest. Omitted ⇒ a hold with no expiry. */\n ttlMinutes?: number | null\n /** A retried checkout must not hold the unit twice. */\n idempotencyKey?: string | null\n}\n\n// --- Read options -------------------------------------------------------------\n\nexport interface ListStockBalancesOptions {\n variantId?: string\n variantIds?: string[]\n locationId?: string\n lotId?: string\n /** Only rows a shopper could be promised (sellable, active locations). */\n sellableOnly?: boolean\n}\n\nexport interface ListStockLotsOptions {\n variantId?: string\n status?: StockLotStatus\n /** Lots expiring on or before this date — the \"what is about to go off\" read. */\n expiresBefore?: string\n /** FEFO order: expiresAt then receivedAt, nulls last. Default true. */\n fefo?: boolean\n limit?: number\n}\n\nexport interface ListStockMovementsOptions {\n variantId?: string\n lotId?: string\n orderId?: string\n kind?: string\n reasonCode?: string\n /** Newest first. Default true — \"why is this 3?\" reads backwards. */\n newestFirst?: boolean\n limit?: number\n}\n","import { Registry } from '@fayz-ai/core'\nimport type { RegistryMeta } from '@fayz-ai/core'\nimport type {\n RecordStockMovementInput,\n StockMovementKind,\n StockReasonCode,\n StockTrackingMode,\n} from './stock-types'\n\n// ---------------------------------------------------------------------------\n// The stock vocabulary — DATA, not a hardcoded list (spine I9), and ONE\n// validator shared with the SQL (spine: one validator, never two that drift).\n//\n// Movement kinds and reason codes ship as ROWS in\n// plg_shop_stock_movement_kinds / plg_shop_stock_reason_codes (migration 0034),\n// exactly as rule attributes do in 0032. An agency adding \"quebra de vitrine\"\n// as a loss reason writes an INSERT — and, in code, one\n// registerStockReasonCode call — never a migration and never a fork.\n//\n// The registries below are the TS MIRROR of the core seed rows.\n// migrations.test.ts cross-checks the two so they cannot drift: the admin form,\n// the AI and both validators must read one vocabulary or the point is lost.\n//\n// validateStockMovement() is the TypeScript half of the ONE specification whose\n// other half is shop_validate_stock_movement() in 0034. Every refusal is an I2\n// hard error naming the valid set — never a silent drop, because a silently\n// dropped movement is stock that vanishes.\n// ---------------------------------------------------------------------------\n\n/**\n * The core movement kinds — the SAME rows the 0034 seed inserts with\n * tenant_id NULL. `direction` is the sign contract:\n * in ⇒ quantity must be positive\n * out ⇒ quantity must be negative\n * either ⇒ any non-zero quantity\n */\nexport const CORE_STOCK_MOVEMENT_KINDS: readonly StockMovementKind[] = [\n { key: 'receipt', label: 'Entrada', direction: 'in' },\n { key: 'sale', label: 'Venda', direction: 'out' },\n { key: 'return', label: 'Devolução', direction: 'in' },\n { key: 'adjustment', label: 'Ajuste', direction: 'either' },\n { key: 'transfer_in', label: 'Transferência (entrada)', direction: 'in' },\n { key: 'transfer_out', label: 'Transferência (saída)', direction: 'out' },\n { key: 'loss', label: 'Perda', direction: 'out' },\n { key: 'count', label: 'Contagem', direction: 'either' },\n]\n\n/**\n * The core reason codes — the SAME rows migrations 0034 and 0038 seed with\n * tenant_id NULL. `movementKind` null = valid for any kind.\n *\n * The last five arrived with 0038 so that Shopify's CLOSED adjustment-reason\n * vocabulary maps onto ours without loss (founder: \"vamos padrão Shopify\").\n * They are a widening, which is exactly what I9 promises the vocabulary can\n * take: five INSERTs and five entries here, no migration to the ENGINE and no\n * fork. The mapping itself is published as code in shopify-mapping.ts, and\n * stock-store.test.ts fails if a Shopify reason has no target here.\n */\nexport const CORE_STOCK_REASON_CODES: readonly StockReasonCode[] = [\n // --- 0034 -----------------------------------------------------------------\n { key: 'opening_balance', label: 'Saldo inicial', movementKind: 'receipt' },\n { key: 'purchase', label: 'Compra', movementKind: 'receipt' },\n { key: 'production', label: 'Produção', movementKind: 'receipt' },\n { key: 'customer_order', label: 'Pedido do cliente', movementKind: 'sale' },\n { key: 'customer_return', label: 'Devolução do cliente', movementKind: 'return' },\n { key: 'cycle_count', label: 'Contagem de estoque', movementKind: 'count' },\n { key: 'breakage', label: 'Quebra', movementKind: 'loss' },\n { key: 'expiry', label: 'Vencimento', movementKind: 'loss' },\n { key: 'theft', label: 'Furto', movementKind: 'loss' },\n { key: 'correction', label: 'Correção', movementKind: 'adjustment' },\n { key: 'legacy_write', label: 'Escrita direta em inventory_count', movementKind: 'adjustment' },\n { key: 'transfer', label: 'Transferência entre locais', movementKind: null },\n // --- 0038, for Shopify parity ---------------------------------------------\n // `received` is wider than our `purchase`: stock can arrive from a transfer,\n // a production run or a supplier, and Shopify does not distinguish.\n { key: 'received', label: 'Recebimento', movementKind: 'receipt' },\n // Distinct from our `breakage`: Shopify's `damaged` covers arriving damaged,\n // not only breaking in the shop. Both are kept — a merchant who already uses\n // `breakage` is not renamed.\n { key: 'damaged', label: 'Avariado', movementKind: 'loss' },\n { key: 'quality_control', label: 'Controle de qualidade', movementKind: 'adjustment' },\n { key: 'promotion', label: 'Promoção / brinde', movementKind: 'loss' },\n { key: 'other', label: 'Outro', movementKind: null },\n]\n\n/** The reason 0035 stamps on every backfilled opening balance. */\nexport const OPENING_BALANCE_REASON = 'opening_balance'\n/** The reason 0036's I10 shim stamps on a translated direct inventory_count write. */\nexport const LEGACY_WRITE_REASON = 'legacy_write'\n\n// --- The registries -----------------------------------------------------------\n// Uniform Registry<T> meta envelope (M1), the same one blocks, loaders, handles\n// and rule attributes use, so describeStore reads all of them through one parser.\n\nexport const stockMovementKindRegistry = new Registry<StockMovementKind>('stockMovementKind')\nexport const stockReasonCodeRegistry = new Registry<StockReasonCode>('stockReasonCode')\n\nlet coreRegistered = false\n\n/** Idempotent — consumers call before reads, mirroring registerCoreRuleAttributes. */\nexport function registerCoreStockVocabulary(): void {\n if (coreRegistered && stockMovementKindRegistry.has('receipt')) return\n for (const kind of CORE_STOCK_MOVEMENT_KINDS) {\n stockMovementKindRegistry.register(kind.key, kind, {\n title: kind.label,\n description: `Stock movement kind (${kind.direction})`,\n source: 'sdk',\n })\n }\n for (const reason of CORE_STOCK_REASON_CODES) {\n stockReasonCodeRegistry.register(reason.key, reason, {\n title: reason.label,\n description: reason.movementKind\n ? `Stock reason code for \"${reason.movementKind}\" movements`\n : 'Stock reason code (any movement kind)',\n source: 'sdk',\n })\n }\n coreRegistered = true\n}\n\nexport interface RegisterStockVocabularyOptions {\n meta?: RegistryMeta\n /** Re-registering an existing key is an error unless the caller owns it. */\n replace?: boolean\n}\n\n/**\n * Widen the movement-kind vocabulary. The SQL half of this is one INSERT into\n * plg_shop_stock_movement_kinds with the tenant's id.\n */\nexport function registerStockMovementKind(\n kind: StockMovementKind,\n options: RegisterStockVocabularyOptions = {},\n): void {\n registerCoreStockVocabulary()\n if (!kind.key) throw new Error('registerStockMovementKind: kind.key is required')\n if (!['in', 'out', 'either'].includes(kind.direction)) {\n throw new Error(\n `registerStockMovementKind: \"${kind.key}\" has unknown direction \"${kind.direction}\". ` +\n 'Valid directions: in, out, either',\n )\n }\n if (stockMovementKindRegistry.has(kind.key) && !options.replace) {\n throw new Error(\n `registerStockMovementKind: kind \"${kind.key}\" is already registered. ` +\n `Registered kinds: ${listStockMovementKindKeys().join(', ')}`,\n )\n }\n stockMovementKindRegistry.register(kind.key, kind, {\n title: kind.label,\n description: `Stock movement kind (${kind.direction})`,\n source: 'app',\n ...options.meta,\n })\n}\n\n/** Widen the reason-code vocabulary — \"quebra de vitrine\" is a row, not a fork. */\nexport function registerStockReasonCode(\n reason: StockReasonCode,\n options: RegisterStockVocabularyOptions = {},\n): void {\n registerCoreStockVocabulary()\n if (!reason.key) throw new Error('registerStockReasonCode: reason.key is required')\n if (reason.movementKind && !stockMovementKindRegistry.has(reason.movementKind)) {\n throw new Error(\n `registerStockReasonCode: \"${reason.key}\" names unknown movement kind \"${reason.movementKind}\". ` +\n `Registered kinds: ${listStockMovementKindKeys().join(', ')}`,\n )\n }\n if (stockReasonCodeRegistry.has(reason.key) && !options.replace) {\n throw new Error(\n `registerStockReasonCode: reason \"${reason.key}\" is already registered. ` +\n `Registered reason codes: ${listStockReasonCodeKeys().join(', ')}`,\n )\n }\n stockReasonCodeRegistry.register(reason.key, reason, {\n title: reason.label,\n description: reason.movementKind\n ? `Stock reason code for \"${reason.movementKind}\" movements`\n : 'Stock reason code (any movement kind)',\n source: 'app',\n ...options.meta,\n })\n}\n\n/** The kind for a key, or an I2 hard error naming the valid set. */\nexport function resolveStockMovementKind(key: string): StockMovementKind {\n registerCoreStockVocabulary()\n const kind = stockMovementKindRegistry.get(key)\n if (!kind) {\n throw new Error(\n `Unknown stock movement kind \"${key}\". Registered kinds: ${listStockMovementKindKeys().join(', ')}`,\n )\n }\n return kind\n}\n\n/** The reason for a key, or an I2 hard error naming the valid set. */\nexport function resolveStockReasonCode(key: string): StockReasonCode {\n registerCoreStockVocabulary()\n const reason = stockReasonCodeRegistry.get(key)\n if (!reason) {\n throw new Error(\n `Unknown stock reason code \"${key}\". Registered reason codes: ${listStockReasonCodeKeys().join(', ')}`,\n )\n }\n return reason\n}\n\nexport function listStockMovementKindKeys(): string[] {\n registerCoreStockVocabulary()\n return stockMovementKindRegistry.ids().sort()\n}\n\nexport function listStockReasonCodeKeys(): string[] {\n registerCoreStockVocabulary()\n return stockReasonCodeRegistry.ids().sort()\n}\n\n/** Every kind row, sorted — what an admin form renders itself from. */\nexport function listStockMovementKinds(): StockMovementKind[] {\n registerCoreStockVocabulary()\n return stockMovementKindRegistry\n .list()\n .map((entry) => entry.value)\n .sort((a, b) => a.key.localeCompare(b.key))\n}\n\n/** Every reason row, sorted. Optionally narrowed to one kind, which is exactly\n * what the \"record a movement\" form needs once a kind is chosen. */\nexport function listStockReasonCodes(movementKind?: string): StockReasonCode[] {\n registerCoreStockVocabulary()\n const all = stockReasonCodeRegistry\n .list()\n .map((entry) => entry.value)\n .sort((a, b) => a.key.localeCompare(b.key))\n if (!movementKind) return all\n return all.filter((reason) => reason.movementKind === null || reason.movementKind === movementKind)\n}\n\n/** Test seam — a suite that widens the vocabulary must not leak into the next. */\nexport function clearStockVocabulary(): void {\n stockMovementKindRegistry.clear()\n stockReasonCodeRegistry.clear()\n coreRegistered = false\n}\n\n// --- THE ONE VALIDATOR --------------------------------------------------------\n\n/** What the validator needs to know about the variant a movement targets. */\nexport interface StockMovementVariantFacts {\n tracking: StockTrackingMode\n /** Present only for lot/serial checks. */\n lot?: { id: string; variantId: string; serial: string | null } | null\n /**\n * `on_hand` already recorded for (lot, location), needed ONLY by the serial\n * rule below. Per-movement `|quantity| = 1` is not enough: two `+1` receipts\n * on the same serial lot are each individually legal and together say the\n * one-of-one unit exists twice. The cumulative check is what closes that,\n * and it is the reason this fact has to be read before the write.\n */\n lotOnHand?: number\n}\n\n/**\n * Refuse anything the ledger must not accept. This is the TypeScript half of\n * the specification whose SQL half is `shop_validate_stock_movement()` in\n * migration 0034 — the two implement ONE ruleset, and\n * `packages/shop/src/inventory/migrations.test.ts` pins the error vocabulary of\n * both so they cannot quietly disagree.\n *\n * Throws with a message naming the valid set (I2). Never returns a \"soft\"\n * failure: a movement that is dropped instead of refused is stock that vanishes.\n */\nexport function validateStockMovement(\n input: RecordStockMovementInput,\n facts: StockMovementVariantFacts,\n): void {\n registerCoreStockVocabulary()\n\n if (!input.variantId) {\n throw new Error('stock movement: variantId is required (the ledger is keyed on the sellable unit)')\n }\n\n if (!Number.isInteger(input.quantity)) {\n throw new Error(`stock movement: quantity must be a whole number (got ${input.quantity})`)\n }\n if (input.quantity === 0) {\n throw new Error('stock movement: quantity must not be zero — a movement that moves nothing is not a movement')\n }\n\n // Kind, and the sign contract carried by its vocabulary row.\n const kind = resolveStockMovementKind(input.kind)\n if (kind.direction === 'in' && input.quantity < 0) {\n throw new Error(\n `stock movement: kind \"${kind.key}\" is an inbound movement and needs a positive quantity (got ${input.quantity})`,\n )\n }\n if (kind.direction === 'out' && input.quantity > 0) {\n throw new Error(\n `stock movement: kind \"${kind.key}\" is an outbound movement and needs a negative quantity (got ${input.quantity})`,\n )\n }\n\n if (input.reasonCode) {\n const reason = resolveStockReasonCode(input.reasonCode)\n if (reason.movementKind !== null && reason.movementKind !== kind.key) {\n throw new Error(\n `stock movement: reason \"${reason.key}\" belongs to kind \"${reason.movementKind}\", not \"${kind.key}\"`,\n )\n }\n }\n\n // Tracking policy (§3) — where a per-variant policy stops being a label.\n if (facts.tracking === 'none') {\n throw new Error(`stock movement: variant ${input.variantId} is tracking=none and holds no stock`)\n }\n\n if (facts.tracking === 'quantity') {\n if (input.lotId) {\n throw new Error(\n `stock movement: variant ${input.variantId} is tracking=quantity; it has one implicit lot, so lotId must be null`,\n )\n }\n return\n }\n\n // 'lot' | 'serial'\n if (!input.lotId) {\n throw new Error(`stock movement: variant ${input.variantId} is tracking=${facts.tracking}; lotId is required`)\n }\n const lot = facts.lot\n if (!lot) {\n throw new Error(`stock movement: lot ${input.lotId} not found`)\n }\n if (lot.variantId !== input.variantId) {\n throw new Error(\n `stock movement: lot ${lot.id} belongs to variant ${lot.variantId}, not ${input.variantId}`,\n )\n }\n if (facts.tracking === 'serial') {\n if (!lot.serial) {\n throw new Error(\n `stock movement: variant ${input.variantId} is tracking=serial; lot ${lot.id} carries no serial`,\n )\n }\n if (Math.abs(input.quantity) !== 1) {\n throw new Error(\n `stock movement: variant ${input.variantId} is tracking=serial; quantity must be 1 or -1 (got ${input.quantity})`,\n )\n }\n // A serial IS one physical unit. |quantity| = 1 per movement is necessary\n // and NOT sufficient: two +1 receipts on the same lot are each legal on\n // their own and together claim the one-of-one exists twice. The balance is\n // therefore bounded to {0, 1}, which is the only place \"serial\" stops being\n // a synonym for \"lot with a code\".\n if (facts.lotOnHand !== undefined) {\n const next = facts.lotOnHand + input.quantity\n if (next > 1 || next < 0) {\n throw new Error(\n `stock movement: variant ${input.variantId} is tracking=serial; lot ${lot.id} would go to ${next} on hand ` +\n `(from ${facts.lotOnHand}). A serial is one unit: its balance may only be 0 or 1.`,\n )\n }\n }\n }\n}\n","import { Registry } from '@fayz-ai/core'\nimport type { RegistryMeta } from '@fayz-ai/core'\nimport type {\n StockAllocation,\n StockAllocationCandidate,\n StockAllocationRequest,\n StockAllocationStrategy,\n} from './stock-types'\n\n// ---------------------------------------------------------------------------\n// ALLOCATION — the ordering over lots, as data (inventory-model.md §4).\n//\n// This file is the TypeScript half of ONE specification whose SQL half is\n// shop_allocate_stock() in migration 0038. Same discipline as\n// validateStockMovement()/shop_validate_stock_movement(): two implementations\n// of one ruleset, cross-checked by migrations.test.ts, never two rulesets.\n//\n// WHY THE STRATEGY IS A ROW AND NOT AN ENUM (I9).\n//\n// The naive encoding is `type Strategy = 'fefo' | 'fifo' | 'lifo' | 'manual'`\n// and a switch. That is the hardcoded enumeration the spine rejects: an agency\n// that wants \"oldest cost first\" needs a migration and a code fork.\n//\n// So a strategy is a ROW carrying the ORDERING CONTRACT, exactly as a movement\n// kind carries `direction`:\n//\n// expiresFirst order by expiry, nulls last (FEFO)\n// receivedOrder 'asc' oldest receipt | 'desc' newest (FIFO | LIFO)\n// isManual nothing is picked; the caller names it\n//\n// compareCandidates() below reads those three fields and nothing else, so\n// registering a row is genuinely all it takes — and the bound is honest,\n// because a strategy the comparator cannot express would be free text.\n//\n// WHAT THIS FILE IS NOT. It never touches storage, never writes a movement and\n// never places a hold. Allocation runs INSIDE shop_place_order in Postgres, for\n// the reason §4 gives: that function is already the SECURITY DEFINER trust\n// boundary, and stock that can be allocated from the client is stock that can be\n// lied about. What lives here is the pure ordering — the thing a preview screen,\n// a test and the SQL must all agree on.\n// ---------------------------------------------------------------------------\n\n/**\n * The core four (§4) — the SAME rows migration 0038 seeds with tenant_id NULL.\n * migrations.test.ts cross-checks the two so they cannot drift.\n */\nexport const CORE_STOCK_ALLOCATION_STRATEGIES: readonly StockAllocationStrategy[] = [\n {\n key: 'fefo',\n label: 'Vence primeiro (FEFO)',\n expiresFirst: true,\n receivedOrder: 'asc',\n isManual: false,\n },\n {\n key: 'fifo',\n label: 'Entrou primeiro (FIFO)',\n expiresFirst: false,\n receivedOrder: 'asc',\n isManual: false,\n },\n {\n key: 'lifo',\n label: 'Entrou por ultimo (LIFO)',\n expiresFirst: false,\n receivedOrder: 'desc',\n isManual: false,\n },\n { key: 'manual', label: 'Manual', expiresFirst: false, receivedOrder: 'asc', isManual: true },\n]\n\nexport const stockAllocationStrategyRegistry = new Registry<StockAllocationStrategy>(\n 'stockAllocationStrategy',\n)\n\nlet coreRegistered = false\n\n/** Idempotent — consumers call before reads, mirroring registerCoreStockVocabulary. */\nexport function registerCoreStockAllocationStrategies(): void {\n if (coreRegistered && stockAllocationStrategyRegistry.has('fefo')) return\n for (const strategy of CORE_STOCK_ALLOCATION_STRATEGIES) {\n stockAllocationStrategyRegistry.register(strategy.key, strategy, {\n title: strategy.label,\n description: describeStrategy(strategy),\n source: 'sdk',\n })\n }\n coreRegistered = true\n}\n\nfunction describeStrategy(strategy: StockAllocationStrategy): string {\n if (strategy.isManual) return 'Manual — the caller names the lot'\n const parts = [strategy.expiresFirst ? 'soonest expiry first' : 'ignores expiry']\n parts.push(strategy.receivedOrder === 'asc' ? 'oldest receipt first' : 'newest receipt first')\n return parts.join(', ')\n}\n\n/**\n * Widen the strategy vocabulary. The SQL half is one INSERT into\n * plg_shop_stock_allocation_strategies with the tenant's id.\n */\nexport function registerStockAllocationStrategy(\n strategy: StockAllocationStrategy,\n options: { meta?: RegistryMeta; replace?: boolean } = {},\n): void {\n registerCoreStockAllocationStrategies()\n if (!strategy.key) throw new Error('registerStockAllocationStrategy: strategy.key is required')\n if (strategy.receivedOrder !== 'asc' && strategy.receivedOrder !== 'desc') {\n throw new Error(\n `registerStockAllocationStrategy: \"${strategy.key}\" has unknown receivedOrder \"${strategy.receivedOrder}\". ` +\n 'Valid values: asc, desc',\n )\n }\n if (stockAllocationStrategyRegistry.has(strategy.key) && !options.replace) {\n throw new Error(\n `registerStockAllocationStrategy: strategy \"${strategy.key}\" is already registered. ` +\n `Registered strategies: ${listStockAllocationStrategyKeys().join(', ')}`,\n )\n }\n stockAllocationStrategyRegistry.register(strategy.key, strategy, {\n title: strategy.label,\n description: describeStrategy(strategy),\n source: 'app',\n ...options.meta,\n })\n}\n\n/** The strategy for a key, or an I2 hard error naming the valid set. */\nexport function resolveStockAllocationStrategy(key: string): StockAllocationStrategy {\n registerCoreStockAllocationStrategies()\n const strategy = stockAllocationStrategyRegistry.get(key)\n if (!strategy) {\n throw new Error(\n `shop_allocate_stock: unknown allocation strategy \"${key}\". ` +\n `Valid strategies: ${listStockAllocationStrategyKeys().join(', ')}`,\n )\n }\n return strategy\n}\n\nexport function listStockAllocationStrategyKeys(): string[] {\n registerCoreStockAllocationStrategies()\n return stockAllocationStrategyRegistry.ids().sort()\n}\n\nexport function listStockAllocationStrategies(): StockAllocationStrategy[] {\n registerCoreStockAllocationStrategies()\n return stockAllocationStrategyRegistry\n .list()\n .map((entry) => entry.value)\n .sort((a, b) => a.key.localeCompare(b.key))\n}\n\n/** Test seam — a suite that widens the vocabulary must not leak into the next. */\nexport function clearStockAllocationStrategies(): void {\n stockAllocationStrategyRegistry.clear()\n coreRegistered = false\n}\n\n/**\n * §4's \"default fefo when `expires_at` exists\", resolved most-specific first.\n * The SQL twin is shop_resolve_allocation_strategy() in 0038:\n *\n * 1. the explicit argument\n * 2. the variant's own override\n * 3. the store's default\n * 4. derived — 'fefo' when any candidate lot carries an expiry, else 'fifo'\n *\n * Rule 4 is what makes artorious work with no configuration: the moment a\n * smoked-meat lot has a best-before, picking becomes FEFO on its own. And it is\n * what makes the default cost pulse and figurinhas nothing: no expiry anywhere,\n * so FIFO, which over one implicit lot is a no-op.\n */\nexport function resolveAllocationStrategyKey(input: {\n explicit?: string | null\n variantDefault?: string | null\n tenantDefault?: string | null\n candidates?: readonly StockAllocationCandidate[]\n}): string {\n const named =\n trimmed(input.explicit) ?? trimmed(input.variantDefault) ?? trimmed(input.tenantDefault)\n if (named) {\n // I2: an unknown key is a hard error naming the valid set, never a silent\n // fall back to fefo. A typo that quietly picks a different batch is exactly\n // the failure a food store cannot detect.\n resolveStockAllocationStrategy(named)\n return named\n }\n const hasExpiry = (input.candidates ?? []).some((candidate) => candidate.expiresAt != null)\n return hasExpiry ? 'fefo' : 'fifo'\n}\n\nfunction trimmed(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const next = value.trim()\n return next.length > 0 ? next : null\n}\n\n/**\n * The comparator, and the only place the strategy row's three fields are read.\n * Four terms, matching 0038's ORDER BY one for one:\n *\n * 1. under FEFO a lot with NO expiry never beats one that has a date — the\n * half a naive `ORDER BY expiresAt` gets wrong, and the half a food\n * store's recall depends on;\n * 2. under FEFO the soonest expiry leads;\n * 3. FIFO takes the oldest receipt, LIFO the newest;\n * 4. the default location leads, then the lot id, so the answer is\n * reproducible rather than merely correct.\n */\nexport function compareStockAllocationCandidates(\n strategy: StockAllocationStrategy,\n a: StockAllocationCandidate,\n b: StockAllocationCandidate,\n): number {\n if (strategy.expiresFirst) {\n const aNull = a.expiresAt == null ? 1 : 0\n const bNull = b.expiresAt == null ? 1 : 0\n if (aNull !== bNull) return aNull - bNull\n if (a.expiresAt != null && b.expiresAt != null && a.expiresAt !== b.expiresAt) {\n return a.expiresAt < b.expiresAt ? -1 : 1\n }\n }\n if (a.receivedAt !== b.receivedAt) {\n const older = a.receivedAt < b.receivedAt ? -1 : 1\n return strategy.receivedOrder === 'asc' ? older : -older\n }\n const aDefault = a.isDefaultLocation ? 0 : 1\n const bDefault = b.isDefaultLocation ? 0 : 1\n if (aDefault !== bDefault) return aDefault - bDefault\n return String(a.lotId ?? '').localeCompare(String(b.lotId ?? ''))\n}\n\n/** Thrown when nothing can cover the quantity. Carries both numbers. */\nexport class StockAllocationError extends Error {\n constructor(\n message: string,\n readonly requested: number,\n readonly available: number,\n ) {\n super(message)\n this.name = 'StockAllocationError'\n }\n}\n\n/**\n * Choose which lots cover a quantity, in the strategy's picking order.\n *\n * Mirrors shop_allocate_stock() exactly, including the two refusals:\n *\n * * a `manual` strategy with no lot named is an error, not a silent FEFO;\n * * a SHORTFALL is an error, not a partial answer. Backorder is §10 q3,\n * answered no — returning less than was asked for would let a caller write\n * an order it cannot ship and force it to re-derive the gap to notice.\n *\n * A `none`-tracked variant returns no rows and no error: it never depletes (§3),\n * so there is nothing to allocate and nothing to refuse.\n */\nexport function allocateStock(\n request: StockAllocationRequest,\n candidates: readonly StockAllocationCandidate[],\n): StockAllocation[] {\n if (!Number.isInteger(request.quantity) || request.quantity <= 0) {\n throw new Error(`shop_allocate_stock: quantity must be positive (got ${request.quantity})`)\n }\n if (request.tracking === 'none') return []\n\n const strategy = resolveStockAllocationStrategy(\n resolveAllocationStrategyKey({\n explicit: request.strategy,\n variantDefault: request.variantStrategy,\n tenantDefault: request.tenantStrategy,\n candidates,\n }),\n )\n\n if (request.tracking === 'quantity' && request.lotId) {\n throw new Error(\n `shop_allocate_stock: variant ${request.variantId} is tracking=quantity; it has one implicit lot, so lotId must be null`,\n )\n }\n if (request.tracking !== 'quantity' && strategy.isManual && !request.lotId) {\n throw new Error(\n `shop_allocate_stock: variant ${request.variantId} uses the \"manual\" strategy; name the lot to allocate from (lotId)`,\n )\n }\n\n const eligible = candidates\n .filter((candidate) => candidate.available > 0)\n .filter((candidate) => (request.locationId ? candidate.locationId === request.locationId : true))\n .filter((candidate) => (request.lotId ? candidate.lotId === request.lotId : true))\n // Stock in transit is REAL and the ledger says so; it simply cannot be\n // promised to a shopper.\n .filter((candidate) => candidate.isSellableLocation !== false)\n .filter((candidate) =>\n request.tracking === 'quantity' ? candidate.lotId == null : candidate.lotId != null,\n )\n .slice()\n .sort((a, b) => compareStockAllocationCandidates(strategy, a, b))\n\n const chosen: StockAllocation[] = []\n let remaining = request.quantity\n for (const candidate of eligible) {\n if (remaining <= 0) break\n const take = Math.min(remaining, candidate.available)\n // A serial IS one unit (§3), bounded to {0,1} by the ledger validator, so a\n // lot can only ever offer 1. The assertion says so out loud rather than\n // relying on the bound holding somewhere else.\n if (request.tracking === 'serial' && take !== 1) {\n throw new Error(\n `shop_allocate_stock: variant ${request.variantId} is tracking=serial; lot ${candidate.lotId} offered ${candidate.available} units and a serial is one unit`,\n )\n }\n chosen.push({ lotId: candidate.lotId, locationId: candidate.locationId, quantity: take })\n remaining -= take\n }\n\n if (remaining > 0) {\n const available = candidates\n .filter((candidate) => candidate.isSellableLocation !== false)\n .reduce((sum, candidate) => sum + Math.max(candidate.available, 0), 0)\n throw new StockAllocationError(\n `shop_allocate_stock: variant ${request.variantId} cannot cover ${request.quantity} unit(s); ${available} available`,\n request.quantity,\n available,\n )\n }\n\n return chosen\n}\n\n// --- Reservation TTLs (§5, §10 q2) -------------------------------------------\n\n/**\n * The core rows migration 0038 seeds into plg_shop_stock_reservation_ttls.\n * `null` is the fallback for any method, including an order that names none.\n *\n * §10 q2 asked whether the TTL is one number or one per payment method and\n * answered itself: \"30 minutes covers pix comfortably; boleto is days.\" Thirty\n * minutes is the window every Brazilian PSP quotes for pix; three days is the\n * ordinary boleto compensation window. Holding a unit that long is the cost of\n * accepting boleto, and pretending otherwise is what oversells.\n */\nexport const CORE_RESERVATION_TTL_MINUTES: readonly { paymentMethod: string | null; minutes: number }[] =\n [\n { paymentMethod: null, minutes: 30 },\n { paymentMethod: 'pix', minutes: 30 },\n { paymentMethod: 'credit_card', minutes: 30 },\n { paymentMethod: 'debit_card', minutes: 30 },\n { paymentMethod: 'cash', minutes: 30 },\n { paymentMethod: 'other', minutes: 30 },\n { paymentMethod: 'boleto', minutes: 4320 },\n ]\n\n/** The SQL twin is shop_reservation_ttl(): most specific row wins. */\nexport function resolveReservationTtlMinutes(\n paymentMethod?: string | null,\n overrides: readonly { paymentMethod: string | null; minutes: number }[] = [],\n): number {\n const rows = [...overrides, ...CORE_RESERVATION_TTL_MINUTES]\n const named = rows.find((row) => row.paymentMethod != null && row.paymentMethod === paymentMethod)\n if (named) return named.minutes\n const fallback = rows.find((row) => row.paymentMethod == null)\n return fallback?.minutes ?? 30\n}\n","import type { StockTrackingMode } from './stock-types'\n\n// ---------------------------------------------------------------------------\n// THE SHOPIFY MAPPING, AS CODE.\n//\n// Founder decision, 2026-08-03: \"vamos padrão Shopify\". Wherever we had a free\n// choice of shape, we took Shopify's, so a future connector maps 1:1 with no\n// translation table. Where the shape was NOT free — because materialising\n// Shopify's placeholder would be visible on our surfaces in a way it is not on\n// theirs — we kept the semantics and published the constant here instead of\n// leaving it as prose in a migration header.\n//\n// This file is deliberately data, not logic: it is what a connector reads, what\n// migrations.test.ts pins, and what a reviewer checks against Shopify's docs.\n// It has no dependency on the store, the ledger or Supabase.\n//\n// WHERE WE GO BEYOND SHOPIFY, WE KEEP IT. Shopify has no native lot/batch,\n// expiry or serial tracking — merchants buy third-party apps for both — and our\n// lot + expiresAt + FEFO + serial layer is exactly what artorious (smoked meat,\n// where expiry must drive picking and a recall must be answerable) and\n// cristinarotondaro (every piece one-of-one) need. \"Padrão Shopify\" means\n// compatible-by-default, never limited-to. Everything below that has no Shopify\n// counterpart says so explicitly rather than being quietly omitted.\n// ---------------------------------------------------------------------------\n\n/**\n * Shopify auto-creates one variant per option-less product, titled\n * \"Default Title\", under a single option axis named \"Title\". We carry the\n * SEMANTICS in `plg_shop_product_variants.is_default_variant` and the\n * PLACEHOLDER STRINGS nowhere — because in our schema `plg_shop_product_options`\n * is what renders the PDP picker and `plg_shop_product_variants.options` is what\n * names the order line, so materialising them would be visible in exactly the\n * two places the model must not touch. Shopify hides its placeholder in the\n * theme (`product.has_only_default_variant`); we never create it.\n *\n * A connector writes these constants; it does not read them from a row.\n */\nexport const SHOPIFY_DEFAULT_OPTION_NAME = 'Title'\nexport const SHOPIFY_DEFAULT_VARIANT_TITLE = 'Default Title'\n\n/**\n * `is_default_variant = true` ⟺ Shopify's `has_only_default_variant`. The whole\n * translation, in one predicate.\n */\nexport function toShopifyVariantTitle(isDefaultVariant: boolean, optionsLabel: string | null): string {\n return isDefaultVariant || !optionsLabel ? SHOPIFY_DEFAULT_VARIANT_TITLE : optionsLabel\n}\n\n/** The option axes Shopify would report for a product with no real ones. */\nexport function shopifyDefaultOptions(): { name: string; values: string[] }[] {\n return [{ name: SHOPIFY_DEFAULT_OPTION_NAME, values: [SHOPIFY_DEFAULT_VARIANT_TITLE] }]\n}\n\n// --- Quantity states ----------------------------------------------------------\n\n/**\n * Shopify's inventory quantity names → ours.\n *\n * `committed` is the only genuine synonym, and it is the one place we chose to\n * keep OUR word in the schema: `reserved` is what 0034 shipped, what the\n * contract suite, the SQL regression, the mirror and the mock all assert on, and\n * renaming a landed green column for a synonym is churn. Instead the\n * `plg_shop_stock_levels` view publishes BOTH — `reserved` and `committed` —\n * so the connector reads Shopify's name and nothing internal moved.\n */\nexport const SHOPIFY_QUANTITY_STATES: readonly {\n shopify: string\n ours: string | null\n note: string\n}[] = [\n { shopify: 'available', ours: 'available', note: 'identical (on_hand − reserved)' },\n { shopify: 'on_hand', ours: 'on_hand', note: 'identical' },\n {\n shopify: 'committed',\n ours: 'reserved',\n note: 'same concept; plg_shop_stock_levels publishes both names',\n },\n {\n shopify: 'incoming',\n ours: null,\n note: 'modelled as a PLACE — a balance in a location with is_sellable = false (kind \"transit\") — which is strictly more expressive than one number',\n },\n {\n shopify: 'damaged',\n ours: null,\n note: 'modelled as a `loss` movement with reason_code \"damaged\": carries when, who and how many, where Shopify has a bucket',\n },\n {\n shopify: 'quality_control',\n ours: null,\n note: 'modelled as a lot with status \"quarantined\" — a BATCH under inspection, not a quantity',\n },\n {\n shopify: 'safety_stock',\n ours: null,\n note: 'NOT MODELLED. Reorder point and low-stock threshold are forecasting, which inventory-model.md §8 puts out of scope on purpose',\n },\n]\n\n// --- Adjustment reasons -------------------------------------------------------\n\n/**\n * Shopify's adjustment-reason vocabulary is CLOSED. Ours is rows and stays open\n * (spine I9). Every Shopify reason must therefore land on one of ours without\n * loss, or a connector needs a translation table with holes in it. Migration\n * 0038 seeds the five rows that were missing.\n *\n * `null` means \"there is no movement to write\" and is not a gap — see the note.\n */\nexport const SHOPIFY_ADJUSTMENT_REASONS: readonly {\n shopify: string\n reasonCode: string | null\n movementKind: string | null\n note?: string\n}[] = [\n { shopify: 'correction', reasonCode: 'correction', movementKind: 'adjustment' },\n { shopify: 'cycle_count_available', reasonCode: 'cycle_count', movementKind: 'count' },\n { shopify: 'received', reasonCode: 'received', movementKind: 'receipt' },\n { shopify: 'damaged', reasonCode: 'damaged', movementKind: 'loss' },\n { shopify: 'quality_control', reasonCode: 'quality_control', movementKind: 'adjustment' },\n { shopify: 'promotion', reasonCode: 'promotion', movementKind: 'loss' },\n { shopify: 'movement_created', reasonCode: 'transfer', movementKind: 'transfer_out' },\n { shopify: 'movement_received', reasonCode: 'transfer', movementKind: 'transfer_in' },\n { shopify: 'movement_updated', reasonCode: 'transfer', movementKind: 'transfer_in' },\n { shopify: 'movement_canceled', reasonCode: 'correction', movementKind: 'adjustment' },\n { shopify: 'other', reasonCode: 'other', movementKind: null },\n {\n shopify: 'reservation_created',\n reasonCode: null,\n movementKind: null,\n note: 'NOT a movement. A hold is a row in plg_shop_stock_reservations with a status and a TTL — a lifecycle, not an entry in an append-only ledger. Recording it as a movement is what forces Shopify to have a reason code for it at all.',\n },\n]\n\n/** The reason code a Shopify adjustment reason maps to, or null when it is not a movement. */\nexport function shopifyReasonToStockReason(shopifyReason: string): string | null {\n const row = SHOPIFY_ADJUSTMENT_REASONS.find((entry) => entry.shopify === shopifyReason)\n if (!row) {\n throw new Error(\n `shopifyReasonToStockReason: unknown Shopify reason \"${shopifyReason}\". Known reasons: ${SHOPIFY_ADJUSTMENT_REASONS.map((entry) => entry.shopify).join(', ')}`,\n )\n }\n return row.reasonCode\n}\n\n// --- What Shopify cannot express ----------------------------------------------\n\n/**\n * Named so nobody \"simplifies\" them away in the name of Shopify parity. Each\n * one is a fleet requirement, not a luxury.\n */\nexport const BEYOND_SHOPIFY: readonly { feature: string; why: string }[] = [\n {\n feature: 'lot / batch tracking with expires_at',\n why: 'artorious sells smoked meat: FEFO picking and an answerable recall are regulatory, not optional. Shopify has no native lots.',\n },\n {\n feature: 'FEFO / FIFO / LIFO / manual allocation as data',\n why: 'Shopify allocates per location only. Which BATCH leaves the shelf is the question a food store actually asks.',\n },\n {\n feature: 'serial tracking bounded to {0,1} per lot',\n why: 'cristinarotondaro: every piece is one-of-one. Shopify has no native serials.',\n },\n {\n feature: 'per-variant tracking policy (none | quantity | lot | serial)',\n why: 'One model has to express all six fleet stores without a code fork, and the default must cost a simple store nothing.',\n },\n {\n feature: 'unit_cost on the lot and on the movement',\n why: 'Margin and CMV are derivable. Shopify keeps cost on the InventoryItem only, with no history.',\n },\n]\n\n/** Tracking modes that have no Shopify equivalent — kept deliberately. */\nexport const TRACKING_MODES_BEYOND_SHOPIFY: readonly StockTrackingMode[] = ['lot', 'serial']\n","// Physical table names for @fayz-ai/shop. Renamed to the plg_shop_* industry-pool\n// prefix (was shop_*) when the core DB moved into the public schema. RPC function\n// names (shop_place_order, shop_get_order, shop_resolve_customer) are unchanged.\nexport const T = {\n products: 'plg_shop_products',\n productImages: 'plg_shop_product_images',\n productOptions: 'plg_shop_product_options',\n productVariants: 'plg_shop_product_variants',\n categories: 'plg_shop_categories',\n orders: 'plg_shop_orders',\n orderItems: 'plg_shop_order_items',\n customers: 'plg_shop_customers',\n discounts: 'plg_shop_discounts',\n salesChannels: 'plg_shop_channels',\n // Collections, gift cards and customer groups/segments (migrations 0040-0043).\n // None of them touch the stock ledger or variants.\n collections: 'plg_shop_collections',\n collectionProducts: 'plg_shop_collection_products',\n giftCards: 'plg_shop_gift_cards',\n // Message customisations live in the automations table, not a shop-owned one:\n // the store's emails are events in the same catalog every other module writes\n // to. `plg_shop_email_templates` (0042) is the retired shape — plugin-automations\n // migration 0001 copied its rows over and nothing writes to it anymore.\n messageTemplates: 'plg_automations_templates',\n customerGroups: 'plg_shop_customer_groups',\n customerGroupMembers: 'plg_shop_customer_group_members',\n customerSegments: 'plg_shop_customer_segments',\n /** Public bucket the media library and product photos both live in. */\n mediaBucket: 'shop-images',\n // The inventory ledger (migrations 0034-0036). stockBalances is DERIVED: it is\n // read here and never written, because the only legitimate writers are 0034's\n // SECURITY DEFINER triggers — which is why that table deliberately has no RLS\n // write policy at all.\n stockMovementKinds: 'plg_shop_stock_movement_kinds',\n stockReasonCodes: 'plg_shop_stock_reason_codes',\n stockLocations: 'plg_shop_stock_locations',\n stockLots: 'plg_shop_stock_lots',\n stockMovements: 'plg_shop_stock_movements',\n stockReservations: 'plg_shop_stock_reservations',\n stockBalances: 'plg_shop_stock_balances',\n // Allocation and the reservation lifecycle (0038). The strategies and TTLs are\n // VOCABULARY — rows, not enums (I9) — so an agency widens either with an\n // INSERT. stockLevels is a VIEW: our (variant, lot, location) balances\n // projected to (variant, location), which is Shopify's InventoryLevel shape\n // and what a connector syncs.\n stockAllocationStrategies: 'plg_shop_stock_allocation_strategies',\n stockReservationTtls: 'plg_shop_stock_reservation_ttls',\n stockLevels: 'plg_shop_stock_levels',\n // Traceability (0039): which lot filled which order line. A join table, not a\n // jsonb column, because the query that matters runs BACKWARDS.\n orderItemLots: 'plg_shop_order_item_lots',\n // Tenant-level shop settings (0029). stock_ownership = 'external' means an\n // ERP owns the numbers and our ledger is not authoritative for that store.\n settings: 'plg_shop_settings',\n // Core, not plg_shop_*: a delivery zone is a fact about the business, and\n // fulfilment and financial read it too. Same reasoning as addresses and\n // orders — see migration 0021.\n shippingZones: 'shipping_zones',\n // The store-wide delivery fallback (0015). Core for the same reason zones\n // are: what a business charges to deliver is not a fact about a plugin.\n shippingSettings: 'shipping_settings',\n shippingProfiles: 'plg_shop_shipping_profiles',\n // plg_*, unlike the two above: which boxes a store keeps on the shelf is a\n // fact about running this shop, not about the business. Nothing outside the\n // freight quote reads it.\n shippingPackages: 'plg_shop_packages',\n} as const\n","import { getSupabaseClientOptional } from '@fayz-ai/core'\nimport { getShopTenantId } from '../data/tenant'\nimport { T } from '../data/tables'\nimport { StockMovementError, mirroredInventoryCount } from './stock-store'\nimport type { StockStore } from './stock-store'\nimport { validateStockMovement } from './vocabulary'\nimport type {\n ListStockBalancesOptions,\n ListStockLotsOptions,\n ListStockMovementsOptions,\n RecordStockMovementInput,\n ReserveStockInput,\n StockAllocation,\n StockAllocationRequest,\n StockBalance,\n StockLocation,\n StockLot,\n StockMovement,\n StockReservation,\n StockReservationStatus,\n StockTrackingMode,\n} from './stock-types'\n\n// ---------------------------------------------------------------------------\n// The Supabase StockStore — the canonical implementation of the port, over the\n// plg_shop_stock_* tables from migrations 0034-0036.\n//\n// House pattern is supabase-provider.ts, followed exactly: the same optional\n// global client, the same `getShopTenantId()` scoping, the same\n// `if (error) throw error` style, the same snake_case→camelCase row mappers.\n//\n// WHAT THIS FILE DOES NOT DO, and why that is the design rather than an\n// omission:\n//\n// * It never writes plg_shop_stock_balances. That table is DERIVED and 0034\n// deliberately gives it no RLS write policy at all — the only legitimate\n// writers are the SECURITY DEFINER triggers. A store that \"kept the balance\n// up to date\" would be a second truth, which is the exact thing the ledger\n// replaces.\n// * It never writes plg_shop_product_variants.inventory_count. That column is\n// 0036's mirror. Writing it would go through the I10 shim and translate\n// back into a movement — the long way round to the row we are already\n// inserting.\n// * It never allocates or reserves IN TYPESCRIPT. §9 step 4 has landed, so the\n// verbs exist — but every one of them is an RPC onto the SQL in 0038, for\n// the reason §4 gives: allocation runs inside the SECURITY DEFINER trust\n// boundary, because stock that can be allocated from the client is stock\n// that can be lied about. A second allocator here would race the first with\n// no lock between them.\n// * It never touches shop_place_order, which owns the checkout path outright.\n//\n// So the write surface is: APPEND A MOVEMENT (what a receiving screen, a CSV\n// import and an ERP connector need — §10 q4 names receiving as the first thing a\n// real store touches), plus three thin RPC wrappers over allocation and the\n// reservation lifecycle.\n//\n// THE VALIDATOR RUNS HERE TOO. 0034's shop_validate_stock_movement() is the\n// authority and it cannot be bypassed; validateStockMovement() runs first\n// anyway, for the same reason supabase-entity-store.ts gates writes that RLS\n// would also refuse: the client-side refusal names the valid set (I2) and costs\n// no round trip, while the server-side one is what makes it true.\n// ---------------------------------------------------------------------------\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nfunction getDb(): any {\n const supabase = getSupabaseClientOptional()\n if (!supabase) throw new Error('@fayz-ai/shop: Supabase client not initialized. Call setGlobalSupabaseClient() first.')\n return supabase\n}\n\n// Exported so the admin CRUD in supabase-provider.ts reads the row the same way\n// the ledger does — one mapper, two callers, nothing to drift.\nexport function rowToStockLocation(row: any): StockLocation {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n code: row.code,\n name: row.name,\n kind: row.kind ?? 'store',\n isSellable: row.is_sellable ?? true,\n isDefault: row.is_default ?? false,\n status: row.status ?? 'active',\n postalCode: row.postal_code ?? null,\n city: row.city ?? null,\n state: row.state ?? null,\n street: row.street ?? null,\n number: row.number ?? null,\n district: row.district ?? null,\n complement: row.complement ?? null,\n document: row.document ?? null,\n phone: row.phone ?? null,\n email: row.email ?? null,\n carrierAgencies: row.carrier_agencies ?? null,\n shipsOnline: row.ships_online ?? true,\n fulfillmentProvider: row.fulfillment_provider ?? null,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n}\n\nconst rowToLocation = rowToStockLocation\n\nfunction rowToLot(row: any): StockLot {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n variantId: row.variant_id,\n lotCode: row.lot_code,\n serial: row.serial ?? null,\n manufacturedAt: row.manufactured_at ?? null,\n expiresAt: row.expires_at ?? null,\n receivedAt: row.received_at,\n // numeric(12,4) arrives as a string on the wire; Number() once, here, so no\n // caller ever adds a cost to a string and gets concatenation.\n unitCost: row.unit_cost == null ? null : Number(row.unit_cost),\n supplierRef: row.supplier_ref ?? null,\n status: row.status ?? 'active',\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n}\n\nfunction rowToMovement(row: any): StockMovement {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n variantId: row.variant_id ?? null,\n productId: row.product_id ?? null,\n locationId: row.location_id,\n lotId: row.lot_id ?? null,\n kind: row.kind,\n reasonCode: row.reason_code ?? null,\n quantity: Number(row.quantity),\n unitCost: row.unit_cost == null ? null : Number(row.unit_cost),\n orderId: row.order_id ?? null,\n reservationId: row.reservation_id ?? null,\n idempotencyKey: row.idempotency_key ?? null,\n occurredAt: row.occurred_at,\n createdBy: row.created_by ?? null,\n note: row.note ?? null,\n createdAt: row.created_at,\n }\n}\n\nfunction rowToBalance(row: any): StockBalance {\n const onHand = Number(row.on_hand ?? 0)\n const reserved = Number(row.reserved ?? 0)\n return {\n id: row.id,\n tenantId: row.tenant_id,\n variantId: row.variant_id,\n locationId: row.location_id,\n lotId: row.lot_id ?? null,\n onHand,\n reserved,\n // `available` is a STORED generated column in 0034. It is recomputed here\n // rather than trusted, so a projection that omitted the column cannot make\n // `available` silently read 0 — the one number the storefront depends on.\n available: row.available == null ? onHand - reserved : Number(row.available),\n updatedAt: row.updated_at,\n }\n}\n\nfunction rowToReservation(row: any): StockReservation {\n return {\n id: row.id,\n tenantId: row.tenant_id,\n variantId: row.variant_id,\n locationId: row.location_id,\n lotId: row.lot_id ?? null,\n quantity: Number(row.quantity),\n status: row.status ?? 'held',\n orderId: row.order_id ?? null,\n cartToken: row.cart_token ?? null,\n expiresAt: row.expires_at ?? null,\n idempotencyKey: row.idempotency_key ?? null,\n createdBy: row.created_by ?? null,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n}\n\n/** Postgres unique_violation — the idempotency index doing its job under a race. */\nconst UNIQUE_VIOLATION = '23505'\n\nexport class SupabaseStockStore implements StockStore {\n /**\n * An explicit tenant pins the store to one pool (what an ERP connector or a\n * background job needs); omitted, it resolves per call through the same\n * resolver every other plg_shop_* read uses.\n */\n constructor(private readonly explicitTenantId?: string) {}\n\n private tenantId(): string | undefined {\n return this.explicitTenantId ?? getShopTenantId()\n }\n\n private requireTenantId(operation: string): string {\n const tenantId = this.tenantId()\n if (!tenantId) {\n throw new Error(\n `@fayz-ai/shop: ${operation} requires a tenant id (configure the shop tenant resolver, or construct SupabaseStockStore with one).`,\n )\n }\n return tenantId\n }\n\n // --- reads ------------------------------------------------------------------\n\n async listLocations(): Promise<StockLocation[]> {\n const db = getDb()\n let q = db.from(T.stockLocations).select('*')\n const tenantId = this.tenantId()\n if (tenantId) q = q.eq('tenant_id', tenantId)\n // Default first, then a stable handle order — the shape a picker renders.\n q = q.order('is_default', { ascending: false }).order('code', { ascending: true })\n const { data, error } = await q\n if (error) throw error\n return (data ?? []).map(rowToLocation)\n }\n\n async getDefaultLocation(): Promise<StockLocation | null> {\n const db = getDb()\n let q = db.from(T.stockLocations).select('*').eq('is_default', true)\n const tenantId = this.tenantId()\n if (tenantId) q = q.eq('tenant_id', tenantId)\n const { data, error } = await q.maybeSingle()\n if (error) throw error\n return data ? rowToLocation(data) : null\n }\n\n /**\n * `sellableOnly` filters by an id set read from the locations table rather\n * than by an embedded `!inner` join. Locations are a handful of rows per\n * tenant, and the set is the same one mirroredInventoryCount() takes — so the\n * mock, this store and 0036's mirror all narrow \"sellable\" through one\n * definition instead of three query dialects.\n */\n async listBalances(options: ListStockBalancesOptions = {}): Promise<StockBalance[]> {\n const db = getDb()\n let q = db.from(T.stockBalances).select('*')\n const tenantId = this.tenantId()\n if (tenantId) q = q.eq('tenant_id', tenantId)\n if (options.variantId) q = q.eq('variant_id', options.variantId)\n if (options.variantIds) q = q.in('variant_id', options.variantIds)\n if (options.locationId) q = q.eq('location_id', options.locationId)\n if (options.lotId) q = q.eq('lot_id', options.lotId)\n if (options.sellableOnly) {\n const sellable = await this.sellableLocationIds()\n if (sellable.size === 0) return []\n q = q.in('location_id', [...sellable])\n }\n const { data, error } = await q\n if (error) throw error\n return (data ?? []).map(rowToBalance)\n }\n\n async getAvailable(variantId: string): Promise<number> {\n const [balances, sellable] = await Promise.all([\n this.listBalances({ variantId }),\n this.sellableLocationIds(),\n ])\n return mirroredInventoryCount(balances, sellable)\n }\n\n async listLots(options: ListStockLotsOptions = {}): Promise<StockLot[]> {\n const db = getDb()\n let q = db.from(T.stockLots).select('*')\n const tenantId = this.tenantId()\n if (tenantId) q = q.eq('tenant_id', tenantId)\n if (options.variantId) q = q.eq('variant_id', options.variantId)\n if (options.status) q = q.eq('status', options.status)\n if (options.expiresBefore) q = q.lte('expires_at', options.expiresBefore)\n if (options.fefo !== false) {\n // FEFO: soonest expiry first, then oldest received. nullsFirst:false is\n // load-bearing — Postgres sorts NULLs LAST on ASC by default but PostgREST\n // sends nullsfirst explicitly, and a lot with no expiry must never be\n // picked ahead of one that has a date.\n q = q\n .order('expires_at', { ascending: true, nullsFirst: false })\n .order('received_at', { ascending: true })\n }\n if (options.limit != null) q = q.limit(options.limit)\n const { data, error } = await q\n if (error) throw error\n return (data ?? []).map(rowToLot)\n }\n\n async listMovements(options: ListStockMovementsOptions = {}): Promise<StockMovement[]> {\n const db = getDb()\n let q = db.from(T.stockMovements).select('*')\n const tenantId = this.tenantId()\n if (tenantId) q = q.eq('tenant_id', tenantId)\n if (options.variantId) q = q.eq('variant_id', options.variantId)\n if (options.lotId) q = q.eq('lot_id', options.lotId)\n if (options.orderId) q = q.eq('order_id', options.orderId)\n if (options.kind) q = q.eq('kind', options.kind)\n if (options.reasonCode) q = q.eq('reason_code', options.reasonCode)\n const ascending = options.newestFirst === false\n // occurred_at is WHEN it happened and is routinely backdated, so it ties.\n // created_at breaks the tie, which is what makes \"the order I wrote them in\"\n // reproducible for a stock count entered in one batch.\n q = q.order('occurred_at', { ascending }).order('created_at', { ascending })\n if (options.limit != null) q = q.limit(options.limit)\n const { data, error } = await q\n if (error) throw error\n return (data ?? []).map(rowToMovement)\n }\n\n async listReservations(variantId?: string): Promise<StockReservation[]> {\n const db = getDb()\n let q = db.from(T.stockReservations).select('*')\n const tenantId = this.tenantId()\n if (tenantId) q = q.eq('tenant_id', tenantId)\n if (variantId) q = q.eq('variant_id', variantId)\n q = q.order('created_at', { ascending: true })\n const { data, error } = await q\n if (error) throw error\n return (data ?? []).map(rowToReservation)\n }\n\n // --- append -----------------------------------------------------------------\n\n /**\n * Append to the ledger. Never an update — a mistake is corrected by an\n * opposing movement.\n *\n * IDEMPOTENCY IS TWO MECHANISMS, not one, and the second is the real one:\n *\n * 1. A pre-read on (tenant_id, idempotency_key) returns the existing\n * movement. This is the ordinary retry — same caller, seconds later —\n * and it costs one cheap indexed SELECT.\n * 2. A `23505` on the INSERT is caught and re-read. This is the race the\n * pre-read cannot cover: two retries in flight at once both miss the\n * SELECT and both attempt the INSERT. 0034's partial unique index\n * plg_shop_stock_movements_idempotency_key is what turns the loser into\n * an error we can recognise instead of a second decrement.\n *\n * Without (2) a retried place_order under load decrements twice, which is\n * precisely the failure the idempotency key exists to prevent.\n */\n async recordMovement(input: RecordStockMovementInput): Promise<StockMovement> {\n const db = getDb()\n const tenantId = this.requireTenantId('recordMovement')\n\n if (input.idempotencyKey) {\n const existing = await this.findByIdempotencyKey(input.idempotencyKey)\n if (existing) return existing\n }\n\n const variant = await this.readVariant(input.variantId)\n if (!variant) {\n throw new StockMovementError(`stock movement: variant ${input.variantId} not found`, input)\n }\n if (variant.tenantId !== tenantId) {\n throw new StockMovementError(\n `stock movement: variant ${input.variantId} belongs to another store`,\n input,\n )\n }\n\n const lot = input.lotId ? await this.readLot(input.lotId) : null\n\n try {\n validateStockMovement(input, {\n tracking: variant.tracking,\n lot,\n // Summed over EVERY location: a serial is one physical unit in the whole\n // store, so moving it between locations must not let a second copy\n // appear. Same predicate as 0034's SELECT, and read only when it can\n // matter, so the quantity-tracked common case costs nothing.\n lotOnHand: lot && variant.tracking === 'serial' ? await this.lotOnHand(lot.id) : undefined,\n })\n } catch (error) {\n throw new StockMovementError((error as Error).message, input)\n }\n\n // An explicitly named location must belong to this store. Omitted, the\n // column is sent NULL and 0034's BEFORE INSERT trigger fills it with\n // shop_default_stock_location() — creating the tenant's default on demand,\n // under an ON CONFLICT that two concurrent first-movements cannot lose. We\n // deliberately do NOT reimplement that race here.\n let locationId = input.locationId ?? null\n if (locationId) {\n const known = await this.listLocations()\n if (!known.some((location) => location.id === locationId)) {\n throw new StockMovementError(\n `stock movement: location ${locationId} does not belong to store ${tenantId}`,\n input,\n )\n }\n } else {\n locationId = (await this.getDefaultLocation())?.id ?? null\n }\n\n const payload = {\n tenant_id: tenantId,\n variant_id: input.variantId,\n location_id: locationId,\n lot_id: input.lotId ?? null,\n kind: input.kind,\n reason_code: input.reasonCode ?? null,\n quantity: input.quantity,\n unit_cost: input.unitCost ?? null,\n order_id: input.orderId ?? null,\n reservation_id: input.reservationId ?? null,\n idempotency_key: input.idempotencyKey ?? null,\n ...(input.occurredAt !== undefined ? { occurred_at: input.occurredAt } : {}),\n note: input.note ?? null,\n // product_id is denormalised by the validator trigger from the variant,\n // so the ledger row still names its product after an ON DELETE SET NULL.\n }\n\n const { data, error } = await db.from(T.stockMovements).insert(payload).select().single()\n\n if (error) {\n if (error.code === UNIQUE_VIOLATION && input.idempotencyKey) {\n const winner = await this.findByIdempotencyKey(input.idempotencyKey)\n if (winner) return winner\n }\n // Every other failure is the ledger REFUSING the movement — the validator\n // trigger, a foreign key, RLS. It is raised, never swallowed: a movement\n // that is dropped instead of refused is stock that vanishes.\n throw new StockMovementError((error as Error).message ?? String(error), input)\n }\n return rowToMovement(data)\n }\n\n // --- allocation and the reservation lifecycle (§9 step 4) ---------------------\n //\n // All three go through an RPC rather than being computed here, and that is the\n // whole design rather than a shortcut. §4: allocation runs IN POSTGRES, inside\n // the SECURITY DEFINER trust boundary, because \"stock that can be allocated\n // from the client is stock that can be lied about\". A TypeScript\n // implementation that read balances and picked lots itself would be a second\n // allocator racing the first — two answers to \"which batch leaves the shelf\",\n // with no lock between them.\n //\n // The pure ordering in allocation.ts is the SPECIFICATION both sides share and\n // what the mock executes; this class calls the authority.\n\n async allocate(request: Omit<StockAllocationRequest, 'tracking'>): Promise<StockAllocation[]> {\n const db = getDb()\n const tenantId = this.requireTenantId('allocate')\n const { data, error } = await db.rpc('shop_allocate_stock', {\n p_tenant_id: tenantId,\n p_variant_id: request.variantId,\n p_quantity: request.quantity,\n p_location_id: request.locationId ?? null,\n p_strategy: request.strategy ?? null,\n p_lot_id: request.lotId ?? null,\n })\n if (error) throw new Error((error as Error).message ?? String(error))\n return (data ?? []).map((row: any) => ({\n lotId: row.lot_id ?? null,\n locationId: row.location_id,\n quantity: Number(row.quantity),\n }))\n }\n\n async reserve(input: ReserveStockInput): Promise<StockReservation> {\n const db = getDb()\n const tenantId = this.requireTenantId('reserve')\n const { data, error } = await db.rpc('shop_reserve_stock', {\n p_tenant_id: tenantId,\n p_variant_id: input.variantId,\n p_quantity: input.quantity,\n p_location_id: input.locationId,\n p_lot_id: input.lotId ?? null,\n p_order_id: input.orderId ?? null,\n p_cart_token: input.cartToken ?? null,\n // Postgres parses an ISO-8601 interval literal; minutes keeps the port's\n // surface a number rather than a Postgres dialect.\n p_ttl: input.ttlMinutes == null ? null : `${input.ttlMinutes} minutes`,\n p_idempotency_key: input.idempotencyKey ?? null,\n })\n if (error) throw new Error((error as Error).message ?? String(error))\n const id = typeof data === 'string' ? data : data?.[0]\n const rows = await this.listReservations(input.variantId)\n const created = rows.find((row) => row.id === id)\n if (!created) throw new Error(`shop_reserve_stock: reservation ${id} could not be read back`)\n return created\n }\n\n async setReservationStatus(reservationId: string, status: StockReservationStatus): Promise<void> {\n const db = getDb()\n let q = db.from(T.stockReservations).update({ status }).eq('id', reservationId)\n const tenantId = this.tenantId()\n if (tenantId) q = q.eq('tenant_id', tenantId)\n const { error } = await q\n if (error) throw error\n }\n\n async sweepExpiredReservations(variantId?: string): Promise<number> {\n const db = getDb()\n const tenantId = this.requireTenantId('sweepExpiredReservations')\n const { data, error } = await db.rpc('shop_sweep_stock_reservations', {\n p_tenant_id: tenantId,\n p_variant_id: variantId ?? null,\n })\n if (error) throw new Error((error as Error).message ?? String(error))\n return Number(Array.isArray(data) ? (data[0] ?? 0) : (data ?? 0))\n }\n\n // --- helpers ------------------------------------------------------------------\n\n private async findByIdempotencyKey(key: string): Promise<StockMovement | null> {\n const db = getDb()\n let q = db.from(T.stockMovements).select('*').eq('idempotency_key', key)\n const tenantId = this.tenantId()\n if (tenantId) q = q.eq('tenant_id', tenantId)\n const { data, error } = await q.maybeSingle()\n if (error) throw error\n return data ? rowToMovement(data) : null\n }\n\n /** The variant facts the validator needs — tracking is 0034's new column. */\n private async readVariant(\n variantId: string,\n ): Promise<{ id: string; tenantId: string; productId: string | null; tracking: StockTrackingMode } | null> {\n const { data, error } = await getDb()\n .from(T.productVariants)\n .select('id,tenant_id,product_id,tracking')\n .eq('id', variantId)\n .maybeSingle()\n if (error) throw error\n if (!data) return null\n return {\n id: data.id,\n tenantId: data.tenant_id,\n productId: data.product_id ?? null,\n tracking: (data.tracking ?? 'quantity') as StockTrackingMode,\n }\n }\n\n private async readLot(\n lotId: string,\n ): Promise<{ id: string; variantId: string; serial: string | null } | null> {\n const { data, error } = await getDb()\n .from(T.stockLots)\n .select('id,variant_id,serial')\n .eq('id', lotId)\n .maybeSingle()\n if (error) throw error\n if (!data) return null\n return { id: data.id, variantId: data.variant_id, serial: data.serial ?? null }\n }\n\n /** on_hand for one lot across every location — the serial-bound predicate. */\n private async lotOnHand(lotId: string): Promise<number> {\n const rows = await this.listBalances({ lotId })\n return rows.reduce((sum, row) => sum + row.onHand, 0)\n }\n\n private async sellableLocationIds(): Promise<Set<string>> {\n const locations = await this.listLocations()\n return new Set(\n locations.filter((location) => location.isSellable && location.status === 'active').map((l) => l.id),\n )\n }\n}\n\nexport function createSupabaseStockStore(tenantId?: string): StockStore {\n return new SupabaseStockStore(tenantId)\n}\n","import {\n StockMovementError,\n mirroredInventoryCount,\n replayStockLedger,\n stockBalanceKey,\n} from './stock-store'\nimport type { StockStore } from './stock-store'\nimport { validateStockMovement } from './vocabulary'\nimport { allocateStock } from './allocation'\nimport { DEFAULT_STOCK_TRACKING } from './stock-types'\nimport type {\n ListStockBalancesOptions,\n ListStockLotsOptions,\n ListStockMovementsOptions,\n RecordStockMovementInput,\n ReserveStockInput,\n StockAllocation,\n StockAllocationCandidate,\n StockAllocationRequest,\n StockBalance,\n StockLocation,\n StockLot,\n StockMovement,\n StockReservation,\n StockTrackingMode,\n} from './stock-types'\n\n// ---------------------------------------------------------------------------\n// The in-memory StockStore. It is not a stub: it runs the SAME validator and\n// the SAME ledger→balance arithmetic as the SQL, so the behavioural claims in\n// stock-store.test.ts (\"balance follows the ledger\", \"the mirror follows the\n// balance\", \"a movement can never be silently lost\") are asserted against the\n// real rules rather than a convenient imitation.\n//\n// What it deliberately does NOT model: RLS, concurrency, and the GRANT layer.\n// Those are properties of Postgres and are proven in\n// packages/shop/test/stock-ledger.regression.sql.\n// ---------------------------------------------------------------------------\n\nexport interface MockVariantSeed {\n id: string\n tenantId?: string\n productId?: string | null\n tracking?: StockTrackingMode\n /** Starting mirror value. The seed writes NO movement for it — the opening\n * balance is 0035's job and tests exercise it explicitly. */\n inventoryCount?: number\n}\n\nexport interface MockStockSeed {\n tenantId?: string\n variants?: MockVariantSeed[]\n locations?: Partial<StockLocation>[]\n lots?: Partial<StockLot>[]\n}\n\nconst TENANT = 'mock-tenant'\n\nlet counter = 0\nfunction nextId(prefix: string): string {\n counter += 1\n return `${prefix}-${String(counter).padStart(4, '0')}`\n}\n\nconst ISO = '2026-01-01T00:00:00.000Z'\n\n/**\n * An in-memory stock ledger. `variants` is the mirror surface: every recorded\n * movement updates `inventoryCount` through the same projection the 0036\n * trigger performs, so a test can assert the mirror without a database.\n */\nexport class MockStockStore implements StockStore {\n readonly tenantId: string\n private readonly locations: StockLocation[] = []\n private readonly lots: StockLot[] = []\n private readonly movements: StockMovement[] = []\n private readonly reservations: StockReservation[] = []\n private readonly variants = new Map<\n string,\n { id: string; tenantId: string; productId: string | null; tracking: StockTrackingMode; inventoryCount: number }\n >()\n\n constructor(seed: MockStockSeed = {}) {\n this.tenantId = seed.tenantId ?? TENANT\n\n const seededLocations = seed.locations ?? []\n if (!seededLocations.some((l) => l.isDefault)) {\n this.locations.push(this.makeLocation({ code: 'default', name: 'Estoque principal', isDefault: true }))\n }\n for (const location of seededLocations) this.locations.push(this.makeLocation(location))\n\n for (const variant of seed.variants ?? []) {\n this.variants.set(variant.id, {\n id: variant.id,\n tenantId: variant.tenantId ?? this.tenantId,\n productId: variant.productId ?? null,\n tracking: variant.tracking ?? DEFAULT_STOCK_TRACKING,\n inventoryCount: variant.inventoryCount ?? 0,\n })\n }\n\n for (const lot of seed.lots ?? []) {\n this.lots.push({\n id: lot.id ?? nextId('lot'),\n tenantId: lot.tenantId ?? this.tenantId,\n variantId: lot.variantId ?? '',\n lotCode: lot.lotCode ?? nextId('LOT'),\n serial: lot.serial ?? null,\n manufacturedAt: lot.manufacturedAt ?? null,\n expiresAt: lot.expiresAt ?? null,\n receivedAt: lot.receivedAt ?? ISO,\n unitCost: lot.unitCost ?? null,\n supplierRef: lot.supplierRef ?? null,\n status: lot.status ?? 'active',\n createdAt: ISO,\n updatedAt: ISO,\n })\n }\n }\n\n private makeLocation(partial: Partial<StockLocation>): StockLocation {\n return {\n id: partial.id ?? nextId('loc'),\n tenantId: partial.tenantId ?? this.tenantId,\n code: partial.code ?? nextId('code'),\n name: partial.name ?? 'Local',\n kind: partial.kind ?? 'store',\n isSellable: partial.isSellable ?? true,\n isDefault: partial.isDefault ?? false,\n status: partial.status ?? 'active',\n createdAt: ISO,\n updatedAt: ISO,\n }\n }\n\n // --- reads ------------------------------------------------------------------\n\n async listLocations(): Promise<StockLocation[]> {\n return [...this.locations].sort((a, b) => Number(b.isDefault) - Number(a.isDefault))\n }\n\n async getDefaultLocation(): Promise<StockLocation | null> {\n return this.locations.find((l) => l.isDefault) ?? null\n }\n\n async listBalances(options: ListStockBalancesOptions = {}): Promise<StockBalance[]> {\n const replayed = replayStockLedger(this.movements, this.reservations)\n const sellable = new Set(this.locations.filter((l) => l.isSellable && l.status === 'active').map((l) => l.id))\n const rows: StockBalance[] = []\n for (const [key, row] of replayed) {\n if (options.variantId && row.variantId !== options.variantId) continue\n if (options.variantIds && !options.variantIds.includes(row.variantId)) continue\n if (options.locationId && row.locationId !== options.locationId) continue\n if (options.lotId && row.lotId !== options.lotId) continue\n if (options.sellableOnly && !sellable.has(row.locationId)) continue\n rows.push({\n id: key,\n tenantId: row.tenantId || this.tenantId,\n variantId: row.variantId,\n locationId: row.locationId,\n lotId: row.lotId,\n onHand: row.onHand,\n reserved: row.reserved,\n available: row.onHand - row.reserved,\n updatedAt: ISO,\n })\n }\n return rows.sort((a, b) => a.id.localeCompare(b.id))\n }\n\n async getAvailable(variantId: string): Promise<number> {\n const balances = await this.listBalances({ variantId })\n return mirroredInventoryCount(balances, this.sellableLocationIds())\n }\n\n async listLots(options: ListStockLotsOptions = {}): Promise<StockLot[]> {\n let rows = [...this.lots]\n if (options.variantId) rows = rows.filter((l) => l.variantId === options.variantId)\n if (options.status) rows = rows.filter((l) => l.status === options.status)\n if (options.expiresBefore) {\n rows = rows.filter((l) => l.expiresAt !== null && l.expiresAt <= options.expiresBefore!)\n }\n if (options.fefo !== false) {\n // FEFO: soonest expiry first, nulls last (a lot with no expiry never\n // beats one that does), then oldest received.\n rows.sort((a, b) => {\n if (a.expiresAt === b.expiresAt) return a.receivedAt.localeCompare(b.receivedAt)\n if (a.expiresAt === null) return 1\n if (b.expiresAt === null) return -1\n return a.expiresAt.localeCompare(b.expiresAt)\n })\n }\n return options.limit != null ? rows.slice(0, options.limit) : rows\n }\n\n async listMovements(options: ListStockMovementsOptions = {}): Promise<StockMovement[]> {\n let rows = [...this.movements]\n if (options.variantId) rows = rows.filter((m) => m.variantId === options.variantId)\n if (options.lotId) rows = rows.filter((m) => m.lotId === options.lotId)\n if (options.orderId) rows = rows.filter((m) => m.orderId === options.orderId)\n if (options.kind) rows = rows.filter((m) => m.kind === options.kind)\n if (options.reasonCode) rows = rows.filter((m) => m.reasonCode === options.reasonCode)\n if (options.newestFirst !== false) rows.reverse()\n return options.limit != null ? rows.slice(0, options.limit) : rows\n }\n\n async listReservations(variantId?: string): Promise<StockReservation[]> {\n return variantId ? this.reservations.filter((r) => r.variantId === variantId) : [...this.reservations]\n }\n\n // --- append -----------------------------------------------------------------\n\n async recordMovement(input: RecordStockMovementInput): Promise<StockMovement> {\n // Idempotency first: a retried write must return the SAME movement, never\n // a second one. This is the property that lets place_order be retried.\n if (input.idempotencyKey) {\n const existing = this.movements.find((m) => m.idempotencyKey === input.idempotencyKey)\n if (existing) return existing\n }\n\n const variant = this.variants.get(input.variantId)\n if (!variant) {\n throw new StockMovementError(`stock movement: variant ${input.variantId} not found`, input)\n }\n\n const lot = input.lotId ? (this.lots.find((l) => l.id === input.lotId) ?? null) : null\n try {\n validateStockMovement(input, {\n tracking: variant.tracking,\n lot: lot ? { id: lot.id, variantId: lot.variantId, serial: lot.serial } : null,\n // Summed over EVERY location: a serial is one physical unit in the\n // whole store, so moving it between locations must not let a second\n // copy appear. Same predicate as the SQL validator's SELECT.\n lotOnHand: lot ? await this.lotOnHand(lot.id) : undefined,\n })\n } catch (error) {\n throw new StockMovementError((error as Error).message, input)\n }\n\n const locationId = input.locationId ?? (await this.getDefaultLocation())!.id\n if (!this.locations.some((l) => l.id === locationId)) {\n throw new StockMovementError(\n `stock movement: location ${locationId} does not belong to store ${this.tenantId}`,\n input,\n )\n }\n\n const movement: StockMovement = {\n id: nextId('mov'),\n tenantId: variant.tenantId,\n variantId: variant.id,\n productId: variant.productId,\n locationId,\n lotId: input.lotId ?? null,\n kind: input.kind,\n reasonCode: input.reasonCode ?? null,\n quantity: input.quantity,\n unitCost: input.unitCost ?? null,\n orderId: input.orderId ?? null,\n reservationId: input.reservationId ?? null,\n idempotencyKey: input.idempotencyKey ?? null,\n occurredAt: input.occurredAt ?? ISO,\n createdBy: null,\n note: input.note ?? null,\n createdAt: ISO,\n }\n this.movements.push(movement)\n await this.syncMirror(variant.id)\n return movement\n }\n\n // --- allocation and the reservation lifecycle (§9 step 4) ---------------------\n\n /**\n * Runs the SHARED allocateStock() over the mock's own balances and lots, so\n * \"fefo picked the right lot\" is asserted against the same ordering the SQL\n * executes rather than against a convenient imitation.\n */\n async allocate(request: Omit<StockAllocationRequest, 'tracking'>): Promise<StockAllocation[]> {\n const variant = this.variants.get(request.variantId)\n if (!variant) {\n throw new StockMovementError(`stock movement: variant ${request.variantId} not found`, {\n variantId: request.variantId,\n kind: 'sale',\n quantity: -request.quantity,\n })\n }\n // §5's opportunistic sweep, on the one variant we are about to read: an\n // expired hold must not block the transaction that would have released it.\n await this.sweepExpiredReservations(request.variantId)\n return allocateStock(\n { ...request, tracking: variant.tracking },\n await this.allocationCandidates(request.variantId, variant.tracking),\n )\n }\n\n private async allocationCandidates(\n variantId: string,\n tracking: StockTrackingMode,\n ): Promise<StockAllocationCandidate[]> {\n const balances = await this.listBalances({ variantId })\n const byId = new Map(this.locations.map((l) => [l.id, l]))\n return balances.map((balance) => {\n const lot = balance.lotId ? this.lots.find((l) => l.id === balance.lotId) : null\n const location = byId.get(balance.locationId)\n return {\n lotId: balance.lotId,\n locationId: balance.locationId,\n available: balance.onHand - balance.reserved,\n expiresAt: lot?.expiresAt ?? null,\n // A quantity-tracked variant's implicit lot has no receipt date of its\n // own; the ledger's own order stands in, and with one position it never\n // ties anything.\n receivedAt: lot?.receivedAt ?? ISO,\n isSellableLocation: (location?.isSellable ?? true) && (location?.status ?? 'active') === 'active',\n isDefaultLocation: location?.isDefault ?? false,\n }\n }).filter((candidate) => (tracking === 'quantity' ? candidate.lotId == null : true))\n }\n\n async reserve(input: ReserveStockInput): Promise<StockReservation> {\n if (input.idempotencyKey) {\n const existing = this.reservations.find((r) => r.idempotencyKey === input.idempotencyKey)\n if (existing) return existing\n }\n return this.addReservation({\n variantId: input.variantId,\n locationId: input.locationId,\n lotId: input.lotId ?? null,\n quantity: input.quantity,\n status: 'held',\n orderId: input.orderId ?? null,\n cartToken: input.cartToken ?? null,\n expiresAt:\n input.ttlMinutes == null\n ? null\n : new Date(Date.now() + input.ttlMinutes * 60_000).toISOString(),\n idempotencyKey: input.idempotencyKey ?? null,\n createdBy: null,\n })\n }\n\n async sweepExpiredReservations(variantId?: string): Promise<number> {\n const now = new Date().toISOString()\n let swept = 0\n for (const reservation of this.reservations) {\n if (reservation.status !== 'held') continue\n if (variantId && reservation.variantId !== variantId) continue\n if (!reservation.expiresAt || reservation.expiresAt > now) continue\n reservation.status = 'released'\n swept += 1\n await this.syncMirror(reservation.variantId)\n }\n return swept\n }\n\n // --- the parts a database would do for us ------------------------------------\n\n /** on_hand for one lot across every location — the serial-bound predicate. */\n private async lotOnHand(lotId: string): Promise<number> {\n const rows = await this.listBalances({ lotId })\n return rows.reduce((sum, row) => sum + row.onHand, 0)\n }\n\n private sellableLocationIds(): Set<string> {\n return new Set(this.locations.filter((l) => l.isSellable && l.status === 'active').map((l) => l.id))\n }\n\n /** The 0036 mirror, in memory. */\n private async syncMirror(variantId: string): Promise<void> {\n const variant = this.variants.get(variantId)\n if (!variant) return\n if (variant.tracking === 'none') return\n const balances = await this.listBalances({ variantId })\n if (balances.length === 0) return // never entered the ledger — leave it alone\n variant.inventoryCount = mirroredInventoryCount(balances, this.sellableLocationIds())\n }\n\n /** The mirror column, for assertions. */\n getInventoryCount(variantId: string): number | undefined {\n return this.variants.get(variantId)?.inventoryCount\n }\n\n /**\n * The 0036 I10 shim: a direct write to `inventory_count` is allowed, logged\n * and TRANSLATED into an adjustment movement carrying the DELTA, so the\n * ledger never diverges from the column every current writer still uses.\n * Returns the warning the SQL trigger would have raised.\n */\n async writeInventoryCountDirectly(variantId: string, value: number): Promise<string | null> {\n const variant = this.variants.get(variantId)\n if (!variant) throw new Error(`variant ${variantId} not found`)\n const delta = value - variant.inventoryCount\n if (delta === 0) return null\n if (variant.tracking === 'none') {\n variant.inventoryCount = value\n return null\n }\n if (variant.tracking === 'lot' || variant.tracking === 'serial') {\n throw new StockMovementError(\n `plg_shop_product_variants.inventory_count is a derived mirror: variant ${variantId} is ${variant.tracking}-tracked, so a direct write cannot say which lot it means.`,\n { variantId, kind: 'adjustment', quantity: delta },\n )\n }\n const warning = `DEPRECATED (I10): direct write to plg_shop_product_variants.inventory_count on variant ${variantId} (${variant.inventoryCount} -> ${value}). Translated to an adjustment movement; write plg_shop_stock_movements instead.`\n variant.inventoryCount = value\n await this.recordMovement({\n variantId,\n kind: 'adjustment',\n reasonCode: 'legacy_write',\n quantity: delta,\n })\n return warning\n }\n\n /** Rebuild balances by replaying the ledger — proof the balance is a cache. */\n async rebuildBalances(): Promise<StockBalance[]> {\n return this.listBalances()\n }\n\n /**\n * Seed a hold. The lifecycle itself is §9 step 4; this exists so\n * `available = onHand − reserved` is provable today.\n *\n * async, and the mirror is AWAITED rather than fired and forgotten: a\n * floating promise here meant `getInventoryCount()` read the pre-hold value\n * on the very next line, which is the assertion a reservation test makes.\n */\n async addReservation(\n reservation: Omit<StockReservation, 'id' | 'tenantId' | 'createdAt' | 'updatedAt'> & { id?: string },\n ): Promise<StockReservation> {\n const row: StockReservation = {\n // Spread FIRST: spreading last let an explicit `{ id: undefined }` win\n // over the generated id and produced a reservation with no identity.\n ...reservation,\n id: reservation.id ?? nextId('res'),\n tenantId: this.tenantId,\n createdAt: ISO,\n updatedAt: ISO,\n }\n this.reservations.push(row)\n await this.syncMirror(row.variantId)\n return row\n }\n\n /** Move a hold through its lifecycle, re-projecting the mirror. */\n async setReservationStatus(id: string, status: StockReservation['status']): Promise<void> {\n const row = this.reservations.find((r) => r.id === id)\n if (!row) throw new Error(`reservation ${id} not found`)\n row.status = status\n await this.syncMirror(row.variantId)\n }\n\n /** Every ledger row, in insertion order. Nothing is ever removed from it. */\n get ledger(): readonly StockMovement[] {\n return this.movements\n }\n\n /** The stock the variant was created with, unchanged by the mock. */\n getTracking(variantId: string): StockTrackingMode | undefined {\n return this.variants.get(variantId)?.tracking\n }\n\n /** Flip a variant's tracking policy (an admin action), for tests. */\n setTracking(variantId: string, tracking: StockTrackingMode): void {\n const variant = this.variants.get(variantId)\n if (!variant) throw new Error(`variant ${variantId} not found`)\n variant.tracking = tracking\n }\n\n /** The balance key helper, re-exported for assertions that group by it. */\n static key = stockBalanceKey\n}\n\nexport function createMockStockStore(seed: MockStockSeed = {}): MockStockStore {\n return new MockStockStore(seed)\n}\n"]}