diff --git a/AGENTS.md b/AGENTS.md index 56e0eca..54418e5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ ## Run - Create the environment exactly as documented in `README.md`: `python3 -m venv .venv`, `source .venv/bin/activate`, `pip install -r requirements.txt`. - Start the app with `python3 app.py`. `app.py` calls `app.run(debug=True)` directly under `if __name__ == "__main__"`. -- Default local URL is `http://127.0.0.1:5000`. +- Default local URL is `http://127.0.0.1:5006`. ## Data And Side Effects - The app writes to repo-local files next to `app.py`: SQLite database `inventory.db` and log file `inventory.log`. diff --git a/README.md b/README.md index 0f8ad87..0f830bf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Verwaltung fuer Tuerchips und Parkkarten +# Verwaltung fuer Tuerchips, Parkkarten und Poolfahrzeuge ## Voraussetzungen - Python 3.10 oder neuer @@ -15,7 +15,14 @@ pip install -r requirements.txt python3 app.py ``` -Die Anwendung ist danach unter `http://127.0.0.1:5000` erreichbar. +Die Anwendung ist danach unter `http://127.0.0.1:5006` erreichbar. + +## Start mit Docker +```bash +docker compose up --build +``` + +Die Anwendung ist danach ebenfalls unter `http://127.0.0.1:5006` erreichbar. ## Funktionen - Anmeldung fuer Bearbeiter und Admins @@ -24,8 +31,8 @@ Die Anwendung ist danach unter `http://127.0.0.1:5000` erreichbar. - Admin kann Passwort-Reset fuer Bearbeiter ausloesen - Admin kann vorhandene Bestandsdaten per CSV importieren - User anlegen -- Ausgabe von Tuerchips und Parkkarten -- Rueckgabe von Tuerchips und Parkkarten +- Ausgabe von Tuerchips, Parkkarten und Poolfahrzeugen +- Rueckgabe von Tuerchips, Parkkarten und Poolfahrzeugen - Uebersicht mit Suche und letzten Bewegungen - Einfache Logdatei mit Datum, Medium und bearbeitendem Mitarbeiter - Anzeige der letzten Logeintraege im Webinterface @@ -60,7 +67,8 @@ Erika Muster;Parkkarte;PARK-2001;Import - Eine optionale Kopfzeile `User;Typ;Kennung;Aktion` wird automatisch erkannt und uebersprungen. -- Unterstuetzte Typen sind `Tuerchip` und `Parkkarte`. +- Unterstuetzte Typen sind `Tuerchip`, `Parkkarte` und `Poolfahrzeug`. +- Bei der Ausgabe von `Poolfahrzeug` wird das Kennzeichen als Kennung erfasst. - Die Aktion `Import` uebernimmt vorhandene aktive Bestandsdaten in die Datenbank. - Falls ein User noch nicht existiert, wird er beim Import automatisch angelegt. - Bereits vergebene Kennungen oder widerspruechliche aktive Zuordnungen werden gesammelt als Fehler angezeigt; der Import wird erst ausgefuehrt, wenn keine Fehler mehr vorhanden sind. diff --git a/app.py b/app.py index b9addd7..f4fe023 100644 --- a/app.py +++ b/app.py @@ -26,6 +26,7 @@ logging.basicConfig( ASSET_LABELS = { "chip": "Tuerchip", "parking_card": "Parkkarte", + "pool_vehicle": "Poolfahrzeug", } ACTION_LABELS = { @@ -38,6 +39,12 @@ PRINT_DESCRIPTIONS = { "return": "Rueckgabebestaetigung fuer die Ruecknahme eines Mediums", } +INPUT_PLACEHOLDERS = { + "chip": "z. B. CHIP-1001", + "parking_card": "z. B. PARK-2001", + "pool_vehicle": "z. B. GZ-CC-123", +} + IMPORT_ACTIONS = {"import", "ausgabe", "assign"} IMPORT_HEADER = ["user", "typ", "kennung", "aktion"] @@ -79,13 +86,15 @@ def init_db() -> None: chip_assigned_at TEXT, parking_card_code TEXT, parking_card_assigned_at TEXT, + pool_vehicle_code TEXT, + pool_vehicle_assigned_at TEXT, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS transactions ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, - asset_type TEXT NOT NULL CHECK (asset_type IN ('chip', 'parking_card')), + asset_type TEXT NOT NULL CHECK (asset_type IN ('chip', 'parking_card', 'pool_vehicle')), asset_code TEXT NOT NULL, handled_by TEXT, action TEXT NOT NULL CHECK (action IN ('assign', 'return')), @@ -112,6 +121,35 @@ def init_db() -> None: if "handled_by" not in columns: db.execute("ALTER TABLE transactions ADD COLUMN handled_by TEXT") + transactions_sql = db.execute( + "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'transactions'" + ).fetchone() + if transactions_sql and "pool_vehicle" not in (transactions_sql["sql"] or ""): + db.execute("DROP TABLE transactions") + db.execute( + """ + CREATE TABLE transactions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL, + asset_type TEXT NOT NULL CHECK (asset_type IN ('chip', 'parking_card', 'pool_vehicle')), + asset_code TEXT NOT NULL, + handled_by TEXT, + action TEXT NOT NULL CHECK (action IN ('assign', 'return')), + created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) + ) + """ + ) + + user_columns = { + row["name"] + for row in db.execute("PRAGMA table_info(users)").fetchall() + } + if "pool_vehicle_code" not in user_columns: + db.execute("ALTER TABLE users ADD COLUMN pool_vehicle_code TEXT") + if "pool_vehicle_assigned_at" not in user_columns: + db.execute("ALTER TABLE users ADD COLUMN pool_vehicle_assigned_at TEXT") + admin_exists = db.execute( "SELECT id FROM staff_users WHERE role = 'admin' LIMIT 1" ).fetchone() @@ -194,7 +232,11 @@ def read_recent_logs(limit: int = 20) -> list[str]: def asset_code_in_use(db: sqlite3.Connection, asset_type: str, asset_code: str) -> bool: - column_name = "chip_code" if asset_type == "chip" else "parking_card_code" + column_name = { + "chip": "chip_code", + "parking_card": "parking_card_code", + "pool_vehicle": "pool_vehicle_code", + }[asset_type] existing = db.execute( f"SELECT id FROM users WHERE {column_name} = ?", (asset_code,), @@ -210,6 +252,9 @@ def normalize_asset_type(value: str) -> str | None: "parkkarte": "parking_card", "parking_card": "parking_card", "parking card": "parking_card", + "poolfahrzeug": "pool_vehicle", + "pool vehicle": "pool_vehicle", + "pool_vehicle": "pool_vehicle", } return aliases.get(normalized) @@ -461,17 +506,20 @@ def import_data() -> str: current_chip_code = user["chip_code"] if user else None current_card_code = user["parking_card_code"] if user else None + current_vehicle_code = user["pool_vehicle_code"] if user else None user_id = user["id"] if user else None if pending_user is not None: current_chip_code = pending_user["chip_code"] current_card_code = pending_user["parking_card_code"] + current_vehicle_code = pending_user["pool_vehicle_code"] if user is None and pending_user is None: pending_user = { "full_name": full_name, "chip_code": None, "parking_card_code": None, + "pool_vehicle_code": None, } operations.append(("user", pending_user)) @@ -480,6 +528,8 @@ def import_data() -> str: asset_type == "chip" and current_chip_code == asset_code ) or ( asset_type == "parking_card" and current_card_code == asset_code + ) or ( + asset_type == "pool_vehicle" and current_vehicle_code == asset_code ) if not assigned_to_same_user: errors.append(f"Zeile {index}: Kennung '{asset_code}' ist bereits vergeben.") @@ -504,12 +554,18 @@ def import_data() -> str: continue if pending_user is not None: pending_user["chip_code"] = asset_code - else: + elif asset_type == "parking_card": if current_card_code and current_card_code != asset_code: errors.append(f"Zeile {index}: User '{full_name}' hat bereits eine andere Parkkarte.") continue if pending_user is not None: pending_user["parking_card_code"] = asset_code + else: + if current_vehicle_code and current_vehicle_code != asset_code: + errors.append(f"Zeile {index}: User '{full_name}' hat bereits ein anderes Poolfahrzeug.") + continue + if pending_user is not None: + pending_user["pool_vehicle_code"] = asset_code operations.append( ( @@ -549,11 +605,16 @@ def import_data() -> str: "UPDATE users SET chip_code = ?, chip_assigned_at = CURRENT_TIMESTAMP WHERE id = ?", (payload["asset_code"], resolved_user_id), ) - else: + elif payload["asset_type"] == "parking_card": db.execute( "UPDATE users SET parking_card_code = ?, parking_card_assigned_at = CURRENT_TIMESTAMP WHERE id = ?", (payload["asset_code"], resolved_user_id), ) + else: + db.execute( + "UPDATE users SET pool_vehicle_code = ?, pool_vehicle_assigned_at = CURRENT_TIMESTAMP WHERE id = ?", + (payload["asset_code"], resolved_user_id), + ) db.execute( "INSERT INTO transactions (user_id, asset_type, asset_code, handled_by, action) VALUES (?, ?, ?, ?, 'assign')", @@ -577,7 +638,8 @@ def index() -> str: params: tuple[str, ...] = () user_query = """ SELECT id, full_name, email, department, chip_code, chip_assigned_at, - parking_card_code, parking_card_assigned_at + parking_card_code, parking_card_assigned_at, + pool_vehicle_code, pool_vehicle_assigned_at FROM users """ @@ -586,10 +648,11 @@ def index() -> str: user_query += """ WHERE full_name LIKE ? OR email LIKE ? - OR chip_code LIKE ? - OR parking_card_code LIKE ? + OR chip_code LIKE ? + OR parking_card_code LIKE ? + OR pool_vehicle_code LIKE ? """ - params = (like_value, like_value, like_value, like_value) + params = (like_value, like_value, like_value, like_value, like_value) user_query += " ORDER BY full_name COLLATE NOCASE" users = db.execute(user_query, params).fetchall() @@ -599,7 +662,8 @@ def index() -> str: SELECT COUNT(*) AS users, SUM(CASE WHEN chip_code IS NOT NULL AND chip_code != '' THEN 1 ELSE 0 END) AS active_chips, - SUM(CASE WHEN parking_card_code IS NOT NULL AND parking_card_code != '' THEN 1 ELSE 0 END) AS active_cards + SUM(CASE WHEN parking_card_code IS NOT NULL AND parking_card_code != '' THEN 1 ELSE 0 END) AS active_cards, + SUM(CASE WHEN pool_vehicle_code IS NOT NULL AND pool_vehicle_code != '' THEN 1 ELSE 0 END) AS active_pool_vehicles FROM users """ ).fetchone() @@ -624,6 +688,7 @@ def index() -> str: "users": stats["users"], "active_chips": stats["active_chips"], "active_cards": stats["active_cards"], + "active_pool_vehicles": stats["active_pool_vehicles"], }, search_query=search_query, asset_labels=ASSET_LABELS, @@ -660,14 +725,19 @@ def create_user() -> str: @login_required def assign_asset() -> str: db = get_db() + asset_type = request.form.get("asset_type", "chip").strip() if request.method == "POST" else request.args.get("asset_type", "chip").strip() + if asset_type not in {"chip", "parking_card", "pool_vehicle"}: + asset_type = "chip" if request.method == "POST": user_id = request.form.get("user_id", "").strip() - asset_type = request.form.get("asset_type", "").strip() asset_code = request.form.get("asset_code", "").strip() handled_by = g.current_staff["full_name"] - if not user_id or asset_type not in {"chip", "parking_card"} or not asset_code: + if not user_id or asset_type not in {"chip", "parking_card", "pool_vehicle"}: + flash("Bitte alle Felder fuer die Ausgabe ausfuellen.") + return redirect(url_for("assign_asset")) + if not asset_code: flash("Bitte alle Felder fuer die Ausgabe ausfuellen.") return redirect(url_for("assign_asset")) @@ -677,7 +747,7 @@ def assign_asset() -> str: return redirect(url_for("assign_asset")) if asset_code_in_use(db, asset_type, asset_code): - flash("Diese Kennung ist bereits vergeben.") + flash("Dieses Kennzeichen ist bereits vergeben." if asset_type == "pool_vehicle" else "Diese Kennung ist bereits vergeben.") return redirect(url_for("assign_asset")) if asset_type == "chip": @@ -688,7 +758,7 @@ def assign_asset() -> str: "UPDATE users SET chip_code = ?, chip_assigned_at = CURRENT_TIMESTAMP WHERE id = ?", (asset_code, user_id), ) - else: + elif asset_type == "parking_card": if user["parking_card_code"]: flash("Dieser User hat bereits eine aktive Parkkarte.") return redirect(url_for("assign_asset")) @@ -696,6 +766,14 @@ def assign_asset() -> str: "UPDATE users SET parking_card_code = ?, parking_card_assigned_at = CURRENT_TIMESTAMP WHERE id = ?", (asset_code, user_id), ) + else: + if user["pool_vehicle_code"]: + flash("Dieser User hat bereits ein aktives Poolfahrzeug.") + return redirect(url_for("assign_asset")) + db.execute( + "UPDATE users SET pool_vehicle_code = ?, pool_vehicle_assigned_at = CURRENT_TIMESTAMP WHERE id = ?", + (asset_code, user_id), + ) db.execute( "INSERT INTO transactions (user_id, asset_type, asset_code, handled_by, action) VALUES (?, ?, ?, ?, 'assign')", @@ -708,20 +786,27 @@ def assign_asset() -> str: return redirect(url_for("print_transaction", transaction_id=transaction_id)) users = db.execute("SELECT id, full_name FROM users ORDER BY full_name COLLATE NOCASE").fetchall() - return render_template("assign_asset.html", users=users) + return render_template( + "assign_asset.html", + users=users, + selected_asset_type=asset_type, + input_placeholder=INPUT_PLACEHOLDERS[asset_type], + ) @app.route("/return", methods=["GET", "POST"]) @login_required def return_asset() -> str: db = get_db() + asset_type = request.form.get("asset_type", "chip").strip() if request.method == "POST" else request.args.get("asset_type", "chip").strip() + if asset_type not in {"chip", "parking_card", "pool_vehicle"}: + asset_type = "chip" if request.method == "POST": user_id = request.form.get("user_id", "").strip() - asset_type = request.form.get("asset_type", "").strip() handled_by = g.current_staff["full_name"] - if not user_id or asset_type not in {"chip", "parking_card"}: + if not user_id or asset_type not in {"chip", "parking_card", "pool_vehicle"}: flash("Bitte User und Typ fuer die Rueckgabe waehlen.") return redirect(url_for("return_asset")) @@ -730,7 +815,13 @@ def return_asset() -> str: flash("Ausgewaehlter User wurde nicht gefunden.") return redirect(url_for("return_asset")) - asset_code = user["chip_code"] if asset_type == "chip" else user["parking_card_code"] + asset_code = ( + user["chip_code"] + if asset_type == "chip" + else user["parking_card_code"] + if asset_type == "parking_card" + else user["pool_vehicle_code"] + ) if not asset_code: flash("Fuer diesen User ist kein entsprechendes Medium aktiv hinterlegt.") return redirect(url_for("return_asset")) @@ -740,11 +831,16 @@ def return_asset() -> str: "UPDATE users SET chip_code = NULL, chip_assigned_at = NULL WHERE id = ?", (user_id,), ) - else: + elif asset_type == "parking_card": db.execute( "UPDATE users SET parking_card_code = NULL, parking_card_assigned_at = NULL WHERE id = ?", (user_id,), ) + else: + db.execute( + "UPDATE users SET pool_vehicle_code = NULL, pool_vehicle_assigned_at = NULL WHERE id = ?", + (user_id,), + ) db.execute( "INSERT INTO transactions (user_id, asset_type, asset_code, handled_by, action) VALUES (?, ?, ?, ?, 'return')", @@ -757,7 +853,11 @@ def return_asset() -> str: return redirect(url_for("print_transaction", transaction_id=transaction_id)) users = db.execute("SELECT id, full_name FROM users ORDER BY full_name COLLATE NOCASE").fetchall() - return render_template("return_asset.html", users=users) + return render_template( + "return_asset.html", + users=users, + selected_asset_type=asset_type, + ) @app.route("/transactions//print") diff --git a/docker-compose.yml b/docker-compose.yml index 9570687..e1e7434 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: dockerfile: Dockerfile platforms: - linux/amd64 - image: gitea.teamthiele.de/ethiele/keyVerwaltung:latest + image: gitea.teamthiele.de/ethiele/keyverwaltung:latest ports: - "5006:5006" - restart: unless-stopped \ No newline at end of file + restart: unless-stopped diff --git a/inventory.db b/inventory.db index fbce2d7..a1d78a4 100644 Binary files a/inventory.db and b/inventory.db differ diff --git a/inventory.log b/inventory.log index 6976d31..fbf13c6 100644 --- a/inventory.log +++ b/inventory.log @@ -719,3 +719,280 @@ 2026-05-18 21:19:15,878 INFO * Restarting with stat 2026-05-18 21:19:16,201 WARNING * Debugger is active! 2026-05-18 21:19:16,216 INFO * Debugger PIN: 428-899-358 +2026-05-18 21:20:04,905 INFO 127.0.0.1 - - [18/May/2026 21:20:04] "GET / HTTP/1.1" 200 - +2026-05-18 21:20:04,931 INFO 127.0.0.1 - - [18/May/2026 21:20:04] "GET /static/cancom.svg HTTP/1.1" 200 - +2026-05-18 21:20:04,958 INFO 127.0.0.1 - - [18/May/2026 21:20:04] "GET /static/favicon.ico HTTP/1.1" 200 - +2026-05-19 08:59:28,642 INFO WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on all addresses (0.0.0.0) + * Running on http://127.0.0.1:5006 + * Running on http://10.2.200.65:5006 +2026-05-19 08:59:28,642 INFO Press CTRL+C to quit +2026-05-19 08:59:28,646 INFO * Restarting with stat +2026-05-19 08:59:28,946 WARNING * Debugger is active! +2026-05-19 08:59:28,984 INFO * Debugger PIN: 428-899-358 +2026-05-19 08:59:36,119 INFO 127.0.0.1 - - [19/May/2026 08:59:36] "GET / HTTP/1.1" 200 - +2026-05-19 08:59:36,367 INFO 127.0.0.1 - - [19/May/2026 08:59:36] "GET /static/cancom.svg HTTP/1.1" 200 - +2026-05-19 09:00:09,239 INFO 127.0.0.1 - - [19/May/2026 09:00:09] "GET /users/new HTTP/1.1" 200 - +2026-05-19 09:00:09,285 INFO 127.0.0.1 - - [19/May/2026 09:00:09] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:00:10,898 INFO 127.0.0.1 - - [19/May/2026 09:00:10] "GET /assign HTTP/1.1" 200 - +2026-05-19 09:00:10,933 INFO 127.0.0.1 - - [19/May/2026 09:00:10] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:00:18,472 INFO 127.0.0.1 - - [19/May/2026 09:00:18] "GET /assign HTTP/1.1" 200 - +2026-05-19 09:00:18,496 INFO 127.0.0.1 - - [19/May/2026 09:00:18] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:00:21,083 INFO 127.0.0.1 - - [19/May/2026 09:00:21] "GET /return HTTP/1.1" 200 - +2026-05-19 09:00:21,117 INFO 127.0.0.1 - - [19/May/2026 09:00:21] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:00:24,238 INFO 127.0.0.1 - - [19/May/2026 09:00:24] "GET /logout HTTP/1.1" 302 - +2026-05-19 09:00:24,255 INFO 127.0.0.1 - - [19/May/2026 09:00:24] "GET /login HTTP/1.1" 200 - +2026-05-19 09:00:24,285 INFO 127.0.0.1 - - [19/May/2026 09:00:24] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:00:24,299 INFO 127.0.0.1 - - [19/May/2026 09:00:24] "GET /static/favicon.ico HTTP/1.1" 200 - +2026-05-19 09:00:30,232 INFO 127.0.0.1 - - [19/May/2026 09:00:30] "POST /login HTTP/1.1" 302 - +2026-05-19 09:00:30,269 INFO 127.0.0.1 - - [19/May/2026 09:00:30] "GET / HTTP/1.1" 200 - +2026-05-19 09:00:30,342 INFO 127.0.0.1 - - [19/May/2026 09:00:30] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:00:30,346 INFO 127.0.0.1 - - [19/May/2026 09:00:30] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 09:00:44,664 INFO 127.0.0.1 - - [19/May/2026 09:00:44] "GET /admin/import HTTP/1.1" 200 - +2026-05-19 09:00:44,694 INFO 127.0.0.1 - - [19/May/2026 09:00:44] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:00:54,099 INFO 127.0.0.1 - - [19/May/2026 09:00:54] "GET /admin/staff HTTP/1.1" 200 - +2026-05-19 09:00:54,133 INFO 127.0.0.1 - - [19/May/2026 09:00:54] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:01:06,202 INFO 127.0.0.1 - - [19/May/2026 09:01:06] "GET / HTTP/1.1" 200 - +2026-05-19 09:01:06,228 INFO 127.0.0.1 - - [19/May/2026 09:01:06] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:01:21,990 INFO 127.0.0.1 - - [19/May/2026 09:01:21] "GET /assign HTTP/1.1" 200 - +2026-05-19 09:01:22,029 INFO 127.0.0.1 - - [19/May/2026 09:01:22] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:01:30,896 INFO 127.0.0.1 - - [19/May/2026 09:01:30] "POST /assign HTTP/1.1" 302 - +2026-05-19 09:01:30,907 INFO 127.0.0.1 - - [19/May/2026 09:01:30] "GET /assign HTTP/1.1" 200 - +2026-05-19 09:01:30,931 INFO 127.0.0.1 - - [19/May/2026 09:01:30] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:01:30,945 INFO 127.0.0.1 - - [19/May/2026 09:01:30] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 09:01:37,960 INFO 127.0.0.1 - - [19/May/2026 09:01:37] "GET / HTTP/1.1" 200 - +2026-05-19 09:01:37,993 INFO 127.0.0.1 - - [19/May/2026 09:01:37] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:01:38,265 INFO 127.0.0.1 - - [19/May/2026 09:01:38] "GET / HTTP/1.1" 200 - +2026-05-19 09:01:38,293 INFO 127.0.0.1 - - [19/May/2026 09:01:38] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 09:01:41,573 INFO 127.0.0.1 - - [19/May/2026 09:01:41] "GET /transactions/4/print HTTP/1.1" 200 - +2026-05-19 09:01:41,596 INFO 127.0.0.1 - - [19/May/2026 09:01:41] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:36:27,486 INFO 127.0.0.1 - - [19/May/2026 19:36:27] "GET / HTTP/1.1" 200 - +2026-05-19 19:36:27,549 INFO 127.0.0.1 - - [19/May/2026 19:36:27] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:36:36,490 INFO 127.0.0.1 - - [19/May/2026 19:36:36] "GET /logout HTTP/1.1" 302 - +2026-05-19 19:36:36,498 INFO 127.0.0.1 - - [19/May/2026 19:36:36] "GET /login HTTP/1.1" 200 - +2026-05-19 19:36:36,520 INFO 127.0.0.1 - - [19/May/2026 19:36:36] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:36:36,529 INFO 127.0.0.1 - - [19/May/2026 19:36:36] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:36:46,776 INFO 127.0.0.1 - - [19/May/2026 19:36:46] "POST /login HTTP/1.1" 302 - +2026-05-19 19:36:46,801 INFO 127.0.0.1 - - [19/May/2026 19:36:46] "GET / HTTP/1.1" 200 - +2026-05-19 19:36:46,828 INFO 127.0.0.1 - - [19/May/2026 19:36:46] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:36:46,833 INFO 127.0.0.1 - - [19/May/2026 19:36:46] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:37:12,390 INFO 127.0.0.1 - - [19/May/2026 19:37:12] "GET / HTTP/1.1" 200 - +2026-05-19 19:37:12,412 INFO 127.0.0.1 - - [19/May/2026 19:37:12] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:37:26,587 INFO 127.0.0.1 - - [19/May/2026 19:37:26] "GET /users/new HTTP/1.1" 200 - +2026-05-19 19:37:26,612 INFO 127.0.0.1 - - [19/May/2026 19:37:26] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:37:34,017 INFO 127.0.0.1 - - [19/May/2026 19:37:34] "GET /assign HTTP/1.1" 200 - +2026-05-19 19:37:34,036 INFO 127.0.0.1 - - [19/May/2026 19:37:34] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:37:47,727 INFO 127.0.0.1 - - [19/May/2026 19:37:47] "POST /assign HTTP/1.1" 302 - +2026-05-19 19:37:47,736 INFO 127.0.0.1 - - [19/May/2026 19:37:47] "GET /assign HTTP/1.1" 200 - +2026-05-19 19:37:47,760 INFO 127.0.0.1 - - [19/May/2026 19:37:47] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:37:47,765 INFO 127.0.0.1 - - [19/May/2026 19:37:47] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:37:50,839 INFO 127.0.0.1 - - [19/May/2026 19:37:50] "GET / HTTP/1.1" 200 - +2026-05-19 19:37:50,864 INFO 127.0.0.1 - - [19/May/2026 19:37:50] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:37:56,289 INFO 127.0.0.1 - - [19/May/2026 19:37:56] "GET / HTTP/1.1" 200 - +2026-05-19 19:37:56,308 INFO 127.0.0.1 - - [19/May/2026 19:37:56] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:37:57,640 INFO 127.0.0.1 - - [19/May/2026 19:37:57] "GET / HTTP/1.1" 200 - +2026-05-19 19:37:57,655 INFO 127.0.0.1 - - [19/May/2026 19:37:57] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:38:10,246 INFO 127.0.0.1 - - [19/May/2026 19:38:10] "GET /return HTTP/1.1" 200 - +2026-05-19 19:38:10,269 INFO 127.0.0.1 - - [19/May/2026 19:38:10] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:38:16,491 INFO rueckgabe | user=Erik Thiele | typ=Tuerchip | kennung=120 | bearbeiter=Erik Thiele +2026-05-19 19:38:16,492 INFO 127.0.0.1 - - [19/May/2026 19:38:16] "POST /return HTTP/1.1" 302 - +2026-05-19 19:38:16,501 INFO 127.0.0.1 - - [19/May/2026 19:38:16] "GET /transactions/5/print HTTP/1.1" 200 - +2026-05-19 19:38:16,521 INFO 127.0.0.1 - - [19/May/2026 19:38:16] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:38:16,528 INFO 127.0.0.1 - - [19/May/2026 19:38:16] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:38:18,296 INFO 127.0.0.1 - - [19/May/2026 19:38:18] "GET / HTTP/1.1" 200 - +2026-05-19 19:38:18,316 INFO 127.0.0.1 - - [19/May/2026 19:38:18] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:38:18,326 INFO 127.0.0.1 - - [19/May/2026 19:38:18] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:38:30,366 INFO 127.0.0.1 - - [19/May/2026 19:38:30] "GET /assign HTTP/1.1" 200 - +2026-05-19 19:38:30,387 INFO 127.0.0.1 - - [19/May/2026 19:38:30] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:38:40,646 INFO ausgabe | user=Erik Thiele | typ=Tuerchip | kennung=120 | bearbeiter=Erik Thiele +2026-05-19 19:38:40,647 INFO 127.0.0.1 - - [19/May/2026 19:38:40] "POST /assign HTTP/1.1" 302 - +2026-05-19 19:38:40,657 INFO 127.0.0.1 - - [19/May/2026 19:38:40] "GET /transactions/6/print HTTP/1.1" 200 - +2026-05-19 19:38:40,677 INFO 127.0.0.1 - - [19/May/2026 19:38:40] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:38:40,683 INFO 127.0.0.1 - - [19/May/2026 19:38:40] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:39:09,992 INFO 127.0.0.1 - - [19/May/2026 19:39:09] "GET / HTTP/1.1" 200 - +2026-05-19 19:39:10,016 INFO 127.0.0.1 - - [19/May/2026 19:39:10] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:39:10,025 INFO 127.0.0.1 - - [19/May/2026 19:39:10] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:39:11,969 INFO 127.0.0.1 - - [19/May/2026 19:39:11] "GET /return HTTP/1.1" 200 - +2026-05-19 19:39:11,995 INFO 127.0.0.1 - - [19/May/2026 19:39:11] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:39:21,037 INFO rueckgabe | user=Erik Thiele | typ=Tuerchip | kennung=120 | bearbeiter=Erik Thiele +2026-05-19 19:39:21,038 INFO 127.0.0.1 - - [19/May/2026 19:39:21] "POST /return HTTP/1.1" 302 - +2026-05-19 19:39:21,047 INFO 127.0.0.1 - - [19/May/2026 19:39:21] "GET /transactions/7/print HTTP/1.1" 200 - +2026-05-19 19:39:21,066 INFO 127.0.0.1 - - [19/May/2026 19:39:21] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:39:21,070 INFO 127.0.0.1 - - [19/May/2026 19:39:21] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:39:37,875 INFO 127.0.0.1 - - [19/May/2026 19:39:37] "GET / HTTP/1.1" 200 - +2026-05-19 19:39:37,899 INFO 127.0.0.1 - - [19/May/2026 19:39:37] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:39:37,911 INFO 127.0.0.1 - - [19/May/2026 19:39:37] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:41:56,887 INFO 127.0.0.1 - - [19/May/2026 19:41:56] "GET /logout HTTP/1.1" 302 - +2026-05-19 19:41:56,898 INFO 127.0.0.1 - - [19/May/2026 19:41:56] "GET /login HTTP/1.1" 200 - +2026-05-19 19:41:56,919 INFO 127.0.0.1 - - [19/May/2026 19:41:56] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:41:56,929 INFO 127.0.0.1 - - [19/May/2026 19:41:56] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:42:02,095 INFO 127.0.0.1 - - [19/May/2026 19:42:02] "POST /login HTTP/1.1" 302 - +2026-05-19 19:42:02,118 INFO 127.0.0.1 - - [19/May/2026 19:42:02] "GET / HTTP/1.1" 200 - +2026-05-19 19:42:02,177 INFO 127.0.0.1 - - [19/May/2026 19:42:02] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:42:02,183 INFO 127.0.0.1 - - [19/May/2026 19:42:02] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:42:23,475 INFO 127.0.0.1 - - [19/May/2026 19:42:23] "GET /admin/staff HTTP/1.1" 200 - +2026-05-19 19:42:23,495 INFO 127.0.0.1 - - [19/May/2026 19:42:23] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:43:41,915 INFO 127.0.0.1 - - [19/May/2026 19:43:41] "GET /users/new HTTP/1.1" 200 - +2026-05-19 19:43:41,950 INFO 127.0.0.1 - - [19/May/2026 19:43:41] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:43:45,744 INFO 127.0.0.1 - - [19/May/2026 19:43:45] "GET /admin/staff HTTP/1.1" 200 - +2026-05-19 19:43:45,769 INFO 127.0.0.1 - - [19/May/2026 19:43:45] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:44:08,662 INFO 127.0.0.1 - - [19/May/2026 19:44:08] "POST /admin/staff HTTP/1.1" 302 - +2026-05-19 19:44:08,671 INFO 127.0.0.1 - - [19/May/2026 19:44:08] "GET /admin/staff HTTP/1.1" 200 - +2026-05-19 19:44:08,692 INFO 127.0.0.1 - - [19/May/2026 19:44:08] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:44:08,696 INFO 127.0.0.1 - - [19/May/2026 19:44:08] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:44:20,804 INFO 127.0.0.1 - - [19/May/2026 19:44:20] "GET /logout HTTP/1.1" 302 - +2026-05-19 19:44:20,816 INFO 127.0.0.1 - - [19/May/2026 19:44:20] "GET /login HTTP/1.1" 200 - +2026-05-19 19:44:20,837 INFO 127.0.0.1 - - [19/May/2026 19:44:20] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:44:20,862 INFO 127.0.0.1 - - [19/May/2026 19:44:20] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:44:28,199 INFO 127.0.0.1 - - [19/May/2026 19:44:28] "POST /login HTTP/1.1" 302 - +2026-05-19 19:44:28,218 INFO 127.0.0.1 - - [19/May/2026 19:44:28] "GET /set-password HTTP/1.1" 200 - +2026-05-19 19:44:28,238 INFO 127.0.0.1 - - [19/May/2026 19:44:28] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:44:28,260 INFO 127.0.0.1 - - [19/May/2026 19:44:28] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:44:50,603 INFO 127.0.0.1 - - [19/May/2026 19:44:50] "POST /set-password HTTP/1.1" 302 - +2026-05-19 19:44:50,658 INFO 127.0.0.1 - - [19/May/2026 19:44:50] "GET /set-password HTTP/1.1" 200 - +2026-05-19 19:44:50,718 INFO 127.0.0.1 - - [19/May/2026 19:44:50] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:44:50,722 INFO 127.0.0.1 - - [19/May/2026 19:44:50] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:45:01,966 INFO 127.0.0.1 - - [19/May/2026 19:45:01] "POST /set-password HTTP/1.1" 302 - +2026-05-19 19:45:01,988 INFO 127.0.0.1 - - [19/May/2026 19:45:01] "GET / HTTP/1.1" 200 - +2026-05-19 19:45:02,047 INFO 127.0.0.1 - - [19/May/2026 19:45:02] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:45:02,057 INFO 127.0.0.1 - - [19/May/2026 19:45:02] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:45:11,107 INFO 127.0.0.1 - - [19/May/2026 19:45:11] "GET /logout HTTP/1.1" 302 - +2026-05-19 19:45:11,116 INFO 127.0.0.1 - - [19/May/2026 19:45:11] "GET /login HTTP/1.1" 200 - +2026-05-19 19:45:11,137 INFO 127.0.0.1 - - [19/May/2026 19:45:11] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:45:11,157 INFO 127.0.0.1 - - [19/May/2026 19:45:11] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:45:19,164 INFO 127.0.0.1 - - [19/May/2026 19:45:19] "POST /login HTTP/1.1" 302 - +2026-05-19 19:45:19,171 INFO 127.0.0.1 - - [19/May/2026 19:45:19] "GET /login HTTP/1.1" 200 - +2026-05-19 19:45:19,234 INFO 127.0.0.1 - - [19/May/2026 19:45:19] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:45:34,144 INFO 127.0.0.1 - - [19/May/2026 19:45:34] "POST /login HTTP/1.1" 302 - +2026-05-19 19:45:34,172 INFO 127.0.0.1 - - [19/May/2026 19:45:34] "GET / HTTP/1.1" 200 - +2026-05-19 19:45:34,202 INFO 127.0.0.1 - - [19/May/2026 19:45:34] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:45:34,212 INFO 127.0.0.1 - - [19/May/2026 19:45:34] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 19:46:18,384 INFO 127.0.0.1 - - [19/May/2026 19:46:18] "GET /transactions/6/print HTTP/1.1" 200 - +2026-05-19 19:46:18,417 INFO 127.0.0.1 - - [19/May/2026 19:46:18] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:47:38,224 INFO 127.0.0.1 - - [19/May/2026 19:47:38] "GET / HTTP/1.1" 200 - +2026-05-19 19:47:38,247 INFO 127.0.0.1 - - [19/May/2026 19:47:38] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:57:20,498 INFO * Detected change in '/Users/erik/Documents/DEV/Key Verwaltung/app.py', reloading +2026-05-19 19:57:20,601 INFO * Restarting with stat +2026-05-19 19:57:22,594 WARNING * Debugger is active! +2026-05-19 19:57:22,624 INFO * Debugger PIN: 428-899-358 +2026-05-19 19:57:28,967 INFO * Detected change in '/Users/erik/Documents/DEV/Key Verwaltung/app.py', reloading +2026-05-19 19:57:28,995 INFO * Restarting with stat +2026-05-19 19:57:29,204 WARNING * Debugger is active! +2026-05-19 19:57:29,215 INFO * Debugger PIN: 428-899-358 +2026-05-19 19:57:36,603 INFO * Detected change in '/Users/erik/Documents/DEV/Key Verwaltung/app.py', reloading +2026-05-19 19:57:36,627 INFO * Restarting with stat +2026-05-19 19:57:38,136 WARNING * Debugger is active! +2026-05-19 19:57:38,173 INFO * Debugger PIN: 428-899-358 +2026-05-19 19:58:54,755 INFO 127.0.0.1 - - [19/May/2026 19:58:54] "GET / HTTP/1.1" 200 - +2026-05-19 19:58:54,809 INFO 127.0.0.1 - - [19/May/2026 19:58:54] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:58:57,065 INFO 127.0.0.1 - - [19/May/2026 19:58:57] "GET / HTTP/1.1" 200 - +2026-05-19 19:58:57,083 INFO 127.0.0.1 - - [19/May/2026 19:58:57] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:59:08,469 INFO 127.0.0.1 - - [19/May/2026 19:59:08] "GET /assign HTTP/1.1" 200 - +2026-05-19 19:59:08,506 INFO 127.0.0.1 - - [19/May/2026 19:59:08] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 19:59:21,896 INFO 127.0.0.1 - - [19/May/2026 19:59:21] "GET /assign HTTP/1.1" 200 - +2026-05-19 19:59:22,179 INFO 127.0.0.1 - - [19/May/2026 19:59:22] "GET /static/cancom.svg HTTP/1.1" 200 - +2026-05-19 19:59:22,194 INFO 127.0.0.1 - - [19/May/2026 19:59:22] "GET /static/favicon.ico HTTP/1.1" 200 - +2026-05-19 19:59:44,462 INFO 127.0.0.1 - - [19/May/2026 19:59:44] "POST /assign HTTP/1.1" 500 - +2026-05-19 19:59:44,500 INFO 127.0.0.1 - - [19/May/2026 19:59:44] "GET /assign?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - +2026-05-19 19:59:44,510 INFO 127.0.0.1 - - [19/May/2026 19:59:44] "GET /assign?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - +2026-05-19 19:59:44,592 INFO 127.0.0.1 - - [19/May/2026 19:59:44] "GET /assign?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 - +2026-05-19 19:59:44,594 INFO 127.0.0.1 - - [19/May/2026 19:59:44] "GET /assign?__debugger__=yes&cmd=resource&f=console.png&s=SnLrAdctl57EpB7alHco HTTP/1.1" 200 - +2026-05-19 20:00:19,837 INFO * Detected change in '/Users/erik/Documents/DEV/Key Verwaltung/app.py', reloading +2026-05-19 20:00:19,877 INFO * Restarting with stat +2026-05-19 20:00:20,122 WARNING * Debugger is active! +2026-05-19 20:00:20,135 INFO * Debugger PIN: 428-899-358 +2026-05-19 20:00:52,818 INFO WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on all addresses (0.0.0.0) + * Running on http://127.0.0.1:5006 + * Running on http://192.168.10.191:5006 +2026-05-19 20:00:52,818 INFO Press CTRL+C to quit +2026-05-19 20:00:52,819 INFO * Restarting with stat +2026-05-19 20:00:52,968 WARNING * Debugger is active! +2026-05-19 20:00:52,981 INFO * Debugger PIN: 428-899-358 +2026-05-19 20:00:58,425 INFO 127.0.0.1 - - [19/May/2026 20:00:58] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:01:00,056 INFO 127.0.0.1 - - [19/May/2026 20:01:00] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:01:00,081 INFO 127.0.0.1 - - [19/May/2026 20:01:00] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:01:01,229 INFO 127.0.0.1 - - [19/May/2026 20:01:01] "GET / HTTP/1.1" 200 - +2026-05-19 20:01:01,252 INFO 127.0.0.1 - - [19/May/2026 20:01:01] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:01:11,315 INFO 127.0.0.1 - - [19/May/2026 20:01:11] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:01:11,339 INFO 127.0.0.1 - - [19/May/2026 20:01:11] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:01:23,982 INFO 127.0.0.1 - - [19/May/2026 20:01:23] "POST /assign HTTP/1.1" 500 - +2026-05-19 20:01:24,002 INFO 127.0.0.1 - - [19/May/2026 20:01:24] "GET /assign?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 304 - +2026-05-19 20:01:24,007 INFO 127.0.0.1 - - [19/May/2026 20:01:24] "GET /assign?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 304 - +2026-05-19 20:01:24,018 INFO 127.0.0.1 - - [19/May/2026 20:01:24] "GET /assign?__debugger__=yes&cmd=resource&f=console.png&s=BKWhsNSqaeiPep8siyqT HTTP/1.1" 200 - +2026-05-19 20:01:48,757 INFO * Detected change in '/Users/erik/Documents/DEV/Key Verwaltung/app.py', reloading +2026-05-19 20:01:48,805 INFO * Restarting with stat +2026-05-19 20:01:49,068 WARNING * Debugger is active! +2026-05-19 20:01:49,083 INFO * Debugger PIN: 428-899-358 +2026-05-19 20:02:25,283 INFO 127.0.0.1 - - [19/May/2026 20:02:25] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:02:26,977 INFO 127.0.0.1 - - [19/May/2026 20:02:26] "GET / HTTP/1.1" 200 - +2026-05-19 20:02:27,001 INFO 127.0.0.1 - - [19/May/2026 20:02:27] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:02:35,268 INFO 127.0.0.1 - - [19/May/2026 20:02:35] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:02:35,292 INFO 127.0.0.1 - - [19/May/2026 20:02:35] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:02:47,485 INFO ausgabe | user=Erik Thiele | typ=Poolfahrzeug | kennung=GZ-CC-433E | bearbeiter=Erik Thiele +2026-05-19 20:02:47,486 INFO 127.0.0.1 - - [19/May/2026 20:02:47] "POST /assign HTTP/1.1" 302 - +2026-05-19 20:02:47,511 INFO 127.0.0.1 - - [19/May/2026 20:02:47] "GET /transactions/1/print HTTP/1.1" 200 - +2026-05-19 20:02:47,530 INFO 127.0.0.1 - - [19/May/2026 20:02:47] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:02:47,540 INFO 127.0.0.1 - - [19/May/2026 20:02:47] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 20:03:29,290 INFO 127.0.0.1 - - [19/May/2026 20:03:29] "GET / HTTP/1.1" 200 - +2026-05-19 20:03:29,316 INFO 127.0.0.1 - - [19/May/2026 20:03:29] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:03:29,326 INFO 127.0.0.1 - - [19/May/2026 20:03:29] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 20:04:24,371 INFO 127.0.0.1 - - [19/May/2026 20:04:24] "GET /?q=GZ-CC-433E HTTP/1.1" 200 - +2026-05-19 20:04:24,398 INFO 127.0.0.1 - - [19/May/2026 20:04:24] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:04:36,099 INFO 127.0.0.1 - - [19/May/2026 20:04:36] "GET /return HTTP/1.1" 200 - +2026-05-19 20:04:36,121 INFO 127.0.0.1 - - [19/May/2026 20:04:36] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:04:44,190 INFO rueckgabe | user=Erik Thiele | typ=Poolfahrzeug | kennung=GZ-CC-433E | bearbeiter=Erik Thiele +2026-05-19 20:04:44,191 INFO 127.0.0.1 - - [19/May/2026 20:04:44] "POST /return HTTP/1.1" 302 - +2026-05-19 20:04:44,199 INFO 127.0.0.1 - - [19/May/2026 20:04:44] "GET /transactions/2/print HTTP/1.1" 200 - +2026-05-19 20:04:44,228 INFO 127.0.0.1 - - [19/May/2026 20:04:44] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:04:44,234 INFO 127.0.0.1 - - [19/May/2026 20:04:44] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 20:04:49,367 INFO 127.0.0.1 - - [19/May/2026 20:04:49] "GET / HTTP/1.1" 200 - +2026-05-19 20:04:49,391 INFO 127.0.0.1 - - [19/May/2026 20:04:49] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:04:49,397 INFO 127.0.0.1 - - [19/May/2026 20:04:49] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 20:06:17,108 INFO 127.0.0.1 - - [19/May/2026 20:06:17] "GET / HTTP/1.1" 200 - +2026-05-19 20:06:17,146 INFO 127.0.0.1 - - [19/May/2026 20:06:17] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:07:26,942 INFO 127.0.0.1 - - [19/May/2026 20:07:26] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:07:26,965 INFO 127.0.0.1 - - [19/May/2026 20:07:26] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:07:40,687 INFO ausgabe | user=Erik Thiele | typ=Poolfahrzeug | kennung=GZ-CC-433E | bearbeiter=Erik Thiele +2026-05-19 20:07:40,688 INFO 127.0.0.1 - - [19/May/2026 20:07:40] "POST /assign HTTP/1.1" 302 - +2026-05-19 20:07:40,696 INFO 127.0.0.1 - - [19/May/2026 20:07:40] "GET /transactions/3/print HTTP/1.1" 200 - +2026-05-19 20:07:40,714 INFO 127.0.0.1 - - [19/May/2026 20:07:40] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:07:40,726 INFO 127.0.0.1 - - [19/May/2026 20:07:40] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 20:07:49,202 INFO 127.0.0.1 - - [19/May/2026 20:07:49] "GET / HTTP/1.1" 200 - +2026-05-19 20:07:49,227 INFO 127.0.0.1 - - [19/May/2026 20:07:49] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:07:49,234 INFO 127.0.0.1 - - [19/May/2026 20:07:49] "GET /static/favicon.ico HTTP/1.1" 304 - +2026-05-19 20:08:34,139 INFO 127.0.0.1 - - [19/May/2026 20:08:34] "GET /?q=GZ-CC HTTP/1.1" 200 - +2026-05-19 20:08:34,164 INFO 127.0.0.1 - - [19/May/2026 20:08:34] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:11:43,873 INFO 127.0.0.1 - - [19/May/2026 20:11:43] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:11:43,905 INFO 127.0.0.1 - - [19/May/2026 20:11:43] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:11:56,587 INFO 127.0.0.1 - - [19/May/2026 20:11:56] "GET / HTTP/1.1" 200 - +2026-05-19 20:11:56,610 INFO 127.0.0.1 - - [19/May/2026 20:11:56] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:14:51,208 INFO * Detected change in '/Users/erik/Documents/DEV/Key Verwaltung/app.py', reloading +2026-05-19 20:14:51,240 INFO * Restarting with stat +2026-05-19 20:14:52,984 WARNING * Debugger is active! +2026-05-19 20:14:53,007 INFO * Debugger PIN: 428-899-358 +2026-05-19 20:15:29,765 INFO * Detected change in '/Users/erik/Documents/DEV/Key Verwaltung/app.py', reloading +2026-05-19 20:15:29,795 INFO * Restarting with stat +2026-05-19 20:15:30,023 WARNING * Debugger is active! +2026-05-19 20:15:30,035 INFO * Debugger PIN: 428-899-358 +2026-05-19 20:15:59,485 INFO 127.0.0.1 - - [19/May/2026 20:15:59] "GET / HTTP/1.1" 200 - +2026-05-19 20:15:59,542 INFO 127.0.0.1 - - [19/May/2026 20:15:59] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:16:00,687 INFO 127.0.0.1 - - [19/May/2026 20:16:00] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:16:00,710 INFO 127.0.0.1 - - [19/May/2026 20:16:00] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:16:18,443 INFO 127.0.0.1 - - [19/May/2026 20:16:18] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:16:18,928 INFO 127.0.0.1 - - [19/May/2026 20:16:18] "GET /static/cancom.svg HTTP/1.1" 200 - +2026-05-19 20:16:18,947 INFO 127.0.0.1 - - [19/May/2026 20:16:18] "GET /static/favicon.ico HTTP/1.1" 200 - +2026-05-19 20:16:20,679 INFO 127.0.0.1 - - [19/May/2026 20:16:20] "GET /assign HTTP/1.1" 200 - +2026-05-19 20:16:20,701 INFO 127.0.0.1 - - [19/May/2026 20:16:20] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:18:44,322 INFO 127.0.0.1 - - [19/May/2026 20:18:44] "GET / HTTP/1.1" 200 - +2026-05-19 20:18:44,350 INFO 127.0.0.1 - - [19/May/2026 20:18:44] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:19:57,184 INFO 127.0.0.1 - - [19/May/2026 20:19:57] "GET / HTTP/1.1" 200 - +2026-05-19 20:19:57,209 INFO 127.0.0.1 - - [19/May/2026 20:19:57] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:20:47,653 INFO 127.0.0.1 - - [19/May/2026 20:20:47] "GET / HTTP/1.1" 200 - +2026-05-19 20:20:47,677 INFO 127.0.0.1 - - [19/May/2026 20:20:47] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:20:50,056 INFO 127.0.0.1 - - [19/May/2026 20:20:50] "GET / HTTP/1.1" 200 - +2026-05-19 20:20:50,076 INFO 127.0.0.1 - - [19/May/2026 20:20:50] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:21:17,827 INFO 127.0.0.1 - - [19/May/2026 20:21:17] "GET / HTTP/1.1" 200 - +2026-05-19 20:21:17,850 INFO 127.0.0.1 - - [19/May/2026 20:21:17] "GET /static/cancom.svg HTTP/1.1" 304 - +2026-05-19 20:21:44,466 INFO 127.0.0.1 - - [19/May/2026 20:21:44] "GET / HTTP/1.1" 200 - +2026-05-19 20:21:44,485 INFO 127.0.0.1 - - [19/May/2026 20:21:44] "GET /static/cancom.svg HTTP/1.1" 304 - diff --git a/templates/assign_asset.html b/templates/assign_asset.html index cc181d7..7208a51 100644 --- a/templates/assign_asset.html +++ b/templates/assign_asset.html @@ -3,12 +3,12 @@ {% block content %}

