[ADD] OFFBOARDING: Added group by to resignation letter

This commit is contained in:
Horilla
2024-02-26 20:03:58 +05:30
parent 3d1216412c
commit 5ca421c846
9 changed files with 1056 additions and 17 deletions

View File

@@ -132,3 +132,19 @@ class PipelineEmployeeFilter(FilterSet):
| queryset.filter(stage_id__title__icontains=value)
| queryset.filter(stage_id__offboarding_id__title__icontains=value)
).distinct()
class LetterReGroup(FilterSet):
"""
Class to keep the field name for group by option
"""
fields = [
("", "Select"),
("employee_id", "Employee"),
("planned_to_leave_on", "Planned to leave date"),
("status", "Status"),
("employee_id__employee_work_info__department_id", "Department"),
("employee_id__employee_work_info__job_position_id", "Job Position"),
("employee_id__employee_work_info__reporting_manager_id", "Reporting Manager"),
]

View File

@@ -9,6 +9,7 @@
x-show="open"
@click.outside="open = false"
>
<input type="hidden" name="view" id="filterView" value="">
<div class="oh-dropdown__filter-body">
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Resignation" %}</div>

View File

@@ -0,0 +1,353 @@
{% load attendancefilters %} {% load basefilters %} {% load static %}
{% load i18n %} {% include 'filter_tags.html' %}
{% comment %} {% if perms.base.view_worktyperequest %}
<div
class="oh-checkpoint-badge text-success mb-2"
id="selectAllWorktypes"
style="cursor: pointer"
>
{% trans "Select All Worktypes" %}
</div>
<div
class="oh-checkpoint-badge text-secondary mb-2"
id="unselectAllWorktypes"
style="cursor: pointer;display: none;"
>
{% trans "Unselect All Worktypes" %}
</div>
{% endif %}
<div
class="oh-checkpoint-badge text-info mb-2"
id="exportWorktypes"
style="cursor: pointer; display: none"
>
{% trans "Export Worktypes" %}
</div>
<div class="oh-checkpoint-badge text-danger mb-2" id="selectedShowWorktypes" style="display: none"></div> {% endcomment %}
<div class="oh-card oh-wrapper">
{% for letter_list in letters %}
<div class="oh-accordion-meta">
<div class="oh-accordion-meta__item">
<div class="oh-accordion-meta__header" onclick='$(this).toggleClass("oh-accordion-meta__header--show");'>
<span class="oh-accordion-meta__title pt-3 pb-3">
<div class="oh-tabs__input-badge-container">
<span
class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round mr-1"
>
{{letter_list.list.paginator.count}}
</span>
{{letter_list.grouper}}
</div>
</span>
</div>
<div class="oh-accordion-meta__body d-none">
<div class="oh-sticky-table oh-sticky-table--no-overflow mb-5">
<div class="oh-sticky-table__table oh-table--sortable">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div
class="oh-sticky-table__th {% if request.sort_option.order == '-employee_id__employee_first_name' %}arrow-up {% elif request.sort_option.order == 'employee_id__employee_first_name' %}arrow-down {% else %}arrow-up-down {% endif %}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&sortby=employee_id__employee_first_name"
hx-target="#resignationLetterContianer"
>
{% trans "Employee" %}
</div>
<div
data-cell-index="1"
data-cell-title="{% trans 'Title' %}"
class="oh-sticky-table__th {% if request.sort_option.order == '-title' %}arrow-up {% elif request.sort_option.order == 'title' %}arrow-down {% else %}arrow-up-down {% endif %}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&sortby=title"
hx-target="#resignationLetterContianer"
>
{% trans "Title" %}
</div>
<div
data-cell-index="2"
data-cell-title="{% trans 'Planned To Leave' %}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&sortby=planned_to_leave_on"
hx-target="#resignationLetterContianer"
class="oh-sticky-table__th {% if request.sort_option.order == '-planned_to_leave_on' %}arrow-up {% elif request.sort_option.order == 'planned_to_leave_on' %}arrow-down {% else %}arrow-up-down {% endif %}"
>
{% trans "Planned To Leave" %}
</div>
<div
data-cell-index="3"
data-cell-title="{% trans 'Status' %}"
class="oh-sticky-table__th {% if request.sort_option.order == '-status' %}arrow-up {% elif request.sort_option.order == 'status' %}arrow-down {% else %}arrow-up-down {% endif %}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&sortby=status"
hx-target="#resignationLetterContianer"
>
{% trans "Status" %}
</div>
<div
data-cell-index="4"
data-cell-title="{% trans 'Description' %}"
class="oh-sticky-table__th"
>
{% trans "Description" %}
</div>
<div class="oh-sticky-table__th oh-sticky-table__right">
{% trans "Actions" %}
</div>
</div>
</div>
{% for letter in letter_list.list %}
<div
class="oh-sticky-table__tbody ui-sortable"
draggable="true"
hx-get="{% url 'resignation-request-single-view' letter.id %}?requests_ids={{requests_ids}}"
hx-target="#resignationModalBody"
data-toggle="oh-modal-toggle"
data-target="#resignationModal"
>
<div class="oh-sticky-table__tr ui-sortable-handle">
<div class="oh-sticky-table__sd">
{{letter.employee_id}}
</div>
<div class="oh-sticky-table__td" data-cell-index="1">{{letter.title}}</div>
<div data-cell-index="2" class="oh-sticky-table__td">
{{letter.planned_to_leave_on}}
</div>
<div data-cell-index="3" class="oh-sticky-table__td">
{{letter.status}}
</div>
<div data-cell-index="4" class="oh-sticky-table__td">
{{letter.description|safe|truncatechars:30}}
</div>
<div class="oh-sticky-table__td oh-sticky-table__right">
<form action="{% url 'update-letter-status' %}">
{% if perms.offboarding.change_resignationletter %}
<div class="oh-btn-group">
{% if letter.status != "approved" %}
<button
title="By approving the request employee will added to the offboarding pipeline"
type="button"
onclick="$(this).closest('form').find('input[name=status]').val('approved');resignLetterConfirmation('{% trans 'Do You really want to approve the request' %}?',$(this).closest('form').find('[type=submit]'),true);"
class="oh-btn oh-btn--success w-100 oh-btn--block w-100"
>
<ion-icon
name="checkmark"
class="mr-1 md hydrated"
role="img"
aria-label="checkmark"
></ion-icon>
</button>
{% else %}
<button
type="button"
class="oh-btn oh-btn--success oh-btn--disabled oh-btn--block w-100"
>
<ion-icon
name="checkmark"
class="mr-1 md hydrated"
role="img"
aria-label="checkmark"
></ion-icon>
</button>
{% endif %}
<button
type="button"
onclick="$(this).closest('form').find('input[name=status]').val('rejected');resignLetterConfirmation('{% trans 'Do You really want to reject the request?' %}',$(this).closest('form').find('[type=submit]'));"
class="oh-btn oh-btn--danger oh-btn--block w-100"
>
<ion-icon
name="close-circle-outline"
class="mr-1 md hydrated"
role="img"
aria-label="close"
></ion-icon>
</button>
<input type="hidden" name="status" />
<input
type="hidden"
name="letter_ids"
value="{{letter.id}}"
/>
<input type="hidden" name="offboarding_id" />
<input type="hidden" name="notice_period_starts"
value="{% now "Y-m-d" %}"
id="notice_period_starts{{letter.id}}">
<input
type="hidden"
name="notice_period_ends"
id="notice_period_ends{{letter.id}}"
/>
<button type="submit" hidden></button>
</div>
{% endif %}
<input
type="submit"
hidden=""
id="requestCard1Button"
/>
</form>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="oh-pagination">
<span class="oh-pagination__page">
{% trans "Page" %} {{ letter_list.list.number }}
{%trans "of" %} {{letter_list.list.paginator.num_pages }}.
</span>
<nav class="oh-pagination__nav">
<div class="oh-pagination__input-container me-3">
<span class="oh-pagination__label me-1"
>{% trans "Page" %}</span
>
<input
type="number"
name="{{letter_list.dynamic_name}}"
class="oh-pagination__input"
value="{{letter_list.list.number}}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}"
hx-target="#resignationLetterContianer"
min="1"
/>
<span class="oh-pagination__label"
>{% trans "of" %}
{{letter_list.list.paginator.num_pages}}</span
>
</div>
<ul class="oh-pagination__items">
{% if letter_list.list.has_previous %}
<li
class="oh-pagination__item oh-pagination__item--wide"
>
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&{{letter_list.dynamic_name}}=1"
class="oh-pagination__link"
>{% trans "First" %}</a
>
</li>
<li
class="oh-pagination__item oh-pagination__item--wide"
>
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&{{letter_list.dynamic_name}}={{ letter_list.list.previous_page_number }}"
class="oh-pagination__link"
>{% trans "Previous" %}</a
>
</li>
{% endif %} {% if letter_list.list.has_next %}
<li
class="oh-pagination__item oh-pagination__item--wide"
>
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&{{letter_list.dynamic_name}}={{ letter_list.list.next_page_number }}"
class="oh-pagination__link"
>{% trans "Next" %}</a
>
</li>
<li
class="oh-pagination__item oh-pagination__item--wide"
>
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&{{letter_list.dynamic_name}}={{ letter_list.list.paginator.num_pages }}"
class="oh-pagination__link"
>{% trans "Last" %}</a
>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
</div>
</div>
{% endfor %}
<div class="oh-pagination">
<span class="oh-pagination__page">
{% trans "Page" %} {{ letters.number }} {% trans "of" %}
{{letters.paginator.num_pages }}.
</span>
<nav class="oh-pagination__nav">
<div class="oh-pagination__input-container me-3">
<span class="oh-pagination__label me-1"
>{% trans "Page" %}</span
>
<input
type="number"
name="page"
class="oh-pagination__input"
value="{{letters.number}}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list"
hx-target="#resignationLetterContianer"
min="1"
/>
<span class="oh-pagination__label"
>{% trans "of" %} {{letters.paginator.num_pages}}</span
>
</div>
<ul class="oh-pagination__items">
{% if letters.has_previous %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list&page=1"
class="oh-pagination__link"
>{% trans "First" %}</a
>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list&page={{ letters.previous_page_number }}"
class="oh-pagination__link"
>{% trans "Previous" %}</a
>
</li>
{% endif %} {% if letters.has_next %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list&page={{ letters.next_page_number }}"
class="oh-pagination__link"
>{% trans "Next" %}</a
>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list&page={{ letters.paginator.num_pages }}"
class="oh-pagination__link"
>{% trans "Last" %}</a
>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
{% comment %}
<!-- start of comment modal -->
<div
class="oh-modal"
id="WorktypecommentModal"
role="dialog"
aria-labelledby="emptagModal"
aria-hidden="true"
>
<div class="oh-modal__dialog">
<div class="oh-modal__dialog-header">
<h2 class="oh-modal__dialog-title" id="createModalTitle">
{% trans "Add Comment" %}
</h2>
<button class="oh-modal__close" aria-label="Close">
<ion-icon name="close-outline"></ion-icon>
</button>
</div>
<div class="oh-modal__dialog-body" id="WorktypeRequestCommentForm"></div>
</div>
</div>
<!-- end of comment modal -->
{% endcomment %}

View File

@@ -5,13 +5,79 @@
</div>
<div class="oh-main__titlebar oh-main__titlebar--right oh-d-flex-column--resp oh-mb-3--small">
<form class="oh-main__titlebar oh-main__titlebar--right oh-d-flex-column--resp oh-mb-3--small" hx-get="{% url 'search-resignation-request' %}" hx-target="#resignationLetterContianer">
<div class="oh-input-group oh-input__search-group"></div>
<div class="oh-input-group oh-input__search-group">
<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 onkeyup="$(this).closest('form').find('input[type=submit]').click()" name="search" id="pipelineSearch" hx-target="#offboardingContainer" type="text" placeholder="Search" style="margin-right:10px" class="oh-input oh-input__icon mr-3" aria-label="Search Input" />
</div>
<div class="oh-input-group oh-input__search-group">
<ul class="oh-view-types ml-2" style="margin-bottom: 0">
<li class="oh-view-type view-type" data-view="list">
<a
class="oh-btn oh-btn--view {% if request.GET.view == 'list' %} oh-btn--view-active {% endif %}"
title='{% trans "List" %}'
onclick="$('[name=view]').val('list');$('.filterButton')[0].click();"
>
<ion-icon
name="list-outline"
role="img"
class="md hydrated"
aria-label="list outline"
></ion-icon>
</a>
</li>
<li class="oh-view-type view-type" data-view="card">
<a
class="oh-btn oh-btn--view {% if request.GET.view != 'list' %} oh-btn--view-active {% endif %}"
title='{% trans "Card" %}'
onclick="$('[name=view]').val('card');$('.filterButton')[0].click();"
>
<ion-icon
name="grid-outline"
role="img"
class="md hydrated"
aria-label="grid outline"
></ion-icon>
</a>
</li>
</ul>
</div>
{% include 'offboarding/resignation/filter.html' %}
<input type="submit" hidden>
<input type="submit" hidden><div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn ml-2" @click="open = !open" onclick="event.preventDefault()">
<ion-icon name="library-outline" class="mr-1"></ion-icon>{% trans "Group By" %}
</button>
<div
class="oh-dropdown__menu oh-dropdown__menu--right oh-dropdown__filter p-4"
x-show="open"
@click.outside="open = false"
style="display: none"
>
<div class="oh-accordion">
<label>{% trans "Group By" %}</label>
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Field" %}</label>
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<select
class="oh-select mt-1 w-100"
id="id_field"
name="field"
class="select2-selection select2-selection--single"
>
{% for field in gp_fields %}
<option value="{{ field.0 }}">{% trans field.1 %}</option>
{% endfor %}
</select>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<div class="oh-main__titlebar-button-container">
<div class="oh-main__titlebar-button-container">
@@ -30,6 +96,37 @@
<button type="button" class="oh-modal__close" aria-label="Close"><ion-icon name="close-outline"></ion-icon></button>
</div>
<div class="oh-modal__dialog-body" id="resignationModalBody"></div>
<div class="oh-modal__dialog-body oh-modal__dialog-relative" id="resignationModalBody"></div>
</div>
</div>
<div class="oh-modal" id="resignationEditModal" role="dialog" aria-hidden="true">
<div class="oh-modal__dialog" style="max-width: 550px">
<div class="oh-modal__dialog-header">
<button type="button" class="oh-modal__close--custom" aria-label="Close" onclick="$(this).parents().closest('.oh-modal--show').toggleClass('oh-modal--show')"><ion-icon name="close-outline"></ion-icon></button>
</div>
<div class="oh-modal__dialog-body" id="resignationEditModalBody"></div>
</div>
</div>
<script>
$(".view-type").on('click',function (e) {
var view = $(this).attr("data-view");
var currentURL = window.location.href;
if (/\?view=[^&]+/.test(currentURL)) {
newURL = currentURL.replace(/\?view=[^&]+/, "?view=" + view);
} else {
var separator = currentURL.includes("?") ? "&" : "?";
newURL = currentURL + separator + "view=" + view;
}
history.pushState({}, "", newURL);
$(".oh-btn--view-active").removeClass("oh-btn--view-active");
$(this).children("a").addClass("oh-btn--view-active");
});
$(document).ready(function () {
$("#id_field").on("change", function () {
$(".filterButton")[0].click();
});
});
</script>

View File

@@ -25,7 +25,7 @@
<div class="oh-faq-card" id="requestCard{{ record.id }}">
<div class="d-flex justify-content-between">
<div style="margin-bottom: 10px;">
<div class="reisgn-status" style="display: inline;">{{ record.status|capfirst }}</div>
<div class="resign-status" style="display: inline;">{{ record.status|capfirst }}</div>
</div>
<div>
<div class="oh-btn-group">
@@ -38,13 +38,13 @@
</button>
{% endif %}
<a hx-get="{% url 'create-resignation-request' %}?instance_id={{ record.id }}" {% trans "Edit" %}
<a hx-get="{% url 'create-resignation-request' %}?instance_id={{ record.id }}" title = {% trans "Edit" %}
class="oh-btn oh-btn--light" data-toggle="oh-modal-toggle" hx-target="#resignationModalBody"
data-target="#resignationModal" style="flex: 1 0 auto; width: 40px; height: 40.68px; padding: 0"><ion-icon
class="text-dark md hydrated" name="create-outline" role="img" aria-label="create outline"></ion-icon></a>
{% if perms.offboarding.delete_resignationletter %}
<a href="{% url 'delete-resignation-request' %}?letter_ids={{record.id}}" class="oh-btn oh-btn--light" {%
trans "Delete" %} style="flex: 1 0 auto; width: 40px; height: 40.68px; padding: 0"
<a href="{% url 'delete-resignation-request' %}?letter_ids={{record.id}}" class="oh-btn oh-btn--light"
title = {%trans "Delete" %} style="flex: 1 0 auto; width: 40px; height: 40.68px; padding: 0"
onclick="return confirm('{% trans 'Do you want to delete this record' %}?')"><ion-icon
class="text-danger md hydrated" name="trash-outline" role="img" aria-label="trash outline"></ion-icon>
</a>

View File

@@ -0,0 +1,338 @@
{% load i18n %} {% load yes_no %} {% load static %}
{% include 'filter_tags.html' %} {% if messages %}
<div class="oh-wrapper">
{% for message in messages %}
<div class="oh-alert-container">
<div class="oh-alert oh-alert--animated {{message.tags}}">
{{ message }}
</div>
</div>
{% endfor %}
</div>
{% endif %} {% if letters %}
<!-- start of column toggle -->
<div class="oh-table_sticky--wrapper oh-wrapper">
<div class="oh-sticky-dropdown--header">
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-sticky-dropdown_btn" @click="open = !open">
<ion-icon
name="ellipsis-vertical-sharp"
role="img"
class="md hydrated"
aria-label="ellipsis vertical sharp"
></ion-icon>
</button>
<div
class="oh-dropdown__menu oh-sticky-table_dropdown"
x-show="open"
@click.outside="open = false"
>
<ul class="oh-dropdown__items" id="resignationCells"></ul>
</div>
</div>
</div>
</div>
<!-- end of column toggle -->
<div class="oh-wrapper" id="resignation-column-table" data-table-name="resignation_column_tab">
<!-- start of sticky table -->
<div class="oh-sticky-table">
<div class="oh-sticky-table__table oh-table--sortable">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div
class="oh-sticky-table__th {% if request.sort_option.order == '-employee_id__employee_first_name' %}arrow-up {% elif request.sort_option.order == 'employee_id__employee_first_name' %}arrow-down {% else %}arrow-up-down {% endif %}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&sortby=employee_id__employee_first_name"
hx-target="#resignationLetterContianer"
>
{% trans "Employee" %}
</div>
<div
data-cell-index="1"
data-cell-title="{% trans 'Title' %}"
class="oh-sticky-table__th {% if request.sort_option.order == '-title' %}arrow-up {% elif request.sort_option.order == 'title' %}arrow-down {% else %}arrow-up-down {% endif %}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&sortby=title"
hx-target="#resignationLetterContianer"
>
{% trans "Title" %}
</div>
<div
data-cell-index="2"
data-cell-title="{% trans 'Planned To Leave' %}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&sortby=planned_to_leave_on"
hx-target="#resignationLetterContianer"
class="oh-sticky-table__th {% if request.sort_option.order == '-planned_to_leave_on' %}arrow-up {% elif request.sort_option.order == 'planned_to_leave_on' %}arrow-down {% else %}arrow-up-down {% endif %}"
>
{% trans "Planned To Leave" %}
</div>
<div
data-cell-index="3"
data-cell-title="{% trans 'Status' %}"
class="oh-sticky-table__th {% if request.sort_option.order == '-status' %}arrow-up {% elif request.sort_option.order == 'status' %}arrow-down {% else %}arrow-up-down {% endif %}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&sortby=status"
hx-target="#resignationLetterContianer"
>
{% trans "Status" %}
</div>
<div
data-cell-index="4"
data-cell-title="{% trans 'Description' %}"
class="oh-sticky-table__th"
>
{% trans "Description" %}
</div>
<div class="oh-sticky-table__th oh-sticky-table__right">
{% trans "Actions" %}
</div>
</div>
</div>
{% for letter in letters %}
<div
class="oh-sticky-table__tbody ui-sortable"
draggable="true"
hx-get="{% url 'resignation-request-single-view' letter.id %}?requests_ids={{requests_ids}}"
hx-target="#resignationModalBody"
data-toggle="oh-modal-toggle"
data-target="#resignationModal"
>
<div class="oh-sticky-table__tr ui-sortable-handle">
<div class="oh-sticky-table__sd">
{{letter.employee_id}}
</div>
<div class="oh-sticky-table__td" data-cell-index="1">{{letter.title}}</div>
<div data-cell-index="2" class="oh-sticky-table__td">
{{letter.planned_to_leave_on}}
</div>
<div data-cell-index="3" class="oh-sticky-table__td">
{{letter.status}}
</div>
<div data-cell-index="4" class="oh-sticky-table__td">
{{letter.description|safe|truncatechars:30}}
</div>
<div class="oh-sticky-table__td oh-sticky-table__right">
<form action="{% url 'update-letter-status' %}">
{% if perms.offboarding.change_resignationletter %}
<div class="oh-btn-group">
{% if letter.status != "approved" %}
<button
title="By approving the request employee will added to the offboarding pipeline"
type="button"
onclick="$(this).closest('form').find('input[name=status]').val('approved');resignLetterConfirmation('{% trans 'Do You really want to approve the request' %}?',$(this).closest('form').find('[type=submit]'),true);"
class="oh-btn oh-btn--success w-100 oh-btn--block w-100"
>
<ion-icon
name="checkmark"
class="mr-1 md hydrated"
role="img"
aria-label="checkmark"
></ion-icon>
</button>
{% else %}
<button
type="button"
class="oh-btn oh-btn--success oh-btn--disabled oh-btn--block w-100"
>
<ion-icon
name="checkmark"
class="mr-1 md hydrated"
role="img"
aria-label="checkmark"
></ion-icon>
</button>
{% endif %}
<button
type="button"
onclick="$(this).closest('form').find('input[name=status]').val('rejected');resignLetterConfirmation('{% trans 'Do You really want to reject the request?' %}',$(this).closest('form').find('[type=submit]'));"
class="oh-btn oh-btn--danger oh-btn--block w-100"
>
<ion-icon
name="close-circle-outline"
class="mr-1 md hydrated"
role="img"
aria-label="close"
></ion-icon>
</button>
<input type="hidden" name="status" />
<input
type="hidden"
name="letter_ids"
value="{{letter.id}}"
/>
<input type="hidden" name="offboarding_id" />
<input type="hidden" name="notice_period_starts"
value="{% now "Y-m-d" %}"
id="notice_period_starts{{letter.id}}">
<input
type="hidden"
name="notice_period_ends"
id="notice_period_ends{{letter.id}}"
/>
<button type="submit" hidden></button>
</div>
{% endif %}
<input
type="submit"
hidden=""
id="requestCard1Button"
/>
</form>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- end of sticky table -->
<!-- start of pagination -->
<div class="oh-pagination">
<span class="oh-pagination__page">
{% trans "Page" %} {{ letters.number }} {% trans "of" %}
{{letters.paginator.num_pages }}.
</span>
<nav class="oh-pagination__nav">
<div class="oh-pagination__input-container me-3">
<span class="oh-pagination__label me-1"
>{% trans "Page" %}</span
>
<input
type="number"
name="page"
class="oh-pagination__input"
value="{{letters.number}}"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list"
hx-target="#resignationLetterContianer"
min="1"
/>
<span class="oh-pagination__label"
>{% trans "of" %} {{letters.paginator.num_pages}}</span
>
</div>
<ul class="oh-pagination__items">
{% if letters.has_previous %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list&page=1"
class="oh-pagination__link"
>{% trans "First" %}</a
>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list&page={{ letters.previous_page_number }}"
class="oh-pagination__link"
>{% trans "Previous" %}</a
>
</li>
{% endif %} {% if letters.has_next %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list&page={{ letters.next_page_number }}"
class="oh-pagination__link"
>{% trans "Next" %}</a
>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a
hx-target="#resignationLetterContianer"
hx-get="{% url 'search-resignation-request' %}?{{pd}}&view=list&page={{ letters.paginator.num_pages }}"
class="oh-pagination__link"
>{% trans "Last" %}</a
>
</li>
{% endif %}
</ul>
</nav>
</div>
<!-- end of pagination -->
</div>
{% else %}
<!-- start of empty page -->
<div class="oh-404">
<img
style="width: 150px; height: 150px"
src="{% static 'images/ui/no-results.png' %}"
class="oh-404__image mb-4"
/>
<h5 class="oh-404__subtitle">{% trans "No search result found!" %}</h5>
</div>
<!-- end of empty page -->
{% endif %}
<script>
// toggle columns //
toggleColumns("resignation-column-table", "resignationCells");
localStorageresignationCells = localStorage.getItem(
"resignation_column_tab"
);
if (!localStorageresignationCells) {
$("#resignationCells").find("[type=checkbox]").prop("checked", true);
}
$("[type=checkbox]").change();
function resignLetterConfirmation(params, target, approve = false) {
// Define the select box options
var selectOptions = ``;
var dateFields = '<label style="display:block;" for="notice_period_starts">Start Date:</label>' +
`<input style="display:block;" onchange="$('#${target.siblings("input[name=notice_period_starts]").first().attr("id")}').val(this.value)" class="oh-input" type="date" id="notice_period_starts" name="notice_period_starts">` +
'<label style="display:block;" for="notice_period_ends">End Date:</label>' +
`<input style="display:block;" onchange="$('#${target.siblings("input[name=notice_period_ends]").first().attr("id")}').val(this.value)" class="oh-input" type="date" id="notice_period_ends" name="notice_period_ends">`;
html = '<p>' + params + '</p>'
if (approve) { html = html + "<div >" + selectOptions + `
<div class='row' style='overflow-x:hidden;'>
<div class="col-12">
<div class="oh-label__info" for="offboardingSelect">
<label class="oh-label" for="offboardingSelect">Add to</label>
</div>
<select id="offboardingSelect" class="oh-select oh-select2 w-100" name="reason" title="{% trans "Add to offboarding" %}">
// {% for offboarding in offboardings %}
<option value="{{offboarding.id}}">{{offboarding.title}}</option>
// {% endfor %}
</select>
</div>
<div class="col-6 col-md-6">
<div class="oh-label__info" for="notice_period_starts">
<label class="oh-label" for="notice_period_starts">Planned to leave on</label>
</div>
<input type="date" onchange="$('#${target.siblings("input[name=notice_period_starts]").first().attr("id")}').val(this.value);alert()" name="notice_period_starts" value="{% now "Y-m-d" %}" class="oh-input w-100 form-control" required id="notice_period_starts">
</div>
<div class="col-6 col-md-6">
<div class="oh-label__info" for="notice_period_ends">
<label class="oh-label" for="notice_period_ends">Notice period end</label>
</div>
<input type="date" onchange="$('#${target.siblings("input[name=notice_period_ends]").first().attr("id")}').val(this.value);alert()" name="notice_period_ends" class="oh-input w-100 form-control" required id="notice_period_ends">
</div>
</div>
` + "</div>" }
Swal.fire({
html: html,
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#008000',
cancelButtonColor: '#d33',
confirmButtonText: "Confirm",
cancelButtonText: "Close"
}).then((result) => {
if (result.isConfirmed) {
// Access the selected value from the select box
if (approve) {
var selectedOffboarding = document.getElementById('offboardingSelect').value;
target.siblings("input[name=offboarding_id]").val(selectedOffboarding)
}
target.click();
if (event.target.tagName.toLowerCase() === 'form') {
event.target.submit();
} else if (event.target.tagName.toLowerCase() === 'a') {
window.location.href = event.target.href;
}
} else {
// Handle cancel
}
});
}
</script>

View File

@@ -0,0 +1,174 @@
{% load i18n %}
{% if request.GET.requests_ids %}
<div class="oh-modal__dialog oh-modal__dialog--navigation m-0 p-0">
<button hx-get="{% url 'resignation-request-single-view' previous %}?requests_ids={{requests_ids}}" hx-target = "#resignationModalBody" class="oh-modal__diaglog-nav oh-modal__nav-prev">
<ion-icon name="chevron-back-outline" class="md hydrated" role="img"
aria-label="chevron back outline"></ion-icon>
</button>
<button hx-get="{% url 'resignation-request-single-view' next %}?requests_ids={{requests_ids}}" hx-target = "#resignationModalBody" class="oh-modal__diaglog-nav oh-modal__nav-next">
<ion-icon name="chevron-forward-outline" class="md hydrated" role="img"
aria-label="chevron forward outline"></ion-icon>
</button>
</div>
{% endif %}
<div class="mt-4" >
<div class="d-flex justify-content-between">
<div style="margin-bottom: 10px">
<div class="resign-status" style="display: inline">
{{ letter.status|capfirst }}
</div>
</div>
<div>
<div class="oh-btn-group">
{% if perms.offboarding.change_resignationletter %}
<button
type="button"
hx-get="{% url 'send-mail-employee' letter.employee_id.id %}"
title="{% trans " Send Mail" %} "
hx-target="#resignationEditModalBody"
class="oh-btn oh-btn--light"
data-toggle="oh-modal-toggle"
data-target="#resignationEditModal"
style="
flex: 1 0 auto;
width: 40px;
height: 40.68px;
padding: 0;
"
onclick="event.stopPropagation()"
>
<ion-icon
name="mail-open-outline"
role="img"
class="md hydrated"
aria-label="mail open outline"
></ion-icon>
</button>
{% endif %}
<a
hx-get="{% url 'create-resignation-request' %}?instance_id={{ letter.id }}"
class="oh-btn oh-btn--light"
title="{% trans "Edit" %}"
data-toggle="oh-modal-toggle"
hx-target="#resignationEditModalBody"
data-target="#resignationEditModal"
style="
flex: 1 0 auto;
width: 40px;
height: 40.68px;
padding: 0;
"
><ion-icon
class="text-dark md hydrated"
name="create-outline"
role="img"
aria-label="create outline"
></ion-icon
></a>
{% if perms.offboarding.delete_resignationletter %}
<a
href="{% url 'delete-resignation-request' %}?letter_ids={{letter.id}}"
class="oh-btn oh-btn--light"
style="
flex: 1 0 auto;
width: 40px;
height: 40.68px;
padding: 0;
"
title = "{% trans "Delete" %}"
onclick="return confirm('{% trans 'Do you want to delete this letter' %}?')"
><ion-icon
class="text-danger md hydrated"
name="trash-outline"
role="img"
aria-label="trash outline"
></ion-icon>
</a>
{% endif %}
</div>
</div>
</div>
<div class="oh-timeoff-modal__profile-content">
<div class="oh-profile mb-2">
<div class="oh-profile__avatar">
<img
src="{{ letter.employee_id.get_avatar }}"
class="oh-profile__image me-2"
/>
</div>
<div class="oh-timeoff-modal__profile-info">
<span class="oh-timeoff-modal__user m-0 fw-bold"
>{{ letter.employee_id.get_full_name }}</span
>
<span
class="oh-timeoff-modal__user m-0"
style="font-size: 12px; color: #4d4a4a"
>
{{ letter.employee_id.get_department }} /
{{letter.employee_id.get_job_position }}
</span>
</div>
</div>
</div>
<h3 class="oh-faq-card__title">{{ letter.title }}</h3>
<div class="oh-faq-card__desc">{{ letter.description|safe }}</div>
<form action="{% url 'update-letter-status' %}">
{% if perms.offboarding.change_resignationletter %}
<div class="oh-btn-group">
{% if letter.status != "approved" %}
<button
title="By approving the request employee will added to the offboarding pipeline"
type="button"
onclick="$(this).closest('form').find('input[name=status]').val('approved');resignLetterConfirmation('{% trans 'Do You really want to approve the request' %}?',$(this).closest('form').find('[type=submit]'),true);"
class="oh-btn oh-btn--success w-100 oh-btn--block w-100"
>
<ion-icon
name="checkmark"
class="mr-1 md hydrated"
role="img"
aria-label="checkmark"
></ion-icon>
</button>
{% else %}
<button
type="button"
class="oh-btn oh-btn--success oh-btn--disabled oh-btn--block w-100"
>
<ion-icon
name="checkmark"
class="mr-1 md hydrated"
role="img"
aria-label="checkmark"
></ion-icon>
</button>
{% endif %}
<button
type="button"
onclick="$(this).closest('form').find('input[name=status]').val('rejected');resignLetterConfirmation('{% trans 'Do You really want to reject the request?' %}',$(this).closest('form').find('[type=submit]'));"
class="oh-btn oh-btn--danger oh-btn--block w-100"
>
<ion-icon
name="close-circle-outline"
class="mr-1 md hydrated"
role="img"
aria-label="close"
></ion-icon>
</button>
<input type="hidden" name="status" />
<input type="hidden" name="letter_ids" value="{{letter.id}}" />
<input type="hidden" name="offboarding_id" />
<input type="hidden" name="notice_period_starts" value="{% now
"Y-m-d" %}" id="notice_period_starts{{letter.id}}">
<input
type="hidden"
name="notice_period_ends"
id="notice_period_ends{{letter.id}}"
/>
<button type="submit" hidden></button>
</div>
{% endif %}
<input type="submit" hidden="" id="requestCard1Button" />
</form>
</div>

View File

@@ -1,7 +1,7 @@
{% extends "index.html" %}
{% block content %}
<style>
.reisgn-status {
.resign-status {
background: #73bbe12b;
font-size: 0.8rem;
padding: 4px 8px;
@@ -13,6 +13,10 @@
</style>
{% include "offboarding/resignation/nav.html" %}
<div id="resignationLetterContianer">
{% include "offboarding/resignation/request_cards.html" %}
{% if request.GET.view == 'list' %}
{% include "offboarding/resignation/request_list.html" %}
{% else %}
{% include "offboarding/resignation/request_cards.html" %}
{% endif %}
</div>
{% endblock content %}

View File

@@ -1,21 +1,24 @@
import datetime
import json
from urllib.parse import parse_qs
from django.http import HttpResponse, JsonResponse
from django.shortcuts import redirect, render
from django.contrib import messages
from django.contrib.auth.models import User
from base.context_processors import intial_notice_period
from base.methods import closest_numbers, sortby
from employee.models import Employee
from horilla.decorators import login_required, manager_can_enter, permission_required
from base.views import paginator_qry
from offboarding.decorators import (
any_manager_can_enter,
check_feature_endabled,
check_feature_enabled,
offboarding_manager_can_enter,
offboarding_or_stage_manager_can_enter,
)
from offboarding.filters import (
LetterFilter,
LetterReGroup,
PipelineEmployeeFilter,
PipelineFilter,
PipelineStageFilter,
@@ -45,6 +48,7 @@ from django.utils.translation import gettext_lazy as _
from onboarding.filters import OnboardingStageFilter
from payroll.models.models import Contract
from attendance.methods.group_by import group_by_queryset as group_by
from recruitment.pipeline_grouper import group_by_queryset
@@ -597,7 +601,7 @@ def offboarding_individual_view(request, emp_id):
@login_required
@permission_required("offboarding.view_resignationletter")
@check_feature_endabled("resignation_request")
@check_feature_enabled("resignation_request")
def request_view(request):
"""
This method is used to view the resignation request
@@ -614,12 +618,34 @@ def request_view(request):
"f": filter_instance,
"filter_dict": {"status": ["Requested"]},
"offboardings": offboardings,
"gp_fields": LetterReGroup.fields,
},
)
@login_required
@check_feature_endabled("resignation_request")
@permission_required("offboarding.view_resignationletter")
def request_single_view(request, id):
letter = ResignationLetter.objects.get(id=id)
context = {
"letter": letter,
}
requests_ids_json = request.GET.get("requests_ids")
if requests_ids_json:
requests_ids = json.loads(requests_ids_json)
previous_id, next_id = closest_numbers(requests_ids, id)
context["requests_ids"] = requests_ids_json
context["previous"] = previous_id
context["next"] = next_id
return render(
request,
"offboarding/resignation/request_single_view.html",
context,
)
@login_required
@check_feature_enabled("resignation_request")
def search_resignation_request(request):
"""
This method is used to search/filter the letter
@@ -630,20 +656,50 @@ def search_resignation_request(request):
letters = ResignationLetter.objects.filter(
employee_id__employee_user_id=request.user
)
field = request.GET.get("field")
data_dict = parse_qs(request.GET.urlencode())
template = "offboarding/resignation/request_cards.html"
if request.GET.get("view") == "list":
template = "offboarding/resignation/request_list.html"
if request.GET.get("sortby"):
letters = sortby(request, letters, "sortby")
data_dict.pop("sortby")
if field != "" and field is not None:
letters = group_by(letters, field, request.GET.get("page"), "page")
list_values = [entry["list"] for entry in letters]
id_list = []
for value in list_values:
for instance in value.object_list:
id_list.append(instance.id)
requests_ids = json.dumps(list(id_list))
template = "offboarding/resignation/group_by.html"
else:
letters = paginator_qry(letters, request.GET.get("page"))
requests_ids = json.dumps([instance.id for instance in letters.object_list])
if request.GET.get("view"):
data_dict.pop("view")
return render(
request,
"offboarding/resignation/request_cards.html",
template,
{
"letters": paginator_qry(letters, request.GET.get("page")),
"letters": letters,
"filter_dict": data_dict,
"pd": request.GET.urlencode(),
"requests_ids": requests_ids,
"field": field,
},
)
@login_required
@check_feature_endabled("resignation_request")
@check_feature_enabled("resignation_request")
@permission_required("offboarding.delete_resignationletter")
def delete_resignation_request(request):
"""
@@ -656,7 +712,7 @@ def delete_resignation_request(request):
@login_required
@check_feature_endabled("resignation_request")
@check_feature_enabled("resignation_request")
def create_resignation_request(request):
"""
This method is used to render form to create resignation requests
@@ -676,7 +732,7 @@ def create_resignation_request(request):
@login_required
@check_feature_endabled("resignation_request")
@check_feature_enabled("resignation_request")
@permission_required("offboarding.change_resignationletter")
def update_status(request):
"""