Skip to content

Documentación Técnica y Funcional: Comparativa Presupuesto vs. Real (Ejecución Presupuestaria) ​

Módulo: Presupuesto (BudgetView.tsx / BudgetComparisonView.tsx)
Fecha: Septiembre 2026
Propósito: Explicar el funcionamiento, origen de datos, fórmulas matemáticas, diagnóstico del desfase en ingresos y hoja de ruta para su integración en el Módulo de Finanzas.


1. Propósito y Valor del Módulo ​

La vista Presupuesto vs. Real (Ejecución) es la herramienta de control financiero y de gestión del condominio. Su finalidad es:

  1. Monitoreo de Desviaciones: Contrastar en tiempo real lo proyectado en la asamblea ordinaria (Presupuesto Anual aprobado) contra la ejecución contable real que ocurre en la cuenta bancaria y en el registro de egresos.
  2. Semáforo de Sobregiro y Eficiencia: Identificar con antelación partidas en riesgo de sobregiro presupuestario (gastos que superan el 80% o el 100% de la cuota anual/mensual) o partidas de ingresos con baja recaudación (alta morosidad).
  3. Toma de Decisiones y Reasignación: Servir de base analítica para que la administración y el directorio decidan traslados presupuestarios entre partidas mediante el Asistente de Traslado antes de comprometer nuevos egresos.

2. Arquitectura y Origen de Datos ​

Actualmente, la vista comparativa reside en el componente src/components/budget/BudgetComparisonView.tsx, invocado desde src/components/BudgetView.tsx.

                      ┌────────────────────────────────────────┐
                      │          BudgetView.tsx                │
                      │  (Pestaña "Presupuesto vs. Real")      │
                      └──────────────────┬─────────────────────┘
                                         │ Props
                                         ▼
                      ┌────────────────────────────────────────┐
                      │       BudgetComparisonView.tsx         │
                      └────┬─────────────┬─────────────┬───────┘
                           │             │             │
        ┌──────────────────┘             │             └──────────────────┐
        ▼                                ▼                                ▼
┌──────────────┐               ┌──────────────────┐             ┌───────────────────┐
│ YearlyBudget │               │  ExpenseRecord[] │             │  BankMovement[]   │
│ (Planificado)│               │  (Egresos Reales)│             │ (Movimientos Bco) │
└──────────────┘               └──────────────────┘             └───────────────────┘

Fuentes de Información: ​

  1. Presupuesto (YearlyBudget): Provee las 4 secciones planificadas:
    • ordinaryIncome (Ingresos Ordinarios proyectados).
    • extraordinaryIncome (Ingresos Extraordinarios proyectados).
    • ordinaryExpense (Gastos Ordinarios presupuestados).
    • extraordinaryExpense (Gastos Extraordinarios presupuestados).
  2. Egresos Reales (ExpenseRecord[]): Registros capturados en el módulo de Egresos.
  3. Movimientos Bancarios (BankMovement[]): Movimientos registrados en la cuenta operativa.

3. Diagnóstico Forense: ¿Por qué los Egresos funcionan y los Ingresos marcan 0? ​

A. Mecanismo de Egresos (Funciona al 100%) ​

En el módulo de Egresos (CaptureExpenseMainView.tsx), al registrar un desembolso, el operador selecciona directamente una partida del presupuesto. Dicho registro guarda explícitamente:

  • e.budgetItemId: ID determinístico de la partida presupuestaria (ej. item-ordinaryExpense-1).
  • e.budgetCategory: Nombre canónico de la categoría (ej. EgOrd - 1.1 Mantenimiento de Ascensores).
  • e.budgetSubItemId: ID de la subpartida específica.

En BudgetComparisonView.tsx (líneas 98–104):

typescript
const matching = yearExpenses.filter((e) => {
  if (e.budgetItemId && e.budgetItemId === item.id) return true; // <-- Coincidencia exacta por ID
  const cat = (e.budgetCategory || '').toLowerCase();
  if (cat.includes(itemNameClean)) return true;
  if (itemCodeClean && cat.includes(itemCodeClean)) return true;
  return false;
});

Dado que existe un enlace directo por ID (e.budgetItemId === item.id), la suma acumulada (real) y el conteo de transacciones son exactos.


B. Mecanismo de Ingresos (Causa Raíz del 0) ​

En los ingresos (cobro de alícuotas, cuotas y pagos de residentes), la cadena de datos está desacoplada:

  1. Sin enlace por ID: Ni BankMovement ni RegisteredPaymentRecord almacenan el campo budgetItemId.
  2. Props Faltantes: BudgetView y BudgetComparisonView no reciben la lista de paymentRecords ni de generatedDebts. Únicamente reciben bankMovements: BankMovement[].
  3. Filtro Ingenuo por Substring: En BudgetComparisonView.tsx (líneas 115–123):