Ausgabe

-

Tuerchips und Parkkarten an bestehende User ausgeben.

+

Tuerchips, Parkkarten und Poolfahrzeuge an bestehende User ausgeben.

-

Chip oder Parkkarte ausgeben

+

Medium ausgeben

@@ -21,17 +21,39 @@
- + + +
- - + +
+ {% endblock %} diff --git a/templates/base.html b/templates/base.html index a218acd..f9caece 100644 --- a/templates/base.html +++ b/templates/base.html @@ -118,7 +118,7 @@ .stats-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(195px, 1fr)); gap: 1rem; } @@ -162,6 +162,11 @@ border-radius: 999px; background: rgba(255, 255, 255, 0.18); font-size: 1.5rem; + flex: 0 0 auto; + } + + .card.stat-card-pool .stat-icon { + margin-right: 0.15rem; } .card.stat-card.stat-card-users { @@ -489,7 +494,7 @@ CANCOM BU Sued/West - Tuerchip und Parkkartenverwaltung + Tuerchip-, Parkkarten- und Poolfahrzeugverwaltung +
+
+
+
Poolfahrzeuge
+
{{ stats.active_pool_vehicles }}
+
+
+
+
@@ -70,6 +79,7 @@ Abteilung Tuerchip Parkkarte + Poolfahrzeug @@ -94,6 +104,14 @@ - {% endif %} + + {% if user.pool_vehicle_code %} + {{ user.pool_vehicle_code }}
+ seit {{ user.pool_vehicle_assigned_at }} + {% else %} + - + {% endif %} + {% endfor %} diff --git a/templates/login.html b/templates/login.html index c20c0e1..cb6ac24 100644 --- a/templates/login.html +++ b/templates/login.html @@ -3,7 +3,7 @@ {% block content %}
-

Signage Admin

+

Chipverwaltung

diff --git a/templates/print_transaction.html b/templates/print_transaction.html index e0d1d83..351b388 100644 --- a/templates/print_transaction.html +++ b/templates/print_transaction.html @@ -279,7 +279,7 @@ {{ asset_labels[transaction.asset_type] }} - Kennung + {% if transaction.asset_type == 'pool_vehicle' %}Kennzeichen{% else %}Kennung{% endif %} {{ transaction.asset_code }} diff --git a/templates/return_asset.html b/templates/return_asset.html index 5583088..2cd3c46 100644 --- a/templates/return_asset.html +++ b/templates/return_asset.html @@ -3,12 +3,12 @@ {% block content %}

Rueckgabe

-

Ausgegebene Tuerchips und Parkkarten wieder zuruecknehmen.

+

Ausgegebene Tuerchips, Parkkarten und Poolfahrzeuge wieder zuruecknehmen.

-

Chip oder Parkkarte zuruecknehmen

+

Medium zuruecknehmen

@@ -21,13 +21,27 @@
- + + +
+ {% endblock %}