fire-planner/tests/test_tax_other_regimes.py
2026-05-07 17:06:19 +00:00

150 lines
5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Nomad, Malaysia, Thailand, Cyprus, Bulgaria, UAE regimes."""
from decimal import Decimal
import pytest
from fire_planner.tax.base import TaxInputs, TaxRegime
from fire_planner.tax.bulgaria import BulgariaTaxRegime
from fire_planner.tax.cyprus import CyprusTaxRegime
from fire_planner.tax.malaysia import MalaysiaTaxRegime
from fire_planner.tax.nomad import NomadTaxRegime
from fire_planner.tax.thailand import ThailandTaxRegime
from fire_planner.tax.uae import UaeTaxRegime
def test_nomad_zero_inputs() -> None:
assert NomadTaxRegime().compute_tax(TaxInputs()).total == Decimal("0")
def test_nomad_one_pc_premium() -> None:
b = NomadTaxRegime().compute_tax(
TaxInputs(capital_gains=Decimal("100000"), dividends=Decimal("20000")))
assert b.other == Decimal("1200")
assert b.total == Decimal("1200")
def test_nomad_isa_excluded_from_premium() -> None:
b = NomadTaxRegime().compute_tax(TaxInputs(isa_withdrawals=Decimal("100000")))
assert b.total == Decimal("0")
def test_malaysia_zero_on_foreign_income() -> None:
b = MalaysiaTaxRegime().compute_tax(
TaxInputs(capital_gains=Decimal("500000"), dividends=Decimal("50000")))
assert b.total == Decimal("0")
def test_thailand_zero_on_foreign_income() -> None:
b = ThailandTaxRegime().compute_tax(
TaxInputs(capital_gains=Decimal("500000"), dividends=Decimal("50000")))
assert b.total == Decimal("0")
def test_cyprus_gesy_below_cap() -> None:
# £100k chargeable, below €180k cap (~£154,800 default)
# 2.65% × £100,000 = £2,650
b = CyprusTaxRegime().compute_tax(TaxInputs(dividends=Decimal("100000")))
assert b.healthcare_levy == Decimal("2650.0000")
assert b.income_tax == Decimal("0")
assert b.capital_gains_tax == Decimal("0")
def test_cyprus_gesy_above_cap() -> None:
# £200k chargeable; cap GBP = £154,800 (€180k × 0.86)
# 2.65% × £154,800 = £4,102.20
b = CyprusTaxRegime().compute_tax(TaxInputs(dividends=Decimal("200000")))
assert b.healthcare_levy == Decimal("4102.2000")
def test_cyprus_custom_fx() -> None:
# Cap = 180,000 × 0.90 = 162,000
b = CyprusTaxRegime(gbp_per_eur=Decimal("0.90")).compute_tax(
TaxInputs(dividends=Decimal("200000")))
assert b.healthcare_levy == Decimal("4293.0000")
def test_uae_zero_on_all_personal_income() -> None:
"""UAE has 0% PIT — capital gains, dividends, earned income all 0."""
b = UaeTaxRegime().compute_tax(
TaxInputs(
earned_income=Decimal("60000"),
capital_gains=Decimal("500000"),
dividends=Decimal("80000"),
interest=Decimal("5000"),
))
assert b.total == Decimal("0")
assert b.income_tax == Decimal("0")
assert b.capital_gains_tax == Decimal("0")
assert b.dividend_tax == Decimal("0")
assert b.healthcare_levy == Decimal("0")
assert b.other == Decimal("0")
def test_uae_no_regulatory_premium() -> None:
"""Unlike NomadTaxRegime, UAE charges no premium — it's a real
tax residence with a treaty network."""
b = UaeTaxRegime().compute_tax(TaxInputs(capital_gains=Decimal("100000")))
assert b.total == Decimal("0")
def test_uae_zero_inputs() -> None:
assert UaeTaxRegime().compute_tax(TaxInputs()).total == Decimal("0")
def test_bulgaria_flat_10_pc() -> None:
b = BulgariaTaxRegime().compute_tax(
TaxInputs(
earned_income=Decimal("50000"),
capital_gains=Decimal("30000"),
dividends=Decimal("10000"),
))
assert b.income_tax == Decimal("5000.00")
assert b.capital_gains_tax == Decimal("3000.00")
assert b.dividend_tax == Decimal("1000.00")
assert b.total == Decimal("9000.00")
@pytest.mark.parametrize("regime", [
NomadTaxRegime(),
MalaysiaTaxRegime(),
ThailandTaxRegime(),
CyprusTaxRegime(),
BulgariaTaxRegime(),
UaeTaxRegime(),
])
def test_total_equals_sum(regime: TaxRegime) -> None:
inputs = TaxInputs(
earned_income=Decimal("60000"),
capital_gains=Decimal("15000"),
dividends=Decimal("8000"),
interest=Decimal("500"),
)
b = regime.compute_tax(inputs)
assert (b.total == b.income_tax + b.national_insurance + b.capital_gains_tax + b.dividend_tax +
b.healthcare_levy + b.other)
@pytest.mark.parametrize("regime", [
NomadTaxRegime(),
MalaysiaTaxRegime(),
ThailandTaxRegime(),
CyprusTaxRegime(),
BulgariaTaxRegime(),
UaeTaxRegime(),
])
def test_each_regime_has_a_name(regime: TaxRegime) -> None:
assert regime.name
assert isinstance(regime.name, str)
@pytest.mark.parametrize("regime", [
BulgariaTaxRegime(),
NomadTaxRegime(),
CyprusTaxRegime(),
])
def test_lower_spend_lower_tax(regime: TaxRegime) -> None:
"""Sanity: more chargeable income → never less tax (for the
regimes that actually charge)."""
less = regime.compute_tax(TaxInputs(dividends=Decimal("10000")))
more = regime.compute_tax(TaxInputs(dividends=Decimal("100000")))
assert more.total >= less.total