Phase 4: SEPA-Validierung (schwifty), Globale Suche (Cmd+K) & Jahresbericht-Modul
- SEPA-Export: IBAN/BIC-Validierung via schwifty, Schuldner-Konto aus StiftungsKonto - Globale Suche: Cmd+K Modal über Destinatäre, Pächter, Ländereien, Förderungen, Dokumente - Jahresbericht: Vollständige Jahresbilanz mit Einnahmen/Ausgaben/Netto, Unterstützungen, Landabrechnungen, Verwaltungskosten nach Kategorie, PDF-Export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1768,9 +1768,14 @@ def unterstuetzung_abschliessen(request, pk):
|
||||
|
||||
@login_required
|
||||
def sepa_xml_export(request):
|
||||
"""2c: SEPA pain.001 XML-Export für freigegebene Zahlungen."""
|
||||
"""Phase 4: SEPA pain.001 XML-Export mit schwifty IBAN/BIC-Validierung."""
|
||||
from xml.etree.ElementTree import Element, SubElement, tostring
|
||||
import xml.dom.minidom
|
||||
try:
|
||||
from schwifty import IBAN as SchwiftyIBAN, BIC as SchwiftyBIC
|
||||
schwifty_available = True
|
||||
except ImportError:
|
||||
schwifty_available = False
|
||||
|
||||
zahlungen = DestinataerUnterstuetzung.objects.filter(
|
||||
status="freigegeben"
|
||||
@@ -1780,10 +1785,32 @@ def sepa_xml_export(request):
|
||||
messages.warning(request, "Keine freigegebenen Zahlungen für SEPA-Export vorhanden.")
|
||||
return redirect("stiftung:zahlungs_pipeline")
|
||||
|
||||
# IBAN/BIC-Validierung mit schwifty
|
||||
validierungsfehler = []
|
||||
if schwifty_available:
|
||||
for zahlung in zahlungen:
|
||||
iban_raw = (zahlung.empfaenger_iban or zahlung.destinataer.iban or "").replace(" ", "")
|
||||
if not iban_raw:
|
||||
validierungsfehler.append(
|
||||
f"{zahlung.destinataer.get_full_name()}: Keine IBAN hinterlegt"
|
||||
)
|
||||
continue
|
||||
try:
|
||||
SchwiftyIBAN(iban_raw)
|
||||
except Exception:
|
||||
validierungsfehler.append(
|
||||
f"{zahlung.destinataer.get_full_name()}: Ungültige IBAN '{iban_raw}'"
|
||||
)
|
||||
|
||||
if validierungsfehler:
|
||||
for fehler in validierungsfehler:
|
||||
messages.error(request, f"SEPA-Validierungsfehler: {fehler}")
|
||||
return redirect("stiftung:zahlungs_pipeline")
|
||||
|
||||
heute = date.today()
|
||||
msg_id = f"STIFTUNG-{heute.strftime('%Y%m%d%H%M%S')}"
|
||||
nb_of_txs = zahlungen.count()
|
||||
ctrl_sum = str(sum(z.betrag for z in zahlungen))
|
||||
ctrl_sum = f"{sum(z.betrag for z in zahlungen):.2f}"
|
||||
|
||||
root = Element("Document", {
|
||||
"xmlns": "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03",
|
||||
@@ -1810,18 +1837,34 @@ def sepa_xml_export(request):
|
||||
dbtr = SubElement(pmt_inf, "Dbtr")
|
||||
SubElement(dbtr, "Nm").text = "van Hees-Theyssen-Vogel'sche Stiftung"
|
||||
|
||||
# Schuldner-IBAN aus aktivem Stiftungskonto
|
||||
if zahlungen.first() and zahlungen.first().konto and zahlungen.first().konto.iban:
|
||||
dbtr_acct = SubElement(pmt_inf, "DbtrAcct")
|
||||
dbtr_acct_id = SubElement(dbtr_acct, "Id")
|
||||
SubElement(dbtr_acct_id, "IBAN").text = zahlungen.first().konto.iban.replace(" ", "")
|
||||
dbtr_agt = SubElement(pmt_inf, "DbtrAgt")
|
||||
fin_instn_id = SubElement(dbtr_agt, "FinInstnId")
|
||||
bic_val = zahlungen.first().konto.bic.strip()
|
||||
if schwifty_available and bic_val:
|
||||
try:
|
||||
bic_val = str(SchwiftyBIC(bic_val))
|
||||
except Exception:
|
||||
pass
|
||||
SubElement(fin_instn_id, "BIC").text = bic_val or "NOTPROVIDED"
|
||||
|
||||
for zahlung in zahlungen:
|
||||
cdt_trf = SubElement(pmt_inf, "CdtTrfTxInf")
|
||||
pmt_id_el = SubElement(cdt_trf, "PmtId")
|
||||
SubElement(pmt_id_el, "EndToEndId").text = str(zahlung.id)[:35]
|
||||
amt = SubElement(cdt_trf, "Amt")
|
||||
instd_amt = SubElement(amt, "InstdAmt", {"Ccy": "EUR"})
|
||||
instd_amt.text = str(zahlung.betrag)
|
||||
instd_amt.text = f"{zahlung.betrag:.2f}"
|
||||
cdtr = SubElement(cdt_trf, "Cdtr")
|
||||
SubElement(cdtr, "Nm").text = (zahlung.empfaenger_name or zahlung.destinataer.get_full_name())[:70]
|
||||
cdtr_acct = SubElement(cdt_trf, "CdtrAcct")
|
||||
cdtr_id = SubElement(cdtr_acct, "Id")
|
||||
SubElement(cdtr_id, "IBAN").text = (zahlung.empfaenger_iban or zahlung.destinataer.iban or "").replace(" ", "")
|
||||
iban_clean = (zahlung.empfaenger_iban or zahlung.destinataer.iban or "").replace(" ", "")
|
||||
SubElement(cdtr_id, "IBAN").text = iban_clean
|
||||
rmt_inf = SubElement(cdt_trf, "RmtInf")
|
||||
SubElement(rmt_inf, "Ustrd").text = (zahlung.verwendungszweck or zahlung.beschreibung or "Stiftungsunterstützung")[:140]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user