50 lines
2 KiB
Python
50 lines
2 KiB
Python
|
|
"""Cyprus regime — non-dom 17-year exemption on foreign dividends +
|
|||
|
|
interest, plus 2.65% GeSY healthcare levy capped at €180k.
|
|||
|
|
|
|||
|
|
The non-dom regime (Art 8(20)/(20A) Income Tax Law 118(I)/2002) gives
|
|||
|
|
17 years of full exemption from SDC (Special Defence Contribution) on
|
|||
|
|
foreign dividends and interest. Capital gains on shares are exempt
|
|||
|
|
under standard CGT rules (only Cypriot real estate is taxed). Earned
|
|||
|
|
income from employment is taxed under standard PIT bands — irrelevant
|
|||
|
|
for our retirement scenarios.
|
|||
|
|
|
|||
|
|
GeSY (Γε.Σ.Υ. — General Healthcare System) levies 2.65% on worldwide
|
|||
|
|
income with an annual cap of €180,000 of contributing income. We
|
|||
|
|
convert the €180k cap to GBP via the FX rate at scenario time;
|
|||
|
|
default = 0.86 GBP/EUR ≈ £154,800.
|
|||
|
|
"""
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
from decimal import Decimal
|
|||
|
|
|
|||
|
|
from fire_planner.tax.base import TaxBreakdown, TaxInputs, TaxRegime
|
|||
|
|
|
|||
|
|
DEFAULT_GESY_RATE = Decimal("0.0265")
|
|||
|
|
DEFAULT_GESY_CAP_EUR = Decimal("180000")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class CyprusTaxRegime(TaxRegime):
|
|||
|
|
name = "cyprus"
|
|||
|
|
|
|||
|
|
def __init__(
|
|||
|
|
self,
|
|||
|
|
gesy_rate: Decimal = DEFAULT_GESY_RATE,
|
|||
|
|
gesy_cap_gbp: Decimal | None = None,
|
|||
|
|
gbp_per_eur: Decimal = Decimal("0.86"),
|
|||
|
|
) -> None:
|
|||
|
|
self.gesy_rate = gesy_rate
|
|||
|
|
self.gesy_cap_gbp = (gesy_cap_gbp if gesy_cap_gbp is not None else DEFAULT_GESY_CAP_EUR *
|
|||
|
|
gbp_per_eur)
|
|||
|
|
|
|||
|
|
def compute_tax(self, inputs: TaxInputs) -> TaxBreakdown:
|
|||
|
|
# Foreign divs/interest exempt under non-dom (assumed within 17y window).
|
|||
|
|
# Foreign capital gains exempt unless the underlying is Cypriot real estate.
|
|||
|
|
chargeable = (inputs.earned_income + inputs.pension_withdrawal + inputs.capital_gains +
|
|||
|
|
inputs.dividends + inputs.interest)
|
|||
|
|
capped = min(chargeable, self.gesy_cap_gbp)
|
|||
|
|
return TaxBreakdown(
|
|||
|
|
healthcare_levy=capped * self.gesy_rate,
|
|||
|
|
notes=("cyprus-non-dom", f"gesy_rate={self.gesy_rate}",
|
|||
|
|
f"gesy_cap_gbp={self.gesy_cap_gbp}"),
|
|||
|
|
)
|