%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /var/www/html/hr/api/app/Models/
Upload File :
Create Path :
Current File : /var/www/html/hr/api/app/Models/User.php

<?php

namespace App\Models;

use App\Exceptions\AppException;
use App\Notifications\AccountCreatedNotification;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Laravel\Passport\HasApiTokens;
use Spatie\MediaLibrary\Exceptions\FileCannotBeAdded;
use Spatie\MediaLibrary\HasMedia\HasMedia;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
use Spatie\MediaLibrary\Models\Media;
use Spatie\Permission\Traits\HasRoles;
use Throwable;

/**
 * @property integer id
 * @property string name
 * @property string surname
 * @property string email
 * @property string phone
 * @property string channel_id
 * @property string password
 * @property string external_reference
 * @property mixed birthday
 * @property boolean is_confirmed
 * @property boolean is_enabled
 * @property mixed created_at
 * @property mixed confirmed_at
 * @property mixed updated_at
 * @property mixed roles
 * @property mixed projects
 * @property AnnualLeave annualLeave
 */
class User extends Authenticatable implements HasMedia
{
    use HasApiTokens, Notifiable, HasRoles, HasMediaTrait;

    const AVATAR = 'avatars';

    protected $perPage = 10;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'surname',
        'birthday',
        'email',
        'phone',
        'channel_id',
        'password',
        'is_confirmed',
        'confirmed_at',
        'is_enabled',
        'external_reference',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'id'                 => 'integer',
        'name'               => 'string',
        'surname'            => 'string',
        'birthday'           => 'date',
        'email'              => 'string',
        'phone'              => 'string',
        'channel_id'         => 'string',
        'is_confirmed'       => 'boolean',
        'confirmed_at'       => 'datetime',
        'is_enabled'         => 'boolean',
        'external_reference' => 'string',
    ];

    /**
     * @param $data
     * @param bool $notify
     * @return User
     * @throws Throwable
     */
    public static function createItem($data, $notify = false)
    {
        try {
            DB::beginTransaction();
            $channelId = BaseModel::generateRandomToken(20);
            /** @var User $user */
            $user = self::query()
                        ->create([
                            'name'               => $data['name'],
                            'surname'            => $data['surname'],
                            'email'              => $data['email'],
                            'phone'              => $data['phone'],
                            'channel_id'         => $channelId,
                            'birthday'           => $data['birthday'],
                            'external_reference' => array_key_exists('external_reference', $data)
                                ? $data['external_reference']
                                : null,
                            'password'           => Str::random(16),
                            'is_confirmed'       => true,
                            'is_enabled'         => true,
                        ]);
            if (array_key_exists('role_ids', $data)) {
                $user->roles()
                     ->sync($data['role_ids']);
            }
            if (!array_key_exists('configurations', $data)) {
                $data['configurations'] = [];
            }
            $configData = array_merge(Configuration::getCurrent()
                                                   ->toArray(), $data['configurations']);
            $configData['user_id'] = $user->id;
            /** @var Configuration $config */
            $config = Configuration::createItem($configData);
            $days = round(AnnualLeave::calculatePercentage($config->valid_from, $config->valid_to) * $config->annual_leave_quantity);
            $user->setupAnnualLeave($days, AnnualLeaveTransaction::ADD, $config->holidays_validity_in_months);
            DB::commit();
            if ($notify) {
                $token = ResetPassword::generateToken($user->email);
                $user->notify(new AccountCreatedNotification($token));
            }
            return $user;
        } catch (Throwable $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * @param $quantity
     * @param $type
     * @param $validity
     * @throws Throwable
     */
    public function setupAnnualLeave($quantity, $type, $validity)
    {
        try {
            DB::beginTransaction();
            /** @var AnnualLeave $leave */
            $leave = $this->annualLeave()
                          ->make([
                              'quantity' => $quantity,
                          ]);
            $leave->save();
            $leave->transactions()
                  ->create([
                      'type'       => $type,
                      'notes'      => 'Annual leave',
                      'quantity'   => $quantity,
                      'expires_at' => Carbon::now()
                                            ->startOfYear()
                                            ->addMonths($validity),
                  ]);
            DB::commit();
        } catch (Throwable $e) {
            DB::rollBack();
            throw $e;
        }
    }

    public function annualLeave()
    {
        return $this->hasOne(AnnualLeave::class);
    }

    public static function getHrUsers()
    {
        return self::query()
                   ->whereHas('roles', function (Builder $q) {
                       $q->where('name', Role::HR);
                   })
                   ->get();
    }

    /**
     * @param $data
     * @return User
     * @throws Throwable
     */
    public function updateItem($data)
    {
        try {
            $loggedUser = BaseModel::getLoggedInUser();
            DB::beginTransaction();
            $this->name = $data['name'];
            $this->surname = $data['surname'];
            $this->email = $data['email'];
            $this->phone = $data['phone'];
            $this->birthday = $data['birthday'];
            $this->external_reference = array_key_exists('external_reference', $data)
                ? $data['external_reference']
                : null;
            $this->save();

            if (array_key_exists('role_ids', $data) && ($loggedUser->isAdmin() || $loggedUser->isHR())) {
                $this->roles()
                     ->sync($data['role_ids']);
            }
            DB::commit();
            return $this;
        } catch (Throwable $e) {
            DB::rollBack();
            throw $e;
        }
    }

    public function isAdmin()
    {
        return $this->hasRole(Role::ADMIN);
    }

    public function isHR()
    {
        return $this->hasRole(Role::HR);
    }

    /**
     * @param $value
     */
    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = bcrypt($value);
    }

    /**
     * @param $value
     * @return string
     */
    public function getCreatedAtAttribute($value)
    {
        return Carbon::parse($value)
                     ->toIso8601String();
    }

    /**
     * @param $value
     * @return string
     */
    public function getUpdatedAtAttribute($value)
    {
        return Carbon::parse($value)
                     ->toIso8601String();
    }

    /**
     * @return $this
     */
    public function confirm()
    {
        $this->is_confirmed = true;
        $this->confirmed_at = Carbon::now();
        $this->save();
        return $this;
    }

    /**
     * @return $this
     */
    public function enable()
    {
        $this->is_enabled = true;
        $this->save();
        return $this;
    }

    /**
     * @return $this
     * @throws AppException
     */
    public function disable()
    {
        $loggedUser = BaseModel::getLoggedInUser();
        if ($this->id === $loggedUser->id) {
            throw new AppException(trans('users.cant_disable_your_account'));
        }
        $this->is_enabled = false;
        $this->save();
        return $this;
    }

    /**
     * @param $password
     * @return $this
     */
    public function updatePassword($password)
    {
        $this->password = $password;
        $this->save();
        return $this;
    }

    /**
     * @param $base64data
     * @return $this
     * @throws FileCannotBeAdded
     */
    public function setAvatarBase64($base64data)
    {
        $name = md5(time());
        DB::beginTransaction();
        try {
            if ($media = $this->getMedia(self::AVATAR)
                              ->first()) {
                $media->delete();
            }
            $this->addMediaFromBase64($base64data)
                 ->usingName($name)
                 ->usingFileName("$name.png")
                 ->toMediaCollection(self::AVATAR, self::AVATAR);
            $this->save();
            DB::commit();
            return $this;
        } catch (FileCannotBeAdded $e) {
            DB::rollBack();
            throw $e;
        }
    }

    public function getAvatar()
    {
        /** @var Media $media */
        if ($media = $this->getMedia(self::AVATAR)
                          ->first()) {
            return asset($media->getUrl());
        }
        return asset('images/user.png');
    }

    public function isFinance()
    {
        return $this->hasRole(Role::FINANCE);
    }

    public function isManager()
    {
        return $this->hasRole(Role::MANAGER);
    }

    public function formatDate($date, $format = 'Y-m-d')
    {
        if (!$date) {
            return null;
        }
        return Carbon::parse($date)
                     ->toISOString();
    }

    public function getDaysOffIn($start, $end, $includePto = true)
    {
        $holidays = Holiday::getHolidaysInDates($start, $end, [
            'name',
            'date',
        ]);
        $ptos = collect($holidays);
        if ($includePto) {
            $daysOff = Pto::getPtos($start, $end)
                          ->where('user_id', $this->id)
                          ->where('status', Pto::APPROVED)
                          ->get();
            /** @var Pto $dayOff */
            foreach ($daysOff as $dayOff) {
                $range = CarbonPeriod::create($dayOff->start_date, $dayOff->end_date);
                foreach ($range as $date) {
                    $isAlreadyOff = $ptos->contains(function ($p) use ($date) {
                        return Carbon::parse($p['date'])
                                     ->isSameDay(Carbon::parse($date));
                    });
                    if (Day::isWorkingDay($date) && !$isAlreadyOff) {
                        $ptos->push([
                            'name' => 'PTO',
                            'date' => $date,
                        ]);
                    }
                }
            }
        }
        return $ptos->sortBy('date')
                    ->values()
                    ->all();
    }

    public function getCalendarData($start, $end)
    {
        $holidays = Holiday::getHolidaysInDates($start, $end, [
            'name',
            'date',
        ]);
        $workingDayNames = WorkingDay::getDayNames();
        /** @var Configuration $config */
        $config = $this->currentConfigurations();
        $daysOff = Pto::getPtos($start, $end)
                      ->where('user_id', $this->id)
                      ->where('status', Pto::APPROVED)
                      ->get()
                      ->map(function ($timecard) use ($config) {
                          $timecard['type'] = 'Holiday';
                          $timecard['hours'] = $config->expected_daily_working_hours;
                          return $timecard;
                      });
        $ptos = collect($holidays)->map(function ($holiday) use ($config) {
            $holiday['type'] = 'Holiday';
            $holiday['hours'] = 0;
            return $holiday;
        });

        /** @var Pto $dayOff */
        foreach ($daysOff as $dayOff) {
            $range = CarbonPeriod::create($dayOff->start_date, $dayOff->end_date);
            /** @var Carbon $date */
            foreach ($range as $date) {
                $isAlreadyOff = $ptos->contains(function ($p) use ($date) {
                    return Carbon::parse($p['date'])
                                 ->isSameDay($date);
                });
                if (in_array($date->dayName, $workingDayNames) && !$isAlreadyOff) {
                    $ptos->push([
                        'name'  => 'PTO',
                        'type'  => 'PTO',
                        'hours' => $config->expected_daily_working_hours,
                        'date'  => $date,
                    ]);
                }
            }
        }

        $timecards = Timecard::query()
                             ->where('user_id', $this->id)
                             ->where('date', '>=', $start)
                             ->where('date', '<=', $end)
                             ->groupBy('date')
                             ->get([
                                 DB::raw('date'),
                                 DB::raw('SUM(hours) as hours'),
                             ])
                             ->map(function ($timecard) use ($ptos, $config, $workingDayNames) {
                                 $timecard['type'] = 'Timecard';
                                 $isAlreadyOff = $ptos->contains(function ($p) use ($timecard) {
                                     return Carbon::parse($p['date'])
                                                  ->isSameDay(Carbon::parse($timecard->date));
                                 });
                                 if ($isAlreadyOff) {
                                     $timecard['name'] = "Daily tasks ({$timecard['hours']})";
                                     $timecard['has_overtime'] = true;
                                     $timecard['has_undertime'] = false;
                                 } else {
                                     // if (Day::isWorkingDay($timecard->date)) {
                                     if (in_array(Carbon::parse($timecard->date)->dayName, $workingDayNames)) {
                                         $timecard['name'] = "Daily tasks ({$timecard['hours']} / {$config->expected_daily_working_hours})";
                                         $timecard['has_overtime'] = $timecard['hours'] > $config->expected_daily_working_hours;
                                         $timecard['has_undertime'] = $timecard['hours'] < $config->expected_daily_working_hours;
                                     } else {
                                         $timecard['name'] = "Daily tasks ({$timecard['hours']})";
                                         $timecard['has_overtime'] = true;
                                         $timecard['has_undertime'] = false;
                                     }
                                 }
                                 return $timecard;
                             });
        $ptos = $ptos->merge(collect($timecards));

        $allDates = CarbonPeriod::create($start, Carbon::now());
        /** @var Carbon $date */
        foreach ($allDates as $date) {
            $exists = $ptos->contains(function ($p) use ($date) {
                return Carbon::parse($p['date'])
                             ->isSameDay(Carbon::parse($date));
            });
            if (!$exists && in_array($date->dayName, $workingDayNames)) {
                $ptos->push([
                    'date'          => $date,
                    'name'          => "Daily tasks (0 / $config->expected_daily_working_hours)",
                    'has_overtime'  => false,
                    'has_undertime' => $config->expected_daily_working_hours > 0,
                ]);
            }
        }

        return $ptos->sortBy('date')
                    ->values()
                    ->all();
    }

    public function currentConfigurations()
    {
        $now = Carbon::now();
        return $this->configurations()
                    ->where(function (Builder $q) use ($now) {
                        $q->whereNull('valid_to');
                        $q->orWhere('valid_to', '>=', $now);
                    })
                    ->first();
    }

    public function configurations()
    {
        return $this->hasMany(Configuration::class);
    }

    public function performance($start = null, $end = null)
    {
        if (!$start) {
            $start = BaseModel::getStartOfMonth();
        }
        if (!$end) {
            $end = BaseModel::getEndOfMonth();
        }
        $totalHours = Timecard::query()
                              ->where('user_id', $this->id)
                              ->where('date', '>=', $start)
                              ->where('date', '<=', $end)
                              ->get([
                                  DB::raw('SUM(hours) as hours'),
                              ]);
        $approvedHours = Timecard::query()
                                 ->where('user_id', $this->id)
                                 ->where('date', '>=', $start)
                                 ->where('date', '<=', $end)
                                 ->where('status', Timecard::APPROVED)
                                 ->get([
                                     DB::raw('SUM(hours) as hours'),
                                     DB::raw('SUM(approved_hours) as approved_hours'),
                                 ]);
        return [
            'total_worked'     => head(head($totalHours))->hours,
            'waiting_approval' => head(head($totalHours))->hours - head(head($approvedHours))->hours,
            'approved_hours'   => head(head($approvedHours))->hours,
            'billable_hours'   => head(head($approvedHours))->approved_hours,
            'performance'      => round(100 * head(head($approvedHours))->approved_hours / head(head($approvedHours))->hours, 0) . "%",
        ];
    }

    public function hasProjectAccess($projectId)
    {
        return $this->projects()
                    ->where('project_id', $projectId)
                    ->exists();
    }

    public function projects()
    {
        return $this->belongsToMany(Project::class, 'user_project');
    }

    public function managingProjects()
    {
        return $this->hasMany(Project::class, 'manager_id');
    }

    public function getActiveProjects(Carbon $date)
    {
        return $this->projects()
                    ->where('start_date', '<=', $date)
                    ->where('end_date', '>=', $date)
                    ->get();
    }

    public function markAllNotificationsAsRead()
    {
        $this->notifications()
             ->where('is_read', false)
             ->update([
                 'is_read' => true,
                 'read_at' => Carbon::now(),
             ]);
        return $this;
    }

    public function notifications()
    {
        return $this->hasMany(Notification::class);
    }

    public function getBadge()
    {
        return $this->notifications()
                    ->where('is_read', false)
                    ->count();
    }

    public function sendBirthdayNotification()
    {
        $this->notifications()
             ->create([
                 'title'      => trans('users.happy_birthday', [
                     'name' => $this->getFullName(),
                 ]),
                 'model_type' => 'User',
                 'model_id'   => $this->id,
                 'type'       => Notification::TYPE_SUCCESS,
             ]);
    }

    public function getFullName()
    {
        return $this->name . ' ' . $this->surname;
    }

    public function notifyForTimecardApproval()
    {
        $this->notifications()
             ->create([
                 'title'      => trans('timecards.notify_for_approval'),
                 'model_type' => 'Timecard',
                 'model_id'   => 0,
                 'type'       => Notification::TYPE_WARNING,
             ]);
    }

    public function notifyForPaymentComingUp(MaintenancePayment $payment)
    {
        $params = [
            'name'   => $payment->name,
            'client' => $payment->client->name,
            'date'   => Carbon::parse($payment->next_payment_date)
                              ->format('d M Y'),
        ];
        $title = trans('maintenancePayments.payment_coming_up', $params);
        $type = Notification::TYPE_SUCCESS;
        if ($payment->type === MaintenancePayment::EXPENSE) {
            $title = trans('maintenancePayments.expense_coming_up', $params);
            $type = Notification::TYPE_WARNING;
        }

        $this->notifications()
             ->create([
                 'title'      => $title,
                 'model_type' => 'MaintenancePayment',
                 'model_id'   => $payment->id,
                 'type'       => $type,
             ]);
    }

    public function notifyForDuePayment(MaintenancePayment $payment)
    {
        $this->notifications()
             ->create([
                 'title'      => trans('maintenancePayments.due_payment', [
                     'name'   => $payment->name,
                     'client' => $payment->client->name,
                 ]),
                 'model_type' => 'MaintenancePayment',
                 'model_id'   => $payment->id,
                 'type'       => Notification::TYPE_ERROR,
             ]);
    }

}

Zerion Mini Shell 1.0