updates
This commit is contained in:
@@ -313,54 +313,77 @@ class HRService {
|
||||
// ========== LEAVES ==========
|
||||
|
||||
async createLeaveRequest(data: any, userId: string) {
|
||||
const allowedLeaveTypes = ['ANNUAL', 'HOURLY'];
|
||||
const allowedLeaveTypes = ['ANNUAL', 'HOURLY'];
|
||||
const normalizedLeaveType = String(data.leaveType || '').toUpperCase();
|
||||
|
||||
if (!allowedLeaveTypes.includes(String(data.leaveType || '').toUpperCase())) {
|
||||
throw new AppError(400, 'نوع الإجازة غير مدعوم - Only ANNUAL and HOURLY leave types are allowed');
|
||||
}
|
||||
|
||||
const normalizedLeaveType = String(data.leaveType).toUpperCase();
|
||||
const days = this.calculateLeaveDays(data.startDate, data.endDate);
|
||||
const startDate = new Date(data.startDate);
|
||||
const year = startDate.getFullYear();
|
||||
|
||||
const ent = await prisma.leaveEntitlement.findUnique({
|
||||
where: {
|
||||
employeeId_year_leaveType: {
|
||||
employeeId: data.employeeId,
|
||||
year,
|
||||
leaveType: normalizedLeaveType,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (ent) {
|
||||
const available = ent.totalDays + ent.carriedOver - ent.usedDays;
|
||||
if (days > available) {
|
||||
throw new AppError(400, `رصيد الإجازة غير كافٍ - Insufficient leave balance. Available: ${available}, Requested: ${days}`);
|
||||
if (!allowedLeaveTypes.includes(normalizedLeaveType)) {
|
||||
throw new AppError(400, 'نوع الإجازة غير مدعوم - Only ANNUAL and HOURLY leave types are allowed');
|
||||
}
|
||||
|
||||
const startDate = new Date(data.startDate);
|
||||
const endDate = new Date(data.endDate);
|
||||
|
||||
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
|
||||
throw new AppError(400, 'تاريخ أو وقت الإجازة غير صالح');
|
||||
}
|
||||
|
||||
const isInvalidRange = normalizedLeaveType === 'HOURLY'
|
||||
? endDate <= startDate
|
||||
: endDate < startDate;
|
||||
|
||||
if (isInvalidRange) {
|
||||
throw new AppError(400, 'وقت/تاريخ النهاية يجب أن يكون بعد البداية');
|
||||
}
|
||||
|
||||
const days = normalizedLeaveType === 'HOURLY'
|
||||
? 0
|
||||
: this.calculateLeaveDays(startDate, endDate);
|
||||
|
||||
const year = startDate.getFullYear();
|
||||
|
||||
if (normalizedLeaveType !== 'HOURLY') {
|
||||
const ent = await prisma.leaveEntitlement.findUnique({
|
||||
where: {
|
||||
employeeId_year_leaveType: {
|
||||
employeeId: data.employeeId,
|
||||
year,
|
||||
leaveType: normalizedLeaveType,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (ent) {
|
||||
const available = ent.totalDays + ent.carriedOver - ent.usedDays;
|
||||
if (days > available) {
|
||||
throw new AppError(400, `رصيد الإجازة غير كافٍ - Insufficient leave balance. Available: ${available}, Requested: ${days}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const leave = await prisma.leave.create({
|
||||
data: {
|
||||
employeeId: data.employeeId,
|
||||
leaveType: normalizedLeaveType,
|
||||
startDate,
|
||||
endDate,
|
||||
days,
|
||||
reason: data.reason || undefined,
|
||||
},
|
||||
include: {
|
||||
employee: true,
|
||||
},
|
||||
});
|
||||
|
||||
await AuditLogger.log({
|
||||
entityType: 'LEAVE',
|
||||
entityId: leave.id,
|
||||
action: 'CREATE',
|
||||
userId,
|
||||
});
|
||||
|
||||
return leave;
|
||||
}
|
||||
|
||||
const leave = await prisma.leave.create({
|
||||
data: {
|
||||
...data,
|
||||
leaveType: normalizedLeaveType,
|
||||
days,
|
||||
},
|
||||
include: {
|
||||
employee: true,
|
||||
},
|
||||
});
|
||||
|
||||
await AuditLogger.log({
|
||||
entityType: 'LEAVE',
|
||||
entityId: leave.id,
|
||||
action: 'CREATE',
|
||||
userId,
|
||||
});
|
||||
|
||||
return leave;
|
||||
}
|
||||
async approveLeave(id: string, approvedBy: string, userId: string) {
|
||||
const leave = await prisma.leave.update({
|
||||
where: { id },
|
||||
|
||||
@@ -144,19 +144,65 @@ export class PortalController {
|
||||
}
|
||||
}
|
||||
|
||||
async submitLeaveRequest(req: AuthRequest, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const data = {
|
||||
...req.body,
|
||||
startDate: new Date(req.body.startDate),
|
||||
endDate: new Date(req.body.endDate),
|
||||
};
|
||||
const leave = await portalService.submitLeaveRequest(req.user?.employeeId, data, req.user!.id);
|
||||
res.status(201).json(ResponseFormatter.success(leave, 'تم إرسال طلب الإجازة - Leave request submitted'));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
async submitLeaveRequest(req: AuthRequest, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const body = { ...req.body };
|
||||
const leaveType = String(body.leaveType || '').toUpperCase();
|
||||
|
||||
let startDate: Date;
|
||||
let endDate: Date;
|
||||
|
||||
if (leaveType === 'HOURLY' && body.leaveDate && body.startTime && body.endTime) {
|
||||
startDate = new Date(`${body.leaveDate}T${body.startTime}:00+03:00`);
|
||||
endDate = new Date(`${body.leaveDate}T${body.endTime}:00+03:00`);
|
||||
} else {
|
||||
startDate = new Date(body.startDate);
|
||||
endDate = new Date(body.endDate);
|
||||
}
|
||||
|
||||
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'تاريخ أو وقت الإجازة غير صالح - Invalid leave date or time',
|
||||
});
|
||||
}
|
||||
|
||||
const isInvalidRange = leaveType === 'HOURLY'
|
||||
? endDate <= startDate
|
||||
: endDate < startDate;
|
||||
|
||||
if (isInvalidRange) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'وقت/تاريخ النهاية يجب أن يكون بعد البداية - End date/time must be after start date/time',
|
||||
});
|
||||
}
|
||||
|
||||
const data = {
|
||||
leaveType,
|
||||
startDate,
|
||||
endDate,
|
||||
reason: body.reason || undefined,
|
||||
};
|
||||
|
||||
const leave = await portalService.submitLeaveRequest(
|
||||
req.user?.employeeId,
|
||||
data,
|
||||
req.user!.id
|
||||
);
|
||||
|
||||
res
|
||||
.status(201)
|
||||
.json(
|
||||
ResponseFormatter.success(
|
||||
leave,
|
||||
'تم إرسال طلب الإجازة - Leave request submitted'
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
async getMyPurchaseRequests(req: AuthRequest, res: Response, next: NextFunction) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user