[ADD] EMPLOYEE: Disciplinary action for employees

This commit is contained in:
Horilla
2024-01-24 15:30:27 +05:30
parent 7613092218
commit 52d4875488
15 changed files with 781 additions and 11 deletions

View File

@@ -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])

View File

@@ -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",
]

View File

@@ -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__"

View File

@@ -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}"

View File

@@ -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(),
},
)

View 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 %}

View File

@@ -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>
&nbsp to &nbsp<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>

View 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>

View 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>

View File

@@ -330,5 +330,8 @@
});
});
toggleColumns("employee-table","fieldContainerTable")
if (!localStorage.getItem("employee_table")) {
$("#fieldContainerTable").find("[type=checkbox]").prop("checked",true).change()
}
</script>

View File

@@ -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>

View File

View 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

View 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"),
]