Saltar a contenido

Convoca Gateway

Guía para administradores: pasarela de pagos con Redsys (tarjeta, Bizum y transferencia).


Manual para la junta directiva (sin conocimientos técnicos)

Esta página es la referencia técnica del plugin. Para el día a día hay un manual en tres partes, en castellano y con capturas:

1. Introducción

Convoca Gateway procesa pagos a través de Redsys (Sermepa), el TPV virtual más usado en España. Permite:

  • Cobrar cuotas de socio, donaciones e inscripciones de pago.
  • Generar enlaces de pago únicos para compartir por email o WhatsApp.
  • Recibir la confirmación del TPV de forma asíncrona (notificación servidor a servidor) y síncrona (retorno del navegador).
  • Emitir pagos desde el propio sitio con un formulario público.

Versión: 2.12.1 · Requiere: WordPress 6.4+, PHP 8.1+ y convoca-core activo. El plugin se aborta al activarse si no detecta Convoca\Core\Utils.

El plugin no almacena datos bancarios del pagador: la tarjeta se introduce siempre en la página segura de Redsys.

2. Requisitos

Requisito Valor
WordPress 6.4 o superior (testado hasta 7.1)
PHP 8.1 o superior
Dependencia Plugin convoca-core activo
Extensión PHP OpenSSL (necesaria para la firma SHA-256)
Cuenta Redsys TPV virtual con FUC, terminal y clave secreta

3. Instalación

  1. Asegúrate de que Convoca Core está activo.
  2. Sube la carpeta convoca-gateway a /wp-content/plugins/.
  3. Activa el plugin desde Plugins.
  4. Configura Redsys en Pagos → Configuración.

4. Configuración de Redsys

Ve a Pagos → Configuración (pestaña General).

Ajustes de Redsys (pestaña General)

Campo Descripción
FUC (Código comercio) Número de comercio Redsys (9 dígitos)
FUC Bizum Código de comercio para Bizum. Si se rellena, habilita el pago por Bizum
Terminal Número de terminal (por defecto 001, 1–3 dígitos)
Clave secreta (SHA-256) Clave de firma proporcionada por el banco (mínimo 16 caracteres)
Entorno Test (sandbox) o Producción

Además hay secciones para transferencia bancaria (IBAN, titular, instrucciones), páginas de pago y notificaciones por email.

4.1 Clave secreta cifrada

La clave secreta se guarda cifrada con AES-256-CBC en la base de datos (prefijo enc:). Si cambias las sales de WordPress (AUTH_SALT), la clave dejará de descifrarse: el plugin muestra un aviso en el admin y bloquea los pagos hasta que vuelvas a introducirla.

4.2 Credenciales por constante (opcional)

Puedes definir las credenciales en wp-config.php en lugar de guardarlas en la base de datos. Si una constante está definida, el campo correspondiente aparece deshabilitado:

define( 'CONVOCA_GATEWAY_SECRET_KEY', '...' );
define( 'CONVOCA_GATEWAY_MERCHANT_CODE', '...' );
define( 'CONVOCA_GATEWAY_BIZUM_MERCHANT_CODE', '...' );

4.3 URL de notificación en Redsys

Configura en el panel de tu comercio Redsys la URL de notificación:

https://tudominio.com/wp-json/convoca-gateway/v1/notify

El endpoint real registrado por el plugin es POST /wp-json/convoca-gateway/v1/notify (espacio de nombres convoca-gateway/v1, ruta /notify). No uses convoca-gateway/v1/notificacion ni otras variantes.

4.4 Datos fiscales de la entidad

En Pagos → Configuración → General, al final, hay tres campos cuyo único destino es la cabecera del recibo:

Campo Descripción
Nombre de la entidad Razón social que figura como emisora. Si se deja vacío se usa el nombre del sitio
CIF / NIF Ej. G-12345678
Domicilio fiscal Dirección social de la entidad

Rellénalos antes de emitir el primer recibo

