diff --git a/attendance/templates/attendance_form.html b/attendance/templates/attendance_form.html
index 1a6413d2d..bd73a34f3 100644
--- a/attendance/templates/attendance_form.html
+++ b/attendance/templates/attendance_form.html
@@ -16,7 +16,7 @@
title="{{ field.help_text|safe }}"
>{% trans field.label %}
-
+
{{ field|add_class:"form-control" }}
diff --git a/employee/views.py b/employee/views.py
index b0917c52d..f671bf357 100755
--- a/employee/views.py
+++ b/employee/views.py
@@ -106,7 +106,8 @@ from horilla_documents.forms import (
DocumentUpdateForm,
)
from horilla_documents.models import Document, DocumentRequest
-from leave.models import LeaveRequest
+from leave.methods import get_leave_day_attendance
+from leave.models import LeaveGeneralSetting, LeaveRequest
from notifications.signals import notify
from onboarding.models import OnboardingStage, OnboardingTask
from payroll.methods.payslip_calc import dynamic_attr
@@ -174,7 +175,11 @@ def employee_profile(request):
"""
user = request.user
employee = request.user.employee_get
- user_leaves = employee.available_leave.all()
+ user_leaves = employee.available_leave.all().exclude(
+ leave_type_id__is_compensatory_leave=True
+ )
+ if LeaveGeneralSetting.objects.first().compensatory_leave:
+ user_leaves = employee.available_leave.all()
instances = LeaveRequest.objects.filter(employee_id=employee)
leave_request_ids = json.dumps([instance.id for instance in instances])
employee = Employee.objects.filter(employee_user_id=user).first()
diff --git a/leave/admin.py b/leave/admin.py
index 50ee69a8e..2db666447 100644
--- a/leave/admin.py
+++ b/leave/admin.py
@@ -9,9 +9,11 @@ from simple_history.admin import SimpleHistoryAdmin
from .models import (
AvailableLeave,
CompanyLeave,
+ CompensatoryLeaveRequest,
Holiday,
LeaveAllocationRequest,
LeaveallocationrequestComment,
+ LeaveGeneralSetting,
LeaveRequest,
LeaverequestComment,
LeaveRequestConditionApproval,
@@ -30,3 +32,5 @@ admin.site.register(LeaveRequestConditionApproval)
admin.site.register(LeaverequestComment)
admin.site.register(LeaveallocationrequestComment)
admin.site.register(RestrictLeave)
+admin.site.register(CompensatoryLeaveRequest)
+admin.site.register(LeaveGeneralSetting)
diff --git a/leave/filters.py b/leave/filters.py
index ccc595473..adcd4ba5f 100644
--- a/leave/filters.py
+++ b/leave/filters.py
@@ -22,6 +22,7 @@ from employee.models import Employee
from .models import (
AvailableLeave,
CompanyLeave,
+ CompensatoryLeaveRequest,
Holiday,
LeaveAllocationRequest,
LeaveRequest,
@@ -575,3 +576,78 @@ class RestrictLeaveFilter(FilterSet):
super().__init__(data=data, queryset=queryset, request=request, prefix=prefix)
for field in self.form.fields.keys():
self.form.fields[field].widget.attrs["id"] = f"{uuid.uuid4()}"
+
+
+class CompensatoryLeaveRequestFilter(FilterSet):
+ """
+ Filter class for CompensatoryLeaveRequest model specific to user leave requests.
+ This filter allows searching user-specific LeaveRequest objects
+ based on leave type, date range, and status.
+ """
+
+ id = django_filters.NumberFilter(field_name="id")
+
+ leave_type = filters.CharFilter(
+ field_name="leave_type_id__name", lookup_expr="icontains"
+ )
+ search = filters.CharFilter(method="filter_by_name")
+ created_by__employee_get = django_filters.CharFilter(
+ field_name="created_by__employee_get",
+ lookup_expr="exact",
+ widget=forms.SelectMultiple(attrs={"class": "form-control"}),
+ )
+ number_of_days_up_to = filters.NumberFilter(
+ field_name="requested_days", lookup_expr="lte"
+ )
+ number_of_days_more_than = filters.NumberFilter(
+ field_name="requested_days", lookup_expr="gte"
+ )
+
+ class Meta:
+ """
+ Meta class defines the model and fields to filter
+ """
+
+ model = CompensatoryLeaveRequest
+ fields = {
+ "id": ["exact"],
+ "created_by__employee_get": ["exact"],
+ "status": ["exact"],
+ "leave_type_id": ["exact"],
+ "employee_id": ["exact"],
+ }
+
+ def filter_by_name(self, queryset, name, value):
+ # Call the imported function
+ filter_method = {
+ "leave_type": "leave_type_id__name__icontains",
+ "status": "status__icontains",
+ "department": "employee_id__employee_work_info__department_id__department__icontains",
+ "job_position": "employee_id__employee_work_info__job_position_id__job_position__icontains",
+ "company": "employee_id__employee_work_info__company_id__company__icontains",
+ }
+ search_field = self.data.get("search_field")
+ if not search_field:
+ parts = value.split()
+ first_name = parts[0]
+ last_name = " ".join(parts[1:]) if len(parts) > 1 else ""
+
+ # Filter the queryset by first name and last name
+ if first_name and last_name:
+ queryset = queryset.filter(
+ employee_id__employee_first_name__icontains=first_name,
+ employee_id__employee_last_name__icontains=last_name,
+ )
+ elif first_name:
+ queryset = queryset.filter(
+ employee_id__employee_first_name__icontains=first_name
+ )
+ elif last_name:
+ queryset = queryset.filter(
+ employee_id__employee_last_name__icontains=last_name
+ )
+ else:
+ filter = filter_method.get(search_field)
+ queryset = queryset.filter(**{filter: value})
+
+ return queryset
diff --git a/leave/forms.py b/leave/forms.py
index c5c1297ee..8d1a70505 100644
--- a/leave/forms.py
+++ b/leave/forms.py
@@ -10,13 +10,14 @@ from typing import Any
from django import forms
from django.core.exceptions import ValidationError
+from django.db.models import Q
from django.forms import ModelForm
from django.forms.widgets import TextInput
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from base import thread_local_middleware
-from base.methods import reload_queryset
+from base.methods import filtersubordinates, reload_queryset
from base.models import Department
from employee.filters import EmployeeFilter
from employee.forms import MultipleFileField
@@ -28,12 +29,15 @@ from horilla_widgets.widgets.select_widgets import HorillaMultiSelectWidget
from .methods import (
calculate_requested_days,
company_leave_dates_list,
+ get_leave_day_attendance,
holiday_dates_list,
leave_requested_dates,
)
from .models import (
AvailableLeave,
CompanyLeave,
+ CompensatoryLeaveRequest,
+ CompensatoryLeaverequestComment,
Holiday,
LeaveAllocationRequest,
LeaveallocationrequestComment,
@@ -1250,3 +1254,129 @@ class RestrictLeaveForm(ModelForm):
def __init__(self, *args, **kwargs):
super(RestrictLeaveForm, self).__init__(*args, **kwargs)
self.fields["title"].widget.attrs["autocomplete"] = "title"
+
+
+class CompensatoryLeaveForm(ModelForm):
+ """
+ Form for creating a leave allocation request.
+
+ This form allows users to create a leave allocation request by specifying
+ details such as leave type, employee, requested days, description, and attachment.
+
+ Methods:
+ - as_p: Render the form fields as HTML table rows with Bootstrap styling.
+ """
+
+ class Meta:
+ """
+ Meta class for additional options
+ """
+
+ attendance_id = forms.MultipleChoiceField(required=True)
+ model = CompensatoryLeaveRequest
+ fields = [
+ # "leave_type_id",
+ "employee_id",
+ "attendance_id",
+ # "requested_days",
+ "description",
+ ]
+
+ def __init__(self, *args, **kwargs):
+ from attendance.models import Attendance
+
+ super(CompensatoryLeaveForm, self).__init__(*args, **kwargs)
+
+ request = getattr(thread_local_middleware._thread_locals, "request", None)
+ instance_id = None
+ if self.instance:
+ instance_id = self.instance.id
+ if (
+ request
+ and hasattr(request, "user")
+ and hasattr(request.user, "employee_get")
+ ):
+ employee = request.user.employee_get
+ holiday_attendance = get_leave_day_attendance(employee, comp_id=instance_id)
+ # Get a list of tuples containing (id, attendance_date)
+ attendance_dates = list(
+ holiday_attendance.values_list("id", "attendance_date")
+ )
+ # Set the queryset of attendance_id to the attendance_dates
+ self.fields["attendance_id"].choices = attendance_dates
+ self.fields["employee_id"].widget.attrs.update(
+ {
+ "hx-target": "#id_attendance_id_parent_div",
+ "hx-trigger": "change",
+ "hx-get": "/leave/get-leave-attendance-dates",
+ }
+ )
+
+ def as_p(self, *args, **kwargs):
+ """
+ Render the form fields as HTML table rows with Bootstrap styling.
+ """
+ context = {"form": self}
+ table_html = render_to_string("attendance_form.html", context)
+ return table_html
+
+ def clean(self):
+ cleaned_data = super().clean()
+ attendance_id = cleaned_data.get("attendance_id")
+ employee = cleaned_data.get("employee_id")
+ attendance_repeat = False
+ instance_id = None
+ if self.instance:
+ instance_id = self.instance.id
+ for attendance in attendance_id:
+ if (
+ CompensatoryLeaveRequest.objects.filter(
+ employee_id=employee, attendance_id=attendance
+ )
+ .exclude(Q(id=instance_id) | Q(status="rejected"))
+ .exists()
+ ):
+ attendance_repeat = True
+ break
+ if attendance_repeat:
+ raise forms.ValidationError(
+ {
+ "attendance_id": "This attendance is already converted to complimentory leave"
+ }
+ )
+ return cleaned_data
+
+
+class CompensatoryLeaveRequestRejectForm(forms.Form):
+ """
+ Form for rejecting a compensatory leave request.
+
+ This form allows administrators to provide a rejection reason when rejecting
+ a compensatory leave request.
+
+ Attributes:
+ - reason: A CharField representing the reason for rejecting the compensatory leave request.
+ """
+
+ reason = forms.CharField(
+ label=_("Rejection Reason"),
+ widget=forms.Textarea(attrs={"rows": 4, "class": "p-4 oh-input w-100"}),
+ )
+
+ class Meta:
+ model = CompensatoryLeaveRequest
+ fields = ["reject_reason"]
+
+
+class CompensatoryLeaveRequestcommentForm(ModelForm):
+ """
+ LeaverequestComment form
+ """
+
+ class Meta:
+ """
+ Meta class for additional options
+ """
+
+ model = CompensatoryLeaverequestComment
+ fields = ("comment",)
diff --git a/leave/methods.py b/leave/methods.py
index 87803e0d6..588ce2ba9 100644
--- a/leave/methods.py
+++ b/leave/methods.py
@@ -1,6 +1,8 @@
import calendar
from datetime import datetime, timedelta
+from django.db.models import Q
+
def calculate_requested_days(
start_date, end_date, start_date_breakdown, end_date_breakdown
@@ -102,3 +104,63 @@ def company_leave_dates_list(company_leaves, start_date):
if date not in company_leave_dates:
company_leave_dates.append(date)
return company_leave_dates
+
+
+def get_leave_day_attendance(employee, comp_id=None):
+ """
+ This function returns a queryset of attendance on leave dates
+ """
+ from attendance.filters import AttendanceFilters
+ from attendance.models import Attendance
+ from leave.models import CompensatoryLeaveRequest, LeaveRequest
+
+ holiday_dates = LeaveRequest.holiday_dates(None)
+ company_leave_dates = LeaveRequest.company_leave_dates(None)
+ leave_day_attendance = Attendance.objects.none()
+ converted_dates = []
+ if (
+ CompensatoryLeaveRequest.objects.filter(employee_id=employee)
+ .exclude(Q(id=comp_id) | Q(status="rejected"))
+ .exists()
+ ):
+ comp_leave_reqs = CompensatoryLeaveRequest.objects.filter(
+ employee_id=employee
+ ).exclude(Q(id=comp_id) | Q(status="rejected"))
+ attendances = Attendance.objects.none() # Empty queryset to start with
+ for req in comp_leave_reqs:
+ attendances |= req.attendance_id.all()
+ converted_dates = [attendance.attendance_date for attendance in attendances]
+ leave_dates = set(company_leave_dates + holiday_dates) - set(converted_dates)
+ for leave_day in leave_dates:
+ attendance_qs = AttendanceFilters(
+ {"employee": employee.id, "attendance_date": leave_day}
+ ).qs
+ if attendance_qs.exists():
+ leave_day_attendance |= attendance_qs
+
+ return leave_day_attendance
+
+
+def attendance_days(employee, attendances):
+ """
+ This function returns count of workrecord from the attendance
+ """
+ from payroll.models.models import WorkRecord
+
+ attendance_days = 0
+ for attendance in attendances:
+ if WorkRecord.objects.filter(
+ employee_id=employee, date=attendance.attendance_date
+ ).exists():
+ work_record_type = (
+ WorkRecord.objects.filter(
+ employee_id=employee, date=attendance.attendance_date
+ )
+ .first()
+ .work_record_type
+ )
+ if work_record_type == "HDP":
+ attendance_days += 0.5
+ elif work_record_type == "FDP":
+ attendance_days += 1
+ return attendance_days
diff --git a/leave/models.py b/leave/models.py
index 3f499b3ae..ed0702601 100644
--- a/leave/models.py
+++ b/leave/models.py
@@ -30,7 +30,7 @@ from horilla_audit.methods import get_diff
from horilla_audit.models import HorillaAuditInfo, HorillaAuditLog
from leave.threading import LeaveClashThread
-from .methods import calculate_requested_days
+from .methods import attendance_days, calculate_requested_days
operator_mapping = {
"equal": operator.eq,
@@ -195,6 +195,7 @@ class LeaveType(HorillaModel):
max_length=30, choices=CHOICES, default="no"
)
exclude_holiday = models.CharField(max_length=30, choices=CHOICES, default="no")
+ is_compensatory_leave = models.BooleanField(default=False)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
@@ -215,13 +216,17 @@ class LeaveType(HorillaModel):
url = self.icon.url
return url
+ def clean(self, *args, **kwargs):
+ if self.is_compensatory_leave:
+ if LeaveType.objects.filter(is_compensatory_leave=True).count() >= 1:
+ raise ValidationError(_("Compensatory Leave Request already exists."))
+
def save(self, *args, **kwargs):
if (
self.carryforward_type != "no carryforward"
and self.carryforward_max is None
):
self.carryforward_max = math.inf
- super().save(*args, **kwargs)
def __str__(self):
return self.name
@@ -557,10 +562,15 @@ class LeaveRequest(HorillaModel):
def company_leave_dates(self):
"""
:return: This function returns a list of all company leave dates"""
+ from datetime import date
+
company_leaves = CompanyLeave.objects.all()
company_leave_dates = []
for company_leave in company_leaves:
- year = self.start_date.year
+ if self:
+ year = self.start_date.year
+ else:
+ year = date.today().year
based_on_week = company_leave.based_on_week
based_on_week_day = company_leave.based_on_week_day
for month in range(1, 13):
@@ -945,3 +955,94 @@ class RestrictLeave(HorillaModel):
def __str__(self) -> str:
return f"{self.title}"
+
+
+class CompensatoryLeaveRequest(HorillaModel):
+ from attendance.models import Attendance
+
+ leave_type_id = models.ForeignKey(
+ LeaveType, on_delete=models.PROTECT, verbose_name="Leave type"
+ )
+ employee_id = models.ForeignKey(
+ Employee, on_delete=models.CASCADE, verbose_name="Employee"
+ )
+ attendance_id = models.ManyToManyField(Attendance, verbose_name="Attendance")
+ requested_days = models.FloatField(blank=True, null=True)
+ requested_date = models.DateField(default=timezone.now)
+ description = models.TextField(max_length=255)
+ status = models.CharField(
+ max_length=30, choices=LEAVE_ALLOCATION_STATUS, default="requested"
+ )
+ reject_reason = models.TextField(blank=True, max_length=255)
+ history = HorillaAuditLog(
+ related_name="history_set",
+ bases=[
+ HorillaAuditInfo,
+ ],
+ )
+ objects = HorillaCompanyManager(
+ related_company_field="employee_id__employee_work_info__company_id"
+ )
+
+ class Meta:
+ ordering = ["-id"]
+
+ def __str__(self):
+ return f"{self.employee_id}| {self.leave_type_id}| {self.id}"
+
+ def assign_compensatory_leave_type(self):
+ available_leave, created = AvailableLeave.objects.get_or_create(
+ employee_id=self.employee_id,
+ leave_type_id=self.leave_type_id,
+ )
+ available_leave.available_days += self.requested_days
+ available_leave.save()
+
+ def exclude_compensatory_leave(self):
+ if AvailableLeave.objects.filter(
+ employee_id=self.employee_id,
+ leave_type_id=self.leave_type_id,
+ ).exists():
+ available_leave = AvailableLeave.objects.filter(
+ employee_id=self.employee_id,
+ leave_type_id=self.leave_type_id,
+ ).first()
+ if available_leave.available_days < self.requested_days:
+ available_leave.available_days = 0
+ available_leave.carryforward_days = max(
+ 0,
+ available_leave.carryforward_days
+ - (self.requested_days - available_leave.available_days),
+ )
+ else:
+ available_leave.available_days -= self.requested_days
+ available_leave.save()
+
+ def save(self, *args, **kwargs):
+ self.leave_type_id = LeaveType.objects.filter(
+ is_compensatory_leave=True
+ ).first()
+ super().save(*args, **kwargs)
+
+
+class LeaveGeneralSetting(HorillaModel):
+ """
+ AttendanceGeneralSettings
+ """
+
+ compensatory_leave = models.BooleanField(default=True)
+ company_id = models.ForeignKey(Company, on_delete=models.CASCADE, null=True)
+
+
+class CompensatoryLeaverequestComment(HorillaModel):
+ """
+ LeaveallocationrequestComment Model
+ """
+
+ request_id = models.ForeignKey(CompensatoryLeaveRequest, on_delete=models.CASCADE)
+ employee_id = models.ForeignKey(Employee, on_delete=models.CASCADE)
+ files = models.ManyToManyField(LeaverequestFile, blank=True)
+ comment = models.TextField(null=True, verbose_name=_("Comment"), max_length=255)
+
+ def __str__(self) -> str:
+ return f"{self.comment}"
diff --git a/leave/templates/leave/compensatory_leave/attendance_id.html b/leave/templates/leave/compensatory_leave/attendance_id.html
new file mode 100644
index 000000000..ad8938412
--- /dev/null
+++ b/leave/templates/leave/compensatory_leave/attendance_id.html
@@ -0,0 +1 @@
+{{form.attendance_id}}
\ No newline at end of file
diff --git a/leave/templates/leave/compensatory_leave/comp_leave_form.html b/leave/templates/leave/compensatory_leave/comp_leave_form.html
new file mode 100644
index 000000000..e100043a6
--- /dev/null
+++ b/leave/templates/leave/compensatory_leave/comp_leave_form.html
@@ -0,0 +1,43 @@
+{% load i18n %}
+{% if form.errors %}
+
+
+ {% for error in form.non_field_errors %}
+
{{ error }}
+ {% endfor %}
+
+
+{% endif %}
+
+
+
+
+
\ No newline at end of file
diff --git a/leave/templates/leave/compensatory_leave/compensatory_leave_comment.html b/leave/templates/leave/compensatory_leave/compensatory_leave_comment.html
new file mode 100644
index 000000000..3e69b84b1
--- /dev/null
+++ b/leave/templates/leave/compensatory_leave/compensatory_leave_comment.html
@@ -0,0 +1,177 @@
+{% load i18n static %}
+
+
+{% if messages %}
+
+ {% for message in messages %}
+
{{ message }}
+ {% endfor %}
+
+
+{% endif %}
+
+
+
+
+
+
+{% if comments %}
+
+{% else %}
+
+
+
+
{% trans "There are no comments to show." %}
+

+
+
+
+{% endif %}
+
+
+
+
+
+
+
diff --git a/leave/templates/leave/compensatory_leave/compensatory_leave_reject_form..html b/leave/templates/leave/compensatory_leave/compensatory_leave_reject_form..html
new file mode 100644
index 000000000..1064a985d
--- /dev/null
+++ b/leave/templates/leave/compensatory_leave/compensatory_leave_reject_form..html
@@ -0,0 +1,38 @@
+{% load i18n %} {% if form.errors %}
+
+
+
+ {% for error in form.non_field_errors %}
+
{{ error }}
+ {% endfor %}
+
+
+{% endif %}
+
+
diff --git a/leave/templates/leave/compensatory_leave/compensatory_leave_req_list.html b/leave/templates/leave/compensatory_leave/compensatory_leave_req_list.html
new file mode 100644
index 000000000..6e5012acf
--- /dev/null
+++ b/leave/templates/leave/compensatory_leave/compensatory_leave_req_list.html
@@ -0,0 +1,426 @@
+{% load i18n %}
+{% load static %}
+{% load basefilters %}
+{% include 'filter_tags.html' %}
+{% if messages %}
+
+ {% for message in messages %}
+
+ {% endfor %}
+
+{% endif %}
+
+ -
+ {% trans "My compensatory leave requests" %}
+
+ {% if request.user|is_reportingmanager or perms.leave.change_leaveallocationrequest %}
+ -
+ {% trans "Compensatory leave requests" %}
+
+ {% endif %}
+
+
+
+ {% if my_comp_leave_requests %}
+
+
+
+
+
+
{% trans "Employee" %}
+
{% trans "Leave Type" %}
+
{% trans "Attendance Dates" %}
+
{% trans "Requested Days" %}
+
{% trans "Created By" %}
+
{% trans "Status" %}
+
{% trans "Description" %}
+
{% trans "Comment" %}
+
{% trans "Actions" %}
+
+
+
+ {% for comp_leave_request in my_comp_leave_requests %}
+
+
+
+
+ {% if comp_leave_request.employee_id.employee_profile %}
+

+ {% else %}
+

+ {% endif %}
+
+
{{comp_leave_request.employee_id}}
+
+
+
{{comp_leave_request.leave_type_id}}
+
+ {% for attendance in comp_leave_request.attendance_id.all %}
+ {{ attendance.attendance_date }}
+ {% endfor %}
+
+
{{comp_leave_request.requested_days}}
+
{{comp_leave_request.created_by.employee_get}}
+
{{comp_leave_request.get_status_display}}
+
{{comp_leave_request.description|truncatechars:25}}
+
+
+
+
+
+
+
+ {% if comp_leave_request.status == 'requested' %}
+
+ {% else %}
+
+ {% endif %}
+ {% if comp_leave_request.status != 'approved' %}
+
+
+
+ {% else %}
+
+ {% endif %}
+
+
+
+ {% endfor %}
+
+
+
+
+
+
+
+ {% else %}
+
+
+
+

+
{% trans "You have No leave requests for this filter." %}
+
+
+
+ {% endif %}
+
+
+ {% if request.user|is_reportingmanager or perms.leave.view_compensatoryleaverequest %}
+
+ {% if comp_leave_requests %}
+
+
+
+
+
+
{% trans "Employee" %}
+
{% trans "Leave Type" %}
+
{% trans "Attendance Dates" %}
+
{% trans "Requested Days" %}
+
{% trans "Created By" %}
+
{% trans "Status" %}
+
{% trans "Description" %}
+
{% trans "Comment" %}
+
{% trans "Actions" %}
+
{% trans "Confirmation" %}
+
+
+
+ {% for comp_leave_request in comp_leave_requests %}
+
+
+
+
+

+
+
{{comp_leave_request.employee_id}}
+
+
+
{{comp_leave_request.leave_type_id}}
+
+ {% for attendance in comp_leave_request.attendance_id.all %}
+ {{ attendance.attendance_date }}
+ {% endfor %}
+
+
{{comp_leave_request.requested_days}}
+
{{comp_leave_request.created_by.employee_get}}
+
{{comp_leave_request.get_status_display}}
+
{{ comp_leave_request.description|truncatechars:20}}
+
+
+
+
+
+
+
+ {% if comp_leave_request.status == 'requested' %}
+
+ {% else %}
+
+ {% endif %}
+ {% if comp_leave_request.status != 'approved' %}
+
+
+
+ {% else %}
+
+ {% endif %}
+
+
+
+
+
+ {% if perms.leave.change_leaveallocationrequest or request.user|is_reportingmanager %}
+ {% if comp_leave_request.status == 'requested' %}
+
+
+
+ {% else %}
+
+
+
+ {% endif %}
+ {% if comp_leave_request.status == 'requested' or comp_leave_request.status == 'approved' %}
+
+
+
+ {% else %}
+
+
+
+ {% endif %}
+ {% endif %}
+
+
+
+ {% endfor %}
+
+
+
+
+
+
+
+ {% else %}
+
+
+

+
{% trans "You have No leave requests for this filter." %}
+
+
+
+ {% endif %}
+
+ {% endif %}
+
+
+
+
+
+
+
+