family $this->name $this->ot"; } public function archiveHistory() { return $this->morphMany(ArchiveHistory::class, 'historyable'); } public function archiveInfo() { return $this->morphOne(ArchiveInfo::class, 'historyable'); } /** * Проверяет, можно ли выдать эту карту */ public function canBeIssued(): bool { // Проверяем, есть ли открытые выдачи $hasOpenIssue = $this->archiveHistory() ->whereNotNull('issue_at') ->whereNull('return_at') ->where('has_lost', false) ->exists(); return !$hasOpenIssue; } /** * Получает текущую открытую выдачу (если есть) */ public function getCurrentIssue(): ?ArchiveHistory { return $this->archiveHistory() ->whereNotNull('issue_at') ->whereNull('return_at') ->where('has_lost', false) ->latest('issue_at') ->first(); } public function scopeSearch($query, $searchText) { return $query->where(function($q) use ($searchText) { if (is_numeric($searchText)) { $q->where('medcardnum', 'ILIKE', "$searchText"); } else { // Ищем в объединенном ФИО и в отдельных полях $searchPattern = "%{$searchText}%"; $q->where(function($subQ) use ($searchPattern) { // Поиск в объединенной строке $subQ->whereRaw("CONCAT(family, ' ', name, ' ', COALESCE(ot, '')) ILIKE ?", [$searchPattern]) // И дополнительно в отдельных полях для точности ->orWhere('family', 'ILIKE', $searchPattern) ->orWhere('name', 'ILIKE', $searchPattern) ->orWhere('ot', 'ILIKE', $searchPattern); }); } }); } }