fix(CSV): fix csv structure to match Desjardins

This commit is contained in:
Matthieu Haineault 2026-02-16 09:36:13 -05:00
parent a9637a93a6
commit ef969d3c42
3 changed files with 73 additions and 74 deletions

View File

@ -5,29 +5,34 @@ import { CsvRow, InternalCsvRow } from "src/time-and-attendance/exports/export-c
// You made a helper to pull bank codes from the db, but omitted to use it here... curious.
const REGULAR = 1;
const OVERTIME = 43;
const VACATION = 109;
export const consolidateRowHoursAndAmountByType = (rows: CsvRow[]): CsvRow[] => {
const map = new Map<string, CsvRow>();
export const consolidateRowHoursAndAmountByType = (rows: InternalCsvRow[]): InternalCsvRow[] => {
const map = new Map<string, InternalCsvRow>();
for (const row of rows) {
if (row.code = VACATION) {
map.set(`${row.code}|${row.shift_date}`, row);
} else {
const key = `${row.code}|${row.semaine_no}`;
if (!map.has(key)) {
map.set(key, { ...row });
map.set(key, row);
} else {
const existing = map.get(key)!;
existing.quantite_hre = (existing.quantite_hre ?? 0) + (row.quantite_hre ?? 0);
existing.montant = (existing.montant ?? 0) + (row.montant ?? 0);
}
}
}
return Array.from(map.values());
}
export const applyHolidayRequalifications = async (
rows: CsvRow[],
rows: InternalCsvRow[],
holiday_service: HolidayService,
holiday_bank_code: string,
): Promise<CsvRow[]> => {
const result: CsvRow[] = [];
): Promise<InternalCsvRow[]> => {
const result: InternalCsvRow[] = [];
const HOLIDAY_BANK_CODE = Number(holiday_bank_code.slice(1,));
for (const row of rows) {
@ -53,15 +58,15 @@ export const applyHolidayRequalifications = async (
}
export const applyOvertimeRequalifications = async (
consolidated_rows: CsvRow[],
consolidated_rows: InternalCsvRow[],
overtime_service: OvertimeService,
): Promise<CsvRow[]> => {
const result: CsvRow[] = [];
const result: InternalCsvRow[] = [];
//grouped by timesheet and week number
const grouped_rows = new Map<string, CsvRow[]>();
const grouped_rows = new Map<string, InternalCsvRow[]>();
for (const row of consolidated_rows) {
const key = `${row.compagnie_no}|${row.employee_matricule}|${row.semaine_no}`;
const key = `${row.timesheet_id}|${row.semaine_no}`;
if (!grouped_rows.has(key)) {
grouped_rows.set(key, []);
}
@ -104,8 +109,6 @@ export const applyOvertimeRequalifications = async (
quantite_hre: deducted,
});
}
// return consolidateRowHoursAndAmountByType(result);
return result;
}

View File

@ -65,7 +65,7 @@ export interface CsvRow {
dernier_jour_absence: string | undefined;
}
export type InternalCsvRow = CsvRow & { timesheet_id: number; shift_date: Date; email: string; }
export type InternalCsvRow = CsvRow & { timesheet_id: number; shift_date: Date; }
export type Filters = {

View File

@ -7,9 +7,6 @@ import { OvertimeService } from "src/time-and-attendance/domains/services/overti
import { HolidayService } from "src/time-and-attendance/domains/services/holiday.service";
import { select_csv_expense_lines, select_csv_shift_lines } from "src/time-and-attendance/utils/selects.utils";
import { BillableShiftType } from "src/time-and-attendance/shifts/shift.types";
import { Prisma } from "prisma/postgres/generated/prisma/client/postgres/client";
import { DefaultArgs } from "@prisma/client/runtime/client";
@Injectable()
export class CsvExportService {
@ -36,20 +33,16 @@ export class CsvExportService {
* @returns The desired filtered data in semi-colon-separated format, grouped and sorted by
* employee and by bank codes.
*/
async collectTransaction( year: number, period_no: number, filters: Filters ): Promise<CsvRow[]> {
const BILLABLE_SHIFT_TYPES: BillableShiftType[] = [
'REGULAR',
'EVENING',
'EMERGENCY',
'OVERTIME',
'SICK',
'HOLIDAY',
'VACATION',
];
async collectTransaction(year: number, period_no: number, filters: Filters): Promise<CsvRow[]> {
const BILLABLE_SHIFT_TYPES: BillableShiftType[] = [];
if (filters.types.shifts) BILLABLE_SHIFT_TYPES.push('REGULAR', 'OVERTIME', 'EMERGENCY', 'EVENING', 'SICK');
if (filters.types.holiday) BILLABLE_SHIFT_TYPES.push('HOLIDAY');
if (filters.types.vacation) BILLABLE_SHIFT_TYPES.push('VACATION');
const BILLABLE_SHIFT_CODES = await this.resolveShiftTypeCode(BILLABLE_SHIFT_TYPES);
const PTO_SHIFT_CODES = await this.resolveShiftTypeCode(['VACATION', 'SICK', 'HOLIDAY']);
const HOLIDAY_SHIFT_CODE = await this.resolveShiftTypeCode(['HOLIDAY'])[0];
const HOLIDAY_SHIFT_CODE = await this.resolveShiftTypeCode(['HOLIDAY']);
const period = await this.prisma.payPeriods.findFirst({
where: { pay_year: year, pay_period_no: period_no },
@ -76,16 +69,7 @@ export class CsvExportService {
select: select_csv_shift_lines,
});
const exportedExpenses = await this.prisma.expenses.findMany({
where: {
date: { gte: start, lte: end },
is_approved: true,
timesheet: { employee: { company_code: { in: company_codes } } },
},
select: select_csv_expense_lines,
});
const rows: CsvRow[] = exportedShifts.map(shift => {
const rows: InternalCsvRow[] = exportedShifts.map(shift => {
const employee = shift!.timesheet.employee;
const week = computeWeekNumber(start, shift!.date);
const type_transaction = shift!.bank_code.bank_code.charAt(0);
@ -93,6 +77,8 @@ export class CsvExportService {
const isPTO = PTO_SHIFT_CODES.includes(shift.bank_code.bank_code)
return {
timesheet_id: shift.timesheet.id,
shift_date: shift.date,
compagnie_no: employee.company_code,
employee_matricule: employee.external_payroll_id,
releve: 0,
@ -112,6 +98,16 @@ export class CsvExportService {
}
});
if (filters.types.expenses) {
const exportedExpenses = await this.prisma.expenses.findMany({
where: {
date: { gte: start, lte: end },
is_approved: true,
timesheet: { employee: { company_code: { in: company_codes } } },
},
select: select_csv_expense_lines,
});
exportedExpenses.map(expense => {
const employee = expense.timesheet.employee;
const type_transaction = expense!.bank_code.bank_code.charAt(0);
@ -119,6 +115,8 @@ export class CsvExportService {
const week = computeWeekNumber(start, expense.date);
rows.push({
timesheet_id: expense.timesheet.id,
shift_date: expense.date,
compagnie_no: employee.company_code,
employee_matricule: employee.external_payroll_id,
releve: 0,
@ -138,6 +136,8 @@ export class CsvExportService {
});
});
}
// Sort shifts and expenses according to their bank codes
rows.sort((a, b) => {
if (a.code !== b.code)
@ -146,11 +146,8 @@ export class CsvExportService {
return 0;
});
const holiday_rows = await applyHolidayRequalifications(rows, this.holiday_service, HOLIDAY_SHIFT_CODE);
const holiday_rows = await applyHolidayRequalifications(rows, this.holiday_service, HOLIDAY_SHIFT_CODE[0]);
const consolidated_rows = await consolidateRowHoursAndAmountByType(holiday_rows);
//requalifies regular hours into overtime when needed
const requalified_rows = await applyOvertimeRequalifications(consolidated_rows, this.overtime_service);
@ -173,7 +170,6 @@ export class CsvExportService {
const shiftCodes: string[] = [];
billableBankCodes.map(billableBankCode => shiftCodes.push(billableBankCode.bank_code));
return shiftCodes;
}