iteracion 2

This commit is contained in:
Nachou-u
2026-09-07 18:44:32 -03:00
parent a103a47ae6
commit 09a3f6fb37
93 changed files with 7394 additions and 349 deletions
+162
View File
@@ -0,0 +1,162 @@
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})