Appearance
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:
- 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.
- 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).
- 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:
- Presupuesto (
YearlyBudget): Provee las 4 secciones planificadas:ordinaryIncome(Ingresos Ordinarios proyectados).extraordinaryIncome(Ingresos Extraordinarios proyectados).ordinaryExpense(Gastos Ordinarios presupuestados).extraordinaryExpense(Gastos Extraordinarios presupuestados).
- Egresos Reales (
ExpenseRecord[]): Registros capturados en el módulo de Egresos. - 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:
- Sin enlace por ID: Ni
BankMovementniRegisteredPaymentRecordalmacenan el campobudgetItemId. - Props Faltantes:
BudgetViewyBudgetComparisonViewno reciben la lista depaymentRecordsni degeneratedDebts. Únicamente recibenbankMovements: BankMovement[]. - 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 = 0transactionCount = 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:
- Paso de Props: Inyectar
paymentRecords: RegisteredPaymentRecord[]ygeneratedDebts: GeneratedDebt[]enBudgetViewyBudgetComparisonView. - Resolución de Partida de Ingreso:
- Si el movimiento bancario proviene de un cobro de alícuota ordinaria (
fundType === 'ordinary'odebt.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')odebt.concept.includes('Multa')), atribuir a las partidas de ingresos por intereses o penalidades.
- Si el movimiento bancario proviene de un cobro de alícuota ordinaria (
- Mapeo por Fallback Semántico: Si no se dispone de
generatedDebts, evaluar palabras clave semánticas:typescriptconst 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étrica | Fórmula para Egresos | Fórmula para Ingresos | Interpretación |
|---|---|---|---|
Presupuestado (budgeted) | Anual o suma de meses seleccionados | Anual o suma de meses seleccionados | Techo o meta aprobada |
Real Ejecutado (real) | Suma de gastos con estado no cancelado | Suma de movimientos de ingreso | Flujo 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) * 100 | Nivel 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
Presupuestoes 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:
- Mantener en Presupuesto: La herramienta de edición, calibración de montos mensuales y reasignación por traslados.
- 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.