Powershell/Hermes/iban_tool/iban_csv_converter.py

150 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""
iban_csv_converter.py - Konvertiert eine CSV mit Kontodaten in eine CSV mit 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
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, BIC
from schwifty.exceptions import InvalidBankCode
def generate_iban(kontonummer: str, bankleitzahl: str) -> dict:
"""Erzeugt eine deutsche IBAN aus Kontonummer und Bankleitzahl."""
try:
bankleitzahl_clean = str(int(bankleitzahl)) # fuehrende Nullen entfernen
except ValueError:
bankleitzahl_clean = bankleitzahl
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 + 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 (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 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
try:
data = generate_iban(kontonummer, bankleitzahl)
except Exception as e:
print(f"Fehler in Zeile {i+1} (BLZ={bankleitzahl}, Konto={kontonummer}): {e}",
file=sys.stderr)
data = {"iban": "", "bic": "", "bankleitzahl": bankleitzahl, "kontonummer": kontonummer}
# Erstelle neue Zeile: Original-Felder + BIC (Index 8) + IBAN (Index 9)
new_row = list(row)
while len(new_row) < 10:
new_row.append("")
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
with open(args.ausgabe_datei, mode="w", encoding="iso-8859-1", newline="") as outfile:
writer = csv.writer(outfile, delimiter=";", quotechar='"', quoting=csv.QUOTE_ALL)
writer.writerows(output_rows)
print(f"Erfolgreich verarbeitet: {len(output_rows)} Zeilen.")
print(f"Ergebnis gespeichert in: {args.ausgabe_datei}")
if __name__ == "__main__":
try:
main()
except Exception as e:
print(f"\\nFEHLER: {e}", file=sys.stderr)
print("\\n--- Details:", file=sys.stderr)
import traceback
traceback.print_exc()
finally:
input("\\n--- Fertig (Enter zum Schließen) ---")