From bcab7573c34f345446a2ca1693bcffd8bbf305cb Mon Sep 17 00:00:00 2001 From: Marco Gallegos Date: Sun, 14 Sep 2025 09:02:27 -0600 Subject: [PATCH] fix: Implement folio prefix system with database migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix generateFolio() to use configured prefix (e.g. "AP-k8hcg" instead of "AP--k8hcg") - Add migration endpoint /api/migrate-folios to update existing folios with prefix - Add automatic migration prompt when folio prefix changes in settings - Ensure all new folios use the configured prefix format - Maintain backward compatibility with existing folios Migration process: - Detects folios without prefix and adds the configured prefix - Only updates folios that don't already have the prefix - Provides user feedback on migration results - Automatically refreshes ticket list after successful migration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- app.js | 50 +++++++++++++++++++++++++++++++++++++++++++++- server.js | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/app.js b/app.js index 487e36e..3824f48 100644 --- a/app.js +++ b/app.js @@ -844,12 +844,13 @@ async function loadDashboardData() { } function generateFolio() { + const prefix = settings.folioPrefix || 'AP-'; const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; for (let i = 0; i < 5; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } - return result; + return `${prefix}${result}`; } async function addMovement(mov) { @@ -1188,6 +1189,22 @@ async function handleSaveSettings(e) { }); if (response.ok) { alert('Configuración guardada.'); + + // Check if folio prefix changed and needs migration + const oldPrefix = window.settings?.folioPrefix; + const newPrefix = settings.folioPrefix; + + if (oldPrefix && newPrefix && oldPrefix !== newPrefix) { + const shouldMigrate = confirm( + `El prefijo de folio cambió de "${oldPrefix}" a "${newPrefix}".\n\n` + + '¿Deseas actualizar todos los folios existentes con el nuevo prefijo?\n\n' + + 'Esto agregará el prefijo a todos los folios que no lo tengan.' + ); + + if (shouldMigrate) { + await migrateFolios(settings); + } + } } else { throw new Error('Failed to save settings'); } @@ -1197,6 +1214,37 @@ async function handleSaveSettings(e) { } } +// Function to migrate existing folios +async function migrateFolios(settings) { + try { + console.log('Starting folio migration...'); + const response = await fetch('/api/migrate-folios', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ settings }) + }); + + const result = await response.json(); + + if (result.success) { + if (result.updated > 0) { + alert(`✅ Migración completada!\n\n${result.updated} folios actualizados con el nuevo prefijo.`); + // Refresh the tickets table if visible + if (document.querySelector('.tab-content').style.display !== 'none') { + loadMovements(); + } + } else { + alert('ℹ️ No hay folios que necesiten migración.'); + } + } else { + throw new Error(result.message || 'Migration failed'); + } + } catch (error) { + console.error('Error during migration:', error); + alert('❌ Error durante la migración de folios: ' + error.message); + } +} + async function handleSaveCredentials(e) { e.preventDefault(); const name = document.getElementById('s-name').value; diff --git a/server.js b/server.js index 670c4fd..c0ca84f 100644 --- a/server.js +++ b/server.js @@ -789,6 +789,66 @@ function startServer() { }); }); + // Migration endpoint to update existing folios with prefix + apiRouter.post('/migrate-folios', (req, res) => { + const settings = req.body.settings; + const prefix = settings?.folioPrefix || 'AP-'; + + console.log(`Starting folio migration with prefix: ${prefix}`); + + // Get all movements that don't already have the prefix + db.all(`SELECT id, folio FROM movements WHERE folio NOT LIKE '${prefix}%'`, [], (err, rows) => { + if (err) { + console.error('Error fetching movements for migration:', err); + return res.status(500).json({ error: err.message }); + } + + if (rows.length === 0) { + console.log('No folios need migration'); + return res.json({ + success: true, + message: 'No folios need migration', + updated: 0 + }); + } + + let updatedCount = 0; + let errorCount = 0; + + // Update each folio + const updatePromises = rows.map(row => { + return new Promise((resolve) => { + const newFolio = `${prefix}${row.folio}`; + + db.run(`UPDATE movements SET folio = ? WHERE id = ?`, + [newFolio, row.id], + function(updateErr) { + if (updateErr) { + console.error(`Error updating folio ${row.folio}:`, updateErr); + errorCount++; + } else { + console.log(`Updated folio: ${row.folio} → ${newFolio}`); + updatedCount++; + } + resolve(); + } + ); + }); + }); + + // Wait for all updates to complete + Promise.all(updatePromises).then(() => { + console.log(`Migration completed: ${updatedCount} updated, ${errorCount} errors`); + res.json({ + success: true, + message: `Migration completed: ${updatedCount} folios updated, ${errorCount} errors`, + updated: updatedCount, + errors: errorCount + }); + }); + }); + }); + app.use('/api', apiRouter); app.listen(port, () => {