248 lines
8.3 KiB
JavaScript
248 lines
8.3 KiB
JavaScript
/**
|
||
* Script de seed pour insérer des données de test
|
||
* Usage: node database/seed.js
|
||
*/
|
||
import bcrypt from 'bcrypt';
|
||
import { pool } from '../db.js';
|
||
import { randomUUID } from 'crypto';
|
||
|
||
const SALT_ROUNDS = 10;
|
||
|
||
async function seedDatabase() {
|
||
try {
|
||
console.log('🌱 Démarrage du seed de la base de données...\n');
|
||
|
||
// ============================================
|
||
// 1. SEED USERS
|
||
// ============================================
|
||
console.log('👥 Création des utilisateurs...');
|
||
|
||
// Hash des mots de passe
|
||
const adminPassword = await bcrypt.hash('Admin123!', SALT_ROUNDS);
|
||
const employeePassword = await bcrypt.hash('Employee123!', SALT_ROUNDS);
|
||
const clientPassword = await bcrypt.hash('Client123!', SALT_ROUNDS);
|
||
|
||
// Admin
|
||
const adminResult = await pool.query(
|
||
`INSERT INTO users (email, password, first_name, last_name, phone, role, is_verified)
|
||
VALUES ($1, $2, $3, $4, $5, 'ADMIN', TRUE)
|
||
ON CONFLICT (email) DO UPDATE SET role = 'ADMIN'
|
||
RETURNING id, email, role`,
|
||
['admin@thetiptop.com', adminPassword, 'Admin', 'Principal', '+33123456789']
|
||
);
|
||
console.log('✅ Admin créé:', adminResult.rows[0].email);
|
||
|
||
// Employé 1
|
||
const employee1Result = await pool.query(
|
||
`INSERT INTO users (email, password, first_name, last_name, phone, role, is_verified)
|
||
VALUES ($1, $2, $3, $4, $5, 'EMPLOYEE', TRUE)
|
||
ON CONFLICT (email) DO UPDATE SET role = 'EMPLOYEE'
|
||
RETURNING id, email, role`,
|
||
['employee1@thetiptop.com', employeePassword, 'Marie', 'Dupont', '+33198765432']
|
||
);
|
||
console.log('✅ Employé 1 créé:', employee1Result.rows[0].email);
|
||
|
||
// Employé 2
|
||
const employee2Result = await pool.query(
|
||
`INSERT INTO users (email, password, first_name, last_name, phone, role, is_verified)
|
||
VALUES ($1, $2, $3, $4, $5, 'EMPLOYEE', TRUE)
|
||
ON CONFLICT (email) DO UPDATE SET role = 'EMPLOYEE'
|
||
RETURNING id, email, role`,
|
||
['employee2@thetiptop.com', employeePassword, 'Pierre', 'Martin', '+33187654321']
|
||
);
|
||
console.log('✅ Employé 2 créé:', employee2Result.rows[0].email);
|
||
|
||
// Clients
|
||
const clients = [
|
||
{
|
||
email: 'client1@example.com',
|
||
firstName: 'Jean',
|
||
lastName: 'Dupuis',
|
||
phone: '+33612345678',
|
||
},
|
||
{
|
||
email: 'client2@example.com',
|
||
firstName: 'Sophie',
|
||
lastName: 'Bernard',
|
||
phone: '+33623456789',
|
||
},
|
||
{
|
||
email: 'client3@example.com',
|
||
firstName: 'Luc',
|
||
lastName: 'Lefevre',
|
||
phone: '+33634567890',
|
||
},
|
||
{
|
||
email: 'client4@example.com',
|
||
firstName: 'Emma',
|
||
lastName: 'Petit',
|
||
phone: '+33645678901',
|
||
},
|
||
{
|
||
email: 'client5@example.com',
|
||
firstName: 'Thomas',
|
||
lastName: 'Robert',
|
||
phone: '+33656789012',
|
||
},
|
||
];
|
||
|
||
const clientIds = [];
|
||
for (const client of clients) {
|
||
const result = await pool.query(
|
||
`INSERT INTO users (email, password, first_name, last_name, phone, role, is_verified)
|
||
VALUES ($1, $2, $3, $4, $5, 'CLIENT', TRUE)
|
||
ON CONFLICT (email) DO UPDATE SET role = 'CLIENT'
|
||
RETURNING id`,
|
||
[
|
||
client.email,
|
||
clientPassword,
|
||
client.firstName,
|
||
client.lastName,
|
||
client.phone,
|
||
]
|
||
);
|
||
clientIds.push(result.rows[0].id);
|
||
console.log(`✅ Client créé: ${client.email}`);
|
||
}
|
||
|
||
console.log(`\n✅ ${clients.length + 3} utilisateurs créés avec succès\n`);
|
||
|
||
// ============================================
|
||
// 2. SEED TICKETS
|
||
// ============================================
|
||
console.log('🎟️ Création des tickets de test...');
|
||
|
||
// Récupérer les IDs des prix
|
||
const prizesResult = await pool.query(
|
||
'SELECT id, type FROM prizes ORDER BY type'
|
||
);
|
||
const prizes = prizesResult.rows;
|
||
|
||
if (prizes.length === 0) {
|
||
console.log('⚠️ Aucun prix trouvé. Exécutez d\'abord le schema.sql');
|
||
return;
|
||
}
|
||
|
||
// Créer des tickets avec différents statuts pour chaque client
|
||
const ticketStatuses = ['PENDING', 'CLAIMED', 'REJECTED'];
|
||
let ticketCount = 0;
|
||
|
||
for (let i = 0; i < clientIds.length; i++) {
|
||
const clientId = clientIds[i];
|
||
|
||
// Chaque client obtient 3-5 tickets
|
||
const numTickets = Math.floor(Math.random() * 3) + 3;
|
||
|
||
for (let j = 0; j < numTickets; j++) {
|
||
// Sélectionner un prix aléatoire
|
||
const randomPrize = prizes[Math.floor(Math.random() * prizes.length)];
|
||
|
||
// Sélectionner un statut (80% PENDING, 10% CLAIMED, 10% REJECTED)
|
||
const rand = Math.random();
|
||
let status;
|
||
if (rand < 0.8) {
|
||
status = 'PENDING';
|
||
} else if (rand < 0.9) {
|
||
status = 'CLAIMED';
|
||
} else {
|
||
status = 'REJECTED';
|
||
}
|
||
|
||
// Générer un code unique
|
||
const ticketCode = `TT-${Date.now()}-${randomUUID().substring(0, 8).toUpperCase()}`;
|
||
|
||
// Créer le ticket
|
||
const insertQuery = `
|
||
INSERT INTO tickets (code, user_id, prize_id, status, played_at, claimed_at, validated_by, validated_at, rejection_reason)
|
||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||
`;
|
||
|
||
const playedAt = new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000); // Dans les 30 derniers jours
|
||
|
||
let claimedAt = null;
|
||
let validatedBy = null;
|
||
let validatedAt = null;
|
||
let rejectionReason = null;
|
||
|
||
if (status === 'CLAIMED') {
|
||
claimedAt = new Date(playedAt.getTime() + Math.random() * 7 * 24 * 60 * 60 * 1000); // 0-7 jours après
|
||
validatedBy = employee1Result.rows[0].id;
|
||
validatedAt = claimedAt;
|
||
} else if (status === 'REJECTED') {
|
||
claimedAt = new Date(playedAt.getTime() + Math.random() * 7 * 24 * 60 * 60 * 1000);
|
||
validatedBy = employee1Result.rows[0].id;
|
||
validatedAt = claimedAt;
|
||
rejectionReason = 'Ticket non conforme ou expiré';
|
||
}
|
||
|
||
await pool.query(insertQuery, [
|
||
ticketCode,
|
||
clientId,
|
||
randomPrize.id,
|
||
status,
|
||
playedAt,
|
||
claimedAt,
|
||
validatedBy,
|
||
validatedAt,
|
||
rejectionReason,
|
||
]);
|
||
|
||
ticketCount++;
|
||
}
|
||
}
|
||
|
||
console.log(`✅ ${ticketCount} tickets créés avec succès\n`);
|
||
|
||
// ============================================
|
||
// 3. AFFICHER LES STATISTIQUES
|
||
// ============================================
|
||
console.log('📊 Statistiques de la base de données:\n');
|
||
|
||
const usersStats = await pool.query(`
|
||
SELECT
|
||
COUNT(*) as total,
|
||
COUNT(CASE WHEN role = 'ADMIN' THEN 1 END) as admins,
|
||
COUNT(CASE WHEN role = 'EMPLOYEE' THEN 1 END) as employees,
|
||
COUNT(CASE WHEN role = 'CLIENT' THEN 1 END) as clients
|
||
FROM users
|
||
`);
|
||
|
||
const ticketsStats = await pool.query(`
|
||
SELECT
|
||
COUNT(*) as total,
|
||
COUNT(CASE WHEN status = 'PENDING' THEN 1 END) as pending,
|
||
COUNT(CASE WHEN status = 'CLAIMED' THEN 1 END) as claimed,
|
||
COUNT(CASE WHEN status = 'REJECTED' THEN 1 END) as rejected
|
||
FROM tickets
|
||
`);
|
||
|
||
console.log('👥 Utilisateurs:');
|
||
console.log(` Total: ${usersStats.rows[0].total}`);
|
||
console.log(` Admins: ${usersStats.rows[0].admins}`);
|
||
console.log(` Employés: ${usersStats.rows[0].employees}`);
|
||
console.log(` Clients: ${usersStats.rows[0].clients}`);
|
||
|
||
console.log('\n🎟️ Tickets:');
|
||
console.log(` Total: ${ticketsStats.rows[0].total}`);
|
||
console.log(` En attente: ${ticketsStats.rows[0].pending}`);
|
||
console.log(` Réclamés: ${ticketsStats.rows[0].claimed}`);
|
||
console.log(` Rejetés: ${ticketsStats.rows[0].rejected}`);
|
||
|
||
console.log('\n✅ Seed terminé avec succès!');
|
||
console.log('\n🔐 Comptes de test créés:');
|
||
console.log(' Admin: admin@thetiptop.com / Admin123!');
|
||
console.log(' Employé 1: employee1@thetiptop.com / Employee123!');
|
||
console.log(' Employé 2: employee2@thetiptop.com / Employee123!');
|
||
console.log(' Clients: client1@example.com à client5@example.com / Client123!');
|
||
} catch (error) {
|
||
console.error('❌ Erreur lors du seed:', error);
|
||
throw error;
|
||
} finally {
|
||
// Fermer la connexion
|
||
await pool.end();
|
||
}
|
||
}
|
||
|
||
// Exécuter le seed
|
||
seedDatabase();
|