import { Injectable, NotFoundException } from "@nestjs/common"; import { PrismaService } from "src/prisma/prisma.service"; import { CreateExpenseDto } from "../dtos/create-expense"; import { Expenses, ExpensesArchive } from "@prisma/client"; import { UpdateExpenseDto } from "../dtos/update-expense"; import { MileageService } from "src/modules/business-logics/services/mileage.service"; @Injectable() export class ExpensesService { constructor( private readonly prisma: PrismaService, private readonly mileageService: MileageService, ) {} async create(dto: CreateExpenseDto): Promise { const { timesheet_id, bank_code_id, date, amount:rawAmount, description, is_approved,supervisor_comment} = dto; //fetches type and modifier const bankCode = await this.prisma.bankCodes.findUnique({ where: { id: bank_code_id }, select: { type: true, modifier: true }, }); if(!bankCode) { throw new NotFoundException(`bank_code #${bank_code_id} not found`) } //if mileage -> service, otherwise the ratio is amount:1 let finalAmount: number; if(bankCode.type === 'mileage') { finalAmount = await this.mileageService.calculateReimbursement(rawAmount, bank_code_id); }else { finalAmount = parseFloat( (rawAmount * bankCode.modifier).toFixed(2)); } return this.prisma.expenses.create({ data: { timesheet_id, bank_code_id, date, amount: finalAmount, description, is_approved, supervisor_comment}, include: { timesheet: { include: { employee: { include: { user: true }}}}, bank_code: true, }, }) } findAll(): Promise { return this.prisma.expenses.findMany({ include: { timesheet: { include: { employee: { include: { user: true } } } } }, }); } async findOne(id: number): Promise { const expense = await this.prisma.expenses.findUnique({ where: { id }, include: { timesheet: { include: { employee: { include: { user:true } } } }, bank_code: true, }, }); if (!expense) { throw new NotFoundException(`Expense #${id} not found`); } return expense; } async update(id: number, dto: UpdateExpenseDto): Promise { await this.findOne(id); const { timesheet_id, bank_code_id, date, amount, description, is_approved, supervisor_comment} = dto; return this.prisma.expenses.update({ where: { id }, data: { ...(timesheet_id !== undefined && { timesheet_id}), ...(bank_code_id !== undefined && { bank_code_id }), ...(date !== undefined && { date }), ...(amount !== undefined && { amount }), ...(description !== undefined && { description }), ...(is_approved !== undefined && { is_approved }), ...(supervisor_comment !== undefined && { supervisor_comment }), }, include: { timesheet: { include: { employee: { include: { user: true } } } }, bank_code: true, }, }); } async remove(id: number): Promise { await this.findOne(id); return this.prisma.expenses.delete({ where: { id } }); } //archivation functions ****************************************************** async archiveOld(): Promise { //fetches archived timesheet's Ids const archivedTimesheets = await this.prisma.timesheetsArchive.findMany({ select: { timesheet_id: true }, }); const timesheetIds = archivedTimesheets.map(sheet => sheet.timesheet_id); if(timesheetIds.length === 0) { return; } // copy/delete transaction await this.prisma.$transaction(async transaction => { //fetches expenses to move to archive const expensesToArchive = await transaction.expenses.findMany({ where: { timesheet_id: { in: timesheetIds } }, }); if(expensesToArchive.length === 0) { return; } //copies sent to archive table await transaction.expensesArchive.createMany({ data: expensesToArchive.map(exp => ({ expense_id: exp.id, timesheet_id: exp.timesheet_id, bank_code_id: exp.bank_code_id, date: exp.date, amount: exp.amount, attachement: exp.attachement, description: exp.description, is_approved: exp.is_approved, supervisor_comment: exp.supervisor_comment, })), }); //delete from expenses table await transaction.expenses.deleteMany({ where: { id: { in: expensesToArchive.map(exp => exp.id) } }, }) }) } //fetches all archived timesheets async findAllArchived(): Promise { return this.prisma.expensesArchive.findMany(); } //fetches an archived timesheet async findOneArchived(id: number): Promise { return this.prisma.expensesArchive.findUniqueOrThrow({ where: { id } }); } }