Commit f99774c0 authored by Mahmoud Aglan's avatar Mahmoud Aglan

testing

parent c23742ac
...@@ -54,8 +54,7 @@ class DisciplinaryController extends Controller ...@@ -54,8 +54,7 @@ class DisciplinaryController extends Controller
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$employee = $this->currentEmployee(); $employee = $this->currentEmployee();
$data['status'] = 'reported'; $data['status'] = 'investigation';
$data['reported_by'] = $employee ? (int) $employee->id : null;
$data['created_at'] = date('Y-m-d H:i:s'); $data['created_at'] = date('Y-m-d H:i:s');
$data['updated_at'] = date('Y-m-d H:i:s'); $data['updated_at'] = date('Y-m-d H:i:s');
$data['created_by'] = $employee ? (int) $employee->id : null; $data['created_by'] = $employee ? (int) $employee->id : null;
...@@ -79,10 +78,6 @@ class DisciplinaryController extends Controller ...@@ -79,10 +78,6 @@ class DisciplinaryController extends Controller
$canAppeal = DisciplinaryService::canAppeal($action->toArray()); $canAppeal = DisciplinaryService::canAppeal($action->toArray());
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$reporter = $action->reported_by
? $db->selectOne("SELECT name FROM employees WHERE id = ?", [(int) $action->reported_by])
: null;
$decider = $action->decided_by $decider = $action->decided_by
? $db->selectOne("SELECT name FROM employees WHERE id = ?", [(int) $action->decided_by]) ? $db->selectOne("SELECT name FROM employees WHERE id = ?", [(int) $action->decided_by])
: null; : null;
...@@ -91,7 +86,6 @@ class DisciplinaryController extends Controller ...@@ -91,7 +86,6 @@ class DisciplinaryController extends Controller
'action' => $action, 'action' => $action,
'profile' => $profile, 'profile' => $profile,
'canAppeal' => $canAppeal, 'canAppeal' => $canAppeal,
'reporter' => $reporter,
'decider' => $decider, 'decider' => $decider,
]); ]);
} }
...@@ -103,7 +97,7 @@ class DisciplinaryController extends Controller ...@@ -103,7 +97,7 @@ class DisciplinaryController extends Controller
return $this->redirect('/hr/disciplinary')->withError('الإجراء التأديبي غير موجود'); return $this->redirect('/hr/disciplinary')->withError('الإجراء التأديبي غير موجود');
} }
if (!in_array($action->status, ['reported', 'under_investigation'], true)) { if (!in_array($action->status, ['investigation', 'pending_decision'], true)) {
return $this->redirect('/hr/disciplinary/' . $id)->withError('لا يمكن تعديل إجراء تأديبي في هذه الحالة'); return $this->redirect('/hr/disciplinary/' . $id)->withError('لا يمكن تعديل إجراء تأديبي في هذه الحالة');
} }
...@@ -122,7 +116,7 @@ class DisciplinaryController extends Controller ...@@ -122,7 +116,7 @@ class DisciplinaryController extends Controller
return $this->redirect('/hr/disciplinary')->withError('الإجراء التأديبي غير موجود'); return $this->redirect('/hr/disciplinary')->withError('الإجراء التأديبي غير موجود');
} }
if (!in_array($action->status, ['reported', 'under_investigation'], true)) { if (!in_array($action->status, ['investigation', 'pending_decision'], true)) {
return $this->redirect('/hr/disciplinary/' . $id)->withError('لا يمكن تعديل إجراء تأديبي في هذه الحالة'); return $this->redirect('/hr/disciplinary/' . $id)->withError('لا يمكن تعديل إجراء تأديبي في هذه الحالة');
} }
...@@ -146,27 +140,27 @@ class DisciplinaryController extends Controller ...@@ -146,27 +140,27 @@ class DisciplinaryController extends Controller
return $this->redirect('/hr/disciplinary')->withError('الإجراء التأديبي غير موجود'); return $this->redirect('/hr/disciplinary')->withError('الإجراء التأديبي غير موجود');
} }
if (!in_array($action->status, ['reported', 'under_investigation'], true)) { if (!in_array($action->status, ['investigation', 'pending_decision'], true)) {
return $this->redirect('/hr/disciplinary/' . $id)->withError('لا يمكن اتخاذ قرار في هذه الحالة'); return $this->redirect('/hr/disciplinary/' . $id)->withError('لا يمكن اتخاذ قرار في هذه الحالة');
} }
$penaltyType = trim((string) $request->post('penalty_type', '')); $penaltyType = trim((string) $request->post('penalty_type', ''));
$penaltyDays = (int) $request->post('penalty_days', 0); $penaltyDays = (int) $request->post('penalty_days', 0);
$enforcementDate = trim((string) $request->post('enforcement_date', date('Y-m-d'))); $effectiveDate = trim((string) $request->post('effective_date', date('Y-m-d')));
$decisionNotes = trim((string) $request->post('decision_notes', '')); $notes = trim((string) $request->post('notes', ''));
$errors = []; $errors = [];
if (!in_array($penaltyType, ['warning', 'deduction', 'suspension', 'demotion', 'termination'], true)) { if (!in_array($penaltyType, ['warning', 'wage_deduction', 'raise_postponement', 'suspension', 'demotion', 'termination'], true)) {
$errors[] = 'نوع الجزاء غير صالح'; $errors[] = 'نوع الجزاء غير صالح';
} }
// Validate against Art.58 limits // Validate against Art.58 limits
if (in_array($penaltyType, ['deduction', 'suspension'], true) && $penaltyDays > 0) { if (in_array($penaltyType, ['wage_deduction', 'suspension'], true) && $penaltyDays > 0) {
$limitErrors = DisciplinaryService::validatePenalty( $limitErrors = DisciplinaryService::validatePenalty(
(int) $action->employee_profile_id, (int) $action->employee_profile_id,
$penaltyType, $penaltyType,
$penaltyDays, $penaltyDays,
$enforcementDate $effectiveDate
); );
$errors = array_merge($errors, $limitErrors); $errors = array_merge($errors, $limitErrors);
} }
...@@ -180,17 +174,24 @@ class DisciplinaryController extends Controller ...@@ -180,17 +174,24 @@ class DisciplinaryController extends Controller
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$employee = $this->currentEmployee(); $employee = $this->currentEmployee();
$db->update('hr_disciplinary_actions', [ $updateData = [
'penalty_type' => $penaltyType, 'penalty_type' => $penaltyType,
'penalty_days' => $penaltyDays, 'effective_date' => $effectiveDate,
'enforcement_date' => $enforcementDate, 'notes' => $notes ?: null,
'decision_notes' => $decisionNotes ?: null, 'decided_by' => $employee ? (int) $employee->id : null,
'decided_by' => $employee ? (int) $employee->id : null, 'decided_at' => date('Y-m-d H:i:s'),
'decided_at' => date('Y-m-d H:i:s'), 'status' => 'decided',
'status' => 'enforced', 'updated_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'), 'updated_by' => $employee ? (int) $employee->id : null,
'updated_by' => $employee ? (int) $employee->id : null, ];
], '`id` = ?', [(int) $id]);
if ($penaltyType === 'wage_deduction') {
$updateData['wage_deduction_days'] = $penaltyDays;
} elseif ($penaltyType === 'suspension') {
$updateData['suspension_days'] = $penaltyDays;
}
$db->update('hr_disciplinary_actions', $updateData, '`id` = ?', [(int) $id]);
Logger::info("Disciplinary decision made", [ Logger::info("Disciplinary decision made", [
'action_id' => (int) $id, 'action_id' => (int) $id,
...@@ -212,8 +213,8 @@ class DisciplinaryController extends Controller ...@@ -212,8 +213,8 @@ class DisciplinaryController extends Controller
return $this->redirect('/hr/disciplinary/' . $id)->withError('انتهت فترة التظلم (7 أيام من تاريخ التنفيذ)'); return $this->redirect('/hr/disciplinary/' . $id)->withError('انتهت فترة التظلم (7 أيام من تاريخ التنفيذ)');
} }
$appealReason = trim((string) $request->post('appeal_reason', '')); $appealText = trim((string) $request->post('appeal_text', ''));
if ($appealReason === '') { if ($appealText === '') {
return $this->redirect('/hr/disciplinary/' . $id)->withError('سبب التظلم مطلوب'); return $this->redirect('/hr/disciplinary/' . $id)->withError('سبب التظلم مطلوب');
} }
...@@ -221,11 +222,11 @@ class DisciplinaryController extends Controller ...@@ -221,11 +222,11 @@ class DisciplinaryController extends Controller
$employee = $this->currentEmployee(); $employee = $this->currentEmployee();
$db->update('hr_disciplinary_actions', [ $db->update('hr_disciplinary_actions', [
'status' => 'appealed', 'status' => 'appealed',
'appeal_reason' => $appealReason, 'appeal_text' => $appealText,
'appeal_date' => date('Y-m-d'), 'appeal_date' => date('Y-m-d'),
'updated_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
'updated_by' => $employee ? (int) $employee->id : null, 'updated_by' => $employee ? (int) $employee->id : null,
], '`id` = ?', [(int) $id]); ], '`id` = ?', [(int) $id]);
return $this->redirect('/hr/disciplinary/' . $id)->withSuccess('تم تقديم التظلم بنجاح'); return $this->redirect('/hr/disciplinary/' . $id)->withSuccess('تم تقديم التظلم بنجاح');
...@@ -234,11 +235,10 @@ class DisciplinaryController extends Controller ...@@ -234,11 +235,10 @@ class DisciplinaryController extends Controller
private function extractData(Request $request): array private function extractData(Request $request): array
{ {
return [ return [
'employee_profile_id' => (int) $request->post('employee_profile_id', 0), 'employee_profile_id' => (int) $request->post('employee_profile_id', 0),
'incident_date' => trim((string) $request->post('incident_date', '')), 'incident_date' => trim((string) $request->post('incident_date', '')),
'incident_description' => trim((string) $request->post('incident_description', '')), 'incident_description' => trim((string) $request->post('incident_description', '')),
'investigation_notes' => trim((string) $request->post('investigation_notes', '')) ?: null, 'investigation_notes' => trim((string) $request->post('investigation_notes', '')) ?: null,
'violation_type' => trim((string) $request->post('violation_type', '')) ?: null,
]; ];
} }
......
...@@ -56,8 +56,7 @@ class EmployeeDocumentController extends Controller ...@@ -56,8 +56,7 @@ class EmployeeDocumentController extends Controller
{ {
$profileId = (int) $request->post('employee_profile_id', 0); $profileId = (int) $request->post('employee_profile_id', 0);
$documentType = trim((string) $request->post('document_type', '')); $documentType = trim((string) $request->post('document_type', ''));
$documentNumber = trim((string) $request->post('document_number', '')) ?: null; $titleAr = trim((string) $request->post('title_ar', '')) ?: null;
$issueDate = trim((string) $request->post('issue_date', '')) ?: null;
$expiryDate = trim((string) $request->post('expiry_date', '')) ?: null; $expiryDate = trim((string) $request->post('expiry_date', '')) ?: null;
$notes = trim((string) $request->post('notes', '')) ?: null; $notes = trim((string) $request->post('notes', '')) ?: null;
...@@ -69,14 +68,24 @@ class EmployeeDocumentController extends Controller ...@@ -69,14 +68,24 @@ class EmployeeDocumentController extends Controller
$errors[] = 'نوع المستند مطلوب'; $errors[] = 'نوع المستند مطلوب';
} }
// File is required (NOT NULL columns depend on it)
if (!isset($_FILES['document_file']) || $_FILES['document_file']['error'] !== UPLOAD_ERR_OK) {
$errors[] = 'يجب رفع ملف';
}
// Handle file upload // Handle file upload
$filePath = null; $filePath = null;
$originalFilename = '';
$storedFilename = '';
$fileSize = 0;
$mimeType = '';
if (isset($_FILES['document_file']) && $_FILES['document_file']['error'] === UPLOAD_ERR_OK) { if (isset($_FILES['document_file']) && $_FILES['document_file']['error'] === UPLOAD_ERR_OK) {
$allowedTypes = ['application/pdf', 'image/jpeg', 'image/png', 'image/jpg']; $allowedTypes = ['application/pdf', 'image/jpeg', 'image/png', 'image/jpg'];
$fileType = $_FILES['document_file']['type']; $mimeType = $_FILES['document_file']['type'];
$fileSize = $_FILES['document_file']['size']; $fileSize = (int) $_FILES['document_file']['size'];
$originalFilename = $_FILES['document_file']['name'];
if (!in_array($fileType, $allowedTypes, true)) { if (!in_array($mimeType, $allowedTypes, true)) {
$errors[] = 'نوع الملف غير مسموح. المسموح: PDF, JPEG, PNG'; $errors[] = 'نوع الملف غير مسموح. المسموح: PDF, JPEG, PNG';
} }
if ($fileSize > 5 * 1024 * 1024) { if ($fileSize > 5 * 1024 * 1024) {
...@@ -91,12 +100,12 @@ class EmployeeDocumentController extends Controller ...@@ -91,12 +100,12 @@ class EmployeeDocumentController extends Controller
mkdir($absUploadDir, 0755, true); mkdir($absUploadDir, 0755, true);
} }
$ext = pathinfo($_FILES['document_file']['name'], PATHINFO_EXTENSION); $ext = pathinfo($originalFilename, PATHINFO_EXTENSION);
$fileName = $documentType . '_' . date('Ymd_His') . '.' . $ext; $storedFilename = $documentType . '_' . date('Ymd_His') . '.' . $ext;
$targetPath = $absUploadDir . '/' . $fileName; $targetPath = $absUploadDir . '/' . $storedFilename;
if (move_uploaded_file($_FILES['document_file']['tmp_name'], $targetPath)) { if (move_uploaded_file($_FILES['document_file']['tmp_name'], $targetPath)) {
$filePath = $uploadDir . '/' . $fileName; $filePath = $uploadDir . '/' . $storedFilename;
} else { } else {
$errors[] = 'فشل رفع الملف'; $errors[] = 'فشل رفع الملف';
} }
...@@ -112,16 +121,21 @@ class EmployeeDocumentController extends Controller ...@@ -112,16 +121,21 @@ class EmployeeDocumentController extends Controller
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$employee = $this->currentEmployee(); $employee = $this->currentEmployee();
$docTypes = HrEmployeeDocument::getDocumentTypes();
$docId = $db->insert('hr_employee_documents', [ $docId = $db->insert('hr_employee_documents', [
'employee_profile_id' => $profileId, 'employee_profile_id' => $profileId,
'document_type' => $documentType, 'document_type' => $documentType,
'document_number' => $documentNumber, 'title_ar' => $titleAr ?: ($docTypes[$documentType] ?? $documentType),
'issue_date' => $issueDate, 'original_filename' => $originalFilename,
'expiry_date' => $expiryDate, 'stored_filename' => $storedFilename,
'file_path' => $filePath, 'file_path' => $filePath,
'file_size' => $fileSize,
'mime_type' => $mimeType,
'expiry_date' => $expiryDate,
'notes' => $notes, 'notes' => $notes,
'is_verified' => 0, 'is_verified' => 0,
'uploaded_by' => $employee ? (int) $employee->id : null,
'created_at' => date('Y-m-d H:i:s'), 'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
'created_by' => $employee ? (int) $employee->id : null, 'created_by' => $employee ? (int) $employee->id : null,
......
...@@ -46,8 +46,8 @@ class EndOfServiceController extends Controller ...@@ -46,8 +46,8 @@ class EndOfServiceController extends Controller
{ {
$profileId = (int) $request->post('employee_profile_id', 0); $profileId = (int) $request->post('employee_profile_id', 0);
$terminationType = trim((string) $request->post('termination_type', '')); $terminationType = trim((string) $request->post('termination_type', ''));
$terminationDate = trim((string) $request->post('termination_date', date('Y-m-d'))); $effectiveDate = trim((string) $request->post('effective_date', date('Y-m-d')));
$terminationReason = trim((string) $request->post('termination_reason', '')); $notes = trim((string) $request->post('notes', ''));
$errors = []; $errors = [];
if ($profileId <= 0) { if ($profileId <= 0) {
...@@ -56,7 +56,7 @@ class EndOfServiceController extends Controller ...@@ -56,7 +56,7 @@ class EndOfServiceController extends Controller
if ($terminationType === '') { if ($terminationType === '') {
$errors[] = 'نوع إنهاء الخدمة مطلوب'; $errors[] = 'نوع إنهاء الخدمة مطلوب';
} }
if ($terminationDate === '') { if ($effectiveDate === '') {
$errors[] = 'تاريخ إنهاء الخدمة مطلوب'; $errors[] = 'تاريخ إنهاء الخدمة مطلوب';
} }
...@@ -73,8 +73,13 @@ class EndOfServiceController extends Controller ...@@ -73,8 +73,13 @@ class EndOfServiceController extends Controller
$recordId = $db->insert('hr_end_of_service', [ $recordId = $db->insert('hr_end_of_service', [
'employee_profile_id' => $profileId, 'employee_profile_id' => $profileId,
'termination_type' => $terminationType, 'termination_type' => $terminationType,
'termination_date' => $terminationDate, 'request_date' => date('Y-m-d'),
'termination_reason' => $terminationReason ?: null, 'effective_date' => $effectiveDate,
'notes' => $notes ?: null,
'years_of_service' => '0.00',
'last_basic_salary' => '0.00',
'last_total_salary' => '0.00',
'calculation_json' => '{}',
'status' => 'draft', 'status' => 'draft',
'created_at' => date('Y-m-d H:i:s'), 'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
...@@ -118,8 +123,8 @@ class EndOfServiceController extends Controller ...@@ -118,8 +123,8 @@ class EndOfServiceController extends Controller
$result = EndOfServiceService::calculate( $result = EndOfServiceService::calculate(
(int) $record->employee_profile_id, (int) $record->employee_profile_id,
$record->termination_date, $record->termination_type,
$record->termination_type $record->effective_date
); );
if (!$result['success']) { if (!$result['success']) {
...@@ -128,19 +133,22 @@ class EndOfServiceController extends Controller ...@@ -128,19 +133,22 @@ class EndOfServiceController extends Controller
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$db->update('hr_end_of_service', [ $db->update('hr_end_of_service', [
'years_of_service' => $result['years_of_service'], 'years_of_service' => $result['years_of_service'],
'last_basic_salary' => $result['last_basic_salary'], 'last_basic_salary' => $result['last_basic_salary'],
'severance_amount' => $result['severance_amount'], 'last_total_salary' => $result['last_total_salary'],
'notice_compensation' => $result['notice_compensation'], 'severance_first_5y' => $result['severance_first_5y'],
'leave_compensation' => $result['leave_compensation'], 'severance_after_5y' => $result['severance_after_5y'],
'other_compensation' => '0.00', 'total_severance' => $result['total_severance'],
'total_entitlements' => $result['total_entitlements'], 'notice_period_compensation' => $result['notice_period_compensation'],
'outstanding_loans' => $result['outstanding_loans'], 'remaining_leave_days' => $result['remaining_leave_days'],
'other_deductions' => '0.00', 'leave_compensation' => $result['leave_compensation'],
'net_settlement' => $result['net_settlement'], 'total_entitlement' => $result['total_entitlement'],
'calculation_json' => json_encode($result['breakdown'], JSON_UNESCAPED_UNICODE), 'deductions_json' => json_encode($result['deductions_json'], JSON_UNESCAPED_UNICODE),
'status' => 'calculated', 'total_deductions' => $result['total_deductions'],
'updated_at' => date('Y-m-d H:i:s'), 'net_settlement' => $result['net_settlement'],
'calculation_json' => json_encode($result['calculation_json'], JSON_UNESCAPED_UNICODE),
'status' => 'calculated',
'updated_at' => date('Y-m-d H:i:s'),
], '`id` = ?', [(int) $id]); ], '`id` = ?', [(int) $id]);
Logger::info("End of service calculated", ['record_id' => (int) $id, 'net_settlement' => $result['net_settlement']]); Logger::info("End of service calculated", ['record_id' => (int) $id, 'net_settlement' => $result['net_settlement']]);
...@@ -174,9 +182,9 @@ class EndOfServiceController extends Controller ...@@ -174,9 +182,9 @@ class EndOfServiceController extends Controller
// Update employee status to terminated // Update employee status to terminated
$db->update('hr_employee_profiles', [ $db->update('hr_employee_profiles', [
'employment_status' => 'terminated', 'employment_status' => 'terminated',
'termination_date' => $record->termination_date, 'termination_date' => $record->effective_date,
'termination_type' => $record->termination_type, 'termination_type' => $record->termination_type,
'termination_reason' => $record->termination_reason, 'termination_reason' => $record->notes,
'updated_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
], '`id` = ? AND `is_archived` = 0', [(int) $record->employee_profile_id]); ], '`id` = ? AND `is_archived` = 0', [(int) $record->employee_profile_id]);
......
...@@ -151,14 +151,24 @@ class LeaveController extends Controller ...@@ -151,14 +151,24 @@ class LeaveController extends Controller
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$employee = $this->currentEmployee(); $employee = $this->currentEmployee();
// If was approved, restore balance // Restore balance
if ($leaveRequest->status === 'approved') { $year = (int) date('Y', strtotime($leaveRequest->start_date));
HrLeaveBalance::releasePendingDays( $balance = HrLeaveBalance::getBalance(
(int) $leaveRequest->employee_profile_id, (int) $leaveRequest->employee_profile_id,
(int) $leaveRequest->leave_type_id, (int) $leaveRequest->leave_type_id,
(int) date('Y', strtotime($leaveRequest->start_date)), $year
(float) $leaveRequest->total_days );
); if ($balance) {
if ($leaveRequest->status === 'approved') {
// Approved leave: days are in used_days, reduce them
$db->update('hr_leave_balances', [
'used_days' => new \App\Core\RawExpression("GREATEST(used_days - {$leaveRequest->total_days}, 0)"),
'updated_at' => date('Y-m-d H:i:s'),
], '`id` = ?', [(int) $balance['id']]);
} else {
// Pending leave: days are in pending_days, release them
HrLeaveBalance::releasePendingDays((int) $balance['id'], (string) $leaveRequest->total_days);
}
} }
$db->update('hr_leave_requests', [ $db->update('hr_leave_requests', [
...@@ -277,10 +287,10 @@ class LeaveController extends Controller ...@@ -277,10 +287,10 @@ class LeaveController extends Controller
$newAdjustment = bcadd((string) ($balance['adjustment_days'] ?? '0'), (string) $adjustment, 2); $newAdjustment = bcadd((string) ($balance['adjustment_days'] ?? '0'), (string) $adjustment, 2);
$db->update('hr_leave_balances', [ $db->update('hr_leave_balances', [
'adjustment_days' => $newAdjustment, 'adjustment_days' => $newAdjustment,
'notes' => $reason ?: null, 'adjustment_reason'=> $reason ?: null,
'updated_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
'updated_by' => $employee ? (int) $employee->id : null, 'updated_by' => $employee ? (int) $employee->id : null,
], '`id` = ?', [(int) $balance['id']]); ], '`id` = ?', [(int) $balance['id']]);
return $this->redirect('/hr/leaves/balances/' . $profileId . '?year=' . $year)->withSuccess('تم تعديل رصيد الإجازة بنجاح'); return $this->redirect('/hr/leaves/balances/' . $profileId . '?year=' . $year)->withSuccess('تم تعديل رصيد الإجازة بنجاح');
......
...@@ -200,8 +200,8 @@ class PerformanceController extends Controller ...@@ -200,8 +200,8 @@ class PerformanceController extends Controller
$overallRating = (float) $request->post('overall_rating', 0); $overallRating = (float) $request->post('overall_rating', 0);
$strengths = trim((string) $request->post('strengths', '')) ?: null; $strengths = trim((string) $request->post('strengths', '')) ?: null;
$improvements = trim((string) $request->post('improvements', '')) ?: null; $improvements = trim((string) $request->post('improvements', '')) ?: null;
$goals = trim((string) $request->post('goals', '')) ?: null; $goalsText = trim((string) $request->post('goals', '')) ?: null;
$reviewerComments = trim((string) $request->post('reviewer_comments', '')) ?: null; $notes = trim((string) $request->post('notes', '')) ?: null;
$errors = []; $errors = [];
if ($overallRating < 1 || $overallRating > 5) { if ($overallRating < 1 || $overallRating > 5) {
...@@ -221,10 +221,10 @@ class PerformanceController extends Controller ...@@ -221,10 +221,10 @@ class PerformanceController extends Controller
'overall_rating' => $overallRating, 'overall_rating' => $overallRating,
'strengths' => $strengths, 'strengths' => $strengths,
'improvements' => $improvements, 'improvements' => $improvements,
'goals' => $goals, 'goals_json' => $goalsText ? json_encode($goalsText, JSON_UNESCAPED_UNICODE) : null,
'reviewer_comments' => $reviewerComments, 'notes' => $notes,
'review_date' => date('Y-m-d'), 'review_date' => date('Y-m-d'),
'status' => 'completed', 'status' => 'submitted',
]); ]);
return $this->redirect('/hr/performance/reviews/' . $id)->withSuccess('تم حفظ تقييم الأداء بنجاح'); return $this->redirect('/hr/performance/reviews/' . $id)->withSuccess('تم حفظ تقييم الأداء بنجاح');
......
...@@ -31,7 +31,7 @@ class HrAttendance extends Model ...@@ -31,7 +31,7 @@ class HrAttendance extends Model
'absent' => 'غائب', 'absent' => 'غائب',
'late' => 'متأخر', 'late' => 'متأخر',
'half_day' => 'نصف يوم', 'half_day' => 'نصف يوم',
'on_leave' => 'في إجازة', 'leave' => 'في إجازة',
'holiday' => 'عطلة رسمية', 'holiday' => 'عطلة رسمية',
'rest_day' => 'يوم راحة', 'rest_day' => 'يوم راحة',
]; ];
...@@ -82,7 +82,7 @@ class HrAttendance extends Model ...@@ -82,7 +82,7 @@ class HrAttendance extends Model
SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) as present_days, SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) as present_days,
SUM(CASE WHEN status = 'absent' THEN 1 ELSE 0 END) as absent_days, SUM(CASE WHEN status = 'absent' THEN 1 ELSE 0 END) as absent_days,
SUM(CASE WHEN status = 'late' THEN 1 ELSE 0 END) as late_days, SUM(CASE WHEN status = 'late' THEN 1 ELSE 0 END) as late_days,
SUM(CASE WHEN status = 'on_leave' THEN 1 ELSE 0 END) as leave_days, SUM(CASE WHEN status = 'leave' THEN 1 ELSE 0 END) as leave_days,
SUM(CASE WHEN status = 'holiday' THEN 1 ELSE 0 END) as holiday_days, SUM(CASE WHEN status = 'holiday' THEN 1 ELSE 0 END) as holiday_days,
COALESCE(SUM(actual_hours), 0) as total_actual_hours, COALESCE(SUM(actual_hours), 0) as total_actual_hours,
COALESCE(SUM(overtime_hours), 0) as total_overtime_hours, COALESCE(SUM(overtime_hours), 0) as total_overtime_hours,
......
...@@ -16,41 +16,39 @@ class HrDisciplinaryAction extends Model ...@@ -16,41 +16,39 @@ class HrDisciplinaryAction extends Model
protected static bool $autoTrackAuthor = true; protected static bool $autoTrackAuthor = true;
protected static array $fillable = [ protected static array $fillable = [
'employee_profile_id', 'incident_date', 'reported_date', 'incident_description', 'employee_profile_id', 'action_number', 'incident_date', 'incident_description',
'investigation_notes', 'investigated_by', 'investigation_date', 'investigation_notes', 'investigation_by', 'investigation_date',
'penalty_type', 'penalty_details_json', 'penalty_type', 'penalty_details_json',
'wage_deduction_days', 'suspension_days', 'wage_deduction_days', 'wage_deduction_amount', 'suspension_days',
'decision_date', 'decided_by', 'decision_notes', 'effective_date', 'status',
'appeal_date', 'appeal_reason', 'appeal_decision', 'appeal_decided_by', 'appeal_decision_date', 'decided_by', 'decided_at',
'enforcement_date', 'status', 'workflow_instance_id', 'notes', 'appeal_deadline', 'appeal_text', 'appeal_date',
'appeal_result', 'appeal_reviewed_by', 'appeal_reviewed_at',
'workflow_instance_id', 'document_path', 'notes',
]; ];
public static function getPenaltyTypes(): array public static function getPenaltyTypes(): array
{ {
return [ return [
'warning' => 'إنذار', 'warning' => 'إنذار',
'deduction' => 'خصم من الراتب', 'wage_deduction' => 'خصم من الراتب',
'suspension' => 'إيقاف عن العمل', 'raise_postponement' => 'تأجيل علاوة',
'demotion' => 'تخفيض الدرجة', 'suspension' => 'إيقاف عن العمل',
'termination' => 'فصل من العمل', 'demotion' => 'تخفيض الدرجة',
'termination' => 'فصل من العمل',
]; ];
} }
public static function getStatuses(): array public static function getStatuses(): array
{ {
return [ return [
'reported' => 'تم الإبلاغ', 'investigation' => 'تحت التحقيق',
'under_investigation' => 'تحت التحقيق', 'pending_decision' => 'في انتظار القرار',
'investigation_done' => 'انتهى التحقيق', 'decided' => 'تم تحديد العقوبة',
'penalty_decided' => 'تم تحديد العقوبة', 'appealed' => 'تم التظلم',
'enforced' => 'تم التنفيذ', 'appeal_reviewed' => 'تم مراجعة التظلم',
'appealed' => 'تم التظلم', 'enforced' => 'تم التنفيذ',
'appeal_reviewed' => 'تم مراجعة التظلم', 'cancelled' => 'ملغى',
'upheld' => 'تم تأييد العقوبة',
'modified' => 'تم تعديل العقوبة',
'overturned' => 'تم إلغاء العقوبة',
'dismissed' => 'تم الحفظ',
'closed' => 'مغلق',
]; ];
} }
...@@ -61,9 +59,9 @@ class HrDisciplinaryAction extends Model ...@@ -61,9 +59,9 @@ class HrDisciplinaryAction extends Model
"SELECT COALESCE(SUM(wage_deduction_days), 0) as total "SELECT COALESCE(SUM(wage_deduction_days), 0) as total
FROM hr_disciplinary_actions FROM hr_disciplinary_actions
WHERE employee_profile_id = ? WHERE employee_profile_id = ?
AND YEAR(enforcement_date) = ? AND MONTH(enforcement_date) = ? AND YEAR(effective_date) = ? AND MONTH(effective_date) = ?
AND penalty_type = 'deduction' AND penalty_type = 'wage_deduction'
AND status IN ('enforced', 'upheld', 'closed') AND status IN ('enforced', 'decided')
AND is_archived = 0", AND is_archived = 0",
[$profileId, $year, $month] [$profileId, $year, $month]
); );
...@@ -77,9 +75,9 @@ class HrDisciplinaryAction extends Model ...@@ -77,9 +75,9 @@ class HrDisciplinaryAction extends Model
"SELECT COALESCE(SUM(suspension_days), 0) as total "SELECT COALESCE(SUM(suspension_days), 0) as total
FROM hr_disciplinary_actions FROM hr_disciplinary_actions
WHERE employee_profile_id = ? WHERE employee_profile_id = ?
AND YEAR(enforcement_date) = ? AND MONTH(enforcement_date) = ? AND YEAR(effective_date) = ? AND MONTH(effective_date) = ?
AND penalty_type = 'suspension' AND penalty_type = 'suspension'
AND status IN ('enforced', 'upheld', 'closed') AND status IN ('enforced', 'decided')
AND is_archived = 0", AND is_archived = 0",
[$profileId, $year, $month] [$profileId, $year, $month]
); );
...@@ -118,7 +116,7 @@ class HrDisciplinaryAction extends Model ...@@ -118,7 +116,7 @@ class HrDisciplinaryAction extends Model
FROM hr_disciplinary_actions da FROM hr_disciplinary_actions da
JOIN hr_employee_profiles p ON p.id = da.employee_profile_id JOIN hr_employee_profiles p ON p.id = da.employee_profile_id
WHERE {$where} WHERE {$where}
ORDER BY da.reported_date DESC ORDER BY da.incident_date DESC
LIMIT {$perPage} OFFSET {$offset}", LIMIT {$perPage} OFFSET {$offset}",
$params $params
); );
......
...@@ -16,10 +16,11 @@ class HrEmployeeDocument extends Model ...@@ -16,10 +16,11 @@ class HrEmployeeDocument extends Model
protected static bool $autoTrackAuthor = true; protected static bool $autoTrackAuthor = true;
protected static array $fillable = [ protected static array $fillable = [
'employee_profile_id', 'document_type', 'document_number', 'employee_profile_id', 'document_type', 'title_ar',
'file_path', 'file_name', 'issue_date', 'expiry_date', 'original_filename', 'stored_filename', 'file_path',
'issuing_authority', 'is_verified', 'verified_by', 'verified_at', 'file_size', 'mime_type', 'expiry_date',
'notes', 'is_verified', 'verified_by', 'verified_at',
'uploaded_by', 'notes',
]; ];
public static function getDocumentTypes(): array public static function getDocumentTypes(): array
......
...@@ -63,9 +63,16 @@ class HrEndOfService extends Model ...@@ -63,9 +63,16 @@ class HrEndOfService extends Model
$where .= ' AND eos.status = ?'; $where .= ' AND eos.status = ?';
$params[] = $filters['status']; $params[] = $filters['status'];
} }
if (!empty($filters['termination_type'])) { if (!empty($filters['type'])) {
$where .= ' AND eos.termination_type = ?'; $where .= ' AND eos.termination_type = ?';
$params[] = $filters['termination_type']; $params[] = $filters['type'];
}
if (!empty($filters['q'])) {
$where .= ' AND (p.first_name_ar LIKE ? OR p.last_name_ar LIKE ? OR p.employee_number LIKE ?)';
$term = '%' . $filters['q'] . '%';
$params[] = $term;
$params[] = $term;
$params[] = $term;
} }
$countRow = $db->selectOne( $countRow = $db->selectOne(
......
...@@ -29,7 +29,7 @@ final class DisciplinaryService ...@@ -29,7 +29,7 @@ final class DisciplinaryService
$errors = []; $errors = [];
if ($penaltyType === 'deduction') { if ($penaltyType === 'wage_deduction') {
$currentTotal = HrDisciplinaryAction::getMonthlyDeductionDays($profileId, $year, $month); $currentTotal = HrDisciplinaryAction::getMonthlyDeductionDays($profileId, $year, $month);
$maxAllowed = self::getMaxDeductionDays(); $maxAllowed = self::getMaxDeductionDays();
$remaining = $maxAllowed - $currentTotal; $remaining = $maxAllowed - $currentTotal;
...@@ -55,14 +55,14 @@ final class DisciplinaryService ...@@ -55,14 +55,14 @@ final class DisciplinaryService
*/ */
public static function canAppeal(array $action): bool public static function canAppeal(array $action): bool
{ {
if ($action['status'] !== 'enforced') { if (!in_array($action['status'] ?? '', ['decided', 'enforced'], true)) {
return false; return false;
} }
$enforcementDate = $action['enforcement_date'] ?? null; $effectiveDate = $action['effective_date'] ?? $action['decided_at'] ?? null;
if (!$enforcementDate) { if (!$effectiveDate) {
return false; return false;
} }
$appealDeadline = date('Y-m-d', strtotime($enforcementDate . ' +' . self::getAppealWindowDays() . ' days')); $appealDeadline = date('Y-m-d', strtotime($effectiveDate . ' +' . self::getAppealWindowDays() . ' days'));
return date('Y-m-d') <= $appealDeadline; return date('Y-m-d') <= $appealDeadline;
} }
......
...@@ -30,12 +30,12 @@ use App\Modules\HR\Models\HrEmployeeLoan; ...@@ -30,12 +30,12 @@ use App\Modules\HR\Models\HrEmployeeLoan;
*/ */
final class EndOfServiceService final class EndOfServiceService
{ {
public static function calculate(int $employeeId, string $terminationType, string $effectiveDate): array public static function calculate(int $profileId, string $terminationType, string $effectiveDate): array
{ {
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$config = self::loadConfig(); $config = self::loadConfig();
$profile = HrEmployeeProfile::findByEmployeeId($employeeId); $profile = HrEmployeeProfile::find($profileId);
if (!$profile) { if (!$profile) {
return ['success' => false, 'error' => 'الموظف غير موجود']; return ['success' => false, 'error' => 'الموظف غير موجود'];
} }
...@@ -134,7 +134,7 @@ final class EndOfServiceService ...@@ -134,7 +134,7 @@ final class EndOfServiceService
return [ return [
'success' => true, 'success' => true,
'employee_id' => $employeeId, 'profile_id' => $profileId,
'termination_type' => $terminationType, 'termination_type' => $terminationType,
'effective_date' => $effectiveDate, 'effective_date' => $effectiveDate,
'years_of_service' => number_format($yearsOfService, 2), 'years_of_service' => number_format($yearsOfService, 2),
......
...@@ -63,10 +63,10 @@ final class PayrollCalculationService ...@@ -63,10 +63,10 @@ final class PayrollCalculationService
} }
// Delete previous runs for this period (recalculation) // Delete previous runs for this period (recalculation)
$db->execute("DELETE FROM hr_payroll_components_log WHERE payroll_run_id IN (SELECT id FROM hr_payroll_runs WHERE period_id = ?)", [$periodId]); $db->query("DELETE FROM hr_payroll_components_log WHERE payroll_run_id IN (SELECT id FROM hr_payroll_runs WHERE period_id = ?)", [$periodId]);
$db->execute("DELETE FROM hr_insurance_records WHERE period_id = ?", [$periodId]); $db->query("DELETE FROM hr_insurance_records WHERE period_id = ?", [$periodId]);
$db->execute("DELETE FROM hr_tax_records WHERE period_id = ?", [$periodId]); $db->query("DELETE FROM hr_tax_records WHERE period_id = ?", [$periodId]);
$db->execute("DELETE FROM hr_payroll_runs WHERE period_id = ?", [$periodId]); $db->query("DELETE FROM hr_payroll_runs WHERE period_id = ?", [$periodId]);
$totalGross = '0.00'; $totalGross = '0.00';
$totalDeductions = '0.00'; $totalDeductions = '0.00';
...@@ -100,10 +100,8 @@ final class PayrollCalculationService ...@@ -100,10 +100,8 @@ final class PayrollCalculationService
'total_gross' => $totalGross, 'total_gross' => $totalGross,
'total_deductions' => $totalDeductions, 'total_deductions' => $totalDeductions,
'total_net' => $totalNet, 'total_net' => $totalNet,
'employee_count' => $processedCount,
'calculated_at' => date('Y-m-d H:i:s'),
'calculated_by' => $employee ? (int) $employee->id : null,
'updated_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
'updated_by' => $employee ? (int) $employee->id : null,
], '`id` = ?', [$periodId]); ], '`id` = ?', [$periodId]);
Logger::info("Payroll calculated", [ Logger::info("Payroll calculated", [
...@@ -383,6 +381,7 @@ final class PayrollCalculationService ...@@ -383,6 +381,7 @@ final class PayrollCalculationService
'employee_id' => $employeeId, 'employee_id' => $employeeId,
'period_id' => $periodId, 'period_id' => $periodId,
'payroll_run_id' => $runId, 'payroll_run_id' => $runId,
'month' => $month,
'gross_taxable_monthly' => $tax['gross_taxable_monthly'], 'gross_taxable_monthly' => $tax['gross_taxable_monthly'],
'annual_taxable_income' => $tax['annual_taxable_income'], 'annual_taxable_income' => $tax['annual_taxable_income'],
'personal_exemption' => $tax['personal_exemption'], 'personal_exemption' => $tax['personal_exemption'],
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
<option value="present" <?= $attendance->status === 'present' ? 'selected' : '' ?>>حاضر</option> <option value="present" <?= $attendance->status === 'present' ? 'selected' : '' ?>>حاضر</option>
<option value="absent" <?= $attendance->status === 'absent' ? 'selected' : '' ?>>غائب</option> <option value="absent" <?= $attendance->status === 'absent' ? 'selected' : '' ?>>غائب</option>
<option value="late" <?= $attendance->status === 'late' ? 'selected' : '' ?>>متأخر</option> <option value="late" <?= $attendance->status === 'late' ? 'selected' : '' ?>>متأخر</option>
<option value="on_leave" <?= $attendance->status === 'on_leave' ? 'selected' : '' ?>>إجازة</option> <option value="leave" <?= $attendance->status === 'leave' ? 'selected' : '' ?>>إجازة</option>
<option value="rest_day" <?= $attendance->status === 'rest_day' ? 'selected' : '' ?>>يوم راحة</option>
<option value="half_day" <?= $attendance->status === 'half_day' ? 'selected' : '' ?>>نصف يوم</option>
<option value="holiday" <?= $attendance->status === 'holiday' ? 'selected' : '' ?>>عطلة</option> <option value="holiday" <?= $attendance->status === 'holiday' ? 'selected' : '' ?>>عطلة</option>
</select> </select>
</div> </div>
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<option value="present" <?= $filters['status'] === 'present' ? 'selected' : '' ?>>حاضر</option> <option value="present" <?= $filters['status'] === 'present' ? 'selected' : '' ?>>حاضر</option>
<option value="absent" <?= $filters['status'] === 'absent' ? 'selected' : '' ?>>غائب</option> <option value="absent" <?= $filters['status'] === 'absent' ? 'selected' : '' ?>>غائب</option>
<option value="late" <?= $filters['status'] === 'late' ? 'selected' : '' ?>>متأخر</option> <option value="late" <?= $filters['status'] === 'late' ? 'selected' : '' ?>>متأخر</option>
<option value="on_leave" <?= $filters['status'] === 'on_leave' ? 'selected' : '' ?>>إجازة</option> <option value="leave" <?= $filters['status'] === 'leave' ? 'selected' : '' ?>>إجازة</option>
</select> </select>
</div> </div>
<button type="submit" class="btn btn-secondary">بحث</button> <button type="submit" class="btn btn-secondary">بحث</button>
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
<tr><td colspan="9" style="text-align:center;padding:40px;color:#9CA3AF;">لا توجد سجلات</td></tr> <tr><td colspan="9" style="text-align:center;padding:40px;color:#9CA3AF;">لا توجد سجلات</td></tr>
<?php else: ?> <?php else: ?>
<?php foreach ($records as $r): ?> <?php foreach ($records as $r): ?>
<?php $statusLabels = ['present' => 'حاضر', 'absent' => 'غائب', 'late' => 'متأخر', 'on_leave' => 'إجازة', 'holiday' => 'عطلة']; ?> <?php $statusLabels = ['present' => 'حاضر', 'absent' => 'غائب', 'late' => 'متأخر', 'leave' => 'إجازة', 'holiday' => 'عطلة', 'rest_day' => 'يوم راحة', 'half_day' => 'نصف يوم']; ?>
<?php $statusColors = ['present' => '#DEF7EC;color:#03543F', 'absent' => '#FDE8E8;color:#9B1C1C', 'late' => '#FEF3C7;color:#92400E', 'on_leave' => '#DBEAFE;color:#1E40AF', 'holiday' => '#E5E7EB;color:#374151']; ?> <?php $statusColors = ['present' => '#DEF7EC;color:#03543F', 'absent' => '#FDE8E8;color:#9B1C1C', 'late' => '#FEF3C7;color:#92400E', 'leave' => '#DBEAFE;color:#1E40AF', 'holiday' => '#E5E7EB;color:#374151', 'rest_day' => '#E5E7EB;color:#374151', 'half_day' => '#FEF3C7;color:#92400E']; ?>
<tr> <tr>
<td><?php if (!$r['is_approved']): ?><input type="checkbox" name="ids[]" value="<?= (int) $r['id'] ?>"><?php endif; ?></td> <td><?php if (!$r['is_approved']): ?><input type="checkbox" name="ids[]" value="<?= (int) $r['id'] ?>"><?php endif; ?></td>
<td><?= e($r['attendance_date']) ?></td> <td><?= e($r['attendance_date']) ?></td>
......
...@@ -31,8 +31,8 @@ ...@@ -31,8 +31,8 @@
<td><?= number_format((float) ($r['actual_hours'] ?? 0), 1) ?></td> <td><?= number_format((float) ($r['actual_hours'] ?? 0), 1) ?></td>
<td><?= number_format((float) ($r['overtime_hours'] ?? 0), 1) ?></td> <td><?= number_format((float) ($r['overtime_hours'] ?? 0), 1) ?></td>
<td> <td>
<?php $sl = ['present'=>'حاضر','absent'=>'غائب','late'=>'متأخر','on_leave'=>'إجازة','holiday'=>'عطلة']; ?> <?php $sl = ['present'=>'حاضر','absent'=>'غائب','late'=>'متأخر','leave'=>'إجازة','holiday'=>'عطلة','rest_day'=>'يوم راحة','half_day'=>'نصف يوم']; ?>
<?php $sc = ['present'=>'#DEF7EC;color:#03543F','absent'=>'#FDE8E8;color:#9B1C1C','late'=>'#FEF3C7;color:#92400E','on_leave'=>'#DBEAFE;color:#1E40AF','holiday'=>'#E5E7EB;color:#374151']; ?> <?php $sc = ['present'=>'#DEF7EC;color:#03543F','absent'=>'#FDE8E8;color:#9B1C1C','late'=>'#FEF3C7;color:#92400E','leave'=>'#DBEAFE;color:#1E40AF','holiday'=>'#E5E7EB;color:#374151','rest_day'=>'#E5E7EB;color:#374151','half_day'=>'#FEF3C7;color:#92400E']; ?>
<span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$r['status']] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$r['status']] ?? $r['status']) ?></span> <span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$r['status']] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$r['status']] ?? $r['status']) ?></span>
</td> </td>
</tr> </tr>
......
...@@ -14,13 +14,6 @@ ...@@ -14,13 +14,6 @@
</div> </div>
<?php endif; ?> <?php endif; ?>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">تاريخ الواقعة <span style="color:#DC2626;">*</span></label><input type="date" name="incident_date" value="<?= e(old('incident_date') ?? ($action->incident_date ?? date('Y-m-d'))) ?>" class="form-control" required></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">تاريخ الواقعة <span style="color:#DC2626;">*</span></label><input type="date" name="incident_date" value="<?= e(old('incident_date') ?? ($action->incident_date ?? date('Y-m-d'))) ?>" class="form-control" required></div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">نوع المخالفة</label>
<?php $vtypes = ['attendance'=>'حضور وانصراف','misconduct'=>'سوء سلوك','negligence'=>'إهمال','insubordination'=>'عصيان','safety'=>'سلامة مهنية','other'=>'أخرى']; ?>
<select name="violation_type" class="form-control">
<option value="">-- اختر --</option>
<?php foreach ($vtypes as $k => $v): ?><option value="<?= $k ?>" <?= (old('violation_type') ?? ($action->violation_type ?? '')) === $k ? 'selected' : '' ?>><?= $v ?></option><?php endforeach; ?>
</select>
</div>
<div style="grid-column:1/-1;"><label style="display:block;margin-bottom:4px;font-size:13px;">وصف الواقعة <span style="color:#DC2626;">*</span></label><textarea name="incident_description" class="form-control" rows="3" required><?= e(old('incident_description') ?? ($action->incident_description ?? '')) ?></textarea></div> <div style="grid-column:1/-1;"><label style="display:block;margin-bottom:4px;font-size:13px;">وصف الواقعة <span style="color:#DC2626;">*</span></label><textarea name="incident_description" class="form-control" rows="3" required><?= e(old('incident_description') ?? ($action->incident_description ?? '')) ?></textarea></div>
<div style="grid-column:1/-1;"><label style="display:block;margin-bottom:4px;font-size:13px;">ملاحظات التحقيق</label><textarea name="investigation_notes" class="form-control" rows="2"><?= e(old('investigation_notes') ?? ($action->investigation_notes ?? '')) ?></textarea></div> <div style="grid-column:1/-1;"><label style="display:block;margin-bottom:4px;font-size:13px;">ملاحظات التحقيق</label><textarea name="investigation_notes" class="form-control" rows="2"><?= e(old('investigation_notes') ?? ($action->investigation_notes ?? '')) ?></textarea></div>
</div> </div>
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
<?php $__template->section('title'); ?>الإجراءات التأديبية<?php $__template->endSection(); ?> <?php $__template->section('title'); ?>الإجراءات التأديبية<?php $__template->endSection(); ?>
<?php $__template->section('page_actions'); ?><a href="/hr/disciplinary/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 $__template->endSection(); ?> <?php $__template->section('page_actions'); ?><a href="/hr/disciplinary/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 $__template->endSection(); ?>
<?php $__template->section('content'); ?> <?php $__template->section('content'); ?>
<?php $sl = ['reported'=>'مبلغ عنه','under_investigation'=>'تحت التحقيق','enforced'=>'منفذ','appealed'=>'متظلم','closed'=>'مغلق']; ?> <?php $sl = ['investigation'=>'تحت التحقيق','pending_decision'=>'في انتظار القرار','decided'=>'تم تحديد العقوبة','appealed'=>'متظلم','appeal_reviewed'=>'تم مراجعة التظلم','enforced'=>'منفذ','cancelled'=>'ملغى']; ?>
<?php $sc = ['reported'=>'#FEF3C7;color:#92400E','under_investigation'=>'#DBEAFE;color:#1E40AF','enforced'=>'#FDE8E8;color:#9B1C1C','appealed'=>'#E0E7FF;color:#3730A3','closed'=>'#E5E7EB;color:#374151']; ?> <?php $sc = ['investigation'=>'#DBEAFE;color:#1E40AF','pending_decision'=>'#FEF3C7;color:#92400E','decided'=>'#FDE8E8;color:#9B1C1C','appealed'=>'#E0E7FF;color:#3730A3','appeal_reviewed'=>'#E0E7FF;color:#3730A3','enforced'=>'#DEF7EC;color:#03543F','cancelled'=>'#E5E7EB;color:#374151']; ?>
<?php $pl = ['warning'=>'إنذار','deduction'=>'خصم','suspension'=>'إيقاف','demotion'=>'تنزيل درجة','termination'=>'فصل']; ?> <?php $pl = ['warning'=>'إنذار','wage_deduction'=>'خصم من الراتب','raise_postponement'=>'تأجيل علاوة','suspension'=>'إيقاف','demotion'=>'تنزيل درجة','termination'=>'فصل']; ?>
<div class="card" style="margin-bottom:20px;"> <div class="card" style="margin-bottom:20px;">
<form method="GET" action="/hr/disciplinary" style="display:flex;gap:10px;flex-wrap:wrap;align-items:end;padding:16px;"> <form method="GET" action="/hr/disciplinary" style="display:flex;gap:10px;flex-wrap:wrap;align-items:end;padding:16px;">
<div style="flex:1;min-width:160px;"><label style="display:block;margin-bottom:4px;font-size:13px;color:#6B7280;">بحث</label><input type="text" name="q" value="<?= e($filters['q']) ?>" placeholder="اسم الموظف..." class="form-control"></div> <div style="flex:1;min-width:160px;"><label style="display:block;margin-bottom:4px;font-size:13px;color:#6B7280;">بحث</label><input type="text" name="q" value="<?= e($filters['q']) ?>" placeholder="اسم الموظف..." class="form-control"></div>
...@@ -33,8 +33,8 @@ ...@@ -33,8 +33,8 @@
<tr> <tr>
<td><a href="/hr/employees/<?= (int) $a['employee_profile_id'] ?>"><?= e(($a['first_name_ar'] ?? '') . ' ' . ($a['last_name_ar'] ?? '')) ?></a></td> <td><a href="/hr/employees/<?= (int) $a['employee_profile_id'] ?>"><?= e(($a['first_name_ar'] ?? '') . ' ' . ($a['last_name_ar'] ?? '')) ?></a></td>
<td><?= e($a['incident_date'] ?? '') ?></td> <td><?= e($a['incident_date'] ?? '') ?></td>
<td><?= e($a['violation_type'] ?? '-') ?></td> <td><?= e(mb_substr($a['incident_description'] ?? '-', 0, 50)) ?></td>
<td><?php if (!empty($a['penalty_type'])): ?><span style="font-weight:600;"><?= e($pl[$a['penalty_type']] ?? $a['penalty_type']) ?></span><?php if ((int) ($a['penalty_days'] ?? 0) > 0): ?> (<?= (int) $a['penalty_days'] ?> يوم)<?php endif; ?><?php else: ?>-<?php endif; ?></td> <td><?php if (!empty($a['penalty_type'])): ?><span style="font-weight:600;"><?= e($pl[$a['penalty_type']] ?? $a['penalty_type']) ?></span><?php $pd = (int) ($a['wage_deduction_days'] ?? $a['suspension_days'] ?? 0); if ($pd > 0): ?> (<?= $pd ?> يوم)<?php endif; ?><?php else: ?>-<?php endif; ?></td>
<td><span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$a['status']] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$a['status']] ?? $a['status']) ?></span></td> <td><span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$a['status']] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$a['status']] ?? $a['status']) ?></span></td>
<td><a href="/hr/disciplinary/<?= (int) $a['id'] ?>" style="color:#2563EB;"><i data-lucide="eye" style="width:16px;height:16px;"></i></a></td> <td><a href="/hr/disciplinary/<?= (int) $a['id'] ?>" style="color:#2563EB;"><i data-lucide="eye" style="width:16px;height:16px;"></i></a></td>
</tr> </tr>
......
...@@ -2,18 +2,16 @@ ...@@ -2,18 +2,16 @@
<?php $__template->section('title'); ?>إجراء تأديبي #<?= (int) $action->id ?><?php $__template->endSection(); ?> <?php $__template->section('title'); ?>إجراء تأديبي #<?= (int) $action->id ?><?php $__template->endSection(); ?>
<?php $__template->section('page_actions'); ?><a href="/hr/disciplinary" class="btn btn-secondary">رجوع</a><?php $__template->endSection(); ?> <?php $__template->section('page_actions'); ?><a href="/hr/disciplinary" class="btn btn-secondary">رجوع</a><?php $__template->endSection(); ?>
<?php $__template->section('content'); ?> <?php $__template->section('content'); ?>
<?php $sl = ['reported'=>'مبلغ عنه','under_investigation'=>'تحت التحقيق','enforced'=>'منفذ','appealed'=>'متظلم','closed'=>'مغلق']; ?> <?php $sl = ['investigation'=>'تحت التحقيق','pending_decision'=>'في انتظار القرار','decided'=>'تم تحديد العقوبة','appealed'=>'متظلم','appeal_reviewed'=>'تم مراجعة التظلم','enforced'=>'منفذ','cancelled'=>'ملغى']; ?>
<?php $sc = ['reported'=>'#FEF3C7;color:#92400E','under_investigation'=>'#DBEAFE;color:#1E40AF','enforced'=>'#FDE8E8;color:#9B1C1C','appealed'=>'#E0E7FF;color:#3730A3','closed'=>'#E5E7EB;color:#374151']; ?> <?php $sc = ['investigation'=>'#DBEAFE;color:#1E40AF','pending_decision'=>'#FEF3C7;color:#92400E','decided'=>'#FDE8E8;color:#9B1C1C','appealed'=>'#E0E7FF;color:#3730A3','appeal_reviewed'=>'#E0E7FF;color:#3730A3','enforced'=>'#DEF7EC;color:#03543F','cancelled'=>'#E5E7EB;color:#374151']; ?>
<?php $pl = ['warning'=>'إنذار','deduction'=>'خصم','suspension'=>'إيقاف','demotion'=>'تنزيل درجة','termination'=>'فصل']; ?> <?php $pl = ['warning'=>'إنذار','wage_deduction'=>'خصم من الراتب','raise_postponement'=>'تأجيل علاوة','suspension'=>'إيقاف','demotion'=>'تنزيل درجة','termination'=>'فصل']; ?>
<?php $vtypes = ['attendance'=>'حضور وانصراف','misconduct'=>'سوء سلوك','negligence'=>'إهمال','insubordination'=>'عصيان','safety'=>'سلامة مهنية','other'=>'أخرى']; ?>
<div class="card" style="margin-bottom:20px;"> <div class="card" style="margin-bottom:20px;">
<div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;display:flex;align-items:center;gap:8px;">تفاصيل الإجراء <span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$action->status] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$action->status] ?? $action->status) ?></span></h3></div> <div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;display:flex;align-items:center;gap:8px;">تفاصيل الإجراء <span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$action->status] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$action->status] ?? $action->status) ?></span></h3></div>
<div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;"> <div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;">
<div><span style="color:#6B7280;font-size:13px;">الموظف</span><div style="font-weight:600;"><?php if ($profile): ?><a href="/hr/employees/<?= (int) $profile->id ?>"><?= e($profile->first_name_ar . ' ' . $profile->last_name_ar) ?></a><?php else: ?>-<?php endif; ?></div></div> <div><span style="color:#6B7280;font-size:13px;">الموظف</span><div style="font-weight:600;"><?php if ($profile): ?><a href="/hr/employees/<?= (int) $profile->id ?>"><?= e($profile->first_name_ar . ' ' . $profile->last_name_ar) ?></a><?php else: ?>-<?php endif; ?></div></div>
<div><span style="color:#6B7280;font-size:13px;">تاريخ الواقعة</span><div><?= e($action->incident_date ?? '-') ?></div></div> <div><span style="color:#6B7280;font-size:13px;">تاريخ الواقعة</span><div><?= e($action->incident_date ?? '-') ?></div></div>
<div><span style="color:#6B7280;font-size:13px;">نوع المخالفة</span><div><?= e($vtypes[$action->violation_type] ?? ($action->violation_type ?: '-')) ?></div></div> <?php if ($action->action_number): ?><div><span style="color:#6B7280;font-size:13px;">رقم الإجراء</span><div><?= e($action->action_number) ?></div></div><?php endif; ?>
<?php if ($reporter): ?><div><span style="color:#6B7280;font-size:13px;">المبلغ</span><div><?= e($reporter['name']) ?></div></div><?php endif; ?>
</div> </div>
<div style="padding:0 16px 16px;"> <div style="padding:0 16px 16px;">
<span style="color:#6B7280;font-size:13px;">وصف الواقعة</span> <span style="color:#6B7280;font-size:13px;">وصف الواقعة</span>
...@@ -32,35 +30,35 @@ ...@@ -32,35 +30,35 @@
<div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;">القرار التأديبي</h3></div> <div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;">القرار التأديبي</h3></div>
<div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;"> <div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;">
<div><span style="color:#6B7280;font-size:13px;">نوع الجزاء</span><div style="font-weight:700;color:#DC2626;"><?= e($pl[$action->penalty_type] ?? $action->penalty_type) ?></div></div> <div><span style="color:#6B7280;font-size:13px;">نوع الجزاء</span><div style="font-weight:700;color:#DC2626;"><?= e($pl[$action->penalty_type] ?? $action->penalty_type) ?></div></div>
<?php if ((int) ($action->penalty_days ?? 0) > 0): ?><div><span style="color:#6B7280;font-size:13px;">عدد الأيام</span><div style="font-weight:600;"><?= (int) $action->penalty_days ?> يوم</div></div><?php endif; ?> <?php $pd = (int) ($action->wage_deduction_days ?? $action->suspension_days ?? 0); if ($pd > 0): ?><div><span style="color:#6B7280;font-size:13px;">عدد الأيام</span><div style="font-weight:600;"><?= $pd ?> يوم</div></div><?php endif; ?>
<div><span style="color:#6B7280;font-size:13px;">تاريخ التنفيذ</span><div><?= e($action->enforcement_date ?? '-') ?></div></div> <div><span style="color:#6B7280;font-size:13px;">تاريخ التنفيذ</span><div><?= e($action->effective_date ?? '-') ?></div></div>
<?php if ($decider): ?><div><span style="color:#6B7280;font-size:13px;">قرار بواسطة</span><div><?= e($decider['name']) ?></div></div><?php endif; ?> <?php if ($decider): ?><div><span style="color:#6B7280;font-size:13px;">قرار بواسطة</span><div><?= e($decider['name']) ?></div></div><?php endif; ?>
</div> </div>
<?php if ($action->decision_notes): ?> <?php if ($action->notes): ?>
<div style="padding:0 16px 16px;"> <div style="padding:0 16px 16px;">
<span style="color:#6B7280;font-size:13px;">ملاحظات القرار</span> <span style="color:#6B7280;font-size:13px;">ملاحظات</span>
<div style="margin-top:4px;padding:12px;background:#F9FAFB;border-radius:6px;"><?= nl2br(e($action->decision_notes)) ?></div> <div style="margin-top:4px;padding:12px;background:#F9FAFB;border-radius:6px;"><?= nl2br(e($action->notes)) ?></div>
</div> </div>
<?php endif; ?> <?php endif; ?>
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php if ($action->status === 'appealed' || $action->appeal_reason): ?> <?php if ($action->status === 'appealed' || $action->appeal_text): ?>
<div class="card" style="margin-bottom:20px;"> <div class="card" style="margin-bottom:20px;">
<div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;">التظلم</h3></div> <div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;">التظلم</h3></div>
<div style="padding:16px;"> <div style="padding:16px;">
<?php if ($action->appeal_date): ?><div style="margin-bottom:8px;"><span style="color:#6B7280;font-size:13px;">تاريخ التظلم:</span> <?= e($action->appeal_date) ?></div><?php endif; ?> <?php if ($action->appeal_date): ?><div style="margin-bottom:8px;"><span style="color:#6B7280;font-size:13px;">تاريخ التظلم:</span> <?= e($action->appeal_date) ?></div><?php endif; ?>
<div style="padding:12px;background:#FEF3C7;border-radius:6px;"><?= nl2br(e($action->appeal_reason ?? '')) ?></div> <div style="padding:12px;background:#FEF3C7;border-radius:6px;"><?= nl2br(e($action->appeal_text ?? '')) ?></div>
</div> </div>
</div> </div>
<?php endif; ?> <?php endif; ?>
<div style="display:flex;gap:10px;flex-wrap:wrap;"> <div style="display:flex;gap:10px;flex-wrap:wrap;">
<?php if (in_array($action->status, ['reported', 'under_investigation'], true)): ?> <?php if (in_array($action->status, ['investigation', 'pending_decision'], true)): ?>
<a href="/hr/disciplinary/<?= (int) $action->id ?>/edit" class="btn btn-secondary">تعديل</a> <a href="/hr/disciplinary/<?= (int) $action->id ?>/edit" class="btn btn-secondary">تعديل</a>
<?php endif; ?> <?php endif; ?>
<?php if (in_array($action->status, ['reported', 'under_investigation'], true)): ?> <?php if (in_array($action->status, ['investigation', 'pending_decision'], true)): ?>
<div class="card" style="flex:1;min-width:300px;padding:16px;"> <div class="card" style="flex:1;min-width:300px;padding:16px;">
<h4 style="margin:0 0 12px;font-size:14px;">اتخاذ قرار تأديبي</h4> <h4 style="margin:0 0 12px;font-size:14px;">اتخاذ قرار تأديبي</h4>
<form method="POST" action="/hr/disciplinary/<?= (int) $action->id ?>/decide" style="display:flex;flex-direction:column;gap:10px;"> <form method="POST" action="/hr/disciplinary/<?= (int) $action->id ?>/decide" style="display:flex;flex-direction:column;gap:10px;">
...@@ -73,20 +71,20 @@ ...@@ -73,20 +71,20 @@
</div> </div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">عدد الأيام</label><input type="number" name="penalty_days" value="0" min="0" max="6" class="form-control"></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">عدد الأيام</label><input type="number" name="penalty_days" value="0" min="0" max="6" class="form-control"></div>
</div> </div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">تاريخ التنفيذ</label><input type="date" name="enforcement_date" value="<?= date('Y-m-d') ?>" class="form-control"></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">تاريخ التنفيذ</label><input type="date" name="effective_date" value="<?= date('Y-m-d') ?>" class="form-control"></div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">ملاحظات القرار</label><textarea name="decision_notes" class="form-control" rows="2"></textarea></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">ملاحظات</label><textarea name="notes" class="form-control" rows="2"></textarea></div>
<div style="display:flex;gap:6px;"><button type="submit" class="btn btn-danger">تنفيذ الجزاء</button></div> <div style="display:flex;gap:6px;"><button type="submit" class="btn btn-danger">تنفيذ الجزاء</button></div>
<div style="font-size:12px;color:#6B7280;">* وفقاً للمادة 58: أقصى خصم 5 أيام/شهر، أقصى إيقاف 6 أيام/شهر</div> <div style="font-size:12px;color:#6B7280;">* وفقاً للمادة 58: أقصى خصم 5 أيام/شهر، أقصى إيقاف 6 أيام/شهر</div>
</form> </form>
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php if ($canAppeal && $action->status === 'enforced'): ?> <?php if ($canAppeal && in_array($action->status, ['decided', 'enforced'], true)): ?>
<div class="card" style="flex:1;min-width:300px;padding:16px;"> <div class="card" style="flex:1;min-width:300px;padding:16px;">
<h4 style="margin:0 0 12px;font-size:14px;">تقديم تظلم <span style="color:#6B7280;font-size:12px;">(خلال 7 أيام من التنفيذ)</span></h4> <h4 style="margin:0 0 12px;font-size:14px;">تقديم تظلم <span style="color:#6B7280;font-size:12px;">(خلال 7 أيام من القرار)</span></h4>
<form method="POST" action="/hr/disciplinary/<?= (int) $action->id ?>/appeal" style="display:flex;flex-direction:column;gap:10px;"> <form method="POST" action="/hr/disciplinary/<?= (int) $action->id ?>/appeal" style="display:flex;flex-direction:column;gap:10px;">
<?= csrf_field() ?> <?= csrf_field() ?>
<div><textarea name="appeal_reason" class="form-control" rows="3" placeholder="سبب التظلم..." required></textarea></div> <div><textarea name="appeal_text" class="form-control" rows="3" placeholder="سبب التظلم..." required></textarea></div>
<button type="submit" class="btn btn-primary">تقديم التظلم</button> <button type="submit" class="btn btn-primary">تقديم التظلم</button>
</form> </form>
</div> </div>
......
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
<?php foreach ($documentTypes as $k => $v): ?><option value="<?= e($k) ?>"><?= e($v) ?></option><?php endforeach; ?> <?php foreach ($documentTypes as $k => $v): ?><option value="<?= e($k) ?>"><?= e($v) ?></option><?php endforeach; ?>
</select> </select>
</div> </div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">رقم المستند</label><input type="text" name="document_number" class="form-control"></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">عنوان المستند</label><input type="text" name="title_ar" class="form-control" placeholder="اختياري - يُستخدم اسم النوع كافتراضي"></div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">تاريخ الإصدار</label><input type="date" name="issue_date" class="form-control"></div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">تاريخ الانتهاء</label><input type="date" name="expiry_date" class="form-control"></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">تاريخ الانتهاء</label><input type="date" name="expiry_date" class="form-control"></div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">الملف (PDF, JPG, PNG - حد 5MB)</label><input type="file" name="document_file" accept=".pdf,.jpg,.jpeg,.png" class="form-control"></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">الملف (PDF, JPG, PNG - حد 5MB)</label><input type="file" name="document_file" accept=".pdf,.jpg,.jpeg,.png" class="form-control"></div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">ملاحظات</label><input type="text" name="notes" class="form-control"></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">ملاحظات</label><input type="text" name="notes" class="form-control"></div>
...@@ -32,14 +31,13 @@ ...@@ -32,14 +31,13 @@
<?php else: ?> <?php else: ?>
<div class="table-responsive"> <div class="table-responsive">
<table class="data-table"> <table class="data-table">
<thead><tr><th>النوع</th><th>رقم المستند</th><th>الإصدار</th><th>الانتهاء</th><th>التحقق</th><th>إجراءات</th></tr></thead> <thead><tr><th>النوع</th><th>العنوان</th><th>الانتهاء</th><th>التحقق</th><th>إجراءات</th></tr></thead>
<tbody> <tbody>
<?php foreach ($documents as $d): ?> <?php foreach ($documents as $d): ?>
<?php $isExpired = !empty($d['expiry_date']) && $d['expiry_date'] < date('Y-m-d'); ?> <?php $isExpired = !empty($d['expiry_date']) && $d['expiry_date'] < date('Y-m-d'); ?>
<tr> <tr>
<td><?= e($documentTypes[$d['document_type']] ?? $d['document_type']) ?></td> <td><?= e($documentTypes[$d['document_type']] ?? $d['document_type']) ?></td>
<td><?= e($d['document_number'] ?? '-') ?></td> <td><?= e($d['title_ar'] ?? '-') ?></td>
<td><?= e($d['issue_date'] ?? '-') ?></td>
<td><span style="<?= $isExpired ? 'color:#DC2626;font-weight:600;' : '' ?>"><?= e($d['expiry_date'] ?? '-') ?><?php if ($isExpired): ?> (منتهي)<?php endif; ?></span></td> <td><span style="<?= $isExpired ? 'color:#DC2626;font-weight:600;' : '' ?>"><?= e($d['expiry_date'] ?? '-') ?><?php if ($isExpired): ?> (منتهي)<?php endif; ?></span></td>
<td> <td>
<?php if ((int) ($d['is_verified'] ?? 0)): ?> <?php if ((int) ($d['is_verified'] ?? 0)): ?>
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
<div class="card"> <div class="card">
<div class="table-responsive"> <div class="table-responsive">
<table class="data-table"> <table class="data-table">
<thead><tr><th>الموظف</th><th>نوع المستند</th><th>رقم المستند</th><th>تاريخ الانتهاء</th><th>التحقق</th><th>إجراءات</th></tr></thead> <thead><tr><th>الموظف</th><th>نوع المستند</th><th>العنوان</th><th>تاريخ الانتهاء</th><th>التحقق</th><th>إجراءات</th></tr></thead>
<tbody> <tbody>
<?php if (empty($documents)): ?> <?php if (empty($documents)): ?>
<tr><td colspan="6" style="text-align:center;padding:40px;color:#9CA3AF;">لا توجد مستندات</td></tr> <tr><td colspan="6" style="text-align:center;padding:40px;color:#9CA3AF;">لا توجد مستندات</td></tr>
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
<tr> <tr>
<td><a href="/hr/documents/employee/<?= (int) $d['employee_profile_id'] ?>"><?= e(($d['first_name_ar'] ?? '') . ' ' . ($d['last_name_ar'] ?? '')) ?></a></td> <td><a href="/hr/documents/employee/<?= (int) $d['employee_profile_id'] ?>"><?= e(($d['first_name_ar'] ?? '') . ' ' . ($d['last_name_ar'] ?? '')) ?></a></td>
<td><?= e($documentTypes[$d['document_type']] ?? $d['document_type']) ?></td> <td><?= e($documentTypes[$d['document_type']] ?? $d['document_type']) ?></td>
<td><?= e($d['document_number'] ?? '-') ?></td> <td><?= e($d['title_ar'] ?? '-') ?></td>
<td><?php if (!empty($d['expiry_date'])): ?><span style="<?= $isExpired ? 'color:#DC2626;font-weight:600;' : ($isExpiringSoon ? 'color:#D97706;font-weight:600;' : '') ?>"><?= e($d['expiry_date']) ?><?php if ($isExpired): ?> (منتهي)<?php elseif ($isExpiringSoon): ?> (قارب)<?php endif; ?></span><?php else: ?>-<?php endif; ?></td> <td><?php if (!empty($d['expiry_date'])): ?><span style="<?= $isExpired ? 'color:#DC2626;font-weight:600;' : ($isExpiringSoon ? 'color:#D97706;font-weight:600;' : '') ?>"><?= e($d['expiry_date']) ?><?php if ($isExpired): ?> (منتهي)<?php elseif ($isExpiringSoon): ?> (قارب)<?php endif; ?></span><?php else: ?>-<?php endif; ?></td>
<td><?php if ((int) ($d['is_verified'] ?? 0)): ?><span style="color:#059669;font-weight:600;">متحقق</span><?php else: ?><span style="color:#D97706;">غير متحقق</span><?php endif; ?></td> <td><?php if ((int) ($d['is_verified'] ?? 0)): ?><span style="color:#059669;font-weight:600;">متحقق</span><?php else: ?><span style="color:#D97706;">غير متحقق</span><?php endif; ?></td>
<td><a href="/hr/documents/employee/<?= (int) $d['employee_profile_id'] ?>" style="color:#2563EB;"><i data-lucide="eye" style="width:16px;height:16px;"></i></a></td> <td><a href="/hr/documents/employee/<?= (int) $d['employee_profile_id'] ?>" style="color:#2563EB;"><i data-lucide="eye" style="width:16px;height:16px;"></i></a></td>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<?php $__template->section('title'); ?>إنهاء خدمة جديد<?php $__template->endSection(); ?> <?php $__template->section('title'); ?>إنهاء خدمة جديد<?php $__template->endSection(); ?>
<?php $__template->section('page_actions'); ?><a href="/hr/end-of-service" class="btn btn-secondary">رجوع</a><?php $__template->endSection(); ?> <?php $__template->section('page_actions'); ?><a href="/hr/end-of-service" class="btn btn-secondary">رجوع</a><?php $__template->endSection(); ?>
<?php $__template->section('content'); ?> <?php $__template->section('content'); ?>
<?php $tl = ['resignation'=>'استقالة','termination'=>'فصل','retirement'=>'تقاعد','contract_end'=>'انتهاء عقد','mutual'=>'إنهاء بالتراضي','death'=>'وفاة']; ?> <?php $tl = ['resignation'=>'استقالة','termination'=>'فصل','end_of_contract'=>'انتهاء عقد','retirement'=>'تقاعد','death'=>'وفاة','disability'=>'عجز','mutual_agreement'=>'اتفاق مشترك']; ?>
<form method="POST" action="/hr/end-of-service"> <form method="POST" action="/hr/end-of-service">
<?= csrf_field() ?> <?= csrf_field() ?>
<div class="card" style="margin-bottom:20px;"> <div class="card" style="margin-bottom:20px;">
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
<?php foreach ($tl as $k => $v): ?><option value="<?= $k ?>" <?= old('termination_type') === $k ? 'selected' : '' ?>><?= $v ?></option><?php endforeach; ?> <?php foreach ($tl as $k => $v): ?><option value="<?= $k ?>" <?= old('termination_type') === $k ? 'selected' : '' ?>><?= $v ?></option><?php endforeach; ?>
</select> </select>
</div> </div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">تاريخ إنهاء الخدمة <span style="color:#DC2626;">*</span></label><input type="date" name="termination_date" value="<?= e(old('termination_date') ?? date('Y-m-d')) ?>" class="form-control" required></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">تاريخ إنهاء الخدمة <span style="color:#DC2626;">*</span></label><input type="date" name="effective_date" value="<?= e(old('effective_date') ?? date('Y-m-d')) ?>" class="form-control" required></div>
<div style="grid-column:1/-1;"><label style="display:block;margin-bottom:4px;font-size:13px;">سبب إنهاء الخدمة</label><textarea name="termination_reason" class="form-control" rows="3"><?= e(old('termination_reason') ?? '') ?></textarea></div> <div style="grid-column:1/-1;"><label style="display:block;margin-bottom:4px;font-size:13px;">ملاحظات</label><textarea name="notes" class="form-control" rows="3"><?= e(old('notes') ?? '') ?></textarea></div>
</div> </div>
</div> </div>
<div style="display:flex;gap:10px;justify-content:flex-end;"> <div style="display:flex;gap:10px;justify-content:flex-end;">
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
<?php $__template->section('title'); ?>نهاية الخدمة<?php $__template->endSection(); ?> <?php $__template->section('title'); ?>نهاية الخدمة<?php $__template->endSection(); ?>
<?php $__template->section('page_actions'); ?><a href="/hr/end-of-service/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 $__template->endSection(); ?> <?php $__template->section('page_actions'); ?><a href="/hr/end-of-service/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 $__template->endSection(); ?>
<?php $__template->section('content'); ?> <?php $__template->section('content'); ?>
<?php $sl = ['draft'=>'مسودة','calculated'=>'محسوب','approved'=>'معتمد','paid'=>'مصروف']; ?> <?php $sl = ['draft'=>'مسودة','calculated'=>'تم الحساب','pending_approval'=>'في انتظار الاعتماد','approved'=>'معتمد','paid'=>'تم الصرف','cancelled'=>'ملغى']; ?>
<?php $sc = ['draft'=>'#FEF3C7;color:#92400E','calculated'=>'#DBEAFE;color:#1E40AF','approved'=>'#D1FAE5;color:#065F46','paid'=>'#E5E7EB;color:#374151']; ?> <?php $sc = ['draft'=>'#FEF3C7;color:#92400E','calculated'=>'#DBEAFE;color:#1E40AF','pending_approval'=>'#FDE8E8;color:#9B1C1C','approved'=>'#D1FAE5;color:#065F46','paid'=>'#E5E7EB;color:#374151','cancelled'=>'#E5E7EB;color:#6B7280']; ?>
<?php $tl = ['resignation'=>'استقالة','termination'=>'فصل','retirement'=>'تقاعد','contract_end'=>'انتهاء عقد','mutual'=>'إنهاء بالتراضي','death'=>'وفاة']; ?> <?php $tl = ['resignation'=>'استقالة','termination'=>'فصل','end_of_contract'=>'انتهاء عقد','retirement'=>'تقاعد','death'=>'وفاة','disability'=>'عجز','mutual_agreement'=>'اتفاق مشترك']; ?>
<div class="card" style="margin-bottom:20px;"> <div class="card" style="margin-bottom:20px;">
<form method="GET" action="/hr/end-of-service" style="display:flex;gap:10px;flex-wrap:wrap;align-items:end;padding:16px;"> <form method="GET" action="/hr/end-of-service" style="display:flex;gap:10px;flex-wrap:wrap;align-items:end;padding:16px;">
<div style="flex:1;min-width:160px;"><label style="display:block;margin-bottom:4px;font-size:13px;color:#6B7280;">بحث</label><input type="text" name="q" value="<?= e($filters['q']) ?>" placeholder="اسم الموظف..." class="form-control"></div> <div style="flex:1;min-width:160px;"><label style="display:block;margin-bottom:4px;font-size:13px;color:#6B7280;">بحث</label><input type="text" name="q" value="<?= e($filters['q']) ?>" placeholder="اسم الموظف..." class="form-control"></div>
...@@ -31,9 +31,9 @@ ...@@ -31,9 +31,9 @@
<?php else: ?> <?php else: ?>
<?php foreach ($records as $r): ?> <?php foreach ($records as $r): ?>
<tr> <tr>
<td><a href="/hr/employees/<?= (int) $r['employee_profile_id'] ?>"><?= e(($r['first_name_ar'] ?? '') . ' ' . ($r['last_name_ar'] ?? '')) ?></a></td> <td><a href="/hr/employees/<?= (int) $r['employee_profile_id'] ?>"><?= e($r['full_name_ar'] ?? '-') ?></a></td>
<td><?= e($tl[$r['termination_type']] ?? $r['termination_type']) ?></td> <td><?= e($tl[$r['termination_type']] ?? $r['termination_type']) ?></td>
<td><?= e($r['termination_date'] ?? '-') ?></td> <td><?= e($r['effective_date'] ?? '-') ?></td>
<td style="font-weight:700;"><?= $r['net_settlement'] !== null ? number_format((float) $r['net_settlement'], 2) . ' ج.م' : '-' ?></td> <td style="font-weight:700;"><?= $r['net_settlement'] !== null ? number_format((float) $r['net_settlement'], 2) . ' ج.م' : '-' ?></td>
<td><span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$r['status']] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$r['status']] ?? $r['status']) ?></span></td> <td><span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$r['status']] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$r['status']] ?? $r['status']) ?></span></td>
<td><a href="/hr/end-of-service/<?= (int) $r['id'] ?>" style="color:#2563EB;"><i data-lucide="eye" style="width:16px;height:16px;"></i></a></td> <td><a href="/hr/end-of-service/<?= (int) $r['id'] ?>" style="color:#2563EB;"><i data-lucide="eye" style="width:16px;height:16px;"></i></a></td>
......
...@@ -2,23 +2,23 @@ ...@@ -2,23 +2,23 @@
<?php $__template->section('title'); ?>نهاية خدمة #<?= (int) $record->id ?><?php $__template->endSection(); ?> <?php $__template->section('title'); ?>نهاية خدمة #<?= (int) $record->id ?><?php $__template->endSection(); ?>
<?php $__template->section('page_actions'); ?><a href="/hr/end-of-service" class="btn btn-secondary">رجوع</a><?php $__template->endSection(); ?> <?php $__template->section('page_actions'); ?><a href="/hr/end-of-service" class="btn btn-secondary">رجوع</a><?php $__template->endSection(); ?>
<?php $__template->section('content'); ?> <?php $__template->section('content'); ?>
<?php $sl = ['draft'=>'مسودة','calculated'=>'محسوب','approved'=>'معتمد','paid'=>'مصروف']; ?> <?php $sl = ['draft'=>'مسودة','calculated'=>'تم الحساب','pending_approval'=>'في انتظار الاعتماد','approved'=>'معتمد','paid'=>'تم الصرف','cancelled'=>'ملغى']; ?>
<?php $sc = ['draft'=>'#FEF3C7;color:#92400E','calculated'=>'#DBEAFE;color:#1E40AF','approved'=>'#D1FAE5;color:#065F46','paid'=>'#E5E7EB;color:#374151']; ?> <?php $sc = ['draft'=>'#FEF3C7;color:#92400E','calculated'=>'#DBEAFE;color:#1E40AF','pending_approval'=>'#FDE8E8;color:#9B1C1C','approved'=>'#D1FAE5;color:#065F46','paid'=>'#E5E7EB;color:#374151','cancelled'=>'#E5E7EB;color:#6B7280']; ?>
<?php $tl = ['resignation'=>'استقالة','termination'=>'فصل','retirement'=>'تقاعد','contract_end'=>'انتهاء عقد','mutual'=>'إنهاء بالتراضي','death'=>'وفاة']; ?> <?php $tl = ['resignation'=>'استقالة','termination'=>'فصل','end_of_contract'=>'انتهاء عقد','retirement'=>'تقاعد','death'=>'وفاة','disability'=>'عجز','mutual_agreement'=>'اتفاق مشترك']; ?>
<div class="card" style="margin-bottom:20px;"> <div class="card" style="margin-bottom:20px;">
<div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;display:flex;align-items:center;gap:8px;">بيانات إنهاء الخدمة <span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$record->status] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$record->status] ?? $record->status) ?></span></h3></div> <div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;display:flex;align-items:center;gap:8px;">بيانات إنهاء الخدمة <span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $sc[$record->status] ?? '#E5E7EB;color:#374151' ?>;"><?= e($sl[$record->status] ?? $record->status) ?></span></h3></div>
<div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;"> <div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;">
<div><span style="color:#6B7280;font-size:13px;">الموظف</span><div style="font-weight:600;"><?php if ($profile): ?><a href="/hr/employees/<?= (int) $profile->id ?>"><?= e($profile->first_name_ar . ' ' . $profile->last_name_ar) ?></a><?php else: ?>-<?php endif; ?></div></div> <div><span style="color:#6B7280;font-size:13px;">الموظف</span><div style="font-weight:600;"><?php if ($profile): ?><a href="/hr/employees/<?= (int) $profile->id ?>"><?= e($profile->first_name_ar . ' ' . $profile->last_name_ar) ?></a><?php else: ?>-<?php endif; ?></div></div>
<div><span style="color:#6B7280;font-size:13px;">نوع الإنهاء</span><div><?= e($tl[$record->termination_type] ?? $record->termination_type) ?></div></div> <div><span style="color:#6B7280;font-size:13px;">نوع الإنهاء</span><div><?= e($tl[$record->termination_type] ?? $record->termination_type) ?></div></div>
<div><span style="color:#6B7280;font-size:13px;">تاريخ الإنهاء</span><div><?= e($record->termination_date ?? '-') ?></div></div> <div><span style="color:#6B7280;font-size:13px;">تاريخ الإنهاء</span><div><?= e($record->effective_date ?? '-') ?></div></div>
<?php if ($record->years_of_service !== null): ?><div><span style="color:#6B7280;font-size:13px;">سنوات الخدمة</span><div style="font-weight:600;"><?= number_format((float) $record->years_of_service, 1) ?> سنة</div></div><?php endif; ?> <?php if ($record->years_of_service !== null): ?><div><span style="color:#6B7280;font-size:13px;">سنوات الخدمة</span><div style="font-weight:600;"><?= number_format((float) $record->years_of_service, 1) ?> سنة</div></div><?php endif; ?>
<?php if ($approver): ?><div><span style="color:#6B7280;font-size:13px;">معتمد بواسطة</span><div><?= e($approver['name']) ?></div></div><?php endif; ?> <?php if ($approver): ?><div><span style="color:#6B7280;font-size:13px;">معتمد بواسطة</span><div><?= e($approver['name']) ?></div></div><?php endif; ?>
</div> </div>
<?php if ($record->termination_reason): ?> <?php if ($record->notes): ?>
<div style="padding:0 16px 16px;"> <div style="padding:0 16px 16px;">
<span style="color:#6B7280;font-size:13px;">سبب الإنهاء</span> <span style="color:#6B7280;font-size:13px;">ملاحظات</span>
<div style="margin-top:4px;padding:12px;background:#F9FAFB;border-radius:6px;"><?= nl2br(e($record->termination_reason)) ?></div> <div style="margin-top:4px;padding:12px;background:#F9FAFB;border-radius:6px;"><?= nl2br(e($record->notes)) ?></div>
</div> </div>
<?php endif; ?> <?php endif; ?>
</div> </div>
...@@ -35,31 +35,23 @@ ...@@ -35,31 +35,23 @@
</tr> </tr>
<tr style="border-bottom:1px solid #F3F4F6;"> <tr style="border-bottom:1px solid #F3F4F6;">
<td style="padding:10px 0;color:#6B7280;">مكافأة نهاية الخدمة</td> <td style="padding:10px 0;color:#6B7280;">مكافأة نهاية الخدمة</td>
<td style="padding:10px 0;text-align:left;font-weight:600;"><?= number_format((float) ($record->severance_amount ?? 0), 2) ?> ج.م</td> <td style="padding:10px 0;text-align:left;font-weight:600;"><?= number_format((float) ($record->total_severance ?? 0), 2) ?> ج.م</td>
</tr> </tr>
<tr style="border-bottom:1px solid #F3F4F6;"> <tr style="border-bottom:1px solid #F3F4F6;">
<td style="padding:10px 0;color:#6B7280;">تعويض فترة الإنذار</td> <td style="padding:10px 0;color:#6B7280;">تعويض فترة الإنذار</td>
<td style="padding:10px 0;text-align:left;"><?= number_format((float) ($record->notice_compensation ?? 0), 2) ?> ج.م</td> <td style="padding:10px 0;text-align:left;"><?= number_format((float) ($record->notice_period_compensation ?? 0), 2) ?> ج.م</td>
</tr> </tr>
<tr style="border-bottom:1px solid #F3F4F6;"> <tr style="border-bottom:1px solid #F3F4F6;">
<td style="padding:10px 0;color:#6B7280;">رصيد الإجازات</td> <td style="padding:10px 0;color:#6B7280;">رصيد الإجازات</td>
<td style="padding:10px 0;text-align:left;"><?= number_format((float) ($record->leave_compensation ?? 0), 2) ?> ج.م</td> <td style="padding:10px 0;text-align:left;"><?= number_format((float) ($record->leave_compensation ?? 0), 2) ?> ج.م</td>
</tr> </tr>
<tr style="border-bottom:1px solid #F3F4F6;">
<td style="padding:10px 0;color:#6B7280;">تعويضات أخرى</td>
<td style="padding:10px 0;text-align:left;"><?= number_format((float) ($record->other_compensation ?? 0), 2) ?> ج.م</td>
</tr>
<tr style="border-bottom:1px solid #F3F4F6;background:#F0FDF4;"> <tr style="border-bottom:1px solid #F3F4F6;background:#F0FDF4;">
<td style="padding:10px 0;font-weight:700;">إجمالي المستحقات</td> <td style="padding:10px 0;font-weight:700;">إجمالي المستحقات</td>
<td style="padding:10px 0;text-align:left;font-weight:700;color:#059669;"><?= number_format((float) ($record->total_entitlements ?? 0), 2) ?> ج.م</td> <td style="padding:10px 0;text-align:left;font-weight:700;color:#059669;"><?= number_format((float) ($record->total_entitlement ?? 0), 2) ?> ج.م</td>
</tr>
<tr style="border-bottom:1px solid #F3F4F6;">
<td style="padding:10px 0;color:#DC2626;">(-) سلف مستحقة</td>
<td style="padding:10px 0;text-align:left;color:#DC2626;"><?= number_format((float) ($record->outstanding_loans ?? 0), 2) ?> ج.م</td>
</tr> </tr>
<tr style="border-bottom:1px solid #F3F4F6;"> <tr style="border-bottom:1px solid #F3F4F6;">
<td style="padding:10px 0;color:#DC2626;">(-) خصومات أخرى</td> <td style="padding:10px 0;color:#DC2626;">(-) خصومات (سلف وغيرها)</td>
<td style="padding:10px 0;text-align:left;color:#DC2626;"><?= number_format((float) ($record->other_deductions ?? 0), 2) ?> ج.م</td> <td style="padding:10px 0;text-align:left;color:#DC2626;"><?= number_format((float) ($record->total_deductions ?? 0), 2) ?> ج.م</td>
</tr> </tr>
<tr style="background:#EFF6FF;"> <tr style="background:#EFF6FF;">
<td style="padding:12px 0;font-weight:700;font-size:16px;">صافي التسوية</td> <td style="padding:12px 0;font-weight:700;font-size:16px;">صافي التسوية</td>
......
...@@ -58,8 +58,8 @@ $existingScores = json_decode($review->scores_json ?? '{}', true); ...@@ -58,8 +58,8 @@ $existingScores = json_decode($review->scores_json ?? '{}', true);
<div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:16px;"> <div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:16px;">
<div><label style="display:block;margin-bottom:4px;font-size:13px;">نقاط القوة</label><textarea name="strengths" class="form-control" rows="3"><?= e(old('strengths') ?? ($review->strengths ?? '')) ?></textarea></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">نقاط القوة</label><textarea name="strengths" class="form-control" rows="3"><?= e(old('strengths') ?? ($review->strengths ?? '')) ?></textarea></div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">مجالات التحسين</label><textarea name="improvements" class="form-control" rows="3"><?= e(old('improvements') ?? ($review->improvements ?? '')) ?></textarea></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">مجالات التحسين</label><textarea name="improvements" class="form-control" rows="3"><?= e(old('improvements') ?? ($review->improvements ?? '')) ?></textarea></div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">الأهداف للفترة القادمة</label><textarea name="goals" class="form-control" rows="3"><?= e(old('goals') ?? ($review->goals ?? '')) ?></textarea></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">الأهداف للفترة القادمة</label><textarea name="goals" class="form-control" rows="3"><?= e(old('goals') ?? (($review->goals_json ? json_decode($review->goals_json, true) : '') ?: '')) ?></textarea></div>
<div><label style="display:block;margin-bottom:4px;font-size:13px;">ملاحظات المقيّم</label><textarea name="reviewer_comments" class="form-control" rows="3"><?= e(old('reviewer_comments') ?? ($review->reviewer_comments ?? '')) ?></textarea></div> <div><label style="display:block;margin-bottom:4px;font-size:13px;">ملاحظات المقيّم</label><textarea name="notes" class="form-control" rows="3"><?= e(old('notes') ?? ($review->notes ?? '')) ?></textarea></div>
</div> </div>
</div> </div>
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
<?php $__template->section('title'); ?>تقييم أداء: <?= e($profile->first_name_ar . ' ' . $profile->last_name_ar) ?><?php $__template->endSection(); ?> <?php $__template->section('title'); ?>تقييم أداء: <?= e($profile->first_name_ar . ' ' . $profile->last_name_ar) ?><?php $__template->endSection(); ?>
<?php $__template->section('page_actions'); ?><a href="/hr/performance/cycles/<?= (int) $review->cycle_id ?>" class="btn btn-secondary">رجوع للدورة</a><?php $__template->endSection(); ?> <?php $__template->section('page_actions'); ?><a href="/hr/performance/cycles/<?= (int) $review->cycle_id ?>" class="btn btn-secondary">رجوع للدورة</a><?php $__template->endSection(); ?>
<?php $__template->section('content'); ?> <?php $__template->section('content'); ?>
<?php $rsl = ['pending'=>'بانتظار التقييم','completed'=>'مكتمل','acknowledged'=>'تم الإقرار']; ?> <?php $rsl = ['pending'=>'بانتظار التقييم','in_progress'=>'قيد التقييم','submitted'=>'مكتمل','acknowledged'=>'تم الإقرار']; ?>
<?php $rsc = ['pending'=>'#FEF3C7;color:#92400E','completed'=>'#D1FAE5;color:#065F46','acknowledged'=>'#DBEAFE;color:#1E40AF']; ?> <?php $rsc = ['pending'=>'#FEF3C7;color:#92400E','in_progress'=>'#FEF3C7;color:#92400E','submitted'=>'#D1FAE5;color:#065F46','acknowledged'=>'#DBEAFE;color:#1E40AF']; ?>
<div class="card" style="margin-bottom:20px;"> <div class="card" style="margin-bottom:20px;">
<div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;display:flex;align-items:center;gap:8px;">بيانات التقييم <span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $rsc[$review->status] ?? '#E5E7EB;color:#374151' ?>;"><?= e($rsl[$review->status] ?? $review->status) ?></span></h3></div> <div style="padding:16px;border-bottom:1px solid #E5E7EB;"><h3 style="margin:0;font-size:16px;display:flex;align-items:center;gap:8px;">بيانات التقييم <span style="display:inline-block;padding:2px 8px;border-radius:9999px;font-size:12px;background:<?= $rsc[$review->status] ?? '#E5E7EB;color:#374151' ?>;"><?= e($rsl[$review->status] ?? $review->status) ?></span></h3></div>
...@@ -51,7 +51,8 @@ $scores = json_decode($review->scores_json ?? '{}', true); ...@@ -51,7 +51,8 @@ $scores = json_decode($review->scores_json ?? '{}', true);
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php if ($review->strengths || $review->improvements || $review->goals): ?> <?php $goalsText = $review->goals_json ? json_decode($review->goals_json, true) : null; ?>
<?php if ($review->strengths || $review->improvements || $goalsText): ?>
<div class="card" style="margin-bottom:20px;"> <div class="card" style="margin-bottom:20px;">
<div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:16px;"> <div style="padding:16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:16px;">
<?php if ($review->strengths): ?> <?php if ($review->strengths): ?>
...@@ -60,18 +61,18 @@ $scores = json_decode($review->scores_json ?? '{}', true); ...@@ -60,18 +61,18 @@ $scores = json_decode($review->scores_json ?? '{}', true);
<?php if ($review->improvements): ?> <?php if ($review->improvements): ?>
<div><span style="color:#D97706;font-size:13px;font-weight:600;">مجالات التحسين</span><div style="margin-top:4px;padding:12px;background:#FFFBEB;border-radius:6px;line-height:1.6;"><?= nl2br(e($review->improvements)) ?></div></div> <div><span style="color:#D97706;font-size:13px;font-weight:600;">مجالات التحسين</span><div style="margin-top:4px;padding:12px;background:#FFFBEB;border-radius:6px;line-height:1.6;"><?= nl2br(e($review->improvements)) ?></div></div>
<?php endif; ?> <?php endif; ?>
<?php if ($review->goals): ?> <?php if ($goalsText): ?>
<div><span style="color:#2563EB;font-size:13px;font-weight:600;">الأهداف</span><div style="margin-top:4px;padding:12px;background:#EFF6FF;border-radius:6px;line-height:1.6;"><?= nl2br(e($review->goals)) ?></div></div> <div><span style="color:#2563EB;font-size:13px;font-weight:600;">الأهداف</span><div style="margin-top:4px;padding:12px;background:#EFF6FF;border-radius:6px;line-height:1.6;"><?= nl2br(e(is_string($goalsText) ? $goalsText : json_encode($goalsText, JSON_UNESCAPED_UNICODE))) ?></div></div>
<?php endif; ?> <?php endif; ?>
</div> </div>
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php if ($review->reviewer_comments): ?> <?php if ($review->notes): ?>
<div class="card" style="margin-bottom:20px;"> <div class="card" style="margin-bottom:20px;">
<div style="padding:16px;"> <div style="padding:16px;">
<span style="color:#6B7280;font-size:13px;">ملاحظات المقيّم</span> <span style="color:#6B7280;font-size:13px;">ملاحظات المقيّم</span>
<div style="margin-top:4px;padding:12px;background:#F9FAFB;border-radius:6px;line-height:1.6;"><?= nl2br(e($review->reviewer_comments)) ?></div> <div style="margin-top:4px;padding:12px;background:#F9FAFB;border-radius:6px;line-height:1.6;"><?= nl2br(e($review->notes)) ?></div>
</div> </div>
</div> </div>
<?php endif; ?> <?php endif; ?>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<?php $__template->section('content'); ?> <?php $__template->section('content'); ?>
<?php if ($ytd): ?> <?php if ($ytd): ?>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:20px;"> <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:20px;">
<div class="card" style="padding:16px;text-align:center;"><div style="font-size:13px;color:#6B7280;">إجمالي خاضع تراكمي</div><div style="font-size:18px;font-weight:700;"><?= number_format((float) ($ytd['ytd_taxable'] ?? 0), 2) ?></div></div> <div class="card" style="padding:16px;text-align:center;"><div style="font-size:13px;color:#6B7280;">إجمالي خاضع تراكمي</div><div style="font-size:18px;font-weight:700;"><?= number_format((float) ($ytd['ytd_taxable_income'] ?? 0), 2) ?></div></div>
<div class="card" style="padding:16px;text-align:center;"><div style="font-size:13px;color:#6B7280;">إجمالي ضريبة تراكمي</div><div style="font-size:18px;font-weight:700;color:#DC2626;"><?= number_format((float) ($ytd['ytd_tax'] ?? 0), 2) ?></div></div> <div class="card" style="padding:16px;text-align:center;"><div style="font-size:13px;color:#6B7280;">إجمالي ضريبة تراكمي</div><div style="font-size:18px;font-weight:700;color:#DC2626;"><?= number_format((float) ($ytd['ytd_tax'] ?? 0), 2) ?></div></div>
</div> </div>
<?php endif; ?> <?php endif; ?>
......
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