fix(notify): fixes and setup notify for daily overtime
This commit is contained in:
parent
dc8c4d048c
commit
1e4ec836d3
|
|
@ -12,6 +12,7 @@ import { ExpensesModule } from './modules/expenses/expenses.module';
|
|||
import { HealthModule } from './health/health.module';
|
||||
import { HealthController } from './health/health.controller';
|
||||
import { LeaveRequestsModule } from './modules/leave-requests/leave-requests.module';
|
||||
import { NotificationsModule } from './modules/notifications/notifications.module';
|
||||
import { OauthSessionsModule } from './modules/oauth-sessions/oauth-sessions.module';
|
||||
import { OvertimeService } from './modules/business-logics/services/overtime.service';
|
||||
import { PayperiodsModule } from './modules/pay-periods/pay-periods.module';
|
||||
|
|
@ -33,6 +34,7 @@ import { UsersModule } from './modules/users-management/users.module';
|
|||
ExpensesModule,
|
||||
HealthModule,
|
||||
LeaveRequestsModule,
|
||||
NotificationsModule,
|
||||
OauthSessionsModule,
|
||||
PayperiodsModule,
|
||||
PrismaModule,
|
||||
|
|
|
|||
|
|
@ -48,3 +48,37 @@ export function getWeekEnd(startOfWeek: Date): Date {
|
|||
export function getYearStart(date:Date): Date {
|
||||
return new Date(date.getFullYear(),0,1,0,0,0,0);
|
||||
}
|
||||
|
||||
//cloning methods (helps with notify for overtime in a single day)
|
||||
// export function toDateOnly(day: Date): Date {
|
||||
// const d = new Date(day);
|
||||
// d.setHours(0, 0, 0, 0);
|
||||
// return d;
|
||||
// }
|
||||
|
||||
// export function composeDateWithTime(day: Date, timeOnly: Date): Date {
|
||||
// const base = toDateOnly(day);
|
||||
// base.setHours(timeOnly.getHours(),
|
||||
// timeOnly.getMinutes(),
|
||||
// timeOnly.getSeconds(),
|
||||
// timeOnly.getMilliseconds());
|
||||
// return base;
|
||||
// }
|
||||
|
||||
export function hoursBetweenSameDay(day: Date, startTime: Date, endTime: Date): number {
|
||||
const start = new Date(day); start.setHours(startTime.getHours(),
|
||||
startTime.getMinutes(),
|
||||
startTime.getSeconds(),
|
||||
startTime.getMilliseconds());
|
||||
const end = new Date(day); end.setHours(endTime.getHours(),
|
||||
endTime.getMinutes(),
|
||||
endTime.getSeconds(),
|
||||
endTime.getMilliseconds());
|
||||
const ms = Math.max(0, end.getTime() - start.getTime());
|
||||
return ms / 3_600_000; // decimal hours
|
||||
}
|
||||
|
||||
// //utils to print Date into locale date format
|
||||
// export function fmtDayLocal(day:Date, locale = 'fr-CA'): string {
|
||||
// return new Date(day).toLocaleDateString(locale, { year: 'numeric', month: '2-digit', day: '2-digit'});
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
export const NOTIF_TYPES = {
|
||||
SHIFT_OVERTIME_DAILY: 'shift.overtime.daily',
|
||||
|
||||
} as const;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { Controller, Get, Req, Sse, UseGuards,
|
||||
MessageEvent as NestMessageEvent } from "@nestjs/common";
|
||||
import { JwtAuthGuard } from "../authentication/guards/jwt-auth.guard";
|
||||
import { NotificationsService } from "./notifications.service";
|
||||
import { JwtAuthGuard } from "../../authentication/guards/jwt-auth.guard";
|
||||
import { NotificationsService } from "../services/notifications.service";
|
||||
import { Observable } from "rxjs";
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { Module } from "@nestjs/common";
|
||||
import { NotificationsController } from "./notifications.controller";
|
||||
import { NotificationsService } from "./notifications.service";
|
||||
import { NotificationsController } from "./controllers/notifications.controller";
|
||||
import { NotificationsService } from "./services/notifications.service";
|
||||
|
||||
@Module({
|
||||
providers: [NotificationsService],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Injectable, Logger } from "@nestjs/common";
|
||||
import { Subject } from "rxjs";
|
||||
import { NotificationCard } from "./notifications.types";
|
||||
import { NotificationCard } from "../dtos/notifications.types";
|
||||
|
||||
@Injectable()
|
||||
export class NotificationsService {
|
||||
|
|
@ -5,19 +5,59 @@ import { Shifts, ShiftsArchive } from "@prisma/client";
|
|||
import { UpdateShiftsDto } from "../dtos/update-shift.dto";
|
||||
import { buildPrismaWhere } from "src/common/shared/build-prisma-where";
|
||||
import { SearchShiftsDto } from "../dtos/search-shifts.dto";
|
||||
import { NotificationsService } from "src/modules/notifications/services/notifications.service";
|
||||
import { hoursBetweenSameDay } from "src/common/utils/date-utils";
|
||||
|
||||
const DAILY_LIMIT_HOURS = Number(process.env.DAILY_LIMIT_HOURS ?? 8);
|
||||
|
||||
@Injectable()
|
||||
export class ShiftsService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly notifs: NotificationsService,
|
||||
) {}
|
||||
|
||||
async create(dto: CreateShiftDto): Promise<Shifts> {
|
||||
const { timesheet_id, bank_code_id, date, start_time, end_time } = dto;
|
||||
return this.prisma.shifts.create({
|
||||
|
||||
//shift creation
|
||||
const shift = await this.prisma.shifts.create({
|
||||
data: { timesheet_id, bank_code_id, date, start_time, end_time },
|
||||
include: { timesheet: { include: { employee: { include: { user: true } } } },
|
||||
bank_code: true,
|
||||
},
|
||||
});
|
||||
|
||||
//fetches all shifts of the same day to check for daily overtime
|
||||
const sameDayShifts = await this.prisma.shifts.findMany({
|
||||
where: { timesheet_id, date },
|
||||
select: { id: true, date: true, start_time: true, end_time: true },
|
||||
});
|
||||
|
||||
//sums hours of the day
|
||||
const totalHours = sameDayShifts.reduce((sum, s) => {
|
||||
return sum + hoursBetweenSameDay(s.date, s.start_time, s.end_time);
|
||||
}, 0 );
|
||||
|
||||
//Notify if total hours > 8 for a single day
|
||||
if(totalHours > DAILY_LIMIT_HOURS ) {
|
||||
const userId = String(shift.timesheet.employee.user.id);
|
||||
const dateLabel = new Date(date).toLocaleDateString('fr-CA');
|
||||
this.notifs.notify(userId, {
|
||||
type: 'shift.overtime.daily',
|
||||
severity: 'warn',
|
||||
message: `Tu viens de dépasser ${DAILY_LIMIT_HOURS.toFixed(2)}h pour la journée du ${dateLabel} (total: ${totalHours.toFixed(2)}h).`,
|
||||
ts: new Date().toISOString(),
|
||||
meta: {
|
||||
timesheet_id,
|
||||
date: new Date(date).toISOString(),
|
||||
totalHours,
|
||||
threshold: DAILY_LIMIT_HOURS,
|
||||
lastShiftId: shift.id
|
||||
},
|
||||
});
|
||||
}
|
||||
return shift;
|
||||
}
|
||||
|
||||
async findAll(filters: SearchShiftsDto): Promise <Shifts[]> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user