[ADD] EMPLOYEE: Disciplinary action for employees
This commit is contained in:
@@ -13,6 +13,8 @@ from employee.models import (
|
||||
EmployeeTag,
|
||||
PolicyMultipleFile,
|
||||
Policy,
|
||||
DisciplinaryAction,
|
||||
Actiontype
|
||||
)
|
||||
from simple_history.admin import SimpleHistoryAdmin
|
||||
|
||||
@@ -23,3 +25,5 @@ admin.site.register(Employee)
|
||||
admin.site.register(EmployeeBankDetails)
|
||||
admin.site.register(EmployeeWorkInformation, SimpleHistoryAdmin)
|
||||
admin.site.register([EmployeeNote, EmployeeTag, PolicyMultipleFile, Policy, BonusPoint])
|
||||
admin.site.register([DisciplinaryAction, Actiontype])
|
||||
|
||||
|
||||
@@ -4,20 +4,19 @@ filters.py
|
||||
This page is used to register filter for employee models
|
||||
|
||||
"""
|
||||
from employee.models import Policy
|
||||
from employee.models import DisciplinaryAction, Policy
|
||||
import uuid
|
||||
from django import forms
|
||||
import django_filters
|
||||
from django.contrib.auth.models import Permission, Group
|
||||
from django import forms
|
||||
from django_filters.filters import ModelChoiceFilter
|
||||
from django.utils.translation import gettext as _
|
||||
from base.methods import reload_queryset
|
||||
from base.models import WorkType
|
||||
from horilla.filters import FilterSet
|
||||
from horilla.filters import FilterSet, filter_by_name
|
||||
from employee.models import Employee
|
||||
from horilla_documents.models import Document
|
||||
from django_filters import CharFilter
|
||||
from django_filters import CharFilter, DateFilter
|
||||
|
||||
|
||||
class EmployeeFilter(FilterSet):
|
||||
@@ -292,3 +291,32 @@ class DocumentRequestFilter(FilterSet):
|
||||
"employee_id__employee_work_info__company_id",
|
||||
"employee_id__employee_work_info__shift_id",
|
||||
]
|
||||
|
||||
|
||||
class DisciplinaryActionFilter(FilterSet):
|
||||
|
||||
"""
|
||||
Custom filter for Disciplinary Action.
|
||||
|
||||
"""
|
||||
|
||||
search = CharFilter(method=filter_by_name)
|
||||
|
||||
start_date = django_filters.DateFilter(
|
||||
widget=forms.DateInput(attrs={"type": "date"}),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
||||
model = DisciplinaryAction
|
||||
fields = [
|
||||
"employee_id",
|
||||
"action",
|
||||
"employee_id__employee_work_info__job_position_id",
|
||||
"employee_id__employee_work_info__department_id",
|
||||
"employee_id__employee_work_info__work_type_id",
|
||||
"employee_id__employee_work_info__job_role_id",
|
||||
"employee_id__employee_work_info__reporting_manager_id",
|
||||
"employee_id__employee_work_info__company_id",
|
||||
"employee_id__employee_work_info__shift_id",
|
||||
]
|
||||
|
||||
@@ -28,7 +28,9 @@ from django.forms import DateInput, ModelChoiceField, TextInput
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as trans
|
||||
from employee.models import (
|
||||
Actiontype,
|
||||
BonusPoint,
|
||||
DisciplinaryAction,
|
||||
Employee,
|
||||
EmployeeWorkInformation,
|
||||
EmployeeBankDetails,
|
||||
@@ -536,3 +538,31 @@ class BonusPointRedeemForm(ModelForm):
|
||||
class Meta:
|
||||
model = BonusPoint
|
||||
fields = ["points"]
|
||||
|
||||
|
||||
|
||||
class DisciplinaryActionForm(ModelForm):
|
||||
class Meta:
|
||||
model = DisciplinaryAction
|
||||
fields = "__all__"
|
||||
exclude = ["company_id","objects"]
|
||||
|
||||
widgets = {
|
||||
"start_date": DateInput(attrs={"type": "date"}),
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["action"].widget.attrs.update(
|
||||
{
|
||||
"onchange": "actiontypechange($(this))",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class ActiontypeForm(ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Actiontype
|
||||
fields = "__all__"
|
||||
|
||||
@@ -627,4 +627,41 @@ class BonusPointThreading(threading.Thread):
|
||||
employee_id = employee
|
||||
)
|
||||
|
||||
BonusPointThreading().start()
|
||||
BonusPointThreading().start()
|
||||
|
||||
|
||||
class Actiontype(models.Model):
|
||||
"""
|
||||
Action type model
|
||||
"""
|
||||
|
||||
choice_actions = [
|
||||
("warning", trans("Warning")),
|
||||
("suspension", trans("Suspension")),
|
||||
("dismissal", trans("Dismissal")),
|
||||
]
|
||||
|
||||
title = models.CharField(max_length=50)
|
||||
action_type = models.CharField(max_length=30, choices=choice_actions)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.title}"
|
||||
|
||||
|
||||
class DisciplinaryAction(models.Model):
|
||||
"""
|
||||
Disciplinary model
|
||||
"""
|
||||
|
||||
employee_id = models.ManyToManyField(Employee)
|
||||
action = models.ForeignKey(Actiontype, on_delete=models.CASCADE)
|
||||
description = models.TextField()
|
||||
days = models.IntegerField(null=True, blank = True)
|
||||
start_date = models.DateField(null=True)
|
||||
attachment = models.FileField(upload_to="employee/discipline", null=True, blank = True)
|
||||
company_id = models.ManyToManyField(Company, blank=True)
|
||||
|
||||
objects = HorillaCompanyManager()
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.action}"
|
||||
|
||||
@@ -5,14 +5,22 @@ This module is used to write operation related to policies
|
||||
"""
|
||||
|
||||
|
||||
import json
|
||||
from django.contrib import messages
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.shortcuts import redirect, render
|
||||
from base.views import paginator_qry
|
||||
from employee.filters import PolicyFilter
|
||||
from employee.forms import PolicyForm
|
||||
from employee.models import Policy, PolicyMultipleFile
|
||||
from urllib.parse import parse_qs
|
||||
from employee.filters import DisciplinaryActionFilter, PolicyFilter
|
||||
from employee.forms import DisciplinaryActionForm, PolicyForm
|
||||
from employee.models import Actiontype, DisciplinaryAction, Policy, PolicyMultipleFile
|
||||
from horilla.decorators import permission_required, login_required
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from notifications.signals import notify
|
||||
from base.methods import (
|
||||
get_key_instances,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -83,6 +91,16 @@ def view_policy(request):
|
||||
},
|
||||
)
|
||||
|
||||
@login_required
|
||||
@permission_required("employee.delete_policy")
|
||||
def delete_policies(request):
|
||||
"""
|
||||
This method is to delete policy
|
||||
"""
|
||||
ids = request.GET.getlist("ids")
|
||||
Policy.objects.filter(id__in=ids).delete()
|
||||
messages.success(request,"Policies deleted")
|
||||
return redirect(view_policies)
|
||||
|
||||
@login_required
|
||||
@permission_required("employee.change_policy")
|
||||
@@ -125,3 +143,162 @@ def get_attachments(request):
|
||||
policy = request.GET["policy_id"]
|
||||
policy = Policy.objects.get(id=policy)
|
||||
return render(request, "policies/attachments.html", {"policy": policy})
|
||||
|
||||
|
||||
@login_required
|
||||
def disciplinary_actions(request):
|
||||
"""
|
||||
This method is used to view all Disciplinaryaction
|
||||
"""
|
||||
form = DisciplinaryActionFilter()
|
||||
queryset = DisciplinaryAction.objects.all()
|
||||
page_number = request.GET.get("page")
|
||||
page_obj = paginator_qry(queryset, page_number)
|
||||
previous_data = request.GET.urlencode()
|
||||
|
||||
return render(request,
|
||||
"disciplinary_actions/disciplinary_nav.html",
|
||||
{
|
||||
"data": page_obj,
|
||||
"pd": previous_data,
|
||||
"f": form,
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("employee.add_disciplinaryaction")
|
||||
def create_actions(request):
|
||||
"""
|
||||
Method is used to create Disciplinaryaction
|
||||
"""
|
||||
|
||||
form = DisciplinaryActionForm(request.FILES)
|
||||
employees = []
|
||||
if request.method == "POST":
|
||||
form = DisciplinaryActionForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
emp = form.cleaned_data['employee_id']
|
||||
|
||||
for i in emp:
|
||||
name = i.employee_user_id
|
||||
employees.append(name)
|
||||
|
||||
form.save()
|
||||
messages.success(request, _("Disciplinary action taken."))
|
||||
|
||||
notify.send(
|
||||
request.user.employee_get,
|
||||
recipient=employees,
|
||||
verb="Disciplinary action is taken on you.",
|
||||
verb_ar="تم اتخاذ إجراء disziplinarisch ضدك.",
|
||||
verb_de="Disziplinarische Maßnahmen wurden gegen Sie ergriffen.",
|
||||
verb_es="Se ha tomado acción disciplinaria en tu contra.",
|
||||
verb_fr="Des mesures disciplinaires ont été prises à votre encontre.",
|
||||
redirect="/employee/disciplinary-actions/",
|
||||
icon="chatbox-ellipses",
|
||||
)
|
||||
|
||||
return HttpResponse("<script>window.location.reload()</script>")
|
||||
return render(request, "disciplinary_actions/form.html", {"form": form})
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("employee.change_disciplinaryaction")
|
||||
def update_actions(request, action_id ):
|
||||
"""
|
||||
Method is used to update Disciplinaryaction
|
||||
"""
|
||||
|
||||
action = DisciplinaryAction.objects.get(id=action_id)
|
||||
form = DisciplinaryActionForm(instance = action)
|
||||
employees = []
|
||||
if request.method == "POST":
|
||||
form = DisciplinaryActionForm(request.POST, request.FILES, instance=action)
|
||||
|
||||
if form.is_valid():
|
||||
emp = form.cleaned_data['employee_id']
|
||||
|
||||
for i in emp:
|
||||
name = i.employee_user_id
|
||||
employees.append(name)
|
||||
|
||||
form.save()
|
||||
messages.success(request, _("Disciplinary action updated."))
|
||||
|
||||
notify.send(
|
||||
request.user.employee_get,
|
||||
recipient=employees,
|
||||
verb="Disciplinary action is taken on you.",
|
||||
verb_ar="تم اتخاذ إجراء disziplinarisch ضدك.",
|
||||
verb_de="Disziplinarische Maßnahmen wurden gegen Sie ergriffen.",
|
||||
verb_es="Se ha tomado acción disciplinaria en tu contra.",
|
||||
verb_fr="Des mesures disciplinaires ont été prises à votre encontre.",
|
||||
redirect="/employee/disciplinary-actions/",
|
||||
icon="chatbox-ellipses",
|
||||
)
|
||||
|
||||
return HttpResponse("<script>window.location.reload()</script>")
|
||||
return render(request, "disciplinary_actions/update_form.html", {"form": form})
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("employee.delete_disciplinaryaction")
|
||||
def delete_actions(request, action_id):
|
||||
"""
|
||||
This method is used to delete Disciplinary action
|
||||
"""
|
||||
|
||||
DisciplinaryAction.objects.filter(id = action_id).delete()
|
||||
messages.success(request, _("Disciplinary action deleted."))
|
||||
return redirect(disciplinary_actions)
|
||||
|
||||
|
||||
@login_required
|
||||
def action_type_details(request):
|
||||
"""
|
||||
This method is used to get the action type by the selection of title in the form.
|
||||
"""
|
||||
action_id = request.POST["action_type"]
|
||||
action = Actiontype.objects.get(id=action_id)
|
||||
action_type = action.action_type
|
||||
return JsonResponse({"action_type": action_type})
|
||||
|
||||
|
||||
@login_required
|
||||
def disciplinary_filter_view(request):
|
||||
"""
|
||||
This method is used to filter Disciplinary Action.
|
||||
"""
|
||||
|
||||
previous_data = request.GET.urlencode()
|
||||
dis_filter = DisciplinaryActionFilter(request.GET).qs
|
||||
page_number = request.GET.get("page")
|
||||
page_obj = paginator_qry(dis_filter, page_number)
|
||||
data_dict = parse_qs(previous_data)
|
||||
get_key_instances(DisciplinaryAction, data_dict)
|
||||
return render(
|
||||
request,
|
||||
"disciplinary_actions/disciplinary_records.html",
|
||||
{
|
||||
"data": page_obj,
|
||||
"pd": previous_data,
|
||||
"filter_dict": data_dict,
|
||||
"dashboard": request.GET.get("dashboard"),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def search_disciplinary(request):
|
||||
"""
|
||||
This method is used to search in Disciplinary Actions
|
||||
"""
|
||||
disciplinary = DisciplinaryActionFilter(request.GET).qs
|
||||
return render(
|
||||
request,
|
||||
"disciplinary_actions/disciplinary_records.html",
|
||||
{
|
||||
"data": paginator_qry(disciplinary, request.GET.get("page")),
|
||||
"pd": request.GET.urlencode(),
|
||||
},
|
||||
)
|
||||
|
||||
197
employee/templates/disciplinary_actions/disciplinary_nav.html
Normal file
197
employee/templates/disciplinary_actions/disciplinary_nav.html
Normal file
@@ -0,0 +1,197 @@
|
||||
{% extends 'index.html' %}
|
||||
{% block content %}
|
||||
{% load i18n %}
|
||||
<section class="oh-wrapper oh-main__topbar" style="padding-bottom: 1rem;">
|
||||
<div class="oh-main__titlebar oh-main__titlebar--left oh-d-flex-column--resp oh-mb-3--small">
|
||||
<h1 class="oh-main__titlebar-title fw-bold">{% trans 'Disciplinary Actions' %}</h1>
|
||||
</div>
|
||||
|
||||
<div class="oh-main__titlebar oh-main__titlebar--right oh-d-flex-column--resp oh-mb-3--small">
|
||||
|
||||
{% if perms.employee.add_disciplinaryaction %}
|
||||
|
||||
<div class="oh-main__titlebar-button-container">
|
||||
<div class="oh-input-group oh-input__search-group mr-4">
|
||||
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left md hydrated" role="img" aria-label="search outline"></ion-icon>
|
||||
<input hx-get="{% url 'search-disciplinary' %}" name="search" hx-trigger="keyup changed delay:.2s" hx-target="#policyContainer" type="text" placeholder="Search" style="margin-right:10px" class="oh-input oh-input__icon mr-3" autocomplete="false" aria-label="Search Input" />
|
||||
</div>
|
||||
<form
|
||||
hx-get="{% url 'disciplinary-filter-view' %}"
|
||||
hx-target="#policyContainer"
|
||||
id="filterForm"
|
||||
class="d-flex"
|
||||
>
|
||||
<div class="oh-dropdown" x-data="{open: false}">
|
||||
<button
|
||||
class="oh-btn ml-2"
|
||||
@click="open = !open"
|
||||
onclick="event.preventDefault()"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
<div class="oh-dropdown__filter-body">
|
||||
<div class="oh-accordion">
|
||||
<div class="oh-accordion-header">{% trans "Disciplinary Action" %}</div>
|
||||
<div class="oh-accordion-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12 col-lg-12">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label" for="{{f.form.employee_id.id_for_label}}">{% trans "Employee" %}</label>
|
||||
{{f.form.employee_id}}
|
||||
</div>
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label" for ="{{f.form.action.id_for_label}}"
|
||||
>{% trans "Action Taken" %}</label
|
||||
>
|
||||
{{f.form.action}}
|
||||
</div>
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label" for="{{f.form.start_date.id_for_label}}">{% trans "Date" %}</label>
|
||||
{{f.form.start_date}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="oh-accordion">
|
||||
<div class="oh-accordion-header">{% trans "Work Information" %}</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" for="{{f.form.employee_id__employee_work_info__company_id.id_for_label}}">{% trans "Company" %}</label>
|
||||
{{f.form.employee_id__employee_work_info__company_id}}
|
||||
</div>
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label" for ="{{f.form.employee_id__employee_work_info__department_id_for_label}}"
|
||||
>{% trans "Department" %}</label
|
||||
>
|
||||
{{f.form.employee_id__employee_work_info__department_id}}
|
||||
</div>
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label" for="{{f.form.employee_id__employee_work_info__shift_id.id_for_label}}">{% trans "Shift" %}</label>
|
||||
{{f.form.employee_id__employee_work_info__shift_id}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label" for ="{{f.form.employee_id__employee_work_info__reporting_manager_id.id_for_label}}"
|
||||
>{% trans "Reporting Manager" %}</label
|
||||
>
|
||||
{{f.form.employee_id__employee_work_info__reporting_manager_id}}
|
||||
</div>
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label" for="{{f.form.employee_id__employee_work_info__job_position_id.id_for_label}}">{% trans "Job Position" %}</label>
|
||||
{{f.form.employee_id__employee_work_info__job_position_id}}
|
||||
</div>
|
||||
<div class="oh-input-group">
|
||||
<label class="oh-label" for="{{f.form.employee_id__employee_work_info__work_type_id.id_for_label}}">{% trans "Work Type" %}</label>
|
||||
{{f.form.employee_id__employee_work_info__work_type_id}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="oh-dropdown__filter-footer">
|
||||
<button
|
||||
class="oh-btn oh-btn--secondary oh-btn--small w-100 filterButton"
|
||||
>
|
||||
{% trans "Filter" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="oh-main__titlebar-button-container">
|
||||
<a hx-get="{% url 'create-actions' %}" hx-target="#createannouncementForm" hx-swap="innerHTML" data-toggle="oh-modal-toggle" data-target="#anouncementModal" class="oh-btn oh-btn--secondary">
|
||||
<ion-icon name="add-outline"></ion-icon>
|
||||
{% trans 'Take An Action' %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="oh-modal" id="policyModal" 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" aria-label="Close"><ion-icon name="close-outline"></ion-icon></button>
|
||||
</div>
|
||||
|
||||
<div class="oh-modal__dialog-body" id="policyModalBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- start of create modal -->
|
||||
<div
|
||||
class="oh-modal"
|
||||
id="anouncementModal"
|
||||
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 "Take An Action." %}
|
||||
</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="createannouncementForm"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end of create modal -->
|
||||
|
||||
|
||||
<!-- start of update modal -->
|
||||
<div
|
||||
class="oh-modal"
|
||||
id="announcementUpdateModal"
|
||||
role="dialog"
|
||||
aria-labelledby="announcementUpdateModal"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="oh-modal__dialog">
|
||||
<div class="oh-modal__dialog-header">
|
||||
<h5 class="oh-modal__dialog-title" id="announcementUpdateModalLabel"
|
||||
>{% trans "Edit Action." %}</span
|
||||
>
|
||||
<button class="oh-modal__close" aria-label="Close" >
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oh-modal__dialog-body" id='announcementUpdate'>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end of update modal -->
|
||||
|
||||
|
||||
<div class="oh-wrapper" id="policyContainer">
|
||||
{% include 'disciplinary_actions/disciplinary_records.html' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,187 @@
|
||||
{% load basefilters %}
|
||||
{% load attendancefilters %}
|
||||
{% load employee_filter %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% include 'filter_tags.html' %}
|
||||
|
||||
|
||||
<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">
|
||||
{% trans "Employee" %}
|
||||
</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Action Taken" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Action Date" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Attachments" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Description" %}</div>
|
||||
{% if perms.payroll.change_disciplinaryaction or perms.payroll.delete_disciplinaryaction %}
|
||||
<div class="oh-sticky-table__th">{% trans "Options" %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for i in data %}
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__td">
|
||||
{% for emp in i.employee_id.all %}
|
||||
<div class="oh-profile oh-profile--md mt-2">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="{{ emp.get_avatar }}" class="oh-profile__image" alt="{{ emp }}">
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark">{{ emp }}</span>
|
||||
</div><br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if i.action.action_type == 'suspension' %}
|
||||
<div class="oh-sticky-table__td">{{ i.action }}
|
||||
<p class="fw-bold mt-2">{% trans "Suspended for" %} {{ i.days }} {% trans "days." %}</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="oh-sticky-table__td">{{ i.action }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if i.action.action_type == 'suspension' %}
|
||||
<div class="oh-sticky-table__td">
|
||||
<span class="dateformat_changer">{{ i.start_date }}</span>
|
||||
  to  <span class="dateformat_changer">{{ i.start_date | add_days:i.days }}</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="oh-sticky-table__td dateformat_changer">{{ i.start_date }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if i.attachment %}
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="oh-helpdesk_attached--content">
|
||||
<div class="oh-helpdesk__attachment-icon">
|
||||
<a href="{{ i.attachment.url }}" target="_blank"><span class="oh-file-icon oh-file-icon--pdf"></span></a>
|
||||
</div>
|
||||
<a href="{{ i.attachment.url }}" target="_blank"><span class="oh-helpdesk__filename">{% trans "View File" %}</span></a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="oh-sticky-table__td">{% trans "No file has been uploaded." %}</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="oh-sticky-table__td">{{ i.description }}</div>
|
||||
|
||||
{% if perms.payroll.change_disciplinaryaction or perms.payroll.delete_disciplinaryaction %}
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="oh-btn-group" >
|
||||
{% if perms.payroll.change_disciplinaryaction %}
|
||||
<a hx-get="{% url 'update-actions' i.id %}" hx-target='#announcementUpdate' data-toggle='oh-modal-toggle' data-target="#announcementUpdateModal" class="oh-btn oh-btn--light-bkg w-50" title="{% trans 'Edit' %}">
|
||||
<ion-icon name="create-outline"></ion-icon></a>
|
||||
{% endif %}
|
||||
{% if perms.payroll.delete_disciplinaryaction %}
|
||||
<form action="{% url 'delete-actions' i.id %}" onsubmit="return confirm('{% trans "Are you sure you want to delete this disciplinary action?" %}');" method='post' class="w-50">
|
||||
{% csrf_token %}
|
||||
<button 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>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Pagination Start-->
|
||||
|
||||
<div class="oh-pagination">
|
||||
<span class="oh-pagination__page">
|
||||
{% trans "Page" %} {{ data.number }} {% trans "of" %} {{ data.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="{{data.number}}"
|
||||
hx-get="{% url 'disciplinary-filter-view' %}?{{pd}}"
|
||||
hx-target="#policyContainer"
|
||||
min="1"
|
||||
/>
|
||||
<span class="oh-pagination__label"
|
||||
>{% trans "of" %} {{data.paginator.num_pages}}</span
|
||||
>
|
||||
</div>
|
||||
<ul class="oh-pagination__items">
|
||||
{% if data.has_previous %}
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-target="#policyContainer"
|
||||
hx-get="{% url 'disciplinary-filter-view' %}?{{pd}}&page=1"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "First" %}</a
|
||||
>
|
||||
</li>
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-target="#policyContainer"
|
||||
hx-get="{% url 'disciplinary-filter-view' %}?{{pd}}&page={{ data.previous_page_number }}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "Previous" %}</a
|
||||
>
|
||||
</li>
|
||||
{% endif %} {% if data.has_next %}
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-target="#policyContainer"
|
||||
hx-get="{% url 'disciplinary-filter-view' %}?{{pd}}&page={{ data.next_page_number }}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "Next" %}</a
|
||||
>
|
||||
</li>
|
||||
<li class="oh-pagination__item oh-pagination__item--wide">
|
||||
<a
|
||||
hx-target="#policyContainer"
|
||||
hx-get="{% url 'disciplinary-filter-view' %}?{{pd}}&page={{ data.paginator.num_pages }}"
|
||||
class="oh-pagination__link"
|
||||
>{% trans "Last" %}</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Pagination End-->
|
||||
|
||||
|
||||
<script>
|
||||
function actiontypechange(selectElement) {
|
||||
var selectedActiontype = selectElement.val();
|
||||
|
||||
let parentForm = selectElement.parents().closest("form");
|
||||
|
||||
$.ajax({
|
||||
type: "post",
|
||||
url: "{% url 'action-type-details' %}",
|
||||
data: {
|
||||
csrfmiddlewaretoken: getCookie("csrftoken"),
|
||||
"action_type": selectedActiontype,
|
||||
},
|
||||
success: function (response) {
|
||||
console.log(response.action_type);
|
||||
|
||||
// Check if the response.action_type is "suspension"
|
||||
if (response.action_type === "suspension") {
|
||||
// Show the 'days' field
|
||||
parentForm.find('#daysDiv').show();
|
||||
parentForm.find('[name=days]').prop('required', true);
|
||||
} else {
|
||||
// Hide the 'days' field
|
||||
parentForm.find('#daysDiv').hide();
|
||||
parentForm.find('[name=days]').prop('required', false);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
35
employee/templates/disciplinary_actions/form.html
Normal file
35
employee/templates/disciplinary_actions/form.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{% load i18n %}
|
||||
|
||||
<form hx-post="{% url 'create-actions' %}" hx-target="#createannouncementForm"
|
||||
method="post" hx-encoding="multipart/form-data" id="disciplinaryActionForm">
|
||||
{% csrf_token %}
|
||||
|
||||
<div id="employeeIdDiv">
|
||||
<label class="oh-input__label">{% trans "Employee" %}</label>
|
||||
{{ form.employee_id }}
|
||||
</div>
|
||||
<div id="actionDiv">
|
||||
<label class="oh-input__label">{% trans "Action" %}</label>
|
||||
{{ form.action }}
|
||||
</div>
|
||||
<div id="daysDiv" style="display: none;">
|
||||
<label class="oh-input__label">{% trans "Days" %}</label>
|
||||
{{ form.days }}
|
||||
</div>
|
||||
<div id="startdateDiv">
|
||||
<label class="oh-input__label">{% trans "Action Date" %}</label>
|
||||
{{ form.start_date }}
|
||||
</div>
|
||||
|
||||
<div id="descriptionDiv">
|
||||
<label class="oh-input__label">{% trans "Description" %}</label>
|
||||
{{ form.description }}
|
||||
</div>
|
||||
<div id="attachmentDiv">
|
||||
<label class="oh-input__label">{% trans "Attachment" %}</label>
|
||||
{{ form.attachment }}
|
||||
</div>
|
||||
|
||||
<button type="submit" class="oh-btn oh-btn--secondary">{% trans "Submit" %}</button>
|
||||
</form>
|
||||
|
||||
49
employee/templates/disciplinary_actions/update_form.html
Normal file
49
employee/templates/disciplinary_actions/update_form.html
Normal file
@@ -0,0 +1,49 @@
|
||||
{% load i18n %}
|
||||
{% if form.errors %}
|
||||
<!-- form errors -->
|
||||
<div class="oh-wrapper">
|
||||
<div class="oh-alert-container">
|
||||
{% for error in form.non_field_errors %}
|
||||
<div class="oh-alert oh-alert--animated oh-alert--danger">
|
||||
{{ error }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<form
|
||||
hx-post="{% url 'update-actions' form.instance.id %}"
|
||||
hx-target="#announcementUpdate"
|
||||
method="post"
|
||||
hx-encoding="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<div id="employeeIdDiv">
|
||||
<label class="oh-input__label">{% trans "Employee" %}</label>
|
||||
{{ form.employee_id }}
|
||||
</div>
|
||||
<div id="actionDiv">
|
||||
<label class="oh-input__label">{% trans "Action" %}</label>
|
||||
{{ form.action }}
|
||||
</div>
|
||||
<div id="daysDiv" style="display: none;">
|
||||
<label class="oh-input__label">{% trans "Days" %}</label>
|
||||
{{ form.days }}
|
||||
</div>
|
||||
|
||||
<div id="startdateDiv">
|
||||
<label class="oh-input__label">{% trans "Action Date" %}</label>
|
||||
{{ form.start_date }}
|
||||
</div>
|
||||
|
||||
<div id="descriptionDiv">
|
||||
<label class="oh-input__label">{% trans "Description" %}</label>
|
||||
{{ form.description }}
|
||||
</div>
|
||||
<div id="attachmentDiv">
|
||||
<label class="oh-input__label">{% trans "Attachment" %}</label>
|
||||
{{ form.attachment }}
|
||||
</div>
|
||||
|
||||
<button type="submit" class="oh-btn oh-btn--secondary">{% trans "Submit" %}</button>
|
||||
</form>
|
||||
|
||||
@@ -330,5 +330,8 @@
|
||||
});
|
||||
});
|
||||
toggleColumns("employee-table","fieldContainerTable")
|
||||
if (!localStorage.getItem("employee_table")) {
|
||||
$("#fieldContainerTable").find("[type=checkbox]").prop("checked",true).change()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<a hx-get="{% url 'create-policy' %}?instance_id={{ policy.id }}" hx-target="#policyModalBody" data-toggle="oh-modal-toggle" data-target="#policyModal" title="Edit" style="cursor: pointer;"><ion-icon name="create-outline" role="img" class="md hydrated" aria-label="copy outline"></ion-icon></a>
|
||||
{% endif %}
|
||||
{% if perms.employee.delete_policy %}
|
||||
<a href="/recruitment/delete-mail-template/?ids=1" class="text-danger" style="cursor: pointer;" onclick="return confirm('Do you want to delete this policy?')" title="Delete"><ion-icon name="trash-outline" role="img" class="md hydrated" aria-label="trash outline"></ion-icon></a>
|
||||
<a href="{% url "delete-policies" %}?ids={{policy.id}}" class="text-danger" style="cursor: pointer;" onclick="return confirm('Do you want to delete this policy?')" title="Delete"><ion-icon name="trash-outline" role="img" class="md hydrated" aria-label="trash outline"></ion-icon></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</h3>
|
||||
|
||||
0
employee/templatetags/__init__ .py
Normal file
0
employee/templatetags/__init__ .py
Normal file
12
employee/templatetags/employee_filter.py
Normal file
12
employee/templatetags/employee_filter.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django import template
|
||||
from datetime import timedelta
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.filter(name='add_days')
|
||||
def add_days(value, days):
|
||||
# Check if value is not None before adding days
|
||||
if value is not None:
|
||||
return value + timedelta(days=days)
|
||||
else:
|
||||
return None
|
||||
0
employee/templatetags/migrations/__init__.py
Normal file
0
employee/templatetags/migrations/__init__.py
Normal file
@@ -271,4 +271,15 @@ urlpatterns = [
|
||||
views.document_delete,
|
||||
name="document-delete",
|
||||
),
|
||||
|
||||
path("delete-policies",policies.delete_policies,name="delete-policies"),
|
||||
|
||||
path("disciplinary-actions/", policies.disciplinary_actions, name="disciplinary-actions"),
|
||||
path("create-actions", policies.create_actions, name="create-actions"),
|
||||
path("update-actions/<int:action_id>/", policies.update_actions, name="update-actions"),
|
||||
path("delete-actions/<int:action_id>/",policies.delete_actions, name="delete-actions"),
|
||||
path("action-type-details",policies.action_type_details,name="action-type-details",),
|
||||
path("disciplinary-filter-view", policies.disciplinary_filter_view, name="disciplinary-filter-view"),
|
||||
path("search-disciplinary", policies.search_disciplinary, name="search-disciplinary"),
|
||||
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user