Initial commit - Stand 26.04.2026
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
#!/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)
|
||||
Reference in New Issue
Block a user