# Código de reimpresión

La protección de reimpresiones es global. El código no es recuperable: Laravel guarda exclusivamente un hash de contraseña y verifica cada solicitud con `Hash::check`.

| Método | Ruta | Permiso |
| --- | --- | --- |
| GET | `/api/v1/admin/settings/ticket-reprint-code` | consulta de ajustes |
| PUT | `/api/v1/admin/settings/ticket-reprint-code` | actualización de ajustes |

La consulta devuelve solamente el estado, fechas, responsable y capacidades. Nunca devuelve el código, una parte de él, su longitud ni su hash.

```json
{
  "is_configured": true,
  "configured_at": "2026-07-28T12:00:00.000000Z",
  "updated_at": "2026-07-28T12:00:00.000000Z",
  "updated_by": { "id": "uuid", "name": "Administrador" },
  "capabilities": { "can_view": true, "can_update": true }
}
```

Para guardar se envían `code`, `code_confirmation` y `expected_updated_at`. El código admite de 6 a 32 caracteres, conserva mayúsculas/minúsculas y no admite espacios extremos ni caracteres de control. Un conflicto concurrente responde `409 TICKET_REPRINT_CODE_CONFLICT`.

La primera impresión no requiere código. Si cualquier boleto del lote ya se imprimió, todo el lote es una reimpresión: exige el permiso existente de reimpresión, un código válido y `reprint_reason` (`damaged_print`, `paper_jam`, `lost_document`, `printer_error` u `other`; este último requiere `reprint_reason_other`). La API registra un lote independiente sin alterar la primera impresión de cada boleto.

Sin una configuración, la reimpresión responde `409 TICKET_REPRINT_ACCESS_CODE_NOT_CONFIGURED`. Cinco intentos fallidos por usuario e IP bloquean temporalmente la comprobación y responden `429 TICKET_REPRINT_RATE_LIMITED`. La rotación invalida el código anterior de inmediato.

El mecanismo anterior `PROMOTION_TICKET_REPRINT_ACCESS_CODE` fue retirado del flujo activo y queda deprecado para no dejar consumidores externos sin aviso. No se migra automáticamente ningún secreto legacy a texto plano ni a la nueva tabla.
