Encryptable::class, 'national_id' => Encryptable::class, 'password' => 'hashed', 'pin_hash' => 'hashed', 'status' => UserStatus::class, 'kyc_level' => 'integer', 'failed_login_count' => 'integer', 'locked_until' => 'datetime', 'last_login_at' => 'datetime', 'phone_verified_at' => 'datetime', 'email_verified_at' => 'datetime', ]; // ── Hide sensitive fields from API/array serialization ── protected $hidden = [ 'id', 'password', 'pin_hash', 'phone_number', // encrypted ciphertext 'national_id', // encrypted ciphertext 'phone_hash', // internal hash 'national_id_hash', // internal hash 'failed_login_count', 'locked_until', 'created_at', 'updated_at', 'deleted_at', ]; protected $visible = [ 'uuid', 'full_name', 'email', 'status', 'kyc_level', 'language', 'country_code', 'phone_verified_at', 'last_login_at', ]; // ── Helper: get masked phone for display (e.g., +963 *** 456) ── public function maskedPhone(): ?string { $phone = $this->phone_number; if (!$phone || strlen($phone) < 6) { return null; } $len = strlen($phone); $maskLen = max(3, $len - 6); return substr($phone, 0, 3) . str_repeat('*', $maskLen) . substr($phone, -3); } // ── Relationships ── public function wallets() { return $this->hasMany(Wallet::class); } public function devices() { return $this->hasMany(UserDevice::class); } public function kycDocuments() { return $this->hasMany(KycDocument::class); } public function transactions() { // Transactions where user is either sender or receiver (via wallets) return Transaction::whereIn('debit_wallet_id', $this->wallets()->select('id')) ->orWhereIn('credit_wallet_id', $this->wallets()->select('id')); } // ── Status helpers ── public function isActive(): bool { return $this->status === UserStatus::ACTIVE; } public function canTransact(): bool { return $this->isActive() && $this->kyc_level > 0; } public function isLocked(): bool { return $this->locked_until && $this->locked_until->isFuture(); } public function isPhoneVerified(): bool { return !is_null($this->phone_verified_at); } // ── Scopes ── public function scopeActive($query) { return $query->where('status', UserStatus::ACTIVE); } public function scopeByPhoneHash($query, string $hash) { return $query->where('phone_hash', $hash); } }