[ADD] RECRUITMENT: Candidate rating and average rating

This commit is contained in:
Horilla
2024-01-06 09:52:53 +05:30
parent 0a85fe4d14
commit 19d1fe629c
8 changed files with 179 additions and 5 deletions

View File

@@ -5,6 +5,7 @@ This page is used to register the model with admins site.
"""
from django.contrib import admin
from recruitment.models import (
CandidateRating,
Stage,
Recruitment,
Candidate,
@@ -23,3 +24,4 @@ admin.site.register(Candidate)
admin.site.register(RecruitmentSurveyAnswer)
admin.site.register(RecruitmentSurvey)
admin.site.register(RecruitmentMailTemplate)
admin.site.register(CandidateRating)

View File

@@ -21,6 +21,7 @@ from employee.models import Employee
from base.models import JobPosition, Company
from django.core.files.storage import default_storage
from base.horilla_company_manager import HorillaCompanyManager
from django.core.validators import MinValueValidator, MaxValueValidator
# Create your models here.
@@ -513,3 +514,15 @@ class RecruitmentMailTemplate(models.Model):
def __str__(self) -> str:
return self.title
class CandidateRating(models.Model):
employee_id = models.ForeignKey(Employee,on_delete=models.PROTECT, related_name="candidate_rating")
candidate_id = models.ForeignKey(Candidate,on_delete=models.PROTECT, related_name="candidate_rating")
rating = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(5)])
class Meta:
unique_together = ['employee_id', 'candidate_id']
def __str__(self) -> str:
return f"{self.employee_id} - {self.candidate_id} rating {self.rating}"

View File

@@ -1,4 +1,4 @@
{% extends 'index.html' %} {% load i18n %} {% load yes_no %} {% load static %} {% block content %}
{% extends 'index.html' %} {% load i18n %} {% load yes_no %} {% load static %} {% block content %} {% load recruitmentfilters %}
<style>
.enlarge-image-container {
@@ -16,6 +16,15 @@
height: auto;
border-radius: 5%;
}
.oh-rate:not(:checked)>label {
font-size:40px;
}
.star {
font-size:20px !important;
}
.ul {
margin:0;
}
</style>
<div id="enlargeImageContainer" class="enlarge-image-container"></div>
@@ -27,7 +36,7 @@
<div class='d-flex float-end ms-4'>
{% if candidate.email in emp_list %}
{% else %}
<form action="{% url 'candidate-conversion' candidate.id %}" style="color: inherit;text-decoration: none;""
<form action="{% url 'candidate-conversion' candidate.id %}" style="color: inherit;text-decoration: none;"
onsubmit="return confirm('{% trans "Are you sure you want to convert this candidate into an employee?" %}')"
>
{% csrf_token %}
@@ -68,7 +77,7 @@
</div>
</div>
<div
class="col-12 col-sm-12 col-md-12 col-lg-8 d-flex align-items-center"
class="col-12 col-sm-12 col-md-12 col-lg-8 d-flex align-items-center justify-content-between"
>
<ul class="oh-profile__info-list">
<li class="oh-profile__info-list-item">
@@ -87,6 +96,18 @@
<span class="oh-profile__info-value">{{candidate.mobile}}</span>
</li>
</ul>
<div class="oh-rate">
<input type="radio" id="star5" value="5" disabled {% if average_rate == 5 %} checked {% endif %} />
<label for="star5" title="5 Stars" class="rating-star">5 {% trans "Stars" %}</label>
<input type="radio" id="star4" value="4" disabled {% if average_rate == 4 %} checked {% endif %} />
<label for="star4" title="4 Stars" class="rating-star">4 {% trans "Stars" %}</label>
<input type="radio" id="star3" value="3" disabled {% if average_rate == 3 %} checked {% endif %} />
<label for="star3" title="3 Stars" class="rating-star">3 {% trans "Stars" %}</label>
<input type="radio" id="star2" value="2" disabled {% if average_rate == 2 %} checked {% endif %} />
<label for="star2" title="2 Stars" class="rating-star">2 {% trans "Stars" %}</label>
<input type="radio" id="star1" value="1" disabled {% if average_rate == 1 %} checked {% endif %} />
<label for="star1" title="1 Star" class="rating-star">1 {% trans "Star" %}</label>
</div>
</div>
</div>
<div class="row">
@@ -139,6 +160,17 @@
>{% trans "History" %}</a
>
</li>
{% if request.user|stage_manages:rec or perms.recruitment.change_candidate %}
<li class="oh-general__tab">
<a
href="#"
class="oh-general__tab-link"
data-action="general-tab"
data-target="#rating"
>{% trans "Rating" %}</a
>
</li>
{% endif %}
{% if candidate.hired %}
<li class="oh-general__tab">
<a
@@ -431,6 +463,12 @@
>
{% include "candidate/history.html" %}
</div>
<div
class="oh-general__tab-target oh-profile__info-tab mb-4 d-none"
id="rating"
>
{% include "candidate/rating_tab.html" %}
</div>
<div
class="oh-general__tab-target oh-profile__info-tab mb-4 d-none"
id="resume"

View File

@@ -0,0 +1,40 @@
{% load static %} {% load audit_filters %} {% load i18n %}
<div class="row p-4">
{% for rate in candidate.candidate_rating.all %}
<div class="oh-history__container pb-2">
<div class="d-flex">
<div class="oh-history_user-img">
<img
src="{{rate.employee_id.get_avatar}}"
alt=""
class="oh-history_user-pic"
/>
<div class="oh-history_user-state oh-user_inactive"></div>
</div>
<div class="oh-history_user-details">
<span class="oh-history__username">{{rate.employee_id}}</span>
<ul class="ul ps-0">
<div class="oh-rate">
<input type="radio" id="star5" value="5" disabled {% if rate.rating == 5 %} checked {% endif %} />
<label for="star5" title="5 Stars" class="star">5 {% trans "Stars" %}</label>
<input type="radio" id="star4" value="4" disabled {% if rate.rating == 4 %} checked {% endif %} />
<label for="star4" title="4 Stars" class="star">4 {% trans "Stars" %}</label>
<input type="radio" id="star3" value="3" disabled {% if rate.rating == 3 %} checked {% endif %} />
<label for="star3" title="3 Stars" class="star">3 {% trans "Stars" %}</label>
<input type="radio" id="star2" value="2" disabled {% if rate.rating == 2 %} checked {% endif %} />
<label for="star2" title="2 Stars" class="star">2 {% trans "Stars" %}</label>
<input type="radio" id="star1" value="1" disabled {% if rate.rating == 1 %} checked {% endif %} />
<label for="star1" title="1 Star" class="star">1 {% trans "Star" %}</label>
</div>
</ul>
{% comment %} <div class="oh-history_msg-container">
<div class="oh-history_task-tracker">
</div>
</div> {% endcomment %}
</div>
</div>
</div>
{% endfor %}
</div>

View File

@@ -252,6 +252,11 @@
<div class="oh-sticky-table__th oh-table-config__th">
<span> {% trans "Contact" %} </span>
</div>
{% if request.user|stage_manages:rec or perms.recruitment.change_candidate %}
<div class="oh-sticky-table__th oh-table-config__th">
<span> {% trans "Rating" %} </span>
</div>
{% endif %}
<div class="oh-sticky-table__th oh-table-config__th">{% trans "Stage" %}</div>
<div class="oh-sticky-table__th oh-table-config__th" style="width: 200px;" >
<select name="bulk_stage" class="oh-select w-100" data-stage-id="{{stage.id}}">
@@ -316,6 +321,41 @@
<div class="oh-sticky-table__td oh-table-config__td">
{{cand.mobile}}
</div>
{% if request.user|stage_manages:rec or perms.recruitment.change_candidate %}
<div class="oh-sticky-table__td oh-table-config__td" onclick="event.stopPropagation()">
{% with request.user.employee_get.candidate_rating.all as candidate_ratings %}
{% if candidate_ratings|has_candidate_rating:cand %}
<form hx-swap="none" hx-post='{% url "update-candidate-rating" cand.id %}' method="post">
{% csrf_token %}
<div class="d-block mb-0">
<div class="oh-rate" onclick="$(this).parents().closest('form').find('button').click()">
{% for i in "54321" %}
<input type="radio" id="star{{i}}{{cand.id}}" name="rating" class="rating-radio" value="{{i}}" {% if candidate_ratings|rating:cand == i %} checked {% endif %} />
<label for="star{{i}}{{cand.id}}" title="{{i}} Stars">5 {% trans "Stars" %}</label>
{% endfor %}
</div>
<button type="submit" hidden="true"></button>
<span id="rating-radio-error"></span>
</div>
</form>
{% else %}
<form hx-swap="none" hx-post='{% url "create-candidate-rating" cand.id %}' method="post">
{% csrf_token %}
<div class="d-block mb-0">
<div class="oh-rate" onclick="$(this).parents().closest('form').find('button').click()">
{% for i in "54321" %}
<input type="radio" id="star{{i}}{{cand.id}}" name="rating" class="rating-radio" value="{{i}}" />
<label for="star{{i}}{{cand.id}}" title="5 Stars">5 {% trans "Stars" %}</label>
{% endfor %}
</div>
<button type="submit" hidden="true"></button>
<span id="rating-radio-error"></span>
</div>
</form>
{% endif %}
{% endwith %}
</div>
{% endif %}
<div class="oh-sticky-table__td oh-table-config__td">
<select
name=""

View File

@@ -98,4 +98,12 @@ def generate_id(element, label=""):
return element
# @register.filter
@register.filter(name='has_candidate_rating')
def has_candidate_rating(candidate_ratings, cand):
candidate_rating = candidate_ratings.filter(candidate_id=cand.id).first()
return candidate_rating
@register.filter(name='rating')
def rating(candidate_ratings,cand):
rating = candidate_ratings.filter(candidate_id=cand.id).first().rating
return str(rating)

View File

@@ -285,4 +285,6 @@ urlpatterns = [
path("create-mail-template/", create_letter, name="create-mail-template"),
path("delete-mail-template/", delete_mail_templates, name="delete-mail-template"),
path("get-template/<int:obj_id>/", get_template, name="get-template"),
path("create-candidate-rating/<int:cand_id>/", views.create_candidate_rating, name="create-candidate-rating"),
path("update-candidate-rating/<int:cand_id>/", views.update_candidate_rating, name="update-candidate-rating"),
]

View File

@@ -35,6 +35,7 @@ from horilla.decorators import permission_required, login_required, hx_request_r
from base.methods import export_data, generate_pdf, get_key_instances
from recruitment.views.paginator_qry import paginator_qry
from recruitment.models import (
CandidateRating,
RecruitmentMailTemplate,
Recruitment,
Candidate,
@@ -950,9 +951,17 @@ def candidate_view_individual(request, cand_id, **kwargs):
mails= list(Candidate.objects.values_list("email",flat=True))
# Query the User model to check if any email is present
existing_emails = list(User.objects.filter(username__in=mails).values_list('email', flat=True))
ratings = candidate_obj.candidate_rating.all()
rating_list = []
avg_rate = 0
for rating in ratings:
rating_list.append(rating.rating)
if len(rating_list) != 0:
avg_rate = round(sum(rating_list) / len(rating_list))
return render(request, "candidate/individual.html",
{"candidate": candidate_obj, "emp_list" : existing_emails })
{"candidate": candidate_obj, "emp_list" : existing_emails,"average_rate": avg_rate,})
@login_required
@@ -1193,3 +1202,25 @@ def candidate_select_filter(request):
context = {"employee_ids": employee_ids, "total_count": total_count}
return JsonResponse(context)
@login_required
def create_candidate_rating(request,cand_id):
cand_id = cand_id
candidate = Candidate.objects.get(id=cand_id)
employee_id = request.user.employee_get
rating = request.POST.get("rating")
CandidateRating.objects.create(candidate_id=candidate, rating=rating, employee_id=employee_id)
return redirect(recruitment_pipeline)
@login_required
def update_candidate_rating(request,cand_id):
cand_id = cand_id
candidate = Candidate.objects.get(id=cand_id)
employee_id = request.user.employee_get
rating = request.POST.get("rating")
rate = CandidateRating.objects.get(candidate_id=candidate, employee_id=employee_id)
rate.rating = int(rating)
rate.save()
return redirect(recruitment_pipeline)