87 lines
3.1 KiB
Python
87 lines
3.1 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from django.db.models import Avg, Count, Max, Q, QuerySet
|
|
|
|
from apps.profiles.models import SearchProfile
|
|
from apps.sources.models import Source
|
|
|
|
from ..models import Application, Employer, JobPosting, ScoreRun
|
|
from .cockpit import annotate_latest_profile_score
|
|
from .relevance import it_relevance_query
|
|
|
|
|
|
def employer_index_queryset(*, user, profile: SearchProfile | None) -> QuerySet[Employer]:
|
|
score_filter = Q(jobs__scores__profile=profile) if profile else Q(pk__isnull=True)
|
|
return Employer.objects.annotate(
|
|
active_vacancies=Count(
|
|
"jobs", filter=Q(jobs__status=JobPosting.Status.ACTIVE), distinct=True
|
|
),
|
|
relevant_vacancies=Count(
|
|
"jobs",
|
|
filter=Q(jobs__status=JobPosting.Status.ACTIVE) & it_relevance_query("jobs__"),
|
|
distinct=True,
|
|
),
|
|
previous_applications=Count(
|
|
"jobs__applications",
|
|
filter=Q(jobs__applications__user=user),
|
|
distinct=True,
|
|
),
|
|
source_count=Count("jobs__source_aliases__source", distinct=True),
|
|
latest_job_at=Max("jobs__first_seen"),
|
|
average_match=Avg("jobs__scores__score", filter=score_filter),
|
|
)
|
|
|
|
|
|
def filter_employers(
|
|
queryset: QuerySet[Employer], *, query: str = "", channel: str = "", active_only: bool = False
|
|
) -> QuerySet[Employer]:
|
|
if query.strip():
|
|
queryset = queryset.filter(
|
|
Q(name__icontains=query.strip())
|
|
| Q(domain__icontains=query.strip())
|
|
| Q(jobs__raw_location__icontains=query.strip())
|
|
)
|
|
if channel == "direct":
|
|
queryset = queryset.filter(is_direct_employer=True, is_recruiter=False)
|
|
elif channel == "recruiter":
|
|
queryset = queryset.filter(is_recruiter=True)
|
|
if active_only:
|
|
queryset = queryset.filter(active_vacancies__gt=0)
|
|
return queryset.order_by("-relevant_vacancies", "-active_vacancies", "name").distinct()
|
|
|
|
|
|
def build_employer_detail(
|
|
*, employer: Employer, user, profile: SearchProfile | None
|
|
) -> dict[str, Any]:
|
|
jobs = annotate_latest_profile_score(
|
|
employer.jobs.select_related("employer").all(), profile
|
|
).order_by("-first_seen")
|
|
sources = Source.objects.filter(job_aliases__job__employer=employer).distinct().order_by("name")
|
|
locations = list(
|
|
employer.jobs.exclude(raw_location="")
|
|
.order_by("raw_location")
|
|
.values_list("raw_location", flat=True)
|
|
.distinct()[:8]
|
|
)
|
|
return {
|
|
"employer": employer,
|
|
"recent_jobs": list(jobs[:12]),
|
|
"active_jobs": list(jobs.filter(status=JobPosting.Status.ACTIVE)[:8]),
|
|
"applications": list(
|
|
Application.objects.filter(user=user, job__employer=employer)
|
|
.select_related("job")
|
|
.order_by("-updated_at")[:8]
|
|
),
|
|
"sources": list(sources[:10]),
|
|
"locations": locations,
|
|
"match_history": list(
|
|
ScoreRun.objects.filter(profile=profile, job__employer=employer)
|
|
.select_related("job")
|
|
.order_by("-created_at")[:20]
|
|
)
|
|
if profile
|
|
else [],
|
|
}
|