feat: add email notifications, order references, stock badges, and sale flags
- Add customer email field and PayPal payment reminder emails with order reference (HEL-YEAR-ID format) - Display stock availability with color-coded badges (available/low/unavailable) - Add sale/clearance flag with animated red badge overlay - Implement automatic fallback placeholder for missing/broken product images - Add email column to order management view Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
116
wawi/templates/abrechnung.html
Executable file
116
wawi/templates/abrechnung.html
Executable file
@@ -0,0 +1,116 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="toolbar">
|
||||
<h2 style="margin: 0; font-size: 20px;">Abrechnung {{ year }}</h2>
|
||||
<form class="search" method="get" action="{{ url_for('bp.abrechnung') }}">
|
||||
<select name="year">
|
||||
{% for y in range(current_year, 2025, -1) %}
|
||||
<option value="{{ y }}" {% if year == y|string %}selected{% endif %}>{{ y }}</option>
|
||||
{% endfor %}
|
||||
<option value="ALT" {% if year == "ALT" %}selected{% endif %}>Vor 2026 (gesamt)</option>
|
||||
</select>
|
||||
<button class="btn" type="submit">Anzeigen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; margin-bottom: 20px;">
|
||||
<div class="stat">
|
||||
<div class="label">Gesamtumsatz</div>
|
||||
<div class="value">{{ "%.2f"|format(total_revenue) }} €</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="label">Verkaufte Artikel</div>
|
||||
<div class="value">{{ total_items }}</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="label">PayPal ({{ paypal_count }}x)</div>
|
||||
<div class="value">{{ "%.2f"|format(paypal_revenue) }} €</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="label">Bar ({{ bar_count }}x)</div>
|
||||
<div class="value">{{ "%.2f"|format(bar_revenue) }} €</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-bottom: 20px;">
|
||||
<div style="padding: 16px; border-bottom: 1px solid rgba(255,255,255,.08);">
|
||||
<h3 style="margin: 0; font-size: 16px;">Umsatz nach Artikel</h3>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Artikel</th>
|
||||
<th>Verkaufte Menge</th>
|
||||
<th>Umsatz</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if artikel_list %}
|
||||
{% for a in artikel_list %}
|
||||
<tr>
|
||||
<td>{{ a.artikel }}</td>
|
||||
<td>{{ a.menge }}</td>
|
||||
<td>{{ "%.2f"|format(a.umsatz) }} €</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="3" class="empty">Keine Daten für {{ year }}.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div style="padding: 16px; border-bottom: 1px solid rgba(255,255,255,.08);">
|
||||
<h3 style="margin: 0; font-size: 16px;">Alle erledigten Bestellungen ({{ orders|length }})</h3>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Name</th>
|
||||
<th>Mannschaft</th>
|
||||
<th>Artikel</th>
|
||||
<th>Größe</th>
|
||||
<th>Menge</th>
|
||||
<th>Preis/Stk</th>
|
||||
<th>Gesamt</th>
|
||||
<th>Zahlungsart</th>
|
||||
<th>Zahlung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if orders %}
|
||||
{% for o in orders %}
|
||||
<tr>
|
||||
<td>{{ o.completed_at }}</td>
|
||||
<td>{{ o.name }}</td>
|
||||
<td>{{ o.mannschaft }}</td>
|
||||
<td>{{ o.artikel }}</td>
|
||||
<td>{{ o.groesse }}</td>
|
||||
<td>{{ o.menge }}</td>
|
||||
<td>{{ "%.2f"|format(o.preis or 0) }} €</td>
|
||||
<td><strong>{{ "%.2f"|format((o.preis or 0) * (o.menge or 0)) }} €</strong></td>
|
||||
<td>
|
||||
{% if o.payment_method == "paypal" %}PayPal
|
||||
{% else %}Bar
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if o.payment_status == "paid" %}<span class="badge success">Bezahlt</span>
|
||||
{% else %}<span class="badge warning">Unbezahlt</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="10" class="empty">Keine erledigten Bestellungen für {{ year }}.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -25,6 +25,10 @@
|
||||
Bild hochladen (optional)
|
||||
<input type="file" name="bild_file" accept="image/*" />
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 8px; padding-top: 8px;">
|
||||
<input type="checkbox" name="sale" value="1" {% if item and item.sale %}checked{% endif %} style="width: auto; height: 18px;" />
|
||||
<span style="color: var(--text);">Sale / Abverkauf 🔥</span>
|
||||
</label>
|
||||
<label>
|
||||
Soll
|
||||
<input type="number" name="soll" min="0" value="{{ item.soll if item else 0 }}" />
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<th>Datum</th>
|
||||
<th>Name</th>
|
||||
<th>Handy</th>
|
||||
<th>E-Mail</th>
|
||||
<th>Mannschaft</th>
|
||||
<th>Artikel</th>
|
||||
<th>Größe</th>
|
||||
@@ -33,6 +34,7 @@
|
||||
<td>{{ o.created_at }}</td>
|
||||
<td>{{ o.name }}</td>
|
||||
<td>{{ o.handy }}</td>
|
||||
<td>{{ o.email or "–" }}</td>
|
||||
<td>{{ o.mannschaft }}</td>
|
||||
<td>{{ o.artikel }}</td>
|
||||
<td>{{ o.groesse }}</td>
|
||||
@@ -43,7 +45,8 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if o.payment_status == "paid" %}<span class="badge success">Bezahlt</span>
|
||||
{% if o.canceled %}–
|
||||
{% elif o.payment_status == "paid" %}<span class="badge success">Bezahlt</span>
|
||||
{% else %}<span class="badge warning">Unbezahlt</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
@@ -68,7 +71,7 @@
|
||||
{% endif %}
|
||||
<form method="post" action="{{ url_for('bp.cancel_order', order_id=o.id) }}" onsubmit="return confirm('Bestellung wirklich stornieren?');">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
<button class="btn small danger" type="submit">Stornieren</button>
|
||||
<button class="btn small danger" type="submit">Storno</button>
|
||||
</form>
|
||||
{% else %}
|
||||
–
|
||||
@@ -76,7 +79,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="order-history">
|
||||
<td colspan="12">
|
||||
<td colspan="13">
|
||||
<details class="inline-details">
|
||||
<summary>Historie</summary>
|
||||
<div class="history-grid">
|
||||
@@ -92,7 +95,7 @@
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="12" class="empty">Keine Bestellungen.</td>
|
||||
<td colspan="13" class="empty">Keine Bestellungen.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
Reference in New Issue
Block a user