From 63da64282d598e3aa129494c821e134338b23ada Mon Sep 17 00:00:00 2001 From: Horilla Date: Mon, 14 Aug 2023 14:47:15 +0530 Subject: [PATCH] [FIX]leave reset carryforward --- base/methods.py | 61 +++-- base/models.py | 2 +- base/translator.py | 64 ++--- leave/admin.py | 8 +- leave/apps.py | 6 +- leave/filters.py | 235 ++++++++++++------ leave/forms.py | 24 +- leave/methods.py | 112 +++++---- leave/models.py | 134 +++++----- leave/resources.py | 7 +- leave/scheduler.py | 7 - .../leave/leave_request/leave-requests.html | 4 +- leave/views.py | 141 ++++------- 13 files changed, 445 insertions(+), 360 deletions(-) diff --git a/base/methods.py b/base/methods.py index ab6e4b538..07bb56a1b 100644 --- a/base/methods.py +++ b/base/methods.py @@ -1,7 +1,8 @@ from employee.models import Employee +from django.utils.translation import gettext as _ -def filtersubordinates(request,queryset,perm=None): +def filtersubordinates(request, queryset, perm=None): """ This method is used to filter out subordinates queryset element. """ @@ -9,11 +10,13 @@ def filtersubordinates(request,queryset,perm=None): if user.has_perm(perm): return queryset manager = Employee.objects.filter(employee_user_id=user).first() - queryset = queryset.filter(employee_id__employee_work_info__reporting_manager_id=manager) + queryset = queryset.filter( + employee_id__employee_work_info__reporting_manager_id=manager + ) return queryset -def filtersubordinatesemployeemodel(request,queryset,perm=None): +def filtersubordinatesemployeemodel(request, queryset, perm=None): """ This method is used to filter out subordinates queryset element. """ @@ -25,7 +28,6 @@ def filtersubordinatesemployeemodel(request,queryset,perm=None): return queryset - def is_reportingmanager(request): """ This method is used to check weather the employee is reporting manager or not. @@ -37,63 +39,68 @@ def is_reportingmanager(request): return False -def choosesubordinates(request,form,perm,): +def choosesubordinates( + request, + form, + perm, +): user = request.user if user.has_perm(perm): return form manager = Employee.objects.filter(employee_user_id=user).first() queryset = Employee.objects.filter(employee_work_info__reporting_manager_id=manager) - form.fields['employee_id'].queryset = queryset + form.fields["employee_id"].queryset = queryset return form -def choosesubordinatesemployeemodel(request,form,perm): +def choosesubordinatesemployeemodel(request, form, perm): user = request.user if user.has_perm(perm): return form manager = Employee.objects.filter(employee_user_id=user).first() queryset = Employee.objects.filter(employee_work_info__reporting_manager_id=manager) - form.fields['employee_id'].queryset = queryset + form.fields["employee_id"].queryset = queryset return form +orderingList = [ + { + "id": "", + "field": "", + "ordering": "", + } +] -orderingList = [{ - 'id':'', - 'field':'', - 'ordering':'', -}] -def sortby(request,queryset,key): +def sortby(request, queryset, key): """ This method is used to sort query set by asc or desc """ global orderingList - id = request.user.id - # here will create dictionary object to the global orderingList if not exists, + id = request.user.id + # here will create dictionary object to the global orderingList if not exists, # if exists then method will switch corresponding object ordering. - filtered_list = [x for x in orderingList if x['id'] ==id] + filtered_list = [x for x in orderingList if x["id"] == id] ordering = filtered_list[0] if filtered_list else None if ordering is None: ordering = { - 'id':id, - 'field':None, - 'ordering':'-', + "id": id, + "field": None, + "ordering": "-", } orderingList.append(ordering) sortby = request.GET.get(key) - if sortby is not None and sortby != '': + if sortby is not None and sortby != "": # here will update the orderingList - ordering['field']=sortby + ordering["field"] = sortby if queryset.query.order_by == queryset.query.order_by: queryset = queryset.order_by(f'{ordering["ordering"]}{sortby}') - if ordering['ordering']=='-': - ordering['ordering']='' + if ordering["ordering"] == "-": + ordering["ordering"] = "" else: - ordering["ordering"]='-' + ordering["ordering"] = "-" orderingList = [item for item in orderingList if item["id"] != id] orderingList.append(ordering) - return queryset - + return queryset \ No newline at end of file diff --git a/base/models.py b/base/models.py index 5b218d475..d88debe7a 100644 --- a/base/models.py +++ b/base/models.py @@ -254,7 +254,7 @@ class EmployeeShiftDay(models.Model): def __str__(self) -> str: return str(_(self.day)) - +from django.utils.translation import gettext_lazy as _ class EmployeeShift(models.Model): """ EmployeeShift model diff --git a/base/translator.py b/base/translator.py index e5e6ab429..657627832 100644 --- a/base/translator.py +++ b/base/translator.py @@ -1,17 +1,17 @@ -from django.utils.translation import gettext as _ +from django.utils.translation import gettext as _ -_('monday'), -_('tuesday'), -_('wednesday'), -_('thursday'), -_('friday'), -_('saturday'), -_('sunday'), -_('after'), -_('weekly'), -_('monthly'), -_('Employee First Name'), -_('Employee Last Name'), +_("monday"), +_("tuesday"), +_("wednesday"), +_("thursday"), +_("friday"), +_("saturday"), +_("sunday"), +_("after"), +_("weekly"), +_("monthly"), +_("Employee First Name"), +_("Employee Last Name"), _("Bank Code #1"), _("Bank Code #2"), _("RECRUITMENT"), @@ -21,28 +21,28 @@ _("PAYROLL"), _("ATTENDANCE"), _("LEAVE"), _("ASSET"), -_('Your asset request approved!.'), -_('Your asset request rejected!.'), -_('You are added to rotating work type'), +_("Your asset request approved!."), +_("Your asset request rejected!."), +_("You are added to rotating work type"), _("You are added to rotating shift"), -_('Your work type request has been canceled.'), -_('Your work type request has been approved.'), -_('Your work type request has been deleted.'), -_('Your shift request has been canceled.'), -_('Your shift request has been approved.'), -_('Your shift request has been deleted.'), -_('Your work details has been updated.'), +_("Your work type request has been canceled."), +_("Your work type request has been approved."), +_("Your work type request has been deleted."), +_("Your shift request has been canceled."), +_("Your shift request has been approved."), +_("Your shift request has been deleted."), +_("Your work details has been updated."), _("You have a new leave request to validate."), _("New leave type is assigned to you"), _("Your Leave request has been cancelled"), _("Your Leave request has been approved"), _("You are chosen as onboarding stage manager"), _("You are chosen as onboarding task manager"), -_('You got an OKR!.'), -_('You have received feedback!'), -_('You have been assigned as a manager in a feedback!'), -_('You have been assigned as a subordinate in a feedback!'), -_('You have been assigned as a colleague in a feedback!'), +_("You got an OKR!."), +_("You have received feedback!"), +_("You have been assigned as a manager in a feedback!"), +_("You have been assigned as a subordinate in a feedback!"), +_("You have been assigned as a colleague in a feedback!"), _("You are chosen as one of recruitment manager"), _("Your attendance for the date "), _(" is validated"), @@ -96,4 +96,10 @@ _("Divorced"), _("Description"), _("Rotate every weekend"), _("Rotate every"), -_(), +_("Request description"), +_("Attendance validated"), +_("Is validate request"), +_("Is validate request approved"), +_("Reporting Manager"), +_("Employment Type"), +_("Regular Shift"), diff --git a/leave/admin.py b/leave/admin.py index 0e02c0e00..3831686d0 100644 --- a/leave/admin.py +++ b/leave/admin.py @@ -1,6 +1,9 @@ +""" +Module for registering LeaveType, LeaveRequest, AvailableLeave, Holiday, and CompanyLeave +models with the Django admin site. +""" from django.contrib import admin -from .models import * - +from .models import LeaveType, LeaveRequest, AvailableLeave, Holiday, CompanyLeave # Register your models here. @@ -9,4 +12,3 @@ admin.site.register(LeaveRequest) admin.site.register(AvailableLeave) admin.site.register(Holiday) admin.site.register(CompanyLeave) - diff --git a/leave/apps.py b/leave/apps.py index f74dffcb7..20cbe88c2 100644 --- a/leave/apps.py +++ b/leave/apps.py @@ -1,6 +1,6 @@ from django.apps import AppConfig -class LeaveConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'leave' +class LeaveConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "leave" diff --git a/leave/filters.py b/leave/filters.py index dcabaaee3..c53c79af1 100644 --- a/leave/filters.py +++ b/leave/filters.py @@ -1,171 +1,254 @@ -from .models import * +""" +This module contains custom filter classes used for filtering +various models in the Leave Management System app. +The filters are designed to provide flexible search and filtering +capabilities for LeaveType, LeaveRequest,AvailableLeave, Holiday, and CompanyLeave models. +""" from django import forms from django_filters import FilterSet, DateFilter, filters +from .models import LeaveType, LeaveRequest, AvailableLeave, Holiday, CompanyLeave class FilterSet(FilterSet): + """ + Custom FilterSet class for styling filter widgets. + """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field_name, field in self.filters.items(): filter_widget = self.filters[field_name] widget = filter_widget.field.widget - if isinstance(widget, (forms.NumberInput, forms.EmailInput, forms.TextInput)): - filter_widget.field.widget.attrs.update( - {'class': 'oh-input w-100'}) + if isinstance( + widget, (forms.NumberInput, forms.EmailInput, forms.TextInput) + ): + filter_widget.field.widget.attrs.update({"class": "oh-input w-100"}) elif isinstance(widget, (forms.Select,)): filter_widget.field.widget.attrs.update( - {'class': 'oh-select oh-select-2 select2-hidden-accessible', }) + { + "class": "oh-select oh-select-2 select2-hidden-accessible", + } + ) elif isinstance(widget, (forms.Textarea)): + filter_widget.field.widget.attrs.update({"class": "oh-input w-100"}) + elif isinstance( + widget, + ( + forms.CheckboxInput, + forms.CheckboxSelectMultiple, + ), + ): filter_widget.field.widget.attrs.update( - {'class': 'oh-input w-100'}) - elif isinstance(widget, (forms.CheckboxInput, forms.CheckboxSelectMultiple,)): - filter_widget.field.widget.attrs.update( - {'class': 'oh-switch__checkbox'}) + {"class": "oh-switch__checkbox"} + ) elif isinstance(widget, (forms.ModelChoiceField)): filter_widget.field.widget.attrs.update( - {'class': 'oh-select oh-select-2 select2-hidden-accessible', }) + { + "class": "oh-select oh-select-2 select2-hidden-accessible", + } + ) class LeaveTypeFilter(FilterSet): - name = filters.CharFilter(field_name='name', lookup_expr='icontains') + """ + Filter class for LeaveType model. + + This filter allows searching LeaveType objects based on their name and payment attributes. + """ + + name = filters.CharFilter(field_name="name", lookup_expr="icontains") class Meta: + """ " + Meta class defines the model and fields to filter + """ + model = LeaveType fields = { - - 'payment': ['exact'], - + "payment": ["exact"], } -class AssignedLeavefilter(FilterSet): +class AssignedLeaveFilter(FilterSet): + """ + Filter class for AvailableLeave model. + + This filter allows searching AvailableLeave objects based on leave type, + employee, assigned date and payment attributes. + """ + leave_type = filters.CharFilter( - field_name='leave_type_id__name', lookup_expr='icontains') + field_name="leave_type_id__name", lookup_expr="icontains" + ) employee_id = filters.CharFilter( - field_name='employee_id__employee_first_name', lookup_expr='icontains') + field_name="employee_id__employee_first_name", lookup_expr="icontains" + ) assigned_date = DateFilter( - field_name='assigned_date', - lookup_expr='exact', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="assigned_date", + lookup_expr="exact", + widget=forms.DateInput(attrs={"type": "date"}), ) class Meta: + """ " + Meta class defines the model and fields to filter + """ + model = AvailableLeave fields = { - 'leave_type_id': ['exact'], - + "leave_type_id": ["exact"], } class LeaveRequestFilter(FilterSet): + """ + Filter class for LeaveRequest model. + 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') + field_name="employee_id__employee_first_name", lookup_expr="icontains" + ) from_date = DateFilter( - field_name='start_date', - lookup_expr='gte', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="start_date", + lookup_expr="gte", + widget=forms.DateInput(attrs={"type": "date"}), ) to_date = DateFilter( - field_name='end_date', - lookup_expr='lte', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="end_date", + lookup_expr="lte", + widget=forms.DateInput(attrs={"type": "date"}), ) start_date = DateFilter( - field_name='start_date', - lookup_expr='exact', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="start_date", + lookup_expr="exact", + widget=forms.DateInput(attrs={"type": "date"}), ) end_date = DateFilter( - field_name='end_date', - lookup_expr='exact', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="end_date", + lookup_expr="exact", + widget=forms.DateInput(attrs={"type": "date"}), ) class Meta: + """ " + Meta class defines the model and fields to filter + """ + model = LeaveRequest fields = { - 'leave_type_id': ['exact'], - 'status' : ['exact'], + "leave_type_id": ["exact"], + "status": ["exact"], } class HolidayFilter(FilterSet): - name = filters.CharFilter( - field_name='name', lookup_expr='icontains') + """ + Filter class for Holiday model. + + This filter allows searching Holiday objects based on name and date range. + """ + + name = filters.CharFilter(field_name="name", lookup_expr="icontains") from_date = DateFilter( - field_name='start_date', - lookup_expr='gte', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="start_date", + lookup_expr="gte", + widget=forms.DateInput(attrs={"type": "date"}), ) to_date = DateFilter( - field_name='end_date', - lookup_expr='lte', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="end_date", + lookup_expr="lte", + widget=forms.DateInput(attrs={"type": "date"}), ) start_date = DateFilter( - field_name='start_date', - lookup_expr='exact', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="start_date", + lookup_expr="exact", + widget=forms.DateInput(attrs={"type": "date"}), ) end_date = DateFilter( - field_name='end_date', - lookup_expr='exact', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="end_date", + lookup_expr="exact", + widget=forms.DateInput(attrs={"type": "date"}), ) class Meta: + """ " + Meta class defines the model and fields to filter + """ + model = Holiday fields = { - 'recurring': ['exact'], - + "recurring": ["exact"], } -class CompanyLeavefilter(FilterSet): - name = filters.CharFilter( - field_name='based_on_week_day', lookup_expr='icontains') - +class CompanyLeaveFilter(FilterSet): + """ + Filter class for CompanyLeave model. + + This filter allows searching CompanyLeave objects based on + name, week day and based_on_week choices. + """ + + name = filters.CharFilter(field_name="based_on_week_day", lookup_expr="icontains") + class Meta: + """ " + Meta class defines the model and fields to filter + """ + model = CompanyLeave fields = { - 'based_on_week': ['exact'], - 'based_on_week_day': ['exact'], + "based_on_week": ["exact"], + "based_on_week_day": ["exact"], } -class userLeaveRequestFilter(FilterSet): +class UserLeaveRequestFilter(FilterSet): + """ + Filter class for LeaveRequest 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') + field_name="leave_type_id__name", lookup_expr="icontains" + ) from_date = DateFilter( - field_name='start_date', - lookup_expr='gte', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="start_date", + lookup_expr="gte", + widget=forms.DateInput(attrs={"type": "date"}), ) to_date = DateFilter( - field_name='end_date', - lookup_expr='lte', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="end_date", + lookup_expr="lte", + widget=forms.DateInput(attrs={"type": "date"}), ) start_date = DateFilter( - field_name='start_date', - lookup_expr='exact', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="start_date", + lookup_expr="exact", + widget=forms.DateInput(attrs={"type": "date"}), ) end_date = DateFilter( - field_name='end_date', - lookup_expr='exact', - widget=forms.DateInput(attrs={'type': 'date'}) + field_name="end_date", + lookup_expr="exact", + widget=forms.DateInput(attrs={"type": "date"}), ) class Meta: + """ " + Meta class defines the model and fields to filter + """ + model = LeaveRequest fields = { - 'leave_type_id': ['exact'], - 'status' : ['exact'], - } \ No newline at end of file + "leave_type_id": ["exact"], + "status": ["exact"], + } diff --git a/leave/forms.py b/leave/forms.py index 266bc90f2..4b323389d 100644 --- a/leave/forms.py +++ b/leave/forms.py @@ -1,20 +1,17 @@ -from typing import Any -from django.forms import ModelForm -from django.template.loader import render_to_string -from .models import * -from django.forms import DateInput -from django.forms.widgets import TextInput +import re from django import forms +from django.forms import ModelForm +from django.forms.widgets import TextInput +from django.core.exceptions import ValidationError +from django.utils.translation import gettext_lazy as _ from employee.models import Employee +from .models import LeaveType, LeaveRequest, AvailableLeave, Holiday, CompanyLeave from .methods import ( calculate_requested_days, leave_requested_dates, holiday_dates_list, company_leave_dates_list, ) -from django.core.exceptions import ValidationError -from django.utils.translation import gettext_lazy as _ -import re CHOICES = [("yes", _("Yes")), ("no", _("No"))] @@ -30,21 +27,19 @@ class ModelForm(forms.ModelForm): field.widget.attrs.update({"class": "oh-input oh-calendar-input w-100"}) elif isinstance( widget, (forms.NumberInput, forms.EmailInput, forms.TextInput) - ): - placeholder = _(field.label) + ): field.widget.attrs.update( - {"class": "oh-input w-100", "placeholder": placeholder} + {"class": "oh-input w-100", "placeholder": field.label} ) elif isinstance(widget, (forms.Select,)): field.widget.attrs.update( {"class": "oh-select oh-select-2 select2-hidden-accessible"} ) elif isinstance(widget, (forms.Textarea)): - placeholder = _(field.label) field.widget.attrs.update( { "class": "oh-input w-100", - "placeholder": placeholder, + "placeholder": field.label, "rows": 2, "cols": 40, } @@ -363,7 +358,6 @@ class HolidayForm(ModelForm): widget=forms.DateInput(attrs={"type": "date"}), ) end_date = forms.DateField( - required=False, widget=forms.DateInput(attrs={"type": "date"}), ) diff --git a/leave/methods.py b/leave/methods.py index 8ba454174..87803e0d6 100644 --- a/leave/methods.py +++ b/leave/methods.py @@ -1,9 +1,10 @@ -from datetime import datetime, timedelta import calendar -from django.utils import timezone +from datetime import datetime, timedelta -def calculate_requested_days(start_date, end_date, start_date_breakdown, end_date_breakdown): +def calculate_requested_days( + start_date, end_date, start_date_breakdown, end_date_breakdown +): if start_date == end_date: if start_date_breakdown == "full_day" and end_date_breakdown == "full_day": requested_days = 1 @@ -21,14 +22,17 @@ def calculate_requested_days(start_date, end_date, start_date_breakdown, end_dat if start_date_breakdown == "full_day" and end_date_breakdown == "full_day": requested_days = (end_date - start_date).days + start_days + end_days + 1 else: - if start_date_breakdown == 'full_day' or end_date_breakdown == 'full_day': + if start_date_breakdown == "full_day" or end_date_breakdown == "full_day": requested_days = (end_date - start_date).days + start_days + end_days else: - requested_days = (end_date - start_date).days + start_days + end_days - 1 + requested_days = ( + (end_date - start_date).days + start_days + end_days - 1 + ) return requested_days -def leave_requested_dates(start_date,end_date): + +def leave_requested_dates(start_date, end_date): """ :return: this functions returns a list of dates from start date to end date. """ @@ -43,46 +47,58 @@ def leave_requested_dates(start_date,end_date): requested_dates.append(date) return requested_dates -def holiday_dates_list(holidays): - """ - :return: this functions returns a list of all holiday dates. - """ - holiday_dates = [] - for holiday in holidays: - holiday_start_date = holiday.start_date - holiday_end_date = holiday.end_date - if holiday_end_date is None: - holiday_end_date = holiday_start_date - holiday_days = holiday_end_date - holiday_start_date - for i in range(holiday_days.days + 1): - date = holiday_start_date + timedelta(i) - holiday_dates.append(date) - return holiday_dates -def company_leave_dates_list(company_leaves,start_date): - """ - :return: This function returns a list of all company leave dates""" - company_leave_dates = [] - for company_leave in company_leaves: - year = start_date.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): - if based_on_week != None: - # Set Sunday as the first day of the week - calendar.setfirstweekday(6) - month_calendar = calendar.monthcalendar(year, 7) - weeks = month_calendar[based_on_week] - day = weeks[based_on_week_day] - company_leave_dates.append(date(year=year, month=7, day=day)) - else: - # Set Monday as the first day of the week - calendar.setfirstweekday(0) - month_calendar = calendar.monthcalendar(year, month) - for week in month_calendar: - if week[int(based_on_week_day)-1] != 0: - date = datetime.strptime( - f"{year}-{month:02}-{week[int(based_on_week_day)-1]:02}", '%Y-%m-%d').date() - if date not in company_leave_dates: - company_leave_dates.append(date) - return list(set(company_leave_dates)) \ No newline at end of file +def holiday_dates_list(holidays): + """ + :return: this functions returns a list of all holiday dates. + """ + holiday_dates = [] + for holiday in holidays: + holiday_start_date = holiday.start_date + holiday_end_date = holiday.end_date + if holiday_end_date is None: + holiday_end_date = holiday_start_date + holiday_days = holiday_end_date - holiday_start_date + for i in range(holiday_days.days + 1): + date = holiday_start_date + timedelta(i) + holiday_dates.append(date) + return holiday_dates + + +def company_leave_dates_list(company_leaves, start_date): + """ + :return: This function returns a list of all company leave dates""" + company_leave_dates = [] + for company_leave in company_leaves: + year = start_date.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): + if based_on_week != None: + # Set Sunday as the first day of the week + calendar.setfirstweekday(6) + month_calendar = calendar.monthcalendar(year, month) + weeks = month_calendar[int(based_on_week)] + weekdays_in_weeks = [day for day in weeks if day != 0] + for day in weekdays_in_weeks: + date = datetime.strptime( + f"{year}-{month:02}-{day:02}", "%Y-%m-%d" + ).date() + if ( + date.weekday() == int(based_on_week_day) + and date not in company_leave_dates + ): + company_leave_dates.append(date) + else: + # Set Monday as the first day of the week + calendar.setfirstweekday(0) + month_calendar = calendar.monthcalendar(year, month) + for week in month_calendar: + if week[int(based_on_week_day)] != 0: + date = datetime.strptime( + f"{year}-{month:02}-{week[int(based_on_week_day)]:02}", + "%Y-%m-%d", + ).date() + if date not in company_leave_dates: + company_leave_dates.append(date) + return company_leave_dates diff --git a/leave/models.py b/leave/models.py index d2e432cfb..a976b58ae 100644 --- a/leave/models.py +++ b/leave/models.py @@ -1,16 +1,11 @@ -""" -models.py - -This module is used to regster models for the leave app -""" import calendar from datetime import datetime, timedelta +from django.db import models +from django.utils import timezone from dateutil.relativedelta import relativedelta from django.utils.translation import gettext_lazy as _ -from django.utils import timezone -from django.db import models from employee.models import Employee -from leave.methods import calculate_requested_days +from .methods import calculate_requested_days # Create your models here. @@ -102,18 +97,18 @@ WEEKS = [ ("1", _("Second Week")), ("2", _("Third Week")), ("3", _("Fourth Week")), - ("5", _("Fifth Week")), + ("4", _("Fifth Week")), ] WEEK_DAYS = [ - ("1", _("Monday")), - ("2", _("Tuesday")), - ("3", _("Wednesday")), - ("4", _("Thursday")), - ("5", _("Friday")), - ("6", _("Saturday")), - ("7", _("Sunday")), + ("0", _("Monday")), + ("1", _("Tuesday")), + ("2", _("Wednesday")), + ("3", _("Thursday")), + ("4", _("Friday")), + ("5", _("Saturday")), + ("6", _("Sunday")), ] @@ -150,6 +145,7 @@ class LeaveType(models.Model): ) exclude_company_leave = models.CharField(max_length=30, choices=CHOICES) exclude_holiday = models.CharField(max_length=30, choices=CHOICES) + objects = models.Manager() def __str__(self): return self.name @@ -197,6 +193,7 @@ class AvailableLeave(models.Model): assigned_date = models.DateField(default=timezone.now) reset_date = models.DateField(blank=True, null=True) expired_date = models.DateField(blank=True, null=True) + objects = models.Manager() class Meta: unique_together = ("leave_type_id", "employee_id") @@ -221,45 +218,61 @@ class AvailableLeave(models.Model): available_leave.save() # Setting the reset date for carryforward leaves - def set_reset_date(self,assigned_date,available_leave): - if available_leave.leave_type_id.reset_based == 'monthly': - reset_day = available_leave.leave_type_id.reset_day - if reset_day == 'last day' : - target_reset_date = assigned_date + relativedelta(months=0,day=31) - if assigned_date < target_reset_date: - reset_date = target_reset_date - else: - reset_date = assigned_date + relativedelta(months=1,day=31) - - else: - target_reset_date = assigned_date + relativedelta(months=0,day=int(reset_day)) - if assigned_date < target_reset_date: - reset_date = target_reset_date - else: - reset_date = assigned_date + relativedelta(months=1,day=int(reset_day)) - elif available_leave.leave_type_id.reset_based == 'weekly': - target_reset_date = 7 - (assigned_date.isoweekday() - int(available_leave.leave_type_id.reset_weekend)) - if target_reset_date != 7 : - reset_date = assigned_date + relativedelta(days=(target_reset_date % 7)) + def set_reset_date(self, assigned_date, available_leave): + if available_leave.leave_type_id.reset_based == "monthly": + reset_day = available_leave.leave_type_id.reset_day + if reset_day == "last day": + temp_date = assigned_date + relativedelta(months=0, day=31) + if assigned_date < temp_date: + reset_date = temp_date + else: + reset_date = assigned_date + relativedelta(months=1, day=31) + + else: + temp_date = assigned_date + relativedelta(months=0, day=int(reset_day)) + if assigned_date < temp_date: + reset_date = temp_date + else: + reset_date = assigned_date + relativedelta( + months=1, day=int(reset_day) + ) + + elif available_leave.leave_type_id.reset_based == "weekly": + temp = 7 - ( + assigned_date.isoweekday() + - int(available_leave.leave_type_id.reset_weekend) + - 1 + ) + if temp != 7: + reset_date = assigned_date + relativedelta(days=(temp % 7)) else: reset_date = assigned_date + relativedelta(days=7) else: reset_month = int(available_leave.leave_type_id.reset_month) - reset_day = available_leave.leave_type_id.reset_day + reset_day = available_leave.leave_type_id.reset_day - if reset_day == 'last day' : - target_reset_date = assigned_date + relativedelta(years=0,month = reset_month,day=31) - if assigned_date < target_reset_date: - reset_date = target_reset_date - else: - reset_date = assigned_date + relativedelta(years=1,month = reset_month,day=31) - else: - target_reset_date = assigned_date + relativedelta(years=0,month = reset_month,day=int(reset_day)) - if assigned_date < target_reset_date: - reset_date = target_reset_date + if reset_day == "last day": + temp_date = assigned_date + relativedelta( + years=0, month=reset_month, day=31 + ) + if assigned_date < temp_date: + reset_date = temp_date else: - # nth_day = int(reset_day) - reset_date = assigned_date + relativedelta(years=1,month=reset_month,day=int(reset_day)) + reset_date = assigned_date + relativedelta( + years=1, month=reset_month, day=31 + ) + else: + temp_date = assigned_date + relativedelta( + years=0, month=reset_month, day=int(reset_day) + ) + if assigned_date < temp_date: + reset_date = temp_date + else: + # nth_day = int(reset_day) + reset_date = assigned_date + relativedelta( + years=1, month=reset_month, day=int(reset_day) + ) + return reset_date # Setting the expiration date for carryforward leaves @@ -324,6 +337,7 @@ class LeaveRequest(models.Model): approved_available_days = models.FloatField(default=0) approved_carryforward_days = models.FloatField(default=0) created_at = models.DateTimeField(auto_now="True") + objects = models.Manager() def __str__(self): return f"{self.employee_id} | {self.leave_type_id} | {self.status}" @@ -373,23 +387,31 @@ class LeaveRequest(models.Model): if based_on_week != None: # Set Sunday as the first day of the week calendar.setfirstweekday(6) - month_calendar = calendar.monthcalendar(year, 7) - weeks = month_calendar[based_on_week] - day = weeks[based_on_week_day] - company_leave_dates.append(date(year=year, month=7, day=day)) + month_calendar = calendar.monthcalendar(year, month) + weeks = month_calendar[int(based_on_week)] + weekdays_in_weeks = [day for day in weeks if day != 0] + for day in weekdays_in_weeks: + date = datetime.strptime( + f"{year}-{month:02}-{day:02}", "%Y-%m-%d" + ).date() + if ( + date.weekday() == int(based_on_week_day) + and date not in company_leave_dates + ): + company_leave_dates.append(date) else: # Set Monday as the first day of the week calendar.setfirstweekday(0) month_calendar = calendar.monthcalendar(year, month) for week in month_calendar: - if week[int(based_on_week_day) - 1] != 0: + if week[int(based_on_week_day)] != 0: date = datetime.strptime( - f"{year}-{month:02}-{week[int(based_on_week_day) - 1]:02}", + f"{year}-{month:02}-{week[int(based_on_week_day)]:02}", "%Y-%m-%d", ).date() if date not in company_leave_dates: company_leave_dates.append(date) - return list(set(company_leave_dates)) + return company_leave_dates def save(self, *args, **kwargs): self.requested_days = calculate_requested_days( diff --git a/leave/resources.py b/leave/resources.py index 12047340f..7a47d52df 100644 --- a/leave/resources.py +++ b/leave/resources.py @@ -1,7 +1,12 @@ +""" +Module for Import-Export Resources + +This module defines resources for exporting and importing data using the django-import-export library. +""" from import_export import resources from .models import Holiday class HolidayResource(resources.ModelResource): class Meta: - model = Holiday \ No newline at end of file + model = Holiday diff --git a/leave/scheduler.py b/leave/scheduler.py index 9ac2c1b37..630bc6bf6 100644 --- a/leave/scheduler.py +++ b/leave/scheduler.py @@ -1,9 +1,3 @@ -""" -scheduler.py - -Used to register the scheduled tasks. -""" - from apscheduler.schedulers.background import BackgroundScheduler from datetime import datetime, timedelta from dateutil.relativedelta import relativedelta @@ -25,7 +19,6 @@ def leave_reset(): for available_leave in available_leaves: reset_date = available_leave.reset_date expired_date = available_leave.expired_date - if reset_date == today_date: available_leave.update_carryforward(available_leave=available_leave) # new_reset_date = available_leave.set_reset_date(assigned_date=today_date,available_leave = available_leave) diff --git a/leave/templates/leave/leave_request/leave-requests.html b/leave/templates/leave/leave_request/leave-requests.html index f4b14e0e0..8826e4720 100644 --- a/leave/templates/leave/leave_request/leave-requests.html +++ b/leave/templates/leave/leave_request/leave-requests.html @@ -80,12 +80,12 @@
-
diff --git a/leave/views.py b/leave/views.py index d36f7b3ed..c3052bf6c 100644 --- a/leave/views.py +++ b/leave/views.py @@ -1,69 +1,30 @@ -# Standard library imports import contextlib -from datetime import datetime, timedelta, date - -# Third-party imports +from django.shortcuts import render, redirect +from horilla.decorators import login_required, hx_request_required +from .forms import * +from .models import * from django.http import JsonResponse, HttpResponse +from employee.models import Employee +from .filters import * from django.contrib import messages from django.db.models import Q -from django.core.paginator import Paginator -from django.db.models.functions import TruncYear -from django.utils.translation import gettext_lazy as _ -from notifications.signals import notify -from django.shortcuts import render, redirect - -# Django imports (grouped together) -from django.utils.translation import gettext_lazy as _ - -# Local imports (grouped together) -from horilla.decorators import ( - login_required, - hx_request_required, - permission_required, - manager_can_enter, -) -from base.models import Department -from base.methods import filtersubordinates, choosesubordinates -from employee.models import Employee - -from .forms import ( - LeaveTypeForm, - UpdateLeaveTypeForm, - LeaveRequestCreationForm, - LeaveRequestUpdationForm, - LeaveOneAssignForm, - AvailableLeaveForm, - AvailableLeaveUpdateForm, - HolidayForm, - CompanyLeaveForm, - UserLeaveRequestForm, -) - -from .models import ( - LeaveType, - AvailableLeave, - LeaveRequest, - Holiday, - CompanyLeave, - WEEKS, - WEEK_DAYS, -) - -from .filters import ( - LeaveTypeFilter, - AssignedLeavefilter, - LeaveRequestFilter, - HolidayFilter, - userLeaveRequestFilter, - CompanyLeavefilter, -) - +from datetime import datetime, timedelta, date +from django.utils import timezone +from base.models import * from .methods import ( calculate_requested_days, leave_requested_dates, holiday_dates_list, company_leave_dates_list, ) +import random +from django.core.paginator import Paginator +from django.db.models.functions import TruncYear +from horilla.decorators import permission_required +from horilla.decorators import manager_can_enter +from base.methods import filtersubordinates, choosesubordinates +from django.utils.translation import gettext_lazy as _ +from notifications.signals import notify @login_required @@ -247,7 +208,7 @@ def leave_request_creation(request): recipient=leave_request.employee_id.employee_work_info.reporting_manager_id.employee_user_id, verb=f"New leave request created for {leave_request.employee_id}.", verb_ar=f"تم إنشاء طلب إجازة جديد لـ {leave_request.employee_id}.", - verb_de=f"Neuer Urlaubsantrag für {leave_request.employee_id} erstellt.", + verb_de=f"Neuer Urlaubsantrag erstellt für {leave_request.employee_id}.", verb_es=f"Nueva solicitud de permiso creada para {leave_request.employee_id}.", verb_fr=f"Nouvelle demande de congé créée pour {leave_request.employee_id}.", icon="people-circle", @@ -353,7 +314,7 @@ def leave_request_update(request, id): recipient=leave_request.employee_id.employee_work_info.reporting_manager_id.employee_user_id, verb=f"Leave request updated for {leave_request.employee_id}.", verb_ar=f"تم تحديث طلب الإجازة لـ {leave_request.employee_id}.", - verb_de=f"Urlaubsantrag für {leave_request.employee_id} aktualisiert.", + verb_de=f"Urlaubsantrag aktualisiert für {leave_request.employee_id}.", verb_es=f"Solicitud de permiso actualizada para {leave_request.employee_id}.", verb_fr=f"Demande de congé mise à jour pour {leave_request.employee_id}.", icon="people-circle", @@ -418,10 +379,8 @@ def leave_request_approve(request, id): ) leave_request.approved_carryforward_days = leave else: - available_days = available_leave.available_days - available_leave.available_days = ( - available_days - leave_request.requested_days - ) + temp = available_leave.available_days + 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() @@ -432,10 +391,10 @@ def leave_request_approve(request, id): request.user.employee_get, recipient=leave_request.employee_id.employee_user_id, verb="Your Leave request has been approved", - verb_ar="تمت الموافقة على طلب الإجازة الخاص بك.", - verb_de="Ihr Urlaubsantrag wurde genehmigt.", - verb_es="Se ha aprobado su solicitud de permiso.", - verb_fr="Votre demande de congé a été approuvée.", + verb_ar="تمت الموافقة على طلب الإجازة الخاص بك", + verb_de="Ihr Urlaubsantrag wurde genehmigt", + verb_es="Se ha aprobado su solicitud de permiso", + verb_fr="Votre demande de congé a été approuvée", icon="people-circle", redirect="/leave/user-request-view", ) @@ -480,10 +439,10 @@ def leave_request_cancel(request, id): request.user.employee_get, recipient=leave_request.employee_id.employee_user_id, verb="Your Leave request has been cancelled", - verb_ar="تم إلغاء طلب الإجازة الخاص بك.", - verb_de="Ihr Urlaubsantrag wurde storniert.", - verb_es="Se ha cancelado su solicitud de permiso.", - verb_fr="Votre demande de congé a été annulée.", + verb_ar="تم إلغاء طلب الإجازة الخاص بك", + verb_de="Ihr Urlaubsantrag wurde storniert", + verb_es="Se ha cancelado su solicitud de permiso", + verb_fr="Votre demande de congé a été annulée", icon="people-circle", redirect="/leave/user-request-view", ) @@ -544,10 +503,10 @@ def leave_assign_one(request, id): request.user.employee_get, recipient=employee.employee_user_id, verb="New leave type is assigned to you", - verb_ar="تم تعيين نوع إجازة جديد لك.", - verb_de="Ihnen wurde ein neuer Urlaubstyp zugewiesen.", - verb_es="Se le ha asignado un nuevo tipo de permiso.", - verb_fr="Un nouveau type de congé vous a été attribué.", + verb_ar="تم تعيين نوع إجازة جديد لك", + verb_de="Ihnen wurde ein neuer Urlaubstyp zugewiesen", + verb_es="Se le ha asignado un nuevo tipo de permiso", + verb_fr="Un nouveau type de congé vous a été attribué", icon="people-circle", redirect="/leave/user-leave", ) @@ -581,7 +540,7 @@ def leave_assign_view(request): previous_data = request.environ["QUERY_STRING"] page_number = request.GET.get("page") page_obj = paginator_qry(queryset, page_number) - assigned_leave_filter = AssignedLeavefilter() + assigned_leave_filter = AssignedLeaveFilter() return render( request, "leave/assign-view.html", @@ -608,7 +567,7 @@ def leave_assign_filter(request): """ queryset = AvailableLeave.objects.all() queryset = filtersubordinates(request, queryset, "leave.view_availableleave") - assigned_leave_filter = AssignedLeavefilter(request.GET, queryset).qs + assigned_leave_filter = AssignedLeaveFilter(request.GET, queryset).qs previous_data = request.environ["QUERY_STRING"] page_number = request.GET.get("page") page_obj = paginator_qry(assigned_leave_filter, page_number) @@ -661,10 +620,10 @@ def leave_assign(request): request.user.employee_get, recipient=employee.employee_user_id, verb="New leave type is assigned to you", - verb_ar="تم تعيين نوع إجازة جديد لك.", - verb_de="Ihnen wurde ein neuer Urlaubstyp zugewiesen.", - verb_es="Se te ha asignado un nuevo tipo de permiso.", - verb_fr="Un nouveau type de congé vous a été attribué.", + verb_ar="تم تعيين نوع إجازة جديد لك", + verb_de="Ihnen wurde ein neuer Urlaubstyp zugewiesen", + verb_es="Se le ha asignado un nuevo tipo de permiso", + verb_fr="Un nouveau type de congé vous a été attribué", icon="people-circle", redirect="/leave/user-leave", ) @@ -709,7 +668,7 @@ def available_leave_update(request, id): request.user.employee_get, recipient=available_leave.employee_id.employee_user_id, verb=f"Your {available_leave.leave_type_id} leave type updated.", - verb_ar=f"تم تحديث نوع إجازتك {available_leave.leave_type_id}.", + verb_ar=f"تم تحديث نوع الإجازة {available_leave.leave_type_id} الخاص بك.", verb_de=f"Ihr Urlaubstyp {available_leave.leave_type_id} wurde aktualisiert.", verb_es=f"Se ha actualizado su tipo de permiso {available_leave.leave_type_id}.", verb_fr=f"Votre type de congé {available_leave.leave_type_id} a été mis à jour.", @@ -916,7 +875,7 @@ def company_leave_view(request): previous_data = request.environ["QUERY_STRING"] page_number = request.GET.get("page") page_obj = paginator_qry(queryset, page_number) - company_leave_filter = CompanyLeavefilter() + company_leave_filter = CompanyLeaveFilter() return render( request, "leave/company-leave-view.html", @@ -946,7 +905,7 @@ def company_leave_filter(request): queryset = CompanyLeave.objects.all() previous_data = request.environ["QUERY_STRING"] page_number = request.GET.get("page") - company_leave_filter = CompanyLeavefilter(request.GET, queryset).qs + company_leave_filter = CompanyLeaveFilter(request.GET, queryset).qs page_obj = paginator_qry(company_leave_filter, page_number) return render( request, @@ -1087,12 +1046,10 @@ def user_leave_request(request, id): leave_request = form.save(commit=False) leave_request.leave_type_id = leave_type leave_request.employee_id = employee - leave_request.requested_days = requested_days - leave_request.end_date_breakdown = end_date_breakdown + leave_request.save() if leave_request.leave_type_id.require_approval == "no": employee_id = leave_request.employee_id leave_type_id = leave_request.leave_type_id - leave_request.requested_days = requested_days available_leave = AvailableLeave.objects.get( leave_type_id=leave_type_id, employee_id=employee_id ) @@ -1127,9 +1084,9 @@ def user_leave_request(request, id): request.user.employee_get, recipient=leave_request.employee_id.employee_work_info.reporting_manager_id.employee_user_id, verb="You have a new leave request to validate.", - verb_ar="لديك طلب إجازة جديد يحتاج إلى التحقق منه.", + verb_ar="لديك طلب إجازة جديد يجب التحقق منه.", verb_de="Sie haben eine neue Urlaubsanfrage zur Validierung.", - verb_es="Tiene una nueva solicitud de permiso para validar.", + verb_es="Tiene una nueva solicitud de permiso que debe validar.", verb_fr="Vous avez une nouvelle demande de congé à valider.", icon="people-circle", redirect="/leave/user-request-view", @@ -1284,7 +1241,7 @@ def user_leave_view(request): previous_data = request.environ["QUERY_STRING"] page_number = request.GET.get("page") page_obj = paginator_qry(queryset, page_number) - assigned_leave_filter = AssignedLeavefilter() + assigned_leave_filter = AssignedLeaveFilter() return render( request, "leave/user-leave-view.html", @@ -1316,7 +1273,7 @@ def user_leave_filter(request): queryset = employee.available_leave.all() previous_data = request.environ["QUERY_STRING"] page_number = request.GET.get("page") - assigned_leave_filter = AssignedLeavefilter(request.GET, queryset).qs + assigned_leave_filter = AssignedLeaveFilter(request.GET, queryset).qs page_obj = paginator_qry(assigned_leave_filter, page_number) return render( request, @@ -1345,7 +1302,7 @@ def user_request_view(request): previous_data = request.environ["QUERY_STRING"] page_number = request.GET.get("page") page_obj = paginator_qry(queryset, page_number) - user_request_filter = userLeaveRequestFilter() + user_request_filter = UserLeaveRequestFilter() return render( request, "leave/user-request-view.html", @@ -1377,7 +1334,7 @@ def user_request_filter(request): queryset = user.leaverequest_set.all() previous_data = request.environ["QUERY_STRING"] page_number = request.GET.get("page") - user_request_filter = userLeaveRequestFilter(request.GET, queryset).qs + user_request_filter = UserLeaveRequestFilter(request.GET, queryset).qs page_obj = paginator_qry(user_request_filter, page_number) return render( request,