fix(timesheets): fix backend return to send an array of expenses with total mileage and total expense

This commit is contained in:
Matthieu Haineault 2025-10-07 12:00:52 -04:00
parent 4d905c905e
commit a750f79107
5 changed files with 43 additions and 47 deletions

View File

@ -8,6 +8,7 @@ const WEEK_IN_MS = 7 * 24 * 60 * 60 * 1000;
le calcul est 1/20 des 4 dernières semaines, précédent la semaine incluant le férier.
Un maximum de 08h00 est allouable pour le férier
Un maximum de 40hrs par semaine est retenue pour faire le calcul.
le bank-code à soumettre à Desjardins doit être le G104
*/
@Injectable()

View File

@ -13,8 +13,6 @@ export class ExpenseDto {
amount: number;
mileage: number;
comment: string;
total_mileage: number;
total_expense: number;
is_approved: boolean;
supervisor_comment: string;
}
@ -33,10 +31,9 @@ export class DetailedShifts {
}
export class DayExpensesDto {
expense: ExpenseDto[] = [];
mileage: ExpenseDto[] = [];
per_diem: ExpenseDto[] = [];
on_call: ExpenseDto[] = [];
expenses: ExpenseDto[];
total_mileage: number;
total_expense: number;
}
export class WeekDto {

View File

@ -5,10 +5,9 @@ import { addDays, shortDate } from "../utils/timesheet.helpers";
// Factories
export function makeEmptyDayExpenses(): DayExpensesDto {
return {
expense: [],
mileage: [],
per_diem: [],
on_call: [],
expenses: [],
total_expense: -1,
total_mileage: -1,
};
}

View File

@ -43,10 +43,6 @@ export const EXPENSE_TYPES = {
export const DAY_KEYS = ['sun','mon','tue','wed','thu','fri','sat'] as const;
export type DayKey = typeof DAY_KEYS[number];
export const EXPENSE_BUCKETS = ['expense', 'mileage'] as const;
export type ExpenseBucketKey = typeof EXPENSE_BUCKETS[number];
//shifts's hour by type
export type ShiftsHours = {
regular: number;

View File

@ -1,6 +1,12 @@
import { DayKey, DAY_KEYS, EXPENSE_BUCKETS, EXPENSE_TYPES, ExpenseBucketKey, ExpenseRow, MS_PER_HOUR, SHIFT_TYPES, ShiftRow, make_hours, ShiftsHours, ExpensesAmount } from "../types/timesheet.types";
import { isBetweenUTC, dayKeyFromDate, toTimeString, round2, toUTCDateOnly, endOfDayUTC, addDays } from "./timesheet.helpers";
import { WeekDto, ShiftDto, ExpenseDto, TimesheetPeriodDto } from "../dtos/timesheet-period.dto";
import {
DayKey, DAY_KEYS, EXPENSE_TYPES, ExpenseRow, MS_PER_HOUR,
SHIFT_TYPES, ShiftRow, make_hours, ShiftsHours, ExpensesAmount
} from "../types/timesheet.types";
import {
isBetweenUTC, dayKeyFromDate, toTimeString, round2,
toUTCDateOnly, endOfDayUTC, addDays
} from "./timesheet.helpers";
import { WeekDto, ShiftDto, TimesheetPeriodDto, DayExpensesDto, ExpenseDto } from "../dtos/timesheet-period.dto";
import { makeAmounts, makeEmptyWeek } from "../mappers/timesheet.mappers";
import { toDateString } from "src/modules/pay-periods/utils/pay-year.util";
@ -25,13 +31,21 @@ export function buildWeek(
acc[key] = makeAmounts(); return acc;
}, {} as Record<DayKey, ExpensesAmount>);
const day_expense_rows: Record<DayKey, Record<ExpenseBucketKey, ExpenseRow[]>> = DAY_KEYS.reduce((acc, key) => {
const day_expense_rows: Record<DayKey, DayExpensesDto> = DAY_KEYS.reduce((acc, key) => {
acc[key] = {
expense: [],
mileage: [],
expenses: [{
type: '',
amount: -1,
mileage: -1,
comment: '',
is_approved: false,
supervisor_comment: '',
}],
total_expense: -1,
total_mileage: -1,
};
return acc;
}, {} as Record<DayKey, Record<ExpenseBucketKey, ExpenseRow[]>>);
}, {} as Record<DayKey, DayExpensesDto>);
//regroup hours per type of shifts
const week_shifts = shifts.filter(shift => isBetweenUTC(shift.date, week_start, week_end));
@ -69,18 +83,24 @@ export function buildWeek(
const key = dayKeyFromDate(expense.date, true);
const type = (expense.type || '').toUpperCase();
let bucket: ExpenseBucketKey;
const row: ExpenseDto = {
type,
amount: round2(expense.amount ?? 0),
mileage: round2(expense.mileage ?? 0),
comment: expense.comment ?? '',
is_approved: expense.is_approved ?? true,
supervisor_comment: expense.supervisor_comment ?? '',
};
day_expense_rows[key].expenses.push(row);
if(type === EXPENSE_TYPES.MILEAGE) {
bucket = 'mileage';
day_amounts[key].mileage += expense.mileage ?? 0;
day_amounts[key].mileage += row.mileage ?? 0;
} else {
bucket = 'expense';
day_amounts[key].expense += expense.amount;
day_amounts[key].expense += row.amount;
}
day_expense_rows[key][bucket].push(expense);
all_approved = all_approved && (expense.is_approved ?? true );
all_approved = all_approved && row.is_approved;
}
for (const key of DAY_KEYS) {
@ -101,26 +121,9 @@ export function buildWeek(
//daily totals
const totals = day_amounts[key];
const total_mileage = round2(totals.mileage);
const total_expense = round2(totals.expense);
const target_buckets = week.expenses[key] as Record<ExpenseBucketKey, ExpenseDto[]>;
const source_buckets = day_expense_rows[key];
for (const bucket of EXPENSE_BUCKETS) {
for (const row of source_buckets[bucket]) {
target_buckets[bucket].push({
type: (row.type || '').toUpperCase(),
amount: round2(row.amount),
mileage: round2(row.mileage ?? 0),
comment: row.comment,
is_approved: row.is_approved ?? true,
supervisor_comment: row.supervisor_comment,
total_mileage,
total_expense,
});
}
}
day_expense_rows[key].total_mileage = round2(totals.mileage);
day_expense_rows[key].total_expense = round2(totals.expense);
}
week.is_approved = all_approved;