Refresh
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
"""Vult een fictieve demo-omgeving voor het demo-account.
|
||||
|
||||
Wordt aangeroepen bij 'Bekijk demo' zodat de gebruiker meteen een geloofwaardige,
|
||||
gevulde cockpit ziet (profiel, vacatures, matchscores en een sollicitatiepijplijn)
|
||||
in plaats van een leeg dashboard. Volledig idempotent: eenmaal geseed, wordt er
|
||||
niet opnieuw geseed.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.profiles.models import SearchProfile
|
||||
|
||||
_DEMO_PROFILE_NAME = "Demo · IT-infrastructuur Limburg"
|
||||
|
||||
# (titel, werkgever, domein, gemeente, regio, werkplek, skills_required,
|
||||
# skills_preferred, score, recommendation, positives, concerns)
|
||||
_DEMO_JOBS = [
|
||||
(
|
||||
"Infrastructure Engineer",
|
||||
"CloudNexus",
|
||||
"cloudnexus.example",
|
||||
"Hasselt",
|
||||
"Limburg",
|
||||
"hybrid",
|
||||
["Microsoft 365", "VMware", "Azure"],
|
||||
["Terraform"],
|
||||
Decimal("92.4"),
|
||||
"strong",
|
||||
["Dichtbij Hasselt", "Sterke match op Microsoft 365 en VMware", "Hybride werk"],
|
||||
[],
|
||||
),
|
||||
(
|
||||
"Cloud Architect",
|
||||
"Skylink Solutions",
|
||||
"skylink.example",
|
||||
"Remote",
|
||||
"Vlaanderen",
|
||||
"remote",
|
||||
["Azure", "Kubernetes"],
|
||||
["Bicep", "Landing Zones"],
|
||||
Decimal("88.1"),
|
||||
"strong",
|
||||
["Volledig remote", "Azure-zwaartepunt sluit aan"],
|
||||
["Iets seniorder dan gevraagd"],
|
||||
),
|
||||
(
|
||||
"Systeembeheerder Microsoft 365",
|
||||
"Gemeente Genk",
|
||||
"genk.example",
|
||||
"Genk",
|
||||
"Limburg",
|
||||
"on_site",
|
||||
["Microsoft 365", "Active Directory"],
|
||||
["Intune"],
|
||||
Decimal("83.6"),
|
||||
"strong",
|
||||
["Publieke sector met stabiliteit", "M365-focus"],
|
||||
["Volledig op locatie"],
|
||||
),
|
||||
(
|
||||
"DevOps Engineer",
|
||||
"Datastroom BV",
|
||||
"datastroom.example",
|
||||
"Leuven",
|
||||
"Vlaams-Brabant",
|
||||
"hybrid",
|
||||
["CI/CD", "Docker", "Azure"],
|
||||
["GitLab", "Observability"],
|
||||
Decimal("77.9"),
|
||||
"possible",
|
||||
["Moderne toolchain", "Hybride"],
|
||||
["Reistijd naar Leuven"],
|
||||
),
|
||||
(
|
||||
"Network Engineer",
|
||||
"Noorder Telecom",
|
||||
"noordertelecom.example",
|
||||
"Antwerpen",
|
||||
"Antwerpen",
|
||||
"on_site",
|
||||
["Cisco", "Netwerkbeheer"],
|
||||
["Fortinet"],
|
||||
Decimal("70.4"),
|
||||
"possible",
|
||||
["Stevige netwerkrol"],
|
||||
["Weinig cloudcomponent", "Op locatie in Antwerpen"],
|
||||
),
|
||||
(
|
||||
"IT Support Specialist",
|
||||
"MediCare Groep",
|
||||
"medicare.example",
|
||||
"Diepenbeek",
|
||||
"Limburg",
|
||||
"on_site",
|
||||
["Servicedesk", "Windows"],
|
||||
["ITIL"],
|
||||
Decimal("62.3"),
|
||||
"weak",
|
||||
["Dichtbij"],
|
||||
["Sterk supportgericht", "Weinig infrastructuurverdieping"],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _digest(*parts: str) -> str:
|
||||
return hashlib.sha256("::".join(parts).encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
def demo_environment_seeded(user) -> bool:
|
||||
profile = SearchProfile.objects.filter(user=user, name=_DEMO_PROFILE_NAME).first()
|
||||
if profile is None:
|
||||
return False
|
||||
from apps.jobs.models import ScoreRun
|
||||
|
||||
return ScoreRun.objects.filter(profile=profile).exists()
|
||||
|
||||
|
||||
def seed_demo_environment(user) -> None:
|
||||
"""Maak (idempotent) een fictieve demo-omgeving voor ``user``."""
|
||||
if demo_environment_seeded(user):
|
||||
return
|
||||
|
||||
from apps.jobs.models import Application, Employer, JobPosting, ScoreRun
|
||||
|
||||
profile, _ = SearchProfile.objects.get_or_create(
|
||||
user=user,
|
||||
name=_DEMO_PROFILE_NAME,
|
||||
defaults={
|
||||
"is_active": True,
|
||||
"home_municipality": "Hasselt",
|
||||
"home_latitude": Decimal("50.930700"),
|
||||
"home_longitude": Decimal("5.332500"),
|
||||
"max_distance_km": 60,
|
||||
"experience_years": 5,
|
||||
"learning_enabled": True,
|
||||
"desired_titles": ["infrastructure engineer", "systeembeheerder", "cloud engineer"],
|
||||
"excluded_titles": ["sales", "recruiter"],
|
||||
"desired_skills": ["Microsoft 365", "VMware", "Azure"],
|
||||
"allowed_employment_types": ["full_time", "permanent"],
|
||||
"preferred_workplace": ["hybrid", "remote", "on_site"],
|
||||
"preferred_regions": ["Limburg", "Vlaams-Brabant"],
|
||||
},
|
||||
)
|
||||
SearchProfile.objects.filter(user=user).exclude(pk=profile.pk).update(is_active=False)
|
||||
if not profile.is_active:
|
||||
profile.is_active = True
|
||||
profile.save(update_fields=["is_active"])
|
||||
|
||||
now = timezone.now()
|
||||
workplace_map = {
|
||||
"hybrid": JobPosting.Workplace.HYBRID,
|
||||
"remote": JobPosting.Workplace.REMOTE,
|
||||
"on_site": JobPosting.Workplace.ON_SITE,
|
||||
}
|
||||
created_jobs: list = []
|
||||
|
||||
for index, (
|
||||
title,
|
||||
employer_name,
|
||||
domain,
|
||||
municipality,
|
||||
region,
|
||||
workplace,
|
||||
req_skills,
|
||||
pref_skills,
|
||||
score,
|
||||
recommendation,
|
||||
positives,
|
||||
concerns,
|
||||
) in enumerate(_DEMO_JOBS):
|
||||
employer, _ = Employer.objects.get_or_create(
|
||||
normalized_name=employer_name.lower(),
|
||||
defaults={
|
||||
"name": employer_name,
|
||||
"domain": domain,
|
||||
"is_direct_employer": True,
|
||||
"is_recruiter": False,
|
||||
"confidence": 0.92,
|
||||
},
|
||||
)
|
||||
slug = _digest("demo-job", str(index), title, employer_name)
|
||||
job, job_created = JobPosting.objects.get_or_create(
|
||||
canonical_key=slug,
|
||||
defaults={
|
||||
"employer": employer,
|
||||
"original_title": title,
|
||||
"normalized_title": title.lower(),
|
||||
"job_family": "infrastructure",
|
||||
"canonical_url": f"https://{domain}/vacatures/{slug[:12]}",
|
||||
"content_hash": _digest("demo-content", slug),
|
||||
"description_text": (
|
||||
f"{title} bij {employer_name} in {municipality}. "
|
||||
"Fictieve demovacature voor de VacatureRadar-demo-omgeving."
|
||||
),
|
||||
"raw_location": f"{municipality}, {region}",
|
||||
"region": region,
|
||||
"municipality": municipality,
|
||||
"workplace_type": workplace_map[workplace],
|
||||
"employment_types": ["full_time", "permanent"],
|
||||
"skills_required": req_skills,
|
||||
"skills_preferred": pref_skills,
|
||||
"direct_employer": True,
|
||||
"recruiter": False,
|
||||
"extraction_confidence": 0.9,
|
||||
"analysis_features": {
|
||||
"support_ratio": 0.1,
|
||||
"public_sector_signal": 1.0 if "Gemeente" in employer_name else 0.0,
|
||||
"experience_years_max": 6,
|
||||
},
|
||||
"status": JobPosting.Status.ACTIVE,
|
||||
"first_seen": now - timedelta(days=index + 1),
|
||||
"last_seen": now,
|
||||
"date_posted": now - timedelta(days=index + 1),
|
||||
},
|
||||
)
|
||||
created_jobs.append(job)
|
||||
|
||||
ScoreRun.objects.create(
|
||||
job=job,
|
||||
profile=profile,
|
||||
profile_version=profile.version,
|
||||
score=score,
|
||||
confidence=Decimal("0.78"),
|
||||
recommendation=recommendation,
|
||||
components={
|
||||
"content": float(score) * 0.45,
|
||||
"skills": float(score) * 0.30,
|
||||
"location": float(score) * 0.25,
|
||||
},
|
||||
positives=positives,
|
||||
concerns=concerns,
|
||||
hard_exclusions=[],
|
||||
evidence={"demo": True},
|
||||
model_version="demo-seed",
|
||||
prompt_version="1.0.0",
|
||||
created_at=now - timedelta(hours=index),
|
||||
)
|
||||
|
||||
# Een kleine sollicitatiepijplijn voor de demo.
|
||||
if created_jobs:
|
||||
Application.objects.get_or_create(
|
||||
user=user,
|
||||
job=created_jobs[0],
|
||||
defaults={
|
||||
"status": Application.Status.INTERVIEW,
|
||||
"applied_at": now - timedelta(days=6),
|
||||
"follow_up_date": (now + timedelta(days=2)).date(),
|
||||
"contact_name": "Sofie Vandael",
|
||||
"contact_email": "sofie.vandael@cloudnexus.example",
|
||||
"notes": "Eerste gesprek gepland. Demo-data.",
|
||||
},
|
||||
)
|
||||
if len(created_jobs) > 3:
|
||||
Application.objects.get_or_create(
|
||||
user=user,
|
||||
job=created_jobs[3],
|
||||
defaults={
|
||||
"status": Application.Status.APPLIED,
|
||||
"applied_at": now - timedelta(days=2),
|
||||
"follow_up_date": (now + timedelta(days=5)).date(),
|
||||
"notes": "Sollicitatie verstuurd. Demo-data.",
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user