# Compra pública por evento

## Resultado funcional

Cada evento publicado posee una página independiente:

```text
/evento/{slug}
```

Cuando cumple simultáneamente estas condiciones, aparece **Comprar cartones**:

- estado `sales_open`;
- acceso `public`;
- compra pública habilitada;
- fecha actual dentro de `sales_open_at` y `sales_close_at`, cuando están configuradas;
- al menos un cartón con estado `generated`;
- al menos un método de pago activo.

El tablero continúa disponible en:

```text
/juego/{slug}
```

## Flujo del comprador

1. Abre la página pública del evento.
2. Revisa fecha, sede, precio, premios, inventario y formas de pago.
3. Selecciona **Comprar cartones**.
4. Indica cantidad, nombre, correo, teléfono y documento opcional.
5. Acepta condiciones de compra y tratamiento de datos.
6. Elige transferencia o pago en taquilla, según la configuración del evento.
7. El backend crea una orden con token privado e idempotencia.
8. MySQL bloquea y reserva cartones mediante `SELECT ... FOR UPDATE`.
9. El comprador es enviado a `/pedido/{token}`.
10. En transferencia, declara titular y referencia; adjunta PDF/JPG/PNG cuando el evento lo exige o de forma opcional. La orden cambia a `payment_review`.
11. Caja revisa la evidencia y aprueba o rechaza.
12. Al aprobar, los cartones pasan de `reserved` a `sold` y se muestran al comprador.
13. Al rechazar, expirar o cancelar el evento, se eliminan las asignaciones temporales y los cartones vuelven a `generated`.

## Estados de orden

| Estado | Significado |
|---|---|
| `pending_payment` | Reserva creada, aún sin comprobante. |
| `payment_review` | Comprobante recibido y pendiente de caja. |
| `pending_venue_payment` | Pago presencial pendiente. |
| `paid` | Pago aprobado y cartones activos. |
| `payment_rejected` | Pago rechazado; inventario liberado. |
| `expired` | Venció la reserva; inventario liberado. |
| `cancelled` | Cancelación administrativa o del evento. |

## Configuración administrativa

### 1. Cuenta bancaria

Ingrese en:

```text
/admin/payment-settings
```

Registre banco, tipo, número, titular, identificación e instrucciones. La cuenta puede activarse, desactivarse y marcarse como predeterminada.

### 2. Evento

Abra el evento y configure **Compra de cartones por evento**:

- compra pública activa;
- mínimo y máximo por orden;
- minutos de reserva;
- mensaje público;
- comprobante obligatorio u opcional;
- transferencia bancaria y cuenta asociada;
- pago en taquilla e instrucciones.

### 3. Revisión de compras

Ingrese en:

```text
/admin/public-orders
```

Permisos:

- `public_orders.view`: consultar órdenes y comprobantes;
- `public_orders.manage`: aprobar o rechazar;
- `payment_settings.view`: consultar cuentas;
- `payment_settings.manage`: crear y cambiar cuentas.

## Cron de expiración

Aunque las solicitudes públicas liberan reservas vencidas de forma oportunista, producción debe ejecutar:

```bash
php bin/expire_reservations.php
```

Cron recomendado cada cinco minutos:

```cron
*/5 * * * * /usr/bin/php /ruta/bingo/bin/expire_reservations.php >> /ruta/bingo/storage/logs/reservations.log 2>&1
```

En Windows puede programarse con Task Scheduler ejecutando `php.exe` y el script.

## Protección de comprobantes

- Se admiten únicamente `application/pdf`, `image/jpeg` e `image/png`.
- Tamaño predeterminado: 5 MB, configurable con `PAYMENT_PROOF_MAX_BYTES`.
- Se valida `is_uploaded_file()` y MIME real mediante `finfo`.
- Los archivos se guardan en `storage/private/payment-proofs`.
- No existe URL pública directa.
- La descarga requiere sesión y `public_orders.view`.
- El nombre físico es aleatorio y no conserva el nombre enviado por el usuario.

## Pasarela automática

Esta versión no captura datos de tarjeta ni simula un cobro. Para integrar PayPhone, Kushki, Datafast, Stripe u otro proveedor se recomienda:

1. crear una interfaz `PaymentGateway`;
2. generar intención de pago desde el servidor;
3. recibir webhook firmado;
4. verificar importe, moneda, orden e idempotencia;
5. activar cartones únicamente desde el webhook validado;
6. registrar payload reducido y hash en auditoría, nunca datos sensibles de tarjeta.
