Skip to content

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 pago

Patró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 paga
  • facturas: Array con las facturas a pagar
  • total: Monto total a pagar
  • tenantContext: Contexto del tenant (configuración)

Flujo de negocio:

  1. Obtener configuración del gateway del tenant
  2. Validar que el tenant tenga un medio de pago configurado
  3. Crear adapter mediante factory
  4. Generar payment_id único
  5. Crear pago en el gateway externo
  6. Guardar registro en portal_payments con estado "pending"
  7. 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 webhook
  • body: Datos del webhook
  • tenantContext: Contexto del tenant

Flujo de negocio:

  1. Obtener configuración del gateway
  2. Crear adapter
  3. Validar firma del webhook (seguridad)
  4. Procesar datos del webhook
  5. Verificar idempotencia (evitar procesamiento duplicado)
  6. Si el pago fue aprobado:
    • Actualizar portal_payments con estado "approved"
    • Crear recibo en CtaCte usando ReciboRelationsService
    • Vincular recibo con el pago
  7. Si el pago fue rechazado:
    • Actualizar portal_payments con estado "rejected"
    • Guardar respuesta del gateway para debug

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 cliente
  • tenantContext: 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: MercadoPago
  • pagotic: Pago TIC
  • pagomiscuentas: PagoMisCuentas
  • none: Sin medio de pago (solo cupones)

Configuración por tenant: Cada tenant tiene configurado en ini.sistemas:

  • payment_gateway: Nombre del gateway
  • payment_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

  1. Cliente selecciona facturas en el portal
  2. Frontend llama a /api/portal/pagos/iniciar
  3. Backend crea registro en portal_payments (pending)
  4. Backend redirige al cliente al gateway de pago
  5. Cliente completa el pago en el gateway
  6. Gateway notifica resultado vía webhook a /api/portal/pagos/webhook
  7. Backend valida webhook y procesa resultado
  8. Si aprobado: Se crea recibo en CtaCte y se vincula
  9. Frontend muestra confirmación al cliente

Casos de Uso

Pago Aprobado

  1. Webhook llega con status "approved"
  2. Se actualiza portal_payments.status = 'approved'
  3. Se crea recibo en ordcta usando ReciboRelationsService
  4. Se vincula portal_payments.recibo_id = recibo.id
  5. Cliente puede ver el recibo en su historial

Pago Rechazado

  1. Webhook llega con status "rejected"
  2. Se actualiza portal_payments.status = 'rejected'
  3. Se guarda respuesta del gateway para análisis
  4. Cliente puede ver el intento fallido y volver a intentar

Idempotencia de Webhooks

  1. Gateway puede enviar el mismo webhook múltiples veces
  2. Se verifica portal_payments.status antes de procesar
  3. Si ya está "approved", se ignora el webhook
  4. Evita crear recibos duplicados

Gateway No Configurado

  1. Tenant no tiene payment_gateway configurado (o es "none")
  2. Se retorna error: "Medio de pago no configurado"
  3. 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

  1. Ver implementación específica de MercadoPago en ../../integrations/payment-gateways/mercadopago.md
  2. Configurar webhooks en la consola del gateway
  3. Probar flujo completo en ambiente de testing