#!/usr/bin/env python3 """ Importiert alle Zahlungen aus "Schulden Kerstin.xlsx" für Kredit ID bdcb8b1e-a0e6-4d49-b6ee-c16742e38403 """ import openpyxl from datetime import datetime import re import requests import sys # Konfiguration EXCEL_FILE = "Schulden Kerstin.xlsx" SHEET_NAME = "Tabelle2" KREDIT_ID = "bdcb8b1e-a0e6-4d49-b6ee-c16742e38403" API_BASE = "http://localhost:3000/api" def parse_betrag(value): """Parst einen Geldbetrag aus verschiedenen Formaten""" if value is None: return None if isinstance(value, (int, float)): return float(value) if isinstance(value, str): # Entferne € und Leerzeichen, konvertiere Komma zu Punkt text = value.replace('€', '').replace(' ', '').strip() text = text.replace(',', '.') # Extrahiere Zahl mit optionalem Vorzeichen match = re.search(r'[+-]?[\d.]+', text) if match: try: return float(match.group()) except ValueError: return None return None def parse_datum(value): """Parst ein Datum aus verschiedenen Formaten""" if value is None: return None if isinstance(value, datetime): return value if isinstance(value, str): # Verschiedene Datumsformate formats = [ '%d.%m.%Y', '%Y-%m-%d', '%d/%m/%Y', '%m/%d/%Y', '%d.%m.%y', ] for fmt in formats: try: return datetime.strptime(value.strip(), fmt) except ValueError: continue return None def is_datum_in_zelle(value): """Prüft ob ein Wert ein Datum enthält (Zahl oder Text mit Datum)""" if isinstance(value, datetime): return True if isinstance(value, str): # Prüfe auf Datumsformate if re.search(r'\d{1,2}[./]\d{1,2}[./]\d{2,4}', value): return True # Excel-Datum als Zahl (Oberfläche: Zahl > 30000 sind meist Datums) if isinstance(value, (int, float)): if 30000 < value < 50000: # Excel-Datum-Bereich ca. 1980-2030 return True return False def excel_date_to_datetime(excel_date): """Konvertiert Excel-Datum (Zahl) zu datetime""" # Excel-Datum: Tage seit 30.12.1899 return datetime(1899, 12, 30) + __import__('datetime').timedelta(days=excel_date) def main(): print(f"Lade Excel-Datei: {EXCEL_FILE}") # Excel laden wb = openpyxl.load_workbook(EXCEL_FILE, data_only=True) # Sheet "Tabelle2" verwenden oder zweites Sheet if SHEET_NAME in wb.sheetnames: ws = wb[SHEET_NAME] else: ws = wb.worksheets[1] if len(wb.worksheets) > 1 else wb.worksheets[0] print(f"Verwende Sheet: {ws.title}") print(f"Sheet hat {ws.max_row} Zeilen und {ws.max_column} Spalten") # Suche nach Datum- und Betragsspalten zahlungen = [] print("\n--- Suche nach Zahlungen in allen Zeilen ---") # Durchsuche alle Zeilen for row_idx, row in enumerate(ws.iter_rows(min_row=1, max_row=ws.max_row, values_only=True), 1): # Prüfe jede Zelle in der Zeile auf Datum for col_idx, cell_value in enumerate(row, 1): if cell_value is None: continue # Prüfe ob Zelle ein Datum enthält datum = None betrag = None notiz = None # Fall 1: Direktes datetime-Objekt if isinstance(cell_value, datetime): datum = cell_value # Suche Betrag in derselben Zeile (andere Spalten) for other_idx, other_val in enumerate(row, 1): if other_idx != col_idx: parsed = parse_betrag(other_val) if parsed is not None: betrag = parsed break # Fall 2: String mit Datum elif isinstance(cell_value, str): datum = parse_datum(cell_value) if datum: # Suche Betrag in derselben Zeile for other_idx, other_val in enumerate(row, 1): if other_idx != col_idx: parsed = parse_betrag(other_val) if parsed is not None: betrag = parsed break # Fall 3: Excel-Datum als Zahl elif isinstance(cell_value, (int, float)): if 30000 < cell_value < 50000: datum = excel_date_to_datetime(cell_value) # Suche Betrag in derselben Zeile for other_idx, other_val in enumerate(row, 1): if other_idx != col_idx: parsed = parse_betrag(other_val) if parsed is not None: betrag = parsed break # Wenn wir ein Datum haben, extrahiere Notiz aus erster nicht-leerer Spalte if datum: for other_idx, other_val in enumerate(row, 1): if other_val and other_idx != col_idx: if isinstance(other_val, str) and not parse_betrag(other_val): notiz = other_val.strip() break # Füge Zahlung hinzu zahlung = { 'zeile': row_idx, 'spalte': col_idx, 'datum': datum, 'betrag': betrag, 'notiz': notiz or f"Zeile {row_idx}" } zahlungen.append(zahlung) print(f" Zeile {row_idx}, Spalte {col_idx}: {datum.strftime('%d.%m.%Y')}, {betrag}€, Notiz: {notiz}") break # Nur eine Zahlung pro Zeile print(f"\n--- Gefundene Zahlungen: {len(zahlungen)} ---") for z in zahlungen: print(f" {z['datum'].strftime('%d.%m.%Y')}: {z['betrag']}€ - {z['notiz']}") # Speichere gefundene Zahlungen für Debugging with open('gefundene_zahlungen.txt', 'w', encoding='utf-8') as f: f.write(f"Gefundene Zahlungen: {len(zahlungen)}\n\n") for z in zahlungen: f.write(f"{z['datum'].strftime('%d.%m.%Y')}: {z['betrag']}€ - {z['notiz']}\n") # Importiere Zahlungen via API print(f"\n--- Importiere {len(zahlungen)} Zahlungen via API ---") erfolgreich = 0 fehler = [] for zahlung in zahlungen: # Bestimme Typ typ = 'monatsrate' if zahlung['betrag'] and zahlung['betrag'] > 0 else 'auslage' # Betrag immer positiv speichern (Typ gibt Richtung an) betrag_abs = abs(zahlung['betrag']) if zahlung['betrag'] else 0 payload = { 'datum': zahlung['datum'].strftime('%Y-%m-%d'), 'betrag': betrag_abs, 'typ': typ, 'notiz': zahlung['notiz'] } try: url = f"{API_BASE}/kredite/{KREDIT_ID}/zahlungen" print(f" POST {url}") print(f" Payload: {payload}") response = requests.post(url, json=payload, timeout=10) if response.status_code == 201: print(f" ✓ Erfolgreich importiert") erfolgreich += 1 else: error_msg = f"Fehler {response.status_code}: {response.text}" print(f" ✗ {error_msg}") fehler.append({'zahlung': zahlung, 'fehler': error_msg}) except Exception as e: error_msg = f"Exception: {str(e)}" print(f" ✗ {error_msg}") fehler.append({'zahlung': zahlung, 'fehler': error_msg}) # Ergebnis print(f"\n=== ERGEBNIS ===") print(f"Gefundene Zahlungen in Excel: {len(zahlungen)}") print(f"Erfolgreich importiert: {erfolgreich}") print(f"Fehler: {len(fehler)}") if fehler: print(f"\nFehlerhafte Zahlungen:") for f in fehler: print(f" - {f['zahlung']['datum'].strftime('%d.%m.%Y')}: {f['fehler']}") # Verifiziere via API print(f"\n--- Verifizierung ---") try: verify_url = f"{API_BASE}/kredite/{KREDIT_ID}/zahlungen" response = requests.get(verify_url, timeout=10) if response.status_code == 200: db_zahlungen = response.json() print(f"Zahlungen in Datenbank: {len(db_zahlungen)}") if len(db_zahlungen) == len(zahlungen): print("✓ Anzahl stimmt überein!") else: print(f"✗ ANZAHL STIMMT NICHT ÜBEREIN: Excel={len(zahlungen)}, DB={len(db_zahlungen)}") else: print(f"Konnte DB nicht prüfen: {response.status_code}") except Exception as e: print(f"Konnte Verifizierung nicht durchführen: {e}") return erfolgreich == len(zahlungen) if __name__ == "__main__": success = main() sys.exit(0 if success else 1)