erp-core/docs/04-modelado/requerimientos-funcionales/mgn-016/RF-MGN-016-001-integracion-mercadopago.md

8.6 KiB

RF-MGN-016-001: Integración MercadoPago

Módulo: MGN-016 - Integraciones de Pagos y POS Prioridad: P1 Story Points: 13 Estado: Definido Fecha: 2025-12-05

Descripción

El sistema debe permitir a los tenants conectar su cuenta de MercadoPago para procesar pagos de sus clientes finales. Esto incluye pagos con tarjeta (presencial y online), pagos en efectivo (OXXO), transferencias SPEI, y el uso de terminales Point de MercadoPago.

Actores

  • Actor Principal: Tenant Admin (configura integración)
  • Actores Secundarios:
    • Vendedor/Cajero (procesa pagos)
    • Cliente final (realiza pago)
    • MercadoPago API (procesa transacción)

Precondiciones

  1. Tenant debe tener suscripción activa con feature mercadopago_enabled
  2. Tenant Admin debe tener credenciales de MercadoPago (o crearlas vía OAuth)
  3. Cuenta MercadoPago debe estar verificada

Flujo Principal - Configurar Integración

  1. Tenant Admin accede a "Configuración > Integraciones > Pagos"
  2. Sistema muestra proveedores disponibles
  3. Admin selecciona "Conectar MercadoPago"
  4. Sistema redirige a MercadoPago OAuth
  5. Admin autoriza acceso a la aplicación
  6. MercadoPago retorna access_token y refresh_token
  7. Sistema almacena tokens encriptados
  8. Sistema verifica conexión exitosa
  9. Admin configura opciones adicionales (terminales, notificaciones)

Flujo Alternativo - Procesar Pago con Terminal Point

  1. Vendedor crea venta en sistema (o selecciona orden existente)
  2. Vendedor selecciona "Cobrar con MercadoPago"
  3. Sistema crea Payment Intent via API
  4. Sistema envía intent a terminal Point vinculada
  5. Cliente presenta tarjeta/NFC en terminal
  6. Terminal procesa y envía resultado a MercadoPago
  7. MercadoPago envía webhook con confirmación
  8. Sistema actualiza estado de pago
  9. Sistema genera recibo

Flujo Alternativo - Pago con OXXO

  1. Vendedor crea cobro con método "OXXO"
  2. Sistema genera referencia de pago via API
  3. Sistema muestra/imprime ficha de pago con:
    • Referencia OXXO
    • Monto
    • Fecha de vencimiento
  4. Cliente paga en tienda OXXO
  5. MercadoPago envía webhook de confirmación (24-48h)
  6. Sistema actualiza estado de pago

Métodos de Pago Soportados

Método Tipo Comisión Tiempo de Acreditación
Tarjeta Crédito (presencial) card_present 3.49% + IVA Inmediato
Tarjeta Débito (presencial) card_present 2.49% + IVA Inmediato
Tarjeta Online card_not_present 3.49% + IVA Inmediato
OXXO ticket $10 MXN + IVA 24-48h
SPEI bank_transfer $7 MXN + IVA Inmediato
Mercado Crédito credit 4.99% + IVA Inmediato

Reglas de Negocio

  • RN-1: Tokens OAuth se refrescan automáticamente antes de expirar
  • RN-2: Pagos fallidos se reintentan hasta 3 veces
  • RN-3: Webhooks deben validar firma HMAC
  • RN-4: Montos se expresan en centavos (int) para la API
  • RN-5: IPN URL debe ser HTTPS con certificado válido
  • RN-6: Reembolsos solo hasta 180 días después del pago
  • RN-7: Un tenant puede tener múltiples terminales Point

Criterios de Aceptación

  • Tenant Admin puede conectar cuenta MercadoPago vía OAuth
  • Sistema almacena tokens de forma segura (encriptados)
  • Sistema refresca tokens automáticamente
  • Vendedor puede procesar pago con tarjeta presencial
  • Vendedor puede generar ficha de pago OXXO
  • Sistema recibe y procesa webhooks correctamente
  • Dashboard muestra transacciones de MercadoPago
  • Admin puede desconectar integración
  • Logs de todas las transacciones disponibles

Entidades Involucradas

integrations.payment_providers

CREATE TABLE integrations.payment_providers (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES core_tenants.tenants(id),
    provider_code VARCHAR(50) NOT NULL, -- 'mercadopago', 'clip', 'stripe'
    display_name VARCHAR(100),
    is_active BOOLEAN DEFAULT true,
    is_default BOOLEAN DEFAULT false,
    config JSONB DEFAULT '{}', -- Configuración específica
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT uq_provider_tenant UNIQUE (tenant_id, provider_code)
);

