with('message', [ 'color' => '#ff8800ff', 'text' => 'ابتدا باید وارد شوید!', ]); } $user = User::where('user_name', $_COOKIE['user_identity'])->first(); if (!$user) { return redirect('/')->with('message', [ 'color' => '#ff8800ff', 'text' => 'کاربر یافت نشد!', ]); } $type = $request->input('type'); if (!in_array($type, ['daily', 'hourly'], true)) { return back()->with('message', [ 'color' => '#ff4400ff', 'text' => 'نوع مرخصی نامعتبر است.', ]); } if ($type === 'daily') { $dateFrom = $this->parseJalaliDate($request->input('date_from')); $dateTo = $this->parseJalaliDate($request->input('date_to')); if (!$dateFrom || !$dateTo) { return back()->with('message', [ 'color' => '#ff4400ff', 'text' => 'بازه تاریخ مرخصی روزانه الزامی است.', ]); } if ($dateTo < $dateFrom) { return back()->with('message', [ 'color' => '#ff4400ff', 'text' => 'تاریخ پایان نمی‌تواند قبل از شروع باشد.', ]); } $timeFrom = null; $timeTo = null; } else { $dateFrom = $this->parseJalaliDate($request->input('date')); $dateTo = $dateFrom; $timeFrom = $this->normalizeTime($request->input('time_from')); $timeTo = $this->normalizeTime($request->input('time_to')); if (!$dateFrom || !$timeFrom || !$timeTo) { return back()->with('message', [ 'color' => '#ff4400ff', 'text' => 'تاریخ و ساعت شروع/پایان مرخصی ساعتی الزامی است.', ]); } if ($timeTo <= $timeFrom) { return back()->with('message', [ 'color' => '#ff4400ff', 'text' => 'ساعت پایان باید بعد از ساعت شروع باشد.', ]); } } $leave = LeaveRequest::create([ 'user_id' => $user->id, 'user_identity' => $user->user_name, 'type' => $type, 'date_from' => $dateFrom, 'date_to' => $dateTo, 'time_from' => $timeFrom, 'time_to' => $timeTo, 'reason' => $request->input('reason'), 'status' => 'pending', ]); $user->req_counts = (int) $user->req_counts + 1; $user->save(); $this->notifyAdminsNewLeave($leave, $user); return redirect('/')->with('message', [ 'color' => '#00c300ff', 'text' => 'درخواست مرخصی ثبت شد و برای تأیید ادمین ارسال گردید.', ]); } public function decide(Request $request) { if (!isset($_COOKIE['user_identity'])) { return back()->with('message', [ 'color' => '#ff8800ff', 'text' => 'ابتدا باید وارد شوید!', ]); } $admin = User::where('user_name', $_COOKIE['user_identity'])->first(); if (!$admin || !in_array((string) $admin->is_admin, ['1', '2'], true)) { return back()->with('message', [ 'color' => '#ff8800ff', 'text' => 'دسترسی ندارید!', ]); } $leave = LeaveRequest::find($request->input('leave_id')); if (!$leave || $leave->status !== 'pending') { return back()->with('message', [ 'color' => '#ff8800ff', 'text' => 'درخواست مرخصی یافت نشد.', ]); } $action = $request->input('update'); if (!in_array($action, ['approve', 'reject'], true)) { return back()->with('message', [ 'color' => '#ff4400ff', 'text' => 'عملیات نامعتبر است.', ]); } $leave->status = $action === 'approve' ? 'approved' : 'rejected'; $leave->reviewed_by = $admin->id; $leave->reviewed_at = now(); $leave->save(); $owner = User::where('user_name', $leave->user_identity)->first(); if ($owner && (int) $owner->req_counts > 0) { $owner->req_counts -= 1; $owner->save(); } if ($leave->status === 'approved') { $this->recalculateLateForLeavePeriod($leave); } $statusFa = $leave->status === 'approved' ? 'تایید' : 'رد'; if ($owner) { $this->notifyUserLeaveDecision($owner, $statusFa); } return back()->with('message', [ 'color' => '#6aff00ff', 'text' => "درخواست مرخصی با موفقیت {$statusFa} شد.", ]); } private function notifyUserLeaveDecision(User $user, string $statusFa): void { if (!$user->bale) { return; } try { Http::withoutVerifying()->post( 'https://tapi.bale.ai/1482838710:sYbLzby0tuLRzHvP4d3LsbcNwg2sjSDLTAU/sendMessage', [ 'chat_id' => $user->bale, 'text' => "درخواست مرخصی شما {$statusFa} شد.", ] ); } catch (\Exception $e) { } } private function recalculateLateForLeavePeriod(LeaveRequest $leave): void { $service = app(LatePenaltyService::class); $from = Carbon::parse($leave->date_from)->startOfDay(); $to = Carbon::parse($leave->date_to)->endOfDay(); $attendances = Attendance::query() ->where('user_identity', $leave->user_identity) ->whereBetween('entered_at', [$from, $to]) ->orderBy('entered_at') ->get(); foreach ($attendances as $attendance) { $service->syncAttendance($attendance); } } private function notifyAdminsNewLeave(LeaveRequest $leave, User $user): void { $typeFa = $leave->type === 'daily' ? 'روزانه' : 'ساعتی'; $from = JalaliHelper::format($leave->date_from, 'Y/m/d'); $to = JalaliHelper::format($leave->date_to, 'Y/m/d'); $message = "درخواست مرخصی {$typeFa}\n"; $message .= "کارمند: {$user->name}\n"; if ($leave->type === 'daily') { $message .= "از {$from} تا {$to}\n"; } else { $timeFrom = substr((string) $leave->time_from, 0, 5); $timeTo = substr((string) $leave->time_to, 0, 5); $message .= "تاریخ: {$from}\nساعت: {$timeFrom} تا {$timeTo}\n"; } if ($leave->reason) { $message .= "دلیل: {$leave->reason}"; } $this->send_admins($message); } private function parseJalaliDate(?string $value): ?string { if (!$value) { return null; } $value = \Morilog\Jalali\CalendarUtils::convertNumbers(trim($value), true); $value = str_replace('/', '-', $value); try { if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { // اگر سال شمسی باشد (مثلاً 1404) با Jalalian تبدیل می‌شود $year = (int) substr($value, 0, 4); if ($year >= 1300 && $year <= 1500) { return Jalalian::fromFormat('Y-m-d', $value)->toCarbon()->format('Y-m-d'); } return $value; } return Carbon::parse($value)->format('Y-m-d'); } catch (\Throwable $e) { return null; } } private function normalizeTime(?string $value): ?string { if (!$value) { return null; } $value = trim(\Morilog\Jalali\CalendarUtils::convertNumbers($value, true)); if (preg_match('/^(\d{1,2}):(\d{2})/', $value, $m)) { return sprintf('%02d:%02d:00', (int) $m[1], (int) $m[2]); } return null; } }