feat(recipes): la ricetta decide cosa pretendere e come si misura
Tre cose che prima non erano di nessuno diventano regole della ricetta, decise da chi la scrive e fatte valere dal server. Punto 8 — tracciabilita' obbligatoria. Lotto e seriale si dichiarano obbligatori sulla ricetta. L'operatore li inserisce alla selezione, dove il pulsante non si attiva finche' mancano, e la stessa regola vale sulla lista task, raggiungibile anche per link diretto, e sul barcode: uno sbarramento che dura solo finche' qualcuno prende in mano il lettore non e' uno sbarramento. La produzione non si apre e la misura non si salva senza cio' che la ricetta pretende, perche' un valore senza il suo lotto non e' riconducibile a niente, e accorgersene dopo significa accorgersene tardi. Punto 9 — inserimento manuale. Una ricetta puo' vietare i valori digitati, ed e' il valore predefinito: il calibro e' lo strumento, digitare e' cio' che va concesso. Dove e' vietato il tastierino non viene disegnato (non nascosto con i CSS: il markup nascosto e' markup che si puo' rimostrare) e restano correzione e conferma, perche' una lettura sbagliata va cancellata. Il controllo vero e' sul server: una regola che vive solo nel frontend e' un consiglio. Migliorato al passaggio il riconoscimento del calibro. Contava solo la raffica di cifre, cosi' una lettura corta come "9.5" — tre battute — finiva registrata come digitata a mano; ora conta anche l'Invio che il wedge manda dentro la stessa raffica. Senza questa correzione il divieto avrebbe respinto misure legittime. Punto 11 — formattazione delle descrizioni. A capo e grassetto sopravvivono: chi scrive le ricette incolla dal PDF della scheda tecnica e il testo arrivava appiattito, da risistemare a mano ogni volta. Nessun HTML viene accettato o salvato — il testo viene escapato e gli unici tag nel risultato sono quelli prodotti dal renderer. La sanificazione e' questa: non c'e' niente da sanificare perche' non si accetta niente. Le stesse due regole in Jinja e in JS, cosi' una descrizione si legge uguale ovunque. E la descrizione ora si vede anche in esecuzione: era scritta per l'operatore e la vedeva solo chi la scriveva. Migrazione 009: tre colonne sulla ricetta. Le due di tracciabilita' partono false, che e' il comportamento di oggi; l'inserimento manuale parte *vero* sulle ricette gia' esistenti — il default della colonna e' falso, quindi le ricette nuove sono solo-calibro, ma spegnerlo d'ufficio su quelle in uso fermerebbe una linea alla misura successiva. Chi possiede la ricetta lo decide dall'editor. Test: +26 (291). Coprono il rifiuto sul server per lotto, seriale e valore digitato, il calibro sempre ammesso, le regole che sopravvivono alla nuova versione, il tastierino assente in pagina, l'Avvia sbarrato, e il renderer delle descrizioni compreso il caso in cui si prova a farci passare un tag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -248,6 +248,48 @@
|
||||
{{ _('Timer cicalino per ricordare la misurazione periodica') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Regole di misura: cosa la ricetta pretende dall'operatore -->
|
||||
<div class="sm:col-span-2 pt-2 border-t border-[var(--border-color)]">
|
||||
<p class="tmf-label mb-2">{{ _('Regole di misura') }}</p>
|
||||
<div class="grid sm:grid-cols-3 gap-3">
|
||||
|
||||
<label class="flex items-start gap-2 cursor-pointer">
|
||||
<input type="checkbox" x-model="requiresLot"
|
||||
class="mt-0.5 rounded border-[var(--border-color)] text-primary focus:ring-primary">
|
||||
<span>
|
||||
<span class="text-sm text-[var(--text-primary)]">{{ _('Lotto obbligatorio') }}</span>
|
||||
<span class="block text-xs text-[var(--text-muted)]">
|
||||
{{ _('Senza lotto la produzione non parte') }}
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="flex items-start gap-2 cursor-pointer">
|
||||
<input type="checkbox" x-model="requiresSerial"
|
||||
class="mt-0.5 rounded border-[var(--border-color)] text-primary focus:ring-primary">
|
||||
<span>
|
||||
<span class="text-sm text-[var(--text-primary)]">{{ _('Seriale obbligatorio') }}</span>
|
||||
<span class="block text-xs text-[var(--text-muted)]">
|
||||
{{ _('Senza seriale la produzione non parte') }}
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
{# Off by default: the caliper is the instrument, and a value that
|
||||
happens to be in tolerance must not be enterable by hand. #}
|
||||
<label class="flex items-start gap-2 cursor-pointer">
|
||||
<input type="checkbox" x-model="allowManualInput"
|
||||
class="mt-0.5 rounded border-[var(--border-color)] text-primary focus:ring-primary">
|
||||
<span>
|
||||
<span class="text-sm text-[var(--text-primary)]">{{ _('Consenti inserimento manuale') }}</span>
|
||||
<span class="block text-xs text-[var(--text-muted)]">
|
||||
{{ _('Se disattivo si misura solo col calibro') }}
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -486,6 +528,13 @@ function recipeEditor() {
|
||||
// ---- Measurement interval ----
|
||||
measurementIntervalMinutes: {{ (recipe.measurement_interval_minutes if recipe and recipe.measurement_interval_minutes else 'null')|tojson }},
|
||||
|
||||
// ---- Rules of measurement (points 8 and 9) ----
|
||||
// A new recipe forbids typing: the caliper is the instrument, and permission
|
||||
// to type is what has to be given, not taken away.
|
||||
requiresLot: {{ (recipe.requires_lot|default(false) if recipe else false)|tojson }},
|
||||
requiresSerial: {{ (recipe.requires_serial|default(false) if recipe else false)|tojson }},
|
||||
allowManualInput: {{ (recipe.allow_manual_input|default(false) if recipe else false)|tojson }},
|
||||
|
||||
// ---- File upload (preview image) ----
|
||||
currentFilePath: {{ (recipe.image_path if recipe and recipe.image_path else '')|tojson }},
|
||||
uploadingFile: false,
|
||||
@@ -512,6 +561,12 @@ function recipeEditor() {
|
||||
payload.measurement_interval_minutes = parseInt(this.measurementIntervalMinutes, 10);
|
||||
}
|
||||
|
||||
// Rules of measurement. Sent every time, including when false: these are the
|
||||
// settings an operator gets told about, so turning one off has to travel.
|
||||
payload.requires_lot = !!this.requiresLot;
|
||||
payload.requires_serial = !!this.requiresSerial;
|
||||
payload.allow_manual_input = !!this.allowManualInput;
|
||||
|
||||
// Include image_path for preview thumbnail
|
||||
if (this.currentFilePath) {
|
||||
payload.image_path = this.currentFilePath;
|
||||
|
||||
Reference in New Issue
Block a user