# Despliegue a produccion — pagos CyberSource REST

Lista de salida para reapuntar el checkout de MAS al modulo REST. El detalle
tecnico de la integracion esta en `app/Services/Payments/README.md`; este
archivo es solo el procedimiento.

**Vencimiento que lo motiva:** Secure Acceptance deja de estar disponible el
**30 de septiembre de 2026**.

---

## Antes de empezar: como funciona el corte

No hay un switch que accionar. El blade define `URL_REST_STEP1`; cuando esa
constante existe, `api.js` llama a `/booking/rest/step1`, ese devuelve un
capture context, y `CheckoutPageMain` enciende el flujo REST con
`const esFlujoRest = !!captureContext;`.

**Desplegar el blade con esa linea ES el corte.** Y quitarla es la reversa.

Las rutas heredadas (`/booking/step1`, `/booking/step2_post`, `/payment/response3Ds`…)
se quedan en su lugar y siguen apuntando a `PayBookingController`. No se tocan.

---

## 1. Base de datos

La tabla **`payment_attempts`**. **No existe una migracion**: en dev se creo a
mano. Saca el DDL del servidor de pruebas y correlo en produccion:

```sql
-- en dev
SHOW CREATE TABLE payment_attempts;
```

> Conviene generar la migracion despues del corte, para que el proyecto no
> dependa de que alguien recuerde este paso. Hoy no la hay.

Nada mas cambia en base de datos. `reservations`, `clients_payment_methods` y
`cybersource_log` ya tienen las columnas que el modulo usa.

---

## 2. Variables de entorno

```dotenv
CBS_REST_ENV=prod
CBS_REST_AUTH_TYPE=jwt
CBS_REST_KEY_DIRECTORY=app/certificates/rest

# Politica de riesgo. AMBAS son criticas en produccion.
CBS_REST_RISK_ON_MISSING_VERDICT=reject
CBS_REST_FORCE_3DS=false

CBS_REST_CURRENCY=MXN
```

**`CBS_REST_RISK_ON_MISSING_VERDICT=reject`** — declarala explicitamente aunque
el config traiga un valor por omision. Si Decision Manager deja de emitir
veredicto —por ejemplo si alguien desactiva el perfil por omision— el sistema
debe fallar CERRADO. La alternativa es cobrar sin evaluacion de riesgo: sobre el
historico de produccion serian unas 29 transacciones al mes que hoy se rechazan.

**`CBS_REST_FORCE_3DS=false`** — si queda encendido, TODA transaccion pasa por
autenticacion. No rompe nada, pero mete friccion al 74% que hoy no la tiene.

Las llaves de la cuenta van en `storage/app/certificates/rest`. Verifica
permisos de lectura para el usuario de php-fpm.

---

## 3. Codigo

```
app/Services/Payments/            (el modulo completo)
app/Http/Controllers/Web/Booking/PayBookingRestController.php
app/Providers/PaymentsServiceProvider.php     registrado en config/app.php
config/cybersource_rest.php
routes/web.php                    (las rutas /booking/rest/* y /payment/rest/*)
resources/views/web/booking-engine/prepago/rest_3ds_return.blade.php
resources/views/web/booking-engine/index.blade.php        <- el corte vive aqui
resources/lang/{es,en}/general.php
resources/assets/booking-engine/rez-process-component/
    components/Foms/Payment/PaymentFormRest.jsx
    components/Foms/Payment/SavedPaymentMethodsRest.jsx
    components/Foms/Payment/useCobroRest.js
    components/Foms/index.js
    components/PaymentStep/payment/CheckoutPageMain.jsx
    components/PaymentStep/PaymentManager.jsx
    utils/api.js
```

Mas el SDK: `composer require cybersource/rest-client-php` (o `composer install`
si el `composer.lock` ya lo trae).

---

## 4. Comandos, en este orden

```bash
 
npm ci && npm run prod
php artisan config:clear
php artisan view:clear
# si el despliegue cachea configuracion:
php artisan config:cache
# si el servidor tiene OPcache con validate_timestamps=0:
sudo systemctl reload php8.x-fpm
```

---

## 5. Decision Manager

**No hay que tocar nada.** Produccion ya tiene perfil activo por omision — es de
donde salen los 31,170 veredictos historicos. Solo confirma que sigue activo:

```sql
SELECT JSON_UNQUOTE(JSON_EXTRACT(reply_json, '$.status')) AS veredicto, COUNT(*)
FROM cybersource_log
WHERE type = 'REST Decision Manager' AND created_at > NOW() - INTERVAL 1 DAY
GROUP BY 1;
```

Si `veredicto` sale NULL en todos, el perfil no esta aplicando y **con la
politica en `reject` los pagos se detienen**. Eso es el diseno funcionando, pero
conviene verlo antes que un cliente.

---

## 6. Verificacion post-despliegue

Un cobro real de monto bajo, y despues:

```sql
SELECT type, created_at FROM cybersource_log
WHERE code_reservation = '<reserva>' ORDER BY id;
```

La secuencia esperada:

| Veredicto de DM | Renglones |
|---|---|
| ACCEPTED | `3DS Setup`, `Decision Manager`, `Authorization` |
| REVIEW | los anteriores mas `3DS Enrollment` y, si hubo challenge, `3DS Validation` |

Y en la reserva: `paid_at` con fecha, y el intento en `payment_attempts` con
estado `authorized`.

---

## 7. Reversa

Comentar **una linea** en `resources/views/web/booking-engine/index.blade.php`:

```php
const URL_REST_STEP1 = "{{ url(session("lang")."/booking/rest/step1") }}";
```

Sin la constante, `api.js` cae al step1 heredado, `captureContext` llega vacio,
`esFlujoRest` se apaga y vuelve el formulario anterior con Songbird. Despues
`php artisan view:clear`.

Sin revertir rutas, sin tocar base de datos, sin deshacer el despliegue.

**Esa reversa existe mientras `PayBookingController` siga en su lugar.** Por eso
no se borra todavia.

---

## 8. Despues del corte

**No borrar el flujo heredado** hasta que el nuevo lleve unas semanas
funcionando. Retirarlo es tarea aparte y sin prisa.

Queda pendiente, sin bloquear el despliegue:

- Generar la migracion de `payment_attempts`
- Alertar sobre el warning `[payments] Decision Manager no emitio veredicto` en
  el monitoreo de logs
- Actualizar Songbird a v2.1.3 en el flujo heredado, como seguro por si hubiera
  que revertir despues del 3 de noviembre — ese dia los endpoints viejos de
  Payer Authentication dejan de funcionar, y con ellos la reversa
