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,65 @@
|
||||
"""Istoricul pachetelor si exportul CSV."""
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import io
|
||||
|
||||
from flask import Blueprint, Response, render_template, request
|
||||
|
||||
from ..repositories import get_recipe, list_packages, list_recipes, to_csv_rows
|
||||
from ..units import format_weight
|
||||
|
||||
bp = Blueprint("history", __name__, url_prefix="/istoric")
|
||||
|
||||
|
||||
def _filters() -> dict:
|
||||
recipe_id = request.args.get("recipe_id", "").strip()
|
||||
status = request.args.get("status", "").strip()
|
||||
return {
|
||||
"date_from": request.args.get("date_from", "").strip(),
|
||||
"date_to": request.args.get("date_to", "").strip(),
|
||||
"recipe_id": int(recipe_id) if recipe_id.isdigit() else None,
|
||||
"status": status if status in {"open", "done", "void"} else "",
|
||||
"query": request.args.get("q", "").strip(),
|
||||
"limit": 1000,
|
||||
}
|
||||
|
||||
|
||||
def _totals(packages: list[dict]) -> str:
|
||||
groups: dict[str, float] = {}
|
||||
for package in packages:
|
||||
if package.get("status") != "done":
|
||||
continue
|
||||
unit = package.get("unit") or ""
|
||||
groups[unit] = groups.get(unit, 0.0) + float(package.get("total_weight") or 0)
|
||||
return ", ".join(
|
||||
f"{format_weight(value)} {unit}" for unit, value in sorted(groups.items())
|
||||
) or "0"
|
||||
|
||||
|
||||
@bp.get("")
|
||||
def index():
|
||||
filters = _filters()
|
||||
packages = list_packages(**filters)
|
||||
recipe = get_recipe(filters["recipe_id"]) if filters["recipe_id"] else None
|
||||
return render_template(
|
||||
"history/list.html",
|
||||
packages=packages,
|
||||
filters=filters,
|
||||
recipes=list_recipes(include_inactive=True),
|
||||
total=_totals(packages),
|
||||
selected_recipe=recipe,
|
||||
)
|
||||
|
||||
|
||||
@bp.get("/export.csv")
|
||||
def export_csv():
|
||||
packages = list_packages(**_filters())
|
||||
buffer = io.StringIO()
|
||||
writer = csv.writer(buffer, delimiter=";", lineterminator="\r\n")
|
||||
writer.writerows(to_csv_rows(packages))
|
||||
return Response(
|
||||
buffer.getvalue(),
|
||||
mimetype="text/csv; charset=utf-8",
|
||||
headers={"Content-Disposition": 'attachment; filename="produse-finite.csv"'},
|
||||
)
|
||||
Reference in New Issue
Block a user