fix(seeder): fix seeders
This commit is contained in:
parent
213b68fb7d
commit
ea76435f4f
|
|
@ -10,7 +10,7 @@ async function main() {
|
||||||
|
|
||||||
// 8 timesheets / employee
|
// 8 timesheets / employee
|
||||||
for (const e of employees) {
|
for (const e of employees) {
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 16; i++) {
|
||||||
const is_approved = Math.random() < 0.3;
|
const is_approved = Math.random() < 0.3;
|
||||||
rows.push({ employee_id: e.id, is_approved });
|
rows.push({ employee_id: e.id, is_approved });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@ import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
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)
|
// Stocker une heure (Postgres TIME) via Date (UTC 1970-01-01)
|
||||||
function timeAt(hour: number, minute: number) {
|
function timeAt(hour: number, minute: number) {
|
||||||
return new Date(Date.UTC(1970, 0, 1, hour, minute, 0));
|
return new Date(Date.UTC(1970, 0, 1, hour, minute, 0));
|
||||||
|
|
@ -9,18 +13,16 @@ function timeAt(hour: number, minute: number) {
|
||||||
|
|
||||||
// Lundi de la semaine (en UTC) pour la date courante
|
// Lundi de la semaine (en UTC) pour la date courante
|
||||||
function mondayOfThisWeekUTC(now = new Date()) {
|
function mondayOfThisWeekUTC(now = new Date()) {
|
||||||
// converti en UTC (sans l'heure)
|
|
||||||
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
||||||
const day = d.getUTCDay(); // 0=Dim, 1=Lun, ...
|
const day = d.getUTCDay(); // 0=Dim, 1=Lun, ...
|
||||||
const diffToMonday = (day + 6) % 7; // 0 si lundi, 1 si mardi, ... 6 si dimanche
|
const diffToMonday = (day + 6) % 7; // 0 si lundi
|
||||||
d.setUTCDate(d.getUTCDate() - diffToMonday);
|
d.setUTCDate(d.getUTCDate() - diffToMonday);
|
||||||
d.setUTCHours(0, 0, 0, 0);
|
d.setUTCHours(0, 0, 0, 0);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retourne les 5 dates Lundi→Vendredi (UTC, à minuit)
|
// Retourne les 5 dates Lundi→Vendredi (UTC, à minuit) à partir d’un lundi donné
|
||||||
function currentWeekDates() {
|
function weekDatesFromMonday(monday: Date) {
|
||||||
const monday = mondayOfThisWeekUTC();
|
|
||||||
return Array.from({ length: 5 }, (_, i) => {
|
return Array.from({ length: 5 }, (_, i) => {
|
||||||
const d = new Date(monday);
|
const d = new Date(monday);
|
||||||
d.setUTCDate(monday.getUTCDate() + i);
|
d.setUTCDate(monday.getUTCDate() + i);
|
||||||
|
|
@ -28,51 +30,79 @@ function currentWeekDates() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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() {
|
async function main() {
|
||||||
// On récupère les bank codes requis (ajuste le nom de la colonne "code" si besoin)
|
// Bank codes utilisés
|
||||||
const BANKS = ['G1', 'G305', 'G105'] as const;
|
const BANKS = ['G1', 'G305', 'G105'] as const;
|
||||||
const bcRows = await prisma.bankCodes.findMany({
|
const bcRows = await prisma.bankCodes.findMany({
|
||||||
where: { bank_code: { in: BANKS as unknown as string[] } },
|
where: { bank_code: { in: BANKS as unknown as string[] } },
|
||||||
select: { id: true, bank_code: true },
|
select: { id: true, bank_code: true },
|
||||||
});
|
});
|
||||||
const bcMap = new Map(bcRows.map(b => [b.bank_code, b.id]));
|
const bcMap = new Map(bcRows.map(b => [b.bank_code, b.id]));
|
||||||
|
|
||||||
// Vérifications
|
|
||||||
for (const c of BANKS) {
|
for (const c of BANKS) {
|
||||||
if (!bcMap.has(c)) throw new Error(`Bank code manquant: ${c}`);
|
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 } });
|
const employees = await prisma.employees.findMany({ select: { id: true } });
|
||||||
if (!employees.length) {
|
if (!employees.length) {
|
||||||
console.log('Aucun employé — rien à insérer.');
|
console.log('Aucun employé — rien à insérer.');
|
||||||
return;
|
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 })));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const weekDays = currentWeekDates();
|
// 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);
|
||||||
|
|
||||||
// Par défaut: G1 (régulier). 1 employé sur 5 : 1 jour de la semaine passe à G305 OU G105 (au hasard)
|
|
||||||
// Horaires: on décale par employé pour garantir des horaires différents.
|
|
||||||
// - start = 7, 7h30, 8, 8h30 selon l’index employé
|
|
||||||
// - durée = 8h sauf vendredi (7h) pour varier un peu
|
|
||||||
for (let ei = 0; ei < employees.length; ei++) {
|
for (let ei = 0; ei < employees.length; ei++) {
|
||||||
const e = employees[ei];
|
const e = employees[ei];
|
||||||
|
const tss = tsByEmp.get(e.id) ?? [];
|
||||||
const tss = await prisma.timesheets.findMany({
|
|
||||||
where: { employee_id: e.id },
|
|
||||||
select: { id: true },
|
|
||||||
orderBy: { id: 'asc' }, // ajuste si tu préfères "created_at" etc.
|
|
||||||
});
|
|
||||||
if (!tss.length) continue;
|
if (!tss.length) continue;
|
||||||
|
|
||||||
// Horaires spécifiques à l’employé (déterministes)
|
// Base horaire spécifique à l’employé (garantit la diversité)
|
||||||
const startHalfHourSlot = ei % 4; // 0..3 -> 7:00, 7:30, 8:00, 8:30
|
// Heures: 6..10 (selon l'index employé)
|
||||||
const startHourBase = 7 + Math.floor(startHalfHourSlot / 2); // 7 ou 8
|
const baseStartHour = 6 + (ei % 5); // 6,7,8,9,10
|
||||||
const startMinuteBase = (startHalfHourSlot % 2) * 30; // 0 ou 30
|
// Minutes: 0, 15, 30, 45 (selon l'index employé)
|
||||||
|
const baseStartMinute = (ei * 15) % 60; // 0,15,30,45 (répète)
|
||||||
|
|
||||||
// Doit-on donner un jour "différent" de G1 à cet employé ?
|
// 1 employé sur 5 a un jour spécial (G305/G105) par semaine
|
||||||
const isSpecial = (ei % 5) === 0; // 1 sur 5
|
const isSpecial = (ei % 5) === 0;
|
||||||
const specialDayIdx = isSpecial ? Math.floor(Math.random() * 5) : -1;
|
const specialDayIdx = isSpecial ? ((ei + wi) % 5) : -1;
|
||||||
const specialCode = isSpecial ? (Math.random() < 0.5 ? 'G305' : 'G105') : 'G1';
|
const specialCode = isSpecial ? ((ei + wi) % 2 === 0 ? 'G305' : 'G105') : 'G1';
|
||||||
|
|
||||||
// 5 jours (lun→ven)
|
// 5 jours (lun→ven)
|
||||||
for (let di = 0; di < weekDays.length; di++) {
|
for (let di = 0; di < weekDays.length; di++) {
|
||||||
|
|
@ -82,35 +112,37 @@ async function main() {
|
||||||
const codeToday = (di === specialDayIdx) ? specialCode : 'G1';
|
const codeToday = (di === specialDayIdx) ? specialCode : 'G1';
|
||||||
const bank_code_id = bcMap.get(codeToday)!;
|
const bank_code_id = bcMap.get(codeToday)!;
|
||||||
|
|
||||||
// Durée : 8h habituellement, 7h le vendredi pour varier (di==4)
|
// Durée aléatoire entre 4 et 10 heures
|
||||||
const duration = (di === 4) ? 7 : 8;
|
const duration = rndInt(4, 10);
|
||||||
|
|
||||||
// Légère variation journalière (+0..2h) pour casser la monotonie, mais bornée
|
// Variation jour+semaine pour casser les patterns (décalage 0..2h)
|
||||||
const dayOffset = di % 3; // 0,1,2
|
const dayWeekOffset = (di + wi + (ei % 3)) % 3; // 0,1,2
|
||||||
const startH = Math.min(10, startHourBase + dayOffset);
|
const startH = Math.min(12, baseStartHour + dayWeekOffset); // borne supérieure prudente
|
||||||
const startM = startMinuteBase;
|
const startM = baseStartMinute;
|
||||||
|
|
||||||
const endH = startH + duration;
|
const endH = startH + duration; // <= 22 en pratique
|
||||||
const endM = startM;
|
const endM = startM;
|
||||||
|
|
||||||
const ts = tss[di % tss.length];
|
const ts = tss[(di + wi) % tss.length];
|
||||||
|
|
||||||
await prisma.shifts.create({
|
await prisma.shifts.create({
|
||||||
data: {
|
data: {
|
||||||
timesheet_id: ts.id,
|
timesheet_id: ts.id,
|
||||||
bank_code_id,
|
bank_code_id,
|
||||||
description: `Shift ${di + 1} (Semaine courante) emp ${e.id} — ${codeToday}`,
|
description: `Shift ${di + 1} (semaine du ${monday.toISOString().slice(0,10)}) emp ${e.id} — ${codeToday}`,
|
||||||
date, // Date du jour (UTC minuit)
|
date, // Date du jour (UTC minuit)
|
||||||
start_time: timeAt(startH, startM),
|
start_time: timeAt(startH, startM),
|
||||||
end_time: timeAt(endH, endM),
|
end_time: timeAt(endH, endM),
|
||||||
is_approved: Math.random() < 0.5,
|
is_approved: Math.random() < 0.5,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
created++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const total = await prisma.shifts.count();
|
const total = await prisma.shifts.count();
|
||||||
console.log(`✓ Shifts: ${total} total rows (semaine courante L→V)`);
|
console.log(`✓ Shifts: ${created} nouvelles lignes, ${total} total rows (${INCLUDE_CURRENT ? 'courante +' : ''}${PREVIOUS_WEEKS} semaines précédentes, L→V)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().finally(() => prisma.$disconnect());
|
main().finally(() => prisma.$disconnect());
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ async function main() {
|
||||||
if (!tss.length) continue;
|
if (!tss.length) continue;
|
||||||
|
|
||||||
const createdShiftIds: number[] = [];
|
const createdShiftIds: number[] = [];
|
||||||
for (let i = 0; i < 30; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
const ts = tss[i % tss.length];
|
const ts = tss[i % tss.length];
|
||||||
const bc = bankCodes[i % bankCodes.length];
|
const bc = bankCodes[i % bankCodes.length];
|
||||||
const date = daysAgo(200 + i); // bien dans le passé
|
const date = daysAgo(200 + i); // bien dans le passé
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ async function main() {
|
||||||
// ✅ typer pour éviter never[]
|
// ✅ typer pour éviter never[]
|
||||||
const created: Expenses[] = [];
|
const created: Expenses[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < 20; i++) {
|
for (let i = 0; i < 4; i++) {
|
||||||
const ts = timesheets[i % timesheets.length];
|
const ts = timesheets[i % timesheets.length];
|
||||||
const bc = expenseCodes[i % expenseCodes.length];
|
const bc = expenseCodes[i % expenseCodes.length];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
export class ShiftDto {
|
export class ShiftDto {
|
||||||
start: string;
|
start: string;
|
||||||
end : string;
|
end : string;
|
||||||
|
bank_code: string;
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExpenseDto {
|
export class ExpenseDto {
|
||||||
amount: number;
|
amount: number;
|
||||||
|
bank_code: string;
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,13 @@ export class TimesheetsQueryService {
|
||||||
timesheet: { is: { employee_id: employee.id } },
|
timesheet: { is: { employee_id: employee.id } },
|
||||||
date: { gte: from, lte: to },
|
date: { gte: from, lte: to },
|
||||||
},
|
},
|
||||||
select: { date: true,start_time: true, end_time: true, is_approved: true },
|
select: {
|
||||||
|
date: true,
|
||||||
|
start_time: true,
|
||||||
|
end_time: true,
|
||||||
|
is_approved: true,
|
||||||
|
bank_code: { select: { bank_code: true } },
|
||||||
|
},
|
||||||
orderBy: [{date: 'asc'}, { start_time: 'asc' }],
|
orderBy: [{date: 'asc'}, { start_time: 'asc' }],
|
||||||
}),
|
}),
|
||||||
this.prisma.expenses.findMany({
|
this.prisma.expenses.findMany({
|
||||||
|
|
@ -61,8 +67,14 @@ export class TimesheetsQueryService {
|
||||||
timesheet: { is: { employee_id: employee.id } },
|
timesheet: { is: { employee_id: employee.id } },
|
||||||
date: { gte: from, lte: to },
|
date: { gte: from, lte: to },
|
||||||
},
|
},
|
||||||
select: { date: true, amount: true, is_approved: true, bank_code: {
|
select: {
|
||||||
select: { type: true } },
|
date: true,
|
||||||
|
amount: true,
|
||||||
|
is_approved: true,
|
||||||
|
bank_code: { select: {
|
||||||
|
type: true,
|
||||||
|
bank_code: true,
|
||||||
|
} },
|
||||||
},
|
},
|
||||||
orderBy: { date: 'asc' },
|
orderBy: { date: 'asc' },
|
||||||
}),
|
}),
|
||||||
|
|
@ -73,6 +85,7 @@ export class TimesheetsQueryService {
|
||||||
date: shift.date,
|
date: shift.date,
|
||||||
start_time: shift.start_time,
|
start_time: shift.start_time,
|
||||||
end_time: shift.end_time,
|
end_time: shift.end_time,
|
||||||
|
bank_code: shift.bank_code?.bank_code ?? '',
|
||||||
is_approved: shift.is_approved ?? true,
|
is_approved: shift.is_approved ?? true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -81,6 +94,7 @@ export class TimesheetsQueryService {
|
||||||
amount: typeof (expense.amount as any)?.toNumber() === 'function' ?
|
amount: typeof (expense.amount as any)?.toNumber() === 'function' ?
|
||||||
(expense.amount as any).toNumber() : Number(expense.amount),
|
(expense.amount as any).toNumber() : Number(expense.amount),
|
||||||
type: expense.bank_code?.type ?? 'CASH',
|
type: expense.bank_code?.type ?? 'CASH',
|
||||||
|
bank_code: expense.bank_code?.bank_code ?? '',
|
||||||
is_approved: expense.is_approved ?? true,
|
is_approved: expense.is_approved ?? true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ export const DAY_KEYS = ['sun','mon','tue','wed','thu','fri','sat'] as const;
|
||||||
export type DayKey = typeof DAY_KEYS[number];
|
export type DayKey = typeof DAY_KEYS[number];
|
||||||
|
|
||||||
//DB line types
|
//DB line types
|
||||||
export type ShiftRow = { date: Date; start_time: Date; end_time: Date; is_approved?: boolean };
|
export type ShiftRow = { date: Date; start_time: Date; end_time: Date; bank_code: string; is_approved?: boolean };
|
||||||
export type ExpenseRow = { date: Date; amount: number; type: string; is_approved?: boolean };
|
export type ExpenseRow = { date: Date; amount: number; type: string; bank_code: string; is_approved?: boolean };
|
||||||
|
|
||||||
export function dayKeyFromDate(date: Date, useUTC = true): DayKey {
|
export function dayKeyFromDate(date: Date, useUTC = true): DayKey {
|
||||||
const index = useUTC ? date.getUTCDay() : date.getDay(); // 0=Sunday..6=Saturday
|
const index = useUTC ? date.getUTCDay() : date.getDay(); // 0=Sunday..6=Saturday
|
||||||
|
|
@ -119,8 +119,9 @@ export function buildWeek(
|
||||||
week.shifts[key].shifts.push({
|
week.shifts[key].shifts.push({
|
||||||
start: toTimeString(shift.start_time),
|
start: toTimeString(shift.start_time),
|
||||||
end : toTimeString(shift.end_time),
|
end : toTimeString(shift.end_time),
|
||||||
|
bank_code: shift.bank_code,
|
||||||
is_approved: shift.is_approved ?? true,
|
is_approved: shift.is_approved ?? true,
|
||||||
} as ShiftDto);
|
});
|
||||||
all_approved = all_approved && (shift.is_approved ?? true);
|
all_approved = all_approved && (shift.is_approved ?? true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,6 +134,7 @@ export function buildWeek(
|
||||||
week.expenses[key][bucket].push({
|
week.expenses[key][bucket].push({
|
||||||
amount: round2(expense.amount),
|
amount: round2(expense.amount),
|
||||||
is_approved: expense.is_approved ?? true,
|
is_approved: expense.is_approved ?? true,
|
||||||
|
bank_code: expense.bank_code,
|
||||||
});
|
});
|
||||||
all_approved = all_approved && (expense.is_approved ?? true);
|
all_approved = all_approved && (expense.is_approved ?? true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user