integrations.payment_credentials

CREATE TABLE integrations.payment_credentials (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    provider_id UUID NOT NULL REFERENCES integrations.payment_providers(id),
    credential_type VARCHAR(50) NOT NULL, -- 'oauth', 'api_key'
    -- Todos los campos sensibles encriptados con AES-256
    access_token_encrypted BYTEA,
    refresh_token_encrypted BYTEA,
    expires_at TIMESTAMPTZ,
    merchant_id VARCHAR(100), -- ID de cuenta en MercadoPago
    environment VARCHAR(20) DEFAULT 'sandbox', -- 'sandbox', 'production'
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

integrations.payment_transactions

CREATE TABLE integrations.payment_transactions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,
    provider_id UUID NOT NULL REFERENCES integrations.payment_providers(id),

    -- Referencias internas
    order_id UUID, -- Orden de venta relacionada
    invoice_id UUID, -- Factura relacionada

    -- Datos de MercadoPago
    external_id VARCHAR(100), -- ID en MercadoPago
    external_reference VARCHAR(100), -- Nuestra referencia enviada
    payment_type VARCHAR(50), -- card, ticket, bank_transfer
    payment_method VARCHAR(50), -- visa, mastercard, oxxo, spei

    -- Montos
    amount DECIMAL(15,2) NOT NULL,
    currency VARCHAR(3) DEFAULT 'MXN',
    fee_amount DECIMAL(15,2), -- Comisión cobrada
    net_amount DECIMAL(15,2), -- Monto neto recibido

    -- Estado
    status VARCHAR(50) NOT NULL, -- pending, approved, rejected, refunded
    status_detail VARCHAR(100),

    -- Tarjeta (si aplica)
    card_last_four VARCHAR(4),
    card_brand VARCHAR(20),

    -- Terminal (si aplica)
    terminal_id UUID REFERENCES integrations.payment_terminals(id),

    -- Timestamps
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    approved_at TIMESTAMPTZ,

    -- Metadata
    raw_response JSONB, -- Respuesta completa de la API

    CONSTRAINT chk_status CHECK (status IN ('pending', 'approved', 'rejected', 'cancelled', 'refunded', 'in_process'))
);

API de MercadoPago

Crear Payment Intent

// POST https://api.mercadopago.com/v1/payments
const paymentData = {
  transaction_amount: 1500.00,
  description: "Venta #ORD-2025-001",
  payment_method_id: "visa",
  payer: {
    email: "cliente@email.com"
  },
  external_reference: "ORD-2025-001",
  notification_url: "https://erp.example.com/webhooks/mercadopago",
  metadata: {
    tenant_id: "uuid-tenant",
    order_id: "uuid-order"
  }
};

Procesar Webhook

// POST /webhooks/mercadopago
interface MercadoPagoWebhook {
  id: string;
  type: 'payment' | 'merchant_order';
  action: 'payment.created' | 'payment.updated';
  data: {
    id: string; // Payment ID
  };
}

// Validar firma
const isValid = validateMercadoPagoSignature(
  request.headers['x-signature'],
  request.body,
  webhookSecret
);

Terminales Point

Modelos Soportados

Modelo Conectividad Características
Point Smart WiFi, 4G Pantalla táctil, impresora
Point Pro 2 Bluetooth Portable, NFC
Point Mini Bluetooth Básico, económico

Vincular Terminal

// POST /api/v1/integrations/mercadopago/terminals
{
  serialNumber: "MP-123456789",
  displayName: "Caja 1",
  locationId: "uuid-sucursal"
}

Seguridad

  1. OAuth Tokens: Encriptados con AES-256-GCM
  2. Webhook Signature: HMAC-SHA256 validation
  3. HTTPS: Obligatorio para todos los endpoints
  4. Rate Limiting: Respeto de límites de API
  5. Audit Log: Todas las transacciones logueadas

Manejo de Errores

Código Descripción Acción
cc_rejected_insufficient_amount Fondos insuficientes Notificar, solicitar otro método
cc_rejected_bad_filled_card_number Número inválido Solicitar re-ingreso
cc_rejected_call_for_authorize Llamar al banco Contactar emisor
pending_contingency En revisión Esperar webhook

Referencias

Dependencias

  • RF Requeridos: Ninguno (módulo base)
  • Bloqueante para: RF-MGN-016-004 (Gestión de Terminales), RF-MGN-016-005 (Conciliación)