Sin estos datos el recibo sale sin emisor: el pagador ve el importe y el concepto, pero no a quién le ha pagado. Y en los donativos el documento pierde parte de su valor como justificante.

5. Páginas de pago y shortcodes

El plugin expone tres shortcodes:

Shortcode Función
[convoca_pago] Página de pago: formulario manual + selección de método + redirección a Redsys
[convoca_pago_ok] Página de pago correcto (procesa el retorno síncrono)
[convoca_pago_ko] Página de pago fallido/cancelado

Créalas como páginas normales e indica su ID en Pagos → Configuración → Páginas de pago (payment_page_id, ok_page_id, ko_page_id).

  • Si no configuras ninguna página, el plugin usa los fallbacks /pago/ (pago), /pago-completado/ y /pago-error/ (retorno).
  • El diagnóstico (pestaña Estado) ofrece un botón Reparar que crea automáticamente las páginas pago-completado y pago-error con el shortcode correcto.

5.1 Formulario manual

Cuando se visita [convoca_pago] sin parámetros, se muestra el formulario "Emitir Pago Nuevo", también en dos pantallas: primero el método de pago (las mismas tarjetas grandes que en el enlace de donativo) y después el importe, el concepto y el email. Al enviarlo se genera un enlace de pago con el método ya elegido y sin caducidad, y se redirige directamente al pago por ese método, sin volver a preguntarlo.

El selector de método es un componente único (render_method_picker() en includes/Payment_Handler.php) que comparten el enlace de pago, el formulario manual y el enlace de donativo, con su CSS en methods_css(): un solo sitio define qué métodos hay (enabled_methods()) y cómo se ven.

[convoca_pago]

6. Generador de enlaces de pago

En Pagos → Generar Enlace puedes crear un enlace de pago para enviarlo a quien quieras.

Campo Descripción
Cantidad (€) Importe (mínimo 0,50 €). Déjala vacía para crear un enlace de donativo de importe libre (ver 6.1)
Concepto Descripción del pago (máx. 125 caracteres)
Método de pago Cualquiera, Tarjeta, Bizum o Transferencia (solo si hay IBAN configurado)
Email destinatario Pre-rellena el email en el formulario de pago
Parámetros personalizados Clave=Valor por línea; se muestran como datos informativos
Fecha de caducidad Fecha de vencimiento, o casilla "no caduca nunca"

La caducidad por defecto es 7 días. El enlace generado usa un token HMAC persistente (convoca_gateway_persistent_salt), de modo que no se rompe si cambian las sales de WordPress.

El listado de enlaces generados está en Pagos → Enlaces de Pago (Pedido, Concepto, Importe, Método, Origen, Email destinatario, Activo, Caducidad y Generado). La columna Activo distingue Activo, Caducado y cuántos cobros ha emitido el enlace: un enlace no se gasta, así que no tiene «estado de pago» propio.

6.3 Enlaces de cuota e inscripción: se cierran al cobrarse

Los enlaces que emiten Convoca Members y Convoca Enroll —el de la cuota de un socio o el de una inscripción— existen para cobrar una sola cosa. Así que, en cuanto su pago se confirma correctamente, el enlace queda cerrado: deja de admitir pagos y tampoco se puede generar otro nuevo para el mismo pago. Quien lo abra después ve un aviso de que ese enlace ya se ha cobrado, con la fecha.

Si el intento es erróneo —el banco rechaza o el pago se queda a medias—, el enlace no se cierra: sigue vivo para volver a intentarlo.

Dos matices que conviene tener claros:

  • El cierre no es una caducidad. Un enlace caduca por su fecha (7 días por defecto, o «no caduca nunca» si se marca así); el cierre por cobro es un estado distinto y solo lo aplican los enlaces de cuota e inscripción.
  • Los enlaces de donativo y los generados a mano en Pagos → Generar Enlace no se cierran al usarse: siguen vivos y solo caducan si tienen fecha, como hasta ahora.

6.2 Editar o eliminar un enlace

