Initial Ladill Frontdesk release with deploy pipeline.
Visitor management app with SSO, kiosk, badges, reports, and Gitea CI deploy to frontdesk.ladill.com. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class AuditLog extends Model
|
||||
{
|
||||
use BelongsToOwner;
|
||||
|
||||
protected $table = 'frontdesk_audit_logs';
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'owner_ref', 'organization_id', 'actor_ref', 'action',
|
||||
'subject_type', 'subject_id', 'metadata', 'ip_address', 'created_at',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'metadata' => 'array',
|
||||
'created_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
public static function record(
|
||||
string $ownerRef,
|
||||
string $action,
|
||||
?int $organizationId = null,
|
||||
?string $actorRef = null,
|
||||
?string $subjectType = null,
|
||||
?int $subjectId = null,
|
||||
?array $metadata = null,
|
||||
): self {
|
||||
return static::create([
|
||||
'owner_ref' => $ownerRef,
|
||||
'organization_id' => $organizationId,
|
||||
'actor_ref' => $actorRef,
|
||||
'action' => $action,
|
||||
'subject_type' => $subjectType,
|
||||
'subject_id' => $subjectId,
|
||||
'metadata' => $metadata,
|
||||
'ip_address' => request()?->ip(),
|
||||
'created_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Branch extends Model
|
||||
{
|
||||
use BelongsToOwner, SoftDeletes;
|
||||
|
||||
protected $table = 'frontdesk_branches';
|
||||
|
||||
protected $fillable = [
|
||||
'owner_ref', 'organization_id', 'name', 'code', 'address', 'phone', 'is_active',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return ['is_active' => 'boolean'];
|
||||
}
|
||||
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function buildings(): HasMany
|
||||
{
|
||||
return $this->hasMany(Building::class, 'branch_id');
|
||||
}
|
||||
|
||||
public function hosts(): HasMany
|
||||
{
|
||||
return $this->hasMany(Host::class, 'branch_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Building extends Model
|
||||
{
|
||||
use BelongsToOwner, SoftDeletes;
|
||||
|
||||
protected $table = 'frontdesk_buildings';
|
||||
|
||||
protected $fillable = ['owner_ref', 'branch_id', 'name', 'floor_count'];
|
||||
|
||||
public function branch(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Branch::class, 'branch_id');
|
||||
}
|
||||
|
||||
public function receptionDesks(): HasMany
|
||||
{
|
||||
return $this->hasMany(ReceptionDesk::class, 'building_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Concerns;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
trait BelongsToOwner
|
||||
{
|
||||
public function scopeOwned(Builder $query, string $ownerRef): Builder
|
||||
{
|
||||
return $query->where($this->getTable().'.owner_ref', $ownerRef);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Device extends Model
|
||||
{
|
||||
use BelongsToOwner, SoftDeletes;
|
||||
|
||||
protected $table = 'frontdesk_devices';
|
||||
|
||||
protected $fillable = [
|
||||
'owner_ref', 'organization_id', 'branch_id', 'reception_desk_id',
|
||||
'name', 'type', 'status', 'device_token', 'config', 'last_online_at',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'config' => 'array',
|
||||
'last_online_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function branch(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Branch::class, 'branch_id');
|
||||
}
|
||||
|
||||
public function receptionDesk(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ReceptionDesk::class, 'reception_desk_id');
|
||||
}
|
||||
|
||||
public function isOnline(int $staleMinutes = 10): bool
|
||||
{
|
||||
return $this->status === 'online'
|
||||
&& $this->last_online_at
|
||||
&& $this->last_online_at->gte(now()->subMinutes($staleMinutes));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Host extends Model
|
||||
{
|
||||
use BelongsToOwner, SoftDeletes;
|
||||
|
||||
protected $table = 'frontdesk_hosts';
|
||||
|
||||
protected $fillable = [
|
||||
'owner_ref', 'organization_id', 'branch_id', 'name', 'department',
|
||||
'office', 'phone', 'email', 'extension', 'is_available', 'user_ref',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return ['is_available' => 'boolean'];
|
||||
}
|
||||
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function branch(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Branch::class, 'branch_id');
|
||||
}
|
||||
|
||||
public function visits(): HasMany
|
||||
{
|
||||
return $this->hasMany(Visit::class, 'host_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Member extends Model
|
||||
{
|
||||
use BelongsToOwner;
|
||||
|
||||
protected $table = 'frontdesk_members';
|
||||
|
||||
protected $fillable = ['owner_ref', 'organization_id', 'user_ref', 'role', 'branch_id'];
|
||||
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function branch(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Branch::class, 'branch_id');
|
||||
}
|
||||
|
||||
public function hasRole(string ...$roles): bool
|
||||
{
|
||||
return in_array($this->role, $roles, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class OfflineCheckIn extends Model
|
||||
{
|
||||
protected $table = 'frontdesk_offline_checkins';
|
||||
|
||||
protected $fillable = ['device_id', 'client_id', 'payload', 'synced_at', 'visit_id'];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'payload' => 'array',
|
||||
'synced_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
public function device(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Device::class, 'device_id');
|
||||
}
|
||||
|
||||
public function visit(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Visit::class, 'visit_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Organization extends Model
|
||||
{
|
||||
use BelongsToOwner, SoftDeletes;
|
||||
|
||||
protected $table = 'frontdesk_organizations';
|
||||
|
||||
protected $fillable = [
|
||||
'owner_ref', 'name', 'slug', 'logo_path', 'timezone', 'settings',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return ['settings' => 'array'];
|
||||
}
|
||||
|
||||
public function branches(): HasMany
|
||||
{
|
||||
return $this->hasMany(Branch::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function hosts(): HasMany
|
||||
{
|
||||
return $this->hasMany(Host::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function visitors(): HasMany
|
||||
{
|
||||
return $this->hasMany(Visitor::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function members(): HasMany
|
||||
{
|
||||
return $this->hasMany(Member::class, 'organization_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class ReceptionDesk extends Model
|
||||
{
|
||||
use BelongsToOwner, SoftDeletes;
|
||||
|
||||
protected $table = 'frontdesk_reception_desks';
|
||||
|
||||
protected $fillable = ['owner_ref', 'building_id', 'name', 'location', 'is_active'];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return ['is_active' => 'boolean'];
|
||||
}
|
||||
|
||||
public function building(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Building::class, 'building_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
|
||||
/**
|
||||
* Thin local mirror of the platform identity (auth.ladill.com owns users).
|
||||
* Keyed by the OIDC `sub` (public_id); every CRM record is scoped to it.
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens, Notifiable;
|
||||
|
||||
protected $fillable = ['public_id', 'name', 'email', 'avatar_url', 'password', 'last_app_active_at'];
|
||||
|
||||
protected $hidden = ['password', 'remember_token'];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'last_app_active_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
|
||||
/** The owner reference used to scope every CRM record to this account. */
|
||||
public function ownerRef(): string
|
||||
{
|
||||
return (string) $this->public_id;
|
||||
}
|
||||
|
||||
public function customers(): HasMany
|
||||
{
|
||||
return $this->hasMany(Customer::class, 'owner_ref', 'public_id');
|
||||
}
|
||||
|
||||
public function leads(): HasMany
|
||||
{
|
||||
return $this->hasMany(Lead::class, 'owner_ref', 'public_id');
|
||||
}
|
||||
|
||||
public function avatarUrl(): ?string
|
||||
{
|
||||
$url = trim((string) $this->avatar_url);
|
||||
|
||||
return $url !== '' ? $url : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Visit extends Model
|
||||
{
|
||||
use BelongsToOwner, SoftDeletes;
|
||||
|
||||
protected $table = 'frontdesk_visits';
|
||||
|
||||
public const STATUS_SCHEDULED = 'scheduled';
|
||||
|
||||
public const STATUS_EXPECTED = 'expected';
|
||||
|
||||
public const STATUS_WAITING = 'waiting';
|
||||
|
||||
public const STATUS_CHECKED_IN = 'checked_in';
|
||||
|
||||
public const STATUS_CHECKED_OUT = 'checked_out';
|
||||
|
||||
public const STATUS_CANCELLED = 'cancelled';
|
||||
|
||||
public const STATUS_OVERDUE = 'overdue';
|
||||
|
||||
public const ACTIVE_STATUSES = [
|
||||
self::STATUS_EXPECTED,
|
||||
self::STATUS_WAITING,
|
||||
self::STATUS_CHECKED_IN,
|
||||
self::STATUS_OVERDUE,
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'public_id', 'external_ref', 'source', 'owner_ref', 'organization_id', 'branch_id', 'reception_desk_id',
|
||||
'visitor_id', 'host_id', 'visitor_type', 'status', 'purpose',
|
||||
'expected_duration_minutes', 'scheduled_at', 'checked_in_at', 'checked_out_at',
|
||||
'badge_expires_at', 'badge_code', 'qr_token', 'photo_path', 'signature_path',
|
||||
'policies_accepted', 'vehicle_info', 'contractor_details', 'delivery_details',
|
||||
'allowed_areas', 'notes', 'integration_metadata', 'checked_in_by', 'checked_out_by',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'scheduled_at' => 'datetime',
|
||||
'checked_in_at' => 'datetime',
|
||||
'checked_out_at' => 'datetime',
|
||||
'badge_expires_at' => 'datetime',
|
||||
'policies_accepted' => 'boolean',
|
||||
'vehicle_info' => 'array',
|
||||
'contractor_details' => 'array',
|
||||
'delivery_details' => 'array',
|
||||
'allowed_areas' => 'array',
|
||||
'integration_metadata' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::creating(function (Visit $visit) {
|
||||
if (! $visit->public_id) {
|
||||
$visit->public_id = (string) Str::uuid();
|
||||
}
|
||||
if (! $visit->qr_token) {
|
||||
$visit->qr_token = Str::random(32);
|
||||
}
|
||||
if (! $visit->badge_code) {
|
||||
$visit->badge_code = strtoupper(Str::random(8));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function branch(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Branch::class, 'branch_id');
|
||||
}
|
||||
|
||||
public function receptionDesk(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ReceptionDesk::class, 'reception_desk_id');
|
||||
}
|
||||
|
||||
public function visitor(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Visitor::class, 'visitor_id');
|
||||
}
|
||||
|
||||
public function host(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Host::class, 'host_id');
|
||||
}
|
||||
|
||||
public function isInside(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_CHECKED_IN;
|
||||
}
|
||||
|
||||
public function isPending(): bool
|
||||
{
|
||||
return in_array($this->status, [
|
||||
self::STATUS_EXPECTED,
|
||||
self::STATUS_SCHEDULED,
|
||||
self::STATUS_WAITING,
|
||||
self::STATUS_OVERDUE,
|
||||
], true);
|
||||
}
|
||||
|
||||
public function awaitingApproval(): bool
|
||||
{
|
||||
if ($this->status !== self::STATUS_WAITING || $this->checked_in_at !== null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) (
|
||||
data_get($this->contractor_details, '_awaiting_approval')
|
||||
|| data_get($this->delivery_details, '_awaiting_approval')
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<string, string|null> */
|
||||
public function typeDetailEntries(): array
|
||||
{
|
||||
$entries = [];
|
||||
$labels = collect(config('frontdesk.visitor_type_config', []))
|
||||
->flatMap(fn (array $config) => collect($config['fields'] ?? [])
|
||||
->mapWithKeys(fn (array $field) => [$field['name'] => $field['label']]));
|
||||
|
||||
foreach (array_filter([$this->contractor_details, $this->delivery_details]) as $details) {
|
||||
foreach ($details as $key => $value) {
|
||||
if (str_starts_with((string) $key, '_') || $value === null || $value === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$label = $labels->get($key, str_replace('_', ' ', (string) $key));
|
||||
|
||||
if (str_contains((string) $key, 'photo') || str_contains((string) $key, 'signature')) {
|
||||
$entries[$label] = 'On file';
|
||||
} elseif ($key === 'received_at') {
|
||||
$entries[$label] = \Illuminate\Support\Carbon::parse($value)->format('M j, Y g:i A');
|
||||
} else {
|
||||
$entries[$label] = is_bool($value) ? ($value ? 'Yes' : 'No') : (string) $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
public function canActivateCheckIn(): bool
|
||||
{
|
||||
return $this->isPending();
|
||||
}
|
||||
|
||||
public function isBadgeExpired(): bool
|
||||
{
|
||||
return $this->badge_expires_at && $this->badge_expires_at->isPast();
|
||||
}
|
||||
|
||||
public function scopeToday($query)
|
||||
{
|
||||
return $query->whereDate('checked_in_at', today())
|
||||
->orWhereDate('scheduled_at', today());
|
||||
}
|
||||
|
||||
public function scopeCurrentlyInside($query)
|
||||
{
|
||||
return $query->where('status', self::STATUS_CHECKED_IN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Visitor extends Model
|
||||
{
|
||||
use BelongsToOwner, SoftDeletes;
|
||||
|
||||
protected $table = 'frontdesk_visitors';
|
||||
|
||||
public const WATCHLIST_ALLOWED = 'allowed';
|
||||
|
||||
public const WATCHLIST_REQUIRES_APPROVAL = 'requires_approval';
|
||||
|
||||
public const WATCHLIST_BLACKLISTED = 'blacklisted';
|
||||
|
||||
protected $fillable = [
|
||||
'owner_ref', 'organization_id', 'full_name', 'company', 'phone', 'email',
|
||||
'photo_path', 'id_document_path', 'watchlist_status', 'notes',
|
||||
'visit_count', 'is_frequent',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return ['is_frequent' => 'boolean'];
|
||||
}
|
||||
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function visits(): HasMany
|
||||
{
|
||||
return $this->hasMany(Visit::class, 'visitor_id');
|
||||
}
|
||||
|
||||
public function isBlacklisted(): bool
|
||||
{
|
||||
return $this->watchlist_status === self::WATCHLIST_BLACKLISTED;
|
||||
}
|
||||
|
||||
public function requiresApproval(): bool
|
||||
{
|
||||
return $this->watchlist_status === self::WATCHLIST_REQUIRES_APPROVAL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class WatchlistEntry extends Model
|
||||
{
|
||||
use BelongsToOwner, SoftDeletes;
|
||||
|
||||
protected $table = 'frontdesk_watchlist_entries';
|
||||
|
||||
protected $fillable = [
|
||||
'owner_ref', 'organization_id', 'visitor_id', 'full_name',
|
||||
'company', 'status', 'reason', 'created_by',
|
||||
];
|
||||
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function visitor(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Visitor::class, 'visitor_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\BelongsToOwner;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class WebhookEndpoint extends Model
|
||||
{
|
||||
use BelongsToOwner;
|
||||
|
||||
protected $table = 'frontdesk_webhook_endpoints';
|
||||
|
||||
protected $fillable = [
|
||||
'owner_ref', 'organization_id', 'url', 'secret', 'events', 'is_active',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'events' => 'array',
|
||||
'is_active' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
public function subscribesTo(string $event): bool
|
||||
{
|
||||
$events = $this->events ?? config('frontdesk.webhook_events', []);
|
||||
|
||||
return in_array($event, $events, true) || in_array('*', $events, true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user