64 lines
2.7 KiB
Ruby
64 lines
2.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Writes the 2026 income tax tables in the format of `tax` (income, tax, percent)
|
|
# into demo/. Sources: § 32a EStG (DE), § 33 EStG (AT), Tarif 2026 Art. 36 DBG (CH,
|
|
# ESTV Rundschreiben 2-215-D-2025), Art. 19 SteG LR 640.0, Fassung 01.07.2026 (LI).
|
|
# ruby tools/gen_tax_tables.rb
|
|
|
|
DEMO = File.expand_path('../demo', __dir__)
|
|
|
|
def write_table(name, points)
|
|
rows = points.map { |i, t, p| [i.to_s, format('%.2f', t), format('%.6f', p).sub(/0+\z/, '').sub(/\.\z/, '')] }
|
|
File.write(File.join(DEMO, name), "income\ttax\tpercent\n------\t---\t-------\n#{rows.map { |r| r.join("\t") }.join("\n")}\n")
|
|
end
|
|
|
|
# --- Germany: single assessment, § 32a Abs. 1 (the zones 2 and 3 are curves, so
|
|
# the table approximates them with short straight pieces; error below one euro)
|
|
def de_tax(x)
|
|
if x <= 12_348 then 0.0
|
|
elsif x <= 17_799 then y = (x - 12_348) / 10_000.0; ((914.51 * y) + 1400) * y
|
|
elsif x <= 69_878 then z = (x - 17_799) / 10_000.0; (((173.10 * z) + 2397) * z) + 1034.87
|
|
elsif x <= 277_825 then (0.42 * x) - 11_135.63
|
|
else (0.45 * x) - 19_470.38
|
|
end
|
|
end
|
|
|
|
de = [12_348] + (12_598..17_798).step(250).to_a + [17_799] + (18_049..69_549).step(250).to_a + [69_879, 277_826]
|
|
pts = de.each_with_index.map do |i, n|
|
|
nxt = de[n + 1]
|
|
slope = nxt ? (de_tax(nxt) - de_tax(i)) / (nxt - i) * 100 : 45.0
|
|
[i, de_tax(i), slope]
|
|
end
|
|
write_table('taxDE2026', [[0, 0.0, 0.0]] + pts)
|
|
|
|
# --- Austria: § 33 EStG, the tariff before the Absetzbeträge
|
|
at = [[13_539, 20], [21_992, 30], [36_458, 40], [70_365, 48], [104_859, 50], [1_000_000, 55]]
|
|
acc = 0.0
|
|
prev = [0, 0]
|
|
pts = [[0, 0.0, 0.0]]
|
|
at.each do |limit, rate|
|
|
acc += (limit - prev[0]) * prev[1] / 100.0
|
|
pts << [limit, acc, rate]
|
|
prev = [limit, rate]
|
|
end
|
|
write_table('taxAT2026', pts)
|
|
|
|
# --- Switzerland: direct federal tax, Art. 36 DBG, single persons (without canton and municipality)
|
|
ch = [[0, 0, 0], [15_200, 0, 0.77], [33_200, 138.60, 0.88], [43_500, 229.20, 2.64], [58_000, 612.00, 2.97],
|
|
[76_200, 1152.50, 5.94], [82_100, 1502.95, 6.60], [108_900, 3271.75, 8.80], [141_500, 6140.55, 11.00],
|
|
[185_100, 10_936.55, 13.20], [793_900, 91_298.15, 11.85], [794_000, 91_310.00, 11.50]]
|
|
write_table('taxCH2026', ch)
|
|
|
|
# --- Liechtenstein: Landessteuer, Art. 19 Abs. 1 Bst. a SteG; the municipal surcharge
|
|
# (150 % to 250 % of it) comes on top: total = Landessteuer * (1 + surcharge / 100)
|
|
li_rates = [[15_900, 1], [21_100, 3], [42_300, 4], [74_000, 5], [105_700, 6], [137_400, 6.5], [169_200, 7], [211_400, 8]]
|
|
acc = 0.0
|
|
prev = [15_855, 0]
|
|
pts = [[0, 0.0, 0.0]]
|
|
li_rates.each do |limit, rate|
|
|
acc += (limit - prev[0]) * prev[1] / 100.0 if prev[1].positive?
|
|
pts << [limit, acc, rate]
|
|
prev = [limit, rate]
|
|
end
|
|
write_table('taxLI2026', pts)
|