#!/usr/bin/env python3 """ Importiert "Schulden Niki.xlsx" in die Buchhaltungsdatenbank. Erstellt einen Kredit und importiert alle Zahlungen/Auslagen. """ import openpyxl import psycopg2 import uuid from datetime import datetime from pathlib import Path # Konfiguration DB_CONFIG = { 'host': '192.168.2.200', 'port': 5432, 'database': 'postgres', 'user': 'postgres', 'password': 'postgres' # Passwort aus .env } EXCEL_FILE = r'C:\Users\renet\.openclaw\workspace\buchhaltungs-app\Schulden Niki.xlsx' def connect_db(): """Verbindet zur Datenbank""" return psycopg2.connect(**DB_CONFIG) def read_excel_data(filepath): """Liest die Excel-Daten ein""" wb = openpyxl.load_workbook(filepath, data_only=True) ws = wb['Tabelle1'] data = [] headers = {} # Zeile 6: Headers for col_idx in range(1, 9): cell = ws.cell(row=6, column=col_idx) if cell.value: headers[cell.value] = col_idx print(f"Gefundene Spalten: {headers}") # Zeile 7+: Daten for row_idx in range(7, ws.max_row + 1): row_data = {} for header, col_idx in headers.items(): row_data[header] = ws.cell(row=row_idx, column=col_idx).value # Nur Zeilen mit Datum verarbeiten if row_data.get('Datum'): data.append(row_data) return data, headers def determine_payment_type(abgezahlt, neue_kosten, fuer_was): """ Bestimmt den Zahlungstyp: - monatsrate: Regelmäßige Rate - sondertilgung: Zusätzliche Tilgung - auslage: Neue Kosten/Auslagen """ if neue_kosten and neue_kosten != 0: return 'auslage' elif fuer_was and ('tilgung' in str(fuer_was).lower() or 'sonder' in str(fuer_was).lower()): return 'sondertilgung' elif abgezahlt and abgezahlt > 0: return 'monatsrate' return 'sondertilgung' # Fallback def get_monthly_rate(data): """Ermittelt die monatliche Rate aus den Daten""" rates = [] for row in data: abgezahlt = row.get('Abgezahlt') neue_kosten = row.get('Neue Kosten') # Nur regelmäßige Zahlungen (positive Abgezahlt-Werte) if abgezahlt and abgezahlt > 0 and (not neue_kosten or neue_kosten == 0): rates.append(abgezahlt) # Häufigster Wert = Rate if rates: from collections import Counter return Counter(rates).most_common(1)[0][0] return 0 def import_niki_schulden(): """Hauptimport-Funktion""" print("=" * 60) print("IMPORT: Schulden Niki") print("=" * 60) # 1. Excel-Daten lesen print("\n1. Lese Excel-Daten...") data, headers = read_excel_data(EXCEL_FILE) print(f" {len(data)} Datensätze gefunden") if not data: print(" KEINE DATEN GEFUNDEN!") return False # Erste Zeile analysieren first_row = data[0] start_datum = first_row.get('Datum') restschuld_start = abs(first_row.get('Restschuld', 0)) # Negativ = Schulden print(f" Startdatum: {start_datum}") print(f" Ursprungsschuld: {restschuld_start}") # Rate ermitteln monatsrate = get_monthly_rate(data) print(f" Erkannte Monatsrate: {monatsrate}") # 2. Datenbankverbindung print("\n2. Verbinde zur Datenbank...") conn = connect_db() cursor = conn.cursor() try: # 3. Kredit erstellen print("\n3. Erstelle Kredit...") kredit_id = str(uuid.uuid4()) # Aktuelle Restschuld aus letzter Zeile last_row = data[-1] restschuld_aktuell = abs(last_row.get('Restschuld', 0)) cursor.execute(""" INSERT INTO kredite ( id, name, kreditgeber, person, ursprungsschuld, restschuld, monatsrate, zinssatz, start_datum, status, notizen ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """, ( kredit_id, 'Niki Schulden', 'René Täger', # Kreditgeber 'Niki', # Person restschuld_start, restschuld_aktuell, monatsrate if monatsrate > 0 else 0, 10.0, # Zinssatz 10% start_datum.date() if hasattr(start_datum, 'date') else start_datum, 'aktiv', 'Importiert aus Excel "Schulden Niki.xlsx" am ' + datetime.now().strftime('%Y-%m-%d') )) print(f" Kredit-ID: {kredit_id}") print(f" Name: Niki Schulden") print(f" Ursprungsschuld: {restschuld_start:.2f} €") print(f" Aktuelle Restschuld: {restschuld_aktuell:.2f} €") # 4. Zahlungen importieren print("\n4. Importiere Zahlungen...") zahlungen_count = 0 for row in data: datum = row.get('Datum') abgezahlt = row.get('Abgezahlt') or 0 neue_kosten = row.get('Neue Kosten') or 0 fuer_was = row.get('Für was', '') # Abgezahlt als positive Zahlung if abgezahlt and abgezahlt > 0: zahlung_id = str(uuid.uuid4()) typ = determine_payment_type(abgezahlt, None, fuer_was) cursor.execute(""" INSERT INTO kredit_zahlungen ( id, kredit_id, betrag, datum, typ, notiz ) VALUES (%s, %s, %s, %s, %s, %s) """, ( zahlung_id, kredit_id, abgezahlt, datum.date() if hasattr(datum, 'date') else datum, typ, fuer_was if fuer_was else f'{typ.capitalize()}' )) zahlungen_count += 1 # Neue Kosten als Auslage (negativer Betrag = mehr Schulden) if neue_kosten and neue_kosten < 0: zahlung_id = str(uuid.uuid4()) cursor.execute(""" INSERT INTO kredit_zahlungen ( id, kredit_id, betrag, datum, typ, notiz ) VALUES (%s, %s, %s, %s, %s, %s) """, ( zahlung_id, kredit_id, abs(neue_kosten), # Absolutwert für den Betrag datum.date() if hasattr(datum, 'date') else datum, 'auslage', fuer_was if fuer_was else 'Auslage' )) zahlungen_count += 1 print(f" {zahlungen_count} Zahlungen importiert") # 5. Commit conn.commit() print("\n5. Import erfolgreich abgeschlossen!") # 6. Verifikation print("\n6. Verifikation:") cursor.execute("SELECT COUNT(*) FROM kredit_zahlungen WHERE kredit_id = %s", (kredit_id,)) count = cursor.fetchone()[0] print(f" Zahlungen in Datenbank: {count}") cursor.execute("SELECT restschuld FROM kredite WHERE id = %s", (kredit_id,)) db_restschuld = cursor.fetchone()[0] print(f" Restschuld in Datenbank: {db_restschuld:.2f} €") print(f" Restschuld in Excel: {restschuld_aktuell:.2f} €") if abs(float(db_restschuld) - float(restschuld_aktuell)) < 0.01: print(" ✓ Restschuld stimmt überein!") else: print(" ⚠ Restschuld weicht ab!") return True except Exception as e: conn.rollback() print(f"\n✗ FEHLER: {e}") import traceback traceback.print_exc() return False finally: cursor.close() conn.close() if __name__ == '__main__': success = import_niki_schulden() exit(0 if success else 1)