Appearance
PaymentGatewayService
Responsabilidad
Servicio genérico para integración con medios de pago online. Utiliza el patrón Adapter para soportar múltiples gateways configurables por tenant (MercadoPago, Pago TIC, PagoMisCuentas, etc.).
Arquitectura
PaymentGatewayService (Orquestador)
↓
PaymentGatewayFactory (Selector de adapter)
↓
Adapter específico (MercadoPago, PagoTIC, etc.)
↓
API del medio de pagoPatrón de diseño: Factory + Adapter
- Cada medio de pago tiene su adapter que implementa una interfaz común
- El Factory selecciona el adapter según la configuración del tenant
- El Service orquesta el flujo completo y maneja la lógica de negocio
Métodos Principales
iniciarPago()
Propósito: Iniciar un pago online redirigiendo al cliente al gateway de pago.
Parámetros:
clienteId: ID del cliente que pagafacturas: Array con las facturas a pagartotal: Monto total a pagartenantContext: Contexto del tenant (configuración)
Flujo de negocio:
- Obtener configuración del gateway del tenant
- Validar que el tenant tenga un medio de pago configurado
- Crear adapter mediante factory
- Generar payment_id único
- Crear pago en el gateway externo
- Guardar registro en
portal_paymentscon estado "pending" - Retornar URL de redirección para el cliente
Respuesta:
json
{
"payment_id": "portal_payment_abc123",
"redirect_url": "https://checkout.mercadopago.com/...",
"payment_method": "mercadopago"
}procesarWebhook()
Propósito: Procesar notificaciones del gateway cuando el pago cambia de estado.
Parámetros:
gateway: Nombre del gateway (mercadopago, pagotic, etc.)headers: Headers HTTP del webhookbody: Datos del webhooktenantContext: Contexto del tenant
Flujo de negocio:
- Obtener configuración del gateway
- Crear adapter
- Validar firma del webhook (seguridad)
- Procesar datos del webhook
- Verificar idempotencia (evitar procesamiento duplicado)
- Si el pago fue aprobado:
- Actualizar
portal_paymentscon estado "approved" - Crear recibo en CtaCte usando
ReciboRelationsService - Vincular recibo con el pago
- Actualizar
- Si el pago fue rechazado:
- Actualizar
portal_paymentscon estado "rejected" - Guardar respuesta del gateway para debug
- Actualizar
Consideraciones de seguridad:
- Validación de firma para evitar webhooks falsos
- Idempotencia: verificar si el pago ya fue procesado antes
- Guardar respuesta completa del gateway para auditoría
getHistorial()
Propósito: Obtener historial de pagos del cliente.
Parámetros:
clienteId: ID del clientetenantContext: Contexto del tenant
Retorna: Lista de pagos aprobados y reembolsados del cliente.
Interfaz del Adapter
Cada gateway debe implementar estos métodos:
createPayment()
Propósito: Crear un pago en el gateway externo.
Entrada:
json
{
"payment_id": "portal_payment_abc123",
"total": 15000.00,
"tenant_name": "Empresa A",
"domain": "ctacte.empresaa.com.ar"
}Salida:
json
{
"external_id": "1234567890",
"redirect_url": "https://checkout.gateway.com/..."
}processWebhook()
Propósito: Interpretar datos del webhook del gateway.
Entrada: Datos raw del webhook (varía según gateway)
Salida:
json
{
"status": "approved",
"external_id": "1234567890",
"amount": 15000.00,
"payment_date": "2026-01-20 14:30:00",
"raw_response": { /* respuesta completa del gateway */ }
}Estados posibles: pending, approved, rejected, refunded
validateWebhook()
Propósito: Validar que el webhook realmente proviene del gateway (firma/secret).
Retorna: true si es válido, false si es fraudulento.
getPaymentStatus()
Propósito: Consultar estado actual de un pago en el gateway.
Entrada: external_id (ID en el sistema del gateway)
Retorna: Estado actual (pending, approved, rejected, refunded)
Factory de Gateways
El Factory crea el adapter correcto según el tipo de gateway:
Gateways soportados:
mercadopago: MercadoPagopagotic: Pago TICpagomiscuentas: PagoMisCuentasnone: Sin medio de pago (solo cupones)
Configuración por tenant: Cada tenant tiene configurado en ini.sistemas:
payment_gateway: Nombre del gatewaypayment_gateway_config: JSON con tokens, secrets, environment
Ejemplo de configuración:
json
{
"access_token": "APP_USR-xxxxx",
"webhook_secret": "secret_key",
"environment": "production"
}Integración con Endpoints
Endpoint: Iniciar Pago
Request:
json
POST /api/portal/pagos/iniciar
{
"cliente_id": 123,
"facturas": [
{ "id": "uuid-1", "monto": 10000.00 },
{ "id": "uuid-2", "monto": 5000.00 }
],
"total": 15000.00
}Response:
json
{
"payment_id": "portal_payment_abc123",
"redirect_url": "https://checkout.mercadopago.com/...",
"payment_method": "mercadopago"
}Endpoint: Webhook
Request:
POST /api/portal/pagos/webhook?gateway=mercadopago
Headers:
X-Signature: abc123...
Body: { /* datos del gateway */ }Response:
json
{
"status": "processed"
}Flujo Completo de Pago
- Cliente selecciona facturas en el portal
- Frontend llama a
/api/portal/pagos/iniciar - Backend crea registro en
portal_payments(pending) - Backend redirige al cliente al gateway de pago
- Cliente completa el pago en el gateway
- Gateway notifica resultado vía webhook a
/api/portal/pagos/webhook - Backend valida webhook y procesa resultado
- Si aprobado: Se crea recibo en CtaCte y se vincula
- Frontend muestra confirmación al cliente
Casos de Uso
Pago Aprobado
- Webhook llega con status "approved"
- Se actualiza
portal_payments.status = 'approved' - Se crea recibo en
ordctausandoReciboRelationsService - Se vincula
portal_payments.recibo_id = recibo.id - Cliente puede ver el recibo en su historial
Pago Rechazado
- Webhook llega con status "rejected"
- Se actualiza
portal_payments.status = 'rejected' - Se guarda respuesta del gateway para análisis
- Cliente puede ver el intento fallido y volver a intentar
Idempotencia de Webhooks
- Gateway puede enviar el mismo webhook múltiples veces
- Se verifica
portal_payments.statusantes de procesar - Si ya está "approved", se ignora el webhook
- Evita crear recibos duplicados
Gateway No Configurado
- Tenant no tiene
payment_gatewayconfigurado (o es "none") - Se retorna error: "Medio de pago no configurado"
- Cliente solo puede usar cupones de pago
Validaciones de Negocio
- El tenant debe tener un gateway configurado (no "none")
- El pago debe tener facturas válidas asociadas
- El monto total debe coincidir con la suma de facturas
- El webhook debe tener firma válida (seguridad)
- No se puede procesar un pago que ya fue aprobado (idempotencia)
Próximos Pasos
- Ver implementación específica de MercadoPago en ../../integrations/payment-gateways/mercadopago.md
- Configurar webhooks en la consola del gateway
- Probar flujo completo en ambiente de testing