bff6d70b17
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
66 lines
2.0 KiB
Python
66 lines
2.0 KiB
Python
"""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"'},
|
|
)
|