targo-backend/prisma/mock-seeds-scripts/10-shifts.ts
2025-08-28 14:43:23 -04:00

149 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 dun 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 à lemployé (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());