208 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			208 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
<?php
 | 
						|
 | 
						|
namespace App\Jobs;
 | 
						|
 | 
						|
use App\Mail\TicketMail;
 | 
						|
use App\Models\User;
 | 
						|
use Carbon\Carbon;
 | 
						|
use Illuminate\Bus\Queueable;
 | 
						|
use Illuminate\Contracts\Queue\ShouldQueue;
 | 
						|
use Illuminate\Foundation\Bus\Dispatchable;
 | 
						|
use Illuminate\Queue\InteractsWithQueue;
 | 
						|
use Illuminate\Queue\SerializesModels;
 | 
						|
use Illuminate\Support\Facades\Mail;
 | 
						|
use Modules\Admin\app\Http\Controllers\CategoryController;
 | 
						|
use Modules\Admin\app\Models\Admin;
 | 
						|
use Modules\Admin\app\Models\Ticket;
 | 
						|
use Modules\Admin\app\Models\Tracking;
 | 
						|
 | 
						|
class CheckUserAttendanceJob implements ShouldQueue
 | 
						|
{
 | 
						|
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
						|
 | 
						|
    protected $period;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create a new job instance.
 | 
						|
     * @param string|null $period
 | 
						|
     */
 | 
						|
    public function __construct($period = null)
 | 
						|
    {
 | 
						|
        $this->period = $period;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Execute the job.
 | 
						|
     */
 | 
						|
    public function handle()
 | 
						|
    {
 | 
						|
        // Lấy tất cả người dùng
 | 
						|
        $users = User::where('permission', 'not like', '%admin%')
 | 
						|
            ->where('permission', 'not like', '%accountant%')->get();
 | 
						|
 | 
						|
        foreach ($users as $key => $user) {
 | 
						|
            // Check nhân viên nghỉ việc
 | 
						|
            if ($user->is_separated) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            // Kiểm tra dựa trên period (Sáng 'S' hoặc Chiều 'C')
 | 
						|
            if ($this->period === 'S') {
 | 
						|
                $this->checkMorning($user);
 | 
						|
            } elseif ($this->period === 'C') {
 | 
						|
                $this->checkAfternoon($user);
 | 
						|
            } else {
 | 
						|
                if ($this->period == null) {
 | 
						|
                    // Nếu không có period, kiểm tra cả sáng và chiều
 | 
						|
                    $this->checkMorning($user);
 | 
						|
                    $this->checkAfternoon($user);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private function checkAttendance($user, $periodCode, $startTime, $endTime)
 | 
						|
    {
 | 
						|
        $today = Carbon::today();
 | 
						|
        $userId = $user->id;
 | 
						|
        // Lấy tất cả tracking của user trong khoảng thời gian được chỉ định
 | 
						|
        $records = Tracking::where('user_id', $userId)
 | 
						|
            ->whereBetween('time_string', [$startTime, $endTime])
 | 
						|
            ->get();
 | 
						|
 | 
						|
        $hasCheckIn = $records->where('status', 'check in')->isNotEmpty();
 | 
						|
        $hasCheckOut = $records->where('status', 'check out')->isNotEmpty();
 | 
						|
 | 
						|
        // Kiểm tra nếu đã có ticket chờ xử lý hoặc đã được xác nhận, cho cả sáng và chiều
 | 
						|
        $existingTicket = Ticket::where('user_id', $userId)
 | 
						|
            ->where(function ($query) use ($today, $periodCode) {
 | 
						|
                // Check for tickets that exactly cover the current day and period
 | 
						|
                $query->where(function ($subQuery) use ($today, $periodCode) {
 | 
						|
                    $subQuery->where('start_date', $today->format('Y-m-d'))
 | 
						|
                        ->where('end_date', $today->format('Y-m-d'))
 | 
						|
                        ->where(function ($periodQuery) use ($periodCode) {
 | 
						|
                            // Check if the ticket covers the current period
 | 
						|
                            $periodQuery->where('start_period', $periodCode)
 | 
						|
                                ->orWhere(function ($query) {
 | 
						|
                                    // Check for a full-day ticket (S -> C)
 | 
						|
                                    $query->where('start_period', 'S')
 | 
						|
                                        ->where('end_period', 'C');
 | 
						|
                                });
 | 
						|
                        });
 | 
						|
                })
 | 
						|
                    // Check for tickets that span multiple days
 | 
						|
                    ->orWhere(function ($subQuery) use ($today, $periodCode) {
 | 
						|
                        $subQuery->where('start_date', '<=', $today->format('Y-m-d'))
 | 
						|
                            ->where('end_date', '>=', $today->format('Y-m-d'))
 | 
						|
                            ->where(function ($periodQuery) use ($periodCode, $today) {
 | 
						|
                                $periodQuery->where(function ($query)  use ($today) {
 | 
						|
                                    $query->where('start_date', '<', $today->format('Y-m-d'))
 | 
						|
                                        ->where('end_date', '>', $today->format('Y-m-d'));
 | 
						|
                                })
 | 
						|
                                    ->orWhere(function ($query) use ($today, $periodCode) {
 | 
						|
                                        $query->where(function ($queryDateStart) use ($today, $periodCode) {
 | 
						|
                                            $queryDateStart->where('start_date', '=', $today->format('Y-m-d'))
 | 
						|
                                                ->where('end_date', '>', $today->format('Y-m-d'))
 | 
						|
                                                ->where(function ($queryDateStartChild) use ($periodCode) {
 | 
						|
                                                    $queryDateStartChild->where('start_period', $periodCode)
 | 
						|
                                                        ->orWhere(function ($query) {
 | 
						|
                                                            $query->where('start_period', 'S');
 | 
						|
                                                        });
 | 
						|
                                                });
 | 
						|
                                        })
 | 
						|
                                            ->orWhere(function ($queryDateEnd) use ($today, $periodCode) {
 | 
						|
                                                $queryDateEnd->where('end_date', '=', $today->format('Y-m-d'))
 | 
						|
                                                    ->where('start_date', '<', $today->format('Y-m-d'))
 | 
						|
                                                    ->where(function ($queryDateStartChild) use ($periodCode) {
 | 
						|
                                                        $queryDateStartChild->where('end_period', $periodCode)
 | 
						|
                                                            ->orWhere(function ($query) {
 | 
						|
                                                                $query->where('end_period', 'C');
 | 
						|
                                                            });
 | 
						|
                                                    });
 | 
						|
                                            });
 | 
						|
                                    });
 | 
						|
                            });
 | 
						|
                    });
 | 
						|
            })
 | 
						|
            ->whereIn('status', ['WAITING', 'CONFIRMED'])
 | 
						|
            ->first();
 | 
						|
 | 
						|
        $type = 'ONLEAVE';
 | 
						|
        $reason = 'KHONG PHEP';
 | 
						|
 | 
						|
        //Check ngày hợp lệ nếu có check và check out của user khác
 | 
						|
        $dateNow = Tracking::whereBetween('time_string', [$startTime, $endTime])->exists();
 | 
						|
 | 
						|
        // Nếu không có check in/out, không gửi ticket và có check in/out của người khác => tạo ticket không phép
 | 
						|
        if ($hasCheckIn || $hasCheckOut) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($existingTicket) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($dateNow) {
 | 
						|
            $ticket = Ticket::create([
 | 
						|
                'user_id' => $userId,
 | 
						|
                'start_date' => $today->format('Y-m-d'),
 | 
						|
                'start_period' => $periodCode,
 | 
						|
                'end_date' => $today->format('Y-m-d'),
 | 
						|
                'end_period' => $periodCode,
 | 
						|
                'type' => $type,
 | 
						|
                'reason' => $reason,
 | 
						|
                'status' => 'WAITING',
 | 
						|
                'created_at' => Carbon::now(),
 | 
						|
                'updated_at' => Carbon::now()
 | 
						|
            ]);
 | 
						|
 | 
						|
            //Send mail
 | 
						|
            $dataMasterStartPeriod = CategoryController::getListMasterByCodeAndType("TIME_TYPE", $periodCode);
 | 
						|
            $dataMasterEndPeriod = CategoryController::getListMasterByCodeAndType("TIME_TYPE", $periodCode);
 | 
						|
            $dataMasterType = CategoryController::getListMasterByCodeAndType("REASON", $type);
 | 
						|
 | 
						|
            $formattedStartDate = $today->format('d/m/Y');
 | 
						|
            $formattedEndDate = $today->format('d/m/Y');
 | 
						|
 | 
						|
            $admins = Admin::where('permission', 'like', '%admin%')->get();
 | 
						|
            foreach ($admins as $key => $value) {
 | 
						|
                $data = array(
 | 
						|
                    "ticket_id" => $ticket->id,
 | 
						|
                    "email_template" => "email.notification_tickets",
 | 
						|
                    "email" => $user->email,
 | 
						|
                    "admin_email" => $value->email,
 | 
						|
                    "name" => $user->name,
 | 
						|
                    "date" => $dataMasterStartPeriod->c_name . " (" . $formattedStartDate . ") - " . $dataMasterEndPeriod->c_name . " (" . $formattedEndDate . ")",
 | 
						|
                    "type" => $dataMasterType->c_name,
 | 
						|
                    "note" => $reason,
 | 
						|
                    "link" => "/tickets-management", //link đến page admin
 | 
						|
                    "subject" => "[Ticket request] Ticket From " . $user->name
 | 
						|
                );
 | 
						|
                Mail::to($value->email)->send(new TicketMail($data));
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Kiểm tra check-in/check-out buổi sáng và tạo ticket nếu thiếu.
 | 
						|
     * @param int $userId
 | 
						|
     */
 | 
						|
    public function checkMorning($user)
 | 
						|
    {
 | 
						|
        $startTime = Carbon::today()->setTime(6, 0);  // Thời gian bắt đầu buổi sáng
 | 
						|
        $endTime = Carbon::createFromTime(12, 0);     // Thời gian kết thúc buổi sáng
 | 
						|
        $this->checkAttendance($user, 'S', $startTime, $endTime);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Kiểm tra check-in/check-out buổi chiều và tạo ticket nếu thiếu.
 | 
						|
     * @param int $userId
 | 
						|
     */
 | 
						|
    public function checkAfternoon($user)
 | 
						|
    {
 | 
						|
        $startTime = Carbon::today()->setTime(12, 0);  // Thời gian bắt đầu buổi chiều
 | 
						|
        $endTime = Carbon::createFromTime(17, 30);     // Thời gian kết thúc buổi chiều
 | 
						|
        $this->checkAttendance($user, 'C', $startTime, $endTime);
 | 
						|
    }
 | 
						|
}
 |