feat(measure): l'operatore entra nella sequenza, non in un elenco
Punto 10. Sceglere una ricetta apriva la lista completa dei task e chiedeva all'operatore di decidere da dove cominciare prima ancora di aver fatto qualcosa. Ora AVVIA IN SEQUENZA porta dentro il primo task; la lista resta, un livello sotto, per quando serve vederla tutta o tornare indietro. - nuova rotta /measure/start/<ricetta>: memorizza lotto e seriale (prima lo faceva la lista, che ora si salta), verifica la tracciabilità obbligatoria e apre il primo task - GET /api/measurements/task-progress: quante quote ha già preso ogni task di misura, contate per quota e non per tentativo, delimitate dalla produzione aperta o, fuori produzione, dall'operatore - la lista distingue «Incompiuto 1/3» da «Completato 3/3»: un task lasciato a metà non somigliava più a uno mai aperto - «Visualizza singolo TASK» non è più riservato al Maker — dire «incompiuto» senza dare la strada per tornarci sarebbe una lamentela, non una funzione - nel task «Riepilogo» diventa «Completato» e si apre solo quando il ciclo è chiuso: altrimenti sarebbe la scorciatoia che rende facoltative le quote - «Fine ciclo misura» si vede da subito, spento, e dice quante quote mancano; prima compariva a task già finito, quando non serviva più saperlo Il pulsante verde del footer diventa «Task successivo»: due bottoni con la stessa parola addosso sono uno di troppo. Test: 334 (erano 309). Il side effect dei mock del client Flask ora risponde per endpoint invece che per turno — una lista posizionale si rompe appena una pagina fa una domanda in più al server, che è come crescono tutte. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ from src.backend.models.api.measurement import (
|
||||
MeasurementCreate,
|
||||
MeasurementListResponse,
|
||||
MeasurementResponse,
|
||||
TaskProgressListResponse,
|
||||
)
|
||||
from src.backend.services import auth_service, measurement_service
|
||||
from src.backend.services.measurement_service import save_measurement
|
||||
@@ -77,6 +78,24 @@ async def get_pending_authorisation(
|
||||
return MeasurementResponse.model_validate(blocking) if blocking else None
|
||||
|
||||
|
||||
@router.get("/task-progress", response_model=TaskProgressListResponse)
|
||||
async def get_task_progress(
|
||||
version_id: int = Query(..., gt=0),
|
||||
production_run_id: int | None = Query(None, gt=0),
|
||||
user: User = Depends(require_measurement_tec),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""How many quotes of each measurement task are already taken.
|
||||
|
||||
The task list is where an operator picks up work they left behind, and until
|
||||
now it showed a task begun and a task never touched identically.
|
||||
"""
|
||||
tasks = await measurement_service.task_progress(
|
||||
db, version_id, user.id, production_run_id,
|
||||
)
|
||||
return TaskProgressListResponse(tasks=tasks)
|
||||
|
||||
|
||||
@router.post("/{measurement_id}/authorise", response_model=MeasurementResponse)
|
||||
async def authorise_measurement(
|
||||
measurement_id: int,
|
||||
|
||||
@@ -63,6 +63,22 @@ class MeasurementAuthorisation(BaseModel):
|
||||
supervisor_password: str = Field(..., min_length=1)
|
||||
|
||||
|
||||
class TaskProgressResponse(BaseModel):
|
||||
"""How far one measurement task has got: quotes taken out of quotes expected."""
|
||||
|
||||
task_id: int
|
||||
quotes: int
|
||||
measured: int
|
||||
# empty (declared as measurement, no quotes yet) | none | partial | complete
|
||||
state: str
|
||||
|
||||
|
||||
class TaskProgressListResponse(BaseModel):
|
||||
"""Progress of every measurement task of a version."""
|
||||
|
||||
tasks: list[TaskProgressResponse]
|
||||
|
||||
|
||||
class MeasurementQuery(BaseModel):
|
||||
"""Schema for measurement query filters."""
|
||||
recipe_id: Optional[int] = None
|
||||
|
||||
@@ -8,7 +8,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from src.backend.models.orm.measurement import Measurement
|
||||
from src.backend.models.orm.recipe import Recipe, RecipeVersion
|
||||
from src.backend.models.orm.task import RecipeSubtask
|
||||
from src.backend.models.orm.task import (
|
||||
MEASURING_TASK_TYPES, RecipeSubtask, RecipeTask,
|
||||
)
|
||||
from src.backend.models.orm.user import User
|
||||
|
||||
|
||||
@@ -135,6 +137,71 @@ async def pending_authorisation(
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
|
||||
async def task_progress(
|
||||
db: AsyncSession,
|
||||
version_id: int,
|
||||
measured_by: int,
|
||||
production_run_id: int | None = None,
|
||||
) -> list[dict]:
|
||||
"""How far each measurement task of a version has got.
|
||||
|
||||
A task left half done is the thing the operator cannot see today: they walk
|
||||
away from it, come back to the list, and it looks exactly like one never
|
||||
started. Counting quotes against measurements is what tells them apart.
|
||||
|
||||
Documental tasks are not in here. A note cannot be half read, and marking one
|
||||
incomplete for ever would be noise on the only screen that has to stay legible.
|
||||
Which tasks count is read from the declared type, not from whether quotes happen
|
||||
to have been entered yet - the same rule point 2 settled everywhere else.
|
||||
"""
|
||||
rows = (await db.execute(
|
||||
select(RecipeTask.id, RecipeSubtask.id)
|
||||
.join(RecipeSubtask, RecipeSubtask.task_id == RecipeTask.id, isouter=True)
|
||||
.where(
|
||||
RecipeTask.version_id == version_id,
|
||||
RecipeTask.task_type.in_(MEASURING_TASK_TYPES),
|
||||
)
|
||||
)).all()
|
||||
if not rows:
|
||||
return []
|
||||
|
||||
by_task: dict[int, set[int]] = {}
|
||||
for task_id, subtask_id in rows:
|
||||
quotes = by_task.setdefault(task_id, set())
|
||||
if subtask_id is not None:
|
||||
quotes.add(subtask_id)
|
||||
|
||||
measured = set((await db.execute(
|
||||
_scope(
|
||||
select(Measurement.subtask_id).distinct(),
|
||||
version_id, measured_by, production_run_id,
|
||||
)
|
||||
)).scalars().all())
|
||||
|
||||
progress = []
|
||||
for task_id, subtask_ids in by_task.items():
|
||||
total = len(subtask_ids)
|
||||
done = len(subtask_ids & measured)
|
||||
if total == 0:
|
||||
# Declared as a measurement but with no quotes on it yet: nothing to
|
||||
# take, so nothing to report as missing either.
|
||||
state = "empty"
|
||||
elif done == total:
|
||||
state = "complete"
|
||||
elif done:
|
||||
state = "partial"
|
||||
else:
|
||||
state = "none"
|
||||
progress.append({
|
||||
"task_id": task_id,
|
||||
"quotes": total,
|
||||
"measured": done,
|
||||
"state": state,
|
||||
})
|
||||
progress.sort(key=lambda row: row["task_id"])
|
||||
return progress
|
||||
|
||||
|
||||
async def authorise_measurement(
|
||||
db: AsyncSession, measurement: Measurement, supervisor: User,
|
||||
) -> Measurement:
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
"""Point 10: a task left half done has to look different from one never opened.
|
||||
|
||||
The task list showed both the same way, so an operator coming back to a recipe
|
||||
had to remember where they had got to - or measure something twice. These tests
|
||||
are about the count the list now puts on each card.
|
||||
"""
|
||||
from httpx import AsyncClient
|
||||
from sqlalchemy import select
|
||||
|
||||
from src.backend.models.orm.recipe import RecipeVersion
|
||||
from src.backend.models.orm.station import Station
|
||||
from src.backend.models.orm.task import RecipeSubtask, RecipeTask
|
||||
from src.backend.tests.conftest import auth_headers, create_test_recipe
|
||||
|
||||
|
||||
async def _version_and_task(db_session, recipe_id: int):
|
||||
version = (await db_session.execute(
|
||||
select(RecipeVersion).where(
|
||||
RecipeVersion.recipe_id == recipe_id,
|
||||
RecipeVersion.is_current == True, # noqa: E712
|
||||
)
|
||||
)).scalar_one()
|
||||
task = (await db_session.execute(
|
||||
select(RecipeTask).where(RecipeTask.version_id == version.id)
|
||||
)).scalars().first()
|
||||
return version, task
|
||||
|
||||
|
||||
async def _add_quote(db_session, task_id: int, marker: int):
|
||||
quote = RecipeSubtask(
|
||||
task_id=task_id, marker_number=marker, description=f"Quota {marker}",
|
||||
nominal=10.0, utl=10.5, uwl=10.3, lwl=9.7, ltl=9.5, unit="mm",
|
||||
)
|
||||
db_session.add(quote)
|
||||
await db_session.commit()
|
||||
await db_session.refresh(quote)
|
||||
return quote
|
||||
|
||||
|
||||
async def _measure(client, user, subtask_id, version_id, value=10.0):
|
||||
return await client.post(
|
||||
"/api/measurements/", headers=auth_headers(user),
|
||||
json={"subtask_id": subtask_id, "version_id": version_id, "value": value},
|
||||
)
|
||||
|
||||
|
||||
async def _progress(client, user, version_id):
|
||||
resp = await client.get(
|
||||
"/api/measurements/task-progress",
|
||||
headers=auth_headers(user),
|
||||
params={"version_id": version_id},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
return {row["task_id"]: row for row in resp.json()["tasks"]}
|
||||
|
||||
|
||||
async def test_untouched_task_reads_as_none(
|
||||
client: AsyncClient, db_session, measurement_tec_user,
|
||||
):
|
||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||
version, task = await _version_and_task(db_session, recipe.id)
|
||||
|
||||
rows = await _progress(client, measurement_tec_user, version.id)
|
||||
assert rows[task.id]["state"] == "none"
|
||||
assert rows[task.id]["measured"] == 0
|
||||
|
||||
|
||||
async def test_half_measured_task_reads_as_partial(
|
||||
client: AsyncClient, db_session, measurement_tec_user,
|
||||
):
|
||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||
version, task = await _version_and_task(db_session, recipe.id)
|
||||
first = (await db_session.execute(
|
||||
select(RecipeSubtask).where(RecipeSubtask.task_id == task.id)
|
||||
)).scalars().first()
|
||||
await _add_quote(db_session, task.id, 2)
|
||||
|
||||
await _measure(client, measurement_tec_user, first.id, version.id)
|
||||
|
||||
rows = await _progress(client, measurement_tec_user, version.id)
|
||||
assert rows[task.id] == {
|
||||
"task_id": task.id, "quotes": 2, "measured": 1, "state": "partial",
|
||||
}
|
||||
|
||||
|
||||
async def test_every_quote_taken_reads_as_complete(
|
||||
client: AsyncClient, db_session, measurement_tec_user,
|
||||
):
|
||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||
version, task = await _version_and_task(db_session, recipe.id)
|
||||
first = (await db_session.execute(
|
||||
select(RecipeSubtask).where(RecipeSubtask.task_id == task.id)
|
||||
)).scalars().first()
|
||||
second = await _add_quote(db_session, task.id, 2)
|
||||
|
||||
await _measure(client, measurement_tec_user, first.id, version.id)
|
||||
await _measure(client, measurement_tec_user, second.id, version.id)
|
||||
|
||||
rows = await _progress(client, measurement_tec_user, version.id)
|
||||
assert rows[task.id]["state"] == "complete"
|
||||
assert rows[task.id]["measured"] == 2
|
||||
|
||||
|
||||
async def test_measuring_the_same_quote_twice_does_not_inflate_the_count(
|
||||
client: AsyncClient, db_session, measurement_tec_user,
|
||||
):
|
||||
"""Two readings of one quote are one quote done, not two.
|
||||
|
||||
Re-measuring is allowed - it is how an operator recovers from a caliper that
|
||||
slipped - and counting attempts would show a task of two quotes as finished
|
||||
after one of them had been measured twice.
|
||||
"""
|
||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||
version, task = await _version_and_task(db_session, recipe.id)
|
||||
first = (await db_session.execute(
|
||||
select(RecipeSubtask).where(RecipeSubtask.task_id == task.id)
|
||||
)).scalars().first()
|
||||
await _add_quote(db_session, task.id, 2)
|
||||
|
||||
await _measure(client, measurement_tec_user, first.id, version.id, 10.0)
|
||||
await _measure(client, measurement_tec_user, first.id, version.id, 10.1)
|
||||
|
||||
rows = await _progress(client, measurement_tec_user, version.id)
|
||||
assert rows[task.id]["measured"] == 1
|
||||
assert rows[task.id]["state"] == "partial"
|
||||
|
||||
|
||||
async def test_documental_tasks_are_left_out(
|
||||
client: AsyncClient, db_session, measurement_tec_user,
|
||||
):
|
||||
"""A note cannot be half read; carrying it as unfinished for ever is noise."""
|
||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||
version, task = await _version_and_task(db_session, recipe.id)
|
||||
note = RecipeTask(
|
||||
version_id=version.id, order_index=5, title="Leggere prima",
|
||||
task_type="note",
|
||||
)
|
||||
db_session.add(note)
|
||||
await db_session.commit()
|
||||
await db_session.refresh(note)
|
||||
|
||||
rows = await _progress(client, measurement_tec_user, version.id)
|
||||
assert note.id not in rows
|
||||
assert task.id in rows
|
||||
|
||||
|
||||
async def test_a_measurement_task_without_quotes_is_not_reported_as_missing(
|
||||
client: AsyncClient, db_session, measurement_tec_user,
|
||||
):
|
||||
"""Declared as a measurement, no quotes entered yet: nothing to take."""
|
||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||
version, _task = await _version_and_task(db_session, recipe.id)
|
||||
empty = RecipeTask(
|
||||
version_id=version.id, order_index=6, title="Da compilare",
|
||||
task_type="measure",
|
||||
)
|
||||
db_session.add(empty)
|
||||
await db_session.commit()
|
||||
await db_session.refresh(empty)
|
||||
|
||||
rows = await _progress(client, measurement_tec_user, version.id)
|
||||
assert rows[empty.id]["state"] == "empty"
|
||||
assert rows[empty.id]["quotes"] == 0
|
||||
|
||||
|
||||
async def test_another_operators_work_is_not_counted_as_yours(
|
||||
client: AsyncClient, db_session, measurement_tec_user, admin_user,
|
||||
):
|
||||
"""Outside a production the boundary is the operator, as it is everywhere else."""
|
||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||
version, task = await _version_and_task(db_session, recipe.id)
|
||||
first = (await db_session.execute(
|
||||
select(RecipeSubtask).where(RecipeSubtask.task_id == task.id)
|
||||
)).scalars().first()
|
||||
|
||||
await _measure(client, admin_user, first.id, version.id)
|
||||
|
||||
rows = await _progress(client, measurement_tec_user, version.id)
|
||||
assert rows[task.id]["state"] == "none"
|
||||
|
||||
|
||||
async def test_inside_a_production_the_run_is_the_boundary(
|
||||
client: AsyncClient, db_session, measurement_tec_user, admin_user,
|
||||
):
|
||||
"""A quote measured before the production opened is not part of it.
|
||||
|
||||
The list is read during the run, and carrying yesterday's readings into it
|
||||
would show a task as finished that this production has not touched.
|
||||
"""
|
||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||
version, task = await _version_and_task(db_session, recipe.id)
|
||||
first = (await db_session.execute(
|
||||
select(RecipeSubtask).where(RecipeSubtask.task_id == task.id)
|
||||
)).scalars().first()
|
||||
|
||||
# Measured outside any production.
|
||||
await _measure(client, measurement_tec_user, first.id, version.id)
|
||||
|
||||
station = Station(
|
||||
code="ST-PROG", name="Stazione", active=True, created_by=admin_user.id,
|
||||
)
|
||||
db_session.add(station)
|
||||
await db_session.commit()
|
||||
run = (await client.post(
|
||||
"/api/production-runs",
|
||||
headers=auth_headers(measurement_tec_user),
|
||||
json={"station_code": station.code, "recipe_id": recipe.id},
|
||||
)).json()
|
||||
|
||||
resp = await client.get(
|
||||
"/api/measurements/task-progress",
|
||||
headers=auth_headers(measurement_tec_user),
|
||||
params={"version_id": version.id, "production_run_id": run["id"]},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
rows = {row["task_id"]: row for row in resp.json()["tasks"]}
|
||||
assert rows[task.id]["state"] == "none"
|
||||
|
||||
await client.post(
|
||||
"/api/measurements/", headers=auth_headers(measurement_tec_user),
|
||||
json={
|
||||
"subtask_id": first.id, "version_id": version.id, "value": 10.0,
|
||||
"production_run_id": run["id"],
|
||||
},
|
||||
)
|
||||
resp = await client.get(
|
||||
"/api/measurements/task-progress",
|
||||
headers=auth_headers(measurement_tec_user),
|
||||
params={"version_id": version.id, "production_run_id": run["id"]},
|
||||
)
|
||||
rows = {row["task_id"]: row for row in resp.json()["tasks"]}
|
||||
assert rows[task.id]["state"] == "complete"
|
||||
|
||||
|
||||
async def test_progress_needs_a_measurement_role(
|
||||
client: AsyncClient, db_session, maker_user, measurement_tec_user,
|
||||
):
|
||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||
version, _task = await _version_and_task(db_session, recipe.id)
|
||||
|
||||
resp = await client.get(
|
||||
"/api/measurements/task-progress",
|
||||
headers=auth_headers(maker_user),
|
||||
params={"version_id": version.id},
|
||||
)
|
||||
assert resp.status_code == 403
|
||||
@@ -119,6 +119,112 @@ def select_recipe():
|
||||
)
|
||||
|
||||
|
||||
def _remember_traceability() -> tuple[str, str]:
|
||||
"""Carry lot and serial from the query string into the session."""
|
||||
lot_number = request.args.get("lot_number", session.get("lot_number", ""))
|
||||
serial_number = request.args.get(
|
||||
"serial_number", session.get("serial_number", ""),
|
||||
)
|
||||
if lot_number:
|
||||
session["lot_number"] = lot_number
|
||||
if serial_number:
|
||||
session["serial_number"] = serial_number
|
||||
return lot_number, serial_number
|
||||
|
||||
|
||||
def _missing_traceability(recipe: dict, lot: str, serial: str) -> list[str]:
|
||||
"""The compulsory fields this recipe is still owed."""
|
||||
missing = []
|
||||
if recipe.get("requires_lot") and not (lot or "").strip():
|
||||
missing.append(_("lotto"))
|
||||
if recipe.get("requires_serial") and not (serial or "").strip():
|
||||
missing.append(_("seriale"))
|
||||
return missing
|
||||
|
||||
|
||||
def _ordered_tasks(recipe_id: int) -> list[dict] | None:
|
||||
"""Tasks of a recipe's current version in execution order, or None on error."""
|
||||
resp = api_client.get(f"/api/recipes/{recipe_id}/tasks")
|
||||
if isinstance(resp, dict) and resp.get("error"):
|
||||
return None
|
||||
tasks = resp if isinstance(resp, list) else resp.get("items", [])
|
||||
return sorted(tasks, key=lambda t: (t.get("order_index", 0), t.get("id", 0)))
|
||||
|
||||
|
||||
def _task_progress(version_id, run_id) -> dict[int, dict]:
|
||||
"""Quotes already taken per measurement task, keyed by task id.
|
||||
|
||||
Never fatal: a list that cannot say which task was left half done is still a
|
||||
usable list, and losing the whole page over a badge would be the worse trade.
|
||||
"""
|
||||
if not version_id:
|
||||
return {}
|
||||
params = {"version_id": version_id}
|
||||
if run_id:
|
||||
params["production_run_id"] = run_id
|
||||
resp = api_client.get("/api/measurements/task-progress", params=params)
|
||||
if not isinstance(resp, dict) or resp.get("error"):
|
||||
return {}
|
||||
return {row["task_id"]: row for row in resp.get("tasks", [])}
|
||||
|
||||
|
||||
def _current_run_id() -> int | None:
|
||||
"""The production open at this station, if there is one."""
|
||||
station_code, _overridden = _current_station()
|
||||
if not station_code:
|
||||
return None
|
||||
# The endpoint answers with the run itself, or null when nothing is running.
|
||||
resp = api_client.get(
|
||||
"/api/production-runs/current", params={"station_code": station_code},
|
||||
)
|
||||
if not isinstance(resp, dict) or resp.get("error"):
|
||||
return None
|
||||
return resp.get("id")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Route: start the guided sequence
|
||||
# ---------------------------------------------------------------------------
|
||||
@measure_bp.route("/start/<int:recipe_id>")
|
||||
@login_required
|
||||
@role_required("MeasurementTec")
|
||||
def start_sequence(recipe_id: int):
|
||||
"""Open the first task of a recipe and let the operator walk the sequence.
|
||||
|
||||
Choosing a recipe used to land on the full task list, which asked the operator
|
||||
to pick a starting point before they had done anything. The sequence is the
|
||||
normal way through; the list is still there, one level down, for when they need
|
||||
to see the whole of it.
|
||||
"""
|
||||
lot_number, serial_number = _remember_traceability()
|
||||
|
||||
recipe_resp = api_client.get(f"/api/recipes/{recipe_id}")
|
||||
if recipe_resp.get("error"):
|
||||
flash(
|
||||
_("Ricetta non trovata: %(detail)s",
|
||||
detail=recipe_resp.get("detail", "")),
|
||||
"error",
|
||||
)
|
||||
return redirect(url_for("measure.select_recipe"))
|
||||
|
||||
missing = _missing_traceability(recipe_resp, lot_number, serial_number)
|
||||
if missing:
|
||||
flash(
|
||||
_("Compila prima: %(fields)s", fields=", ".join(missing)),
|
||||
"error",
|
||||
)
|
||||
return redirect(url_for(
|
||||
"measure.select_recipe", recipe=recipe_resp.get("code", ""),
|
||||
))
|
||||
|
||||
tasks = _ordered_tasks(recipe_id)
|
||||
if not tasks:
|
||||
flash(_("Questa ricetta non ha ancora task definiti."), "error")
|
||||
return redirect(url_for("measure.task_list", recipe_id=recipe_id))
|
||||
|
||||
return redirect(url_for("measure.task_execute", task_id=tasks[0]["id"]))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Route: Task list for a recipe
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -127,17 +233,7 @@ def select_recipe():
|
||||
@role_required("MeasurementTec")
|
||||
def task_list(recipe_id: int):
|
||||
"""Task list for selected recipe."""
|
||||
# Persist lot/serial from query params into session
|
||||
lot_number = request.args.get(
|
||||
"lot_number", session.get("lot_number", ""),
|
||||
)
|
||||
serial_number = request.args.get(
|
||||
"serial_number", session.get("serial_number", ""),
|
||||
)
|
||||
if lot_number:
|
||||
session["lot_number"] = lot_number
|
||||
if serial_number:
|
||||
session["serial_number"] = serial_number
|
||||
lot_number, serial_number = _remember_traceability()
|
||||
|
||||
# Load recipe details
|
||||
recipe_resp = api_client.get(f"/api/recipes/{recipe_id}")
|
||||
@@ -149,22 +245,19 @@ def task_list(recipe_id: int):
|
||||
)
|
||||
return redirect(url_for("measure.select_recipe"))
|
||||
|
||||
# Load tasks for this recipe
|
||||
tasks_resp = api_client.get(f"/api/recipes/{recipe_id}/tasks")
|
||||
if isinstance(tasks_resp, dict) and tasks_resp.get("error"):
|
||||
flash(
|
||||
_("Errore nel caricamento dei task: %(detail)s",
|
||||
detail=tasks_resp.get("detail", "")),
|
||||
"error",
|
||||
)
|
||||
tasks = _ordered_tasks(recipe_id)
|
||||
if tasks is None:
|
||||
flash(_("Errore nel caricamento dei task."), "error")
|
||||
tasks = []
|
||||
else:
|
||||
tasks = tasks_resp if isinstance(tasks_resp, list) else tasks_resp.get("items", [])
|
||||
|
||||
version = recipe_resp.get("current_version") or {}
|
||||
progress = _task_progress(version.get("id"), _current_run_id())
|
||||
|
||||
return render_template(
|
||||
"measure/task_list.html",
|
||||
recipe=recipe_resp,
|
||||
tasks=tasks,
|
||||
progress=progress,
|
||||
lot_number=lot_number,
|
||||
serial_number=serial_number,
|
||||
)
|
||||
|
||||
@@ -31,8 +31,11 @@
|
||||
if (recipe.requires_serial && !this.serial_number.trim()) missing.push('{{ _('seriale') }}');
|
||||
return missing;
|
||||
},
|
||||
/* Straight into the first task. Choosing a recipe used to open the full
|
||||
task list, which asked the operator to decide where to begin before they
|
||||
had done anything; the list is still one tap away from inside the task. */
|
||||
buildTaskUrl(recipeId) {
|
||||
let url = '/measure/tasks/' + recipeId + '?';
|
||||
let url = '/measure/start/' + recipeId + '?';
|
||||
const params = [];
|
||||
if (this.lot_number) params.push('lot_number=' + encodeURIComponent(this.lot_number));
|
||||
if (this.serial_number) params.push('serial_number=' + encodeURIComponent(this.serial_number));
|
||||
@@ -285,13 +288,18 @@
|
||||
: 'group-hover:shadow-md'"
|
||||
class="btn btn-primary w-full justify-center text-sm font-semibold
|
||||
transition-shadow duration-200">
|
||||
<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="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>
|
||||
{{ _('Seleziona') }}
|
||||
<svg class="w-4 h-4 transition-transform group-hover:translate-x-0.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5 3l14 9-14 9V3z"/>
|
||||
</svg>
|
||||
{{ _('AVVIA IN SEQUENZA') }}
|
||||
</a>
|
||||
|
||||
{# The whole list, for when the operator wants to see it or go back to a
|
||||
task left unfinished. Deliberately the quiet one of the two. #}
|
||||
<a :href="'/measure/tasks/' + recipe.id"
|
||||
class="mt-2 block text-center text-xs text-[var(--text-secondary)]
|
||||
hover:text-primary transition-colors">
|
||||
{{ _('Vedi tutti i task') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -96,7 +96,16 @@
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{# Lista task + Riepilogo buttons #}
|
||||
{#
|
||||
Lista task + Completato.
|
||||
|
||||
The list is the second level now: the operator arrives inside the sequence
|
||||
and comes here when they want the whole of it. What used to sit beside it
|
||||
was «Riepilogo», which jumped out of the sequence to a recap - the wrong
|
||||
thing to offer someone halfway through a task. The way forward is
|
||||
«Completato», and on a measurement task it stays shut until the cycle is
|
||||
closed, which is the same rule the footer enforces.
|
||||
#}
|
||||
<div class="shrink-0 flex items-center gap-1.5">
|
||||
<a href="{{ url_for('measure.task_list', recipe_id=task.recipe_id or 0) }}"
|
||||
class="btn btn-secondary text-xs py-1 px-2.5 gap-1">
|
||||
@@ -105,12 +114,15 @@
|
||||
</svg>
|
||||
{{ _('Lista task') }}
|
||||
</a>
|
||||
<button @click="goToSummary()"
|
||||
<button @click="goToNextTask()"
|
||||
:disabled="!canLeaveTask"
|
||||
:title="canLeaveTask ? '' : blockedReason"
|
||||
:class="canLeaveTask ? '' : 'opacity-40 cursor-not-allowed'"
|
||||
class="btn btn-secondary text-xs py-1 px-2.5 gap-1">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
|
||||
</svg>
|
||||
{{ _('Riepilogo') }}
|
||||
{{ _('Completato') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -630,18 +642,30 @@
|
||||
x-text="Math.round(progressPercent) + '%'"></span>
|
||||
</div>
|
||||
|
||||
{# Right: Fine ciclo misura (measurement tasks) / Completato (non-measurement or after cycle) #}
|
||||
{# Right: Fine ciclo misura (measurement tasks) / Task successivo (after cycle) #}
|
||||
<template x-if="isMeasureTask && subtasks.length > 0">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<button x-show="isComplete && !cycleConfirmed"
|
||||
{#
|
||||
Shown from the start, and greyed until every quote has a value. It used
|
||||
to appear only once the task was finished, which left the operator with
|
||||
no sign that the button existed or what would bring it out - a control
|
||||
that is missing teaches nothing, one that is disabled says what is left.
|
||||
#}
|
||||
<button x-show="!cycleConfirmed"
|
||||
x-transition
|
||||
@click="confirmCycle()"
|
||||
class="btn text-xs shrink-0 gap-1 py-1.5 px-3 shadow-md
|
||||
bg-primary text-white hover:bg-primary-700">
|
||||
:disabled="!isComplete"
|
||||
:title="isComplete ? '' : missingQuotesLabel"
|
||||
:class="isComplete
|
||||
? 'bg-primary text-white hover:bg-primary-700 shadow-md'
|
||||
: 'bg-steel-200 dark:bg-steel-700 text-steel-500 dark:text-steel-400 cursor-not-allowed'"
|
||||
class="btn text-xs shrink-0 gap-1 py-1.5 px-3">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
{{ _('Fine ciclo misura') }}
|
||||
<span x-text="isComplete
|
||||
? {{ _('Fine ciclo misura')|tojson_attr }}
|
||||
: missingQuotesLabel"></span>
|
||||
</button>
|
||||
{# Girare il pezzo e rimisurare, senza chiudere il ciclo: a second reading
|
||||
of the same part is not a new one, and must not restart the interval. #}
|
||||
@@ -654,6 +678,9 @@
|
||||
</svg>
|
||||
{{ _('Rimisura') }}
|
||||
</button>
|
||||
{# The cycle is closed; this only walks on. «Completato» is the header's
|
||||
word for finishing a task, and two buttons wearing it would be one too
|
||||
many. #}
|
||||
<button x-show="cycleConfirmed"
|
||||
x-transition
|
||||
@click="goToNextTask()"
|
||||
@@ -662,7 +689,7 @@
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
|
||||
</svg>
|
||||
{{ _('Completato') }}
|
||||
{{ _('Task successivo') }}
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3"/>
|
||||
</svg>
|
||||
@@ -988,6 +1015,40 @@ function taskExecute() {
|
||||
: 0;
|
||||
},
|
||||
|
||||
/* How many quotes are still owed, worded rather than counted down in silence.
|
||||
This is what the greyed «Fine ciclo misura» says instead of nothing. */
|
||||
get missingQuotes() {
|
||||
return Math.max(0, this.totalSubtasks - this.completedCount);
|
||||
},
|
||||
|
||||
get missingQuotesLabel() {
|
||||
const n = this.missingQuotes;
|
||||
return n === 1
|
||||
? {{ _('Manca 1 quota')|tojson }}
|
||||
: {{ _('Mancano')|tojson }} + ' ' + n + ' ' + {{ _('quote')|tojson }};
|
||||
},
|
||||
|
||||
/* Whether «Completato» can take the operator on.
|
||||
|
||||
A documental task is done when they say it is. A measurement task is done
|
||||
when its cycle is closed - otherwise the button would be a way round «Fine
|
||||
ciclo misura», and the quotes it exists to collect would be optional. */
|
||||
get canLeaveTask() {
|
||||
if (this.blockedByTolerance) return false;
|
||||
if (this.isMeasureTask && this.subtasks.length > 0) {
|
||||
return this.cycleConfirmed;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
get blockedReason() {
|
||||
if (this.blockedByTolerance) {
|
||||
return {{ _("Serve l'autorizzazione del capoturno")|tojson }};
|
||||
}
|
||||
if (!this.isComplete) return this.missingQuotesLabel;
|
||||
return {{ _('Chiudi prima il ciclo di misura')|tojson }};
|
||||
},
|
||||
|
||||
// ---- Pass/fail logic ----
|
||||
get passFailStatus() {
|
||||
if (this.currentValue === null || !this.currentSubtask) return null;
|
||||
|
||||
@@ -97,14 +97,14 @@
|
||||
{{ _('Compila prima:') }} {{ missing_trace|join(', ') }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('measure.task_execute', task_id=tasks[0].id) }}"
|
||||
<a href="{{ url_for('measure.start_sequence', recipe_id=recipe.id) }}"
|
||||
class="btn gap-3 w-full sm:w-auto justify-center text-lg font-bold
|
||||
bg-red-600 hover:bg-red-700 text-white shadow-lg hover:shadow-xl
|
||||
px-8 py-3 rounded-xl transition-all duration-200">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5 3l14 9-14 9V3z"/>
|
||||
</svg>
|
||||
{{ _('AVVIA') }}
|
||||
{{ _('AVVIA IN SEQUENZA') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -162,7 +162,12 @@
|
||||
{% if tasks %}
|
||||
<div class="space-y-2.5">
|
||||
{% for task in tasks %}
|
||||
<div class="tmf-card hover:border-primary/30 transition-all duration-200 group">
|
||||
{# How far this task got. A task walked away from halfway through used to look
|
||||
exactly like one never opened; this is what tells them apart. #}
|
||||
{% set prog = (progress|default({})).get(task.id) %}
|
||||
<div class="tmf-card transition-all duration-200 group
|
||||
{% if prog and prog.state == 'partial' %}border-amber-300 dark:border-amber-700
|
||||
{% else %}hover:border-primary/30{% endif %}">
|
||||
<div class="p-3 sm:p-4">
|
||||
<div class="flex flex-row items-center gap-3">
|
||||
|
||||
@@ -208,7 +213,27 @@
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
{% if task.subtask_count is defined or task.subtasks %}
|
||||
{% if prog and prog.state in ('partial', 'complete') %}
|
||||
<span class="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[11px] font-semibold
|
||||
{% if prog.state == 'complete' %}
|
||||
bg-measure-pass/10 text-measure-pass
|
||||
{% else %}
|
||||
bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300
|
||||
{% endif %}">
|
||||
{% if prog.state == 'complete' %}
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/>
|
||||
</svg>
|
||||
{{ _('Completato') }}
|
||||
{% else %}
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 8v4l2.5 2.5M12 21a9 9 0 110-18 9 9 0 010 18z"/>
|
||||
</svg>
|
||||
{{ _('Incompiuto') }}
|
||||
{% endif %}
|
||||
<span class="font-mono">{{ prog.measured }}/{{ prog.quotes }}</span>
|
||||
</span>
|
||||
{% elif task.subtask_count is defined or task.subtasks %}
|
||||
<span class="inline-flex items-center gap-1 text-xs text-[var(--text-secondary)]"
|
||||
title="{{ _('misurazioni') }}">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
||||
@@ -233,23 +258,23 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Action Button (Maker only — operators start the guided flow with AVVIA) -->
|
||||
{% if current_user and 'Maker' in current_user.get('roles', []) %}
|
||||
{#
|
||||
Opening one task on its own. The sequence is the normal way through the
|
||||
recipe - this is the way back to a task left unfinished, which is why the
|
||||
operator has it now and not only the Maker: a list that says "incompiuto"
|
||||
and gives you no way there would be a complaint, not a feature.
|
||||
#}
|
||||
<div class="shrink-0 sm:ml-4">
|
||||
<a href="{{ url_for('measure.task_execute', task_id=task.id) }}"
|
||||
class="btn btn-primary gap-2 w-full sm:w-auto justify-center
|
||||
class="btn btn-secondary gap-2 w-full sm:w-auto justify-center
|
||||
group-hover:shadow-md transition-shadow duration-200">
|
||||
<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="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
{{ _('Visualizza Task') }}
|
||||
<svg class="w-4 h-4 transition-transform group-hover:translate-x-0.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
|
||||
</svg>
|
||||
{{ _('Visualizza singolo TASK') }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -73,6 +73,27 @@ def logged_in_client(flask_app):
|
||||
yield test_client
|
||||
|
||||
|
||||
def api_get_router(routes: dict, default=None):
|
||||
"""A ``get`` side effect that answers by endpoint instead of by turn.
|
||||
|
||||
A list of responses in call order breaks the moment a page asks the server one
|
||||
more question - which is how every page grows. Matching on the endpoint says
|
||||
what a test actually means: this is what /api/recipes/3 replies.
|
||||
|
||||
Keys are matched as substrings of the endpoint, longest first, so
|
||||
``/api/recipes/3/tasks`` wins over ``/api/recipes/3``.
|
||||
"""
|
||||
ordered = sorted(routes.items(), key=lambda kv: -len(kv[0]))
|
||||
|
||||
def _get(endpoint, *args, **kwargs):
|
||||
for prefix, response in ordered:
|
||||
if prefix in endpoint:
|
||||
return response() if callable(response) else response
|
||||
return {} if default is None else default
|
||||
|
||||
return _get
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_api_client():
|
||||
"""Patch the api_client singleton used in blueprints.
|
||||
|
||||
@@ -4,6 +4,8 @@ Covers recipe selection, task list, login requirement, and measurement submissio
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from tests.conftest import api_get_router
|
||||
|
||||
|
||||
class TestSelectRecipe:
|
||||
"""GET /measure/select tests."""
|
||||
@@ -36,22 +38,129 @@ class TestTaskList:
|
||||
|
||||
def test_task_list_renders(self, logged_in_client, mock_api_client):
|
||||
"""Task list page renders with recipe and task data."""
|
||||
# First call: recipe details (dict), second call: tasks list.
|
||||
# The route calls tasks_resp.get("error") so the mock must return
|
||||
# a dict (not a bare list) to avoid AttributeError.
|
||||
mock_api_client.get.side_effect = [
|
||||
{"id": 1, "code": "REC-001", "name": "Test Recipe"},
|
||||
{
|
||||
mock_api_client.get.side_effect = api_get_router({
|
||||
"/api/recipes/1/tasks": {
|
||||
"items": [
|
||||
{"id": 1, "title": "Task 1", "order_index": 0},
|
||||
{"id": 2, "title": "Task 2", "order_index": 1},
|
||||
],
|
||||
},
|
||||
]
|
||||
"/api/recipes/1": {"id": 1, "code": "REC-001", "name": "Test Recipe"},
|
||||
"/api/production-runs/current": None,
|
||||
})
|
||||
|
||||
resp = logged_in_client.get("/measure/tasks/1")
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_task_list_marks_the_task_left_half_done(
|
||||
self, logged_in_client, mock_api_client,
|
||||
):
|
||||
"""A task with some of its quotes taken says so, and says how many."""
|
||||
with logged_in_client.session_transaction() as sess:
|
||||
sess["language"] = "it"
|
||||
mock_api_client.get.side_effect = api_get_router({
|
||||
"/api/recipes/1/tasks": [
|
||||
{"id": 7, "title": "Misura", "order_index": 0, "task_type": "measure"},
|
||||
{"id": 8, "title": "Nota", "order_index": 1, "task_type": "note"},
|
||||
],
|
||||
"/api/recipes/1": {
|
||||
"id": 1, "code": "REC-001", "name": "Test Recipe",
|
||||
"current_version": {"id": 42, "version_number": 1},
|
||||
},
|
||||
"/api/production-runs/current": None,
|
||||
"/api/measurements/task-progress": {
|
||||
"tasks": [
|
||||
{"task_id": 7, "quotes": 3, "measured": 1, "state": "partial"},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
resp = logged_in_client.get("/measure/tasks/1")
|
||||
assert resp.status_code == 200
|
||||
html = resp.get_data(as_text=True)
|
||||
assert "Incompiuto" in html
|
||||
assert "1/3" in html
|
||||
|
||||
def test_task_list_survives_a_progress_lookup_that_fails(
|
||||
self, logged_in_client, mock_api_client,
|
||||
):
|
||||
"""Losing the badges must not lose the page."""
|
||||
mock_api_client.get.side_effect = api_get_router({
|
||||
"/api/recipes/1/tasks": [
|
||||
{"id": 7, "title": "Misura", "order_index": 0, "task_type": "measure"},
|
||||
],
|
||||
"/api/recipes/1": {
|
||||
"id": 1, "code": "REC-001", "name": "Test Recipe",
|
||||
"current_version": {"id": 42},
|
||||
},
|
||||
"/api/production-runs/current": None,
|
||||
"/api/measurements/task-progress": {
|
||||
"error": True, "status_code": 500, "detail": "boom",
|
||||
},
|
||||
})
|
||||
|
||||
resp = logged_in_client.get("/measure/tasks/1")
|
||||
assert resp.status_code == 200
|
||||
assert "Misura" in resp.get_data(as_text=True)
|
||||
|
||||
|
||||
class TestStartSequence:
|
||||
"""GET /measure/start/<recipe_id> — the operator's way in."""
|
||||
|
||||
def test_start_goes_to_the_first_task(self, logged_in_client, mock_api_client):
|
||||
mock_api_client.get.side_effect = api_get_router({
|
||||
"/api/recipes/1/tasks": [
|
||||
{"id": 31, "title": "Nota", "order_index": 1},
|
||||
{"id": 30, "title": "Prima", "order_index": 0},
|
||||
],
|
||||
"/api/recipes/1": {"id": 1, "code": "REC-001", "name": "Test Recipe"},
|
||||
})
|
||||
|
||||
resp = logged_in_client.get("/measure/start/1?lot_number=L1")
|
||||
assert resp.status_code == 302
|
||||
assert resp.headers["Location"].endswith("/measure/execute/30")
|
||||
|
||||
def test_start_remembers_the_traceability(self, logged_in_client, mock_api_client):
|
||||
"""The list used to be where lot and serial were stored; the sequence
|
||||
skips it, so the storing has to happen on the way in."""
|
||||
mock_api_client.get.side_effect = api_get_router({
|
||||
"/api/recipes/1/tasks": [{"id": 30, "title": "Prima", "order_index": 0}],
|
||||
"/api/recipes/1": {"id": 1, "code": "REC-001", "name": "Test Recipe"},
|
||||
})
|
||||
|
||||
logged_in_client.get("/measure/start/1?lot_number=L9&serial_number=S9")
|
||||
with logged_in_client.session_transaction() as sess:
|
||||
assert sess["lot_number"] == "L9"
|
||||
assert sess["serial_number"] == "S9"
|
||||
|
||||
def test_start_refuses_without_the_compulsory_lot(
|
||||
self, logged_in_client, mock_api_client,
|
||||
):
|
||||
"""Point 8 holds on this door too: it is a way into the measurement."""
|
||||
mock_api_client.get.side_effect = api_get_router({
|
||||
"/api/recipes/1/tasks": [{"id": 30, "title": "Prima", "order_index": 0}],
|
||||
"/api/recipes/1": {
|
||||
"id": 1, "code": "REC-001", "name": "Test Recipe",
|
||||
"requires_lot": True,
|
||||
},
|
||||
})
|
||||
|
||||
resp = logged_in_client.get("/measure/start/1")
|
||||
assert resp.status_code == 302
|
||||
assert "/measure/select" in resp.headers["Location"]
|
||||
|
||||
def test_start_without_tasks_falls_back_to_the_list(
|
||||
self, logged_in_client, mock_api_client,
|
||||
):
|
||||
mock_api_client.get.side_effect = api_get_router({
|
||||
"/api/recipes/1/tasks": [],
|
||||
"/api/recipes/1": {"id": 1, "code": "REC-001", "name": "Test Recipe"},
|
||||
})
|
||||
|
||||
resp = logged_in_client.get("/measure/start/1")
|
||||
assert resp.status_code == 302
|
||||
assert resp.headers["Location"].endswith("/measure/tasks/1")
|
||||
|
||||
|
||||
class TestTaskComplete:
|
||||
"""GET /measure/complete/<recipe_id> tests."""
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
"""Point 10: the operator's way through a recipe.
|
||||
|
||||
The sequence is the normal path and the list is a place you go on purpose. What
|
||||
these tests hold on to is the part that is easy to undo by accident: the way in
|
||||
lands on a task, the list says which task was left unfinished and lets the
|
||||
operator back into it, «Fine ciclo misura» is visible before it is usable, and
|
||||
nothing in any of it opens a door to the statistics (point 15).
|
||||
"""
|
||||
from tests.conftest import api_get_router
|
||||
|
||||
TASK = {
|
||||
"id": 11,
|
||||
"recipe_id": 3,
|
||||
"version_id": 5,
|
||||
"task_type": "measure",
|
||||
"title": "Quota",
|
||||
"directive": None,
|
||||
"description": None,
|
||||
"file_path": None,
|
||||
"file_type": None,
|
||||
"annotations_json": None,
|
||||
"subtasks": [{
|
||||
"id": 21, "marker_number": 1, "description": "Altezza", "order_index": 0,
|
||||
"nominal": 10.0, "utl": 10.5, "uwl": 10.2, "lwl": 9.8, "ltl": 9.5,
|
||||
"unit": "mm",
|
||||
}],
|
||||
}
|
||||
|
||||
RECIPE = {
|
||||
"id": 3, "code": "REC-1", "name": "Ricetta",
|
||||
"measurement_interval_minutes": 30, "allow_manual_input": True,
|
||||
"current_version": {"id": 5, "version_number": 1},
|
||||
}
|
||||
|
||||
|
||||
def _italian(client):
|
||||
with client.session_transaction() as sess:
|
||||
sess["language"] = "it"
|
||||
|
||||
|
||||
def _operator_only(client):
|
||||
"""Strip the Maker role: this is what the shop floor account looks like."""
|
||||
with client.session_transaction() as sess:
|
||||
user = dict(sess["user"])
|
||||
user["roles"] = ["MeasurementTec"]
|
||||
user["is_admin"] = False
|
||||
sess["user"] = user
|
||||
|
||||
|
||||
def _execute_page(client, mock_api_client):
|
||||
_italian(client)
|
||||
mock_api_client.get.side_effect = api_get_router({
|
||||
"/api/tasks/11": TASK,
|
||||
"/api/recipes/3/tasks": [{"id": 11, "order_index": 0}],
|
||||
"/api/recipes/3": RECIPE,
|
||||
})
|
||||
resp = client.get("/measure/execute/11")
|
||||
assert resp.status_code == 200
|
||||
return resp.get_data(as_text=True)
|
||||
|
||||
|
||||
def _list_page(client, mock_api_client, progress=None):
|
||||
_italian(client)
|
||||
mock_api_client.get.side_effect = api_get_router({
|
||||
"/api/recipes/3/tasks": [
|
||||
{"id": 11, "title": "Misura", "order_index": 0, "task_type": "measure"},
|
||||
],
|
||||
"/api/recipes/3": RECIPE,
|
||||
"/api/production-runs/current": None,
|
||||
"/api/measurements/task-progress": {"tasks": progress or []},
|
||||
})
|
||||
resp = client.get("/measure/tasks/3")
|
||||
assert resp.status_code == 200
|
||||
return resp.get_data(as_text=True)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# The way in: a recipe opens on a task, not on a list
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_the_selection_screen_starts_the_sequence(
|
||||
logged_in_client, mock_api_client, monkeypatch,
|
||||
):
|
||||
_italian(logged_in_client)
|
||||
# The page refuses to render without a station, which is the right answer on a
|
||||
# real terminal and only an obstacle here.
|
||||
monkeypatch.setattr("blueprints.measure.Config.STATION_CODE", "ST-TEST")
|
||||
mock_api_client.get_station_recipes.return_value = []
|
||||
resp = logged_in_client.get("/measure/select")
|
||||
assert resp.status_code == 200
|
||||
html = resp.get_data(as_text=True)
|
||||
assert "'/measure/start/'" in html
|
||||
# The full list is still reachable, deliberately as the quiet option.
|
||||
assert "'/measure/tasks/'" in html
|
||||
|
||||
|
||||
def test_avvia_on_the_list_starts_the_sequence(logged_in_client, mock_api_client):
|
||||
html = _list_page(logged_in_client, mock_api_client)
|
||||
assert "/measure/start/3" in html
|
||||
assert "AVVIA IN SEQUENZA" in html
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# The list: second level, and it says what was left unfinished
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_the_operator_can_open_a_single_task(logged_in_client, mock_api_client):
|
||||
"""Without this, «incompiuto» would be a label with no way to act on it."""
|
||||
_operator_only(logged_in_client)
|
||||
html = _list_page(logged_in_client, mock_api_client)
|
||||
assert "Visualizza singolo TASK" in html
|
||||
assert "/measure/execute/11" in html
|
||||
|
||||
|
||||
def test_a_half_measured_task_is_marked(logged_in_client, mock_api_client):
|
||||
html = _list_page(
|
||||
logged_in_client, mock_api_client,
|
||||
progress=[{"task_id": 11, "quotes": 3, "measured": 2, "state": "partial"}],
|
||||
)
|
||||
assert "Incompiuto" in html
|
||||
assert "2/3" in html
|
||||
|
||||
|
||||
def test_a_finished_task_is_marked(logged_in_client, mock_api_client):
|
||||
html = _list_page(
|
||||
logged_in_client, mock_api_client,
|
||||
progress=[{"task_id": 11, "quotes": 3, "measured": 3, "state": "complete"}],
|
||||
)
|
||||
assert "Completato" in html
|
||||
assert "3/3" in html
|
||||
|
||||
|
||||
def test_an_untouched_task_says_nothing(logged_in_client, mock_api_client):
|
||||
"""A list that shouts at every row is a list nobody reads."""
|
||||
html = _list_page(
|
||||
logged_in_client, mock_api_client,
|
||||
progress=[{"task_id": 11, "quotes": 3, "measured": 0, "state": "none"}],
|
||||
)
|
||||
assert "Incompiuto" not in html
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Inside the task: «Completato» forward, «Fine ciclo misura» visible but shut
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_the_header_offers_completato_not_the_summary(
|
||||
logged_in_client, mock_api_client,
|
||||
):
|
||||
html = _execute_page(logged_in_client, mock_api_client)
|
||||
assert 'x-data="taskExecute()"' in html
|
||||
# The header control moves the operator on and is gated by the same rule as
|
||||
# the footer, rather than jumping out of the sequence to a recap.
|
||||
assert 'canLeaveTask' in html
|
||||
assert '@click="goToNextTask()"' in html
|
||||
|
||||
|
||||
def test_fine_ciclo_is_shown_before_it_can_be_used(
|
||||
logged_in_client, mock_api_client,
|
||||
):
|
||||
"""It used to appear only once the task was already finished."""
|
||||
html = _execute_page(logged_in_client, mock_api_client)
|
||||
assert 'x-show="!cycleConfirmed"' in html
|
||||
assert ':disabled="!isComplete"' in html
|
||||
assert "Fine ciclo misura" in html
|
||||
|
||||
|
||||
def test_the_missing_quotes_are_counted_out_loud(
|
||||
logged_in_client, mock_api_client,
|
||||
):
|
||||
html = _execute_page(logged_in_client, mock_api_client)
|
||||
assert "missingQuotesLabel" in html
|
||||
assert "Mancano" in html
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Point 15: none of this may open a way to the statistics
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_the_operator_flow_never_links_to_the_statistics(
|
||||
logged_in_client, mock_api_client,
|
||||
):
|
||||
_operator_only(logged_in_client)
|
||||
pages = [
|
||||
_list_page(logged_in_client, mock_api_client),
|
||||
_execute_page(logged_in_client, mock_api_client),
|
||||
]
|
||||
for html in pages:
|
||||
assert "/statistics" not in html
|
||||
@@ -24,6 +24,8 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.conftest import api_get_router
|
||||
|
||||
|
||||
# Match every inline <script>…</script> (i.e. without `src=`) so we don't try
|
||||
# to syntax-check Alpine.js / Plotly bundles served from a CDN.
|
||||
@@ -307,13 +309,20 @@ def test_task_list_inline_js_is_valid(logged_in_client, mock_measure_api):
|
||||
with it, and the operator would simply never be called back.
|
||||
"""
|
||||
_force_italian(logged_in_client)
|
||||
mock_measure_api.get.side_effect = [
|
||||
{"id": 3, "code": "REC-3", "name": "Ricetta", "description": None},
|
||||
[{
|
||||
mock_measure_api.get.side_effect = api_get_router({
|
||||
"/api/recipes/3/tasks": [{
|
||||
"id": 11, "order_index": 0, "title": "Quota d'ingresso",
|
||||
"task_type": "measure", "subtasks": [], "file_path": None,
|
||||
}],
|
||||
]
|
||||
"/api/recipes/3": {
|
||||
"id": 3, "code": "REC-3", "name": "Ricetta", "description": None,
|
||||
"current_version": {"id": 5},
|
||||
},
|
||||
"/api/production-runs/current": None,
|
||||
"/api/measurements/task-progress": {
|
||||
"tasks": [{"task_id": 11, "quotes": 2, "measured": 1, "state": "partial"}],
|
||||
},
|
||||
})
|
||||
|
||||
resp = logged_in_client.get("/measure/tasks/3")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@@ -3,7 +3,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: TieMeasureFlow 1.0\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-07-28 20:48+0000\n"
|
||||
"POT-Creation-Date: 2026-07-28 21:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: en\n"
|
||||
@@ -129,43 +129,64 @@ msgstr "Current station: %(code)s"
|
||||
msgid "Errore nel caricamento delle ricette: %(detail)s"
|
||||
msgstr "Error loading recipes: %(detail)s"
|
||||
|
||||
#: blueprints/measure.py:146 blueprints/measure.py:237
|
||||
# Measure - Task List
|
||||
#: blueprints/measure.py:139 templates/measure/select_recipe.html:30
|
||||
#: templates/measure/task_list.html:86
|
||||
msgid "lotto"
|
||||
msgstr "lot"
|
||||
|
||||
#: blueprints/measure.py:141 templates/measure/select_recipe.html:31
|
||||
#: templates/measure/task_list.html:87
|
||||
msgid "seriale"
|
||||
msgstr "serial"
|
||||
|
||||
#: blueprints/measure.py:204 blueprints/measure.py:242
|
||||
#: blueprints/measure.py:330
|
||||
#, python-format
|
||||
msgid "Ricetta non trovata: %(detail)s"
|
||||
msgstr "Recipe not found: %(detail)s"
|
||||
|
||||
#: blueprints/measure.py:156
|
||||
#: blueprints/measure.py:213
|
||||
#, python-format
|
||||
msgid "Errore nel caricamento dei task: %(detail)s"
|
||||
msgstr "Error loading tasks: %(detail)s"
|
||||
msgid "Compila prima: %(fields)s"
|
||||
msgstr "Fill in first: %(fields)s"
|
||||
|
||||
#: blueprints/measure.py:185
|
||||
#: blueprints/measure.py:222 templates/measure/task_list.html:297
|
||||
msgid "Questa ricetta non ha ancora task definiti."
|
||||
msgstr "This recipe has no tasks defined yet."
|
||||
|
||||
#: blueprints/measure.py:250
|
||||
|
||||
msgid "Errore nel caricamento dei task."
|
||||
msgstr "Error loading tasks."
|
||||
|
||||
#: blueprints/measure.py:278
|
||||
#, python-format
|
||||
msgid "Task non trovato: %(detail)s"
|
||||
msgstr "Task not found: %(detail)s"
|
||||
|
||||
#: blueprints/measure.py:306
|
||||
#: blueprints/measure.py:399
|
||||
msgid "Codice non fornito"
|
||||
msgstr "Code not provided"
|
||||
|
||||
#: blueprints/measure.py:312 templates/measure/select_recipe.html:57
|
||||
#: blueprints/measure.py:405 templates/measure/select_recipe.html:60
|
||||
msgid "Ricetta non trovata"
|
||||
msgstr "Recipe not found"
|
||||
|
||||
#: blueprints/measure.py:368
|
||||
#: blueprints/measure.py:461
|
||||
msgid "Dati mancanti: subtask_id, version_id e value sono obbligatori"
|
||||
msgstr "Missing data: subtask_id, version_id and value are required"
|
||||
|
||||
#: blueprints/measure.py:393 templates/admin/stations.html:549
|
||||
#: blueprints/measure.py:486 templates/admin/stations.html:549
|
||||
#: templates/maker/recipe_editor.html:598
|
||||
msgid "Errore nel salvataggio"
|
||||
msgstr "Error saving"
|
||||
|
||||
#: blueprints/measure.py:437 blueprints/measure.py:542
|
||||
#: blueprints/measure.py:530 blueprints/measure.py:635
|
||||
msgid "Username e password richiesti"
|
||||
msgstr "Username and password required"
|
||||
|
||||
#: blueprints/measure.py:463 blueprints/measure.py:480
|
||||
#: blueprints/measure.py:556 blueprints/measure.py:573
|
||||
#: templates/errors/station_not_configured.html:2
|
||||
#: templates/errors/station_not_configured.html:16
|
||||
msgid "Stazione non configurata"
|
||||
@@ -371,8 +392,8 @@ msgstr "Optional notes"
|
||||
#: templates/maker/task_editor.html:312 templates/maker/task_editor.html:421
|
||||
#: templates/maker/task_editor.html:782 templates/maker/task_editor.html:901
|
||||
#: templates/maker/task_editor.html:966 templates/maker/task_editor.html:1071
|
||||
#: templates/measure/select_recipe.html:405
|
||||
#: templates/measure/task_execute.html:860
|
||||
#: templates/measure/select_recipe.html:413
|
||||
#: templates/measure/task_execute.html:887
|
||||
msgid "Annulla"
|
||||
msgstr "Cancel"
|
||||
|
||||
@@ -388,7 +409,7 @@ msgstr "Create Station"
|
||||
#: templates/admin/stations.html:241 templates/admin/users.html:299
|
||||
#: templates/maker/recipe_editor.html:107
|
||||
#: templates/maker/recipe_editor.html:490 templates/maker/task_drawing.html:61
|
||||
#: templates/measure/task_execute.html:412
|
||||
#: templates/measure/task_execute.html:424
|
||||
msgid "Salvataggio..."
|
||||
msgstr "Saving..."
|
||||
|
||||
@@ -517,7 +538,7 @@ msgstr "New User"
|
||||
#: templates/admin/users.html:48 templates/admin/users.html:173
|
||||
#: templates/admin/users.html:179 templates/auth/login.html:35
|
||||
#: templates/auth/login.html:49 templates/auth/profile.html:36
|
||||
#: templates/measure/task_execute.html:842
|
||||
#: templates/measure/task_execute.html:869
|
||||
msgid "Username"
|
||||
msgstr "Username"
|
||||
|
||||
@@ -569,7 +590,7 @@ msgstr "Username cannot be changed"
|
||||
|
||||
#: templates/admin/users.html:206 templates/admin/users.html:214
|
||||
#: templates/auth/login.html:57 templates/auth/login.html:71
|
||||
#: templates/measure/task_execute.html:847
|
||||
#: templates/measure/task_execute.html:874
|
||||
msgid "Password"
|
||||
msgstr "Password"
|
||||
|
||||
@@ -724,8 +745,8 @@ msgstr "Logout"
|
||||
|
||||
#: templates/components/barcode_scanner.html:21
|
||||
#: templates/components/barcode_scanner.html:54
|
||||
#: templates/measure/select_recipe.html:128
|
||||
#: templates/measure/select_recipe.html:357
|
||||
#: templates/measure/select_recipe.html:131
|
||||
#: templates/measure/select_recipe.html:365
|
||||
msgid "Scansiona Barcode"
|
||||
msgstr "Scan Barcode"
|
||||
|
||||
@@ -824,14 +845,14 @@ msgid "Misura solo da calibro: questa ricetta non ammette valori digitati"
|
||||
msgstr "Caliper only: this recipe does not accept typed values"
|
||||
|
||||
#: templates/components/production_clock.html:42
|
||||
#: templates/measure/task_execute.html:460
|
||||
#: templates/measure/task_execute.html:472
|
||||
msgid "Prossima misurazione tra"
|
||||
msgstr "Next measurement in"
|
||||
|
||||
#: templates/components/production_clock.html:49
|
||||
#: templates/components/production_clock.html:62
|
||||
#: templates/measure/task_execute.html:463
|
||||
#: templates/measure/task_execute.html:542
|
||||
#: templates/measure/task_execute.html:475
|
||||
#: templates/measure/task_execute.html:554
|
||||
msgid "Misurazione in ritardo di"
|
||||
msgstr "Measurement overdue by"
|
||||
|
||||
@@ -840,27 +861,27 @@ msgid "Linea ferma — conto alla rovescia congelato a"
|
||||
msgstr "Line stopped — countdown frozen at"
|
||||
|
||||
#: templates/components/production_clock.html:62
|
||||
#: templates/measure/task_execute.html:536
|
||||
#: templates/measure/task_execute.html:548
|
||||
msgid "Linea ferma"
|
||||
msgstr "Line stopped"
|
||||
|
||||
#: templates/components/production_clock.html:74
|
||||
#: templates/measure/task_execute.html:472
|
||||
#: templates/measure/task_execute.html:484
|
||||
msgid "Ciclo"
|
||||
msgstr "Cycle"
|
||||
|
||||
#: templates/components/production_clock.html:92
|
||||
#: templates/measure/task_execute.html:704
|
||||
#: templates/measure/task_execute.html:731
|
||||
msgid "È ora di misurare"
|
||||
msgstr "Time to measure"
|
||||
|
||||
#: templates/components/production_clock.html:95
|
||||
#: templates/measure/task_execute.html:706
|
||||
#: templates/measure/task_execute.html:733
|
||||
msgid "Ritorno alla misurazione tra"
|
||||
msgstr "Returning to the measurement in"
|
||||
|
||||
#: templates/components/production_clock.html:101
|
||||
#: templates/measure/task_execute.html:711
|
||||
#: templates/measure/task_execute.html:738
|
||||
msgid "Vai alla misura"
|
||||
msgstr "Go to the measurement"
|
||||
|
||||
@@ -913,8 +934,8 @@ msgstr "Preview"
|
||||
#: templates/maker/recipe_editor.html:128 templates/maker/recipe_list.html:246
|
||||
#: templates/maker/task_drawing.html:106 templates/maker/task_editor.html:130
|
||||
#: templates/measure/task_complete.html:171
|
||||
#: templates/measure/task_execute.html:615 templates/measure/task_list.html:2
|
||||
#: templates/measure/task_list.html:180
|
||||
#: templates/measure/task_execute.html:627 templates/measure/task_list.html:2
|
||||
#: templates/measure/task_list.html:185
|
||||
msgid "Task"
|
||||
msgstr "Task"
|
||||
|
||||
@@ -1089,9 +1110,9 @@ msgid "Errore durante eliminazione"
|
||||
msgstr "Error during deletion"
|
||||
|
||||
# Recipe Selection Additional
|
||||
#: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:72
|
||||
#: templates/measure/task_execute.html:1362
|
||||
#: templates/measure/task_execute.html:1672
|
||||
#: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:75
|
||||
#: templates/measure/task_execute.html:1423
|
||||
#: templates/measure/task_execute.html:1733
|
||||
msgid "Errore di connessione"
|
||||
msgstr "Connection Error"
|
||||
|
||||
@@ -1124,7 +1145,7 @@ msgid "ricetta trovata"
|
||||
msgstr "recipe found"
|
||||
|
||||
#: templates/maker/recipe_list.html:144
|
||||
#: templates/measure/select_recipe.html:196
|
||||
#: templates/measure/select_recipe.html:199
|
||||
msgid "ricette trovate"
|
||||
msgstr "recipes found"
|
||||
|
||||
@@ -1142,7 +1163,7 @@ msgid "Versioni"
|
||||
msgstr "Versions"
|
||||
|
||||
#: templates/maker/recipe_list.html:297
|
||||
#: templates/measure/select_recipe.html:311
|
||||
#: templates/measure/select_recipe.html:319
|
||||
msgid "Nessuna ricetta trovata"
|
||||
msgstr "No recipe found"
|
||||
|
||||
@@ -1221,7 +1242,7 @@ msgid "Apri PDF"
|
||||
msgstr "Open PDF"
|
||||
|
||||
#: templates/maker/recipe_preview.html:254
|
||||
#: templates/measure/task_execute.html:287
|
||||
#: templates/measure/task_execute.html:299
|
||||
msgid "Nessuna immagine allegata"
|
||||
msgstr "No image attached"
|
||||
|
||||
@@ -1232,7 +1253,7 @@ msgstr "Measurement Points"
|
||||
#: templates/maker/recipe_preview.html:299 templates/maker/task_editor.html:579
|
||||
#: templates/maker/task_editor.html:721
|
||||
#: templates/measure/task_complete.html:173
|
||||
#: templates/measure/task_execute.html:321
|
||||
#: templates/measure/task_execute.html:333
|
||||
msgid "Nominale"
|
||||
msgstr "Nominal"
|
||||
|
||||
@@ -1286,7 +1307,6 @@ msgid "Torna ai Task"
|
||||
msgstr "Back to Tasks"
|
||||
|
||||
#: templates/maker/task_drawing.html:205 templates/maker/task_drawing.html:209
|
||||
#: templates/measure/select_recipe.html:291
|
||||
msgid "Seleziona"
|
||||
msgstr "Select"
|
||||
|
||||
@@ -1402,18 +1422,18 @@ msgid "Tipo"
|
||||
msgstr "Type"
|
||||
|
||||
#: templates/maker/task_editor.html:277 templates/maker/task_editor.html:543
|
||||
#: templates/measure/task_list.html:198
|
||||
#: templates/measure/task_list.html:203
|
||||
msgid "Nota"
|
||||
msgstr "Note"
|
||||
|
||||
#: templates/maker/task_editor.html:278 templates/maker/task_editor.html:544
|
||||
#: templates/measure/task_execute.html:309 templates/measure/task_list.html:196
|
||||
#: templates/measure/task_execute.html:321 templates/measure/task_list.html:201
|
||||
msgid "Misura"
|
||||
msgstr "Measure"
|
||||
|
||||
# Maker - Task Editor
|
||||
#: templates/maker/task_editor.html:279 templates/maker/task_editor.html:545
|
||||
#: templates/measure/task_list.html:197
|
||||
#: templates/measure/task_list.html:202
|
||||
msgid "Disegno"
|
||||
msgstr "Drawing"
|
||||
|
||||
@@ -1444,7 +1464,7 @@ msgstr "Drag to reorder"
|
||||
|
||||
#: templates/maker/task_editor.html:390
|
||||
#: templates/maker/version_history.html:188
|
||||
#: templates/measure/task_list.html:213
|
||||
#: templates/measure/task_list.html:238
|
||||
msgid "misurazioni"
|
||||
msgstr "measurements"
|
||||
|
||||
@@ -1710,7 +1730,7 @@ msgid "Misurazione aggiunta"
|
||||
msgstr "Measurement added"
|
||||
|
||||
#: templates/maker/task_editor.html:1685
|
||||
#: templates/measure/task_execute.html:1170
|
||||
#: templates/measure/task_execute.html:1231
|
||||
msgid "Errore nel salvataggio della misurazione"
|
||||
msgstr "Error saving measurement"
|
||||
|
||||
@@ -1773,122 +1793,123 @@ msgstr ""
|
||||
|
||||
# Measure - Recipe Selection
|
||||
#: templates/measure/select_recipe.html:2
|
||||
#: templates/measure/select_recipe.html:94
|
||||
#: templates/measure/select_recipe.html:97
|
||||
msgid "Seleziona Ricetta"
|
||||
msgstr "Select Recipe"
|
||||
|
||||
# Measure - Task List
|
||||
#: templates/measure/select_recipe.html:30 templates/measure/task_list.html:86
|
||||
msgid "lotto"
|
||||
msgstr "lot"
|
||||
|
||||
#: templates/measure/select_recipe.html:31 templates/measure/task_list.html:87
|
||||
msgid "seriale"
|
||||
msgstr "serial"
|
||||
|
||||
#: templates/measure/select_recipe.html:64
|
||||
#: templates/measure/select_recipe.html:277 templates/measure/task_list.html:97
|
||||
#: templates/measure/select_recipe.html:67
|
||||
#: templates/measure/select_recipe.html:280 templates/measure/task_list.html:97
|
||||
msgid "Compila prima:"
|
||||
msgstr "Fill in first:"
|
||||
|
||||
#: templates/measure/select_recipe.html:97
|
||||
#: templates/measure/select_recipe.html:100
|
||||
msgid "Scegli la ricetta di misura da eseguire"
|
||||
msgstr "Choose the measurement recipe to execute"
|
||||
|
||||
#: templates/measure/select_recipe.html:100
|
||||
#: templates/measure/select_recipe.html:103
|
||||
msgid "Stazione"
|
||||
msgstr "Station"
|
||||
|
||||
#: templates/measure/select_recipe.html:110
|
||||
#: templates/measure/select_recipe.html:113
|
||||
msgid "Stazione forzata per collaudo"
|
||||
msgstr "Station overridden for commissioning"
|
||||
|
||||
#: templates/measure/select_recipe.html:110
|
||||
#: templates/measure/select_recipe.html:113
|
||||
msgid "configurata"
|
||||
msgstr "configured"
|
||||
|
||||
#: templates/measure/select_recipe.html:115
|
||||
#: templates/measure/select_recipe.html:118
|
||||
msgid "Ripristina"
|
||||
msgstr "Restore"
|
||||
|
||||
#: templates/measure/select_recipe.html:140
|
||||
#: templates/measure/select_recipe.html:143
|
||||
msgid "Cerca ricetta"
|
||||
msgstr "Search recipe"
|
||||
|
||||
#: templates/measure/select_recipe.html:144
|
||||
#: templates/measure/select_recipe.html:147
|
||||
msgid "Nome, codice o descrizione..."
|
||||
msgstr "Name, code or description..."
|
||||
|
||||
#: templates/measure/select_recipe.html:157
|
||||
#: templates/measure/select_recipe.html:160
|
||||
msgid "Tracciabilità"
|
||||
msgstr "Traceability"
|
||||
|
||||
#: templates/measure/select_recipe.html:158
|
||||
#: templates/measure/select_recipe.html:161
|
||||
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"
|
||||
|
||||
#: templates/measure/select_recipe.html:168
|
||||
#: templates/measure/select_recipe.html:171
|
||||
#: templates/measure/task_complete.html:284
|
||||
msgid "Numero Lotto"
|
||||
msgstr "Lot Number"
|
||||
|
||||
#: templates/measure/select_recipe.html:172
|
||||
#: templates/measure/select_recipe.html:175
|
||||
msgid "Es. LOT-2026-001"
|
||||
msgstr "E.g. LOT-2026-001"
|
||||
|
||||
#: templates/measure/select_recipe.html:182
|
||||
#: templates/measure/select_recipe.html:185
|
||||
#: templates/measure/task_complete.html:285
|
||||
msgid "Numero Seriale"
|
||||
msgstr "Serial Number"
|
||||
|
||||
#: templates/measure/select_recipe.html:186
|
||||
#: templates/measure/select_recipe.html:189
|
||||
msgid "Es. SN-000123"
|
||||
msgstr "E.g. SN-000123"
|
||||
|
||||
#: templates/measure/select_recipe.html:239
|
||||
#: templates/measure/select_recipe.html:242
|
||||
msgid "Nessuna descrizione disponibile"
|
||||
msgstr "No description available"
|
||||
|
||||
#: templates/measure/select_recipe.html:315
|
||||
#: templates/measure/select_recipe.html:294
|
||||
#: templates/measure/task_list.html:107
|
||||
msgid "AVVIA IN SEQUENZA"
|
||||
msgstr "START THE SEQUENCE"
|
||||
|
||||
# Maker - Task Editor
|
||||
#: templates/measure/select_recipe.html:302
|
||||
|
||||
msgid "Vedi tutti i task"
|
||||
msgstr "See all tasks"
|
||||
|
||||
#: templates/measure/select_recipe.html:323
|
||||
msgid "Nessun risultato per"
|
||||
msgstr "No results for"
|
||||
|
||||
#: templates/measure/select_recipe.html:316
|
||||
#: templates/measure/select_recipe.html:324
|
||||
msgid "Prova con un termine diverso."
|
||||
msgstr "Try a different search term."
|
||||
|
||||
#: templates/measure/select_recipe.html:319
|
||||
#: templates/measure/select_recipe.html:327
|
||||
msgid "Non ci sono ricette disponibili al momento."
|
||||
msgstr "No recipes available at the moment."
|
||||
|
||||
#: templates/measure/select_recipe.html:372
|
||||
#: templates/measure/select_recipe.html:380
|
||||
msgid ""
|
||||
"Inserisci o scansiona il codice della ricetta per selezionarla "
|
||||
"automaticamente."
|
||||
msgstr "Enter or scan the recipe code to select it automatically."
|
||||
|
||||
#: templates/measure/select_recipe.html:377
|
||||
#: templates/measure/select_recipe.html:385
|
||||
msgid "Codice Ricetta"
|
||||
msgstr "Recipe Code"
|
||||
|
||||
#: templates/measure/select_recipe.html:383
|
||||
#: templates/measure/select_recipe.html:391
|
||||
msgid "Es. REC-001"
|
||||
msgstr "E.g. REC-001"
|
||||
|
||||
#: templates/measure/select_recipe.html:419
|
||||
#: templates/measure/select_recipe.html:427
|
||||
msgid "Cerca"
|
||||
msgstr "Search"
|
||||
|
||||
#: templates/measure/task_complete.html:3
|
||||
#: templates/measure/task_complete.html:39
|
||||
#: templates/measure/task_execute.html:113
|
||||
#: templates/measure/task_execute.html:765
|
||||
#: templates/measure/task_execute.html:792
|
||||
#: templates/statistics/dashboard.html:139
|
||||
msgid "Riepilogo"
|
||||
msgstr "Summary"
|
||||
|
||||
#: templates/measure/task_complete.html:47
|
||||
#: templates/measure/task_execute.html:742
|
||||
#: templates/measure/task_execute.html:769
|
||||
msgid "Misurazioni Complete"
|
||||
msgstr "Measurements Complete"
|
||||
|
||||
@@ -1910,12 +1931,12 @@ msgid "Totale"
|
||||
msgstr "Total"
|
||||
|
||||
#: templates/measure/task_complete.html:106
|
||||
#: templates/measure/task_execute.html:750
|
||||
#: templates/measure/task_execute.html:777
|
||||
msgid "Conformi"
|
||||
msgstr "Pass"
|
||||
|
||||
#: templates/measure/task_complete.html:123
|
||||
#: templates/measure/task_execute.html:754
|
||||
#: templates/measure/task_execute.html:781
|
||||
msgid "Attenzione"
|
||||
msgstr "Warning"
|
||||
|
||||
@@ -2079,175 +2100,197 @@ msgstr "MEASUREMENT DETAILS"
|
||||
msgid "Task di misurazione"
|
||||
msgstr "Measurement task"
|
||||
|
||||
#: templates/measure/task_execute.html:106
|
||||
#: templates/measure/task_execute.html:115
|
||||
msgid "Lista task"
|
||||
msgstr "Task list"
|
||||
|
||||
#: templates/measure/task_execute.html:128
|
||||
msgid "Fermo linea"
|
||||
msgstr "Line stop"
|
||||
|
||||
#: templates/measure/task_execute.html:136
|
||||
msgid "Riprendi"
|
||||
msgstr "Resume"
|
||||
|
||||
#: templates/measure/task_execute.html:144
|
||||
msgid "Fine Produzione"
|
||||
msgstr "End Production"
|
||||
|
||||
#: templates/measure/task_execute.html:259
|
||||
msgid "Immagine dettaglio misura"
|
||||
msgstr "Measurement detail image"
|
||||
|
||||
#: templates/measure/task_execute.html:307
|
||||
msgid "Misurazione"
|
||||
msgstr "Measurement"
|
||||
|
||||
#: templates/measure/task_execute.html:385
|
||||
msgid "Registrata"
|
||||
msgstr "Recorded"
|
||||
|
||||
#: templates/measure/task_execute.html:491
|
||||
msgid "Task di misura senza quote configurate: la ricetta è incompleta"
|
||||
msgstr "Measurement task with no quotes configured: the recipe is incomplete"
|
||||
|
||||
#: templates/measure/task_execute.html:510
|
||||
msgid "Quota fuori tolleranza"
|
||||
msgstr "Measurement out of tolerance"
|
||||
|
||||
#: templates/measure/task_execute.html:513
|
||||
msgid "serve il capoturno, oppure una nuova misura della stessa quota"
|
||||
msgstr "the supervisor must authorise it, or the same quote must be measured again"
|
||||
|
||||
#: templates/measure/task_execute.html:517
|
||||
#: templates/measure/task_execute.html:870
|
||||
msgid "Autorizza"
|
||||
msgstr "Authorize"
|
||||
|
||||
#: templates/measure/task_execute.html:541
|
||||
msgid "Il conto alla rovescia è congelato a"
|
||||
msgstr "The countdown is frozen at"
|
||||
|
||||
#: templates/measure/task_execute.html:544
|
||||
msgid "serve il capoturno per riprendere"
|
||||
msgstr "the supervisor must authorise the restart"
|
||||
|
||||
#: templates/measure/task_execute.html:563
|
||||
msgid "Produzione non registrata sul server"
|
||||
msgstr "Production not recorded on the server"
|
||||
|
||||
#: templates/measure/task_execute.html:584
|
||||
#: templates/measure/task_execute.html:793
|
||||
msgid "Avvio Produzione"
|
||||
msgstr "Production Start"
|
||||
|
||||
#: templates/measure/task_execute.html:588
|
||||
msgid "Invia segnale al gestionale per avviare il timer della linea"
|
||||
msgstr "Send a signal to the ERP system to start the line timer"
|
||||
|
||||
#: templates/measure/task_execute.html:599
|
||||
msgid "Produzione avviata"
|
||||
msgstr "Production started"
|
||||
|
||||
#: templates/measure/task_execute.html:644
|
||||
msgid "Fine ciclo misura"
|
||||
msgstr "Measurement cycle complete"
|
||||
|
||||
#: templates/measure/task_execute.html:655
|
||||
msgid "Rimisura"
|
||||
msgstr "Measure again"
|
||||
|
||||
#: templates/measure/task_execute.html:665
|
||||
#: templates/measure/task_execute.html:679
|
||||
#: templates/measure/task_execute.html:125
|
||||
#: templates/measure/task_execute.html:706 templates/measure/task_list.html:227
|
||||
msgid "Completato"
|
||||
msgstr "Completed"
|
||||
|
||||
#: templates/measure/task_execute.html:744
|
||||
msgid "Tutte le"
|
||||
msgstr "All"
|
||||
#: templates/measure/task_execute.html:140
|
||||
msgid "Fermo linea"
|
||||
msgstr "Line stop"
|
||||
|
||||
#: templates/measure/task_execute.html:744
|
||||
msgid "misurazioni sono state registrate."
|
||||
msgstr "measurements have been recorded."
|
||||
#: templates/measure/task_execute.html:148
|
||||
msgid "Riprendi"
|
||||
msgstr "Resume"
|
||||
|
||||
#: templates/measure/task_execute.html:758
|
||||
msgid "Non Conf."
|
||||
msgstr "Fail"
|
||||
#: templates/measure/task_execute.html:156
|
||||
msgid "Fine Produzione"
|
||||
msgstr "End Production"
|
||||
|
||||
#: templates/measure/task_execute.html:773
|
||||
msgid "Conferma ciclo"
|
||||
msgstr "Confirm cycle"
|
||||
#: templates/measure/task_execute.html:271
|
||||
msgid "Immagine dettaglio misura"
|
||||
msgstr "Measurement detail image"
|
||||
|
||||
#: templates/measure/task_execute.html:783
|
||||
#: templates/measure/task_execute.html:319
|
||||
msgid "Misurazione"
|
||||
msgstr "Measurement"
|
||||
|
||||
#: templates/measure/task_execute.html:397
|
||||
msgid "Registrata"
|
||||
msgstr "Recorded"
|
||||
|
||||
#: templates/measure/task_execute.html:503
|
||||
msgid "Task di misura senza quote configurate: la ricetta è incompleta"
|
||||
msgstr "Measurement task with no quotes configured: the recipe is incomplete"
|
||||
|
||||
#: templates/measure/task_execute.html:522
|
||||
msgid "Quota fuori tolleranza"
|
||||
msgstr "Measurement out of tolerance"
|
||||
|
||||
#: templates/measure/task_execute.html:525
|
||||
msgid "serve il capoturno, oppure una nuova misura della stessa quota"
|
||||
msgstr "the supervisor must authorise it, or the same quote must be measured again"
|
||||
|
||||
#: templates/measure/task_execute.html:529
|
||||
#: templates/measure/task_execute.html:897
|
||||
msgid "Autorizza"
|
||||
msgstr "Authorize"
|
||||
|
||||
#: templates/measure/task_execute.html:553
|
||||
msgid "Il conto alla rovescia è congelato a"
|
||||
msgstr "The countdown is frozen at"
|
||||
|
||||
#: templates/measure/task_execute.html:556
|
||||
msgid "serve il capoturno per riprendere"
|
||||
msgstr "the supervisor must authorise the restart"
|
||||
|
||||
#: templates/measure/task_execute.html:575
|
||||
msgid "Produzione non registrata sul server"
|
||||
msgstr "Production not recorded on the server"
|
||||
|
||||
#: templates/measure/task_execute.html:596
|
||||
#: templates/measure/task_execute.html:820
|
||||
msgid "Avvio Produzione"
|
||||
msgstr "Production Start"
|
||||
|
||||
#: templates/measure/task_execute.html:600
|
||||
msgid "Invia segnale al gestionale per avviare il timer della linea"
|
||||
msgstr "Send a signal to the ERP system to start the line timer"
|
||||
|
||||
#: templates/measure/task_execute.html:611
|
||||
msgid "Produzione avviata"
|
||||
msgstr "Production started"
|
||||
|
||||
#: templates/measure/task_execute.html:667
|
||||
msgid "Fine ciclo misura"
|
||||
msgstr "Measurement cycle complete"
|
||||
|
||||
#: templates/measure/task_execute.html:679
|
||||
msgid "Rimisura"
|
||||
msgstr "Measure again"
|
||||
|
||||
#: templates/measure/task_execute.html:692
|
||||
#: templates/measure/task_execute.html:810
|
||||
msgid "Task successivo"
|
||||
msgstr "Next task"
|
||||
|
||||
#: templates/measure/task_execute.html:809
|
||||
#: templates/measure/task_execute.html:771
|
||||
msgid "Tutte le"
|
||||
msgstr "All"
|
||||
|
||||
#: templates/measure/task_execute.html:771
|
||||
msgid "misurazioni sono state registrate."
|
||||
msgstr "measurements have been recorded."
|
||||
|
||||
#: templates/measure/task_execute.html:785
|
||||
msgid "Non Conf."
|
||||
msgstr "Fail"
|
||||
|
||||
#: templates/measure/task_execute.html:800
|
||||
msgid "Conferma ciclo"
|
||||
msgstr "Confirm cycle"
|
||||
|
||||
#: templates/measure/task_execute.html:836
|
||||
msgid "Girare il pezzo e rimisurare"
|
||||
msgstr "Turn the piece over and measure again"
|
||||
|
||||
#: templates/measure/task_execute.html:835
|
||||
#: templates/measure/task_execute.html:862
|
||||
msgid "Autorizzazione capoturno"
|
||||
msgstr "Shift supervisor authorization"
|
||||
|
||||
#: templates/measure/task_execute.html:844
|
||||
#: templates/measure/task_execute.html:871
|
||||
msgid "Username capoturno"
|
||||
msgstr "Supervisor username"
|
||||
|
||||
#: templates/measure/task_execute.html:861
|
||||
#: templates/measure/task_execute.html:888
|
||||
msgid "Rimisura la quota"
|
||||
msgstr "Measure this quote again"
|
||||
|
||||
#: templates/measure/task_execute.html:1125
|
||||
#: templates/measure/task_execute.html:1027
|
||||
|
||||
msgid "Manca 1 quota"
|
||||
msgstr "1 quote missing"
|
||||
|
||||
#: templates/measure/task_execute.html:1028
|
||||
msgid "Mancano"
|
||||
msgstr "Missing"
|
||||
|
||||
#: templates/measure/task_execute.html:1028
|
||||
|
||||
msgid "quote"
|
||||
msgstr "quotes"
|
||||
|
||||
#: templates/measure/task_execute.html:1046
|
||||
|
||||
msgid "Serve l'autorizzazione del capoturno"
|
||||
msgstr "The shift supervisor must authorise it"
|
||||
|
||||
#: templates/measure/task_execute.html:1049
|
||||
msgid "Chiudi prima il ciclo di misura"
|
||||
msgstr "Close the measurement cycle first"
|
||||
|
||||
#: templates/measure/task_execute.html:1186
|
||||
msgid "Questa ricetta non ammette valori digitati: usare il calibro"
|
||||
msgstr "This recipe does not accept typed values: use the caliper"
|
||||
|
||||
#: templates/measure/task_execute.html:1222
|
||||
#: templates/measure/task_execute.html:1283
|
||||
msgid "Errore di rete. Riprovare."
|
||||
msgstr "Network error. Please retry."
|
||||
|
||||
#: templates/measure/task_execute.html:1260
|
||||
#: templates/measure/task_execute.html:1321
|
||||
msgid ""
|
||||
"Quota fuori tolleranza: serve l'autorizzazione del capoturno, oppure "
|
||||
"misurare di nuovo la quota"
|
||||
msgstr "Out of tolerance: the supervisor must authorise it, or the quote must be measured again"
|
||||
msgstr ""
|
||||
"Out of tolerance: the supervisor must authorise it, or the quote must be "
|
||||
"measured again"
|
||||
|
||||
#: templates/measure/task_execute.html:1357
|
||||
#: templates/measure/task_execute.html:1418
|
||||
msgid "Errore di comunicazione con il server"
|
||||
msgstr "Error communicating with the server"
|
||||
|
||||
#: templates/measure/task_execute.html:1609
|
||||
#: templates/measure/task_execute.html:1670
|
||||
msgid "Misurazione fuori tolleranza"
|
||||
msgstr "Measurement out of tolerance"
|
||||
|
||||
#: templates/measure/task_execute.html:1610
|
||||
#: templates/measure/task_execute.html:1671
|
||||
msgid "Fermo linea richiesto"
|
||||
msgstr "Line stop requested"
|
||||
|
||||
#: templates/measure/task_execute.html:1611
|
||||
#: templates/measure/task_execute.html:1672
|
||||
msgid "Ripresa della produzione"
|
||||
msgstr "Resuming production"
|
||||
|
||||
#: templates/measure/task_execute.html:1612
|
||||
#: templates/measure/task_execute.html:1673
|
||||
msgid "Fine produzione richiesta"
|
||||
msgstr "End of production requested"
|
||||
|
||||
#: templates/measure/task_execute.html:1656
|
||||
#: templates/measure/task_execute.html:1717
|
||||
msgid "Credenziali non valide o utente non autorizzato"
|
||||
msgstr "Invalid credentials or unauthorized user"
|
||||
|
||||
#: templates/measure/task_execute.html:1683
|
||||
#: templates/measure/task_execute.html:1744
|
||||
msgid "Nessuna produzione aperta su questa stazione"
|
||||
msgstr "No production open at this station"
|
||||
|
||||
#: templates/measure/task_execute.html:1700
|
||||
#: templates/measure/task_execute.html:1761
|
||||
msgid "Azione non riuscita"
|
||||
msgstr "Action failed"
|
||||
|
||||
#: templates/measure/task_list.html:107
|
||||
msgid "AVVIA"
|
||||
msgstr "START"
|
||||
|
||||
#: templates/measure/task_list.html:145
|
||||
msgid "Task da eseguire"
|
||||
msgstr "Tasks to execute"
|
||||
@@ -2256,30 +2299,32 @@ msgstr "Tasks to execute"
|
||||
msgid "misurazioni totali"
|
||||
msgstr "total measurements"
|
||||
|
||||
#: templates/measure/task_list.html:199
|
||||
#: templates/measure/task_list.html:204
|
||||
msgid "Confronto profilo"
|
||||
msgstr "Profile comparison"
|
||||
|
||||
#: templates/measure/task_list.html:200
|
||||
#: templates/measure/task_list.html:205
|
||||
msgid "Misura camera"
|
||||
msgstr "Camera measurement"
|
||||
|
||||
#: templates/measure/task_list.html:222
|
||||
#: templates/measure/task_list.html:232
|
||||
|
||||
msgid "Incompiuto"
|
||||
msgstr "Unfinished"
|
||||
|
||||
#: templates/measure/task_list.html:247
|
||||
msgid "Allegato"
|
||||
msgstr "Attachment"
|
||||
|
||||
#: templates/measure/task_list.html:246
|
||||
msgid "Visualizza Task"
|
||||
msgstr "View Tasks"
|
||||
#: templates/measure/task_list.html:275
|
||||
|
||||
#: templates/measure/task_list.html:269
|
||||
msgid "Visualizza singolo TASK"
|
||||
msgstr "View single TASK"
|
||||
|
||||
#: templates/measure/task_list.html:294
|
||||
msgid "Nessun task disponibile"
|
||||
msgstr "No tasks available"
|
||||
|
||||
#: templates/measure/task_list.html:272
|
||||
msgid "Questa ricetta non ha ancora task definiti."
|
||||
msgstr "This recipe has no tasks defined yet."
|
||||
|
||||
# SPC Statistics Dashboard
|
||||
#: templates/statistics/dashboard.html:3 templates/statistics/dashboard.html:17
|
||||
msgid "Statistiche SPC"
|
||||
@@ -2700,3 +2745,6 @@ msgstr "Error generating report"
|
||||
#~ msgid "Utente non autorizzato (richiesto capoturno)"
|
||||
#~ msgstr "User not authorized (shift supervisor required)"
|
||||
|
||||
#~ msgid "Errore nel caricamento dei task: %(detail)s"
|
||||
#~ msgstr "Error loading tasks: %(detail)s"
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: TieMeasureFlow 1.0\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-07-28 20:48+0000\n"
|
||||
"POT-Creation-Date: 2026-07-28 21:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: it\n"
|
||||
@@ -129,43 +129,64 @@ msgstr "Stazione corrente: %(code)s"
|
||||
msgid "Errore nel caricamento delle ricette: %(detail)s"
|
||||
msgstr "Errore nel caricamento delle ricette: %(detail)s"
|
||||
|
||||
#: blueprints/measure.py:146 blueprints/measure.py:237
|
||||
# Measure - Task List
|
||||
#: blueprints/measure.py:139 templates/measure/select_recipe.html:30
|
||||
#: templates/measure/task_list.html:86
|
||||
msgid "lotto"
|
||||
msgstr "lotto"
|
||||
|
||||
#: blueprints/measure.py:141 templates/measure/select_recipe.html:31
|
||||
#: templates/measure/task_list.html:87
|
||||
msgid "seriale"
|
||||
msgstr "seriale"
|
||||
|
||||
#: blueprints/measure.py:204 blueprints/measure.py:242
|
||||
#: blueprints/measure.py:330
|
||||
#, python-format
|
||||
msgid "Ricetta non trovata: %(detail)s"
|
||||
msgstr "Ricetta non trovata: %(detail)s"
|
||||
|
||||
#: blueprints/measure.py:156
|
||||
#: blueprints/measure.py:213
|
||||
#, python-format
|
||||
msgid "Errore nel caricamento dei task: %(detail)s"
|
||||
msgstr "Errore nel caricamento dei task: %(detail)s"
|
||||
msgid "Compila prima: %(fields)s"
|
||||
msgstr "Compila prima: %(fields)s"
|
||||
|
||||
#: blueprints/measure.py:185
|
||||
#: blueprints/measure.py:222 templates/measure/task_list.html:297
|
||||
msgid "Questa ricetta non ha ancora task definiti."
|
||||
msgstr "Questa ricetta non ha ancora task definiti."
|
||||
|
||||
#: blueprints/measure.py:250
|
||||
|
||||
msgid "Errore nel caricamento dei task."
|
||||
msgstr "Errore nel caricamento dei task."
|
||||
|
||||
#: blueprints/measure.py:278
|
||||
#, python-format
|
||||
msgid "Task non trovato: %(detail)s"
|
||||
msgstr "Task non trovato: %(detail)s"
|
||||
|
||||
#: blueprints/measure.py:306
|
||||
#: blueprints/measure.py:399
|
||||
msgid "Codice non fornito"
|
||||
msgstr "Codice non fornito"
|
||||
|
||||
#: blueprints/measure.py:312 templates/measure/select_recipe.html:57
|
||||
#: blueprints/measure.py:405 templates/measure/select_recipe.html:60
|
||||
msgid "Ricetta non trovata"
|
||||
msgstr "Ricetta non trovata"
|
||||
|
||||
#: blueprints/measure.py:368
|
||||
#: blueprints/measure.py:461
|
||||
msgid "Dati mancanti: subtask_id, version_id e value sono obbligatori"
|
||||
msgstr "Dati mancanti: subtask_id, version_id e value sono obbligatori"
|
||||
|
||||
#: blueprints/measure.py:393 templates/admin/stations.html:549
|
||||
#: blueprints/measure.py:486 templates/admin/stations.html:549
|
||||
#: templates/maker/recipe_editor.html:598
|
||||
msgid "Errore nel salvataggio"
|
||||
msgstr "Errore nel salvataggio"
|
||||
|
||||
#: blueprints/measure.py:437 blueprints/measure.py:542
|
||||
#: blueprints/measure.py:530 blueprints/measure.py:635
|
||||
msgid "Username e password richiesti"
|
||||
msgstr "Username e password richiesti"
|
||||
|
||||
#: blueprints/measure.py:463 blueprints/measure.py:480
|
||||
#: blueprints/measure.py:556 blueprints/measure.py:573
|
||||
#: templates/errors/station_not_configured.html:2
|
||||
#: templates/errors/station_not_configured.html:16
|
||||
msgid "Stazione non configurata"
|
||||
@@ -373,8 +394,8 @@ msgstr "Note opzionali"
|
||||
#: templates/maker/task_editor.html:312 templates/maker/task_editor.html:421
|
||||
#: templates/maker/task_editor.html:782 templates/maker/task_editor.html:901
|
||||
#: templates/maker/task_editor.html:966 templates/maker/task_editor.html:1071
|
||||
#: templates/measure/select_recipe.html:405
|
||||
#: templates/measure/task_execute.html:860
|
||||
#: templates/measure/select_recipe.html:413
|
||||
#: templates/measure/task_execute.html:887
|
||||
msgid "Annulla"
|
||||
msgstr "Annulla"
|
||||
|
||||
@@ -390,7 +411,7 @@ msgstr "Crea Stazione"
|
||||
#: templates/admin/stations.html:241 templates/admin/users.html:299
|
||||
#: templates/maker/recipe_editor.html:107
|
||||
#: templates/maker/recipe_editor.html:490 templates/maker/task_drawing.html:61
|
||||
#: templates/measure/task_execute.html:412
|
||||
#: templates/measure/task_execute.html:424
|
||||
msgid "Salvataggio..."
|
||||
msgstr "Salvataggio..."
|
||||
|
||||
@@ -519,7 +540,7 @@ msgstr "Nuovo Utente"
|
||||
#: templates/admin/users.html:48 templates/admin/users.html:173
|
||||
#: templates/admin/users.html:179 templates/auth/login.html:35
|
||||
#: templates/auth/login.html:49 templates/auth/profile.html:36
|
||||
#: templates/measure/task_execute.html:842
|
||||
#: templates/measure/task_execute.html:869
|
||||
msgid "Username"
|
||||
msgstr "Username"
|
||||
|
||||
@@ -571,7 +592,7 @@ msgstr "Il nome utente non può essere modificato"
|
||||
|
||||
#: templates/admin/users.html:206 templates/admin/users.html:214
|
||||
#: templates/auth/login.html:57 templates/auth/login.html:71
|
||||
#: templates/measure/task_execute.html:847
|
||||
#: templates/measure/task_execute.html:874
|
||||
msgid "Password"
|
||||
msgstr "Password"
|
||||
|
||||
@@ -726,8 +747,8 @@ msgstr "Logout"
|
||||
|
||||
#: templates/components/barcode_scanner.html:21
|
||||
#: templates/components/barcode_scanner.html:54
|
||||
#: templates/measure/select_recipe.html:128
|
||||
#: templates/measure/select_recipe.html:357
|
||||
#: templates/measure/select_recipe.html:131
|
||||
#: templates/measure/select_recipe.html:365
|
||||
msgid "Scansiona Barcode"
|
||||
msgstr "Scansiona Barcode"
|
||||
|
||||
@@ -826,14 +847,14 @@ msgid "Misura solo da calibro: questa ricetta non ammette valori digitati"
|
||||
msgstr "Misura solo da calibro: questa ricetta non ammette valori digitati"
|
||||
|
||||
#: templates/components/production_clock.html:42
|
||||
#: templates/measure/task_execute.html:460
|
||||
#: templates/measure/task_execute.html:472
|
||||
msgid "Prossima misurazione tra"
|
||||
msgstr "Prossima misurazione tra"
|
||||
|
||||
#: templates/components/production_clock.html:49
|
||||
#: templates/components/production_clock.html:62
|
||||
#: templates/measure/task_execute.html:463
|
||||
#: templates/measure/task_execute.html:542
|
||||
#: templates/measure/task_execute.html:475
|
||||
#: templates/measure/task_execute.html:554
|
||||
msgid "Misurazione in ritardo di"
|
||||
msgstr "Misurazione in ritardo di"
|
||||
|
||||
@@ -842,27 +863,27 @@ msgid "Linea ferma — conto alla rovescia congelato a"
|
||||
msgstr "Linea ferma — conto alla rovescia congelato a"
|
||||
|
||||
#: templates/components/production_clock.html:62
|
||||
#: templates/measure/task_execute.html:536
|
||||
#: templates/measure/task_execute.html:548
|
||||
msgid "Linea ferma"
|
||||
msgstr "Linea ferma"
|
||||
|
||||
#: templates/components/production_clock.html:74
|
||||
#: templates/measure/task_execute.html:472
|
||||
#: templates/measure/task_execute.html:484
|
||||
msgid "Ciclo"
|
||||
msgstr "Ciclo"
|
||||
|
||||
#: templates/components/production_clock.html:92
|
||||
#: templates/measure/task_execute.html:704
|
||||
#: templates/measure/task_execute.html:731
|
||||
msgid "È ora di misurare"
|
||||
msgstr "È ora di misurare"
|
||||
|
||||
#: templates/components/production_clock.html:95
|
||||
#: templates/measure/task_execute.html:706
|
||||
#: templates/measure/task_execute.html:733
|
||||
msgid "Ritorno alla misurazione tra"
|
||||
msgstr "Ritorno alla misurazione tra"
|
||||
|
||||
#: templates/components/production_clock.html:101
|
||||
#: templates/measure/task_execute.html:711
|
||||
#: templates/measure/task_execute.html:738
|
||||
msgid "Vai alla misura"
|
||||
msgstr "Vai alla misura"
|
||||
|
||||
@@ -915,8 +936,8 @@ msgstr "Anteprima"
|
||||
#: templates/maker/recipe_editor.html:128 templates/maker/recipe_list.html:246
|
||||
#: templates/maker/task_drawing.html:106 templates/maker/task_editor.html:130
|
||||
#: templates/measure/task_complete.html:171
|
||||
#: templates/measure/task_execute.html:615 templates/measure/task_list.html:2
|
||||
#: templates/measure/task_list.html:180
|
||||
#: templates/measure/task_execute.html:627 templates/measure/task_list.html:2
|
||||
#: templates/measure/task_list.html:185
|
||||
msgid "Task"
|
||||
msgstr "Task"
|
||||
|
||||
@@ -1091,9 +1112,9 @@ msgid "Errore durante eliminazione"
|
||||
msgstr "Errore durante eliminazione"
|
||||
|
||||
# Recipe Selection Additional
|
||||
#: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:72
|
||||
#: templates/measure/task_execute.html:1362
|
||||
#: templates/measure/task_execute.html:1672
|
||||
#: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:75
|
||||
#: templates/measure/task_execute.html:1423
|
||||
#: templates/measure/task_execute.html:1733
|
||||
msgid "Errore di connessione"
|
||||
msgstr "Errore di connessione"
|
||||
|
||||
@@ -1126,7 +1147,7 @@ msgid "ricetta trovata"
|
||||
msgstr "ricetta trovata"
|
||||
|
||||
#: templates/maker/recipe_list.html:144
|
||||
#: templates/measure/select_recipe.html:196
|
||||
#: templates/measure/select_recipe.html:199
|
||||
msgid "ricette trovate"
|
||||
msgstr "ricette trovate"
|
||||
|
||||
@@ -1144,7 +1165,7 @@ msgid "Versioni"
|
||||
msgstr "Versioni"
|
||||
|
||||
#: templates/maker/recipe_list.html:297
|
||||
#: templates/measure/select_recipe.html:311
|
||||
#: templates/measure/select_recipe.html:319
|
||||
msgid "Nessuna ricetta trovata"
|
||||
msgstr "Nessuna ricetta trovata"
|
||||
|
||||
@@ -1223,7 +1244,7 @@ msgid "Apri PDF"
|
||||
msgstr "Apri PDF"
|
||||
|
||||
#: templates/maker/recipe_preview.html:254
|
||||
#: templates/measure/task_execute.html:287
|
||||
#: templates/measure/task_execute.html:299
|
||||
msgid "Nessuna immagine allegata"
|
||||
msgstr "Nessuna immagine allegata"
|
||||
|
||||
@@ -1234,7 +1255,7 @@ msgstr "Punti di Misura"
|
||||
#: templates/maker/recipe_preview.html:299 templates/maker/task_editor.html:579
|
||||
#: templates/maker/task_editor.html:721
|
||||
#: templates/measure/task_complete.html:173
|
||||
#: templates/measure/task_execute.html:321
|
||||
#: templates/measure/task_execute.html:333
|
||||
msgid "Nominale"
|
||||
msgstr "Nominale"
|
||||
|
||||
@@ -1288,7 +1309,6 @@ msgid "Torna ai Task"
|
||||
msgstr "Torna ai Task"
|
||||
|
||||
#: templates/maker/task_drawing.html:205 templates/maker/task_drawing.html:209
|
||||
#: templates/measure/select_recipe.html:291
|
||||
msgid "Seleziona"
|
||||
msgstr "Seleziona"
|
||||
|
||||
@@ -1404,18 +1424,18 @@ msgid "Tipo"
|
||||
msgstr "Tipo"
|
||||
|
||||
#: templates/maker/task_editor.html:277 templates/maker/task_editor.html:543
|
||||
#: templates/measure/task_list.html:198
|
||||
#: templates/measure/task_list.html:203
|
||||
msgid "Nota"
|
||||
msgstr "Nota"
|
||||
|
||||
#: templates/maker/task_editor.html:278 templates/maker/task_editor.html:544
|
||||
#: templates/measure/task_execute.html:309 templates/measure/task_list.html:196
|
||||
#: templates/measure/task_execute.html:321 templates/measure/task_list.html:201
|
||||
msgid "Misura"
|
||||
msgstr "Misura"
|
||||
|
||||
# Maker - Task Editor
|
||||
#: templates/maker/task_editor.html:279 templates/maker/task_editor.html:545
|
||||
#: templates/measure/task_list.html:197
|
||||
#: templates/measure/task_list.html:202
|
||||
msgid "Disegno"
|
||||
msgstr "Disegno"
|
||||
|
||||
@@ -1446,7 +1466,7 @@ msgstr "Trascina per riordinare"
|
||||
|
||||
#: templates/maker/task_editor.html:390
|
||||
#: templates/maker/version_history.html:188
|
||||
#: templates/measure/task_list.html:213
|
||||
#: templates/measure/task_list.html:238
|
||||
msgid "misurazioni"
|
||||
msgstr "misurazioni"
|
||||
|
||||
@@ -1712,7 +1732,7 @@ msgid "Misurazione aggiunta"
|
||||
msgstr "Misurazione aggiunta"
|
||||
|
||||
#: templates/maker/task_editor.html:1685
|
||||
#: templates/measure/task_execute.html:1170
|
||||
#: templates/measure/task_execute.html:1231
|
||||
msgid "Errore nel salvataggio della misurazione"
|
||||
msgstr "Errore nel salvataggio della misurazione"
|
||||
|
||||
@@ -1775,95 +1795,97 @@ msgstr ""
|
||||
|
||||
# Measure - Recipe Selection
|
||||
#: templates/measure/select_recipe.html:2
|
||||
#: templates/measure/select_recipe.html:94
|
||||
#: templates/measure/select_recipe.html:97
|
||||
msgid "Seleziona Ricetta"
|
||||
msgstr "Seleziona Ricetta"
|
||||
|
||||
# Measure - Task List
|
||||
#: templates/measure/select_recipe.html:30 templates/measure/task_list.html:86
|
||||
msgid "lotto"
|
||||
msgstr "lotto"
|
||||
|
||||
#: templates/measure/select_recipe.html:31 templates/measure/task_list.html:87
|
||||
msgid "seriale"
|
||||
msgstr "seriale"
|
||||
|
||||
#: templates/measure/select_recipe.html:64
|
||||
#: templates/measure/select_recipe.html:277 templates/measure/task_list.html:97
|
||||
#: templates/measure/select_recipe.html:67
|
||||
#: templates/measure/select_recipe.html:280 templates/measure/task_list.html:97
|
||||
msgid "Compila prima:"
|
||||
msgstr "Compila prima:"
|
||||
|
||||
#: templates/measure/select_recipe.html:97
|
||||
#: templates/measure/select_recipe.html:100
|
||||
msgid "Scegli la ricetta di misura da eseguire"
|
||||
msgstr "Scegli la ricetta di misura da eseguire"
|
||||
|
||||
#: templates/measure/select_recipe.html:100
|
||||
#: templates/measure/select_recipe.html:103
|
||||
msgid "Stazione"
|
||||
msgstr "Stazione"
|
||||
|
||||
#: templates/measure/select_recipe.html:110
|
||||
#: templates/measure/select_recipe.html:113
|
||||
msgid "Stazione forzata per collaudo"
|
||||
msgstr "Stazione forzata per collaudo"
|
||||
|
||||
#: templates/measure/select_recipe.html:110
|
||||
#: templates/measure/select_recipe.html:113
|
||||
msgid "configurata"
|
||||
msgstr "configurata"
|
||||
|
||||
#: templates/measure/select_recipe.html:115
|
||||
#: templates/measure/select_recipe.html:118
|
||||
msgid "Ripristina"
|
||||
msgstr "Ripristina"
|
||||
|
||||
#: templates/measure/select_recipe.html:140
|
||||
#: templates/measure/select_recipe.html:143
|
||||
msgid "Cerca ricetta"
|
||||
msgstr "Cerca ricetta"
|
||||
|
||||
#: templates/measure/select_recipe.html:144
|
||||
#: templates/measure/select_recipe.html:147
|
||||
msgid "Nome, codice o descrizione..."
|
||||
msgstr "Nome, codice o descrizione..."
|
||||
|
||||
#: templates/measure/select_recipe.html:157
|
||||
#: templates/measure/select_recipe.html:160
|
||||
msgid "Tracciabilità"
|
||||
msgstr "Tracciabilità"
|
||||
|
||||
#: templates/measure/select_recipe.html:158
|
||||
#: templates/measure/select_recipe.html:161
|
||||
msgid "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:168
|
||||
#: templates/measure/select_recipe.html:171
|
||||
#: templates/measure/task_complete.html:284
|
||||
msgid "Numero Lotto"
|
||||
msgstr "Numero Lotto"
|
||||
|
||||
#: templates/measure/select_recipe.html:172
|
||||
#: templates/measure/select_recipe.html:175
|
||||
msgid "Es. LOT-2026-001"
|
||||
msgstr "Es. LOT-2026-001"
|
||||
|
||||
#: templates/measure/select_recipe.html:182
|
||||
#: templates/measure/select_recipe.html:185
|
||||
#: templates/measure/task_complete.html:285
|
||||
msgid "Numero Seriale"
|
||||
msgstr "Numero Seriale"
|
||||
|
||||
#: templates/measure/select_recipe.html:186
|
||||
#: templates/measure/select_recipe.html:189
|
||||
msgid "Es. SN-000123"
|
||||
msgstr "Es. SN-000123"
|
||||
|
||||
#: templates/measure/select_recipe.html:239
|
||||
#: templates/measure/select_recipe.html:242
|
||||
msgid "Nessuna descrizione disponibile"
|
||||
msgstr "Nessuna descrizione disponibile"
|
||||
|
||||
#: templates/measure/select_recipe.html:315
|
||||
#: templates/measure/select_recipe.html:294
|
||||
#: templates/measure/task_list.html:107
|
||||
msgid "AVVIA IN SEQUENZA"
|
||||
msgstr "AVVIA IN SEQUENZA"
|
||||
|
||||
# Maker - Task Editor
|
||||
#: templates/measure/select_recipe.html:302
|
||||
|
||||
msgid "Vedi tutti i task"
|
||||
msgstr "Vedi tutti i task"
|
||||
|
||||
#: templates/measure/select_recipe.html:323
|
||||
msgid "Nessun risultato per"
|
||||
msgstr "Nessun risultato per"
|
||||
|
||||
#: templates/measure/select_recipe.html:316
|
||||
#: templates/measure/select_recipe.html:324
|
||||
msgid "Prova con un termine diverso."
|
||||
msgstr "Prova con un termine diverso."
|
||||
|
||||
#: templates/measure/select_recipe.html:319
|
||||
#: templates/measure/select_recipe.html:327
|
||||
msgid "Non ci sono ricette disponibili al momento."
|
||||
msgstr "Non ci sono ricette disponibili al momento."
|
||||
|
||||
#: templates/measure/select_recipe.html:372
|
||||
#: templates/measure/select_recipe.html:380
|
||||
msgid ""
|
||||
"Inserisci o scansiona il codice della ricetta per selezionarla "
|
||||
"automaticamente."
|
||||
@@ -1871,28 +1893,27 @@ msgstr ""
|
||||
"Inserisci o scansiona il codice della ricetta per selezionarla "
|
||||
"automaticamente."
|
||||
|
||||
#: templates/measure/select_recipe.html:377
|
||||
#: templates/measure/select_recipe.html:385
|
||||
msgid "Codice Ricetta"
|
||||
msgstr "Codice Ricetta"
|
||||
|
||||
#: templates/measure/select_recipe.html:383
|
||||
#: templates/measure/select_recipe.html:391
|
||||
msgid "Es. REC-001"
|
||||
msgstr "Es. REC-001"
|
||||
|
||||
#: templates/measure/select_recipe.html:419
|
||||
#: templates/measure/select_recipe.html:427
|
||||
msgid "Cerca"
|
||||
msgstr "Cerca"
|
||||
|
||||
#: templates/measure/task_complete.html:3
|
||||
#: templates/measure/task_complete.html:39
|
||||
#: templates/measure/task_execute.html:113
|
||||
#: templates/measure/task_execute.html:765
|
||||
#: templates/measure/task_execute.html:792
|
||||
#: templates/statistics/dashboard.html:139
|
||||
msgid "Riepilogo"
|
||||
msgstr "Riepilogo"
|
||||
|
||||
#: templates/measure/task_complete.html:47
|
||||
#: templates/measure/task_execute.html:742
|
||||
#: templates/measure/task_execute.html:769
|
||||
msgid "Misurazioni Complete"
|
||||
msgstr "Misurazioni Complete"
|
||||
|
||||
@@ -1914,12 +1935,12 @@ msgid "Totale"
|
||||
msgstr "Totale"
|
||||
|
||||
#: templates/measure/task_complete.html:106
|
||||
#: templates/measure/task_execute.html:750
|
||||
#: templates/measure/task_execute.html:777
|
||||
msgid "Conformi"
|
||||
msgstr "Conformi"
|
||||
|
||||
#: templates/measure/task_complete.html:123
|
||||
#: templates/measure/task_execute.html:754
|
||||
#: templates/measure/task_execute.html:781
|
||||
msgid "Attenzione"
|
||||
msgstr "Attenzione"
|
||||
|
||||
@@ -2083,175 +2104,197 @@ msgstr "DETTAGLIO MISURE"
|
||||
msgid "Task di misurazione"
|
||||
msgstr "Task di misurazione"
|
||||
|
||||
#: templates/measure/task_execute.html:106
|
||||
#: templates/measure/task_execute.html:115
|
||||
msgid "Lista task"
|
||||
msgstr "Lista task"
|
||||
|
||||
#: templates/measure/task_execute.html:128
|
||||
msgid "Fermo linea"
|
||||
msgstr "Fermo linea"
|
||||
|
||||
#: templates/measure/task_execute.html:136
|
||||
msgid "Riprendi"
|
||||
msgstr "Riprendi"
|
||||
|
||||
#: templates/measure/task_execute.html:144
|
||||
msgid "Fine Produzione"
|
||||
msgstr "Fine Produzione"
|
||||
|
||||
#: templates/measure/task_execute.html:259
|
||||
msgid "Immagine dettaglio misura"
|
||||
msgstr "Immagine dettaglio misura"
|
||||
|
||||
#: templates/measure/task_execute.html:307
|
||||
msgid "Misurazione"
|
||||
msgstr "Misurazione"
|
||||
|
||||
#: templates/measure/task_execute.html:385
|
||||
msgid "Registrata"
|
||||
msgstr "Registrata"
|
||||
|
||||
#: templates/measure/task_execute.html:491
|
||||
msgid "Task di misura senza quote configurate: la ricetta è incompleta"
|
||||
msgstr "Task di misura senza quote configurate: la ricetta è incompleta"
|
||||
|
||||
#: templates/measure/task_execute.html:510
|
||||
msgid "Quota fuori tolleranza"
|
||||
msgstr "Quota fuori tolleranza"
|
||||
|
||||
#: templates/measure/task_execute.html:513
|
||||
msgid "serve il capoturno, oppure una nuova misura della stessa quota"
|
||||
msgstr "serve il capoturno, oppure una nuova misura della stessa quota"
|
||||
|
||||
#: templates/measure/task_execute.html:517
|
||||
#: templates/measure/task_execute.html:870
|
||||
msgid "Autorizza"
|
||||
msgstr "Autorizza"
|
||||
|
||||
#: templates/measure/task_execute.html:541
|
||||
msgid "Il conto alla rovescia è congelato a"
|
||||
msgstr "Il conto alla rovescia è congelato a"
|
||||
|
||||
#: templates/measure/task_execute.html:544
|
||||
msgid "serve il capoturno per riprendere"
|
||||
msgstr "serve il capoturno per riprendere"
|
||||
|
||||
#: templates/measure/task_execute.html:563
|
||||
msgid "Produzione non registrata sul server"
|
||||
msgstr "Produzione non registrata sul server"
|
||||
|
||||
#: templates/measure/task_execute.html:584
|
||||
#: templates/measure/task_execute.html:793
|
||||
msgid "Avvio Produzione"
|
||||
msgstr "Avvio Produzione"
|
||||
|
||||
#: templates/measure/task_execute.html:588
|
||||
msgid "Invia segnale al gestionale per avviare il timer della linea"
|
||||
msgstr "Invia segnale al gestionale per avviare il timer della linea"
|
||||
|
||||
#: templates/measure/task_execute.html:599
|
||||
msgid "Produzione avviata"
|
||||
msgstr "Produzione avviata"
|
||||
|
||||
#: templates/measure/task_execute.html:644
|
||||
msgid "Fine ciclo misura"
|
||||
msgstr "Fine ciclo misura"
|
||||
|
||||
#: templates/measure/task_execute.html:655
|
||||
msgid "Rimisura"
|
||||
msgstr "Rimisura"
|
||||
|
||||
#: templates/measure/task_execute.html:665
|
||||
#: templates/measure/task_execute.html:679
|
||||
#: templates/measure/task_execute.html:125
|
||||
#: templates/measure/task_execute.html:706 templates/measure/task_list.html:227
|
||||
msgid "Completato"
|
||||
msgstr "Completato"
|
||||
|
||||
#: templates/measure/task_execute.html:744
|
||||
msgid "Tutte le"
|
||||
msgstr "Tutte le"
|
||||
#: templates/measure/task_execute.html:140
|
||||
msgid "Fermo linea"
|
||||
msgstr "Fermo linea"
|
||||
|
||||
#: templates/measure/task_execute.html:744
|
||||
msgid "misurazioni sono state registrate."
|
||||
msgstr "misurazioni sono state registrate."
|
||||
#: templates/measure/task_execute.html:148
|
||||
msgid "Riprendi"
|
||||
msgstr "Riprendi"
|
||||
|
||||
#: templates/measure/task_execute.html:758
|
||||
msgid "Non Conf."
|
||||
msgstr "Non Conf."
|
||||
#: templates/measure/task_execute.html:156
|
||||
msgid "Fine Produzione"
|
||||
msgstr "Fine Produzione"
|
||||
|
||||
#: templates/measure/task_execute.html:773
|
||||
msgid "Conferma ciclo"
|
||||
msgstr "Conferma ciclo"
|
||||
#: templates/measure/task_execute.html:271
|
||||
msgid "Immagine dettaglio misura"
|
||||
msgstr "Immagine dettaglio misura"
|
||||
|
||||
#: templates/measure/task_execute.html:783
|
||||
#: templates/measure/task_execute.html:319
|
||||
msgid "Misurazione"
|
||||
msgstr "Misurazione"
|
||||
|
||||
#: templates/measure/task_execute.html:397
|
||||
msgid "Registrata"
|
||||
msgstr "Registrata"
|
||||
|
||||
#: templates/measure/task_execute.html:503
|
||||
msgid "Task di misura senza quote configurate: la ricetta è incompleta"
|
||||
msgstr "Task di misura senza quote configurate: la ricetta è incompleta"
|
||||
|
||||
#: templates/measure/task_execute.html:522
|
||||
msgid "Quota fuori tolleranza"
|
||||
msgstr "Quota fuori tolleranza"
|
||||
|
||||
#: templates/measure/task_execute.html:525
|
||||
msgid "serve il capoturno, oppure una nuova misura della stessa quota"
|
||||
msgstr "serve il capoturno, oppure una nuova misura della stessa quota"
|
||||
|
||||
#: templates/measure/task_execute.html:529
|
||||
#: templates/measure/task_execute.html:897
|
||||
msgid "Autorizza"
|
||||
msgstr "Autorizza"
|
||||
|
||||
#: templates/measure/task_execute.html:553
|
||||
msgid "Il conto alla rovescia è congelato a"
|
||||
msgstr "Il conto alla rovescia è congelato a"
|
||||
|
||||
#: templates/measure/task_execute.html:556
|
||||
msgid "serve il capoturno per riprendere"
|
||||
msgstr "serve il capoturno per riprendere"
|
||||
|
||||
#: templates/measure/task_execute.html:575
|
||||
msgid "Produzione non registrata sul server"
|
||||
msgstr "Produzione non registrata sul server"
|
||||
|
||||
#: templates/measure/task_execute.html:596
|
||||
#: templates/measure/task_execute.html:820
|
||||
msgid "Avvio Produzione"
|
||||
msgstr "Avvio Produzione"
|
||||
|
||||
#: templates/measure/task_execute.html:600
|
||||
msgid "Invia segnale al gestionale per avviare il timer della linea"
|
||||
msgstr "Invia segnale al gestionale per avviare il timer della linea"
|
||||
|
||||
#: templates/measure/task_execute.html:611
|
||||
msgid "Produzione avviata"
|
||||
msgstr "Produzione avviata"
|
||||
|
||||
#: templates/measure/task_execute.html:667
|
||||
msgid "Fine ciclo misura"
|
||||
msgstr "Fine ciclo misura"
|
||||
|
||||
#: templates/measure/task_execute.html:679
|
||||
msgid "Rimisura"
|
||||
msgstr "Rimisura"
|
||||
|
||||
#: templates/measure/task_execute.html:692
|
||||
#: templates/measure/task_execute.html:810
|
||||
msgid "Task successivo"
|
||||
msgstr "Task successivo"
|
||||
|
||||
#: templates/measure/task_execute.html:809
|
||||
#: templates/measure/task_execute.html:771
|
||||
msgid "Tutte le"
|
||||
msgstr "Tutte le"
|
||||
|
||||
#: templates/measure/task_execute.html:771
|
||||
msgid "misurazioni sono state registrate."
|
||||
msgstr "misurazioni sono state registrate."
|
||||
|
||||
#: templates/measure/task_execute.html:785
|
||||
msgid "Non Conf."
|
||||
msgstr "Non Conf."
|
||||
|
||||
#: templates/measure/task_execute.html:800
|
||||
msgid "Conferma ciclo"
|
||||
msgstr "Conferma ciclo"
|
||||
|
||||
#: templates/measure/task_execute.html:836
|
||||
msgid "Girare il pezzo e rimisurare"
|
||||
msgstr "Girare il pezzo e rimisurare"
|
||||
|
||||
#: templates/measure/task_execute.html:835
|
||||
#: templates/measure/task_execute.html:862
|
||||
msgid "Autorizzazione capoturno"
|
||||
msgstr "Autorizzazione capoturno"
|
||||
|
||||
#: templates/measure/task_execute.html:844
|
||||
#: templates/measure/task_execute.html:871
|
||||
msgid "Username capoturno"
|
||||
msgstr "Username capoturno"
|
||||
|
||||
#: templates/measure/task_execute.html:861
|
||||
#: templates/measure/task_execute.html:888
|
||||
msgid "Rimisura la quota"
|
||||
msgstr "Rimisura la quota"
|
||||
|
||||
#: templates/measure/task_execute.html:1125
|
||||
#: templates/measure/task_execute.html:1027
|
||||
|
||||
msgid "Manca 1 quota"
|
||||
msgstr "Manca 1 quota"
|
||||
|
||||
#: templates/measure/task_execute.html:1028
|
||||
msgid "Mancano"
|
||||
msgstr "Mancano"
|
||||
|
||||
#: templates/measure/task_execute.html:1028
|
||||
|
||||
msgid "quote"
|
||||
msgstr "quote"
|
||||
|
||||
#: templates/measure/task_execute.html:1046
|
||||
|
||||
msgid "Serve l'autorizzazione del capoturno"
|
||||
msgstr "Serve l'autorizzazione del capoturno"
|
||||
|
||||
#: templates/measure/task_execute.html:1049
|
||||
msgid "Chiudi prima il ciclo di misura"
|
||||
msgstr "Chiudi prima il ciclo di misura"
|
||||
|
||||
#: templates/measure/task_execute.html:1186
|
||||
msgid "Questa ricetta non ammette valori digitati: usare il calibro"
|
||||
msgstr "Questa ricetta non ammette valori digitati: usare il calibro"
|
||||
|
||||
#: templates/measure/task_execute.html:1222
|
||||
#: templates/measure/task_execute.html:1283
|
||||
msgid "Errore di rete. Riprovare."
|
||||
msgstr "Errore di rete. Riprovare."
|
||||
|
||||
#: templates/measure/task_execute.html:1260
|
||||
#: templates/measure/task_execute.html:1321
|
||||
msgid ""
|
||||
"Quota fuori tolleranza: serve l'autorizzazione del capoturno, oppure "
|
||||
"misurare di nuovo la quota"
|
||||
msgstr "Quota fuori tolleranza: serve l'autorizzazione del capoturno, oppure misurare di nuovo la quota"
|
||||
msgstr ""
|
||||
"Quota fuori tolleranza: serve l'autorizzazione del capoturno, oppure "
|
||||
"misurare di nuovo la quota"
|
||||
|
||||
#: templates/measure/task_execute.html:1357
|
||||
#: templates/measure/task_execute.html:1418
|
||||
msgid "Errore di comunicazione con il server"
|
||||
msgstr "Errore di comunicazione con il server"
|
||||
|
||||
#: templates/measure/task_execute.html:1609
|
||||
#: templates/measure/task_execute.html:1670
|
||||
msgid "Misurazione fuori tolleranza"
|
||||
msgstr "Misurazione fuori tolleranza"
|
||||
|
||||
#: templates/measure/task_execute.html:1610
|
||||
#: templates/measure/task_execute.html:1671
|
||||
msgid "Fermo linea richiesto"
|
||||
msgstr "Fermo linea richiesto"
|
||||
|
||||
#: templates/measure/task_execute.html:1611
|
||||
#: templates/measure/task_execute.html:1672
|
||||
msgid "Ripresa della produzione"
|
||||
msgstr "Ripresa della produzione"
|
||||
|
||||
#: templates/measure/task_execute.html:1612
|
||||
#: templates/measure/task_execute.html:1673
|
||||
msgid "Fine produzione richiesta"
|
||||
msgstr "Fine produzione richiesta"
|
||||
|
||||
#: templates/measure/task_execute.html:1656
|
||||
#: templates/measure/task_execute.html:1717
|
||||
msgid "Credenziali non valide o utente non autorizzato"
|
||||
msgstr "Credenziali non valide o utente non autorizzato"
|
||||
|
||||
#: templates/measure/task_execute.html:1683
|
||||
#: templates/measure/task_execute.html:1744
|
||||
msgid "Nessuna produzione aperta su questa stazione"
|
||||
msgstr "Nessuna produzione aperta su questa stazione"
|
||||
|
||||
#: templates/measure/task_execute.html:1700
|
||||
#: templates/measure/task_execute.html:1761
|
||||
msgid "Azione non riuscita"
|
||||
msgstr "Azione non riuscita"
|
||||
|
||||
#: templates/measure/task_list.html:107
|
||||
msgid "AVVIA"
|
||||
msgstr "AVVIA"
|
||||
|
||||
#: templates/measure/task_list.html:145
|
||||
msgid "Task da eseguire"
|
||||
msgstr "Task da eseguire"
|
||||
@@ -2260,30 +2303,32 @@ msgstr "Task da eseguire"
|
||||
msgid "misurazioni totali"
|
||||
msgstr "misurazioni totali"
|
||||
|
||||
#: templates/measure/task_list.html:199
|
||||
#: templates/measure/task_list.html:204
|
||||
msgid "Confronto profilo"
|
||||
msgstr "Confronto profilo"
|
||||
|
||||
#: templates/measure/task_list.html:200
|
||||
#: templates/measure/task_list.html:205
|
||||
msgid "Misura camera"
|
||||
msgstr "Misura camera"
|
||||
|
||||
#: templates/measure/task_list.html:222
|
||||
#: templates/measure/task_list.html:232
|
||||
|
||||
msgid "Incompiuto"
|
||||
msgstr "Incompiuto"
|
||||
|
||||
#: templates/measure/task_list.html:247
|
||||
msgid "Allegato"
|
||||
msgstr "Allegato"
|
||||
|
||||
#: templates/measure/task_list.html:246
|
||||
msgid "Visualizza Task"
|
||||
msgstr "Visualizza Task"
|
||||
#: templates/measure/task_list.html:275
|
||||
|
||||
#: templates/measure/task_list.html:269
|
||||
msgid "Visualizza singolo TASK"
|
||||
msgstr "Visualizza singolo TASK"
|
||||
|
||||
#: templates/measure/task_list.html:294
|
||||
msgid "Nessun task disponibile"
|
||||
msgstr "Nessun task disponibile"
|
||||
|
||||
#: templates/measure/task_list.html:272
|
||||
msgid "Questa ricetta non ha ancora task definiti."
|
||||
msgstr "Questa ricetta non ha ancora task definiti."
|
||||
|
||||
# SPC Statistics Dashboard
|
||||
#: templates/statistics/dashboard.html:3 templates/statistics/dashboard.html:17
|
||||
msgid "Statistiche SPC"
|
||||
@@ -2688,3 +2733,6 @@ msgstr "Errore nella generazione del report"
|
||||
#~ msgid "Utente non autorizzato (richiesto capoturno)"
|
||||
#~ msgstr "Utente non autorizzato (richiesto capoturno)"
|
||||
|
||||
#~ msgid "Errore nel caricamento dei task: %(detail)s"
|
||||
#~ msgstr "Errore nel caricamento dei task: %(detail)s"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-07-28 20:48+0000\n"
|
||||
"POT-Creation-Date: 2026-07-28 21:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -126,43 +126,62 @@ msgstr ""
|
||||
msgid "Errore nel caricamento delle ricette: %(detail)s"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:146 blueprints/measure.py:237
|
||||
#: blueprints/measure.py:139 templates/measure/select_recipe.html:30
|
||||
#: templates/measure/task_list.html:86
|
||||
msgid "lotto"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:141 templates/measure/select_recipe.html:31
|
||||
#: templates/measure/task_list.html:87
|
||||
msgid "seriale"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:204 blueprints/measure.py:242
|
||||
#: blueprints/measure.py:330
|
||||
#, python-format
|
||||
msgid "Ricetta non trovata: %(detail)s"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:156
|
||||
#: blueprints/measure.py:213
|
||||
#, python-format
|
||||
msgid "Errore nel caricamento dei task: %(detail)s"
|
||||
msgid "Compila prima: %(fields)s"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:185
|
||||
#: blueprints/measure.py:222 templates/measure/task_list.html:297
|
||||
msgid "Questa ricetta non ha ancora task definiti."
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:250
|
||||
msgid "Errore nel caricamento dei task."
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:278
|
||||
#, python-format
|
||||
msgid "Task non trovato: %(detail)s"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:306
|
||||
#: blueprints/measure.py:399
|
||||
msgid "Codice non fornito"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:312 templates/measure/select_recipe.html:57
|
||||
#: blueprints/measure.py:405 templates/measure/select_recipe.html:60
|
||||
msgid "Ricetta non trovata"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:368
|
||||
#: blueprints/measure.py:461
|
||||
msgid "Dati mancanti: subtask_id, version_id e value sono obbligatori"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:393 templates/admin/stations.html:549
|
||||
#: blueprints/measure.py:486 templates/admin/stations.html:549
|
||||
#: templates/maker/recipe_editor.html:598
|
||||
msgid "Errore nel salvataggio"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:437 blueprints/measure.py:542
|
||||
#: blueprints/measure.py:530 blueprints/measure.py:635
|
||||
msgid "Username e password richiesti"
|
||||
msgstr ""
|
||||
|
||||
#: blueprints/measure.py:463 blueprints/measure.py:480
|
||||
#: blueprints/measure.py:556 blueprints/measure.py:573
|
||||
#: templates/errors/station_not_configured.html:2
|
||||
#: templates/errors/station_not_configured.html:16
|
||||
msgid "Stazione non configurata"
|
||||
@@ -364,8 +383,8 @@ msgstr ""
|
||||
#: templates/maker/task_editor.html:312 templates/maker/task_editor.html:421
|
||||
#: templates/maker/task_editor.html:782 templates/maker/task_editor.html:901
|
||||
#: templates/maker/task_editor.html:966 templates/maker/task_editor.html:1071
|
||||
#: templates/measure/select_recipe.html:405
|
||||
#: templates/measure/task_execute.html:860
|
||||
#: templates/measure/select_recipe.html:413
|
||||
#: templates/measure/task_execute.html:887
|
||||
msgid "Annulla"
|
||||
msgstr ""
|
||||
|
||||
@@ -381,7 +400,7 @@ msgstr ""
|
||||
#: templates/admin/stations.html:241 templates/admin/users.html:299
|
||||
#: templates/maker/recipe_editor.html:107
|
||||
#: templates/maker/recipe_editor.html:490 templates/maker/task_drawing.html:61
|
||||
#: templates/measure/task_execute.html:412
|
||||
#: templates/measure/task_execute.html:424
|
||||
msgid "Salvataggio..."
|
||||
msgstr ""
|
||||
|
||||
@@ -509,7 +528,7 @@ msgstr ""
|
||||
#: templates/admin/users.html:48 templates/admin/users.html:173
|
||||
#: templates/admin/users.html:179 templates/auth/login.html:35
|
||||
#: templates/auth/login.html:49 templates/auth/profile.html:36
|
||||
#: templates/measure/task_execute.html:842
|
||||
#: templates/measure/task_execute.html:869
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
@@ -561,7 +580,7 @@ msgstr ""
|
||||
|
||||
#: templates/admin/users.html:206 templates/admin/users.html:214
|
||||
#: templates/auth/login.html:57 templates/auth/login.html:71
|
||||
#: templates/measure/task_execute.html:847
|
||||
#: templates/measure/task_execute.html:874
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
@@ -712,8 +731,8 @@ msgstr ""
|
||||
|
||||
#: templates/components/barcode_scanner.html:21
|
||||
#: templates/components/barcode_scanner.html:54
|
||||
#: templates/measure/select_recipe.html:128
|
||||
#: templates/measure/select_recipe.html:357
|
||||
#: templates/measure/select_recipe.html:131
|
||||
#: templates/measure/select_recipe.html:365
|
||||
msgid "Scansiona Barcode"
|
||||
msgstr ""
|
||||
|
||||
@@ -807,14 +826,14 @@ msgid "Misura solo da calibro: questa ricetta non ammette valori digitati"
|
||||
msgstr ""
|
||||
|
||||
#: templates/components/production_clock.html:42
|
||||
#: templates/measure/task_execute.html:460
|
||||
#: templates/measure/task_execute.html:472
|
||||
msgid "Prossima misurazione tra"
|
||||
msgstr ""
|
||||
|
||||
#: templates/components/production_clock.html:49
|
||||
#: templates/components/production_clock.html:62
|
||||
#: templates/measure/task_execute.html:463
|
||||
#: templates/measure/task_execute.html:542
|
||||
#: templates/measure/task_execute.html:475
|
||||
#: templates/measure/task_execute.html:554
|
||||
msgid "Misurazione in ritardo di"
|
||||
msgstr ""
|
||||
|
||||
@@ -823,27 +842,27 @@ msgid "Linea ferma — conto alla rovescia congelato a"
|
||||
msgstr ""
|
||||
|
||||
#: templates/components/production_clock.html:62
|
||||
#: templates/measure/task_execute.html:536
|
||||
#: templates/measure/task_execute.html:548
|
||||
msgid "Linea ferma"
|
||||
msgstr ""
|
||||
|
||||
#: templates/components/production_clock.html:74
|
||||
#: templates/measure/task_execute.html:472
|
||||
#: templates/measure/task_execute.html:484
|
||||
msgid "Ciclo"
|
||||
msgstr ""
|
||||
|
||||
#: templates/components/production_clock.html:92
|
||||
#: templates/measure/task_execute.html:704
|
||||
#: templates/measure/task_execute.html:731
|
||||
msgid "È ora di misurare"
|
||||
msgstr ""
|
||||
|
||||
#: templates/components/production_clock.html:95
|
||||
#: templates/measure/task_execute.html:706
|
||||
#: templates/measure/task_execute.html:733
|
||||
msgid "Ritorno alla misurazione tra"
|
||||
msgstr ""
|
||||
|
||||
#: templates/components/production_clock.html:101
|
||||
#: templates/measure/task_execute.html:711
|
||||
#: templates/measure/task_execute.html:738
|
||||
msgid "Vai alla misura"
|
||||
msgstr ""
|
||||
|
||||
@@ -892,8 +911,8 @@ msgstr ""
|
||||
#: templates/maker/recipe_editor.html:128 templates/maker/recipe_list.html:246
|
||||
#: templates/maker/task_drawing.html:106 templates/maker/task_editor.html:130
|
||||
#: templates/measure/task_complete.html:171
|
||||
#: templates/measure/task_execute.html:615 templates/measure/task_list.html:2
|
||||
#: templates/measure/task_list.html:180
|
||||
#: templates/measure/task_execute.html:627 templates/measure/task_list.html:2
|
||||
#: templates/measure/task_list.html:185
|
||||
msgid "Task"
|
||||
msgstr ""
|
||||
|
||||
@@ -1066,9 +1085,9 @@ msgstr ""
|
||||
msgid "Errore durante eliminazione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:72
|
||||
#: templates/measure/task_execute.html:1362
|
||||
#: templates/measure/task_execute.html:1672
|
||||
#: templates/maker/recipe_list.html:55 templates/measure/select_recipe.html:75
|
||||
#: templates/measure/task_execute.html:1423
|
||||
#: templates/measure/task_execute.html:1733
|
||||
msgid "Errore di connessione"
|
||||
msgstr ""
|
||||
|
||||
@@ -1101,7 +1120,7 @@ msgid "ricetta trovata"
|
||||
msgstr ""
|
||||
|
||||
#: templates/maker/recipe_list.html:144
|
||||
#: templates/measure/select_recipe.html:196
|
||||
#: templates/measure/select_recipe.html:199
|
||||
msgid "ricette trovate"
|
||||
msgstr ""
|
||||
|
||||
@@ -1119,7 +1138,7 @@ msgid "Versioni"
|
||||
msgstr ""
|
||||
|
||||
#: templates/maker/recipe_list.html:297
|
||||
#: templates/measure/select_recipe.html:311
|
||||
#: templates/measure/select_recipe.html:319
|
||||
msgid "Nessuna ricetta trovata"
|
||||
msgstr ""
|
||||
|
||||
@@ -1195,7 +1214,7 @@ msgid "Apri PDF"
|
||||
msgstr ""
|
||||
|
||||
#: templates/maker/recipe_preview.html:254
|
||||
#: templates/measure/task_execute.html:287
|
||||
#: templates/measure/task_execute.html:299
|
||||
msgid "Nessuna immagine allegata"
|
||||
msgstr ""
|
||||
|
||||
@@ -1206,7 +1225,7 @@ msgstr ""
|
||||
#: templates/maker/recipe_preview.html:299 templates/maker/task_editor.html:579
|
||||
#: templates/maker/task_editor.html:721
|
||||
#: templates/measure/task_complete.html:173
|
||||
#: templates/measure/task_execute.html:321
|
||||
#: templates/measure/task_execute.html:333
|
||||
msgid "Nominale"
|
||||
msgstr ""
|
||||
|
||||
@@ -1258,7 +1277,6 @@ msgid "Torna ai Task"
|
||||
msgstr ""
|
||||
|
||||
#: templates/maker/task_drawing.html:205 templates/maker/task_drawing.html:209
|
||||
#: templates/measure/select_recipe.html:291
|
||||
msgid "Seleziona"
|
||||
msgstr ""
|
||||
|
||||
@@ -1372,17 +1390,17 @@ msgid "Tipo"
|
||||
msgstr ""
|
||||
|
||||
#: templates/maker/task_editor.html:277 templates/maker/task_editor.html:543
|
||||
#: templates/measure/task_list.html:198
|
||||
#: templates/measure/task_list.html:203
|
||||
msgid "Nota"
|
||||
msgstr ""
|
||||
|
||||
#: templates/maker/task_editor.html:278 templates/maker/task_editor.html:544
|
||||
#: templates/measure/task_execute.html:309 templates/measure/task_list.html:196
|
||||
#: templates/measure/task_execute.html:321 templates/measure/task_list.html:201
|
||||
msgid "Misura"
|
||||
msgstr ""
|
||||
|
||||
#: templates/maker/task_editor.html:279 templates/maker/task_editor.html:545
|
||||
#: templates/measure/task_list.html:197
|
||||
#: templates/measure/task_list.html:202
|
||||
msgid "Disegno"
|
||||
msgstr ""
|
||||
|
||||
@@ -1413,7 +1431,7 @@ msgstr ""
|
||||
|
||||
#: templates/maker/task_editor.html:390
|
||||
#: templates/maker/version_history.html:188
|
||||
#: templates/measure/task_list.html:213
|
||||
#: templates/measure/task_list.html:238
|
||||
msgid "misurazioni"
|
||||
msgstr ""
|
||||
|
||||
@@ -1679,7 +1697,7 @@ msgid "Misurazione aggiunta"
|
||||
msgstr ""
|
||||
|
||||
#: templates/maker/task_editor.html:1685
|
||||
#: templates/measure/task_execute.html:1170
|
||||
#: templates/measure/task_execute.html:1231
|
||||
msgid "Errore nel salvataggio della misurazione"
|
||||
msgstr ""
|
||||
|
||||
@@ -1738,121 +1756,121 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:2
|
||||
#: templates/measure/select_recipe.html:94
|
||||
#: templates/measure/select_recipe.html:97
|
||||
msgid "Seleziona Ricetta"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:30 templates/measure/task_list.html:86
|
||||
msgid "lotto"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:31 templates/measure/task_list.html:87
|
||||
msgid "seriale"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:64
|
||||
#: templates/measure/select_recipe.html:277 templates/measure/task_list.html:97
|
||||
#: templates/measure/select_recipe.html:67
|
||||
#: templates/measure/select_recipe.html:280 templates/measure/task_list.html:97
|
||||
msgid "Compila prima:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:97
|
||||
#: templates/measure/select_recipe.html:100
|
||||
msgid "Scegli la ricetta di misura da eseguire"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:100
|
||||
#: templates/measure/select_recipe.html:103
|
||||
msgid "Stazione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:110
|
||||
#: templates/measure/select_recipe.html:113
|
||||
msgid "Stazione forzata per collaudo"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:110
|
||||
#: templates/measure/select_recipe.html:113
|
||||
msgid "configurata"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:115
|
||||
#: templates/measure/select_recipe.html:118
|
||||
msgid "Ripristina"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:140
|
||||
#: templates/measure/select_recipe.html:143
|
||||
msgid "Cerca ricetta"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:144
|
||||
#: templates/measure/select_recipe.html:147
|
||||
msgid "Nome, codice o descrizione..."
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:157
|
||||
#: templates/measure/select_recipe.html:160
|
||||
msgid "Tracciabilità"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:158
|
||||
#: templates/measure/select_recipe.html:161
|
||||
msgid "Dati del pezzo da misurare — compila prima di selezionare la ricetta"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:168
|
||||
#: templates/measure/select_recipe.html:171
|
||||
#: templates/measure/task_complete.html:284
|
||||
msgid "Numero Lotto"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:172
|
||||
#: templates/measure/select_recipe.html:175
|
||||
msgid "Es. LOT-2026-001"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:182
|
||||
#: templates/measure/select_recipe.html:185
|
||||
#: templates/measure/task_complete.html:285
|
||||
msgid "Numero Seriale"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:186
|
||||
#: templates/measure/select_recipe.html:189
|
||||
msgid "Es. SN-000123"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:239
|
||||
#: templates/measure/select_recipe.html:242
|
||||
msgid "Nessuna descrizione disponibile"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:315
|
||||
#: templates/measure/select_recipe.html:294
|
||||
#: templates/measure/task_list.html:107
|
||||
msgid "AVVIA IN SEQUENZA"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:302
|
||||
msgid "Vedi tutti i task"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:323
|
||||
msgid "Nessun risultato per"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:316
|
||||
#: templates/measure/select_recipe.html:324
|
||||
msgid "Prova con un termine diverso."
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:319
|
||||
#: templates/measure/select_recipe.html:327
|
||||
msgid "Non ci sono ricette disponibili al momento."
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:372
|
||||
#: templates/measure/select_recipe.html:380
|
||||
msgid ""
|
||||
"Inserisci o scansiona il codice della ricetta per selezionarla "
|
||||
"automaticamente."
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:377
|
||||
#: templates/measure/select_recipe.html:385
|
||||
msgid "Codice Ricetta"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:383
|
||||
#: templates/measure/select_recipe.html:391
|
||||
msgid "Es. REC-001"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/select_recipe.html:419
|
||||
#: templates/measure/select_recipe.html:427
|
||||
msgid "Cerca"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_complete.html:3
|
||||
#: templates/measure/task_complete.html:39
|
||||
#: templates/measure/task_execute.html:113
|
||||
#: templates/measure/task_execute.html:765
|
||||
#: templates/measure/task_execute.html:792
|
||||
#: templates/statistics/dashboard.html:139
|
||||
msgid "Riepilogo"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_complete.html:47
|
||||
#: templates/measure/task_execute.html:742
|
||||
#: templates/measure/task_execute.html:769
|
||||
msgid "Misurazioni Complete"
|
||||
msgstr ""
|
||||
|
||||
@@ -1873,12 +1891,12 @@ msgid "Totale"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_complete.html:106
|
||||
#: templates/measure/task_execute.html:750
|
||||
#: templates/measure/task_execute.html:777
|
||||
msgid "Conformi"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_complete.html:123
|
||||
#: templates/measure/task_execute.html:754
|
||||
#: templates/measure/task_execute.html:781
|
||||
msgid "Attenzione"
|
||||
msgstr ""
|
||||
|
||||
@@ -2040,175 +2058,192 @@ msgstr ""
|
||||
msgid "Task di misurazione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:106
|
||||
#: templates/measure/task_execute.html:115
|
||||
msgid "Lista task"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:128
|
||||
msgid "Fermo linea"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:136
|
||||
msgid "Riprendi"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:144
|
||||
msgid "Fine Produzione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:259
|
||||
msgid "Immagine dettaglio misura"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:307
|
||||
msgid "Misurazione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:385
|
||||
msgid "Registrata"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:491
|
||||
msgid "Task di misura senza quote configurate: la ricetta è incompleta"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:510
|
||||
msgid "Quota fuori tolleranza"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:513
|
||||
msgid "serve il capoturno, oppure una nuova misura della stessa quota"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:517
|
||||
#: templates/measure/task_execute.html:870
|
||||
msgid "Autorizza"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:541
|
||||
msgid "Il conto alla rovescia è congelato a"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:544
|
||||
msgid "serve il capoturno per riprendere"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:563
|
||||
msgid "Produzione non registrata sul server"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:584
|
||||
#: templates/measure/task_execute.html:793
|
||||
msgid "Avvio Produzione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:588
|
||||
msgid "Invia segnale al gestionale per avviare il timer della linea"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:599
|
||||
msgid "Produzione avviata"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:644
|
||||
msgid "Fine ciclo misura"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:655
|
||||
msgid "Rimisura"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:665
|
||||
#: templates/measure/task_execute.html:679
|
||||
#: templates/measure/task_execute.html:125
|
||||
#: templates/measure/task_execute.html:706 templates/measure/task_list.html:227
|
||||
msgid "Completato"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:744
|
||||
msgid "Tutte le"
|
||||
#: templates/measure/task_execute.html:140
|
||||
msgid "Fermo linea"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:744
|
||||
msgid "misurazioni sono state registrate."
|
||||
#: templates/measure/task_execute.html:148
|
||||
msgid "Riprendi"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:758
|
||||
msgid "Non Conf."
|
||||
#: templates/measure/task_execute.html:156
|
||||
msgid "Fine Produzione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:773
|
||||
msgid "Conferma ciclo"
|
||||
#: templates/measure/task_execute.html:271
|
||||
msgid "Immagine dettaglio misura"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:783
|
||||
#: templates/measure/task_execute.html:319
|
||||
msgid "Misurazione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:397
|
||||
msgid "Registrata"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:503
|
||||
msgid "Task di misura senza quote configurate: la ricetta è incompleta"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:522
|
||||
msgid "Quota fuori tolleranza"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:525
|
||||
msgid "serve il capoturno, oppure una nuova misura della stessa quota"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:529
|
||||
#: templates/measure/task_execute.html:897
|
||||
msgid "Autorizza"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:553
|
||||
msgid "Il conto alla rovescia è congelato a"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:556
|
||||
msgid "serve il capoturno per riprendere"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:575
|
||||
msgid "Produzione non registrata sul server"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:596
|
||||
#: templates/measure/task_execute.html:820
|
||||
msgid "Avvio Produzione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:600
|
||||
msgid "Invia segnale al gestionale per avviare il timer della linea"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:611
|
||||
msgid "Produzione avviata"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:667
|
||||
msgid "Fine ciclo misura"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:679
|
||||
msgid "Rimisura"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:692
|
||||
#: templates/measure/task_execute.html:810
|
||||
msgid "Task successivo"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:809
|
||||
#: templates/measure/task_execute.html:771
|
||||
msgid "Tutte le"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:771
|
||||
msgid "misurazioni sono state registrate."
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:785
|
||||
msgid "Non Conf."
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:800
|
||||
msgid "Conferma ciclo"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:836
|
||||
msgid "Girare il pezzo e rimisurare"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:835
|
||||
#: templates/measure/task_execute.html:862
|
||||
msgid "Autorizzazione capoturno"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:844
|
||||
#: templates/measure/task_execute.html:871
|
||||
msgid "Username capoturno"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:861
|
||||
#: templates/measure/task_execute.html:888
|
||||
msgid "Rimisura la quota"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1125
|
||||
#: templates/measure/task_execute.html:1027
|
||||
msgid "Manca 1 quota"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1028
|
||||
msgid "Mancano"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1028
|
||||
msgid "quote"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1046
|
||||
msgid "Serve l'autorizzazione del capoturno"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1049
|
||||
msgid "Chiudi prima il ciclo di misura"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1186
|
||||
msgid "Questa ricetta non ammette valori digitati: usare il calibro"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1222
|
||||
#: templates/measure/task_execute.html:1283
|
||||
msgid "Errore di rete. Riprovare."
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1260
|
||||
#: templates/measure/task_execute.html:1321
|
||||
msgid ""
|
||||
"Quota fuori tolleranza: serve l'autorizzazione del capoturno, oppure "
|
||||
"misurare di nuovo la quota"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1357
|
||||
#: templates/measure/task_execute.html:1418
|
||||
msgid "Errore di comunicazione con il server"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1609
|
||||
#: templates/measure/task_execute.html:1670
|
||||
msgid "Misurazione fuori tolleranza"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1610
|
||||
#: templates/measure/task_execute.html:1671
|
||||
msgid "Fermo linea richiesto"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1611
|
||||
#: templates/measure/task_execute.html:1672
|
||||
msgid "Ripresa della produzione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1612
|
||||
#: templates/measure/task_execute.html:1673
|
||||
msgid "Fine produzione richiesta"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1656
|
||||
#: templates/measure/task_execute.html:1717
|
||||
msgid "Credenziali non valide o utente non autorizzato"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1683
|
||||
#: templates/measure/task_execute.html:1744
|
||||
msgid "Nessuna produzione aperta su questa stazione"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_execute.html:1700
|
||||
#: templates/measure/task_execute.html:1761
|
||||
msgid "Azione non riuscita"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_list.html:107
|
||||
msgid "AVVIA"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_list.html:145
|
||||
msgid "Task da eseguire"
|
||||
msgstr ""
|
||||
@@ -2217,30 +2252,30 @@ msgstr ""
|
||||
msgid "misurazioni totali"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_list.html:199
|
||||
#: templates/measure/task_list.html:204
|
||||
msgid "Confronto profilo"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_list.html:200
|
||||
#: templates/measure/task_list.html:205
|
||||
msgid "Misura camera"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_list.html:222
|
||||
#: templates/measure/task_list.html:232
|
||||
msgid "Incompiuto"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_list.html:247
|
||||
msgid "Allegato"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_list.html:246
|
||||
msgid "Visualizza Task"
|
||||
#: templates/measure/task_list.html:275
|
||||
msgid "Visualizza singolo TASK"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_list.html:269
|
||||
#: templates/measure/task_list.html:294
|
||||
msgid "Nessun task disponibile"
|
||||
msgstr ""
|
||||
|
||||
#: templates/measure/task_list.html:272
|
||||
msgid "Questa ricetta non ha ancora task definiti."
|
||||
msgstr ""
|
||||
|
||||
#: templates/statistics/dashboard.html:3 templates/statistics/dashboard.html:17
|
||||
msgid "Statistiche SPC"
|
||||
msgstr ""
|
||||
|
||||
Reference in New Issue
Block a user