7. Pagos

Aviso: en el despliegue actual no hay componentes de tipo payment en la base de datos, por lo que la pantalla /cta muestra el mensaje "No hay componentes de pago creados". Esta sección documenta la funcionalidad a partir del código fuente y de cómo se ven las pantallas cuando sí hay datos: la captura incluida (01-listado.png) refleja precisamente ese estado vacío.

Introducción

Los pagos se gestionan a través de componentes de tipo payment, integrados con Stripe. Aquí verás cómo se listan, se reembolsan y cómo funciona la integración con el proveedor de pagos.

Un componente de pago combina un formulario de checkout con la lógica de cobro: el visitante introduce sus datos de tarjeta (o usa métodos express como Apple Pay / Google Pay), Stripe procesa el cargo, y el panel registra el resultado mediante un webhook que actualiza el estado del pago en la base de datos interna.

Acceso rápido

Detalle del despliegue: la URL /payments devuelve 404 en este panel. La URL canónica para ver los pagos es /cta (misma ruta que comparten los formularios tipo form, ver sección 6). Si tu bookmark apunta a /payments, actualízalo.

Pantalla principal (listado)

Pantalla /cta en estado vacío (sin componentes de pago)
Pantalla /cta en estado vacío. El panel muestra el mensaje "No hay componentes de pago creados" porque en este despliegue no hay componentes de tipo payment en la base de datos.

Cuando sí hay componentes de pago definidos, esta misma pantalla muestra una tabla con, para cada componente payment:

Tareas habituales

7.1 Ver el listado de pagos

Una vez creado un componente de pago y recibida la primera transacción confirmada, el panel empieza a mostrar pagos en /cta:

  1. Entra en /cta.
  2. Verás una fila por cada componente de tipo payment con los totales agregados (cobrado, reembolsado, último pago).
  3. Pulsa sobre un componente para abrir el detalle con la lista completa de transacciones.

El listado detallado de transacciones (ruta /components/{id}/payments) muestra, para cada pago:

7.2 Ver el detalle de un pago

Para inspeccionar toda la información de un pago individual:

  1. Desde el listado (/components/{id}/payments), pulsa sobre el ID o el botón Ver del pago que te interese.
  2. Se abre la ficha de detalle con:
    • Datos de la transacción (importe, moneda, descripción).
    • Estado y metadatos que Stripe devuelve (payment_method, receipt_url, customer, etc.).
    • Historial de eventos: created → processing → succeeded, o failed.
    • Log del webhook recibido para ese pago (timestamp, payload parcial).
  3. Desde aquí puedes lanzar un reembolso (ver 7.3) o abrir la ficha de Stripe en una pestaña externa.

7.3 Reembolsar un pago

El panel permite lanzar reembolsos contra Stripe sin salir de la administración:

  1. Abre el detalle del pago (ver 7.2).
  2. Pulsa el botón Reembolsar.
  3. Indica el importe (por defecto se rellena con el total del pago):
    • Reembolso total: el importe completo, el estado del pago pasa a refunded.
    • Reembolso parcial: un importe menor, el estado pasa a partially_refunded y se puede lanzar más de un reembolso parcial hasta agotar el total.
  4. Opcional: añade un motivo interno (visible solo para administradores) para auditoría.
  5. Confirma. El panel llama a la API de Stripe (POST /v1/refunds) y, si Stripe acepta la operación, el estado del pago se actualiza al recibir el webhook charge.refunded.
Consejo: los reembolsos se procesan sobre el método de pago original. No es posible cambiar la cuenta de destino desde el panel: para casos excepcionales (transferencia manual, etc.) hay que hacerlo desde el dashboard de Stripe.

Referencia técnica (webmasters)

Integración con Stripe

La integración con Stripe se apoya en tres claves que deben estar configuradas en el .env del servidor:

STRIPE_PUBLIC_KEY=pk_live_xxxxxxxxxxxxxxxxxxxx
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxx

Flujo del webhook

Cuando Stripe confirma (o rechaza) un cargo, envía un evento HTTP POST a un endpoint del backend. El panel expone una ruta interna que:

  1. Verifica la firma del evento con STRIPE_WEBHOOK_SECRET. Si la firma no encaja, el panel responde 400 y descarta el evento (esto evita que un atacante pueda inyectar pagos falsos).
  2. Identifica el pago interno a partir del id del PaymentIntent o Charge.
  3. Actualiza el estado del pago en la base de datos interna (pending → succeeded / failed / refunded).
  4. Registra un evento en el log para auditoría (timestamp, tipo de evento, payload parcial).
  5. Responde 200 OK a Stripe para que no reintente.

La ruta típica del endpoint de webhook es:

POST /api/payments/webhook
Content-Type: application/json
Stripe-Signature: t=...,v1=...

{ "type": "charge.succeeded", "data": { "object": { "id": "ch_..." } } }

Dónde se guardan los pagos

Las transacciones se almacenan en una tabla dedicada (nombre habitual payments o payment_transactions). Cada fila contiene, como mínimo:

Configuración en el panel

El modo de operación (test vs live) se controla habitualmente con:

Importante: cambiar las claves en el .env no migra los pagos ya registrados. Los pagos confirmados con claves live siguen siendo reales aunque luego cambies a claves test, y viceversa. Para distinguir pagos de test en producción, fíjate siempre en el prefijo del PaymentIntent (pi_ + identificador alfanumérico) en el dashboard de Stripe.

Rutas internas relevantes

Errores frecuentes