fiscal-es 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/LICENSE +21 -0
- package/README.md +116 -2
- package/cases/SCHEMA.md +68 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-001.yaml +20 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-002.yaml +19 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-003.yaml +21 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-004.yaml +21 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-005.yaml +20 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-006.yaml +22 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-007.yaml +22 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-008.yaml +23 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-009.yaml +22 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-010.yaml +20 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-011.yaml +22 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-012.yaml +22 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-013.yaml +23 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-014.yaml +23 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-015.yaml +22 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-016.yaml +22 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-017.yaml +23 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-018.yaml +20 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-019.yaml +21 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-020.yaml +21 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-021.yaml +21 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-022.yaml +21 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-023.yaml +23 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-024.yaml +21 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-025.yaml +22 -0
- package/cases/irpf/ahorro/irpf-ahorro-2026-026.yaml +22 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-001.yaml +21 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-002.yaml +22 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-003.yaml +22 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-004.yaml +25 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-005.yaml +25 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-006.yaml +21 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-007.yaml +23 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-008.yaml +20 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-009.yaml +21 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-010.yaml +21 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-011.yaml +24 -0
- package/cases/irpf/compensacion/irpf-compensacion-2026-012.yaml +23 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.js +20 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +4 -0
- package/dist/money.d.ts +32 -0
- package/dist/money.js +65 -0
- package/dist/tables/2026.d.ts +28 -0
- package/dist/tables/2026.js +16 -0
- package/dist/tables/index.d.ts +6 -0
- package/dist/tables/index.js +14 -0
- package/dist/tables/tipos.d.ts +21 -0
- package/dist/tables/tipos.js +1 -0
- package/dist/tax/brackets.d.ts +7 -0
- package/dist/tax/brackets.js +18 -0
- package/dist/tax/offsetting.d.ts +10 -0
- package/dist/tax/offsetting.js +13 -0
- package/dist/tax/savings.d.ts +6 -0
- package/dist/tax/savings.js +44 -0
- package/dist/tax/tipos.d.ts +23 -0
- package/dist/tax/tipos.js +1 -0
- package/package.json +53 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
**Breaking: all public identifiers renamed to English** (ADR-009). The computation is unchanged: every verified
|
|
6
|
+
case in `cases/` gives the same output as in 0.1.0. The YAML keys of the cases do not change.
|
|
7
|
+
|
|
8
|
+
Error messages are now in English.
|
|
9
|
+
|
|
10
|
+
| 0.1.0 | 1.0.0 |
|
|
11
|
+
| ----- | ----- |
|
|
12
|
+
| `Centimos` | `Cents` |
|
|
13
|
+
| `Bp`, `bp`, `parseEuros`, `formatEuros` | unchanged |
|
|
14
|
+
| `CERO` | `ZERO` |
|
|
15
|
+
| `sumar` | `add` |
|
|
16
|
+
| `restar` | `subtract` |
|
|
17
|
+
| `max0` | `clampZero` |
|
|
18
|
+
| `porBp` | `timesBp` |
|
|
19
|
+
| `redondearCentimos` | `roundCents` |
|
|
20
|
+
| `calcularAhorro` | `computeSavingsTax` |
|
|
21
|
+
| `EntradaAhorro` | `SavingsInput` |
|
|
22
|
+
| `EntradaAhorro.ejercicio` | `SavingsInput.taxYear` |
|
|
23
|
+
| `EntradaAhorro.gananciasPatrimoniales` | `SavingsInput.capitalGains` |
|
|
24
|
+
| `EntradaAhorro.perdidasPatrimoniales` | `SavingsInput.capitalLosses` |
|
|
25
|
+
| `EntradaAhorro.rendimientosCapitalMobiliario` | `SavingsInput.investmentIncome` |
|
|
26
|
+
| `ResultadoAhorro` | `SavingsResult` |
|
|
27
|
+
| `ResultadoAhorro.baseLiquidableAhorro` | `SavingsResult.savingsTaxableBase` |
|
|
28
|
+
| `ResultadoAhorro.cuotaEstatal` | `SavingsResult.stateTax` |
|
|
29
|
+
| `ResultadoAhorro.cuotaAutonomica` | `SavingsResult.regionalTax` |
|
|
30
|
+
| `ResultadoAhorro.cuotaAhorro` | `SavingsResult.totalTax` |
|
|
31
|
+
| `getTabla` | `getTaxTable` |
|
|
32
|
+
| `ejerciciosDisponibles` | `availableTaxYears` |
|
|
33
|
+
| `TablaIRPF` | `TaxTable` |
|
|
34
|
+
| `TablaIRPF.ejercicio` | `TaxTable.taxYear` |
|
|
35
|
+
| `TablaIRPF.fuente` / `fuente.verificado` | `TaxTable.source` / `source.verifiedOn` |
|
|
36
|
+
| `TablaIRPF.escalaAhorro` | `TaxTable.brackets` |
|
|
37
|
+
| `TramoAhorro` | `TaxBracket` |
|
|
38
|
+
| `TramoAhorro.hasta` / `estatalBp` / `autonomicoBp` | `TaxBracket.upTo` / `stateBp` / `regionalBp` |
|
|
39
|
+
| `EjercicioSinTabla` (`.ejercicio`, `name`) | `UnknownTaxYear` (`.taxYear`, `name`) |
|
|
40
|
+
| `EntradaInvalida` (`.campo`, `.valor`, `name`) | `InvalidInput` (`.field`, `.value`, `name`) |
|
|
41
|
+
|
|
42
|
+
## 0.1.0
|
|
43
|
+
|
|
44
|
+
First release.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Miguel Vidal Bellido
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,117 @@
|
|
|
1
|
-
#
|
|
1
|
+
# fiscal-es
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Spanish personal income tax (IRPF) on the savings base (Spain, common territory): integrates capital gains, capital
|
|
4
|
+
losses and investment income for one tax year and applies the state and regional scales separately.
|
|
5
|
+
|
|
6
|
+
TypeScript, ESM, no runtime dependencies, pure functions. Amounts in integer cents (`Cents`) and rates in integer
|
|
7
|
+
basis points (`Bp`); never floating point.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install fiscal-es
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
ESM only (`import`); there is no CommonJS build.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Computing the savings tax
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import { computeSavingsTax, formatEuros, parseEuros } from "fiscal-es";
|
|
23
|
+
|
|
24
|
+
const r = computeSavingsTax({
|
|
25
|
+
taxYear: 2026,
|
|
26
|
+
capitalGains: parseEuros("10000.00"),
|
|
27
|
+
capitalLosses: parseEuros("3000.00"),
|
|
28
|
+
investmentIncome: parseEuros("0.00"),
|
|
29
|
+
});
|
|
30
|
+
// r = { savingsTaxableBase: 700000, stateTax: 67500, regionalTax: 67500, totalTax: 135000 }
|
|
31
|
+
formatEuros(r.totalTax); // "1350.00"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`parseEuros` only accepts the format `"-1234.56"` (decimal point, two decimals); anything else throws
|
|
35
|
+
`SyntaxError`. Input that makes no sense (non-integer amounts, negative gains or losses) throws `InvalidInput`;
|
|
36
|
+
a tax year without a table throws `UnknownTaxYear`.
|
|
37
|
+
|
|
38
|
+
### Available tax years
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
import { availableTaxYears, getTaxTable } from "fiscal-es";
|
|
42
|
+
|
|
43
|
+
for (const taxYear of availableTaxYears()) {
|
|
44
|
+
console.log(taxYear, getTaxTable(taxYear).source.verifiedOn); // 2026 "2026-10-25"
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Range and errors
|
|
49
|
+
|
|
50
|
+
The computation is exact for amounts up to ≈ 9 000 million euros per operation: with rates up to 10 000 bp, the
|
|
51
|
+
intermediate product cents × basis points fits in `Number.MAX_SAFE_INTEGER`. Above that, any operation whose result
|
|
52
|
+
or intermediate product leaves the safe integer range throws `RangeError`.
|
|
53
|
+
|
|
54
|
+
- `SyntaxError`: `parseEuros` receives a format other than `"-1234.56"` (see [Usage](#usage)).
|
|
55
|
+
- `InvalidInput`: `computeSavingsTax` receives an amount that is not an integer number of cents (`NaN`, a fraction
|
|
56
|
+
of a cent), negative gains or losses, or a non-integer tax year.
|
|
57
|
+
- `UnknownTaxYear`: `computeSavingsTax` receives a tax year without a table.
|
|
58
|
+
- `RangeError`: `parseEuros`, `add`, `subtract`, `timesBp` or `roundCents` receive or produce a value outside the
|
|
59
|
+
safe integer range.
|
|
60
|
+
|
|
61
|
+
## Supported tax years
|
|
62
|
+
|
|
63
|
+
| Tax year | Scale verified on |
|
|
64
|
+
| -------- | ----------------- |
|
|
65
|
+
| 2026 | 2026-10-25 |
|
|
66
|
+
|
|
67
|
+
## `cases/`: the executable spec
|
|
68
|
+
|
|
69
|
+
Each YAML file in `cases/` is a case with its input, the expected output to the cent, the legal reference and the
|
|
70
|
+
date on which a person verified it. The package's test suite runs all of them against the engine; a change to the
|
|
71
|
+
engine that alters the output of a verified case is a major version change. The format is described in
|
|
72
|
+
`cases/SCHEMA.md`. The cases are written in Spanish, with Spanish keys (`ganancias_patrimoniales`, `cuota_ahorro`…),
|
|
73
|
+
because they are checked against the Spanish tax return manual; [Terminology](#terminology) maps them to the API.
|
|
74
|
+
|
|
75
|
+
## Terminology
|
|
76
|
+
|
|
77
|
+
| Identifier | Spanish term | LIRPF |
|
|
78
|
+
| ---------- | ------------ | ----- |
|
|
79
|
+
| `computeSavingsTax` | cuota del ahorro | arts. 49, 50.2, 66.1 y 76 |
|
|
80
|
+
| `SavingsInput` / `SavingsResult` | entrada / resultado del ahorro | |
|
|
81
|
+
| `taxYear` | ejercicio | |
|
|
82
|
+
| `capitalGains` (`ganancias_patrimoniales`) | ganancias patrimoniales | art. 33 |
|
|
83
|
+
| `capitalLosses` (`perdidas_patrimoniales`) | pérdidas patrimoniales | art. 33 |
|
|
84
|
+
| `investmentIncome` (`rendimientos_capital_mobiliario`) | rendimientos del capital mobiliario | art. 25 |
|
|
85
|
+
| `savingsTaxableBase` (`base_liquidable_ahorro`) | base liquidable del ahorro | arts. 49 y 50.2 |
|
|
86
|
+
| `stateTax` (`cuota_estatal`) | cuota estatal | art. 66.1 |
|
|
87
|
+
| `regionalTax` (`cuota_autonomica`) | cuota autonómica | art. 76 |
|
|
88
|
+
| `totalTax` (`cuota_ahorro`) | cuota del ahorro (estatal + autonómica) | |
|
|
89
|
+
| `TaxTable` / `getTaxTable` / `availableTaxYears` | tabla normativa del ejercicio / ejercicios disponibles | |
|
|
90
|
+
| `TaxBracket` (`upTo`, `stateBp`, `regionalBp`) | tramo de la escala del ahorro (hasta, tipo estatal, tipo autonómico) | arts. 66.1 y 76 |
|
|
91
|
+
| `UnknownTaxYear` | ejercicio sin tabla | |
|
|
92
|
+
| `InvalidInput` | entrada inválida | |
|
|
93
|
+
| `Cents` / `Bp` | céntimos / puntos básicos | |
|
|
94
|
+
| `add` / `subtract` / `clampZero` / `ZERO` | sumar / restar / acotar a cero / cero | |
|
|
95
|
+
| `timesBp` / `roundCents` | céntimos × puntos básicos / redondeo al céntimo | |
|
|
96
|
+
|
|
97
|
+
## Known limitations
|
|
98
|
+
|
|
99
|
+
- No cross-offsetting: a negative balance of gains and losses does not offset positive investment income, nor the
|
|
100
|
+
other way round (art. 49.1 LIRPF). The negative balance simply is not taxed.
|
|
101
|
+
- No carry-forward of negative balances to the following four tax years (art. 49.2 LIRPF).
|
|
102
|
+
- No foral regimes (Navarra, País Vasco).
|
|
103
|
+
- Savings base only: does not compute the general base, personal allowances or deductions.
|
|
104
|
+
|
|
105
|
+
## Development in the monorepo
|
|
106
|
+
|
|
107
|
+
`exports` has a custom condition, `fiscal-es-src`, pointing to `src/` so the monorepo app can use the engine without
|
|
108
|
+
building it; external consumers do not enable it and get `dist/`.
|
|
109
|
+
|
|
110
|
+
## Disclaimer
|
|
111
|
+
|
|
112
|
+
A calculation tool. Not tax or financial advice. Check your situation against current legislation or with a
|
|
113
|
+
professional.
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
MIT
|
package/cases/SCHEMA.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Casos fiscales — esquema y reglas
|
|
2
|
+
|
|
3
|
+
Los ficheros `cases/**/*.yaml` son **la spec del motor**. A la vez: test, documentación y contrato público.
|
|
4
|
+
Un único test genérico (`tests/cases.test.ts`) los carga todos y ejecuta cada uno contra el motor.
|
|
5
|
+
Comparación exacta en céntimos. No hay tolerancias.
|
|
6
|
+
|
|
7
|
+
## Formato
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
id: irpf-ahorro-2026-002 # único; <área>-<tema>-<ejercicio>-<nnn>
|
|
11
|
+
title: Ganancia que cruza el primer tramo de la base del ahorro
|
|
12
|
+
ejercicio: 2026
|
|
13
|
+
estado: rojo # rojo | verde. Solo pasa a verde tras revisión humana del resultado.
|
|
14
|
+
normativa:
|
|
15
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
16
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
17
|
+
verificado: null # fecha ISO cuando una persona ha contrastado expected con la fuente; null si no
|
|
18
|
+
input:
|
|
19
|
+
ganancias_patrimoniales: "8000.00"
|
|
20
|
+
perdidas_patrimoniales: "0.00"
|
|
21
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
22
|
+
expected:
|
|
23
|
+
base_liquidable_ahorro: "8000.00"
|
|
24
|
+
cuota_estatal: "780.00" # 6000·9,5 % + 2000·10,5 %
|
|
25
|
+
cuota_autonomica: "780.00"
|
|
26
|
+
cuota_ahorro: "1560.00"
|
|
27
|
+
notas: >
|
|
28
|
+
Texto libre opcional: cómo se ha calculado a mano, dudas, referencias al manual de Renta.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Reglas de validación (el loader las aplica; un caso inválido hace fallar la suite)
|
|
32
|
+
|
|
33
|
+
1. Todo importe (`input.*` y `expected.*`) es un **string** decimal con exactamente dos decimales y punto.
|
|
34
|
+
Un número YAML (`8000`, `8000.0`) para dinero es un error. Motivo: ADR-002.
|
|
35
|
+
2. `id` único en todo `cases/`. El nombre del fichero es `<id>.yaml`.
|
|
36
|
+
3. `ejercicio` tiene que tener tabla en `src/tablas/`. Si no, el caso falla con un mensaje que lo diga.
|
|
37
|
+
4. `normativa` tiene al menos una entrada. Sin cita, no hay caso.
|
|
38
|
+
5. `estado: verde` exige `verificado` no nulo. El test lo comprueba: un caso verde sin verificación es un fallo.
|
|
39
|
+
6. Un cambio en `expected` de un caso existente exige cambiar `verificado` a `null` o a una fecha nueva.
|
|
40
|
+
(Esto lo comprueba la revisión humana y `fiscal-reviewer`, no el test.)
|
|
41
|
+
|
|
42
|
+
## Cómo se calcula (para quien escribe casos a mano)
|
|
43
|
+
|
|
44
|
+
- La base liquidable del ahorro = saldo de rendimientos del capital mobiliario + saldo de (ganancias − pérdidas).
|
|
45
|
+
En v1 cada saldo se integra por separado y **un saldo negativo se trata como cero**: ni compensa al otro saldo
|
|
46
|
+
(el 25 % cruzado del art. 49.1) ni se arrastra a ejercicios siguientes. Es una simplificación deliberada
|
|
47
|
+
(ADR-005); cuando se implemente la compensación cruzada se añadirán casos nuevos, no se cambiarán estos.
|
|
48
|
+
Consecuencias: pérdidas mayores que ganancias → saldo cero; rendimientos negativos → saldo cero.
|
|
49
|
+
- Cuota estatal y cuota autonómica se calculan **por separado**, cada una aplicando su escala por tramos a la
|
|
50
|
+
misma base, y cada una se redondea al céntimo. `cuota_ahorro` es la suma de las dos ya redondeadas.
|
|
51
|
+
Esto importa: 1.234,56 € × 9,5 % = 117,2832 → 117,28; dos veces = 234,56, mientras que 1.234,56 × 19 %
|
|
52
|
+
= 234,5664 → 234,57. El motor replica el cálculo de Renta, no el atajo.
|
|
53
|
+
|
|
54
|
+
## Qué NO va aquí
|
|
55
|
+
|
|
56
|
+
- Casos de UI, de formato o de URL. Eso es Vitest normal en `apps/web`.
|
|
57
|
+
- Simulaciones completas de N años. Eso es `packages/fiscal-es/tests/simulacion.test.ts` cuando exista
|
|
58
|
+
(y usa el motor caso a caso).
|
|
59
|
+
|
|
60
|
+
## Convención de carpetas
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
cases/
|
|
64
|
+
irpf/
|
|
65
|
+
ahorro/ # escala de la base del ahorro
|
|
66
|
+
compensacion/
|
|
67
|
+
README-por-area.md (opcional)
|
|
68
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-001
|
|
2
|
+
title: Ganancia dentro del primer tramo de la base del ahorro
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "5000.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "5000.00"
|
|
15
|
+
cuota_estatal: "475.00"
|
|
16
|
+
cuota_autonomica: "475.00"
|
|
17
|
+
cuota_ahorro: "950.00"
|
|
18
|
+
notas: >
|
|
19
|
+
5.000 × 9,5 % = 475,00 estatal; igual autonómico. Total 19 %.
|
|
20
|
+
Pendiente de verificar la escala vigente del ejercicio 2026 contra el manual de Renta.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-002
|
|
2
|
+
title: Ganancia que cruza el primer tramo de la base del ahorro
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "8000.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "8000.00"
|
|
15
|
+
cuota_estatal: "780.00"
|
|
16
|
+
cuota_autonomica: "780.00"
|
|
17
|
+
cuota_ahorro: "1560.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal: 6.000 × 9,5 % = 570,00 + 2.000 × 10,5 % = 210,00 → 780,00. Autonómico idéntico.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-003
|
|
2
|
+
title: Base que recorre todos los tramos de la escala del ahorro
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "350000.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "350000.00"
|
|
15
|
+
cuota_estatal: "43440.00"
|
|
16
|
+
cuota_autonomica: "43440.00"
|
|
17
|
+
cuota_ahorro: "86880.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Tipos combinados: 19 % hasta 6.000; 21 % hasta 50.000; 23 % hasta 200.000; 27 % hasta 300.000; 30 % resto.
|
|
20
|
+
Combinado: 1.140 + 9.240 + 34.500 + 27.000 + 15.000 = 86.880,00. Mitad estatal, mitad autonómico.
|
|
21
|
+
Este caso existe para pillar errores de umbral (¿el tramo cierra en 50.000,00 o en 50.000,01?).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-004
|
|
2
|
+
title: Redondeo por separado de cuota estatal y autonómica (intereses de cuenta remunerada)
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 25.2 (intereses como rendimiento del capital mobiliario)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 y art. 76"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "0.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "1234.56"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "1234.56"
|
|
15
|
+
cuota_estatal: "117.28"
|
|
16
|
+
cuota_autonomica: "117.28"
|
|
17
|
+
cuota_ahorro: "234.56"
|
|
18
|
+
notas: >
|
|
19
|
+
1.234,56 × 9,5 % = 117,2832 → 117,28 (cada cuota por separado). Suma 234,56.
|
|
20
|
+
El atajo 1.234,56 × 19 % = 234,5664 → 234,57 es INCORRECTO. Este caso existe para detectar
|
|
21
|
+
implementaciones que calculan con el tipo combinado. Verificar la regla de redondeo con el manual de Renta.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-005
|
|
2
|
+
title: Base del ahorro cero
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "0.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "0.00"
|
|
15
|
+
cuota_estatal: "0.00"
|
|
16
|
+
cuota_autonomica: "0.00"
|
|
17
|
+
cuota_ahorro: "0.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Sin rentas del ahorro. Base 0 → cuotas 0,00. Detecta implementaciones que fallan con base vacía
|
|
20
|
+
(bucle de tramos que no arranca, división por cero, "-0.00" en la salida).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-006
|
|
2
|
+
title: Base exactamente en el umbral superior del primer tramo (6.000,00)
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "6000.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "6000.00"
|
|
15
|
+
cuota_estatal: "570.00"
|
|
16
|
+
cuota_autonomica: "570.00"
|
|
17
|
+
cuota_ahorro: "1140.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal: 6.000,00 × 9,5 % = 570,00. Autonómico idéntico. Total 1.140,00.
|
|
20
|
+
Todo dentro del primer tramo: ni un céntimo puede ir al 10,5 %. Si el motor trata `hasta` como
|
|
21
|
+
exclusivo y cruza al segundo tramo, la diferencia aquí es 0 céntimos (ver 007); el caso sirve sobre
|
|
22
|
+
todo para detectar que se aplique el tipo marginal a toda la base (6.000 × 10,5 % = 630,00).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-007
|
|
2
|
+
title: Base un céntimo por encima del primer umbral (6.000,01)
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "6000.01"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "6000.01"
|
|
15
|
+
cuota_estatal: "570.00"
|
|
16
|
+
cuota_autonomica: "570.00"
|
|
17
|
+
cuota_ahorro: "1140.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal en céntimos·bp: 600.000 × 950 = 570.000.000 + 1 × 1.050 = 1.050 → 570.001.050 / 10.000
|
|
20
|
+
= 57.000,105 c → 57.000 c = 570,00. Autonómico idéntico. Total 1.140,00.
|
|
21
|
+
Errores que detecta: el tipo marginal sobre toda la base (6.000,01 × 10,5 % = 630,00), y el redondeo
|
|
22
|
+
hacia arriba o por exceso del tramo de 0,01 € (daría 570,01).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-008
|
|
2
|
+
title: Medio céntimo exacto en cada cuota (redondeo mitad alejándose de cero, no bancario ni truncado)
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 25.2 (intereses como rendimiento del capital mobiliario)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 y art. 76"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "0.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "3.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "3.00"
|
|
15
|
+
cuota_estatal: "0.29"
|
|
16
|
+
cuota_autonomica: "0.29"
|
|
17
|
+
cuota_ahorro: "0.58"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal: 300 c × 950 bp = 285.000 → 28,5 c → 29 c = 0,29 (mitad hacia arriba). Autonómico idéntico. Total 0,58.
|
|
20
|
+
Resultados erróneos que distingue: truncado → 0,28 + 0,28 = 0,56; redondeo bancario (half-even, 28,5 → 28)
|
|
21
|
+
→ 0,56; tipo combinado 3,00 × 19 % = 0,57.
|
|
22
|
+
Duda normativa: confirmar con el manual de Renta o con el programa Renta Web que la AEAT redondea cada
|
|
23
|
+
cuota al céntimo con la mitad hacia arriba (ADR-002 lo asume).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-009
|
|
2
|
+
title: Base con céntimos en el segundo tramo; el redondeo por cuota separada difiere del combinado
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "7777.77"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "7777.77"
|
|
15
|
+
cuota_estatal: "756.67"
|
|
16
|
+
cuota_autonomica: "756.67"
|
|
17
|
+
cuota_ahorro: "1513.34"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal en céntimos·bp: 600.000 × 950 = 570.000.000; 177.777 × 1.050 = 186.665.850; suma 756.665.850
|
|
20
|
+
/ 10.000 = 75.666,585 c → 75.667 c = 756,67. Autonómico idéntico. Total 1.513,34.
|
|
21
|
+
Atajo combinado: 600.000 × 1.900 + 177.777 × 2.100 = 1.513.331.700 → 151.333,17 c → 1.513,33 (incorrecto).
|
|
22
|
+
Este caso es como el 004, pero cruza un tramo y lleva céntimos en la base.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-010
|
|
2
|
+
title: Base de un céntimo; la cuota redondea a cero
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 25.2 (intereses como rendimiento del capital mobiliario)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 y art. 76"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "0.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.01"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "0.01"
|
|
15
|
+
cuota_estatal: "0.00"
|
|
16
|
+
cuota_autonomica: "0.00"
|
|
17
|
+
cuota_ahorro: "0.00"
|
|
18
|
+
notas: >
|
|
19
|
+
1 c × 950 bp = 950 → 0,095 c → 0 c. Autonómico idéntico. Total 0,00.
|
|
20
|
+
Detecta el redondeo hacia arriba (ceil), que daría 0,01 + 0,01.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-011
|
|
2
|
+
title: Base un céntimo por encima del segundo umbral (50.000,01)
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "50000.01"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "50000.01"
|
|
15
|
+
cuota_estatal: "5190.00"
|
|
16
|
+
cuota_autonomica: "5190.00"
|
|
17
|
+
cuota_ahorro: "10380.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal en céntimos·bp: 600.000 × 950 = 570.000.000; 4.400.000 × 1.050 = 4.620.000.000; 1 × 1.150 = 1.150;
|
|
20
|
+
suma 5.190.001.150 / 10.000 = 519.000,115 c → 519.000 c = 5.190,00. Autonómico idéntico. Total 10.380,00.
|
|
21
|
+
Detecta `hasta` tratado como exclusivo en el segundo tramo y el marginal aplicado a toda la base
|
|
22
|
+
(50.000,01 × 11,5 % = 5.750,00).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-012
|
|
2
|
+
title: Base un céntimo por encima del último umbral (300.000,01), entra en el tramo sin límite
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "300000.01"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "300000.01"
|
|
15
|
+
cuota_estatal: "35940.00"
|
|
16
|
+
cuota_autonomica: "35940.00"
|
|
17
|
+
cuota_ahorro: "71880.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal en céntimos·bp: 600.000 × 950 = 570.000.000; 4.400.000 × 1.050 = 4.620.000.000;
|
|
20
|
+
15.000.000 × 1.150 = 17.250.000.000; 10.000.000 × 1.350 = 13.500.000.000; 1 × 1.500 = 1.500;
|
|
21
|
+
suma 35.940.001.500 / 10.000 = 3.594.000,15 c → 3.594.000 c = 35.940,00. Autonómico idéntico. Total 71.880,00.
|
|
22
|
+
Detecta un tramo `hasta: null` que no se aplica, o que se aplica desde 0, y el `hasta` exclusivo en el último umbral.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-013
|
|
2
|
+
title: Medio céntimo exacto en el segundo tramo (redondeo mitad hacia arriba y cuotas separadas)
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "6001.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "6001.00"
|
|
15
|
+
cuota_estatal: "570.11"
|
|
16
|
+
cuota_autonomica: "570.11"
|
|
17
|
+
cuota_ahorro: "1140.22"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal en céntimos·bp: 600.000 × 950 = 570.000.000 + 100 × 1.050 = 105.000 → 570.105.000 / 10.000
|
|
20
|
+
= 57.010,5 c → 57.011 c = 570,11 (mitad hacia arriba). Autonómico idéntico. Total 1.140,22.
|
|
21
|
+
Errores que detecta: half-even o truncado (57.010 → 570,10; total 1.140,20); tipo combinado
|
|
22
|
+
(600.000 × 1.900 + 100 × 2.100 = 1.140.210.000 → 1.140,21). El caso 008 cubre el medio céntimo solo
|
|
23
|
+
en el primer tramo; este lo cubre en un tramo que no es el primero.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-014
|
|
2
|
+
title: Medio céntimo exacto en el último tramo (sin límite superior)
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "300000.30"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "300000.30"
|
|
15
|
+
cuota_estatal: "35940.05"
|
|
16
|
+
cuota_autonomica: "35940.05"
|
|
17
|
+
cuota_ahorro: "71880.10"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal en céntimos·bp: tramos completos 570.000.000 + 4.620.000.000 + 17.250.000.000 + 13.500.000.000
|
|
20
|
+
= 35.940.000.000; + 30 × 1.500 = 45.000 → 35.940.045.000 / 10.000 = 3.594.004,5 c → 3.594.005 c
|
|
21
|
+
= 35.940,05. Autonómico idéntico. Total 71.880,10.
|
|
22
|
+
Errores que detecta: half-even o truncado (3.594.004 → 71.880,08); tipo combinado
|
|
23
|
+
(7.188.000.000... + 30 × 3.000 = 90.000 → 71.880,09).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-015
|
|
2
|
+
title: Base exactamente en el umbral de 200.000,00
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "200000.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "200000.00"
|
|
15
|
+
cuota_estatal: "22440.00"
|
|
16
|
+
cuota_autonomica: "22440.00"
|
|
17
|
+
cuota_ahorro: "44880.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal: 600.000 × 950 + 4.400.000 × 1.050 + 15.000.000 × 1.150 = 22.440.000.000 / 10.000
|
|
20
|
+
= 2.244.000 c = 22.440,00. Autonómico idéntico. Total 44.880,00 (1.140 + 9.240 + 34.500).
|
|
21
|
+
Ningún caso existente toca el umbral de 200.000 (el 003 lo cruza de largo). Detecta el tipo marginal
|
|
22
|
+
aplicado a toda la base (200.000 × 11,5 % = 23.000,00) y un tercer tramo mal cerrado.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-016
|
|
2
|
+
title: Un céntimo por encima del umbral de 200.000,00
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "200000.01"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "200000.01"
|
|
15
|
+
cuota_estatal: "22440.00"
|
|
16
|
+
cuota_autonomica: "22440.00"
|
|
17
|
+
cuota_ahorro: "44880.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal: 22.440.000.000 + 1 × 1.350 = 22.440.001.350 / 10.000 = 2.244.000,135 c → 2.244.000 c = 22.440,00.
|
|
20
|
+
Autonómico idéntico. Total 44.880,00.
|
|
21
|
+
Detecta el marginal sobre toda la base (200.000,01 × 13,5 % = 27.000,00) y el redondeo hacia arriba
|
|
22
|
+
del céntimo que entra en el cuarto tramo (daría 22.440,01).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
id: irpf-ahorro-2026-017
|
|
2
|
+
title: Base muy grande dentro del rango seguro (1.000 millones de euros)
|
|
3
|
+
ejercicio: 2026
|
|
4
|
+
estado: verde
|
|
5
|
+
normativa:
|
|
6
|
+
- ref: "Ley 35/2006 IRPF, art. 66.1 (gravamen estatal base del ahorro)"
|
|
7
|
+
- ref: "Ley 35/2006 IRPF, art. 76 (gravamen autonómico base del ahorro)"
|
|
8
|
+
verificado: "2026-10-25"
|
|
9
|
+
input:
|
|
10
|
+
ganancias_patrimoniales: "1000000000.00"
|
|
11
|
+
perdidas_patrimoniales: "0.00"
|
|
12
|
+
rendimientos_capital_mobiliario: "0.00"
|
|
13
|
+
expected:
|
|
14
|
+
base_liquidable_ahorro: "1000000000.00"
|
|
15
|
+
cuota_estatal: "149990940.00"
|
|
16
|
+
cuota_autonomica: "149990940.00"
|
|
17
|
+
cuota_ahorro: "299981880.00"
|
|
18
|
+
notas: >
|
|
19
|
+
Estatal en céntimos·bp: tramos completos 35.940.000.000 + (100.000.000.000 − 30.000.000) × 1.500
|
|
20
|
+
= 149.955.000.000.000 → suma 149.990.940.000.000 (≈ 1,5 × 10¹⁴, dentro de MAX_SAFE_INTEGER)
|
|
21
|
+
/ 10.000 = 14.999.094.000 c = 149.990.940,00. Autonómico idéntico. Total 299.981.880,00
|
|
22
|
+
(= 71.880 + 999.700.000 × 30 %). Comprueba que el acumulado de toda la escala no pierde precisión
|
|
23
|
+
ni lanza un falso RangeError por debajo del límite de ADR-002.
|