Cada fila del listado tiene Editar y Eliminar (también se puede seleccionar varios y usar la acción en bloque Eliminar).

Editar lleva a una pantalla donde se cambian el concepto, el importe, el método, la caducidad y el email de notificación:

  • Dejar el importe vacío convierte el enlace en enlace de donativo (importe libre); poner un importe lo devuelve a enlace normal.
  • La dirección del enlace no cambia: el token (_convoca_link_key) no se toca, así que lo que ya esté publicado sigue funcionando.

Eliminar pide confirmación en una pantalla que lista lo que se va a borrar. El borrado es definitivo y queda anotado en el diario del plugin. Los pagos hechos desde ese enlace no se borran: son registros independientes y la pantalla lo avisa.

6.1 Enlaces de donativo (importe libre)

Si al generar el enlace se deja la Cantidad vacía, se crea un enlace de donativo: un enlace reutilizable —no lo consume un pago y no caduca— pensado para publicarse y que cualquiera pueda aportar. El concepto por defecto es «Donativo».

Quien quiera aportar lo hace en dos pantallas:

  1. Primero el método de pago, con tres tarjetas grandes: tarjeta y Bizum en paralelo y transferencia debajo, a lo ancho. Solo aparecen los métodos que estén configurados.
  2. Después el importe y el email (opcional). Arriba se recuerda el método elegido, con un enlace «Cambiar método» para volver sin perder lo tecleado.
Campo Detalle
Método Tarjeta, Bizum o transferencia, según lo que esté configurado
Importe (€) Lo decide quien dona (mínimo 0,50 €)
Email para el recibo Opcional: si lo indica, recibe el recibo de su aportación

Cada aportación crea su propio registro de pago, con su orden de Redsys, su estado y su recibo propios, marcado como donación y enlazado al enlace del que nace (_convoca_origin = donativo, _convoca_origin_id = ID del enlace). Así el enlace sirve para muchas aportaciones y la contabilidad y los recibos quedan por donativo, no por enlace.

Del enlace de donativo se guarda la marca _convoca_open_amount y en Pagos → Enlaces de Pago su importe aparece como Importe libre.

Nota de desarrollo: el HTML va sin saltos entre etiquetas

Los bloques de pago se generan con las etiquetas pegadas (compact_html()): WordPress pasa el contenido de la página por wpautop y un salto de línea entre dos etiquetas se convierte en un <br>. En una rejilla CSS ese <br> es un hijo de más y desmonta la maquetación — las tarjetas salían apiladas en páginas con el editor clásico, mientras que en las de bloques se veían bien. Cualquier bloque nuevo que use rejilla debe pasar por el mismo filtro.

Caducidad y regeneración de enlaces

La gestión de la caducidad vive en el include Link_Expiry.php. Los enlaces de pago enviados por email tienen una caducidad por defecto de 7 días (opción convoca_gateway_link_expiry_days).

Ajuste Clave Descripción
Días de caducidad convoca_gateway_link_expiry_days Caducidad por defecto de los enlaces (7 días)
Horas de preaviso convoca_gateway_link_expiry_notice_hours Antelación del aviso previo a la caducidad (24 h)

Un cron diario (convoca_gateway_expiry_notice) envía un aviso 24 horas antes de la caducidad. Cuando un enlace caduca, la página de pago muestra un botón «Solicitar nuevo enlace» que regenera la meta _convoca_expires_at manteniendo el mismo pago (order id) y reenvía el email (Link_Expiry::regenerate_link).

6.3 Uso del enlace: emite un cobro, no se gasta

Un enlace es una plantilla: no se convierte en el cobro al usarse. Cada vez que alguien lo usa, se crea un registro de pago propio con el origen Cobro con enlace, que aparece en Pagos → Todos los Pagos con su pedido, su importe y su método.

  • Un enlace puede emitir uno o más cobros, mientras no haya caducado ni se haya eliminado.
  • El enlace conserva su estado, su caducidad y su dirección: se puede seguir compartiendo. La columna de estado del listado muestra cuántos cobros ha emitido.
  • El cobro se emite al enviar el formulario del método de pago, no al abrir la página: una visita (o un rastreador) no deja registros sueltos.
  • Al pagar, quien aporta va a la pantalla del cobro emitido, no a la del enlace: así la referencia de la transferencia y el pago con tarjeta corresponden al cobro correcto.
  • Borrar el enlace no borra los cobros que ha emitido (la pantalla de confirmación lo indica).

