2017-11-03 05:26:07 +00:00
|
|
|
<?php
|
|
|
|
|
2021-06-29 03:18:52 +00:00
|
|
|
namespace App\Models;
|
2017-11-03 05:26:07 +00:00
|
|
|
|
2022-04-21 04:41:26 +00:00
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
2017-12-12 05:28:49 +00:00
|
|
|
use Illuminate\Notifications\Notifiable;
|
|
|
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
2020-01-12 12:42:32 +00:00
|
|
|
use Illuminate\Support\Collection;
|
|
|
|
use Illuminate\Database\Eloquent\Collection as DatabaseCollection;
|
2024-07-07 00:21:27 +00:00
|
|
|
use Illuminate\Support\Facades\Log;
|
2018-07-13 04:53:44 +00:00
|
|
|
use Laravel\Passport\HasApiTokens;
|
2022-04-21 06:25:29 +00:00
|
|
|
use Leenooks\Traits\ScopeActive;
|
2018-07-13 04:53:44 +00:00
|
|
|
use Leenooks\Traits\UserSwitch;
|
2017-11-03 05:26:07 +00:00
|
|
|
|
2022-04-22 01:47:46 +00:00
|
|
|
use App\Interfaces\IDs;
|
2020-07-21 06:39:23 +00:00
|
|
|
use App\Notifications\ResetPassword as ResetPasswordNotification;
|
2024-07-23 05:05:56 +00:00
|
|
|
use App\Traits\SiteID;
|
2022-04-21 04:41:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Class User
|
|
|
|
*
|
|
|
|
* Attributes for users:
|
|
|
|
* + role : User's role
|
|
|
|
*/
|
2022-04-22 01:47:46 +00:00
|
|
|
class User extends Authenticatable implements IDs
|
2017-11-03 05:26:07 +00:00
|
|
|
{
|
2024-07-23 05:05:56 +00:00
|
|
|
use HasFactory,HasApiTokens,Notifiable,UserSwitch,ScopeActive,SiteID;
|
2022-04-21 04:41:26 +00:00
|
|
|
|
|
|
|
private const CACHE_TIME = 3600;
|
2020-02-10 11:07:46 +00:00
|
|
|
|
2024-07-05 12:56:02 +00:00
|
|
|
protected $casts = [
|
|
|
|
'last_access' => 'datetime:Y-m-d H:i:s',
|
2024-07-22 14:13:54 +00:00
|
|
|
'passkey' => 'json',
|
2020-02-08 11:51:50 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The attributes that are mass assignable.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $fillable = [
|
2022-04-21 06:25:29 +00:00
|
|
|
'name',
|
|
|
|
'email',
|
|
|
|
'password',
|
2020-02-08 11:51:50 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The attributes that should be hidden for arrays.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $hidden = [
|
|
|
|
'password',
|
|
|
|
'remember_token',
|
|
|
|
];
|
2018-04-10 11:23:13 +00:00
|
|
|
|
2020-04-18 22:33:41 +00:00
|
|
|
/**
|
|
|
|
* Role hierarchy order
|
2022-04-21 06:25:29 +00:00
|
|
|
*
|
2020-04-18 22:33:41 +00:00
|
|
|
* @var array
|
|
|
|
*/
|
2022-04-21 06:25:29 +00:00
|
|
|
public const role_order = [
|
2020-04-18 22:33:41 +00:00
|
|
|
'wholesaler',
|
|
|
|
'reseller',
|
|
|
|
'customer',
|
|
|
|
];
|
|
|
|
|
2022-04-21 06:25:29 +00:00
|
|
|
/* OVERRIDES */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Users password reset email notification
|
|
|
|
*
|
|
|
|
* @param string $token
|
|
|
|
*/
|
|
|
|
public function sendPasswordResetNotification($token)
|
|
|
|
{
|
|
|
|
$this->notify((new ResetPasswordNotification($token))->onQueue('high'));
|
|
|
|
}
|
|
|
|
|
2022-04-22 01:47:46 +00:00
|
|
|
/* INTERFACES */
|
|
|
|
|
|
|
|
public function getLIDAttribute(): string
|
|
|
|
{
|
|
|
|
return sprintf('#%04s',$this->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getSIDAttribute(): string
|
|
|
|
{
|
|
|
|
return sprintf('%02s-%s',$this->site_id,$this->getLIDAttribute());
|
|
|
|
}
|
|
|
|
|
2021-07-13 02:31:56 +00:00
|
|
|
/* RELATIONS */
|
|
|
|
|
2020-02-08 11:51:50 +00:00
|
|
|
/**
|
2024-07-05 12:56:02 +00:00
|
|
|
* This user's accounts
|
2020-02-08 11:51:50 +00:00
|
|
|
*/
|
2018-07-17 04:10:40 +00:00
|
|
|
public function accounts()
|
2020-02-08 11:51:50 +00:00
|
|
|
{
|
2022-04-21 04:41:26 +00:00
|
|
|
return $this->hasMany(Account::class)
|
2023-05-09 10:28:51 +00:00
|
|
|
->active();
|
2020-02-08 11:51:50 +00:00
|
|
|
}
|
2018-05-20 12:53:14 +00:00
|
|
|
|
2020-02-08 11:51:50 +00:00
|
|
|
/**
|
2024-07-05 12:56:02 +00:00
|
|
|
* The accounts that this user manages
|
2020-02-08 11:51:50 +00:00
|
|
|
*
|
2024-07-05 12:56:02 +00:00
|
|
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
|
|
|
* @note This cannot be preloaded with load() or with() - $this is a blank object
|
2020-02-08 11:51:50 +00:00
|
|
|
*/
|
2024-07-05 12:56:02 +00:00
|
|
|
public function accounts_all()
|
2022-04-21 06:25:29 +00:00
|
|
|
{
|
2024-07-05 12:56:02 +00:00
|
|
|
return $this->hasMany(Account::class)
|
|
|
|
->when((! is_null($this->rtm) && $this->id),
|
|
|
|
fn($query)=>$query->orWhereIn('rtm_id',$this->rtm?->children_all()->pluck('id')))
|
2022-04-21 06:25:29 +00:00
|
|
|
->active();
|
2018-07-13 04:53:44 +00:00
|
|
|
}
|
|
|
|
|
2020-02-08 11:51:50 +00:00
|
|
|
/**
|
|
|
|
* This users language configuration
|
|
|
|
*
|
|
|
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
|
|
*/
|
2018-08-01 07:09:38 +00:00
|
|
|
public function language()
|
|
|
|
{
|
2021-06-29 03:18:52 +00:00
|
|
|
return $this->belongsTo(Language::class);
|
2018-08-01 07:09:38 +00:00
|
|
|
}
|
|
|
|
|
2022-04-21 04:41:26 +00:00
|
|
|
/**
|
|
|
|
* Return the routes to market account for this user
|
|
|
|
*/
|
|
|
|
public function rtm()
|
|
|
|
{
|
|
|
|
return $this->hasOneThrough(Rtm::class,Account::class);
|
|
|
|
}
|
|
|
|
|
2022-04-21 06:25:29 +00:00
|
|
|
/* ATTRIBUTES */
|
2018-07-13 04:53:44 +00:00
|
|
|
|
2024-07-07 00:21:27 +00:00
|
|
|
/**
|
|
|
|
* Logged in user's full name
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
* @deprecated use getNameFullAttribute()
|
|
|
|
*/
|
|
|
|
public function getFullNameAttribute(): string
|
|
|
|
{
|
|
|
|
Log::alert('UMO:! Deprecated function getFullNameAttribute()');
|
|
|
|
return $this->getNameFullAttribute();
|
|
|
|
}
|
|
|
|
|
2020-02-08 11:51:50 +00:00
|
|
|
/**
|
2022-04-21 06:25:29 +00:00
|
|
|
* This is an alias method, as it is used by the framework
|
2020-02-08 11:51:50 +00:00
|
|
|
*
|
2022-04-21 06:25:29 +00:00
|
|
|
* @return string
|
2020-02-08 11:51:50 +00:00
|
|
|
*/
|
2022-04-21 06:25:29 +00:00
|
|
|
public function getNameAttribute(): string
|
2018-08-08 23:33:51 +00:00
|
|
|
{
|
2024-07-07 00:21:27 +00:00
|
|
|
return $this->name_full;
|
2018-08-08 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
2018-07-06 06:57:49 +00:00
|
|
|
/**
|
2024-07-05 12:56:02 +00:00
|
|
|
* Logged in user's full name
|
2018-07-06 06:57:49 +00:00
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2024-07-07 00:21:27 +00:00
|
|
|
public function getNameFullAttribute(): string
|
2018-07-06 06:57:49 +00:00
|
|
|
{
|
|
|
|
return sprintf('%s %s',$this->firstname,$this->lastname);
|
|
|
|
}
|
|
|
|
|
2024-07-07 00:21:27 +00:00
|
|
|
/**
|
|
|
|
* Return the name, surname first
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getNameSurFirstAttribute()
|
|
|
|
{
|
|
|
|
return sprintf('%s, %s',$this->lastname,$this->firstname);
|
|
|
|
}
|
|
|
|
|
2022-04-21 04:41:26 +00:00
|
|
|
/**
|
|
|
|
* Return a friendly string of this persons role
|
2024-07-05 12:56:02 +00:00
|
|
|
*
|
2022-04-21 04:41:26 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getRoleAttribute(): string
|
|
|
|
{
|
|
|
|
return ucfirst($this->role());
|
|
|
|
}
|
|
|
|
|
2024-07-07 00:21:27 +00:00
|
|
|
/**
|
|
|
|
* Return the name, surname first
|
|
|
|
* @return string
|
|
|
|
* @deprecated use getNameSurFirstAttribute()
|
|
|
|
*/
|
2018-08-09 14:10:51 +00:00
|
|
|
public function getSurFirstNameAttribute()
|
2018-08-08 23:33:51 +00:00
|
|
|
{
|
2024-07-07 00:21:27 +00:00
|
|
|
Log::alert('UMO:! Deprecated function getSurFirstNameAttribute()');
|
|
|
|
return $this->getNameSurFirstAttribute();
|
2018-08-08 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
2021-07-13 02:31:56 +00:00
|
|
|
/* SCOPES */
|
2018-08-09 14:10:51 +00:00
|
|
|
|
2020-02-06 22:11:02 +00:00
|
|
|
/**
|
|
|
|
* Search for a record
|
|
|
|
*
|
2020-02-08 11:51:50 +00:00
|
|
|
* @param $query
|
2020-02-06 22:11:02 +00:00
|
|
|
* @param string $term
|
|
|
|
*/
|
|
|
|
public function scopeSearch($query,string $term)
|
|
|
|
{
|
|
|
|
// Build our where clause
|
|
|
|
// First Name, Last name
|
2024-07-06 12:56:51 +00:00
|
|
|
if (preg_match('/\s+/',$term)) {
|
2020-04-14 07:40:47 +00:00
|
|
|
[$fn,$ln] = explode(' ',$term,2);
|
2020-02-06 22:11:02 +00:00
|
|
|
|
|
|
|
$query->where(function($query1) use ($fn,$ln,$term) {
|
|
|
|
$query1->where(function($query2) use ($fn,$ln) {
|
|
|
|
return $query2
|
2024-07-06 12:56:51 +00:00
|
|
|
->where('firstname','ilike','%'.$fn.'%')
|
|
|
|
->where('lastname','ilike','%'.$ln.'%');
|
2020-02-06 22:11:02 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
} elseif (is_numeric($term)) {
|
2022-08-07 02:17:20 +00:00
|
|
|
$query->where('users.id','like','%'.$term.'%');
|
2020-02-06 22:11:02 +00:00
|
|
|
|
2024-07-06 12:56:51 +00:00
|
|
|
} elseif (preg_match('/@/',$term)) {
|
|
|
|
$query->where('email','ilike','%'.$term.'%');
|
2020-02-06 22:11:02 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
$query
|
2024-07-06 12:56:51 +00:00
|
|
|
->Where('firstname','ilike','%'.$term.'%')
|
|
|
|
->orWhere('lastname','ilike','%'.$term.'%');
|
2020-02-06 22:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
2022-04-21 04:41:26 +00:00
|
|
|
/* METHODS */
|
2021-07-13 02:31:56 +00:00
|
|
|
|
2022-04-21 06:25:29 +00:00
|
|
|
/**
|
|
|
|
* Determine if the user is an admin of the user with $id
|
|
|
|
*
|
2022-06-28 11:57:55 +00:00
|
|
|
* @param User|null $user
|
2022-04-21 06:25:29 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2022-06-28 11:57:55 +00:00
|
|
|
public function isAdmin(User $user=NULL): bool
|
2022-04-21 06:25:29 +00:00
|
|
|
{
|
2024-07-05 12:56:02 +00:00
|
|
|
return $user->exists
|
|
|
|
&& $this->isReseller()
|
|
|
|
&& $this->accounts_all
|
|
|
|
->pluck('user_id')
|
|
|
|
->contains($user->id);
|
2022-04-21 06:25:29 +00:00
|
|
|
}
|
|
|
|
|
2018-08-09 14:10:51 +00:00
|
|
|
/**
|
|
|
|
* Determine if the logged in user is a reseller or wholesaler
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
2020-02-08 11:51:50 +00:00
|
|
|
public function isReseller(): bool
|
2018-08-09 14:10:51 +00:00
|
|
|
{
|
|
|
|
return in_array($this->role(),['wholesaler','reseller']);
|
|
|
|
}
|
|
|
|
|
2020-02-08 11:51:50 +00:00
|
|
|
/**
|
|
|
|
* Determine if the logged in user is a wholesaler
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function isWholesaler(): bool
|
2018-08-23 05:17:26 +00:00
|
|
|
{
|
|
|
|
return in_array($this->role(),['wholesaler']);
|
|
|
|
}
|
|
|
|
|
2020-02-08 11:51:50 +00:00
|
|
|
/**
|
|
|
|
* Get all the items for the next invoice
|
|
|
|
*
|
2020-04-14 07:40:47 +00:00
|
|
|
* @param bool $future
|
|
|
|
* @return DatabaseCollection
|
2024-07-05 12:56:02 +00:00
|
|
|
* @deprecated This should be done in accounts
|
2020-02-08 11:51:50 +00:00
|
|
|
*/
|
2024-07-05 12:56:02 +00:00
|
|
|
public function next_invoice_items(bool $future=FALSE): Collection
|
2020-02-08 11:51:50 +00:00
|
|
|
{
|
2024-07-05 12:56:02 +00:00
|
|
|
return collect();
|
2020-02-08 11:51:50 +00:00
|
|
|
$result = new DatabaseCollection;
|
2022-06-14 06:51:18 +00:00
|
|
|
$this->services->load(['invoice_items.taxes']);
|
2020-02-08 11:51:50 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-02-12 10:32:57 +00:00
|
|
|
foreach ($o->next_invoice_items($future) as $oo)
|
2020-02-08 11:51:50 +00:00
|
|
|
$result->push($oo);
|
|
|
|
}
|
|
|
|
|
|
|
|
$result->load([
|
2022-10-18 12:23:45 +00:00
|
|
|
'product.translate',
|
2020-02-08 11:51:50 +00:00
|
|
|
'service.type',
|
|
|
|
]);
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2021-07-13 02:31:56 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2018-07-06 06:57:49 +00:00
|
|
|
public function role()
|
|
|
|
{
|
2024-07-05 12:56:02 +00:00
|
|
|
return $this->rtm
|
|
|
|
? ($this->rtm->parent_id ? 'reseller' : 'wholesaler')
|
|
|
|
: 'customer';
|
2018-07-06 06:57:49 +00:00
|
|
|
}
|
2018-06-19 12:31:49 +00:00
|
|
|
}
|