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) {