7. Panel de pagos

En Pagos → Todos los Pagos se listan los cobros.

Panel de pagos de Convoca Gateway

  • Columnas: Pedido, Importe, Método, Estado, Origen, Fecha.
  • Filtros por estado, método y origen (actividades, socio/a, donaciones), y buscador por ID de pedido.
  • Ordenación por fecha e importe.
  • Cada fila tiene la acción Eliminar, y la acción en bloque permite borrar varios a la vez.

Un pago es un pago y un enlace es un enlace

Los enlaces de pago (plantillas que se generan para cobrar) no aparecen en este listado: su sitio es Pagos → Enlaces de Pago. Así no se confunden con un pago pendiente al seleccionar filas para borrar.

Los cobros hechos desde un enlace sí se listan aquí, porque son cobros: cada uso de un enlace emite su propio registro de pago (Cobro con enlace), las aportaciones de un enlace de donativo emiten el suyo (Donación) y el formulario de pago el suyo (Formulario web).

  • Origen: Inscripción, Socio/a, Donación, Formulario web, Cobro con enlace.

7.1 Eliminar un pago

Se puede eliminar cualquier pago, sea cual sea su estado. Al pulsar Eliminar (o al aplicar la acción en bloque) no se borra nada todavía: aparece una pantalla de confirmación con la lista de registros y, por cada uno, lo que conviene saber antes de borrarlo:

Aviso Cuándo aparece
Está marcado como PAGADO: cuenta en los informes de ingresos El pago está en estado paid
Tiene recibo emitido (D-2026-001) Se le generó justificante, con su número
Cobrado el … Tiene fecha de cobro
Las N aportaciones hechas con estos enlaces se conservan Al borrar enlaces de donativo con aportaciones

Solo el botón «Sí, eliminar» (formulario firmado con nonce) ejecuta el borrado, que es definitivo —no va a la papelera— y deja rastro en el diario (Gateway/Delete). Quién puede borrar: quien tenga la capacidad convoca_manage_payments o sea administrador del sitio.

7.2 Estados del pago

Estado Significado
pending Pendiente de confirmación
paid Pagado (autorizado por Redsys)
failed Fallido
refunded Reembolsado (marcado manualmente)

7.3 Detalle del pago

Al pulsar sobre un pedido se abre la vista de detalle con:

  • Datos completos: importe, método, origen, descripción, código de autorización y respuesta Redsys; en caso de fallo, el código de error legible (Redsys_Client::get_response_message).
  • Justificante de pago (si el pagador lo subió por transferencia).
  • Registro de eventos (logs) asociados al pago.
  • Acciones: Reenviar email de confirmación (solo pagado), Confirmar Pago Manual (para transferencias recibidas), Marcar como Reembolsado.

8. Métodos de pago

Método Disponible si Comportamiento
Tarjeta Siempre (si hay FUC y clave) Redirección al TPV de Redsys
Bizum FUC Bizum configurado Pago instantáneo con móvil
Transferencia IBAN configurado Muestra IBAN y concepto; permite subir justificante

La página pública muestra la selección de método (💳 Tarjeta, 📱 Bizum, 🍀 Transferencia) con el método sugerido destacado.

8.1 Transferencia bancaria

Cuando el pagador elige transferencia, ve el IBAN, el titular y el concepto (ID de pedido) que debe indicar. Puede adjuntar un justificante (PDF, JPG o PNG, máximo 5 MB). El pago queda pendiente hasta que un administrador lo confirme con Confirmar Pago Manual.

9. Flujo de pago y confirmación

