167 lines
5.8 KiB
Markdown
167 lines
5.8 KiB
Markdown
# TPV — Checkout, pagos mixtos y tickets
|
|
|
|
> Implementado en F-186 y ampliado en F-187. 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.
|
|
|
|
### Cajeros
|
|
|
|
En **Administración → TPV → Cajeros** puedes crear cuentas con rol cajero y consultar su estado:
|
|
|
|
- **Activo**: puede iniciar sesión y abrir caja.
|
|
- **Inactivo**: no puede autenticarse; se puede reactivar.
|
|
- **Eliminado**: no puede autenticarse ni reactivarse.
|
|
|
|
**Desactivar** revoca inmediatamente todas las sesiones del cajero. Al reactivarlo tendrá que iniciar una sesión nueva.
|
|
|
|
**Eliminar** requiere confirmación y realiza una baja lógica irreversible. La fila y el UUID se conservan para que tickets, ventas, sesiones de caja, reporting y auditoría sigan indicando quién realizó la operación.
|
|
|
|
No se puede desactivar ni eliminar un cajero con una sesión de caja abierta. Primero debe cerrarse y cuadrarse esa sesión.
|
|
|
|
API administrativa:
|
|
|
|
- `GET /pos/users`: lista personal POS y estado de lifecycle.
|
|
- `POST /pos/users`: crea cajero/manager; contraseña mínima de ocho caracteres.
|
|
- `PATCH /pos/users/:id/status` con `{ "active": false }` o `{ "active": true }`.
|
|
- `DELETE /pos/users/:id`: baja lógica irreversible del cajero.
|
|
|
|
Las operaciones de estado y eliminación solo admiten objetivos con rol `pos_cashier`, requieren administrador y generan eventos de auditoría.
|
|
|
|
## 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-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.
|