diff --git a/src/cli.py b/src/cli.py index d76d42c..b581bf3 100755 --- a/src/cli.py +++ b/src/cli.py @@ -12,7 +12,6 @@ import data_fetcher import database import rate_finder import rate_reporter -import rate_stats import holidays # Global debug flag @@ -23,12 +22,10 @@ def debug_print(*args, **kwargs): if DEBUG: print(*args, **kwargs) -def check_and_update_yearly_data(): - """ - Zkontroluje konzistenci ročních dat pro aktuální rok a případně je aktualizuje. - """ - current_year = datetime.now().year - debug_print(f"Kontroluji konzistenci ročních dat pro rok {current_year}...") +def set_debug_mode(debug): + """Set the debug mode for all modules.""" + global DEBUG + DEBUG = debug # Nastavíme debug mód pro všechny moduly database.set_debug_mode(DEBUG) @@ -36,19 +33,28 @@ def check_and_update_yearly_data(): holidays.set_debug_mode(DEBUG) rate_finder.set_debug_mode(DEBUG) rate_reporter.set_debug_mode(DEBUG) - rate_stats.set_debug_mode(DEBUG) + +def check_and_update_yearly_data(): + """ + Zkontroluje konzistenci ročních dat pro aktuální rok a případně je aktualizuje. + """ + current_year = datetime.now().year + if DEBUG: + debug_print(f"Kontroluji konzistenci ročních dat pro rok {current_year}...") # Zkontrolujeme konzistenci dat is_consistent = data_fetcher.check_yearly_data_consistency(current_year, output_dir="data") if not is_consistent: - debug_print(f"Roční data pro rok {current_year} nejsou konzistentní. Stahuji aktualizovaná data...") + if DEBUG: + debug_print(f"Roční data pro rok {current_year} nejsou konzistentní. Stahuji aktualizovaná data...") # Ujistěme se, že adresář data existuje os.makedirs("data", exist_ok=True) # Stáhneme roční data znovu data_fetcher.download_yearly_data(current_year, output_dir="data", force=True) else: - debug_print(f"Roční data pro rok {current_year} jsou aktuální.") + if DEBUG: + debug_print(f"Roční data pro rok {current_year} jsou aktuální.") def main(): global DEBUG @@ -65,7 +71,7 @@ def main(): parser.add_argument( "-c", "--currency", type=str, - help="Kód měny (např. USD) pro měsíční stahování, vyhledání kurzu, generování reportu nebo statistik." + help="Kód měny (např. USD) pro měsíční stahování, vyhledání kurzu nebo generování reportu." ) parser.add_argument( "--start-date", @@ -108,11 +114,6 @@ def main(): metavar=('START_DATE', 'END_DATE'), help="Období, pro které se má vygenerovat report kurzů. Formát: DD.MM.YYYY DD.MM.YYYY" ) - parser.add_argument( - "--stats", - type=int, - help="Vygeneruje statistiky pro zadaný rok. Formát: ROK" - ) parser.add_argument( "--debug", action="store_true", @@ -123,41 +124,37 @@ def main(): # Nastavíme debug mód DEBUG = args.debug - - # Nastavíme debug mód pro všechny moduly - database.set_debug_mode(DEBUG) - data_fetcher.set_debug_mode(DEBUG) - holidays.set_debug_mode(DEBUG) - rate_finder.set_debug_mode(DEBUG) - rate_reporter.set_debug_mode(DEBUG) - rate_stats.set_debug_mode(DEBUG) + set_debug_mode(DEBUG) # Kontrola a případná aktualizace ročních dat pro aktuální rok (pouze v debug módu) if DEBUG: check_and_update_yearly_data() else: # V normálním módu zkontrolujeme pouze při stahování dat - if args.year or args.start_date or args.date or args.get_rate or args.report_year or args.report_period or args.stats: + if args.year or args.start_date or args.end_date or args.date or args.get_rate or args.report_year or args.report_period: current_year = datetime.now().year # Pro jednoduchost v normálním módu nebudeme kontrolovat konzistenci automaticky pass # Zde bude logika pro zpracování argumentů if args.year: - debug_print(f"Stahuji roční data pro rok {args.year}...") + if DEBUG: + debug_print(f"Stahuji roční data pro rok {args.year}...") # Ujistěme se, že adresář data existuje os.makedirs("data", exist_ok=True) # Volání funkce pro stažení ročních dat data_fetcher.download_yearly_data(args.year, output_dir="data") elif args.currency and args.start_date and args.end_date and not args.report_period: # Měsíční stahování dat - debug_print(f"Stahuji měsíční data pro měnu {args.currency} od {args.start_date} do {args.end_date}...") + if DEBUG: + debug_print(f"Stahuji měsíční data pro měnu {args.currency} od {args.start_date} do {args.end_date}...") # Ujistěme se, že adresář data existuje os.makedirs("data", exist_ok=True) # Volání funkce pro stažení měsíčních dat data_fetcher.download_monthly_data(args.currency, args.start_date, args.end_date, output_dir="data") elif args.date: - debug_print(f"Stahuji denní data pro datum {args.date}...") + if DEBUG: + debug_print(f"Stahuji denní data pro datum {args.date}...") # Ujistěme se, že adresář data existuje os.makedirs("data", exist_ok=True) # Volání funkce pro stažení denních dat @@ -165,7 +162,8 @@ def main(): elif args.get_rate and args.currency: date_str = args.get_rate currency_code = args.currency - debug_print(f"Vyhledávám kurz pro {currency_code} na datum {date_str}...") + if DEBUG: + debug_print(f"Vyhledávám kurz pro {currency_code} na datum {date_str}...") rate = rate_finder.get_rate_for_date(date_str, currency_code) if rate: # Pro --get-rate v normálním režimu zobrazíme pouze kurz @@ -184,7 +182,8 @@ def main(): if requested_date.date() == today.date(): # Zkontrolujeme, zda je čas po 14:30 if today.time() >= datetime.strptime("14:30", "%H:%M").time(): - debug_print("Automaticky stahuji denní data...") + if DEBUG: + debug_print("Automaticky stahuji denní data...") # Ujistěme se, že adresář data existuje os.makedirs("data", exist_ok=True) # Stáhneme denní data pro dnešní datum @@ -225,23 +224,20 @@ def main(): elif args.report_year and args.currency: if args.report_month: # Generování měsíčního reportu - debug_print(f"Generuji měsíční report pro {args.currency} za {args.report_month}/{args.report_year}...") + if DEBUG: + debug_print(f"Generuji měsíční report pro {args.currency} za {args.report_month}/{args.report_year}...") rate_reporter.generate_monthly_report(args.report_year, args.report_month, args.currency, output_dir="data") else: # Generování ročního reportu - debug_print(f"Generuji roční report pro {args.currency} za rok {args.report_year}...") + if DEBUG: + debug_print(f"Generuji roční report pro {args.currency} za rok {args.report_year}...") rate_reporter.generate_yearly_report(args.report_year, args.currency, output_dir="data") elif args.report_period and args.currency: # Generování reportu za období start_date, end_date = args.report_period - debug_print(f"Generuji report pro {args.currency} za období {start_date} - {end_date}...") + if DEBUG: + debug_print(f"Generuji report pro {args.currency} za období {start_date} - {end_date}...") rate_reporter.generate_period_report(start_date, end_date, args.currency, output_dir="data") - elif args.stats and args.currency: - # Generování statistik - year = args.stats - debug_print(f"Generuji statistiky pro {args.currency} za rok {year}...") - stats = rate_stats.generate_yearly_stats(year, args.currency, output_dir="data") - rate_stats.print_stats(stats) else: if DEBUG: parser.print_help() diff --git a/src/database.py b/src/database.py index 01fd74d..4a7f99d 100644 --- a/src/database.py +++ b/src/database.py @@ -108,6 +108,29 @@ def get_rate(date, currency_code): else: return None +def get_years_with_data(): + """ + Vrátí seznam všech roků, pro které databáze obsahuje data. + + :return: Seznam roků jako celá čísla. + """ + conn = sqlite3.connect(DB_PATH) + cursor = conn.cursor() + + # Získáme seznam všech roků z databáze + cursor.execute(''' + SELECT DISTINCT strftime('%Y', date) FROM exchange_rates + ORDER BY strftime('%Y', date) + ''') + + rows = cursor.fetchall() + conn.close() + + # Převedeme řetězce na celá čísla + years = [int(row[0]) for row in rows if row[0]] + + return years + # Příklad použití if __name__ == "__main__": init_db() \ No newline at end of file diff --git a/src/rate_reporter.py b/src/rate_reporter.py index d044693..0f5d631 100644 --- a/src/rate_reporter.py +++ b/src/rate_reporter.py @@ -50,7 +50,7 @@ def get_rate_for_date_with_fallback(date_str, currency_code): # a pro případnou následující sobotu, neděli či státní svátek" # # To znamená: - # - Pro víkendy a svátky hledáme kurz zpět v čase (viz níže) + # - Pro víkendy a svátky hledáme kurz zpět v čase podle pravidel ČNB # - Pro běžné dny, které nemají kurz, hledáme kurz z posledního pracovního dne před nimi # Zkontrolujeme, zda je datum víkend nebo svátek @@ -87,30 +87,6 @@ def get_rate_for_date_with_fallback(date_str, currency_code): return None -def get_czech_day_name(date_str): - """ - Vrátí český název dne v týdnu pro zadané datum. - - :param date_str: Datum ve formátu DD.MM.YYYY - :return: Český název dne v týdnu - """ - try: - date_obj = datetime.strptime(date_str, "%d.%m.%Y") - # Czech day names - czech_days = ["pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota", "neděle"] - return czech_days[date_obj.weekday()] - except ValueError: - return "neznámý den" - -def is_holiday(date_str): - """ - Zkontroluje, zda je zadané datum státní svátek. - - :param date_str: Datum ve formátu DD.MM.YYYY - :return: True pokud je svátek, jinak False - """ - return holidays.is_holiday(date_str) - def generate_yearly_report(year, currency_code, output_dir="data"): """ Vygeneruje report kurzů pro zadaný rok a měnu. @@ -123,10 +99,11 @@ def generate_yearly_report(year, currency_code, output_dir="data"): debug_print(f"Generuji report kurzů pro {currency_code} za rok {year}...") # Zkontrolujeme, zda databáze obsahuje data pro daný rok - # Stáhneme roční data pouze pokud nejsou kompletní - debug_print(f"Kontroluji dostupnost ročních dat pro rok {year}...") + # Pro generování reportu vždy stáhneme aktuální roční data, aby byl report kompletní + debug_print(f"Stahuji roční data pro rok {year}...") + # Stáhneme roční data s vynuceným stažením 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=True) # Vytvoříme seznam všech dní v roce start_date = datetime(year, 1, 1) @@ -207,10 +184,11 @@ def generate_monthly_report(year, month, currency_code, output_dir="data"): debug_print(f"Generuji report kurzů pro {currency_code} za {month}/{year}...") # Zkontrolujeme, zda databáze obsahuje data pro daný rok - # Stáhneme roční data pouze pokud nejsou kompletní - debug_print(f"Kontroluji dostupnost ročních dat pro rok {year}...") + # Pro generování reportu vždy stáhneme aktuální roční data, aby byl report kompletní + debug_print(f"Stahuji roční data pro rok {year}...") + # Stáhneme roční data s vynuceným stažením 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=True) # Vytvoříme seznam všech dní v měsíci start_date = datetime(year, month, 1) @@ -312,14 +290,15 @@ def generate_period_report(start_date_str, end_date_str, currency_code, output_d end_date = today # Zkontrolujeme, zda databáze obsahuje data pro roky v rozmezí - # Stáhneme roční data pouze pokud nejsou kompletní + # Pro generování reportu vždy stáhneme aktuální roční data, aby byl report kompletní start_year = start_date.year end_year = end_date.year for year in range(start_year, end_year + 1): - debug_print(f"Kontroluji dostupnost ročních dat pro rok {year}...") + debug_print(f"Stahuji roční data pro rok {year}...") + # Stáhneme roční data s vynuceným stažením 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=True) # Otevřeme CSV soubor pro zápis filename = f"report_{currency_code}_{start_date_str.replace('.', '_')}_to_{end_date_str.replace('.', '_')}.csv" @@ -372,6 +351,30 @@ def generate_period_report(start_date_str, end_date_str, currency_code, output_d debug_print(f"Chyba při zápisu do souboru: {e}") return None +def get_czech_day_name(date_str): + """ + Vrátí český název dne v týdnu pro zadané datum. + + :param date_str: Datum ve formátu DD.MM.YYYY + :return: Český název dne v týdnu + """ + try: + date_obj = datetime.strptime(date_str, "%d.%m.%Y") + # Czech day names + czech_days = ["pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota", "neděle"] + return czech_days[date_obj.weekday()] + except ValueError: + return "neznámý den" + +def is_holiday(date_str): + """ + Zkontroluje, zda je zadané datum státní svátek. + + :param date_str: Datum ve formátu DD.MM.YYYY + :return: True pokud je svátek, jinak False + """ + return holidays.is_holiday(date_str) + # Příklad použití if __name__ == "__main__": # Inicializace databáze (pro případ spuštění samostatně) diff --git a/tests/test_rate_calculation.py b/tests/test_rate_calculation.py index ea88efc..019c511 100644 --- a/tests/test_rate_calculation.py +++ b/tests/test_rate_calculation.py @@ -1,7 +1,6 @@ import sys import os import sqlite3 -from datetime import datetime # Přidání adresáře src do sys.path, aby bylo možné importovat moduly sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) @@ -25,35 +24,9 @@ def test_rate_calculation(): # Pondělí 4.1.2021 - pracovní den, kurz 21.259 database.insert_rate("04.01.2021", "TEST", 1, 21.259) - # Zkontrolujeme, co je ve skutečnosti v databázi - print("\nObsah databáze pro měnu TEST:") - conn = sqlite3.connect(database.DB_PATH) - cursor = conn.cursor() - cursor.execute("SELECT * FROM exchange_rates WHERE currency_code = 'TEST'") - rows = cursor.fetchall() - for row in rows: - print(f" {row}") - conn.close() - # Test 1: Sobota 2.1.2021 (víkend po svátku) # Měla by být použita hodnota z pátku 1.1.2021 (poslední den s kurzem před víkendem/svátkem) - print("\nTest 1: Sobota 2.1.2021 (víkend po svátku)") - # Zkontrolujeme, zda je 2.1.2021 víkend - is_weekend = holidays.is_weekend("02.01.2021") - print(f" Je 02.01.2021 víkend? {is_weekend}") - # Zkontrolujeme, zda je 1.1.2021 svátek - is_holiday = holidays.is_holiday("01.01.2021") - print(f" Je 01.01.2021 svátek? {is_holiday}") - # Zkontrolujeme, jaký předchozí pracovní den vrátí funkce - prev_workday = holidays.get_previous_working_day("02.01.2021") - print(f" Předchozí pracovní den před 02.01.2021: {prev_workday}") - # Zkontrolujeme kurz pro 1.1.2021 - rate_01_01 = database.get_rate("01.01.2021", "TEST") - print(f" Kurz pro 01.01.2021: {rate_01_01}") - # Zkontrolujeme kurz pro 31.12.2020 - rate_31_12 = database.get_rate("31.12.2020", "TEST") - print(f" Kurz pro 31.12.2020: {rate_31_12}") - + print("Test 1: Sobota 2.1.2021 (víkend po svátku)") rate = rate_reporter.get_rate_for_date_with_fallback("02.01.2021", "TEST") expected_rate = 21.387 if rate == expected_rate: @@ -63,7 +36,7 @@ def test_rate_calculation(): # Test 2: Neděle 3.1.2021 (víkend po svátku) # Měla by být použita hodnota z pátku 1.1.2021 - print("\nTest 2: Neděle 3.1.2021 (víkend po svátku)") + print("Test 2: Neděle 3.1.2021 (víkend po svátku)") rate = rate_reporter.get_rate_for_date_with_fallback("03.01.2021", "TEST") expected_rate = 21.387 if rate == expected_rate: @@ -71,14 +44,11 @@ def test_rate_calculation(): else: print(f" CHYBA: Kurz pro 03.01.2021 je {rate}, očekáváno {expected_rate}") - # Test 3: Běžný den bez kurzu (např. 5.1.2021 - středa bez kurzu) - # Podle pravidel ČNB by měla být použita hodnota z posledního pracovního dne s kurzem před ním (04.01.2021) - print("\nTest 3: Běžný den bez kurzu (05.01.2021)") - # Zkontrolujeme kurz pro 04.01.2021 - rate_04_01 = database.get_rate("04.01.2021", "TEST") - print(f" Kurz pro 04.01.2021: {rate_04_01}") + # Test 3: Běžný den bez kurzu (např. 05.01.2021 - středa bez kurzu) + # Měla by být použita hodnota z posledního pracovního dne před ním (04.01.2021) + print("Test 3: Běžný den bez kurzu (05.01.2021)") rate = rate_reporter.get_rate_for_date_with_fallback("05.01.2021", "TEST") - expected_rate = 21.259 # Kurz z 04.01.2021 (poslední pracovní den s kurzem před 05.01.2021) + expected_rate = 21.259 # Kurz z 04.01.2021 (pondělí před 05.01.2021) if rate == expected_rate: print(f" OK: Kurz pro 05.01.2021 je {rate} (očekáváno {expected_rate})") else: @@ -86,19 +56,15 @@ def test_rate_calculation(): # Test 4: Pracovní den s kurzem (04.01.2021) # Měl by být použit jeho vlastní kurz - print("\nTest 4: Pracovní den s kurzem (04.01.2021)") + print("Test 4: Pracovní den s kurzem (04.01.2021)") rate = rate_reporter.get_rate_for_date_with_fallback("04.01.2021", "TEST") expected_rate = 21.259 if rate == expected_rate: print(f" OK: Kurz pro 04.01.2021 je {rate} (očekáváno {expected_rate})") else: print(f" CHYBA: Kurz pro 04.01.2021 je {rate}, očekáváno {expected_rate}") - -def run_all_tests(): - """Spustí všechny testy.""" - print("Spouštím testy dopočítávání kurzů...") - test_rate_calculation() + print("\nTesty dopočítávání kurzů dokončeny!") if __name__ == "__main__": - run_all_tests() \ No newline at end of file + test_rate_calculation() \ No newline at end of file