Files
a.montask/app/Http/Controllers/LeaveController.php
T
2026-07-26 11:02:22 +03:30

258 lines
8.6 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Attendance;
use App\Models\LeaveRequest;
use App\Models\User;
use App\Services\LatePenaltyService;
use App\Support\JalaliHelper;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Morilog\Jalali\Jalalian;
class LeaveController extends Controller
{
public function store(Request $request)
{
if (!isset($_COOKIE['user_identity'])) {
return redirect('/')->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;
}
}