Fix: BIC generation + correct input format handling in CSV converter
This commit is contained in:
parent
ece0177a56
commit
3584385883
@ -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) ---")
|
||||||
|
|||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user