El pago se confirma por dos vías independientes e idempotentes:

9.1 Notificación asíncrona (servidor a servidor)

Tras cada transacción, Redsys llama al endpoint REST POST /wp-json/convoca-gateway/v1/notify. El plugin:

  1. Valida la IP de origen (rangos de Redsys 195.76.9.0/24 y direcciones conocidas; en entornos no productivos también acepta 127.0.0.1/::1). Rechaza cualquier otra IP.
  2. Verifica la firma HMAC-SHA256 de Ds_Signature. Si es inválida, registra el intento en el log con el Ds_Order decodificado para trazabilidad (v2.6.6).
  3. Localiza y bloquea el pago por order_id (FOR UPDATE) para evitar condiciones de carrera.
  4. Si ya estaba pagado, ignora la notificación duplicada.
  5. Valida la integridad financiera: el importe (Ds_Amount), la moneda (978) y el código de comercio deben coincidir con lo esperado para ese pago.
  6. Marca paid solo si Ds_Response === '0000' (autorización de compra); en caso contrario, failed.
  7. Guarda la respuesta y el código de autorización de Redsys.
  8. Dispara el hook convoca_gateway_payment_completed (o convoca_gateway_payment_failed).
  9. Responde con el texto plano OK, como espera Redsys.

Un cortafuegos por delante puede cortar el aviso

El aviso lo manda un cliente Java (Java/1.8.0_441), sin cabeceras de navegador. Los cortafuegos que aplican Browser Integrity Check —Cloudflare, entre otros— lo bloquean antes de que llegue a WordPress: desde fuera parece que Redsys no avisa y el pago se queda pendiente para siempre.

Comprobación rápida: pide a alguien de fuera que haga POST a la URL de notificación. Si responde 403 y en los registros de Redsys figura como avisada, el aviso lo está cortando el cortafuegos: deja esa ruta exenta de retos y comprobaciones, sin abrir nada más del sitio.

9.2 Retorno síncrono (navegador) — E2E-5

El aviso del servidor es la vía principal y la que hay que vigilar: es la que cobra el pago aunque el pagador cierre el navegador antes de volver al sitio. La página [convoca_pago_ok] procesa además el retorno del navegador en el momento, como red de seguridad:

  • Si el pago aún no está confirmado y la URL trae Ds_MerchantParameters, se llama a process_return().
  • process_return() verifica la firma HMAC (sin restricción de IP, porque la IP del navegador es arbitraria), localiza el pago, valida importe y comercio, aplica el estado y dispara los mismos hooks.
  • Es idempotente: si el pago ya estaba paid, no vuelve a procesarse (evita duplicar hooks y correos).

Esto garantiza que la confirmación no dependa exclusivamente de que la notificación asíncrona llegue.

Retorno TPV → /pago-ok/?Ds_MerchantParameters=…&Ds_Signature=… → [convoca_pago_ok] procesa en el momento

9.3 Verificación de firma

  • Versión de firma: HMAC_SHA256_V1 (por defecto) y HMAC_SHA256_V2 soportadas. El algoritmo no lo decide el input del atacante: solo se acepta la versión configurada por el comercio (signature_version).
  • Ds_MerchantParameters es Base64 (con soporte base64url) de un JSON con los campos Ds_Order, Ds_Amount, Ds_Currency, Ds_MerchantCode, etc.

10. Webhook REST (referencia técnica)

Propiedad Valor
Método POST
Endpoint /wp-json/convoca-gateway/v1/notify
Autenticación Ninguna (exige Redsys); la seguridad se valida por IP + firma HMAC
Rate limit 30 notificaciones/minuto por IP
Límite de payload 16 KB
Respuesta correcta OK (200)

11. Hooks y funciones públicas

11.1 Acciones (events)

Hook Argumentos Cuándo se dispara
convoca_gateway_payment_completed $pago_id, $origin, $origin_id, $meta Pago confirmado (asíncrono o síncrono)
convoca_gateway_payment_failed $pago_id, $response_code Pago denegado
convoca_gateway_payment_refunded $pago_id Marcar como reembolsado manualmente
convoca_gateway_resend_email $pago_id Reenviar email de confirmación

