138 lines
5.5 KiB
TypeScript
138 lines
5.5 KiB
TypeScript
|
|
import { NUMBER_OF_TIMESHEETS_TO_RETURN } from "src/common/utils/constants.utils";
|
|
import { Injectable } from "@nestjs/common";
|
|
import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
|
|
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
|
|
import { Timesheets } from "src/time-and-attendance/timesheets/timesheet.dto";
|
|
import { Result } from "src/common/errors/result-error.factory";
|
|
import { toDateFromString } from "src/common/utils/date-utils";
|
|
import { mapOneTimesheet } from "src/time-and-attendance/timesheets/timesheet.mapper";
|
|
|
|
@Injectable()
|
|
export class GetTimesheetsOverviewService {
|
|
constructor(
|
|
private readonly prisma: PrismaPostgresService,
|
|
private readonly emailResolver: EmailToIdResolver,
|
|
) { }
|
|
|
|
async getTimesheetsForEmployeeByPeriod(
|
|
email: string,
|
|
pay_year: number,
|
|
pay_period_no: number,
|
|
employee_email?: string
|
|
): Promise<Result<Timesheets, string>> {
|
|
try {
|
|
const account_email = employee_email ?? email;
|
|
|
|
//find period using year and period_no
|
|
const period = await this.prisma.payPeriods.findFirst({ where: { pay_year, pay_period_no } });
|
|
if (!period) return { success: false, error: `PAY_PERIOD_NOT_FOUND` };
|
|
|
|
//fetch the employee_id using the email
|
|
const employee_id = await this.emailResolver.findIdByEmail(account_email);
|
|
if (!employee_id.success) return { success: false, error: employee_id.error }
|
|
|
|
//loads the timesheets related to the fetched pay-period
|
|
let rows = await this.loadTimesheets(employee_id.data, period.period_start, period.period_end);
|
|
|
|
//Normalized dates from pay-period strings
|
|
const normalized_start = toDateFromString(period.period_start);
|
|
const normalized_end = toDateFromString(period.period_end);
|
|
|
|
//creates empty timesheet to make sure to return desired amount of timesheet
|
|
for (let i = 0; i < NUMBER_OF_TIMESHEETS_TO_RETURN; i++) {
|
|
const week_start = new Date(normalized_start);
|
|
week_start.setUTCDate(week_start.getUTCDate() + i * 7);
|
|
|
|
if (week_start.getTime() > normalized_end.getTime()) break;
|
|
|
|
const has_existing_timesheets = rows.some(
|
|
(row) => toDateFromString(row.start_date).getTime() === week_start.getTime()
|
|
);
|
|
if (!has_existing_timesheets) await this.ensureTimesheet(employee_id.data, week_start);
|
|
}
|
|
rows = await this.loadTimesheets(employee_id.data, period.period_start, period.period_end);
|
|
|
|
//find user infos using the employee_id
|
|
const employee = await this.prisma.employees.findUnique({
|
|
where: { id: employee_id.data },
|
|
select: { daily_expected_hours: true, schedule_preset: true, user: true },
|
|
});
|
|
if (!employee) return { success: false, error: `EMPLOYEE_NOT_FOUND` }
|
|
|
|
//builds employee details
|
|
const has_preset_schedule = employee.schedule_preset !== null;
|
|
const user = employee.user;
|
|
const employee_fullname = `${user.first_name} ${user.last_name}`.trim();
|
|
|
|
|
|
//maps all timesheet's infos
|
|
const timesheets = await Promise.all(rows.map((timesheet) => mapOneTimesheet(timesheet)));
|
|
if (!timesheets) return { success: false, error: 'INVALID_TIMESHEET' }
|
|
|
|
const data: Timesheets = {
|
|
has_preset_schedule,
|
|
employee_fullname,
|
|
daily_expected_hours: employee.daily_expected_hours,
|
|
timesheets,
|
|
}
|
|
|
|
return { success: true, data };
|
|
} catch (error) {
|
|
console.error(error);
|
|
return { success: false, error: 'TIMESHEET_NOT_FOUND' }
|
|
}
|
|
}
|
|
|
|
private async loadTimesheets(
|
|
employee_id: number,
|
|
period_start: Date,
|
|
period_end: Date
|
|
) {
|
|
return this.prisma.timesheets.findMany({
|
|
where: { employee_id, start_date: { gte: period_start, lte: period_end } },
|
|
include: {
|
|
employee: { include: { user: true } },
|
|
shift: { include: { bank_code: true }, orderBy: { start_time: 'asc' } },
|
|
expense: { include: { bank_code: true }, orderBy: [{ date: 'asc' }, { bank_code_id: 'desc' }] },
|
|
},
|
|
orderBy: { start_date: 'asc' },
|
|
});
|
|
}
|
|
|
|
private ensureTimesheet = async (
|
|
employee_id: number,
|
|
start_date: Date | string
|
|
) => {
|
|
const start = toDateFromString(start_date);
|
|
|
|
let row = await this.prisma.timesheets.findFirst({
|
|
where: { employee_id, start_date: start },
|
|
include: {
|
|
employee: { include: { user: true } },
|
|
shift: { include: { bank_code: true } },
|
|
expense: { include: { bank_code: true } },
|
|
},
|
|
});
|
|
if (row) return row;
|
|
|
|
await this.prisma.timesheets.create({
|
|
data: {
|
|
employee_id,
|
|
start_date: start,
|
|
is_approved: false
|
|
},
|
|
});
|
|
|
|
row = await this.prisma.timesheets.findFirst({
|
|
where: { employee_id, start_date: start },
|
|
include: {
|
|
employee: { include: { user: true } },
|
|
shift: { include: { bank_code: true } },
|
|
expense: { include: { bank_code: true } },
|
|
},
|
|
});
|
|
return row!;
|
|
}
|
|
}
|