Volver al blog
El panel del optimizador fiscal foral: el ahorro identificado del ejercicio en grande, la barra del crédito vitalicio de vivienda agotado a 36.000 €, y el desglose por vivienda, EPSV e inversiones, con el pie que recuerda que todo es una proyección del mismo log de eventos y que la herramienta es orientativa.

Un simulador de la Renta foral de Bizkaia

LaboratorioEvent sourcingFiscalidadReact

Las hojas de cálculo con las que la gente planifica su fiscalidad tienen todas el mismo defecto: no se pueden deshacer. Pruebas a amortizar hipoteca, la celda cambia, y ya no sabes cuál era el número de antes ni por qué lo habías puesto. Cuando además las decisiones se pisan entre sí —lo que aportas a un plan de pensiones cambia la base que decide si puedes deducirte la vivienda— la hoja deja de ser una herramienta y pasa a ser una fuente de errores con formato bonito.

El experimento fue construir esa herramienta para la normativa foral de Bizkaia de 2026 con una restricción autoimpuesta: que el estado no se pueda modificar nunca, solo derivarse. Event sourcing en una calculadora de andar por casa, a ver si aguanta o si es artillería para matar moscas.

El log es la verdad; la pantalla, una opinión

No hay estado guardado. Hay una lista de hechos que ocurrieron —fijaste este campo, añadiste esta posición, registraste esta venta— y el estado es lo que sale de recorrerla desde cero. Dos funciones, y ninguna tiene misterio:

// El estado nunca se muta directamente: es la proyección de un log de eventos
// { id, ts, type, payload }. Reproducir el log desde el estado inicial
// reconstruye exactamente el estado actual (y los perfiles guardan el log).
export function reducirEvento(estado, ev) {
  const p = ev.payload || {};
  switch (ev.type) {
    case "CAMPO_FIJADO":
      return { ...estado, [p.campo]: p.valor };

    case "POSICION_ANADIDA":
      return { ...estado, cartera: [...(estado.cartera || []), p] };

    // …
  }
}

export const proyectar = (eventos, inicial) =>
  (eventos || []).reduce(reducirEvento, inicial);

De ahí salen tres cosas gratis que en la versión con estado mutable habrían costado trabajo. Deshacer es quitar el último evento. Guardar un perfil es guardar el log, no el resultado, así que al abrirlo se reproduce entero y sabes por qué cada número es el que es. Y comparar dos escenarios es comparar dos listas, no dos hojas.

Lo que sí obligó a pensar fue el deshacer de las decisiones grandes. Cuando aplicas un plan de desinversión no se emite un evento: se emiten muchos, uno por venta. Deshacerlo truncando el historial es tentador y está mal, porque borra hechos que sí ocurrieron. Se revierte con eventos compensatorios: hechos nuevos que anulan a los anteriores y dejan el rastro completo de que hubo un plan y de que se retiró.

La regla del 3 % obliga a trocear por años

El caso que justifica todo lo anterior es la desinversión. La norma foral permite tributar determinadas ventas a un gravamen especial del 3 % siempre que el valor de transmisión del ejercicio sea inferior a 10.000 €. Por encima, régimen general. Con una cartera de cierto tamaño, la pregunta deja de ser «¿cuánto pago?» y pasa a ser «¿en qué orden y en cuántos años vendo?».

El planificador reparte: lo que va por régimen general se vende entero en el primer ejercicio, y lo que se acoge al 3 % se trocea en tramos que nunca llegan al límite, saltando de año cuando se agota el hueco. Es un caso de uso de dominio puro —entra una cartera, salen los hechos que habría que registrar— y por eso se puede probar sin abrir la aplicación.

Lo que es oficial y lo que es mi modelo

Esta es la parte de la que estoy más satisfecho, y no es código. Una calculadora fiscal escrita por alguien que no es asesor fiscal tiene un problema de honestidad antes que de exactitud: hay cifras que salen del boletín oficial y hay cifras que salen de mis suposiciones, y mezclarlas es lo que convierte una herramienta útil en una trampa.

La suite de validación separa las dos cosas explícitamente. Sesenta y tres de las comprobaciones se contrastan contra la fuente publicada: las escalas del ahorro y la general de 2026, tramo a tramo contra la columna de cuotas; el ejemplo resuelto de deducción de vivienda de la guía de la Hacienda Foral, reproducido al céntimo; los límites de aportación y la frontera del 3 % ya descrita.

Otras van marcadas como modelo: la cotización social, la bonificación de rendimientos del trabajo, la simplificación del autónomo. Ahí no hay una cifra oficial que reproducir, así que se validan por coherencia interna y se dice que son aproximaciones. La suite entera son 155 comprobaciones y pasan todas; lo que importa no es el número, sino que al leer un resultado sepas de qué lado de esa línea viene.

155comprobaciones, todas en verde
63contra fuente oficial publicada
322líneas del motor de cálculo
0estado mutable

¿Compensó el event sourcing?

Para una calculadora de un solo usuario, sin concurrencia y sin auditoría real, la respuesta honesta es que es más de lo que el problema pedía. Un estado mutable con un historial de deshacer habría tardado menos.

Compensó por otro sitio. Lo que arreglaron los eventos no fue el deshacer: fue poder responder «¿de dónde sale este número?». Cuando el resultado depende de cuatro decisiones que se afectan entre sí, y el usuario vuelve tres semanas después, la diferencia entre un estado opaco y un log legible es la diferencia entre fiarse de la herramienta o no. Esa es la propiedad que me llevo, y es la misma que pido en un sistema de empresa donde alguien va a preguntar por qué se cobró lo que se cobró.

Límites, y uno importante

  • No es asesoramiento fiscal. Es una herramienta de divulgación construida leyendo las normas forales. La norma vigente manda siempre, y una interpretación equivocada mía no deja de serlo porque la suite esté en verde.
  • Un único territorio y un único ejercicio. Bizkaia, 2026. Las escalas están escritas en el motor; llevarlo a otro territorio foral no es configurarlo, es volver a leerse otra norma.
  • Caduca. Cada norma de presupuestos mueve tarifas y límites. Sin alguien que revise las fuentes cada año, esto envejece solo — y una calculadora fiscal desactualizada es peor que no tener ninguna.

El patrón sí viaja, aunque el contenido caduque: normativa compleja convertida en funciones puras, una suite que distingue lo que dice el boletín de lo que supone el autor, y un log de decisiones en vez de un estado que se pisa. Sirve igual para calcular una nómina, una tarifa regulada o una comisión con tramos. El simulador completo es público y está en el repositorio de GitHub.

Zetesis-Labs/optimizador-fiscal-bizkaia

Simulador de la Renta foral de Bizkaia: crédito de vivienda, regla del 3 %, EPSV y cartera.

JavaScript

Más del laboratorio