Commit a901d48a authored by Mahmoud Aglan's avatar Mahmoud Aglan

feat(hr): add Leave Type management CRUD (أنواع الإجازات)

Full admin UI to create/edit/view/archive leave types with all rule
fields: entitlement, limits, pay percentage, carry-over, accumulation,
gender restriction, service requirements, and legal references.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent fc229f20
This diff is collapsed.
......@@ -18,10 +18,12 @@ class HrLeaveType extends Model
'default_days_per_year', 'max_days_per_year', 'pay_percentage',
'is_paid', 'requires_approval', 'requires_attachment',
'min_days_per_request', 'max_days_per_request', 'min_consecutive_annual',
'advance_notice_days', 'carry_over_allowed', 'max_carry_over_days',
'carry_over_expiry_months', 'accumulation_max_years',
'max_consecutive_days', 'max_per_occurrence', 'max_times_in_career',
'min_service_months', 'advance_notice_days',
'carry_over_allowed', 'max_carry_over_days',
'carry_over_expiry_months', 'is_accumulative', 'accumulation_max_years',
'gender_restriction', 'career_max_times', 'career_max_days',
'legal_reference', 'is_active', 'sort_order', 'rules_json',
'deduct_from_salary', 'legal_reference', 'is_active', 'sort_order', 'rules_json',
];
public static function allActive(): array
......
......@@ -65,6 +65,15 @@ return [
['POST', '/hr/attendance/approve', 'HR\Controllers\AttendanceController@approveBulk', ['auth', 'csrf'], 'hr.attendance.approve'],
['GET', '/hr/attendance/monthly/{employeeId:\d+}', 'HR\Controllers\AttendanceController@monthly', ['auth'], 'hr.attendance.view'],
// ── Leave Types (Admin) ──
['GET', '/hr/leave-types', 'HR\Controllers\LeaveTypeController@index', ['auth'], 'hr.leave.manage'],
['GET', '/hr/leave-types/create', 'HR\Controllers\LeaveTypeController@create', ['auth'], 'hr.leave.manage'],
['POST', '/hr/leave-types', 'HR\Controllers\LeaveTypeController@store', ['auth', 'csrf'], 'hr.leave.manage'],
['GET', '/hr/leave-types/{id:\d+}', 'HR\Controllers\LeaveTypeController@show', ['auth'], 'hr.leave.manage'],
['GET', '/hr/leave-types/{id:\d+}/edit', 'HR\Controllers\LeaveTypeController@edit', ['auth'], 'hr.leave.manage'],
['POST', '/hr/leave-types/{id:\d+}/update', 'HR\Controllers\LeaveTypeController@update', ['auth', 'csrf'], 'hr.leave.manage'],
['POST', '/hr/leave-types/{id:\d+}/archive', 'HR\Controllers\LeaveTypeController@archive', ['auth', 'csrf'], 'hr.leave.manage'],
// ── Leaves ──
['GET', '/hr/leaves', 'HR\Controllers\LeaveController@index', ['auth'], 'hr.leave.view'],
['GET', '/hr/leaves/request', 'HR\Controllers\LeaveController@requestForm', ['auth'], 'hr.leave.request'],
......
This diff is collapsed.
<?php $__template->layout('Layout.main'); ?>
<?php $__template->section('title'); ?>أنواع الإجازات<?php $__template->endSection(); ?>
<?php $__template->section('page_actions'); ?>
<?php if (can('hr.leave.manage')): ?>
<a href="/hr/leave-types/create" class="btn btn-primary" style="display:inline-flex;align-items:center;gap:6px;">
<i data-lucide="plus" style="width:16px;height:16px;"></i> إضافة نوع إجازة
</a>
<?php endif; ?>
<?php $__template->endSection(); ?>
<?php $__template->section('content'); ?>
<div class="card">
<div class="table-responsive">
<table class="data-table">
<thead>
<tr>
<th style="width:50px;">#</th>
<th>الكود</th>
<th>الاسم</th>
<th>التصنيف</th>
<th>الأيام/سنة</th>
<th>مدفوعة</th>
<th>نسبة الراتب</th>
<th>الجنس</th>
<th>ترحيل</th>
<th>الحالة</th>
<th>إجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($types)): ?>
<tr><td colspan="11" style="text-align:center;padding:40px;color:#9CA3AF;">لا يوجد أنواع إجازات</td></tr>
<?php else: ?>
<?php foreach ($types as $type): ?>
<tr>
<td><?= (int) $type['sort_order'] ?></td>
<td><code style="font-size:12px;background:#F3F4F6;padding:2px 6px;border-radius:4px;"><?= e($type['code']) ?></code></td>
<td><a href="/hr/leave-types/<?= (int) $type['id'] ?>"><?= e($type['name_ar']) ?></a></td>
<td><?= e($categories[$type['category'] ?? ''] ?? '-') ?></td>
<td><?= $type['default_days_per_year'] !== null ? number_format((float)$type['default_days_per_year'], 1) : '-' ?></td>
<td>
<?php if ((int) $type['is_paid']): ?>
<span style="color:#059669;">✓ مدفوعة</span>
<?php else: ?>
<span style="color:#DC2626;">✗ بدون راتب</span>
<?php endif; ?>
</td>
<td><?= number_format((float)$type['pay_percentage'], 0) ?>%</td>
<td>
<?php
$genderMap = ['male' => 'ذكور فقط', 'female' => 'إناث فقط'];
echo e($genderMap[$type['gender_restriction'] ?? ''] ?? 'الكل');
?>
</td>
<td>
<?php if ((int) $type['carry_over_allowed']): ?>
<span style="color:#059669;"></span>
<?php else: ?>
<span style="color:#9CA3AF;"></span>
<?php endif; ?>
</td>
<td>
<?php if ((int) $type['is_active']): ?>
<span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:#DEF7EC;color:#03543F;">مفعّل</span>
<?php else: ?>
<span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:#FDE8E8;color:#9B1C1C;">معطّل</span>
<?php endif; ?>
</td>
<td style="white-space:nowrap;">
<a href="/hr/leave-types/<?= (int) $type['id'] ?>" title="عرض" style="color:#2563EB;margin-inline-end:8px;"><i data-lucide="eye" style="width:16px;height:16px;"></i></a>
<a href="/hr/leave-types/<?= (int) $type['id'] ?>/edit" title="تعديل" style="color:#059669;"><i data-lucide="edit" style="width:16px;height:16px;"></i></a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<script>if(typeof lucide!=='undefined')lucide.createIcons();</script>
<?php $__template->endSection(); ?>
This diff is collapsed.
......@@ -124,6 +124,7 @@ MenuRegistry::register('hr', [
['label_ar' => 'الهيكل الراتبي', 'label_en' => 'Salary Structures', 'route' => '/hr/salary-structures', 'permission' => 'hr.employee.view_salary','order' => 5],
['label_ar' => 'الحضور والانصراف', 'label_en' => 'Attendance', 'route' => '/hr/attendance', 'permission' => 'hr.attendance.view', 'order' => 6],
['label_ar' => 'الإجازات', 'label_en' => 'Leaves', 'route' => '/hr/leaves', 'permission' => 'hr.leave.view', 'order' => 7],
['label_ar' => 'أنواع الإجازات', 'label_en' => 'Leave Types', 'route' => '/hr/leave-types', 'permission' => 'hr.leave.manage', 'order' => 8],
['label_ar' => 'كشوف الرواتب', 'label_en' => 'Payroll', 'route' => '/hr/payroll', 'permission' => 'hr.payroll.view', 'order' => 8],
['label_ar' => 'التأمينات الاجتماعية', 'label_en' => 'Social Insurance', 'route' => '/hr/insurance', 'permission' => 'hr.insurance.view', 'order' => 9],
['label_ar' => 'السلف والقروض', 'label_en' => 'Loans', 'route' => '/hr/loans', 'permission' => 'hr.loan.view', 'order' => 10],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment