refactor(timesheets): refactored findAll to return more data
This commit is contained in:
parent
301d5f2c9d
commit
9bc5c41de8
|
|
@ -1,4 +1,4 @@
|
||||||
import { Injectable, Logger } from "@nestjs/common";
|
import { Injectable, Logger, NotFoundException } from "@nestjs/common";
|
||||||
import { PrismaService } from "../../../prisma/prisma.service";
|
import { PrismaService } from "../../../prisma/prisma.service";
|
||||||
import { computeHours, getWeekStart } from "src/common/utils/date-utils";
|
import { computeHours, getWeekStart } from "src/common/utils/date-utils";
|
||||||
|
|
||||||
|
|
@ -8,7 +8,23 @@ export class HolidayService {
|
||||||
|
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
//switch employeeId for email
|
//fetch employee_id by email
|
||||||
|
private async resolveEmployeeByEmail(email: string): Promise<number> {
|
||||||
|
const employee = await this.prisma.employees.findFirst({
|
||||||
|
where: {
|
||||||
|
user: { email }
|
||||||
|
},
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
if(!employee) throw new NotFoundException(`Employee with email : ${email} not found`);
|
||||||
|
return employee.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async computeHoursPrevious4WeeksByEmail(email: string, holiday_date: Date): Promise<number> {
|
||||||
|
const employee_id = await this.resolveEmployeeByEmail(email);
|
||||||
|
return this.computeHoursPrevious4Weeks(employee_id, holiday_date)
|
||||||
|
}
|
||||||
|
|
||||||
private async computeHoursPrevious4Weeks(employee_id: number, holiday_date: Date): Promise<number> {
|
private async computeHoursPrevious4Weeks(employee_id: number, holiday_date: Date): Promise<number> {
|
||||||
//sets the end of the window to 1ms before the week with the holiday
|
//sets the end of the window to 1ms before the week with the holiday
|
||||||
const holiday_week_start = getWeekStart(holiday_date);
|
const holiday_week_start = getWeekStart(holiday_date);
|
||||||
|
|
@ -32,9 +48,8 @@ export class HolidayService {
|
||||||
return daily_hours;
|
return daily_hours;
|
||||||
}
|
}
|
||||||
|
|
||||||
//switch employeeId for email
|
async calculateHolidayPay( email: string, holiday_date: Date, modifier: number): Promise<number> {
|
||||||
async calculateHolidayPay( employee_id: number, holiday_date: Date, modifier: number): Promise<number> {
|
const hours = await this.computeHoursPrevious4WeeksByEmail(email, holiday_date);
|
||||||
const hours = await this.computeHoursPrevious4Weeks(employee_id, holiday_date);
|
|
||||||
const daily_rate = Math.min(hours, 8);
|
const daily_rate = Math.min(hours, 8);
|
||||||
this.logger.debug(`Holiday pay calculation: hours= ${hours.toFixed(2)}`);
|
this.logger.debug(`Holiday pay calculation: hours= ${hours.toFixed(2)}`);
|
||||||
return daily_rate * modifier;
|
return daily_rate * modifier;
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,13 @@ import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||||
export class CsvExportController {
|
export class CsvExportController {
|
||||||
constructor(private readonly csvService: CsvExportService) {}
|
constructor(private readonly csvService: CsvExportService) {}
|
||||||
|
|
||||||
@Get('csv')
|
@Get('csv/:year/:period_no')
|
||||||
@Header('Content-Type', 'text/csv; charset=utf-8')
|
@Header('Content-Type', 'text/csv; charset=utf-8')
|
||||||
@Header('Content-Dispoition', 'attachment; filename="export.csv"')
|
@Header('Content-Disposition', 'attachment; filename="export.csv"')
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.ACCOUNTING, RoleEnum.HR)
|
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.ACCOUNTING, RoleEnum.HR)
|
||||||
async exportCsv(@Query() options: ExportCsvOptionsDto,
|
async exportCsv(@Query() options: ExportCsvOptionsDto,
|
||||||
@Query('period') periodId: string ): Promise<Buffer> {
|
@Query('period') periodId: string ): Promise<Buffer> {
|
||||||
|
//modify to accept year and period_number
|
||||||
//sets default values
|
//sets default values
|
||||||
const companies = options.companies && options.companies.length ? options.companies :
|
const companies = options.companies && options.companies.length ? options.companies :
|
||||||
[ ExportCompany.TARGO, ExportCompany.SOLUCOM];
|
[ ExportCompany.TARGO, ExportCompany.SOLUCOM];
|
||||||
|
|
@ -28,11 +28,10 @@ export class CsvExportController {
|
||||||
const all = await this.csvService.collectTransaction(Number(periodId), companies);
|
const all = await this.csvService.collectTransaction(Number(periodId), companies);
|
||||||
|
|
||||||
//filters by type
|
//filters by type
|
||||||
const filtered = all.filter(r => {
|
const filtered = all.filter(row => {
|
||||||
switch (r.bank_code.toLocaleLowerCase()) {
|
switch (row.bank_code.toLocaleLowerCase()) {
|
||||||
case 'holiday' : return types.includes(ExportType.HOLIDAY);
|
case 'holiday' : return types.includes(ExportType.HOLIDAY);
|
||||||
case 'vacation' : return types.includes(ExportType.VACATION);
|
case 'vacation' : return types.includes(ExportType.VACATION);
|
||||||
case 'sick-leave': return types.includes(ExportType.SICK_LEAVE);
|
|
||||||
case 'expenses' : return types.includes(ExportType.EXPENSES);
|
case 'expenses' : return types.includes(ExportType.EXPENSES);
|
||||||
default : return types.includes(ExportType.SHIFTS);
|
default : return types.includes(ExportType.SHIFTS);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,47 @@
|
||||||
import { IsArray, IsEnum, IsOptional } from "class-validator";
|
import { Transform } from "class-transformer";
|
||||||
|
import { IsBoolean, IsInt, IsOptional, Max, Min } from "class-validator";
|
||||||
|
|
||||||
export enum ExportType {
|
function toBoolean(v: any) {
|
||||||
SHIFTS = 'Quart de travail',
|
if(typeof v === 'boolean') return v;
|
||||||
EXPENSES = 'Depenses',
|
if(typeof v === 'string') return ['true', '1', 'on','yes'].includes(v.toLowerCase());
|
||||||
HOLIDAY = 'Ferie',
|
return false;
|
||||||
VACATION = 'Vacance',
|
|
||||||
SICK_LEAVE = 'Absence'
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ExportCompany {
|
|
||||||
TARGO = 'Targo',
|
|
||||||
SOLUCOM = 'Solucom',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExportCsvOptionsDto {
|
export class ExportCsvOptionsDto {
|
||||||
@IsOptional()
|
|
||||||
@IsArray()
|
|
||||||
@IsEnum(ExportCompany, { each: true })
|
|
||||||
companies?: ExportCompany[];
|
|
||||||
|
|
||||||
@IsOptional()
|
@Transform(({ value }) => parseInt(value,10))
|
||||||
@IsArray()
|
@IsInt() @Min(2023)
|
||||||
@IsEnum(ExportType, { each: true })
|
year! : number;
|
||||||
type?: ExportType[];
|
|
||||||
|
@Transform(({ value }) => parseInt(value,10))
|
||||||
|
@IsInt() @Min(1) @Max(26)
|
||||||
|
period_no!: number;
|
||||||
|
|
||||||
|
@IsOptional() @IsBoolean()
|
||||||
|
@Transform(({ value }) => toBoolean(value))
|
||||||
|
approved? : boolean = true;
|
||||||
|
|
||||||
|
@IsOptional() @IsBoolean()
|
||||||
|
@Transform(({ value }) => toBoolean(value))
|
||||||
|
shifts? : boolean = true;
|
||||||
|
|
||||||
|
@IsOptional() @IsBoolean()
|
||||||
|
@Transform(({ value }) => toBoolean(value))
|
||||||
|
expenses? : boolean = true;
|
||||||
|
|
||||||
|
@IsOptional() @IsBoolean()
|
||||||
|
@Transform(({ value }) => toBoolean(value))
|
||||||
|
holiday? : boolean = true;
|
||||||
|
|
||||||
|
@IsOptional() @IsBoolean()
|
||||||
|
@Transform(({ value }) => toBoolean(value))
|
||||||
|
vacation? : boolean = true;
|
||||||
|
|
||||||
|
@IsOptional() @IsBoolean()
|
||||||
|
@Transform(({ value }) => toBoolean(value))
|
||||||
|
targo? : boolean = true;
|
||||||
|
|
||||||
|
@IsOptional() @IsBoolean()
|
||||||
|
@Transform(({ value }) => toBoolean(value))
|
||||||
|
solucom? : boolean = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
import { PrismaService } from "src/prisma/prisma.service";
|
||||||
import { ExportCompany } from "../dtos/export-csv-options.dto";
|
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
||||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
|
||||||
|
|
||||||
export interface CsvRow {
|
export interface CsvRow {
|
||||||
company_code: number;
|
company_code: number;
|
||||||
|
|
@ -14,135 +13,189 @@ export interface CsvRow {
|
||||||
holiday_date?: string;
|
holiday_date?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Filters = {
|
||||||
|
types: {
|
||||||
|
shifts: boolean;
|
||||||
|
expenses: boolean;
|
||||||
|
holiday: boolean;
|
||||||
|
vacation: boolean;
|
||||||
|
};
|
||||||
|
companies: {
|
||||||
|
targo: boolean;
|
||||||
|
solucom: boolean;
|
||||||
|
};
|
||||||
|
approved: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CsvExportService {
|
export class CsvExportService {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
async collectTransaction( period_id: number, companies: ExportCompany[], approved: boolean = true):
|
async collectTransaction(
|
||||||
Promise<CsvRow[]> {
|
year: number,
|
||||||
|
period_no: number,
|
||||||
const company_codes = companies.map(c => c === ExportCompany.TARGO ? 1 : 2);
|
filters: Filters,
|
||||||
|
approved: boolean = true
|
||||||
|
): Promise<CsvRow[]> {
|
||||||
|
//fetch period
|
||||||
const period = await this.prisma.payPeriods.findFirst({
|
const period = await this.prisma.payPeriods.findFirst({
|
||||||
where: { pay_period_no: period_id },
|
where: { pay_year: year, pay_period_no: period_no },
|
||||||
|
select: { period_start: true, period_end: true },
|
||||||
});
|
});
|
||||||
if(!period) throw new NotFoundException(`Pay period ${period_id} not found`);
|
if(!period) throw new NotFoundException(`Pay period ${ year }-${ period_no } not found`);
|
||||||
|
|
||||||
const start_date = period.period_start;
|
const start = period.period_start;
|
||||||
const end_date = period.period_end;
|
const end = period.period_end;
|
||||||
|
|
||||||
const approved_filter = approved ? { is_approved: true } : {};
|
//fetch company codes from .env
|
||||||
|
const comapany_codes = this.resolveCompanyCodes(filters.companies);
|
||||||
|
if(comapany_codes.length === 0) throw new BadRequestException('No company selected');
|
||||||
|
|
||||||
//fetching shifts
|
//Flag types
|
||||||
const shifts = await this.prisma.shifts.findMany({
|
const { shifts: want_shifts, expenses: want_expense, holiday: want_holiday, vacation: want_vacation } = filters.types;
|
||||||
where: {
|
if(!want_shifts && !want_expense && !want_holiday && !want_vacation) {
|
||||||
date: { gte: start_date, lte: end_date },
|
throw new BadRequestException(' No export type selected ');
|
||||||
...approved_filter,
|
|
||||||
timesheet: {
|
|
||||||
employee: { company_code: { in: company_codes} } },
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
bank_code: true,
|
|
||||||
timesheet: { include: {
|
|
||||||
employee: { include: {
|
|
||||||
user:true,
|
|
||||||
supervisor: { include: {
|
|
||||||
user:true } } } } } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
//fetching expenses
|
|
||||||
const expenses = await this.prisma.expenses.findMany({
|
|
||||||
where: {
|
|
||||||
date: { gte: start_date, lte: end_date },
|
|
||||||
...approved_filter,
|
|
||||||
timesheet: { employee: { company_code: { in: company_codes} } },
|
|
||||||
},
|
|
||||||
include: { bank_code: true,
|
|
||||||
timesheet: { include: {
|
|
||||||
employee: { include: {
|
|
||||||
user: true,
|
|
||||||
supervisor: { include: {
|
|
||||||
user:true } } } } } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
//fetching leave requests
|
|
||||||
const leaves = await this.prisma.leaveRequests.findMany({
|
|
||||||
where : {
|
|
||||||
start_date_time: { gte: start_date, lte: end_date },
|
|
||||||
employee: { company_code: { in: company_codes } },
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
bank_code: true,
|
|
||||||
employee: { include: {
|
|
||||||
user: true,
|
|
||||||
supervisor: { include: {
|
|
||||||
user: true } } } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const rows: CsvRow[] = [];
|
|
||||||
|
|
||||||
//Shifts Mapping
|
|
||||||
for (const shift of shifts) {
|
|
||||||
const emp = shift.timesheet.employee;
|
|
||||||
const week_number = this.computeWeekNumber(start_date, shift.date);
|
|
||||||
const hours = this.computeHours(shift.start_time, shift.end_time);
|
|
||||||
|
|
||||||
rows.push({
|
|
||||||
company_code: emp.company_code,
|
|
||||||
external_payroll_id: emp.external_payroll_id,
|
|
||||||
full_name: `${emp.user.first_name} ${emp.user.last_name}`,
|
|
||||||
bank_code: shift.bank_code.bank_code,
|
|
||||||
quantity_hours: hours,
|
|
||||||
amount: undefined,
|
|
||||||
week_number,
|
|
||||||
pay_date: this.formatDate(end_date),
|
|
||||||
holiday_date: undefined,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Expenses Mapping
|
const approved_filter = filters.approved? { is_approved: true } : {};
|
||||||
for (const e of expenses) {
|
|
||||||
const emp = e.timesheet.employee;
|
|
||||||
const week_number = this.computeWeekNumber(start_date, e.date);
|
|
||||||
|
|
||||||
rows.push({
|
//Prisma queries
|
||||||
company_code: emp.company_code,
|
const [shifts, expenses] = await Promise.all([
|
||||||
external_payroll_id: emp.external_payroll_id,
|
want_shifts || want_expense || want_holiday || want_vacation
|
||||||
full_name: `${emp.user.first_name} ${emp.user.last_name}`,
|
])
|
||||||
bank_code: e.bank_code.bank_code,
|
|
||||||
quantity_hours: undefined,
|
|
||||||
amount: Number(e.amount),
|
|
||||||
week_number,
|
|
||||||
pay_date: this.formatDate(end_date),
|
|
||||||
holiday_date: undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//Leaves Mapping
|
|
||||||
for(const l of leaves) {
|
|
||||||
if(!l.bank_code) continue;
|
|
||||||
const emp = l.employee;
|
|
||||||
const start = l.start_date_time;
|
|
||||||
const end = l.end_date_time ?? start;
|
|
||||||
|
|
||||||
const week_number = this.computeWeekNumber(start_date, start);
|
|
||||||
const hours = this.computeHours(start, end);
|
|
||||||
|
|
||||||
rows.push({
|
|
||||||
company_code: emp.company_code,
|
|
||||||
external_payroll_id: emp.external_payroll_id,
|
|
||||||
full_name: `${emp.user.first_name} ${emp.user.last_name}`,
|
|
||||||
bank_code: l.bank_code.bank_code,
|
// const company_codes = companies.map(c => c === ExportCompany.TARGO ? 1 : 2);
|
||||||
quantity_hours: hours,
|
|
||||||
amount: undefined,
|
// const period = await this.prisma.payPeriods.findFirst({
|
||||||
week_number,
|
// where: { pay_period_no: period_id },
|
||||||
pay_date: this.formatDate(end_date),
|
// });
|
||||||
holiday_date: undefined,
|
// if(!period) throw new NotFoundException(`Pay period ${period_id} not found`);
|
||||||
});
|
|
||||||
}
|
// const start_date = period.period_start;
|
||||||
|
// const end_date = period.period_end;
|
||||||
|
|
||||||
|
// const included_shifts = await this.prisma.shifts.findMany({
|
||||||
|
// where: { }
|
||||||
|
// })
|
||||||
|
|
||||||
|
// const approved_filter = approved ? { is_approved: true } : {};
|
||||||
|
|
||||||
|
// //fetching shifts
|
||||||
|
// const shifts = await this.prisma.shifts.findMany({
|
||||||
|
// where: {
|
||||||
|
// date: { gte: start_date, lte: end_date },
|
||||||
|
// ...approved_filter,
|
||||||
|
// timesheet: {
|
||||||
|
// employee: { company_code: { in: company_codes} } },
|
||||||
|
// },
|
||||||
|
// include: {
|
||||||
|
// bank_code: true,
|
||||||
|
// timesheet: { include: {
|
||||||
|
// employee: { include: {
|
||||||
|
// user:true,
|
||||||
|
// supervisor: { include: {
|
||||||
|
// user:true } } } } } },
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// //fetching expenses
|
||||||
|
// const expenses = await this.prisma.expenses.findMany({
|
||||||
|
// where: {
|
||||||
|
// date: { gte: start_date, lte: end_date },
|
||||||
|
// ...approved_filter,
|
||||||
|
// timesheet: { employee: { company_code: { in: company_codes} } },
|
||||||
|
// },
|
||||||
|
// include: { bank_code: true,
|
||||||
|
// timesheet: { include: {
|
||||||
|
// employee: { include: {
|
||||||
|
// user: true,
|
||||||
|
// supervisor: { include: {
|
||||||
|
// user:true } } } } } },
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// //fetching leave requests
|
||||||
|
// const leaves = await this.prisma.leaveRequests.findMany({
|
||||||
|
// where : {
|
||||||
|
// start_date_time: { gte: start_date, lte: end_date },
|
||||||
|
// employee: { company_code: { in: company_codes } },
|
||||||
|
// },
|
||||||
|
// include: {
|
||||||
|
// bank_code: true,
|
||||||
|
// employee: { include: {
|
||||||
|
// user: true,
|
||||||
|
// supervisor: { include: {
|
||||||
|
// user: true } } } },
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const rows: CsvRow[] = [];
|
||||||
|
|
||||||
|
// //Shifts Mapping
|
||||||
|
// for (const shift of shifts) {
|
||||||
|
// const emp = shift.timesheet.employee;
|
||||||
|
// const week_number = this.computeWeekNumber(start_date, shift.date);
|
||||||
|
// const hours = this.computeHours(shift.start_time, shift.end_time);
|
||||||
|
|
||||||
|
// rows.push({
|
||||||
|
// company_code: emp.company_code,
|
||||||
|
// external_payroll_id: emp.external_payroll_id,
|
||||||
|
// full_name: `${emp.user.first_name} ${emp.user.last_name}`,
|
||||||
|
// bank_code: shift.bank_code.bank_code,
|
||||||
|
// quantity_hours: hours,
|
||||||
|
// amount: undefined,
|
||||||
|
// week_number,
|
||||||
|
// pay_date: this.formatDate(end_date),
|
||||||
|
// holiday_date: undefined,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //Expenses Mapping
|
||||||
|
// for (const e of expenses) {
|
||||||
|
// const emp = e.timesheet.employee;
|
||||||
|
// const week_number = this.computeWeekNumber(start_date, e.date);
|
||||||
|
|
||||||
|
// rows.push({
|
||||||
|
// company_code: emp.company_code,
|
||||||
|
// external_payroll_id: emp.external_payroll_id,
|
||||||
|
// full_name: `${emp.user.first_name} ${emp.user.last_name}`,
|
||||||
|
// bank_code: e.bank_code.bank_code,
|
||||||
|
// quantity_hours: undefined,
|
||||||
|
// amount: Number(e.amount),
|
||||||
|
// week_number,
|
||||||
|
// pay_date: this.formatDate(end_date),
|
||||||
|
// holiday_date: undefined,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //Leaves Mapping
|
||||||
|
// for(const l of leaves) {
|
||||||
|
// if(!l.bank_code) continue;
|
||||||
|
// const emp = l.employee;
|
||||||
|
// const start = l.start_date_time;
|
||||||
|
// const end = l.end_date_time ?? start;
|
||||||
|
|
||||||
|
// const week_number = this.computeWeekNumber(start_date, start);
|
||||||
|
// const hours = this.computeHours(start, end);
|
||||||
|
|
||||||
|
// rows.push({
|
||||||
|
// company_code: emp.company_code,
|
||||||
|
// external_payroll_id: emp.external_payroll_id,
|
||||||
|
// full_name: `${emp.user.first_name} ${emp.user.last_name}`,
|
||||||
|
// bank_code: l.bank_code.bank_code,
|
||||||
|
// quantity_hours: hours,
|
||||||
|
// amount: undefined,
|
||||||
|
// week_number,
|
||||||
|
// pay_date: this.formatDate(end_date),
|
||||||
|
// holiday_date: undefined,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
//Final Mapping and sorts
|
//Final Mapping and sorts
|
||||||
return rows.sort((a,b) => {
|
return rows.sort((a,b) => {
|
||||||
|
|
@ -155,6 +208,9 @@ export class CsvExportService {
|
||||||
return a.week_number - b.week_number;
|
return a.week_number - b.week_number;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
resolveCompanyCodes(companies: { targo: boolean; solucom: boolean; }) {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
generateCsv(rows: CsvRow[]): Buffer {
|
generateCsv(rows: CsvRow[]): Buffer {
|
||||||
const header = [
|
const header = [
|
||||||
|
|
@ -172,7 +228,7 @@ export class CsvExportService {
|
||||||
const body = rows.map(r => [
|
const body = rows.map(r => [
|
||||||
r.company_code,
|
r.company_code,
|
||||||
r.external_payroll_id,
|
r.external_payroll_id,
|
||||||
`${r.full_name.replace(/"/g, '""')}"`,
|
`${r.full_name.replace(/"/g, '""')}`,
|
||||||
r.bank_code,
|
r.bank_code,
|
||||||
r.quantity_hours?.toFixed(2) ?? '',
|
r.quantity_hours?.toFixed(2) ?? '',
|
||||||
r.week_number,
|
r.week_number,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,13 @@ export class ExpenseDto {
|
||||||
|
|
||||||
export type DayShiftsDto = ShiftDto[];
|
export type DayShiftsDto = ShiftDto[];
|
||||||
|
|
||||||
|
export class DetailedShifts {
|
||||||
|
shifts: DayShiftsDto;
|
||||||
|
total_hours: number;
|
||||||
|
short_date: string;
|
||||||
|
break_durations?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class DayExpensesDto {
|
export class DayExpensesDto {
|
||||||
cash: ExpenseDto[] = [];
|
cash: ExpenseDto[] = [];
|
||||||
km : ExpenseDto[] = [];
|
km : ExpenseDto[] = [];
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ export type DayKey = 'sun'|'mon'|'tue'|'wed'|'thu'|'fri'|'sat';
|
||||||
|
|
||||||
//DB line types
|
//DB line types
|
||||||
type ShiftRow = { date: Date; start_time: Date; end_time: Date; is_approved?: boolean };
|
type ShiftRow = { date: Date; start_time: Date; end_time: Date; is_approved?: boolean };
|
||||||
type ExpenseRow = {date: Date; amount: number; type: string; is_approved?: boolean };
|
type ExpenseRow = { date: Date; amount: number; type: string; is_approved?: boolean };
|
||||||
|
|
||||||
export function dayKeyFromDate(date: Date, useUTC = true): DayKey {
|
export function dayKeyFromDate(date: Date, useUTC = true): DayKey {
|
||||||
const index = useUTC ? date.getUTCDay() : date.getDay(); // 0=Sunday..6=Saturday
|
const index = useUTC ? date.getUTCDay() : date.getDay(); // 0=Sunday..6=Saturday
|
||||||
|
|
@ -98,6 +98,7 @@ export function buildWeek( week_start: Date, week_end: Date, shifts: ShiftRow[],
|
||||||
for (const shift of week_shifts) {
|
for (const shift of week_shifts) {
|
||||||
const key = dayKeyFromDate(shift.date, true);
|
const key = dayKeyFromDate(shift.date, true);
|
||||||
week.shifts[key].push({
|
week.shifts[key].push({
|
||||||
|
shifts: [],
|
||||||
start: toTimeString(shift.start_time),
|
start: toTimeString(shift.start_time),
|
||||||
end : toTimeString(shift.end_time),
|
end : toTimeString(shift.end_time),
|
||||||
is_approved: shift.is_approved ?? true,
|
is_approved: shift.is_approved ?? true,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user