import { Injectable, NotFoundException } from "@nestjs/common"; import { PrismaService } from "src/prisma/prisma.service"; import { CreateExpenseDto } from "../dtos/create-expense.dto"; import { Expenses, ExpensesArchive } from "@prisma/client"; import { UpdateExpenseDto } from "../dtos/update-expense.dto"; import { MileageService } from "src/modules/business-logics/services/mileage.service"; import { SearchExpensesDto } from "../dtos/search-expense.dto"; import { buildPrismaWhere } from "src/common/shared/build-prisma-where"; @Injectable() export class ExpensesQueryService { constructor( private readonly prisma: PrismaService, private readonly mileageService: MileageService, ) {} async create(dto: CreateExpenseDto): Promise { const { timesheet_id, bank_code_id, date, amount:rawAmount, comment, is_approved,supervisor_comment} = dto; //fetches type and modifier const bank_code = await this.prisma.bankCodes.findUnique({ where: { id: bank_code_id }, select: { type: true, modifier: true }, }); if(!bank_code) { throw new NotFoundException(`bank_code #${bank_code_id} not found`) } //if mileage -> service, otherwise the ratio is amount:1 let final_amount: number; if(bank_code.type === 'mileage') { final_amount = await this.mileageService.calculateReimbursement(rawAmount, bank_code_id); }else { final_amount = parseFloat( (rawAmount * bank_code.modifier).toFixed(2)); } return this.prisma.expenses.create({ data: { timesheet_id, bank_code_id, date, amount: final_amount, comment, is_approved, supervisor_comment}, include: { timesheet: { include: { employee: { include: { user: true }}}}, bank_code: true, }, }) } async findAll(filters: SearchExpensesDto): Promise { const where = buildPrismaWhere(filters); const expenses = await this.prisma.expenses.findMany({ where }) return expenses; } 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, comment, 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 }), ...(comment !== undefined && { comment }), ...(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 archived_timesheets = await this.prisma.timesheetsArchive.findMany({ select: { timesheet_id: true }, }); const timesheet_ids = archived_timesheets.map(sheet => sheet.timesheet_id); if(timesheet_ids.length === 0) { return; } // copy/delete transaction await this.prisma.$transaction(async transaction => { //fetches expenses to move to archive const expenses_to_archive = await transaction.expenses.findMany({ where: { timesheet_id: { in: timesheet_ids } }, }); if(expenses_to_archive.length === 0) { return; } //copies sent to archive table await transaction.expensesArchive.createMany({ data: expenses_to_archive.map(exp => ({ expense_id: exp.id, timesheet_id: exp.timesheet_id, bank_code_id: exp.bank_code_id, date: exp.date, amount: exp.amount, attachment: exp.attachment, comment: exp.comment, is_approved: exp.is_approved, supervisor_comment: exp.supervisor_comment, })), }); //delete from expenses table await transaction.expenses.deleteMany({ where: { id: { in: expenses_to_archive.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 } }); } }