[ADD] ONBOARDING: Onboarding pipeline filteration

This commit is contained in:
Horilla
2024-02-15 12:12:23 +05:30
parent 4be6d52308
commit 9a3734b13e
9 changed files with 771 additions and 679 deletions

View File

@@ -2,9 +2,10 @@
filters.py
Used to register filter for onboarding models
"""
from django import forms
from django_filters import filters
from onboarding.models import Candidate
from django_filters import filters
from onboarding.models import Candidate, CandidateStage, OnboardingStage
from base.filters import FilterSet
@@ -22,3 +23,39 @@ class CandidateFilter(FilterSet):
model = Candidate
fields = {}
class OnboardingStageFilter(FilterSet):
"""
OnboardingStageFilter
"""
search_onboarding = filters.CharFilter(field_name="stage_title", method="pipeline_search")
class Meta:
model = OnboardingStage
fields = "__all__"
def pipeline_search(self, queryset, _, value):
"""
This method is used to search recruitment
"""
queryset = (
queryset.filter(stage_title__icontains=value)
| queryset.filter(candidate__candidate_id__name__icontains=value)
)
return queryset.distinct()
class OnboardingCandidateFilter(FilterSet):
"""
OnboardingStageFilter
"""
search_onboarding = filters.CharFilter(
field_name="candidate_id__name", lookup_expr="icontains"
)
class Meta:
model = CandidateStage
fields = "__all__"

View File

@@ -0,0 +1,59 @@
{% load i18n %}
{% load static %}
<div class="oh-dropdown__filter-body">
<div class="oh-accordion">
<div class="oh-accordion-header">
{% trans 'Recruitment' %}
</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans 'Managers' %}</label>
{{ rec_filter_obj.form.recruitment_managers }}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans 'Start Date' %}</label>
{{ rec_filter_obj.form.start_date }}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans 'Company' %}</label>
{{ rec_filter_obj.form.company_id }}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans 'End Date' %}</label>
{{ rec_filter_obj.form.end_date }}
</div>
</div>
</div>
</div>
</div>
<div class="oh-accordion">
<div class="oh-accordion-header">
{% trans 'Advanced' %}
</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans 'Start Date From' %}</label>
{{ rec_filter_obj.form.start_from }}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans 'Till End Date' %}</label>
{{ rec_filter_obj.form.end_till }}
</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" id="">{% trans 'Filter' %}</button>
</div>

View File

@@ -17,137 +17,33 @@
<div class="oh-wrapper">
<section class=" oh-main__topbar" x-data="{searchShow: false}">
<div class="oh-main__titlebar oh-main__titlebar--left">
<div class="oh-main__titlebar-title fw-bold mb-0 text-dark" style="cursor:pointer;">{% trans "Onboarding" %}</div>
</div>
<div class="oh-main__titlebar oh-main__titlebar--right">
<div class="oh-input-group oh-input__search-group"
:class="searchShow ? 'oh-input__search-group--show' : ''">
<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 type="text" id="search" placeholder="{% trans 'Search' %}" name="search"
class="oh-input oh-input__icon" aria-label="Search Input">
</div>
<div class="oh-switch ms-3" style="width: 30px;">
<input type="checkbox" name="is_closed" data-widget="style-widget" class="style-widget oh-switch__checkbox" {% if request.GET.closed %} checked title="{% trans 'Ongoing Recruitments' %}" {% else %}title="{% trans 'Closed Recruitments' %}" {% endif %} id="is_closed" >
</div>
<ul class="oh-view-types ml-2" style="margin-bottom: 0;">
<li class="oh-view-type candidate-view-type" data-view="list" title="{% trans "List" %}">
<a href="{% url 'onboarding-view' %}?closed={{status}}" hx-target="#section" class="oh-btn oh-btn--view "><ion-icon
name="list-outline" role="img" class="md hydrated" aria-label="list outline"></ion-icon></a>
</li>
<li class="oh-view-type candidate-view-type" data-view="card" title="{% trans "Card" %}">
<a href="{% url 'kanban-view' %}?closed={{status}}" hx-target="#section" class="oh-btn oh-btn--view oh-btn--view-active"><ion-icon
name="grid-outline" role="img" class="md hydrated" aria-label="grid outline"></ion-icon></a>
</li>
</ul>
<div class="oh-main__titlebar-button-container">
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn ml-2" @click="open = !open">
<ion-icon name="filter" class="mr-1"></ion-icon>{% trans "Filter" %}<div id="filterCount"></div>
</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;" @click.>
<div class="mb-3 mt-3">
<label for="job_position_id" class="oh-label">{% trans "Job position" %}</label>
<select class="" name="job_position_id" id="job_position_id">
<option value="">------------------</option>
{% for job_position in job_positions %}
<option value="{{job_position}}">{{job_position}}</option>
{% endfor %}
</select>
</div>
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<label class ="mb-2" for="join_date">{% trans "Join Date" %}</label>
<input type="date" name="join_date" id="join_date" class="oh-input w-100">
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<label class ="mb-2" for="portal_stage">{% trans "Onboarding Portal Stage" %}</label>
<select class="" name="portal_stage" id="portal_stage">
<option value="">------------------</option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</div>
</div>
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Advanced" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class ="mb-2" for="join_date">{% trans "Join Date From" %}</label>
<input type="date" name="join_date" id="join_date_start" class="oh-input w-100">
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class ="mb-2" for="join_date">{% trans "Join Date To" %}</label>
<input type="date" name="join_date" id="join_date_end" class="oh-input w-100">
</div>
</div>
</div>
</div>
</div>
<div class="oh-tabs__action-bar mt-2" id="filter_item" x-on:click="open = false" >
<button class="oh-btn oh-btn--small oh-btn--secondary oh-tabs__action-new-table w-100" >
<ion-icon class="me-1 md hydrated" name="add-outline" role="img"aria-label="add outline"></ion-icon>
{% trans "Filter" %}
</button>
</div>
</div>
</div>
</div>
</div>
</section>
{% include "onboarding/onboarding_view_nav.html" %}
<div id = "stage-messages"></div>
<div class="oh-wrapper oh-filter-tag-container filter-value" style="margin-left:-3px"></div>
<div class="oh-tabs">
<ul class="oh-tabs__tablist">
{% for rec in recruitments %}
{% if request.user|task_manages:rec or perms.onboarding.view_candidatestage %}
<li class="oh-tabs__tab" data-target="#tab_{{rec.id}}" data-recruitment-id="{{rec.id}}" {% if request.user|recruitment_manages:rec %} style="background-color: hsl(38.08deg 100% 50% / 8%);" {% endif %}>
{{rec.title}}
<span
class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2" title="{{rec.onboardingstage_set.all|length}} {% trans 'Stage' %}" onclick="event.stopPropagation()">
{{rec.onboardingstage_set.all|length}}
</span>
</li>
{% endif %}
{% endfor %}
</ul>
{% include "onboarding/tabs.html" %}
<div class="oh-tabs__contents">
{% for rec in recruitments %}
<div class="oh-tabs__content " id="tab_{{rec.id}}" data-recruitment-id="{{rec.id}}">
<div class="oh-kanban">
{% for stage in rec.onboarding_stage.all %}
<div class="oh-kanban__section stage" id="b3a7bac2-2a16-40fe-9b7e-78a1101ee9d3" data-recruitment-id="{{rec.id}}" data-stage-id="{{stage.id}}" data-sequence="{{forloop.counter}}">
<div class="oh-kanban__section-head oh-kanban__section-head--white" {% if request.user.employee_get in stage.employee_id.all %} style="background-color: hsl(38.08deg 100% 50% / 8%) !important;" {% endif %}>
{% for stage in rec.stages %}
<div class="oh-kanban__section stage" id="b3a7bac2-2a16-40fe-9b7e-78a1101ee9d3" data-recruitment-id="{{rec.id}}" data-stage-id="{{stage.grouper.id}}" data-sequence="{{forloop.counter}}">
<div class="oh-kanban__section-head oh-kanban__section-head--white" {% if request.user.employee_get in stage.grouper.employee_id.all %} style="background-color: hsl(38.08deg 100% 50% / 8%) !important;" {% endif %}>
<div class="d-flex ">
<span class="oh-kanban__section-title" data-type="label">
<input
class="oh-tabs__movable-title oh-table__editable-input"
value="{{stage}}"
hx-post="{% url 'stage-name-update' stage.id %}"
value="{{stage.grouper}}"
hx-post="{% url 'stage-name-update' stage.grouper.id %}"
name='stage'
hx-target="#stage-messages"
style="width: 160px;"
readonly=""
/>
</span>
<span class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2 stage_count" title="{{stage.candidate.count}} {% trans 'Candidate' %}">{{stage.candidate.count}}</span>
<span class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2 stage_count" title="{{stage.grouper.candidate.count}} {% trans 'Candidate' %}">{{stage.grouper.candidate.count}}</span>
</div>
<div class="oh-kanban__head-actions oh-kanban__dropdown">
<button
@@ -161,11 +57,11 @@
<li class="oh-dropdown__item">
<a data-toggle="oh-modal-toggle"
data-target="#editModal3"
hx-get="{% url 'stage-update' stage.id rec.id %}"
hx-get="{% url 'stage-update' stage.grouper.id rec.id %}"
hx-target="#updateStage">{% trans "Edit" %}</a>
</li>
<li class="oh-dropdown__item">
<a href="{% url 'stage-delete' stage.id %}"
<a href="{% url 'stage-delete' stage.grouper.id %}"
onclick="return confirm('{% trans "Do you want to delete this stage?" %}')"
class="oh-dropdown__link oh-dropdown__link--danger">{% trans "Delete" %}</a>
</li>
@@ -176,7 +72,7 @@
class="oh-btn oh-btn--small oh-btn--transparent p-0"
data-toggle="oh-modal-toggle"
data-target="#taskModal"
hx-get="{% url 'task-creation' %}?stage_id=stage.id"
hx-get="{% url 'task-creation' %}?stage_id={{stage.grouper.id}}"
hx-target = "#taskModalBody"
title="{% trans 'Add task' %}">
@@ -185,8 +81,8 @@
</button>
</div>
</div>
<div class="oh-kanban__section-body ui-sortable onboarding_items" data-stage-id="{{stage.id}}" data-recruitment-id="{{rec.id}}">
{% for candidate in stage.candidate.all %}
<div class="oh-kanban__section-body ui-sortable onboarding_items" data-stage-id="{{stage.grouper.id}}" data-recruitment-id="{{rec.id}}">
{% for candidate in stage.list %}
<div class="oh-kanban__card candidate" id="{{candidate.id}}" data-candidate="{{candidate.candidate_id}}" data-candidate-id="{{candidate.candidate_id.id}}" data-recruitment-id="{{rec.id}}" data-candidate-now = "{{stage.id}}" data-job-position = "{{candidate.candidate_id.job_position_id}}" data-portal-count="{{candidate.candidate_id.onboarding_portal.count}}" data-join-date="{{candidate.candidate_id.joining_date}}" >
<div class="oh-kanban__card-head">
<div class="oh-profile oh-profile--md">
@@ -234,6 +130,45 @@
</div>
</div>
{% endfor %}
{% if stage.list.number %}
<div class="oh-pagination">
<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="{{stage.dynamic_name}}"
class="oh-pagination__input"
value="{{stage.list.number}}"
href="?{{pd}}"
min="1"
/>
<span class="oh-pagination__label"
>{% trans "of" %} {{stage.list.paginator.num_pages}}</span
>
</div>
<ul class="oh-pagination__items">
{% if stage.list.has_previous %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a
href="?{{pd}}&{{stage.dynamic_name}}={{ stage.list.previous_page_number }}"
class="oh-pagination__link"
>{% trans "Previous" %}</a
>
</li>
{% endif %} {% if stage.list.has_next %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a
href="?{{pd}}&{{stage.dynamic_name}}={{ stage.list.next_page_number }}"
class="oh-pagination__link"
>{% trans "Next" %}</a
>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
</div>
</div>

View File

@@ -1,371 +1,406 @@
{% load onboardingfilters %} {% load i18n %} {% load static %}
<style>
.oh-accordion-meta__body .oh-sticky-table--no-overflow {
height:300px;
}
.select2-container .select2-selection.select2-selection--multiple{
padding: 5px !important;
max-height: 70px !important;
overflow: hidden;
overflow-y: scroll;
}
.oh-accordion-meta__body .oh-sticky-table--no-overflow {
height:300px;
}
.select2-container .select2-selection.select2-selection--multiple{
padding: 5px !important;
max-height: 70px !important;
overflow: hidden;
overflow-y: scroll;
}
</style>
<script src="{% static 'htmx/htmx.min.js' %}"></script>
{% for stage in recruitment.onboarding_stage.all %}
{% for stage in recruitment.stages %}
<div class="oh-accordion-meta" >
<div class="oh-accordion-meta__item" id="onboarding_stage{{stage.id}}">
<div class="oh-accordion-meta__header oh-accordion-meta__header--show" {% if request.user.employee_get in stage.employee_id.all %} style="background-color: hsl(38.08deg 100% 50% / 8%);" {% endif %}>
<div style="display: -webkit-inline-box;"
<div class="oh-accordion-meta__item" id="onboarding_stage{{stage.grouper.id}}">
{% comment %} fixed {% endcomment %}
<div class="oh-accordion-meta__header oh-accordion-meta__header--show"
{% if request.user.employee_get in stage.grouper.employee_id.all %}
style="background-color: hsl(38.08deg 100% 50% / 8%);"
{% endif %}>
<div style="display: -webkit-inline-box;"
>
<span class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2 stage_count" title="{{stage.list|length}} {% trans 'Candidate' %}">{{stage.list|length}}</span>
<span class="oh-accordion-meta__title">{{stage.grouper}}</span>
</div>
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingstage or perms.onboarding.delete_onboardingstage %}
<div class="oh-btn-group" style="margin-left:70%">
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingstage %}
<a
onclick="event.stopPropagation();"
hx-get="{% url 'stage-update' stage.grouper.id recruitment.id %}"
hx-target="#updateStage"
data-toggle="oh-modal-toggle"
data-target="#editModal3"
class="oh-btn oh-btn--light-bkg w-100"
title="{% trans 'Edit' %}"
>
<ion-icon name="create-outline"></ion-icon
>
</a>
{% else %}
<a
onclick="event.stopPropagation();"
data-toggle="oh-modal-toggle"
data-target="#editModal3"
class="oh-btn oh-btn--light-bkg w-100 oh-btn--disabled"
title="{% trans 'Edit' %}"
>
<ion-icon name="create-outline"></ion-icon
>
</a>
{% endif %}
{% if request.user|stage_manages:stage or perms.onboarding.delete_onboardingstage %}
<form action="{% url 'stage-delete' stage.grouper.id %}"
onsubmit="return confirm('{% trans "Do you want to delete this stage?" %}')"
class="oh-dropdown__link oh-dropdown__link--danger"
>
<span class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2 stage_count" title="{{stage.candidate.count}} {% trans 'Candidate' %}">{{stage.candidate.count}}</span>
<span class="oh-accordion-meta__title">{{stage}}</span>
</div>
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingstage or perms.onboarding.delete_onboardingstage %}
<div class="oh-btn-group" style="margin-left:70%">
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingstage %}
<a
onclick="event.stopPropagation();"
hx-get="{% url 'stage-update' stage.id recruitment.id %}"
hx-target="#updateStage"
data-toggle="oh-modal-toggle"
data-target="#editModal3"
class="oh-btn oh-btn--light-bkg w-100"
title="{% trans 'Edit' %}"
><ion-icon name="create-outline"></ion-icon
></a>
{% else %}
<a
onclick="event.stopPropagation();"
data-toggle="oh-modal-toggle"
data-target="#editModal3"
class="oh-btn oh-btn--light-bkg w-100 oh-btn--disabled"
title="{% trans 'Edit' %}"
><ion-icon name="create-outline"></ion-icon
></a>
{% endif %}
{% if request.user|stage_manages:stage or perms.onboarding.delete_onboardingstage %}
<form action="{% url 'stage-delete' stage.id %}"
onsubmit="return confirm('{% trans "Do you want to delete this stage?" %}')"
class="oh-dropdown__link oh-dropdown__link--danger"
>
<button
onclick="event.stopPropagation();"
type="submit"
class="oh-btn oh-btn--danger-outline oh-btn--light-bkg w-100"
title="{% trans 'Remove' %}"
>
<ion-icon name="trash-outline"></ion-icon>
</button>
</form>
{% else %}
<button
onclick="event.stopPropagation();"
type="submit"
class="oh-btn oh-btn--danger-outline oh-btn--light-bkg w-100 oh-btn--disabled "
title="{% trans 'Remove' %}"
>
<ion-icon name="trash-outline"></ion-icon>
</button>
{% endif %}
</div>
{% comment %} <div class="oh-accordion-meta__actions" onclick="event.stopPropagation()">
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn oh-stop-prop oh-accordion-meta__btn" @click="open = !open"
@click.outside="open = false"
title="{% trans "Action" %}">
{% trans "Actions" %}
<ion-icon class="ms-2 oh-accordion-meta__btn-icon" name="caret-down-outline"></ion-icon>
</button>
<div class="oh-dropdown__menu oh-dropdown__menu--right" x-show="open">
<ul class="oh-dropdown__items">
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingstage %}
<li class="oh-dropdown__item">
<a class="oh-dropdown__link" data-toggle="oh-modal-toggle" data-target="#editModal3"
hx-get="{% url 'stage-update' stage.id recruitment.id %}"
hx-target="#updateStage">{% trans "Edit" %}</a>
</li>
{% endif %} {% endcomment %}
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingstage %}
{% comment %} <li class="oh-dropdown__item">
<a class="oh-dropdown__link mb-2">{% trans "Bulk Change Stage" %}</a> {% endcomment %}
<select id=""
class="w-100 bulkStageChange"
style="border: 1px solid hsl(213deg,22%,84%);
padding: 0.3rem 0.8rem 0.3rem 0.3rem;
border-radius: 0rem;" name="stage"
data-stage = "#onboarding_stage{{stage.id}}"
data-recruitment = {{recruitment.id}}
title = "Bulk stage change"
onchange = "bulkStageChange(this)">
{% for on_stage in recruitment.onboarding_stage.all %}
{% if on_stage == stage %}
<option value="{{on_stage.id}}" selected>{{on_stage}}</option>
{% else %}
<option value="{{on_stage.id}}">{{on_stage}}</option>
{% endif %}
{% endfor %}
</select>
{% comment %} </li> {% endcomment %}
{% endif %}
{% comment %} {% if request.user|stage_manages:stage or perms.onboarding.delete_onboardingstage %}
<li class="oh-dropdown__item">
<a href="{% url 'stage-delete' stage.id %}"
onclick="return confirm('{% trans "Do you want to delete this stage?" %}')"
class="oh-dropdown__link oh-dropdown__link--danger">{% trans "Delete" %}
</a>
</li>
{% endif %}
</ul>
</div>
</div>
</div> {% endcomment %}
<button
onclick="event.stopPropagation();"
type="submit"
class="oh-btn oh-btn--danger-outline oh-btn--light-bkg w-100"
title="{% trans 'Remove' %}"
>
<ion-icon name="trash-outline"></ion-icon>
</button>
</form>
{% else %}
<button
onclick="event.stopPropagation();"
type="submit"
class="oh-btn oh-btn--danger-outline oh-btn--light-bkg w-100 oh-btn--disabled "
title="{% trans 'Remove' %}"
>
<ion-icon name="trash-outline"></ion-icon>
</button>
{% endif %}
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingstage %}
<select id=""
class="w-100 bulkStageChange"
style="border: 1px solid hsl(213deg,22%,84%);
padding: 0.3rem 0.8rem 0.3rem 0.3rem;
border-radius: 0rem;" name="stage"
data-stage = "#onboarding_stage{{stage.grouper.id}}"
data-recruitment = {{recruitment.id}}
title = "Bulk stage change"
onclick="event.stopPropagation();"
onchange = "bulkStageChange(this);">
{% for on_stage in recruitment.onboarding_stage.all %}
{% if on_stage == stage %}
<option value="{{on_stage.id}}" selected>{{on_stage}}</option>
{% else %}
<option value="{{on_stage.id}}">{{on_stage}}</option>
{% endif %}
{% endfor %}
</select>
{% endif %}
</div>
<div class="oh-accordion-meta__body onboarding_items">
<div class="oh-sticky-table oh-sticky-table--no-overflow mb-5">
<div class="oh-sticky-table__table">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th" style="width:10px;">
<div class="centered-div">
<input
type="checkbox"
class="oh-input payslip-checkbox oh-input__checkbox select-all"
data-stage="#onboarding_stage{{stage.id}}"
onclick="event.stopPropagation()"
onchange="select_all(this)"
/>
</div>
</div>
<div class="oh-sticky-table__th">{% trans "Candidate" %}</div>
<div class="oh-sticky-table__th">{% trans "Email" %}</div>
<div class="oh-sticky-table__th">{% trans "Job Position" %}</div>
<div class="oh-sticky-table__th">{% trans "Mobile" %}</div>
<div class="oh-sticky-table__th">{% trans "Joining Date" %}</div>
<div class="oh-sticky-table__th">{% trans "Portal Status" %}</div>
<div class="oh-sticky-table__th">{% trans "Task Status" %}</div>
<div class="oh-sticky-table__th">{% trans "Stage" %}</div>
<div class="oh-sticky-table__th">{% trans "Options" %}</div>
{% for task in stage.onboarding_task.all %}
<div class="oh-sticky-table__th" style="width: 250px;">
<div class="d-flex align-items-center justify-content-between">
<span title="{{task}}">{{task|truncatechars:20}}</span>
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingtask or perms.onboarding.delete_onboardingtask %}
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn oh-stop-prop oh-btn--transparent oh-accordion-meta__btn"
@click="open = !open" @click.outside="open = false"
title="{% trans "Actions" %}">
<ion-icon name="ellipsis-vertical"></ion-icon>
</button>
<div class="oh-dropdown__menu oh-dropdown__menu--right" x-show="open" style="text-align:left !important">
<ul class="oh-dropdown__items">
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingtask %}
<li class="oh-dropdown__item">
<a class="oh-dropdown__link" data-toggle="oh-modal-toggle"
data-target="#editModal4"
hx-get="{% url 'task-update' task.id %}"
hx-target="#updateTask">{% trans "Edit" %}
</a>
</li>
{% endif %}
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingstage %}
<li class="oh-dropdown__item">
<a class="oh-dropdown__link mb-2">{% trans "Bulk Change Task" %}</a>
<select id="" class="w-100 bulkTaskChange" style="
border: 1px solid hsl(213deg,22%,84%);
padding: 0.3rem 0.8rem 0.3rem 0.3rem;
border-radius: 0rem;" name="stage"
data-task = "{{task.id}}" onchange = "bulkTaskChange(this)">
{% for choice in choices %}
<option value="{{choice.0}}">{{choice.1}}</option>
{% endfor %}
</select>
</li>
{% endif %}
{% if request.user|stage_manages:stage or perms.onboarding.delete_onboardingtask %}
<li class="oh-dropdown__item">
<a class="oh-dropdown__link oh-dropdown__link--danger"
href="{% url 'task-delete' task.id %}"
onclick="return confirm('Do you want to delete this task?')">{% trans "Delete" %}</a>
</li>
{% endif %}
</ul>
</div>
</div>
{% endif %}
</div>
</div>
{% endfor %}
{% if request.user|stage_manages:stage or perms.onboarding.add_onboardingtask %}
<div class="oh-sticky-table__th">
<button class="oh-btn oh-btn--small oh-btn--secondary oh-tabs__action-new-table"
data-toggle="oh-modal-toggle" data-target="#editModal2"
hx-get="{% url 'task-creation' %}?stage_id={{stage.id}}" hx-target="#taskForm">
<ion-icon class="me-1 md hydrated" name="add-outline" role="img"
aria-label="add outline"></ion-icon>{% trans "Task" %}
</button>
</div>
{% endif %}
</div>
</div>
<div class="oh-sticky-table__tbody candidate-container">
{% for candidate in stage.candidate.all %}
{% if candidate.candidate_id.recruitment_id == recruitment %}
<div class="oh-sticky-table__tr oh-multiple-table-sort__movable change-cand"
data-candidate-id="{{candidate.candidate_id}}" data-drop="candidate"
data-change-cand-id="{{candidate.candidate_id}}"
data-candidate="{{candidate.candidate_id}}"
data-job-position = "{{candidate.candidate_id.job_position_id}}"
data-join-date="{{candidate.candidate_id.joining_date}}"
data-portal-count="{{candidate.candidate_id.onboarding_portal.count}}"
data-toggle="oh-modal-toggle" data-target="#tableTimeOff"
hx-get="{% url 'candidate-single-view' candidate.candidate_id.id %}" hx-target="#singleView"
>
<div class="oh-sticky-table__sd" onclick="event.stopPropagation()">
<div class="oh-profile oh-profile--md">
<div class="centered-div">
<input
type="checkbox"
id="{{candidate.candidate_id.id}}"
value="{{candidate.candidate_id.id}}"
class="oh-input payslip-checkbox oh-input__checkbox checkbox-row"
onchange="$(this).closest('.oh-sticky-table__tr').toggleClass('highlight-selected', $(this).is(':checked'))"
/>
</div>
</div>
</div>
<div class="oh-sticky-table__td">
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
<img src="{{candidate.candidate_id.get_avatar}}"
class="oh-profile__image" alt="" />
</div>
<span class="oh-profile__name oh-text--dark">{{candidate.candidate_id}}</span>
</div>
</div>
<div class="oh-sticky-table__td">{{candidate.candidate_id.email}}</div>
<div class="oh-sticky-table__td">{{candidate.candidate_id.job_position_id}}</div>
<div class="oh-sticky-table__td">{{candidate.candidate_id.mobile}}</div>
<div class="oh-sticky-table__td dateformat_changer">{{candidate.candidate_id.joining_date}}</div>
<div class="oh-sticky-table__td">
<div class="oh-checkpoint-badge oh-checkpoint-badge--secondary" >
{% if candidate.candidate_id.onboarding_portal.count %}
{{candidate.candidate_id.onboarding_portal.count}} / 4
{% else %}
0 / 4
{% endif %}
</div>
</div>
<div class="oh-sticky-table__td">
<div class="oh-checkpoint-badge oh-checkpoint-badge--primary" >
{{candidate.task_completion_ratio}}
</div>
</div>
<div class="oh-sticky-table__td" onclick="event.stopPropagation()">
{% if request.user|stage_manages:stage or perms.onboarding.change_candidatestage %}
<select id="" class="w-100" style="
border: 1px solid hsl(213deg,22%,84%);
padding: 0.3rem 0.8rem 0.3rem 0.3rem;
border-radius: 0rem;" name="stage"
hx-post="{% url 'candidate-stage-update' candidate.candidate_id.id recruitment.id %}"
hx-trigger="change" hx-target="#onboardingTable{{recruitment.id}}">
{% for stage in recruitment.onboarding_stage.all %}
{% if candidate.onboarding_stage_id == stage %}
<option value="{{stage.id}}" selected>{{stage}}</option>
{% else %}
<option value="{{stage.id}}">{{stage}}</option>
{% endif %}
{% endfor %}
</select>
{% else %}
{% for stage in recruitment.onboarding_stage.all %}
{% if candidate.onboarding_stage_id == stage %}
{{stage}}
{% endif %}
{% endfor %}
{% endif %}
</div>
<div class="oh-sticky-table__td" onclick="event.stopPropagation()">
<button class="oh-checkpoint-badge text-success" data-toggle="oh-modal-toggle" data-target="#sendMailModal" hx-get="{% url 'send-mail' candidate.candidate_id.id %}" hx-target="#sendMailModalBody">
{% trans "Send mail" %}
</button>
</div>
{% for task in stage.onboarding_task.all %}
<div class="oh-sticky-table__td" onclick="event.stopPropagation()" id="task{{task.id}}{{candidate.candidate_id.id}}">
{% if request.user|task_manager:task or perms.onboarding.change_candidatetask %}
{% include 'onboarding/candidate_task.html' %}
{% else %}
{% for choice in choices %}
{% if choice.0 == task.status %}
{{choice.1}}
{% endif %}
{% endfor %}
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
</div>
</div><br>
{% comment %} fixed {% endcomment %}
<div class="oh-accordion-meta__body onboarding_items">
{% comment %} fixed {% endcomment %}
<div class="oh-sticky-table oh-sticky-table--no-overflow mb-5">
<div class="oh-sticky-table__table">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th" style="width:10px;">
<div class="centered-div">
<input
type="checkbox"
class="oh-input payslip-checkbox oh-input__checkbox select-all"
data-stage="#onboarding_stage{{stage.grouper.id}}"
onclick="event.stopPropagation()"
onchange="select_all(this)"
/>
</div>
</div>
<div class="oh-sticky-table__th">{% trans "Candidate" %}</div>
<div class="oh-sticky-table__th">{% trans "Email" %}</div>
<div class="oh-sticky-table__th">{% trans "Job Position" %}</div>
<div class="oh-sticky-table__th">{% trans "Mobile" %}</div>
<div class="oh-sticky-table__th">{% trans "Joining Date" %}</div>
<div class="oh-sticky-table__th">{% trans "Portal Status" %}</div>
<div class="oh-sticky-table__th">{% trans "Task Status" %}</div>
<div class="oh-sticky-table__th">{% trans "Stage" %}</div>
<div class="oh-sticky-table__th">{% trans "Options" %}</div>
{% for task in stage.grouper.onboarding_task.all %}
<div class="oh-sticky-table__th" style="width: 250px;">
<div class="d-flex align-items-center justify-content-between">
<span title="{{task}}">{{task|truncatechars:20}}</span>
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingtask or perms.onboarding.delete_onboardingtask %}
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn oh-stop-prop oh-btn--transparent oh-accordion-meta__btn"
@click="open = !open" @click.outside="open = false"
title="{% trans "Actions" %}">
<ion-icon name="ellipsis-vertical"></ion-icon>
</button>
<div class="oh-dropdown__menu oh-dropdown__menu--right" x-show="open" style="text-align:left !important">
<ul class="oh-dropdown__items">
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingtask %}
<li class="oh-dropdown__item">
<a class="oh-dropdown__link" data-toggle="oh-modal-toggle"
data-target="#editModal4"
hx-get="{% url 'task-update' task.id %}"
hx-target="#updateTask">{% trans "Edit" %}
</a>
</li>
{% endif %}
{% if request.user|stage_manages:stage or perms.onboarding.change_onboardingstage %}
<li class="oh-dropdown__item">
<a class="oh-dropdown__link mb-2">{% trans "Bulk Change Task" %}</a>
<select id="" class="w-100 bulkTaskChange" style="
border: 1px solid hsl(213deg,22%,84%);
padding: 0.3rem 0.8rem 0.3rem 0.3rem;
border-radius: 0rem;" name="stage"
data-task = "{{task.id}}" onchange = "bulkTaskChange(this)">
{% for choice in choices %}
<option value="{{choice.0}}">{{choice.1}}</option>
{% endfor %}
</select>
</li>
{% endif %}
{% if request.user|stage_manages:stage or perms.onboarding.delete_onboardingtask %}
<li class="oh-dropdown__item">
<a class="oh-dropdown__link oh-dropdown__link--danger"
href="{% url 'task-delete' task.id %}"
onclick="return confirm('Do you want to delete this task?')">{% trans "Delete" %}</a>
</li>
{% endif %}
</ul>
</div>
</div>
{% endif %}
</div>
</div>
{% endfor %}
{% if request.user|stage_manages:stage or perms.onboarding.add_onboardingtask %}
<div class="oh-sticky-table__th">
<button class="oh-btn oh-btn--small oh-btn--secondary oh-tabs__action-new-table"
data-toggle="oh-modal-toggle" data-target="#editModal2"
hx-get="{% url 'task-creation' %}?stage_id={{stage.grouper.id}}" hx-target="#taskForm">
<ion-icon class="me-1 md hydrated" name="add-outline" role="img"
aria-label="add outline"></ion-icon>
{% trans "Task" %}
</button>
</div>
{% endif %}
</div>
</div>
<div class="oh-sticky-table__tbody candidate-container">
{% for candidate in stage.list %}
{% if candidate.candidate_id.recruitment_id == recruitment %}
<div class="oh-sticky-table__tr oh-multiple-table-sort__movable change-cand"
data-candidate-id="{{candidate.candidate_id}}" data-drop="candidate"
data-change-cand-id="{{candidate.candidate_id}}"
data-candidate="{{candidate.candidate_id}}"
data-job-position = "{{candidate.candidate_id.job_position_id}}"
data-join-date="{{candidate.candidate_id.joining_date}}"
data-portal-count="{{candidate.candidate_id.onboarding_portal.count}}"
data-toggle="oh-modal-toggle" data-target="#tableTimeOff"
hx-get="{% url 'candidate-single-view' candidate.candidate_id.id %}" hx-target="#singleView"
>
<div class="oh-sticky-table__sd" onclick="event.stopPropagation()">
<div class="oh-profile oh-profile--md">
<div class="centered-div">
<input
type="checkbox"
id="{{candidate.candidate_id.id}}"
value="{{candidate.candidate_id.id}}"
class="oh-input payslip-checkbox oh-input__checkbox checkbox-row"
onchange="$(this).closest('.oh-sticky-table__tr').toggleClass('highlight-selected', $(this).is(':checked'))"
/>
</div>
</div>
</div>
<div class="oh-sticky-table__td">
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
<img src="{{candidate.candidate_id.get_avatar}}"
class="oh-profile__image" alt="" />
</div>
<span class="oh-profile__name oh-text--dark">{{candidate.candidate_id}}</span>
</div>
</div>
<div class="oh-sticky-table__td">{{candidate.candidate_id.email}}</div>
<div class="oh-sticky-table__td">{{candidate.candidate_id.job_position_id}}</div>
<div class="oh-sticky-table__td">{{candidate.candidate_id.mobile}}</div>
<div class="oh-sticky-table__td dateformat_changer">{{candidate.candidate_id.joining_date}}</div>
<div class="oh-sticky-table__td">
<div class="oh-checkpoint-badge oh-checkpoint-badge--secondary" >
{% if candidate.candidate_id.onboarding_portal.count %}
{{candidate.candidate_id.onboarding_portal.count}} / 4
{% else %}
0 / 4
{% endif %}
</div>
</div>
<div class="oh-sticky-table__td">
<div class="oh-checkpoint-badge oh-checkpoint-badge--primary" >
{{candidate.task_completion_ratio}}
</div>
</div>
<div class="oh-sticky-table__td" onclick="event.stopPropagation()">
{% if request.user|stage_manages:stage or perms.onboarding.change_candidatestage %}
<select id="" class="w-100" style="
border: 1px solid hsl(213deg,22%,84%);
padding: 0.3rem 0.8rem 0.3rem 0.3rem;
border-radius: 0rem;" name="stage"
hx-post="{% url 'candidate-stage-update' candidate.candidate_id.id recruitment.id %}"
hx-trigger="change" hx-target="#onboardingTable{{recruitment.id}}">
{% for stage in recruitment.onboarding_stage.all %}
{% if candidate.onboarding_stage_id == stage %}
<option value="{{stage.id}}" selected>{{stage}}</option>
{% else %}
<option value="{{stage.id}}">{{stage}}</option>
{% endif %}
{% endfor %}
</select>
{% else %}
{% for stage in recruitment.onboarding_stage.all %}
{% if candidate.onboarding_stage_id == stage %}
{{stage}}
{% endif %}
{% endfor %}
{% endif %}
</div>
<div class="oh-sticky-table__td" onclick="event.stopPropagation()">
<button class="oh-checkpoint-badge text-success" data-toggle="oh-modal-toggle" data-target="#sendMailModal" hx-get="{% url 'send-mail' candidate.candidate_id.id %}" hx-target="#sendMailModalBody">
{% trans "Send mail" %}
</button>
</div>
{% for task in stage.grouper.onboarding_task.all %}
<div class="oh-sticky-table__td" onclick="event.stopPropagation()" id="task{{task.id}}{{candidate.candidate_id.id}}">
{% if request.user|task_manager:task or perms.onboarding.change_candidatetask %}
{% include 'onboarding/candidate_task.html' %}
{% else %}
{% for choice in choices %}
{% if choice.0 == task.status %}
{{choice.1}}
{% endif %}
{% endfor %}
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% comment %}till heree{% endcomment %}
<div class="oh-pagination">
{% if stage.list.paginator.num_pages %}
<span class="oh-pagination__page">
{% trans "Page" %} {{ stage.list.number }} {% trans "of" %} {{ stage.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="{{stage.dynamic_name}}"
class="oh-pagination__input"
value="{{stage.list.number}}"
href="?{{pd}}"
min="1"
/>
<span class="oh-pagination__label"
>{% trans "of" %} {{stage.list.paginator.num_pages}}</span
>
</div>
<ul class="oh-pagination__items">
{% if stage.list.has_previous %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a
href="?{{pd}}&{{stage.dynamic_name}}=1"
class="oh-pagination__link"
>{% trans "First" %}</a
>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a
href="?{{pd}}&{{stage.dynamic_name}}={{ stage.list.previous_page_number }}"
class="oh-pagination__link"
>{% trans "Previous" %}</a
>
</li>
{% endif %}
{% if stage.list.has_next %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a
href="?{{pd}}&{{stage.dynamic_name}}={{ stage.list.next_page_number }}"
class="oh-pagination__link"
>{% trans "Next" %}</a
>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a
href="?{{pd}}&{{stage.dynamic_name}}={{ stage.list.paginator.num_pages }}"
class="oh-pagination__link"
>{% trans "Last" %}</a
>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
<script>
function bulkTaskChange(element){
let NewStatus = $(element).val();
let Task = $(element).data("task");
let checkbox = $("input[type='checkbox']:checked")
let ids =[]
checkbox.each(function(index){
ids.push(parseInt($(this).val()))
})
ids=ids.filter(value => !isNaN(value))
$.ajax({
type: "POST",
url: '/onboarding/candidate-task-bulk-update',
data: {
"ids": JSON.stringify(ids),
"task": Task,
"status": NewStatus,
csrfmiddlewaretoken: getCookie("csrftoken"),
},
success: function (response) {
for (let i of ids) {
var tasks = $(`[data-onboarding-task-id=${Task}][data-candidate-id=${i}]`);
tasks.val(NewStatus);
}
var alertContainer = $('<div class="oh-alert-container">');
var message = "{% trans 'Candidates stage updated successfully...' %}"
var alertDiv = $('<div class="oh-alert oh-alert--animated oh-alert--info">').text(`${ids.length} ${message}`);
alertContainer.append(alertDiv);
$(".messages").html(alertContainer);
function bulkTaskChange(element){
let NewStatus = $(element).val();
let Task = $(element).data("task");
let checkbox = $("input[type='checkbox']:checked")
let ids =[]
checkbox.each(function(index){
ids.push(parseInt($(this).val()))
})
ids=ids.filter(value => !isNaN(value))
$.ajax({
type: "POST",
url: '/onboarding/candidate-task-bulk-update',
data: {
"ids": JSON.stringify(ids),
"task": Task,
"status": NewStatus,
csrfmiddlewaretoken: getCookie("csrftoken"),
},
error: () => {
console.log("error")
}
})
}
$(document).ready(function() {
$("select[name='stage']").on("htmx:afterRequest", function(event, xhr, data) {
var alertContainer = $('<div class="oh-alert-container">');
var alertDiv = $('<div class="oh-alert oh-alert--animated oh-alert--info">').text("{% trans 'Candidate task stage updated successfully..' %}")
alertContainer.append(alertDiv);
$(".messages").html(alertContainer);
});
});
</script>
success: function (response) {
for (let i of ids) {
var tasks = $(`[data-onboarding-task-id=${Task}][data-candidate-id=${i}]`);
tasks.val(NewStatus);
}
var alertContainer = $('<div class="oh-alert-container">');
var message = "{% trans 'Candidates stage updated successfully...' %}"
var alertDiv = $('<div class="oh-alert oh-alert--animated oh-alert--info">').text(`${ids.length} ${message}`);
alertContainer.append(alertDiv);
$(".messages").html(alertContainer);
},
error: () => {
console.log("error")
}
})
}
$(document).ready(function() {
$("select[name='stage']").on("htmx:afterRequest", function(event, xhr, data) {
var alertContainer = $('<div class="oh-alert-container">');
var alertDiv = $('<div class="oh-alert oh-alert--animated oh-alert--info">').text("{% trans 'Candidate task stage updated successfully..' %}")
alertContainer.append(alertDiv);
$(".messages").html(alertContainer);
});
});
</script>

View File

@@ -43,126 +43,16 @@
<div class="oh-alert-container messages" >
</div>
<section class="oh-wrapper oh-main__topbar" x-data="{searchShow: false}">
<div class="oh-main__titlebar oh-main__titlebar--left">
<h1 class="oh-main__titlebar-title fw-bold">{% trans "Onboarding" %}</h1>
<a class="oh-main__titlebar-search-toggle" role="button" aria-label="Toggle Search"
@click="searchShow = !searchShow">
<ion-icon name="search-outline" class="oh-main__titlebar-serach-icon"></ion-icon>
</a>
</div>
<div class="oh-main__titlebar oh-main__titlebar--right">
{% if recruitments %}
<div class="oh-input-group oh-input__search-group" :class="searchShow ? 'oh-input__search-group--show' : ''">
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left"></ion-icon>
<input type="text" id="search" name='search' class="oh-input oh-input__icon" aria-label="Search Input" placeholder="{% trans 'Search' %}" />
</div>
{% endif %}
<div class="oh-switch ms-3" style="width: 30px;">
<input type="checkbox" name="is_closed" data-widget="style-widget" class="style-widget oh-switch__checkbox" {% if request.GET.closed %} checked title="{% trans 'Switch to Ongoing Recruitments' %}" {% else %} title="{% trans 'Switch to Closed Recruitments' %}" {% endif %} id="is_closed" >
</div>
{% if recruitments %}
<ul class="oh-view-types ml-2" style="margin-bottom: 0;">
<li class="oh-view-type candidate-view-type" data-view="list" title="{% trans "List" %}">
<a href="{% url 'onboarding-view' %}?closed={{status}}" hx-target="#section" class="oh-btn oh-btn--view oh-btn--view-active"><ion-icon
name="list-outline" role="img" class="md hydrated" aria-label="list outline"></ion-icon></a>
</li>
<li class="oh-view-type candidate-view-type" data-view="card" title="{% trans "Card" %}">
<a href="{% url 'kanban-view' %}?closed={{status}}" hx-target="#section" class="oh-btn oh-btn--view"><ion-icon
name="grid-outline" role="img" class="md hydrated" aria-label="grid outline"></ion-icon></a>
</li>
</ul>
<div class="oh-main__titlebar-button-container">
<div class="oh-dropdown" x-data="{open: false}">
<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" style="display: none;" @click.>
<div class="mb-3 mt-3">
<label for="job_position_id" class="oh-label">{% trans "Job position" %}</label>
<select class="" name="job_position_id" id="job_position_id">
<option value="">------------------</option>
{% for job_position in job_positions %}
<option value="{{job_position}}">{{job_position}}</option>
{% endfor %}
</select>
</div>
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<label class ="mb-2" for="join_date">{% trans "Join Date" %}</label>
<input type="date" name="join_date" id="join_date" class="oh-input w-100">
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<label class ="mb-2" for="portal_stage">{% trans "Portal Stage" %}</label>
<select class="" name="portal_stage" id="portal_stage">
<option value="">------------------</option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</div>
</div>
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Advanced" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class ="mb-2" for="join_date">{% trans "Join Date From" %}</label>
<input type="date" name="join_date" id="join_date_start" class="oh-input w-100">
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class ="mb-2" for="join_date">{% trans "Join Date To" %}</label>
<input type="date" name="join_date" id="join_date_end" class="oh-input w-100">
</div>
</div>
</div>
</div>
</div>
<div class="oh-tabs__action-bar mt-2" id="filter_item" x-on:click="open = false" >
<button class="oh-btn oh-btn--small oh-btn--secondary oh-tabs__action-new-table w-100" >
<ion-icon class="me-1 md hydrated" name="add-outline" role="img"aria-label="add outline"></ion-icon>
{% trans "Filter" %}
</button>
</div>
</div>
</div>
</div>
{% endif %}
</div>
</section>
{% include "onboarding/onboarding_view_nav.html" %}
<div class="oh-wrapper oh-filter-tag-container filter-value"></div>
<div class="oh-wrapper">
{% if recruitments %}
<div class="oh-tabs">
<ul class="oh-tabs__tablist">
{% for recruitment in recruitments %}
{% if request.user|task_manages:recruitment or perms.onboarding.view_candidatestage %}
<li class="oh-tabs__tab" {% if request.user|recruitment_manages:recruitment %} style="background-color: hsl(38.08deg 100% 50% / 8%);" {% endif %} data-target="#tab_{{recruitment.id}}">
{{recruitment}}
<span
class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2" title="{{recruitment.onboarding_stage.all|length}} {% trans 'Stage' %}" style="padding-right: 0;" onclick="event.stopPropagation()">{{recruitment.onboarding_stage.all|length}}</span>
</li>
{% endif %}
{% endfor %}
</ul>
{% include "onboarding/tabs.html" %}
<div class="oh-tabs__contents">
{% for recruitment in recruitments %}
{% if request.user|task_manages:recruitment or perms.onboarding.view_candidatestage %}
{% if request.user|task_manages:recruitment or perms.onboarding.view_candidatestage %}
<div class="oh-tabs__content" id="tab_{{recruitment.id}}">
<!-- End of Sticky Table -->
<div class="oh-card">
{% if request.user|task_manages:recruitment or perms.onboarding.add_onboardingstage %}
<div class="oh-tabs__action-bar">
@@ -174,11 +64,10 @@
</button>
</div>
{% endif %}
<div id="onboardingTable{{recruitment.id}}" class="demo">
<div id="onboardingTable{{recruitment.id}}" class="demo dd">
{% include 'onboarding/onboarding_table.html' %}
</div>
</div>
</div>
{% endif %}
{% endfor %}

View File

@@ -0,0 +1,50 @@
{% load i18n %}
<section class="oh-wrapper oh-main__topbar" x-data="{searchShow: false}">
<div class="oh-main__titlebar oh-main__titlebar--left">
<h1 class="oh-main__titlebar-title fw-bold">{% trans "Onboarding" %}</h1>
<a class="oh-main__titlebar-search-toggle" role="button" aria-label="Toggle Search"
@click="searchShow = !searchShow">
<ion-icon name="search-outline" class="oh-main__titlebar-serach-icon"></ion-icon>
</a>
</div>
<form action="" class="oh-main__titlebar oh-main__titlebar--right">
<div class="oh-input-group oh-input__search-group" :class="searchShow ? 'oh-input__search-group--show' : ''">
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left"></ion-icon>
<input type="text" value="{{request.GET.search_onboarding}}" onkeyup="setTimeout(() => {
$(this).closest('form').submit()
}, 1000);" name='search_onboarding' class="oh-input oh-input__icon" aria-label="Search Input" placeholder="{% trans 'Search' %}" />
</div>
<ul class="oh-view-types ml-2" style="margin-bottom: 0;">
<li class="oh-view-type candidate-view-type" data-view="list" title="{% trans "List" %}">
<a href="{% url 'onboarding-view' %}?{{request.GET.urlencode}}" hx-target="#section" class="oh-btn oh-btn--view {% if not card %}oh-btn--view-active{% endif %} "><ion-icon
name="list-outline" role="img" class="md hydrated" aria-label="list outline"></ion-icon></a>
</li>
<li class="oh-view-type candidate-view-type" data-view="card" title="{% trans "Card" %}">
<a href="{% url 'kanban-view' %}?{{request.GET.urlencode}}" hx-target="#section" class="oh-btn oh-btn--view {% if card %}oh-btn--view-active{% endif %}"><ion-icon
name="grid-outline" role="img" class="md hydrated" aria-label="grid outline"></ion-icon></a>
</li>
</ul>
<div class="oh-main__titlebar-button-container">
<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">
{% include "onboarding/filters.html" %}
</div>
</div>
</div>
</form>
</section>
{% include "filter_tags.html" %}
<div class="d-flex flex-row-reverse oh-wrapper">
<span onclick="$('[name=closed]').val('True'); $('[name=closed]').first().change(); $('.filterButton').click()" style="cursor: pointer;margin-left: 10px;margin-right: 10px;">
<span class="oh-dot oh-dot--small me-1" style="background-color:orangered"></span>
{% trans "Closed" %}
</span>
<span onclick="$('[name=closed]').val('');$('[name=closed]').first().change(); $('.filterButton').click()" style="cursor: pointer;margin-left: 10px;margin-right: 10px;">
<span class="oh-dot oh-dot--small me-1" style="background-color: yellowgreen"></span>
{% trans "Open" %}
</span>
</div>

View File

@@ -0,0 +1,18 @@
{% load i18n %}
{% load recruitmentfilters %}
{% load onboardingfilters %}
<ul class="oh-tabs__tablist">
{% for rec in recruitments %}
{% if request.user|task_manages:rec or perms.onboarding.view_candidatestage %}
<li class="oh-tabs__tab" data-target="#tab_{{rec.id}}" data-recruitment-id="{{rec.id}}" {% if request.user|recruitment_manages:rec %} style="background-color: hsl(38.08deg 100% 50% / 8%);" {% endif %}>
{{rec.title}}
<span
class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2" title="{{rec.stages|length}} {% trans 'Stages' %}" onclick="event.stopPropagation()">
{{rec.stages|length}}
</span>
</li>
{% endif %}
{% endfor %}
</ul>

View File

@@ -32,6 +32,7 @@ from horilla import settings
from horilla.decorators import login_required, hx_request_required
from horilla.decorators import permission_required
from base.methods import generate_pdf, get_key_instances, get_pagination, sortby
from onboarding.filters import OnboardingCandidateFilter, OnboardingStageFilter
from recruitment.forms import RejectedCandidateForm
from recruitment.models import Candidate, Recruitment, RecruitmentMailTemplate, RejectedCandidate
from recruitment.filters import CandidateFilter, RecruitmentFilter
@@ -58,6 +59,7 @@ from onboarding.decorators import (
stage_manager_can_enter,
recruitment_manager_can_enter,
)
from recruitment.pipeline_grouper import group_by_queryset
@login_required
@@ -677,6 +679,47 @@ def email_send(request):
return HttpResponse("<script>window.location.reload()</script>")
def onboarding_query_grouper(request,queryset):
"""
This method is used to make group of the onboarding records
"""
groups = []
for rec in queryset:
stages = OnboardingStageFilter(request.GET, queryset=rec.onboarding_stage.all()).qs
all_stages_grouper = []
for stage_in_all in stages.order_by("sequence"):
all_stages_grouper.append({"grouper": stage_in_all, "list": []})
data = {"recruitment": rec, "stages": []}
for stage in stages.order_by("sequence"):
stage_candidates = OnboardingCandidateFilter(
request.GET,
stage.candidate.order_by("sequence").filter(
candidate_id__is_active=True,
),
).qs
page_name = "page" + stage.stage_title + str(rec.id)
grouper = group_by_queryset(
stage_candidates,
"onboarding_stage_id",
request.GET.get(page_name),
page_name,
).object_list
data["stages"] = data["stages"] + grouper
existing_grouper_ids = {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
@all_manager_can_enter("onboarding.view_candidatestage")
@@ -690,59 +733,39 @@ def onboarding_view(request):
Returns:
GET : return onboarding view template
"""
candidates = Candidate.objects.filter(hired=True, start_onboard=True)
job_positions = JobPosition.objects.all()
# for candidate in candidates:
# recruitment =candidate.recruitment_id
# if not CandidateStage.objects.filter(candidate_id=candidate).exists():
# try:
# onboarding_stage = OnboardingStage.objects.filter(
# recruitment_id=candidate.recruitment_id
# ).order_by("sequence")[0]
# CandidateStage(
# candidate_id=candidate, onboarding_stage_id=onboarding_stage
# ).save()
# except Exception:
# messages.error(
# request,
# _("%(recruitment)s has no stage..")
# % {"recruitment": candidate.recruitment_id},
# )
# if tasks := OnboardingTask.objects.filter(
# recruitment_id=candidate.recruitment_id
# ):
# for task in tasks:
# if not CandidateTask.objects.filter(
# candidate_id=candidate, onboarding_task_id=task
# ).exists():
# CandidateTask(
# candidate_id=candidate, onboarding_task_id=task
# ).save()
recruitments = Recruitment.objects.filter(closed=False)
status = "closed"
if request.GET.get("closed") == "closed":
recruitments = Recruitment.objects.filter(closed=True)
status = "closed"
else:
status = ""
filter_obj = RecruitmentFilter(request.GET)
# is active filteration not providing on pipeline
recruitments = filter_obj.qs.filter(is_active=True)
status = request.GET.get("closed")
if not status:
recruitments = recruitments.filter(closed=False)
onboarding_stages = OnboardingStage.objects.all()
choices = CandidateTask.choice
previous_data = request.GET.urlencode()
filter_obj = RecruitmentFilter(request.GET, queryset=recruitments)
paginator = Paginator(filter_obj.qs, 4)
paginator = Paginator(recruitments, 4)
page_number = request.GET.get("page")
page_obj = paginator.get_page(page_number)
groups = onboarding_query_grouper(request,page_obj)
for item in groups:
setattr(item["recruitment"], "stages", item["stages"])
filter_dict = parse_qs(request.GET.urlencode())
if not request.GET.get("closed"):
filter_obj.form.initial["closed"] = False
filter_dict["closed"] = ["false"]
for key, val in filter_dict.copy().items():
if val[0] == "unknown" or key == "view":
del filter_dict[key]
return render(
request,
"onboarding/onboarding_view.html",
{
"recruitments": page_obj,
"rec_filter_obj": filter_obj,
"onboarding_stages": onboarding_stages,
"choices": choices,
"job_positions": job_positions,
"filter_dict": filter_dict,
"status": status,
"pd": previous_data,
},
@@ -752,42 +775,13 @@ def onboarding_view(request):
@login_required
@all_manager_can_enter("onboarding.view_candidatestage")
def kanban_view(request):
candidates = Candidate.objects.filter(hired=True, start_onboard=True)
job_positions = JobPosition.objects.all()
# for candidate in candidates:
# if not CandidateStage.objects.filter(candidate_id=candidate).exists():
# try:
# onboarding_stage = OnboardingStage.objects.filter(
# recruitment_id=candidate.recruitment_id
# ).order_by("sequence")[0]
# CandidateStage(
# candidate_id=candidate, onboarding_stage_id=onboarding_stage
# ).save()
# except Exception:
# messages.error(
# request,
# _("%(recruitment)s has no stage..")
# % {"recruitment": candidate.recruitment_id},
# )
# if tasks := OnboardingTask.objects.filter(
# recruitment_id=candidate.recruitment_id
# ):
# for task in tasks:
# if not CandidateTask.objects.filter(
# candidate_id=candidate, onboarding_task_id=task
# ).exists():
# pass
# CandidateTask(
# candidate_id=candidate, onboarding_task_id=task
# ).save()
recruitments = Recruitment.objects.filter(closed=False)
status = "closed"
if request.GET.get("closed") == "closed":
recruitments = Recruitment.objects.filter(closed=True)
status = "closed"
else:
status = ""
filter_obj = RecruitmentFilter(request.GET)
# is active filteration not providing on pipeline
recruitments = filter_obj.qs.filter(is_active=True)
status = request.GET.get("closed")
if not status:
recruitments = recruitments.filter(closed=False)
onboarding_stages = OnboardingStage.objects.all()
choices = CandidateTask.choice
stage_form = OnboardingViewStageForm()
@@ -795,22 +789,37 @@ def kanban_view(request):
previous_data = request.GET.urlencode()
filter_obj = RecruitmentFilter(request.GET, queryset=recruitments)
paginator = Paginator(filter_obj.qs, 4)
paginator = Paginator(recruitments, 4)
page_number = request.GET.get("page")
page_obj = paginator.get_page(page_number)
groups = onboarding_query_grouper(request,page_obj)
for item in groups:
setattr(item["recruitment"], "stages", item["stages"])
filter_dict = parse_qs(request.GET.urlencode())
if not request.GET.get("closed"):
filter_obj.form.initial["closed"] = False
filter_dict["closed"] = ["false"]
for key, val in filter_dict.copy().items():
if val[0] == "unknown" or key == "view":
del filter_dict[key]
return render(
request,
"onboarding/kanban/kanban.html",
{
"recruitments": page_obj,
"rec_filter_obj": filter_obj,
"onboarding_stages": onboarding_stages,
"choices": choices,
"job_positions": job_positions,
"filter_dict": filter_dict,
"stage_form": stage_form,
"status": status,
"choices": choices,
"pd": previous_data,
"card": True,
},
)
@@ -1195,7 +1204,10 @@ def candidate_stage_update(request, candidate_id, recruitment_id):
POST : return candidate task template
"""
stage_id = request.POST.get("stage")
recruitment = Recruitment.objects.get(id=recruitment_id)
recruitments = Recruitment.objects.filter(id=recruitment_id)
groups = onboarding_query_grouper(request,recruitments)
for item in groups:
setattr(item["recruitment"], "stages", item["stages"])
stage = OnboardingStage.objects.get(id=stage_id)
candidate = Candidate.objects.get(id=candidate_id)
candidate_stage = CandidateStage.objects.get(candidate_id=candidate)
@@ -1224,7 +1236,7 @@ def candidate_stage_update(request, candidate_id, recruitment_id):
request,
"onboarding/onboarding_table.html",
{
"recruitment": recruitment,
"recruitment": groups[0]["recruitment"],
"onboarding_stages": onboarding_stages,
"choices": choices,
},

View File

@@ -15,6 +15,7 @@ from recruitment.models import (
SkillZoneCandidate,
Stage,
RecruitmentSurvey,
SurveyTemplate,
)
from base.filters import FilterSet
@@ -31,7 +32,9 @@ class CandidateFilter(FilterSet):
name = django_filters.CharFilter(field_name="name", lookup_expr="icontains")
# for pipeline use
candidate_name = django_filters.CharFilter(field_name="name", lookup_expr="icontains")
candidate_name = django_filters.CharFilter(
field_name="name", lookup_expr="icontains"
)
start_date = django_filters.DateFilter(
field_name="recruitment_id__start_date",
widget=forms.DateInput(attrs={"type": "date"}),
@@ -151,6 +154,12 @@ class RecruitmentFilter(FilterSet):
FilterSet (class): custom filter set class to apply styling
"""
candidate_name = django_filters.CharFilter(
field_name="title", method="pipeline_search"
)
search_onboarding = django_filters.CharFilter(
field_name="title", method="onboarding_search"
)
description = django_filters.CharFilter(lookup_expr="icontains")
start_date = django_filters.DateFilter(
field_name="start_date", widget=forms.DateInput(attrs={"type": "date"})
@@ -226,6 +235,30 @@ class RecruitmentFilter(FilterSet):
queryset = queryset | job_queryset
return queryset.distinct()
def pipeline_search(self, queryset, _, value):
"""
This method is used to search recruitment
"""
queryset = (
queryset.filter(title__icontains=value)
| queryset.filter(stage_set__stage__icontains=value)
| queryset.filter(candidate__name__icontains=value)
)
return queryset.distinct()
def onboarding_search(self, queryset, _, value):
"""
This method is used to search recruitment
"""
queryset = (
queryset.filter(title__icontains=value)
| queryset.filter(onboarding_stage__stage_title__icontains=value)
| queryset.filter(
candidate__onboarding_stage__candidate_id__name__icontains=value
)
)
return queryset.distinct()
class StageFilter(FilterSet):
"""
@@ -236,6 +269,7 @@ class StageFilter(FilterSet):
"""
search = django_filters.CharFilter(method="filter_by_name")
candidate_name = django_filters.CharFilter(method="pipeline_search")
class Meta:
"""
@@ -261,7 +295,7 @@ class StageFilter(FilterSet):
parts = value.split()
first_name = parts[0]
last_name = " ".join(parts[1:]) if len(parts) > 1 else ""
recruitment_query = queryset.filter(recruitment_id__title__icontains=value)
# Filter the queryset by first name and last name
stage_queryset = queryset.filter(stage__icontains=value)
if first_name and last_name:
@@ -278,7 +312,17 @@ class StageFilter(FilterSet):
stage_managers__employee_last_name__icontains=last_name
)
return queryset | stage_queryset
queryset = queryset | stage_queryset | recruitment_query
return queryset
def pipeline_search(self, queryset, _, value):
"""
This method is used to search recruitment
"""
queryset = queryset.filter(stage__icontains=value) | queryset.filter(
candidate__name__icontains=value
)
return queryset.distinct()
class SurveyFilter(FilterSet):
@@ -310,6 +354,20 @@ class SurveyFilter(FilterSet):
]
class SurveyTemplateFilter(django_filters.FilterSet):
"""
SurveyTemplateFilter
"""
question = django_filters.CharFilter(
lookup_expr="icontains",
label="Title",
field_name="title",
)
class Meta:
model = SurveyTemplate
fields = "__all__"
class CandidateReGroup:
"""
Class to keep the field name for group by option
@@ -342,7 +400,6 @@ class SkillZoneFilter(FilterSet):
"skillzonecandidate_set__candidate_id__recruitment_id",
"skillzonecandidate_set__candidate_id__job_position_id",
"skillzonecandidate_set__candidate_id__stage_id__stage_type",
]