Skip to content

Instantly share code, notes, and snippets.

@jrosell
Last active August 10, 2023 13:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jrosell/962c86a0e7a5b0fe16ff0b8e78a683a9 to your computer and use it in GitHub Desktop.
Save jrosell/962c86a0e7a5b0fe16ff0b8e78a683a9 to your computer and use it in GitHub Desktop.
Calculando el rendimiento después de IRPF en España 2023 según detallado aquí https://www.bankinter.com/blog/finanzas-personales/como-calcular-irpf-caso-practico
# Hasta 12450 euros: 19 %
# De 12.450 euros hasta 20.200 euros: 24 %
# De 20.200 euros hasta 35.200 euros: 30 %
# De 35.200 euros hasta 60.000 euros: 37 %
# De 60.000 euros hasta300.000 euros: 45 %
# Más de 300.000 euros: 47 %
library(tidyverse)
library(patchwork)
minimo_exento <- 5500
my_theme <- function() {
ggplot2::theme_minimal(base_size = 22) +
theme(
plot.title = element_text(size = 18),
axis.text.x = element_text(size = 9),
axis.text.y = element_text(size = 9),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
)
}
ggplot2::theme_set(my_theme())
caclular_irpf <- function(x){
if (x <= minimo_exento) return(0)
irpf_19_val = min(x, 12450)
irpf_24 = x >= 12450
irpf_24_val = min(x - 12450, 20200 - 12450)
irpf_30 = x >= 20200
irpf_30_val = min(x - 20200, 35200 - 20200)
irpf_37 = x >= 35200
irpf_37_val = min(x - 35200, 60000 - 35200)
irpf_45 = x >= 60000
irpf_45_val = min(x - 60000, 300000 - 60000)
irpf_47 = x >= 300000
irpf_47_val = x - 300000
irpf = (irpf_19_val * 0.19) +
(irpf_24 * irpf_24_val * 0.24) +
(irpf_30 * irpf_30_val * 0.3) +
(irpf_37 * irpf_37_val * 0.37) +
(irpf_45 * irpf_45_val * 0.45) +
(irpf_47 * irpf_47_val * 0.47)
return(irpf)
}
irpf_df <- tibble(x = 100 * (1:1000)) %>%
arrange(x) %>%
mutate(irpf = map_dbl(x, caclular_irpf)) %>%
mutate(rendimiento_neto = x - irpf) %>%
mutate(tipo = irpf / x) %>%
select(x, irpf, rendimiento_neto, everything()) %>%
print() -> df
df %>%
filter(x > 8000, x < 12300) %>%
glimpse()
df %>%
filter(x > 12450, x < 12800) %>%
glimpse()
df %>%
filter(x > 20300, x < 30000) %>%
glimpse()
df %>%
filter(x > 36000, x < 38000) %>%
glimpse()
euro_format <- function(...) {
scales::dollar_format(..., suffix = "€", prefix = "", big.mark = ".", decimal.mark = ",")
}
p1 <- df %>%
ggplot(aes(x, irpf)) +
geom_line() +
scale_x_continuous(labels = euro_format()) +
scale_y_continuous(labels = euro_format()) +
labs(title = "IRPF a pagar")
# plotly::ggplotly(p1)
p2 <- df %>%
ggplot(aes(x, rendimiento_neto)) +
geom_line() +
scale_x_continuous(labels = euro_format()) +
scale_y_continuous(labels = euro_format()) +
labs(title = "Rendimiento neto")
# plotly::ggplotly(p2)
p3 <- df %>%
filter(x <= 20000) %>%
ggplot(aes(x, irpf)) +
geom_line() +
scale_x_continuous(labels = euro_format()) +
scale_y_continuous(labels = euro_format()) +
labs(title = "IRPF a pagar <= 20k")
# plotly::ggplotly(p3)
p4 <- df %>%
filter(x <= 20000) %>%
ggplot(aes(x, rendimiento_neto)) +
geom_line() +
scale_x_continuous(labels = euro_format()) +
scale_y_continuous(labels = euro_format()) +
labs(title = "Rendimiento neto <= 20k")
# plotly::ggplotly(p4)
(p1 + p2) / (p3 + p4)
## Alternativa
irpf <- function(x) {
if (x > 300000)
return(0.47 * (x - 300000) + irpf(300000))
if (x > 60000)
return(0.45 * (x - 60000) + irpf(60000))
if (x > 35200)
return(0.37 * (x - 35200) + irpf(35200))
if (x > 20200)
return(0.3 * (x - 20200) + irpf(20200))
if (x > 12450)
return(.24 * (x - 12450) + irpf(12450))
if (x > 0)
return(.19 * x)
return(0)
}
irpf_neto <- function(x) {
if (x > minimo_exento)
irpf(x)
else 0
}
brutos <- 100 * (1:1000)
impuesto <- sapply(brutos, irpf_neto)
alternativa_df <- tibble(
x = brutos,
irpf = impuesto,
rendimiento_neto = impuesto / brutos,
tipo = irpf / x
)
testthat::expect_identical(irpf_df, alternativa_df)
@jrosell
Copy link
Author

