fix(pay-period, timesheet): fix issue where overtime wasn't calculated properly.

Also fix issue where employee overviews would sometimes falsely return as approved if employee had no timesheets created yet. This is due to Array.prototype.every returning true on an empty array.
This commit is contained in:
Nic D 2026-03-13 15:21:04 -04:00
parent aa68b5384b
commit 5f4fb3594a
2 changed files with 23 additions and 38 deletions

View File

@ -211,7 +211,9 @@ export class GetOverviewService {
cutoff_date.setDate(cutoff_date.getDate() + 14);
const is_active = employee.last_work_day ? employee.last_work_day.getTime() >= cutoff_date.getTime() : true;
record.is_approved = timesheets.every(timesheet => timesheet.is_approved === true);
if (timesheets.length > 0)
record.is_approved = timesheets.every(timesheet => timesheet.is_approved);
record.is_active = is_active;
}

View File

@ -73,53 +73,31 @@ export const mapOneTimesheet = (
const daily_hours = emptyHours();
const daily_expenses = emptyExpenses();
//totals by shift types
//daily totals by shift types
for (const shift of shifts_source) {
const hours = diffOfHours(shift.start_time, shift.end_time);
const subgroup = hoursSubGroupFromBankCode(shift.bank_code);
const worked_weekly_hours = weekly_hours.regular + weekly_hours.emergency + weekly_hours.banking + weekly_hours.evening + weekly_hours.overtime + weekly_hours.holiday;
if ((worked_weekly_hours + hours <= 40) && (subgroup === 'regular' || subgroup === 'evening')) {
daily_hours['overtime'] += Math.max(daily_hours[subgroup] + hours - 8, 0);
weekly_hours['overtime'] += Math.max(daily_hours[subgroup] + hours - 8, 0);
weekly_hours[subgroup] += Math.min(hours, 8 - daily_hours[subgroup]);
daily_hours[subgroup] += Math.min(hours, 8 - daily_hours[subgroup]);
} else if (subgroup === 'regular' || subgroup === 'evening') {
daily_hours[subgroup] += Math.max((40 - worked_weekly_hours), 0);
daily_hours['overtime'] += Math.min((worked_weekly_hours + hours) - 40, hours);
weekly_hours[subgroup] += Math.max((40 - worked_weekly_hours), 0);
weekly_hours['overtime'] += Math.min((worked_weekly_hours + hours) - 40, hours);
} else {
daily_hours[subgroup] += hours;
weekly_hours[subgroup] += hours;
}
}
// const dailyOvertimeOwed = Math.max(daily_hours.regular - timesheet.employee.daily_expected_hours, 0)
// daily_hours.overtime = dailyOvertimeOwed;
// daily_hours.regular -= dailyOvertimeOwed;
//totals by expense types
for (const expense of expenses_source) {
const subgroup = expenseSubgroupFromBankCode(expense.bank_code);
if (subgroup === 'mileage') {
const mileage = num(expense.mileage);
daily_expenses.mileage += mileage;
weekly_expenses.mileage += mileage;
} else if (subgroup === 'per_diem') {
const amount = num(expense.amount);
daily_expenses.per_diem += amount;
weekly_expenses.per_diem += amount;
} else if (subgroup === 'on_call') {
const amount = num(expense.amount);
daily_expenses.on_call += amount;
weekly_expenses.on_call += amount;
daily_expenses.mileage += Number(expense.mileage);
weekly_expenses.mileage += Number(expense.mileage);
} else {
const amount = num(expense.amount);
daily_expenses.expenses += amount;
weekly_expenses.expenses += amount;
daily_expenses.expenses[subgroup] += Number(expense.amount);
weekly_expenses.expenses[subgroup] += Number(expense.amount);
}
}
return {
date: date_iso,
shifts,
@ -129,6 +107,14 @@ export const mapOneTimesheet = (
};
});
const totalWeekHoursWorked = weekly_hours.regular +
weekly_hours.evening +
weekly_hours.emergency +
weekly_hours.holiday +
weekly_hours.vacation
weekly_hours.overtime = Math.max(totalWeekHoursWorked - 40, 0);
return {
timesheet_id: timesheet.id,
is_approved: timesheet.is_approved ?? false,
@ -149,9 +135,6 @@ const diffOfHours = (a: Date, b: Date): number => {
return Math.max(0, Math.round((ms / 36e5) * 1000) / 1000);
}
//validate numeric values
const num = (value: any): number => { return value ? Number(value) : 0 };
// shift's subgroup types
const hoursSubGroupFromBankCode = (bank_code: BankCodeDto): keyof TotalHours => {
const type = bank_code.type;