También se disparan los hooks heredados convoca_payment_completed y convoca_payment_failed (vía Convoca\Core\Utils::do_action). Enroll confirma inscripciones y Members activa membresías escuchando estos hooks.

11.2 Filtros

Filtro Descripción
convoca_gateway_bank_entity Nombre de la entidad bancaria mostrado en la nota de seguridad
convoca_gateway_redsys_allowed_ips Ampliar la lista de IPs permitidas de Redsys
convoca_gateway_receipt_payer_name Nombre del pagador impreso en el recibo ($pago_id); útil cuando el pago lo hizo una entidad o una persona distinta del titular

11.3 Funciones públicas

  • convoca_gateway_create_payment( array $args ): array|\WP_Error — crea un pago y devuelve ['pago_id' => int, 'payment_url' => string]. Argumentos: amount_cents (en céntimos), method (tarjeta/bizum), origin (enroll/members), origin_id, product_desc (máx. 125), tokenize (para pago recurrente).
  • convoca_get_gateway_settings(): array — devuelve los ajustes guardados.

11.4 Pagos de cuota e inscripción (otros plugins)

convoca_gateway_create_payment() (y Payment_Handler::create_payment()) es la puerta que usan convoca-members y convoca-enroll: cuando alguien se da de alta pagando la cuota o se inscribe a una actividad de pago, el plugin crea el registro de pago y recibe su URL de pago.

Qué Cómo
Importe y concepto Los pone el plugin: cuota (CUOTA <plan>), renovación (RENOVACIÓN …), inscripción (Aportación para <actividad>)
Origen members o enroll → en el listado de pagos se leen como Socio/a o Inscripción, con filtro
Correo de contacto El plugin entrega el correo del alta o la inscripción (payer_email): sirve para el recibo y para el aviso de caducidad
URL de pago Con token y caducidad configurable (ajuste Caducidad por defecto, 7 días) — el método se elige en la misma pantalla de pago
Un solo uso Al completarse el pago, la URL deja de servir: la página avisa de que ya está cobrado

Estos pagos no son plantillas: viven en Pagos → Todos los Pagos (no en Enlaces de Pago) y se pueden eliminar como cualquier otro, con su pantalla de confirmación.

12. Correos automáticos

En Pagos → Configuración → pestaña Correos:

  • Habilitar confirmación de pago (checkbox) y nombre del remitente.
  • Plantillas editables de asunto y cuerpo para éxito y fallo, con variables:
Variable Valor
{importe} Importe formateado
{metodo} Método de pago
{fecha} Fecha del pago
{producto} Concepto/origen
{enlace_pago} URL del enlace de pago
{enlace_inscripcion} URL de la inscripción (si aplica)
{recibo_url} URL del recibo o justificante del pago

El correo se envía al email del pagador (_convoca_payer_email), solo si la confirmación está habilitada.

En los donativos, el email que deja quien aporta se guarda como email del pagador y el recibo se envía siempre que lo haya, sin depender de ese checkbox (marca _convoca_receipt_always): el donante espera su justificante. El campo «Email de notificación» del formulario de pago viaja con el método elegido, de modo que también en los enlaces normales se puede enviar el recibo si la confirmación está habilitada.

Recibo automático de cuotas e inscripciones (PRO)

Al cobrarse una cuota o una inscripción se envía el recibo a quien paga, al correo que dejó al apuntarse. Tiene su propio interruptor en Pagos → Configuración → Correos (activado por defecto) y es una funcionalidad PRO: sin licencia, estos pagos siguen rigiéndose por el aviso general de confirmaciones.

Los donativos mantienen su comportamiento de siempre: el recibo sale al donante siempre que haya dejado correo, sin depender de ningún interruptor.

Recordatorio de pago sin terminar

