completed story 1.1 with QA tests and fixes
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class AdminLog extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'admin_id',
|
||||
'action',
|
||||
'target_type',
|
||||
'target_id',
|
||||
'old_values',
|
||||
'new_values',
|
||||
'ip_address',
|
||||
'created_at',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'old_values' => 'array',
|
||||
'new_values' => 'array',
|
||||
'created_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the admin that created the log.
|
||||
*/
|
||||
public function admin(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'admin_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class BlockedTime extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'block_date',
|
||||
'start_time',
|
||||
'end_time',
|
||||
'reason',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'block_date' => 'date',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a full day block.
|
||||
*/
|
||||
public function isFullDay(): bool
|
||||
{
|
||||
return is_null($this->start_time) && is_null($this->end_time);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\ConsultationStatus;
|
||||
use App\Enums\ConsultationType;
|
||||
use App\Enums\PaymentStatus;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Consultation extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'booking_date',
|
||||
'booking_time',
|
||||
'problem_summary',
|
||||
'consultation_type',
|
||||
'payment_amount',
|
||||
'payment_status',
|
||||
'status',
|
||||
'admin_notes',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'booking_date' => 'date',
|
||||
'consultation_type' => ConsultationType::class,
|
||||
'payment_status' => PaymentStatus::class,
|
||||
'status' => ConsultationStatus::class,
|
||||
'payment_amount' => 'decimal:2',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that owns the consultation.
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Notification extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'type',
|
||||
'data',
|
||||
'read_at',
|
||||
'sent_at',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'data' => 'array',
|
||||
'read_at' => 'datetime',
|
||||
'sent_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that owns the notification.
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the notification as read.
|
||||
*/
|
||||
public function markAsRead(): void
|
||||
{
|
||||
$this->update(['read_at' => now()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter unread notifications.
|
||||
*/
|
||||
public function scopeUnread($query)
|
||||
{
|
||||
return $query->whereNull('read_at');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\PostStatus;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Post extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'body',
|
||||
'status',
|
||||
'published_at',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'title' => 'array',
|
||||
'body' => 'array',
|
||||
'status' => PostStatus::class,
|
||||
'published_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter published posts.
|
||||
*/
|
||||
public function scopePublished($query)
|
||||
{
|
||||
return $query->where('status', PostStatus::Published);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter draft posts.
|
||||
*/
|
||||
public function scopeDraft($query)
|
||||
{
|
||||
return $query->where('status', PostStatus::Draft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the title in the specified locale, with fallback to Arabic.
|
||||
*/
|
||||
public function getTitle(?string $locale = null): string
|
||||
{
|
||||
$locale ??= app()->getLocale();
|
||||
|
||||
return $this->title[$locale] ?? $this->title['ar'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the body in the specified locale, with fallback to Arabic.
|
||||
*/
|
||||
public function getBody(?string $locale = null): string
|
||||
{
|
||||
$locale ??= app()->getLocale();
|
||||
|
||||
return $this->body[$locale] ?? $this->body['ar'] ?? '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\TimelineStatus;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Timeline extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'case_name',
|
||||
'case_reference',
|
||||
'status',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'status' => TimelineStatus::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that owns the timeline.
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the updates for the timeline.
|
||||
*/
|
||||
public function updates(): HasMany
|
||||
{
|
||||
return $this->hasMany(TimelineUpdate::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class TimelineUpdate extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'timeline_id',
|
||||
'admin_id',
|
||||
'update_text',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the timeline that owns the update.
|
||||
*/
|
||||
public function timeline(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Timeline::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the admin that created the update.
|
||||
*/
|
||||
public function admin(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'admin_id');
|
||||
}
|
||||
}
|
||||
+115
-4
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use App\Enums\UserStatus;
|
||||
use App\Enums\UserType;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -20,9 +22,18 @@ class User extends Authenticatable
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'user_type',
|
||||
'full_name',
|
||||
'national_id',
|
||||
'company_name',
|
||||
'company_cert_number',
|
||||
'contact_person_name',
|
||||
'contact_person_id',
|
||||
'email',
|
||||
'phone',
|
||||
'password',
|
||||
'status',
|
||||
'preferred_language',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -32,6 +43,7 @@ class User extends Authenticatable
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'national_id',
|
||||
'two_factor_secret',
|
||||
'two_factor_recovery_codes',
|
||||
'remember_token',
|
||||
@@ -45,20 +57,119 @@ class User extends Authenticatable
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'user_type' => UserType::class,
|
||||
'status' => UserStatus::class,
|
||||
'email_verified_at' => 'datetime',
|
||||
'two_factor_confirmed_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user's initials
|
||||
* Get the user's initials.
|
||||
*/
|
||||
public function initials(): string
|
||||
{
|
||||
return Str::of($this->name)
|
||||
return Str::of($this->full_name)
|
||||
->explode(' ')
|
||||
->take(2)
|
||||
->map(fn ($word) => Str::substr($word, 0, 1))
|
||||
->implode('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is an admin.
|
||||
*/
|
||||
public function isAdmin(): bool
|
||||
{
|
||||
return $this->user_type === UserType::Admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is an individual client.
|
||||
*/
|
||||
public function isIndividual(): bool
|
||||
{
|
||||
return $this->user_type === UserType::Individual;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is a company client.
|
||||
*/
|
||||
public function isCompany(): bool
|
||||
{
|
||||
return $this->user_type === UserType::Company;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is a client (individual or company).
|
||||
*/
|
||||
public function isClient(): bool
|
||||
{
|
||||
return $this->isIndividual() || $this->isCompany();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter admin users.
|
||||
*/
|
||||
public function scopeAdmins($query)
|
||||
{
|
||||
return $query->where('user_type', UserType::Admin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter client users (individual or company).
|
||||
*/
|
||||
public function scopeClients($query)
|
||||
{
|
||||
return $query->whereIn('user_type', [UserType::Individual, UserType::Company]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter active users.
|
||||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('status', UserStatus::Active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the consultations for the user.
|
||||
*/
|
||||
public function consultations(): HasMany
|
||||
{
|
||||
return $this->hasMany(Consultation::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timelines for the user.
|
||||
*/
|
||||
public function timelines(): HasMany
|
||||
{
|
||||
return $this->hasMany(Timeline::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notifications for the user.
|
||||
*/
|
||||
public function customNotifications(): HasMany
|
||||
{
|
||||
return $this->hasMany(Notification::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the admin logs for the user.
|
||||
*/
|
||||
public function adminLogs(): HasMany
|
||||
{
|
||||
return $this->hasMany(AdminLog::class, 'admin_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timeline updates created by this admin.
|
||||
*/
|
||||
public function timelineUpdates(): HasMany
|
||||
{
|
||||
return $this->hasMany(TimelineUpdate::class, 'admin_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class WorkingHour extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'day_of_week',
|
||||
'start_time',
|
||||
'end_time',
|
||||
'is_active',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'day_of_week' => 'integer',
|
||||
'is_active' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter active working hours.
|
||||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('is_active', true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user