Migrationen 003–009, Kundaufträge mit Lieferschein, Abräumen mit Urteil, ntfy/Backup/Zeitfenster, Live-Stream und Mobile-Mehr-Menü.
157 lines
5.0 KiB
Python
157 lines
5.0 KiB
Python
"""Wartungs-Teile und Laufzähler aus dem Protokoll."""
|
|
|
|
from __future__ import annotations
|
|
|
|
def _baseline(conn, host, part_key):
|
|
row = conn.execute(
|
|
"""
|
|
SELECT hours_at, meters_at FROM maintenance_log
|
|
WHERE printer_host = %s AND part_key = %s AND event IN ('install', 'reset')
|
|
ORDER BY created_at DESC, id DESC
|
|
LIMIT 1
|
|
""",
|
|
(host, part_key),
|
|
).fetchone()
|
|
if not row:
|
|
return 0.0, 0.0
|
|
return float(row.get("hours_at") or 0), float(row.get("meters_at") or 0)
|
|
|
|
|
|
def counters_for_host(conn, host):
|
|
"""Summe Druckzeit, Filament und Anzahl Läufe für einen Host."""
|
|
host = (host or "").strip()
|
|
if not host:
|
|
return {"hours": 0.0, "meters": 0.0, "runs": 0}
|
|
row = conn.execute(
|
|
"""
|
|
SELECT
|
|
COALESCE(SUM(duration_s), 0) AS duration_s,
|
|
COALESCE(SUM(filament_used_mm), 0) AS meters,
|
|
COUNT(*) AS runs
|
|
FROM runs
|
|
WHERE printer_host = %s AND state = 'completed'
|
|
""",
|
|
(host,),
|
|
).fetchone()
|
|
if not row:
|
|
return {"hours": 0.0, "meters": 0.0, "runs": 0}
|
|
return {
|
|
"hours": float(row.get("duration_s") or 0) / 3600.0,
|
|
"meters": float(row.get("meters") or 0),
|
|
"runs": int(row.get("runs") or 0),
|
|
}
|
|
|
|
|
|
def part_out(row, counters=None, conn=None):
|
|
counters = counters or {}
|
|
life_h = float(row.get("life_hours") or 0)
|
|
life_m = float(row.get("life_meters") or 0)
|
|
hours_total = float(counters.get("hours") or 0)
|
|
meters_total = float(counters.get("meters") or 0)
|
|
host = row["printer_host"]
|
|
part_key = row["part_key"]
|
|
base_h, base_m = (0.0, 0.0)
|
|
if conn is not None:
|
|
base_h, base_m = _baseline(conn, host, part_key)
|
|
hours_since = max(0.0, hours_total - base_h)
|
|
meters_since = max(0.0, meters_total - base_m)
|
|
installed = row.get("installed_at")
|
|
return {
|
|
"id": row["id"],
|
|
"printer_host": host,
|
|
"part_key": part_key,
|
|
"label": row.get("label") or "",
|
|
"installed_at": installed.isoformat() if hasattr(installed, "isoformat") else str(installed or ""),
|
|
"life_hours": life_h,
|
|
"life_meters": life_m,
|
|
"note": row.get("note") or "",
|
|
"hours_since": hours_since,
|
|
"meters_since": meters_since,
|
|
"overdue_hours": life_h > 0 and hours_since >= life_h,
|
|
"overdue_meters": life_m > 0 and meters_since >= life_m,
|
|
}
|
|
|
|
|
|
def list_for_api(conn, printers):
|
|
out = []
|
|
for printer in printers or []:
|
|
host = printer.get("host") or ""
|
|
counters = counters_for_host(conn, host)
|
|
rows = conn.execute(
|
|
"SELECT * FROM maintenance_parts WHERE printer_host = %s ORDER BY label, part_key, id",
|
|
(host,),
|
|
).fetchall()
|
|
out.append({
|
|
"host": host,
|
|
"name": printer.get("name") or host,
|
|
"counters": counters,
|
|
"parts": [part_out(r, counters, conn=conn) for r in rows],
|
|
})
|
|
return out
|
|
|
|
|
|
def create_part(conn, printer_host, part_key, label="", life_hours=0, life_meters=0, note=""):
|
|
printer_host = (printer_host or "").strip()
|
|
part_key = (part_key or "").strip()
|
|
if not printer_host or not part_key:
|
|
raise ValueError("Drucker und part_key nötig.")
|
|
row = conn.execute(
|
|
"""
|
|
INSERT INTO maintenance_parts (printer_host, part_key, label, life_hours, life_meters, note)
|
|
VALUES (%s, %s, %s, %s, %s, %s)
|
|
RETURNING *
|
|
""",
|
|
(
|
|
printer_host,
|
|
part_key,
|
|
(label or part_key).strip(),
|
|
float(life_hours or 0),
|
|
float(life_meters or 0),
|
|
(note or "").strip(),
|
|
),
|
|
).fetchone()
|
|
counters = counters_for_host(conn, printer_host)
|
|
conn.execute(
|
|
"""
|
|
INSERT INTO maintenance_log (printer_host, part_key, event, hours_at, meters_at, note)
|
|
VALUES (%s, %s, 'install', %s, %s, %s)
|
|
""",
|
|
(printer_host, part_key, counters["hours"], counters["meters"], (note or "").strip()),
|
|
)
|
|
return part_out(row, counters, conn=conn)
|
|
|
|
|
|
def reset_part(conn, part_id):
|
|
row = conn.execute(
|
|
"SELECT * FROM maintenance_parts WHERE id = %s",
|
|
(int(part_id),),
|
|
).fetchone()
|
|
if not row:
|
|
return None
|
|
host = row["printer_host"]
|
|
counters = counters_for_host(conn, host)
|
|
conn.execute(
|
|
"""
|
|
INSERT INTO maintenance_log (printer_host, part_key, event, hours_at, meters_at, note)
|
|
VALUES (%s, %s, 'reset', %s, %s, %s)
|
|
""",
|
|
(
|
|
host,
|
|
row["part_key"],
|
|
counters["hours"],
|
|
counters["meters"],
|
|
row.get("note") or "",
|
|
),
|
|
)
|
|
updated = conn.execute(
|
|
"""
|
|
UPDATE maintenance_parts
|
|
SET installed_at = now()
|
|
WHERE id = %s
|
|
RETURNING *
|
|
""",
|
|
(int(part_id),),
|
|
).fetchone()
|
|
fresh_counters = counters_for_host(conn, host)
|
|
return part_out(updated, fresh_counters, conn=conn)
|