'boolean', ]; } public function attendance(): HasOne { return $this->hasOne(AttendanceRecord::class); } public function drawResults(): HasMany { return $this->hasMany(DrawResult::class); } public function hasAttended(): bool { return $this->attendance()->exists(); } /** Adakah anggota ini sudah menang & disahkan? */ public function hasConfirmedWin(): bool { return $this->drawResults()->where('status', DrawResult::STATUS_CONFIRMED)->exists(); } /** No KP bertopeng untuk paparan biasa: 850101-01-**** */ public function maskedKp(): ?string { if (! $this->no_kp) { return null; } $kp = $this->no_kp; // Format standard 12 digit (boleh ada sempang) $digits = preg_replace('/\D/', '', $kp); if (strlen($digits) === 12) { return substr($digits, 0, 6) . '-' . substr($digits, 6, 2) . '-****'; } // Fallback: tunjukkan 4 aksara pertama, topeng selebihnya $visible = substr($kp, 0, max(strlen($kp) - 4, 0)); return $visible . str_repeat('*', min(4, strlen($kp))); } public function scopeAktif(Builder $query): Builder { return $query->where('status_aktif', true); } public function scopeHadir(Builder $query): Builder { return $query->whereHas('attendance'); } public function scopeBelumHadir(Builder $query): Builder { return $query->whereDoesntHave('attendance'); } public function scopeSearch(Builder $query, ?string $term): Builder { $term = trim((string) $term); if ($term === '') { return $query; } $like = '%' . $term . '%'; $digits = preg_replace('/\D/', '', $term); return $query->where(function (Builder $q) use ($like, $term, $digits) { $q->where('nama', 'like', $like) ->orWhere('no_pekerja', 'like', $like) ->orWhere('no_anggota', 'like', $like) ->orWhere('no_kp', 'like', $like); if ($digits !== '') { $q->orWhere('no_kp', 'like', '%' . $digits . '%') ->orWhere('no_pekerja', 'like', '%' . $digits . '%'); } }); } }