typescript
// Income
const matching = yearIncomeMovements.filter((m) => {
  const conc = (m.concept || '').toLowerCase();
  return conc.includes(itemNameClean); // <-- Búsqueda por subcadena exacta
});
  • Nombre de la partida presupuestaria (itemNameClean): "Cuotas Ordinarias de Mantenimiento".
  • Concepto real del movimiento bancario (m.concept): "Pago de adeudo Vivienda 101 - Cuota Ordinaria Mayo 2026" o "Pago — Vivienda 202 [Cuota de Mantenimiento ($90.00)]".

Como la subcadena "Cuotas Ordinarias de Mantenimiento" jamás coincide literalmente con "Pago de adeudo Vivienda 101...", el arreglo de coincidencias resulta siempre vacío (matching = []), provocando que:

  • real = 0
  • transactionCount = 0
  • El badge de "Ejecutado Real" en el editor de presupuesto quede oculto (ya que solo renderiza cuando realExec.count > 0).

4. Solución Técnica Propuesta para Resolver el Ejecutado de Ingresos ​

Para que los ingresos se computen con la misma robustez que los egresos sin alterar el núcleo contable:

  1. Paso de Props: Inyectar paymentRecords: RegisteredPaymentRecord[] y generatedDebts: GeneratedDebt[] en BudgetView y BudgetComparisonView.
  2. Resolución de Partida de Ingreso:
    • Si el movimiento bancario proviene de un cobro de alícuota ordinaria (fundType === 'ordinary' o debt.category === 'ordinary'), mapear automáticamente a la partida principal de Cuotas Ordinarias.
    • Si corresponde a cuota extraordinaria (fundType === 'extraordinary'), mapear a la partida de Cuotas Extraordinarias.
    • Si corresponde a intereses o multas (debt.concept.includes('Interés') o debt.concept.includes('Multa')), atribuir a las partidas de ingresos por intereses o penalidades.
  3. Mapeo por Fallback Semántico: Si no se dispone de generatedDebts, evaluar palabras clave semánticas:
    typescript
    const isOrdinaryFee = /cuota ordinaria|alícuota|mantenimiento/i.test(m.concept);
    const isExtraordinaryFee = /cuota extraordinaria|fondo reserva|obra/i.test(m.concept);

5. Fórmulas Matemáticas y Lógica de Semáforos ​

MétricaFórmula para EgresosFórmula para IngresosInterpretación
Presupuestado (budgeted)Anual o suma de meses seleccionadosAnual o suma de meses seleccionadosTecho o meta aprobada
Real Ejecutado (real)Suma de gastos con estado no canceladoSuma de movimientos de ingresoFlujo real ejecutado
Desviación / Saldo (variance)budgeted - real (Saldo por gastar)real - budgeted (Superávit / Déficit)Margen remanente
% de Ejecución(real / budgeted) * 100(real / budgeted) * 100Nivel de avance

Criterios de Semáforo: ​

  • Verde / Azul (<= 80% en egresos, >= 100% en ingresos): Ejecución saludable dentro de los parámetros previstos.
  • Ámbar (80% a 100% en egresos): Partida próxima al límite; alerta preventiva para el administrador.
  • Rojo (> 100% en egresos - Sobregiro): La partida ha sobrepasado el presupuesto aprobado en asamblea; requiere traslado presupuestario compensatorio.

6. Oportunidad Estratégica: Migración / Espejo hacia el Módulo de Finanzas ​

¿Por qué moverlo o habilitarlo en Finanzas? ​

Actualmente, la comparativa reside dentro de la pestaña Presupuesto. En la estructura del SaaS:

  • La pestaña Presupuesto es típicamente un espacio de configuración operativa del Administrador.
  • El módulo de Finanzas (FinancialsPreview.tsx) es el centro de rendición de cuentas y consulta, diseñado para tener vistas auditables para miembros del directorio y reportes transparentes para copropietarios.

Propuesta de Evolución: ​

  1. Mantener en Presupuesto: La herramienta de edición, calibración de montos mensuales y reasignación por traslados.
  2. Incorporar en Finanzas como Subsección (ej. budget_execution):
    • Una vista de solo lectura ejecutiva de la Ejecución Presupuestaria vs. Real, con filtros mensuales y anuales.
    • Acceso parametrizable por rol (administrador, directorio, auditor, residente).
    • Exportación de la matriz comparativa a PDF y Excel para asambleas de copropietarios.

Wiki Técnica Oficial — ITECEL ADM