PDF-Rechnung neues Layout: Logo rechts, Empfänger links, Firmendaten aus Einstellungen, Footer mit Kontakt/Paypal/IBAN
This commit is contained in:
188
app.py
188
app.py
@@ -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')),
|
||||
|
||||
@@ -42,6 +42,42 @@
|
||||
|
||||
<form id="settings-form" onchange="onInputChange()" onkeyup="onInputChange()">
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header"><i class="ti ti-building me-2"></i>Firmendaten</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Firmenname</label>
|
||||
<input type="text" class="form-control" data-var="firmenName" value="{{ config.firmenName }}">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Telefon</label>
|
||||
<input type="text" class="form-control" data-var="telefon" value="{{ config.telefon }}">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">E-Mail</label>
|
||||
<input type="email" class="form-control" data-var="email" value="{{ config.email }}">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">PayPal</label>
|
||||
<input type="text" class="form-control" data-var="paypal" value="{{ config.paypal }}">
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<label class="form-label">IBAN</label>
|
||||
<input type="text" class="form-control" data-var="iban" value="{{ config.iban }}">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Bankname</label>
|
||||
<input type="text" class="form-control" data-var="bankName" value="{{ config.bankName }}">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label">Adresse</label>
|
||||
<input type="text" class="form-control" data-var="firmenAdresse" value="{{ config.firmenAdresse }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header"><i class="ti ti-tools me-2"></i>Drucker Abschreibung</div>
|
||||
<div class="card-body">
|
||||
|
||||
Reference in New Issue
Block a user