[ADD] OFFOARDING: Added dashboard for offboarding module
This commit is contained in:
@@ -21,8 +21,13 @@ from offboarding.models import (
|
||||
def any_manager_can_enter(function, perm, offboarding_employee_can_enter=False):
|
||||
def _function(request, *args, **kwargs):
|
||||
employee = request.user.employee_get
|
||||
permissions = perm
|
||||
has_permission = False
|
||||
if not isinstance(permissions, (list, tuple, set)):
|
||||
permissions = [permissions]
|
||||
has_permission = any(request.user.has_perm(perm) for perm in permissions)
|
||||
if (
|
||||
request.user.has_perm(perm)
|
||||
has_permission
|
||||
or offboarding_employee_can_enter
|
||||
or (
|
||||
Offboarding.objects.filter(managers=employee).exists()
|
||||
@@ -32,6 +37,7 @@ def any_manager_can_enter(function, perm, offboarding_employee_can_enter=False):
|
||||
):
|
||||
return function(request, *args, **kwargs)
|
||||
else:
|
||||
messages.info(request, "You don't have permission.")
|
||||
previous_url = request.META.get("HTTP_REFERER", "/")
|
||||
script = f'<script>window.location.href = "{previous_url}"</script>'
|
||||
key = "HTTP_HX_REQUEST"
|
||||
|
||||
@@ -17,6 +17,11 @@ ACCESSIBILITY = "offboarding.sidebar.offboarding_accessibility"
|
||||
|
||||
|
||||
SUBMENUS = [
|
||||
{
|
||||
"menu": _("Dashboard"),
|
||||
"redirect": reverse("offboarding-dashboard"),
|
||||
"accessibility": "offboarding.sidebar.dashboard_accessibility",
|
||||
},
|
||||
{
|
||||
"menu": _("Exit Process"),
|
||||
"redirect": reverse("offboarding-pipeline"),
|
||||
@@ -33,7 +38,7 @@ def offboarding_accessibility(request, menu, user_perms, *args, **kwargs):
|
||||
accessible = False
|
||||
try:
|
||||
accessible = (
|
||||
request.user.has_perm("offboarding.view_offboarding")
|
||||
request.user.has_module_perms("offboarding")
|
||||
or any_manager(request.user.employee_get)
|
||||
or is_offboarding_employee(request.user.employee_get)
|
||||
)
|
||||
@@ -45,3 +50,13 @@ def resignation_letter_accessibility(request, menu, user_perms, *args, **kwargs)
|
||||
return resignation_request_enabled(request)[
|
||||
"enabled_resignation_request"
|
||||
] and request.user.has_perm("offboarding.view_resignationletter")
|
||||
|
||||
|
||||
def dashboard_accessibility(request, *args):
|
||||
"""
|
||||
Check if the user has permission to view the dashboard.
|
||||
"""
|
||||
|
||||
return request.user.has_module_perms("offboarding") or any_manager(
|
||||
request.user.employee_get
|
||||
)
|
||||
|
||||
98
offboarding/static/offboarding/dashboard.js
Normal file
98
offboarding/static/offboarding/dashboard.js
Normal file
@@ -0,0 +1,98 @@
|
||||
$(document).ready(function () {
|
||||
var departmentChart;
|
||||
var joinChart;
|
||||
|
||||
var department_chart = () => {
|
||||
$.ajax({
|
||||
url: "/offboarding/dashboard-department-chart",
|
||||
type: "GET",
|
||||
success: function (data) {
|
||||
var ctx = $("#departmentChart");
|
||||
if (departmentChart) {
|
||||
departmentChart.destroy();
|
||||
}
|
||||
departmentChart = new Chart(ctx, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: data.labels,
|
||||
datasets: data.datasets,
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true,
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
afterRender: (chart) => emptyChart(chart),
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
console.error("Error fetching department chart data:", error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
var join_chart = (type) => {
|
||||
$.ajax({
|
||||
url: "/offboarding/dashboard-join-chart",
|
||||
type: "GET",
|
||||
success: function (data) {
|
||||
var ctx = $("#joinChart");
|
||||
if (joinChart) {
|
||||
joinChart.destroy();
|
||||
}
|
||||
joinChart = new Chart(ctx, {
|
||||
type: type,
|
||||
data: {
|
||||
labels: data.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: "Employees",
|
||||
data: data.items,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
afterRender: (chart) => emptyChart(chart),
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
console.error("Error fetching department chart data:", error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
$("#joinChartChange").click(function (e) {
|
||||
var chartType = joinChart.config.type;
|
||||
if (chartType === "line") {
|
||||
chartType = "bar";
|
||||
} else if (chartType === "bar") {
|
||||
chartType = "doughnut";
|
||||
} else if (chartType === "doughnut") {
|
||||
chartType = "pie";
|
||||
} else if (chartType === "pie") {
|
||||
chartType = "line";
|
||||
}
|
||||
join_chart(chartType);
|
||||
});
|
||||
|
||||
department_chart("pie");
|
||||
join_chart("bar");
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
{% load static i18n offboarding_filter %}
|
||||
|
||||
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
||||
<span class="oh-card-dashboard__title"
|
||||
>{% trans "Not Returned Assets" %}</span
|
||||
>
|
||||
</div>
|
||||
<div class="oh-card-dashboard__body h-75 overflow-auto position-relative">
|
||||
{% if assets %}
|
||||
<div
|
||||
class="oh-sticky-table__table"
|
||||
style="border: 1px solid hsl(213, 22%, 93%)"
|
||||
>
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Employee" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Asset" %}</div>
|
||||
<div class="oh-sticky-table__th text-center">
|
||||
{% trans "Reminder" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for asset in assets %}
|
||||
<div
|
||||
class="oh-sticky-table__tr oh-multiple-table-sort__movable"
|
||||
onclick="
|
||||
localStorage.setItem('activeTabAsset','#tab_2');
|
||||
window.location.href = '{% url 'asset-request-allocation-view' %}?assigned_to_employee_id={{asset.assigned_to_employee_id.id}}'
|
||||
"
|
||||
>
|
||||
<div class="oh-sticky-table__sd">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img
|
||||
src="{{ asset.assigned_to_employee_id.get_avatar }}"
|
||||
class="oh-profile__image"
|
||||
/>
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"
|
||||
>{{ asset.assigned_to_employee_id.get_full_name}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
{{asset.asset_id.asset_name}} -
|
||||
{{asset.asset_id.asset_category_id}}
|
||||
</div>
|
||||
<div
|
||||
class="oh-sticky-table__td text-center"
|
||||
onclick="event.stopPropagation()"
|
||||
>
|
||||
<a
|
||||
hx-get="{% url 'send-mail-employee' asset.assigned_to_employee_id.id %}"
|
||||
data-toggle="oh-modal-toggle"
|
||||
data-target="#sendMailModal"
|
||||
title="{% trans 'Send Mail' %}"
|
||||
hx-target="#mail-content"
|
||||
>
|
||||
<ion-icon name="mail-outline"></ion-icon>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="oh-404">
|
||||
<img
|
||||
style="display: block; width: 120px; margin: 20px auto"
|
||||
src="{% static 'images/ui/asset.png' %}"
|
||||
class=""
|
||||
/>
|
||||
<h3 style="font-size: 16px" class="oh-404__subtitle">
|
||||
{% trans "No Assets Due for Return from Offboarding Employees." %}
|
||||
</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$("[data-toggle='oh-modal-toggle']").on("click", function () {
|
||||
var target = $(this).data("target");
|
||||
$(target).toggleClass("oh-modal--show");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
208
offboarding/templates/offboarding/dashboard/dashboard.html
Normal file
208
offboarding/templates/offboarding/dashboard/dashboard.html
Normal file
@@ -0,0 +1,208 @@
|
||||
{% extends 'index.html' %} {% block content %} {% load static i18n horillafilters %}
|
||||
|
||||
<div class="oh-wrapper" id="offboardingDashboard">
|
||||
<div class="oh-dashboard mb-5" id="dashboard">
|
||||
<div class="oh-dashboard__left col-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="oh-dashboard__cards row">
|
||||
<div class="col-12 col-sm-12 col-md-6 col-lg-4">
|
||||
<div
|
||||
class="oh-card-dashboard oh-card-dashboard--success h-100"
|
||||
>
|
||||
<a
|
||||
href="{% url 'offboarding-pipeline' %}"
|
||||
class="text-decoration-none recruitment"
|
||||
>
|
||||
<div
|
||||
class="oh-card-dashboard__header d-flex justify-content-between align-items-center"
|
||||
>
|
||||
<span class="oh-card-dashboard__title"
|
||||
>{% trans "Exit Ratio" %}</span
|
||||
>
|
||||
<span
|
||||
style="font-size: 24px"
|
||||
title="{% trans 'Archived Employees / Total Employees' %}"
|
||||
><ion-icon
|
||||
name="help-circle-outline"
|
||||
></ion-icon
|
||||
></span>
|
||||
</div>
|
||||
<div class="oh-card-dashboard__body">
|
||||
<span class="oh-card-dashboard__count"
|
||||
>{{exit_ratio}}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-6 col-lg-4">
|
||||
<div
|
||||
class="oh-card-dashboard oh-card-dashboard--warning h-100"
|
||||
>
|
||||
<div
|
||||
class="oh-card-dashboard__header d-flex justify-content-between align-items-center"
|
||||
>
|
||||
<span class="oh-card-dashboard__title"
|
||||
>{% trans "Exiting to Joining Ratio" %}</span
|
||||
>
|
||||
<span
|
||||
style="font-size: 24px"
|
||||
title="{% trans 'Exiting Employees : Joining Employees' %}"
|
||||
><ion-icon name="help-circle-outline"></ion-icon
|
||||
></span>
|
||||
</div>
|
||||
<div class="oh-card-dashboard__body">
|
||||
<span class="oh-card-dashboard__count"
|
||||
>{{resigning_employees.count}} :
|
||||
{{onboarding_employees}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-6 col-lg-4">
|
||||
<div
|
||||
class="oh-card-dashboard oh-card-dashboard--success h-100"
|
||||
>
|
||||
<a
|
||||
href="{% url 'employee-view' %}?is_active=False"
|
||||
style="text-decoration: none"
|
||||
>
|
||||
<div class="oh-card-dashboard__header">
|
||||
<span class="oh-card-dashboard__title"
|
||||
>{% trans "Archived Employees" %}</span
|
||||
>
|
||||
</div>
|
||||
<div class="oh-card-dashboard__body">
|
||||
<span
|
||||
style="text-decoration: none"
|
||||
class="oh-card-dashboard__counts"
|
||||
>
|
||||
<span class="oh-card-dashboard__count">
|
||||
{{archived_employees.count}}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
{% if perms.offboarding.view_offboardingtask %}
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6 mt-4">
|
||||
<div
|
||||
class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent oh-offboarding-card"
|
||||
hx-get="{% url 'dashboard-task-table' %}"
|
||||
hx-trigger="load"
|
||||
>
|
||||
<div class="animated-background"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if "asset"|app_installed %}
|
||||
{% if perms.offboarding.view_offboarding %}
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6 mt-4">
|
||||
<div
|
||||
class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent oh-offboarding-card"
|
||||
style="cursor: default"
|
||||
hx-get="{% url 'dashboard-asset-table' %}"
|
||||
hx-trigger="load"
|
||||
>
|
||||
<div class="animated-background"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if perms.offboarding.view_offboarding %}
|
||||
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-4 mt-4">
|
||||
<div
|
||||
class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent oh-offboarding-card"
|
||||
style="cursor: default"
|
||||
>
|
||||
<div
|
||||
class="oh-card-dashboard__header oh-card-dashboard__header--divider"
|
||||
>
|
||||
<span class="oh-card-dashboard__title"
|
||||
>{% trans "Department - JobPosition Offboarding" %}</span
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="oh-card-dashboard__body"
|
||||
style="height: 350px; overflow: auto"
|
||||
>
|
||||
<canvas id="departmentChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-4 mt-4">
|
||||
<div
|
||||
class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent oh-offboarding-card"
|
||||
style="cursor: default"
|
||||
hx-get="{% url 'dashboard-feedback-table' %}"
|
||||
hx-trigger="load"
|
||||
>
|
||||
<div
|
||||
class="oh-card-dashboard__body"
|
||||
>
|
||||
<div class="animated-background"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-4 mt-4">
|
||||
<div
|
||||
class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent oh-offboarding-card"
|
||||
style="cursor: default"
|
||||
>
|
||||
<div
|
||||
class="oh-card-dashboard__header oh-card-dashboard__header--divider"
|
||||
>
|
||||
<span class="oh-card-dashboard__title"
|
||||
>{% trans "Joining and Offboarding Chart" %}</span
|
||||
>
|
||||
<span
|
||||
class="oh-card-dashboard__title float-end"
|
||||
id="joinChartChange"
|
||||
style="cursor: pointer"
|
||||
>
|
||||
<ion-icon
|
||||
name="caret-forward"
|
||||
role="img"
|
||||
class="md hydrated"
|
||||
></ion-icon>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="oh-card-dashboard__body"
|
||||
style="height: 350px; overflow: auto"
|
||||
>
|
||||
<canvas id="joinChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="oh-modal"
|
||||
id="sendMailModal"
|
||||
role="dialog"
|
||||
aria-labelledby="sendMailModal"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="oh-modal__dialog">
|
||||
<div class="oh-modal__dialog-header">
|
||||
<h5 class="oh-modal__dialog-title" id="sendMailModalLabel">
|
||||
{% trans "Send Mail" %}
|
||||
</h5>
|
||||
<button class="oh-modal__close" aria-label="Close">
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oh-modal__dialog-body" id="mail-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{% static 'offboarding/dashboard.js' %}"></script>
|
||||
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,75 @@
|
||||
{% load static i18n offboarding_filter %}
|
||||
|
||||
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
||||
<span class="oh-card-dashboard__title"
|
||||
>{% trans "Offboarding Employees Feedbacks" %}</span
|
||||
>
|
||||
</div>
|
||||
<div class="oh-card-dashboard__body h-75 overflow-auto position-relative">
|
||||
{% if feedbacks %}
|
||||
<div
|
||||
class="oh-sticky-table__table"
|
||||
style="border: 1px solid hsl(213, 22%, 93%)"
|
||||
>
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Employee" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Feedback" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Status" %}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for feedback in feedbacks %}
|
||||
<div class="oh-sticky-table__tr oh-multiple-table-sort__movable">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<a href="">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img
|
||||
src="{{ feedback.employee_id.get_avatar }}"
|
||||
class="oh-profile__image"
|
||||
/>
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"
|
||||
>{{ feedback.employee_id.get_full_name}}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="oh-sticky-table__td"
|
||||
onclick="event.stopPropagation()"
|
||||
>
|
||||
{{feedback.review_cycle}}
|
||||
</div>
|
||||
<div
|
||||
class="oh-sticky-table__td fw-bold"
|
||||
onclick="event.stopPropagation()"
|
||||
>
|
||||
{{feedback.status}}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class= "oh-404">
|
||||
<img
|
||||
style="display: block; width: 120px; margin: 20px auto"
|
||||
src="{% static 'images/ui/feedback.png' %}"
|
||||
class=""
|
||||
/>
|
||||
<h3 style="font-size: 16px" class="oh-404__subtitle">
|
||||
{% trans "No feedbacks for Offboarding Employees." %}
|
||||
</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$("[data-toggle='oh-modal-toggle']").on("click", function () {
|
||||
var target = $(this).data("target");
|
||||
$(target).toggleClass("oh-modal--show");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,70 @@
|
||||
{% load static i18n offboarding_filter %}
|
||||
|
||||
<div class="oh-card-dashboard__header oh-card-dashboard__header--divider">
|
||||
<span class="oh-card-dashboard__title">{% trans "Task Status" %}</span>
|
||||
</div>
|
||||
<div class="oh-card-dashboard__body h-75 overflow-auto position-relative">
|
||||
{% if employees %}
|
||||
<div
|
||||
class="oh-sticky-table__table"
|
||||
style="border: 1px solid hsl(213, 22%, 93%)"
|
||||
>
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">{% trans "Employee" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Stage" %}</div>
|
||||
<div class="oh-sticky-table__th text-center">
|
||||
{% trans "Task Status" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for employee in employees %}
|
||||
<div class="oh-sticky-table__tr oh-multiple-table-sort__movable">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<a href="{% url 'employee-view-individual' employee.employee_id.id %}">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img
|
||||
src="{{ employee.employee_id.get_avatar }}"
|
||||
class="oh-profile__image"
|
||||
/>
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark"
|
||||
>{{ employee.employee_id.get_full_name }}</span
|
||||
>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="oh-sticky-table__td"
|
||||
onclick="event.stopPropagation()"
|
||||
>
|
||||
{{employee.stage_id}}
|
||||
</div>
|
||||
<div class="oh-sticky-table__td text-center">
|
||||
<div
|
||||
class="oh-checkpoint-badge oh-checkpoint-badge--secondary"
|
||||
title="Completed {{ employee.employeetask_set|completed_tasks }} of {{employee.employeetask_set.all|length}} tasks"
|
||||
>
|
||||
{{ employee.employeetask_set|completed_tasks }} /
|
||||
{{ employee.employeetask_set.all|length }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class= "oh-404">
|
||||
<img
|
||||
style="display: block; width: 120px; margin: 20px auto"
|
||||
src="{% static 'images/ui/conditions.png' %}"
|
||||
class=""
|
||||
/>
|
||||
<h3 style="font-size: 16px" class="oh-404__subtitle">
|
||||
{% trans "No Pending Tasks for Offboarding Employees." %}
|
||||
</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -112,7 +112,7 @@
|
||||
><ion-icon name="create-outline"></ion-icon
|
||||
></a>
|
||||
{% endif %}
|
||||
{% if employee.employee_id.get_archive_condition %}
|
||||
{% if employee.employee_id and employee.employee_id.get_archive_condition %}
|
||||
<a
|
||||
type="button"
|
||||
title="{% trans 'Show managing records' %}"
|
||||
|
||||
@@ -4,6 +4,7 @@ offboarding/urls.py
|
||||
This module is used to register url mappings to functions
|
||||
"""
|
||||
|
||||
from django.apps import apps
|
||||
from django.urls import path
|
||||
|
||||
from offboarding import views
|
||||
@@ -96,4 +97,42 @@ urlpatterns = [
|
||||
views.filter_pipeline,
|
||||
name="offboarding-pipeline-filter",
|
||||
),
|
||||
path(
|
||||
"dashboard",
|
||||
views.offboarding_dashboard,
|
||||
name="offboarding-dashboard",
|
||||
),
|
||||
path(
|
||||
"dashboard-task-table",
|
||||
views.dashboard_task_table,
|
||||
name="dashboard-task-table",
|
||||
),
|
||||
path(
|
||||
"dashboard-department-chart",
|
||||
views.department_job_postion_chart,
|
||||
name="dashboard-department-chart",
|
||||
),
|
||||
path(
|
||||
"dashboard-join-chart",
|
||||
views.dashboard_join_chart,
|
||||
name="dashboard-join-chart",
|
||||
),
|
||||
]
|
||||
|
||||
if apps.is_installed("asset"):
|
||||
urlpatterns += [
|
||||
path(
|
||||
"dashboard-asset-table",
|
||||
views.dashboard_asset_table,
|
||||
name="dashboard-asset-table",
|
||||
),
|
||||
]
|
||||
|
||||
if apps.is_installed("pms"):
|
||||
urlpatterns += [
|
||||
path(
|
||||
"dashboard-feedback-table",
|
||||
views.dashboard_feedback_table,
|
||||
name="dashboard-feedback-table",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -13,6 +13,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from base.context_processors import intial_notice_period
|
||||
from base.methods import closest_numbers, eval_validate, paginator_qry, sortby
|
||||
from base.models import Department, JobPosition
|
||||
from base.views import general_settings
|
||||
from employee.models import Employee
|
||||
from horilla.decorators import (
|
||||
@@ -73,9 +74,7 @@ def pipeline_grouper(filters={}, offboardings=[]):
|
||||
all_stages_grouper.append({"grouper": stage, "list": []})
|
||||
stage_employees = PipelineEmployeeFilter(
|
||||
filters,
|
||||
OffboardingEmployee.objects.filter(
|
||||
stage_id=stage, employee_id__is_active=True
|
||||
),
|
||||
OffboardingEmployee.objects.filter(stage_id=stage),
|
||||
).qs.order_by("stage_id__id")
|
||||
page_name = "page" + stage.title + str(offboarding.id)
|
||||
employee_grouper = group_by(
|
||||
@@ -997,3 +996,206 @@ def get_notice_period_end_date(request):
|
||||
"end_date": end_date,
|
||||
}
|
||||
return JsonResponse(response)
|
||||
|
||||
|
||||
@login_required
|
||||
@any_manager_can_enter(
|
||||
perm=[
|
||||
"offboarding.view_offboarding",
|
||||
"offboarding.view_offboardingtask",
|
||||
"offboarding.view_offboardingemployee",
|
||||
]
|
||||
)
|
||||
def offboarding_dashboard(request):
|
||||
"""
|
||||
This method is used to render the offboarding dashboard page.
|
||||
"""
|
||||
|
||||
onboarding_employees = []
|
||||
if apps.is_installed("recruitment"):
|
||||
Candidate = get_horilla_model_class("recruitment", "candidate")
|
||||
onboarding_employees = Candidate.objects.filter(
|
||||
onboarding_stage__isnull=False, converted_employee_id__isnull=True
|
||||
)
|
||||
|
||||
employees = Employee.objects.entire()
|
||||
offboarding_employees = OffboardingEmployee.objects.entire()
|
||||
archived_employees = offboarding_employees.filter(stage_id__type="archived")
|
||||
resigning_employees = employees.filter(resignationletter__isnull=False).exclude(
|
||||
offboardingemployee__stage_id__type="archived"
|
||||
)
|
||||
|
||||
exit_ratio = (
|
||||
(archived_employees.count() / employees.count()) if employees.count() > 0 else 0
|
||||
)
|
||||
|
||||
context = {
|
||||
"exit_ratio": round(exit_ratio, 4),
|
||||
"employees": employees,
|
||||
"archived_employees": archived_employees,
|
||||
"resigning_employees": resigning_employees,
|
||||
"onboarding_employees": len(onboarding_employees),
|
||||
}
|
||||
return render(request, "offboarding/dashboard/dashboard.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
@any_manager_can_enter(
|
||||
["offboarding.view_offboarding", "offboarding.view_offboardingtask"]
|
||||
)
|
||||
def dashboard_task_table(request):
|
||||
"""
|
||||
This method is used to render the employee task table page in the dashboard.
|
||||
"""
|
||||
|
||||
employees = OffboardingEmployee.objects.entire()
|
||||
return render(
|
||||
request,
|
||||
"offboarding/dashboard/employee_task_table.html",
|
||||
{
|
||||
"employees": employees,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
if apps.is_installed("asset"):
|
||||
|
||||
@login_required
|
||||
@any_manager_can_enter(["offboarding.view_offboarding"])
|
||||
def dashboard_asset_table(request):
|
||||
"""
|
||||
This method is used to render the employee assets table page in the dashboard.
|
||||
"""
|
||||
AssetAssignment = get_horilla_model_class(
|
||||
app_label="asset", model="assetassignment"
|
||||
)
|
||||
|
||||
offboarding_employees = OffboardingEmployee.objects.entire().values_list(
|
||||
"employee_id__id", flat=True
|
||||
)
|
||||
assets = AssetAssignment.objects.entire().filter(
|
||||
return_status__isnull=True,
|
||||
assigned_to_employee_id__in=offboarding_employees,
|
||||
)
|
||||
return render(
|
||||
request,
|
||||
"offboarding/dashboard/asset_returned_table.html",
|
||||
{"assets": assets},
|
||||
)
|
||||
|
||||
|
||||
if apps.is_installed("pms"):
|
||||
|
||||
@login_required
|
||||
@any_manager_can_enter("offboarding.view_offboarding")
|
||||
def dashboard_feedback_table(request):
|
||||
"""
|
||||
This method is used to render the employee assets table page in the dashboard.
|
||||
"""
|
||||
|
||||
Feedback = get_horilla_model_class(app_label="pms", model="feedback")
|
||||
|
||||
offboarding_employees = OffboardingEmployee.objects.entire().values_list(
|
||||
"employee_id__id", "notice_period_starts"
|
||||
)
|
||||
|
||||
if offboarding_employees:
|
||||
id_list, date_list = map(list, zip(*offboarding_employees))
|
||||
else:
|
||||
id_list, date_list = [], []
|
||||
|
||||
feedbacks = (
|
||||
Feedback.objects.entire()
|
||||
.filter(employee_id__in=id_list)
|
||||
.exclude(status="Closed")
|
||||
)
|
||||
return render(
|
||||
request,
|
||||
"offboarding/dashboard/employee_feedback_table.html",
|
||||
{"feedbacks": feedbacks},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@any_manager_can_enter("offboarding.view_offboarding")
|
||||
def dashboard_join_chart(request):
|
||||
"""
|
||||
This method is used to render the joining - offboarding chart.
|
||||
"""
|
||||
|
||||
employees = Employee.objects.entire()
|
||||
offboarding_employees = OffboardingEmployee.objects.entire()
|
||||
archived_employees = offboarding_employees.filter(stage_id__type="archived")
|
||||
resigning_employees = employees.filter(resignationletter__isnull=False).exclude(
|
||||
offboardingemployee__stage_id__type="archived"
|
||||
)
|
||||
|
||||
labels = ["resigning", "archived"]
|
||||
items = [
|
||||
resigning_employees.count(),
|
||||
archived_employees.count(),
|
||||
]
|
||||
if apps.is_installed("recruitment"):
|
||||
Candidate = get_horilla_model_class(app_label="recruitment", model="candidate")
|
||||
onboarding_employees = Candidate.objects.filter(
|
||||
onboarding_stage__isnull=False, converted_employee_id__isnull=True
|
||||
)
|
||||
labels.append("New")
|
||||
items.append(onboarding_employees.count())
|
||||
|
||||
response = {
|
||||
"labels": labels,
|
||||
"items": items,
|
||||
}
|
||||
return JsonResponse(response)
|
||||
|
||||
|
||||
@login_required
|
||||
@any_manager_can_enter("offboarding.view_offboarding")
|
||||
def department_job_postion_chart(request):
|
||||
"""
|
||||
This method is used to render the department - job position chart.
|
||||
"""
|
||||
|
||||
departments = Department.objects.all()
|
||||
offboarding_employees = OffboardingEmployee.objects.entire()
|
||||
|
||||
selected_departments = [
|
||||
dept
|
||||
for dept in departments
|
||||
if offboarding_employees.filter(
|
||||
employee_id__employee_work_info__department_id=dept.id
|
||||
).exists()
|
||||
]
|
||||
|
||||
job_positions = JobPosition.objects.filter(
|
||||
id__in=offboarding_employees.values(
|
||||
"employee_id__employee_work_info__job_position_id"
|
||||
).distinct()
|
||||
)
|
||||
|
||||
labels = [dept.department for dept in selected_departments]
|
||||
|
||||
datasets = []
|
||||
for job in job_positions:
|
||||
job_dept = job.department_id
|
||||
if job_dept not in selected_departments:
|
||||
continue
|
||||
|
||||
data = [0] * len(selected_departments)
|
||||
dept_index = labels.index(job_dept.department)
|
||||
|
||||
count = offboarding_employees.filter(
|
||||
employee_id__employee_work_info__job_position_id=job.id
|
||||
).count()
|
||||
data[dept_index] = count
|
||||
|
||||
datasets.append(
|
||||
{
|
||||
"label": f"{job.job_position} ({job_dept.department})",
|
||||
"data": data,
|
||||
"backgroundColor": f"hsl({hash(job.job_position) % 360}, 70%, 50%, 0.6)",
|
||||
}
|
||||
)
|
||||
|
||||
return JsonResponse({"labels": labels, "datasets": datasets})
|
||||
|
||||
Reference in New Issue
Block a user