diff --git a/leave/admin.py b/leave/admin.py index 3831686d0..5f23fe69b 100644 --- a/leave/admin.py +++ b/leave/admin.py @@ -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) diff --git a/leave/filters.py b/leave/filters.py index 3a4fb9443..bab845300 100644 --- a/leave/filters.py +++ b/leave/filters.py @@ -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"] + } diff --git a/leave/forms.py b/leave/forms.py index 618e066c0..b437b3585 100644 --- a/leave/forms.py +++ b/leave/forms.py @@ -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() } - \ No newline at end of file + +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 \ No newline at end of file diff --git a/leave/models.py b/leave/models.py index 26333ab82..0cdee257f 100644 --- a/leave/models.py +++ b/leave/models.py @@ -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() diff --git a/leave/templates/leave/leave_allocation_request/leave_allocation_request_create.html b/leave/templates/leave/leave_allocation_request/leave_allocation_request_create.html new file mode 100644 index 000000000..437223e3a --- /dev/null +++ b/leave/templates/leave/leave_allocation_request/leave_allocation_request_create.html @@ -0,0 +1,17 @@ +{% load i18n %} +{% if form.errors %} + +
+
+ {% for error in form.non_field_errors %} +
+ {{ error }} +
+ {% endfor %} +
+
+{% endif %} +
+ {{form.as_p}} +
\ No newline at end of file diff --git a/leave/templates/leave/leave_allocation_request/leave_allocation_request_list.html b/leave/templates/leave/leave_allocation_request/leave_allocation_request_list.html new file mode 100644 index 000000000..ee132eae5 --- /dev/null +++ b/leave/templates/leave/leave_allocation_request/leave_allocation_request_list.html @@ -0,0 +1,194 @@ +{% load i18n %} +{% load static %} +{% if messages %} +
+ {% for message in messages %} +
+
+ {{ message }} +
+
+ {% endfor %} +
+{% endif %} +{% include 'filter_tags.html' %} + {% comment %} {% if not request.GET.dashboard %} {% endcomment %} +{% if leave_allocation_requests %} +
+ + + {% trans "Rejected" %} + + + + {% trans "Cancelled" %} + + + + {% trans "Requested" %} + + +
+ {% comment %} {% endif %} {% endcomment %} + +
+
+
+
+
{% trans "Employee" %}
+
{% trans "Leave Type" %}
+
{% trans "Requested Days" %}
+
{% trans "Status" %}
+
{% trans "Options" %}
+
{% trans "Actions" %}
+
+
+
+ {% for leave_request in leave_allocation_requests %} +
+
+
+
+ {% if leave_request.employee_id.employee_profile %} + + {% else %} + + {% endif %} +
+ {{leave_request.employee_id}} +
+
+
{{leave_request.leave_type_id}}
+
{{leave_request.requested_days}}
+
{{leave_request.get_status_display}}
+
+
+ {% if leave_request.status == 'requested' or leave_request.status == 'rejected' %} + + + + {% else %} + + + + {% endif %} + {% if leave_request.status != 'rejected' %} + + + + + {% else %} + + + + {% endif %} +
+
+
+
+ + + + +
+
+
+ {% endfor %} +
+
+
+ {% comment %} start of pagination {% endcomment %} +
+ + {% trans "Page" %} {{ leave_requests.number }} {% trans "of" %} {{ leave_requests.paginator.num_pages }}. + + +
+ {% comment %} end of pagination {% endcomment %} +{% else %} +
+
+ +

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

