115 lines
3.7 KiB
JavaScript
115 lines
3.7 KiB
JavaScript
import { pool } from '../db.js';
|
||
|
||
const TOTAL_TICKETS = 500000;
|
||
const BATCH_SIZE = 1000;
|
||
|
||
const PRIZE_DISTRIBUTION = {
|
||
'INFUSEUR': { percentage: 0.60, name: 'Infuseur à thé' },
|
||
'THE_GRATUIT': { percentage: 0.20, name: 'Thé détox/infusion 100g' },
|
||
'THE_SIGNATURE': { percentage: 0.10, name: 'Thé signature 100g' },
|
||
'COFFRET_DECOUVERTE': { percentage: 0.06, name: 'Coffret découverte 39€' },
|
||
'COFFRET_PRESTIGE': { percentage: 0.04, name: 'Coffret prestige 69€' }
|
||
};
|
||
|
||
const generateCode = () => {
|
||
// Format: TT + 8 caractères alphanumériques mélangés (ex: TT11BA22KO)
|
||
// Mélange de chiffres et lettres de manière aléatoire
|
||
|
||
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||
const digits = '0123456789';
|
||
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||
|
||
let code = 'TT';
|
||
|
||
// Générer 8 caractères alphanumériques mélangés
|
||
for (let i = 0; i < 8; i++) {
|
||
const randomChar = chars[Math.floor(Math.random() * chars.length)];
|
||
code += randomChar;
|
||
}
|
||
|
||
return code;
|
||
};
|
||
|
||
const generateTickets = async () => {
|
||
try {
|
||
console.log('🎫 Génération de 500,000 tickets Thé Tip Top\n');
|
||
|
||
const prizesResult = await pool.query('SELECT id, name, type FROM prizes');
|
||
const prizes = {};
|
||
prizesResult.rows.forEach(p => prizes[p.type] = p);
|
||
|
||
const distribution = {};
|
||
let total = 0;
|
||
|
||
console.log('📊 DISTRIBUTION:');
|
||
for (const [type, config] of Object.entries(PRIZE_DISTRIBUTION)) {
|
||
const count = Math.floor(TOTAL_TICKETS * config.percentage);
|
||
distribution[type] = count;
|
||
total += count;
|
||
const percent = (config.percentage * 100).toFixed(0);
|
||
const countStr = count.toLocaleString('fr-FR');
|
||
console.log(` • ${percent}% - ${countStr} tickets - ${config.name}`);
|
||
}
|
||
|
||
if (total < TOTAL_TICKETS) {
|
||
const diff = TOTAL_TICKETS - total;
|
||
distribution.infuseur += diff;
|
||
console.log(`\n⚙️ Ajustement: +${diff} tickets ajoutés aux infuseurs`);
|
||
}
|
||
|
||
const existing = await pool.query('SELECT COUNT(*) FROM tickets');
|
||
if (parseInt(existing.rows[0].count) > 0) {
|
||
console.log('\n⚠️ Suppression des anciens tickets...');
|
||
await pool.query('DELETE FROM tickets');
|
||
console.log('✅ Anciens tickets supprimés');
|
||
}
|
||
|
||
console.log('\n🚀 Génération en cours...\n');
|
||
|
||
let generated = 0;
|
||
const start = Date.now();
|
||
|
||
for (const [type, count] of Object.entries(distribution)) {
|
||
const prize = prizes[type];
|
||
if (!prize) {
|
||
console.log(`⚠️ Lot "${type}" introuvable, ignoré`);
|
||
continue;
|
||
}
|
||
|
||
const prizeCountStr = count.toLocaleString('fr-FR');
|
||
console.log(`📦 ${prize.name}: ${prizeCountStr} tickets`);
|
||
|
||
for (let i = 0; i < count; i += BATCH_SIZE) {
|
||
const batch = Math.min(BATCH_SIZE, count - i);
|
||
const values = [];
|
||
|
||
for (let j = 0; j < batch; j++) {
|
||
const code = generateCode();
|
||
values.push(`('${code}', '${prize.id}', NULL)`);
|
||
}
|
||
|
||
const query = `INSERT INTO tickets (code, prize_id, status) VALUES ${values.join(', ')}`;
|
||
await pool.query(query);
|
||
generated += batch;
|
||
|
||
const genStr = generated.toLocaleString('fr-FR');
|
||
const totalStr = TOTAL_TICKETS.toLocaleString('fr-FR');
|
||
process.stdout.write(`\r Progression: ${genStr} / ${totalStr}`);
|
||
}
|
||
console.log('');
|
||
}
|
||
|
||
const duration = ((Date.now() - start) / 1000).toFixed(2);
|
||
const genStr = generated.toLocaleString('fr-FR');
|
||
console.log(`\n✅ Terminé! ${genStr} tickets générés en ${duration}s\n`);
|
||
|
||
process.exit(0);
|
||
} catch (error) {
|
||
console.error('❌ Erreur:', error.message);
|
||
console.error(error.stack);
|
||
process.exit(1);
|
||
}
|
||
};
|
||
|
||
generateTickets();
|