From 1d761200f513e8e64d15d5abd37e4c5742a9ab3c Mon Sep 17 00:00:00 2001 From: Sidney Date: Fri, 1 May 2026 16:15:33 -0300 Subject: [PATCH] =?UTF-8?q?feat:=20sincroniza=C3=A7=C3=A3o=20total=20blind?= =?UTF-8?q?ada=20JSON=20->=20Postgres=20(Alunos,=20Turmas,=20Provas,=20Fre?= =?UTF-8?q?qu=C3=AAncias)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manager/scratch/diag_sync.js | 53 ++++++++++++++++++++ manager/services/database.js | 96 +++++++++++++++++++----------------- 2 files changed, 104 insertions(+), 45 deletions(-) create mode 100644 manager/scratch/diag_sync.js diff --git a/manager/scratch/diag_sync.js b/manager/scratch/diag_sync.js new file mode 100644 index 0000000..10034b9 --- /dev/null +++ b/manager/scratch/diag_sync.js @@ -0,0 +1,53 @@ + +import pkg from 'pg'; +const { Pool } = pkg; + +const DATABASE_URL = 'postgresql://edumanager:EduManager2026!Seguro@localhost:5432/edumanager'; +const pool = new Pool({ connectionString: DATABASE_URL }); + +async function runDiag() { + try { + const { rows } = await pool.query('SELECT data FROM school_data WHERE id = 1'); + const data = rows[0]?.data || {}; + + console.log('--- DIAGNÓSTICO DE SINCRONIZAÇÃO ---'); + + // 1. Verificar Alunos + const jsonStudents = data.students || []; + const { rows: dbStudents } = await pool.query('SELECT id, nome FROM alunos'); + console.log(`JSON: ${jsonStudents.length} alunos | DB: ${dbStudents.length} alunos`); + + if (jsonStudents.length > 0) { + const sample = jsonStudents[0]; + const inDb = dbStudents.find(s => s.id === sample.id); + console.log(`Exemplo Aluno [${sample.name}]: ${inDb ? '✅ No DB' : '❌ NÃO ESTÁ NO DB'}`); + + // Verificar campos específicos do primeiro aluno + if (inDb) { + const { rows: fullStudent } = await pool.query('SELECT * FROM alunos WHERE id = $1', [sample.id]); + const dbS = fullStudent[0]; + console.log('--- Comparação de Campos (Exemplo) ---'); + console.log(`CPF: JSON[${sample.cpf || '?'}] vs DB[${dbS.cpf || '?'}]`); + console.log(`Telefone: JSON[${sample.phone || '?'}] vs DB[${dbS.telefone || '?'}]`); + console.log(`Status: JSON[${sample.status || '?'}] vs DB[${dbS.status || '?'}]`); + } + } + + // 2. Verificar Turmas + const jsonClasses = data.classes || []; + const { rows: dbClasses } = await pool.query('SELECT COUNT(*) FROM turmas'); + console.log(`JSON: ${jsonClasses.length} turmas | DB: ${dbClasses[0].count} turmas`); + + // 3. Verificar Provas + const jsonExams = data.exams || []; + const { rows: dbExams } = await pool.query('SELECT COUNT(*) FROM provas'); + console.log(`JSON: ${jsonExams.length} provas | DB: ${dbExams[0].count} provas`); + + } catch (err) { + console.error('Erro no diagnóstico:', err.message); + } finally { + await pool.end(); + } +} + +runDiag(); diff --git a/manager/services/database.js b/manager/services/database.js index a1fb5fb..85cc7ca 100644 --- a/manager/services/database.js +++ b/manager/services/database.js @@ -283,7 +283,7 @@ export async function syncJsonToRelationalTables() { const data = await getSchoolData(); if (!data) return; - console.log('[Sincronização] 🔄 Iniciando espelhamento total JSON -> Tabelas Relacionais...'); + console.log('[Sincronização] 🔄 Iniciando espelhamento TOTAL (Modo Blindado)...'); await client.query('BEGIN'); // 1. Sincronizar Cursos @@ -303,7 +303,33 @@ export async function syncJsonToRelationalTables() { } } - // 2. Sincronizar Turmas + // 2. Sincronizar Disciplinas (Subjects) + if (data.subjects && Array.isArray(data.subjects)) { + for (const sub of data.subjects) { + if (!sub.id || !sub.name) continue; + await client.query( + `INSERT INTO disciplinas (id, nome) + VALUES ($1, $2) + ON CONFLICT (id) DO UPDATE SET nome = EXCLUDED.nome`, + [sub.id, sub.name] + ); + } + } + + // 3. Sincronizar Períodos (Bimestres) + if (data.periods && Array.isArray(data.periods)) { + for (const p of data.periods) { + if (!p.id || !p.name) continue; + await client.query( + `INSERT INTO periodos (id, nome) + VALUES ($1, $2) + ON CONFLICT (id) DO UPDATE SET nome = EXCLUDED.nome`, + [p.id, p.name] + ); + } + } + + // 4. Sincronizar Turmas if (data.classes && Array.isArray(data.classes)) { for (const t of data.classes) { if (!t.id || !t.name) continue; @@ -320,7 +346,7 @@ export async function syncJsonToRelationalTables() { } } - // 3. Sincronizar Alunos + // 5. Sincronizar Alunos (Mapeamento Completo de Campos) if (data.students && Array.isArray(data.students)) { for (const s of data.students) { if (!s.id || !s.name) continue; @@ -353,61 +379,41 @@ export async function syncJsonToRelationalTables() { } } - // 4. Sincronizar Frequências + // 6. Sincronizar Provas (Corrigindo vínculo com disciplinas) + if (data.exams && Array.isArray(data.exams)) { + for (const e of data.exams) { + if (!e.id || !e.title) continue; + await client.query( + `INSERT INTO provas (id, turma_id, disciplina_id, periodo_id, titulo, duracao_minutos, status) + VALUES ($1, $2, $3, $4, $5, $6, $7) + ON CONFLICT (id) DO UPDATE SET + turma_id = EXCLUDED.turma_id, disciplina_id = EXCLUDED.disciplina_id, periodo_id = EXCLUDED.periodo_id, + titulo = EXCLUDED.titulo, duracao_minutos = EXCLUDED.duracao_minutos, status = EXCLUDED.status`, + [e.id, e.classId || null, e.subjectId || null, e.periodId || null, e.title, e.durationMinutes || 60, e.status || 'draft'] + ).catch(err => console.warn(`[Sync:Provas] Erro na prova ${e.id}:`, err.message)); + } + } + + // 7. Sincronizar Frequências (Baseado na estrutura real do JSON) if (data.attendance && Array.isArray(data.attendance)) { for (const f of data.attendance) { if (!f.id || !f.studentId || !f.classId) continue; await client.query( - `INSERT INTO frequencias (id, aluno_id, turma_id, data, foto, verificado, tipo, justificativa, justificativa_aceita) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) + `INSERT INTO frequencias (id, aluno_id, turma_id, data, foto, verificado, tipo) + VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT (id) DO UPDATE SET aluno_id = EXCLUDED.aluno_id, turma_id = EXCLUDED.turma_id, data = EXCLUDED.data, - foto = EXCLUDED.foto, verificado = EXCLUDED.verificado, tipo = EXCLUDED.tipo, - justificativa = EXCLUDED.justificativa, justificativa_aceita = EXCLUDED.justificativa_aceita`, - [f.id, f.studentId, f.classId, f.date, f.photo || '', f.verified || false, f.type || 'presence', f.justification || '', f.justificationAccepted || false] + foto = EXCLUDED.foto, verificado = EXCLUDED.verificado, tipo = EXCLUDED.tipo`, + [f.id, f.studentId, f.classId, f.date, f.photo || '', f.verified || false, f.type || 'presence'] ); } } - // 5. Sincronizar Disciplinas (Subjects) - if (data.subjects && Array.isArray(data.subjects)) { - for (const sub of data.subjects) { - if (!sub.id || !sub.name) continue; - await client.query(`INSERT INTO cursos (id, nome) VALUES ($1, $2) ON CONFLICT (id) DO NOTHING`, [sub.id, sub.name]); - } - } - - // 6. Sincronizar Períodos (Bimestres) - if (data.periods && Array.isArray(data.periods)) { - for (const p of data.periods) { - if (!p.id || !p.name) continue; - // Se houver tabela de períodos, inserimos. Se não, garantimos ao menos o ID. - await client.query(`INSERT INTO school_data (id) VALUES (1) ON CONFLICT (id) DO NOTHING`); - } - } - - // 7. Sincronizar Provas/Avaliações - if (data.exams && Array.isArray(data.exams)) { - for (const e of data.exams) { - if (!e.id || !e.title) continue; - try { - await client.query( - `INSERT INTO provas (id, titulo, disciplina_id) - VALUES ($1, $2, $3) - ON CONFLICT (id) DO UPDATE SET titulo = EXCLUDED.titulo, disciplina_id = EXCLUDED.disciplina_id`, - [e.id, e.title, e.subjectId || null] - ); - } catch(err) { - // Fallback se a tabela provas não estiver pronta - } - } - } - await client.query('COMMIT'); - console.log('[Sincronização] 🚀 Sincronização COMPLETA (Alunos, Turmas, Provas, Frequência) concluída!'); + console.log('[Sincronização] 🚀 Espelhamento TOTAL concluído com sucesso!'); } catch (err) { await client.query('ROLLBACK'); - console.error('[Sincronização] ❌ Erro crítico ao sincronizar:', err.message); + console.error('[Sincronização] ❌ Erro Crítico:', err.message); } finally { client.release(); }