149 lines
5.1 KiB
TypeScript
149 lines
5.1 KiB
TypeScript
import { PrismaClient } from '@prisma/client';
|
||
|
||
const prisma = new PrismaClient();
|
||
|
||
// ====== Config ======
|
||
const PREVIOUS_WEEKS = 5; // nombre de semaines à générer avant la semaine actuelle
|
||
const INCLUDE_CURRENT = false; // passe à true si tu veux aussi générer la semaine actuelle
|
||
|
||
// Stocker une heure (Postgres TIME) via Date (UTC 1970-01-01)
|
||
function timeAt(hour: number, minute: number) {
|
||
return new Date(Date.UTC(1970, 0, 1, hour, minute, 0));
|
||
}
|
||
|
||
// Lundi de la semaine (en UTC) pour la date courante
|
||
function mondayOfThisWeekUTC(now = new Date()) {
|
||
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
||
const day = d.getUTCDay(); // 0=Dim, 1=Lun, ...
|
||
const diffToMonday = (day + 6) % 7; // 0 si lundi
|
||
d.setUTCDate(d.getUTCDate() - diffToMonday);
|
||
d.setUTCHours(0, 0, 0, 0);
|
||
return d;
|
||
}
|
||
|
||
// Retourne les 5 dates Lundi→Vendredi (UTC, à minuit) à partir d’un lundi donné
|
||
function weekDatesFromMonday(monday: Date) {
|
||
return Array.from({ length: 5 }, (_, i) => {
|
||
const d = new Date(monday);
|
||
d.setUTCDate(monday.getUTCDate() + i);
|
||
return d;
|
||
});
|
||
}
|
||
|
||
// Lundi n semaines avant un lundi donné
|
||
function mondayNWeeksBefore(monday: Date, n: number) {
|
||
const d = new Date(monday);
|
||
d.setUTCDate(d.getUTCDate() - n * 7);
|
||
return d;
|
||
}
|
||
|
||
// Random int inclusif
|
||
function rndInt(min: number, max: number) {
|
||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||
}
|
||
|
||
async function main() {
|
||
// Bank codes utilisés
|
||
const BANKS = ['G1', 'G305', 'G105'] as const;
|
||
const bcRows = await prisma.bankCodes.findMany({
|
||
where: { bank_code: { in: BANKS as unknown as string[] } },
|
||
select: { id: true, bank_code: true },
|
||
});
|
||
const bcMap = new Map(bcRows.map(b => [b.bank_code, b.id]));
|
||
for (const c of BANKS) {
|
||
if (!bcMap.has(c)) throw new Error(`Bank code manquant: ${c}`);
|
||
}
|
||
|
||
// Employés + cache des timesheets par employé (évite un findMany dans les boucles)
|
||
const employees = await prisma.employees.findMany({ select: { id: true } });
|
||
if (!employees.length) {
|
||
console.log('Aucun employé — rien à insérer.');
|
||
return;
|
||
}
|
||
const tsByEmp = new Map<number, { id: number }[]>();
|
||
{
|
||
const allTs = await prisma.timesheets.findMany({
|
||
where: { employee_id: { in: employees.map(e => e.id) } },
|
||
select: { id: true, employee_id: true },
|
||
orderBy: { id: 'asc' },
|
||
});
|
||
for (const e of employees) {
|
||
tsByEmp.set(e.id, allTs.filter(t => t.employee_id === e.id).map(t => ({ id: t.id })));
|
||
}
|
||
}
|
||
|
||
// Construit la liste des semaines à insérer
|
||
const mondayThisWeek = mondayOfThisWeekUTC();
|
||
const mondays: Date[] = [];
|
||
|
||
if (INCLUDE_CURRENT) mondays.push(mondayThisWeek);
|
||
for (let n = 1; n <= PREVIOUS_WEEKS; n++) {
|
||
mondays.push(mondayNWeeksBefore(mondayThisWeek, n));
|
||
}
|
||
|
||
let created = 0;
|
||
|
||
// Pour chaque semaine à générer
|
||
for (let wi = 0; wi < mondays.length; wi++) {
|
||
const monday = mondays[wi];
|
||
const weekDays = weekDatesFromMonday(monday);
|
||
|
||
for (let ei = 0; ei < employees.length; ei++) {
|
||
const e = employees[ei];
|
||
const tss = tsByEmp.get(e.id) ?? [];
|
||
if (!tss.length) continue;
|
||
|
||
// Base horaire spécifique à l’employé (garantit la diversité)
|
||
// Heures: 6..10 (selon l'index employé)
|
||
const baseStartHour = 6 + (ei % 5); // 6,7,8,9,10
|
||
// Minutes: 0, 15, 30, 45 (selon l'index employé)
|
||
const baseStartMinute = (ei * 15) % 60; // 0,15,30,45 (répète)
|
||
|
||
// 1 employé sur 5 a un jour spécial (G305/G105) par semaine
|
||
const isSpecial = (ei % 5) === 0;
|
||
const specialDayIdx = isSpecial ? ((ei + wi) % 5) : -1;
|
||
const specialCode = isSpecial ? ((ei + wi) % 2 === 0 ? 'G305' : 'G105') : 'G1';
|
||
|
||
// 5 jours (lun→ven)
|
||
for (let di = 0; di < weekDays.length; di++) {
|
||
const date = weekDays[di];
|
||
|
||
// Bank code du jour
|
||
const codeToday = (di === specialDayIdx) ? specialCode : 'G1';
|
||
const bank_code_id = bcMap.get(codeToday)!;
|
||
|
||
// Durée aléatoire entre 4 et 10 heures
|
||
const duration = rndInt(4, 10);
|
||
|
||
// Variation jour+semaine pour casser les patterns (décalage 0..2h)
|
||
const dayWeekOffset = (di + wi + (ei % 3)) % 3; // 0,1,2
|
||
const startH = Math.min(12, baseStartHour + dayWeekOffset); // borne supérieure prudente
|
||
const startM = baseStartMinute;
|
||
|
||
const endH = startH + duration; // <= 22 en pratique
|
||
const endM = startM;
|
||
|
||
const ts = tss[(di + wi) % tss.length];
|
||
|
||
await prisma.shifts.create({
|
||
data: {
|
||
timesheet_id: ts.id,
|
||
bank_code_id,
|
||
description: `Shift ${di + 1} (semaine du ${monday.toISOString().slice(0,10)}) emp ${e.id} — ${codeToday}`,
|
||
date, // Date du jour (UTC minuit)
|
||
start_time: timeAt(startH, startM),
|
||
end_time: timeAt(endH, endM),
|
||
is_approved: Math.random() < 0.5,
|
||
},
|
||
});
|
||
created++;
|
||
}
|
||
}
|
||
}
|
||
|
||
const total = await prisma.shifts.count();
|
||
console.log(`✓ Shifts: ${created} nouvelles lignes, ${total} total rows (${INCLUDE_CURRENT ? 'courante +' : ''}${PREVIOUS_WEEKS} semaines précédentes, L→V)`);
|
||
}
|
||
|
||
main().finally(() => prisma.$disconnect());
|