From 068e6627d9b5314d38f492825fed52b80f532b15 Mon Sep 17 00:00:00 2001 From: dfuhrmann3 Date: Fri, 3 Jul 2026 13:07:33 +0200 Subject: [PATCH] ZUGFeRD --- main.py | 79 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 17 deletions(-) diff --git a/main.py b/main.py index 45f9e42..a5019a6 100644 --- a/main.py +++ b/main.py @@ -20,6 +20,7 @@ if "invoice_counter" not in st.session_state: # 1. API-CLIENT FÜR DAS vLLM-BACKEND # ========================================== class LLMClient: + """Client für das vLLM-Backend (OpenAI-kompatibel) mit JSON-Schema-Unterstützung.""" def __init__(self, model="gemma431b", base_url="http://10.192.0.140:8002"): self.model = model @@ -350,7 +351,9 @@ with col1: uploaded_file = st.file_uploader("Wähle eine Rechnungs-PDF", type=["pdf"]) pdf_text = "" if uploaded_file is not None: - doc = fitz.open(stream=uploaded_file.read(), filetype="pdf") + # Optimierung: Nutze getvalue(), damit die PDF-Bytes später für ZUGFeRD erhalten bleiben + pdf_data = uploaded_file.getvalue() + doc = fitz.open(stream=pdf_data, filetype="pdf") for page in doc: pdf_text += page.get_text("text") + "\n" st.success("PDF eingelesen!") @@ -545,23 +548,65 @@ with col2: with c_vat_ui: st.metric("MwSt-Gesamt (€)", f"{computed_vat_amount:.2f}") with c_gross_ui: st.metric("Brutto-Zahlbetrag (€)", f"{computed_gross_amount:.2f}") + # --- NEU: DYNAMISCHE EXPORT-SEKTION FÜR ZUGFeRD ODER XRECHNUNG --- st.markdown("---") - if st.button("🔒 XRechnung exportieren", type="primary", width="stretch"): - final_invoice_dict = { - "invoice_type_code": selected_type_code, - "invoice_number": inv_num, "invoice_date": inv_date, "delivery_date": inv_delivery, - "buyer_reference": buyer_ref, "recipient_name": r_name, "recipient_email": r_email, - "recipient_street": r_street, "recipient_zip": r_zip, "recipient_city": r_city, - "items": edited_items, "total_net_amount": computed_net_amount, "total_vat_amount": computed_vat_amount, - "vat_rate_percent": vat_rate, "total_gross_amount": computed_gross_amount, "iban": "DE06120700240456207000", - "delivery_note_id": dn_id, - "order_id": o_id, - "contract_id": c_id, - "service_start_date": s_start, - "service_end_date": s_end, - "invoice_note": i_note - } - st.download_button(label="📥 Download XML", data=generate_compliant_xrechnung(final_invoice_dict), file_name=f"XRechnung_{inv_num}.xml", mime="text/xml") + export_format = st.selectbox( + "💾 Export-Format wählen", + options=["XRechnung (Reines XML)", "ZUGFeRD (Hybrid-PDF mit eingebettetem XML)"], + help="XRechnung generiert eine reine XML-Datei. ZUGFeRD bettet dieses XML direkt in dein originales PDF-Dokument ein." + ) + + final_invoice_dict = { + "invoice_type_code": selected_type_code, + "invoice_number": inv_num, "invoice_date": inv_date, "delivery_date": inv_delivery, + "buyer_reference": buyer_ref, "recipient_name": r_name, "recipient_email": r_email, + "recipient_street": r_street, "recipient_zip": r_zip, "recipient_city": r_city, + "items": edited_items, "total_net_amount": computed_net_amount, "total_vat_amount": computed_vat_amount, + "vat_rate_percent": vat_rate, "total_gross_amount": computed_gross_amount, "iban": "DE06120700240456207000", + "delivery_note_id": dn_id, + "order_id": o_id, + "contract_id": c_id, + "service_start_date": s_start, + "service_end_date": s_end, + "invoice_note": i_note + } + + xml_string = generate_compliant_xrechnung(final_invoice_dict) + + if export_format == "XRechnung (Reines XML)": + st.download_button( + label="📥 XRechnung XML herunterladen", + data=xml_string, + file_name=f"XRechnung_{inv_num}.xml", + mime="text/xml", + type="primary", + use_container_width=True + ) + else: + try: + # ZUGFeRD: Nutzt PyMuPDF, um das XML direkt in die hochgeladene PDF einzubetten + original_pdf_bytes = uploaded_file.getvalue() + doc = fitz.open(stream=original_pdf_bytes, filetype="pdf") + doc.embedded_file_add( + "factur-x.xml", + xml_string.encode("utf-8"), + filename="factur-x.xml", + desc="Factur-X/ZUGFeRD E-Invoice", + mimetype="text/xml" + ) + zugferd_pdf_bytes = doc.write() + doc.close() + + st.download_button( + label="📥 ZUGFeRD Hybrid-PDF herunterladen", + data=zugferd_pdf_bytes, + file_name=f"ZUGFeRD_{inv_num}.pdf", + mime="application/pdf", + type="primary", + use_container_width=True + ) + except Exception as e: + st.error(f"Fehler bei der ZUGFeRD-Generierung: {e}") # ========================================== # FOOTER