Initial commit
This commit is contained in:
23
wawi/templates/ausbuchen.html
Normal file
23
wawi/templates/ausbuchen.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="card form-card">
|
||||
<h2>Ausbuchen: {{ item.artikel }} ({{ item.groesse }})</h2>
|
||||
<div class="note">Aktueller Bestand: <strong>{{ item.gezaehlt }}</strong></div>
|
||||
<form method="post" onsubmit="return confirm('Wirklich ausbuchen?');">
|
||||
<div class="form-grid">
|
||||
<label>
|
||||
Menge
|
||||
<input type="number" name="menge" min="1" required />
|
||||
</label>
|
||||
<label>
|
||||
Grund (optional)
|
||||
<input type="text" name="grund" placeholder="z. B. Verkauf, Defekt, Muster" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-accent" type="submit">Ausbuchen</button>
|
||||
<a class="btn ghost" href="{{ url_for('bp.index') }}">Abbrechen</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
37
wawi/templates/base.html
Normal file
37
wawi/templates/base.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>{{ title or "Hellas Artikelverwaltung" }}</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="wrap top">
|
||||
<div class="brand">
|
||||
<img src="{{ url_for('static', filename='logo.png') }}" alt="Hellas 1899 Logo" />
|
||||
<div>
|
||||
<h1>Hellas 1899 · Artikelverwaltung</h1>
|
||||
<div class="meta">Bestand & Ausbuchungen</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="nav">
|
||||
{% if logged_in %}
|
||||
<a class="btn icon" href="{{ url_for('bp.index') }}" title="Übersicht" aria-label="Übersicht"><span>⌂</span></a>
|
||||
<a class="btn icon accent" href="{{ url_for('bp.new_item') }}" title="Neuer Artikel" aria-label="Neuer Artikel"><span>+</span></a>
|
||||
<a class="btn icon" href="{{ url_for('bp.users') }}" title="Benutzer" aria-label="Benutzer"><span>☺︎</span></a>
|
||||
<a class="btn icon" href="{{ url_for('bp.orders') }}" title="Bestellungen" aria-label="Bestellungen"><span>☑︎</span></a>
|
||||
<a class="btn icon ghost" href="{{ url_for('bp.logout') }}" title="Logout" aria-label="Logout"><span>⏻</span></a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<div class="wrap">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</main>
|
||||
<a href="#" class="to-top" title="Nach oben" aria-label="Nach oben">↑</a>
|
||||
</body>
|
||||
</html>
|
||||
46
wawi/templates/edit.html
Normal file
46
wawi/templates/edit.html
Normal file
@@ -0,0 +1,46 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="card form-card">
|
||||
<h2>{{ "Artikel bearbeiten" if item else "Neuen Artikel anlegen" }}</h2>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="form-grid">
|
||||
<label>
|
||||
Artikel
|
||||
<input type="text" name="artikel" required value="{{ item.artikel if item else '' }}" />
|
||||
</label>
|
||||
<label>
|
||||
Größe
|
||||
<input type="text" name="groesse" required value="{{ item.groesse if item else '' }}" />
|
||||
</label>
|
||||
<label>
|
||||
Preis (EUR)
|
||||
<input type="number" name="preis" step="0.01" min="0" value="{{ item.preis if item else 0 }}" />
|
||||
</label>
|
||||
<label>
|
||||
Bild‑URL (optional)
|
||||
<input type="text" name="bild_url" placeholder="/images/artikel.jpg" value="{{ item.bild_url if item else '' }}" />
|
||||
</label>
|
||||
<label>
|
||||
Bild hochladen (optional)
|
||||
<input type="file" name="bild_file" accept="image/*" />
|
||||
</label>
|
||||
<label>
|
||||
Soll
|
||||
<input type="number" name="soll" min="0" value="{{ item.soll if item else 0 }}" />
|
||||
</label>
|
||||
<label>
|
||||
Bestand
|
||||
<input type="number" name="gezaehlt" min="0" value="{{ item.gezaehlt if item else 0 }}" />
|
||||
</label>
|
||||
<label>
|
||||
Verkäufe
|
||||
<input type="number" name="verkaeufe" min="0" value="{{ item.verkaeufe if item else 0 }}" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-accent" type="submit">Speichern</button>
|
||||
<a class="btn ghost" href="{{ url_for('bp.index') }}">Abbrechen</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
88
wawi/templates/index.html
Normal file
88
wawi/templates/index.html
Normal file
@@ -0,0 +1,88 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="toolbar">
|
||||
<form class="search" method="get" action="{{ url_for('bp.index') }}">
|
||||
<input type="search" name="q" placeholder="Artikel oder Größe suchen…" value="{{ q }}" />
|
||||
<select name="sort">
|
||||
<option value="gezaehlt" {% if sort == "gezaehlt" %}selected{% endif %}>Bestand</option>
|
||||
<option value="soll" {% if sort == "soll" %}selected{% endif %}>Soll</option>
|
||||
<option value="artikel" {% if sort == "artikel" %}selected{% endif %}>Artikel</option>
|
||||
<option value="groesse" {% if sort == "groesse" %}selected{% endif %}>Größe</option>
|
||||
<option value="verkaeufe" {% if sort == "verkaeufe" %}selected{% endif %}>Verkäufe</option>
|
||||
</select>
|
||||
<select name="dir">
|
||||
<option value="desc" {% if direction == "desc" %}selected{% endif %}>↓</option>
|
||||
<option value="asc" {% if direction == "asc" %}selected{% endif %}>↑</option>
|
||||
</select>
|
||||
<button class="btn" type="submit">Filtern</button>
|
||||
<a class="btn ghost" href="{{ url_for('bp.index') }}">Zurücksetzen</a>
|
||||
</form>
|
||||
<div class="stat">
|
||||
<div class="label">Artikel gesamt</div>
|
||||
<div class="value">{{ total }}</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="label">Bestand gesamt</div>
|
||||
<div class="value">{{ total_bestand }}</div>
|
||||
</div>
|
||||
<a class="stat stat-link" href="{{ url_for('bp.orders') }}" title="Offene Bestellungen anzeigen">
|
||||
<div class="label">Offene Bestellungen</div>
|
||||
<div class="value">{{ open_orders }}</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Artikel</th>
|
||||
<th>Größe</th>
|
||||
<th>Preis</th>
|
||||
<th>Soll</th>
|
||||
<th>Bestand</th>
|
||||
<th>Abweichung</th>
|
||||
<th>Fehlbestand</th>
|
||||
<th>Verkäufe</th>
|
||||
<th class="actions">Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if groups %}
|
||||
{% for g in groups %}
|
||||
<tr class="group-row">
|
||||
<td colspan="9"><strong>{{ g.artikel }}</strong></td>
|
||||
</tr>
|
||||
{% for r in g.rows %}
|
||||
{% set diff = (r.gezaehlt or 0) - (r.soll or 0) %}
|
||||
{% set fehl = (r.soll or 0) - (r.gezaehlt or 0) %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>{{ r.groesse }}</td>
|
||||
<td>{{ "%.2f"|format(r.preis or 0) }} €</td>
|
||||
<td>{{ r.soll }}</td>
|
||||
<td>{{ r.gezaehlt }}</td>
|
||||
<td class="{{ 'pos' if diff > 0 else 'neg' if diff < 0 else '' }}">{{ diff }}</td>
|
||||
<td>{{ fehl if fehl > 0 else "–" }}</td>
|
||||
<td>{{ r.verkaeufe }}</td>
|
||||
<td class="actions">
|
||||
<a class="btn icon" href="{{ url_for('bp.edit_item', item_id=r.id) }}" title="Bearbeiten" aria-label="Bearbeiten"><span>✎</span></a>
|
||||
<form method="post" action="{{ url_for('bp.verkauf', item_id=r.id) }}" onsubmit="return confirm('Wirklich 1 Stück als verkauft buchen?');">
|
||||
<button class="btn icon" type="submit" title="Verkauf +1" aria-label="Verkauf +1"><span>🛒</span></button>
|
||||
</form>
|
||||
<a class="btn icon" href="{{ url_for('bp.ausbuchen', item_id=r.id) }}" title="Ausbuchen" aria-label="Ausbuchen"><span>⇩</span></a>
|
||||
<form method="post" action="{{ url_for('bp.delete_item', item_id=r.id) }}" onsubmit="return confirm('Wirklich löschen? Dieser Vorgang kann nicht rückgängig gemacht werden.');">
|
||||
<button class="btn icon danger" type="submit" title="Löschen" aria-label="Löschen"><span>🗑</span></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="9" class="empty">Keine Treffer.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
24
wawi/templates/login.html
Normal file
24
wawi/templates/login.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="card form-card">
|
||||
<h2>Login</h2>
|
||||
{% if error %}
|
||||
<div class="note">Benutzername oder Passwort ist falsch.</div>
|
||||
{% endif %}
|
||||
<form method="post">
|
||||
<div class="form-grid">
|
||||
<label>
|
||||
Benutzer
|
||||
<input type="text" name="user" required />
|
||||
</label>
|
||||
<label>
|
||||
Passwort
|
||||
<input type="password" name="password" required />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-accent" type="submit">Anmelden</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
79
wawi/templates/orders.html
Normal file
79
wawi/templates/orders.html
Normal file
@@ -0,0 +1,79 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="note">
|
||||
{% for m in messages %}
|
||||
<div>{{ m }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="card">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Name</th>
|
||||
<th>Handy</th>
|
||||
<th>Mannschaft</th>
|
||||
<th>Artikel</th>
|
||||
<th>Größe</th>
|
||||
<th>Menge</th>
|
||||
<th>Notiz</th>
|
||||
<th>Status</th>
|
||||
<th class="actions">Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for o in rows %}
|
||||
<tr>
|
||||
<td>{{ o.created_at }}</td>
|
||||
<td>{{ o.name }}</td>
|
||||
<td>{{ o.handy }}</td>
|
||||
<td>{{ o.mannschaft }}</td>
|
||||
<td>{{ o.artikel }}</td>
|
||||
<td>{{ o.groesse }}</td>
|
||||
<td>{{ o.menge }}</td>
|
||||
<td>{{ o.notiz or "–" }}</td>
|
||||
<td>
|
||||
{% if o.canceled %}Storniert
|
||||
{% elif o.done %}Erledigt
|
||||
{% else %}Offen
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="actions">
|
||||
{% if not o.done and not o.canceled %}
|
||||
<form method="post" action="{{ url_for('bp.complete_order', order_id=o.id) }}" onsubmit="return confirm('Bestellung als erledigt markieren?');">
|
||||
<button class="btn small" type="submit">Erledigt</button>
|
||||
</form>
|
||||
<form method="post" action="{{ url_for('bp.cancel_order', order_id=o.id) }}" onsubmit="return confirm('Bestellung wirklich stornieren?');">
|
||||
<button class="btn small danger" type="submit">Stornieren</button>
|
||||
</form>
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="order-history">
|
||||
<td colspan="10">
|
||||
<details class="inline-details">
|
||||
<summary>Historie</summary>
|
||||
<div class="history-grid">
|
||||
<div><strong>Abgeschlossen von:</strong> {{ o.completed_by or "–" }}</div>
|
||||
<div><strong>Abgeschlossen am:</strong> {{ o.completed_at or "–" }}</div>
|
||||
<div><strong>Storniert von:</strong> {{ o.canceled_by or "–" }}</div>
|
||||
<div><strong>Storniert am:</strong> {{ o.canceled_at or "–" }}</div>
|
||||
</div>
|
||||
</details>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="10" class="empty">Keine Bestellungen.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
65
wawi/templates/users.html
Normal file
65
wawi/templates/users.html
Normal file
@@ -0,0 +1,65 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="card form-card">
|
||||
<h2>Benutzer verwalten</h2>
|
||||
{% if error %}
|
||||
<div class="note">{{ error }}</div>
|
||||
{% endif %}
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="note">
|
||||
{% for m in messages %}
|
||||
<div>{{ m }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post">
|
||||
<div class="form-grid">
|
||||
<label>
|
||||
Benutzername
|
||||
<input type="text" name="username" required />
|
||||
</label>
|
||||
<label>
|
||||
Passwort
|
||||
<input type="password" name="password" required />
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-accent" type="submit">Anlegen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top: 14px;">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Benutzer</th>
|
||||
<th>Erstellt</th>
|
||||
<th class="actions">Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for u in rows %}
|
||||
<tr>
|
||||
<td>{{ u.username }}</td>
|
||||
<td>{{ u.created_at }}</td>
|
||||
<td class="actions">
|
||||
<form method="post" action="{{ url_for('bp.reset_user_password', user_id=u.id) }}" onsubmit="return confirm('Passwort für diesen Benutzer wirklich zurücksetzen?');">
|
||||
<button class="btn small" type="submit">Passwort neu</button>
|
||||
</form>
|
||||
<form method="post" action="{{ url_for('bp.delete_user', user_id=u.id) }}" onsubmit="return confirm('Benutzer wirklich löschen?');">
|
||||
<button class="btn small danger" type="submit">Löschen</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="3" class="empty">Keine Benutzer.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user