Si el pagador deja su correo y el pago se queda a medias, a la media hora se le manda un recordatorio con un botón para terminarlo. La comprobación corre cada cuarto de hora, así que el aviso sale entre los 30 y los 45 minutos siguientes.

Situación Qué hace
El pago dejó de estar pendiente No envía nada
No hay correo del pagador No envía nada: no hay a quién
El enlace ya caducó No envía nada: el botón del mensaje ya no serviría
Ya se avisó una vez No repite: el aviso sale una sola vez por pago

El texto usa la plantilla de recordatorio con sus valores por defecto, y en ella funciona la variable {enlace_pago} (que respeta la caducidad del enlace). Hoy se cambia desde los ajustes (email_pending_subject y email_pending_body), no desde la interfaz: los campos de la pestaña Correos cubren las plantillas de éxito y de fallo.

Error de TPV y reintento

Cuando Redsys rechaza la operación, el pagador recibe un email con un motivo legible («Tu banco rechazó la operación» o el texto del mapa de códigos de Redsys, junto al código numérico). El estado del pago queda failed.

Desde la página de pago hay un botón «Reintentar pago» que genera un nuevo enlace para el mismo pago. El detalle del pago en admin muestra el código de error (vía Redsys_Client::get_response_message).

13. Dashboard

El widget "Resumen de Pagos Convoca" aparece en el Escritorio de WordPress (para usuarios con convoca_view_payments):

  • Total cobrado este mes, pagos hoy y pagos este mes.
  • Uso de métodos (tarjeta vs Bizum).
  • Evolución de los últimos 7 días.

Pagos sin terminar

El Escritorio incluye además el widget «Convoca · Pagos sin terminar» (solo para administradores), que responde a una pregunta concreta: ¿alguien empezó a pagar y no terminó?

Un pago cuenta como sin terminar cuando lleva más de 30 minutos empezado y el banco no ha respondido nada —ni bien ni mal—. Muestra hasta ocho, con el concepto, el importe, el método, la fecha y si hay correo dejado, y cada uno enlaza a su detalle.

Un enlace caducado no se esconde

Justo entonces es cuando hay que mirarlo: un pago con el enlace caducado y sin respuesta del banco ya no se va a cobrar solo. Para eso está el aviso, no para ocultarlo.

Si el widget aparece vacío, no significa que no haya habido pagos: significa que todos terminaron, que es lo normal.

La misma regla, desde la consola

\Convoca\Gateway\Pending_Payments::stuck_ids() devuelve los IDs de esos pagos. Es la única definición de «pago a medias»: la comparten el widget y el recordatorio por correo, para que nunca digan cosas distintas.

14. Diagnóstico y reparación

La pestaña Estado (Pagos → Configuración) ejecuta 8 comprobaciones, con botón de reparación automática:

Chequeo Reparación disponible
Modo de entorno / clave —
Código de comercio (FUC) —
Terminal Fijar 001
Páginas de retorno (OK/KO) Crear pago-completado y pago-error
Métodos offline (transferencia) —
PHP —
OpenSSL —
Base de datos (tabla de logs) —

El resultado se cachea 1 hora; el botón Forzar comprobación lo recalcula.

15. Seguridad

  • Firma HMAC-SHA256 obligatoria en notificaciones y retornos.
  • Validación de IP en el webhook (rangos Redsys + lista filtrable).
  • Rate limit (30/min/IP) y límite de payload (16 KB) anti-DoS.
  • Integridad financiera: importe, moneda y comercio deben coincidir con el pago esperado.
  • is_approved estricto: solo Ds_Response === '0000' marca pagado (no todo el rango 0–99).
  • Clave secreta cifrada en reposo (AES-256-CBC).
  • Bloqueo de fila (FOR UPDATE) contra condiciones de carrera y notificaciones duplicadas.
  • Protección anti inyección CSV (prefija =, +, -, @).
  • Justificantes: validación de tipo MIME real y renombrado con UUID contra path traversal; el directorio de subidas se protege contra ejecución de scripts.

16. Exportación CSV

