fire-planner/tests/test_tax_other_regimes.py

151 lines
5 KiB
Python
Raw Normal View History

2026-05-07 17:06:19 +00:00
"""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