+
-
-
+
-
-
-
-
-
-
-
-
-
- {{conversion_ratio}}%
-
-
{{100|sub:conversion_ratio|floatformat:1}}%
-
-
+
+
+
-
-
-
-
-
-
- {{acceptance_ratio}}%
-
-
{{100|sub:acceptance_ratio|floatformat:1}}%
-
+
+
+ {{conversion_ratio}}%
+
-
+
+
+
+
+
+ {{acceptance_ratio}}%
+
+
+
+
+
+
+
+
+
+
+
+ {% if skill_zone %}
+
+ {% else %}
+
+
+

+
{% trans "No skill zone available." %}
+
+
+ {% endif %}
+
+
+
+
+
+
-
+
{% if onboarding_count %}
@@ -164,7 +193,9 @@
{{cand}}
-
- {{cand.job_position_id}}
+
+
+   {{cand.job_position_id}}
{% endfor %}
@@ -176,81 +207,112 @@
{% endif %}
-
-
-
- {% if request.user|is_in_task_managers %}
-
-
- {% endif %}
-
+
+ {% if request.user|is_in_task_managers %}
+
+ {% endif %}
+
-
- {% if stage_chart_count %}
-
- {% else %}
+
+
+
+
+
+
+
+
+
+ {% if joining %}
+
+ {% else %}
-

-
{% trans "No recruitment stages currently available." %}
+

