feat(schema): migration of the new table paid_time_off and added a column to employee table = daily_expected_hours

This commit is contained in:
Matthieu Haineault 2026-01-06 09:13:36 -05:00
parent e3006b9b82
commit 0791f124a0
9 changed files with 607 additions and 566 deletions

View File

@ -0,0 +1,36 @@
/*
Warnings:
- You are about to drop the column `sort_order` on the `schedule_preset_shifts` table. All the data in the column will be lost.
- A unique constraint covering the columns `[preset_id,week_day]` on the table `schedule_preset_shifts` will be added. If there are existing duplicate values, this will fail.
- Added the required column `daily_expected_hours` to the `employees` table without a default value. This is not possible if the table is not empty.
*/
-- DropIndex
DROP INDEX "public"."schedule_preset_shifts_preset_id_week_day_sort_order_key";
-- AlterTable
ALTER TABLE "employees" ADD COLUMN "daily_expected_hours" INTEGER NOT NULL;
-- AlterTable
ALTER TABLE "schedule_preset_shifts" DROP COLUMN "sort_order";
-- CreateTable
CREATE TABLE "paid_time_off" (
"id" SERIAL NOT NULL,
"employee_id" INTEGER NOT NULL,
"vacation_hours" INTEGER NOT NULL DEFAULT 0,
"sick_hours" INTEGER NOT NULL DEFAULT 0,
"last_updated" DATE NOT NULL,
CONSTRAINT "paid_time_off_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "paid_time_off_employee_id_key" ON "paid_time_off"("employee_id");
-- CreateIndex
CREATE UNIQUE INDEX "schedule_preset_shifts_preset_id_week_day_key" ON "schedule_preset_shifts"("preset_id", "week_day");
-- AddForeignKey
ALTER TABLE "paid_time_off" ADD CONSTRAINT "paid_time_off_employee_id_fkey" FOREIGN KEY ("employee_id") REFERENCES "employees"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -43,6 +43,7 @@ model Employees {
user_id String @unique @db.Uuid user_id String @unique @db.Uuid
external_payroll_id Int external_payroll_id Int
company_code Int company_code Int
daily_expected_hours Int
first_work_day DateTime @db.Date first_work_day DateTime @db.Date
last_work_day DateTime? @db.Date last_work_day DateTime? @db.Date
supervisor_id Int? supervisor_id Int?

View File

@ -5,7 +5,7 @@ import * as path from 'path';
const prisma = new PrismaClient(); const prisma = new PrismaClient();
// ⚙️ Chemin vers ton CSV employees // Chemin vers ton CSV employees
const CSV_PATH = path.resolve(__dirname, 'data/export_new_employee_table.csv'); const CSV_PATH = path.resolve(__dirname, 'data/export_new_employee_table.csv');
// Rôles éligibles pour la table Employees // Rôles éligibles pour la table Employees
@ -78,7 +78,7 @@ function parseIntSafe(value: string, fieldName: string): number | null {
const n = Number.parseInt(trimmed, 10); const n = Number.parseInt(trimmed, 10);
if (Number.isNaN(n)) { if (Number.isNaN(n)) {
console.warn(`⚠️ Impossible de parser "${value}" en entier pour le champ ${fieldName}`); console.warn(` Impossible de parser "${value}" en entier pour le champ ${fieldName}`);
return null; return null;
} }
return n; return n;
@ -90,7 +90,7 @@ function millisToDate(value: string): Date | null {
const ms = Number(trimmed); const ms = Number(trimmed);
if (!Number.isFinite(ms)) { if (!Number.isFinite(ms)) {
console.warn(`⚠️ Impossible de parser "${value}" en millis pour une Date`); console.warn(` Impossible de parser "${value}" en millis pour une Date`);
return null; return null;
} }
@ -135,7 +135,7 @@ async function main() {
return row as EmployeeCsvRow; return row as EmployeeCsvRow;
}); });
console.log(`➡️ ${csvRows.length} lignes trouvées dans le CSV employees`); console.log(` ${csvRows.length} lignes trouvées dans le CSV employees`);
// 2. Récupérer tous les emails du CSV // 2. Récupérer tous les emails du CSV
const emails = Array.from( const emails = Array.from(
@ -146,7 +146,7 @@ async function main() {
), ),
); );
console.log(`➡️ ${emails.length} emails uniques trouvés dans le CSV`); console.log(` ${emails.length} emails uniques trouvés dans le CSV`);
// 3. Charger les users correspondants avec les bons rôles // 3. Charger les users correspondants avec les bons rôles
const users = (await prisma.users.findMany({ const users = (await prisma.users.findMany({
@ -161,7 +161,7 @@ async function main() {
}, },
})) as UserSummary[]; })) as UserSummary[];
console.log(`➡️ ${users.length} users éligibles trouvés dans la DB`); console.log(` ${users.length} users éligibles trouvés dans la DB`);
// Map email → user // Map email → user
const userByEmail = new Map<string, UserSummary>(); const userByEmail = new Map<string, UserSummary>();
@ -180,6 +180,7 @@ async function main() {
job_title: string | null; job_title: string | null;
is_supervisor: boolean; is_supervisor: boolean;
supervisor_id?: number | null; supervisor_id?: number | null;
daily_expected_hours: number;
}[] = []; }[] = [];
const rowsWithoutUser: EmployeeCsvRow[] = []; const rowsWithoutUser: EmployeeCsvRow[] = [];
@ -209,7 +210,7 @@ async function main() {
if (!first_work_day) { if (!first_work_day) {
console.warn( console.warn(
`⚠️ Date d'onboarding invalide pour ${row.email} (employee_number=${row.employee_number})`, `WARNING: Date d'onboarding invalide pour ${row.email} (employee_number=${row.employee_number})`,
); );
continue; continue;
} }
@ -220,16 +221,17 @@ async function main() {
company_code, company_code,
first_work_day, first_work_day,
last_work_day, last_work_day,
daily_expected_hours: 8,
job_title, job_title,
is_supervisor, is_supervisor,
supervisor_id: null, // on pourra gérer ça plus tard si tu as les infos supervisor_id: null, // on pourra gérer ça plus tard si tu as les infos
}); });
} }
console.log(`➡️ ${employeesToCreate.length} entrées Employees prêtes à être insérées`); console.log(` ${employeesToCreate.length} entrées Employees prêtes à être insérées`);
if (rowsWithoutUser.length > 0) { if (rowsWithoutUser.length > 0) {
console.warn(`⚠️ ${rowsWithoutUser.length} lignes CSV sans user correspondant (email / rôle) :`); console.warn(` ${rowsWithoutUser.length} lignes CSV sans user correspondant (email / rôle) :`);
for (const row of rowsWithoutUser) { for (const row of rowsWithoutUser) {
console.warn( console.warn(
` - email=${row.email}, employee_number=${row.employee_number}, company=${row.company}`, ` - email=${row.email}, employee_number=${row.employee_number}, company=${row.company}`,
@ -238,7 +240,7 @@ async function main() {
} }
if (rowsWithInvalidNumbers.length > 0) { if (rowsWithInvalidNumbers.length > 0) {
console.warn(`⚠️ ${rowsWithInvalidNumbers.length} lignes CSV avec ids/compagnies invalides :`); console.warn(` ${rowsWithInvalidNumbers.length} lignes CSV avec ids/compagnies invalides :`);
for (const row of rowsWithInvalidNumbers) { for (const row of rowsWithInvalidNumbers) {
console.warn( console.warn(
` - email=${row.email}, employee_number="${row.employee_number}", company="${row.company}"`, ` - email=${row.email}, employee_number="${row.employee_number}", company="${row.company}"`,
@ -247,7 +249,7 @@ async function main() {
} }
if (employeesToCreate.length === 0) { if (employeesToCreate.length === 0) {
console.warn('⚠️ Aucun Employees à créer, arrêt.'); console.warn(' Aucun Employees à créer, arrêt.');
return; return;
} }
@ -257,12 +259,12 @@ async function main() {
skipDuplicates: true, // évite les erreurs si tu relances le script skipDuplicates: true, // évite les erreurs si tu relances le script
}); });
console.log(` ${result.count} employees insérés dans la DB`); console.log(` ${result.count} employees insérés dans la DB`);
} }
main() main()
.catch((err) => { .catch((err) => {
console.error(' Erreur pendant limport CSV → Employees', err); console.error(' Erreur pendant limport CSV → Employees', err);
process.exit(1); process.exit(1);
}) })
.finally(async () => { .finally(async () => {

View File

@ -1,106 +1,106 @@
// // src/scripts/import-users-from-csv.ts // src/scripts/import-users-from-csv.ts
// import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
// import * as fs from 'fs'; import * as fs from 'fs';
// import * as path from 'path'; import * as path from 'path';
// const prisma = new PrismaClient(); const prisma = new PrismaClient();
// // ⚙️ Chemin vers ton CSV (à adapter selon où tu le mets) // ⚙️ Chemin vers ton CSV (à adapter selon où tu le mets)
// const CSV_PATH = path.resolve(__dirname, 'data/export_employee_table.csv'); const CSV_PATH = path.resolve(__dirname, 'data/export_employee_table.csv');
// // Type aligné sur les colonnes du CSV // Type aligné sur les colonnes du CSV
// type CsvUserRow = { type CsvUserRow = {
// email: string; email: string;
// first_name: string; first_name: string;
// last_name: string; last_name: string;
// phone_number: string; phone_number: string;
// }; };
// // Petit parseur de ligne CSV sans dépendance // Petit parseur de ligne CSV sans dépendance
// function splitCsvLine(line: string): string[] { function splitCsvLine(line: string): string[] {
// const result: string[] = []; const result: string[] = [];
// let current = ''; let current = '';
// let inQuotes = false; let inQuotes = false;
// for (let i = 0; i < line.length; i++) { for (let i = 0; i < line.length; i++) {
// const char = line[i]; const char = line[i];
// if (char === '"') { if (char === '"') {
// // guillemet échappé "" // guillemet échappé ""
// if (inQuotes && line[i + 1] === '"') { if (inQuotes && line[i + 1] === '"') {
// current += '"'; current += '"';
// i++; // on saute le deuxième i++; // on saute le deuxième
// } else { } else {
// inQuotes = !inQuotes; inQuotes = !inQuotes;
// } }
// } else if (char === ',' && !inQuotes) { } else if (char === ',' && !inQuotes) {
// result.push(current); result.push(current);
// current = ''; current = '';
// } else { } else {
// current += char; current += char;
// } }
// } }
// result.push(current); result.push(current);
// return result.map((v) => v.trim()); return result.map((v) => v.trim());
// } }
// async function main() { async function main() {
// // 1. Lecture du fichier CSV // 1. Lecture du fichier CSV
// const fileContent = fs.readFileSync(CSV_PATH, 'utf-8'); const fileContent = fs.readFileSync(CSV_PATH, 'utf-8');
// const lines = fileContent const lines = fileContent
// .split(/\r?\n/) .split(/\r?\n/)
// .map((l) => l.trim()) .map((l) => l.trim())
// .filter((l) => l.length > 0); .filter((l) => l.length > 0);
// if (lines.length <= 1) { if (lines.length <= 1) {
// console.error('CSV vide ou seulement un header'); console.error('CSV vide ou seulement un header');
// return; return;
// } }
// // 2. Header (noms de colonnes) -> ["email", "first_name", "last_name", "phone_number"] // 2. Header (noms de colonnes) -> ["email", "first_name", "last_name", "phone_number"]
// const header = splitCsvLine(lines[0]); const header = splitCsvLine(lines[0]);
// const dataLines = lines.slice(1); const dataLines = lines.slice(1);
// // 3. Conversion de chaque ligne en objet { email, first_name, last_name, phone_number } // 3. Conversion de chaque ligne en objet { email, first_name, last_name, phone_number }
// const records: CsvUserRow[] = dataLines.map((line) => { const records: CsvUserRow[] = dataLines.map((line) => {
// const values = splitCsvLine(line); const values = splitCsvLine(line);
// const row: any = {}; const row: any = {};
// header.forEach((col, idx) => { header.forEach((col, idx) => {
// row[col] = values[idx] ?? ''; row[col] = values[idx] ?? '';
// }); });
// return row as CsvUserRow; return row as CsvUserRow;
// }); });
// // 4. Mapping vers le format attendu par Prisma (model Users) // 4. Mapping vers le format attendu par Prisma (model Users)
// const data = records.map((row) => ({ const data = records.map((row) => ({
// email: row.email.trim(), email: row.email.trim(),
// first_name: row.first_name.trim(), first_name: row.first_name.trim(),
// last_name: row.last_name.trim(), last_name: row.last_name.trim(),
// phone_number: row.phone_number.trim(), phone_number: row.phone_number.trim(),
// // residence: null, // si tu veux la forcer à null // residence: null,
// // role: 'GUEST', // sinon Prisma va appliquer la valeur par défaut // role: 'EMPLOYEE',
// })); }));
// console.log(`➡️ ${data.length} lignes trouvées dans le CSV`); console.log(`➡️ ${data.length} lignes trouvées dans le CSV`);
// console.log('Exemple importé :', data[0]); console.log('Exemple importé :', data[0]);
// const result = await prisma.users.createMany({ const result = await prisma.users.createMany({
// data, data,
// }); });
// console.log(`✅ ${result.count} utilisateurs insérés dans la DB`); console.log(`${result.count} utilisateurs insérés dans la DB`);
// } }
// main() main()
// .catch((err) => { .catch((err) => {
// console.error('❌ Erreur pendant limport CSV → DB', err); console.error('Erreur pendant limport CSV → DB', err);
// process.exit(1); process.exit(1);
// }) })
// .finally(async () => { .finally(async () => {
// await prisma.$disconnect(); await prisma.$disconnect();
// }); });

View File

@ -1,165 +1,165 @@
// import { PrismaClient as Prisma } from "@prisma/client"; import { PrismaClient as Prisma } from "@prisma/client";
// import { PrismaClient as PrismaLegacy } from "@prisma/client-legacy" import { PrismaClient as PrismaLegacy } from "@prisma/client-legacy"
// import { toDateFromString, toHHmmFromDate, toStringFromDate } from "src/common/utils/date-utils"; import { toDateFromString, toHHmmFromDate, toStringFromDate } from "src/common/utils/date-utils";
// const prisma_legacy = new PrismaLegacy({}); const prisma_legacy = new PrismaLegacy({});
// const prisma = new Prisma({}); const prisma = new Prisma({});
// type NewEmployee = { type NewEmployee = {
// id: number; id: number;
// company_code: number; company_code: number;
// external_payroll_id: number; external_payroll_id: number;
// } }
// type OldExpense = { type OldExpense = {
// time_sheet_id: string | null; time_sheet_id: string | null;
// date: string | null; date: string | null;
// code: string | null; code: string | null;
// description: string | null; description: string | null;
// value: number | null; value: number | null;
// status: boolean | null; status: boolean | null;
// } }
// export const extractOldExpenses = async () => { export const extractOldExpenses = async () => {
// for (let id = 1; id <= 61; id++) { for (let id = 1; id <= 61; id++) {
// console.log(`Start of Expense migration ***************************************************************`); console.log(`Start of Expense migration ***************************************************************`);
// const new_employee = await findOneNewEmployee(id); const new_employee = await findOneNewEmployee(id);
// console.log(`Employee ${id} found in new DB`); console.log(`Employee ${id} found in new DB`);
// const new_timesheets = await findManyNewTimesheets(new_employee.id); const new_timesheets = await findManyNewTimesheets(new_employee.id);
// console.log(`New Timesheets found for employee ${id}`); console.log(`New Timesheets found for employee ${id}`);
// const old_employee_id = await findOneOldEmployee(new_employee); const old_employee_id = await findOneOldEmployee(new_employee);
// console.log(`Employee ${new_employee.id} found in old DB`); console.log(`Employee ${new_employee.id} found in old DB`);
// const old_timesheets = await findManyOldTimesheets(old_employee_id); const old_timesheets = await findManyOldTimesheets(old_employee_id);
// console.log(`Timesheets for employee ${old_employee_id}/${new_employee.id} found in old DB`); console.log(`Timesheets for employee ${old_employee_id}/${new_employee.id} found in old DB`);
// console.log('Start of Expense creation*****************************************************************'); console.log('Start of Expense creation*****************************************************************');
// for (const old_timesheet of old_timesheets) { for (const old_timesheet of old_timesheets) {
// if (!old_timesheet.start_date) continue; if (!old_timesheet.start_date) continue;
// const new_timesheet = new_timesheets.find((ts) => ts.start_date.getTime() === old_timesheet.start_date!.getTime()); const new_timesheet = new_timesheets.find((ts) => ts.start_date.getTime() === old_timesheet.start_date!.getTime());
// if (!new_timesheet) { if (!new_timesheet) {
// console.warn(`No new timesheet matching legacy timesheet ${old_timesheet.id}`); console.warn(`No new timesheet matching legacy timesheet ${old_timesheet.id}`);
// continue; continue;
// } }
// const old_expenses = await prisma_legacy.expenses.findMany({ const old_expenses = await prisma_legacy.expenses.findMany({
// where: { time_sheet_id: old_timesheet.id }, where: { time_sheet_id: old_timesheet.id },
// select: { select: {
// time_sheet_id: true, time_sheet_id: true,
// date: true, date: true,
// code: true, code: true,
// description: true, description: true,
// value: true, value: true,
// status: true, status: true,
// }, },
// }); });
// await createManyNewExpenses(new_timesheet.id, old_expenses); await createManyNewExpenses(new_timesheet.id, old_expenses);
// } }
// } }
// await prisma_legacy.$disconnect(); await prisma_legacy.$disconnect();
// await prisma.$disconnect(); await prisma.$disconnect();
// } }
// const findOneNewEmployee = async (id: number): Promise<NewEmployee> => { const findOneNewEmployee = async (id: number): Promise<NewEmployee> => {
// const new_employee = await prisma.employees.findUnique({ const new_employee = await prisma.employees.findUnique({
// where: { id: id }, where: { id: id },
// select: { select: {
// id: true, id: true,
// company_code: true, company_code: true,
// external_payroll_id: true, external_payroll_id: true,
// }, },
// }); });
// if (!new_employee) throw new Error(`New Employee with id ${id} not found`) if (!new_employee) throw new Error(`New Employee with id ${id} not found`)
// return new_employee; return new_employee;
// } }
// const findOneOldEmployee = async (new_employee: NewEmployee): Promise<string> => { const findOneOldEmployee = async (new_employee: NewEmployee): Promise<string> => {
// const old_employee = await prisma_legacy.employees.findFirst({ const old_employee = await prisma_legacy.employees.findFirst({
// where: { where: {
// company: new_employee.company_code, company: new_employee.company_code,
// employee_number: new_employee.external_payroll_id.toString(), employee_number: new_employee.external_payroll_id.toString(),
// }, },
// select: { select: {
// id: true, id: true,
// }, },
// }); });
// if (!old_employee) throw new Error(`Old Employee not found`); if (!old_employee) throw new Error(`Old Employee not found`);
// return old_employee.id; return old_employee.id;
// } }
// const findManyOldTimesheets = async (old_employee_id: string) => { const findManyOldTimesheets = async (old_employee_id: string) => {
// const old_timesheets = await prisma_legacy.time_sheets.findMany({ const old_timesheets = await prisma_legacy.time_sheets.findMany({
// where: { employee_id: old_employee_id }, where: { employee_id: old_employee_id },
// select: { id: true, start_date: true, status: true } select: { id: true, start_date: true, status: true }
// }); });
// return old_timesheets; return old_timesheets;
// } }
// const findManyNewTimesheets = async (employee_id: number) => { const findManyNewTimesheets = async (employee_id: number) => {
// const timesheets = await prisma.timesheets.findMany({ const timesheets = await prisma.timesheets.findMany({
// where: { employee_id: employee_id }, where: { employee_id: employee_id },
// select: { id: true, start_date: true } select: { id: true, start_date: true }
// }) })
// return timesheets; return timesheets;
// } }
// const createManyNewExpenses = async (timesheet_id: number, old_expenses: OldExpense[]) => { const createManyNewExpenses = async (timesheet_id: number, old_expenses: OldExpense[]) => {
// for (const old_expense of old_expenses) { for (const old_expense of old_expenses) {
// let mileage: number = 0; let mileage: number = 0;
// let amount: number = old_expense.value ?? 0; let amount: number = old_expense.value ?? 0;
// if (old_expense.code === 'G503') { if (old_expense.code === 'G503') {
// mileage = old_expense.value!; mileage = old_expense.value!;
// amount = mileage * 0.72; amount = mileage * 0.72;
// } }
// if (mileage < 0 || amount < 0) { if (mileage < 0 || amount < 0) {
// console.warn(`expense of value less than '0' found`) console.warn(`expense of value less than '0' found`)
// continue; continue;
// } }
// if (old_expense.date == null) { if (old_expense.date == null) {
// console.warn(`Expense date invalid ${old_expense.date}`); console.warn(`Expense date invalid ${old_expense.date}`);
// continue; continue;
// } }
// const date = toDateFromString(old_expense.date); const date = toDateFromString(old_expense.date);
// if (old_expense.status == null) { if (old_expense.status == null) {
// console.warn(`status null for legacy expense ${old_expense}`); console.warn(`status null for legacy expense ${old_expense}`);
// continue; continue;
// } }
// if (old_expense.code == null) { if (old_expense.code == null) {
// console.warn(`Code null for legacy expense ${old_expense.code}`); console.warn(`Code null for legacy expense ${old_expense.code}`);
// continue; continue;
// } }
// const bank_code_id = await findBankCodeIdUsingOldCode(old_expense.code); const bank_code_id = await findBankCodeIdUsingOldCode(old_expense.code);
// await prisma.expenses.upsert({ await prisma.expenses.upsert({
// where: { unique_ts_id_date_amount_mileage: { timesheet_id: timesheet_id, date, amount, mileage } }, where: { unique_ts_id_date_amount_mileage: { timesheet_id: timesheet_id, date, amount, mileage } },
// update: { update: {
// is_approved: old_expense.status, is_approved: old_expense.status,
// }, },
// create: { create: {
// date: date, date: date,
// comment: old_expense.description ?? '', comment: old_expense.description ?? '',
// timesheet_id: timesheet_id, timesheet_id: timesheet_id,
// bank_code_id: bank_code_id, bank_code_id: bank_code_id,
// amount: amount, amount: amount,
// mileage: mileage, mileage: mileage,
// } }
// }); });
// } }
// } }
// const findBankCodeIdUsingOldCode = async (code: string): Promise<number> => { const findBankCodeIdUsingOldCode = async (code: string): Promise<number> => {
// const bank_code = await prisma.bankCodes.findFirst({ const bank_code = await prisma.bankCodes.findFirst({
// where: { bank_code: code }, where: { bank_code: code },
// select: { id: true }, select: { id: true },
// }); });
// if (!bank_code) throw new Error(`Bank_code_id not found for Code ${code}`) if (!bank_code) throw new Error(`Bank_code_id not found for Code ${code}`)
// return bank_code.id; return bank_code.id;
// } }

View File

@ -1,210 +1,210 @@
// import { PrismaClient as PrismaNew } from "@prisma/client"; import { PrismaClient as PrismaNew } from "@prisma/client";
// import { PrismaClient as PrismaLegacy } from "@prisma/client-legacy" import { PrismaClient as PrismaLegacy } from "@prisma/client-legacy"
// const prisma_legacy = new PrismaLegacy({}); const prisma_legacy = new PrismaLegacy({});
// const prisma = new PrismaNew({}); const prisma = new PrismaNew({});
// type NewEmployee = { type NewEmployee = {
// id: number; id: number;
// company_code: number; company_code: number;
// external_payroll_id: number; external_payroll_id: number;
// } }
// type OldShifts = { type OldShifts = {
// time_sheet_id: string | null; time_sheet_id: string | null;
// code: string | null; code: string | null;
// type: string | null; type: string | null;
// date: Date | null; date: Date | null;
// start_time: bigint | null; start_time: bigint | null;
// end_time: bigint | null; end_time: bigint | null;
// comment: string | null; comment: string | null;
// status: boolean | null; status: boolean | null;
// } }
// export const extractOldShifts = async () => { export const extractOldShifts = async () => {
// for (let id = 1; id <= 61; id++) { for (let id = 1; id <= 61; id++) {
// console.log(`Start of shift migration ***************************************************************`); console.log(`Start of shift migration ***************************************************************`);
// const new_employee = await findOneNewEmployee(id); const new_employee = await findOneNewEmployee(id);
// console.log(`Employee ${id} found in new DB`); console.log(`Employee ${id} found in new DB`);
// const new_timesheets = await findManyNewTimesheets(new_employee.id); const new_timesheets = await findManyNewTimesheets(new_employee.id);
// console.log(`New Timesheets found for employee ${id}`); console.log(`New Timesheets found for employee ${id}`);
// for (const ts of new_timesheets) { for (const ts of new_timesheets) {
// console.log(`start_date = ${ts.start_date} timesheet_id = ${ts.id}`) console.log(`start_date = ${ts.start_date} timesheet_id = ${ts.id}`)
// } }
// console.log('***************************************************************'); console.log('***************************************************************');
// const old_employee_id = await findOneOldEmployee(new_employee); const old_employee_id = await findOneOldEmployee(new_employee);
// console.log(`Employee ${new_employee.id} found in old DB`); console.log(`Employee ${new_employee.id} found in old DB`);
// const old_timesheets = await findManyOldTimesheets(old_employee_id); const old_timesheets = await findManyOldTimesheets(old_employee_id);
// console.log(`Timesheets for employee ${old_employee_id}/${new_employee.id} found in old DB`); console.log(`Timesheets for employee ${old_employee_id}/${new_employee.id} found in old DB`);
// for (const old_timesheet of old_timesheets) { for (const old_timesheet of old_timesheets) {
// if (!old_timesheet.start_date) continue; if (!old_timesheet.start_date) continue;
// const new_timesheet = new_timesheets.find((ts) => ts.start_date.getTime() === old_timesheet.start_date!.getTime()); const new_timesheet = new_timesheets.find((ts) => ts.start_date.getTime() === old_timesheet.start_date!.getTime());
// if (!new_timesheet) { if (!new_timesheet) {
// console.warn(`No new timesheet ${new_timesheet} matching legacy timesheet ${old_timesheet.id}`); console.warn(`No new timesheet ${new_timesheet} matching legacy timesheet ${old_timesheet.id}`);
// continue; continue;
// } }
// const old_shifts = await prisma_legacy.shifts.findMany({ const old_shifts = await prisma_legacy.shifts.findMany({
// where: { time_sheet_id: old_timesheet.id }, where: { time_sheet_id: old_timesheet.id },
// select: { select: {
// time_sheet_id: true, time_sheet_id: true,
// code: true, code: true,
// type: true, type: true,
// date: true, date: true,
// start_time: true, start_time: true,
// end_time: true, end_time: true,
// comment: true, comment: true,
// status: true, status: true,
// }, },
// }); });
// await createManyNewShifts(new_timesheet.id, old_shifts); await createManyNewShifts(new_timesheet.id, old_shifts);
// } }
// } }
// await prisma_legacy.$disconnect(); await prisma_legacy.$disconnect();
// await prisma.$disconnect(); await prisma.$disconnect();
// } }
// const findOneNewEmployee = async (id: number): Promise<NewEmployee> => { const findOneNewEmployee = async (id: number): Promise<NewEmployee> => {
// const new_employee = await prisma.employees.findUnique({ const new_employee = await prisma.employees.findUnique({
// where: { id: id }, where: { id: id },
// select: { select: {
// id: true, id: true,
// company_code: true, company_code: true,
// external_payroll_id: true, external_payroll_id: true,
// }, },
// }); });
// if (!new_employee) throw new Error(`New Employee with id ${id} not found`) if (!new_employee) throw new Error(`New Employee with id ${id} not found`)
// return new_employee; return new_employee;
// } }
// const findOneOldEmployee = async (new_employee: NewEmployee): Promise<string> => { const findOneOldEmployee = async (new_employee: NewEmployee): Promise<string> => {
// const old_employee = await prisma_legacy.employees.findFirst({ const old_employee = await prisma_legacy.employees.findFirst({
// where: { where: {
// company: new_employee.company_code, company: new_employee.company_code,
// employee_number: new_employee.external_payroll_id.toString(), employee_number: new_employee.external_payroll_id.toString(),
// }, },
// select: { select: {
// id: true, id: true,
// }, },
// }); });
// if (!old_employee) throw new Error(`Old Employee not found`); if (!old_employee) throw new Error(`Old Employee not found`);
// return old_employee.id; return old_employee.id;
// } }
// const findManyOldTimesheets = async (old_employee_id: string) => { const findManyOldTimesheets = async (old_employee_id: string) => {
// const old_timesheets = await prisma_legacy.time_sheets.findMany({ const old_timesheets = await prisma_legacy.time_sheets.findMany({
// where: { employee_id: old_employee_id }, where: { employee_id: old_employee_id },
// select: { id: true, start_date: true, status: true } select: { id: true, start_date: true, status: true }
// }); });
// return old_timesheets; return old_timesheets;
// } }
// const findManyNewTimesheets = async (employee_id: number) => { const findManyNewTimesheets = async (employee_id: number) => {
// const timesheets = await prisma.timesheets.findMany({ const timesheets = await prisma.timesheets.findMany({
// where: { employee_id: employee_id }, where: { employee_id: employee_id },
// select: { id: true, start_date: true } select: { id: true, start_date: true }
// }) })
// return timesheets; return timesheets;
// } }
// const createManyNewShifts = async (timesheet_id: number, old_shifts: OldShifts[]) => { const createManyNewShifts = async (timesheet_id: number, old_shifts: OldShifts[]) => {
// for (const old_shift of old_shifts) { for (const old_shift of old_shifts) {
// let is_remote = true; let is_remote = true;
// const start = toHHmmfromLegacyTimestamp(old_shift.start_time); const start = toHHmmfromLegacyTimestamp(old_shift.start_time);
// if (old_shift.start_time == null || !start) { if (old_shift.start_time == null || !start) {
// console.warn(`Shift start invalid ${old_shift.start_time}`); console.warn(`Shift start invalid ${old_shift.start_time}`);
// continue; continue;
// } }
// const end = toHHmmfromLegacyTimestamp(old_shift.end_time); const end = toHHmmfromLegacyTimestamp(old_shift.end_time);
// if (old_shift.end_time == null || !end) { if (old_shift.end_time == null || !end) {
// console.warn(`Shift end invalid ${old_shift.end_time}`); console.warn(`Shift end invalid ${old_shift.end_time}`);
// continue; continue;
// } }
// if (old_shift.date == null) { if (old_shift.date == null) {
// console.warn(`Shift date invalid ${old_shift.date}`); console.warn(`Shift date invalid ${old_shift.date}`);
// continue; continue;
// } }
// if (old_shift.status == null) { if (old_shift.status == null) {
// console.warn(`status null for legacy shift ${old_shift}`); console.warn(`status null for legacy shift ${old_shift}`);
// continue; continue;
// } }
// if (old_shift.type == null) { if (old_shift.type == null) {
// console.warn(`type null for legacy shift ${old_shift.type}`); console.warn(`type null for legacy shift ${old_shift.type}`);
// continue; continue;
// } }
// if (old_shift.type === 'office') { if (old_shift.type === 'office') {
// is_remote = false; is_remote = false;
// } }
// if (old_shift.code == null) { if (old_shift.code == null) {
// console.warn(`Code null for legacy shift ${old_shift.code}`); console.warn(`Code null for legacy shift ${old_shift.code}`);
// continue; continue;
// } }
// const bank_code_id = await findBankCodeIdUsingOldCode(old_shift.code); const bank_code_id = await findBankCodeIdUsingOldCode(old_shift.code);
// try { try {
// await prisma.shifts.create({ await prisma.shifts.create({
// // where: { unique_ts_id_date_start_time: { // where: { unique_ts_id_date_start_time: {
// // timesheet_id, // timesheet_id,
// // date: old_shift.date, // date: old_shift.date,
// // start_time: toDateFromHHmm(start) }}, // start_time: toDateFromHHmm(start) }},
// // update: { // update: {
// // start_time: toDateFromHHmm(start), // start_time: toDateFromHHmm(start),
// // end_time: toDateFromHHmm(end), // end_time: toDateFromHHmm(end),
// // comment: old_shift.comment, // comment: old_shift.comment,
// // is_approved: old_shift.status, // is_approved: old_shift.status,
// // is_remote: is_remote, // is_remote: is_remote,
// // bank_code_id: bank_code_id, // bank_code_id: bank_code_id,
// // }, // },
// data: { data: {
// date: old_shift.date, date: old_shift.date,
// start_time: toDateFromHHmm(start), start_time: toDateFromHHmm(start),
// end_time: toDateFromHHmm(end), end_time: toDateFromHHmm(end),
// comment: old_shift.comment, comment: old_shift.comment,
// is_approved: old_shift.status, is_approved: old_shift.status,
// is_remote: is_remote, is_remote: is_remote,
// timesheet_id: timesheet_id, timesheet_id: timesheet_id,
// bank_code_id: bank_code_id, bank_code_id: bank_code_id,
// }, },
// }); });
// } catch (error) { } catch (error) {
// console.log('An error occured during shifts creation'); console.log('An error occured during shifts creation');
// } }
// } }
// } }
// const toHHmmfromLegacyTimestamp = (value: bigint | null): string | null => { const toHHmmfromLegacyTimestamp = (value: bigint | null): string | null => {
// if (value == null) return null; if (value == null) return null;
// const date = new Date(Number(value)); const date = new Date(Number(value));
// const hh = String(date.getHours()).padStart(2, '0'); const hh = String(date.getHours()).padStart(2, '0');
// const mm = String(date.getMinutes()).padStart(2, '0'); const mm = String(date.getMinutes()).padStart(2, '0');
// return `${hh}:${mm}`; return `${hh}:${mm}`;
// } }
// const toDateFromHHmm = (hhmm: string): Date => { const toDateFromHHmm = (hhmm: string): Date => {
// const [hh, mm] = hhmm.split(':'); const [hh, mm] = hhmm.split(':');
// const hours = Number(hh); const hours = Number(hh);
// const minutes = Number(mm); const minutes = Number(mm);
// return new Date(Date.UTC(1970, 0, 1, hours, minutes, 0, 0)); return new Date(Date.UTC(1970, 0, 1, hours, minutes, 0, 0));
// } }
// const findBankCodeIdUsingOldCode = async (code: string): Promise<number> => { const findBankCodeIdUsingOldCode = async (code: string): Promise<number> => {
// if (code === 'G700') { if (code === 'G700') {
// code = 'G104'; code = 'G104';
// } else if (code === 'G140') { } else if (code === 'G140') {
// code = 'G56' code = 'G56'
// } }
// const bank_code = await prisma.bankCodes.findFirst({ const bank_code = await prisma.bankCodes.findFirst({
// where: { bank_code: code }, where: { bank_code: code },
// select: { id: true, bank_code: true }, select: { id: true, bank_code: true },
// }); });
// if (!bank_code) throw new Error(`Bank_code_id not found for Code ${code}`) if (!bank_code) throw new Error(`Bank_code_id not found for Code ${code}`)
// return bank_code.id; return bank_code.id;
// } }

View File

@ -1,118 +1,117 @@
// import { PrismaClient as Prisma } from "@prisma/client"; import { PrismaClient as Prisma } from "@prisma/client";
// import { PrismaClient as PrismaLegacy } from "@prisma/client-legacy" import { PrismaClient as PrismaLegacy } from "@prisma/client-legacy"
// import { toStringFromDate } from "src/common/utils/date-utils"; import { toStringFromDate } from "src/common/utils/date-utils";
type NewEmployee = {
id: number;
company_code: number;
external_payroll_id: number;
}
// type NewEmployee = { type OldTimesheets = {
// id: number; id: string;
// company_code: number; start_date: Date | null;
// external_payroll_id: number; status: boolean | null;
// } }
// type OldTimesheets = { const prisma_legacy = new PrismaLegacy({});
// id: string; const prisma_new = new Prisma({});
// start_date: Date | null;
// status: boolean | null;
// }
// const prisma_legacy = new PrismaLegacy({}); export const extractOldTimesheets = async () => {
// const prisma_new = new Prisma({}); for (let id = 1; id <= 61; id++) {
const new_employee = await findOneNewEmployee(id);
console.log(`Employee ${id} found in new DB ${new_employee.external_payroll_id}`);
// export const extractOldTimesheets = async () => { const old_employee_id = await findOneOldEmployee(new_employee);
// for (let id = 1; id <= 61; id++) { console.log(`Employee ${new_employee.id} found in old DB`);
// const new_employee = await findOneNewEmployee(id);
// console.log(`Employee ${id} found in new DB ${new_employee.external_payroll_id}`);
// const old_employee_id = await findOneOldEmployee(new_employee); const old_timesheets = await findManyOldTimesheets(old_employee_id);
// console.log(`Employee ${new_employee.id} found in old DB`); console.log(` ${old_timesheets.length} Timesheets for employee ${old_employee_id} / ${new_employee.id} found in old DB`);
// const old_timesheets = await findManyOldTimesheets(old_employee_id); await createManyNewTimesheets(old_timesheets, new_employee);
// console.log(` ${old_timesheets.length} Timesheets for employee ${old_employee_id}/${new_employee.id} found in old DB`); console.log(`${old_timesheets.length} New Timesheets created in new DB for employee ${new_employee.id}`);
}
await prisma_legacy.$disconnect();
await prisma_new.$disconnect();
}
// await createManyNewTimesheets(old_timesheets, new_employee); const findOneNewEmployee = async (id: number): Promise<NewEmployee> => {
// console.log(`${old_timesheets.length} New Timesheets created in new DB for employee ${new_employee.id}`); const new_employee = await prisma_new.employees.findUnique({
// } where: { id: id },
// await prisma_legacy.$disconnect(); select: {
// await prisma_new.$disconnect(); id: true,
// } company_code: true,
external_payroll_id: true,
},
});
if (!new_employee) throw new Error(`New Employee with id ${id} not found`)
return new_employee;
}
// const findOneNewEmployee = async (id: number): Promise<NewEmployee> => { const findOneOldEmployee = async (new_employee: NewEmployee): Promise<string> => {
// const new_employee = await prisma_new.employees.findUnique({ const employee_number = new_employee.external_payroll_id.toString()
// where: { id: id }, const old_employee = await prisma_legacy.employees.findFirst({
// select: { where: {
// id: true, company: new_employee.company_code,
// company_code: true, employee_number: employee_number,
// external_payroll_id: true, },
// }, select: {
// }); id: true,
// if (!new_employee) throw new Error(`New Employee with id ${id} not found`) },
// return new_employee; });
// } if (!old_employee) throw new Error(`Old Employee not found`);
return old_employee.id;
}
// const findOneOldEmployee = async (new_employee: NewEmployee): Promise<string> => { const findManyOldTimesheets = async (old_employee_id: string) => {
// const employee_number = new_employee.external_payroll_id.toString() const old_timesheets = await prisma_legacy.time_sheets.findMany({
// const old_employee = await prisma_legacy.employees.findFirst({ where: { employee_id: old_employee_id },
// where: { select: { id: true, start_date: true, status: true }
// company: new_employee.company_code, });
// employee_number: employee_number, if (!old_timesheets) throw new Error(`old Timesheets not found for employee_id ${old_employee_id}`)
// }, return old_timesheets;
// select: { }
// id: true,
// },
// });
// if (!old_employee) throw new Error(`Old Employee not found`);
// return old_employee.id;
// }
// const findManyOldTimesheets = async (old_employee_id: string) => { const createManyNewTimesheets = async (old_timesheets: OldTimesheets[], new_employee: NewEmployee) => {
// const old_timesheets = await prisma_legacy.time_sheets.findMany({ for (const timesheet of old_timesheets) {
// where: { employee_id: old_employee_id }, if (timesheet.start_date == null) {
// select: { id: true, start_date: true, status: true } console.warn(`start_date invalid for legacy timesheet ${timesheet.id}`);
// }); continue;
// if (!old_timesheets) throw new Error(`old Timesheets not found for employee_id ${old_employee_id}`) }
// return old_timesheets; if (timesheet.status == null) {
// } console.warn(`status null for legacy timesheet ${timesheet.id}`);
continue;
}
// const createManyNewTimesheets = async (old_timesheets: OldTimesheets[], new_employee: NewEmployee) => { try {
// for (const timesheet of old_timesheets) { const new_timesheet = await prisma_new.timesheets.upsert({
// if (timesheet.start_date == null) { where: { employee_id_start_date: { employee_id: new_employee.id, start_date: timesheet.start_date } },
// console.warn(`start_date invalid for legacy timesheet ${timesheet.id}`); update: {
// continue; is_approved: timesheet.status,
// } },
// if (timesheet.status == null) { create: {
// console.warn(`status null for legacy timesheet ${timesheet.id}`); employee_id: new_employee.id,
// continue; start_date: timesheet.start_date,
// } is_approved: timesheet.status,
},
});
if (!new_timesheet) throw new Error(
`Timesheet with start_date: ${toStringFromDate(timesheet.start_date!)} for employee ${new_employee.id} not created`
);
} catch (error) {
throw new Error('An error occured during timesheets creation');
}
}
}
// try { extractOldTimesheets()
// const new_timesheet = await prisma_new.timesheets.upsert({ .then(() => {
// where: { employee_id_start_date: { employee_id: new_employee.id, start_date: timesheet.start_date } }, console.log("Migration completed");
// update: { })
// is_approved: timesheet.status, .catch((error) => {
// }, console.error("Migration failed:", error);
// create: { })
// employee_id: new_employee.id, .finally(async () => {
// start_date: timesheet.start_date, await prisma_legacy.$disconnect();
// is_approved: timesheet.status, await prisma_new.$disconnect();
// }, });
// });
// if (!new_timesheet) throw new Error(
// `Timesheet with start_date: ${toStringFromDate(timesheet.start_date!)} for employee ${new_employee.id} not created`
// );
// } catch (error) {
// throw new Error('An error occured during timesheets creation');
// }
// }
// }
// extractOldTimesheets()
// .then(() => {
// console.log("Migration completed");
// })
// .catch((error) => {
// console.error("Migration failed:", error);
// })
// .finally(async () => {
// await prisma_legacy.$disconnect();
// await prisma_new.$disconnect();
// });

