From b13d718d9278ef37d52a65a50f43fa5878cb350b Mon Sep 17 00:00:00 2001 From: Jo Date: Tue, 7 Jul 2026 12:46:37 +0200 Subject: [PATCH] fix: capacity check ignores physically-ended slots; feat: ha_poll_interval setting (default 60s) --- __pycache__/app.cpython-310.pyc | Bin 82670 -> 86252 bytes app.py | 21 ++++- templates/calendar_blocks.html | 32 ++++++- templates/job_detail.html | 159 ++++++++++++++++++++++++++++++++ templates/new_job.html | 2 +- templates/planning.html | 4 +- templates/settings.html | 29 ++++-- 7 files changed, 227 insertions(+), 20 deletions(-) diff --git a/__pycache__/app.cpython-310.pyc b/__pycache__/app.cpython-310.pyc index 596867eee646ddc37f7086d76c870e6d773a9013..e7432ba83f27f8e61c6413b48b431af47e68852e 100644 GIT binary patch delta 20067 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 diff --git a/app.py b/app.py index 84317a1..7cd80d8 100644 --- a/app.py +++ b/app.py @@ -226,6 +226,7 @@ def init_db(): ('ical_token',''), ('ha_url',''), ('ha_token',''), + ('ha_poll_interval','60'), ] conn.executemany('INSERT OR IGNORE INTO settings VALUES (?,?)', defaults) @@ -1303,8 +1304,11 @@ def job_detail(id): return redirect(url_for('jobs')) import math as _math total_plates_needed = _math.ceil((job['order_qty'] or 1) / max(1, job['pieces_per_plate'] or 1)) + _s = get_settings() + ha_poll_interval = int(_s.get('ha_poll_interval', 60)) return render_template('job_detail.html', job=job, slots=slots, - total_plates_needed=total_plates_needed) + total_plates_needed=total_plates_needed, + ha_poll_interval=ha_poll_interval) @app.route('/jobs//delete', methods=['POST']) def delete_job(id): @@ -1716,7 +1720,8 @@ def _check_capacity(conn, start_dt, end_dt, max_printers, exclude_id=None): """ q = """SELECT planned_start, planned_end FROM print_slots WHERE status NOT IN ('cancelled','failed','done') - AND planned_start < ? AND planned_end > ?""" + AND planned_start < ? AND planned_end > ? + AND planned_end > datetime('now')""" params = [end_dt.isoformat(), start_dt.isoformat()] if exclude_id: q += ' AND id != ?' @@ -1752,7 +1757,8 @@ def _check_overlap(conn, printer_id, start_dt, end_dt, exclude_id=None): FROM print_slots ps JOIN jobs j ON ps.job_id=j.id WHERE ps.printer_id=? AND ps.status NOT IN ('cancelled','failed','done') - AND ps.planned_start < ? AND ps.planned_end > ?""" + AND ps.planned_start < ? AND ps.planned_end > ? + AND ps.planned_end > datetime('now')""" params = [printer_id, end_dt.isoformat(), start_dt.isoformat()] if exclude_id: q += ' AND ps.id != ?' @@ -2063,7 +2069,14 @@ def _start_ha_poll(): time.sleep(10) while True: _ha_sync_once() - time.sleep(120) + try: + _c = sqlite3.connect(DATABASE, timeout=5) + _c.row_factory = sqlite3.Row + _interval = int(_c.execute("SELECT value FROM settings WHERE key='ha_poll_interval'").fetchone()['value']) + _c.close() + except Exception: + _interval = 60 + time.sleep(max(10, _interval)) t = threading.Thread(target=_loop, daemon=True, name='ha-poll') t.start() diff --git a/templates/calendar_blocks.html b/templates/calendar_blocks.html index da40b4a..2d7f863 100644 --- a/templates/calendar_blocks.html +++ b/templates/calendar_blocks.html @@ -14,9 +14,15 @@
Ajouter une exception
-
- - +
+
+ + +
+
+ + +
@@ -55,12 +61,17 @@ {% if blocks %} - + {% for b in blocks %} - +
DateTypeMachineNote
PériodeTypeMachineNote
{{ b.date }} + {{ b.date }} + {% if b.date_end and b.date_end != b.date %} + {{ b.date_end }} + {% endif %} + {% if b.type == 'off' %}Off {% elif b.type == 'tt' %}TT @@ -89,3 +100,14 @@ {% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/job_detail.html b/templates/job_detail.html index ede3bda..7326eeb 100644 --- a/templates/job_detail.html +++ b/templates/job_detail.html @@ -385,6 +385,129 @@ + +{% set plates_done = slots | selectattr('status','in',['done']) | list | length %} +{% set plates_running = slots | selectattr('status','equalto','running') | list | length %} +{% set plates_planned = slots | selectattr('status','in',['planned','running']) | list | length %} +{% set plates_total = slots | rejectattr('status','in',['cancelled']) | list | length %} +{% set missing_plates = [total_plates_needed - plates_total, 0] | max %} + +
+
+
+
+ Plateaux d'impression +
+ {% if total_plates_needed > 1 %} + + {{ plates_done }}/{{ total_plates_needed }} terminé{{ 's' if plates_done > 1 else '' }} + + {% endif %} + {% if missing_plates > 0 %} + + {{ missing_plates }} plateau{{ 'x' if missing_plates > 1 else '' }} à planifier + + {% endif %} + + Planning + +
+
+ + {% if slots %} +
+ + + + + + + + + + + + {% for s in slots %} + {% if s.status != 'cancelled' %} + + + + + + + + {% if s.status == 'running' and s.ha_entity_prefix %} + + + + {% endif %} + {% endif %} + {% endfor %} + +
#DébutMachinePiècesStatut / Progression
{{ loop.index }}{{ s.planned_start[:16].replace('T',' ') }}{{ s.printer_name }} + {% set ep = s.effective_pieces %} + {% set ig = s.pieces_ignored %} + {% if ig > 0 %} + {{ ep - ig }}/{{ ep }} + ({{ ig }} ignorée{{ 's' if ig > 1 }}) + {% else %}{{ ep }}{% endif %} + + {% set sc = {'planned':'secondary','running':'primary','done':'success','failed':'danger'} %} + {% set sl = {'planned':'Planifié','running':'En cours','done':'Terminé','failed':'Échec'} %} + {{ sl.get(s.status, s.status) }} + {% if s.status == 'running' and s.ha_entity_prefix %} + + + + {% endif %} + {% if s.failure_note %}
{{ s.failure_note }}{% endif %} +
+
+
+
+
+
+
+ {% else %} +
+ Aucun créneau planifié. +
+ Aller au planning + +
+ {% endif %} + + {% if total_plates_needed > 1 %} + + {% endif %} +
+
+
+