refactor(timesheet): added shift types and expenses type data
This commit is contained in:
parent
ea76435f4f
commit
0516736fa2
|
|
@ -5,18 +5,18 @@ const prisma = new PrismaClient();
|
||||||
async function main() {
|
async function main() {
|
||||||
const presets = [
|
const presets = [
|
||||||
// type, categorie, modifier, bank_code
|
// type, categorie, modifier, bank_code
|
||||||
['REGULAR' ,'SHIFT', 1.0 , 'G1'],
|
['REGULAR' ,'SHIFT' , 1.0 , 'G1' ],
|
||||||
['EVENING' ,'SHIFT', 1.25, 'G43'],
|
['OVERTIME' ,'SHIFT' , 2 , 'G43' ],
|
||||||
['Emergency','SHIFT', 2 , 'G48'],
|
['EMERGENCY' ,'SHIFT' , 2 , 'G48' ],
|
||||||
['HOLIDAY' ,'SHIFT', 2.0 , 'G700'],
|
['EVENING' ,'SHIFT' , 1.25, 'G56' ],
|
||||||
|
['SICK' ,'SHIFT' , 1.0 , 'G105'],
|
||||||
|
['PRIME_DISPO','EXPENSE', 1.0 , 'G202'],
|
||||||
['EXPENSES','EXPENSE', 1.0 , 'G517'],
|
['COMMISSION' ,'EXPENSE', 1.0 , 'G234'],
|
||||||
['MILEAGE' ,'EXPENSE', 0.72, 'G57'],
|
['VACATION' ,'SHIFT' , 1.0 , 'G305'],
|
||||||
['PER_DIEM','EXPENSE', 1.0 , 'G502'],
|
['PER_DIEM' ,'EXPENSE', 1.0 , 'G502'],
|
||||||
|
['MILEAGE' ,'EXPENSE', 0.72, 'G503'],
|
||||||
['SICK' ,'LEAVE', 1.0, 'G105'],
|
['EXPENSES' ,'EXPENSE', 1.0 , 'G517'],
|
||||||
['VACATION' ,'LEAVE', 1.0, 'G305'],
|
['HOLIDAY' ,'SHIFT' , 2.0 , 'G700'],
|
||||||
];
|
];
|
||||||
|
|
||||||
await prisma.bankCodes.createMany({
|
await prisma.bankCodes.createMany({
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ async function main() {
|
||||||
await prisma.expenses.create({
|
await prisma.expenses.create({
|
||||||
data: {
|
data: {
|
||||||
timesheet_id: ts.id,
|
timesheet_id: ts.id,
|
||||||
bank_code_id: map.get('G57')!,
|
bank_code_id: map.get('G503')!,
|
||||||
date,
|
date,
|
||||||
amount: km.toString(), // on stocke le nombre de km dans amount (si tu as un champ "quantity_km", remplace ici)
|
amount: km.toString(), // on stocke le nombre de km dans amount (si tu as un champ "quantity_km", remplace ici)
|
||||||
attachement: null,
|
attachement: null,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
export class ShiftDto {
|
export class ShiftDto {
|
||||||
start: string;
|
start: string;
|
||||||
end : string;
|
end : string;
|
||||||
bank_code: string;
|
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExpenseDto {
|
export class ExpenseDto {
|
||||||
amount: number;
|
amount: number;
|
||||||
bank_code: string;
|
total_mileage: number;
|
||||||
|
total_expense: number;
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -15,7 +15,10 @@ export type DayShiftsDto = ShiftDto[];
|
||||||
|
|
||||||
export class DetailedShifts {
|
export class DetailedShifts {
|
||||||
shifts: DayShiftsDto;
|
shifts: DayShiftsDto;
|
||||||
total_hours: number;
|
regular_hours: number;
|
||||||
|
evening_hours: number;
|
||||||
|
overtime_hours: number;
|
||||||
|
emergency_hours: number;
|
||||||
short_date: string;
|
short_date: string;
|
||||||
break_durations?: number;
|
break_durations?: number;
|
||||||
}
|
}
|
||||||
|
|
@ -23,7 +26,7 @@ export class DetailedShifts {
|
||||||
export class DayExpensesDto {
|
export class DayExpensesDto {
|
||||||
cash: ExpenseDto[] = [];
|
cash: ExpenseDto[] = [];
|
||||||
km : ExpenseDto[] = [];
|
km : ExpenseDto[] = [];
|
||||||
[otherType:string]: ExpenseDto[] | any; //pour si on ajoute d'autre type de dépenses
|
[otherType:string]: ExpenseDto[] | any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WeekDto {
|
export class WeekDto {
|
||||||
|
|
|
||||||
|
|
@ -46,55 +46,52 @@ export class TimesheetsQueryService {
|
||||||
const from = toUTCDateOnly(period.period_start);
|
const from = toUTCDateOnly(period.period_start);
|
||||||
const to = endOfDayUTC(period.period_end);
|
const to = endOfDayUTC(period.period_end);
|
||||||
|
|
||||||
//collects data from shifts and expenses
|
const raw_shifts = await this.prisma.shifts.findMany({
|
||||||
const [ raw_shifts, raw_expenses] = await Promise.all([
|
where: {
|
||||||
this.prisma.shifts.findMany({
|
timesheet: { is: { employee_id: employee.id } },
|
||||||
where: {
|
date: { gte: from, lte: to },
|
||||||
timesheet: { is: { employee_id: employee.id } },
|
},
|
||||||
date: { gte: from, lte: to },
|
select: {
|
||||||
},
|
date: true,
|
||||||
select: {
|
start_time: true,
|
||||||
date: true,
|
end_time: true,
|
||||||
start_time: true,
|
is_approved: true,
|
||||||
end_time: true,
|
bank_code: { select: { type: true } },
|
||||||
is_approved: true,
|
},
|
||||||
bank_code: { select: { bank_code: true } },
|
orderBy:[ { date:'asc'}, { start_time: 'asc'} ],
|
||||||
},
|
});
|
||||||
orderBy: [{date: 'asc'}, { start_time: 'asc' }],
|
|
||||||
}),
|
const raw_expenses = await this.prisma.expenses.findMany({
|
||||||
this.prisma.expenses.findMany({
|
where: {
|
||||||
where: {
|
timesheet: { is: { employee_id: employee.id } },
|
||||||
timesheet: { is: { employee_id: employee.id } },
|
date: { gte: from, lte: to },
|
||||||
date: { gte: from, lte: to },
|
},
|
||||||
},
|
select: {
|
||||||
select: {
|
date: true,
|
||||||
date: true,
|
amount: true,
|
||||||
amount: true,
|
is_approved: true,
|
||||||
is_approved: true,
|
bank_code: { select: { type: true } },
|
||||||
bank_code: { select: {
|
},
|
||||||
type: true,
|
orderBy: { date: 'asc' },
|
||||||
bank_code: true,
|
});
|
||||||
} },
|
|
||||||
},
|
const to_num = (value: any) => typeof value.toNumber === 'function' ? value.toNumber() : Number(value);
|
||||||
orderBy: { date: 'asc' },
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 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,
|
||||||
bank_code: shift.bank_code?.bank_code ?? '',
|
type: String(shift.bank_code?.type ?? '').toUpperCase(),
|
||||||
is_approved: shift.is_approved ?? true,
|
is_approved: shift.is_approved ?? true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const expenses: ExpenseRow[] = raw_expenses.map(expense => ({
|
const expenses: ExpenseRow[] = raw_expenses.map(expense => ({
|
||||||
date: expense.date,
|
date: expense.date,
|
||||||
amount: typeof (expense.amount as any)?.toNumber() === 'function' ?
|
amount: typeof (expense.amount as any)?.toNumber === 'function' ?
|
||||||
(expense.amount as any).toNumber() : Number(expense.amount),
|
(expense.amount as any).toNumber() : Number(expense.amount),
|
||||||
type: expense.bank_code?.type ?? 'CASH',
|
type: String(expense.bank_code?.type ?? '').toUpperCase(),
|
||||||
bank_code: expense.bank_code?.bank_code ?? '',
|
|
||||||
is_approved: expense.is_approved ?? true,
|
is_approved: expense.is_approved ?? true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,39 @@ import { DayExpensesDto, DayShiftsDto, DetailedShifts, ShiftDto, TimesheetPeriod
|
||||||
export const DAY_KEYS = ['sun','mon','tue','wed','thu','fri','sat'] as const;
|
export const DAY_KEYS = ['sun','mon','tue','wed','thu','fri','sat'] as const;
|
||||||
export type DayKey = typeof DAY_KEYS[number];
|
export type DayKey = typeof DAY_KEYS[number];
|
||||||
|
|
||||||
//DB line types
|
|
||||||
export type ShiftRow = { date: Date; start_time: Date; end_time: Date; bank_code: string; is_approved?: boolean };
|
|
||||||
export type ExpenseRow = { date: Date; amount: number; type: string; bank_code: 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
|
||||||
return DAY_KEYS[index];
|
return DAY_KEYS[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Date & Format
|
||||||
const MS_PER_DAY = 86_400_000;
|
const MS_PER_DAY = 86_400_000;
|
||||||
const MS_PER_HOUR = 3_600_000;
|
const MS_PER_HOUR = 3_600_000;
|
||||||
|
|
||||||
|
// Types
|
||||||
|
const SHIFT_TYPES = {
|
||||||
|
REGULAR: 'REGULAR',
|
||||||
|
EVENING: 'EVENING',
|
||||||
|
OVERTIME: 'OVERTIME',
|
||||||
|
EMERGENCY: 'EMERGENCY',
|
||||||
|
HOLIDAY: 'HOLIDAY',
|
||||||
|
VACATION: 'VACATION',
|
||||||
|
SICK: 'SICK',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const EXPENSE_TYPES = {
|
||||||
|
MILEAGE: 'MILEAGE',
|
||||||
|
EXPENSE: 'EXPENSES',
|
||||||
|
PER_DIEM: 'PER_DIEM',
|
||||||
|
COMMISSION: 'COMMISSION',
|
||||||
|
PRIME_DISPO: 'PRIME_DISPO',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
//DB line types
|
||||||
|
export type ShiftRow = { date: Date; start_time: Date; end_time: Date; is_approved?: boolean; type: string };
|
||||||
|
export type ExpenseRow = { date: Date; amount: number; type: string; is_approved?: boolean };
|
||||||
|
|
||||||
|
//helper functions
|
||||||
export function toUTCDateOnly(date: Date | string): Date {
|
export function toUTCDateOnly(date: Date | string): Date {
|
||||||
const d = new Date(date);
|
const d = new Date(date);
|
||||||
return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
|
return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
|
||||||
|
|
@ -45,22 +66,25 @@ export function round2(num: number) {
|
||||||
return Math.round(num * 100) / 100;
|
return Math.round(num * 100) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function shortDate(date:Date): string {
|
function shortDate(date:Date): string {
|
||||||
const mm = String(date.getUTCMonth()+1).padStart(2,'0');
|
const mm = String(date.getUTCMonth()+1).padStart(2,'0');
|
||||||
const dd = String(date.getUTCDate()).padStart(2,'0');
|
const dd = String(date.getUTCDate()).padStart(2,'0');
|
||||||
return `${mm}/${dd}`;
|
return `${mm}/${dd}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// export function makeEmptyDayShifts(): DayShiftsDto { return []; }
|
// Factories
|
||||||
|
|
||||||
export function makeEmptyDayExpenses(): DayExpensesDto { return {cash: [], km: []}; }
|
export function makeEmptyDayExpenses(): DayExpensesDto { return {cash: [], km: []}; }
|
||||||
|
|
||||||
export function makeEmptyWeek(week_start: Date): WeekDto {
|
export function makeEmptyWeek(week_start: Date): WeekDto {
|
||||||
const make_empty_shifts = (offset: number): DetailedShifts => ({
|
const make_empty_shifts = (offset: number): DetailedShifts => ({
|
||||||
shifts: [],
|
shifts: [],
|
||||||
total_hours: 0,
|
regular_hours: 0,
|
||||||
|
evening_hours: 0,
|
||||||
|
emergency_hours: 0,
|
||||||
|
overtime_hours: 0,
|
||||||
short_date: shortDate(addDays(week_start, offset)),
|
short_date: shortDate(addDays(week_start, offset)),
|
||||||
break_durations: undefined,
|
break_durations: 0,
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
is_approved: true,
|
is_approved: true,
|
||||||
|
|
@ -89,13 +113,6 @@ export function makeEmptyPeriod(): TimesheetPeriodDto {
|
||||||
return { week1: makeEmptyWeek(new Date()), week2: makeEmptyWeek(new Date()) };
|
return { week1: makeEmptyWeek(new Date()), week2: makeEmptyWeek(new Date()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
//needs ajusting according to DB's data for expenses types
|
|
||||||
export function normalizeExpenseBucket(db_type: string): 'km' | 'cash' {
|
|
||||||
const type = db_type.trim().toUpperCase();
|
|
||||||
if(type.includes('KM') || type.includes('MILEAGE')) return 'km';
|
|
||||||
return 'cash';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildWeek(
|
export function buildWeek(
|
||||||
week_start: Date,
|
week_start: Date,
|
||||||
week_end: Date,
|
week_end: Date,
|
||||||
|
|
@ -105,61 +122,127 @@ export function buildWeek(
|
||||||
const week = makeEmptyWeek(week_start);
|
const week = makeEmptyWeek(week_start);
|
||||||
let all_approved = true;
|
let all_approved = true;
|
||||||
|
|
||||||
//array of shifts per day ( to check for break_gaps and calculate daily total hours )
|
//breaks
|
||||||
const dayTimes: Record<DayKey, Array<{start:Date; end: Date;}>> = {
|
const day_times: Record<DayKey, Array<{ start: Date; end: Date }>> = DAY_KEYS.reduce((acc, key) => {
|
||||||
sun: [], mon: [], tue: [], wed: [],thu: [], fri: [], sat: [],
|
acc[key] = []; return acc;
|
||||||
};
|
}, {} as Record<DayKey, Array<{ start: Date; end: Date}>>);
|
||||||
|
|
||||||
|
//shifts's hour by type
|
||||||
|
type ShiftsHours =
|
||||||
|
{regular: number; evening: number; 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) => {
|
||||||
|
acc[key] = make_hours(); return acc;
|
||||||
|
}, {} as Record<DayKey, ShiftsHours>);
|
||||||
|
|
||||||
//Shifts mapped and filtered by dates
|
//expenses's amount by type
|
||||||
|
type ExpensesAmount =
|
||||||
|
{mileage: number; expense: number; 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) => {
|
||||||
|
acc[key] = make_amounts(); return acc;
|
||||||
|
}, {} as Record<DayKey, ExpensesAmount>);
|
||||||
|
|
||||||
|
const dayExpenseRows: Record<DayKey, { km: ExpenseRow[]; cash: ExpenseRow[] }> = DAY_KEYS.reduce((acc, key) => {
|
||||||
|
acc[key] = {km: [], cash: [] }; return acc;
|
||||||
|
}, {} as Record<DayKey, { km: ExpenseRow[], cash: ExpenseRow[] }>);
|
||||||
|
|
||||||
|
//regroup hours per type of shifts
|
||||||
const week_shifts = shifts.filter(shift => isBetweenUTC(shift.date, week_start, week_end));
|
const week_shifts = shifts.filter(shift => isBetweenUTC(shift.date, week_start, week_end));
|
||||||
for (const shift of week_shifts) {
|
for (const shift of shifts) {
|
||||||
const key = dayKeyFromDate(shift.date, true);
|
const key = dayKeyFromDate(shift.date, true);
|
||||||
dayTimes[key].push({start: shift.start_time, end:shift.end_time });
|
|
||||||
week.shifts[key].shifts.push({
|
week.shifts[key].shifts.push({
|
||||||
start: toTimeString(shift.start_time),
|
start: toTimeString(shift.start_time),
|
||||||
end : toTimeString(shift.end_time),
|
end: toTimeString(shift.end_time),
|
||||||
bank_code: shift.bank_code,
|
|
||||||
is_approved: shift.is_approved ?? true,
|
is_approved: shift.is_approved ?? true,
|
||||||
});
|
} as ShiftDto);
|
||||||
all_approved = all_approved && (shift.is_approved ?? true);
|
|
||||||
|
day_times[key].push({ start: shift.start_time, end: shift.end_time});
|
||||||
|
|
||||||
|
const duration = Math.max(0, (shift.end_time.getTime() - shift.start_time.getTime())/ MS_PER_HOUR);
|
||||||
|
const type = (shift.type || '').toUpperCase();
|
||||||
|
|
||||||
|
if (type === SHIFT_TYPES.REGULAR) day_hours[key].regular += duration;
|
||||||
|
else if( type === SHIFT_TYPES.EVENING) day_hours[key].evening += duration;
|
||||||
|
else if( type === SHIFT_TYPES.EMERGENCY) day_hours[key].emergency += duration;
|
||||||
|
else if( type === SHIFT_TYPES.OVERTIME) day_hours[key].overtime += duration;
|
||||||
|
else if( type === SHIFT_TYPES.SICK) day_hours[key].sick += duration;
|
||||||
|
else if( type === SHIFT_TYPES.VACATION) day_hours[key].vacation += duration;
|
||||||
|
else if( type === SHIFT_TYPES.HOLIDAY) day_hours[key].holiday += duration;
|
||||||
|
|
||||||
|
all_approved = all_approved && (shift.is_approved ?? true );
|
||||||
}
|
}
|
||||||
|
|
||||||
//Expenses mapped and filtered by dates
|
//regroupe amounts to type of expenses
|
||||||
const week_expenses = expenses.filter(expense => isBetweenUTC(expense.date, week_start, week_end));
|
const week_expenses = expenses.filter(expense => isBetweenUTC(expense.date, week_start, week_end));
|
||||||
for (const expense of week_expenses) {
|
for (const expense of week_expenses) {
|
||||||
const key = dayKeyFromDate(expense.date, true);
|
const key = dayKeyFromDate(expense.date, true);
|
||||||
const bucket = normalizeExpenseBucket(expense.type);
|
const type = (expense.type || '').toUpperCase();
|
||||||
if (!Array.isArray(week.expenses[key][bucket])) week.expenses[key][bucket] = [];
|
|
||||||
week.expenses[key][bucket].push({
|
if (type === EXPENSE_TYPES.MILEAGE) {
|
||||||
amount: round2(expense.amount),
|
day_amounts[key].mileage += expense.amount;
|
||||||
is_approved: expense.is_approved ?? true,
|
dayExpenseRows[key].km.push(expense);
|
||||||
bank_code: expense.bank_code,
|
} else if (type === EXPENSE_TYPES.EXPENSE) {
|
||||||
});
|
day_amounts[key].expense += expense.amount;
|
||||||
all_approved = all_approved && (expense.is_approved ?? true);
|
dayExpenseRows[key].cash.push(expense)
|
||||||
|
} else if (type === EXPENSE_TYPES.PER_DIEM) {
|
||||||
|
day_amounts[key].per_diem += expense.amount;
|
||||||
|
dayExpenseRows[key].cash.push(expense)
|
||||||
|
} else if (type === EXPENSE_TYPES.COMMISSION) {
|
||||||
|
day_amounts[key].commission += expense.amount;
|
||||||
|
dayExpenseRows[key].cash.push(expense)
|
||||||
|
} else if (type === EXPENSE_TYPES.PRIME_DISPO) {
|
||||||
|
day_amounts[key].prime_dispo += expense.amount;
|
||||||
|
dayExpenseRows[key].cash.push(expense)
|
||||||
|
}
|
||||||
|
all_approved = all_approved && (expense.is_approved ?? true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (const key of DAY_KEYS) {
|
for (const key of DAY_KEYS) {
|
||||||
//sorts shifts in chronological order
|
//return exposed dto data
|
||||||
const times = dayTimes[key].sort((a,b) => a.start.getTime() - b.start.getTime());
|
week.shifts[key].regular_hours = round2(day_hours[key].regular);
|
||||||
|
week.shifts[key].evening_hours = round2(day_hours[key].evening);
|
||||||
|
week.shifts[key].overtime_hours = round2(day_hours[key].overtime);
|
||||||
|
week.shifts[key].emergency_hours = round2(day_hours[key].emergency);
|
||||||
|
|
||||||
//daily total hours
|
//calculate gaps between shifts
|
||||||
const total = times.reduce((sum, time) => {
|
const times = day_times[key].sort((a,b) => a.start.getTime() - b.start.getTime());
|
||||||
const duration = (time.end.getTime() - time.start.getTime()) / MS_PER_HOUR;
|
let gaps = 0;
|
||||||
return sum + Math.max(0, duration);
|
for (let i = 1; i < times.length; i++) {
|
||||||
}, 0);
|
const gap = (times[i].start.getTime() - times[i - 1].end.getTime()) / MS_PER_HOUR;
|
||||||
week.shifts[key].total_hours = round2(total);
|
if(gap > 0) gaps += gap;
|
||||||
|
}
|
||||||
|
week.shifts[key].break_durations = round2(gaps);
|
||||||
|
|
||||||
//break_duration
|
//daily totals
|
||||||
if (times.length >= 2) {
|
const totals = day_amounts[key];
|
||||||
let break_gaps = 0;
|
const total_mileage = totals.mileage;
|
||||||
for (let i = 1; i < times.length; i++) {
|
const total_expense = totals.expense + totals.per_diem + totals.commission + totals.prime_dispo + totals.expense;
|
||||||
const gap = (times[i].start.getTime() - times[i-1].end.getTime()) / MS_PER_HOUR;
|
|
||||||
if(gap > 0) break_gaps += gap;
|
//pushing mileage rows
|
||||||
}
|
for(const row of dayExpenseRows[key].km) {
|
||||||
if(break_gaps > 0) week.shifts[key].break_durations = round2(break_gaps);
|
week.expenses[key].km.push({
|
||||||
|
amount: round2(row.amount),
|
||||||
|
total_mileage: round2(total_mileage),
|
||||||
|
total_expense: round2(total_expense),
|
||||||
|
is_approved: row.is_approved ?? true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//pushing expense rows
|
||||||
|
for(const row of dayExpenseRows[key].cash) {
|
||||||
|
week.expenses[key].cash.push({
|
||||||
|
amount: round2(row.amount),
|
||||||
|
total_mileage: round2(total_mileage),
|
||||||
|
total_expense: round2(total_expense),
|
||||||
|
is_approved: row.is_approved ?? true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
week.is_approved = all_approved;
|
week.is_approved = all_approved;
|
||||||
return week;
|
return week;
|
||||||
}
|
}
|
||||||
|
|
@ -179,4 +262,6 @@ export function buildPeriod(
|
||||||
week1: buildWeek(week1_start, week1_end, shifts, expenses),
|
week1: buildWeek(week1_start, week1_end, shifts, expenses),
|
||||||
week2: buildWeek(week2_start, week2_end, shifts, expenses),
|
week2: buildWeek(week2_start, week2_end, shifts, expenses),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user