PDF-Rechnung neues Layout: Logo rechts, Empfänger links, Firmendaten aus Einstellungen, Footer mit Kontakt/Paypal/IBAN

This commit is contained in:
Erik Thiele
2026-07-02 15:01:50 +02:00
parent e97cad924d
commit 5a8713ed2d
2 changed files with 188 additions and 36 deletions

188
app.py
View File

@@ -35,6 +35,13 @@ DEFAULT_VALUES = {
'rechnungsnummer': '',
'datum': datetime.now().strftime('%Y-%m-%d'),
'dark_mode': False,
'firmenName': '',
'firmenAdresse': '',
'telefon': '',
'email': '',
'paypal': '',
'iban': '',
'bankName': '',
}
@@ -175,50 +182,159 @@ def invoice_pdf():
gesamt_mwst = round(gesamt_netto * 0.19, 2) if calc.get('mwst_ausweisen') else 0
gesamt_brutto = round(gesamt_netto + gesamt_mwst, 2)
firmen_name = config.get('firmenName', '')
firmen_adresse = config.get('firmenAdresse', '')
telefon = config.get('telefon', '')
email = config.get('email', '')
paypal = config.get('paypal', '')
iban = config.get('iban', '')
bank_name = config.get('bankName', '')
kunde = data.get('kundenName', config.get('kundenName', ''))
adresse = data.get('kundenAdresse', config.get('kundenAdresse', ''))
rechnungsnummer = data.get('rechnungsnummer', config.get('rechnungsnummer', ''))
datum = data.get('datum', config.get('datum', ''))
projekt = config.get('projektName', '')
pdf = FPDF()
pdf.add_page()
pdf.set_font("Arial", "B", 24)
pdf.cell(0, 15, "RECHNUNG", ln=True, align='L')
pdf.ln(10)
pdf.set_font("Arial", "", 11)
rechnungsnummer = data.get('rechnungsnummer', config.get('rechnungsnummer', ''))
if rechnungsnummer:
pdf.cell(0, 6, f"Rechnungsnummer: {rechnungsnummer}", ln=True)
pdf.cell(0, 6, f"Datum: {data.get('datum', config.get('datum', ''))}", ln=True)
pdf.ln(10)
left = 15
right_margin = 15
col_left = left
col_right = 120
col_w = 80
pdf.set_font("Arial", "B", 12)
pdf.cell(0, 6, "Rechnungsempfanger:", ln=True)
pdf.set_font("Arial", "", 11)
pdf.cell(0, 6, data.get('kundenName', config.get('kundenName', '')), ln=True)
pdf.multi_cell(0, 6, data.get('kundenAdresse', config.get('kundenAdresse', '')))
pdf.ln(5)
# --- Header: Absender links, Logo rechts ---
pdf.set_font("Arial", "B", 11)
pdf.set_xy(col_left, 15)
pdf.cell(col_w, 5, firmen_name, ln=True)
pdf.set_font("Arial", "", 9)
if firmen_adresse:
pdf.set_x(col_left)
pdf.cell(col_w, 4, firmen_adresse, ln=True)
contact_parts = []
if telefon:
contact_parts.append(f"Tel: {telefon}")
if email:
contact_parts.append(f"Mail: {email}")
if contact_parts:
pdf.set_x(col_left)
pdf.cell(col_w, 4, " | ".join(contact_parts), ln=True)
pdf.set_font("Arial", "B", 12)
pdf.cell(0, 8, "Leistungsbeschreibung:", ln=True)
pdf.set_font("Arial", "", 11)
pdf.cell(100, 8, f"3D-Druck: {config.get('projektName', '')}")
pdf.cell(30, 8, str(stueckzahl), align='R')
pdf.cell(30, 8, f"{calc['verkaufspreis']:.2f} EUR", align='R')
pdf.cell(30, 8, f"{gesamt_netto:.2f} EUR", ln=True, align='R')
pdf.ln(10)
# Logo rechts
pdf.set_font("Arial", "B", 22)
pdf.set_xy(col_right, 15)
y_logo = pdf.get_y()
pdf.cell(130, 6, "Nettobetrag:")
pdf.cell(60, 6, f"{gesamt_netto:.2f} EUR", ln=True, align='R')
if calc.get('mwst_ausweisen'):
pdf.cell(130, 6, "MwSt. (19%):")
pdf.cell(60, 6, f"{gesamt_mwst:.2f} EUR", ln=True, align='R')
pdf.set_font("Arial", "B", 12)
if calc.get('mwst_ausweisen'):
pdf.cell(130, 8, "GESAMTBETRAG (brutto):")
else:
pdf.cell(130, 8, "GESAMTBETRAG:")
pdf.cell(60, 8, f"{gesamt_brutto:.2f} EUR", ln=True, align='R')
line1 = "JET"
line2 = "Design"
pdf.set_xy(col_right, y_logo)
pdf.set_text_color(6, 111, 209)
pdf.cell(col_w, 8, line1, ln=True, align='R')
pdf.set_x(col_right)
pdf.cell(col_w, 8, line2, ln=True, align='R')
pdf.set_text_color(0, 0, 0)
pdf.ln(10)
# --- Rechnungsdaten ---
invoice_y = max(pdf.get_y(), 50)
pdf.set_xy(left, invoice_y)
pdf.set_font("Arial", "", 10)
pdf.multi_cell(0, 5, "Zahlbar innerhalb von 14 Tagen ohne Abzug.\nVielen Dank fur Ihren Auftrag!")
if rechnungsnummer:
pdf.cell(col_w, 5, f"Rechnungsnr.: {rechnungsnummer}", ln=True)
pdf.set_x(left)
pdf.cell(col_w, 5, f"Datum: {datum}", ln=True)
# --- Empfänger ---
pdf.set_xy(left, pdf.get_y() + 10)
pdf.set_font("Arial", "B", 10)
pdf.cell(col_w, 5, "Rechnungsempfanger:", ln=True)
pdf.set_font("Arial", "", 10)
pdf.set_x(left)
pdf.cell(col_w, 5, kunde, ln=True)
if adresse:
pdf.set_x(left)
pdf.set_font("Arial", "", 9)
for line in adresse.split('\n'):
pdf.set_x(left)
pdf.cell(col_w, 4, line.strip(), ln=True)
# --- Trennlinie ---
pdf.set_draw_color(220, 220, 220)
pdf.line(left, pdf.get_y() + 6, 195, pdf.get_y() + 6)
pdf.set_draw_color(0, 0, 0)
# --- Positionstabelle ---
table_y = pdf.get_y() + 10
pdf.set_xy(left, table_y)
pdf.set_font("Arial", "B", 10)
pdf.cell(85, 6, "Leistungsbeschreibung")
pdf.cell(20, 6, "Menge", align='R')
pdf.cell(30, 6, "Einzelpreis", align='R')
pdf.cell(30, 6, "Gesamt", ln=True, align='R')
pdf.set_draw_color(200, 200, 200)
pdf.line(left, pdf.get_y() + 0.5, 195, pdf.get_y() + 0.5)
pdf.set_draw_color(0, 0, 0)
pdf.set_font("Arial", "", 10)
pdf.set_x(left)
pos_label = f"3D-Druck: {projekt}" if projekt else "3D-Druck"
pdf.cell(85, 7, pos_label)
pdf.cell(20, 7, str(stueckzahl), align='R')
pdf.cell(30, 7, f"{calc['verkaufspreis']:.2f} EUR", align='R')
pdf.cell(30, 7, f"{gesamt_netto:.2f} EUR", ln=True, align='R')
pdf.line(left, pdf.get_y() + 0.5, 195, pdf.get_y() + 0.5)
# --- Summen ---
pdf.set_x(left)
pdf.ln(8)
pdf.set_font("Arial", "", 10)
pdf.cell(130, 6, "Nettobetrag:")
pdf.cell(50, 6, f"{gesamt_netto:.2f} EUR", ln=True, align='R')
if calc.get('mwst_ausweisen'):
pdf.set_x(left)
pdf.cell(130, 6, "MwSt. (19%):")
pdf.cell(50, 6, f"{gesamt_mwst:.2f} EUR", ln=True, align='R')
pdf.set_font("Arial", "B", 12)
pdf.set_x(left)
label_total = "GESAMTBETRAG (brutto):" if calc.get('mwst_ausweisen') else "GESAMTBETRAG:"
pdf.cell(130, 8, label_total)
pdf.cell(50, 8, f"{gesamt_brutto:.2f} EUR", ln=True, align='R')
# --- Zahlungsbedingungen ---
pdf.set_font("Arial", "", 9)
pdf.set_x(left)
pdf.ln(6)
pdf.cell(0, 4, "Zahlbar innerhalb von 14 Tagen ohne Abzug. Vielen Dank fur Ihren Auftrag!")
# --- Footer ---
pdf.set_y(-35)
pdf.set_draw_color(180, 180, 180)
pdf.line(left, pdf.get_y(), 195, pdf.get_y())
pdf.set_draw_color(0, 0, 0)
pdf.ln(3)
pdf.set_font("Arial", "", 8)
pdf.set_text_color(100, 100, 100)
footer_parts = [firmen_name] if firmen_name else []
if telefon:
footer_parts.append(f"Tel: {telefon}")
if email:
footer_parts.append(email)
if footer_parts:
pdf.set_x(left)
pdf.cell(0, 4, " | ".join(footer_parts), ln=True)
if paypal:
pdf.set_x(left)
pdf.cell(0, 4, f"PayPal: {paypal}", ln=True)
if iban and bank_name:
pdf.set_x(left)
pdf.cell(0, 4, f"{iban} | {bank_name}", ln=True)
elif iban:
pdf.set_x(left)
pdf.cell(0, 4, iban, ln=True)
pdf.set_text_color(0, 0, 0)
return send_file(
io.BytesIO(pdf.output(dest='S').encode('latin-1')),