En Pagos → Todos los Pagos → Exportar CSV:

  • Columnas: ID, ID Pedido, Importe (€), Método, Estado, Origen, Email Usuario, Fecha Creación, Fecha Pago.
  • Separador ;, con BOM UTF-8 para compatibilidad con Excel.
  • Máximo 5.000 registros por exportación.
  • Requiere la capacidad convoca_view_payments.

17. Gutenberg

Además de los shortcodes, el plugin registra tres bloques (categoría convoca-gateway):

Bloque Uso
convoca-gateway/pagina-pago Página de pago (selección de método + TPV)
convoca-gateway/pago-ok Confirmación de pago correcto
convoca-gateway/pago-ko Pago fallido/cancelado

18. Problemas comunes

Problema Causa probable Solución
"Firma no válida" en el log Clave secreta incorrecta o cambiada Revisa la clave SHA-256; Redsys distingue mayúsculas
Pago en TPV pero sigue "Pendiente" La notificación asíncrona no llegó (frecuente en test) El retorno síncrono en pago-ok lo confirma; si no, usa Confirmar Pago Manual
Enlace de pago no funciona Ya pagado o caducado Comprueba el estado en Enlaces de Pago
Modo pruebas Entorno Test Usa la tarjeta de prueba 4548 8120 4940 0004 (CVV 123, caducidad 12/34)
Aviso de clave no descifrable Cambiaste las sales de WordPress Vuelve a introducir la clave secreta en Configuración
403 al ver Pagos Falta la capacidad convoca_view_payments Asigna la capacidad al rol correspondiente (la define convoca-core)

19. Recibos y justificantes de pago

Cada pago completado genera automáticamente su recibo: Receipt_Generator.php le asigna número y Receipt_View.php lo sirve. Va enlazado desde el email de confirmación y su número figura en el listado de pagos.

El recibo es un documento propio, no una página dentro del tema: se sirve aparte, sin cabecera, menú ni pie del sitio, con sus propios márgenes de impresión, para que se imprima o se guarde en PDF tal cual. Incluye los datos de la entidad, los del pagador, el método de pago, la referencia, la fecha con la marca «Pagado», el importe destacado y, en los donativos, el texto de la Ley 49/2002.

Característica Detalle
Numeración Anual automática (_convoca_receipt_number): AÑO-NNN (2026-037), con un contador por año
Acceso /pago/?convoca_gateway_pago=ID&convoca_gateway_recibo=1&convoca_gateway_receipt_key=…
Clave Token de capacidad: cada pago tiene la suya y solo abre ese recibo
Impresión Imprimir → Guardar como PDF desde el navegador

La clave no se comparte de más

Da acceso a ese recibo y a ninguno más, pero da acceso: trátala como el documento mismo.

Justificante de donación

Los pagos marcados como donación (meta _convoca_es_donacion) generan en su lugar un justificante de donación con texto fiscal (Ley 49/2002) y numeración de serie separada (D-AÑO-NNN). Se marcan solos cuando nacen de un enlace de donativo, y también se pueden marcar a mano con el checkbox del detalle del pago en admin.

Los datos de la asociación que aparecen en recibos y justificantes se configuran en Ajustes (ver §4.4 Datos fiscales de la entidad):

Ajuste Clave
Nombre de la asociación org_name
CIF org_cif
Dirección org_address

20. Calidad y pruebas

  • PHPStan nivel 5 sin baseline (deuda estática a cero).
  • PHPCS limpio (WordPress Coding Standards).
  • Plugin Check (PCP) 0 errores en la preparación para WordPress.org.
  • Cobertura con PHPUnit (tests de firma, notificación, verify_notification con versión fija, base64url, payload vacío, caducidad, recordatorio, pagos sin terminar, recibo, etc.).
  • La notificación confirmada se comprueba de punta a punta, incluido el protocolo de la transacción: que la última sentencia sea COMMIT. Sin eso, el cambio se pierde al cerrar la conexión y el fallo es invisible (el plugin responde OK y el pago sigue pendiente).