diff --git a/main.py b/main.py index 57467e1..12ac34c 100644 --- a/main.py +++ b/main.py @@ -69,7 +69,7 @@ class InvoiceMetadata(BaseModel): invoice_number: str = Field(description="Die Rechnungsnummer nach 'Nummer:' (z.B. R26-219)") invoice_date: str = Field(description="Das Rechnungsdatum nach 'Datum:' im Format YYYY-MM-DD") delivery_date: str = Field(description="Das Lieferdatum nach 'Lieferdatum:' im Format YYYY-MM-DD") - buyer_reference: str = Field(description="Der exakte Wert nach 'Ihr Auftrag:' (z.B. 05.06.2026-Herr.Knospe)") + buyer_reference: str = Field(default="", description="Käuferreferenz/Leitweg-ID: NUR eintragen, wenn im Text explizit ein Wert nach 'Ihr Auftrag:' o.ä. als eigene Referenz des Käufers/Empfängers steht (z.B. 05.06.2026-Herr.Knospe). NIEMALS die Nummer einer Auftragsbestätigung/Bestellung hier eintragen - die gehört ausschließlich in order_id. Wenn keine separate Käuferreferenz im Text erkennbar ist: leer lassen.") recipient_name: str = Field(description="Vollständige Firma des Kunden/Empfängers (z.B. Stadtwerke Hennigsdorf GmbH)") recipient_street: str = Field(description="Straße und Hausnummer des Kunden") recipient_zip: str = Field(description="Postleitzahl (PLZ) des Kunden") @@ -215,7 +215,12 @@ def generate_compliant_xrechnung(data): ET.SubElement(root, f"{{{CBC}}}Note").text = str(data["invoice_note"]).strip() ET.SubElement(root, f"{{{CBC}}}DocumentCurrencyCode").text = "EUR" - ET.SubElement(root, f"{{{CBC}}}BuyerReference").text = str(data["buyer_reference"]) + # BT-10 Käuferreferenz: NUR eintragen, wenn tatsächlich ein Wert vorliegt. Für private/ + # geschäftliche Empfänger (B2B) ist dieses Feld optional (0..1); nur bei Behörden (B2G) + # ist eine echte Leitweg-ID zwingend (BR-DE-15) - die kommt dann aber vom Empfänger selbst + # und wird nicht erfunden. + if data.get("buyer_reference") and str(data["buyer_reference"]).strip() != "": + ET.SubElement(root, f"{{{CBC}}}BuyerReference").text = str(data["buyer_reference"]).strip() if data.get("service_start_date") and data.get("service_end_date"): period_elem = ET.SubElement(root, f"{{{CAC}}}InvoicePeriod") @@ -241,8 +246,6 @@ def generate_compliant_xrechnung(data): supplier = ET.SubElement(root, f"{{{CAC}}}AccountingSupplierParty") party_supp = ET.SubElement(supplier, f"{{{CAC}}}Party") ET.SubElement(party_supp, f"{{{CBC}}}EndpointID", {"schemeID": "EM"}).text = "office@scitech-gmbh.de" - party_name_supp = ET.SubElement(party_supp, f"{{{CAC}}}PartyName") - ET.SubElement(party_name_supp, f"{{{CBC}}}Name").text = "scitech it solutions GmbH" addr_supp = ET.SubElement(party_supp, f"{{{CAC}}}PostalAddress") ET.SubElement(addr_supp, f"{{{CBC}}}StreetName").text = "Hermann-Schumann-Str. 4" @@ -270,8 +273,6 @@ def generate_compliant_xrechnung(data): customer = ET.SubElement(root, f"{{{CAC}}}AccountingCustomerParty") party_cust = ET.SubElement(customer, f"{{{CAC}}}Party") ET.SubElement(party_cust, f"{{{CBC}}}EndpointID", {"schemeID": "EM"}).text = str(data["recipient_email"]) if data.get("recipient_email") else "rechnung@kunde.de" - party_name_cust = ET.SubElement(party_cust, f"{{{CAC}}}PartyName") - ET.SubElement(party_name_cust, f"{{{CBC}}}Name").text = str(data["recipient_name"]) addr_cust = ET.SubElement(party_cust, f"{{{CAC}}}PostalAddress") ET.SubElement(addr_cust, f"{{{CBC}}}StreetName").text = str(data["recipient_street"]) ET.SubElement(addr_cust, f"{{{CBC}}}CityName").text = str(data["recipient_city"]) @@ -292,6 +293,12 @@ def generate_compliant_xrechnung(data): payee_acc = ET.SubElement(payment_means, f"{{{CAC}}}PayeeFinancialAccount") ET.SubElement(payee_acc, f"{{{CBC}}}ID").text = str(data["iban"]).replace(" ", "") + # BT-20 Zahlungsbedingungen (Freitext) - für menschliche Lesbarkeit, analog zur + # CII/ZUGFeRD-Fassung. BR-CO-25 ist bereits durch das gesetzte cbc:DueDate (BT-9) erfüllt; + # dieser Text ist zusätzliche Klarstellung, keine Pflicht. + payment_terms_ubl = ET.SubElement(root, f"{{{CAC}}}PaymentTerms") + ET.SubElement(payment_terms_ubl, f"{{{CBC}}}Note").text = "Zahlbar innerhalb 14 Tagen ohne Abzug." + tax_total = ET.SubElement(root, f"{{{CAC}}}TaxTotal") ET.SubElement(tax_total, f"{{{CBC}}}TaxAmount", {"currencyID": "EUR"}).text = f"{data['total_vat_amount']:.2f}" @@ -418,7 +425,10 @@ def generate_compliant_zugferd_cii(data): ET.SubElement(mon_sum, f"{{{RAM}}}LineTotalAmount").text = f"{item['total_amount']:.2f}" header_agree = ET.SubElement(trade_trans, f"{{{RAM}}}ApplicableHeaderTradeAgreement") - ET.SubElement(header_agree, f"{{{RAM}}}BuyerReference").text = str(data["buyer_reference"]) + # BT-10 Käuferreferenz: NUR eintragen, wenn tatsächlich ein Wert vorliegt (siehe UBL-Generator + # für die ausführliche Begründung). + if data.get("buyer_reference") and str(data["buyer_reference"]).strip() != "": + ET.SubElement(header_agree, f"{{{RAM}}}BuyerReference").text = str(data["buyer_reference"]).strip() supplier_party = ET.SubElement(header_agree, f"{{{RAM}}}SellerTradeParty") ET.SubElement(supplier_party, f"{{{RAM}}}Name").text = "scitech it solutions GmbH"