Grotti 3.0.0: Aufträge, Wartung, SSE, Ausschuss-Dialog, UI-Umbau.
Migrationen 003–009, Kundaufträge mit Lieferschein, Abräumen mit Urteil, ntfy/Backup/Zeitfenster, Live-Stream und Mobile-Mehr-Menü.
This commit is contained in:
1 parent
0236278929
commit
8e88efc094
45 files changed
+3121
-122
No files matched your search
@@ -0,0 +1,72 @@
|
||||
"""Start-Zeitfenster pro Drucker (Nachtdruck)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, time, timedelta
|
||||
|
||||
|
||||
def _parse_hm(text):
|
||||
text = str(text or "").strip()
|
||||
if not text or ":" not in text:
|
||||
return None
|
||||
parts = text.split(":", 1)
|
||||
try:
|
||||
h, m = int(parts[0]), int(parts[1])
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
if not (0 <= h <= 23 and 0 <= m <= 59):
|
||||
return None
|
||||
return time(h, m)
|
||||
|
||||
|
||||
def _in_segment(now_t, start_t, end_t):
|
||||
if start_t <= end_t:
|
||||
return start_t <= now_t <= end_t
|
||||
return now_t >= start_t or now_t <= end_t
|
||||
|
||||
|
||||
def allowed_now(start_window, now=None):
|
||||
"""True wenn kein Fenster gesetzt oder die aktuelle Uhrzeit erlaubt ist."""
|
||||
window = start_window or {}
|
||||
if not isinstance(window, dict):
|
||||
return True
|
||||
allowed = window.get("allowed")
|
||||
if not allowed:
|
||||
return True
|
||||
if not isinstance(allowed, list):
|
||||
return True
|
||||
now_dt = now if isinstance(now, datetime) else datetime.now().astimezone()
|
||||
now_t = now_dt.timetz().replace(tzinfo=None)
|
||||
for entry in allowed:
|
||||
if not isinstance(entry, dict):
|
||||
continue
|
||||
start_t = _parse_hm(entry.get("from"))
|
||||
end_t = _parse_hm(entry.get("to"))
|
||||
if start_t is None or end_t is None:
|
||||
continue
|
||||
if _in_segment(now_t, start_t, end_t):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def overnight_max_hours(start_window):
|
||||
window = start_window or {}
|
||||
if not isinstance(window, dict):
|
||||
return None
|
||||
try:
|
||||
val = float(window.get("max_hours_overnight") or 0)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return val if val > 0 else None
|
||||
|
||||
|
||||
def job_fits_overnight(start_window, estimated_s, now=None):
|
||||
"""Optional: Job darf max_hours_overnight nicht überschreiten (nur wenn gesetzt)."""
|
||||
max_h = overnight_max_hours(start_window)
|
||||
if max_h is None:
|
||||
return True
|
||||
if not estimated_s or float(estimated_s) <= 0:
|
||||
return True
|
||||
if allowed_now(start_window, now=now):
|
||||
return float(estimated_s) <= max_h * 3600
|
||||
return True
|
||||
Reference in new issue
Block a user