+
{% trans "No records were available." %}
- {% endif %}
+ {% endif %}
-
-
-
-
@@ -326,6 +386,7 @@
+
@@ -344,6 +405,66 @@
}
selectyear.appendChild(option);
}
+
+
+ document.addEventListener("DOMContentLoaded", function() {
+ const icon = document.getElementById('offerhelptext');
+ icon.addEventListener('click', function(event) {
+ acceptance_helptext(event); // Pass the event object to the acceptance_helptext function
+ });
+ });
+
+function acceptance_helptext(event) {
+ event = event || window.event;
+ const icon = event.target || event.srcElement;
+ const tooltip = document.createElement('div');
+ tooltip.className = 'tooltip';
+ tooltip.textContent = 'Offer Acceptance Rate = ( Onboarding candidates / Total Hired Candidates ) * 100'; // Help text
+
+ // Position the tooltip relative to the icon
+ const rect = icon.getBoundingClientRect();
+ tooltip.style.top = rect.top + icon.offsetHeight + 'px';
+ tooltip.style.left = rect.left + 'px';
+
+ // Append tooltip to the body
+ document.body.appendChild(tooltip);
+
+ // Remove tooltip when mouse is moved away from the icon
+ icon.addEventListener('mouseout', function () {
+ document.body.removeChild(tooltip);
+ });
+}
+
+
+document.addEventListener("DOMContentLoaded", function() {
+ const icon = document.getElementById('conversionhelptext');
+ icon.addEventListener('click', function(event) {
+ conversion_helptext(event); // Pass the event object to the conversion_helptext function
+ });
+});
+
+function conversion_helptext(event) {
+ event = event || window.event;
+ const icon = event.target || event.srcElement;
+ const tooltip = document.createElement('div');
+ tooltip.className = 'tooltip';
+ tooltip.textContent = 'Conversion Rate = ( Total Hired Candidates / Total Candidates ) * 100'; // Help text
+
+ // Position the tooltip relative to the icon
+ const rect = icon.getBoundingClientRect();
+ tooltip.style.top = rect.top + icon.offsetHeight + 'px';
+ tooltip.style.left = rect.left + 'px';
+
+ // Append tooltip to the body
+ document.body.appendChild(tooltip);
+
+ // Remove tooltip when mouse is moved away from the icon
+ icon.addEventListener('mouseout', function () {
+ document.body.removeChild(tooltip);
+ });
+}
+
+
{% endblock content %}
diff --git a/recruitment/templates/stage/stage_component.html b/recruitment/templates/stage/stage_component.html
index e201405e3..9ac8a2db0 100644
--- a/recruitment/templates/stage/stage_component.html
+++ b/recruitment/templates/stage/stage_component.html
@@ -57,7 +57,7 @@
>
{% trans "Recruitment" %}
-
+
{% trans "Actions" %}
diff --git a/recruitment/urls.py b/recruitment/urls.py
index 096b90115..a9d6228ee 100644
--- a/recruitment/urls.py
+++ b/recruitment/urls.py
@@ -257,6 +257,11 @@ urlpatterns = [
recruitment.views.dashboard.dashboard_vacancy,
name="dashboard-vacancy",
),
+ path(
+ "candidate-status",
+ recruitment.views.dashboard.candidate_status,
+ name="candidate-status",
+ ),
path(
"candidate-sequence-update",
views.candidate_sequence_update,
diff --git a/recruitment/views/dashboard.py b/recruitment/views/dashboard.py
index 4a5784712..6db4e3dff 100644
--- a/recruitment/views/dashboard.py
+++ b/recruitment/views/dashboard.py
@@ -11,7 +11,7 @@ from django.utils.translation import gettext_lazy as _
from django.shortcuts import render
from horilla.decorators import login_required
from recruitment.decorators import manager_can_enter
-from recruitment.models import Candidate, Recruitment, Stage
+from recruitment.models import Candidate, Recruitment, SkillZone, Stage
from base.models import Department, JobPosition
from employee.models import EmployeeWorkInformation
@@ -86,6 +86,7 @@ def dashboard(request):
job_data = list(zip(all_job, initial, test, interview, hired))
recruitment_obj = Recruitment.objects.filter(closed=False)
+ ongoing_recruitments = len(recruitment_obj)
for rec in recruitment_obj:
data = [stage_type_candidate_count(rec, type[0]) for type in Stage.stage_types]
@@ -130,11 +131,13 @@ def dashboard(request):
total_candidate_ratio = f"{((total_candidates / total_vacancy) * 100):.1f}"
if total_hired_candidates != 0:
acceptance_ratio = f"{((onboarding_count / total_hired_candidates) * 100):.1f}"
+
+ skill_zone = SkillZone.objects.all()
return render(
request,
"dashboard/dashboard.html",
{
- "total_candidates": total_candidates,
+ "ongoing_recruitments": ongoing_recruitments,
"total_candidate_ratio" : total_candidate_ratio,
"total_hired_candidates": total_hired_candidates,
"conversion_ratio": conversion_ratio,
@@ -148,6 +151,8 @@ def dashboard(request):
"dep_vacancy" : dep_vacancy,
"stage_chart_count" : stage_chart_count,
"onboarding_count" : onboarding_count,
+ "total_candidates":total_candidates,
+ 'skill_zone' : skill_zone
},
)
@@ -267,3 +272,43 @@ def get_open_position(request):
job_info = serializers.serialize("json", queryset)
rec_info = serializers.serialize("json", [recruitment_obj])
return JsonResponse({"openPositions": job_info, "recruitmentInfo": rec_info})
+
+
+@login_required
+@manager_can_enter(perm="recruitment.view_recruitment")
+def candidate_status(_request):
+ """
+ This method is used to generate a CAndidate status chart for the dashboard
+ """
+
+ not_sent_candidates = Candidate.objects.filter(offer_letter_status = 'not_sent').count()
+ sent_candidates = Candidate.objects.filter(offer_letter_status = 'sent').count()
+ accepted_candidates = Candidate.objects.filter(offer_letter_status = 'accepted').count()
+ rejected_candidates = Candidate.objects.filter(offer_letter_status = 'rejected').count()
+ joined_candidates = Candidate.objects.filter(offer_letter_status = 'joined').count()
+
+ data_set = []
+ labels = ['Not Sent', 'Sent', 'Accepted', 'Rejected', 'Joined']
+ data = [not_sent_candidates, sent_candidates, accepted_candidates, rejected_candidates, joined_candidates]
+
+ for i in range(len(data)):
+
+ data_set.append(
+ {
+ "label": labels[i],
+ "data":data[i]
+ }
+ )
+
+ # for i in range(len(data)):
+ # if data[i] != 0:
+ # data_set.append({
+ # "label": labels[i],
+ # "data": data[i]
+ # })
+
+ # # Remove labels corresponding to data points with value 0
+ # labels = [label for label, d in zip(labels, data) if d != 0]
+
+
+ return JsonResponse({"dataSet": data_set, "labels": labels})