Files
VacatureRadar/apps/jobs/services/employer_intelligence.py
T

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 [],
}