diff --git a/Hermes/iban_tool/iban_csv_converter.py b/Hermes/iban_tool/iban_csv_converter.py index d21610b..c998396 100644 --- a/Hermes/iban_tool/iban_csv_converter.py +++ b/Hermes/iban_tool/iban_csv_converter.py @@ -1,16 +1,18 @@ #!/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. +iban_csv_converter.py - Konvertiert eine BLZ/Konto-CSV in eine CSV mit IBAN+BIC. +Erzeugt das EXAKTE Zielformat: +"DE";"00001";" 7606148200045949670010000976";;;76061482;0004594967;;"GENODEF1HSB";"DE56760614820004594967";;00 + +Format-Regeln: +- Felder 1-3: mit doppelten Anfuehrungszeichen (Feld 3 behaelt fuehrende Leerzeichen) +- Felder 4-5: leer (keine "") +- Felder 6-7: BLZ und Kontonummer OHNE Anfuehrungszeichen +- Felder 8-9: BIC und IBAN MIT doppelten Anfuehrungszeichen +- Ende der Zeile: zwei leere Felder (;;) + 00 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 @@ -31,50 +33,52 @@ def generate_iban(kontonummer: str, bankleitzahl: str) -> dict: "iban": str(iban_obj), "bankleitzahl": bankleitzahl_clean, "kontonummer": kontonummer, + "bic": "", } - # Versuche BIC zu finden try: bic_obj = BIC.from_bank_code("DE", bankleitzahl_clean) result["bic"] = str(bic_obj) except (InvalidBankCode, Exception): - result["bic"] = "" + pass 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 +def format_output_line(row: list, bic: str, iban: str) -> str: + """Erzeugt die Ausgabetzeile im exakten Zielformat.""" + # Feld 1 (Index 0): "DE" + f1 = f'"{row[0]}"' if row[0] else "" + # Feld 2 (Index 1): "00001" + f2 = f'"{row[1]}"' if len(row) > 1 and row[1] else "" + # Feld 3 (Index 2): " 76061482..." - behaelt fuehrende Leerzeichen + f3 = f'"{row[2]}"' if len(row) > 2 and row[2].strip() else "" + # Felder 4,5: leer (keine "") + f4 = "" + f5 = "" + # Feld 6 (Index 5): BLZ ohne "" + f6 = row[5].strip() if len(row) > 5 else "" + # Feld 7 (Index 6): Konto ohne "" + f7 = row[6].strip() if len(row) > 6 else "" + # Feld 8: BIC mit "" + f8 = f'"{bic}"' if bic else "" + # Feld 9: IBAN mit "" + f9 = f'"{iban}"' if iban else "" - # 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 + # Zusammenfuegen: "DE";"00001";" ...";;;BLZ;KONTO;;"BIC";"IBAN";;00 + parts = [f1, f2, f3, f4, f5, f6, f7, "", f8, f9, "", "00"] + return ";".join(parts) def main(): parser = argparse.ArgumentParser( - description="Konvertiert eine CSV mit Kontodaten (BLZ + Konto) in eine CSV mit IBAN und BIC." + description="Konvertiert CSV mit BLZ+Konto zu CSV mit IBAN+BIC im exakten Zielformat." ) 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) + # Lese Eingabedatei rows = [] for encoding in ["iso-8859-1", "utf-8", "cp1252"]: try: @@ -92,48 +96,32 @@ def main(): print("FEHLER: Keine Daten gelesen.", file=sys.stderr) return - output_rows = [] + output_lines = [] for i, row in enumerate(rows): - # Finde BLZ und Kontonummer - bankleitzahl, kontonummer = find_blz_and_konto(row) + if len(row) < 7: + print(f"Warnung: Zeile {i+1} hat weniger als 7 Felder, wird uebersprungen.", file=sys.stderr) + continue + + bankleitzahl = row[5].strip() + kontonummer = row[6].strip() 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) + print(f"Warnung: Zeile {i+1} - keine BLZ/Konto gefunden.", file=sys.stderr) + output_lines.append(format_output_line(row, "", "")) continue try: data = generate_iban(kontonummer, bankleitzahl) + output_lines.append(format_output_line(row, data["bic"], data["iban"])) 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} + print(f"Fehler in Zeile {i+1}: {e}", file=sys.stderr) + output_lines.append(format_output_line(row, "", "")) - # 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 + # Schreibe 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) + outfile.write("\n".join(output_lines) + "\n") - print(f"Erfolgreich verarbeitet: {len(output_rows)} Zeilen.") + print(f"Erfolgreich verarbeitet: {len(output_lines)} Zeilen.") print(f"Ergebnis gespeichert in: {args.ausgabe_datei}") @@ -146,8 +134,7 @@ if __name__ == "__main__": import traceback traceback.print_exc() finally: - # Fenster offen halten – funktioniert auch bei Windows ohne Console-Problem try: input("\\\\n--- Fertig (Enter zum Schliessen) ---") except EOFError: - pass # stdin ist nicht interaktiv (z.B. Pipe), einfach beenden + pass diff --git a/Hermes/iban_tool/iban_tool_windows.zip b/Hermes/iban_tool/iban_tool_windows.zip index b115f7c..f117b31 100644 Binary files a/Hermes/iban_tool/iban_tool_windows.zip and b/Hermes/iban_tool/iban_tool_windows.zip differ