feat: viewer local upload, Bambu collapse, planning done/fail, stats waste, portal link in jobs, sidebar collapsible, settings layout fix
Deploy via Portainer / deploy (push) Successful in 0s

This commit is contained in:
Jo
2026-07-07 09:16:24 +02:00
parent 7b65c4b2e2
commit b22e5e0fb4
9 changed files with 502 additions and 78 deletions
+51 -5
View File
@@ -219,6 +219,7 @@ def init_db():
('nc_username',''),
('nc_app_password',''),
('nc_root_path','/3D'),
('ical_token',''),
]
conn.executemany('INSERT OR IGNORE INTO settings VALUES (?,?)', defaults)
@@ -1364,11 +1365,36 @@ def mobile_quick():
except Exception:
pass
elif action == 'fail':
slot_id = request.form.get('slot_id')
note = request.form.get('failure_note', '')
slot_id = request.form.get('slot_id')
note = request.form.get('failure_note', '')
wasted_g = float(request.form.get('wasted_g', 0) or 0)
if slot_id:
conn.execute("UPDATE print_slots SET status='failed',failure_note=? WHERE id=?",
(note, slot_id))
slot = conn.execute('''
SELECT ps.weight_g as plate_g, j.material_id, j.weight_g
FROM print_slots ps JOIN jobs j ON ps.job_id=j.id
WHERE ps.id=?''', (slot_id,)).fetchone()
if slot:
if wasted_g == 0:
wasted_g = slot['weight_g'] or 0
conn.execute(
"UPDATE print_slots SET status='failed', failure_note=?, wasted_g=? WHERE id=?",
(note, wasted_g, slot_id))
if slot['material_id'] and wasted_g > 0:
conn.execute(
'UPDATE materials SET stock_g=MAX(0,stock_g-?), total_wasted_g=COALESCE(total_wasted_g,0)+? WHERE id=?',
(wasted_g, wasted_g, slot['material_id']))
conn.commit()
elif action == 'done':
slot_id = request.form.get('slot_id')
actual_g = float(request.form.get('actual_g', 0) or 0)
if slot_id:
slot = conn.execute(
'SELECT j.material_id FROM print_slots ps JOIN jobs j ON ps.job_id=j.id WHERE ps.id=?',
(slot_id,)).fetchone()
conn.execute("UPDATE print_slots SET status='done' WHERE id=?", (slot_id,))
if slot and slot['material_id'] and actual_g > 0:
conn.execute('UPDATE materials SET stock_g=MAX(0,stock_g-?) WHERE id=?',
(actual_g, slot['material_id']))
conn.commit()
conn.close()
return redirect(url_for('mobile_quick'))
@@ -1975,8 +2001,28 @@ def stats():
ROUND(SUM(j.weight_g),1) as total_g, ROUND(SUM(j.final_price),2) as revenue
FROM jobs j LEFT JOIN materials m ON j.material_id=m.id
GROUP BY j.material_id ORDER BY total_g DESC''').fetchall()
waste_by_material = conn.execute('''
SELECT COALESCE(m.name,'Non défini') as name, m.type,
COALESCE(m.color,'') as color,
ROUND(COALESCE(m.total_wasted_g,0),1) as wasted_g,
ROUND(COALESCE(m.stock_g,0),1) as stock_g
FROM materials m
WHERE COALESCE(m.total_wasted_g,0) > 0
ORDER BY wasted_g DESC''').fetchall()
failure_by_printer = conn.execute('''
SELECT COALESCE(p.name,'Inconnu') as name,
COUNT(ps.id) as total_slots,
SUM(CASE WHEN ps.status='failed' THEN 1 ELSE 0 END) as failed_slots,
ROUND(SUM(COALESCE(ps.wasted_g,0)),1) as wasted_g
FROM print_slots ps
LEFT JOIN printers p ON ps.printer_id=p.id
GROUP BY ps.printer_id
HAVING total_slots > 0
ORDER BY failed_slots DESC''').fetchall()
conn.close()
return render_template('stats.html', by_client=by_client, by_month=by_month, by_material=by_material)
return render_template('stats.html', by_client=by_client, by_month=by_month,
by_material=by_material, waste_by_material=waste_by_material,
failure_by_printer=failure_by_printer)
# ─── Export CSV ───────────────────────────────────────────────────────────────