from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.contrib import messages from django.http import JsonResponse from django.db.models import Q, Count, Avg from decimal import Decimal from datetime import date import json from .models import SpecialistCandidate, EvaluationRubric7D, SpecialistCategoryEnum, SeniorityEnum, CandidateStatusEnum from .forms import SpecialistCandidateForm, EvaluationRubric7DForm from .services.rubric import TalentScoringEngine from expenses.chile_regions import REGIONS_COMMUNES @login_required def candidate_list(request): candidates = SpecialistCandidate.objects.select_related().all().order_by('-created_at') # Filter params category = request.GET.get('category') seniority = request.GET.get('seniority') trl = request.GET.get('trl') status = request.GET.get('status') query = request.GET.get('q') if category: candidates = candidates.filter(category_code=category) if seniority: candidates = candidates.filter(seniority=seniority) if trl: candidates = candidates.filter(trl_level=int(trl)) if status: candidates = candidates.filter(status=status) if query: candidates = candidates.filter( Q(first_name__icontains=query) | Q(last_name__icontains=query) | Q(rut__icontains=query) | Q(specialty_title__icontains=query) | Q(summary__icontains=query) ) # Statistics stats = { 'total': SpecialistCandidate.objects.count(), 'approved': SpecialistCandidate.objects.filter(status=CandidateStatusEnum.APROBADO_CARTERA).count(), 'reserve': SpecialistCandidate.objects.filter(status=CandidateStatusEnum.EN_RESERVA).count(), 'evaluating': SpecialistCandidate.objects.filter(status=CandidateStatusEnum.EN_EVALUACION).count(), } return render(request, 'talent/candidate_list.html', { 'candidates': candidates, 'stats': stats, 'categories': SpecialistCategoryEnum.choices, 'seniorities': SeniorityEnum.choices, 'statuses': CandidateStatusEnum.choices, 'selected_category': category, 'selected_seniority': seniority, 'selected_trl': trl, 'selected_status': status, 'query': query, }) @login_required def candidate_create(request): if request.method == 'POST': form = SpecialistCandidateForm(request.POST) if form.is_valid(): cand = form.save() messages.success(request, f"Especialista {cand.full_name} registrado en cartera.") return redirect('talent:candidate_detail', pk=cand.pk) else: form = SpecialistCandidateForm() return render(request, 'talent/candidate_form.html', { 'form': form, 'title': 'Registrar Nuevo Especialista I+D+i', 'regions_json': json.dumps(REGIONS_COMMUNES) }) @login_required def candidate_edit(request, pk): cand = get_object_or_404(SpecialistCandidate, pk=pk) if request.method == 'POST': form = SpecialistCandidateForm(request.POST, instance=cand) if form.is_valid(): cand = form.save() messages.success(request, f"Perfil de {cand.full_name} actualizado.") return redirect('talent:candidate_detail', pk=cand.pk) else: form = SpecialistCandidateForm(instance=cand) return render(request, 'talent/candidate_form.html', { 'form': form, 'title': f"Editar Especialista: {cand.full_name}", 'regions_json': json.dumps(REGIONS_COMMUNES) }) @login_required def candidate_detail(request, pk): cand = get_object_or_404(SpecialistCandidate, pk=pk) evaluations = cand.evaluations.select_related('evaluator').order_by('-evaluation_date', '-created_at') latest_eval = evaluations.first() return render(request, 'talent/candidate_detail.html', { 'candidate': cand, 'evaluations': evaluations, 'latest_eval': latest_eval, }) @login_required def evaluation_create(request, candidate_pk=None): candidate = get_object_or_404(SpecialistCandidate, pk=candidate_pk) if candidate_pk else None if request.method == 'POST': form = EvaluationRubric7DForm(request.POST) if form.is_valid(): ev = form.save(commit=False) ev.evaluator = request.user # Run Scoring Engine result = TalentScoringEngine.evaluate( dim_case_study=ev.dim_case_study, dim_portfolio=ev.dim_portfolio, dim_tech_specific=ev.dim_tech_specific, dim_cardinal_skills=ev.dim_cardinal_skills, dim_experience=ev.dim_experience, dim_principles_safety=ev.dim_principles_safety, dim_innovation_rndi=ev.dim_innovation_rndi, evaluation_date=ev.evaluation_date ) ev.total_weighted_score = result['weighted_score'] ev.is_knockout = result['is_knockout'] ev.result_status = result['result_status'] ev.valid_until = result['valid_until'] ev.save() # Sync candidate status cand_obj = ev.candidate cand_obj.status = ev.result_status cand_obj.save(update_fields=['status']) if ev.is_knockout: messages.error(request, f"Evaluación finalizada: {result['verdict_message']}") else: messages.success(request, f"Evaluación 7D guardada exitosamente. Score: {ev.total_weighted_score}/100 - {result['verdict_message']}") return redirect('talent:candidate_detail', pk=cand_obj.pk) else: initial = {'evaluation_date': date.today()} if candidate: initial['candidate'] = candidate form = EvaluationRubric7DForm(initial=initial) return render(request, 'talent/evaluation_form.html', { 'form': form, 'candidate': candidate, }) @login_required def evaluation_detail(request, pk): eval_obj = get_object_or_404(EvaluationRubric7D.objects.select_related('candidate', 'evaluator'), pk=pk) return render(request, 'talent/evaluation_detail.html', {'eval': eval_obj})