diff --git a/Hermes/iban_tool/iban_csv_converter.py b/Hermes/iban_tool/iban_csv_converter.py index e720437..2432045 100644 --- a/Hermes/iban_tool/iban_csv_converter.py +++ b/Hermes/iban_tool/iban_csv_converter.py @@ -1,84 +1,131 @@ #!/usr/bin/env python3 """ iban_csv_converter.py - Konvertiert eine CSV mit Kontodaten in eine CSV mit IBAN. - -Erwartetes Eingabeformat (Semikolon-getrennt, 12 Felder): -"DE";"00001";" 763910001835904 0021447250";;;76391000;1835904;;;;; - -Feld 6: Bankleitzahl (BLZ) -Feld 7: Kontonummer - -Ausgabedatei enthaelt dieselbe Struktur plus eine zusaetzliche Spalte fuer die IBAN. +Unterstuetzt das Bundesbank-BL-Z-Format mit variabler Spaltenanzahl. +Fuegt BIC (aus BLZ) und IBAN-Spalten automatisch hinzu. Nutzung: python iban_csv_converter.py eingabe.csv ausgabe.csv - # Beispiel mit deinem virtuellen Umfeld: - /home/alin/iban_tool/venv/bin/python /home/alin/iban_tool/iban_csv_converter.py daten.csv daten_m_iban.csv +Erweitert um: +- Automatische BIC-Erzeugung aus BLZ-Feld +- Flexibles Inputformat (erkennt BLZ/Konto anhand der Werte) +- Behaelt alle Original-Spalten bei und fuegt IBAN/BIC hinzu """ import argparse import csv import sys -from schwifty import IBAN +from schwifty import IBAN, BIC +from schwifty.exceptions import InvalidBankCode -def generate_iban(kontonummer: str, bankleitzahl: str) -> str: +def generate_iban(kontonummer: str, bankleitzahl: str) -> dict: """Erzeugt eine deutsche IBAN aus Kontonummer und Bankleitzahl.""" try: - bankleitzahl = str(int(bankleitzahl)) # fuehrende Nullen entfernen + bankleitzahl_clean = str(int(bankleitzahl)) # fuehrende Nullen entfernen except ValueError: - pass + bankleitzahl_clean = bankleitzahl - iban_obj = IBAN.generate("DE", bank_code=bankleitzahl, account_code=kontonummer) - return str(iban_obj) # ohne Leerzeichen, z.B. DE56760614820004594967 + iban_obj = IBAN.generate("DE", bank_code=bankleitzahl_clean, account_code=kontonummer) + result = { + "iban": str(iban_obj), + "bankleitzahl": bankleitzahl_clean, + "kontonummer": kontonummer, + } + + # Versuche BIC zu finden + try: + bic_obj = BIC.from_bank_code("DE", bankleitzahl_clean) + result["bic"] = str(bic_obj) + except (InvalidBankCode, Exception): + result["bic"] = "" + + return result + + +def find_blz_and_konto(row: list) -> tuple: + """Findet Bankleitzahl (BLZ) und Kontonummer in einer CSV-Zeile. + Priorisiert: 6. Feld = BLZ, 7. Feld = Konto (Index 5 und 6) + """ + # Standardfall: BLZ im 6. Feld (Index 5), Konto im 7. (Index 6) + if len(row) >= 7: + bankleitzahl = row[5].strip() + kontonummer = row[6].strip() + # Pruefe ob wir sinnvolle Werte haben + if bankleitzahl and kontonummer: + return bankleitzahl, kontonummer + + # Fallback: Suche nach 8-stelliger BLZ und Konto-Nummer + for i, field in enumerate(row): + field = field.strip() + # BLZ ist 8-stellig (oder 5-8 mit fuehrenden Nullen) + if (len(field) >= 5 and len(field) <= 8 and field.isdigit() + and i + 1 < len(row) and row[i + 1].strip().isdigit()): + return field, row[i + 1].strip() + + return None, None def main(): parser = argparse.ArgumentParser( - description="Konvertiert eine CSV mit Kontodaten (BLZ im 6. Feld) in eine CSV mit IBAN." - ) - parser.add_argument( - "eingabe_datei", type=str, - help="Pfad zur Eingabedatei (CSV mit Semikolon-Separator)" - ) - parser.add_argument( - "ausgabe_datei", type=str, - help="Pfad zur Ausgabedatei (CSV mit zusaetzlicher IBAN-Spalte)" + description="Konvertiert eine CSV mit Kontodaten (BLZ + Konto) in eine CSV mit IBAN und BIC." ) + parser.add_argument("eingabe_datei", type=str, help="Pfad zur Eingabedatei") + parser.add_argument("ausgabe_datei", type=str, help="Pfad zur Ausgabedatei") args = parser.parse_args() - # Lese die Eingabedatei - with open(args.eingabe_datei, mode="r", encoding="iso-8859-1", newline="") as infile: - reader = csv.reader(infile, delimiter=";", quotechar='"') - rows = list(reader) + # Lese die Eingabedatei (probiere mehrere Kodierungen) + rows = [] + for encoding in ["iso-8859-1", "utf-8", "cp1252"]: + try: + with open(args.eingabe_datei, mode="r", encoding=encoding, newline="") as f: + reader = csv.reader(f, delimiter=";", quotechar='"') + rows = list(reader) + break + except UnicodeDecodeError: + continue + except FileNotFoundError: + print(f"FEHLER: Datei nicht gefunden: {args.eingabe_datei}", file=sys.stderr) + return + + if not rows: + print("FEHLER: Keine Daten gelesen.", file=sys.stderr) + return output_rows = [] - for row in rows: - if len(row) < 7: - print(f"Warnung: Zeile hat weniger als 7 Felder, wird uebersprungen: {row}", file=sys.stderr) + for i, row in enumerate(rows): + # Finde BLZ und Kontonummer + bankleitzahl, kontonummer = find_blz_and_konto(row) + + if not bankleitzahl or not kontonummer: + print(f"Warnung: Zeile {i+1} - konnte keine BLZ/Konto finden: {row[:3]}...", + file=sys.stderr) + # Originalzeile behalten, leere IBAN/BIC einsetzen + new_row = list(row) + while len(new_row) < 9: + new_row.append("") + if len(new_row) > 9: + new_row[8] = "" # BIC + if len(new_row) > 9: + new_row[9] = "" # IBAN + else: + new_row.extend(["", ""]) + output_rows.append(new_row) continue - bankleitzahl = row[5] # 6. Feld (Index 5) - kontonummer = row[6] # 7. Feld (Index 6) - try: - iban = generate_iban(kontonummer.strip(), bankleitzahl.strip()) + data = generate_iban(kontonummer, bankleitzahl) except Exception as e: - print(f"Fehler bei BLZ {bankleitzahl}, Konto {kontonummer}: {e}", file=sys.stderr) - iban = "" + print(f"Fehler in Zeile {i+1} (BLZ={bankleitzahl}, Konto={kontonummer}): {e}", + file=sys.stderr) + data = {"iban": "", "bic": "", "bankleitzahl": bankleitzahl, "kontonummer": kontonummer} - # Erstelle die neue Zeile: Original-Felder + IBAN am Ende - # Behalte das Format bei, fuege IBAN als letzte Spalte hinzu + # Erstelle neue Zeile: Original-Felder + BIC (Index 8) + IBAN (Index 9) new_row = list(row) - # Stelle sicher, dass die Zeile genau 12 Felder hat (oder fuege Leerfelder hinzu) - while len(new_row) < 12: + while len(new_row) < 10: new_row.append("") - # Setze IBAN in das 9. Feld (Index 8) wie im Beispiel ("DE56760614820004594967") - # Falls das Feld bereits existiert, ueberschreibe es - if len(new_row) > 8: - new_row[8] = iban - else: - new_row.append(iban) + new_row[8] = data["bic"] # BIC-Spalte (Index 8) + new_row[9] = data["iban"] # IBAN-Spalte (Index 9) output_rows.append(new_row) # Schreibe die Ausgabedatei @@ -95,9 +142,8 @@ if __name__ == "__main__": main() except Exception as e: print(f"\\nFEHLER: {e}", file=sys.stderr) - print("\\n details:", file=sys.stderr) + print("\\n--- Details:", file=sys.stderr) import traceback traceback.print_exc() finally: - # Fenster offen halten, damit der Benutzer den Fehler oder die Bestaetigung lesen kann input("\\n--- Fertig (Enter zum Schließen) ---") diff --git a/Hermes/iban_tool/iban_tool_windows.zip b/Hermes/iban_tool/iban_tool_windows.zip index 0550c1b..8c83807 100644 Binary files a/Hermes/iban_tool/iban_tool_windows.zip and b/Hermes/iban_tool/iban_tool_windows.zip differ