feat(stations): ricette in lista, reset per riga e cambio stazione al volo

Punto 7 del documento modifiche del 28/07, terza richiesta di Menoncin.

GET /api/stations ora usa StationWithRecipesResponse, che era gia' definita nello
schema senza che nessun endpoint la usasse. Non costa query in piu':
Station.assignments e' gia' selectin-loaded. In lista compaiono le sole ricette
attive, coerente con cio' che l'operatore vede davvero a quella stazione.

DELETE /api/stations/{id}/recipes azzera le assegnazioni di una stazione senza
eliminarla, cosi' si riassegna da capo. E' idempotente: azzerare una stazione gia'
vuota risponde removed=0, non 404. In tabella e' un pulsante per riga, con
conferma perche' l'azione e' distruttiva.

Il cambio stazione al volo (?station=CODE, override in sessione) serve al
collaudo: senza, provare N stazioni richiede N PC. E' dietro il flag
STATION_SWITCH_ENABLED, default 0. Non e' legato al ruolo admin perche'
/measure/select richiede MeasurementTec, e gatearlo su is_admin avrebbe escluso
proprio chi fa il collaudo. In fabbrica l'identita' della stazione viene
dall'installazione locale, e misurare contro le ricette di un'altra stazione
romperebbe in silenzio la tracciabilita': per questo il codice richiesto e'
validato prima di essere memorizzato - un refuso lascia l'operatore sulla
stazione configurata con un messaggio, invece di incastrarlo su una stazione
inesistente - e quando l'override e' attivo la pagina lo dichiara, con il codice
configurato accanto e un link per ripristinare.

