334 lines
6.6 KiB
PHP
334 lines
6.6 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Notifications\Notifiable;
|
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Database\Eloquent\Collection as DatabaseCollection;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Laravel\Passport\HasApiTokens;
|
|
use Leenooks\Traits\ScopeActive;
|
|
use Leenooks\Traits\UserSwitch;
|
|
|
|
use App\Interfaces\IDs;
|
|
use App\Notifications\ResetPassword as ResetPasswordNotification;
|
|
|
|
/**
|
|
* Class User
|
|
*
|
|
* Attributes for users:
|
|
* + role : User's role
|
|
*/
|
|
class User extends Authenticatable implements IDs
|
|
{
|
|
use HasFactory,HasApiTokens,Notifiable,UserSwitch,ScopeActive;
|
|
|
|
private const CACHE_TIME = 3600;
|
|
|
|
protected $casts = [
|
|
'last_access' => 'datetime:Y-m-d H:i:s',
|
|
'passkey' => 'json',
|
|
];
|
|
|
|
/**
|
|
* The attributes that are mass assignable.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $fillable = [
|
|
'name',
|
|
'email',
|
|
'password',
|
|
];
|
|
|
|
/**
|
|
* The attributes that should be hidden for arrays.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $hidden = [
|
|
'password',
|
|
'remember_token',
|
|
];
|
|
|
|
/**
|
|
* Role hierarchy order
|
|
*
|
|
* @var array
|
|
*/
|
|
public const role_order = [
|
|
'wholesaler',
|
|
'reseller',
|
|
'customer',
|
|
];
|
|
|
|
/* OVERRIDES */
|
|
|
|
/**
|
|
* Users password reset email notification
|
|
*
|
|
* @param string $token
|
|
*/
|
|
public function sendPasswordResetNotification($token)
|
|
{
|
|
$this->notify((new ResetPasswordNotification($token))->onQueue('high'));
|
|
}
|
|
|
|
/* INTERFACES */
|
|
|
|
public function getLIDAttribute(): string
|
|
{
|
|
return sprintf('#%04s',$this->id);
|
|
}
|
|
|
|
public function getSIDAttribute(): string
|
|
{
|
|
return sprintf('%02s-%s',$this->site_id,$this->getLIDAttribute());
|
|
}
|
|
|
|
/* RELATIONS */
|
|
|
|
/**
|
|
* This user's accounts
|
|
*/
|
|
public function accounts()
|
|
{
|
|
return $this->hasMany(Account::class)
|
|
->active();
|
|
}
|
|
|
|
/**
|
|
* The accounts that this user manages
|
|
*
|
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
|
* @note This cannot be preloaded with load() or with() - $this is a blank object
|
|
*/
|
|
public function accounts_all()
|
|
{
|
|
return $this->hasMany(Account::class)
|
|
->when((! is_null($this->rtm) && $this->id),
|
|
fn($query)=>$query->orWhereIn('rtm_id',$this->rtm?->children_all()->pluck('id')))
|
|
->active();
|
|
}
|
|
|
|
/**
|
|
* This users language configuration
|
|
*
|
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
*/
|
|
public function language()
|
|
{
|
|
return $this->belongsTo(Language::class);
|
|
}
|
|
|
|
/**
|
|
* Return the routes to market account for this user
|
|
*/
|
|
public function rtm()
|
|
{
|
|
return $this->hasOneThrough(Rtm::class,Account::class);
|
|
}
|
|
|
|
/**
|
|
* Supplier configuration for this user
|
|
*
|
|
* @deprecated To move to account->suppliers()
|
|
*/
|
|
public function suppliers()
|
|
{
|
|
return $this->belongsToMany(Supplier::class)
|
|
->withPivot('id','created_at');
|
|
}
|
|
|
|
/* ATTRIBUTES */
|
|
|
|
/**
|
|
* Logged in user's full name
|
|
*
|
|
* @return string
|
|
* @deprecated use getNameFullAttribute()
|
|
*/
|
|
public function getFullNameAttribute(): string
|
|
{
|
|
Log::alert('UMO:! Deprecated function getFullNameAttribute()');
|
|
return $this->getNameFullAttribute();
|
|
}
|
|
|
|
/**
|
|
* This is an alias method, as it is used by the framework
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getNameAttribute(): string
|
|
{
|
|
return $this->name_full;
|
|
}
|
|
|
|
/**
|
|
* Logged in user's full name
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getNameFullAttribute(): string
|
|
{
|
|
return sprintf('%s %s',$this->firstname,$this->lastname);
|
|
}
|
|
|
|
/**
|
|
* Return the name, surname first
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getNameSurFirstAttribute()
|
|
{
|
|
return sprintf('%s, %s',$this->lastname,$this->firstname);
|
|
}
|
|
|
|
/**
|
|
* Return a friendly string of this persons role
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getRoleAttribute(): string
|
|
{
|
|
return ucfirst($this->role());
|
|
}
|
|
|
|
/**
|
|
* Return the name, surname first
|
|
* @return string
|
|
* @deprecated use getNameSurFirstAttribute()
|
|
*/
|
|
public function getSurFirstNameAttribute()
|
|
{
|
|
Log::alert('UMO:! Deprecated function getSurFirstNameAttribute()');
|
|
return $this->getNameSurFirstAttribute();
|
|
}
|
|
|
|
/* SCOPES */
|
|
|
|
/**
|
|
* Search for a record
|
|
*
|
|
* @param $query
|
|
* @param string $term
|
|
*/
|
|
public function scopeSearch($query,string $term)
|
|
{
|
|
// Build our where clause
|
|
// First Name, Last name
|
|
if (preg_match('/\s+/',$term)) {
|
|
[$fn,$ln] = explode(' ',$term,2);
|
|
|
|
$query->where(function($query1) use ($fn,$ln,$term) {
|
|
$query1->where(function($query2) use ($fn,$ln) {
|
|
return $query2
|
|
->where('firstname','ilike','%'.$fn.'%')
|
|
->where('lastname','ilike','%'.$ln.'%');
|
|
});
|
|
});
|
|
|
|
} elseif (is_numeric($term)) {
|
|
$query->where('users.id','like','%'.$term.'%');
|
|
|
|
} elseif (preg_match('/@/',$term)) {
|
|
$query->where('email','ilike','%'.$term.'%');
|
|
|
|
} else {
|
|
$query
|
|
->Where('firstname','ilike','%'.$term.'%')
|
|
->orWhere('lastname','ilike','%'.$term.'%');
|
|
}
|
|
|
|
return $query;
|
|
}
|
|
|
|
/* METHODS */
|
|
|
|
/**
|
|
* Determine if the user is an admin of the user with $id
|
|
*
|
|
* @param User|null $user
|
|
* @return bool
|
|
*/
|
|
public function isAdmin(User $user=NULL): bool
|
|
{
|
|
return $user->exists
|
|
&& $this->isReseller()
|
|
&& $this->accounts_all
|
|
->pluck('user_id')
|
|
->contains($user->id);
|
|
}
|
|
|
|
/**
|
|
* Determine if the logged in user is a reseller or wholesaler
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isReseller(): bool
|
|
{
|
|
return in_array($this->role(),['wholesaler','reseller']);
|
|
}
|
|
|
|
/**
|
|
* Determine if the logged in user is a wholesaler
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isWholesaler(): bool
|
|
{
|
|
return in_array($this->role(),['wholesaler']);
|
|
}
|
|
|
|
/**
|
|
* Get all the items for the next invoice
|
|
*
|
|
* @param bool $future
|
|
* @return DatabaseCollection
|
|
* @deprecated This should be done in accounts
|
|
*/
|
|
public function next_invoice_items(bool $future=FALSE): Collection
|
|
{
|
|
return collect();
|
|
$result = new DatabaseCollection;
|
|
$this->services->load(['invoice_items.taxes']);
|
|
|
|
foreach ($this->services as $o) {
|
|
if ($future) {
|
|
if ($o->invoice_next->subDays(config('app.invoice_inadvance'))->isPast())
|
|
continue;
|
|
|
|
} else {
|
|
if ($o->invoice_next->subDays(config('app.invoice_inadvance'))->isFuture())
|
|
continue;
|
|
}
|
|
|
|
foreach ($o->next_invoice_items($future) as $oo)
|
|
$result->push($oo);
|
|
}
|
|
|
|
$result->load([
|
|
'product.translate',
|
|
'service.type',
|
|
]);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Determine what the logged in user's role is
|
|
* + Wholesaler - aka Super User
|
|
* + Reseller - services accounts on behalf of their customers
|
|
* + Customer - end user customer
|
|
*
|
|
* @return string
|
|
*/
|
|
public function role()
|
|
{
|
|
return $this->rtm
|
|
? ($this->rtm->parent_id ? 'reseller' : 'wholesaler')
|
|
: 'customer';
|
|
}
|
|
} |