# TPV — Checkout, pagos mixtos y tickets > Implementado en F-186. Complementa `POS_API.md` y sustituye el flujo inmediato de pago único descrito en documentos de discovery antiguos. ## Configuración en administración En **Administración → TPV**, selecciona una tienda para configurar: ### Terminal - Navegación táctil por categorías. - Hasta **ocho** productos rápidos por terminal. - **Permitir descuentos por línea**. Desactívalo en terminales de autopago. La restricción se aplica también en backend, no solo ocultando el botón. ### Formas de pago Cada tienda puede activar o desactivar métodos con: - código estable (`cash`, `card`, `bizum`, `stripe`, `apple_pay`, etc.); - etiqueta visible; - tipo `cash`, `card` u `other`. Una etiqueta no integra automáticamente una pasarela. Stripe, Apple Pay, Bizum u otros métodos se registran manualmente hasta que exista un adaptador de proveedor. ### Empresa y ticket Configura: - nombre o razón social; - NIF/CIF; - dirección, teléfono y email; - cabecera y pie; - prefijo, próximo número y dígitos de relleno; - política de devolución. La asignación del siguiente número se bloquea dentro de la transacción de venta, evitando números duplicados entre terminales concurrentes. ## Flujo de caja 1. Añade productos de catálogo o un **Artículo libre** (nombre y precio positivo). 2. Aplica descuentos por línea si el terminal los permite. 3. Pulsa una forma de pago configurada. 4. En el modal elige: - **Paga el total**: asigna todo el importe pendiente. - **Paga una parte**: introduce un importe menor y añade después otro método. 5. En efectivo, indica lo entregado. El TPV muestra el cambio. 6. Revisa las líneas de pago, el total pagado y el importe pendiente. Se puede quitar una asignación antes de confirmar. 7. Cuando el pendiente sea cero, pulsa **Confirmar y cerrar ticket**. 8. Imprime o envía el ticket por email. La caja se limpia después de completar una de estas acciones. Una venta totalmente pagada queda en estado `COMPLETED`. Los pagos pendientes se implementan aparte en F-188. ## Contrato de venta `POST /pos/sales` ### Línea de stock ```json { "kind": "stock", "variantId": "uuid", "quantity": 2, "discountCents": 100 } ``` El backend ignora snapshots antiguos enviados por el cliente y vuelve a cargar nombre, SKU, EAN y precio. También bloquea y actualiza el stock de la tienda. ### Artículo libre ```json { "kind": "free", "name": "Servicio de asesoría", "unitPriceCents": 2500, "quantity": 1 } ``` No reserva ni descuenta inventario. La base de datos exige que `product_id` y `variant_id` sean nulos únicamente en estas líneas. ### Pago ```json { "methodCode": "cash", "amountCents": 1000, "tenderedCents": 2000 } ``` - La suma de `amountCents` debe coincidir exactamente con el total. - Solo un método de tipo efectivo acepta `tenderedCents`. - `tenderedCents` debe ser mayor o igual que el importe aplicado. - El cambio es `tenderedCents - amountCents`. - Un código inactivo o de otra tienda se rechaza. La venta, stock, pagos, líneas de reporting, saldo esperado de caja, número y ticket se confirman en una única transacción idempotente. ## Ticket La respuesta de venta y `GET /pos/sales/:id/receipt` contienen: - datos de empresa; - fecha y hora; - número de ticket; - terminal, sesión y cajero; - artículos, cantidad, precio, subtotal, descuento, IVA y total de línea; - subtotal, descuentos, IVA y total de venta; - métodos e importes pagados; - efectivo entregado y cambio; - política de devolución. ### Impresión `GET /pos/sales/:id/print` devuelve el mismo payload estructurado. El cliente usa impresión estándar del navegador, sin controlador específico de hardware. ### Email `POST /pos/sales/:id/receipt/email` ```json { "email": "cliente@example.es" } ``` Usa la configuración SMTP de **Ajustes → SMTP / Email**. El asunto y contenido se generan exclusivamente desde el ticket; el cliente no puede suministrar HTML arbitrario. ## Reporting y caja Por cada asignación se crea: - una transacción en `payments_transactions`; - una línea `payment` en `reporting_payment_lines` con tienda, terminal, sesión y método. El efectivo esperado aumenta por el importe aplicado, no por el efectivo entregado; el cambio no cuenta como ingreso ni efectivo retenido. ## Próximas ampliaciones - F-187: eliminar/desactivar cajeros preservando histórico. - F-188: ventas con saldo pendiente. - F-189: cantidades negativas, devoluciones parciales/totales y ticket de devolución. - F-190: auditoría completa de actualización/refresco de reporting. - F-191: cierre de terminal y cierre diario conciliando efectivo, tarjetas, devoluciones y pendientes.