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
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
"""Administrarea campurilor variabile proprii (custom.*).
|
||||
|
||||
Un camp propriu este un text care poate include alte campuri fixe, de exemplu
|
||||
`Tel. {{company.phone}}`. La randarea etichetei, textul este expandat cu
|
||||
valorile reale ale pachetului.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from flask import (Blueprint, jsonify, flash, redirect, render_template, request, url_for)
|
||||
|
||||
from .. import designer
|
||||
from ..repositories import (
|
||||
ValidationError,
|
||||
count_label_field_usage,
|
||||
create_label_field,
|
||||
delete_label_field,
|
||||
get_label_field,
|
||||
list_label_fields,
|
||||
update_label_field,
|
||||
)
|
||||
|
||||
bp = Blueprint("fields", __name__, url_prefix="/campuri")
|
||||
|
||||
|
||||
def _form_context(field: dict, *, is_new: bool) -> dict:
|
||||
return {
|
||||
"field": field,
|
||||
"is_new": is_new,
|
||||
"catalog": [
|
||||
{"key": key, "label": label, "sample": sample}
|
||||
for key, label, sample in designer.FIELD_CATALOG
|
||||
],
|
||||
"max_label": designer.MAX_CUSTOM_LABEL,
|
||||
"max_template": designer.MAX_CUSTOM_TEMPLATE,
|
||||
}
|
||||
|
||||
|
||||
@bp.get("")
|
||||
def index():
|
||||
rows = list_label_fields(include_inactive=True)
|
||||
for row in rows:
|
||||
row["usage"] = count_label_field_usage(row["key"])
|
||||
row["preview"] = designer.expand_custom(
|
||||
row.get("template") or "",
|
||||
designer.apply_custom_fields(designer.demo_fields(), [row]),
|
||||
)
|
||||
return render_template("fields/list.html", fields=rows)
|
||||
|
||||
|
||||
@bp.route("/nou", methods=["GET", "POST"])
|
||||
def create():
|
||||
if request.method == "POST":
|
||||
data = dict(request.form)
|
||||
try:
|
||||
designer.validate_custom_field(data)
|
||||
create_label_field(data)
|
||||
flash("Campul a fost adaugat.", "success")
|
||||
return redirect(url_for("fields.index"))
|
||||
except ValidationError as exc:
|
||||
flash(str(exc), "error")
|
||||
return render_template("fields/form.html", **_form_context(data, is_new=True))
|
||||
return render_template("fields/form.html",
|
||||
**_form_context({"active": 1}, is_new=True))
|
||||
|
||||
|
||||
@bp.route("/<int:field_id>/editare", methods=["GET", "POST"])
|
||||
def edit(field_id: int):
|
||||
field = get_label_field(field_id)
|
||||
if field is None:
|
||||
flash("Campul nu exista.", "error")
|
||||
return redirect(url_for("fields.index"))
|
||||
|
||||
if request.method == "POST":
|
||||
data = dict(request.form)
|
||||
try:
|
||||
designer.validate_custom_field(data)
|
||||
update_label_field(field_id, data)
|
||||
flash("Campul a fost actualizat.", "success")
|
||||
return redirect(url_for("fields.index"))
|
||||
except ValidationError as exc:
|
||||
flash(str(exc), "error")
|
||||
field = {**field, **data}
|
||||
return render_template("fields/form.html", **_form_context(field, is_new=False))
|
||||
|
||||
|
||||
@bp.post("/<int:field_id>/stergere")
|
||||
def remove(field_id: int):
|
||||
field = get_label_field(field_id)
|
||||
if field is None:
|
||||
flash("Campul nu exista.", "error")
|
||||
return redirect(url_for("fields.index"))
|
||||
delete_label_field(field_id)
|
||||
usage = count_label_field_usage(field["key"])
|
||||
if usage:
|
||||
flash(
|
||||
f"Campul {field['label']} a fost sters. Atentie: {usage} sabloane il folosesc "
|
||||
"si il vor afisa gol pana il inlocuiesti.",
|
||||
"error",
|
||||
)
|
||||
else:
|
||||
flash(f"Campul {field['label']} a fost sters.", "success")
|
||||
return redirect(url_for("fields.index"))
|
||||
|
||||
|
||||
@bp.get("/previzualizare")
|
||||
def preview():
|
||||
"""Valoarea rezultata pentru textul introdus, cu datele demo."""
|
||||
text = (request.args.get("template") or "")[: designer.MAX_CUSTOM_TEMPLATE * 2]
|
||||
errors = designer.custom_template_errors(text)
|
||||
if errors:
|
||||
return jsonify({"ok": False, "error": errors[0]})
|
||||
demo = designer.demo_fields()
|
||||
return jsonify({"ok": True, "value": designer.expand_custom(text, demo)})
|
||||
Reference in New Issue
Block a user