refactor(seeders): added complexity to shifts and expenses seeders
This commit is contained in:
parent
4f7563ce9b
commit
a73ed4b620
|
|
@ -504,6 +504,52 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/timesheets/shifts/{email}": {
|
||||
"post": {
|
||||
"operationId": "TimesheetsController_createTimesheetShifts",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "email",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "offset",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateWeekShiftsDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Timesheets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/timesheets/{id}": {
|
||||
"get": {
|
||||
"operationId": "TimesheetsController_findOne",
|
||||
|
|
@ -2359,6 +2405,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"CreateWeekShiftsDto": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
},
|
||||
"CreateTimesheetDto": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,16 @@ const prisma = new PrismaClient();
|
|||
|
||||
// ====== Config ======
|
||||
const PREVIOUS_WEEKS = 5;
|
||||
const INCLUDE_CURRENT = false;
|
||||
const INCLUDE_CURRENT = true;
|
||||
const INCR = 15; // incrément ferme de 15 minutes (0.25 h)
|
||||
const DAY_MIN = 5 * 60; // 5h
|
||||
const DAY_MAX = 11 * 60; // 11h
|
||||
const HARD_END = 19 * 60 + 30; // 19:30
|
||||
|
||||
// Times-only via Date (UTC 1970-01-01)
|
||||
// ====== Helpers temps ======
|
||||
function timeAt(hour: number, minute: number) {
|
||||
return new Date(Date.UTC(1970, 0, 1, hour, minute, 0));
|
||||
}
|
||||
|
||||
// Lundi (UTC) de la date fournie
|
||||
function mondayOfThisWeekUTC(now = new Date()) {
|
||||
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
||||
const day = d.getUTCDay();
|
||||
|
|
@ -20,7 +22,6 @@ function mondayOfThisWeekUTC(now = new Date()) {
|
|||
d.setUTCHours(0, 0, 0, 0);
|
||||
return d;
|
||||
}
|
||||
|
||||
function weekDatesFromMonday(monday: Date) {
|
||||
return Array.from({ length: 5 }, (_, i) => {
|
||||
const d = new Date(monday);
|
||||
|
|
@ -28,16 +29,35 @@ function weekDatesFromMonday(monday: Date) {
|
|||
return d;
|
||||
});
|
||||
}
|
||||
|
||||
function mondayNWeeksBefore(monday: Date, n: number) {
|
||||
const d = new Date(monday);
|
||||
d.setUTCDate(d.getUTCDate() - n * 7);
|
||||
return d;
|
||||
}
|
||||
|
||||
function rndInt(min: number, max: number) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
function clamp(n: number, min: number, max: number) {
|
||||
return Math.min(max, Math.max(min, n));
|
||||
}
|
||||
function addMinutes(h: number, m: number, delta: number) {
|
||||
const total = h * 60 + m + delta;
|
||||
const hh = Math.floor(total / 60);
|
||||
const mm = ((total % 60) + 60) % 60;
|
||||
return { h: hh, m: mm };
|
||||
}
|
||||
// Aligne vers le multiple de INCR le plus proche
|
||||
function quantize(mins: number): number {
|
||||
const q = Math.round(mins / INCR) * INCR;
|
||||
return q;
|
||||
}
|
||||
// Tire un multiple de INCR dans [min,max] (inclus), supposés entiers minutes
|
||||
function rndQuantized(min: number, max: number): number {
|
||||
const qmin = Math.ceil(min / INCR);
|
||||
const qmax = Math.floor(max / INCR);
|
||||
const q = rndInt(qmin, qmax);
|
||||
return q * INCR;
|
||||
}
|
||||
|
||||
// Helper: garantit le timesheet de la semaine (upsert)
|
||||
async function getOrCreateTimesheet(employee_id: number, start_date: Date) {
|
||||
|
|
@ -50,8 +70,13 @@ async function getOrCreateTimesheet(employee_id: number, start_date: Date) {
|
|||
}
|
||||
|
||||
async function main() {
|
||||
// Bank codes utilisés
|
||||
// --- Bank codes (pondérés: surtout G1 = régulier) ---
|
||||
const BANKS = ['G1', 'G56', 'G48', 'G700', 'G105', 'G305', 'G43'] as const;
|
||||
const WEIGHTED_CODES = [
|
||||
'G1','G1','G1','G1','G1','G1','G1','G1', // 8x régulier
|
||||
'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 },
|
||||
|
|
@ -70,59 +95,140 @@ async function main() {
|
|||
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));
|
||||
}
|
||||
for (let n = 1; n <= PREVIOUS_WEEKS; n++) mondays.push(mondayNWeeksBefore(mondayThisWeek, n));
|
||||
|
||||
let created = 0;
|
||||
|
||||
for (let wi = 0; wi < mondays.length; wi++) {
|
||||
const monday = mondays[wi];
|
||||
const weekDays = weekDatesFromMonday(monday);
|
||||
const days = weekDatesFromMonday(monday);
|
||||
|
||||
for (let ei = 0; ei < employees.length; ei++) {
|
||||
const e = employees[ei];
|
||||
|
||||
const baseStartHour = 6 + (ei % 5);
|
||||
const baseStartMinute = (ei * 15) % 60;
|
||||
// Cible hebdo 35–45h, multiple de 15 min
|
||||
const weeklyTargetMin = rndQuantized(35 * 60, 45 * 60);
|
||||
|
||||
for (let di = 0; di < weekDays.length; di++) {
|
||||
const date = weekDays[di];
|
||||
// Start de base (7:00, 7:15, 7:30, 7:45, 8:00, 8:15, 8:30, 8:45, 9:00 ...)
|
||||
const baseStartH = 7 + (ei % 3); // 7,8,9
|
||||
const baseStartM = ( (ei * 15) % 60 ); // aligné 15 min
|
||||
|
||||
// 1) Trouver/Créer le timesheet de CETTE semaine pour CET employé
|
||||
const weekStart = mondayOfThisWeekUTC(date);
|
||||
const ts = await getOrCreateTimesheet(e.id, weekStart);
|
||||
// Planification journalière (5 jours) ~8h ± 45 min, quantisée 15 min
|
||||
const plannedDaily: number[] = [];
|
||||
for (let d = 0; d < 5; d++) {
|
||||
const jitter = rndInt(-3, 3) * INCR; // -45..+45 par pas de 15
|
||||
const base = 8 * 60 + jitter;
|
||||
plannedDaily.push(quantize(clamp(base, DAY_MIN, DAY_MAX)));
|
||||
}
|
||||
|
||||
// 2) Tirage aléatoire du bank_code
|
||||
const randomCode = BANKS[Math.floor(Math.random() * BANKS.length)];
|
||||
const bank_code_id = bcMap.get(randomCode)!;
|
||||
// Ajuster le 5e jour pour atteindre la cible hebdo exactement (par pas de 15)
|
||||
const sumFirst4 = plannedDaily.slice(0, 4).reduce((a, b) => a + b, 0);
|
||||
plannedDaily[4] = quantize(clamp(weeklyTargetMin - sumFirst4, DAY_MIN, DAY_MAX));
|
||||
|
||||
// 3) Horaire
|
||||
const duration = rndInt(4, 10);
|
||||
const dayWeekOffset = (di + wi + (ei % 3)) % 3;
|
||||
const startH = Math.min(12, baseStartHour + dayWeekOffset);
|
||||
const startM = baseStartMinute;
|
||||
const endH = startH + duration;
|
||||
const endM = startM;
|
||||
// Corriger le petit écart restant (devrait être multiple de 15) en redistribuant ±15
|
||||
let diff = weeklyTargetMin - plannedDaily.reduce((a, b) => a + b, 0);
|
||||
const step = diff > 0 ? INCR : -INCR;
|
||||
let guard = 100; // anti-boucle
|
||||
while (diff !== 0 && guard-- > 0) {
|
||||
for (let d = 0; d < 5 && diff !== 0; d++) {
|
||||
const next = plannedDaily[d] + step;
|
||||
if (next >= DAY_MIN && next <= DAY_MAX) {
|
||||
plannedDaily[d] = next;
|
||||
diff -= step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Upsert du timesheet (semaine)
|
||||
const ts = await getOrCreateTimesheet(e.id, mondayOfThisWeekUTC(days[0]));
|
||||
|
||||
for (let di = 0; di < 5; di++) {
|
||||
const date = days[di];
|
||||
const targetWorkMin = plannedDaily[di]; // multiple de 15
|
||||
|
||||
// Départ ~ base + jitter (par pas de 15 min aussi)
|
||||
const startJitter = rndInt(-1, 2) * INCR; // -15,0,+15,+30
|
||||
const { h: startH, m: startM } = addMinutes(baseStartH, baseStartM, startJitter);
|
||||
|
||||
// Pause: entre 11:00 et 14:00, mais pas avant start+3h ni après start+6h (le tout quantisé 15)
|
||||
const earliestLunch = Math.max((startH * 60 + startM) + 3 * 60, 11 * 60);
|
||||
const latestLunch = Math.min((startH * 60 + startM) + 6 * 60, 14 * 60);
|
||||
const lunchStartMin = rndQuantized(earliestLunch, latestLunch);
|
||||
const lunchDur = rndQuantized(30, 120); // 30..120 min en pas de 15
|
||||
const lunchEndMin = lunchStartMin + lunchDur;
|
||||
|
||||
// Travail = (lunchStart - start) + (end - lunchEnd)
|
||||
const morningWork = Math.max(0, lunchStartMin - (startH * 60 + startM)); // multiple de 15
|
||||
let afternoonWork = Math.max(60, targetWorkMin - morningWork); // multiple de 15 (diff de deux multiples de 15)
|
||||
if (afternoonWork % INCR !== 0) {
|
||||
// sécurité (ne devrait pas arriver)
|
||||
afternoonWork = quantize(afternoonWork);
|
||||
}
|
||||
|
||||
// Fin de journée (quantisée par construction)
|
||||
const endMinRaw = lunchEndMin + afternoonWork;
|
||||
const endMin = Math.min(endMinRaw, HARD_END);
|
||||
|
||||
// Bank codes variés
|
||||
const bcMorningCode = WEIGHTED_CODES[rndInt(0, WEIGHTED_CODES.length - 1)];
|
||||
const bcAfternoonCode = WEIGHTED_CODES[rndInt(0, WEIGHTED_CODES.length - 1)];
|
||||
const bcMorningId = bcMap.get(bcMorningCode)!;
|
||||
const bcAfternoonId = bcMap.get(bcAfternoonCode)!;
|
||||
|
||||
// Shift matin
|
||||
const lunchStartHM = { h: Math.floor(lunchStartMin / 60), m: lunchStartMin % 60 };
|
||||
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} — ${randomCode}`,
|
||||
bank_code_id: bcMorningId,
|
||||
description: `Matin J${di + 1} (sem ${monday.toISOString().slice(0, 10)}) emp ${e.id} — ${bcMorningCode}`,
|
||||
date,
|
||||
start_time: timeAt(startH, startM),
|
||||
end_time: timeAt(endH, endM),
|
||||
is_approved: Math.random() < 0.5,
|
||||
end_time: timeAt(lunchStartHM.h, lunchStartHM.m),
|
||||
is_approved: Math.random() < 0.6,
|
||||
},
|
||||
});
|
||||
created++;
|
||||
|
||||
// Shift après-midi (si >= 30 min — sera de toute façon multiple de 15)
|
||||
const pmDuration = endMin - lunchEndMin;
|
||||
if (pmDuration >= 30) {
|
||||
const lunchEndHM = { h: Math.floor(lunchEndMin / 60), m: lunchEndMin % 60 };
|
||||
const finalEndHM = { h: Math.floor(endMin / 60), m: endMin % 60 };
|
||||
await prisma.shifts.create({
|
||||
data: {
|
||||
timesheet_id: ts.id,
|
||||
bank_code_id: bcAfternoonId,
|
||||
description: `Après-midi J${di + 1} (sem ${monday.toISOString().slice(0, 10)}) emp ${e.id} — ${bcAfternoonCode}`,
|
||||
date,
|
||||
start_time: timeAt(lunchEndHM.h, lunchEndHM.m),
|
||||
end_time: timeAt(finalEndHM.h, finalEndHM.m),
|
||||
is_approved: Math.random() < 0.6,
|
||||
},
|
||||
});
|
||||
created++;
|
||||
} else {
|
||||
// Fallback très rare : un seul shift couvrant la journée (tout en multiples de 15)
|
||||
const fallbackEnd = addMinutes(startH, startM, targetWorkMin + lunchDur);
|
||||
await prisma.shifts.create({
|
||||
data: {
|
||||
timesheet_id: ts.id,
|
||||
bank_code_id: bcMap.get('G1')!,
|
||||
description: `Fallback J${di + 1} (sem ${monday.toISOString().slice(0, 10)}) emp ${e.id} — G1`,
|
||||
date,
|
||||
start_time: timeAt(startH, startM),
|
||||
end_time: timeAt(fallbackEnd.h, fallbackEnd.m),
|
||||
is_approved: Math.random() < 0.6,
|
||||
},
|
||||
});
|
||||
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)`);
|
||||
console.log(`✓ Shifts créés: ${created} | total en DB: ${total} (${INCLUDE_CURRENT ? 'inclut semaine courante, ' : ''}${PREVIOUS_WEEKS} sem passées, L→V, 2 shifts/jour, pas de décimaux foireux})`);
|
||||
}
|
||||
|
||||
main().finally(() => prisma.$disconnect());
|
||||
|
|
|
|||
|
|
@ -2,7 +2,12 @@ import { PrismaClient } from '@prisma/client';
|
|||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Lundi (UTC) de la date fournie
|
||||
// ====== Config ======
|
||||
const WEEKS_BACK = 4; // 4 semaines avant + semaine courante
|
||||
const INCLUDE_CURRENT = true; // inclure la semaine courante
|
||||
const STEP_CENTS = 25; // montants en quarts de dollar (.00/.25/.50/.75)
|
||||
|
||||
// ====== Helpers dates ======
|
||||
function mondayOfThisWeekUTC(now = new Date()) {
|
||||
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
||||
const day = d.getUTCDay();
|
||||
|
|
@ -11,10 +16,13 @@ function mondayOfThisWeekUTC(now = new Date()) {
|
|||
d.setUTCHours(0, 0, 0, 0);
|
||||
return d;
|
||||
}
|
||||
|
||||
// Dates Lundi→Vendredi (UTC minuit)
|
||||
function currentWeekDates() {
|
||||
const monday = mondayOfThisWeekUTC();
|
||||
function mondayNWeeksBefore(monday: Date, n: number) {
|
||||
const d = new Date(monday);
|
||||
d.setUTCDate(monday.getUTCDate() - n * 7);
|
||||
return d;
|
||||
}
|
||||
// L→V (UTC minuit)
|
||||
function weekDatesMonToFri(monday: Date) {
|
||||
return Array.from({ length: 5 }, (_, i) => {
|
||||
const d = new Date(monday);
|
||||
d.setUTCDate(monday.getUTCDate() + i);
|
||||
|
|
@ -22,15 +30,30 @@ function currentWeekDates() {
|
|||
});
|
||||
}
|
||||
|
||||
// ====== Helpers random / amount ======
|
||||
function rndInt(min: number, max: number) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
function rndAmount(minCents: number, maxCents: number) {
|
||||
const cents = rndInt(minCents, maxCents);
|
||||
return (cents / 100).toFixed(2);
|
||||
// String "xx.yy" à partir de cents ENTiers (jamais de float)
|
||||
function centsToAmountString(cents: number): string {
|
||||
const sign = cents < 0 ? '-' : '';
|
||||
const abs = Math.abs(cents);
|
||||
const dollars = Math.floor(abs / 100);
|
||||
const c = abs % 100;
|
||||
return `${sign}${dollars}.${c.toString().padStart(2, '0')}`;
|
||||
}
|
||||
// Tire un multiple de STEP_CENTS entre minCents et maxCents (inclus)
|
||||
function rndQuantizedCents(minCents: number, maxCents: number, step = STEP_CENTS): number {
|
||||
const qmin = Math.ceil(minCents / step);
|
||||
const qmax = Math.floor(maxCents / step);
|
||||
const q = rndInt(qmin, qmax);
|
||||
return q * step;
|
||||
}
|
||||
function rndAmount(minCents: number, maxCents: number): string {
|
||||
return centsToAmountString(rndQuantizedCents(minCents, maxCents));
|
||||
}
|
||||
|
||||
// Helper: garantit le timesheet de la semaine (upsert)
|
||||
// ====== Timesheet upsert ======
|
||||
async function getOrCreateTimesheet(employee_id: number, start_date: Date) {
|
||||
return prisma.timesheets.upsert({
|
||||
where: { employee_id_start_date: { employee_id, start_date } },
|
||||
|
|
@ -41,8 +64,10 @@ async function getOrCreateTimesheet(employee_id: number, start_date: Date) {
|
|||
}
|
||||
|
||||
async function main() {
|
||||
// Codes autorisés (aléatoires à chaque dépense)
|
||||
// Codes d'EXPENSES (exemples)
|
||||
const BANKS = ['G517', 'G503', 'G502', 'G202', 'G234'] as const;
|
||||
|
||||
// Précharger les bank codes
|
||||
const bcRows = await prisma.bankCodes.findMany({
|
||||
where: { bank_code: { in: BANKS as unknown as string[] } },
|
||||
select: { id: true, bank_code: true },
|
||||
|
|
@ -52,58 +77,85 @@ async function main() {
|
|||
if (!bcMap.has(c)) throw new Error(`Bank code manquant: ${c}`);
|
||||
}
|
||||
|
||||
// Employés
|
||||
const employees = await prisma.employees.findMany({ select: { id: true } });
|
||||
if (!employees.length) {
|
||||
console.warn('Aucun employé — rien à insérer.');
|
||||
return;
|
||||
}
|
||||
|
||||
const weekDays = currentWeekDates();
|
||||
const monday = weekDays[0];
|
||||
const friday = weekDays[4];
|
||||
// Liste des lundis (courant + 4 précédents)
|
||||
const mondayThisWeek = mondayOfThisWeekUTC();
|
||||
const mondays: Date[] = [];
|
||||
if (INCLUDE_CURRENT) mondays.push(mondayThisWeek);
|
||||
for (let n = 1; n <= WEEKS_BACK; n++) mondays.push(mondayNWeeksBefore(mondayThisWeek, n));
|
||||
|
||||
let created = 0;
|
||||
|
||||
for (const e of employees) {
|
||||
// 1) Semaine courante → assurer le timesheet de la semaine
|
||||
const weekStart = mondayOfThisWeekUTC();
|
||||
const ts = await getOrCreateTimesheet(e.id, weekStart);
|
||||
for (const monday of mondays) {
|
||||
const weekDays = weekDatesMonToFri(monday);
|
||||
const friday = weekDays[4];
|
||||
|
||||
// 2) Skip si l’employé a déjà une dépense cette semaine (on garantit ≥1)
|
||||
const already = await prisma.expenses.findFirst({
|
||||
where: { timesheet_id: ts.id, date: { gte: monday, lte: friday } },
|
||||
select: { id: true },
|
||||
});
|
||||
if (already) continue;
|
||||
for (const e of employees) {
|
||||
// Upsert timesheet pour CETTE semaine/employee
|
||||
const ts = await getOrCreateTimesheet(e.id, monday);
|
||||
|
||||
// 3) 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)];
|
||||
// Idempotence: si déjà au moins une expense L→V, on skip la semaine
|
||||
const already = await prisma.expenses.findFirst({
|
||||
where: { timesheet_id: ts.id, date: { gte: monday, lte: friday } },
|
||||
select: { id: true },
|
||||
});
|
||||
if (already) continue;
|
||||
|
||||
// 4) Montant varié
|
||||
const amount =
|
||||
randomCode === 'G503'
|
||||
? rndAmount(1000, 7500) // 10.00..75.00
|
||||
: rndAmount(2000, 25000); // 20.00..250.00
|
||||
// 1 à 3 expenses (jours distincts)
|
||||
const count = rndInt(1, 3);
|
||||
const dayIndexes = [0, 1, 2, 3, 4].sort(() => Math.random() - 0.5).slice(0, count);
|
||||
|
||||
await prisma.expenses.create({
|
||||
data: {
|
||||
timesheet_id: ts.id,
|
||||
bank_code_id,
|
||||
date,
|
||||
amount,
|
||||
attachement: null,
|
||||
description: `Expense ${randomCode} ${amount}$ (emp ${e.id})`,
|
||||
is_approved: Math.random() < 0.6,
|
||||
supervisor_comment: Math.random() < 0.2 ? 'OK' : null,
|
||||
},
|
||||
});
|
||||
created++;
|
||||
for (const idx of dayIndexes) {
|
||||
const date = weekDays[idx];
|
||||
const code = BANKS[rndInt(0, BANKS.length - 1)];
|
||||
const bank_code_id = bcMap.get(code)!;
|
||||
|
||||
// Montants (cents) quantisés à 25¢ => aucun flottant binaire plus tard
|
||||
let amount: string;
|
||||
switch (code) {
|
||||
case 'G503': // petites fournitures
|
||||
amount = rndAmount(1000, 7500); // 10.00 à 75.00
|
||||
break;
|
||||
case 'G502': // repas
|
||||
amount = rndAmount(1500, 3000); // 15.00 à 30.00
|
||||
break;
|
||||
case 'G202': // essence
|
||||
amount = rndAmount(2000, 15000); // 20.00 à 150.00
|
||||
break;
|
||||
case 'G234': // hébergement
|
||||
amount = rndAmount(6000, 25000); // 60.00 à 250.00
|
||||
break;
|
||||
case 'G517': // péages / divers
|
||||
default:
|
||||
amount = rndAmount(500, 5000); // 5.00 à 50.00
|
||||
break;
|
||||
}
|
||||
|
||||
await prisma.expenses.create({
|
||||
data: {
|
||||
timesheet_id: ts.id,
|
||||
bank_code_id,
|
||||
date,
|
||||
amount, // string "xx.yy" (2 décimales exactes)
|
||||
attachement: null,
|
||||
description: `Expense ${code} ${amount}$ (emp ${e.id})`,
|
||||
is_approved: Math.random() < 0.65,
|
||||
supervisor_comment: Math.random() < 0.25 ? 'OK' : null,
|
||||
},
|
||||
});
|
||||
created++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const total = await prisma.expenses.count();
|
||||
console.log(`✓ Expenses: ${created} nouvelles lignes, ${total} total rows (≥1 expense/employee pour la semaine courante)`);
|
||||
console.log(`✓ Expenses: ${created} nouvelles lignes, ${total} total rows (sem courante + ${WEEKS_BACK} précédentes, L→V uniquement, montants en quarts de dollar)`);
|
||||
}
|
||||
|
||||
main().finally(() => prisma.$disconnect());
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user