fix(seeds): added larger scope of data to print
This commit is contained in:
parent
0516736fa2
commit
4bb42ec3ed
|
|
@ -24,15 +24,19 @@ async function main() {
|
|||
|
||||
const pick = <T>(arr: T[]) => arr[Math.floor(Math.random() * arr.length)];
|
||||
|
||||
// 40 employees, avec une distribution initiale
|
||||
const rolesForEmployees: Roles[] = [
|
||||
Roles.ADMIN,
|
||||
...Array(4).fill(Roles.SUPERVISOR),
|
||||
...Array(4).fill(Roles.SUPERVISOR), // 4 superviseurs
|
||||
Roles.HR,
|
||||
Roles.ACCOUNTING,
|
||||
...Array(33).fill(Roles.EMPLOYEE),
|
||||
];
|
||||
|
||||
// 40 employees
|
||||
// --- Normalisation : forcer user5@example.test à SUPERVISOR ---
|
||||
// user5 => index 4 (i = 4)
|
||||
rolesForEmployees[4] = Roles.SUPERVISOR;
|
||||
|
||||
for (let i = 0; i < 40; i++) {
|
||||
const fn = pick(firstNames);
|
||||
const ln = pick(lastNames);
|
||||
|
|
@ -40,8 +44,7 @@ async function main() {
|
|||
first_name: fn,
|
||||
last_name: ln,
|
||||
email: emailFor(i),
|
||||
// on concatène proprement en string
|
||||
phone_number: BASE_PHONE + i.toString(),
|
||||
phone_number: BASE_PHONE + i.toString(),
|
||||
residence: Math.random() < 0.5 ? 'QC' : 'ON',
|
||||
role: rolesForEmployees[i],
|
||||
});
|
||||
|
|
@ -61,8 +64,29 @@ async function main() {
|
|||
});
|
||||
}
|
||||
|
||||
// 1) Insert (sans doublons)
|
||||
await prisma.users.createMany({ data: usersData, skipDuplicates: true });
|
||||
console.log('✓ Users: 50 rows (40 employees, 10 customers)');
|
||||
|
||||
// 2) Validation/Correction post-insert :
|
||||
// - garantir que user5@example.test est SUPERVISOR
|
||||
// - si jamais le projet avait un user avec la typo, on tente aussi de le corriger (fallback)
|
||||
const targetEmails = ['user5@example.test', 'user5@examplte.tset'];
|
||||
for (const email of targetEmails) {
|
||||
try {
|
||||
await prisma.users.update({
|
||||
where: { email },
|
||||
data: { role: Roles.SUPERVISOR },
|
||||
});
|
||||
console.log(`✓ Validation: ${email} est SUPERVISOR`);
|
||||
break; // on s'arrête dès qu'on a corrigé l'un des deux
|
||||
} catch {
|
||||
// ignore si non trouvé, on tente l'autre
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Petite vérif : compter les superviseurs pour sanity check
|
||||
const supCount = await prisma.users.count({ where: { role: Roles.SUPERVISOR } });
|
||||
console.log(`✓ Users: 50 rows (40 employees, 10 customers) — SUPERVISORS: ${supCount}`);
|
||||
}
|
||||
|
||||
main().finally(() => prisma.$disconnect());
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ function randomPastDate(yearsBack = 3) {
|
|||
past.setFullYear(now.getFullYear() - yearsBack);
|
||||
const t = randInt(past.getTime(), now.getTime());
|
||||
const d = new Date(t);
|
||||
d.setHours(0,0,0,0);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +29,12 @@ const jobTitles = [
|
|||
];
|
||||
|
||||
function randomTitle() {
|
||||
return jobTitles[randInt(0, jobTitles.length -1)];
|
||||
return jobTitles[randInt(0, jobTitles.length - 1)];
|
||||
}
|
||||
|
||||
// Sélection aléatoire entre 271583 et 271585
|
||||
function randomCompanyCode() {
|
||||
return Math.random() < 0.5 ? 271583 : 271585;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
|
|
@ -38,40 +43,41 @@ async function main() {
|
|||
orderBy: { email: 'asc' },
|
||||
});
|
||||
|
||||
// Create supervisors first
|
||||
const supervisorUsers = employeeUsers.filter(u => u.role === Roles.SUPERVISOR);
|
||||
const supervisorEmployeeIds: number[] = [];
|
||||
|
||||
for (const u of supervisorUsers) {
|
||||
const emp = await prisma.employees.upsert({
|
||||
where: { user_id: u.id },
|
||||
update: {},
|
||||
create: {
|
||||
user_id: u.id,
|
||||
external_payroll_id: randInt(10000, 99999),
|
||||
company_code: randInt(1, 5),
|
||||
first_work_day: randomPastDate(3),
|
||||
last_work_day: null,
|
||||
job_title: randomTitle(),
|
||||
is_supervisor: true,
|
||||
},
|
||||
});
|
||||
supervisorEmployeeIds.push(emp.id);
|
||||
// 1) Trouver le user qui sera le superviseur fixe
|
||||
const supervisorUser = await prisma.users.findUnique({
|
||||
where: { email: 'user5@examplte.test' },
|
||||
});
|
||||
if (!supervisorUser) {
|
||||
throw new Error("Le user 'user5@examplte.test' n'existe pas !");
|
||||
}
|
||||
|
||||
// Create remaining employees, assign a random supervisor (admin can have none)
|
||||
// 2) Créer ou récupérer son employee avec is_supervisor = true
|
||||
const supervisorEmp = await prisma.employees.upsert({
|
||||
where: { user_id: supervisorUser.id },
|
||||
update: { is_supervisor: true },
|
||||
create: {
|
||||
user_id: supervisorUser.id,
|
||||
external_payroll_id: randInt(10000, 99999),
|
||||
company_code: randomCompanyCode(),
|
||||
first_work_day: randomPastDate(3),
|
||||
last_work_day: null,
|
||||
job_title: randomTitle(),
|
||||
is_supervisor: true,
|
||||
},
|
||||
});
|
||||
|
||||
// 3) Créer tous les autres employés avec ce superviseur (sauf ADMIN qui n’a pas de superviseur)
|
||||
for (const u of employeeUsers) {
|
||||
const already = await prisma.employees.findUnique({ where: { user_id: u.id } });
|
||||
if (already) continue;
|
||||
|
||||
const supervisor_id =
|
||||
u.role === Roles.ADMIN ? null : supervisorEmployeeIds[randInt(0, supervisorEmployeeIds.length - 1)];
|
||||
const supervisor_id = u.role === Roles.ADMIN ? null : supervisorEmp.id;
|
||||
|
||||
await prisma.employees.create({
|
||||
data: {
|
||||
user_id: u.id,
|
||||
external_payroll_id: randInt(10000, 99999),
|
||||
company_code: randInt(1, 5),
|
||||
company_code: randomCompanyCode(),
|
||||
first_work_day: randomPastDate(3),
|
||||
last_work_day: null,
|
||||
supervisor_id,
|
||||
|
|
@ -81,7 +87,7 @@ async function main() {
|
|||
}
|
||||
|
||||
const total = await prisma.employees.count();
|
||||
console.log(`✓ Employees: ${total} rows (with supervisors linked)`);
|
||||
console.log(`✓ Employees: ${total} rows (supervisor = ${supervisorUser.email})`);
|
||||
}
|
||||
|
||||
main().finally(() => prisma.$disconnect());
|
||||
|
|
|
|||
|
|
@ -3,25 +3,22 @@ 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
|
||||
const PREVIOUS_WEEKS = 5;
|
||||
const INCLUDE_CURRENT = false;
|
||||
|
||||
// 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
|
||||
const day = d.getUTCDay();
|
||||
const diffToMonday = (day + 6) % 7;
|
||||
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);
|
||||
|
|
@ -30,21 +27,19 @@ function weekDatesFromMonday(monday: Date) {
|
|||
});
|
||||
}
|
||||
|
||||
// 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 BANKS = ['G1', 'G56', 'G48', 'G700', 'G105', 'G305', 'G43'] as const;
|
||||
const bcRows = await prisma.bankCodes.findMany({
|
||||
where: { bank_code: { in: BANKS as unknown as string[] } },
|
||||
select: { id: true, bank_code: true },
|
||||
|
|
@ -54,12 +49,12 @@ async function main() {
|
|||
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({
|
||||
|
|
@ -72,7 +67,6 @@ async function main() {
|
|||
}
|
||||
}
|
||||
|
||||
// Construit la liste des semaines à insérer
|
||||
const mondayThisWeek = mondayOfThisWeekUTC();
|
||||
const mondays: Date[] = [];
|
||||
|
||||
|
|
@ -83,7 +77,6 @@ async function main() {
|
|||
|
||||
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);
|
||||
|
|
@ -93,34 +86,22 @@ async function main() {
|
|||
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)
|
||||
const baseStartHour = 6 + (ei % 5);
|
||||
const baseStartMinute = (ei * 15) % 60;
|
||||
|
||||
// 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)!;
|
||||
// Tirage aléatoire du bank_code
|
||||
const randomCode = BANKS[Math.floor(Math.random() * BANKS.length)];
|
||||
const bank_code_id = bcMap.get(randomCode)!;
|
||||
|
||||
// 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 dayWeekOffset = (di + wi + (ei % 3)) % 3;
|
||||
const startH = Math.min(12, baseStartHour + dayWeekOffset);
|
||||
const startM = baseStartMinute;
|
||||
|
||||
const endH = startH + duration; // <= 22 en pratique
|
||||
const endH = startH + duration;
|
||||
const endM = startM;
|
||||
|
||||
const ts = tss[(di + wi) % tss.length];
|
||||
|
|
@ -129,8 +110,8 @@ async function main() {
|
|||
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)
|
||||
description: `Shift ${di + 1} (semaine du ${monday.toISOString().slice(0, 10)}) emp ${e.id} — ${randomCode}`,
|
||||
date,
|
||||
start_time: timeAt(startH, startM),
|
||||
end_time: timeAt(endH, endM),
|
||||
is_approved: Math.random() < 0.5,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { PrismaClient } from '@prisma/client';
|
|||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Lundi de la semaine (en UTC) pour la date courante
|
||||
// Lundi (UTC) de la semaine 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, ...
|
||||
|
|
@ -12,7 +12,7 @@ function mondayOfThisWeekUTC(now = new Date()) {
|
|||
return d;
|
||||
}
|
||||
|
||||
// Retourne les 5 dates Lundi→Vendredi (UTC, à minuit)
|
||||
// Dates Lundi→Vendredi (UTC minuit)
|
||||
function currentWeekDates() {
|
||||
const monday = mondayOfThisWeekUTC();
|
||||
return Array.from({ length: 5 }, (_, i) => {
|
||||
|
|
@ -27,19 +27,19 @@ function rndInt(min: number, max: number) {
|
|||
}
|
||||
function rndAmount(minCents: number, maxCents: number) {
|
||||
const cents = rndInt(minCents, maxCents);
|
||||
return (cents / 100).toFixed(2); // string (ex: "123.45")
|
||||
return (cents / 100).toFixed(2); // string "123.45"
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// On veut explicitement G503 (mileage) et G517 (remboursement)
|
||||
const wanted = ['G57', 'G517'] as const;
|
||||
const codes = await prisma.bankCodes.findMany({
|
||||
where: { bank_code: { in: wanted as unknown as string[] } },
|
||||
// Codes autorisés (aléatoires à chaque dépense)
|
||||
const BANKS = ['G517', 'G57', 'G502', 'G202', 'G234'] as const;
|
||||
const bcRows = await prisma.bankCodes.findMany({
|
||||
where: { bank_code: { in: BANKS as unknown as string[] } },
|
||||
select: { id: true, bank_code: true },
|
||||
});
|
||||
const map = new Map(codes.map(c => [c.bank_code, c.id]));
|
||||
for (const c of wanted) {
|
||||
if (!map.has(c)) throw new Error(`Bank code manquant: ${c}`);
|
||||
const bcMap = new Map(bcRows.map(c => [c.bank_code, c.id]));
|
||||
for (const c of BANKS) {
|
||||
if (!bcMap.has(c)) throw new Error(`Bank code manquant: ${c}`);
|
||||
}
|
||||
|
||||
const employees = await prisma.employees.findMany({ select: { id: true } });
|
||||
|
|
@ -49,64 +49,59 @@ async function main() {
|
|||
}
|
||||
|
||||
const weekDays = currentWeekDates();
|
||||
const monday = weekDays[0];
|
||||
const friday = weekDays[4];
|
||||
|
||||
// Règles:
|
||||
// - (index % 5) === 0 -> mileage G503 (km)
|
||||
// - (index % 5) === 1 -> remboursement G517 ($)
|
||||
// Les autres: pas de dépense
|
||||
// On met la dépense un des jours de la semaine (déterministe mais varié).
|
||||
let created = 0;
|
||||
|
||||
for (let ei = 0; ei < employees.length; ei++) {
|
||||
const e = employees[ei];
|
||||
|
||||
for (const e of employees) {
|
||||
// Choisir un timesheet (le plus ancien, ou change 'asc'→'desc' si tu préfères le plus récent)
|
||||
const ts = await prisma.timesheets.findFirst({
|
||||
where: { employee_id: e.id },
|
||||
select: { id: true },
|
||||
orderBy: { id: 'asc' }, // ajuste si tu préfères par date
|
||||
orderBy: { id: 'asc' },
|
||||
});
|
||||
if (!ts) continue;
|
||||
|
||||
const dayIdx = ei % 5; // 0..4 -> répartit sur la semaine
|
||||
const date = weekDays[dayIdx];
|
||||
// Si l’employé a déjà une dépense cette semaine, on n’en recrée pas (≥1 garanti)
|
||||
const already = await prisma.expenses.findFirst({
|
||||
where: {
|
||||
timesheet_id: ts.id,
|
||||
date: { gte: monday, lte: friday },
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
if (already) continue;
|
||||
|
||||
if (ei % 5 === 0) {
|
||||
// Mileage (G503) — amount = km
|
||||
const km = rndInt(10, 180); // 10..180 km
|
||||
await prisma.expenses.create({
|
||||
data: {
|
||||
timesheet_id: ts.id,
|
||||
bank_code_id: map.get('G503')!,
|
||||
date,
|
||||
amount: km.toString(), // on stocke le nombre de km dans amount (si tu as un champ "quantity_km", remplace ici)
|
||||
attachement: null,
|
||||
description: `Mileage ${km} km (emp ${e.id})`,
|
||||
is_approved: Math.random() < 0.6,
|
||||
supervisor_comment: Math.random() < 0.2 ? 'OK' : null,
|
||||
},
|
||||
});
|
||||
created++;
|
||||
} else if (ei % 5 === 1) {
|
||||
// Remboursement (G517) — amount = $
|
||||
const dollars = rndAmount(2000, 25000); // 20.00$..250.00$
|
||||
await prisma.expenses.create({
|
||||
data: {
|
||||
timesheet_id: ts.id,
|
||||
bank_code_id: map.get('G517')!,
|
||||
date,
|
||||
amount: dollars,
|
||||
attachement: null,
|
||||
description: `Remboursement ${dollars}$ (emp ${e.id})`,
|
||||
is_approved: Math.random() < 0.6,
|
||||
supervisor_comment: Math.random() < 0.2 ? 'OK' : null,
|
||||
},
|
||||
});
|
||||
created++;
|
||||
}
|
||||
// Choix aléatoire du code + jour
|
||||
const randomCode = BANKS[Math.floor(Math.random() * BANKS.length)];
|
||||
const bank_code_id = bcMap.get(randomCode)!;
|
||||
const date = weekDays[Math.floor(Math.random() * weekDays.length)];
|
||||
|
||||
// Montant aléatoire (ranges par défaut en $ — ajuste au besoin)
|
||||
// (ex.: G57 plus petit, G517 remboursement plus large)
|
||||
const amount =
|
||||
randomCode === 'G57'
|
||||
? rndAmount(1000, 7500) // 10.00..75.00
|
||||
: rndAmount(2000, 25000); // 20.00..250.00 pour les autres
|
||||
|
||||
await prisma.expenses.create({
|
||||
data: {
|
||||
timesheet_id: ts.id,
|
||||
bank_code_id,
|
||||
date,
|
||||
amount, // stocké en string
|
||||
attachement: null, // garde le champ tel quel si typo volontaire
|
||||
description: `Expense ${randomCode} ${amount}$ (emp ${e.id})`,
|
||||
is_approved: Math.random() < 0.6,
|
||||
supervisor_comment: Math.random() < 0.2 ? 'OK' : null,
|
||||
},
|
||||
});
|
||||
created++;
|
||||
}
|
||||
|
||||
const total = await prisma.expenses.count();
|
||||
console.log(`✓ Expenses: ${created} nouvelles lignes, ${total} total rows (semaine courante)`);
|
||||
console.log(`✓ Expenses: ${created} nouvelles lignes, ${total} total rows (≥1 expense/employee pour la semaine courante)`);
|
||||
}
|
||||
|
||||
main().finally(() => prisma.$disconnect());
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user