refactor(pay-periods): refactored bulkApprove for crew to instead toggle approval of all shifts and expenses of a given employee
This commit is contained in:
parent
447d968f59
commit
58baaade5d
|
|
@ -9,7 +9,7 @@ export function computeHours(start: Date, end: Date, roundToMinutes?: number): n
|
|||
const minutes = roundToMinutes ?
|
||||
Math.round(totalMinutes / roundToMinutes) * roundToMinutes :
|
||||
totalMinutes;
|
||||
return +(minutes / 60).toFixed(2);
|
||||
return +(minutes / 60);
|
||||
}
|
||||
|
||||
//round the amount of hours to quarter
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ export class AuthController {
|
|||
@Get('/callback')
|
||||
@UseGuards(OIDCLoginGuard)
|
||||
loginCallback(@Req() req: Request, @Res() res: Response) {
|
||||
res.redirect("http://10.100.251.2:9013/#/v1/login-success");
|
||||
// res.redirect(process.env.REDIRECT_URL_DEV!);
|
||||
// res.redirect("http://10.100.251.2:9013/#/v1/login-success");
|
||||
res.redirect(process.env.REDIRECT_URL_DEV!);
|
||||
}
|
||||
|
||||
@Get('/me')
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ export abstract class AbstractUserService {
|
|||
|
||||
let module_access: Modules[] = [];
|
||||
if (user.user_module_access !== null) module_access = toKeysFromBoolean(user.user_module_access);
|
||||
console.log('module access: ', module_access);
|
||||
|
||||
const clean_user = {
|
||||
first_name: user.first_name,
|
||||
|
|
|
|||
|
|
@ -43,16 +43,22 @@ export class PayPeriodsController {
|
|||
return this.queryService.findOneByYearPeriod(year, period_no);
|
||||
}
|
||||
|
||||
@Patch("crew/pay-period-approval")
|
||||
@Patch("pay-period-approval")
|
||||
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||
async bulkApproval(@Access('email') email:string, @Body() dto: BulkCrewApprovalDto) {
|
||||
if (!email) throw new UnauthorizedException(`Session infos not found`);
|
||||
return this.commandService.bulkApproveCrew(email, dto);
|
||||
async bulkApproval(
|
||||
@Body('email') email: string,
|
||||
@Body('timesheet_ids') timesheet_ids: number[],
|
||||
@Body('is_approved') is_approved: boolean,
|
||||
): Promise<Result<{ shifts: number, expenses: number }, string>> {
|
||||
if (!email) return {success: false, error: 'EMAIL_REQUIRED'};
|
||||
if (!timesheet_ids || timesheet_ids.length < 1) return {success: false, error: 'TIMESHEET_ID_REQUIRED'};
|
||||
if (!is_approved) return {success: false, error: 'APPROVAL_STATUS_REQUIRED'}
|
||||
return this.commandService.bulkApproveEmployee(email, timesheet_ids, is_approved);
|
||||
}
|
||||
|
||||
@Get('crew/:year/:periodNumber')
|
||||
@ModuleAccessAllowed(ModulesEnum.timesheets_approval)
|
||||
async getCrewOverview(@Access('email') email:string,
|
||||
async getCrewOverview(@Access('email') email: string,
|
||||
@Param('year', ParseIntPipe) year: number,
|
||||
@Param('periodNumber', ParseIntPipe) period_no: number,
|
||||
@Query('includeSubtree', new ParseBoolPipe({ optional: true })) include_subtree = false,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { BulkCrewApprovalDto } from "../dtos/bulk-crew-approval.dto";
|
||||
import { PayPeriodsQueryService } from "./pay-periods-query.service";
|
||||
import { TimesheetApprovalService } from "src/time-and-attendance/timesheets/services/timesheet-approval.service";
|
||||
import { Result } from "src/common/errors/result-error.factory";
|
||||
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
|
||||
//change promise to return result pattern
|
||||
|
|
@ -13,63 +14,56 @@ export class PayPeriodsCommandService {
|
|||
private readonly prisma: PrismaService,
|
||||
private readonly timesheetsApproval: TimesheetApprovalService,
|
||||
private readonly query: PayPeriodsQueryService,
|
||||
private readonly emailResolver: EmailToIdResolver,
|
||||
) { }
|
||||
|
||||
//function to approve pay-periods according to selected crew members
|
||||
async bulkApproveCrew(email: string, dto: BulkCrewApprovalDto): Promise<Result<{ updated: number }, string>> {
|
||||
const { include_subtree, items } = dto;
|
||||
if (!items?.length) return { success: false, error: 'EMPLOYEE_NOT_FOUND' };
|
||||
async bulkApproveEmployee(email: string, timesheet_ids: number[], is_approved: boolean): Promise<Result<{ shifts: number, expenses: number }, string>> {
|
||||
let shifts: Prisma.BatchPayload;
|
||||
let expenses: Prisma.BatchPayload;
|
||||
|
||||
//fetch and validate supervisor status
|
||||
const supervisor = await this.query.getSupervisor(email);
|
||||
if (!supervisor) return { success: false, error: 'EMPLOYEE_NOT_FOUND' };
|
||||
if (!supervisor.is_supervisor) return { success: false, error: 'INVALID_EMPLOYEE' };
|
||||
//fetch employee id
|
||||
const employee_id = await this.emailResolver.findIdByEmail(email);
|
||||
if (!employee_id.success) return { success: false, error: employee_id.error }
|
||||
|
||||
//fetches emails of crew members linked to supervisor
|
||||
const crew_emails = await this.query.resolveCrewEmails(supervisor.id, include_subtree);
|
||||
if (!crew_emails.success) return { success: false, error: 'INVALID_EMAIL' };
|
||||
try {
|
||||
shifts = await this.prisma.shifts.updateMany({
|
||||
where: {
|
||||
timesheet: {
|
||||
id: { in: timesheet_ids },
|
||||
employee_id: employee_id.data,
|
||||
},
|
||||
},
|
||||
data: {
|
||||
is_approved: is_approved,
|
||||
}
|
||||
});
|
||||
|
||||
for (const item of items) {
|
||||
if (!crew_emails.data.has(item.employee_email)) {
|
||||
return { success: false, error: 'INVALID_EMPLOYEE' }
|
||||
}
|
||||
expenses = await this.prisma.expenses.updateMany({
|
||||
where: {
|
||||
timesheet: {
|
||||
id: { in: timesheet_ids },
|
||||
employee_id: employee_id.data,
|
||||
},
|
||||
},
|
||||
data: {
|
||||
is_approved: is_approved,
|
||||
}
|
||||
});
|
||||
|
||||
await this.prisma.timesheets.updateMany({
|
||||
where: {
|
||||
id: { in: timesheet_ids},
|
||||
employee_id: employee_id.data,
|
||||
},
|
||||
data: {
|
||||
is_approved: is_approved,
|
||||
}
|
||||
})
|
||||
} catch (_error) {
|
||||
return { success: false, error: 'UNKNOWN_ERROR_VALIDATING' }
|
||||
}
|
||||
|
||||
const period_cache = new Map<string, { period_start: Date, period_end: Date }>();
|
||||
const getPeriod = async (year: number, period_no: number) => {
|
||||
const key = `${year}-${period_no}`;
|
||||
if (period_cache.has(key)) return period_cache.get(key)!;
|
||||
|
||||
const period = await this.query.getPeriodWindow(year, period_no);
|
||||
if (!period) throw new NotFoundException(`Pay period ${year}-${period_no} not found`);
|
||||
period_cache.set(key, period);
|
||||
return period;
|
||||
};
|
||||
|
||||
let updated = 0;
|
||||
|
||||
await this.prisma.$transaction(async (transaction) => {
|
||||
for (const item of items) {
|
||||
const { period_start, period_end } = await getPeriod(item.pay_year, item.period_no);
|
||||
|
||||
const timesheets = await transaction.timesheets.findMany({
|
||||
where: {
|
||||
employee: { user: { email: item.employee_email } },
|
||||
OR: [
|
||||
{ shift: { some: { date: { gte: period_start, lte: period_end } } } },
|
||||
{ expense: { some: { date: { gte: period_start, lte: period_end } } } },
|
||||
],
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
for (const { id } of timesheets) {
|
||||
await this.timesheetsApproval.cascadeApprovalWithtx(transaction, id, item.approve);
|
||||
updated++;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
return { success: true, data: { updated } };
|
||||
return { success: true, data: { shifts: shifts.count, expenses: expenses.count}}
|
||||
}
|
||||
}
|
||||
|
|
@ -252,10 +252,11 @@ export class PayPeriodsQueryService {
|
|||
|
||||
for (const employee of all_employees) {
|
||||
let is_active = true;
|
||||
|
||||
if (employee.last_work_day !== null) {
|
||||
is_active = this.checkForInactiveDate(employee.last_work_day)
|
||||
}
|
||||
console.log('employee name: ', employee.user.first_name, employee.user.first_name, 'last work day: ', employee.last_work_day);
|
||||
|
||||
by_employee.set(employee.id, {
|
||||
email: employee.user.email,
|
||||
employee_name: employee.user.first_name + ' ' + employee.user.last_name,
|
||||
|
|
@ -311,26 +312,26 @@ export class PayPeriodsQueryService {
|
|||
const hours = computeHours(shift.start_time, shift.end_time);
|
||||
const type = (shift.bank_code?.type ?? '').toUpperCase();
|
||||
switch (type) {
|
||||
case "EVENING": record.other_hours.evening_hours = Number((record.other_hours.evening_hours += hours).toFixed(2));
|
||||
record.total_hours = Number((record.total_hours += hours).toFixed(2));
|
||||
case "EVENING": record.other_hours.evening_hours += hours;
|
||||
record.total_hours += hours;
|
||||
break;
|
||||
case "EMERGENCY": record.other_hours.emergency_hours = Number((record.other_hours.emergency_hours += hours).toFixed(2));
|
||||
record.total_hours = Number((record.total_hours += hours).toFixed(2));
|
||||
case "EMERGENCY": record.other_hours.emergency_hours += hours;
|
||||
record.total_hours += hours;
|
||||
break;
|
||||
case "OVERTIME": record.other_hours.overtime_hours = Number((record.other_hours.overtime_hours += hours).toFixed(2));
|
||||
record.total_hours = Number((record.total_hours += hours).toFixed(2));
|
||||
case "OVERTIME": record.other_hours.overtime_hours += hours;
|
||||
record.total_hours += hours;
|
||||
break;
|
||||
case "SICK": record.other_hours.sick_hours = Number((record.other_hours.sick_hours += hours).toFixed(2));
|
||||
record.total_hours = Number((record.total_hours += hours).toFixed(2));
|
||||
case "SICK": record.other_hours.sick_hours += hours;
|
||||
record.total_hours += hours;
|
||||
break;
|
||||
case "HOLIDAY": record.other_hours.holiday_hours = Number((record.other_hours.holiday_hours += hours).toFixed(2));
|
||||
record.total_hours = Number((record.total_hours += hours).toFixed(2));
|
||||
case "HOLIDAY": record.other_hours.holiday_hours += hours;
|
||||
record.total_hours += hours;
|
||||
break;
|
||||
case "VACATION": record.other_hours.vacation_hours = Number(record.other_hours.vacation_hours += hours);
|
||||
record.total_hours = Number((record.total_hours += hours).toFixed(2));
|
||||
case "VACATION": record.other_hours.vacation_hours += hours;
|
||||
record.total_hours += hours;
|
||||
break;
|
||||
case "REGULAR": record.regular_hours = Number((record.regular_hours += hours).toFixed(2));
|
||||
record.total_hours = Number((record.total_hours += hours).toFixed(2));
|
||||
case "REGULAR": record.regular_hours = record.regular_hours += hours;
|
||||
record.total_hours += hours;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user