# F-138 — Criterios de aceptación ## AC1 — Sembrado inmediato de precio Tras crear una variante, `GET /pricing/variants/:variantId` devuelve **200** (no 404) con una fila default: `netUnitAmountCents = 0`, `vatRate = 'general'`, `currency = 'EUR'`. - **Unit:** `CreateProductVariant.execute` llama a `PricingService.seedVariantPrice(variant.id)` tras `variants.create`. - **Itest (skip sin DB):** POST `/products/:id/variants` → GET `/pricing/variants/:variantId` = 200. ## AC2 — Idempotente (re-sembbrado no-op) Si la fila de precio ya existe, re-sembrar no lanza ni duplica: `ON CONFLICT (variant_id) DO NOTHING`. - **Unit:** segunda llamada a `seedVariantPrice` no arroja; `seedCalls` contiene el id una sola vez (o ambas, sin error). ## AC3 — Best-effort (no rompe la creación) Si `seedVariantPrice` lanza, `CreateProductVariant.execute` **sigue devolviendo la variante creada** (no propaga el error). - **Unit:** con `FakePricingService.seedShouldThrow = true`, `execute` devuelve el `ProductVariant` sin lanzar. ## AC4 — Los 3 call sites crean la variante con precio Los 3 puntos que crean variantes dejan fila de precio: 1. `POST /products` (autovariante `SKU-MV-{id}`). 2. `GET /products/:id/variants` (lazy, admin). 3. `POST /products/:id/variants`. - Todos comparten la misma instancia `createVariant` (inyecta `pricing`) → todos sembran. ## Gates - **reviewer:** arquitectura limpia (pricing owning su tabla; inyección de servicio público; build-app ordering safe). - **security:** SQL con parámetro (`$1`), literales `'general'`/`0`/`NULL` (no user input); no inyección. - **qa:** tests unitarios 3/3 verdes; `npm test` no rompe; tsc 0 errores; verify.sh green.