[ADD] CONFIGURATION: Conditional approval option in leave request
This commit is contained in:
@@ -282,3 +282,5 @@ _("ticket-detail"),
|
||||
_("ticket-type-view"),
|
||||
_("tag-view"),
|
||||
_("mail-server-conf"),
|
||||
_("configuration"),
|
||||
_("multiple-approval-condition"),
|
||||
@@ -4,11 +4,13 @@ from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from base.models import MultipleApprovalManagers
|
||||
from employee.models import Employee, EmployeeWorkInformation
|
||||
from django.contrib import messages
|
||||
from django.shortcuts import render
|
||||
from horilla.settings import TEMPLATES, BASE_DIR
|
||||
from horilla import settings
|
||||
from leave.models import LeaveRequestConditionApproval
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -81,8 +83,19 @@ def manager_can_enter(function, perm):
|
||||
"""
|
||||
|
||||
def _function(request, *args, **kwargs):
|
||||
leave_perm = [
|
||||
"leave.view_leaverequest",
|
||||
"leave.change_leaverequest",
|
||||
"leave.delete_leaverequest",
|
||||
]
|
||||
user = request.user
|
||||
employee = Employee.objects.filter(employee_user_id=user).first()
|
||||
if perm in leave_perm:
|
||||
is_approval_manager = MultipleApprovalManagers.objects.filter(
|
||||
employee_id=employee.id
|
||||
).exists()
|
||||
if is_approval_manager:
|
||||
return function(request, *args, **kwargs)
|
||||
is_manager = EmployeeWorkInformation.objects.filter(
|
||||
reporting_manager_id=employee
|
||||
).exists()
|
||||
@@ -116,7 +129,7 @@ def login_required(view_func):
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
if not settings.DEBUG:
|
||||
return render(request,"went_wrong.html")
|
||||
return render(request, "went_wrong.html")
|
||||
return view_func(request, *args, **kwargs)
|
||||
return func
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -87,6 +87,7 @@ sidebar_urls = [
|
||||
"tag-view",
|
||||
"ticket-type-view",
|
||||
"mail-server-conf",
|
||||
"multiple-approval-condition",
|
||||
]
|
||||
remove_urls = [
|
||||
"objective-detailed-view",
|
||||
|
||||
@@ -3,7 +3,15 @@ Module for registering LeaveType, LeaveRequest, AvailableLeave, Holiday, and Com
|
||||
models with the Django admin site.
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from .models import LeaveType, LeaveRequest, AvailableLeave, Holiday, CompanyLeave,LeaveAllocationRequest
|
||||
from .models import (
|
||||
LeaveRequestConditionApproval,
|
||||
LeaveType,
|
||||
LeaveRequest,
|
||||
AvailableLeave,
|
||||
Holiday,
|
||||
CompanyLeave,
|
||||
LeaveAllocationRequest,
|
||||
)
|
||||
|
||||
|
||||
# Register your models here.
|
||||
@@ -13,3 +21,4 @@ admin.site.register(AvailableLeave)
|
||||
admin.site.register(Holiday)
|
||||
admin.site.register(CompanyLeave)
|
||||
admin.site.register(LeaveAllocationRequest)
|
||||
admin.site.register(LeaveRequestConditionApproval)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import calendar
|
||||
from collections.abc import Iterable
|
||||
from datetime import datetime, timedelta
|
||||
import operator
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.core.exceptions import ValidationError
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from base import thread_local_middleware
|
||||
from base.models import Company, MultipleApprovalCondition
|
||||
from base.horilla_company_manager import HorillaCompanyManager
|
||||
from employee.models import Employee
|
||||
@@ -14,6 +16,15 @@ from django.core.files.storage import default_storage
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
operator_mapping = {
|
||||
"equal": operator.eq,
|
||||
"notequal": operator.ne,
|
||||
"lt": operator.lt,
|
||||
"gt": operator.gt,
|
||||
"le": operator.le,
|
||||
"ge": operator.ge,
|
||||
"icontains": operator.contains,
|
||||
}
|
||||
# Create your models here.
|
||||
BREAKDOWN = [
|
||||
("full_day", _("Full Day")),
|
||||
@@ -522,15 +533,23 @@ class LeaveRequest(models.Model):
|
||||
department_id = self.employee_id.employee_work_info.department_id
|
||||
requested_days = self.requested_days
|
||||
applicable_condition = False
|
||||
conditions = MultipleApprovalCondition.objects.filter(department=department_id)
|
||||
for condition in conditions:
|
||||
operator = condition.condition_operator
|
||||
if operator == "range":
|
||||
start_value = float(condition.condition_start_value)
|
||||
end_value = float(condition.condition_end_value)
|
||||
if start_value <= requested_days <= end_value:
|
||||
applicable_condition = condition
|
||||
break
|
||||
conditions = MultipleApprovalCondition.objects.filter(department=department_id).order_by('condition_value')
|
||||
if conditions:
|
||||
for condition in conditions:
|
||||
operator = condition.condition_operator
|
||||
if operator == "range":
|
||||
start_value = float(condition.condition_start_value)
|
||||
end_value = float(condition.condition_end_value)
|
||||
if start_value <= requested_days <= end_value:
|
||||
applicable_condition = condition
|
||||
break
|
||||
else:
|
||||
operator_func = operator_mapping.get(condition.condition_operator)
|
||||
condition_value = type(requested_days)(condition.condition_value)
|
||||
if operator_func(requested_days, condition_value):
|
||||
applicable_condition = condition
|
||||
break
|
||||
|
||||
if applicable_condition and self.status=="requested":
|
||||
LeaveRequestConditionApproval.objects.filter(leave_request_id=self).delete()
|
||||
sequence = 0
|
||||
@@ -593,7 +612,7 @@ class LeaveRequest(models.Model):
|
||||
self.status = "approved"
|
||||
available_leave.save()
|
||||
|
||||
def conditional_approvals(self, *args, **kwargs):
|
||||
def multiple_approvals(self, *args, **kwargs):
|
||||
approvals = LeaveRequestConditionApproval.objects.filter(leave_request_id=self)
|
||||
requested_query = approvals.filter(is_approved=False).order_by("sequence")
|
||||
approved_query = approvals.filter(is_approved=True).order_by("sequence")
|
||||
@@ -605,10 +624,21 @@ class LeaveRequest(models.Model):
|
||||
"managers": managers,
|
||||
"approved": approved_query,
|
||||
"requested": requested_query,
|
||||
"approvals":approvals,
|
||||
}
|
||||
else:
|
||||
result = False
|
||||
return result
|
||||
|
||||
def is_approved(self):
|
||||
request = getattr(thread_local_middleware._thread_locals,"request",None)
|
||||
if request:
|
||||
employee = Employee.objects.filter(employee_user_id = request.user).first()
|
||||
condition_approval = LeaveRequestConditionApproval.objects.filter(leave_request_id=self,manager_id = employee.id).first()
|
||||
if condition_approval:
|
||||
return not condition_approval.is_approved
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class LeaveAllocationRequest(models.Model):
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
{% load i18n %}
|
||||
{% if messages %}
|
||||
<div class="oh-wrapper">
|
||||
{% for message in messages %}
|
||||
<div class="oh-alert-container">
|
||||
<div class="oh-alert oh-alert--animated {{ message.tags }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<script>
|
||||
setTimeout(() => {
|
||||
$('.oh-modal__close').click();
|
||||
}, 1000);
|
||||
</script>
|
||||
{% endif %}
|
||||
{% if form.errors %}
|
||||
<!-- form errors -->
|
||||
<div class="oh-wrapper">
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
{% load i18n %}
|
||||
{% if messages %}
|
||||
<div class="oh-wrapper">
|
||||
{% for message in messages %}
|
||||
<div class="oh-alert-container">
|
||||
<div class="oh-alert oh-alert--animated {{ message.tags }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<script>
|
||||
setTimeout(() => {
|
||||
$('.oh-modal__close').click();
|
||||
}, 1000);
|
||||
</script>
|
||||
{% endif %}
|
||||
{% if form.errors %}
|
||||
<!-- form errors -->
|
||||
<div class="oh-wrapper">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends 'index.html' %} {% block content %} {% load static %} {% load i18n %}
|
||||
<!-- start of message -->
|
||||
{% if messages %}
|
||||
{% comment %} {% if messages %}
|
||||
<div class="oh-wrapper">
|
||||
{% for message in messages %}
|
||||
<div class="oh-alert-container">
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %} {% endcomment %}
|
||||
<!-- end of messages -->
|
||||
|
||||
<!-- start of nav bar -->
|
||||
@@ -194,7 +194,9 @@
|
||||
<span class="oh-modal__dialog-title" id="editDialogDialog"
|
||||
>{% trans "Create Holiday" %}</span
|
||||
>
|
||||
<button class="oh-modal__close" aria-label="Close">
|
||||
<button class="oh-modal__close" aria-label="Close"
|
||||
hx-get="{% url 'holiday-filter' %}" hx-target="#holidays"
|
||||
>
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
@@ -217,7 +219,9 @@
|
||||
<span class="oh-modal__dialog-title" id="editDialogDialog"
|
||||
>{% trans "Update Holiday" %}</span
|
||||
>
|
||||
<button class="oh-modal__close" aria-label="Close">
|
||||
<button class="oh-modal__close" aria-label="Close"
|
||||
hx-get="{% url 'holiday-filter' %}" hx-target="#holidays"
|
||||
>
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
{% if not dashboard %}
|
||||
<div class="oh-sticky-table__th" >{% trans "Penalties" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Options" %}</div>
|
||||
{% if request.user|is_reportingmanager or perms.leave.chanage_leaverequest or perms.leave.delete_leaverequest %}
|
||||
{% if request.user|is_reportingmanager or perms.leave.chanage_leaverequest or perms.leave.delete_leaverequest or request.user|is_leave_approval_manager %}
|
||||
<div class="oh-sticky-table__th">{% trans "Actions" %}</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -114,7 +114,15 @@
|
||||
<div class="oh-sticky-table__td {% if leave_request.status == 'cancelled' %} diff-cell{% endif %} dateformat_changer">{{leave_request.start_date}}</div>
|
||||
<div class="oh-sticky-table__td {% if leave_request.status == 'cancelled' %} diff-cell{% endif %} dateformat_changer">{{leave_request.end_date}}</div>
|
||||
<div class="oh-sticky-table__td {% if leave_request.status == 'cancelled' %} diff-cell{% endif %}">{{leave_request.requested_days}}</div>
|
||||
<div class="oh-sticky-table__td {% if leave_request.status == 'cancelled' %} diff-cell{% endif %}">{{leave_request.get_status_display}}</div>
|
||||
<div class="oh-sticky-table__td {% if leave_request.status == 'cancelled' %} diff-cell{% endif %}">
|
||||
{% if leave_request.multiple_approvals and leave_request.status == "requested" %}
|
||||
<div class="oh-checkpoint-badge oh-checkpoint-badge--secondary" title="{% for manager in leave_request.multiple_approvals.managers %}{{ manager }}{% if not forloop.last %} , {% endif %}{% endfor %}">
|
||||
{{leave_request.multiple_approvals.approved|length}} / {{leave_request.multiple_approvals.managers|length}} {% trans "Approved" %}
|
||||
</div>
|
||||
{% else %}
|
||||
{{leave_request.get_status_display}}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if not dashboard %}
|
||||
<div class="oh-sticky-table__td">
|
||||
{% if leave_request.get_penalties_count %}
|
||||
@@ -123,7 +131,8 @@
|
||||
</div>
|
||||
<div class="oh-sticky-table__td" onclick="event.stopPropagation()">
|
||||
<div class="oh-btn-group" >
|
||||
{% if leave_request.status == 'requested' %}
|
||||
|
||||
{% if leave_request.is_approved and leave_request.status == 'requested' %}
|
||||
<a type="submit" href="{% url 'request-approve' leave_request.id %}" title="{% trans 'Approve' %}"
|
||||
class="oh-btn oh-btn--success w-100">
|
||||
<ion-icon class="me-1" name="checkmark-outline"></ion-icon>
|
||||
@@ -154,7 +163,7 @@
|
||||
</div>
|
||||
<div class="oh-sticky-table__td" onclick="event.stopPropagation()">
|
||||
<div class="oh-btn-group">
|
||||
{% if request.user|is_reportingmanager or perms.attendance.chanage_penaltyaccount %}
|
||||
{% if request.user|is_reportingmanager or perms.attendance.chanage_penaltyaccount or request.user|is_leave_approval_manager %}
|
||||
<button
|
||||
data-toggle="oh-modal-toggle"
|
||||
data-target="#penaltyModal"
|
||||
@@ -166,13 +175,13 @@
|
||||
<ion-icon name="information-circle-outline"></ion-icon>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if request.user|is_reportingmanager or perms.leave.chanage_leaverequest or perms.leave.delete_leaverequest %}
|
||||
{% if request.user|is_reportingmanager or perms.leave.chanage_leaverequest %}
|
||||
{% if request.user|is_reportingmanager or perms.leave.chanage_leaverequest or perms.leave.delete_leaverequest or request.user|is_leave_approval_manager%}
|
||||
{% if request.user|is_reportingmanager or perms.leave.chanage_leaverequest or request.user|is_leave_approval_manager %}
|
||||
<button class="oh-btn oh-btn--light-bkg w-100" title="{% trans 'Edit' %}" data-toggle="oh-modal-toggle"
|
||||
data-target="#editModal2" hx-get="{% url 'request-update' leave_request.id %}"
|
||||
hx-target="#updateForm"><ion-icon name="create-outline"></ion-icon></button>
|
||||
{% endif %}
|
||||
{% if request.user|is_reportingmanager or perms.leave.delete_leaverequest %}
|
||||
{% if request.user|is_reportingmanager or perms.leave.delete_leaverequest or request.user|is_leave_approval_manager %}
|
||||
<a class="oh-btn oh-btn--danger-outline oh-btn--light-bkg w-100" id="delete-link"
|
||||
href="{% url 'request-delete' leave_request.id %}" onclick="return confirm('{% trans "Are you sure you want to delete ?" %}');" title="{% trans 'Delete' %}"><ion-icon
|
||||
name="trash-outline"></ion-icon></a>
|
||||
|
||||
@@ -62,6 +62,25 @@
|
||||
<span class="oh-timeoff-modal__stat-count">{{leave_request.created_by}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if leave_request.multiple_approvals %}
|
||||
<div class="oh-timeoff-modal__stats w-100 mt-3">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Multiple Approvals" %}</span>
|
||||
{% for approval in leave_request.multiple_approvals.approvals %}
|
||||
<div class="oh-timeoff-modal__stat-description">{{forloop.counter}}.{{approval.manager_id}} :
|
||||
{% if approval.is_approved %}{% trans "Approved" %}
|
||||
{% else %}
|
||||
{% if approval.is_rejected %}
|
||||
{% trans "Rejected" %}
|
||||
{% else %}
|
||||
{% trans "Not Marked" %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="oh-timeoff-modal__stats w-100 mt-3">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
@@ -96,7 +115,7 @@
|
||||
</div>
|
||||
|
||||
<div class="oh-modal__dialog-footer oh-timeoff-modal__footer">
|
||||
{% if leave_request.status == 'requested' %}
|
||||
{% if leave_request.status == 'requested' %}
|
||||
<a type="submit" href="{% url 'request-approve' leave_request.id %}" title="{% trans 'Approve' %}"
|
||||
class="oh-btn oh-btn--success w-100">
|
||||
<ion-icon class="me-1" name="checkmark-outline"></ion-icon>
|
||||
|
||||
23
leave/templates/leave/leave_request/penalty/condition.html
Normal file
23
leave/templates/leave/leave_request/penalty/condition.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends "index.html" %}{% block content %}{% load static %}{% 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 "Multiple Approval Condition" %}
|
||||
</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>
|
||||
</section>
|
||||
<div class="oh-wrapper" id="multipleApproveCondition">
|
||||
{% include "leave/leave_request/penalty/create.html" %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
122
leave/templates/leave/leave_request/penalty/create.html
Normal file
122
leave/templates/leave/leave_request/penalty/create.html
Normal file
@@ -0,0 +1,122 @@
|
||||
{% load static %} {% load i18n %} {% load basefilters %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<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 "Department" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Condition Field" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Condition Operator" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Condition Value" %}</div>
|
||||
<div class="oh-sticky-table__th">{% trans "Approval Managers" %}</div>
|
||||
{% if perms.leave.change_availableleave or perms.leave.delete_availableleave or request.user|is_reportingmanager %}
|
||||
<div class="oh-sticky-table__th">{% trans "Actions" %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for condition in conditions %}
|
||||
<div class="oh-sticky-table__tr" draggable="true">
|
||||
<div class="oh-sticky-table__td">
|
||||
{{condition.department}}
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">{{condition.get_condition_field_display}}</div>
|
||||
<div class="oh-sticky-table__td">{{condition.get_condition_operator_display}}</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
{% if condition.condition_operator == "range" %}
|
||||
{{condition.condition_start_value}} - {{condition.condition_end_value}}
|
||||
{% else %}
|
||||
{{condition.condition_value}}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">
|
||||
{% for manager in condition.approval_managers %}
|
||||
{{ forloop.counter }}. {{ manager }}<br>
|
||||
{% endfor %}</div>
|
||||
{% if perms.leave.change_availableleave or perms.leave.delete_availableleave or request.user|is_reportingmanager %}
|
||||
<div class="oh-sticky-table__td">
|
||||
<div class="oh-btn-group">
|
||||
{% if request.user|is_reportingmanager or perms.leave.change_availableleave %}
|
||||
<button title="{% trans 'Edit' %}"
|
||||
class="oh-btn oh-btn--light-bkg w-100"
|
||||
hx-target="#multipleApproveCondition"
|
||||
hx-get = "{% url 'multiple-level-approval-edit' condition.id %}"
|
||||
><ion-icon name="create-outline"></ion-icon></button>
|
||||
{% endif %}
|
||||
{% if request.user|is_reportingmanager or perms.leave.delete_availableleave %}
|
||||
<a href={% url "multiple-level-approval-delete" condition.id %} class="oh-btn oh-btn--danger-outline oh-btn--light-bkg w-100" onclick="return confirm('{% trans "Are you sure you want to delete ?" %}');" id="delete-link"
|
||||
title="{% trans 'Delete' %}"><ion-icon
|
||||
name="trash-outline"></ion-icon></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 oh-faq-card" style="padding: 0.7rem;">
|
||||
<form
|
||||
hx-post=" {% if create %}
|
||||
{% url 'multiple-level-approval-create' %}
|
||||
{% else %}
|
||||
{% url 'multiple-level-approval-edit' condition.id %}
|
||||
{% endif %}"
|
||||
hx-target="#multipleApproveCondition"
|
||||
>
|
||||
{{form}}
|
||||
<a href="#" role="button" style="color: green" id="id_addMore">{% trans "Add more managers.." %}</a>
|
||||
<div class="oh-modal__dialog-footer" style="padding:1.0rem .2rem 1.0rem;">
|
||||
<button type="submit" class="oh-btn oh-btn--secondary w-100">
|
||||
{% trans "Apply" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function toggleFields(element) {
|
||||
if (element.val() == "range") {
|
||||
$("#id_condition_value").hide();
|
||||
$('label[for="id_condition_start_value"]').show();
|
||||
$('label[for="id_condition_end_value"]').show();
|
||||
$("#id_condition_start_value").show();
|
||||
$("#id_condition_end_value").show();
|
||||
} else {
|
||||
$("#id_condition_value").show();
|
||||
$("#id_condition_start_value").hide();
|
||||
$("#id_condition_end_value").hide();
|
||||
$('label[for="id_condition_start_value"]').hide();
|
||||
$('label[for="id_condition_end_value"]').hide();
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
toggleFields($('#id_condition_operator'));
|
||||
$("#id_addMore").click(function (e) {
|
||||
var existingSelect = $("#id_multi_approval_manager").clone();
|
||||
existingSelect.attr(
|
||||
"class",
|
||||
"select2 select2-container select2-container--default"
|
||||
);
|
||||
existingSelect.attr("dir", "ltr");
|
||||
existingSelect.css({
|
||||
height: "48.54px",
|
||||
border: "1px solid rgb(210 213 216)",
|
||||
width: "100%",
|
||||
"margin-top": "10px",
|
||||
});
|
||||
existingSelect.attr("name", "multi_approval_manager_" + i++);
|
||||
existingSelect.attr("id", "id_multi_approval_manager_" + j++);
|
||||
existingSelect.insertBefore("#id_addMore");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -47,7 +47,7 @@
|
||||
<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"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% load i18n %} {% load yes_no %}
|
||||
{% if request.GET.instances_ids %}
|
||||
<div class="oh-modal__dialog oh-modal__dialog--navigation m-0 p-0">
|
||||
<button
|
||||
@@ -32,7 +32,7 @@
|
||||
<div class="oh-timeoff-modal__stats-container">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Period In" %}</span>
|
||||
<span class="oh-timeoff-modal__stat-count">{{leave_type.period_in}}</span>
|
||||
<span class="oh-timeoff-modal__stat-count">{{leave_type.get_period_in_display}}</span>
|
||||
</div>
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "count" %}</span>
|
||||
@@ -44,12 +44,12 @@
|
||||
</div>
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Reset" %}</span>
|
||||
<span class="oh-timeoff-modal__stat-count">{{leave_type.reset}}</span>
|
||||
<span class="oh-timeoff-modal__stat-count">{{leave_type.reset|yes_no}}</span>
|
||||
</div>
|
||||
{% if leave_type.reset_based %}
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Reset Based" %}</span>
|
||||
<span class="oh-timeoff-modal__stat-count">{{leave_type.reset_based}}</span>
|
||||
<span class="oh-timeoff-modal__stat-count">{{leave_type.get_reset_based_display}}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if leave_type.reset_month %}
|
||||
@@ -67,13 +67,13 @@
|
||||
{% if leave_type.reset_weekend %}
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Reset weekend" %}</span>
|
||||
<span class="oh-timeoff-modal__stat-count">{{leave_type.reset_weekend}}</span>
|
||||
<span class="oh-timeoff-modal__stat-count">{{leave_type.get_reset_weekend_display}}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="oh-timeoff-modal__stats ">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Carryforward Type" %}</span>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.carryforward_type}}</div>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.get_carryforward_type_display}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if leave_type.carryforward_max %}
|
||||
@@ -97,32 +97,32 @@
|
||||
<div class="oh-timeoff-modal__stats ">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Payment Type" %}</span>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.payment}}</div>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.get_payment_display}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-timeoff-modal__stats ">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Require Approval" %}</span>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.require_approval}}</div>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.require_approval|yes_no}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-timeoff-modal__stats">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Require Attachment" %}</span>
|
||||
<div class="oh-timeoff-modal__stat-description">{{leave_type.require_attachment }}</div>
|
||||
<div class="oh-timeoff-modal__stat-description">{{leave_type.require_attachment|yes_no }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oh-timeoff-modal__stats ">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Exclude company Leaves" %}</span>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.exclude_company_leave}}</div>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.exclude_company_leave|yes_no}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-timeoff-modal__stats ">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title">{% trans "Exclude Holidays" %}</span>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.exclude_holiday}}</div>
|
||||
<div class="oh-timeoff-modal__stat-count">{{leave_type.exclude_holiday|yes_no}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ urlpatterns = [
|
||||
views.leave_requests_export,
|
||||
name="leave-requests-info-export",
|
||||
),
|
||||
path("request-view", views.leave_request_view, name="request-view"),
|
||||
path("request-view/", views.leave_request_view, name="request-view"),
|
||||
path(
|
||||
"request-approve/<int:id>", views.leave_request_approve, name="request-approve"
|
||||
),
|
||||
|
||||
@@ -21,7 +21,7 @@ from attendance.forms import PenaltyAccountForm
|
||||
from attendance.models import PenaltyAccount
|
||||
from horilla.decorators import login_required, hx_request_required
|
||||
from horilla.decorators import permission_required, manager_can_enter
|
||||
from base.methods import closest_numbers, export_data
|
||||
from base.methods import closest_numbers, export_data, filter_conditional_leave_request
|
||||
from base.threading import MailSendThread
|
||||
from base.models import *
|
||||
from base.methods import (
|
||||
@@ -346,7 +346,11 @@ def leave_request_view(request):
|
||||
GET : return leave request view template
|
||||
"""
|
||||
queryset = LeaveRequestFilter(request.GET).qs.order_by("-id")
|
||||
queryset = filtersubordinates(request, queryset, "leave.view_leaverequest")
|
||||
multiple_approvals = filter_conditional_leave_request(request)
|
||||
queryset = (
|
||||
filtersubordinates(request, queryset, "leave.view_leaverequest")
|
||||
| multiple_approvals
|
||||
)
|
||||
page_number = request.GET.get("page")
|
||||
page_obj = paginator_qry(queryset, page_number)
|
||||
leave_request_filter = LeaveRequestFilter()
|
||||
@@ -559,8 +563,31 @@ def leave_request_approve(request, id, emp_id=None):
|
||||
available_leave.available_days = temp - leave_request.requested_days
|
||||
leave_request.approved_available_days = leave_request.requested_days
|
||||
leave_request.status = "approved"
|
||||
available_leave.save()
|
||||
leave_request.save()
|
||||
if not leave_request.multiple_approvals():
|
||||
available_leave.save()
|
||||
leave_request.save()
|
||||
else:
|
||||
if request.user.is_superuser:
|
||||
LeaveRequestConditionApproval.objects.filter(
|
||||
leave_request_id=leave_request
|
||||
).update(is_approved=True)
|
||||
available_leave.save()
|
||||
leave_request.save()
|
||||
else:
|
||||
conditional_requests = leave_request.multiple_approvals()
|
||||
approver = [
|
||||
manager
|
||||
for manager in conditional_requests["managers"]
|
||||
if manager.employee_user_id == request.user
|
||||
]
|
||||
condition_approval = LeaveRequestConditionApproval.objects.filter(
|
||||
manager_id=approver[0], leave_request_id=leave_request
|
||||
).first()
|
||||
condition_approval.is_approved = True
|
||||
condition_approval.save()
|
||||
if approver[0] == conditional_requests["managers"][-1]:
|
||||
available_leave.save()
|
||||
leave_request.save()
|
||||
messages.success(request, _("Leave request approved successfully.."))
|
||||
with contextlib.suppress(Exception):
|
||||
notify.send(
|
||||
@@ -627,6 +654,20 @@ def leave_request_cancel(request, id, emp_id=None):
|
||||
leave_request.status = "cancelled_and_rejected"
|
||||
else:
|
||||
leave_request.status = "rejected"
|
||||
if leave_request.multiple_approvals() and not request.user.is_superuser:
|
||||
conditional_requests = leave_request.multiple_approvals()
|
||||
approver = [
|
||||
manager
|
||||
for manager in conditional_requests["managers"]
|
||||
if manager.employee_user_id == request.user
|
||||
]
|
||||
condition_approval = LeaveRequestConditionApproval.objects.filter(
|
||||
manager_id=approver[0], leave_request_id=leave_request
|
||||
).first()
|
||||
condition_approval.is_approved = False
|
||||
condition_approval.is_rejected = True
|
||||
condition_approval.save()
|
||||
|
||||
leave_request.reject_reason = form.cleaned_data["reason"]
|
||||
leave_request.save()
|
||||
available_leave.save()
|
||||
@@ -1143,13 +1184,6 @@ def holiday_creation(request):
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, _("New holiday created successfully.."))
|
||||
response = render(
|
||||
request, "leave/holiday/holiday_form.html", {"form": form}
|
||||
)
|
||||
return HttpResponse(
|
||||
response.content.decode("utf-8")
|
||||
+ "<script>location. reload();</script>"
|
||||
)
|
||||
return render(request, "leave/holiday/holiday_form.html", {"form": form})
|
||||
|
||||
|
||||
@@ -1247,7 +1281,6 @@ def holiday_info_export(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("leave.view_holiday")
|
||||
def holiday_view(request):
|
||||
"""
|
||||
function used to view holidays.
|
||||
@@ -1258,7 +1291,7 @@ def holiday_view(request):
|
||||
Returns:
|
||||
GET : return holiday view template
|
||||
"""
|
||||
queryset = Holiday.objects.all()
|
||||
queryset = Holiday.objects.all()[::-1]
|
||||
previous_data = request.GET.urlencode()
|
||||
page_number = request.GET.get("page")
|
||||
page_obj = paginator_qry(queryset, page_number)
|
||||
@@ -1295,7 +1328,7 @@ def holiday_filter(request):
|
||||
previous_data = request.GET.urlencode()
|
||||
holiday_filter = HolidayFilter(request.GET, queryset).qs
|
||||
page_number = request.GET.get("page")
|
||||
page_obj = paginator_qry(holiday_filter, page_number)
|
||||
page_obj = paginator_qry(holiday_filter[::-1], page_number)
|
||||
data_dict = parse_qs(previous_data)
|
||||
get_key_instances(Holiday, data_dict)
|
||||
return render(
|
||||
@@ -1327,15 +1360,6 @@ def holiday_update(request, id):
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.info(request, _("Holiday updated successfully.."))
|
||||
response = render(
|
||||
request,
|
||||
"leave/holiday/holiday_update_form.html",
|
||||
{"form": form, "id": id},
|
||||
)
|
||||
return HttpResponse(
|
||||
response.content.decode("utf-8")
|
||||
+ "<script>location. reload();</script>"
|
||||
)
|
||||
return render(
|
||||
request, "leave/holiday/holiday_update_form.html", {"form": form, "id": id}
|
||||
)
|
||||
@@ -1420,7 +1444,6 @@ def company_leave_creation(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("leave.view_companyleave")
|
||||
def company_leave_view(request):
|
||||
"""
|
||||
function used to view company leave.
|
||||
@@ -1900,8 +1923,8 @@ def user_request_view(request):
|
||||
request_ids = json.dumps(
|
||||
list(page_obj.object_list.values_list("id", flat=True))
|
||||
)
|
||||
|
||||
user_leave = AvailableLeave.objects.filter(employee_id = user.id)
|
||||
|
||||
user_leave = AvailableLeave.objects.filter(employee_id=user.id)
|
||||
|
||||
current_date = date.today()
|
||||
return render(
|
||||
@@ -1914,8 +1937,7 @@ def user_request_view(request):
|
||||
"current_date": current_date,
|
||||
"gp_fields": MyLeaveRequestReGroup.fields,
|
||||
"request_ids": request_ids,
|
||||
"user_leaves":user_leave,
|
||||
|
||||
"user_leaves": user_leave,
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
@@ -1959,8 +1981,8 @@ def user_request_filter(request):
|
||||
status_list = data_dict["status"]
|
||||
if len(status_list) > 1:
|
||||
data_dict["status"] = [status_list[-1]]
|
||||
|
||||
user_leave = AvailableLeave.objects.filter(employee_id = user.id)
|
||||
|
||||
user_leave = AvailableLeave.objects.filter(employee_id=user.id)
|
||||
|
||||
context = {
|
||||
"leave_requests": page_obj,
|
||||
@@ -1969,8 +1991,7 @@ def user_request_filter(request):
|
||||
"field": field,
|
||||
"current_date": date.today(),
|
||||
"request_ids": request_ids,
|
||||
"user_leaves":user_leave,
|
||||
|
||||
"user_leaves": user_leave,
|
||||
}
|
||||
return render(request, template, context=context)
|
||||
except Exception as e:
|
||||
@@ -3167,8 +3188,6 @@ def employee_leave_details(request):
|
||||
return JsonResponse({"leave_count": balance_count, "employee": employee})
|
||||
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@manager_can_enter("leave.change_availableleave")
|
||||
def cut_available_leave(request, instance_id):
|
||||
@@ -3185,7 +3204,9 @@ def cut_available_leave(request, instance_id):
|
||||
penalty = PenaltyAccount()
|
||||
# leave request id
|
||||
penalty.leave_request_id = instance
|
||||
penalty.deduct_from_carry_forward = penalty_instance.deduct_from_carry_forward
|
||||
penalty.deduct_from_carry_forward = (
|
||||
penalty_instance.deduct_from_carry_forward
|
||||
)
|
||||
penalty.employee_id = instance.employee_id
|
||||
penalty.leave_type_id = penalty_instance.leave_type_id
|
||||
penalty.minus_leaves = penalty_instance.minus_leaves
|
||||
@@ -3207,4 +3228,6 @@ def view_penalties(request):
|
||||
This method is used to filter or view the penalties
|
||||
"""
|
||||
records = PenaltyFilter(request.GET).qs
|
||||
return render(request, "leave/leave_request/penalty/penalty_view.html", {"records": records})
|
||||
return render(
|
||||
request, "leave/leave_request/penalty/penalty_view.html", {"records": records}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user