fix(csv): export dal browser legge nominale/tolleranze/descrizione da m.subtask (#31)

buildMeasurementCSV leggeva m.subtask_name/unit/nominal/tolerance_plus/
tolerance_minus/operator_name: nessuno di questi campi esiste su
MeasurementResponse. I dati reali stanno annidati in m.subtask (description,
unit, nominal, utl, ltl - misurati.py:task_complete() li allega lato server).
tolleranza + = utl-nominal, tolleranza - = nominal-ltl, solo quando entrambi
i lati sono presenti (nessun NaN su tolleranza a un lato solo). Unità dalla
quota, "mm" solo se assente. Operatore: measured_by (id), l'unico campo
reale - non esiste un nome operatore da nessuna parte in questi dati.
Test node in tests/js/test_csv_export.js (stesso pattern di test_numpad.js).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-21 22:52:21 +02:00
parent 4384c4860b
commit e8d21b78a9
3 changed files with 168 additions and 6 deletions
+29 -6
View File
@@ -71,22 +71,38 @@ function csvExport() {
let csv = headers.join(this.delimiter) + '\n';
for (const m of measurements) {
// MeasurementResponse (src/backend/models/api/measurement.py) carries
// none of subtask_name/unit/nominal/tolerance_plus/tolerance_minus -
// that data lives nested under m.subtask (attached server-side in
// measure.py's task_complete(), see subtask/task_info enrichment).
// Reading the flat, nonexistent names is why every one of these
// columns came out empty (#31).
const subtask = m.subtask || {};
const nominal = subtask.nominal;
const tolerancePlus = this.hasNumber(subtask.utl) && this.hasNumber(nominal)
? subtask.utl - nominal : null;
const toleranceMinus = this.hasNumber(nominal) && this.hasNumber(subtask.ltl)
? nominal - subtask.ltl : null;
const row = [
m.id || '',
m.subtask_id || '',
this.escapeCsvValue(m.subtask_name || ''),
this.escapeCsvValue(subtask.description || ''),
this.formatNumber(m.value),
this.escapeCsvValue(m.unit || 'mm'),
this.formatNumber(m.nominal),
this.formatNumber(m.tolerance_plus),
this.formatNumber(m.tolerance_minus),
this.escapeCsvValue(subtask.unit || 'mm'),
this.formatNumber(nominal),
this.formatNumber(tolerancePlus),
this.formatNumber(toleranceMinus),
this.formatNumber(m.deviation),
m.pass_fail || '',
this.escapeCsvValue(m.lot_number || ''),
this.escapeCsvValue(m.serial_number || ''),
m.input_method || '',
this.formatDateTime(m.measured_at),
this.escapeCsvValue(m.operator_name || '')
// No operator name anywhere on this object (or on
// MeasurementResponse) - measured_by is the real field, the
// user's id who took the reading.
this.escapeCsvValue(this.hasNumber(m.measured_by) ? m.measured_by : '')
];
csv += row.join(this.delimiter) + '\n';
}
@@ -163,6 +179,13 @@ function csvExport() {
URL.revokeObjectURL(url);
},
/**
* True for a value that is actually a usable number (not null/undefined/NaN).
*/
hasNumber(value) {
return typeof value === 'number' && !Number.isNaN(value);
},
/**
* Format number with Italian decimal separator
*/