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:
2026-10-18 23:38:45 +03:00
commit bff6d70b17
107 changed files with 21428 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
"""Unitati de masa, normalizare si conversii.
Etichetele de produs finit sunt exprimate de obicei in grame, iar cantarul
poate raporta kilograme. Toate cantaririle sunt convertite in unitatea retetei
inainte de a fi salvate.
"""
from __future__ import annotations
from typing import Optional
# Unitati acceptate, in ordinea afisata in interfata.
UNITS: tuple[str, ...] = ("g", "kg", "mg", "t", "lb", "oz")
GRAMS_PER: dict[str, float] = {
"g": 1.0,
"kg": 1000.0,
"mg": 0.001,
"t": 1_000_000.0,
"lb": 453.59237,
"oz": 28.349523125,
}
ALIASES: dict[str, str] = {
"gr": "g", "gram": "g", "grame": "g", "grams": "g",
"kg": "kg", "kgs": "kg", "kilogram": "kg", "kilograme": "kg",
"mg": "mg", "miligram": "mg", "miligrame": "mg",
"t": "t", "tona": "t", "ton": "t", "to": "t",
"lb": "lb", "lbs": "lb", "pound": "lb",
"oz": "oz", "ounce": "oz",
}
def normalize_unit(value: object, default: str = "g") -> str:
text = str(value or "").strip().lower()
if not text:
return default
return ALIASES.get(text, text if text in GRAMS_PER else default)
def convert(value: float, from_unit: str, to_unit: str) -> Optional[float]:
"""Converteste intre unitati de masa; None daca una nu este unitate de masa."""
source = GRAMS_PER.get(from_unit)
target = GRAMS_PER.get(to_unit)
if source is None or target is None:
return None
return value * source / target
def format_weight(value: object, decimals: int = 3) -> str:
"""Formatare pentru etichete: fara zerouri finale inutile."""
try:
number = float(value) # type: ignore[arg-type]
except (TypeError, ValueError):
return str(value)
text = f"{number:.{int(decimals)}f}"
if "." in text:
text = text.rstrip("0").rstrip(".")
return text or "0"