feat(timesheet): added comment and supervisor comment to payload of findAll
This commit is contained in:
parent
a343ace0b7
commit
125f443ec0
|
|
@ -3,12 +3,15 @@ export class ShiftDto {
|
||||||
type: string;
|
type: string;
|
||||||
start_time: string;
|
start_time: string;
|
||||||
end_time : string;
|
end_time : string;
|
||||||
|
comment: string;
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
is_remote: boolean;
|
is_remote: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExpenseDto {
|
export class ExpenseDto {
|
||||||
amount: number;
|
amount: number;
|
||||||
|
comment: string;
|
||||||
|
supervisor_comment: string;
|
||||||
total_mileage: number;
|
total_mileage: number;
|
||||||
total_expense: number;
|
total_expense: number;
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
|
|
@ -22,6 +25,7 @@ export class DetailedShifts {
|
||||||
evening_hours: number;
|
evening_hours: number;
|
||||||
overtime_hours: number;
|
overtime_hours: number;
|
||||||
emergency_hours: number;
|
emergency_hours: number;
|
||||||
|
comment: string;
|
||||||
short_date: string;
|
short_date: string;
|
||||||
break_durations?: number;
|
break_durations?: number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
import { Timesheets, TimesheetsArchive } from '@prisma/client';
|
import { Timesheets, TimesheetsArchive } from '@prisma/client';
|
||||||
import { UpdateTimesheetDto } from '../dtos/update-timesheet.dto';
|
|
||||||
import { OvertimeService } from 'src/modules/business-logics/services/overtime.service';
|
import { OvertimeService } from 'src/modules/business-logics/services/overtime.service';
|
||||||
import { computeHours, formatDateISO, getCurrentWeek, getWeekEnd, getWeekStart } from 'src/common/utils/date-utils';
|
import { computeHours, formatDateISO, getWeekEnd, getWeekStart } from 'src/common/utils/date-utils';
|
||||||
import { TimesheetPeriodDto } from '../dtos/timesheet-period.dto';
|
import { TimesheetPeriodDto } from '../dtos/timesheet-period.dto';
|
||||||
import { buildPeriod, endOfDayUTC, toUTCDateOnly } from '../utils/timesheet.helpers';
|
import { buildPeriod, endOfDayUTC, toUTCDateOnly } from '../utils/timesheet.helpers';
|
||||||
import type { ShiftRow, ExpenseRow } from '../utils/timesheet.helpers';
|
import type { ShiftRow, ExpenseRow } from '../utils/timesheet.helpers';
|
||||||
import { TimesheetDto } from '../dtos/overview-timesheet.dto';
|
import { TimesheetDto } from '../dtos/overview-timesheet.dto';
|
||||||
import { CreateWeekShiftsDto } from '../dtos/create-timesheet.dto';
|
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|
@ -21,14 +19,14 @@ export class TimesheetsQueryService {
|
||||||
async findAll(year: number, period_no: number, email: string): Promise<TimesheetPeriodDto> {
|
async findAll(year: number, period_no: number, email: string): Promise<TimesheetPeriodDto> {
|
||||||
//finds the employee
|
//finds the employee
|
||||||
const employee = await this.prisma.employees.findFirst({
|
const employee = await this.prisma.employees.findFirst({
|
||||||
where: { user: { is: { email } } },
|
where: { user: { is: { email } } },
|
||||||
select: { id: true },
|
select: { id: true },
|
||||||
});
|
});
|
||||||
if(!employee) throw new NotFoundException(`no employee with email ${email} found`);
|
if(!employee) throw new NotFoundException(`no employee with email ${email} found`);
|
||||||
|
|
||||||
//finds the period
|
//finds the period
|
||||||
const period = await this.prisma.payPeriods.findFirst({
|
const period = await this.prisma.payPeriods.findFirst({
|
||||||
where: { pay_year: year, pay_period_no: period_no },
|
where: { pay_year: year, pay_period_no: period_no },
|
||||||
select: { period_start: true, period_end: true },
|
select: { period_start: true, period_end: true },
|
||||||
});
|
});
|
||||||
if(!period) throw new NotFoundException(`Period ${year}-${period_no} not found`);
|
if(!period) throw new NotFoundException(`Period ${year}-${period_no} not found`);
|
||||||
|
|
@ -45,6 +43,7 @@ export class TimesheetsQueryService {
|
||||||
date: true,
|
date: true,
|
||||||
start_time: true,
|
start_time: true,
|
||||||
end_time: true,
|
end_time: true,
|
||||||
|
comment: true,
|
||||||
is_approved: true,
|
is_approved: true,
|
||||||
is_remote: true,
|
is_remote: true,
|
||||||
bank_code: { select: { type: true } },
|
bank_code: { select: { type: true } },
|
||||||
|
|
@ -60,31 +59,37 @@ export class TimesheetsQueryService {
|
||||||
select: {
|
select: {
|
||||||
date: true,
|
date: true,
|
||||||
amount: true,
|
amount: true,
|
||||||
|
comment: true,
|
||||||
|
supervisor_comment: true,
|
||||||
is_approved: true,
|
is_approved: true,
|
||||||
bank_code: { select: { type: true } },
|
bank_code: { select: { type: true } },
|
||||||
},
|
},
|
||||||
orderBy: { date: 'asc' },
|
orderBy: { date: 'asc' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const to_num = (value: any) => value && typeof (value as any).toNumber === 'function'
|
const to_num = (value: any) =>
|
||||||
? (value as any).toNumber()
|
value && typeof value.toNumber === 'function' ? value.toNumber() :
|
||||||
: Number(value);
|
typeof value === 'number' ? value :
|
||||||
|
value ? Number(value) : 0;
|
||||||
|
|
||||||
// data mapping
|
// data mapping
|
||||||
const shifts: ShiftRow[] = raw_shifts.map(shift => ({
|
const shifts: ShiftRow[] = raw_shifts.map(shift => ({
|
||||||
date: shift.date,
|
date: shift.date,
|
||||||
start_time: shift.start_time,
|
start_time: shift.start_time,
|
||||||
end_time: shift.end_time,
|
end_time: shift.end_time,
|
||||||
type: String(shift.bank_code?.type ?? '').toUpperCase(),
|
comment: shift.comment ?? '',
|
||||||
is_approved: shift.is_approved ?? true,
|
is_approved: shift.is_approved ?? true,
|
||||||
is_remote: shift.is_remote ?? true,
|
is_remote: shift.is_remote ?? true,
|
||||||
|
type: String(shift.bank_code?.type ?? '').toUpperCase(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const expenses: ExpenseRow[] = raw_expenses.map(expense => ({
|
const expenses: ExpenseRow[] = raw_expenses.map(expense => ({
|
||||||
date: expense.date,
|
date: expense.date,
|
||||||
amount: to_num(expense.amount),
|
amount: to_num(expense.amount),
|
||||||
type: String(expense.bank_code?.type ?? '').toUpperCase(),
|
comment: expense.comment ?? '',
|
||||||
|
supervisor_comment: expense.supervisor_comment ?? '',
|
||||||
is_approved: expense.is_approved ?? true,
|
is_approved: expense.is_approved ?? true,
|
||||||
|
type: String(expense.bank_code?.type ?? '').toUpperCase(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return buildPeriod(period.period_start, period.period_end, shifts , expenses);
|
return buildPeriod(period.period_start, period.period_end, shifts , expenses);
|
||||||
|
|
@ -231,7 +236,7 @@ export class TimesheetsQueryService {
|
||||||
await this.prisma.$transaction(async transaction => {
|
await this.prisma.$transaction(async transaction => {
|
||||||
//fetches all timesheets to cutoff
|
//fetches all timesheets to cutoff
|
||||||
const oldSheets = await transaction.timesheets.findMany({
|
const oldSheets = await transaction.timesheets.findMany({
|
||||||
where: { shift: { every: { date: { lt: cutoff } } },
|
where: { shift: { some: { date: { lt: cutoff } } },
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,23 @@ const EXPENSE_TYPES = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
//DB line types
|
//DB line types
|
||||||
export type ShiftRow = { date: Date; start_time: Date; end_time: Date; is_approved?: boolean; is_remote: boolean; type: string };
|
export type ShiftRow = {
|
||||||
export type ExpenseRow = { date: Date; amount: number; type: string; is_approved?: boolean; };
|
date: Date;
|
||||||
|
start_time: Date;
|
||||||
|
end_time: Date;
|
||||||
|
comment: string;
|
||||||
|
is_approved?: boolean;
|
||||||
|
is_remote: boolean;
|
||||||
|
type: string
|
||||||
|
};
|
||||||
|
export type ExpenseRow = {
|
||||||
|
date: Date;
|
||||||
|
amount: number;
|
||||||
|
comment: string;
|
||||||
|
supervisor_comment: string;
|
||||||
|
is_approved?: boolean;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
//helper functions
|
//helper functions
|
||||||
export function toUTCDateOnly(date: Date | string): Date {
|
export function toUTCDateOnly(date: Date | string): Date {
|
||||||
|
|
@ -84,6 +99,7 @@ export function makeEmptyWeek(week_start: Date): WeekDto {
|
||||||
evening_hours: 0,
|
evening_hours: 0,
|
||||||
emergency_hours: 0,
|
emergency_hours: 0,
|
||||||
overtime_hours: 0,
|
overtime_hours: 0,
|
||||||
|
comment: '',
|
||||||
short_date: shortDate(addDays(week_start, offset)),
|
short_date: shortDate(addDays(week_start, offset)),
|
||||||
break_durations: 0,
|
break_durations: 0,
|
||||||
});
|
});
|
||||||
|
|
@ -129,19 +145,44 @@ export function buildWeek(
|
||||||
}, {} as Record<DayKey, Array<{ start: Date; end: Date}>>);
|
}, {} as Record<DayKey, Array<{ start: Date; end: Date}>>);
|
||||||
|
|
||||||
//shifts's hour by type
|
//shifts's hour by type
|
||||||
type ShiftsHours =
|
type ShiftsHours = {
|
||||||
{regular: number; evening: number; overtime: number; emergency: number; sick: number; vacation: number; holiday: number;};
|
regular: number;
|
||||||
const make_hours = (): ShiftsHours =>
|
evening: number;
|
||||||
({ regular: 0, evening: 0, overtime: 0, emergency: 0, sick: 0, vacation: 0, holiday: 0 });
|
overtime: number;
|
||||||
|
emergency: number;
|
||||||
|
sick: number;
|
||||||
|
vacation: number;
|
||||||
|
holiday: number;
|
||||||
|
};
|
||||||
|
const make_hours = (): ShiftsHours => ({
|
||||||
|
regular: 0,
|
||||||
|
evening: 0,
|
||||||
|
overtime: 0,
|
||||||
|
emergency: 0,
|
||||||
|
sick: 0,
|
||||||
|
vacation: 0,
|
||||||
|
holiday: 0
|
||||||
|
});
|
||||||
const day_hours: Record<DayKey, ShiftsHours> = DAY_KEYS.reduce((acc, key) => {
|
const day_hours: Record<DayKey, ShiftsHours> = DAY_KEYS.reduce((acc, key) => {
|
||||||
acc[key] = make_hours(); return acc;
|
acc[key] = make_hours(); return acc;
|
||||||
}, {} as Record<DayKey, ShiftsHours>);
|
}, {} as Record<DayKey, ShiftsHours>);
|
||||||
|
|
||||||
//expenses's amount by type
|
//expenses's amount by type
|
||||||
type ExpensesAmount =
|
type ExpensesAmount = {
|
||||||
{mileage: number; expense: number; per_diem: number; commission: number; prime_dispo: number };
|
mileage: number;
|
||||||
const make_amounts = (): ExpensesAmount =>
|
expense: number;
|
||||||
({ mileage: 0, expense: 0, per_diem: 0, commission: 0, prime_dispo: 0 });
|
per_diem: number;
|
||||||
|
commission: number;
|
||||||
|
prime_dispo: number
|
||||||
|
};
|
||||||
|
|
||||||
|
const make_amounts = (): ExpensesAmount => ({
|
||||||
|
mileage: 0,
|
||||||
|
expense: 0,
|
||||||
|
per_diem: 0,
|
||||||
|
commission: 0,
|
||||||
|
prime_dispo: 0
|
||||||
|
});
|
||||||
const day_amounts: Record<DayKey, ExpensesAmount> = DAY_KEYS.reduce((acc, key) => {
|
const day_amounts: Record<DayKey, ExpensesAmount> = DAY_KEYS.reduce((acc, key) => {
|
||||||
acc[key] = make_amounts(); return acc;
|
acc[key] = make_amounts(); return acc;
|
||||||
}, {} as Record<DayKey, ExpensesAmount>);
|
}, {} as Record<DayKey, ExpensesAmount>);
|
||||||
|
|
@ -159,6 +200,7 @@ export function buildWeek(
|
||||||
type: shift.type,
|
type: shift.type,
|
||||||
start_time: toTimeString(shift.start_time),
|
start_time: toTimeString(shift.start_time),
|
||||||
end_time: toTimeString(shift.end_time),
|
end_time: toTimeString(shift.end_time),
|
||||||
|
comment: shift.comment,
|
||||||
is_approved: shift.is_approved ?? true,
|
is_approved: shift.is_approved ?? true,
|
||||||
is_remote: shift.is_remote,
|
is_remote: shift.is_remote,
|
||||||
} as ShiftDto);
|
} as ShiftDto);
|
||||||
|
|
@ -230,6 +272,8 @@ export function buildWeek(
|
||||||
for(const row of dayExpenseRows[key].km) {
|
for(const row of dayExpenseRows[key].km) {
|
||||||
week.expenses[key].km.push({
|
week.expenses[key].km.push({
|
||||||
amount: round2(row.amount),
|
amount: round2(row.amount),
|
||||||
|
comment: row.comment,
|
||||||
|
supervisor_comment: row.supervisor_comment,
|
||||||
total_mileage: round2(total_mileage),
|
total_mileage: round2(total_mileage),
|
||||||
total_expense: round2(total_expense),
|
total_expense: round2(total_expense),
|
||||||
is_approved: row.is_approved ?? true,
|
is_approved: row.is_approved ?? true,
|
||||||
|
|
@ -240,6 +284,8 @@ export function buildWeek(
|
||||||
for(const row of dayExpenseRows[key].cash) {
|
for(const row of dayExpenseRows[key].cash) {
|
||||||
week.expenses[key].cash.push({
|
week.expenses[key].cash.push({
|
||||||
amount: round2(row.amount),
|
amount: round2(row.amount),
|
||||||
|
comment: row.comment,
|
||||||
|
supervisor_comment: row.supervisor_comment,
|
||||||
total_mileage: round2(total_mileage),
|
total_mileage: round2(total_mileage),
|
||||||
total_expense: round2(total_expense),
|
total_expense: round2(total_expense),
|
||||||
is_approved: row.is_approved ?? true,
|
is_approved: row.is_approved ?? true,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user