View File

@ -43,6 +43,7 @@ export class EmployeesCreateService {
external_payroll_id: dto.external_payroll_id, external_payroll_id: dto.external_payroll_id,
company_code: company_code, company_code: company_code,
job_title: dto.job_title, job_title: dto.job_title,
daily_expected_hours: 8,
first_work_day: first_work_day, first_work_day: first_work_day,
is_supervisor: dto.is_supervisor, is_supervisor: dto.is_supervisor,
supervisor_id: supervisor_id, supervisor_id: supervisor_id,

View File

@ -14,6 +14,7 @@ import * as session from 'express-session';
import * as passport from 'passport'; import * as passport from 'passport';
import { PrismaService } from 'src/prisma/prisma.service'; import { PrismaService } from 'src/prisma/prisma.service';
import { PrismaSessionStore } from '@quixo3/prisma-session-store'; import { PrismaSessionStore } from '@quixo3/prisma-session-store';
// import { initializePreferences } from 'scripts/init-preferences-access';
// import { extractOldShifts } from 'scripts/migrate-shifts'; // import { extractOldShifts } from 'scripts/migrate-shifts';
// import { extractOldTimesheets } from 'scripts/migrate-timesheets'; // import { extractOldTimesheets } from 'scripts/migrate-timesheets';
// import { extractOldExpenses } from 'scripts/migrate-expenses'; // import { extractOldExpenses } from 'scripts/migrate-expenses';
@ -95,5 +96,6 @@ async function bootstrap() {
// await extractOldTimesheets(); // await extractOldTimesheets();
// await extractOldShifts(); // await extractOldShifts();
// await extractOldExpenses(); // await extractOldExpenses();
// await initializePreferences();
} }
bootstrap(); bootstrap();