[ADD] LEAVE: Leave allocation request

This commit is contained in:
Horilla
2023-11-02 12:25:48 +05:30
parent 617654a17c
commit 91ecbbf777
12 changed files with 834 additions and 97 deletions

View File

@@ -3,7 +3,7 @@ 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
from .models import LeaveType, LeaveRequest, AvailableLeave, Holiday, CompanyLeave,LeaveAllocationRequest
# Register your models here.
@@ -12,3 +12,4 @@ admin.site.register(LeaveRequest)
admin.site.register(AvailableLeave)
admin.site.register(Holiday)
admin.site.register(CompanyLeave)
admin.site.register(LeaveAllocationRequest)

View File

@@ -11,7 +11,7 @@ from django_filters import FilterSet, DateFilter, filters, NumberFilter
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext as __
from employee.models import Employee
from .models import LeaveType, LeaveRequest, AvailableLeave, Holiday, CompanyLeave
from .models import LeaveType, LeaveRequest, AvailableLeave, Holiday, CompanyLeave,LeaveAllocationRequest
class FilterSet(FilterSet):
@@ -142,10 +142,9 @@ class AssignedLeaveFilter(FilterSet):
class LeaveRequestFilter(FilterSet):
"""
Filter class for LeaveRequest model.
This filter allows searching LeaveRequest objects based on employee,
date range, leave type, and status.
This filter allows searching LeaveRequest objects
based on employee,date range, leave type, and status.
"""
employee_id = filters.CharFilter(
field_name="employee_id__employee_first_name", lookup_expr="icontains"
)
@@ -316,7 +315,7 @@ class UserLeaveRequestFilter(FilterSet):
)
class Meta:
""" "
"""
Meta class defines the model and fields to filter
"""
@@ -325,3 +324,30 @@ class UserLeaveRequestFilter(FilterSet):
"leave_type_id": ["exact"],
"status": ["exact"],
}
class LeaveAllocationRequestFilter(FilterSet):
"""
Filter class for LeaveAllocationRequest model specific to user leave requests.
This filter allows searching user-specific LeaveRequest objects
based on leave type, date range, and status.
"""
leave_type = filters.CharFilter(
field_name="leave_type_id__name", lookup_expr="icontains"
)
employee_id = filters.CharFilter(
field_name="employee_id__employee_first_name", lookup_expr="icontains"
)
number_of_days = filters.NumberFilter(
field_name='requested_days',
lookup_expr='let'
)
class Meta:
"""
Meta class defines the model and fields to filter
"""
model = LeaveAllocationRequest
fields = {
'created_by':["exact"],
"status":["exact"]
}

View File

@@ -6,7 +6,7 @@ from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from django.template.loader import render_to_string
from employee.models import Employee
from .models import LeaveType, LeaveRequest, AvailableLeave, Holiday, CompanyLeave
from .models import LeaveType, LeaveRequest, AvailableLeave, Holiday, CompanyLeave, LeaveAllocationRequest
from .methods import (
calculate_requested_days,
leave_requested_dates,
@@ -560,4 +560,20 @@ class UserLeaveRequestCreationForm(ModelForm):
widgets = {
'employee_id': forms.HiddenInput()
}
class LeaveAllocationRequestForm(ModelForm):
class Meta:
model = LeaveAllocationRequest
fields = [
'leave_type_id',
'employee_id',
'requested_days',
'description',
]
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

View File

@@ -504,3 +504,28 @@ class LeaveRequest(models.Model):
self.approved_available_days = self.requested_days
self.status = "approved"
available_leave.save()
class LeaveAllocationRequest(models.Model):
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"
)
requested_days = models.FloatField(blank=True, null=True)
requested_date = models.DateField(default=timezone.now)
created_by = models.ForeignKey(
Employee,
on_delete=models.PROTECT,
blank=True,
null=True,
related_name="leave_allocation_request_created",
)
description = models.TextField()
attachment = models.FileField(
null=True, blank=True, upload_to="leave/leave_attachment"
)
status = models.CharField(max_length=30, choices=LEAVE_STATUS, default="requested")
created_at = models.DateTimeField(auto_now="True")
reject_reason = models.TextField(blank=True)
objects = models.Manager()

View File

@@ -0,0 +1,17 @@
{% 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 'leave-allocation-request-create' %}"
hx-encoding="multipart/form-data">
{{form.as_p}}
</form>

View File

@@ -0,0 +1,194 @@
{% load i18n %}
{% load static %}
{% 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>
{% endif %}
{% include 'filter_tags.html' %}
{% comment %} {% if not request.GET.dashboard %} {% endcomment %}
{% if leave_allocation_requests %}
<div class="d-flex flex-row-reverse">
<span class="m-3 review_ongoing" hx-get="{% url "request-filter" %}?{{pd}}&status=rejected" hx-target="#leaveRequest" style="cursor: pointer">
<span class="oh-dot oh-dot--small me-1" style="background-color:red"></span>
{% trans "Rejected" %}
</span>
<span class="m-3 review_ongoing" hx-get="{% url "request-filter" %}?{{pd}}&status=cancelled" hx-target="#leaveRequest" style="cursor: pointer">
<span class="oh-dot oh-dot--small me-1" style="background-color:grey"></span>
{% trans "Cancelled" %}
</span>
<span class="m-3 confirmed" hx-get="{% url "request-filter" %}?{{pd}}&status=requested" hx-target="#leaveRequest" style="cursor: pointer">
<span class="oh-dot oh-dot--small me-1" style="background-color:rgb(103, 171, 238)"></span>
{% trans "Requested" %}
</span>
<span class="m-3 paid" hx-get="{% url "request-filter" %}?{{pd}}&status=approved" hx-target="#leaveRequest" style="cursor: pointer">
<span class="oh-dot oh-dot--small me-1" style="background-color:yellowgreen"></span>
{% trans "Approved" %}
</span>
</div>
{% comment %} {% endif %} {% endcomment %}
<div class="oh-sticky-table">
<div class="oh-sticky-table__table ">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th" hx-get="{% url 'request-filter' %}?{{pd}}&sortby=employee_id" hx-target="#leaveRequest">{% trans "Employee" %}</div>
<div class="oh-sticky-table__th" hx-get="{% url 'request-filter' %}?{{pd}}&sortby=leave_type_id" hx-target="#leaveRequest">{% trans "Leave Type" %}</div>
<div class="oh-sticky-table__th" hx-get="{% url 'request-filter' %}?{{pd}}&sortby=requested_days" hx-target="#leaveRequest">{% trans "Requested Days" %}</div>
<div class="oh-sticky-table__th" hx-get="{% url 'request-filter' %}?{{pd}}&sortby=status" hx-target="#leaveRequest">{% trans "Status" %}</div>
<div class="oh-sticky-table__th">{% trans "Options" %}</div>
<div class="oh-sticky-table__th">{% trans "Actions" %}</div>
</div>
</div>
<div class="oh-sticky-table__tbody">
{% for leave_request in leave_allocation_requests %}
<div class="oh-sticky-table__tr" draggable="true"
data-toggle="oh-modal-toggle"
data-target="#singleViewModal"
hx-get="{% url 'leave-allocation-request-single-view' leave_request.id %}"
hx-target="#singleViewTarget">
<div class="oh-sticky-table__sd {% if leave_request.status == "requested" %} row-status--blue
{% elif leave_request.status == "approved" %} row-status--yellow
{% elif leave_request.status == "cancelled" %} row-status--gray
{% elif leave_request.status == "rejected" %}row-status--red
{% endif %}" >
<div class="oh-profile oh-profile--md">
<div class="oh-profile__avatar mr-1">
{% if leave_request.employee_id.employee_profile %}
<img src="{{leave_request.employee_id.employee_profile.url}}" class="oh-profile__image"
alt="" />
{% else %}
<img src="https://ui-avatars.com/api/?name={{leave_request.employee_id}}&background=random"
class="oh-profile__image" alt="" />
{% endif %}
</div>
<span class="oh-profile__name oh-text--dark">{{leave_request.employee_id}}</span>
</div>
</div>
<div class="oh-sticky-table__td {% if leave_request.status == 'cancelled' %} diff-cell{% endif %}">{{leave_request.leave_type_id}}</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" onclick="event.stopPropagation()">
<div class="oh-btn-group" >
{% if leave_request.status == 'requested' or leave_request.status == 'rejected' %}
<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>
</a>
{% else %}
<a type="submit" href="#" title="{% trans 'Approve' %}"
class="oh-btn oh-btn--success oh-btn--disabled
w-100">
<ion-icon class="me-1" name="checkmark-outline"></ion-icon>
</a>
{% endif %}
{% if leave_request.status != 'rejected' %}
<a type="submit" data-toggle="oh-modal-toggle"
data-target="#rejectModal" hx-get="{% url 'request-cancel' leave_request.id %}" hx-target="#rejectForm" title="{% trans 'Reject' %}"
class="oh-btn oh-btn--danger w-100">
<ion-icon class="me-1" name="close-circle-outline"></ion-icon>
</a>
{% else %}
<a type="submit" href="#" title="{% trans 'Reject' %}"
class="oh-btn oh-btn--danger oh-btn--disabled
w-100" >
<ion-icon class="me-1" name="close-circle-outline"></ion-icon>
</a>
{% endif %}
</div>
</div>
<div class="oh-sticky-table__td" onclick="event.stopPropagation()">
<div class="oh-btn-group">
<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>
<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>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% comment %} start of pagination {% endcomment %}
<div class="oh-pagination">
<span class="oh-pagination__page">
{% trans "Page" %} {{ leave_requests.number }} {% trans "of" %} {{ leave_requests.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="{{leave_requests.number}}"
hx-get="{% url 'request-filter' %}?{{pd}}" hx-target="#leaveRequest" min="1" />
<span class="oh-pagination__label">{% trans "of" %} {{leave_requests.paginator.num_pages}}</span>
</div>
<ul class="oh-pagination__items">
{% if leave_requests.has_previous %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#leaveRequest' hx-get="{% url 'request-filter' %}?{{pd}}&page=1"
class="oh-pagination__link">{% trans "First" %}</a>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#leaveRequest'
hx-get="{% url 'request-filter' %}?{{pd}}&page={{ leave_requests.previous_page_number }}"
class="oh-pagination__link">{% trans "Previous" %}</a>
</li>
{% endif %}
{% if leave_requests.has_next %}
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#leaveRequest'
hx-get="{% url 'request-filter' %}?{{pd}}&page={{ leave_requests.next_page_number }}"
class="oh-pagination__link">{% trans "Next" %}</a>
</li>
<li class="oh-pagination__item oh-pagination__item--wide">
<a hx-target='#leaveRequest'
hx-get="{% url 'request-filter' %}?{{pd}}&page={{ leave_requests.paginator.num_pages }}"
class="oh-pagination__link">{% trans "Last" %}</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% comment %} end of pagination {% endcomment %}
{% else %}
<div style="height: 310px; display:flex;align-items: center;justify-content: center;" class="oh-404">
<div style="" class="">
<img style="display: block;width: 70px;margin: 10px auto ;" src="{% static 'images/ui/attendance.png' %}" class="" alt=""/>
<h3 style="font-size:16px" class="oh-404__subtitle">{% trans "You have No leave requests for this filter." %}</h3>
</div>
</div>
{% endif %}
<!-- End of Sticky Table -->
<!-- start of Modals -->
<div
class="oh-modal"
id="singleViewModal"
role="dialog"
aria-labelledby="singleViewModal"
aria-hidden="true"
>
<div class="oh-modal__dialog">
<div class="oh-modal__dialog-header">
<h2 class="oh-modal__dialog-title" id="singleViewTitle">
{% trans "Leave Allocation Request" %}
</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="singleViewTarget"></div>
</div>
</div>

View File

@@ -0,0 +1,98 @@
{% load i18n %}
<div class="oh-modal__dialog-body oh-timeoff-modal__body pb-2">
<div class="oh-timeoff-modal__profile-content">
<div class="oh-profile">
<div class="oh-profile__avatar mr-1">
{% if leave_allocation_request.employee_id.employee_profile %}
<img src="{{leave_allocation_request.employee_id.employee_profile.url}}" class="oh-profile__image"
alt="" />
{% else %}
<img src="https://ui-avatars.com/api/?name={{leave_allocation_request.employee_id}}&background=random"
class="oh-profile__image" alt="" />
{% endif %}
</div>
</div>
<div class="oh-timeoff-modal__profile-info">
<span class="oh-timeoff-modal__user fw-bold">{{leave_allocation_request.employee_id}}</span>
<span class="oh-timeoff-modal__position">{{leave_allocation_request.employee_id.recruitment_id.job_position_id}}</span>
</div>
</div>
<div class="oh-timeoff-modal__stats-container mt-3">
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title">{% trans "Days" %}</span>
<span class="oh-timeoff-modal__stat-count">{{leave_allocation_request.requested_days}}</span>
</div>
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title">{% trans "Leave Type" %}</span>
<span class="oh-timeoff-modal__stat-count">{{leave_allocation_request.leave_type_id}}</span>
</div>
</div>
<div class="oh-timeoff-modal__stats-container mt-3">
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title">{% trans "Created Date" %}</span>
<span class="oh-timeoff-modal__stat-count">{{leave_allocation_request.requested_date}}</span>
</div>
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title">{% trans "Created By" %}</span>
<span class="oh-timeoff-modal__stat-count">{{leave_allocation_request.created_by}}</span>
</div>
</div>
<div class="oh-timeoff-modal__stats w-100 mt-3">
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title">{% trans "Leave Description" %}</span>
<div class="oh-timeoff-modal__stat-description">{{leave_allocation_request.description}}</div>
</div>
</div>
{% if leave_allocation_request.reject_reason %}
{% if leave_allocation_request.status == "cancelled" %}
<div class="oh-timeoff-modal__stats w-100 mt-3 p-2 row-status--gray diff-cell">
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title">{% trans "Reason for Cancellation" %}</span>
<div class="oh-timeoff-modal__stat-description">{{leave_allocation_request.reject_reason}}</div>
</div>
</div>
{% elif leave_allocation_request.status == "rejected" %}
<div class="oh-timeoff-modal__stats w-100 mt-3 p-2 row-status--red ">
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title">{% trans "Reason for Rejection" %}</span>
<div class="oh-timeoff-modal__stat-description">{{leave_allocation_request.reject_reason}}</div>
</div>
</div>
{% endif %}
{% endif %}
{% if leave_allocation_request.attachment %}
<a href="{{leave_request.attachment.url}}" target="_blank" class="oh-timeoff-modal__download-link">
<ion-icon class="me-1" name="download-outline"></ion-icon>
<span class="oh-timeoff-modal__download-link-text"></span>
{% trans "View attachment" %}
</a>
{% endif %}
</div>
<div class="oh-modal__dialog-footer oh-timeoff-modal__footer">
{% if leave_request.status != 'approved'%}
<a href="" class="oh-btn oh-btn--success">
<ion-icon class="me-1" name="checkmark-outline"></ion-icon>
{% trans "Approve" %}
</a>
{% else %}
<a href="" class="oh-btn oh-btn--success oh-btn--disabled"
onclick="event.preventDefault()">
<ion-icon class="me-1" name="checkmark-outline"></ion-icon>
{% trans "Approve" %}
</a>
{% endif %}
{% if leave_request.status != 'cancelled' %}
<a href="" class="oh-btn oh-btn--danger">
<ion-icon class="me-1" name="close-circle-outline"></ion-icon>
{% trans "Cancel" %}
</a>
{% else %}
<a href="" class="oh-btn oh-btn--danger oh-btn--disabled
" onclick="event.preventDefault()">
<ion-icon class="me-1" name="close-circle-outline"></ion-icon>
{% trans "Cancel" %}
</a>
{% endif %}
</div>

View File

@@ -0,0 +1,238 @@
{% extends 'index.html' %}
{% block content %}
{% load static %}
{% load i18n %}
{% comment %} start of messages {% endcomment %}
{% 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>
{% endif %}
{% comment %} end of messages {% endcomment %}
{% comment %} start of nav bar {% endcomment %}
<section class="oh-wrapper oh-main__topbar" x-data="{searchShow: false}">
{% if user_request_view %}
<div class="oh-main__titlebar oh-main__titlebar--left">
<h1 class="oh-main__titlebar-title fw-bold">{% trans "My Leave Allocation Requests" %}</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>
{% else %}
<div class="oh-main__titlebar oh-main__titlebar--left">
<h1 class="oh-main__titlebar-title fw-bold">{% trans "Leave Allocation Requests" %}</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>
{% endif %}
<div class="oh-main__titlebar oh-main__titlebar--right">
{% if leave_allocation_requests %}
{% comment %} start of search {% endcomment %}
<div class="oh-input-group oh-input__search-group" :class="searchShow ? 'oh-input__search-group--show' : ''">
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left"></ion-icon>
<input type="text" class="oh-input oh-input__icon" aria-label="Search Input" placeholder="{% trans 'Search' %}"
name="leave_type" hx-get="{% url 'leave-allocation-request-filter' %}" hx-trigger="keyup"
hx-target="#userRequest" />
</div>
{% comment %} start of filter {% endcomment %}
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn ml-2" @click="open = !open">
<ion-icon name="filter" class="mr-1"></ion-icon>{% trans "Filter" %}<div id='filterCount'><div>
</button>
<form method="post" hx-get="{% url 'user-request-filter' %}" hx-target="#userRequest" id='filterForm'>
<div class="oh-dropdown__menu oh-dropdown__menu--right oh-dropdown__filter p-4" x-show="open"
style="display: none;" @click.outside="open = false">
<div class="oh-dropdown__filter-body">
<div class="oh-accordion" >
<div class="oh-accordion-header" onclick="event.stopImmediatePropagation();$(this).parent().toggleClass('oh-accordion--show');">{% trans "Leave Request" %}</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">{% trans "Leave Type" %}</label>
{{form.leave_type_id}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Start Date" %}</label>
{{form.start_date}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "End Date" %}</label>
{{form.end_date}}
</div>
</div>
<div class="col-sm-12 col-md-12">
<div class="oh-input-group">
<label class="oh-label">{% trans "Status" %}</label>
{{form.status}}
</div>
</div>
</div>
</div>
</div>
<div class="oh-accordion" >
<div class="oh-accordion-header" onclick="event.stopImmediatePropagation();$(this).parent().toggleClass('oh-accordion--show');">{% trans "Advanced" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "From Date" %}</label>
{{form.from_date}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "To Date" %}</label>
{{form.to_date}}
</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" type="submit">{% trans "Filter" %}</button>
</div>
</div>
</form>
</div>
{% comment %} end of filter {% endcomment %}
{% endif %}
{% comment %} start of create button {% endcomment %}
<div class="oh-btn-group ml-2">
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn oh-btn--secondary oh-btn--shadow"
data-toggle="oh-modal-toggle"
data-target="#editModal1"
hx-get="{% url 'leave-allocation-request-create' %}"
hx-target="#createForm">
<ion-icon name="add-outline" class="me-1 md hydrated" role="img" aria-label="add outline"></ion-icon>
{% trans "Create" %}
</button>
</div>
</div>
{% comment %} end of create button {% endcomment %}
</div>
</section>
{% comment %} start of request view {% endcomment %}
<div class="oh-wrapper" id="userRequest">
{% if leave_allocation_requests %}
{% include 'leave/leave_allocation_request/leave_allocation_request_list.html' %}
{% else %}
<div style="height: 70vh; display:flex;align-items: center;justify-content: center;" class="">
<div style="" class="oh-404">
<img style="display: block;width:150px;height:150px;margin: 10px auto ;" src="{% static 'images/ui/attendance.png' %}" class="mb-4" alt=""/>
<h3 style="font-size:20px" class="oh-404__subtitle">{% trans "There are no leave allocation requests at the moment." %}</h3>
</div>
</div>
{% endif %}
</div>
{% comment %} end of request view {% endcomment %}
{% comment %} modals {% endcomment %}
<div
class="oh-modal"
id="editModal"
role="dialog"
aria-labelledby="editDialogModal"
aria-hidden="true"
>
<div class="oh-modal__dialog">
<div class="oh-modal__dialog-header">
<h2 class="oh-modal__dialog-title" id="editDialogDialog">
{% trans "Update Request" %}
</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="updateForm"></div>
</div>
</div>
<div
class="oh-modal"
id="editModal1"
role="dialog"
aria-labelledby="editDialogModal"
aria-hidden="true"
>
<div class="oh-modal__dialog">
<div class="oh-modal__dialog-header">
<h2 class="oh-modal__dialog-title" id="editDialogDialog">
{% trans "Create Leave Allocation Request" %}
</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="createForm"></div>
</div>
</div>
<div class="oh-modal" id="tableTimeOff" role="dialog" aria-labelledby="tableTimeOffModal" aria-hidden="true">
<div class="oh-modal__dialog oh-modal__dialog--timeoff oh-timeoff-modal">
<div class="oh-modal__dialog-header">
<button class="oh-modal__close" aria-label="Close">
<ion-icon name="close-outline"></ion-icon>
</button>
</div>
<div id="userRequestView">
</div>
</div>
</div>
<script>
$(document).on('htmx:load', '#userRequest', function () {
// Create a new script element
var scriptElement = document.createElement("script");
// Set the source URL of the script file to be loaded
scriptElement.src = "{% static 'build/js/web.frontend.min.js' %}";
// Append the script element to the head of the HTML document
document.head.appendChild(scriptElement);
});
$(document).on('htmx:load', '#updateForm', function () {
{% include 'select2.js' %}
$('#startDate #id_start_date_breakdown').select2();
$('#endDate #id_end_date_breakdown').select2();
});
$('#delete-link').on('click', function (event) {
event.preventDefault(); // prevent the default behavior of the link
const link = $(this);
const confirmation = confirm('{% trans "Are you sure you want to delete?" %}');
if (confirmation) {
window.location.href = link.attr('href'); // execute the href if confirmed
}
});
</script>
<script src="{% static '/base/filter.js' %}"></script>
<script src="./build/js/web.frontend.min.js"></script>
<script type="module" src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.js"></script>
{% endblock %}

View File

@@ -29,111 +29,108 @@
</div>
<div class="oh-main__titlebar oh-main__titlebar--right">
{% if leave_requests %}
<div class="oh-input-group oh-input__search-group" :class="searchShow ? 'oh-input__search-group--show' : ''">
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left"></ion-icon>
<input type="text" class="oh-input oh-input__icon" aria-label="Search Input" placeholder="{% trans 'Search' %}"
name="leave_type" hx-get="{% url 'user-request-filter' %}" hx-trigger="keyup"
hx-target="#userRequest" />
</div>
<div class="oh-main__titlebar-button-container">
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn ml-2" @click="open = !open">
<ion-icon name="filter" class="mr-1"></ion-icon>{% trans "Filter" %}<div id='filterCount'><div>
</button>
<form method="post" hx-get="{% url 'user-request-filter' %}" hx-target="#userRequest" id='filterForm'>
<div class="oh-dropdown__menu oh-dropdown__menu--right oh-dropdown__filter p-4" x-show="open"
style="display: none;" @click.outside="open = false">
<div class="oh-dropdown__filter-body">
<div class="oh-accordion" >
<div class="oh-accordion-header" onclick="event.stopImmediatePropagation();$(this).parent().toggleClass('oh-accordion--show');">{% trans "Leave Request" %}</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">{% trans "Leave Type" %}</label>
{{form.leave_type_id}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Start Date" %}</label>
{{form.start_date}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "End Date" %}</label>
{{form.end_date}}
</div>
</div>
<div class="col-sm-12 col-md-12">
<div class="oh-input-group">
<label class="oh-label">{% trans "Status" %}</label>
{{form.status}}
</div>
</div>
</div>
</div>
</div>
<div class="oh-accordion" >
<div class="oh-accordion-header" onclick="event.stopImmediatePropagation();$(this).parent().toggleClass('oh-accordion--show');">{% trans "Advanced" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "From Date" %}</label>
{{form.from_date}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "To Date" %}</label>
{{form.to_date}}
</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" type="submit">{% trans "Filter" %}</button>
</div>
</div>
</form>
<div class="oh-input-group oh-input__search-group" :class="searchShow ? 'oh-input__search-group--show' : ''">
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left"></ion-icon>
<input type="text" class="oh-input oh-input__icon" aria-label="Search Input" placeholder="{% trans 'Search' %}"
name="leave_type" hx-get="{% url 'user-request-filter' %}" hx-trigger="keyup"
hx-target="#userRequest" />
</div>
{% endif %}
<div class="oh-main__titlebar-button-container">
{% comment %} start of filter {% endcomment %}
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn ml-2" @click="open = !open">
<ion-icon name="filter" class="mr-1"></ion-icon>{% trans "Filter" %}<div id='filterCount'><div>
</button>
<form method="post" hx-get="{% url 'user-request-filter' %}" hx-target="#userRequest" id='filterForm'>
<div class="oh-dropdown__menu oh-dropdown__menu--right oh-dropdown__filter p-4" x-show="open"
style="display: none;" @click.outside="open = false">
<div class="oh-dropdown__filter-body">
<div class="oh-accordion" >
<div class="oh-accordion-header" onclick="event.stopImmediatePropagation();$(this).parent().toggleClass('oh-accordion--show');">{% trans "Leave Request" %}</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">{% trans "Leave Type" %}</label>
{{form.leave_type_id}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Start Date" %}</label>
{{form.start_date}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "End Date" %}</label>
{{form.end_date}}
</div>
</div>
<div class="col-sm-12 col-md-12">
<div class="oh-input-group">
<label class="oh-label">{% trans "Status" %}</label>
{{form.status}}
</div>
</div>
</div>
</div>
</div>
<div class="oh-accordion" >
<div class="oh-accordion-header" onclick="event.stopImmediatePropagation();$(this).parent().toggleClass('oh-accordion--show');">{% trans "Advanced" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "From Date" %}</label>
{{form.from_date}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "To Date" %}</label>
{{form.to_date}}
</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" type="submit">{% trans "Filter" %}</button>
</div>
</div>
</form>
</div>
{% comment %} end of filter {% endcomment %}
{% endif %}
<div class="oh-btn-group ml-2">
<div class="oh-dropdown" x-data="{open: false}">
<button class="oh-btn oh-btn--secondary oh-btn--shadow" data-toggle="oh-modal-toggle" data-target="#editModal1" hx-get="{% url 'leave-request-create' %}" hx-target="#createForm">
<ion-icon name="add-outline" class="me-1 md hydrated" role="img" aria-label="add outline"></ion-icon>
{% trans "Create" %}
</button>
</div>
</div>
</div>
</div>
</section>
<div class="oh-wrapper" id="userRequest">
{% if leave_requests %}
{% include 'leave/user_leave/user_requests.html' %}
{% else %}
<div style="height: 70vh; display:flex;align-items: center;justify-content: center;" class="">
<div style="" class="oh-404">
<img style="display: block;width:150px;height:150px;margin: 10px auto ;" src="{% static 'images/ui/attendance.png' %}" class="mb-4" alt=""/>
<h3 style="font-size:20px" class="oh-404__subtitle">{% trans "There are no leave requests at the moment." %}</h3>
<div style="height: 70vh; display:flex;align-items: center;justify-content: center;" class="">
<div style="" class="oh-404">
<img style="display: block;width:150px;height:150px;margin: 10px auto ;" src="{% static 'images/ui/attendance.png' %}" class="mb-4" alt=""/>
<h3 style="font-size:20px" class="oh-404__subtitle">{% trans "There are no leave requests at the moment." %}</h3>
</div>
</div>
</div>
{% endif %}
</div>
@@ -180,7 +177,6 @@
<div class="oh-modal" id="tableTimeOff" role="dialog" aria-labelledby="tableTimeOffModal" aria-hidden="true">
<div class="oh-modal__dialog oh-modal__dialog--timeoff oh-timeoff-modal">
<div class="oh-modal__dialog-header">
<button class="oh-modal__close" aria-label="Close">
<ion-icon name="close-outline"></ion-icon>
</button>

View File

@@ -131,4 +131,29 @@ urlpatterns = [
path("leave-type-chart", views.leave_type_chart, name="leave-type-chart"),
path("leave-over-period", views.leave_over_period, name="leave-over-period"),
path("leave-request-create", views.leave_request_create, name="leave-request-create"),
path('leave-allocation-request-view',
views.leave_allocation_request_view,
name='leave-allocation-request-view',
),
path('user-leave-allocation-request-view',
views.user_leave_allocation_request_view,
name='user-leave-allocation-request-view',
),
path(
'leave-allocation-request-create',
views.leave_allocation_request_create,
name= "leave-allocation-request-create"
),
path(
'leave-allocation-request-filter',
views.leave_allocation_request_filter,
name= "leave-allocation-request-filter"
),
path(
'leave-allocation-request-single-view/<int:req_id>',
views.leave_allocation_request_single_view,
name= "leave-allocation-request-single-view"
),
]

View File

@@ -2359,3 +2359,86 @@ def leave_request_create(request):
response.content.decode("utf-8") + "<script>location.reload();</script>"
)
return render(request, "leave/user_leave/request_form.html", {"form": form})
@login_required
@manager_can_enter("leave.view_leaveallocationrequest")
def leave_allocation_request_view(request):
"""
function used to view leave allocation request.
Parameters:
request (HttpRequest): The HTTP request object.
Returns:
GET : return leave allocation request view template
"""
queryset = LeaveAllocationRequest.objects.all().order_by('-id')
queryset = filtersubordinates(request,queryset,'leave.view_leaveallocationrequest')
page_number = request.GET.get('page')
page_obj = paginator_qry(queryset,page_number)
previous_data = request.GET.urlencode()
leave_allocation_request_filter = LeaveAllocationRequestFilter()
context={
'leave_allocation_requests' :page_obj,
"pd": previous_data,
"form": leave_allocation_request_filter.form,
}
return render(
request,
'leave/leave_allocation_request/leave_allocation_request_view.html',
context=context
)
@login_required
def user_leave_allocation_request_view(request):
employee = request.user.employee_get
leave_allocation_requests = LeaveAllocationRequest.objects.filter(employee_id=employee.id)
print (leave_allocation_requests)
context = { 'leave_allocation_requests' :leave_allocation_requests,
"user_request_view":True,
}
return render(request,'leave/leave_allocation_request/leave_allocation_request_view.html',context=context)
@login_required
def leave_allocation_request_single_view(request,req_id):
leave_allocation_request = LeaveAllocationRequest.objects.get(id=req_id)
print(leave_allocation_request)
return render(
request,
'leave/leave_allocation_request/leave_allocation_request_single_view.html',
{'leave_allocation_request':leave_allocation_request}
)
@login_required
def leave_allocation_request_create(request):
employee = request.user.employee_get
form = LeaveAllocationRequestForm()
if request.method == 'POST':
form = LeaveAllocationRequestForm(request.POST)
if form.is_valid():
form.save
messages.success(request,_("New Leave allocation request is created"))
response = render(
request,
"leave/leave_allocation_request/leave_allocation_request_create.html",
{'form':form}
)
return HttpResponse(
response.content.decode("utf-8")
+ "<script>location. reload();</script>"
)
context = {
'form':form
}
return render(request,
'leave/leave_allocation_request/leave_allocation_request_create.html',
context=context)
@login_required
def leave_allocation_request_filter(request):
leave_allocation_requests = request.user
context = { 'leave_allocation_requests' :leave_allocation_requests,
}
return render(request,
'leave/leave_allocation_request/leave_allocation_request_view.html',
context=context)

View File

@@ -499,6 +499,13 @@
>{% trans "My Leave Requests" %}</a
>
</li>
<li class="oh-sidebar__submenu-item">
<a
href="{% url 'user-leave-allocation-request-view' %}"
class="oh-sidebar__submenu-link"
>{% trans "My Leave Allocation Requests" %}</a
>
</li>
{% if perms.leave.view_leavetype %}
<li class="oh-sidebar__submenu-item">
<a href="{% url 'type-view' %}" class="oh-sidebar__submenu-link"
@@ -511,7 +518,8 @@
>{% trans "Assigned Leaves" %}</a
>
</li>
{% endif %} {% if perms.leave.view_leaverequest or request.user|is_reportingmanager %}
{% endif %}
{% if perms.leave.view_leaverequest or request.user|is_reportingmanager %}
<li class="oh-sidebar__submenu-item">
<a
href="{% url 'request-view' %}"
@@ -519,7 +527,17 @@
>{% trans "Leave Requests" %}</a
>
</li>
{% endif %} {% if perms.leave.view_holiday %}
{% endif %}
{% if perms.leave.view_leaveallocationrequest or request.user|is_reportingmanager %}
<li class="oh-sidebar__submenu-item">
<a
href="{% url 'leave-allocation-request-view' %}"
class="oh-sidebar__submenu-link"
>{% trans "Leave Allocation Requests" %}</a
>
</li>
{% endif %}
{% if perms.leave.view_holiday %}
<li class="oh-sidebar__submenu-item">
<a
href="{% url 'holiday-view' %}"