[UPDT] OFFBOARDING: Dynamic grouper in offboarding
This commit is contained in:
@@ -3,10 +3,17 @@ offboarding/filters.py
|
||||
|
||||
This module is used to register django_filters
|
||||
"""
|
||||
|
||||
import uuid
|
||||
import django_filters
|
||||
from django import forms
|
||||
from base.filters import FilterSet
|
||||
from offboarding.models import ResignationLetter
|
||||
from offboarding.models import (
|
||||
Offboarding,
|
||||
OffboardingEmployee,
|
||||
OffboardingStage,
|
||||
ResignationLetter,
|
||||
)
|
||||
|
||||
|
||||
class LetterFilter(FilterSet):
|
||||
@@ -30,3 +37,98 @@ class LetterFilter(FilterSet):
|
||||
"employee_id__employee_work_info__job_position_id",
|
||||
"employee_id__employee_work_info__reporting_manager_id",
|
||||
]
|
||||
|
||||
|
||||
class PipelineFilter(FilterSet):
|
||||
"""
|
||||
PipelineFilter
|
||||
"""
|
||||
|
||||
search = django_filters.CharFilter(method="search_method", lookup_expr="icontains")
|
||||
|
||||
class Meta:
|
||||
model = Offboarding
|
||||
fields = "__all__"
|
||||
|
||||
def search_method(self, queryset, _, value):
|
||||
"""
|
||||
This method is used to add custom search condition
|
||||
"""
|
||||
return (
|
||||
queryset.filter(title__icontains=value)
|
||||
| queryset.filter(offboardingstage__title__icontains=value)
|
||||
| queryset.filter(
|
||||
offboardingstage__offboardingemployee__employee_id__employee_first_name__icontains=value
|
||||
)
|
||||
).distinct()
|
||||
|
||||
|
||||
class PipelineStageFilter(FilterSet):
|
||||
"""
|
||||
PipelineStageFilter
|
||||
"""
|
||||
|
||||
search = django_filters.CharFilter(method="search_method", lookup_expr="icontains")
|
||||
|
||||
class Meta:
|
||||
model = OffboardingStage
|
||||
fields = "__all__"
|
||||
exclude = [
|
||||
"sequence",
|
||||
]
|
||||
|
||||
def search_method(self, queryset, _, value):
|
||||
"""
|
||||
This method is used to add custom search condition
|
||||
"""
|
||||
|
||||
return (
|
||||
queryset.filter(title__icontains=value)
|
||||
| queryset.filter(
|
||||
offboardingemployee__employee_id__employee_first_name__icontains=value
|
||||
)
|
||||
| queryset.filter(offboarding_id__title__icontains=value)
|
||||
).distinct()
|
||||
|
||||
|
||||
class PipelineEmployeeFilter(FilterSet):
|
||||
"""
|
||||
PipelineEmployeeFilter
|
||||
"""
|
||||
|
||||
search = django_filters.CharFilter(method="search_method", lookup_expr="icontains")
|
||||
|
||||
notice_period_starts = django_filters.DateFilter(
|
||||
field_name="notice_period_starts",
|
||||
lookup_expr="gte",
|
||||
widget=forms.DateInput(attrs={"type": "date"}),
|
||||
)
|
||||
notice_period_ends = django_filters.DateFilter(
|
||||
field_name="notice_period_ends",
|
||||
lookup_expr="lte",
|
||||
widget=forms.DateInput(attrs={"type": "date"}),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = OffboardingEmployee
|
||||
fields = [
|
||||
"stage_id",
|
||||
"employee_id__gender",
|
||||
"employee_id__employee_work_info__department_id",
|
||||
"employee_id__employee_work_info__job_position_id",
|
||||
"employee_id__employee_work_info__job_role_id",
|
||||
"employee_id__employee_work_info__employee_type_id",
|
||||
"employee_id__employee_work_info__shift_id",
|
||||
"employee_id__employee_work_info__work_type_id",
|
||||
]
|
||||
|
||||
|
||||
def search_method(self, queryset, _, value):
|
||||
"""
|
||||
This method is used to add custom search condition
|
||||
"""
|
||||
return (
|
||||
queryset.filter(employee_id__employee_first_name__icontains=value)
|
||||
| queryset.filter(stage_id__title__icontains=value)
|
||||
| queryset.filter(stage_id__offboarding_id__title__icontains=value)
|
||||
).distinct()
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
{% load i18n %}<div class="oh-dropdown" x-data="{open: false}">
|
||||
<button type="button" class="oh-btn ml-2" @click="open = !open">
|
||||
<ion-icon name="filter" class="mr-1"></ion-icon>{% trans "Filter" %}
|
||||
</button>
|
||||
<div
|
||||
class="oh-dropdown__menu oh-dropdown__menu--right oh-dropdown__filter p-4"
|
||||
x-show="open"
|
||||
@click.outside="open = false"
|
||||
>
|
||||
<div class="oh-dropdown__filter-body">
|
||||
<div class="oh-accordion">
|
||||
<div class="oh-accordion-header">
|
||||
{% trans 'Employee' %}
|
||||
</div>
|
||||
<div class="oh-accordion-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Notice Period Starts' %} (>=)</label>
|
||||
{{employee_filter.form.notice_period_starts}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Notice Period Ends' %} (<=)</label>
|
||||
{{employee_filter.form.notice_period_ends}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Department' %}</label>
|
||||
{{employee_filter.form.employee_id__employee_work_info__department_id}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Job Position' %}</label>
|
||||
{{employee_filter.form.employee_id__employee_work_info__job_position_id}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Job Role' %}</label>
|
||||
{{employee_filter.form.employee_id__employee_work_info__job_role_id}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Employee Type' %}</label>
|
||||
{{employee_filter.form.employee_id__employee_work_info__employee_type_id}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Shift' %}</label>
|
||||
{{employee_filter.form.employee_id__employee_work_info__shift_id}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Work Type' %}</label>
|
||||
{{employee_filter.form.employee_id__employee_work_info__work_type_id}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-accordion">
|
||||
<div class="oh-accordion-header">
|
||||
{% trans 'Offboarding' %}
|
||||
</div>
|
||||
<div class="oh-accordion-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Managers' %}</label>
|
||||
{{pipeline_filter.form.managers}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Status' %}</label>
|
||||
{{pipeline_filter.form.status}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-accordion">
|
||||
<div class="oh-accordion-header">
|
||||
{% trans 'Stage' %}
|
||||
</div>
|
||||
<div class="oh-accordion-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Offboarding' %}</label>
|
||||
{{stage_filter.form.offboarding_id}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 col-lg-6 mb-1">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label">{% trans 'Status' %}</label>
|
||||
{{stage_filter.form.type}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-dropdown__filter-footer">
|
||||
<button class="oh-btn oh-btn--secondary oh-btn--small w-100 filterButton">{% trans 'Filter' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
<h1 class="oh-main__titlebar-title fw-bold">{% trans 'Offboarding' %}</h1>
|
||||
</div>
|
||||
|
||||
<div class="oh-main__titlebar oh-main__titlebar--right oh-d-flex-column--resp oh-mb-3--small">
|
||||
<form onsubmit="event.preventDefault()" hx-target="#offboardingContainer" hx-get="{% url 'offboarding-pipeline-filter' %}" class="oh-main__titlebar oh-main__titlebar--right oh-d-flex-column--resp oh-mb-3--small" >
|
||||
<div class="oh-input-group oh-input__search-group mr-4">
|
||||
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left md hydrated" role="img" aria-label="search outline"></ion-icon>
|
||||
<input name="search" id="pipelineSearch" hx-target="#offboardingContainer" type="text" placeholder="Search" style="margin-right:10px" class="oh-input oh-input__icon mr-3" autocomplete="false" aria-label="Search Input" />
|
||||
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left md hydrated" role="img" aria-label="search outline"></ion-icon>
|
||||
<input name="search" onkeyup="$('#hiddenSubmit').click()" id="pipelineSearch" type="text" placeholder="Search" style="margin-right:10px" class="oh-input oh-input__icon mr-3" autocomplete="false" aria-label="Search Input" />
|
||||
</div>
|
||||
<input type="submit" id="hiddenSubmit" hidden>
|
||||
{% include 'offboarding/pipeline/filter.html' %}
|
||||
{% if perms.offboarding.add_offboarding %}
|
||||
<div class="oh-main__titlebar-button-container">
|
||||
@@ -20,7 +21,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<div class="oh-modal" id="offboardingModal" role="dialog" aria-hidden="true">
|
||||
|
||||
@@ -19,18 +19,55 @@
|
||||
}
|
||||
|
||||
</style>
|
||||
{% include "filter_tags.html" %}
|
||||
<script>
|
||||
function switchTab(e) {
|
||||
let parentContainerEl = e.target.closest(".oh-tabs");
|
||||
let tabElement = e.target.closest(".oh-tabs__tab");
|
||||
|
||||
|
||||
let targetSelector = e.target.dataset.target;
|
||||
let targetEl = parentContainerEl
|
||||
? parentContainerEl.querySelector(targetSelector)
|
||||
: null;
|
||||
|
||||
// Highlight active tabs
|
||||
if (tabElement && !tabElement.classList.contains("oh-tabs__tab--active")) {
|
||||
parentContainerEl
|
||||
.querySelectorAll(".oh-tabs__tab--active")
|
||||
.forEach(function (item) {
|
||||
item.classList.remove("oh-tabs__tab--active");
|
||||
});
|
||||
|
||||
if (!tabElement.classList.contains("oh-tabs__new-tab")) {
|
||||
tabElement.classList.add("oh-tabs__tab--active");
|
||||
}
|
||||
}
|
||||
|
||||
// Switch tabs
|
||||
if (targetEl && !targetEl.classList.contains("oh-tabs__content--active")) {
|
||||
parentContainerEl
|
||||
.querySelectorAll(".oh-tabs__content--active")
|
||||
.forEach(function (item) {
|
||||
item.classList.remove("oh-tabs__content--active");
|
||||
});
|
||||
targetEl.classList.add("oh-tabs__content--active");
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<div id="messages" class="oh-alert-container"></div>
|
||||
<div class="oh-wrapper">
|
||||
<div class="oh-tabs">
|
||||
<div class="oh-tabs" onclick="switchTab(event)">
|
||||
<ul class="oh-tabs__tablist">
|
||||
{% for offboarding in offboardings %}
|
||||
{% if perms.offboarding.view_offboarding or request.user.employee_get|is_in_offboarding:offboarding %}
|
||||
<li class="oh-tabs__tab" onclick="localStorage.setItem('activeTabOffboarding',$(this).attr('data-target'));" data-target="#Offboarding{{ offboarding.id }}">
|
||||
{{ offboarding.title }}
|
||||
<li class="oh-tabs__tab" onclick="localStorage.setItem('activeTabOffboarding',$(this).attr('data-target'));" data-target="#Offboarding{{ offboarding.offboarding.id }}">
|
||||
{{ offboarding.offboarding.title }}
|
||||
<div class="d-flex">
|
||||
<div class="oh-tabs__input-badge-container">
|
||||
<span class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2" id="recruitmentCandidateCount1" title="{{ offboarding.offboardingstage_set.all|length }} Stages" onclick="event.stopPropagation()">
|
||||
{{ offboarding.offboardingstage_set.all|length }}
|
||||
<span class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2" id="recruitmentCandidateCount1" title="{{ offboarding.offboarding.stages|length }} Stages" onclick="event.stopPropagation()">
|
||||
{{ offboarding.offboarding.stages|length }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="oh-dropdown" x-data="{open: false}">
|
||||
@@ -41,12 +78,12 @@
|
||||
<ul class="oh-dropdown__items">
|
||||
{% if perms.offboarding.change_offboarding or request.user.employee_get|is_offboarding_manager %}
|
||||
<li class="oh-dropdown__item">
|
||||
<a hx-get="{% url "create-offboarding" %}?instance_id={{offboarding.id}}" hx-target="#offboardingModalBody" data-toggle="oh-modal-toggle" data-target="#offboardingModal" class="oh-dropdown__link">{% trans "Edit" %}</a>
|
||||
<a hx-get="{% url "create-offboarding" %}?instance_id={{offboarding.offboarding.id}}" hx-target="#offboardingModalBody" data-toggle="oh-modal-toggle" data-target="#offboardingModal" class="oh-dropdown__link">{% trans "Edit" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if perms.offboarding.delete_offboarding %}
|
||||
<li class="oh-dropdown__item">
|
||||
<form action="{% url "delete-offboarding" %}?id={{offboarding.id}}" onsubmit="return confirm('Are you sure you want to delete this offboarding?');" method="post">
|
||||
<form action="{% url "delete-offboarding" %}?id={{offboarding.offboarding.id}}" onsubmit="return confirm('Are you sure you want to delete this offboarding?');" method="post">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="oh-dropdown__link oh-dropdown__link--danger">
|
||||
{% trans "Delete" %}
|
||||
@@ -65,9 +102,9 @@
|
||||
<div class="oh-tabs__contents">
|
||||
{% for offboarding in offboardings %}
|
||||
{% if perms.offboarding.view_offboarding or request.user.employee_get|is_in_offboarding:offboarding %}
|
||||
<div class="oh-tabs__content" id="Offboarding{{ offboarding.id }}">
|
||||
<div class="oh-tabs__content" id="Offboarding{{ offboarding.offboarding.id }}">
|
||||
{% if perms.offboarding.add_offboardingstage or request.user.employee_get|any_manager %}
|
||||
<a hx-get="{% url 'create-offboarding-stage' %}?offboarding_id={{offboarding.id}}" style="width: 100px;" hx-target="#offboardingModalBody" data-toggle="oh-modal-toggle" data-target="#offboardingModal" class="mb-3 oh-btn oh-btn--secondary">
|
||||
<a hx-get="{% url 'create-offboarding-stage' %}?offboarding_id={{offboarding.offboarding.id}}" style="width: 100px;" hx-target="#offboardingModalBody" data-toggle="oh-modal-toggle" data-target="#offboardingModal" class="mb-3 oh-btn oh-btn--secondary">
|
||||
<ion-icon name="add-outline"></ion-icon>
|
||||
{% trans 'Stage' %}
|
||||
</a>
|
||||
|
||||
@@ -5,42 +5,13 @@
|
||||
background-color: rgba(255, 68, 0, 0.076);
|
||||
}
|
||||
</style>
|
||||
|
||||
{% include 'offboarding/pipeline/nav.html' %}
|
||||
{% include 'offboarding/pipeline/offboardings.html' %}
|
||||
<div id="offboardingContainer">
|
||||
{% include 'offboarding/pipeline/offboardings.html' %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#pipelineSearch').keyup(function (e) {
|
||||
e.preventDefault()
|
||||
var search = $(this).val().toLowerCase()
|
||||
$('[data-employee]').each(function () {
|
||||
var employeeFullName = $(this).attr('data-employee')
|
||||
if (employeeFullName.toLowerCase().includes(search)) {
|
||||
$(this).show()
|
||||
$(this).addClass('search-highlight')
|
||||
} else {
|
||||
$(this).hide()
|
||||
$(this).removeClass('search-highlight')
|
||||
}
|
||||
})
|
||||
if (search == '') {
|
||||
$('.search-highlight').removeClass('search-highlight')
|
||||
$('[data-employee]').show()
|
||||
}
|
||||
$('[title="Toggle Archived"]').change()
|
||||
if (search != '') {
|
||||
$('#filterTagContainerSectionNav').html('')
|
||||
$('#filterTagContainerSectionNav').append(
|
||||
'<span class="oh-titlebar__tag filter-field pipelineSearch">Search :' +
|
||||
search +
|
||||
`<button class="oh-titlebar__tag-close" onclick="$('#pipelineSearch').val('');$('#pipelineSearch').keyup()">
|
||||
<ion-icon name="close-outline">
|
||||
</ion-icon>
|
||||
</button>
|
||||
</span>`
|
||||
)
|
||||
} else {
|
||||
$('#filterTagContainerSectionNav').html('')
|
||||
}
|
||||
})
|
||||
// intial select notice period starts and end
|
||||
function intialNoticePeriod($element) {
|
||||
let employeeId = $element.val()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{% load i18n offboarding_filter %}
|
||||
{% for stage in offboarding.offboardingstage_set.all %}
|
||||
{% for stage in offboarding.offboarding.stages %}
|
||||
<div class="oh-accordion-meta" id="accordion{{stage.id}}">
|
||||
<div class="oh-accordion-meta__item">
|
||||
<div class="oh-accordion-meta__header oh-accordion-meta__header--show">
|
||||
<div class="oh-accordion-meta__header {% if stage.grouper.type != "archived" or not stage.list|length %} oh-accordion-meta__header--show" {% endif %}>
|
||||
<span class="oh-accordion-meta__title" data-offboarding-id="{{offboarding.id}}">
|
||||
<span class="d-flex" onclick="event.stopPropagation()">
|
||||
<span class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2"
|
||||
id="offboardingBadge{{offboarding.id}}_{{forloop.counter}}" title="{{stage.offboardingemployee_set.all|length}} {% trans "Employees" %}" onclick="event.stopPropagation()">
|
||||
{{ stage.offboardingemployee_set.all|length }}
|
||||
id="offboardingBadge{{offboarding.id}}_{{forloop.counter}}" title="{{stage.list|length}} {% trans "Employees" %}" onclick="event.stopPropagation()">
|
||||
{{ stage.list|length }}
|
||||
</span>
|
||||
{{stage.title}}
|
||||
{% if stage.is_archived_stage %}
|
||||
{{stage.grouper.title}}
|
||||
{% if stage.grouper.is_archived_stage %}
|
||||
<div class="oh-switch ml-2">
|
||||
<input type="checkbox" class="show-archived oh-switch__checkbox" title="{% trans "Toggle Archived" %}" onchange="showArchived($(this))">
|
||||
</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
<ul class="oh-dropdown__items">
|
||||
{% if perms.offboarding.add_offboardingemployee or request.user.employee_get|any_manager %}
|
||||
<li class="oh-dropdown__item">
|
||||
<a hx-get="{% url "add-employee" %}?stage_id={{stage.id}}" data-target="#offboardingModal"
|
||||
<a hx-get="{% url "add-employee" %}?stage_id={{stage.grouper.id}}" data-target="#offboardingModal"
|
||||
data-toggle="oh-modal-toggle" hx-target="#offboardingModalBody" class="oh-dropdown__link">
|
||||
{% trans "Add Employee" %}</a>
|
||||
</li>
|
||||
@@ -36,14 +36,14 @@
|
||||
{% if perms.offboarding.change_offboardingstage or request.user.employee_get|is_offboarding_manager %}
|
||||
<li class="oh-dropdown__item">
|
||||
<a
|
||||
hx-get="{% url "create-offboarding-stage" %}?offboarding_id={{offboarding.id}}&instance_id={{stage.id}}"
|
||||
hx-get="{% url "create-offboarding-stage" %}?offboarding_id={{offboarding.offboarding.id}}&instance_id={{stage.grouper.id}}"
|
||||
data-target="#offboardingModal"
|
||||
data-toggle="oh-modal-toggle" hx-target="#offboardingModalBody" class="oh-dropdown__link">{% trans "Edit" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if perms.offboarding.delete_offboarding %}
|
||||
<li class="oh-dropdown__item">
|
||||
<a href="{% url "delete-offboarding-stage" %}?ids={{stage.id}}"
|
||||
<a href="{% url "delete-offboarding-stage" %}?ids={{stage.grouper.id}}"
|
||||
onclick="return confirm('Are you sure want to delete this stage?')"
|
||||
class="oh-dropdown__link oh-dropdown__link--danger">{% trans "Delete" %}</a>
|
||||
</li>
|
||||
@@ -53,7 +53,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-accordion-meta__body">
|
||||
<div class="oh-accordion-meta__body {% if stage.grouper.type == "archived" or not stage.list|length %} d-none {% endif %}">
|
||||
<div class="oh-sticky-table oh-sticky-table--no-overflow mb-5">
|
||||
<div class="oh-sticky-table__table">
|
||||
<div class="oh-sticky-table__thead">
|
||||
@@ -66,8 +66,8 @@
|
||||
<div class="oh-sticky-table__th">{% trans "Stage" %}</div>
|
||||
{% endif %}
|
||||
<div class="oh-sticky-table__th">{% trans "Actions" %}</div>
|
||||
{% for task in stage.offboardingtask_set.all %}
|
||||
<div class="oh-sticky-table__th" style="width: 200px;" hx-get="{% url "offboarding-add-task" %}?stage_id={{stage.id}}&instance_id={{task.id}}" hx-target="#offboardingModalBody" data-toggle="oh-modal-toggle" data-target="#offboardingModal">
|
||||
{% for task in stage.grouper.offboardingtask_set.all %}
|
||||
<div class="oh-sticky-table__th" style="width: 200px;" hx-get="{% url "offboarding-add-task" %}?stage_id={{stage.grouper.id}}&instance_id={{task.id}}" hx-target="#offboardingModalBody" data-toggle="oh-modal-toggle" data-target="#offboardingModal">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span title="Click to edit">
|
||||
{{task.title}}
|
||||
@@ -80,14 +80,14 @@
|
||||
{% endfor %}
|
||||
<div class="oh-sticky-table__th" style="width: 120px;">
|
||||
{% if perms.offboarding.add_offboardingtask or request.user.employee_get|any_manager %}
|
||||
<button class="oh-checkpoint-badge text-success" data-toggle="oh-modal-toggle" data-target="#offboardingModal" hx-get="{% url "offboarding-add-task" %}?stage_id={{stage.id}}" hx-target="#offboardingModalBody">
|
||||
<button class="oh-checkpoint-badge text-success" data-toggle="oh-modal-toggle" data-target="#offboardingModal" hx-get="{% url "offboarding-add-task" %}?stage_id={{stage.grouper.id}}" hx-target="#offboardingModalBody">
|
||||
{% trans "Add Task" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody" id="tableBody{{stage.id}}" data-stage-id="{{stage.id}}" data-archive-stage="{{stage.is_archived_stage|lower}}" data-offboarding-id="{{offboarding.id}}">
|
||||
<div class="oh-sticky-table__tbody" id="tableBody{{stage.grouper.id}}" data-stage-id="{{stage.grouper.id}}" data-archive-stage="{{stage.grouper.is_archived_stage|lower}}" data-offboarding-id="{{offboarding.offboarding.id}}">
|
||||
{% include "offboarding/task/table_body.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
submitButton.click()
|
||||
}
|
||||
</script>
|
||||
<div class="oh-card" id="offboardingBody{{offboarding.id}}">
|
||||
<div class="oh-card" id="offboardingBody{{offboarding.offboarding.id}}">
|
||||
{% include "offboarding/stage/offboarding_body.html" %}
|
||||
</div>
|
||||
<div class="oh-activity-sidebar" id="activitySidebar">
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
{{response_message}}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %} {% for employee in stage.offboardingemployee_set.all %}
|
||||
{% if perms.offboarding.view_offboarding or request.user.employee_get|is_in_managers:offboarding or request.user.employee_get|is_in_managers:stage or request.user.employee_get|is_in_managers:employee %}
|
||||
{% endif %} {% for employee in stage.list %}
|
||||
{% if perms.offboarding.view_offboarding or request.user.employee_get|is_in_managers:offboarding.offboarding or request.user.employee_get|is_in_managers:stage.grouper or request.user.employee_get|is_in_managers:employee %}
|
||||
<div
|
||||
class="oh-sticky-table__tr oh-multiple-table-sort__movable"
|
||||
data-employee="{{employee.employee_id.get_full_name}}"
|
||||
@@ -36,8 +36,8 @@
|
||||
{% if request.user.employee_get|is_any_stage_manager or perms.offboarding.change_offboarding or perms.offboarding.change_offboardingemployee %}
|
||||
<div class="oh-sticky-table__td" onclick="event.stopPropagation()">
|
||||
<form hx-get="{% url "offboarding-change-stage" %}?employee_ids={{employee.id}}"
|
||||
hx-target="#offboardingBody{{offboarding.id}}">
|
||||
{{ stage_forms|stages:stage }}
|
||||
hx-target="#offboardingBody{{offboarding.offboarding.id}}">
|
||||
{{ stage_forms|stages:employee.stage_id }}
|
||||
<input type="submit" hidden />
|
||||
</form>
|
||||
</div>
|
||||
@@ -82,7 +82,7 @@
|
||||
{% else %}
|
||||
<a
|
||||
type="button"
|
||||
hx-get="{% url "add-employee" %}?instance_id={{employee.id}}&stage_id={{stage.id}}"
|
||||
hx-get="{% url "add-employee" %}?instance_id={{employee.id}}&stage_id={{stage.grouper.id}}"
|
||||
hx-target="#offboardingModalBody"
|
||||
data-toggle="oh-modal-toggle"
|
||||
data-target="#offboardingModal"
|
||||
@@ -105,13 +105,13 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% for task in stage.offboardingtask_set.all %}
|
||||
{% for task in stage.grouper.offboardingtask_set.all %}
|
||||
<div class="oh-sticky-table__td">
|
||||
{% if task|have_task:employee %}
|
||||
{% for assinged_tasks in employee|get_assigned_task:task %}
|
||||
<select
|
||||
hx-get="{% url "update-task-status" %}?stage_id={{stage.id}}&employee_ids={{employee.id}}&task_id={{assinged_tasks.task_id.id}}"
|
||||
hx-target="#offboardingBody{{offboarding.id}}"
|
||||
hx-get="{% url "update-task-status" %}?stage_id={{stage.grouper.id}}&employee_ids={{employee.id}}&task_id={{assinged_tasks.task_id.id}}"
|
||||
hx-target="#offboardingBody{{offboarding.offboarding.id}}"
|
||||
name="task_status"
|
||||
id="task_status{{assinged_tasks.id}}"
|
||||
class="oh-select-custom w-100"
|
||||
|
||||
@@ -3,6 +3,7 @@ offboarding/urls.py
|
||||
|
||||
This module is used to register url mappings to functions
|
||||
"""
|
||||
|
||||
from django.urls import path
|
||||
from offboarding import views
|
||||
|
||||
@@ -66,4 +67,5 @@ urlpatterns = [
|
||||
name="enable-resignation-request",
|
||||
),
|
||||
path("get-notice-period", views.get_notice_period, name="get-notice-period"),
|
||||
path("offboarding-pipeline-filter",views.filter_pipeline,name="offboarding-pipeline-filter")
|
||||
]
|
||||
|
||||
@@ -14,7 +14,12 @@ from offboarding.decorators import (
|
||||
offboarding_manager_can_enter,
|
||||
offboarding_or_stage_manager_can_enter,
|
||||
)
|
||||
from offboarding.filters import LetterFilter
|
||||
from offboarding.filters import (
|
||||
LetterFilter,
|
||||
PipelineEmployeeFilter,
|
||||
PipelineFilter,
|
||||
PipelineStageFilter,
|
||||
)
|
||||
from offboarding.forms import (
|
||||
NoteForm,
|
||||
OffboardingEmployeeForm,
|
||||
@@ -37,13 +42,53 @@ from offboarding.models import (
|
||||
)
|
||||
from notifications.signals import notify
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from onboarding.filters import OnboardingStageFilter
|
||||
|
||||
from payroll.models.models import Contract
|
||||
from recruitment.pipeline_grouper import group_by_queryset
|
||||
|
||||
|
||||
# Create your views here.
|
||||
|
||||
|
||||
def pipeline_grouper(filters={}, offboardings=[]):
|
||||
groups = []
|
||||
for offboarding in offboardings:
|
||||
stages = PipelineStageFilter(
|
||||
filters, queryset=offboarding.offboardingstage_set.all()
|
||||
).qs.order_by("id")
|
||||
all_stages_grouper = []
|
||||
data = {"offboarding": offboarding, "stages": []}
|
||||
for stage in stages:
|
||||
all_stages_grouper.append({"grouper": stage, "list": []})
|
||||
stage_employees = PipelineEmployeeFilter(
|
||||
filters,
|
||||
OffboardingEmployee.objects.filter(stage_id=stage).order_by("-id"),
|
||||
).qs
|
||||
page_name = "page" + stage.title + str(offboarding.id)
|
||||
grouper = group_by_queryset(
|
||||
stage_employees,
|
||||
"stage_id",
|
||||
filters.get(page_name),
|
||||
page_name,
|
||||
).object_list
|
||||
data["stages"] = data["stages"] + grouper
|
||||
|
||||
existing_grouper_ids = list({item["grouper"].id for item in data["stages"]})
|
||||
for item in all_stages_grouper:
|
||||
if item["grouper"].id not in existing_grouper_ids:
|
||||
data["stages"].append(
|
||||
{
|
||||
"grouper": item["grouper"],
|
||||
"list": [],
|
||||
"dynamic_name": f'dynamic_page_page{item["grouper"].id}',
|
||||
}
|
||||
)
|
||||
|
||||
groups.append(data)
|
||||
return groups
|
||||
|
||||
|
||||
@login_required
|
||||
@any_manager_can_enter(
|
||||
"offboarding.view_offboarding", offboarding_employee_can_enter=True
|
||||
@@ -52,14 +97,49 @@ def pipeline(request):
|
||||
"""
|
||||
Offboarding pipleine view
|
||||
"""
|
||||
offboardings = Offboarding.objects.all()
|
||||
offboardings = PipelineFilter().qs
|
||||
groups = pipeline_grouper({}, offboardings)
|
||||
for item in groups:
|
||||
setattr(item["offboarding"], "stages", item["stages"])
|
||||
stage_forms = {}
|
||||
for offboarding in offboardings:
|
||||
stage_forms[str(offboarding.id)] = StageSelectForm(offboarding=offboarding)
|
||||
filter_dict = parse_qs(request.GET.urlencode())
|
||||
return render(
|
||||
request,
|
||||
"offboarding/pipeline/pipeline.html",
|
||||
{
|
||||
"offboardings": groups,
|
||||
"employee_filter": PipelineEmployeeFilter(),
|
||||
"pipeline_filter": PipelineFilter(),
|
||||
"stage_filter": PipelineStageFilter(),
|
||||
"stage_forms": stage_forms,
|
||||
"filter_dict": filter_dict,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("offboarding_view_offboardingemployee")
|
||||
def filter_pipeline(request):
|
||||
"""
|
||||
This method is used filter offboarding process
|
||||
"""
|
||||
offboardings = PipelineFilter(request.GET).qs
|
||||
groups = pipeline_grouper(request.GET, offboardings)
|
||||
for item in groups:
|
||||
setattr(item["offboarding"], "stages", item["stages"])
|
||||
stage_forms = {}
|
||||
for offboarding in offboardings:
|
||||
stage_forms[str(offboarding.id)] = StageSelectForm(offboarding=offboarding)
|
||||
return render(
|
||||
request,
|
||||
"offboarding/pipeline/pipeline.html",
|
||||
{"offboardings": offboardings, "stage_forms": stage_forms},
|
||||
"offboarding/pipeline/offboardings.html",
|
||||
{
|
||||
"offboardings": groups,
|
||||
"stage_forms": stage_forms,
|
||||
"filter_dict": parse_qs(request.GET.urlencode()),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -239,11 +319,14 @@ def change_stage(request):
|
||||
redirect="offboarding/offboarding-pipeline",
|
||||
icon="information",
|
||||
)
|
||||
groups = pipeline_grouper({}, [stage.offboarding_id])
|
||||
for item in groups:
|
||||
setattr(item["offboarding"], "stages", item["stages"])
|
||||
return render(
|
||||
request,
|
||||
"offboarding/stage/offboarding_body.html",
|
||||
{
|
||||
"offboarding": stage.offboarding_id,
|
||||
"offboarding": groups[0],
|
||||
"stage_forms": stage_forms,
|
||||
"response_message": _("stage changed successfully."),
|
||||
},
|
||||
@@ -406,11 +489,14 @@ def update_task_status(request, *args, **kwargs):
|
||||
stage_forms[str(stage.offboarding_id.id)] = StageSelectForm(
|
||||
offboarding=stage.offboarding_id
|
||||
)
|
||||
groups = pipeline_grouper({}, [stage.offboarding_id])
|
||||
for item in groups:
|
||||
setattr(item["offboarding"], "stages", item["stages"])
|
||||
return render(
|
||||
request,
|
||||
"offboarding/stage/offboarding_body.html",
|
||||
{
|
||||
"offboarding": stage.offboarding_id,
|
||||
"offboarding": groups[0],
|
||||
"stage_forms": stage_forms,
|
||||
"response_message": _("Task status changed successfully."),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user