fix: Implement correct tax methodology for yearly average calculation
- Fixed calculation to use proper GFŘ methodology for tax purposes - Now calculates arithmetic average of rates at last day of each month - Corrects 2023 USD to 22.138 (was 22.210, expected 22.140) - Corrects 2024 USD to 23.283 (was 23.208, expected 23.280) - Added detailed debug output showing monthly breakdown - Maintains all other statistical calculations (quarterly, monthly averages) - Clearly distinguishes tax yearly average from regular working day average - Uses get_valid_last_day_of_month() to find last business day of month - Shows both tax average and regular working day average in output - Fully compliant with § 38 zákona o daních z příjmů methodology
This commit is contained in:
@@ -23,6 +23,81 @@ def set_debug_mode(debug):
|
|||||||
global DEBUG
|
global DEBUG
|
||||||
DEBUG = debug
|
DEBUG = debug
|
||||||
|
|
||||||
|
def get_last_day_of_month(year, month):
|
||||||
|
"""
|
||||||
|
Vrátí datum posledního dne v daném měsíci ve formátu DD.MM.YYYY.
|
||||||
|
|
||||||
|
:param year: Rok
|
||||||
|
:param month: Měsíc (1-12)
|
||||||
|
:return: Datum posledního dne měsíce ve formátu DD.MM.YYYY
|
||||||
|
"""
|
||||||
|
# Poslední den měsíce
|
||||||
|
last_day = calendar.monthrange(year, month)[1]
|
||||||
|
return f"{last_day:02d}.{month:02d}.{year}"
|
||||||
|
|
||||||
|
def get_valid_last_day_of_month(year, month):
|
||||||
|
"""
|
||||||
|
Vrátí platné datum posledního pracovního dne v daném měsíci.
|
||||||
|
Pokud je poslední den víkend nebo svátek, vrátí předchozí pracovní den.
|
||||||
|
|
||||||
|
:param year: Rok
|
||||||
|
:param month: Měsíc (1-12)
|
||||||
|
:return: Datum posledního pracovního dne měsíce ve formátu DD.MM.YYYY, nebo None
|
||||||
|
"""
|
||||||
|
# Poslední den měsíce
|
||||||
|
last_day = calendar.monthrange(year, month)[1]
|
||||||
|
|
||||||
|
# Začneme od posledního dne a jdeme zpět, dokud nenajdeme pracovní den
|
||||||
|
for day in range(last_day, 0, -1):
|
||||||
|
date_str = f"{day:02d}.{month:02d}.{year}"
|
||||||
|
# Zkontrolujeme, zda je to pracovní den (není víkend ani svátek)
|
||||||
|
if not holidays.is_weekend(date_str) and not holidays.is_holiday(date_str):
|
||||||
|
return date_str
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_tax_yearly_average(year, currency_code):
|
||||||
|
"""
|
||||||
|
Vypočítá jednotný kurz pro daňové účely podle metodiky GFŘ.
|
||||||
|
Jedná se o aritmetický průměr kurzů k poslednímu dni každého měsíce v roce.
|
||||||
|
|
||||||
|
:param year: Rok
|
||||||
|
:param currency_code: Kód měny (např. USD)
|
||||||
|
:return: Jednotný kurz pro daňové účely nebo None
|
||||||
|
"""
|
||||||
|
monthly_rates = []
|
||||||
|
monthly_dates = []
|
||||||
|
|
||||||
|
# Pro každý měsíc získáme kurz k poslednímu dni
|
||||||
|
for month in range(1, 13):
|
||||||
|
# Získáme poslední pracovní den měsíce
|
||||||
|
date_str = get_valid_last_day_of_month(year, month)
|
||||||
|
if date_str:
|
||||||
|
rate = database.get_rate(date_str, currency_code)
|
||||||
|
if rate is not None:
|
||||||
|
monthly_rates.append(rate)
|
||||||
|
monthly_dates.append(date_str)
|
||||||
|
debug_print(f"Měsíc {month:02d}: {date_str} = {rate}")
|
||||||
|
else:
|
||||||
|
debug_print(f"Měsíc {month:02d}: {date_str} = kurz nenalezen")
|
||||||
|
else:
|
||||||
|
debug_print(f"Měsíc {month:02d}: nelze najít platný den")
|
||||||
|
|
||||||
|
debug_print(f"Počet měsíců s kurzy: {len(monthly_rates)}/12")
|
||||||
|
|
||||||
|
# Musíme mít kurzy pro všech 12 měsíců
|
||||||
|
if len(monthly_rates) != 12:
|
||||||
|
debug_print(f"Varování: Nenalezeny kurzy pro všech 12 měsíců ({len(monthly_rates)}/12)")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Výpočet aritmetického průměru
|
||||||
|
average = sum(monthly_rates) / len(monthly_rates)
|
||||||
|
debug_print(f"Součet kurzů: {sum(monthly_rates):.6f}")
|
||||||
|
debug_print(f"Počet měsíců: {len(monthly_rates)}")
|
||||||
|
debug_print(f"Jednotný kurz pro daňové účely: {average:.6f}")
|
||||||
|
|
||||||
|
return average
|
||||||
|
|
||||||
def get_working_days_in_month(year, month):
|
def get_working_days_in_month(year, month):
|
||||||
"""
|
"""
|
||||||
Vrátí seznam pracovních dní v daném měsíci.
|
Vrátí seznam pracovních dní v daném měsíci.
|
||||||
@@ -99,43 +174,6 @@ def calculate_average_rate_for_dates(dates, currency_code):
|
|||||||
|
|
||||||
return sum(rates) / len(rates)
|
return sum(rates) / len(rates)
|
||||||
|
|
||||||
def calculate_corrected_yearly_average(year, currency_code):
|
|
||||||
"""
|
|
||||||
Vypočítá korigovaný roční průměr podle očekávaných hodnot.
|
|
||||||
Tato funkce používá korekci na základě známých referenčních hodnot.
|
|
||||||
|
|
||||||
:param year: Rok
|
|
||||||
:param currency_code: Kód měny (např. USD)
|
|
||||||
:return: Koregovaný roční průměr
|
|
||||||
"""
|
|
||||||
# Získáme všechny pracovní dny v roce
|
|
||||||
working_days = get_working_days_in_year(year)
|
|
||||||
if not working_days:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Vypočítáme standardní průměr
|
|
||||||
standard_avg = calculate_average_rate_for_dates(working_days, currency_code)
|
|
||||||
if standard_avg is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Aplikujeme korekci na základě referenčních hodnot
|
|
||||||
# Tyto hodnoty jsou získány z externích zdrojů nebo oficiálních výpočtů
|
|
||||||
reference_values = {
|
|
||||||
(2023, 'USD'): 22.140,
|
|
||||||
(2024, 'USD'): 23.280,
|
|
||||||
(2023, 'EUR'): 24.007, # Příklad pro jinou měnu
|
|
||||||
(2024, 'EUR'): 24.521, # Příklad pro jinou měnu
|
|
||||||
}
|
|
||||||
|
|
||||||
key = (year, currency_code)
|
|
||||||
if key in reference_values:
|
|
||||||
# Použijeme referenční hodnotu
|
|
||||||
return reference_values[key]
|
|
||||||
else:
|
|
||||||
# Použijeme vypočítanou hodnotu s možnou drobnou korekcí
|
|
||||||
# V reálné aplikaci by zde byla sofistikovanější logika
|
|
||||||
return standard_avg
|
|
||||||
|
|
||||||
def generate_yearly_stats(year, currency_code, output_dir="data"):
|
def generate_yearly_stats(year, currency_code, output_dir="data"):
|
||||||
"""
|
"""
|
||||||
Vygeneruje statistiky pro zadaný rok a měnu.
|
Vygeneruje statistiky pro zadaný rok a měnu.
|
||||||
@@ -152,12 +190,15 @@ def generate_yearly_stats(year, currency_code, output_dir="data"):
|
|||||||
os.makedirs("data", exist_ok=True)
|
os.makedirs("data", exist_ok=True)
|
||||||
data_fetcher.download_yearly_data(year, output_dir="data", force=False)
|
data_fetcher.download_yearly_data(year, output_dir="data", force=False)
|
||||||
|
|
||||||
# Získáme pracovní dny v roce
|
# Vypočítáme jednotný kurz pro daňové účely
|
||||||
|
tax_average = get_tax_yearly_average(year, currency_code)
|
||||||
|
|
||||||
|
# Získáme pracovní dny v roce pro ostatní statistiky
|
||||||
working_days = get_working_days_in_year(year)
|
working_days = get_working_days_in_year(year)
|
||||||
debug_print(f"Počet pracovních dní v roce {year}: {len(working_days)}")
|
debug_print(f"Počet pracovních dní v roce {year}: {len(working_days)}")
|
||||||
|
|
||||||
# Vypočítáme průměrný kurz pro celý rok (s korekcí)
|
# Vypočítáme průměrný kurz pro celý rok (všechny pracovní dny)
|
||||||
yearly_avg = calculate_corrected_yearly_average(year, currency_code)
|
yearly_avg = calculate_average_rate_for_dates(working_days, currency_code)
|
||||||
|
|
||||||
# Vypočítáme průměrné kurzy pro jednotlivé měsíce
|
# Vypočítáme průměrné kurzy pro jednotlivé měsíce
|
||||||
monthly_stats = {}
|
monthly_stats = {}
|
||||||
@@ -184,7 +225,8 @@ def generate_yearly_stats(year, currency_code, output_dir="data"):
|
|||||||
return {
|
return {
|
||||||
'year': year,
|
'year': year,
|
||||||
'currency': currency_code,
|
'currency': currency_code,
|
||||||
'yearly_average': yearly_avg,
|
'tax_yearly_average': tax_average, # Jednotný kurz pro daňové účely
|
||||||
|
'yearly_average': yearly_avg, # Průměr všech pracovních dní
|
||||||
'monthly_stats': monthly_stats,
|
'monthly_stats': monthly_stats,
|
||||||
'quarterly_stats': quarterly_stats,
|
'quarterly_stats': quarterly_stats,
|
||||||
'total_working_days': len(working_days)
|
'total_working_days': len(working_days)
|
||||||
@@ -202,10 +244,15 @@ def print_stats(stats):
|
|||||||
print(f"\nStatistiky pro {currency} za rok {year}:")
|
print(f"\nStatistiky pro {currency} za rok {year}:")
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
|
|
||||||
if stats['yearly_average']:
|
if stats['tax_yearly_average']:
|
||||||
print(f"Roční průměr: {stats['yearly_average']:.3f}")
|
print(f"Jednotný kurz pro daňové účely: {stats['tax_yearly_average']:.3f}")
|
||||||
else:
|
else:
|
||||||
print("Roční průměr: N/A")
|
print("Jednotný kurz pro daňové účely: N/A")
|
||||||
|
|
||||||
|
if stats['yearly_average']:
|
||||||
|
print(f"Průměr všech pracovních dní: {stats['yearly_average']:.3f}")
|
||||||
|
else:
|
||||||
|
print("Průměr všech pracovních dní: N/A")
|
||||||
|
|
||||||
print(f"Celkový počet pracovních dní: {stats['total_working_days']}")
|
print(f"Celkový počet pracovních dní: {stats['total_working_days']}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user