jrosell commented Jul 5, 2023

f4c4b706-1635-440d-a925-a4c986080f55

@cjgb
Copy link

cjgb commented Jul 13, 2023

Creo qe te olvidas del mínimo exento. Los primeros 5500 € (más si eres jubilado) no pagan nada. Mira esto:

minimo_exento <- 5500

irpf <- function(x) {
  
  if (x > 300000 + minimo_exento) 
    return(0.47 * (x - 300000 - minimo_exento) + irpf(300000 + minimo_exento))
  
  if (x > 60000 + minimo_exento) 
    return(0.45 * (x - 60000 - minimo_exento) + irpf(60000 + minimo_exento))
  
  if (x > 35200 + minimo_exento) 
    return(0.37 * (x - 35200 - minimo_exento) + irpf(35200 + minimo_exento))
  
  if (x > 20200 + minimo_exento) 
    return(0.3 * (x - 20200 - minimo_exento) + irpf(20200 + minimo_exento))
  
  if (x > 12450 + minimo_exento) 
    return(.24 * (x - 12450 - minimo_exento) + irpf(12450 + minimo_exento))
  
  if (x > minimo_exento) 
    return(.19 * (x - minimo_exento))
           
  return(0)
  
}

# test
irpf(400100) - irpf(400000)
irpf(80100) - irpf(80000)
irpf(30100) - irpf(30000)

brutos <- 1000 * (0:500)
impuesto <- sapply(brutos,  irpf)
plot(brutos, impuesto, , type = "l")

plot(brutos / 1e3, 100 * impuesto / brutos, type = "l")


brutos <- 100 * (0:1000)
impuesto <- sapply(brutos,  irpf)
plot(brutos, impuesto, , type = "l")

plot(brutos / 1e3, 100 * impuesto / brutos, type = "l")

@jrosell
Copy link
Author

jrosell commented Jul 13, 2023

¿Tienes fuente que explique esto? Tengo la duda sobre que haya que descontarlos como primer tramo o si realmente hay que contar 0.19 para todo el tramo de los que superen en mínimo.

@cjgb
Copy link

cjgb commented Jul 14, 2023

Espera, tienes razón, se hace distinto: primero se calcula la cuota bruta. Luego se calcula la cuota correspondiente al mínimo exento (en mi caso fueron 5500 + otras cosas). Luego se restan los dos números. Es decir, es más bien así:

minimo_exento <- 5500

irpf <- function(x) {
  
  if (x > 300000) 
    return(0.47 * (x - 300000) + irpf(300000))
  
  if (x > 60000) 
    return(0.45 * (x - 60000) + irpf(60000))
  
  if (x > 35200) 
    return(0.37 * (x - 35200) + irpf(35200))
  
  if (x > 20200) 
    return(0.3 * (x - 20200) + irpf(20200))
  
  if (x > 12450) 
    return(.24 * (x - 12450) + irpf(12450))
  
  if (x > 0) 
    return(.19 * x)
           
  return(0)
  
}

irpf_neto <- function(x) {
  if (x > minimo_exento) 
    irpf(x)
  else 0
}

# test
irpf_neto(400100) - irpf_neto(400000)
irpf_neto(80100) - irpf_neto(80000)
irpf_neto(30100) - irpf_neto(30000)

brutos <- 1000 * (0:500)
impuesto <- sapply(brutos,  irpf_neto)
plot(brutos, impuesto, , type = "l")

plot(brutos / 1e3, 100 * impuesto / brutos, type = "l")


brutos <- 100 * (0:1000)
impuesto <- sapply(brutos,  irpf_neto)
plot(brutos, impuesto, , type = "l")

plot(brutos / 1e3, 100 * impuesto / brutos, type = "l")

@jrosell
Copy link
Author

jrosell commented Aug 10, 2023

HAHAHAHAHA. Viva la IEEE 754

> testthat::expect_identical(irpf_df, alternativa_df)
Error: `irpf_df` not identical to `alternativa_df`.
Component “rendimiento_neto”: Mean relative difference: 0.9999923

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment