Files
cantarire-etichetare/cantarire/routes/main.py
T
ske087 bff6d70b17 Initial commit: aplicatie de cantarire si etichetare
Aplicatie Flask + SQLite pentru productie alimentara: cantarirea
componentelor unui produs finit si tiparirea etichetei prin QZ Tray.

- produse finite (retete) formate din componente cantarite
- designer vizual de etichete (mm/px, zona sigura, campuri variabile,
  cod QR cu continut din mai multe bucati)
- legare produs finit -> sablon de eticheta
- navigare pe doua taburi: Cantarire / Setari
- administrare: componente, produse finite, sabloane, campuri, istoric
- backup, resetare baza de date, checklist de pregatire, /healthz
- CLI de administrare si serviciu systemd pentru productie
- vendor/syncpulse-scale-bridge (GPL-3.0-or-later) pentru citirea cantarului
2026-10-18 23:38:45 +03:00

136 lines
4.5 KiB
Python

"""Pagina de cantarire si setarile aplicatiei."""
from __future__ import annotations
from flask import (Blueprint, current_app, flash, jsonify, redirect, render_template, request,
send_file, url_for)
from .. import maintenance
from ..db import all_settings, get_setting, set_setting
from ..repositories import (
get_open_package,
get_recipe,
get_template,
list_components,
list_label_fields,
list_recipes,
list_templates,
package_state,
package_stats,
recent_packages,
)
from ..scale import get_scale
bp = Blueprint("main", __name__)
@bp.get("/")
def dashboard():
scale = get_scale(current_app)
profiles = scale.profiles()
active_profile = get_setting("active_scale_profile")
if active_profile not in {p["name"] for p in profiles}:
active_profile = profiles[0]["name"] if profiles else ""
open_package = get_open_package()
initial = package_state(open_package["id"]) if open_package else None
settings = all_settings()
template_id = settings.get("default_template_id") or ""
if template_id and get_template(int(template_id)) is None:
template_id = ""
recipes = [get_recipe(item["id"]) for item in list_recipes()]
recipes = [recipe for recipe in recipes if recipe is not None]
return render_template(
"dashboard.html",
recipes=recipes,
components=list_components(),
initial=initial,
recent=recent_packages(6),
stats=package_stats(),
profiles=profiles,
active_profile=active_profile,
scale_ready=bool(profiles),
default_operator=settings.get("default_operator", ""),
default_template_id=template_id,
auto_print=settings.get("auto_print", "1") == "1" and current_app.config["AUTO_PRINT"],
poll_ms=700,
scale_error=scale.error,
setup=maintenance.readiness_summary(),
)
@bp.get("/healthz")
def healthz():
"""Verificare simpla pentru monitorizare / reverse proxy."""
status = maintenance.database_status()
summary = maintenance.readiness_summary()
healthy = status["integrity"] == "ok"
payload = {
"ok": healthy,
"version": "0.1.0",
"database": {
"path": status["path"],
"size": status["size"],
"integrity": status["integrity"],
"schema_version": status["schema_version"],
"counts": status["counts"],
},
"setup": {
"ready": summary["ready"],
"missing": [item["label"] for item in summary["missing"]],
},
}
return jsonify(payload), (200 if healthy else 503)
@bp.get("/setari")
def settings_page():
scale = get_scale(current_app)
return render_template(
"settings.html",
profiles=scale.profiles(),
scale_available=scale.available,
scale_error=scale.error,
templates=list_templates(),
components=list_components(include_inactive=True),
recipes=list_recipes(include_inactive=True),
fields_count=len(list_label_fields(include_inactive=True)),
db_status=maintenance.database_status(),
backups=maintenance.list_backups()[:5],
setup=maintenance.readiness_summary(),
)
@bp.get("/setari/backup")
def settings_backup():
"""Descarca un backup proaspat al bazei (inainte de o actualizare)."""
path = maintenance.backup_database("manual")
maintenance.prune_backups()
return send_file(path, as_attachment=True, download_name=path.name)
@bp.post("/setari")
def settings_save():
scale = get_scale(current_app)
valid_profiles = {p["name"] for p in scale.profiles()}
active = (request.form.get("active_scale_profile") or "").strip()
if active and active not in valid_profiles:
flash("Profilul de cantar selectat nu exista.", "error")
return redirect(url_for("main.settings_page"))
template_id = (request.form.get("default_template_id") or "").strip()
if template_id and (not template_id.isdigit() or get_template(int(template_id)) is None):
flash("Sabloul implicit selectat nu exista.", "error")
return redirect(url_for("main.settings_page"))
for key in ("company_name", "company_address", "company_phone", "default_operator"):
set_setting(key, (request.form.get(key) or "").strip()[:200])
set_setting("active_scale_profile", active)
set_setting("default_template_id", template_id)
set_setting("auto_print", "1" if request.form.get("auto_print") else "0")
flash("Setarile au fost salvate.", "success")
return redirect(url_for("main.settings_page"))