diff --git a/src/time-and-attendance/expenses/expense.controller.ts b/src/time-and-attendance/expenses/expense.controller.ts index 737228e..d910ad4 100644 --- a/src/time-and-attendance/expenses/expense.controller.ts +++ b/src/time-and-attendance/expenses/expense.controller.ts @@ -35,8 +35,11 @@ export class ExpenseController { @Delete('delete/:expense_id') @ModuleAccessAllowed(ModulesEnum.timesheets) - remove(@Param('expense_id') expense_id: number): Promise> { - return this.deleteService.deleteExpense(expense_id); + remove( + @Param('expense_id') expense_id: number, + @Access('email') email: string, + ): Promise> { + return this.deleteService.deleteExpense(expense_id, email); } } diff --git a/src/time-and-attendance/expenses/services/expense-create.service.ts b/src/time-and-attendance/expenses/services/expense-create.service.ts index 6222c83..298c58c 100644 --- a/src/time-and-attendance/expenses/services/expense-create.service.ts +++ b/src/time-and-attendance/expenses/services/expense-create.service.ts @@ -6,6 +6,7 @@ import { toStringFromDate, weekStartSunday } from "src/common/utils/date-utils"; import { PrismaService } from "src/prisma/prisma.service"; import { ExpenseDto } from "src/time-and-attendance/expenses/expense-create.dto"; import { normalizeAndParseExpenseDto } from "src/time-and-attendance/expenses/expense.utils"; +import { PayPeriodEventService } from "src/time-and-attendance/pay-period/services/pay-period-event.service"; import { expense_select } from "src/time-and-attendance/utils/selects.utils"; @Injectable() @@ -14,6 +15,7 @@ export class ExpenseCreateService { private readonly prisma: PrismaService, private readonly emailResolver: EmailToIdResolver, private readonly typeResolver: BankCodesResolver, + private readonly payPeriodEventService: PayPeriodEventService, ) { } //_________________________________________________________________ @@ -64,8 +66,15 @@ export class ExpenseCreateService { attachment: expense.attachment ?? undefined, supervisor_comment: expense.supervisor_comment ?? undefined, }; - return { success: true, data: created }; + // notify timesheet approval observers of changes + this.payPeriodEventService.emit({ + employee_email: email, + event_type: 'expense', + action: 'create', + }); + + return { success: true, data: created }; } catch (error) { return { success: false, error: 'INVALID_EXPENSE' }; } diff --git a/src/time-and-attendance/expenses/services/expense-delete.service.ts b/src/time-and-attendance/expenses/services/expense-delete.service.ts index 9ad7dd8..01c3bfc 100644 --- a/src/time-and-attendance/expenses/services/expense-delete.service.ts +++ b/src/time-and-attendance/expenses/services/expense-delete.service.ts @@ -1,15 +1,40 @@ import { Injectable } from "@nestjs/common"; import { Result } from "src/common/errors/result-error.factory"; +import { EmailToIdResolver } from "src/common/mappers/email-id.mapper"; import { PrismaService } from "src/prisma/prisma.service"; +import { PayPeriodEventService } from "src/time-and-attendance/pay-period/services/pay-period-event.service"; @Injectable() export class ExpenseDeleteService { - constructor(private readonly prisma: PrismaService) { } + constructor( + private readonly prisma: PrismaService, + private readonly payPeriodEventService: PayPeriodEventService, + private readonly emailResolver: EmailToIdResolver, + ){} //_________________________________________________________________ // DELETE //_________________________________________________________________ - async deleteExpense(expense_id: number): Promise> { + async deleteExpense(expense_id: number, email: string): Promise> { + // get employee id of employee who made delete request + const employee = await this.emailResolver.findIdByEmail(email); + + if (!employee.success) return employee; + + // confirm ownership of expense to employee who made request + const expense = await this.prisma.expenses.findUnique({ + where: { id: expense_id}, + select: { + timesheet: { + select: { + employee_id: true, + } + } + } + }); + + if (!expense || expense.timesheet.employee_id !== employee.data) return { success: false, error: 'EXPENSE_NOT_FOUND'}; + try { await this.prisma.$transaction(async (tx) => { const expense = await tx.expenses.findUnique({ @@ -21,6 +46,14 @@ export class ExpenseDeleteService { await tx.expenses.delete({ where: { id: expense.id } }); return { success: true, data: expense.id }; }); + + // notify timesheet-approval observers of changes + this.payPeriodEventService.emit({ + employee_email: email, + event_type: 'expense', + action: 'delete', + }); + return { success: true, data: expense_id }; } catch (error) { return { success: false, error: `EXPENSE_NOT_FOUND` }; diff --git a/src/time-and-attendance/expenses/services/expense-update.service.ts b/src/time-and-attendance/expenses/services/expense-update.service.ts index 3f2e1e5..a5af26a 100644 --- a/src/time-and-attendance/expenses/services/expense-update.service.ts +++ b/src/time-and-attendance/expenses/services/expense-update.service.ts @@ -8,6 +8,7 @@ import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper"; import { ExpenseDto } from "src/time-and-attendance/expenses/expense-create.dto"; import { Prisma } from "@prisma/client"; import { normalizeAndParseExpenseDto } from "src/time-and-attendance/expenses/expense.utils"; +import { PayPeriodEventService } from "src/time-and-attendance/pay-period/services/pay-period-event.service"; @Injectable() export class ExpenseUpdateService { @@ -15,6 +16,7 @@ export class ExpenseUpdateService { private readonly prisma: PrismaService, private readonly emailResolver: EmailToIdResolver, private readonly typeResolver: BankCodesResolver, + private readonly payPeriodEventService: PayPeriodEventService, ) { } //_________________________________________________________________ // UPDATE @@ -66,6 +68,17 @@ export class ExpenseUpdateService { attachment: expense.attachment ?? undefined, supervisor_comment: expense.supervisor_comment ?? undefined, }; + + // notify timesheet-approval observers of changes, but only if it came + // from timesheet and not timesheet-approval (no employee_email) + if (!employee_email) { + this.payPeriodEventService.emit({ + employee_email: email, + event_type: 'expense', + action: 'update', + }); + } + return { success: true, data: updated }; } catch (error) { return { success: false, error: 'EXPENSE_NOT_FOUND' }; diff --git a/src/time-and-attendance/pay-period/dtos/pay-period-event.dto.ts b/src/time-and-attendance/pay-period/dtos/pay-period-event.dto.ts index 4bf21a0..89faff2 100644 --- a/src/time-and-attendance/pay-period/dtos/pay-period-event.dto.ts +++ b/src/time-and-attendance/pay-period/dtos/pay-period-event.dto.ts @@ -1,5 +1,5 @@ export class PayPeriodEvent { employee_email: string; - event_type: 'expense' | 'shift'; + event_type: 'expense' | 'shift' | 'preset'; action: 'create' | 'update' | 'delete'; } \ No newline at end of file diff --git a/src/time-and-attendance/schedule-presets/schedule-presets.module.ts b/src/time-and-attendance/schedule-presets/schedule-presets.module.ts index 56beb0a..04085d6 100644 --- a/src/time-and-attendance/schedule-presets/schedule-presets.module.ts +++ b/src/time-and-attendance/schedule-presets/schedule-presets.module.ts @@ -13,6 +13,7 @@ import { ShiftsCreateService } from "src/time-and-attendance/shifts/services/shi import { VacationService } from "src/time-and-attendance/domains/services/vacation.service"; import { SickLeaveService } from "src/time-and-attendance/domains/services/sick-leave.service"; import { BankedHoursService } from "src/time-and-attendance/domains/services/banking-hours.service"; +import { PayPeriodEventService } from "../pay-period/services/pay-period-event.service"; @@ -30,6 +31,7 @@ import { BankedHoursService } from "src/time-and-attendance/domains/services/ban VacationService, SickLeaveService, BankedHoursService, + PayPeriodEventService, ], exports: [ SchedulePresetsGetService, diff --git a/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts b/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts index 668418a..97ad01c 100644 --- a/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts +++ b/src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service.ts @@ -11,6 +11,7 @@ import { timesheet_select } from "src/time-and-attendance/utils/selects.utils"; import { ShiftDto } from "src/time-and-attendance/shifts/shift.dto"; import { WEEKDAY_MAP } from "src/time-and-attendance/schedule-presets/schedule-presets.dto"; import { $Enums, Prisma, SchedulePresetShifts } from "@prisma/client"; +import { PayPeriodEventService } from "src/time-and-attendance/pay-period/services/pay-period-event.service"; @Injectable() @@ -20,6 +21,7 @@ export class SchedulePresetsApplyService { private readonly emailResolver: EmailToIdResolver, private readonly shiftService: ShiftsCreateService, private readonly typeResolver: BankCodesResolver, + private readonly payPeriodEventService: PayPeriodEventService, ) { } async applyPresetToTimesheet(email: string, timesheet_id: number): Promise> { @@ -119,6 +121,14 @@ export class SchedulePresetsApplyService { await this.shiftService.createShift(employee_id.data, created_shift.data); } + + // notify timesheet-approval observers of changes + this.payPeriodEventService.emit({ + employee_email: email, + event_type: 'preset', + action: 'create', + }) + return { success: true, data: true }; } diff --git a/src/time-and-attendance/shifts/services/shifts-update.service.ts b/src/time-and-attendance/shifts/services/shifts-update.service.ts index 75c1b09..dcaaf3d 100644 --- a/src/time-and-attendance/shifts/services/shifts-update.service.ts +++ b/src/time-and-attendance/shifts/services/shifts-update.service.ts @@ -61,7 +61,7 @@ export class ShiftsUpdateService { this.payPeriodEventService.emit({ employee_email: email, event_type: 'shift', - action: 'create' + action: 'update' }) } diff --git a/src/time-and-attendance/time-and-attendance.module.ts b/src/time-and-attendance/time-and-attendance.module.ts index c5d1420..7b7696c 100644 --- a/src/time-and-attendance/time-and-attendance.module.ts +++ b/src/time-and-attendance/time-and-attendance.module.ts @@ -43,6 +43,7 @@ import { SchedulePresetDeleteService } from "src/time-and-attendance/schedule-pr import { SchedulePresetUpdateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-update.service"; import { SchedulePresetsCreateService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-create.service"; import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-presets/services/schedule-presets-apply.service"; +import { PayPeriodEventService } from "./pay-period/services/pay-period-event.service"; @Module({ @@ -90,6 +91,7 @@ import { SchedulePresetsApplyService } from "src/time-and-attendance/schedule-pr VacationService, BankedHoursService, PaidTimeOFfBankHoursService, + PayPeriodEventService, ], exports: [TimesheetApprovalService], }) export class TimeAndAttendanceModule { }; \ No newline at end of file