import 'dotenv/config'; import { PrismaClient } from '@prisma/client'; import { PrismaMssql } from '@prisma/adapter-mssql'; // Fixtures de DEV/TEST. À lancer après `npm run seed` (dépend des données de référence). // Non destructif : si déjà chargées (email témoin présent), le script s'arrête. function getEnv(name: string): string { const value = process.env[name]; if (!value) { throw new Error(`Variable d'environnement manquante: ${name}`); } return value; } function required(value: T | null, message: string): T { if (value === null) { throw new Error(message); } return value; } const adapter = new PrismaMssql({ server: getEnv('DB_SERVER'), port: Number(process.env.DB_PORT ?? 1433), database: getEnv('DB_NAME'), user: getEnv('DB_USER'), password: getEnv('DB_PASSWORD'), options: { encrypt: true, trustServerCertificate: true, }, }); const prisma = new PrismaClient({ adapter }); const WITNESS_EMAIL = 'marie.dupont@ensitech.eu'; const now = new Date(); function daysAgo(n: number): Date { const d = new Date(now); d.setDate(d.getDate() - n); return d; } function daysFromNow(n: number): Date { const d = new Date(now); d.setDate(d.getDate() + n); return d; } async function main(): Promise { // Idempotence : on ne recharge pas si déjà présent. const witness = await prisma.utilisateur.findUnique({ where: { email: WITNESS_EMAIL } }); if (witness) { console.log('[fixtures] deja chargees — rien a faire'); return; } // Références (doivent exister via le seed). const roleEtudiant = required( await prisma.role.findUnique({ where: { code: 'ETUDIANT' } }), 'Role ETUDIANT manquant — lance d\'abord `npm run seed`', ); const roleResponsable = required( await prisma.role.findUnique({ where: { code: 'RESPONSABLE' } }), 'Role RESPONSABLE manquant — lance d\'abord `npm run seed`', ); const campus = required( await prisma.campus.findFirst({ where: { nom: 'Campus Saint-Christophe' } }), 'Campus manquant — lance d\'abord `npm run seed`', ); const salle = required( await prisma.sallePret.findFirst({ where: { campusId: campus.id } }), 'Salle de pret manquante — lance d\'abord `npm run seed`', ); const poste = required( await prisma.posteEmprunt.findFirst({ where: { sallePretId: salle.id } }), 'Poste manquant — lance d\'abord `npm run seed`', ); const catOrdi = required( await prisma.categorieMateriel.findFirst({ where: { nom: 'Ordinateur portable' } }), 'Categorie Ordinateur portable manquante', ); const catVideo = required( await prisma.categorieMateriel.findFirst({ where: { nom: 'Vidéoprojecteur' } }), 'Categorie Vidéoprojecteur manquante', ); const catTablette = required( await prisma.categorieMateriel.findFirst({ where: { nom: 'Tablette' } }), 'Categorie Tablette manquante', ); const catCamera = required( await prisma.categorieMateriel.findFirst({ where: { nom: 'Caméra' } }), 'Categorie Caméra manquante', ); const catAudio = required( await prisma.categorieMateriel.findFirst({ where: { nom: 'Périphérique audio' } }), 'Categorie Périphérique audio manquante', ); // Utilisateurs : 3 étudiants (2 info @ensitech.eu, 1 autre @ensup.eu) + 1 responsable. const marie = await prisma.utilisateur.create({ data: { microsoftId: 'ms-marie-dupont', nom: 'Dupont', prenom: 'Marie', email: WITNESS_EMAIL, classe: 'B3 Informatique', roleId: roleEtudiant.id, campusId: campus.id, }, }); const lucas = await prisma.utilisateur.create({ data: { microsoftId: 'ms-lucas-martin', nom: 'Martin', prenom: 'Lucas', email: 'lucas.martin@ensitech.eu', classe: 'B2 Informatique', roleId: roleEtudiant.id, campusId: campus.id, }, }); const sofia = await prisma.utilisateur.create({ data: { microsoftId: 'ms-sofia-bernard', nom: 'Bernard', prenom: 'Sofia', email: 'sofia.bernard@ensup.eu', classe: 'B1 Marketing', roleId: roleEtudiant.id, campusId: campus.id, }, }); const responsable = await prisma.utilisateur.create({ data: { microsoftId: 'ms-karim-benali', nom: 'Benali', prenom: 'Karim', email: 'karim.benali@ensup.eu', classe: null, // un responsable n'a pas de classe roleId: roleResponsable.id, campusId: campus.id, }, }); console.log('[fixtures] 4 utilisateurs crees (3 etudiants + 1 responsable)'); // Cartes étudiantes (qrCode unique par carte). await prisma.carteEtudiante.createMany({ data: [ { utilisateurId: marie.id, qrCode: 'QR-ETU-0001', dateActivation: daysAgo(300), dateExpiration: daysFromNow(400), }, { utilisateurId: lucas.id, qrCode: 'QR-ETU-0002', dateActivation: daysAgo(300), dateExpiration: daysFromNow(400), }, { utilisateurId: sofia.id, qrCode: 'QR-ETU-0003', dateActivation: daysAgo(300), dateExpiration: daysFromNow(400), }, ], }); console.log('[fixtures] 3 cartes etudiantes creees'); // Accessoires. const chargeur = await prisma.accessoire.create({ data: { nom: 'Chargeur', description: 'Chargeur secteur.' }, }); const souris = await prisma.accessoire.create({ data: { nom: 'Souris', description: 'Souris filaire.' }, }); const housse = await prisma.accessoire.create({ data: { nom: 'Housse', description: 'Housse de protection.' }, }); // Matériels (statut explicite — pas de défaut sur ce champ). const pcDell = await prisma.materiel.create({ data: { nom: 'PC portable Dell Latitude', marque: 'Dell', modele: 'Latitude 5440', reference: 'REF-PC-001', numeroInventaire: 'INV-PC-001', numeroSerie: 'SN-DELL-001', statut: 'EMPRUNTE', etatGeneral: 'Bon etat', categorieId: catOrdi.id, campusId: campus.id, }, }); const projecteur = await prisma.materiel.create({ data: { nom: 'Vidéoprojecteur Epson', marque: 'Epson', modele: 'EB-W06', reference: 'REF-VP-001', numeroInventaire: 'INV-VP-001', numeroSerie: 'SN-EPSON-001', statut: 'EMPRUNTE', etatGeneral: 'Bon etat', categorieId: catVideo.id, campusId: campus.id, }, }); const ipad = await prisma.materiel.create({ data: { nom: 'Tablette iPad', marque: 'Apple', modele: 'iPad 10', reference: 'REF-TAB-001', numeroInventaire: 'INV-TAB-001', numeroSerie: 'SN-IPAD-001', statut: 'DISPONIBLE', etatGeneral: 'Bon etat', categorieId: catTablette.id, campusId: campus.id, }, }); const camera = await prisma.materiel.create({ data: { nom: 'Caméra Sony', marque: 'Sony', modele: 'Alpha 6400', reference: 'REF-CAM-001', numeroInventaire: 'INV-CAM-001', numeroSerie: 'SN-SONY-001', statut: 'DETERIORE', etatGeneral: 'Housse manquante au retour', categorieId: catCamera.id, campusId: campus.id, }, }); await prisma.materiel.create({ data: { nom: 'Micro Rode', marque: 'Rode', modele: 'NT-USB', reference: 'REF-MIC-001', numeroInventaire: 'INV-MIC-001', numeroSerie: 'SN-RODE-001', statut: 'DISPONIBLE', etatGeneral: 'Bon etat', categorieId: catAudio.id, campusId: campus.id, }, }); await prisma.materiel.create({ data: { nom: 'PC portable HP', marque: 'HP', modele: 'ProBook 450', reference: 'REF-PC-002', numeroInventaire: 'INV-PC-002', numeroSerie: 'SN-HP-002', statut: 'MAINTENANCE', etatGeneral: 'En revision', categorieId: catOrdi.id, campusId: campus.id, }, }); console.log('[fixtures] 6 materiels crees'); // Accessoires attendus (obligatoire explicite — pas de défaut). await prisma.materielAccessoire.createMany({ data: [ { materielId: pcDell.id, accessoireId: chargeur.id, quantiteAttendue: 1, obligatoire: true }, { materielId: pcDell.id, accessoireId: souris.id, quantiteAttendue: 1, obligatoire: false }, { materielId: camera.id, accessoireId: housse.id, quantiteAttendue: 1, obligatoire: true }, { materielId: camera.id, accessoireId: chargeur.id, quantiteAttendue: 1, obligatoire: true }, ], }); // Emprunt 1 — EN_COURS (Marie / PC Dell) + checklist de départ. const empruntEnCours = await prisma.emprunt.create({ data: { utilisateurId: marie.id, materielId: pcDell.id, campusId: campus.id, sallePretId: salle.id, posteEmpruntId: poste.id, dateEmprunt: daysAgo(2), dateRetourPrevue: daysFromNow(5), statut: 'EN_COURS', modeIdentificationEmprunt: 'QR_CODE', }, }); const clDepart1 = await prisma.checklist.create({ data: { empruntId: empruntEnCours.id, utilisateurId: marie.id, type: 'DEPART', dateVerification: daysAgo(2), }, }); await prisma.checklistElement.createMany({ data: [ { checklistId: clDepart1.id, accessoireId: chargeur.id, nomElement: 'Chargeur', etat: 'PRESENT', quantiteConstatee: 1 }, { checklistId: clDepart1.id, accessoireId: souris.id, nomElement: 'Souris', etat: 'PRESENT', quantiteConstatee: 1 }, ], }); // Emprunt 2 — EN_RETARD (Lucas / Vidéoprojecteur), date de retour dépassée. const empruntEnRetard = await prisma.emprunt.create({ data: { utilisateurId: lucas.id, materielId: projecteur.id, campusId: campus.id, sallePretId: salle.id, posteEmpruntId: poste.id, dateEmprunt: daysAgo(20), dateRetourPrevue: daysAgo(6), statut: 'EN_RETARD', modeIdentificationEmprunt: 'MAIL_ENSUP', }, }); await prisma.checklist.create({ data: { empruntId: empruntEnRetard.id, utilisateurId: lucas.id, type: 'DEPART', dateVerification: daysAgo(20), }, }); // Emprunt 3 — CLOTURE (Marie / iPad), retour conforme. const empruntCloture = await prisma.emprunt.create({ data: { utilisateurId: marie.id, materielId: ipad.id, campusId: campus.id, sallePretId: salle.id, posteEmpruntId: poste.id, dateEmprunt: daysAgo(10), dateRetourPrevue: daysAgo(3), dateRetourReelle: daysAgo(3), statut: 'CLOTURE', modeIdentificationEmprunt: 'QR_CODE', modeIdentificationRetour: 'QR_CODE', }, }); await prisma.checklist.create({ data: { empruntId: empruntCloture.id, utilisateurId: marie.id, type: 'DEPART', dateVerification: daysAgo(10), }, }); await prisma.checklist.create({ data: { empruntId: empruntCloture.id, utilisateurId: marie.id, type: 'RETOUR', dateVerification: daysAgo(3), }, }); // Emprunt 4 — RETOUR_NON_CONFORME (Sofia / Caméra) : housse absente au retour. const empruntNonConforme = await prisma.emprunt.create({ data: { utilisateurId: sofia.id, materielId: camera.id, campusId: campus.id, sallePretId: salle.id, posteEmpruntId: poste.id, dateEmprunt: daysAgo(5), dateRetourPrevue: daysAgo(1), dateRetourReelle: daysAgo(1), statut: 'RETOUR_NON_CONFORME', modeIdentificationEmprunt: 'MAIL_ENSUP', modeIdentificationRetour: 'MAIL_ENSUP', commentaireRetour: 'Housse non rapportee.', }, }); const clDepart4 = await prisma.checklist.create({ data: { empruntId: empruntNonConforme.id, utilisateurId: sofia.id, type: 'DEPART', dateVerification: daysAgo(5), }, }); await prisma.checklistElement.createMany({ data: [ { checklistId: clDepart4.id, accessoireId: housse.id, nomElement: 'Housse', etat: 'PRESENT', quantiteConstatee: 1 }, { checklistId: clDepart4.id, accessoireId: chargeur.id, nomElement: 'Chargeur', etat: 'PRESENT', quantiteConstatee: 1 }, ], }); const clRetour4 = await prisma.checklist.create({ data: { empruntId: empruntNonConforme.id, utilisateurId: sofia.id, type: 'RETOUR', dateVerification: daysAgo(1), }, }); await prisma.checklistElement.createMany({ data: [ { checklistId: clRetour4.id, accessoireId: housse.id, nomElement: 'Housse', etat: 'ABSENT', quantiteConstatee: 0, commentaire: 'Manquante au retour' }, { checklistId: clRetour4.id, accessoireId: chargeur.id, nomElement: 'Chargeur', etat: 'PRESENT', quantiteConstatee: 1 }, ], }); console.log('[fixtures] 4 emprunts + checklists crees'); // Anomalie sur l'emprunt non conforme + notification au responsable. const anomalie = await prisma.anomalie.create({ data: { empruntId: empruntNonConforme.id, materielId: camera.id, utilisateurId: sofia.id, type: 'ACCESSOIRE_MANQUANT', description: 'Housse declaree presente au depart, absente au retour.', statut: 'DETECTEE', detecteeAutomatiquement: true, dateDetection: daysAgo(1), }, }); await prisma.notification.create({ data: { utilisateurId: responsable.id, anomalieId: anomalie.id, titre: 'Nouvelle anomalie detectee', message: 'Retour non conforme sur la Caméra Sony (housse manquante).', type: 'ANOMALIE', }, }); console.log('[fixtures] 1 anomalie + 1 notification creees'); // Historique : quelques traces. await prisma.historique.createMany({ data: [ { utilisateurId: marie.id, empruntId: empruntEnCours.id, materielId: pcDell.id, campusId: campus.id, sallePretId: salle.id, posteEmpruntId: poste.id, action: 'CREATION_EMPRUNT', description: 'Emprunt du PC portable Dell.', dateAction: daysAgo(2), }, { utilisateurId: sofia.id, empruntId: empruntNonConforme.id, materielId: camera.id, campusId: campus.id, sallePretId: salle.id, posteEmpruntId: poste.id, action: 'CREATION_ANOMALIE', description: 'Anomalie detectee au retour de la Caméra Sony.', dateAction: daysAgo(1), }, ], }); console.log('[fixtures] 2 entrees d\'historique creees'); } main() .then(async () => { await prisma.$disconnect(); console.log('[fixtures] termine'); }) .catch(async (error: unknown) => { console.error('[fixtures] echec', error); await prisma.$disconnect(); process.exit(1); });