Le traduzioni: pybabel update aveva indovinato dieci voci da stringhe simili
marcandole fuzzy, in entrambi i cataloghi. "Azzera Stazione" era diventato "Crea
Stazione", l'opposto, su un dialogo distruttivo. Non si vedeva perche' la
compilazione salta le fuzzy e ricade sul sorgente italiano, ma sarebbe emerso al
primo build con --use-fuzzy. Tradotte per esteso le 17 stringhe nuove in IT ed EN
e tolti i flag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-07-28 15:42:17 +00:00
parent 28ee44bcf1
commit a159eb2b8b
15 changed files with 1188 additions and 363 deletions
+5
View File
@@ -24,6 +24,11 @@ API_SERVER_URL=http://localhost:8000
# Each physical tablet/PC deployment must set this unique per-station value. # Each physical tablet/PC deployment must set this unique per-station value.
# Leave empty only for a single-station all-in-one demo using ST-DEFAULT. # Leave empty only for a single-station all-in-one demo using ST-DEFAULT.
STATION_CODE=ST-DEFAULT STATION_CODE=ST-DEFAULT
# Allow switching station from the URL (?station=CODE) during commissioning, so a
# single PC can exercise several stations. Leave at 0 in production: on the shop
# floor the station identity comes from the local install, and measuring against
# another station's recipes would silently break traceability.
STATION_SWITCH_ENABLED=0
# --- File Storage --- # --- File Storage ---
# Resolved against the project root in src/backend/config.py. # Resolved against the project root in src/backend/config.py.
+42 -3
View File
@@ -11,6 +11,8 @@ from src.backend.models.api.station import (
StationResponse, StationResponse,
StationRecipeAssignmentCreate, StationRecipeAssignmentCreate,
StationRecipeAssignmentResponse, StationRecipeAssignmentResponse,
StationResetResponse,
StationWithRecipesResponse,
RecipeSummary, RecipeSummary,
) )
from src.backend.services import station_service from src.backend.services import station_service
@@ -18,15 +20,36 @@ from src.backend.services import station_service
router = APIRouter(prefix="/api/stations", tags=["stations"]) router = APIRouter(prefix="/api/stations", tags=["stations"])
@router.get("", response_model=list[StationResponse]) @router.get("", response_model=list[StationWithRecipesResponse])
async def list_stations( async def list_stations(
active_only: bool = False, active_only: bool = False,
admin: User = Depends(require_admin_user), admin: User = Depends(require_admin_user),
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db),
): ):
"""List all stations (admin only).""" """List all stations with the recipes assigned to each (admin only).
The admin station list shows which products a station handles, so the
assignments travel with the station instead of needing a call per row.
Station.assignments is selectin-loaded, so this costs no extra query.
Only active recipes are listed, matching what an operator actually sees
at that station via /by-code/{code}/recipes.
"""
stations = await station_service.list_stations(db, active_only=active_only) stations = await station_service.list_stations(db, active_only=active_only)
return [StationResponse.model_validate(s) for s in stations] return [
StationWithRecipesResponse(
**StationResponse.model_validate(s).model_dump(),
recipes=sorted(
(
RecipeSummary.model_validate(a.recipe)
for a in s.assignments
if a.recipe is not None and a.recipe.active
),
key=lambda r: r.code,
),
)
for s in stations
]
@router.post("", response_model=StationResponse, status_code=status.HTTP_201_CREATED) @router.post("", response_model=StationResponse, status_code=status.HTTP_201_CREATED)
@@ -128,6 +151,22 @@ async def assign_recipe_to_station(
return StationRecipeAssignmentResponse.model_validate(assignment) return StationRecipeAssignmentResponse.model_validate(assignment)
@router.delete("/{station_id}/recipes", response_model=StationResetResponse)
async def reset_station_recipes(
station_id: int,
admin: User = Depends(require_admin_user),
db: AsyncSession = Depends(get_db),
):
"""Clear every recipe assignment of a station (admin only).
Backs the per-row reset in the admin list: the station is left with no
recipes and can be reassigned from scratch, without deleting the station
itself. Idempotent - resetting an already empty station reports removed=0.
"""
removed = await station_service.unassign_all_recipes(db, station_id)
return StationResetResponse(station_id=station_id, removed=removed)
@router.delete( @router.delete(
"/{station_id}/recipes/{recipe_id}", "/{station_id}/recipes/{recipe_id}",
status_code=status.HTTP_204_NO_CONTENT, status_code=status.HTTP_204_NO_CONTENT,
+7
View File
@@ -57,3 +57,10 @@ class RecipeSummary(BaseModel):
class StationWithRecipesResponse(StationResponse): class StationWithRecipesResponse(StationResponse):
recipes: list[RecipeSummary] = Field(default_factory=list) recipes: list[RecipeSummary] = Field(default_factory=list)
class StationResetResponse(BaseModel):
"""Outcome of clearing every recipe assignment of a station."""
station_id: int
removed: int
+20
View File
@@ -138,6 +138,26 @@ async def unassign_recipe(
await db.flush() await db.flush()
async def unassign_all_recipes(db: AsyncSession, station_id: int) -> int:
"""Drop every recipe assignment of a station and return how many were removed.
Used by the per-row reset in the admin station list: the station goes back to
having no recipes so it can be reassigned from scratch. Unlike unassign_recipe
this is idempotent - resetting an already empty station returns 0 rather than 404.
"""
await get_station(db, station_id)
result = await db.execute(
select(StationRecipeAssignment).where(
StationRecipeAssignment.station_id == station_id
)
)
assignments = list(result.scalars().all())
for assignment in assignments:
await db.delete(assignment)
await db.flush()
return len(assignments)
async def list_station_recipes( async def list_station_recipes(
db: AsyncSession, station_id: int, db: AsyncSession, station_id: int,
) -> list[Recipe]: ) -> list[Recipe]:
+173
View File
@@ -201,3 +201,176 @@ async def test_duplicate_assignment_returns_409(
json={"recipe_id": recipe.id}, json={"recipe_id": recipe.id},
) )
assert second.status_code == 409 assert second.status_code == 409
# ---------------------------------------------------------------------------
# Station list carries assigned recipes (point 7)
# ---------------------------------------------------------------------------
async def test_list_stations_includes_assigned_recipes(
client: AsyncClient, admin_user, db_session,
):
"""The admin list shows which recipes a station handles, without a call per row."""
recipe = await create_test_recipe(db_session, user_id=admin_user.id, code="REC-LIST")
await db_session.commit()
created = await client.post(
"/api/stations",
headers=auth_headers(admin_user),
json={"code": "ST-WITHREC", "name": "Con ricette"},
)
sid = created.json()["id"]
await client.post(
f"/api/stations/{sid}/recipes",
headers=auth_headers(admin_user),
json={"recipe_id": recipe.id},
)
resp = await client.get("/api/stations", headers=auth_headers(admin_user))
assert resp.status_code == 200
station = next(s for s in resp.json() if s["id"] == sid)
assert [r["code"] for r in station["recipes"]] == ["REC-LIST"]
async def test_list_stations_empty_recipes_when_unassigned(
client: AsyncClient, admin_user,
):
created = await client.post(
"/api/stations",
headers=auth_headers(admin_user),
json={"code": "ST-NOREC", "name": "Senza ricette"},
)
sid = created.json()["id"]
resp = await client.get("/api/stations", headers=auth_headers(admin_user))
station = next(s for s in resp.json() if s["id"] == sid)
assert station["recipes"] == []
async def test_list_stations_hides_inactive_recipes(
client: AsyncClient, admin_user, db_session,
):
"""An assigned but deactivated recipe must not show: the operator won't see it."""
recipe = await create_test_recipe(db_session, user_id=admin_user.id, code="REC-OFF")
await db_session.commit()
created = await client.post(
"/api/stations",
headers=auth_headers(admin_user),
json={"code": "ST-INACT", "name": "Con ricetta spenta"},
)
sid = created.json()["id"]
await client.post(
f"/api/stations/{sid}/recipes",
headers=auth_headers(admin_user),
json={"recipe_id": recipe.id},
)
recipe.active = False
await db_session.commit()
resp = await client.get("/api/stations", headers=auth_headers(admin_user))
station = next(s for s in resp.json() if s["id"] == sid)
assert station["recipes"] == []
# ---------------------------------------------------------------------------
# Per-row station reset (point 7)
# ---------------------------------------------------------------------------
async def test_reset_station_removes_all_assignments(
client: AsyncClient, admin_user, db_session,
):
first = await create_test_recipe(db_session, user_id=admin_user.id, code="REC-R1")
second = await create_test_recipe(db_session, user_id=admin_user.id, code="REC-R2")
await db_session.commit()
created = await client.post(
"/api/stations",
headers=auth_headers(admin_user),
json={"code": "ST-RESET", "name": "Da azzerare"},
)
sid = created.json()["id"]
for recipe in (first, second):
await client.post(
f"/api/stations/{sid}/recipes",
headers=auth_headers(admin_user),
json={"recipe_id": recipe.id},
)
resp = await client.delete(
f"/api/stations/{sid}/recipes", headers=auth_headers(admin_user),
)
assert resp.status_code == 200, resp.text
assert resp.json() == {"station_id": sid, "removed": 2}
left = await client.get(
f"/api/stations/{sid}/recipes", headers=auth_headers(admin_user),
)
assert left.json() == []
async def test_reset_station_keeps_the_station(
client: AsyncClient, admin_user, db_session,
):
"""Reset clears assignments only - the station stays and can be reassigned."""
recipe = await create_test_recipe(db_session, user_id=admin_user.id, code="REC-KEEP")
await db_session.commit()
created = await client.post(
"/api/stations",
headers=auth_headers(admin_user),
json={"code": "ST-KEEP", "name": "Resta"},
)
sid = created.json()["id"]
await client.post(
f"/api/stations/{sid}/recipes",
headers=auth_headers(admin_user),
json={"recipe_id": recipe.id},
)
await client.delete(f"/api/stations/{sid}/recipes", headers=auth_headers(admin_user))
still_there = await client.get(
f"/api/stations/{sid}", headers=auth_headers(admin_user),
)
assert still_there.status_code == 200
reassigned = await client.post(
f"/api/stations/{sid}/recipes",
headers=auth_headers(admin_user),
json={"recipe_id": recipe.id},
)
assert reassigned.status_code == 201
async def test_reset_empty_station_is_idempotent(client: AsyncClient, admin_user):
created = await client.post(
"/api/stations",
headers=auth_headers(admin_user),
json={"code": "ST-IDEM", "name": "Gia vuota"},
)
sid = created.json()["id"]
resp = await client.delete(
f"/api/stations/{sid}/recipes", headers=auth_headers(admin_user),
)
assert resp.status_code == 200
assert resp.json()["removed"] == 0
async def test_reset_station_non_admin_is_403(
client: AsyncClient, admin_user, maker_user,
):
created = await client.post(
"/api/stations",
headers=auth_headers(admin_user),
json={"code": "ST-RBAC", "name": "Protetta"},
)
sid = created.json()["id"]
resp = await client.delete(
f"/api/stations/{sid}/recipes", headers=auth_headers(maker_user),
)
assert resp.status_code == 403
async def test_reset_unknown_station_is_404(client: AsyncClient, admin_user):
resp = await client.delete(
"/api/stations/999999/recipes", headers=auth_headers(admin_user),
)
assert resp.status_code == 404
@@ -220,3 +220,14 @@ def api_unassign_recipe(station_id: int, recipe_id: int):
if isinstance(resp, dict) and resp.get("error"): if isinstance(resp, dict) and resp.get("error"):
return jsonify(resp), resp.get("status_code", 500) return jsonify(resp), resp.get("status_code", 500)
return jsonify({"deleted": True}), 200 return jsonify({"deleted": True}), 200
@admin_bp.route("/api/stations/<int:station_id>/recipes", methods=["DELETE"])
@login_required
@admin_required
def api_reset_station_recipes(station_id: int):
"""Proxy: Clear every recipe assignment of a station."""
resp = api_client.delete(f"/api/stations/{station_id}/recipes")
if isinstance(resp, dict) and resp.get("error"):
return jsonify(resp), resp.get("status_code", 500)
return jsonify(resp), 200
+64 -4
View File
@@ -12,6 +12,61 @@ from services.file_proxy import proxy_file
measure_bp = Blueprint("measure", __name__) measure_bp = Blueprint("measure", __name__)
# Session key holding a station chosen at runtime, overriding Config.STATION_CODE.
STATION_OVERRIDE_KEY = "station_override"
def _current_station() -> tuple[str | None, bool]:
"""Return the station this client acts as, and whether it is an override."""
override = session.get(STATION_OVERRIDE_KEY)
if override:
return override, True
return Config.STATION_CODE, False
def _apply_station_switch() -> None:
"""Honour ?station=CODE, used to exercise several stations from one PC.
Only active when STATION_SWITCH_ENABLED is set: in production the station
identity comes from the local install, and silently measuring against another
station's recipes would break traceability. An empty value clears the override
and falls back to the configured station.
The requested code is validated against the server before being stored, so a
typo leaves the operator on the current station with an explanation rather
than stranded on a station that does not exist.
"""
if "station" not in request.args:
return
requested = (request.args.get("station") or "").strip().upper()
if not Config.STATION_SWITCH_ENABLED:
flash(_("Il cambio stazione da URL non è abilitato su questa postazione."), "error")
return
if not requested:
if session.pop(STATION_OVERRIDE_KEY, None):
flash(_("Stazione riportata a quella configurata."), "info")
return
try:
probe = api_client.get_station_recipes(requested)
except Exception:
flash(_("Impossibile contattare il server per cambiare stazione."), "error")
return
if isinstance(probe, dict) and probe.get("error"):
flash(
_("Stazione '%(code)s' inesistente o disattivata: stazione invariata.",
code=requested),
"error",
)
return
session[STATION_OVERRIDE_KEY] = requested
flash(_("Stazione corrente: %(code)s", code=requested), "info")
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Route: Recipe selection # Route: Recipe selection
@@ -21,13 +76,16 @@ measure_bp = Blueprint("measure", __name__)
@role_required("MeasurementTec") @role_required("MeasurementTec")
def select_recipe(): def select_recipe():
"""Recipe selection page with search and barcode support.""" """Recipe selection page with search and barcode support."""
# Fail-fast if STATION_CODE is not configured _apply_station_switch()
if not Config.STATION_CODE: station_code, station_overridden = _current_station()
# Fail-fast if no station is configured and none was chosen
if not station_code:
return render_template("errors/station_not_configured.html"), 503 return render_template("errors/station_not_configured.html"), 503
# Load recipes filtered by station # Load recipes filtered by station
try: try:
resp = api_client.get_station_recipes(Config.STATION_CODE) resp = api_client.get_station_recipes(station_code)
except Exception as e: except Exception as e:
return render_template( return render_template(
"errors/station_not_configured.html", error=str(e), "errors/station_not_configured.html", error=str(e),
@@ -52,7 +110,9 @@ def select_recipe():
return render_template( return render_template(
"measure/select_recipe.html", "measure/select_recipe.html",
recipes=recipes, recipes=recipes,
station_code=Config.STATION_CODE, station_code=station_code,
station_overridden=station_overridden,
station_configured=Config.STATION_CODE,
auto_recipe_code=auto_recipe_code, auto_recipe_code=auto_recipe_code,
auto_lot=auto_lot, auto_lot=auto_lot,
auto_serial=auto_serial, auto_serial=auto_serial,
+8
View File
@@ -26,6 +26,14 @@ class Config:
# code it belongs to. Empty/None means "not configured". # code it belongs to. Empty/None means "not configured".
STATION_CODE: str | None = os.getenv("STATION_CODE") or None STATION_CODE: str | None = os.getenv("STATION_CODE") or None
# Allow switching the current station from the URL (?station=CODE), keeping the
# override in the session. Meant for commissioning: it lets one PC exercise
# several stations instead of needing one machine per station.
# Off by default - on the shop floor the station identity comes from the local
# install, and measuring against the wrong station's recipes would silently
# break traceability.
STATION_SWITCH_ENABLED: bool = os.getenv("STATION_SWITCH_ENABLED", "0") == "1"
# Babel i18n # Babel i18n
BABEL_DEFAULT_LOCALE = "it" BABEL_DEFAULT_LOCALE = "it"
BABEL_DEFAULT_TIMEZONE = "Europe/Rome" BABEL_DEFAULT_TIMEZONE = "Europe/Rome"
@@ -49,6 +49,7 @@
<th class="text-left px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">{{ _('Codice') }}</th> <th class="text-left px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">{{ _('Codice') }}</th>
<th class="text-left px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">{{ _('Nome') }}</th> <th class="text-left px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">{{ _('Nome') }}</th>
<th class="text-left px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider hidden md:table-cell">{{ _('Postazione') }}</th> <th class="text-left px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider hidden md:table-cell">{{ _('Postazione') }}</th>
<th class="text-left px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider hidden lg:table-cell">{{ _('Ricette collegate') }}</th>
<th class="text-center px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">{{ _('Stato') }}</th> <th class="text-center px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">{{ _('Stato') }}</th>
<th class="text-right px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">{{ _('Azioni') }}</th> <th class="text-right px-4 py-3 text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">{{ _('Azioni') }}</th>
</tr> </tr>
@@ -62,6 +63,24 @@
</td> </td>
<td class="px-4 py-3 text-sm text-[var(--text-primary)]" x-text="station.name"></td> <td class="px-4 py-3 text-sm text-[var(--text-primary)]" x-text="station.name"></td>
<td class="px-4 py-3 text-sm text-[var(--text-secondary)] hidden md:table-cell" x-text="station.location || '-'"></td> <td class="px-4 py-3 text-sm text-[var(--text-secondary)] hidden md:table-cell" x-text="station.location || '-'"></td>
<td class="px-4 py-3 hidden lg:table-cell">
<template x-if="!(station.recipes && station.recipes.length)">
<span class="text-xs italic text-[var(--text-secondary)]">{{ _('Nessuna ricetta') }}</span>
</template>
<template x-if="station.recipes && station.recipes.length">
<div class="flex flex-wrap items-center gap-1">
<template x-for="r in station.recipes.slice(0, 3)" :key="r.id">
<span class="inline-flex px-1.5 py-0.5 rounded font-mono text-[11px] font-medium
bg-primary-50 dark:bg-primary-900/20 text-primary"
:title="r.name" x-text="r.code"></span>
</template>
<template x-if="station.recipes.length > 3">
<span class="text-[11px] text-[var(--text-secondary)]"
x-text="'+' + (station.recipes.length - 3)"></span>
</template>
</div>
</template>
</td>
<td class="px-4 py-3 text-center"> <td class="px-4 py-3 text-center">
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-[11px] font-medium" <span class="inline-flex items-center px-2 py-0.5 rounded-full text-[11px] font-medium"
:class="station.active :class="station.active
@@ -78,6 +97,17 @@
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/> <path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>
</svg> </svg>
</button> </button>
<button @click="confirmReset(station)"
:disabled="!(station.recipes && station.recipes.length)"
class="p-1.5 rounded-lg text-[var(--text-secondary)] hover:text-amber-600 hover:bg-amber-50 dark:hover:bg-amber-900/20 transition-colors
disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:text-[var(--text-secondary)] disabled:hover:bg-transparent"
:title="(station.recipes && station.recipes.length)
? '{{ _('Azzera le ricette della stazione') }}'
: '{{ _('Nessuna ricetta da azzerare') }}'">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992V4.356m-.582 9.66a8.25 8.25 0 01-15.356 2.008M3.985 14.652h4.992v4.992m.581-9.66a8.25 8.25 0 0115.356-2.008"/>
</svg>
</button>
<button @click="openEditModal(station)" <button @click="openEditModal(station)"
class="p-1.5 rounded-lg text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20 transition-colors" class="p-1.5 rounded-lg text-[var(--text-secondary)] hover:text-primary hover:bg-primary-50 dark:hover:bg-primary-900/20 transition-colors"
:title="'{{ _('Modifica') }}'"> :title="'{{ _('Modifica') }}'">
@@ -335,6 +365,38 @@
</div> </div>
</div> </div>
<!-- Confirm Reset Modal -->
<div x-show="showResetConfirm" x-cloak
class="fixed inset-0 z-50 flex items-center justify-center p-4"
@keydown.escape.window="showResetConfirm = false">
<div class="absolute inset-0 bg-black/50" @click="showResetConfirm = false"></div>
<div x-show="showResetConfirm"
x-transition
class="relative bg-[var(--bg-card)] rounded-xl border border-[var(--border-color)] shadow-xl w-full max-w-sm p-6">
<h3 class="text-lg font-semibold text-[var(--text-primary)] mb-2">{{ _('Azzera Stazione') }}</h3>
<p class="text-sm text-[var(--text-secondary)] mb-4">
{{ _('Rimuovere tutte le ricette assegnate a') }}
<strong x-text="resetTarget?.code"></strong>?
<br>
<span class="text-xs text-[var(--text-secondary)]">
<span x-text="resetTarget?.recipes?.length || 0"></span>
{{ _('assegnazioni verranno rimosse. La stazione resta, e si potrà riassegnare.') }}
</span>
</p>
<div class="flex justify-end gap-3">
<button @click="showResetConfirm = false"
class="px-4 py-2 text-sm font-medium text-[var(--text-secondary)] rounded-lg hover:bg-[var(--bg-secondary)] transition-colors">
{{ _('Annulla') }}
</button>
<button @click="performReset()"
:disabled="saving"
class="px-4 py-2 text-sm font-medium text-white rounded-lg shadow-sm bg-amber-600 hover:bg-amber-700 disabled:opacity-50 transition-colors">
{{ _('Azzera') }}
</button>
</div>
</div>
</div>
<!-- Confirm Delete Modal --> <!-- Confirm Delete Modal -->
<div x-show="showDeleteConfirm" x-cloak <div x-show="showDeleteConfirm" x-cloak
class="fixed inset-0 z-50 flex items-center justify-center p-4"> class="fixed inset-0 z-50 flex items-center justify-center p-4">
@@ -375,11 +437,13 @@ function stationManagement(initialStations, initialRecipes) {
showModal: false, showModal: false,
showAssignments: false, showAssignments: false,
showDeleteConfirm: false, showDeleteConfirm: false,
showResetConfirm: false,
isEditing: false, isEditing: false,
editingId: null, editingId: null,
saving: false, saving: false,
errorMsg: '', errorMsg: '',
deleteTarget: null, deleteTarget: null,
resetTarget: null,
assignmentStation: null, assignmentStation: null,
assignedRecipes: [], assignedRecipes: [],
recipeSearch: '', recipeSearch: '',
@@ -486,7 +550,9 @@ function stationManagement(initialStations, initialRecipes) {
return; return;
} }
const idx = this.stations.findIndex(s => s.id === this.editingId); const idx = this.stations.findIndex(s => s.id === this.editingId);
if (idx >= 0) this.stations[idx] = result; // PUT returns the station without its assignments; keep the ones the
// row already knows about or the "ricette collegate" column blanks out.
if (idx >= 0) this.stations[idx] = { ...result, recipes: this.stations[idx].recipes || [] };
} else { } else {
if (!this.form.code || !this.form.name) { if (!this.form.code || !this.form.name) {
this.errorMsg = '{{ _("Codice e nome sono obbligatori") }}'; this.errorMsg = '{{ _("Codice e nome sono obbligatori") }}';
@@ -509,7 +575,7 @@ function stationManagement(initialStations, initialRecipes) {
this.errorMsg = result.detail || '{{ _("Errore nella creazione") }}'; this.errorMsg = result.detail || '{{ _("Errore nella creazione") }}';
return; return;
} }
this.stations.push(result); this.stations.push({ ...result, recipes: [] });
} }
this.closeModal(); this.closeModal();
} catch (e) { } catch (e) {
@@ -524,6 +590,40 @@ function stationManagement(initialStations, initialRecipes) {
this.showDeleteConfirm = true; this.showDeleteConfirm = true;
}, },
confirmReset(station) {
if (!station.recipes || station.recipes.length === 0) return;
this.resetTarget = station;
this.showResetConfirm = true;
},
async performReset() {
if (!this.resetTarget) return;
this.saving = true;
try {
const resp = await fetch(`/admin/api/stations/${this.resetTarget.id}/recipes`, {
method: 'DELETE',
headers: { 'X-CSRFToken': this.csrfToken },
});
if (!resp.ok) {
const result = await resp.json().catch(() => ({}));
alert(result.detail || '{{ _("Errore nell azzeramento") }}');
return;
}
// resetTarget is the same object the row renders, so clearing it here
// updates the chips column without reloading the page.
this.resetTarget.recipes = [];
if (this.assignmentStation && this.assignmentStation.id === this.resetTarget.id) {
this.assignedRecipes = [];
}
this.showResetConfirm = false;
this.resetTarget = null;
} catch (e) {
alert('{{ _("Errore di connessione al server") }}');
} finally {
this.saving = false;
}
},
async performDelete() { async performDelete() {
if (!this.deleteTarget) return; if (!this.deleteTarget) return;
this.saving = true; this.saving = true;
@@ -591,7 +691,11 @@ function stationManagement(initialStations, initialRecipes) {
return; return;
} }
const recipe = this.allRecipes.find(r => r.id === id); const recipe = this.allRecipes.find(r => r.id === id);
if (recipe) this.assignedRecipes.push({ id: recipe.id, code: recipe.code, name: recipe.name, active: recipe.active }); if (recipe) {
const summary = { id: recipe.id, code: recipe.code, name: recipe.name, active: recipe.active };
this.assignedRecipes.push(summary);
this._syncStationRecipes();
}
} catch (e) { } catch (e) {
this.errorMsg = '{{ _("Errore di connessione al server") }}'; this.errorMsg = '{{ _("Errore di connessione al server") }}';
} finally { } finally {
@@ -614,12 +718,23 @@ function stationManagement(initialStations, initialRecipes) {
return; return;
} }
this.assignedRecipes = this.assignedRecipes.filter(r => r.id !== recipeId); this.assignedRecipes = this.assignedRecipes.filter(r => r.id !== recipeId);
this._syncStationRecipes();
} catch (e) { } catch (e) {
this.errorMsg = '{{ _("Errore di connessione al server") }}'; this.errorMsg = '{{ _("Errore di connessione al server") }}';
} finally { } finally {
this.saving = false; this.saving = false;
} }
}, },
/* Mirror the modal's assignment list onto the table row, so the chips in
"ricette collegate" stay true after assigning or unassigning. Sorted by
code to match the order the server returns. */
_syncStationRecipes() {
if (!this.assignmentStation) return;
this.assignmentStation.recipes = [...this.assignedRecipes]
.filter(r => r.active !== false)
.sort((a, b) => (a.code || '').localeCompare(b.code || ''));
},
}; };
} }
</script> </script>
@@ -78,6 +78,23 @@
<p class="mt-1 text-sm text-steel-500 dark:text-steel-400"> <p class="mt-1 text-sm text-steel-500 dark:text-steel-400">
{{ _('Stazione') }}: <span class="font-mono font-bold">{{ station_code }}</span> {{ _('Stazione') }}: <span class="font-mono font-bold">{{ station_code }}</span>
</p> </p>
{% if station_overridden %}
<p class="mt-2 inline-flex flex-wrap items-center gap-2 px-2.5 py-1 rounded-lg
bg-amber-50 dark:bg-amber-900/20 border border-amber-300 dark:border-amber-700
text-xs text-amber-800 dark:text-amber-200">
<svg class="w-4 h-4 shrink-0" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"/>
</svg>
<span>
{{ _('Stazione forzata per collaudo') }}{% if station_configured %} — {{ _('configurata') }}:
<span class="font-mono">{{ station_configured }}</span>{% endif %}
</span>
<a href="{{ url_for('measure.select_recipe', station='') }}"
class="font-medium underline underline-offset-2 hover:no-underline">
{{ _('Ripristina') }}
</a>
</p>
{% endif %}
</div> </div>
</div> </div>
@@ -132,3 +132,47 @@ def test_non_admin_cannot_access(client, mock_admin_api):
sess["user_id"] = 2 sess["user_id"] = 2
resp = client.get("/admin/stations", follow_redirects=False) resp = client.get("/admin/stations", follow_redirects=False)
assert resp.status_code in (301, 302) assert resp.status_code in (301, 302)
# ---------------------------------------------------------------------------
# Per-row station reset (point 7)
# ---------------------------------------------------------------------------
def test_reset_station_proxy(logged_in_client, mock_admin_api):
mock_admin_api.delete.return_value = {"station_id": 3, "removed": 2}
resp = logged_in_client.delete("/admin/api/stations/3/recipes")
assert resp.status_code == 200
assert resp.get_json() == {"station_id": 3, "removed": 2}
mock_admin_api.delete.assert_called_once_with("/api/stations/3/recipes")
def test_reset_station_propagates_error(logged_in_client, mock_admin_api):
mock_admin_api.delete.return_value = {
"error": True, "status_code": 404, "detail": "Station not found",
}
resp = logged_in_client.delete("/admin/api/stations/999/recipes")
assert resp.status_code == 404
def test_reset_station_distinct_from_single_unassign(logged_in_client, mock_admin_api):
"""The collection route must not swallow the per-recipe delete."""
mock_admin_api.delete.return_value = {}
logged_in_client.delete("/admin/api/stations/3/recipes/7")
mock_admin_api.delete.assert_called_once_with("/api/stations/3/recipes/7")
def test_station_list_page_renders_assigned_recipes(logged_in_client, mock_admin_api):
"""Recipes assigned to a station reach the page so the row can show them."""
mock_admin_api.get.side_effect = [
[{
"id": 1, "code": "ST-001", "name": "Linea A", "location": "Reparto A",
"notes": None, "active": True, "created_by": 1,
"created_at": "2026-04-25T10:00:00",
"recipes": [{"id": 9, "code": "REC-ABC", "name": "Perno", "active": True}],
}],
[{"id": 9, "code": "REC-ABC", "name": "Perno", "active": True}],
]
resp = logged_in_client.get("/admin/stations")
assert resp.status_code == 200
assert b"REC-ABC" in resp.data
@@ -2,13 +2,32 @@
import importlib import importlib
from unittest.mock import patch, MagicMock from unittest.mock import patch, MagicMock
import pytest
def _reload_measure(monkeypatch, station_code=None):
"""Reload config and measure module under the given STATION_CODE env.""" @pytest.fixture(autouse=True)
def _restore_measure_module():
"""Reload config/measure after each test so env tweaks don't leak.
Reloading runs the module body in its existing namespace, so the view
functions already registered on the app see the refreshed globals. Without
this teardown a station code set here would stay visible to later tests.
Autouse fixtures tear down after monkeypatch, so the env is pristine by then.
"""
yield
import config
importlib.reload(config)
import blueprints.measure
importlib.reload(blueprints.measure)
def _reload_measure(monkeypatch, station_code=None, switch_enabled=False):
"""Reload config and measure module under the given station env."""
if station_code is None: if station_code is None:
monkeypatch.delenv("STATION_CODE", raising=False) monkeypatch.delenv("STATION_CODE", raising=False)
else: else:
monkeypatch.setenv("STATION_CODE", station_code) monkeypatch.setenv("STATION_CODE", station_code)
monkeypatch.setenv("STATION_SWITCH_ENABLED", "1" if switch_enabled else "0")
import config import config
importlib.reload(config) importlib.reload(config)
import blueprints.measure import blueprints.measure
@@ -35,3 +54,100 @@ def test_select_recipe_without_station_code_shows_error(logged_in_client, monkey
assert resp.status_code == 503 assert resp.status_code == 503
body = resp.data.lower() body = resp.data.lower()
assert b"station_code" in body or b"stazione" in body assert b"station_code" in body or b"stazione" in body
# ---------------------------------------------------------------------------
# Switching the current station from the URL (point 7)
# ---------------------------------------------------------------------------
def _station_calls(mock_api):
"""Station codes passed to get_station_recipes, in order."""
return [c.args[0] for c in mock_api.get_station_recipes.call_args_list]
def test_station_switch_ignored_when_disabled(logged_in_client, monkeypatch):
"""Off by default: on the shop floor the station comes from the install."""
_reload_measure(monkeypatch, station_code="ST-CONF", switch_enabled=False)
from blueprints import measure as measure_mod
with patch.object(measure_mod, "api_client") as mock_api:
mock_api.get_station_recipes.return_value = []
resp = logged_in_client.get("/measure/select?station=ST-OTHER")
assert resp.status_code == 200
# The requested station is never even probed.
assert _station_calls(mock_api) == ["ST-CONF"]
def test_station_switch_applies_when_enabled(logged_in_client, monkeypatch):
_reload_measure(monkeypatch, station_code="ST-CONF", switch_enabled=True)
from blueprints import measure as measure_mod
with patch.object(measure_mod, "api_client") as mock_api:
mock_api.get_station_recipes.return_value = []
resp = logged_in_client.get("/measure/select?station=ST-OTHER")
assert resp.status_code == 200
# Probed first to validate, then used to load the recipes.
assert _station_calls(mock_api) == ["ST-OTHER", "ST-OTHER"]
assert b"ST-OTHER" in resp.data
def test_station_switch_survives_next_request(logged_in_client, monkeypatch):
"""The override lives in the session, so it holds without repeating the param."""
_reload_measure(monkeypatch, station_code="ST-CONF", switch_enabled=True)
from blueprints import measure as measure_mod
with patch.object(measure_mod, "api_client") as mock_api:
mock_api.get_station_recipes.return_value = []
logged_in_client.get("/measure/select?station=ST-OTHER")
mock_api.get_station_recipes.reset_mock()
resp = logged_in_client.get("/measure/select")
assert resp.status_code == 200
assert _station_calls(mock_api) == ["ST-OTHER"]
def test_station_switch_rejects_unknown_code(logged_in_client, monkeypatch):
"""A typo must not strand the operator on a station that does not exist."""
_reload_measure(monkeypatch, station_code="ST-CONF", switch_enabled=True)
from blueprints import measure as measure_mod
with patch.object(measure_mod, "api_client") as mock_api:
mock_api.get_station_recipes.side_effect = [
{"error": True, "status_code": 404, "detail": "Station not found"},
[],
]
resp = logged_in_client.get("/measure/select?station=ST-NOPE")
assert resp.status_code == 200
# Probed, refused, then fell back to the configured station.
assert _station_calls(mock_api) == ["ST-NOPE", "ST-CONF"]
assert b"ST-CONF" in resp.data
def test_station_switch_can_be_cleared(logged_in_client, monkeypatch):
_reload_measure(monkeypatch, station_code="ST-CONF", switch_enabled=True)
from blueprints import measure as measure_mod
with patch.object(measure_mod, "api_client") as mock_api:
mock_api.get_station_recipes.return_value = []
logged_in_client.get("/measure/select?station=ST-OTHER")
mock_api.get_station_recipes.reset_mock()
resp = logged_in_client.get("/measure/select?station=")
assert resp.status_code == 200
assert _station_calls(mock_api) == ["ST-CONF"]
def test_station_switch_is_signalled_in_the_page(logged_in_client, monkeypatch):
"""An override must never be silent: wrong-station measurements are untraceable."""
_reload_measure(monkeypatch, station_code="ST-CONF", switch_enabled=True)
from blueprints import measure as measure_mod
with patch.object(measure_mod, "api_client") as mock_api:
mock_api.get_station_recipes.return_value = []
resp = logged_in_client.get("/measure/select?station=ST-OTHER")
body = resp.data.decode()
assert "ST-OTHER" in body
# The configured station is named so the deviation is obvious.
assert "ST-CONF" in body
def test_station_switch_normalises_case(logged_in_client, monkeypatch):
_reload_measure(monkeypatch, station_code="ST-CONF", switch_enabled=True)
from blueprints import measure as measure_mod
with patch.object(measure_mod, "api_client") as mock_api:
mock_api.get_station_recipes.return_value = []
logged_in_client.get("/measure/select?station=st-other")
assert _station_calls(mock_api) == ["ST-OTHER", "ST-OTHER"]
@@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: TieMeasureFlow 1.0\n" "Project-Id-Version: TieMeasureFlow 1.0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-06-11 15:33+0000\n" "POT-Creation-Date: 2026-07-28 15:24+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n" "Language: en\n"
@@ -37,7 +37,7 @@ msgstr "Please log in to continue"
msgid "Inserisci username e password" msgid "Inserisci username e password"
msgstr "Enter username and password" msgstr "Enter username and password"
#: blueprints/auth.py:81 blueprints/measure.py:346 #: blueprints/auth.py:81 blueprints/measure.py:407
msgid "Credenziali non valide" msgid "Credenziali non valide"
msgstr "Invalid credentials" msgstr "Invalid credentials"
@@ -101,65 +101,87 @@ msgstr "No file uploaded"
msgid "Nome file vuoto" msgid "Nome file vuoto"
msgstr "Empty file name" msgstr "Empty file name"
#: blueprints/measure.py:45
msgid "Il cambio stazione da URL non è abilitato su questa postazione."
msgstr "Switching station from the URL is not enabled on this workstation."
#: blueprints/measure.py:50
msgid "Stazione riportata a quella configurata."
msgstr "Station restored to the configured one."
#: blueprints/measure.py:56
msgid "Impossibile contattare il server per cambiare stazione."
msgstr "Could not reach the server to switch station."
#: blueprints/measure.py:61
#, python-format
msgid "Stazione '%(code)s' inesistente o disattivata: stazione invariata."
msgstr "Station '%(code)s' does not exist or is disabled: station unchanged."
#: blueprints/measure.py:68
#, python-format
msgid "Stazione corrente: %(code)s"
msgstr "Current station: %(code)s"
# Measure - API Errors # Measure - API Errors
#: blueprints/measure.py:38 #: blueprints/measure.py:96
#, python-format #, python-format
msgid "Errore nel caricamento delle ricette: %(detail)s" msgid "Errore nel caricamento delle ricette: %(detail)s"
msgstr "Error loading recipes: %(detail)s" msgstr "Error loading recipes: %(detail)s"
#: blueprints/measure.py:86 blueprints/measure.py:172 #: blueprints/measure.py:146 blueprints/measure.py:232
#, python-format #, python-format
msgid "Ricetta non trovata: %(detail)s" msgid "Ricetta non trovata: %(detail)s"
msgstr "Recipe not found: %(detail)s" msgstr "Recipe not found: %(detail)s"
#: blueprints/measure.py:96 #: blueprints/measure.py:156
#, python-format #, python-format
msgid "Errore nel caricamento dei task: %(detail)s" msgid "Errore nel caricamento dei task: %(detail)s"
msgstr "Error loading tasks: %(detail)s" msgstr "Error loading tasks: %(detail)s"
#: blueprints/measure.py:125 #: blueprints/measure.py:185
#, python-format #, python-format
msgid "Task non trovato: %(detail)s" msgid "Task non trovato: %(detail)s"
msgstr "Task not found: %(detail)s" msgstr "Task not found: %(detail)s"
#: blueprints/measure.py:241 #: blueprints/measure.py:301
msgid "Codice non fornito" msgid "Codice non fornito"
msgstr "Code not provided" msgstr "Code not provided"
#: blueprints/measure.py:247 templates/measure/select_recipe.html:48 #: blueprints/measure.py:307 templates/measure/select_recipe.html:48
msgid "Ricetta non trovata" msgid "Ricetta non trovata"
msgstr "Recipe not found" msgstr "Recipe not found"
#: blueprints/measure.py:303 #: blueprints/measure.py:363
msgid "Dati mancanti: subtask_id, version_id e value sono obbligatori" msgid "Dati mancanti: subtask_id, version_id e value sono obbligatori"
msgstr "Missing data: subtask_id, version_id and value are required" msgstr "Missing data: subtask_id, version_id and value are required"
#: blueprints/measure.py:322 templates/admin/stations.html:485 #: blueprints/measure.py:383 templates/admin/stations.html:549
#: templates/maker/recipe_editor.html:543 #: templates/maker/recipe_editor.html:543
msgid "Errore nel salvataggio" msgid "Errore nel salvataggio"
msgstr "Error saving" msgstr "Error saving"
#: blueprints/measure.py:341 #: blueprints/measure.py:402
msgid "Username e password richiesti" msgid "Username e password richiesti"
msgstr "Username and password required" msgstr "Username and password required"
#: blueprints/measure.py:351 #: blueprints/measure.py:412
msgid "Utente non autorizzato (richiesto capoturno)" msgid "Utente non autorizzato (richiesto capoturno)"
msgstr "User not authorized (shift supervisor required)" msgstr "User not authorized (shift supervisor required)"
#: templates/base.html:175 #: templates/base.html:173
msgid "Sessione in scadenza" msgid "Sessione in scadenza"
msgstr "Session expiring" msgstr "Session expiring"
#: templates/base.html:178 #: templates/base.html:176
msgid "Sarai disconnesso tra" msgid "Sarai disconnesso tra"
msgstr "You will be logged out in" msgstr "You will be logged out in"
#: templates/base.html:178 #: templates/base.html:176
msgid "secondi per inattività." msgid "secondi per inattività."
msgstr "seconds due to inactivity." msgstr "seconds due to inactivity."
#: templates/base.html:181 #: templates/base.html:179
msgid "Continua a lavorare" msgid "Continua a lavorare"
msgstr "Keep working" msgstr "Keep working"
@@ -203,16 +225,16 @@ msgstr "Saved"
msgid "Salva impostazioni" msgid "Salva impostazioni"
msgstr "Save settings" msgstr "Save settings"
#: templates/admin/settings.html:107 templates/admin/stations.html:516 #: templates/admin/settings.html:107 templates/admin/stations.html:582
#: templates/admin/stations.html:544 templates/admin/stations.html:565 #: templates/admin/stations.html:621 templates/admin/stations.html:644
#: templates/admin/stations.html:596 templates/admin/stations.html:618 #: templates/admin/stations.html:665 templates/admin/stations.html:700
#: templates/admin/users.html:497 templates/admin/users.html:533 #: templates/admin/stations.html:723 templates/admin/users.html:497
#: templates/maker/recipe_editor.html:571 templates/maker/task_drawing.html:65 #: templates/admin/users.html:533 templates/maker/recipe_editor.html:571
#: templates/maker/task_editor.html:1243 templates/maker/task_editor.html:1321 #: templates/maker/task_drawing.html:65 templates/maker/task_editor.html:1243
#: templates/maker/task_editor.html:1382 templates/maker/task_editor.html:1415 #: templates/maker/task_editor.html:1321 templates/maker/task_editor.html:1382
#: templates/maker/task_editor.html:1510 templates/maker/task_editor.html:1586 #: templates/maker/task_editor.html:1415 templates/maker/task_editor.html:1510
#: templates/maker/task_editor.html:1660 templates/maker/task_editor.html:1697 #: templates/maker/task_editor.html:1586 templates/maker/task_editor.html:1660
#: templates/maker/task_editor.html:1776 #: templates/maker/task_editor.html:1697 templates/maker/task_editor.html:1776
#: templates/statistics/dashboard.html:372 #: templates/statistics/dashboard.html:372
#: templates/statistics/dashboard.html:457 #: templates/statistics/dashboard.html:457
msgid "Errore di connessione al server" msgid "Errore di connessione al server"
@@ -232,209 +254,245 @@ msgstr "Create, edit and manage measurement stations and their assigned recipes"
msgid "Cerca stazione..." msgid "Cerca stazione..."
msgstr "Search station..." msgstr "Search station..."
#: templates/admin/stations.html:39 templates/admin/stations.html:133 #: templates/admin/stations.html:39 templates/admin/stations.html:163
msgid "Nuova Stazione" msgid "Nuova Stazione"
msgstr "New Station" msgstr "New Station"
# Task Complete Page # Task Complete Page
#: templates/admin/stations.html:49 templates/admin/stations.html:143 #: templates/admin/stations.html:49 templates/admin/stations.html:173
#: templates/maker/recipe_editor.html:195 #: templates/maker/recipe_editor.html:195
#: templates/measure/task_complete.html:49 #: templates/measure/task_complete.html:49
msgid "Codice" msgid "Codice"
msgstr "Code" msgstr "Code"
#: templates/admin/stations.html:50 templates/admin/stations.html:160 #: templates/admin/stations.html:50 templates/admin/stations.html:190
#: templates/maker/recipe_editor.html:213 #: templates/maker/recipe_editor.html:213
#: templates/measure/task_complete.html:53 #: templates/measure/task_complete.html:53
msgid "Nome" msgid "Nome"
msgstr "Name" msgstr "Name"
#: templates/admin/stations.html:51 templates/admin/stations.html:169 #: templates/admin/stations.html:51 templates/admin/stations.html:199
msgid "Postazione" msgid "Postazione"
msgstr "Location" msgstr "Location"
#: templates/admin/stations.html:52 templates/admin/users.html:52 #: templates/admin/stations.html:52
msgid "Ricette collegate"
msgstr "Assigned recipes"
#: templates/admin/stations.html:53 templates/admin/users.html:52
#: templates/measure/task_complete.html:292 #: templates/measure/task_complete.html:292
msgid "Stato" msgid "Stato"
msgstr "Status" msgstr "Status"
#: templates/admin/stations.html:53 templates/admin/users.html:53 #: templates/admin/stations.html:54 templates/admin/users.html:53
#: templates/maker/task_editor.html:551 #: templates/maker/task_editor.html:551
msgid "Azioni" msgid "Azioni"
msgstr "Actions" msgstr "Actions"
#: templates/admin/stations.html:70 templates/admin/stations.html:189 #: templates/admin/stations.html:68
msgid "Nessuna ricetta"
msgstr "No recipes"
#: templates/admin/stations.html:89 templates/admin/stations.html:219
#: templates/maker/recipe_list.html:186 #: templates/maker/recipe_list.html:186
msgid "Attiva" msgid "Attiva"
msgstr "Active" msgstr "Active"
#: templates/admin/stations.html:70 templates/maker/recipe_list.html:186 #: templates/admin/stations.html:89 templates/maker/recipe_list.html:186
msgid "Disattivata" msgid "Disattivata"
msgstr "Inactive" msgstr "Inactive"
# Maker - Recipe List # Maker - Recipe List
#: templates/admin/stations.html:76 #: templates/admin/stations.html:95
msgid "Gestisci ricette" msgid "Gestisci ricette"
msgstr "Manage recipes" msgstr "Manage recipes"
#: templates/admin/stations.html:83 templates/admin/users.html:100 #: templates/admin/stations.html:105
msgid "Azzera le ricette della stazione"
msgstr "Clear the station's recipes"
#: templates/admin/stations.html:106
msgid "Nessuna ricetta da azzerare"
msgstr "No recipes to clear"
#: templates/admin/stations.html:113 templates/admin/users.html:100
#: templates/maker/recipe_list.html:237 templates/maker/task_editor.html:602 #: templates/maker/recipe_list.html:237 templates/maker/task_editor.html:602
msgid "Modifica" msgid "Modifica"
msgstr "Edit" msgstr "Edit"
#: templates/admin/stations.html:90 templates/admin/stations.html:359 #: templates/admin/stations.html:120 templates/admin/stations.html:421
#: templates/maker/recipe_list.html:277 templates/maker/recipe_list.html:387 #: templates/maker/recipe_list.html:277 templates/maker/recipe_list.html:387
#: templates/maker/task_drawing.html:275 templates/maker/task_editor.html:610 #: templates/maker/task_drawing.html:275 templates/maker/task_editor.html:610
msgid "Elimina" msgid "Elimina"
msgstr "Delete" msgstr "Delete"
#: templates/admin/stations.html:108 #: templates/admin/stations.html:138
msgid "Nessuna stazione trovata" msgid "Nessuna stazione trovata"
msgstr "No stations found" msgstr "No stations found"
#: templates/admin/stations.html:114 #: templates/admin/stations.html:144
msgid "stazioni" msgid "stazioni"
msgstr "stations" msgstr "stations"
#: templates/admin/stations.html:133 #: templates/admin/stations.html:163
msgid "Modifica Stazione" msgid "Modifica Stazione"
msgstr "Edit Station" msgstr "Edit Station"
#: templates/admin/stations.html:152 #: templates/admin/stations.html:182
msgid "Il codice non può essere modificato" msgid "Il codice non può essere modificato"
msgstr "Code cannot be modified" msgstr "Code cannot be modified"
#: templates/admin/stations.html:155 #: templates/admin/stations.html:185
msgid "Identificativo univoco usato dal client tramite STATION_CODE" msgid "Identificativo univoco usato dal client tramite STATION_CODE"
msgstr "Unique identifier used by client via STATION_CODE" msgstr "Unique identifier used by client via STATION_CODE"
#: templates/admin/stations.html:164 #: templates/admin/stations.html:194
msgid "Nome descrittivo della stazione" msgid "Nome descrittivo della stazione"
msgstr "Descriptive name of the station" msgstr "Descriptive name of the station"
#: templates/admin/stations.html:173 #: templates/admin/stations.html:203
msgid "Es. Reparto A - Linea 2" msgid "Es. Reparto A - Linea 2"
msgstr "E.g. Department A - Line 2" msgstr "E.g. Department A - Line 2"
#: templates/admin/stations.html:178 #: templates/admin/stations.html:208
msgid "Note" msgid "Note"
msgstr "Notes" msgstr "Notes"
#: templates/admin/stations.html:182 #: templates/admin/stations.html:212
msgid "Note opzionali" msgid "Note opzionali"
msgstr "Optional notes" msgstr "Optional notes"
#: templates/admin/stations.html:204 templates/admin/stations.html:354 #: templates/admin/stations.html:234 templates/admin/stations.html:389
#: templates/admin/users.html:292 templates/admin/users.html:323 #: templates/admin/stations.html:416 templates/admin/users.html:292
#: templates/maker/recipe_editor.html:137 #: templates/admin/users.html:323 templates/maker/recipe_editor.html:137
#: templates/maker/recipe_editor.html:456 templates/maker/recipe_list.html:383 #: templates/maker/recipe_editor.html:456 templates/maker/recipe_list.html:383
#: templates/maker/task_editor.html:294 templates/maker/task_editor.html:403 #: templates/maker/task_editor.html:294 templates/maker/task_editor.html:403
#: templates/maker/task_editor.html:747 templates/maker/task_editor.html:866 #: templates/maker/task_editor.html:747 templates/maker/task_editor.html:866
#: templates/maker/task_editor.html:931 templates/maker/task_editor.html:1036 #: templates/maker/task_editor.html:931 templates/maker/task_editor.html:1036
#: templates/measure/select_recipe.html:350 #: templates/measure/select_recipe.html:367
#: templates/measure/task_execute.html:664 #: templates/measure/task_execute.html:664
msgid "Annulla" msgid "Annulla"
msgstr "Cancel" msgstr "Cancel"
#: templates/admin/stations.html:210 templates/admin/users.html:298 #: templates/admin/stations.html:240 templates/admin/users.html:298
#: templates/auth/profile.html:171 #: templates/auth/profile.html:171
msgid "Salva Modifiche" msgid "Salva Modifiche"
msgstr "Save Changes" msgstr "Save Changes"
#: templates/admin/stations.html:210 #: templates/admin/stations.html:240
msgid "Crea Stazione" msgid "Crea Stazione"
msgstr "Create Station" msgstr "Create Station"
#: templates/admin/stations.html:211 templates/admin/users.html:299 #: templates/admin/stations.html:241 templates/admin/users.html:299
#: templates/maker/recipe_editor.html:107 #: templates/maker/recipe_editor.html:107
#: templates/maker/recipe_editor.html:448 templates/maker/task_drawing.html:61 #: templates/maker/recipe_editor.html:448 templates/maker/task_drawing.html:61
#: templates/measure/task_execute.html:380 #: templates/measure/task_execute.html:380
msgid "Salvataggio..." msgid "Salvataggio..."
msgstr "Saving..." msgstr "Saving..."
#: templates/admin/stations.html:228 #: templates/admin/stations.html:258
msgid "Ricette Assegnate" msgid "Ricette Assegnate"
msgstr "Assigned Recipes" msgstr "Assigned Recipes"
#: templates/admin/stations.html:246 #: templates/admin/stations.html:276
msgid "Filtra per codice o nome ricetta..." msgid "Filtra per codice o nome ricetta..."
msgstr "Filter by recipe code or name..." msgstr "Filter by recipe code or name..."
#: templates/admin/stations.html:259 #: templates/admin/stations.html:289
msgid "Ricette disponibili" msgid "Ricette disponibili"
msgstr "Available recipes" msgstr "Available recipes"
#: templates/admin/stations.html:272 #: templates/admin/stations.html:302
msgid "Assegna a questa stazione" msgid "Assegna a questa stazione"
msgstr "Assign to this station" msgstr "Assign to this station"
#: templates/admin/stations.html:276 #: templates/admin/stations.html:306
msgid "Assegna" msgid "Assegna"
msgstr "Assign" msgstr "Assign"
#: templates/admin/stations.html:293 #: templates/admin/stations.html:323
msgid "Assegnate alla stazione" msgid "Assegnate alla stazione"
msgstr "Assigned to the station" msgstr "Assigned to the station"
#: templates/admin/stations.html:305 #: templates/admin/stations.html:335
msgid "Rimuovi assegnazione" msgid "Rimuovi assegnazione"
msgstr "Remove assignment" msgstr "Remove assignment"
#: templates/admin/stations.html:332 #: templates/admin/stations.html:362
#: templates/components/barcode_scanner.html:145 #: templates/components/barcode_scanner.html:145
msgid "Chiudi" msgid "Chiudi"
msgstr "Close" msgstr "Close"
#: templates/admin/stations.html:345 templates/maker/recipe_list.html:363 #: templates/admin/stations.html:376
msgid "Azzera Stazione"
msgstr "Reset Station"
#: templates/admin/stations.html:378
msgid "Rimuovere tutte le ricette assegnate a"
msgstr "Remove every recipe assigned to"
#: templates/admin/stations.html:383
msgid "assegnazioni verranno rimosse. La stazione resta, e si potrà riassegnare."
msgstr "assignments will be removed. The station stays and can be reassigned."
#: templates/admin/stations.html:394
msgid "Azzera"
msgstr "Reset"
#: templates/admin/stations.html:407 templates/maker/recipe_list.html:363
msgid "Conferma Eliminazione" msgid "Conferma Eliminazione"
msgstr "Confirm Deletion" msgstr "Confirm Deletion"
#: templates/admin/stations.html:347 #: templates/admin/stations.html:409
msgid "Sei sicuro di voler eliminare la stazione" msgid "Sei sicuro di voler eliminare la stazione"
msgstr "Are you sure you want to delete the station" msgstr "Are you sure you want to delete the station"
#: templates/admin/stations.html:349 #: templates/admin/stations.html:411
msgid "Verranno rimosse anche tutte le assegnazioni di ricette." msgid "Verranno rimosse anche tutte le assegnazioni di ricette."
msgstr "All recipe assignments will also be removed." msgstr "All recipe assignments will also be removed."
#: templates/admin/stations.html:430 templates/admin/stations.html:436 #: templates/admin/stations.html:494 templates/admin/stations.html:500
msgid "Nessun risultato per il filtro" msgid "Nessun risultato per il filtro"
msgstr "No results for filter" msgstr "No results for filter"
#: templates/admin/stations.html:431 #: templates/admin/stations.html:495
msgid "Nessuna ricetta nel sistema" msgid "Nessuna ricetta nel sistema"
msgstr "No recipes in system" msgstr "No recipes in system"
#: templates/admin/stations.html:432 #: templates/admin/stations.html:496
msgid "Tutte le ricette sono già assegnate" msgid "Tutte le ricette sono già assegnate"
msgstr "All recipes are already assigned" msgstr "All recipes are already assigned"
#: templates/admin/stations.html:437 #: templates/admin/stations.html:501
msgid "Nessuna ricetta assegnata" msgid "Nessuna ricetta assegnata"
msgstr "No assigned recipes" msgstr "No assigned recipes"
#: templates/admin/stations.html:492 #: templates/admin/stations.html:558
msgid "Codice e nome sono obbligatori" msgid "Codice e nome sono obbligatori"
msgstr "Code and name are required" msgstr "Code and name are required"
#: templates/admin/stations.html:509 #: templates/admin/stations.html:575
msgid "Errore nella creazione" msgid "Errore nella creazione"
msgstr "Error during creation" msgstr "Error during creation"
#: templates/admin/stations.html:537 #: templates/admin/stations.html:609
msgid "Errore nell azzeramento"
msgstr "Error clearing assignments"
#: templates/admin/stations.html:637
msgid "Errore nella eliminazione" msgid "Errore nella eliminazione"
msgstr "Error during deletion" msgstr "Error during deletion"
# Maker - API Errors # Maker - API Errors
#: templates/admin/stations.html:562 #: templates/admin/stations.html:662
msgid "Errore nel caricamento delle ricette" msgid "Errore nel caricamento delle ricette"
msgstr "Error loading recipes" msgstr "Error loading recipes"
#: templates/admin/stations.html:590 #: templates/admin/stations.html:690
msgid "Errore nella assegnazione" msgid "Errore nella assegnazione"
msgstr "Error during assignment" msgstr "Error during assignment"
#: templates/admin/stations.html:613 #: templates/admin/stations.html:717
msgid "Errore nella rimozione" msgid "Errore nella rimozione"
msgstr "Error during removal" msgstr "Error during removal"
@@ -455,8 +513,8 @@ msgid "Nuovo Utente"
msgstr "New User" msgstr "New User"
#: templates/admin/users.html:48 templates/admin/users.html:173 #: templates/admin/users.html:48 templates/admin/users.html:173
#: templates/admin/users.html:179 templates/auth/login.html:33 #: templates/admin/users.html:179 templates/auth/login.html:35
#: templates/auth/login.html:47 templates/auth/profile.html:36 #: templates/auth/login.html:49 templates/auth/profile.html:36
#: templates/measure/task_execute.html:649 #: templates/measure/task_execute.html:649
msgid "Username" msgid "Username"
msgstr "Username" msgstr "Username"
@@ -508,7 +566,7 @@ msgid "Il nome utente non può essere modificato"
msgstr "Username cannot be changed" msgstr "Username cannot be changed"
#: templates/admin/users.html:206 templates/admin/users.html:214 #: templates/admin/users.html:206 templates/admin/users.html:214
#: templates/auth/login.html:55 templates/auth/login.html:69 #: templates/auth/login.html:57 templates/auth/login.html:71
#: templates/measure/task_execute.html:654 #: templates/measure/task_execute.html:654
msgid "Password" msgid "Password"
msgstr "Password" msgstr "Password"
@@ -578,36 +636,36 @@ msgid "Username, nome visualizzato e password sono obbligatori"
msgstr "Username, display name and password are required" msgstr "Username, display name and password are required"
# Login Page # Login Page
#: templates/auth/login.html:23 #: templates/auth/login.html:25
msgid "Accedi al sistema" msgid "Accedi al sistema"
msgstr "Sign in to your account" msgstr "Sign in to your account"
#: templates/auth/login.html:73 #: templates/auth/login.html:75
msgid "Nascondi password" msgid "Nascondi password"
msgstr "Hide password" msgstr "Hide password"
#: templates/auth/login.html:73 #: templates/auth/login.html:75
msgid "Mostra password" msgid "Mostra password"
msgstr "Show password" msgstr "Show password"
#: templates/auth/login.html:94 #: templates/auth/login.html:96
msgid "Accedi" msgid "Accedi"
msgstr "Sign In" msgstr "Sign In"
#: templates/auth/login.html:102 #: templates/auth/login.html:104
msgid "Hai dimenticato la password?" msgid "Hai dimenticato la password?"
msgstr "Forgot password?" msgstr "Forgot password?"
#: templates/auth/login.html:104 #: templates/auth/login.html:106
msgid "Contatta l'amministratore" msgid "Contatta l'amministratore"
msgstr "Contact administrator" msgstr "Contact administrator"
# Additional Login Page # Additional Login Page
#: templates/auth/login.html:111 #: templates/auth/login.html:113
msgid "Sistema di misurazione industriale" msgid "Sistema di misurazione industriale"
msgstr "Industrial measurement system" msgstr "Industrial measurement system"
#: templates/auth/profile.html:2 templates/components/navbar.html:147 #: templates/auth/profile.html:2 templates/components/navbar.html:149
msgid "Profilo" msgid "Profilo"
msgstr "Profile" msgstr "Profile"
@@ -657,15 +715,15 @@ msgstr "Logout from system"
msgid "Termina la sessione corrente e torna alla schermata di login" msgid "Termina la sessione corrente e torna alla schermata di login"
msgstr "End current session and return to login screen" msgstr "End current session and return to login screen"
#: templates/auth/profile.html:197 templates/components/navbar.html:158 #: templates/auth/profile.html:197 templates/components/navbar.html:160
#: templates/components/navbar.html:167 #: templates/components/navbar.html:169
msgid "Logout" msgid "Logout"
msgstr "Logout" msgstr "Logout"
#: templates/components/barcode_scanner.html:21 #: templates/components/barcode_scanner.html:21
#: templates/components/barcode_scanner.html:54 #: templates/components/barcode_scanner.html:54
#: templates/measure/select_recipe.html:90 #: templates/measure/select_recipe.html:107
#: templates/measure/select_recipe.html:302 #: templates/measure/select_recipe.html:319
msgid "Scansiona Barcode" msgid "Scansiona Barcode"
msgstr "Scan Barcode" msgstr "Scan Barcode"
@@ -751,7 +809,7 @@ msgstr "Users"
msgid "Stazioni" msgid "Stazioni"
msgstr "Stations" msgstr "Stations"
#: templates/components/navbar.html:154 #: templates/components/navbar.html:156
msgid "Logout bloccato durante le misurazioni" msgid "Logout bloccato durante le misurazioni"
msgstr "Logout blocked during measurements" msgstr "Logout blocked during measurements"
@@ -954,7 +1012,7 @@ msgstr "Error during deletion"
# Recipe Selection Additional # Recipe Selection Additional
#: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:55 #: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:55
#: templates/measure/task_execute.html:1111 #: templates/measure/task_execute.html:1121
msgid "Errore di connessione" msgid "Errore di connessione"
msgstr "Connection Error" msgstr "Connection Error"
@@ -987,7 +1045,7 @@ msgid "ricetta trovata"
msgstr "recipe found" msgstr "recipe found"
#: templates/maker/recipe_list.html:144 #: templates/maker/recipe_list.html:144
#: templates/measure/select_recipe.html:158 #: templates/measure/select_recipe.html:175
msgid "ricette trovate" msgid "ricette trovate"
msgstr "recipes found" msgstr "recipes found"
@@ -1005,7 +1063,7 @@ msgid "Versioni"
msgstr "Versions" msgstr "Versions"
#: templates/maker/recipe_list.html:297 #: templates/maker/recipe_list.html:297
#: templates/measure/select_recipe.html:256 #: templates/measure/select_recipe.html:273
msgid "Nessuna ricetta trovata" msgid "Nessuna ricetta trovata"
msgstr "No recipe found" msgstr "No recipe found"
@@ -1149,7 +1207,7 @@ msgid "Torna ai Task"
msgstr "Back to Tasks" msgstr "Back to Tasks"
#: templates/maker/task_drawing.html:205 templates/maker/task_drawing.html:209 #: templates/maker/task_drawing.html:205 templates/maker/task_drawing.html:209
#: templates/measure/select_recipe.html:236 #: templates/measure/select_recipe.html:253
msgid "Seleziona" msgid "Seleziona"
msgstr "Select" msgstr "Select"
@@ -1552,7 +1610,7 @@ msgid "Misurazione aggiunta"
msgstr "Measurement added" msgstr "Measurement added"
#: templates/maker/task_editor.html:1645 #: templates/maker/task_editor.html:1645
#: templates/measure/task_execute.html:862 #: templates/measure/task_execute.html:870
msgid "Errore nel salvataggio della misurazione" msgid "Errore nel salvataggio della misurazione"
msgstr "Error saving measurement" msgstr "Error saving measurement"
@@ -1627,71 +1685,83 @@ msgstr "Choose the measurement recipe to execute"
msgid "Stazione" msgid "Stazione"
msgstr "Station" msgstr "Station"
#: templates/measure/select_recipe.html:102 #: templates/measure/select_recipe.html:89
msgid "Stazione forzata per collaudo"
msgstr "Station overridden for commissioning"
#: templates/measure/select_recipe.html:89
msgid "configurata"
msgstr "configured"
#: templates/measure/select_recipe.html:94
msgid "Ripristina"
msgstr "Restore"
#: templates/measure/select_recipe.html:119
msgid "Cerca ricetta" msgid "Cerca ricetta"
msgstr "Search recipe" msgstr "Search recipe"
#: templates/measure/select_recipe.html:106 #: templates/measure/select_recipe.html:123
msgid "Nome, codice o descrizione..." msgid "Nome, codice o descrizione..."
msgstr "Name, code or description..." msgstr "Name, code or description..."
#: templates/measure/select_recipe.html:119 #: templates/measure/select_recipe.html:136
msgid "Tracciabilità" msgid "Tracciabilità"
msgstr "Traceability" msgstr "Traceability"
#: templates/measure/select_recipe.html:120 #: templates/measure/select_recipe.html:137
msgid "Dati del pezzo da misurare — compila prima di selezionare la ricetta" msgid "Dati del pezzo da misurare — compila prima di selezionare la ricetta"
msgstr "Data of the part to measure — fill in before selecting the recipe" msgstr "Data of the part to measure — fill in before selecting the recipe"
#: templates/measure/select_recipe.html:130 #: templates/measure/select_recipe.html:147
#: templates/measure/task_complete.html:281 #: templates/measure/task_complete.html:281
msgid "Numero Lotto" msgid "Numero Lotto"
msgstr "Lot Number" msgstr "Lot Number"
#: templates/measure/select_recipe.html:134 #: templates/measure/select_recipe.html:151
msgid "Es. LOT-2026-001 (opzionale)" msgid "Es. LOT-2026-001 (opzionale)"
msgstr "E.g. LOT-2026-001 (optional)" msgstr "E.g. LOT-2026-001 (optional)"
#: templates/measure/select_recipe.html:144 #: templates/measure/select_recipe.html:161
#: templates/measure/task_complete.html:282 #: templates/measure/task_complete.html:282
msgid "Numero Seriale" msgid "Numero Seriale"
msgstr "Serial Number" msgstr "Serial Number"
#: templates/measure/select_recipe.html:148 #: templates/measure/select_recipe.html:165
msgid "Es. SN-000123 (opzionale)" msgid "Es. SN-000123 (opzionale)"
msgstr "E.g. SN-000123 (optional)" msgstr "E.g. SN-000123 (optional)"
#: templates/measure/select_recipe.html:201 #: templates/measure/select_recipe.html:218
msgid "Nessuna descrizione disponibile" msgid "Nessuna descrizione disponibile"
msgstr "No description available" msgstr "No description available"
#: templates/measure/select_recipe.html:260 #: templates/measure/select_recipe.html:277
msgid "Nessun risultato per" msgid "Nessun risultato per"
msgstr "No results for" msgstr "No results for"
#: templates/measure/select_recipe.html:261 #: templates/measure/select_recipe.html:278
msgid "Prova con un termine diverso." msgid "Prova con un termine diverso."
msgstr "Try a different search term." msgstr "Try a different search term."
#: templates/measure/select_recipe.html:264 #: templates/measure/select_recipe.html:281
msgid "Non ci sono ricette disponibili al momento." msgid "Non ci sono ricette disponibili al momento."
msgstr "No recipes available at the moment." msgstr "No recipes available at the moment."
#: templates/measure/select_recipe.html:317 #: templates/measure/select_recipe.html:334
msgid "" msgid ""
"Inserisci o scansiona il codice della ricetta per selezionarla " "Inserisci o scansiona il codice della ricetta per selezionarla "
"automaticamente." "automaticamente."
msgstr "Enter or scan the recipe code to select it automatically." msgstr "Enter or scan the recipe code to select it automatically."
#: templates/measure/select_recipe.html:322 #: templates/measure/select_recipe.html:339
msgid "Codice Ricetta" msgid "Codice Ricetta"
msgstr "Recipe Code" msgstr "Recipe Code"
#: templates/measure/select_recipe.html:328 #: templates/measure/select_recipe.html:345
msgid "Es. REC-001" msgid "Es. REC-001"
msgstr "E.g. REC-001" msgstr "E.g. REC-001"
#: templates/measure/select_recipe.html:364 #: templates/measure/select_recipe.html:381
msgid "Cerca" msgid "Cerca"
msgstr "Search" msgstr "Search"
@@ -1984,23 +2054,23 @@ msgstr "Supervisor username"
msgid "Autorizza" msgid "Autorizza"
msgstr "Authorize" msgstr "Authorize"
#: templates/measure/task_execute.html:906 #: templates/measure/task_execute.html:914
msgid "Errore di rete. Riprovare." msgid "Errore di rete. Riprovare."
msgstr "Network error. Please retry." msgstr "Network error. Please retry."
#: templates/measure/task_execute.html:1068 #: templates/measure/task_execute.html:1078
msgid "Misurazione fuori tolleranza" msgid "Misurazione fuori tolleranza"
msgstr "Measurement out of tolerance" msgstr "Measurement out of tolerance"
#: templates/measure/task_execute.html:1069 #: templates/measure/task_execute.html:1079
msgid "Fermo linea richiesto" msgid "Fermo linea richiesto"
msgstr "Line stop requested" msgstr "Line stop requested"
#: templates/measure/task_execute.html:1070 #: templates/measure/task_execute.html:1080
msgid "Fine produzione richiesta" msgid "Fine produzione richiesta"
msgstr "End of production requested" msgstr "End of production requested"
#: templates/measure/task_execute.html:1089 #: templates/measure/task_execute.html:1099
msgid "Credenziali non valide o utente non autorizzato" msgid "Credenziali non valide o utente non autorizzato"
msgstr "Invalid credentials or unauthorized user" msgstr "Invalid credentials or unauthorized user"
@@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: TieMeasureFlow 1.0\n" "Project-Id-Version: TieMeasureFlow 1.0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-06-11 15:33+0000\n" "POT-Creation-Date: 2026-07-28 15:24+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: it\n" "Language: it\n"
@@ -37,7 +37,7 @@ msgstr "Effettua il login per continuare"
msgid "Inserisci username e password" msgid "Inserisci username e password"
msgstr "Inserisci username e password" msgstr "Inserisci username e password"
#: blueprints/auth.py:81 blueprints/measure.py:346 #: blueprints/auth.py:81 blueprints/measure.py:407
msgid "Credenziali non valide" msgid "Credenziali non valide"
msgstr "Credenziali non valide" msgstr "Credenziali non valide"
@@ -101,65 +101,87 @@ msgstr "Nessun file caricato"
msgid "Nome file vuoto" msgid "Nome file vuoto"
msgstr "Nome file vuoto" msgstr "Nome file vuoto"
#: blueprints/measure.py:45
msgid "Il cambio stazione da URL non è abilitato su questa postazione."
msgstr "Il cambio stazione da URL non è abilitato su questa postazione."
#: blueprints/measure.py:50
msgid "Stazione riportata a quella configurata."
msgstr "Stazione riportata a quella configurata."
#: blueprints/measure.py:56
msgid "Impossibile contattare il server per cambiare stazione."
msgstr "Impossibile contattare il server per cambiare stazione."
#: blueprints/measure.py:61
#, python-format
msgid "Stazione '%(code)s' inesistente o disattivata: stazione invariata."
msgstr "Stazione '%(code)s' inesistente o disattivata: stazione invariata."
#: blueprints/measure.py:68
#, python-format
msgid "Stazione corrente: %(code)s"
msgstr "Stazione corrente: %(code)s"
# Measure - API Errors # Measure - API Errors
#: blueprints/measure.py:38 #: blueprints/measure.py:96
#, python-format #, python-format
msgid "Errore nel caricamento delle ricette: %(detail)s" msgid "Errore nel caricamento delle ricette: %(detail)s"
msgstr "Errore nel caricamento delle ricette: %(detail)s" msgstr "Errore nel caricamento delle ricette: %(detail)s"
#: blueprints/measure.py:86 blueprints/measure.py:172 #: blueprints/measure.py:146 blueprints/measure.py:232
#, python-format #, python-format
msgid "Ricetta non trovata: %(detail)s" msgid "Ricetta non trovata: %(detail)s"
msgstr "Ricetta non trovata: %(detail)s" msgstr "Ricetta non trovata: %(detail)s"
#: blueprints/measure.py:96 #: blueprints/measure.py:156
#, python-format #, python-format
msgid "Errore nel caricamento dei task: %(detail)s" msgid "Errore nel caricamento dei task: %(detail)s"
msgstr "Errore nel caricamento dei task: %(detail)s" msgstr "Errore nel caricamento dei task: %(detail)s"
#: blueprints/measure.py:125 #: blueprints/measure.py:185
#, python-format #, python-format
msgid "Task non trovato: %(detail)s" msgid "Task non trovato: %(detail)s"
msgstr "Task non trovato: %(detail)s" msgstr "Task non trovato: %(detail)s"
#: blueprints/measure.py:241 #: blueprints/measure.py:301
msgid "Codice non fornito" msgid "Codice non fornito"
msgstr "Codice non fornito" msgstr "Codice non fornito"
#: blueprints/measure.py:247 templates/measure/select_recipe.html:48 #: blueprints/measure.py:307 templates/measure/select_recipe.html:48
msgid "Ricetta non trovata" msgid "Ricetta non trovata"
msgstr "Ricetta non trovata" msgstr "Ricetta non trovata"
#: blueprints/measure.py:303 #: blueprints/measure.py:363
msgid "Dati mancanti: subtask_id, version_id e value sono obbligatori" msgid "Dati mancanti: subtask_id, version_id e value sono obbligatori"
msgstr "Dati mancanti: subtask_id, version_id e value sono obbligatori" msgstr "Dati mancanti: subtask_id, version_id e value sono obbligatori"
#: blueprints/measure.py:322 templates/admin/stations.html:485 #: blueprints/measure.py:383 templates/admin/stations.html:549
#: templates/maker/recipe_editor.html:543 #: templates/maker/recipe_editor.html:543
msgid "Errore nel salvataggio" msgid "Errore nel salvataggio"
msgstr "Errore nel salvataggio" msgstr "Errore nel salvataggio"
#: blueprints/measure.py:341 #: blueprints/measure.py:402
msgid "Username e password richiesti" msgid "Username e password richiesti"
msgstr "Username e password richiesti" msgstr "Username e password richiesti"
#: blueprints/measure.py:351 #: blueprints/measure.py:412
msgid "Utente non autorizzato (richiesto capoturno)" msgid "Utente non autorizzato (richiesto capoturno)"
msgstr "Utente non autorizzato (richiesto capoturno)" msgstr "Utente non autorizzato (richiesto capoturno)"
#: templates/base.html:175 #: templates/base.html:173
msgid "Sessione in scadenza" msgid "Sessione in scadenza"
msgstr "Sessione in scadenza" msgstr "Sessione in scadenza"
#: templates/base.html:178 #: templates/base.html:176
msgid "Sarai disconnesso tra" msgid "Sarai disconnesso tra"
msgstr "Sarai disconnesso tra" msgstr "Sarai disconnesso tra"
#: templates/base.html:178 #: templates/base.html:176
msgid "secondi per inattività." msgid "secondi per inattività."
msgstr "secondi per inattività." msgstr "secondi per inattività."
#: templates/base.html:181 #: templates/base.html:179
msgid "Continua a lavorare" msgid "Continua a lavorare"
msgstr "Continua a lavorare" msgstr "Continua a lavorare"
@@ -203,16 +225,16 @@ msgstr "Salvato"
msgid "Salva impostazioni" msgid "Salva impostazioni"
msgstr "Salva impostazioni" msgstr "Salva impostazioni"
#: templates/admin/settings.html:107 templates/admin/stations.html:516 #: templates/admin/settings.html:107 templates/admin/stations.html:582
#: templates/admin/stations.html:544 templates/admin/stations.html:565 #: templates/admin/stations.html:621 templates/admin/stations.html:644
#: templates/admin/stations.html:596 templates/admin/stations.html:618 #: templates/admin/stations.html:665 templates/admin/stations.html:700
#: templates/admin/users.html:497 templates/admin/users.html:533 #: templates/admin/stations.html:723 templates/admin/users.html:497
#: templates/maker/recipe_editor.html:571 templates/maker/task_drawing.html:65 #: templates/admin/users.html:533 templates/maker/recipe_editor.html:571
#: templates/maker/task_editor.html:1243 templates/maker/task_editor.html:1321 #: templates/maker/task_drawing.html:65 templates/maker/task_editor.html:1243
#: templates/maker/task_editor.html:1382 templates/maker/task_editor.html:1415 #: templates/maker/task_editor.html:1321 templates/maker/task_editor.html:1382
#: templates/maker/task_editor.html:1510 templates/maker/task_editor.html:1586 #: templates/maker/task_editor.html:1415 templates/maker/task_editor.html:1510
#: templates/maker/task_editor.html:1660 templates/maker/task_editor.html:1697 #: templates/maker/task_editor.html:1586 templates/maker/task_editor.html:1660
#: templates/maker/task_editor.html:1776 #: templates/maker/task_editor.html:1697 templates/maker/task_editor.html:1776
#: templates/statistics/dashboard.html:372 #: templates/statistics/dashboard.html:372
#: templates/statistics/dashboard.html:457 #: templates/statistics/dashboard.html:457
msgid "Errore di connessione al server" msgid "Errore di connessione al server"
@@ -234,209 +256,245 @@ msgstr ""
msgid "Cerca stazione..." msgid "Cerca stazione..."
msgstr "Cerca stazione..." msgstr "Cerca stazione..."
#: templates/admin/stations.html:39 templates/admin/stations.html:133 #: templates/admin/stations.html:39 templates/admin/stations.html:163
msgid "Nuova Stazione" msgid "Nuova Stazione"
msgstr "Nuova Stazione" msgstr "Nuova Stazione"
# Task Complete Page # Task Complete Page
#: templates/admin/stations.html:49 templates/admin/stations.html:143 #: templates/admin/stations.html:49 templates/admin/stations.html:173
#: templates/maker/recipe_editor.html:195 #: templates/maker/recipe_editor.html:195
#: templates/measure/task_complete.html:49 #: templates/measure/task_complete.html:49
msgid "Codice" msgid "Codice"
msgstr "Codice" msgstr "Codice"
#: templates/admin/stations.html:50 templates/admin/stations.html:160 #: templates/admin/stations.html:50 templates/admin/stations.html:190
#: templates/maker/recipe_editor.html:213 #: templates/maker/recipe_editor.html:213
#: templates/measure/task_complete.html:53 #: templates/measure/task_complete.html:53
msgid "Nome" msgid "Nome"
msgstr "Nome" msgstr "Nome"
#: templates/admin/stations.html:51 templates/admin/stations.html:169 #: templates/admin/stations.html:51 templates/admin/stations.html:199
msgid "Postazione" msgid "Postazione"
msgstr "Postazione" msgstr "Postazione"
#: templates/admin/stations.html:52 templates/admin/users.html:52 #: templates/admin/stations.html:52
msgid "Ricette collegate"
msgstr "Ricette collegate"
#: templates/admin/stations.html:53 templates/admin/users.html:52
#: templates/measure/task_complete.html:292 #: templates/measure/task_complete.html:292
msgid "Stato" msgid "Stato"
msgstr "Stato" msgstr "Stato"
#: templates/admin/stations.html:53 templates/admin/users.html:53 #: templates/admin/stations.html:54 templates/admin/users.html:53
#: templates/maker/task_editor.html:551 #: templates/maker/task_editor.html:551
msgid "Azioni" msgid "Azioni"
msgstr "Azioni" msgstr "Azioni"
#: templates/admin/stations.html:70 templates/admin/stations.html:189 #: templates/admin/stations.html:68
msgid "Nessuna ricetta"
msgstr "Nessuna ricetta"
#: templates/admin/stations.html:89 templates/admin/stations.html:219
#: templates/maker/recipe_list.html:186 #: templates/maker/recipe_list.html:186
msgid "Attiva" msgid "Attiva"
msgstr "Attiva" msgstr "Attiva"
#: templates/admin/stations.html:70 templates/maker/recipe_list.html:186 #: templates/admin/stations.html:89 templates/maker/recipe_list.html:186
msgid "Disattivata" msgid "Disattivata"
msgstr "Disattivata" msgstr "Disattivata"
# Maker - Recipe List # Maker - Recipe List
#: templates/admin/stations.html:76 #: templates/admin/stations.html:95
msgid "Gestisci ricette" msgid "Gestisci ricette"
msgstr "Gestisci ricette" msgstr "Gestisci ricette"
#: templates/admin/stations.html:83 templates/admin/users.html:100 #: templates/admin/stations.html:105
msgid "Azzera le ricette della stazione"
msgstr "Azzera le ricette della stazione"
#: templates/admin/stations.html:106
msgid "Nessuna ricetta da azzerare"
msgstr "Nessuna ricetta da azzerare"
#: templates/admin/stations.html:113 templates/admin/users.html:100
#: templates/maker/recipe_list.html:237 templates/maker/task_editor.html:602 #: templates/maker/recipe_list.html:237 templates/maker/task_editor.html:602
msgid "Modifica" msgid "Modifica"
msgstr "Modifica" msgstr "Modifica"
#: templates/admin/stations.html:90 templates/admin/stations.html:359 #: templates/admin/stations.html:120 templates/admin/stations.html:421
#: templates/maker/recipe_list.html:277 templates/maker/recipe_list.html:387 #: templates/maker/recipe_list.html:277 templates/maker/recipe_list.html:387
#: templates/maker/task_drawing.html:275 templates/maker/task_editor.html:610 #: templates/maker/task_drawing.html:275 templates/maker/task_editor.html:610
msgid "Elimina" msgid "Elimina"
msgstr "Elimina" msgstr "Elimina"
#: templates/admin/stations.html:108 #: templates/admin/stations.html:138
msgid "Nessuna stazione trovata" msgid "Nessuna stazione trovata"
msgstr "Nessuna stazione trovata" msgstr "Nessuna stazione trovata"
#: templates/admin/stations.html:114 #: templates/admin/stations.html:144
msgid "stazioni" msgid "stazioni"
msgstr "stazioni" msgstr "stazioni"
#: templates/admin/stations.html:133 #: templates/admin/stations.html:163
msgid "Modifica Stazione" msgid "Modifica Stazione"
msgstr "Modifica Stazione" msgstr "Modifica Stazione"
#: templates/admin/stations.html:152 #: templates/admin/stations.html:182
msgid "Il codice non può essere modificato" msgid "Il codice non può essere modificato"
msgstr "Il codice non può essere modificato" msgstr "Il codice non può essere modificato"
#: templates/admin/stations.html:155 #: templates/admin/stations.html:185
msgid "Identificativo univoco usato dal client tramite STATION_CODE" msgid "Identificativo univoco usato dal client tramite STATION_CODE"
msgstr "Identificativo univoco usato dal client tramite STATION_CODE" msgstr "Identificativo univoco usato dal client tramite STATION_CODE"
#: templates/admin/stations.html:164 #: templates/admin/stations.html:194
msgid "Nome descrittivo della stazione" msgid "Nome descrittivo della stazione"
msgstr "Nome descrittivo della stazione" msgstr "Nome descrittivo della stazione"
#: templates/admin/stations.html:173 #: templates/admin/stations.html:203
msgid "Es. Reparto A - Linea 2" msgid "Es. Reparto A - Linea 2"
msgstr "Es. Reparto A - Linea 2" msgstr "Es. Reparto A - Linea 2"
#: templates/admin/stations.html:178 #: templates/admin/stations.html:208
msgid "Note" msgid "Note"
msgstr "Note" msgstr "Note"
#: templates/admin/stations.html:182 #: templates/admin/stations.html:212
msgid "Note opzionali" msgid "Note opzionali"
msgstr "Note opzionali" msgstr "Note opzionali"
#: templates/admin/stations.html:204 templates/admin/stations.html:354 #: templates/admin/stations.html:234 templates/admin/stations.html:389
#: templates/admin/users.html:292 templates/admin/users.html:323 #: templates/admin/stations.html:416 templates/admin/users.html:292
#: templates/maker/recipe_editor.html:137 #: templates/admin/users.html:323 templates/maker/recipe_editor.html:137
#: templates/maker/recipe_editor.html:456 templates/maker/recipe_list.html:383 #: templates/maker/recipe_editor.html:456 templates/maker/recipe_list.html:383
#: templates/maker/task_editor.html:294 templates/maker/task_editor.html:403 #: templates/maker/task_editor.html:294 templates/maker/task_editor.html:403
#: templates/maker/task_editor.html:747 templates/maker/task_editor.html:866 #: templates/maker/task_editor.html:747 templates/maker/task_editor.html:866
#: templates/maker/task_editor.html:931 templates/maker/task_editor.html:1036 #: templates/maker/task_editor.html:931 templates/maker/task_editor.html:1036
#: templates/measure/select_recipe.html:350 #: templates/measure/select_recipe.html:367
#: templates/measure/task_execute.html:664 #: templates/measure/task_execute.html:664
msgid "Annulla" msgid "Annulla"
msgstr "Annulla" msgstr "Annulla"
#: templates/admin/stations.html:210 templates/admin/users.html:298 #: templates/admin/stations.html:240 templates/admin/users.html:298
#: templates/auth/profile.html:171 #: templates/auth/profile.html:171
msgid "Salva Modifiche" msgid "Salva Modifiche"
msgstr "Salva Modifiche" msgstr "Salva Modifiche"
#: templates/admin/stations.html:210 #: templates/admin/stations.html:240
msgid "Crea Stazione" msgid "Crea Stazione"
msgstr "Crea Stazione" msgstr "Crea Stazione"
#: templates/admin/stations.html:211 templates/admin/users.html:299 #: templates/admin/stations.html:241 templates/admin/users.html:299
#: templates/maker/recipe_editor.html:107 #: templates/maker/recipe_editor.html:107
#: templates/maker/recipe_editor.html:448 templates/maker/task_drawing.html:61 #: templates/maker/recipe_editor.html:448 templates/maker/task_drawing.html:61
#: templates/measure/task_execute.html:380 #: templates/measure/task_execute.html:380
msgid "Salvataggio..." msgid "Salvataggio..."
msgstr "Salvataggio..." msgstr "Salvataggio..."
#: templates/admin/stations.html:228 #: templates/admin/stations.html:258
msgid "Ricette Assegnate" msgid "Ricette Assegnate"
msgstr "Ricette Assegnate" msgstr "Ricette Assegnate"
#: templates/admin/stations.html:246 #: templates/admin/stations.html:276
msgid "Filtra per codice o nome ricetta..." msgid "Filtra per codice o nome ricetta..."
msgstr "Filtra per codice o nome ricetta..." msgstr "Filtra per codice o nome ricetta..."
#: templates/admin/stations.html:259 #: templates/admin/stations.html:289
msgid "Ricette disponibili" msgid "Ricette disponibili"
msgstr "Ricette disponibili" msgstr "Ricette disponibili"
#: templates/admin/stations.html:272 #: templates/admin/stations.html:302
msgid "Assegna a questa stazione" msgid "Assegna a questa stazione"
msgstr "Assegna a questa stazione" msgstr "Assegna a questa stazione"
#: templates/admin/stations.html:276 #: templates/admin/stations.html:306
msgid "Assegna" msgid "Assegna"
msgstr "Assegna" msgstr "Assegna"
#: templates/admin/stations.html:293 #: templates/admin/stations.html:323
msgid "Assegnate alla stazione" msgid "Assegnate alla stazione"
msgstr "Assegnate alla stazione" msgstr "Assegnate alla stazione"
#: templates/admin/stations.html:305 #: templates/admin/stations.html:335
msgid "Rimuovi assegnazione" msgid "Rimuovi assegnazione"
msgstr "Rimuovi assegnazione" msgstr "Rimuovi assegnazione"
#: templates/admin/stations.html:332 #: templates/admin/stations.html:362
#: templates/components/barcode_scanner.html:145 #: templates/components/barcode_scanner.html:145
msgid "Chiudi" msgid "Chiudi"
msgstr "Chiudi" msgstr "Chiudi"
#: templates/admin/stations.html:345 templates/maker/recipe_list.html:363 #: templates/admin/stations.html:376
msgid "Azzera Stazione"
msgstr "Azzera Stazione"
#: templates/admin/stations.html:378
msgid "Rimuovere tutte le ricette assegnate a"
msgstr "Rimuovere tutte le ricette assegnate a"
#: templates/admin/stations.html:383
msgid "assegnazioni verranno rimosse. La stazione resta, e si potrà riassegnare."
msgstr "assegnazioni verranno rimosse. La stazione resta, e si potrà riassegnare."
#: templates/admin/stations.html:394
msgid "Azzera"
msgstr "Azzera"
#: templates/admin/stations.html:407 templates/maker/recipe_list.html:363
msgid "Conferma Eliminazione" msgid "Conferma Eliminazione"
msgstr "Conferma Eliminazione" msgstr "Conferma Eliminazione"
#: templates/admin/stations.html:347 #: templates/admin/stations.html:409
msgid "Sei sicuro di voler eliminare la stazione" msgid "Sei sicuro di voler eliminare la stazione"
msgstr "Sei sicuro di voler eliminare la stazione" msgstr "Sei sicuro di voler eliminare la stazione"
#: templates/admin/stations.html:349 #: templates/admin/stations.html:411
msgid "Verranno rimosse anche tutte le assegnazioni di ricette." msgid "Verranno rimosse anche tutte le assegnazioni di ricette."
msgstr "Verranno rimosse anche tutte le assegnazioni di ricette." msgstr "Verranno rimosse anche tutte le assegnazioni di ricette."
#: templates/admin/stations.html:430 templates/admin/stations.html:436 #: templates/admin/stations.html:494 templates/admin/stations.html:500
msgid "Nessun risultato per il filtro" msgid "Nessun risultato per il filtro"
msgstr "Nessun risultato per il filtro" msgstr "Nessun risultato per il filtro"
#: templates/admin/stations.html:431 #: templates/admin/stations.html:495
msgid "Nessuna ricetta nel sistema" msgid "Nessuna ricetta nel sistema"
msgstr "Nessuna ricetta nel sistema" msgstr "Nessuna ricetta nel sistema"
#: templates/admin/stations.html:432 #: templates/admin/stations.html:496
msgid "Tutte le ricette sono già assegnate" msgid "Tutte le ricette sono già assegnate"
msgstr "Tutte le ricette sono già assegnate" msgstr "Tutte le ricette sono già assegnate"
#: templates/admin/stations.html:437 #: templates/admin/stations.html:501
msgid "Nessuna ricetta assegnata" msgid "Nessuna ricetta assegnata"
msgstr "Nessuna ricetta assegnata" msgstr "Nessuna ricetta assegnata"
#: templates/admin/stations.html:492 #: templates/admin/stations.html:558
msgid "Codice e nome sono obbligatori" msgid "Codice e nome sono obbligatori"
msgstr "Codice e nome sono obbligatori" msgstr "Codice e nome sono obbligatori"
#: templates/admin/stations.html:509 #: templates/admin/stations.html:575
msgid "Errore nella creazione" msgid "Errore nella creazione"
msgstr "Errore nella creazione" msgstr "Errore nella creazione"
#: templates/admin/stations.html:537 #: templates/admin/stations.html:609
msgid "Errore nell azzeramento"
msgstr "Errore nell azzeramento"
#: templates/admin/stations.html:637
msgid "Errore nella eliminazione" msgid "Errore nella eliminazione"
msgstr "Errore nella eliminazione" msgstr "Errore nella eliminazione"
# Maker - API Errors # Maker - API Errors
#: templates/admin/stations.html:562 #: templates/admin/stations.html:662
msgid "Errore nel caricamento delle ricette" msgid "Errore nel caricamento delle ricette"
msgstr "Errore nel caricamento delle ricette" msgstr "Errore nel caricamento delle ricette"
#: templates/admin/stations.html:590 #: templates/admin/stations.html:690
msgid "Errore nella assegnazione" msgid "Errore nella assegnazione"
msgstr "Errore nella assegnazione" msgstr "Errore nella assegnazione"
#: templates/admin/stations.html:613 #: templates/admin/stations.html:717
msgid "Errore nella rimozione" msgid "Errore nella rimozione"
msgstr "Errore nella rimozione" msgstr "Errore nella rimozione"
@@ -457,8 +515,8 @@ msgid "Nuovo Utente"
msgstr "Nuovo Utente" msgstr "Nuovo Utente"
#: templates/admin/users.html:48 templates/admin/users.html:173 #: templates/admin/users.html:48 templates/admin/users.html:173
#: templates/admin/users.html:179 templates/auth/login.html:33 #: templates/admin/users.html:179 templates/auth/login.html:35
#: templates/auth/login.html:47 templates/auth/profile.html:36 #: templates/auth/login.html:49 templates/auth/profile.html:36
#: templates/measure/task_execute.html:649 #: templates/measure/task_execute.html:649
msgid "Username" msgid "Username"
msgstr "Username" msgstr "Username"
@@ -510,7 +568,7 @@ msgid "Il nome utente non può essere modificato"
msgstr "Il nome utente non può essere modificato" msgstr "Il nome utente non può essere modificato"
#: templates/admin/users.html:206 templates/admin/users.html:214 #: templates/admin/users.html:206 templates/admin/users.html:214
#: templates/auth/login.html:55 templates/auth/login.html:69 #: templates/auth/login.html:57 templates/auth/login.html:71
#: templates/measure/task_execute.html:654 #: templates/measure/task_execute.html:654
msgid "Password" msgid "Password"
msgstr "Password" msgstr "Password"
@@ -580,36 +638,36 @@ msgid "Username, nome visualizzato e password sono obbligatori"
msgstr "Username, nome visualizzato e password sono obbligatori" msgstr "Username, nome visualizzato e password sono obbligatori"
# Login Page # Login Page
#: templates/auth/login.html:23 #: templates/auth/login.html:25
msgid "Accedi al sistema" msgid "Accedi al sistema"
msgstr "Accedi al sistema" msgstr "Accedi al sistema"
#: templates/auth/login.html:73 #: templates/auth/login.html:75
msgid "Nascondi password" msgid "Nascondi password"
msgstr "Nascondi password" msgstr "Nascondi password"
#: templates/auth/login.html:73 #: templates/auth/login.html:75
msgid "Mostra password" msgid "Mostra password"
msgstr "Mostra password" msgstr "Mostra password"
#: templates/auth/login.html:94 #: templates/auth/login.html:96
msgid "Accedi" msgid "Accedi"
msgstr "Accedi" msgstr "Accedi"
#: templates/auth/login.html:102 #: templates/auth/login.html:104
msgid "Hai dimenticato la password?" msgid "Hai dimenticato la password?"
msgstr "Hai dimenticato la password?" msgstr "Hai dimenticato la password?"
#: templates/auth/login.html:104 #: templates/auth/login.html:106
msgid "Contatta l'amministratore" msgid "Contatta l'amministratore"
msgstr "Contatta l'amministratore" msgstr "Contatta l'amministratore"
# Additional Login Page # Additional Login Page
#: templates/auth/login.html:111 #: templates/auth/login.html:113
msgid "Sistema di misurazione industriale" msgid "Sistema di misurazione industriale"
msgstr "Sistema di misurazione industriale" msgstr "Sistema di misurazione industriale"
#: templates/auth/profile.html:2 templates/components/navbar.html:147 #: templates/auth/profile.html:2 templates/components/navbar.html:149
msgid "Profilo" msgid "Profilo"
msgstr "Profilo" msgstr "Profilo"
@@ -659,15 +717,15 @@ msgstr "Esci dal sistema"
msgid "Termina la sessione corrente e torna alla schermata di login" msgid "Termina la sessione corrente e torna alla schermata di login"
msgstr "Termina la sessione corrente e torna alla schermata di login" msgstr "Termina la sessione corrente e torna alla schermata di login"
#: templates/auth/profile.html:197 templates/components/navbar.html:158 #: templates/auth/profile.html:197 templates/components/navbar.html:160
#: templates/components/navbar.html:167 #: templates/components/navbar.html:169
msgid "Logout" msgid "Logout"
msgstr "Logout" msgstr "Logout"
#: templates/components/barcode_scanner.html:21 #: templates/components/barcode_scanner.html:21
#: templates/components/barcode_scanner.html:54 #: templates/components/barcode_scanner.html:54
#: templates/measure/select_recipe.html:90 #: templates/measure/select_recipe.html:107
#: templates/measure/select_recipe.html:302 #: templates/measure/select_recipe.html:319
msgid "Scansiona Barcode" msgid "Scansiona Barcode"
msgstr "Scansiona Barcode" msgstr "Scansiona Barcode"
@@ -753,7 +811,7 @@ msgstr "Utenti"
msgid "Stazioni" msgid "Stazioni"
msgstr "Stazioni" msgstr "Stazioni"
#: templates/components/navbar.html:154 #: templates/components/navbar.html:156
msgid "Logout bloccato durante le misurazioni" msgid "Logout bloccato durante le misurazioni"
msgstr "Logout bloccato durante le misurazioni" msgstr "Logout bloccato durante le misurazioni"
@@ -956,7 +1014,7 @@ msgstr "Errore durante eliminazione"
# Recipe Selection Additional # Recipe Selection Additional
#: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:55 #: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:55
#: templates/measure/task_execute.html:1111 #: templates/measure/task_execute.html:1121
msgid "Errore di connessione" msgid "Errore di connessione"
msgstr "Errore di connessione" msgstr "Errore di connessione"
@@ -989,7 +1047,7 @@ msgid "ricetta trovata"
msgstr "ricetta trovata" msgstr "ricetta trovata"
#: templates/maker/recipe_list.html:144 #: templates/maker/recipe_list.html:144
#: templates/measure/select_recipe.html:158 #: templates/measure/select_recipe.html:175
msgid "ricette trovate" msgid "ricette trovate"
msgstr "ricette trovate" msgstr "ricette trovate"
@@ -1007,7 +1065,7 @@ msgid "Versioni"
msgstr "Versioni" msgstr "Versioni"
#: templates/maker/recipe_list.html:297 #: templates/maker/recipe_list.html:297
#: templates/measure/select_recipe.html:256 #: templates/measure/select_recipe.html:273
msgid "Nessuna ricetta trovata" msgid "Nessuna ricetta trovata"
msgstr "Nessuna ricetta trovata" msgstr "Nessuna ricetta trovata"
@@ -1151,7 +1209,7 @@ msgid "Torna ai Task"
msgstr "Torna ai Task" msgstr "Torna ai Task"
#: templates/maker/task_drawing.html:205 templates/maker/task_drawing.html:209 #: templates/maker/task_drawing.html:205 templates/maker/task_drawing.html:209
#: templates/measure/select_recipe.html:236 #: templates/measure/select_recipe.html:253
msgid "Seleziona" msgid "Seleziona"
msgstr "Seleziona" msgstr "Seleziona"
@@ -1554,7 +1612,7 @@ msgid "Misurazione aggiunta"
msgstr "Misurazione aggiunta" msgstr "Misurazione aggiunta"
#: templates/maker/task_editor.html:1645 #: templates/maker/task_editor.html:1645
#: templates/measure/task_execute.html:862 #: templates/measure/task_execute.html:870
msgid "Errore nel salvataggio della misurazione" msgid "Errore nel salvataggio della misurazione"
msgstr "Errore nel salvataggio della misurazione" msgstr "Errore nel salvataggio della misurazione"
@@ -1629,57 +1687,69 @@ msgstr "Scegli la ricetta di misura da eseguire"
msgid "Stazione" msgid "Stazione"
msgstr "Stazione" msgstr "Stazione"
#: templates/measure/select_recipe.html:102 #: templates/measure/select_recipe.html:89
msgid "Stazione forzata per collaudo"
msgstr "Stazione forzata per collaudo"
#: templates/measure/select_recipe.html:89
msgid "configurata"
msgstr "configurata"
#: templates/measure/select_recipe.html:94
msgid "Ripristina"
msgstr "Ripristina"
#: templates/measure/select_recipe.html:119
msgid "Cerca ricetta" msgid "Cerca ricetta"
msgstr "Cerca ricetta" msgstr "Cerca ricetta"
#: templates/measure/select_recipe.html:106 #: templates/measure/select_recipe.html:123
msgid "Nome, codice o descrizione..." msgid "Nome, codice o descrizione..."
msgstr "Nome, codice o descrizione..." msgstr "Nome, codice o descrizione..."
#: templates/measure/select_recipe.html:119 #: templates/measure/select_recipe.html:136
msgid "Tracciabilità" msgid "Tracciabilità"
msgstr "Tracciabilità" msgstr "Tracciabilità"
#: templates/measure/select_recipe.html:120 #: templates/measure/select_recipe.html:137
msgid "Dati del pezzo da misurare — compila prima di selezionare la ricetta" msgid "Dati del pezzo da misurare — compila prima di selezionare la ricetta"
msgstr "Dati del pezzo da misurare — compila prima di selezionare la ricetta" msgstr "Dati del pezzo da misurare — compila prima di selezionare la ricetta"
#: templates/measure/select_recipe.html:130 #: templates/measure/select_recipe.html:147
#: templates/measure/task_complete.html:281 #: templates/measure/task_complete.html:281
msgid "Numero Lotto" msgid "Numero Lotto"
msgstr "Numero Lotto" msgstr "Numero Lotto"
#: templates/measure/select_recipe.html:134 #: templates/measure/select_recipe.html:151
msgid "Es. LOT-2026-001 (opzionale)" msgid "Es. LOT-2026-001 (opzionale)"
msgstr "Es. LOT-2026-001 (opzionale)" msgstr "Es. LOT-2026-001 (opzionale)"
#: templates/measure/select_recipe.html:144 #: templates/measure/select_recipe.html:161
#: templates/measure/task_complete.html:282 #: templates/measure/task_complete.html:282
msgid "Numero Seriale" msgid "Numero Seriale"
msgstr "Numero Seriale" msgstr "Numero Seriale"
#: templates/measure/select_recipe.html:148 #: templates/measure/select_recipe.html:165
msgid "Es. SN-000123 (opzionale)" msgid "Es. SN-000123 (opzionale)"
msgstr "Es. SN-000123 (opzionale)" msgstr "Es. SN-000123 (opzionale)"
#: templates/measure/select_recipe.html:201 #: templates/measure/select_recipe.html:218
msgid "Nessuna descrizione disponibile" msgid "Nessuna descrizione disponibile"
msgstr "Nessuna descrizione disponibile" msgstr "Nessuna descrizione disponibile"
#: templates/measure/select_recipe.html:260 #: templates/measure/select_recipe.html:277
msgid "Nessun risultato per" msgid "Nessun risultato per"
msgstr "Nessun risultato per" msgstr "Nessun risultato per"
#: templates/measure/select_recipe.html:261 #: templates/measure/select_recipe.html:278
msgid "Prova con un termine diverso." msgid "Prova con un termine diverso."
msgstr "Prova con un termine diverso." msgstr "Prova con un termine diverso."
#: templates/measure/select_recipe.html:264 #: templates/measure/select_recipe.html:281
msgid "Non ci sono ricette disponibili al momento." msgid "Non ci sono ricette disponibili al momento."
msgstr "Non ci sono ricette disponibili al momento." msgstr "Non ci sono ricette disponibili al momento."
#: templates/measure/select_recipe.html:317 #: templates/measure/select_recipe.html:334
msgid "" msgid ""
"Inserisci o scansiona il codice della ricetta per selezionarla " "Inserisci o scansiona il codice della ricetta per selezionarla "
"automaticamente." "automaticamente."
@@ -1687,15 +1757,15 @@ msgstr ""
"Inserisci o scansiona il codice della ricetta per selezionarla " "Inserisci o scansiona il codice della ricetta per selezionarla "
"automaticamente." "automaticamente."
#: templates/measure/select_recipe.html:322 #: templates/measure/select_recipe.html:339
msgid "Codice Ricetta" msgid "Codice Ricetta"
msgstr "Codice Ricetta" msgstr "Codice Ricetta"
#: templates/measure/select_recipe.html:328 #: templates/measure/select_recipe.html:345
msgid "Es. REC-001" msgid "Es. REC-001"
msgstr "Es. REC-001" msgstr "Es. REC-001"
#: templates/measure/select_recipe.html:364 #: templates/measure/select_recipe.html:381
msgid "Cerca" msgid "Cerca"
msgstr "Cerca" msgstr "Cerca"
@@ -1988,23 +2058,23 @@ msgstr "Username capoturno"
msgid "Autorizza" msgid "Autorizza"
msgstr "Autorizza" msgstr "Autorizza"
#: templates/measure/task_execute.html:906 #: templates/measure/task_execute.html:914
msgid "Errore di rete. Riprovare." msgid "Errore di rete. Riprovare."
msgstr "Errore di rete. Riprovare." msgstr "Errore di rete. Riprovare."
#: templates/measure/task_execute.html:1068 #: templates/measure/task_execute.html:1078
msgid "Misurazione fuori tolleranza" msgid "Misurazione fuori tolleranza"
msgstr "Misurazione fuori tolleranza" msgstr "Misurazione fuori tolleranza"
#: templates/measure/task_execute.html:1069 #: templates/measure/task_execute.html:1079
msgid "Fermo linea richiesto" msgid "Fermo linea richiesto"
msgstr "Fermo linea richiesto" msgstr "Fermo linea richiesto"
#: templates/measure/task_execute.html:1070 #: templates/measure/task_execute.html:1080
msgid "Fine produzione richiesta" msgid "Fine produzione richiesta"
msgstr "Fine produzione richiesta" msgstr "Fine produzione richiesta"
#: templates/measure/task_execute.html:1089 #: templates/measure/task_execute.html:1099
msgid "Credenziali non valide o utente non autorizzato" msgid "Credenziali non valide o utente non autorizzato"
msgstr "Credenziali non valide o utente non autorizzato" msgstr "Credenziali non valide o utente non autorizzato"
+189 -119
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PROJECT VERSION\n" "Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-06-11 15:33+0000\n" "POT-Creation-Date: 2026-07-28 15:24+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -39,7 +39,7 @@ msgstr ""
msgid "Inserisci username e password" msgid "Inserisci username e password"
msgstr "" msgstr ""
#: blueprints/auth.py:81 blueprints/measure.py:346 #: blueprints/auth.py:81 blueprints/measure.py:407
msgid "Credenziali non valide" msgid "Credenziali non valide"
msgstr "" msgstr ""
@@ -99,64 +99,86 @@ msgstr ""
msgid "Nome file vuoto" msgid "Nome file vuoto"
msgstr "" msgstr ""
#: blueprints/measure.py:38 #: blueprints/measure.py:45
#, python-format msgid "Il cambio stazione da URL non è abilitato su questa postazione."
msgid "Errore nel caricamento delle ricette: %(detail)s"
msgstr "" msgstr ""
#: blueprints/measure.py:86 blueprints/measure.py:172 #: blueprints/measure.py:50
msgid "Stazione riportata a quella configurata."
msgstr ""
#: blueprints/measure.py:56
msgid "Impossibile contattare il server per cambiare stazione."
msgstr ""
#: blueprints/measure.py:61
#, python-format #, python-format
msgid "Ricetta non trovata: %(detail)s" msgid "Stazione '%(code)s' inesistente o disattivata: stazione invariata."
msgstr ""
#: blueprints/measure.py:68
#, python-format
msgid "Stazione corrente: %(code)s"
msgstr "" msgstr ""
#: blueprints/measure.py:96 #: blueprints/measure.py:96
#, python-format #, python-format
msgid "Errore nel caricamento delle ricette: %(detail)s"
msgstr ""
#: blueprints/measure.py:146 blueprints/measure.py:232
#, python-format
msgid "Ricetta non trovata: %(detail)s"
msgstr ""
#: blueprints/measure.py:156
#, python-format
msgid "Errore nel caricamento dei task: %(detail)s" msgid "Errore nel caricamento dei task: %(detail)s"
msgstr "" msgstr ""
#: blueprints/measure.py:125 #: blueprints/measure.py:185
#, python-format #, python-format
msgid "Task non trovato: %(detail)s" msgid "Task non trovato: %(detail)s"
msgstr "" msgstr ""
#: blueprints/measure.py:241 #: blueprints/measure.py:301
msgid "Codice non fornito" msgid "Codice non fornito"
msgstr "" msgstr ""
#: blueprints/measure.py:247 templates/measure/select_recipe.html:48 #: blueprints/measure.py:307 templates/measure/select_recipe.html:48
msgid "Ricetta non trovata" msgid "Ricetta non trovata"
msgstr "" msgstr ""
#: blueprints/measure.py:303 #: blueprints/measure.py:363
msgid "Dati mancanti: subtask_id, version_id e value sono obbligatori" msgid "Dati mancanti: subtask_id, version_id e value sono obbligatori"
msgstr "" msgstr ""
#: blueprints/measure.py:322 templates/admin/stations.html:485 #: blueprints/measure.py:383 templates/admin/stations.html:549
#: templates/maker/recipe_editor.html:543 #: templates/maker/recipe_editor.html:543
msgid "Errore nel salvataggio" msgid "Errore nel salvataggio"
msgstr "" msgstr ""
#: blueprints/measure.py:341 #: blueprints/measure.py:402
msgid "Username e password richiesti" msgid "Username e password richiesti"
msgstr "" msgstr ""
#: blueprints/measure.py:351 #: blueprints/measure.py:412
msgid "Utente non autorizzato (richiesto capoturno)" msgid "Utente non autorizzato (richiesto capoturno)"
msgstr "" msgstr ""
#: templates/base.html:175 #: templates/base.html:173
msgid "Sessione in scadenza" msgid "Sessione in scadenza"
msgstr "" msgstr ""
#: templates/base.html:178 #: templates/base.html:176
msgid "Sarai disconnesso tra" msgid "Sarai disconnesso tra"
msgstr "" msgstr ""
#: templates/base.html:178 #: templates/base.html:176
msgid "secondi per inattività." msgid "secondi per inattività."
msgstr "" msgstr ""
#: templates/base.html:181 #: templates/base.html:179
msgid "Continua a lavorare" msgid "Continua a lavorare"
msgstr "" msgstr ""
@@ -198,16 +220,16 @@ msgstr ""
msgid "Salva impostazioni" msgid "Salva impostazioni"
msgstr "" msgstr ""
#: templates/admin/settings.html:107 templates/admin/stations.html:516 #: templates/admin/settings.html:107 templates/admin/stations.html:582
#: templates/admin/stations.html:544 templates/admin/stations.html:565 #: templates/admin/stations.html:621 templates/admin/stations.html:644
#: templates/admin/stations.html:596 templates/admin/stations.html:618 #: templates/admin/stations.html:665 templates/admin/stations.html:700
#: templates/admin/users.html:497 templates/admin/users.html:533 #: templates/admin/stations.html:723 templates/admin/users.html:497
#: templates/maker/recipe_editor.html:571 templates/maker/task_drawing.html:65 #: templates/admin/users.html:533 templates/maker/recipe_editor.html:571
#: templates/maker/task_editor.html:1243 templates/maker/task_editor.html:1321 #: templates/maker/task_drawing.html:65 templates/maker/task_editor.html:1243
#: templates/maker/task_editor.html:1382 templates/maker/task_editor.html:1415 #: templates/maker/task_editor.html:1321 templates/maker/task_editor.html:1382
#: templates/maker/task_editor.html:1510 templates/maker/task_editor.html:1586 #: templates/maker/task_editor.html:1415 templates/maker/task_editor.html:1510
#: templates/maker/task_editor.html:1660 templates/maker/task_editor.html:1697 #: templates/maker/task_editor.html:1586 templates/maker/task_editor.html:1660
#: templates/maker/task_editor.html:1776 #: templates/maker/task_editor.html:1697 templates/maker/task_editor.html:1776
#: templates/statistics/dashboard.html:372 #: templates/statistics/dashboard.html:372
#: templates/statistics/dashboard.html:457 #: templates/statistics/dashboard.html:457
msgid "Errore di connessione al server" msgid "Errore di connessione al server"
@@ -227,206 +249,242 @@ msgstr ""
msgid "Cerca stazione..." msgid "Cerca stazione..."
msgstr "" msgstr ""
#: templates/admin/stations.html:39 templates/admin/stations.html:133 #: templates/admin/stations.html:39 templates/admin/stations.html:163
msgid "Nuova Stazione" msgid "Nuova Stazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:49 templates/admin/stations.html:143 #: templates/admin/stations.html:49 templates/admin/stations.html:173
#: templates/maker/recipe_editor.html:195 #: templates/maker/recipe_editor.html:195
#: templates/measure/task_complete.html:49 #: templates/measure/task_complete.html:49
msgid "Codice" msgid "Codice"
msgstr "" msgstr ""
#: templates/admin/stations.html:50 templates/admin/stations.html:160 #: templates/admin/stations.html:50 templates/admin/stations.html:190
#: templates/maker/recipe_editor.html:213 #: templates/maker/recipe_editor.html:213
#: templates/measure/task_complete.html:53 #: templates/measure/task_complete.html:53
msgid "Nome" msgid "Nome"
msgstr "" msgstr ""
#: templates/admin/stations.html:51 templates/admin/stations.html:169 #: templates/admin/stations.html:51 templates/admin/stations.html:199
msgid "Postazione" msgid "Postazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:52 templates/admin/users.html:52 #: templates/admin/stations.html:52
msgid "Ricette collegate"
msgstr ""
#: templates/admin/stations.html:53 templates/admin/users.html:52
#: templates/measure/task_complete.html:292 #: templates/measure/task_complete.html:292
msgid "Stato" msgid "Stato"
msgstr "" msgstr ""
#: templates/admin/stations.html:53 templates/admin/users.html:53 #: templates/admin/stations.html:54 templates/admin/users.html:53
#: templates/maker/task_editor.html:551 #: templates/maker/task_editor.html:551
msgid "Azioni" msgid "Azioni"
msgstr "" msgstr ""
#: templates/admin/stations.html:70 templates/admin/stations.html:189 #: templates/admin/stations.html:68
msgid "Nessuna ricetta"
msgstr ""
#: templates/admin/stations.html:89 templates/admin/stations.html:219
#: templates/maker/recipe_list.html:186 #: templates/maker/recipe_list.html:186
msgid "Attiva" msgid "Attiva"
msgstr "" msgstr ""
#: templates/admin/stations.html:70 templates/maker/recipe_list.html:186 #: templates/admin/stations.html:89 templates/maker/recipe_list.html:186
msgid "Disattivata" msgid "Disattivata"
msgstr "" msgstr ""
#: templates/admin/stations.html:76 #: templates/admin/stations.html:95
msgid "Gestisci ricette" msgid "Gestisci ricette"
msgstr "" msgstr ""
#: templates/admin/stations.html:83 templates/admin/users.html:100 #: templates/admin/stations.html:105
msgid "Azzera le ricette della stazione"
msgstr ""
#: templates/admin/stations.html:106
msgid "Nessuna ricetta da azzerare"
msgstr ""
#: templates/admin/stations.html:113 templates/admin/users.html:100
#: templates/maker/recipe_list.html:237 templates/maker/task_editor.html:602 #: templates/maker/recipe_list.html:237 templates/maker/task_editor.html:602
msgid "Modifica" msgid "Modifica"
msgstr "" msgstr ""
#: templates/admin/stations.html:90 templates/admin/stations.html:359 #: templates/admin/stations.html:120 templates/admin/stations.html:421
#: templates/maker/recipe_list.html:277 templates/maker/recipe_list.html:387 #: templates/maker/recipe_list.html:277 templates/maker/recipe_list.html:387
#: templates/maker/task_drawing.html:275 templates/maker/task_editor.html:610 #: templates/maker/task_drawing.html:275 templates/maker/task_editor.html:610
msgid "Elimina" msgid "Elimina"
msgstr "" msgstr ""
#: templates/admin/stations.html:108 #: templates/admin/stations.html:138
msgid "Nessuna stazione trovata" msgid "Nessuna stazione trovata"
msgstr "" msgstr ""
#: templates/admin/stations.html:114 #: templates/admin/stations.html:144
msgid "stazioni" msgid "stazioni"
msgstr "" msgstr ""
#: templates/admin/stations.html:133 #: templates/admin/stations.html:163
msgid "Modifica Stazione" msgid "Modifica Stazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:152 #: templates/admin/stations.html:182
msgid "Il codice non può essere modificato" msgid "Il codice non può essere modificato"
msgstr "" msgstr ""
#: templates/admin/stations.html:155 #: templates/admin/stations.html:185
msgid "Identificativo univoco usato dal client tramite STATION_CODE" msgid "Identificativo univoco usato dal client tramite STATION_CODE"
msgstr "" msgstr ""
#: templates/admin/stations.html:164 #: templates/admin/stations.html:194
msgid "Nome descrittivo della stazione" msgid "Nome descrittivo della stazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:173 #: templates/admin/stations.html:203
msgid "Es. Reparto A - Linea 2" msgid "Es. Reparto A - Linea 2"
msgstr "" msgstr ""
#: templates/admin/stations.html:178 #: templates/admin/stations.html:208
msgid "Note" msgid "Note"
msgstr "" msgstr ""
#: templates/admin/stations.html:182 #: templates/admin/stations.html:212
msgid "Note opzionali" msgid "Note opzionali"
msgstr "" msgstr ""
#: templates/admin/stations.html:204 templates/admin/stations.html:354 #: templates/admin/stations.html:234 templates/admin/stations.html:389
#: templates/admin/users.html:292 templates/admin/users.html:323 #: templates/admin/stations.html:416 templates/admin/users.html:292
#: templates/maker/recipe_editor.html:137 #: templates/admin/users.html:323 templates/maker/recipe_editor.html:137
#: templates/maker/recipe_editor.html:456 templates/maker/recipe_list.html:383 #: templates/maker/recipe_editor.html:456 templates/maker/recipe_list.html:383
#: templates/maker/task_editor.html:294 templates/maker/task_editor.html:403 #: templates/maker/task_editor.html:294 templates/maker/task_editor.html:403
#: templates/maker/task_editor.html:747 templates/maker/task_editor.html:866 #: templates/maker/task_editor.html:747 templates/maker/task_editor.html:866
#: templates/maker/task_editor.html:931 templates/maker/task_editor.html:1036 #: templates/maker/task_editor.html:931 templates/maker/task_editor.html:1036
#: templates/measure/select_recipe.html:350 #: templates/measure/select_recipe.html:367
#: templates/measure/task_execute.html:664 #: templates/measure/task_execute.html:664
msgid "Annulla" msgid "Annulla"
msgstr "" msgstr ""
#: templates/admin/stations.html:210 templates/admin/users.html:298 #: templates/admin/stations.html:240 templates/admin/users.html:298
#: templates/auth/profile.html:171 #: templates/auth/profile.html:171
msgid "Salva Modifiche" msgid "Salva Modifiche"
msgstr "" msgstr ""
#: templates/admin/stations.html:210 #: templates/admin/stations.html:240
msgid "Crea Stazione" msgid "Crea Stazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:211 templates/admin/users.html:299 #: templates/admin/stations.html:241 templates/admin/users.html:299
#: templates/maker/recipe_editor.html:107 #: templates/maker/recipe_editor.html:107
#: templates/maker/recipe_editor.html:448 templates/maker/task_drawing.html:61 #: templates/maker/recipe_editor.html:448 templates/maker/task_drawing.html:61
#: templates/measure/task_execute.html:380 #: templates/measure/task_execute.html:380
msgid "Salvataggio..." msgid "Salvataggio..."
msgstr "" msgstr ""
#: templates/admin/stations.html:228 #: templates/admin/stations.html:258
msgid "Ricette Assegnate" msgid "Ricette Assegnate"
msgstr "" msgstr ""
#: templates/admin/stations.html:246 #: templates/admin/stations.html:276
msgid "Filtra per codice o nome ricetta..." msgid "Filtra per codice o nome ricetta..."
msgstr "" msgstr ""
#: templates/admin/stations.html:259 #: templates/admin/stations.html:289
msgid "Ricette disponibili" msgid "Ricette disponibili"
msgstr "" msgstr ""
#: templates/admin/stations.html:272 #: templates/admin/stations.html:302
msgid "Assegna a questa stazione" msgid "Assegna a questa stazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:276 #: templates/admin/stations.html:306
msgid "Assegna" msgid "Assegna"
msgstr "" msgstr ""
#: templates/admin/stations.html:293 #: templates/admin/stations.html:323
msgid "Assegnate alla stazione" msgid "Assegnate alla stazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:305 #: templates/admin/stations.html:335
msgid "Rimuovi assegnazione" msgid "Rimuovi assegnazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:332 #: templates/admin/stations.html:362
#: templates/components/barcode_scanner.html:145 #: templates/components/barcode_scanner.html:145
msgid "Chiudi" msgid "Chiudi"
msgstr "" msgstr ""
#: templates/admin/stations.html:345 templates/maker/recipe_list.html:363 #: templates/admin/stations.html:376
msgid "Azzera Stazione"
msgstr ""
#: templates/admin/stations.html:378
msgid "Rimuovere tutte le ricette assegnate a"
msgstr ""
#: templates/admin/stations.html:383
msgid "assegnazioni verranno rimosse. La stazione resta, e si potrà riassegnare."
msgstr ""
#: templates/admin/stations.html:394
msgid "Azzera"
msgstr ""
#: templates/admin/stations.html:407 templates/maker/recipe_list.html:363
msgid "Conferma Eliminazione" msgid "Conferma Eliminazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:347 #: templates/admin/stations.html:409
msgid "Sei sicuro di voler eliminare la stazione" msgid "Sei sicuro di voler eliminare la stazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:349 #: templates/admin/stations.html:411
msgid "Verranno rimosse anche tutte le assegnazioni di ricette." msgid "Verranno rimosse anche tutte le assegnazioni di ricette."
msgstr "" msgstr ""
#: templates/admin/stations.html:430 templates/admin/stations.html:436 #: templates/admin/stations.html:494 templates/admin/stations.html:500
msgid "Nessun risultato per il filtro" msgid "Nessun risultato per il filtro"
msgstr "" msgstr ""
#: templates/admin/stations.html:431 #: templates/admin/stations.html:495
msgid "Nessuna ricetta nel sistema" msgid "Nessuna ricetta nel sistema"
msgstr "" msgstr ""
#: templates/admin/stations.html:432 #: templates/admin/stations.html:496
msgid "Tutte le ricette sono già assegnate" msgid "Tutte le ricette sono già assegnate"
msgstr "" msgstr ""
#: templates/admin/stations.html:437 #: templates/admin/stations.html:501
msgid "Nessuna ricetta assegnata" msgid "Nessuna ricetta assegnata"
msgstr "" msgstr ""
#: templates/admin/stations.html:492 #: templates/admin/stations.html:558
msgid "Codice e nome sono obbligatori" msgid "Codice e nome sono obbligatori"
msgstr "" msgstr ""
#: templates/admin/stations.html:509 #: templates/admin/stations.html:575
msgid "Errore nella creazione" msgid "Errore nella creazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:537 #: templates/admin/stations.html:609
msgid "Errore nell azzeramento"
msgstr ""
#: templates/admin/stations.html:637
msgid "Errore nella eliminazione" msgid "Errore nella eliminazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:562 #: templates/admin/stations.html:662
msgid "Errore nel caricamento delle ricette" msgid "Errore nel caricamento delle ricette"
msgstr "" msgstr ""
#: templates/admin/stations.html:590 #: templates/admin/stations.html:690
msgid "Errore nella assegnazione" msgid "Errore nella assegnazione"
msgstr "" msgstr ""
#: templates/admin/stations.html:613 #: templates/admin/stations.html:717
msgid "Errore nella rimozione" msgid "Errore nella rimozione"
msgstr "" msgstr ""
@@ -447,8 +505,8 @@ msgid "Nuovo Utente"
msgstr "" msgstr ""
#: templates/admin/users.html:48 templates/admin/users.html:173 #: templates/admin/users.html:48 templates/admin/users.html:173
#: templates/admin/users.html:179 templates/auth/login.html:33 #: templates/admin/users.html:179 templates/auth/login.html:35
#: templates/auth/login.html:47 templates/auth/profile.html:36 #: templates/auth/login.html:49 templates/auth/profile.html:36
#: templates/measure/task_execute.html:649 #: templates/measure/task_execute.html:649
msgid "Username" msgid "Username"
msgstr "" msgstr ""
@@ -500,7 +558,7 @@ msgid "Il nome utente non può essere modificato"
msgstr "" msgstr ""
#: templates/admin/users.html:206 templates/admin/users.html:214 #: templates/admin/users.html:206 templates/admin/users.html:214
#: templates/auth/login.html:55 templates/auth/login.html:69 #: templates/auth/login.html:57 templates/auth/login.html:71
#: templates/measure/task_execute.html:654 #: templates/measure/task_execute.html:654
msgid "Password" msgid "Password"
msgstr "" msgstr ""
@@ -569,35 +627,35 @@ msgstr ""
msgid "Username, nome visualizzato e password sono obbligatori" msgid "Username, nome visualizzato e password sono obbligatori"
msgstr "" msgstr ""
#: templates/auth/login.html:23 #: templates/auth/login.html:25
msgid "Accedi al sistema" msgid "Accedi al sistema"
msgstr "" msgstr ""
#: templates/auth/login.html:73 #: templates/auth/login.html:75
msgid "Nascondi password" msgid "Nascondi password"
msgstr "" msgstr ""
#: templates/auth/login.html:73 #: templates/auth/login.html:75
msgid "Mostra password" msgid "Mostra password"
msgstr "" msgstr ""
#: templates/auth/login.html:94 #: templates/auth/login.html:96
msgid "Accedi" msgid "Accedi"
msgstr "" msgstr ""
#: templates/auth/login.html:102 #: templates/auth/login.html:104
msgid "Hai dimenticato la password?" msgid "Hai dimenticato la password?"
msgstr "" msgstr ""
#: templates/auth/login.html:104 #: templates/auth/login.html:106
msgid "Contatta l'amministratore" msgid "Contatta l'amministratore"
msgstr "" msgstr ""
#: templates/auth/login.html:111 #: templates/auth/login.html:113
msgid "Sistema di misurazione industriale" msgid "Sistema di misurazione industriale"
msgstr "" msgstr ""
#: templates/auth/profile.html:2 templates/components/navbar.html:147 #: templates/auth/profile.html:2 templates/components/navbar.html:149
msgid "Profilo" msgid "Profilo"
msgstr "" msgstr ""
@@ -645,15 +703,15 @@ msgstr ""
msgid "Termina la sessione corrente e torna alla schermata di login" msgid "Termina la sessione corrente e torna alla schermata di login"
msgstr "" msgstr ""
#: templates/auth/profile.html:197 templates/components/navbar.html:158 #: templates/auth/profile.html:197 templates/components/navbar.html:160
#: templates/components/navbar.html:167 #: templates/components/navbar.html:169
msgid "Logout" msgid "Logout"
msgstr "" msgstr ""
#: templates/components/barcode_scanner.html:21 #: templates/components/barcode_scanner.html:21
#: templates/components/barcode_scanner.html:54 #: templates/components/barcode_scanner.html:54
#: templates/measure/select_recipe.html:90 #: templates/measure/select_recipe.html:107
#: templates/measure/select_recipe.html:302 #: templates/measure/select_recipe.html:319
msgid "Scansiona Barcode" msgid "Scansiona Barcode"
msgstr "" msgstr ""
@@ -734,7 +792,7 @@ msgstr ""
msgid "Stazioni" msgid "Stazioni"
msgstr "" msgstr ""
#: templates/components/navbar.html:154 #: templates/components/navbar.html:156
msgid "Logout bloccato durante le misurazioni" msgid "Logout bloccato durante le misurazioni"
msgstr "" msgstr ""
@@ -931,7 +989,7 @@ msgid "Errore durante eliminazione"
msgstr "" msgstr ""
#: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:55 #: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:55
#: templates/measure/task_execute.html:1111 #: templates/measure/task_execute.html:1121
msgid "Errore di connessione" msgid "Errore di connessione"
msgstr "" msgstr ""
@@ -964,7 +1022,7 @@ msgid "ricetta trovata"
msgstr "" msgstr ""
#: templates/maker/recipe_list.html:144 #: templates/maker/recipe_list.html:144
#: templates/measure/select_recipe.html:158 #: templates/measure/select_recipe.html:175
msgid "ricette trovate" msgid "ricette trovate"
msgstr "" msgstr ""
@@ -982,7 +1040,7 @@ msgid "Versioni"
msgstr "" msgstr ""
#: templates/maker/recipe_list.html:297 #: templates/maker/recipe_list.html:297
#: templates/measure/select_recipe.html:256 #: templates/measure/select_recipe.html:273
msgid "Nessuna ricetta trovata" msgid "Nessuna ricetta trovata"
msgstr "" msgstr ""
@@ -1121,7 +1179,7 @@ msgid "Torna ai Task"
msgstr "" msgstr ""
#: templates/maker/task_drawing.html:205 templates/maker/task_drawing.html:209 #: templates/maker/task_drawing.html:205 templates/maker/task_drawing.html:209
#: templates/measure/select_recipe.html:236 #: templates/measure/select_recipe.html:253
msgid "Seleziona" msgid "Seleziona"
msgstr "" msgstr ""
@@ -1522,7 +1580,7 @@ msgid "Misurazione aggiunta"
msgstr "" msgstr ""
#: templates/maker/task_editor.html:1645 #: templates/maker/task_editor.html:1645
#: templates/measure/task_execute.html:862 #: templates/measure/task_execute.html:870
msgid "Errore nel salvataggio della misurazione" msgid "Errore nel salvataggio della misurazione"
msgstr "" msgstr ""
@@ -1593,71 +1651,83 @@ msgstr ""
msgid "Stazione" msgid "Stazione"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:102 #: templates/measure/select_recipe.html:89
msgid "Cerca ricetta" msgid "Stazione forzata per collaudo"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:106 #: templates/measure/select_recipe.html:89
msgid "Nome, codice o descrizione..." msgid "configurata"
msgstr ""
#: templates/measure/select_recipe.html:94
msgid "Ripristina"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:119 #: templates/measure/select_recipe.html:119
msgid "Cerca ricetta"
msgstr ""
#: templates/measure/select_recipe.html:123
msgid "Nome, codice o descrizione..."
msgstr ""
#: templates/measure/select_recipe.html:136
msgid "Tracciabilità" msgid "Tracciabilità"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:120 #: templates/measure/select_recipe.html:137
msgid "Dati del pezzo da misurare — compila prima di selezionare la ricetta" msgid "Dati del pezzo da misurare — compila prima di selezionare la ricetta"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:130 #: templates/measure/select_recipe.html:147
#: templates/measure/task_complete.html:281 #: templates/measure/task_complete.html:281
msgid "Numero Lotto" msgid "Numero Lotto"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:134 #: templates/measure/select_recipe.html:151
msgid "Es. LOT-2026-001 (opzionale)" msgid "Es. LOT-2026-001 (opzionale)"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:144 #: templates/measure/select_recipe.html:161
#: templates/measure/task_complete.html:282 #: templates/measure/task_complete.html:282
msgid "Numero Seriale" msgid "Numero Seriale"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:148 #: templates/measure/select_recipe.html:165
msgid "Es. SN-000123 (opzionale)" msgid "Es. SN-000123 (opzionale)"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:201 #: templates/measure/select_recipe.html:218
msgid "Nessuna descrizione disponibile" msgid "Nessuna descrizione disponibile"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:260 #: templates/measure/select_recipe.html:277
msgid "Nessun risultato per" msgid "Nessun risultato per"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:261 #: templates/measure/select_recipe.html:278
msgid "Prova con un termine diverso." msgid "Prova con un termine diverso."
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:264 #: templates/measure/select_recipe.html:281
msgid "Non ci sono ricette disponibili al momento." msgid "Non ci sono ricette disponibili al momento."
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:317 #: templates/measure/select_recipe.html:334
msgid "" msgid ""
"Inserisci o scansiona il codice della ricetta per selezionarla " "Inserisci o scansiona il codice della ricetta per selezionarla "
"automaticamente." "automaticamente."
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:322 #: templates/measure/select_recipe.html:339
msgid "Codice Ricetta" msgid "Codice Ricetta"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:328 #: templates/measure/select_recipe.html:345
msgid "Es. REC-001" msgid "Es. REC-001"
msgstr "" msgstr ""
#: templates/measure/select_recipe.html:364 #: templates/measure/select_recipe.html:381
msgid "Cerca" msgid "Cerca"
msgstr "" msgstr ""
@@ -1947,23 +2017,23 @@ msgstr ""
msgid "Autorizza" msgid "Autorizza"
msgstr "" msgstr ""
#: templates/measure/task_execute.html:906 #: templates/measure/task_execute.html:914
msgid "Errore di rete. Riprovare." msgid "Errore di rete. Riprovare."
msgstr "" msgstr ""
#: templates/measure/task_execute.html:1068 #: templates/measure/task_execute.html:1078
msgid "Misurazione fuori tolleranza" msgid "Misurazione fuori tolleranza"
msgstr "" msgstr ""
#: templates/measure/task_execute.html:1069 #: templates/measure/task_execute.html:1079
msgid "Fermo linea richiesto" msgid "Fermo linea richiesto"
msgstr "" msgstr ""
#: templates/measure/task_execute.html:1070 #: templates/measure/task_execute.html:1080
msgid "Fine produzione richiesta" msgid "Fine produzione richiesta"
msgstr "" msgstr ""
#: templates/measure/task_execute.html:1089 #: templates/measure/task_execute.html:1099
msgid "Credenziali non valide o utente non autorizzato" msgid "Credenziali non valide o utente non autorizzato"
msgstr "" msgstr ""