+
+
+{% endif %} + + + + \ No newline at end of file diff --git a/leave/templates/leave/leave_allocation_request/leave_allocation_request_single_view.html b/leave/templates/leave/leave_allocation_request/leave_allocation_request_single_view.html new file mode 100644 index 000000000..f2fdc63c4 --- /dev/null +++ b/leave/templates/leave/leave_allocation_request/leave_allocation_request_single_view.html @@ -0,0 +1,98 @@ +{% load i18n %} +
+
+
+
+ {% if leave_allocation_request.employee_id.employee_profile %} + + {% else %} + + {% endif %} +
+
+
+ {{leave_allocation_request.employee_id}} + {{leave_allocation_request.employee_id.recruitment_id.job_position_id}} +
+
+
+
+ {% trans "Days" %} + {{leave_allocation_request.requested_days}} +
+
+ {% trans "Leave Type" %} + {{leave_allocation_request.leave_type_id}} +
+
+
+
+ {% trans "Created Date" %} + {{leave_allocation_request.requested_date}} +
+
+ {% trans "Created By" %} + {{leave_allocation_request.created_by}} +
+
+ +
+
+ {% trans "Leave Description" %} +
{{leave_allocation_request.description}}
+
+
+ {% if leave_allocation_request.reject_reason %} + {% if leave_allocation_request.status == "cancelled" %} +
+
+ {% trans "Reason for Cancellation" %} +
{{leave_allocation_request.reject_reason}}
+
+
+ {% elif leave_allocation_request.status == "rejected" %} +
+
+ {% trans "Reason for Rejection" %} +
{{leave_allocation_request.reject_reason}}
+
+
+ {% endif %} + {% endif %} + {% if leave_allocation_request.attachment %} + + + + {% trans "View attachment" %} + + {% endif %} +
+ + \ No newline at end of file diff --git a/leave/templates/leave/leave_allocation_request/leave_allocation_request_view.html b/leave/templates/leave/leave_allocation_request/leave_allocation_request_view.html new file mode 100644 index 000000000..18f898625 --- /dev/null +++ b/leave/templates/leave/leave_allocation_request/leave_allocation_request_view.html @@ -0,0 +1,238 @@ +{% extends 'index.html' %} +{% block content %} +{% load static %} +{% load i18n %} +{% comment %} start of messages {% endcomment %} +{% if messages %} +
+ {% for message in messages %} +
+
+ {{ message }} +
+
+ {% endfor %} +
+{% endif %} +{% comment %} end of messages {% endcomment %} + +{% comment %} start of nav bar {% endcomment %} +
+ {% if user_request_view %} +
+

{% trans "My Leave Allocation Requests" %}

+ + + +
+ {% else %} +
+

{% trans "Leave Allocation Requests" %}

+ + + +
+ {% endif %} +
+ {% if leave_allocation_requests %} + {% comment %} start of search {% endcomment %} +
+ + +
+ {% comment %} start of filter {% endcomment %} +
+ +
+ +
+
+ {% comment %} end of filter {% endcomment %} + {% endif %} + {% comment %} start of create button {% endcomment %} +
+
+ +
+
+ {% comment %} end of create button {% endcomment %} +
+
+{% comment %} start of request view {% endcomment %} +
+ {% if leave_allocation_requests %} + {% include 'leave/leave_allocation_request/leave_allocation_request_list.html' %} + {% else %} +
+
+ +

{% trans "There are no leave allocation requests at the moment." %}

+
+
+ {% endif %} +
+{% comment %} end of request view {% endcomment %} +{% comment %} modals {% endcomment %} + + + + + + + + + + + + + + + +{% endblock %} \ No newline at end of file diff --git a/leave/templates/leave/user_leave/user_request_view.html b/leave/templates/leave/user_leave/user_request_view.html index b18ef05f8..6e6272c3d 100644 --- a/leave/templates/leave/user_leave/user_request_view.html +++ b/leave/templates/leave/user_leave/user_request_view.html @@ -29,111 +29,108 @@
{% if leave_requests %} -
- - -
-
-
- -
- -
+
+ +
- {% endif %} +
+ {% comment %} start of filter {% endcomment %} +
+ +
+ +
+
+ {% comment %} end of filter {% endcomment %} + {% endif %}
-
-
-
{% if leave_requests %} {% include 'leave/user_leave/user_requests.html' %} {% else %} - -
-
- -

{% trans "There are no leave requests at the moment." %}

+
+
+ +

{% trans "There are no leave requests at the moment." %}

+
-
{% endif %} -
@@ -180,7 +177,6 @@