88 lines
4.2 KiB
TypeScript
88 lines
4.2 KiB
TypeScript
import { weekStartSunday, toStringFromDate, toDateFromString } from "src/common/utils/date-utils";
|
|
import { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
|
|
import { expense_select, timesheet_select } from "src/time-and-attendance/utils/selects.utils";
|
|
import { PrismaPostgresService } from "prisma/postgres/prisma-postgres.service";
|
|
import { Injectable } from "@nestjs/common";
|
|
import { Result } from "src/common/errors/result-error.factory";
|
|
import { BankCodesResolver } from "src/common/mappers/bank-type-id.mapper";
|
|
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";
|
|
|
|
@Injectable()
|
|
export class ExpenseUpdateService {
|
|
constructor(
|
|
private readonly prisma: PrismaPostgresService,
|
|
private readonly emailResolver: EmailToIdResolver,
|
|
private readonly typeResolver: BankCodesResolver,
|
|
private readonly payPeriodEventService: PayPeriodEventService,
|
|
) { }
|
|
//_________________________________________________________________
|
|
// UPDATE
|
|
//_________________________________________________________________
|
|
async updateExpense(dto: ExpenseDto, email: string, employee_email?: string): Promise<Result<ExpenseDto, string>> {
|
|
try {
|
|
const account_email = employee_email ?? email;
|
|
//fetch employee_id using req.user.email
|
|
const employee_id = await this.emailResolver.findIdByEmail(account_email);
|
|
if (!employee_id.success) return { success: false, error: employee_id.error };
|
|
//normalize string , date format and parse numbers
|
|
const normed_expense = await normalizeAndParseExpenseDto(dto);
|
|
if (!normed_expense.success) return { success: false, error: normed_expense.error }
|
|
|
|
const type = await this.typeResolver.findBankCodeIDByType(dto.type);
|
|
if (!type.success) return { success: false, error: 'INVALID_EXPENSE_TYPE' }
|
|
//added timesheet_id modification check according to the new date
|
|
const new_timesheet_start_date = weekStartSunday(toDateFromString(dto.date));
|
|
|
|
const timesheet = await this.prisma.client.timesheets.findFirst({
|
|
where: { start_date: new_timesheet_start_date, employee_id: employee_id.data },
|
|
select: timesheet_select,
|
|
});
|
|
if (!timesheet) return { success: false, error: `TIMESHEET_NOT_FOUND` }
|
|
|
|
//checks for modifications
|
|
const data = {
|
|
...normed_expense.data,
|
|
bank_code_id: type.data,
|
|
is_approved: dto.is_approved,
|
|
};
|
|
if (!data) return { success: false, error: `INVALID_EXPENSE` }
|
|
|
|
//push updates and get updated datas
|
|
const expense = await this.prisma.client.expenses.update({
|
|
where: { id: dto.id, timesheet_id: timesheet.id },
|
|
data,
|
|
select: expense_select,
|
|
});
|
|
if (!expense) return { success: false, error: 'INVALID_EXPENSE' }
|
|
|
|
//build an object to return to the frontend
|
|
const updated: ExpenseDto = {
|
|
...expense,
|
|
type: expense.bank_code.type,
|
|
date: toStringFromDate(expense.date),
|
|
amount: expense.amount?.toNumber(),
|
|
mileage: expense.mileage?.toNumber(),
|
|
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' };
|
|
}
|
|
}
|
|
}
|
|
|