Saltar al contenido
Volver a proyectos
Profesional
2021 – 2026

Portal SaaS y CRM de un ERP contable

El portal donde los clientes compran, renuevan y administran su licencia, y donde la empresa gestiona su operación comercial.

40+

módulos de negocio

4

pasarelas de pago

7

bases de datos integradas

El problema

Un ERP vendido por licencias necesita mucho más que un botón de pago: catálogo y cotizaciones, renovaciones, activación de instancias, seguimiento comercial, capacitaciones, certificaciones, tickets de soporte y facturación de todo lo anterior. Todo eso creció durante años sobre tecnología web de generaciones distintas y siguió en producción, con clientes reales pagando a través de él todos los días.

La solución

Portal con más de cuarenta módulos de negocio que sostengo y amplío: licenciamiento, cotizaciones, seguimiento comercial, capacitaciones, tickets, encuestas, agenda, tableros y campañas. Convive tecnología de varias épocas sobre una misma base, con trabajos programados que ejecutan la facturación recurrente y las notificaciones, y notificaciones en vivo hacia el navegador.

La decisión técnica que lo sostiene

Cuatro pasarelas de pago distintas, cada una con su propia forma de cobrar, tokenizar una tarjeta y notificar el resultado. Meterlas en el flujo de cobro habría convertido ese flujo en un nudo imposible de tocar. Cada pasarela está detrás de una estrategia con la misma interfaz: el flujo de cobro no sabe con cuál está hablando, y añadir una quinta no obliga a modificar ni una línea del código que ya funciona. Cuando una pasarela cae, se conmuta a otra por configuración en lugar de por despliegue.

El resultado

Cobro en línea operativo por cuatro vías simultáneas, renovaciones y facturación recurrente ejecutándose solas, y una base heredada que sigue evolucionando en lugar de congelarse.

Cómo se ve por dentro

Ejemplos ilustrativos de los patrones aplicados, con la razón de cada decisión.

El flujo de cobro no sabe qué pasarela está usando

csharp
public interface IPasarelaPago
{
    string Codigo { get; }
    Task<ResultadoPago> CobrarAsync(SolicitudPago solicitud, CancellationToken ct);
    Task<ResultadoPago> ConsultarAsync(string referencia, CancellationToken ct);
}

public sealed class SelectorPasarela(IEnumerable<IPasarelaPago> pasarelas,
                                     IOptionsMonitor<OpcionesCobro> opciones)
{
    public IPasarelaPago Activa() =>
        pasarelas.Single(p => p.Codigo == opciones.CurrentValue.PasarelaPreferida);
}

Una interfaz común y un selector por configuración. Añadir una pasarela es escribir una clase; conmutar de proveedor cuando uno falla es cambiar un valor, no desplegar una versión.

Ejemplo ilustrativo del patrón aplicado; no es código de ningún producto.

Stack del proyecto

¿Necesitas algo parecido?

Cuéntame tu caso y te digo con franqueza si es viable y cuánto toma.

Hablemos