targo-backend/src/time-and-attendance/expenses/services/expense-create.service.ts

82 lines
3.8 KiB
TypeScript

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 { EmailToIdResolver } from "src/common/mappers/email-id.mapper";
import { toStringFromDate, weekStartSunday } from "src/common/utils/date-utils";
import { PrismaService } from "prisma/postgres/prisma-postgres.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()
export class ExpenseCreateService {
constructor(
private readonly prisma: PrismaService,
private readonly emailResolver: EmailToIdResolver,
private readonly typeResolver: BankCodesResolver,
private readonly payPeriodEventService: PayPeriodEventService,
) { }
//_________________________________________________________________
// CREATE
//_________________________________________________________________
async createExpense(dto: ExpenseDto, email: string): Promise<Result<ExpenseDto, string>> {
try {
//fetch employee_id using req.user.email
const employee_id = await this.emailResolver.findIdByEmail(email);
if (!employee_id.success) return { success: false, error: employee_id.error };
//normalize strings and dates 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' }
//finds the timesheet using expense.date by finding the sunday
const start_date = weekStartSunday(normed_expense.data.date);
const timesheet = await this.prisma.timesheets.findFirst({
where: { start_date, employee_id: employee_id.data },
select: { id: true, employee_id: true },
});
if (!timesheet) return { success: false, error: `TIMESHEET_NOT_FOUND` };
//create a new expense
const expense = await this.prisma.expenses.create({
data: {
...normed_expense.data,
bank_code_id: type.data,
timesheet_id: timesheet.id,
is_approved: dto.is_approved,
},
//return the newly created expense with id
select: expense_select,
});
if (!expense) return { success: false, error: `INVALID_EXPENSE` };
//build an object to return to the frontend to display
const created: ExpenseDto = {
...expense,
type: dto.type,
date: toStringFromDate(expense.date),
amount: expense.amount?.toNumber() ?? undefined,
mileage: expense.mileage?.toNumber(),
attachment: expense.attachment ?? undefined,
supervisor_comment: expense.supervisor_comment ?? undefined,
};
// 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' };
}
}
}