diff --git a/app.py b/app.py index b4af1f0..43d1680 100644 --- a/app.py +++ b/app.py @@ -1799,6 +1799,14 @@ def api_new_slot(): if over: conn.close() return jsonify({'error': f"Capacité maximale atteinte : {peak} impression(s) déjà en cours sur ce créneau (limite : {max_printers} simultanées). Décalez l'horaire ou attendez qu'une imprimante se libère."}), 409 + already_done = bool(d.get('already_done', False)) + if already_done: + # Retroactive — skip capacity/overlap checks, insert as done + conn.execute( + 'INSERT INTO print_slots(job_id,printer_id,planned_start,planned_end,status) VALUES(?,?,?,?,?)', + (job_id, printer_id, start_dt.isoformat(), end_dt.isoformat(), 'done')) + conn.commit(); conn.close() + return jsonify({'ok': True}) conn.execute('INSERT INTO print_slots(job_id,printer_id,planned_start,planned_end,status) VALUES(?,?,?,?,?)', (job_id, printer_id, start_dt.isoformat(), end_dt.isoformat(), 'planned')) conn.commit(); conn.close() diff --git a/templates/planning.html b/templates/planning.html index 94b23a7..29ce888 100644 --- a/templates/planning.html +++ b/templates/planning.html @@ -148,6 +148,15 @@ +
+
+ + +
+
Enregistre le plateau comme terminé sans passer par le planning actif.
+
@@ -157,7 +166,7 @@ @@ -525,11 +534,33 @@ function formatDt(iso) { d.toLocaleTimeString('fr-FR',{hour:'2-digit',minute:'2-digit'}); } +function onAlreadyDoneChange() { + const done = document.getElementById('modalAlreadyDone').checked; + const btn = document.getElementById('modalSaveBtn'); + if (done) { + btn.innerHTML = 'Enregistrer comme terminé'; + btn.style.background = '#22c55e'; + // Reset to "now" so user picks when it was done + const now = new Date(); + now.setMinutes(0, 0, 0); + document.getElementById('modalStart').value = now.toISOString().slice(0,16); + document.getElementById('modalSuggestion').classList.add('d-none'); + document.getElementById('modalError').classList.add('d-none'); + } else { + btn.innerHTML = 'Planifier'; + btn.style.background = '#ff6b35'; + } +} + function openScheduleModal(jobId, printTime, jobName) { document.getElementById('modalJobId').value = jobId; document.getElementById('modalPrintTime').value = printTime; document.getElementById('modalJobName').textContent = jobName; document.getElementById('modalSuggestion').classList.add('d-none'); + document.getElementById('modalError').classList.add('d-none'); + // Reset already-done checkbox + document.getElementById('modalAlreadyDone').checked = false; + onAlreadyDoneChange(); // Default: now rounded to next hour const now = new Date(); now.setMinutes(0, 0, 0); @@ -559,15 +590,17 @@ async function suggestSlot(jobId, printTime, jobName) { } async function saveSlot() { - const jobId = parseInt(document.getElementById('modalJobId').value); - const printer = parseInt(document.getElementById('modalPrinter').value); - const start = document.getElementById('modalStart').value; + const jobId = parseInt(document.getElementById('modalJobId').value); + const printer = parseInt(document.getElementById('modalPrinter').value); + const start = document.getElementById('modalStart').value; + const alreadyDone = document.getElementById('modalAlreadyDone').checked; // Clear previous error document.getElementById('modalError').classList.add('d-none'); const r = await fetch('/api/slots/new', { method: 'POST', headers: {'Content-Type':'application/json'}, - body: JSON.stringify({job_id: jobId, printer_id: printer, planned_start: start}) + body: JSON.stringify({job_id: jobId, printer_id: printer, planned_start: start, + already_done: alreadyDone}) }); const res = await r.json(); if (res.ok) {