fix(shifts): clean
This commit is contained in:
parent
0a2369d5a5
commit
4527b0e7f7
|
|
@ -71,10 +71,10 @@ async function getOrCreateTimesheet(employee_id: number, start_date: Date) {
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
// --- Bank codes (pondérés: surtout G1 = régulier) ---
|
// --- Bank codes (pondérés: surtout G1 = régulier) ---
|
||||||
const BANKS = ['G1', 'G56', 'G48', 'G700', 'G105', 'G305', 'G43'] as const;
|
const BANKS = ['G1', 'G56', 'G48', 'G700', 'G105', 'G305'] as const;
|
||||||
const WEIGHTED_CODES = [
|
const WEIGHTED_CODES = [
|
||||||
'G1','G1','G1','G1','G1','G1','G1','G1', // 8x régulier
|
'G1','G1','G1','G1','G1','G1','G1','G1','G1','G1','G1','G1',
|
||||||
'G56','G48','G700','G105','G305','G43'
|
'G56','G48','G104','G105','G305','G1','G1','G1','G1','G1','G1'
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const bcRows = await prisma.bankCodes.findMany({
|
const bcRows = await prisma.bankCodes.findMany({
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,152 @@
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { PrismaService } from '../../../prisma/prisma.service';
|
import { PrismaService } from '../../../prisma/prisma.service';
|
||||||
import { getWeekStart, getWeekEnd, computeHours } from 'src/common/utils/date-utils';
|
import { getWeekStart, getWeekEnd, computeHours } from 'src/common/utils/date-utils';
|
||||||
|
import { Prisma } from '@prisma/client';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OvertimeService {
|
export class OvertimeService {
|
||||||
|
|
||||||
private logger = new Logger(OvertimeService.name);
|
private logger = new Logger(OvertimeService.name);
|
||||||
private daily_max = 12; // maximum for regular hours per day
|
private daily_max = 8; // maximum for regular hours per day
|
||||||
private weekly_max = 80; //maximum for regular hours per week
|
private weekly_max = 40; //maximum for regular hours per week
|
||||||
|
private INCLUDED_TYPES = ['EMERGENCY', 'EVENING','OVERTIME','REGULAR'] as const; // included types for weekly overtime calculation
|
||||||
|
|
||||||
constructor(private prisma: PrismaService) {}
|
constructor(private prisma: PrismaService) {}
|
||||||
|
|
||||||
//calculate Daily overtime
|
//calculate daily overtime
|
||||||
getDailyOvertimeHours(start: Date, end: Date): number {
|
async getDailyOvertimeHoursForDay(employee_id: number, date: Date): Promise<number> {
|
||||||
const hours = computeHours(start, end, 5);
|
const shifts = await this.prisma.shifts.findMany({
|
||||||
const overtime = Math.max(0, hours - this.daily_max);
|
where: { date: date, timesheet: { employee_id: employee_id } },
|
||||||
this.logger.debug(`getDailyOvertimeHours : ${overtime.toFixed(2)}h (threshold ${this.daily_max})`);
|
select: { start_time: true, end_time: true },
|
||||||
return overtime;
|
});
|
||||||
|
const total = shifts.map((shift)=>
|
||||||
|
computeHours(shift.start_time, shift.end_time, 5)).reduce((sum, hours)=> sum + hours, 0);
|
||||||
|
const overtime = Math.max(0, total - this.daily_max);
|
||||||
|
|
||||||
|
this.logger.debug(`[OVERTIME]-[DAILY] total=${total.toFixed(2)}h, overtime= ${overtime.toFixed(2)}h`);
|
||||||
|
return overtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
//calculate Weekly overtime
|
//calculate Weekly overtime
|
||||||
//switch employeeId for email
|
async getWeeklyOvertimeHours(employee_id: number, ref_date: Date): Promise<number> {
|
||||||
async getWeeklyOvertimeHours(employeeId: number, refDate: Date): Promise<number> {
|
const week_start = getWeekStart(ref_date);
|
||||||
const week_start = getWeekStart(refDate);
|
const week_end = getWeekEnd(week_start);
|
||||||
const week_end = getWeekEnd(week_start);
|
|
||||||
|
|
||||||
//fetches all shifts containing hours
|
//fetches all shifts from INCLUDED_TYPES array
|
||||||
const shifts = await this.prisma.shifts.findMany({
|
const included_shifts = await this.prisma.shifts.findMany({
|
||||||
where: { timesheet: { employee_id: employeeId, shift: {
|
where: {
|
||||||
every: {date: { gte: week_start, lte: week_end } }
|
date: { gte:week_start, lte: week_end },
|
||||||
|
timesheet: { employee_id },
|
||||||
|
bank_code: { type: { in: this.INCLUDED_TYPES as unknown as string[] } },
|
||||||
},
|
},
|
||||||
},
|
select: { start_time: true, end_time: true },
|
||||||
},
|
orderBy: [{date: 'asc'}, {start_time:'asc'}],
|
||||||
select: { start_time: true, end_time: true },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//calculate total hours of those shifts minus weekly Max to find total overtime hours
|
//calculate total hours of those shifts minus weekly Max to find total overtime hours
|
||||||
const total = shifts.map(shift => computeHours(shift.start_time, shift.end_time, 5))
|
const total = included_shifts.map(shift => computeHours(shift.start_time, shift.end_time, 5))
|
||||||
.reduce((sum, hours)=> sum+hours, 0);
|
.reduce((sum, hours)=> sum+hours, 0);
|
||||||
const overtime = Math.max(0, total - this.weekly_max);
|
const overtime = Math.max(0, total - this.weekly_max);
|
||||||
|
|
||||||
this.logger.debug(`weekly total = ${total.toFixed(2)}h, weekly Overtime= ${overtime.toFixed(2)}h`);
|
this.logger.debug(`[OVERTIME]-[WEEKLY] total=${total.toFixed(2)}h, overtime= ${overtime.toFixed(2)}h`);
|
||||||
return overtime;
|
return overtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
//apply modifier to overtime hours
|
//transform REGULAR shifts to OVERTIME when exceed 40hrs of included_types of shift
|
||||||
calculateOvertimePay(overtime_hours: number, modifier: number): number {
|
async transformRegularHoursToWeeklyOvertime(
|
||||||
const pay = overtime_hours * modifier;
|
employee_id: number,
|
||||||
this.logger.debug(`Overtime payable hours = ${pay.toFixed(2)} (hours ${overtime_hours}, modifier ${modifier})`);
|
ref_date: Date,
|
||||||
|
tx?: Prisma.TransactionClient,
|
||||||
|
): Promise<void> {
|
||||||
|
//ensures the use of the transaction if needed. fallback to this.prisma if no transaction is detected.
|
||||||
|
const db = tx ?? this.prisma;
|
||||||
|
|
||||||
return pay;
|
//calculate weekly overtime
|
||||||
|
const overtime_hours = await this.getWeeklyOvertimeHours(employee_id, ref_date);
|
||||||
|
if(overtime_hours <= 0) return;
|
||||||
|
|
||||||
|
const convert_to_minutes = Math.round(overtime_hours * 60);
|
||||||
|
|
||||||
|
const [regular, overtime] = await Promise.all([
|
||||||
|
db.bankCodes.findFirst({where: { type: 'REGULAR' }, select: { id: true } }),
|
||||||
|
db.bankCodes.findFirst({where: { type: 'OVERTIME'}, select: { id: true } }),
|
||||||
|
]);
|
||||||
|
if(!regular || !overtime) return;
|
||||||
|
|
||||||
|
const week_start = getWeekStart(ref_date);
|
||||||
|
const week_end = getWeekEnd(week_start);
|
||||||
|
|
||||||
|
//gets all regular shifts and order them by desc
|
||||||
|
const regular_shifts_desc = await db.shifts.findMany({
|
||||||
|
where: {
|
||||||
|
date: { gte:week_start, lte: week_end },
|
||||||
|
timesheet: { employee_id },
|
||||||
|
bank_code_id: regular.id,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
timesheet_id: true,
|
||||||
|
date: true,
|
||||||
|
start_time: true,
|
||||||
|
end_time: true,
|
||||||
|
is_remote: true,
|
||||||
|
comment: true,
|
||||||
|
},
|
||||||
|
orderBy: [{date: 'desc'}, {start_time:'desc'}],
|
||||||
|
});
|
||||||
|
|
||||||
|
let remaining_minutes = convert_to_minutes;
|
||||||
|
|
||||||
|
for(const shift of regular_shifts_desc) {
|
||||||
|
if(remaining_minutes <= 0) break;
|
||||||
|
|
||||||
|
const start = shift.start_time;
|
||||||
|
const end = shift.end_time;
|
||||||
|
const duration_in_minutes = Math.max(0, Math.round((end.getTime() - start.getTime())/60000));
|
||||||
|
if(duration_in_minutes === 0) continue;
|
||||||
|
|
||||||
|
if(duration_in_minutes <= remaining_minutes) {
|
||||||
|
await db.shifts.update({
|
||||||
|
where: { id: shift.id },
|
||||||
|
data: { bank_code_id: overtime.id },
|
||||||
|
});
|
||||||
|
remaining_minutes -= duration_in_minutes;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//sets the start_time of the new overtime shift
|
||||||
|
const new_overtime_start = new Date(end.getTime() - remaining_minutes * 60000);
|
||||||
|
|
||||||
|
//shorten the regular shift
|
||||||
|
await db.shifts.update({
|
||||||
|
where: { id: shift.id },
|
||||||
|
data: { end_time: new_overtime_start },
|
||||||
|
});
|
||||||
|
|
||||||
|
//creates the new overtime shift to replace the shorten regular shift
|
||||||
|
await db.shifts.create({
|
||||||
|
data: {
|
||||||
|
timesheet_id: shift.timesheet_id,
|
||||||
|
date: shift.date,
|
||||||
|
start_time: new_overtime_start,
|
||||||
|
end_time: end,
|
||||||
|
is_remote: shift.is_remote,
|
||||||
|
comment: shift.comment,
|
||||||
|
bank_code_id: overtime.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
remaining_minutes = 0;
|
||||||
|
}
|
||||||
|
this.logger.debug(`[OVERTIME]-[WEEKLY]-[TRANSFORM] emp=${employee_id}
|
||||||
|
week: ${week_start.toISOString().slice(0,10)}..${week_end.toISOString().slice(0,10)}
|
||||||
|
converted= ${(convert_to_minutes-remaining_minutes)/60}h`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//apply modifier to overtime hours
|
||||||
|
// calculateOvertimePay(overtime_hours: number, modifier: number): number {
|
||||||
|
// const pay = overtime_hours * modifier;
|
||||||
|
// this.logger.debug(`Overtime payable hours = ${pay.toFixed(2)} (hours ${overtime_hours}, modifier ${modifier})`);
|
||||||
|
|
||||||
|
// return pay;
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ export class ShiftPayloadDto {
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
is_remote!: boolean;
|
is_remote!: boolean;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
is_approved!: boolean;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@MaxLength(COMMENT_MAX_LENGTH)
|
@MaxLength(COMMENT_MAX_LENGTH)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { BadRequestException, ConflictException, Injectable, NotFoundException, UnprocessableEntityException } from "@nestjs/common";
|
import { BadRequestException, ConflictException, Injectable, Logger, NotFoundException, UnprocessableEntityException } from "@nestjs/common";
|
||||||
import { formatHHmm, toDateOnlyUTC, weekStartSundayUTC } from "../helpers/shifts-date-time-helpers";
|
import { formatHHmm, toDateOnlyUTC, weekStartSundayUTC } from "../helpers/shifts-date-time-helpers";
|
||||||
import { normalizeShiftPayload, overlaps } from "../utils/shifts.utils";
|
import { normalizeShiftPayload, overlaps } from "../utils/shifts.utils";
|
||||||
import { DayShiftResponse, UpsertAction } from "../types-and-interfaces/shifts-upsert.types";
|
import { DayShiftResponse, UpsertAction } from "../types-and-interfaces/shifts-upsert.types";
|
||||||
|
|
@ -8,13 +8,17 @@ import { Prisma, Shifts } from "@prisma/client";
|
||||||
import { UpsertShiftDto } from "../dtos/upsert-shift.dto";
|
import { UpsertShiftDto } from "../dtos/upsert-shift.dto";
|
||||||
import { BaseApprovalService } from "src/common/shared/base-approval.service";
|
import { BaseApprovalService } from "src/common/shared/base-approval.service";
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
import { PrismaService } from "src/prisma/prisma.service";
|
||||||
|
import { OvertimeService } from "src/modules/business-logics/services/overtime.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
||||||
|
private readonly logger = new Logger(ShiftsCommandService.name);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
prisma: PrismaService,
|
prisma: PrismaService,
|
||||||
private readonly emailResolver: EmployeeIdEmailResolver,
|
private readonly emailResolver: EmployeeIdEmailResolver,
|
||||||
private readonly bankTypeResolver: BankCodesResolver,
|
private readonly bankTypeResolver: BankCodesResolver,
|
||||||
|
private readonly overtimeService: OvertimeService,
|
||||||
) { super(prisma); }
|
) { super(prisma); }
|
||||||
|
|
||||||
//_____________________________________________________________________________________________
|
//_____________________________________________________________________________________________
|
||||||
|
|
@ -61,16 +65,16 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
||||||
//validation/sanitation
|
//validation/sanitation
|
||||||
//resolve bank_code_id using type
|
//resolve bank_code_id using type
|
||||||
const old_norm_shift = old_shift ? await normalizeShiftPayload(old_shift) : undefined;
|
const old_norm_shift = old_shift ? await normalizeShiftPayload(old_shift) : undefined;
|
||||||
if (old_norm_shift && old_norm_shift.end_time.getTime() <= old_norm_shift.start_time.getTime()) {
|
// if (old_norm_shift && old_norm_shift.end_time.getTime() <= old_norm_shift.start_time.getTime()) {
|
||||||
throw new UnprocessableEntityException(' old_shift.end_time must be > old_shift.start_time');
|
// throw new UnprocessableEntityException(' old_shift.end_time must be > old_shift.start_time');
|
||||||
}
|
// }
|
||||||
const old_bank_code_id: number | undefined = old_norm_shift ? (await this.bankTypeResolver.findByType(old_norm_shift.type, tx))?.id : undefined;
|
const old_bank_code_id: number | undefined = old_norm_shift ? (await this.bankTypeResolver.findByType(old_norm_shift.type, tx))?.id : undefined;
|
||||||
|
|
||||||
|
|
||||||
const new_norm_shift = new_shift ? await normalizeShiftPayload(new_shift) : undefined;
|
const new_norm_shift = new_shift ? await normalizeShiftPayload(new_shift) : undefined;
|
||||||
if (new_norm_shift && new_norm_shift.end_time.getTime() <= new_norm_shift.start_time.getTime()) {
|
// if (new_norm_shift && new_norm_shift.end_time.getTime() <= new_norm_shift.start_time.getTime()) {
|
||||||
throw new UnprocessableEntityException(' new_shift.end_time must be > new_shift.start_time');
|
// throw new UnprocessableEntityException(' new_shift.end_time must be > new_shift.start_time');
|
||||||
}
|
// }
|
||||||
const new_bank_code_id: number | undefined = new_norm_shift ? (await this.bankTypeResolver.findByType(new_norm_shift.type, tx))?.id : undefined;
|
const new_bank_code_id: number | undefined = new_norm_shift ? (await this.bankTypeResolver.findByType(new_norm_shift.type, tx))?.id : undefined;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -93,6 +97,7 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
||||||
start_time: old_norm_shift.start_time,
|
start_time: old_norm_shift.start_time,
|
||||||
end_time: old_norm_shift.end_time,
|
end_time: old_norm_shift.end_time,
|
||||||
is_remote: old_norm_shift.is_remote,
|
is_remote: old_norm_shift.is_remote,
|
||||||
|
is_approved: old_norm_shift.is_approved,
|
||||||
comment: old_comment,
|
comment: old_comment,
|
||||||
bank_code_id: old_bank_code_id,
|
bank_code_id: old_bank_code_id,
|
||||||
},
|
},
|
||||||
|
|
@ -100,28 +105,28 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//checks for overlaping shifts
|
// //checks for overlaping shifts
|
||||||
const assertNoOverlap = (exclude_shift_id?: number)=> {
|
// const assertNoOverlap = (exclude_shift_id?: number)=> {
|
||||||
if (!new_norm_shift) return;
|
// if (!new_norm_shift) return;
|
||||||
const overlap_with = day_shifts.filter((shift)=> {
|
// const overlap_with = day_shifts.filter((shift)=> {
|
||||||
if(exclude_shift_id && shift.id === exclude_shift_id) return false;
|
// if(exclude_shift_id && shift.id === exclude_shift_id) return false;
|
||||||
return overlaps(
|
// return overlaps(
|
||||||
new_norm_shift.start_time.getTime(),
|
// new_norm_shift.start_time.getTime(),
|
||||||
new_norm_shift.end_time.getTime(),
|
// new_norm_shift.end_time.getTime(),
|
||||||
shift.start_time.getTime(),
|
// shift.start_time.getTime(),
|
||||||
shift.end_time.getTime(),
|
// shift.end_time.getTime(),
|
||||||
);
|
// );
|
||||||
});
|
// });
|
||||||
|
|
||||||
if(overlap_with.length > 0) {
|
// if(overlap_with.length > 0) {
|
||||||
const conflicts = overlap_with.map((shift)=> ({
|
// const conflicts = overlap_with.map((shift)=> ({
|
||||||
start_time: formatHHmm(shift.start_time),
|
// start_time: formatHHmm(shift.start_time),
|
||||||
end_time: formatHHmm(shift.end_time),
|
// end_time: formatHHmm(shift.end_time),
|
||||||
type: shift.bank_code?.type ?? 'UNKNOWN',
|
// type: shift.bank_code?.type ?? 'UNKNOWN',
|
||||||
}));
|
// }));
|
||||||
throw new ConflictException({ error_code: 'SHIFT_OVERLAP', message: 'New shift overlaps with existing shift(s)', conflicts});
|
// throw new ConflictException({ error_code: 'SHIFT_OVERLAP', message: 'New shift overlaps with existing shift(s)', conflicts});
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
let action: UpsertAction;
|
let action: UpsertAction;
|
||||||
//_____________________________________________________________________________________________
|
//_____________________________________________________________________________________________
|
||||||
// DELETE
|
// DELETE
|
||||||
|
|
@ -143,7 +148,7 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
||||||
//_____________________________________________________________________________________________
|
//_____________________________________________________________________________________________
|
||||||
else if (!old_shift && new_shift) {
|
else if (!old_shift && new_shift) {
|
||||||
if (new_bank_code_id === undefined) throw new NotFoundException(`bank code not found for new_shift.type: ${new_norm_shift?.type ?? ''}`);
|
if (new_bank_code_id === undefined) throw new NotFoundException(`bank code not found for new_shift.type: ${new_norm_shift?.type ?? ''}`);
|
||||||
assertNoOverlap();
|
// assertNoOverlap();
|
||||||
await tx.shifts.create({
|
await tx.shifts.create({
|
||||||
data: {
|
data: {
|
||||||
timesheet_id: timesheet.id,
|
timesheet_id: timesheet.id,
|
||||||
|
|
@ -165,7 +170,7 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
||||||
if (new_bank_code_id === undefined) throw new NotFoundException(`bank code not found for new_shift.type: ${new_norm_shift?.type ?? ''}`);
|
if (new_bank_code_id === undefined) throw new NotFoundException(`bank code not found for new_shift.type: ${new_norm_shift?.type ?? ''}`);
|
||||||
const existing = await findExactOldShift();
|
const existing = await findExactOldShift();
|
||||||
if(!existing) throw new NotFoundException({ error_code: 'SHIFT_STALE', message: 'The shift was modified or deleted by someone else'});
|
if(!existing) throw new NotFoundException({ error_code: 'SHIFT_STALE', message: 'The shift was modified or deleted by someone else'});
|
||||||
assertNoOverlap(existing.id);
|
// assertNoOverlap(existing.id);
|
||||||
|
|
||||||
await tx.shifts.update({
|
await tx.shifts.update({
|
||||||
where: {
|
where: {
|
||||||
|
|
@ -182,23 +187,33 @@ export class ShiftsCommandService extends BaseApprovalService<Shifts> {
|
||||||
action = 'updated';
|
action = 'updated';
|
||||||
} else throw new BadRequestException('At least one of old_shift or new_shift must be provided');
|
} else throw new BadRequestException('At least one of old_shift or new_shift must be provided');
|
||||||
|
|
||||||
|
//switches regular hours to overtime hours when exceeds 40hrs per week.
|
||||||
|
await this.overtimeService.transformRegularHoursToWeeklyOvertime(employee_id, date_only, tx);
|
||||||
|
|
||||||
//Reload the day (truth source)
|
//Reload the day (truth source)
|
||||||
const fresh_day = await tx.shifts.findMany({
|
const fresh_day = await tx.shifts.findMany({
|
||||||
where: {
|
where: {
|
||||||
date: date_only,
|
date: date_only,
|
||||||
timesheet_id: timesheet.id,
|
timesheet_id: timesheet.id,
|
||||||
},
|
},
|
||||||
include: {
|
include: { bank_code: true },
|
||||||
bank_code: true
|
orderBy: { start_time: 'asc' },
|
||||||
},
|
|
||||||
orderBy: {
|
|
||||||
start_time: 'asc'
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [ daily_overtime, weekly_overtime ] = await Promise.all([
|
||||||
|
this.overtimeService.getDailyOvertimeHoursForDay(employee_id, date_only),
|
||||||
|
this.overtimeService.getWeeklyOvertimeHours(employee_id, date_only),
|
||||||
|
]);
|
||||||
|
this.logger.debug(`[OVERTIME] employee_id= ${employee_id}, date=${date_only.toISOString().slice(0,10)}
|
||||||
|
| daily= ${daily_overtime.toFixed(2)}h, weekly: ${weekly_overtime.toFixed(2)}h, (action:${action})`);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.warn(`Failed to compute overtime after ${action} : ${(error as Error).message}`);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
action,
|
action,
|
||||||
day: fresh_day.map<DayShiftResponse>((shift)=> ({
|
day: fresh_day.map<DayShiftResponse>((shift) => ({
|
||||||
start_time: formatHHmm(shift.start_time),
|
start_time: formatHHmm(shift.start_time),
|
||||||
end_time: formatHHmm(shift.end_time),
|
end_time: formatHHmm(shift.end_time),
|
||||||
type: shift.bank_code?.type ?? 'UNKNOWN',
|
type: shift.bank_code?.type ?? 'UNKNOWN',
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,15 @@ export function resolveBankCodeByType(type: string): Promise<number> {
|
||||||
|
|
||||||
export function normalizeShiftPayload(payload: ShiftPayloadDto) {
|
export function normalizeShiftPayload(payload: ShiftPayloadDto) {
|
||||||
//normalize shift's infos
|
//normalize shift's infos
|
||||||
const start_time = timeFromHHMMUTC(payload.start_time);
|
const start_time = payload.start_time;
|
||||||
const end_time = timeFromHHMMUTC(payload.end_time );
|
const end_time = payload.end_time;
|
||||||
const type = (payload.type || '').trim().toUpperCase();
|
const type = (payload.type || '').trim().toUpperCase();
|
||||||
const is_remote = payload.is_remote === true;
|
const is_remote = payload.is_remote === true;
|
||||||
|
const is_approved = payload.is_approved === false;
|
||||||
//normalize comment
|
//normalize comment
|
||||||
const raw_comment = payload.comment ?? null;
|
const raw_comment = payload.comment ?? null;
|
||||||
const trimmed = typeof raw_comment === 'string' ? raw_comment.trim() : null;
|
const trimmed = typeof raw_comment === 'string' ? raw_comment.trim() : null;
|
||||||
const comment = trimmed && trimmed.length > 0 ? trimmed: null;
|
const comment = trimmed && trimmed.length > 0 ? trimmed: null;
|
||||||
|
|
||||||
return { start_time, end_time, type, is_remote, comment };
|
return { start_time, end_time, type, is_remote, comment, is_approved };
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user