Fix: BIC generation + correct input format handling in CSV converter

This commit is contained in:
buiaca 2026-08-12 12:58:28 +02:00
parent ece0177a56
commit 3584385883
2 changed files with 96 additions and 50 deletions

View File

@ -1,84 +1,131 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
iban_csv_converter.py - Konvertiert eine CSV mit Kontodaten in eine CSV mit IBAN. iban_csv_converter.py - Konvertiert eine CSV mit Kontodaten in eine CSV mit IBAN.
Unterstuetzt das Bundesbank-BL-Z-Format mit variabler Spaltenanzahl.
Erwartetes Eingabeformat (Semikolon-getrennt, 12 Felder): Fuegt BIC (aus BLZ) und IBAN-Spalten automatisch hinzu.
"DE";"00001";" 763910001835904 0021447250";;;76391000;1835904;;;;;
Feld 6: Bankleitzahl (BLZ)
Feld 7: Kontonummer
Ausgabedatei enthaelt dieselbe Struktur plus eine zusaetzliche Spalte fuer die IBAN.
Nutzung: Nutzung:
python iban_csv_converter.py eingabe.csv ausgabe.csv python iban_csv_converter.py eingabe.csv ausgabe.csv
# Beispiel mit deinem virtuellen Umfeld: Erweitert um:
/home/alin/iban_tool/venv/bin/python /home/alin/iban_tool/iban_csv_converter.py daten.csv daten_m_iban.csv - 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 argparse
import csv import csv
import sys 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.""" """Erzeugt eine deutsche IBAN aus Kontonummer und Bankleitzahl."""
try: try:
bankleitzahl = str(int(bankleitzahl)) # fuehrende Nullen entfernen bankleitzahl_clean = str(int(bankleitzahl)) # fuehrende Nullen entfernen
except ValueError: except ValueError:
pass bankleitzahl_clean = bankleitzahl
iban_obj = IBAN.generate("DE", bank_code=bankleitzahl, account_code=kontonummer) iban_obj = IBAN.generate("DE", bank_code=bankleitzahl_clean, account_code=kontonummer)
return str(iban_obj) # ohne Leerzeichen, z.B. DE56760614820004594967 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(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Konvertiert eine CSV mit Kontodaten (BLZ im 6. Feld) in eine CSV mit IBAN." 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 (CSV mit Semikolon-Separator)"
)
parser.add_argument(
"ausgabe_datei", type=str,
help="Pfad zur Ausgabedatei (CSV mit zusaetzlicher IBAN-Spalte)"
) )
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() args = parser.parse_args()
# Lese die Eingabedatei # Lese die Eingabedatei (probiere mehrere Kodierungen)
with open(args.eingabe_datei, mode="r", encoding="iso-8859-1", newline="") as infile: rows = []
reader = csv.reader(infile, delimiter=";", quotechar='"') for encoding in ["iso-8859-1", "utf-8", "cp1252"]:
rows = list(reader) 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 = [] output_rows = []
for row in rows: for i, row in enumerate(rows):
if len(row) < 7: # Finde BLZ und Kontonummer
print(f"Warnung: Zeile hat weniger als 7 Felder, wird uebersprungen: {row}", file=sys.stderr) 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 continue
bankleitzahl = row[5] # 6. Feld (Index 5)
kontonummer = row[6] # 7. Feld (Index 6)
try: try:
iban = generate_iban(kontonummer.strip(), bankleitzahl.strip()) data = generate_iban(kontonummer, bankleitzahl)
except Exception as e: except Exception as e:
print(f"Fehler bei BLZ {bankleitzahl}, Konto {kontonummer}: {e}", file=sys.stderr) print(f"Fehler in Zeile {i+1} (BLZ={bankleitzahl}, Konto={kontonummer}): {e}",
iban = "" file=sys.stderr)
data = {"iban": "", "bic": "", "bankleitzahl": bankleitzahl, "kontonummer": kontonummer}
# Erstelle die neue Zeile: Original-Felder + IBAN am Ende # Erstelle neue Zeile: Original-Felder + BIC (Index 8) + IBAN (Index 9)
# Behalte das Format bei, fuege IBAN als letzte Spalte hinzu
new_row = list(row) new_row = list(row)
# Stelle sicher, dass die Zeile genau 12 Felder hat (oder fuege Leerfelder hinzu) while len(new_row) < 10:
while len(new_row) < 12:
new_row.append("") new_row.append("")
# Setze IBAN in das 9. Feld (Index 8) wie im Beispiel ("DE56760614820004594967") new_row[8] = data["bic"] # BIC-Spalte (Index 8)
# Falls das Feld bereits existiert, ueberschreibe es new_row[9] = data["iban"] # IBAN-Spalte (Index 9)
if len(new_row) > 8:
new_row[8] = iban
else:
new_row.append(iban)
output_rows.append(new_row) output_rows.append(new_row)
# Schreibe die Ausgabedatei # Schreibe die Ausgabedatei
@ -95,9 +142,8 @@ if __name__ == "__main__":
main() main()
except Exception as e: except Exception as e:
print(f"\\nFEHLER: {e}", file=sys.stderr) print(f"\\nFEHLER: {e}", file=sys.stderr)
print("\\n details:", file=sys.stderr) print("\\n--- Details:", file=sys.stderr)
import traceback import traceback
traceback.print_exc() traceback.print_exc()
finally: finally:
# Fenster offen halten, damit der Benutzer den Fehler oder die Bestaetigung lesen kann
input("\\n--- Fertig (Enter zum Schließen) ---") input("\\n--- Fertig (Enter zum Schließen) ---")