Auftragsübersicht anpassen
Build und Push Docker Image / build-and-push (push) Successful in 11s

This commit is contained in:
2026-08-27 11:52:24 +02:00
parent d6c066e18f
commit 455f513f6e
5 changed files with 74 additions and 24 deletions
+14 -10
View File
@@ -151,16 +151,20 @@ location /app/wdm-performance/ {
(.xlsx) oder CSV-Datei per Drag & Drop oder Dateiauswahl bulk-anlegen, (.xlsx) oder CSV-Datei per Drag & Drop oder Dateiauswahl bulk-anlegen,
siehe eigener Abschnitt unten siehe eigener Abschnitt unten
- **Auftragsübersicht**: alle Aufträge (inkl. Artikel, Maschinenname), - **Auftragsübersicht**: alle Aufträge (inkl. Artikel, Maschinenname),
standardmäßig nur offen/pausiert (umschaltbar auf "Alle"), optional nach standardmäßig offen/pausiert **und aktiv** (umschaltbar auf "Alle", zeigt
Maschine gefiltert, löschbar und (mit Einschränkungen) bearbeitbar: dann zusätzlich auch abgeschlossene Aufträge), optional nach Maschine
- **Status und Priorität sind hier nicht editierbar** (nur informativ gefiltert, löschbar und (mit Einschränkungen) bearbeitbar:
angezeigt) Status ändert sich ausschließlich über die eigentlichen - **Status ist hier manuell änderbar** (z.B. um einen versehentlich
Maschinen-Aktionen (Start/Pause/Beenden), Priorität ausschließlich über abgeschlossenen Auftrag wieder auf "Offen" zu setzen) **"Aktiv" ist als
die Drag & Drop-Seite "Auftragspriorität". Zielwert bewusst ausgeschlossen**, das passiert ausschließlich über die
- **Aktive Aufträge werden angezeigt, können aber nicht bearbeitet eigentlichen Maschinen-Aktionen (Start/Pause/Beenden). **Priorität bleibt
werden** ein Bearbeitungsversuch (auch ein direkter POST) wird mit weiterhin nicht editierbar**, dafür gibt es die Drag & Drop-Seite
einer Fehlermeldung abgelehnt, solange der Auftrag gerade an der "Auftragspriorität".
Maschine läuft. - **Aktive Aufträge werden angezeigt, können aber weder bearbeitet noch
gelöscht werden** Bearbeiten- und Löschen-Button werden für sie in der
Liste durch einen Hinweistext ersetzt; ein direkter POST-Versuch (am UI
vorbei) wird serverseitig ebenfalls abgelehnt, solange der Auftrag gerade
an der Maschine läuft.
- Editierbar bleiben Maschine (inkl. automatischem Umhängen der kompletten - Editierbar bleiben Maschine (inkl. automatischem Umhängen der kompletten
MDE-Buchungshistorie auf die neue Maschine), Auftragsnummer, Artikel, MDE-Buchungshistorie auf die neue Maschine), Auftragsnummer, Artikel,
Produktionsmenge und Stück/Stunde. Produktionsmenge und Stück/Stunde.
+1 -1
View File
@@ -1 +1 @@
1.0.0 1.0.1
+42 -11
View File
@@ -58,6 +58,11 @@ STATUS_LABEL = {
"abgeschlossen": "Abgeschlossen", "abgeschlossen": "Abgeschlossen",
} }
STATUS_OPTIONEN = [("offen", "Offen"), ("aktiv", "Aktiv"), ("pause", "Pausiert"), ("abgeschlossen", "Abgeschlossen")] STATUS_OPTIONEN = [("offen", "Offen"), ("aktiv", "Aktiv"), ("pause", "Pausiert"), ("abgeschlossen", "Abgeschlossen")]
# In der Auftragsübersicht darf der Status manuell gesetzt werden (z.B. um einen
# Auftrag versehentlich abgeschlossenen wieder zu öffnen) - "aktiv" ist hier
# aber bewusst ausgeschlossen, das passiert ausschließlich über die
# Start-Aktion an der Maschine selbst.
STATUS_OPTIONEN_BEARBEITBAR = [(wert, label) for wert, label in STATUS_OPTIONEN if wert != "aktiv"]
# Anzahl Zeilen, auf die MDE-/Auftragslisten ausgelegt sind (kein hartes Limit, # Anzahl Zeilen, auf die MDE-/Auftragslisten ausgelegt sind (kein hartes Limit,
# aber Referenzgröße für Layout/Performance-Überlegungen). # aber Referenzgröße für Layout/Performance-Überlegungen).
@@ -705,7 +710,11 @@ def leitstand_uebersicht():
bedingungen.append('maschine_id = %s') bedingungen.append('maschine_id = %s')
params.append(filter_maschine_id) params.append(filter_maschine_id)
if filter_status == "offen_pause": if filter_status == "offen_pause":
bedingungen.append("status IN ('offen', 'pause')") # "aktiv" wird hier bewusst mit angezeigt (nur informativ, nicht
# bearbeitbar/löschbar - siehe leitstand_uebersicht_bearbeiten
# bzw. leitstand_uebersicht_loeschen), damit laufende Aufträge in
# der Übersicht nicht verschwinden.
bedingungen.append("status IN ('offen', 'pause', 'aktiv')")
where_sql = (" WHERE " + " AND ".join(bedingungen)) if bedingungen else "" where_sql = (" WHERE " + " AND ".join(bedingungen)) if bedingungen else ""
cur.execute( cur.execute(
@@ -735,12 +744,14 @@ def leitstand_uebersicht():
@app.route("/start_uebersicht/<int:auftrag_id>/bearbeiten", methods=["GET", "POST"]) @app.route("/start_uebersicht/<int:auftrag_id>/bearbeiten", methods=["GET", "POST"])
def leitstand_uebersicht_bearbeiten(auftrag_id): def leitstand_uebersicht_bearbeiten(auftrag_id):
"""Auftrag bearbeiten. Status und Priorität (sid) sind hier bewusst NICHT """Auftrag bearbeiten. Der Status ist hier manuell änderbar (z.B. um einen
editierbar - Status ändert sich nur über die eigentlichen Maschinen- versehentlich abgeschlossenen Auftrag wieder auf "offen" zu setzen) -
Aktionen (Start/Pause/Beenden), Priorität nur über die Drag&Drop-Seite "aktiv" ist als Zielwert bewusst ausgeschlossen, das passiert
"Auftragspriorität". Aktive Aufträge werden nur angezeigt, eine ausschließlich über die eigentlichen Maschinen-Aktionen (Start/Pause/
Bearbeitung wird komplett verweigert (Fehlermeldung), da sie gerade an Beenden). Priorität (sid) ist weiterhin NICHT editierbar, dafür gibt es
der Maschine läuft.""" die Drag&Drop-Seite "Auftragspriorität". Aktive Aufträge werden nur
angezeigt, eine Bearbeitung wird komplett verweigert (Fehlermeldung), da
sie gerade an der Maschine läuft."""
filter_maschine_id = request.args.get("maschine_id") or request.form.get("maschine_id_filter") or "" filter_maschine_id = request.args.get("maschine_id") or request.form.get("maschine_id_filter") or ""
filter_status = request.args.get("status") or request.form.get("status_filter") or "offen_pause" filter_status = request.args.get("status") or request.form.get("status_filter") or "offen_pause"
with db.get_cursor() as cur: with db.get_cursor() as cur:
@@ -759,6 +770,7 @@ def leitstand_uebersicht_bearbeiten(auftrag_id):
"leitstand_uebersicht_bearbeiten.html", title="Auftrag bearbeiten", "leitstand_uebersicht_bearbeiten.html", title="Auftrag bearbeiten",
auftrag=alt, maschinen=maschinen, gesperrt=True, auftrag=alt, maschinen=maschinen, gesperrt=True,
status_anzeige=STATUS_LABEL.get(alt["status"], alt["status"]), status_anzeige=STATUS_LABEL.get(alt["status"], alt["status"]),
status_optionen=STATUS_OPTIONEN_BEARBEITBAR,
filter_maschine_id=filter_maschine_id, filter_status=filter_status, filter_maschine_id=filter_maschine_id, filter_status=filter_status,
error="Dieser Auftrag ist aktuell aktiv und kann deshalb nicht bearbeitet werden. " error="Dieser Auftrag ist aktuell aktiv und kann deshalb nicht bearbeitet werden. "
"Bitte an der Maschine erst pausieren oder beenden.", "Bitte an der Maschine erst pausieren oder beenden.",
@@ -770,6 +782,7 @@ def leitstand_uebersicht_bearbeiten(auftrag_id):
soll_h = request.form.get("soll_h") soll_h = request.form.get("soll_h")
artikel = (request.form.get("artikel") or "").strip() or None artikel = (request.form.get("artikel") or "").strip() or None
neue_maschine_id = request.form.get("maschine_id") neue_maschine_id = request.form.get("maschine_id")
neuer_status = request.form.get("status")
error = None error = None
einheiten_f = soll_h_f = None einheiten_f = soll_h_f = None
@@ -782,6 +795,10 @@ def leitstand_uebersicht_bearbeiten(auftrag_id):
if not error and not auftragsnummer: if not error and not auftragsnummer:
error = "Auftragsnummer darf nicht leer sein." error = "Auftragsnummer darf nicht leer sein."
gueltige_status = {wert for wert, _ in STATUS_OPTIONEN_BEARBEITBAR}
if not error and neuer_status not in gueltige_status:
error = "Ungültiger Status."
if not error: if not error:
if not neue_maschine_id: if not neue_maschine_id:
error = "Maschine muss ausgewählt werden." error = "Maschine muss ausgewählt werden."
@@ -806,17 +823,27 @@ def leitstand_uebersicht_bearbeiten(auftrag_id):
auftrag["sid_fmt"] = fmt_num(alt["sid"]) auftrag["sid_fmt"] = fmt_num(alt["sid"])
auftrag["artikel"] = artikel auftrag["artikel"] = artikel
auftrag["maschine_id"] = neue_maschine_id or alt["maschine_id"] auftrag["maschine_id"] = neue_maschine_id or alt["maschine_id"]
auftrag["status"] = neuer_status if neuer_status in gueltige_status else alt["status"]
return render_template( return render_template(
"leitstand_uebersicht_bearbeiten.html", title="Auftrag bearbeiten", "leitstand_uebersicht_bearbeiten.html", title="Auftrag bearbeiten",
auftrag=auftrag, maschinen=maschinen, auftrag=auftrag, maschinen=maschinen,
status_anzeige=STATUS_LABEL.get(alt["status"], alt["status"]), status_anzeige=STATUS_LABEL.get(alt["status"], alt["status"]),
status_optionen=STATUS_OPTIONEN_BEARBEITBAR,
filter_maschine_id=filter_maschine_id, filter_status=filter_status, error=error, filter_maschine_id=filter_maschine_id, filter_status=filter_status, error=error,
) )
# Wurde der Status auf "abgeschlossen" geändert (oder war er das
# schon und bleibt es), Endzeitpunkt entsprechend setzen bzw.
# beibehalten - beim (Wieder-)Öffnen wird er zurückgesetzt.
if neuer_status == "abgeschlossen":
ende_wert = alt["ende"] if alt["status"] == "abgeschlossen" else now_ts()
else:
ende_wert = None
cur.execute( cur.execute(
'UPDATE "Auftraege" SET auftragsnummer = %s, einheiten = %s, soll_h = %s, ' 'UPDATE "Auftraege" SET auftragsnummer = %s, einheiten = %s, soll_h = %s, '
'artikel = %s, maschine_id = %s WHERE id = %s', 'artikel = %s, maschine_id = %s, status = %s, aktiv = false, ende = %s WHERE id = %s',
(auftragsnummer, einheiten_f, soll_h_f, artikel, neue_maschine_id, auftrag_id), (auftragsnummer, einheiten_f, soll_h_f, artikel, neue_maschine_id, neuer_status, ende_wert, auftrag_id),
) )
# Maschine und/oder Auftragsnummer geändert? Dann muss die MDE-Historie # Maschine und/oder Auftragsnummer geändert? Dann muss die MDE-Historie
# (dort per maschine_id + Auftragsnummer verknüpft) mitgezogen werden. # (dort per maschine_id + Auftragsnummer verknüpft) mitgezogen werden.
@@ -835,6 +862,7 @@ def leitstand_uebersicht_bearbeiten(auftrag_id):
"leitstand_uebersicht_bearbeiten.html", title="Auftrag bearbeiten", "leitstand_uebersicht_bearbeiten.html", title="Auftrag bearbeiten",
auftrag=alt, maschinen=maschinen, auftrag=alt, maschinen=maschinen,
status_anzeige=STATUS_LABEL.get(alt["status"], alt["status"]), status_anzeige=STATUS_LABEL.get(alt["status"], alt["status"]),
status_optionen=STATUS_OPTIONEN_BEARBEITBAR,
filter_maschine_id=filter_maschine_id, filter_status=filter_status, filter_maschine_id=filter_maschine_id, filter_status=filter_status,
) )
@@ -844,7 +872,10 @@ def leitstand_uebersicht_loeschen(auftrag_id):
filter_maschine_id = request.form.get("maschine_id") or "" filter_maschine_id = request.form.get("maschine_id") or ""
filter_status = request.form.get("status") or "offen_pause" filter_status = request.form.get("status") or "offen_pause"
with db.get_cursor() as cur: with db.get_cursor() as cur:
cur.execute('DELETE FROM "Auftraege" WHERE id = %s', (auftrag_id,)) # Aktive Aufträge (gerade an der Maschine laufend) dürfen hier nicht
# gelöscht werden können, unabhängig davon, was im UI angeboten wird
# (analog zur Bearbeiten-Sperre für aktive Aufträge).
cur.execute('DELETE FROM "Auftraege" WHERE id = %s AND status <> \'aktiv\'', (auftrag_id,))
return redirect(url_for("leitstand_uebersicht", maschine_id=filter_maschine_id, status=filter_status)) return redirect(url_for("leitstand_uebersicht", maschine_id=filter_maschine_id, status=filter_status))
@@ -1123,4 +1154,4 @@ def health():
if __name__ == "__main__": if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=False) app.run(host="0.0.0.0", port=5000, debug=False)
+6 -2
View File
@@ -14,7 +14,7 @@
</select> </select>
<span>Status:</span> <span>Status:</span>
<select name="status" onchange="this.form.submit()"> <select name="status" onchange="this.form.submit()">
<option value="offen_pause" {% if filter_status == "offen_pause" %}selected{% endif %}>Offen/Pausiert</option> <option value="offen_pause" {% if filter_status == "offen_pause" %}selected{% endif %}>Offen/Pausiert/Aktiv</option>
<option value="alle" {% if filter_status == "alle" %}selected{% endif %}>Alle</option> <option value="alle" {% if filter_status == "alle" %}selected{% endif %}>Alle</option>
</select> </select>
<button type="submit">Filtern</button> <button type="submit">Filtern</button>
@@ -42,6 +42,9 @@
<td>{{ "Ja" if a.aktiv else "Nein" }}</td> <td>{{ "Ja" if a.aktiv else "Nein" }}</td>
<td>{{ a.sid_fmt }}</td> <td>{{ a.sid_fmt }}</td>
<td class="col-actions"> <td class="col-actions">
{% if a.status == "aktiv" %}
<span style="color:var(--text-dim); font-size:0.85em;">gesperrt (aktiv an Maschine)</span>
{% else %}
<div class="row-actions"> <div class="row-actions">
<a class="icon-btn" href="{{ url_for('leitstand_uebersicht_bearbeiten', auftrag_id=a.id, maschine_id=filter_maschine_id, status=filter_status) }}">Bearbeiten</a> <a class="icon-btn" href="{{ url_for('leitstand_uebersicht_bearbeiten', auftrag_id=a.id, maschine_id=filter_maschine_id, status=filter_status) }}">Bearbeiten</a>
<form method="post" action="{{ url_for('leitstand_uebersicht_loeschen', auftrag_id=a.id) }}" class="order-form"> <form method="post" action="{{ url_for('leitstand_uebersicht_loeschen', auftrag_id=a.id) }}" class="order-form">
@@ -50,6 +53,7 @@
<button type="submit" class="icon-btn danger">L&ouml;schen</button> <button type="submit" class="icon-btn danger">L&ouml;schen</button>
</form> </form>
</div> </div>
{% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@@ -57,4 +61,4 @@
</table> </table>
</div> </div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
@@ -31,7 +31,18 @@
<label for="soll_h">St&uuml;ck pro Stunde</label> <label for="soll_h">St&uuml;ck pro Stunde</label>
<input type="number" step="any" id="soll_h" name="soll_h" value="{{ auftrag.soll_h_fmt }}" {{ 'readonly' if gesperrt }} required> <input type="number" step="any" id="soll_h" name="soll_h" value="{{ auftrag.soll_h_fmt }}" {{ 'readonly' if gesperrt }} required>
</div> </div>
{% if gesperrt %}
<div class="status-line"><span class="label">Status</span><span>{{ status_anzeige }}</span></div> <div class="status-line"><span class="label">Status</span><span>{{ status_anzeige }}</span></div>
{% else %}
<div class="form-group">
<label for="status">Status</label>
<select id="status" name="status" required>
{% for wert, label in status_optionen %}
<option value="{{ wert }}" {% if auftrag.status == wert %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
{% endif %}
<div class="status-line"> <div class="status-line">
<span class="label">Priorit&auml;t</span> <span class="label">Priorit&auml;t</span>
<span>{{ auftrag.sid_fmt }} <span style="color:var(--text-dim); font-size:0.85em;">(&auml;nderbar unter "Auftragspriorit&auml;t")</span></span> <span>{{ auftrag.sid_fmt }} <span style="color:var(--text-dim); font-size:0.85em;">(&auml;nderbar unter "Auftragspriorit&auml;t")</span></span>