feat(expenses): method implementation to show a list of all expenses made by an employee using email, year and period_no

This commit is contained in:
Matthieu Haineault 2025-10-07 13:51:35 -04:00
parent a750f79107
commit cc310e286d
3 changed files with 143 additions and 7 deletions

View File

@ -393,6 +393,50 @@
]
}
},
"/Expenses/list/{email}/{year}/{period_no}": {
"get": {
"operationId": "ExpensesController_findExpenseListByPayPeriodAndEmail",
"parameters": [
{
"name": "email",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
},
{
"name": "year",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
},
{
"name": "period_no",
"required": true,
"in": "path",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"security": [
{
"access-token": []
}
],
"tags": [
"Expenses"
]
}
},
"/shifts/upsert/{email}/{date}": {
"put": {
"operationId": "ShiftsController_upsert_by_date",

View File

@ -1,10 +1,12 @@
import { Body, Controller, Param, Put, } from "@nestjs/common";
import { Body, Controller, Get, Param, Put, } from "@nestjs/common";
import { Roles as RoleEnum } from '.prisma/client';
import { ApiBearerAuth, ApiTags } from "@nestjs/swagger";
import { RolesAllowed } from "src/common/decorators/roles.decorators";
import { ExpensesCommandService } from "../services/expenses-command.service";
import { UpsertExpenseDto } from "../dtos/upsert-expense.dto";
import { UpsertExpenseResult } from "../types and interfaces/expenses.types.interfaces";
import { DayExpensesDto } from "src/modules/timesheets/dtos/timesheet-period.dto";
import { ExpensesQueryService } from "../services/expenses-query.service";
@ApiTags('Expenses')
@ApiBearerAuth('access-token')
@ -12,7 +14,7 @@ import { UpsertExpenseResult } from "../types and interfaces/expenses.types.inte
@Controller('Expenses')
export class ExpensesController {
constructor(
// private readonly query: ExpensesQueryService,
private readonly query: ExpensesQueryService,
private readonly command: ExpensesCommandService,
) {}
@ -25,6 +27,15 @@ export class ExpensesController {
return this.command.upsertExpensesByDate(email, date, dto);
}
@Get('list/:email/:year/:period_no')
async findExpenseListByPayPeriodAndEmail(
@Param('email') email:string,
@Param('year') year: number,
@Param('period_no') period_no: number,
): Promise<DayExpensesDto> {
return this.query.findExpenseListByPayPeriodAndEmail(email, year, period_no);
}
//_____________________________________________________________________________________________
// Deprecated or unused methods
//_____________________________________________________________________________________________

View File

@ -1,11 +1,92 @@
import { Injectable } from "@nestjs/common";
import { Injectable, NotFoundException } from "@nestjs/common";
import { PrismaService } from "src/prisma/prisma.service";
import { DayExpensesDto, ExpenseDto } from "src/modules/timesheets/dtos/timesheet-period.dto";
import { EmployeesRepo } from "../repos/employee.repo";
import { round2, toUTCDateOnly } from "src/modules/timesheets/utils/timesheet.helpers";
import { EXPENSE_TYPES } from "src/modules/timesheets/types/timesheet.types";
@Injectable()
export class ExpensesQueryService {
// constructor(
// private readonly prisma: PrismaService,
// private readonly mileageService: MileageService,
// ) {}
constructor(
private readonly prisma: PrismaService,
private readonly employeeRepo: EmployeesRepo,
) {}
//fetchs all expenses for a selected employee using email, pay-period-year and number
async findExpenseListByPayPeriodAndEmail(
email: string,
year: number,
period_no: number
): Promise<DayExpensesDto> {
//fetch employe_id using email
const employee_id = await this.employeeRepo.findIdByEmail(email);
if(!employee_id) throw new NotFoundException(`Employee with email: ${email} not found`);
//fetch pay-period using year and period_no
const pay_period = await this.prisma.payPeriods.findFirst({
where: {
pay_year: year,
pay_period_no: period_no
},
select: { period_start: true, period_end: true },
});
if(!pay_period) throw new NotFoundException(`Pay period ${year}- ${period_no} not found`);
const start = toUTCDateOnly(pay_period.period_start);
const end = toUTCDateOnly(pay_period.period_end);
//sets rows data
const rows = await this.prisma.expenses.findMany({
where: {
date: { gte: start, lte: end },
timesheet: { is: { employee_id } },
},
orderBy: { date: 'asc'},
select: {
amount: true,
mileage: true,
comment: true,
is_approved: true,
supervisor_comment: true,
bank_code: {select: { type: true } },
},
});
//declare return values
const expenses: ExpenseDto[] = [];
let total_amount = 0;
let total_mileage = 0;
//set rows
for(const row of rows) {
const type = (row.bank_code?.type ?? '').toUpperCase();
const amount = round2(Number(row.amount ?? 0));
const mileage = round2(Number(row.mileage ?? 0));
if(type === EXPENSE_TYPES.MILEAGE) {
total_mileage += mileage;
} else {
total_amount += amount;
}
//fills rows array
expenses.push({
type,
amount,
mileage,
comment: row.comment ?? '',
is_approved: row.is_approved ?? false,
supervisor_comment: row.supervisor_comment ?? '',
});
}
return {
expenses,
total_expense: round2(total_amount),
total_mileage: round2(total_mileage),
};
}
//_____________________________________________________________________________________________
// Deprecated or unused methods