feat(tasks): il tipo di un task si dichiara, non si deduce

Punto 2 del documento modifiche del 28/07, prima richiesta di Menoncin.

Il sistema distingueva un task di misura da uno documentale deducendolo: se aveva
quote era una misura, altrimenti una nota. Conseguenza: un task di misura a cui le
quote non erano ancora state inserite veniva trattato come nota, e il sistema si
comportava in modo diverso a seconda di quanto fosse completa la ricetta.

Nuovo campo task_type su recipe_tasks (migrazione 007) con nota, misura e disegno,
piu' xf_compare e camera_measure gia' nell'enum: allargare un enum MySQL piu' avanti
e' un ALTER su tabella viva, e non costa nulla prevederli adesso.

Il backfill riproduce la classificazione che era a schermo, cosi' nessuna ricetta
cambia comportamento all'aggiornamento: i task con quote diventano 'measure'; quelli
senza quote ma con un disegno allegato diventano 'drawing' e non 'note', perche' e'
gia' cio' che mostravano - chiamarli note sarebbe stato l'unico punto in cui questa
migrazione cambiava le carte in tavola.

Il tipo viene copiato esplicitamente nel copy-on-write del versioning: una nuova
versione che lo perdesse riclassificherebbe in silenzio tutti i task alla prima
modifica di una ricetta. Il task "Technical Drawing" creato d'ufficio quando si
carica un disegno su una ricetta senza task nasce come 'drawing'.

Lato operatore decide ora il tipo, non il conteggio delle quote: fermo linea, fine
produzione, avvio produzione e la barra di produzione seguono il tipo. Dove servono
davvero delle quote da mostrare - elenco marker, tastierino, fine ciclo misura -
resta anche il controllo che ce ne sia almeno una, e un task di misura ancora privo
di quote lo dichiara invece di somigliare a una nota. Nella lista task compare il
tipo, cosi' si vede prima di aprire.

La 007 e' stata eseguita su SQLite usa e getta con tre righe costruite apposta - una
con quote, una col solo disegno, una nota secca - e il backfill le classifica come
atteso. Il backfill girera' sui dati reali del cliente, provarlo a mano non bastava.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-07-28 18:15:18 +00:00
parent 7bc3c1f938
commit 6fbff2fe76
12 changed files with 1019 additions and 589 deletions
@@ -270,6 +270,18 @@
class="tmf-input"
placeholder="{{ _('Es. Controllo dimensionale flangia') }}">
</div>
<!-- Tipo: dichiarato qui, non dedotto dal contenuto -->
<div>
<label class="tmf-label">{{ _('Tipo') }} <span class="text-red-500">*</span></label>
<select x-model="newTask.task_type" class="tmf-input">
<option value="note">{{ _('Nota') }}</option>
<option value="measure">{{ _('Misura') }}</option>
<option value="drawing">{{ _('Disegno') }}</option>
</select>
<p class="mt-1 text-xs text-[var(--text-secondary)]">
{{ _('Un task di misura resta tale anche prima di inserire le quote') }}
</p>
</div>
<!-- Direttiva -->
<div>
<label class="tmf-label">{{ _('Direttiva') }}</label>
@@ -516,6 +528,14 @@
<!-- Edit Task Extra Fields (when in edit mode) -->
<template x-if="editingTask === task.id">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 p-3 rounded-lg bg-blue-50 dark:bg-blue-900/10 border border-blue-200 dark:border-blue-800">
<div>
<label class="tmf-label">{{ _('Tipo') }}</label>
<select x-model="editTaskData.task_type" class="tmf-input text-sm">
<option value="note">{{ _('Nota') }}</option>
<option value="measure">{{ _('Misura') }}</option>
<option value="drawing">{{ _('Disegno') }}</option>
</select>
</div>
<div>
<label class="tmf-label">{{ _('Direttiva') }}</label>
<input type="text"
@@ -1084,8 +1104,8 @@ function taskEditor() {
// ---- Task CRUD state ----
editingTask: null,
editTaskData: { title: '', directive: '', description: '' },
newTask: { title: '', directive: '', description: '' },
editTaskData: { title: '', directive: '', description: '', task_type: 'note' },
newTask: { title: '', directive: '', description: '', task_type: 'note' },
// ---- Subtask CRUD state ----
editingSubtaskId: null,
@@ -1207,7 +1227,7 @@ function taskEditor() {
// ============================================================
resetNewTask() {
this.newTask = { title: '', directive: '', description: '' };
this.newTask = { title: '', directive: '', description: '', task_type: 'note' };
},
// ============================================================
@@ -1298,6 +1318,7 @@ function taskEditor() {
},
body: JSON.stringify({
title: this.newTask.title.trim(),
task_type: this.newTask.task_type || 'note',
directive: this.newTask.directive.trim() || null,
description: this.newTask.description.trim() || null
})
@@ -1328,6 +1349,7 @@ function taskEditor() {
this.editingTask = task.id;
this.editTaskData = {
title: task.title,
task_type: task.task_type || 'note',
directive: task.directive || '',
description: task.description || ''
};
@@ -1337,7 +1359,7 @@ function taskEditor() {
cancelEditTask() {
this.editingTask = null;
this.editTaskData = { title: '', directive: '', description: '' };
this.editTaskData = { title: '', directive: '', description: '', task_type: 'note' };
},
async updateTask(taskId) {
@@ -1354,6 +1376,7 @@ function taskEditor() {
},
body: JSON.stringify({
title: this.editTaskData.title.trim(),
task_type: this.editTaskData.task_type || 'note',
directive: this.editTaskData.directive.trim() || null,
description: this.editTaskData.description.trim() || null
})