206 lines
8.3 KiB
TypeScript
206 lines
8.3 KiB
TypeScript
import { Router } from 'express';
|
|
import { hrController } from './hr.controller';
|
|
import { portalController } from './portal.controller';
|
|
import { authenticate, authorize } from '../../shared/middleware/auth';
|
|
import multer from 'multer';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import crypto from 'crypto';
|
|
import { config } from '../../config';
|
|
|
|
const router = Router();
|
|
const expenseClaimsUploadDir = path.join(config.upload.path, 'expense-claims');
|
|
|
|
if (!fs.existsSync(expenseClaimsUploadDir)) {
|
|
fs.mkdirSync(expenseClaimsUploadDir, { recursive: true });
|
|
}
|
|
|
|
const expenseClaimStorage = multer.diskStorage({
|
|
destination: (_req, _file, cb) => cb(null, expenseClaimsUploadDir),
|
|
filename: (_req, file, cb) => {
|
|
const safeName = (file.originalname || 'file').replace(/[^a-zA-Z0-9.-]/g, '_');
|
|
cb(null, `${crypto.randomUUID()}-${safeName}`);
|
|
},
|
|
});
|
|
|
|
const expenseClaimUpload = multer({
|
|
storage: expenseClaimStorage,
|
|
limits: { fileSize: config.upload.maxFileSize },
|
|
|
|
fileFilter: (_req, file, cb) => {
|
|
const allowedTypes = [
|
|
'image/jpeg',
|
|
'image/png',
|
|
'image/webp',
|
|
'image/gif',
|
|
'application/pdf',
|
|
];
|
|
|
|
if (!allowedTypes.includes(file.mimetype)) {
|
|
return cb(
|
|
new Error('نوع الملف غير مدعوم. يرجى رفع صورة أو ملف PDF.')
|
|
);
|
|
}
|
|
|
|
cb(null, true);
|
|
},
|
|
});
|
|
|
|
router.use(authenticate);
|
|
|
|
// ========== EMPLOYEE PORTAL (authenticate only, scoped by employeeId) ==========
|
|
|
|
router.get('/portal/me', portalController.getMe);
|
|
router.get('/portal/loans', portalController.getMyLoans);
|
|
router.post('/portal/loans', portalController.submitLoanRequest);
|
|
router.get('/portal/leave-balance', portalController.getMyLeaveBalance);
|
|
router.get('/portal/leaves', portalController.getMyLeaves);
|
|
router.post('/portal/leaves', portalController.submitLeaveRequest);
|
|
|
|
router.get(
|
|
'/portal/managed-leaves',
|
|
authorize('department_leave_requests', '*', 'read'),
|
|
portalController.getManagedLeaves
|
|
);
|
|
|
|
router.post(
|
|
'/portal/managed-leaves/:id/approve',
|
|
authorize('department_leave_requests', '*', 'approve'),
|
|
portalController.approveManagedLeave
|
|
);
|
|
|
|
router.post(
|
|
'/portal/managed-leaves/:id/reject',
|
|
authorize('department_leave_requests', '*', 'approve'),
|
|
portalController.rejectManagedLeave
|
|
);
|
|
|
|
router.get('/portal/overtime-requests', portalController.getMyOvertimeRequests);
|
|
router.post('/portal/overtime-requests', portalController.submitOvertimeRequest);
|
|
|
|
router.get(
|
|
'/portal/managed-overtime-requests',
|
|
authorize('department_overtime_requests', '*', 'view'),
|
|
portalController.getManagedOvertimeRequests
|
|
);
|
|
|
|
router.post(
|
|
'/portal/managed-overtime-requests/:attendanceId/approve',
|
|
authorize('department_overtime_requests', '*', 'approve'),
|
|
portalController.approveManagedOvertimeRequest
|
|
);
|
|
|
|
router.post(
|
|
'/portal/managed-overtime-requests/:attendanceId/reject',
|
|
authorize('department_overtime_requests', '*', 'approve'),
|
|
portalController.rejectManagedOvertimeRequest
|
|
);
|
|
|
|
router.get('/portal/purchase-requests', portalController.getMyPurchaseRequests);
|
|
router.post('/portal/purchase-requests', portalController.submitPurchaseRequest);
|
|
router.get('/portal/attendance', portalController.getMyAttendance);
|
|
router.get('/portal/salaries', portalController.getMySalaries);
|
|
|
|
router.get('/portal/expense-claims', portalController.getMyExpenseClaims);
|
|
router.post(
|
|
'/portal/expense-claims',
|
|
(req, res, next) => {
|
|
expenseClaimUpload.single('attachment')(req, res, (error: any) => {
|
|
if (error) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: error.message || 'تعذر رفع المرفق',
|
|
});
|
|
}
|
|
|
|
next();
|
|
});
|
|
},
|
|
portalController.submitExpenseClaim
|
|
);
|
|
router.get(
|
|
'/portal/expense-claims/attachments/:attachmentId/view',
|
|
portalController.viewExpenseClaimAttachment
|
|
);
|
|
router.get('/portal/managed-expense-claims', authorize('department_expense_claims', '*', 'read'), portalController.getManagedExpenseClaims);
|
|
|
|
router.post(
|
|
'/portal/managed-expense-claims/:id/approve',
|
|
authorize('department_expense_claims', '*', 'approve'),
|
|
portalController.approveManagedExpenseClaim
|
|
);
|
|
|
|
router.post(
|
|
'/portal/managed-expense-claims/:id/reject',
|
|
authorize('department_expense_claims', '*', 'approve'),
|
|
portalController.rejectManagedExpenseClaim
|
|
);
|
|
|
|
// ========== EMPLOYEES ==========
|
|
|
|
router.get('/employees', authorize('hr', 'employees', 'read'), hrController.findAllEmployees);
|
|
router.get('/employees/:id', authorize('hr', 'employees', 'read'), hrController.findEmployeeById);
|
|
router.post('/employees', authorize('hr', 'employees', 'create'), hrController.createEmployee);
|
|
router.put('/employees/:id', authorize('hr', 'employees', 'update'), hrController.updateEmployee);
|
|
router.post('/employees/:id/terminate', authorize('hr', 'employees', 'terminate'), hrController.terminateEmployee);
|
|
|
|
// ========== ATTENDANCE ==========
|
|
|
|
router.post('/attendance', authorize('hr', 'attendance', 'create'), hrController.recordAttendance);
|
|
router.get('/attendance/:employeeId', authorize('hr', 'attendance', 'read'), hrController.getAttendance);
|
|
router.post('/attendance/sync', authorize('hr', 'attendance', 'create'), hrController.bulkSyncAttendance);
|
|
|
|
// ========== LEAVES ==========
|
|
|
|
router.get('/leaves', authorize('hr', 'leaves', 'read'), hrController.findAllLeaves);
|
|
router.post('/leaves', authorize('hr', 'leaves', 'create'), hrController.createLeaveRequest);
|
|
router.post('/leaves/:id/approve', authorize('hr', 'leaves', 'approve'), hrController.approveLeave);
|
|
router.post('/leaves/:id/reject', authorize('hr', 'leaves', 'approve'), hrController.rejectLeave);
|
|
|
|
// ========== SALARIES ==========
|
|
|
|
router.post('/salaries/process', authorize('hr', 'salaries', 'process'), hrController.processSalary);
|
|
|
|
// ========== DEPARTMENTS ==========
|
|
|
|
router.get('/departments', authorize('hr', 'all', 'read'), hrController.findAllDepartments);
|
|
router.get('/departments/hierarchy', authorize('hr', 'all', 'read'), hrController.getDepartmentsHierarchy);
|
|
router.post('/departments', authorize('hr', 'all', 'create'), hrController.createDepartment);
|
|
router.put('/departments/:id', authorize('hr', 'all', 'update'), hrController.updateDepartment);
|
|
router.delete('/departments/:id', authorize('hr', 'all', 'delete'), hrController.deleteDepartment);
|
|
|
|
// ========== POSITIONS ==========
|
|
|
|
router.get('/positions', authorize('hr', 'all', 'read'), hrController.findAllPositions);
|
|
|
|
// ========== LOANS ==========
|
|
|
|
router.get('/loans', authorize('hr', 'all', 'read'), hrController.findAllLoans);
|
|
router.get('/loans/:id', authorize('hr', 'all', 'read'), hrController.findLoanById);
|
|
router.post('/loans', authorize('hr', 'all', 'create'), hrController.createLoan);
|
|
router.post('/loans/:id/approve', authorize('hr', 'all', 'approve'), hrController.approveLoan);
|
|
router.post('/loans/:id/reject', authorize('hr', 'all', 'approve'), hrController.rejectLoan);
|
|
router.post('/loans/:id/pay-installment', authorize('hr', 'all', 'update'), hrController.recordLoanInstallmentPayment);
|
|
|
|
// ========== PURCHASE REQUESTS ==========
|
|
|
|
router.get('/purchase-requests', authorize('hr', 'all', 'read'), hrController.findAllPurchaseRequests);
|
|
router.get('/purchase-requests/:id', authorize('hr', 'all', 'read'), hrController.findPurchaseRequestById);
|
|
router.post('/purchase-requests', authorize('hr', 'all', 'create'), hrController.createPurchaseRequest);
|
|
router.post('/purchase-requests/:id/approve', authorize('hr', 'all', 'approve'), hrController.approvePurchaseRequest);
|
|
router.post('/purchase-requests/:id/reject', authorize('hr', 'all', 'approve'), hrController.rejectPurchaseRequest);
|
|
|
|
// ========== LEAVE ENTITLEMENTS ==========
|
|
|
|
router.get('/leave-balance/:employeeId', authorize('hr', 'all', 'read'), hrController.getLeaveBalance);
|
|
router.get('/leave-entitlements', authorize('hr', 'all', 'read'), hrController.findAllLeaveEntitlements);
|
|
router.post('/leave-entitlements', authorize('hr', 'all', 'create'), hrController.upsertLeaveEntitlement);
|
|
|
|
// ========== EMPLOYEE CONTRACTS ==========
|
|
|
|
router.get('/contracts', authorize('hr', 'all', 'read'), hrController.findAllEmployeeContracts);
|
|
router.get('/contracts/:id', authorize('hr', 'all', 'read'), hrController.findEmployeeContractById);
|
|
router.post('/contracts', authorize('hr', 'all', 'create'), hrController.createEmployeeContract);
|
|
router.put('/contracts/:id', authorize('hr', 'all', 'update'), hrController.updateEmployeeContract);
|
|
|
|
export default router; |