Zahlungsziel als Klartext (BT-20) und Zahlungsreferenz (BT-83) ergänzt.
BT-20: Das Zahlungsziel erscheint zusätzlich zum strukturierten Fälligkeits-
datum im Klartext ("Zahlbar innerhalb von 14 Tagen ohne Abzug."). Bei Vorkasse
bewusst unterdrückt, da sich beide Angaben widersprechen würden.
BT-83: Die Rechnungsnummer als Verwendungszweck für den automatischen
Zahlungsabgleich - cbc:PaymentID (UBL) bzw. ram:PaymentReference (CII), jeweils
an der schema-korrekten Position der Sequenz.
Beides ergab der Vergleich gegen fünf Eingangs-E-Rechnungen: BT-20 lieferten
vier von fünf Lieferanten, BT-83 zwei von fünf.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
4b4118fe70
commit
df015c9f97
|
|
@ -157,13 +157,36 @@ def format_skonto_text(skonto_percent, skonto_days, invoice_date_str):
|
||||||
return f"Bei Zahlung innerhalb von {days} Tagen gewähren wir {percent_str}% Skonto."
|
return f"Bei Zahlung innerhalb von {days} Tagen gewähren wir {percent_str}% Skonto."
|
||||||
|
|
||||||
|
|
||||||
|
def format_payment_term_text(payment_term_days):
|
||||||
|
"""Klartext des Zahlungsziels fuer BT-20 ('14' -> 'Zahlbar innerhalb von 14 Tagen ohne
|
||||||
|
Abzug.'). Das Faelligkeitsdatum steht strukturiert in BT-9; der Klartext daneben ist bei
|
||||||
|
Lieferanten die Regel (4 von 5 Eingangsrechnungen liefern ihn) und fuer den Empfaenger
|
||||||
|
lesbar. Gibt "" zurueck, wenn kein gueltiges Zahlungsziel angegeben ist - es wird NICHTS
|
||||||
|
geraten."""
|
||||||
|
try:
|
||||||
|
days = int(str(payment_term_days).strip())
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return ""
|
||||||
|
if days <= 0:
|
||||||
|
return ""
|
||||||
|
return f"Zahlbar innerhalb von {days} Tagen ohne Abzug."
|
||||||
|
|
||||||
|
|
||||||
def build_payment_terms_note(data):
|
def build_payment_terms_note(data):
|
||||||
"""Kombinierter Freitext fuer die Zahlungsbedingungen (BT-20): optionaler Vorkasse-Hinweis
|
"""Kombinierter Freitext fuer die Zahlungsbedingungen (BT-20): das Zahlungsziel im Klartext
|
||||||
und/oder eine Skonto-Vereinbarung. Beides sind Zahlungsbedingungen, fuer die EN16931 kein
|
ODER ein Vorkasse-Hinweis, jeweils optional ergaenzt um eine Skonto-Vereinbarung. Fuer all
|
||||||
eigenes strukturiertes Feld kennt. Gibt "" zurueck, wenn keiner von beiden gesetzt ist."""
|
das kennt EN16931 kein eigenes strukturiertes Feld. Gibt "" zurueck, wenn nichts davon
|
||||||
|
gesetzt ist.
|
||||||
|
|
||||||
|
Vorkasse und Zahlungsziel schliessen sich bewusst aus: 'Zahlung per Vorkasse vor Lieferung'
|
||||||
|
und 'zahlbar innerhalb von 14 Tagen' wuerden sich widersprechen."""
|
||||||
parts = []
|
parts = []
|
||||||
if data.get("vorkasse"):
|
if data.get("vorkasse"):
|
||||||
parts.append(VORKASSE_HINWEIS)
|
parts.append(VORKASSE_HINWEIS)
|
||||||
|
else:
|
||||||
|
term_text = format_payment_term_text(data.get("payment_term_days"))
|
||||||
|
if term_text:
|
||||||
|
parts.append(term_text)
|
||||||
skonto_text = format_skonto_text(
|
skonto_text = format_skonto_text(
|
||||||
data.get("skonto_percent"), data.get("skonto_days"), data["invoice_date"]
|
data.get("skonto_percent"), data.get("skonto_days"), data["invoice_date"]
|
||||||
)
|
)
|
||||||
|
|
@ -1050,6 +1073,11 @@ def generate_compliant_xrechnung(data):
|
||||||
# BT-81 Zahlungsart: Standard bleibt 58 (SEPA-Ueberweisung), aber ueber
|
# BT-81 Zahlungsart: Standard bleibt 58 (SEPA-Ueberweisung), aber ueber
|
||||||
# PAYMENT_MEANS_CODES pro Rechnung waehlbar (siehe UN/EDIFACT 4461).
|
# PAYMENT_MEANS_CODES pro Rechnung waehlbar (siehe UN/EDIFACT 4461).
|
||||||
ET.SubElement(payment_means, f"{{{CBC}}}PaymentMeansCode").text = str(data.get("payment_means_code", "58"))
|
ET.SubElement(payment_means, f"{{{CBC}}}PaymentMeansCode").text = str(data.get("payment_means_code", "58"))
|
||||||
|
# BT-83 Zahlungsreferenz (Verwendungszweck): die Rechnungsnummer, damit der Empfaenger die
|
||||||
|
# Zahlung automatisch zuordnen kann. Muss laut UBL-Sequenz NACH PaymentMeansCode und VOR
|
||||||
|
# PayeeFinancialAccount stehen.
|
||||||
|
if str(data.get("invoice_number") or "").strip():
|
||||||
|
ET.SubElement(payment_means, f"{{{CBC}}}PaymentID").text = str(data["invoice_number"]).strip()
|
||||||
payee_acc = ET.SubElement(payment_means, f"{{{CAC}}}PayeeFinancialAccount")
|
payee_acc = ET.SubElement(payment_means, f"{{{CAC}}}PayeeFinancialAccount")
|
||||||
ET.SubElement(payee_acc, f"{{{CBC}}}ID").text = str(data["iban"]).replace(" ", "")
|
ET.SubElement(payee_acc, f"{{{CBC}}}ID").text = str(data["iban"]).replace(" ", "")
|
||||||
# BT-86 BIC der Verkaeuferbank (optional, aber von vielen Empfaengern erwartet).
|
# BT-86 BIC der Verkaeuferbank (optional, aber von vielen Empfaengern erwartet).
|
||||||
|
|
@ -1351,6 +1379,11 @@ def generate_compliant_zugferd_cii(data):
|
||||||
ET.SubElement(dn_ref, f"{{{RAM}}}IssuerAssignedID").text = str(data["delivery_note_id"]).strip()
|
ET.SubElement(dn_ref, f"{{{RAM}}}IssuerAssignedID").text = str(data["delivery_note_id"]).strip()
|
||||||
|
|
||||||
header_settle = ET.SubElement(trade_trans, f"{{{RAM}}}ApplicableHeaderTradeSettlement")
|
header_settle = ET.SubElement(trade_trans, f"{{{RAM}}}ApplicableHeaderTradeSettlement")
|
||||||
|
# BT-83 Zahlungsreferenz (Verwendungszweck): die Rechnungsnummer, damit der Empfaenger die
|
||||||
|
# Zahlung automatisch zuordnen kann. Muss laut CII-Sequenz VOR InvoiceCurrencyCode stehen
|
||||||
|
# (die Sequenz ist CreditorReferenceID -> PaymentReference -> ... -> InvoiceCurrencyCode).
|
||||||
|
if str(data.get("invoice_number") or "").strip():
|
||||||
|
ET.SubElement(header_settle, f"{{{RAM}}}PaymentReference").text = str(data["invoice_number"]).strip()
|
||||||
ET.SubElement(header_settle, f"{{{RAM}}}InvoiceCurrencyCode").text = "EUR"
|
ET.SubElement(header_settle, f"{{{RAM}}}InvoiceCurrencyCode").text = "EUR"
|
||||||
|
|
||||||
pay_means = ET.SubElement(header_settle, f"{{{RAM}}}SpecifiedTradeSettlementPaymentMeans")
|
pay_means = ET.SubElement(header_settle, f"{{{RAM}}}SpecifiedTradeSettlementPaymentMeans")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue