Appearance
Diseño de Base de Datos - Portal Multi-Tenant
Estrategia Multi-Tenant
El Portal PWA reutiliza la arquitectura multi-tenant existente de Bautista ERP:
DB
ini(schemapublic): Configuración global del sistema- Nuevas tablas:
tenant_domains(mapeo dominios → tenants) - Tablas existentes:
sistema(empresas/sucursales)
- Nuevas tablas:
DB
{tenant}(schemapublic- LEVEL_EMPRESA): Datos específicos del tenant- Nuevas tablas:
portal_clients,portal_payments,portal_cupones - Tablas existentes:
ordcon(clientes),ordcta(cuenta corriente)
- Nuevas tablas:
Diagrama Entidad-Relación
┌────────────────────────────────────────────────────────────┐
│ DB: ini (Schema: public) - CONFIGURACIÓN GLOBAL │
├────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ sistema │◄────────┤ tenant_domains │ │
│ │ (existente) │ │ (nuevo) │ │
│ ├──────────────────┤ ├──────────────────┤ │
│ │ cnum (PK) │ │ id (PK) │ │
│ │ cnombre │ │ sistema_id (FK) │ │
│ │ ... │ │ domain (UNIQUE) │ │
│ └──────────────────┘ │ database │ │
│ │ schema_default │ │
│ │ branding_config │ │
│ │ status │ │
│ └──────────────────┘ │
│ │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ DB: {tenant} (Schema: public) - DATOS DEL TENANT │
├────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ ordcon │◄────────┤ portal_clients │ │
│ │ (existente) │ │ (nuevo) │ │
│ ├──────────────────┤ ├──────────────────┤ │
│ │ cnro (PK) │ │ id (PK - UUID) │ │
│ │ cnom │ │ cliente_id (FK) │ │
│ │ ccui (CUIT) │ │ dni_cuit │ │
│ │ ... │ │ email │ │
│ └────────┬─────────┘ │ phone │ │
│ │ │ last_login │ │
│ │ │ failed_attempts │ │
│ │ │ locked_until │ │
│ │ └──────────────────┘ │
│ │ │ │
│ │ ┌────────▼──────────┐ │
│ │ │ portal_payments │ │
│ │ │ (nuevo) │ │
│ │ ├───────────────────┤ │
│ │ │ id (PK - UUID) │ │
│ │ │ cliente_id (FK) │ │
│ │ │ payment_method │ │
│ │ │ amount │ │
│ │ │ status │ │
│ │ │ external_id │ │
│ │ │ facturas_pagadas │ │
│ │ │ recibo_id (FK) │ │
│ │ └───────────────────┘ │
│ │ │ │
│ │ ┌────────▼──────────┐ │
│ │ │ portal_cupones │ │
│ │ │ (nuevo) │ │
│ │ ├───────────────────┤ │
│ │ │ id (PK - UUID) │ │
│ │ │ cliente_id (FK) │ │
│ │ │ codigo_barras │ │
│ │ │ monto │ │
│ │ │ facturas (JSONB) │ │
│ │ │ estado │ │
│ │ │ fecha_vencimiento │ │
│ │ │ recibo_id (FK) │ │
│ │ └───────────────────┘ │
│ │ │
│ │ ┌──────────────────┐ │
│ └──────────────────►│ ordcta │ │
│ │ (existente) │ │
│ ├──────────────────┤ │
│ │ id (PK - UUID) │ │
│ │ cliente_id │ │
│ │ tipo_movimiento │ │
│ │ monto │ │
│ │ ... │ │
│ └──────────────────┘ │
│ │
└────────────────────────────────────────────────────────────┘Entidades Nuevas
1. tenant_domains (DB: ini)
Propósito de negocio: Mapeo de dominios a tenants/empresas para resolver automáticamente qué empresa está accediendo al portal según el dominio usado.
Campos clave:
domain: El dominio web usado para acceder (ej:ctacte.empresaA.com.ar)sistema_id: Referencia a la empresa en tablasistemadatabase: Nombre de la base de datos del tenantbranding_config: Configuración de marca (colores, logos, nombre de la app)status: Estado del dominio (activo, inactivo, suspendido)
Ejemplo de datos:
json
{
"domain": "ctacte.empresaA.com.ar",
"database": "empresa_a",
"branding_config": {
"app_name": "Portal Empresa A",
"short_name": "EmpA",
"logo_url": "https://cdn.example.com/logo-empresa-a.png",
"primary_color": "#1e40af",
"theme_color": "#1e40af"
},
"status": "active"
}2. portal_clients (DB: {tenant})
Propósito de negocio: Datos de acceso y seguridad de clientes al portal. Se crea automáticamente al primer login vinculando con el cliente existente en ordcon.
Campos clave:
cliente_id: Vincula con el cliente existente enordcondni_cuit: Credencial de identificación del clienteemail,phone: Datos de contactolast_login: Última vez que accediófailed_login_attempts: Intentos fallidos (para bloqueo temporal)locked_until: Fecha hasta la que está bloqueado (seguridad)
Relación con ordcon:
- Se busca el cliente en
ordconpor DNI/CUIT o ID de cliente - Si no existe en
portal_clients, se crea automáticamente desdeordcon
3. portal_payments (DB: {tenant})
Propósito de negocio: Histórico de pagos realizados vía portal (online o cupones). Permite rastrear pagos, reintentarlos en caso de falla, y vincularlos con los recibos generados.
Campos clave:
cliente_id: Cliente que realizó el pagopayment_method: Método usado (mercadopago, pagotic, cupón, etc.)amount: Monto total pagadostatus: Estado del pago (pending, approved, rejected, cancelled, refunded)external_id: ID del pago en el gateway externo (para evitar duplicados)facturas_pagadas: JSON con las facturas que se pagaronrecibo_id: Vincula con el recibo generado enordcta
Métodos de pago válidos: mercadopago, pagotic, pagomiscuentas, cupon, manual, none
Estados válidos: pending, approved, rejected, cancelled, refunded
Ejemplo de facturas_pagadas:
json
[
{
"id": "uuid-factura-1",
"tipo": "Factura A",
"numero": 123,
"monto": 10000.00
},
{
"id": "uuid-factura-2",
"tipo": "Factura B",
"numero": 456,
"monto": 5000.00
}
]Ejemplo de respuesta del gateway (external_response):
json
{
"payment_id": 1234567890,
"status": "approved",
"status_detail": "accredited",
"payment_type_id": "credit_card",
"transaction_amount": 15000.00,
"date_approved": "2026-01-20T14:30:00Z"
}4. portal_cupones (DB: {tenant})
Propósito de negocio: Cupones de pago generados por clientes para pagar en ubicaciones físicas. Incluyen código de barras único y fecha de vencimiento.
Campos clave:
cliente_id: Cliente que generó el cupóncodigo_barras: Código ITF de 19 dígitos (único)monto: Monto total del cupónfacturas: JSON con las facturas incluidas en el cupónestado: Estado del cupón (pending, used, expired, cancelled)fecha_vencimiento: Fecha límite para usar el cupónrecibo_id: Vincula con el recibo si el cupón fue usado
Estados válidos: pending, used, expired, cancelled
Estructura del código de barras (19 dígitos):
SUCU(4) + CLIENTE(6) + TIMESTAMP(8) + DV(1)
0001 + 056789 + 20260127 + 4 = 0001056789202601274Ejemplo de facturas en cupón:
json
[
{
"id": "uuid-factura-1",
"tipo": "Factura A",
"numero": 123,
"fecha": "2026-01-01",
"vencimiento": "2026-01-31",
"monto": 10000.00
}
]Entidades Existentes Reutilizadas
ordcon (Clientes)
Propósito: Tabla maestra de clientes del sistema ERP.
Campos usados por el portal:
cnro: ID del cliente (clave primaria)cnom: Nombre del clienteccui: CUIT del clientecemail: Email (opcional)ctel: Teléfono (opcional)
ordcta (Cuenta Corriente)
Propósito: Movimientos de cuenta corriente (facturas, recibos, notas).
Campos usados por el portal:
id: UUID del movimientocliente_id: Cliente del movimientotipo_movimiento: "Factura", "Recibo", "Nota de Crédito", etc.monto: Monto del movimientosaldo: Saldo pendientefecha: Fecha del movimientovencimiento: Fecha de vencimiento (para facturas)
Uso en portal:
- Consulta de deudas: Buscar facturas con saldo > 0
- Generación de recibos: Crear nuevo movimiento tipo "Recibo" al aprobar pago
Flujos de Datos Clave
Identificación de Cliente
- Cliente ingresa DNI/CUIT
- Se busca en
portal_clientspordni_cuit - Si no existe, se busca en
ordcony se crea entrada enportal_clients
Consulta de Deudas
- Buscar en
ordctamovimientos del cliente - Filtrar por tipo "Factura" y saldo > 0
- Ordenar por fecha de vencimiento
Proceso de Pago Online
- Cliente selecciona facturas a pagar
- Se crea registro en
portal_paymentscon estado "pending" - Se redirige al gateway de pago con
external_idúnico - Gateway notifica resultado vía webhook
- Se actualiza
portal_paymentscon respuesta del gateway - Si aprobado, se genera recibo en
ordctay se vincula
Generación de Cupón
- Cliente selecciona facturas
- Se genera código de barras único (19 dígitos)
- Se crea registro en
portal_cuponescon estado "pending" - Se genera PDF con código de barras
- Cuando se usa físicamente, se marca como "used" y se vincula recibo