%PDF- %PDF-
Direktori : /var/www/html/hr/api/app/Models/ |
Current File : /var/www/html/hr/api/app/Models/Pto.php |
<?php namespace App\Models; use App\Events\NotificationSentEvent; use App\Exceptions\AppException; use App\Traits\HasNotifications; use Carbon\Carbon; use Illuminate\Support\Facades\DB; use Throwable; /** * @property integer id * @property mixed start_date * @property mixed end_date * @property string status * @property string type * @property string notes * @property integer user_id * @property integer approved_by * @property User user * @property User approvedBy */ //Stands for Paid time off class Pto extends BaseModel { use HasNotifications; const DRAFT = 'DRAFT'; const PENDING = 'PENDING'; const APPROVED = 'APPROVED'; const REJECTED = 'REJECTED'; const ANNUAL_LEAVE = 'ANNUAL_LEAVE'; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'start_date', 'end_date', 'status', 'type', 'notes', ]; protected $guarded = [ 'user_id', 'approved_by', ]; /** * The attributes that should be cast to native types. * * @var array */ protected $casts = [ 'id' => 'integer', 'start_date' => 'date', 'end_date' => 'date', 'notes' => 'string', 'status' => 'string', 'type' => 'string', 'user_id' => 'integer', 'approved_by' => 'integer', ]; /** * @param $data * @return self * @throws Throwable */ public static function createItem($data) { try { if (Carbon::parse($data['start_date']) ->isBefore(Carbon::now())) { throw new AppException(trans('ptos.should_be_in_future')); } $user = self::getLoggedInUser(); $currentPtos = self::getPtos($data['start_date'], $data['end_date']) ->where('user_id', $user->id); if ($currentPtos->count() > 0) { throw new AppException(trans('ptos.overlapping')); } DB::beginTransaction(); /** @var self $item */ $item = self::query() ->make([ 'start_date' => $data['start_date'], 'end_date' => $data['end_date'], 'notes' => array_key_exists('notes', $data) ? $data['notes'] : null, ]); $item->user() ->associate($user); $item->save(); DB::commit(); return $item->fresh(); } catch (Throwable $e) { DB::rollBack(); throw $e; } } public static function getPtos($startDate, $endDate) { return self::query() ->where('status', '!=', self::REJECTED) ->where('start_date', '<=', $endDate) ->where('end_date', '>=', $startDate); } public function user() { return $this->belongsTo(User::class); } /** * @param $data * @return self * @throws Throwable */ public function updateItem($data) { try { if ($this->status !== self::DRAFT) { throw new AppException(trans('ptos.cant_modify')); } $this->start_date = $data['start_date']; $this->end_date = $data['end_date']; $this->notes = $data['notes']; $this->save(); return $this; } catch (Throwable $e) { throw $e; } } /** * @return $this * @throws Throwable */ public function request() { try { if ($this->status === self::PENDING) { throw new AppException(trans('ptos.awaiting_response')); } if ($this->status === self::APPROVED) { throw new AppException(trans('ptos.already_approved')); } if ($this->status === self::REJECTED) { throw new AppException('ptos.already_rejected'); } $this->status = self::PENDING; $this->save(); $this->notifyForPtoRequest(); return $this; } catch (Throwable $e) { throw $e; } } private function notifyForPtoRequest() { $hrUsers = User::getHrUsers(); /** @var User $requester */ $requester = $this->user; /** @var User $user */ foreach ($hrUsers as $user) { /** @var Notification $notification */ $notification = $user->notifications() ->create([ 'title' => trans('ptos.requested', [ 'name' => $requester->getFullName(), ]), 'model_type' => 'Pto', 'model_id' => $this->id, ]); broadcast(new NotificationSentEvent($user, $notification)); } } /** * @return $this * @throws Throwable */ public function approve() { try { if ($this->status === self::APPROVED) { return $this; } if (Carbon::parse($this->start_date) ->isBefore(Carbon::now())) { throw new AppException(trans('ptos.is_in_the_past')); } $loggedUser = self::getLoggedInUser(); if ($this->user->isAdmin() && !$loggedUser->isAdmin()) { throw new AppException(trans('pto.admin_only')); } $days = $this->calculateWorkingDays(); DB::beginTransaction(); /** @var AnnualLeave $leave */ $leave = $this->user->annualLeave; $leave->quantity -= $days; $leave->save(); $leave->transactions() ->create([ 'type' => AnnualLeaveTransaction::REMOVE, 'notes' => $this->getTransactionNotesforApproval(), 'quantity' => $days, ]); $this->status = self::APPROVED; $this->approvedBy() ->associate($loggedUser); $this->save(); DB::commit(); $this->notifyForPtoApproved(); return $this; } catch (Throwable $e) { DB::rollBack(); throw $e; } } private function calculateWorkingDays($includePto = true) { $start = Carbon::parse($this->start_date); $end = Carbon::parse($this->end_date); return WorkingDay::getWorkingDaysCount($start, $end, $this->user, $includePto); } private function getTransactionNotesForApproval() { return trans('ptos.transaction_notes_for_approval', [ 'date' => $this->getDatesText(), ]); } private function getDatesText() { $start = Carbon::parse($this->start_date); $end = Carbon::parse($this->end_date); if ($start->isSameDay($end)) { return $start->format('d M Y'); } return $start->format('d M Y') . ' - ' . $end->format('d M Y'); } public function approvedBy() { return $this->belongsTo(User::class, 'approved_by'); } private function notifyForPtoApproved() { $approver = $this->approvedBy; /** @var Notification $notification */ $notification = $this->user->notifications() ->create([ 'title' => trans('ptos.approved', [ 'name' => $approver->getFullName(), ]), 'model_type' => 'Pto', 'model_id' => $this->id, 'type' => Notification::TYPE_SUCCESS, ]); broadcast(new NotificationSentEvent($this->user, $notification)); } /** * @return $this * @throws Throwable */ public function reject() { try { if ($this->status === self::REJECTED) { return $this; } if (Carbon::parse($this->start_date) ->isBefore(Carbon::now())) { throw new AppException(trans('ptos.is_in_the_past')); } $loggedUser = self::getLoggedInUser(); if ($this->user->isAdmin() && !$loggedUser->isAdmin()) { throw new AppException(trans('pto.admin_only')); } DB::beginTransaction(); if ($this->status === self::APPROVED) { $days = $this->calculateWorkingDays(false); $leave = $this->user->annualLeave; $leave->quantity += $days; $leave->save(); $leave->transactions() ->create([ 'type' => AnnualLeaveTransaction::ADD, 'notes' => $this->getTransactionNotesForRejection(), 'quantity' => $days, ]); } $this->status = self::REJECTED; $this->approvedBy() ->associate($loggedUser); $this->save(); DB::commit(); $this->notifyForPtoRejected(); return $this; } catch (Throwable $e) { DB::rollBack(); throw $e; } } private function getTransactionNotesForRejection() { return trans('ptos.transaction_notes_for_rejection', [ 'date' => $this->getDatesText(), ]); } private function notifyForPtoRejected() { $approver = $this->approvedBy; /** @var Notification $notification */ $notification = $this->user->notifications() ->create([ 'title' => trans('ptos.rejected', [ 'name' => $approver->getFullName(), ]), 'model_type' => 'Pto', 'model_id' => $this->id, 'type' => Notification::TYPE_ERROR, ]); broadcast(new NotificationSentEvent($this->user, $notification)); } public function isDeletable() { return $this->status === self::DRAFT; } public function isEditable() { return $this->status === self::DRAFT; } public function canApprove() { return $this->status !== self::DRAFT && Carbon::parse($this->start_date) ->isAfter(Carbon::now()); } public function canReject() { return $this->status !== self::DRAFT && Carbon::parse($this->start_date) ->isAfter(Carbon::now()); } }