/// // // M7 — Add structured VIN and duration fields to appointments. // // Older scan imports stored these values inside `notes` as: // VIN: | Duration: min // This migration adds first-class columns, backfills them when missing, and // removes those machine-generated note fragments while preserving any real text. // function compactNoteParts(raw) { return String(raw || '') .split('|') .map((part) => part.trim()) .filter(Boolean); } migrate( (db) => { const col = db.findCollectionByNameOrId('appointments'); if (!col) { console.warn('[M7] appointments collection not found — skipping'); return; } if (!col.fields.find((f) => f.name === 'vin')) { col.fields.push(new TextField({ name: 'vin', required: false })); db.save(col); console.log('[M7] added vin field to appointments'); } if (!col.fields.find((f) => f.name === 'durationMinutes')) { col.fields.push(new NumberField({ name: 'durationMinutes', required: false, min: 0, })); db.save(col); console.log('[M7] added durationMinutes field to appointments'); } const records = Array.from(db.findRecordsByFilter('appointments', '1=1', 'id', 500)); let backfilled = 0; for (const rec of records) { const rawNotes = String(rec.get('notes') || ''); const vinMatch = rawNotes.match(/(?:^|\|)\s*VIN:\s*([^|]+?)\s*(?=\||$)/i); const durationMatch = rawNotes.match(/(?:^|\|)\s*Duration:\s*(\d+)\s*min\s*(?=\||$)/i); const nextVin = String(rec.get('vin') || '').trim(); const rawDuration = rec.get('durationMinutes'); const nextDuration = rawDuration == null || rawDuration === '' ? null : Number(rawDuration); let changed = false; if (!nextVin && vinMatch?.[1]) { rec.set('vin', String(vinMatch[1]).trim()); changed = true; } if ((nextDuration == null || Number.isNaN(nextDuration)) && durationMatch?.[1]) { rec.set('durationMinutes', Number(durationMatch[1])); changed = true; } const cleanedNotes = compactNoteParts(rawNotes) .filter((part) => !/^VIN:\s*/i.test(part) && !/^Duration:\s*\d+\s*min$/i.test(part)) .join(' | '); if (cleanedNotes !== rawNotes.trim()) { rec.set('notes', cleanedNotes); changed = true; } if (changed) { db.saveRecord(rec); backfilled++; } } console.log(`[M7] updated ${backfilled} appointment record(s)`); }, (db) => { const col = db.findCollectionByNameOrId('appointments'); if (!col) return; const durationIdx = col.fields.findIndex((f) => f.name === 'durationMinutes'); if (durationIdx >= 0) { col.fields.splice(durationIdx, 1); db.save(col); } const vinIdx = col.fields.findIndex((f) => f.name === 'vin'); if (vinIdx >= 0) { col.fields.splice(vinIdx, 1); db.save(col); } } );