const { pool } = require('../database') const dayjs = require('dayjs') async function updateCurrentYears() { const fullDate = dayjs().format('YYYY-MM-DD') // Clear current year flag const clearCurrent = 'UPDATE anneescolaire SET is_Current = 0 WHERE id > 0' pool.query(clearCurrent) // Set the new current year const updateCurrent = ` UPDATE anneescolaire SET is_Current = 1 WHERE ? >= debut AND ? <= fin ` // console.log(); pool.query(updateCurrent, [fullDate, fullDate]) // Check if the update was successful const sql = ` SELECT * FROM anneescolaire WHERE ? >= debut AND ? <= fin ` const [rows] = await pool.query(sql, [fullDate, fullDate]) const check = rows[0] if (!check) return // 2. Check if already in traitmentsystem const searchSql = `SELECT * FROM traitmentsystem WHERE code = ?` const [searchRows] = await pool.query(searchSql, [check.code]) if (searchRows.length === 0) { // 3. Insert into traitmentsystem const insertSql = ` INSERT INTO traitmentsystem (code, debut, fin) VALUES (?, ?, ?) ` await pool.query(insertSql, [check.code, check.debut, check.fin]) } else { console.log('No active school year found for the current date.') } } // Helper functions (unchanged) function checkNull(params) { if (params === null || params === undefined) return null return params } function compareSessionNotes(session1, session2) { if (session2) { return session1 < session2.note ? session2.note : session1 } return session1 } function nextLevel(niveau) { const levels = ['L1', 'L2', 'L3', 'M1', 'M2', 'D1', 'D2', 'D3', 'PHD'] const idx = levels.indexOf(niveau) return idx === -1 || idx === levels.length - 1 ? niveau : levels[idx + 1] } function updateSchoolYear(year) { const [startYear, endYear] = year.split('-').map(Number) return `${startYear + 1}-${endYear + 1}` } async function updateStudents() { const connection = await pool.getConnection() try { await connection.beginTransaction() const today = dayjs().format('YYYY-MM-DD') // 1. Récupérer toutes les années scolaires triées par debut const [allYears] = await connection.query( 'SELECT * FROM anneescolaire ORDER BY debut ASC' ) if (allYears.length < 2) { await connection.rollback() connection.release() return { message: 'Pas assez d\'années scolaires configurées.' } } // 2. Seuils de notes const [noteSystemRows] = await connection.query('SELECT * FROM notesystems LIMIT 1') const noteSystem = noteSystemRows[0] let totalProcessed = 0 // 3. Pour chaque paire d'années consécutives (annéeN → annéeN+1) for (let i = 0; i < allYears.length - 1; i++) { const prevYear = allYears[i] const nextYear = allYears[i + 1] // Traiter uniquement si l'année suivante a déjà commencé if (nextYear.debut > today) continue // Trouver les étudiants inscrits en annéeN mais PAS encore en annéeN+1 const [studentsToProcess] = await connection.query( `SELECT i.*, e.nom, e.prenom, e.photos FROM inscriptions i JOIN etudiants e ON i.etudiant_id = e.id WHERE i.annee_scolaire_id = ? AND i.etudiant_id NOT IN ( SELECT etudiant_id FROM inscriptions WHERE annee_scolaire_id = ? )`, [prevYear.id, nextYear.id] ) if (studentsToProcess.length === 0) continue for (const inscription of studentsToProcess) { const inscStatus = parseInt(inscription.status) // Renvoyé → pas de nouvelle inscription if (inscStatus === 4) continue let newNiveau, newStatus // Vérifier si l'étudiant a des notes pour l'année précédente const [notesRows] = await connection.query( `SELECT n.note, n.matiere_id, m.credit FROM notes n JOIN matieres m ON n.matiere_id = m.id WHERE n.etudiant_id = ? AND n.annee_scolaire = ?`, [inscription.etudiant_id, prevYear.code] ) if (notesRows.length > 0) { // Calculer la moyenne avec prise en compte du rattrapage const [repechRows] = await connection.query( `SELECT n.note, n.matiere_id, m.credit FROM notesrepech n JOIN matieres m ON n.matiere_id = m.id WHERE n.etudiant_id = ? AND n.annee_scolaire = ?`, [inscription.etudiant_id, prevYear.code] ) let total = 0 let totalCredit = 0 for (const note of notesRows) { const repNote = repechRows.find(r => r.matiere_id === note.matiere_id) const noteToUse = compareSessionNotes(note.note, checkNull(repNote)) total += (noteToUse ?? 0) * note.credit totalCredit += note.credit } const moyenne = totalCredit > 0 ? total / totalCredit : 0 if (moyenne >= noteSystem.admis) { newNiveau = nextLevel(inscription.niveau) newStatus = 2 // Passant } else if (moyenne >= noteSystem.renvoyer) { newNiveau = inscription.niveau newStatus = 3 // Redoublant } else { newNiveau = inscription.niveau newStatus = 4 // Renvoyé continue // Pas de nouvelle inscription pour les renvoyés } } else { // Pas de notes → utiliser le statut de l'inscription if (inscStatus === 2) { // Passant → niveau supérieur newNiveau = nextLevel(inscription.niveau) newStatus = 2 } else { // Redoublant, Nouveau, Ancien → même niveau newNiveau = inscription.niveau newStatus = 3 } } // Créer l'inscription pour l'année suivante await connection.query( `INSERT INTO inscriptions (etudiant_id, annee_scolaire_id, niveau, mention_id, parcours, status, num_inscription) VALUES (?, ?, ?, ?, ?, ?, ?)`, [ inscription.etudiant_id, nextYear.id, newNiveau, inscription.mention_id, inscription.parcours, newStatus, inscription.num_inscription ] ) // Pour les redoublants, copier les notes de l'année précédente (seulement si pas encore copiées) if (newStatus === 3) { const [existingNotes] = await connection.query( `SELECT COUNT(*) as cnt FROM notes WHERE etudiant_id = ? AND annee_scolaire = ?`, [inscription.etudiant_id, nextYear.code] ) if (existingNotes[0].cnt === 0) { await connection.query( `INSERT INTO notes (etudiant_id, matiere_id, etudiant_niveau, mention_id, note, annee_scolaire) SELECT etudiant_id, matiere_id, etudiant_niveau, mention_id, note, ? FROM notes WHERE etudiant_id = ? AND annee_scolaire = ?`, [nextYear.code, inscription.etudiant_id, prevYear.code] ) await connection.query( `INSERT INTO notesrepech (etudiant_id, matiere_id, etudiant_niveau, mention_id, note, annee_scolaire) SELECT etudiant_id, matiere_id, etudiant_niveau, mention_id, note, ? FROM notesrepech WHERE etudiant_id = ? AND annee_scolaire = ?`, [nextYear.code, inscription.etudiant_id, prevYear.code] ) } } totalProcessed++ } } // 4. Mettre à jour traitmentsystem (nettoyage) await connection.query( 'UPDATE traitmentsystem SET is_finished = 1 WHERE is_finished = 0' ) await connection.commit() connection.release() console.log(`✅ updateStudents: ${totalProcessed} inscription(s) créée(s).`) return { success: true, message: `${totalProcessed} inscription(s) créée(s).`, totalProcessed } } catch (error) { await connection.rollback() connection.release() console.error('❌ updateStudents error:', error) throw error } } async function matiereSysteme(etudiant_niveau) { let systeme if (etudiant_niveau == 'L1') { systeme = ['S1', 'S2'] } else if (etudiant_niveau == 'L2') { systeme = ['S3', 'S4'] } else if (etudiant_niveau == 'L3') { systeme = ['S5', 'S6'] } else if (etudiant_niveau == 'M1') { systeme = ['S7', 'S8'] } else if (etudiant_niveau == 'M2') { systeme = ['S9', 'S10'] } else if (etudiant_niveau == 'D1') { systeme = ['S11', 'S12'] } else if (etudiant_niveau == 'D2') { systeme = ['S13', 'S14'] } else if (etudiant_niveau == 'D3') { systeme = ['S15', 'S16'] } return systeme } async function matiereSystemReverse(semestre) { if (semestre == 'S1' || semestre == 'S2') { return 'L1' } else if (semestre == 'S3' || semestre == 'S4') { return 'L2' } else if (semestre == 'S5' || semestre == 'S6') { return 'L3' } else if (semestre == 'S7' || semestre == 'S8') { return 'M1' } else if (semestre == 'S9' || semestre == 'S10') { return 'M2' } else if (semestre == 'S11' || semestre == 'S12') { return 'D1' } else if (semestre == 'S13' || semestre == 'S14') { return 'D2' } else if (semestre == 'S15' || semestre == 'S16') { return 'D3' } } async function getNessesarytable() { try { const sql = 'SELECT * FROM nessesaryTable' const [rows] = await pool.query(sql) return rows[0] } catch (error) { return error } } async function updateNessesaryTable(id, multiplicateur) { const sql = 'UPDATE nessesaryTable SET uniter_heure = ? WHERE id = ?' try { const [result] = await pool.query(sql, [multiplicateur, id]) if (result.affectedRows === 0) { return { success: false, message: 'Année universitaire non trouvé.' } } return { success: true, message: 'Année universitaire supprimé avec succès.' } } catch (error) { return error } } module.exports = { matiereSysteme, updateCurrentYears, updateStudents, getNessesarytable, updateNessesaryTable, matiereSystemReverse }