diff --git a/app.py b/app.py index ef2d5c6..13d8ab5 100644 --- a/app.py +++ b/app.py @@ -13,7 +13,9 @@ from flask import Flask, render_template, request, jsonify, redirect, url_for, s from fpdf import FPDF app = Flask(__name__) +app.config['MAX_CONTENT_LENGTH'] = 5 * 1024 * 1024 CONFIG_FILE = 'druckkalkulation_config.yaml' +LOGO_FILE = 'static/logo.png' DEFAULT_VALUES = { 'projektName': '', @@ -42,6 +44,7 @@ DEFAULT_VALUES = { 'paypal': '', 'iban': '', 'bankName': '', + 'logo': '', } @@ -163,6 +166,32 @@ def save_config_route(): return jsonify({'status': 'ok'}) +@app.route('/upload_logo', methods=['POST']) +def upload_logo(): + """Logo-Datei hochladen und in static/logo.png speichern.""" + if 'logo' not in request.files: + return jsonify({'error': 'Keine Datei'}), 400 + file = request.files['logo'] + if file.filename == '': + return jsonify({'error': 'Keine Datei ausgewaehlt'}), 400 + file.save(LOGO_FILE) + config = load_config() + config['logo'] = 'logo.png' + save_config(config) + return jsonify({'status': 'ok', 'filename': 'logo.png'}) + + +@app.route('/delete_logo', methods=['POST']) +def delete_logo(): + """Logo loeschen.""" + if os.path.exists(LOGO_FILE): + os.remove(LOGO_FILE) + config = load_config() + config['logo'] = '' + save_config(config) + return jsonify({'status': 'ok'}) + + @app.route('/invoice') def invoice(): """Rechnungsseite mit Kundendaten und Vorschau.""" @@ -221,19 +250,17 @@ def invoice_pdf(): pdf.set_x(left) pdf.cell(col_w, 4, " | ".join(contact_parts), ln=True) - # Logo rechts - pdf.set_font("Arial", "B", 22) - pdf.set_xy(col_right, 15) - y_logo = pdf.get_y() - - 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) + # Logo rechts (Bild oder Text-Fallback) + if os.path.exists(LOGO_FILE): + pdf.image(LOGO_FILE, x=col_right, y=15, w=60) + else: + pdf.set_font("Arial", "B", 22) + pdf.set_xy(col_right, 15) + pdf.set_text_color(6, 111, 209) + pdf.cell(col_w, 8, "JET", ln=True, align='R') + pdf.set_x(col_right) + pdf.cell(col_w, 8, "Design", ln=True, align='R') + pdf.set_text_color(0, 0, 0) # --- Rechnungsdaten --- invoice_y = max(pdf.get_y(), 50) diff --git a/static/script.js b/static/script.js index 58b0ff6..f945988 100644 --- a/static/script.js +++ b/static/script.js @@ -139,6 +139,41 @@ function showNotification(msg) { setTimeout(() => { container.style.display = 'none'; }, 2500); } +/** Logo hochladen via AJAX. */ +async function uploadLogo() { + const input = document.getElementById('logo-upload'); + if (!input.files || !input.files[0]) { + showNotification('Bitte eine Datei auswaehlen'); + return; + } + const formData = new FormData(); + formData.append('logo', input.files[0]); + try { + const res = await fetch('/upload_logo', { method: 'POST', body: formData }); + const data = await res.json(); + if (data.status === 'ok') { + showNotification('Logo gespeichert!'); + setTimeout(() => location.reload(), 800); + } + } catch (e) { + showNotification('Fehler beim Hochladen'); + } +} + +/** Logo loeschen. */ +async function deleteLogo() { + try { + const res = await fetch('/delete_logo', { method: 'POST' }); + const data = await res.json(); + if (data.status === 'ok') { + showNotification('Logo entfernt'); + setTimeout(() => location.reload(), 800); + } + } catch (e) { + showNotification('Fehler beim Loeschen'); + } +} + /** Initiale Berechnung beim Seitenladen. */ document.addEventListener('DOMContentLoaded', () => { recalculate(); diff --git a/templates/settings.html b/templates/settings.html index 28df781..952f683 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -78,6 +78,27 @@ +
+
Logo
+
+
+ {% if config.logo %} +
+ +
+ + {% endif %} + + +
Empfohlen: PNG, max. 240px breit. Erscheint rechts oben auf der Rechnung.
+
+
+
+
Drucker Abschreibung