diff --git a/leave/forms.py b/leave/forms.py index 01e1cd83f..5b66d7750 100644 --- a/leave/forms.py +++ b/leave/forms.py @@ -320,14 +320,19 @@ class LeaveRequestCreationForm(ModelForm): unique_dates = list(set(month_year)) if f"{today.month}-{today.year}" in unique_dates: unique_dates.remove(f"{today.strftime('%m')}-{today.year}") - forcasted_leaves = available_leave.forcasted_leaves() - if leave_type_id.reset_based == "monthly": - if f"{today.year}-{today.strftime('%m')}" not in unique_dates: - for item in unique_dates: - try: - total_leave_days += forcasted_leaves[item] - except: - pass + + forcated_days = available_leave.forcasted_leaves(start_date) + total_leave_days = ( + available_leave.leave_type_id.carryforward_max + if available_leave.leave_type_id.carryforward_type + in ["carryforward", "carryforward expire"] + and available_leave.leave_type_id.carryforward_max < total_leave_days + else total_leave_days + ) + if available_leave.leave_type_id.carryforward_type == "no carryforward": + total_leave_days = 0 + total_leave_days += forcated_days + if not effective_requested_days <= total_leave_days: raise forms.ValidationError(_("Employee doesn't have enough leave days..")) @@ -338,19 +343,27 @@ class LeaveRequestCreationForm(ModelForm): super().__init__(*args, **kwargs) self.fields["leave_type_id"].widget.attrs.update( { - "onchange": "empleavetypeChange($(this))", + "hx-include": "#id_employee_id, #id_start_date", + "hx-target": "#availableLeaveCount", + "hx-swap": "outerHTML", + "hx-trigger": "change", + "hx-get": "/leave/employee-available-leave-count", } ) self.fields["employee_id"].widget.attrs.update( { "hx-target": "#id_leave_type_id_parent_div", "hx-trigger": "change", - "hx-get": "/leave/get-employee-leave-types", + "hx-get": "/leave/get-employee-leave-types?form=LeaveRequestCreationForm", } ) self.fields["start_date"].widget.attrs.update( { - "onchange": "dateChange($(this))", + "hx-include": "#id_employee_id, #id_leave_type_id", + "hx-target": "#availableLeaveCount", + "hx-swap": "outerHTML", + "hx-trigger": "change", + "hx-get": "/leave/employee-available-leave-count", } ) @@ -431,14 +444,19 @@ class LeaveRequestUpdationForm(ModelForm): unique_dates = list(set(month_year)) if f"{today.month}-{today.year}" in unique_dates: unique_dates.remove(f"{today.strftime('%m')}-{today.year}") - forcasted_leaves = available_leave.forcasted_leaves() - if leave_type_id.reset_based == "monthly": - if f"{today.year}-{today.strftime('%m')}" not in unique_dates: - for item in unique_dates: - try: - total_leave_days += forcasted_leaves[item] - except: - pass + + forcated_days = available_leave.forcasted_leaves(start_date) + total_leave_days = ( + available_leave.leave_type_id.carryforward_max + if available_leave.leave_type_id.carryforward_type + in ["carryforward", "carryforward expire"] + and available_leave.leave_type_id.carryforward_max < total_leave_days + else total_leave_days + ) + if available_leave.leave_type_id.carryforward_type == "no carryforward": + total_leave_days = 0 + total_leave_days += forcated_days + if not effective_requested_days <= total_leave_days: raise forms.ValidationError(_("Employee doesn't have enough leave days..")) @@ -449,19 +467,30 @@ class LeaveRequestUpdationForm(ModelForm): super().__init__(*args, **kwargs) self.fields["leave_type_id"].widget.attrs.update( { - "onchange": "empleavetypeChange($(this))", + "id": "id_request_update_leave_type_id", + "hx-include": "#id_request_update_employee_id, #id_request_udpate_start_date", + "hx-target": "#assinedLeaveAvailableCount", + "hx-swap": "outerHTML", + "hx-trigger": "change", + "hx-get": "/leave/employee-available-leave-count", } ) self.fields["employee_id"].widget.attrs.update( { + "id": "id_request_update_employee_id", "hx-target": "#id_leave_type_id_parent_div", "hx-trigger": "change", - "hx-get": "/leave/get-employee-leave-types", + "hx-get": "/leave/get-employee-leave-types?form=LeaveRequestUpdationForm", } ) self.fields["start_date"].widget.attrs.update( { - "onchange": "dateChange($(this))", + "id": "id_request_udpate_start_date", + "hx-include": "#id_request_update_employee_id, #id_request_update_leave_type_id", + "hx-target": "#assinedLeaveAvailableCount", + "hx-swap": "outerHTML", + "hx-trigger": "change", + "hx-get": "/leave/employee-available-leave-count", } ) diff --git a/leave/models.py b/leave/models.py index e59b94f39..e9545d369 100644 --- a/leave/models.py +++ b/leave/models.py @@ -223,6 +223,51 @@ class LeaveType(HorillaModel): url = self.icon.url return url + def leave_type_next_reset_date(self): + today = datetime.now().date() + + if not self.reset: + return None + + def get_reset_day(month, day): + return ( + calendar.monthrange(today.year, month)[1] + if day == "last day" + else int(day) + ) + + if self.reset_based == "yearly": + month, day = int(self.reset_month), get_reset_day( + int(self.reset_month), self.reset_day + ) + reset_date = datetime( + today.year + (datetime(today.year, month, day).date() < today), + month, + day, + ).date() + + elif self.reset_based == "monthly": + month = today.month + reset_date = datetime( + today.year, month, get_reset_day(month, self.reset_day) + ).date() + if reset_date < today: + month = (month % 12) + 1 + year = today.year + (month == 1) + reset_date = datetime( + year, month, get_reset_day(month, self.reset_day) + ).date() + + elif self.reset_based == "weekly": + target_weekday = WEEK_DAYS[self.reset_day] + days_until_reset = (target_weekday - today.weekday()) % 7 or 7 + reset_date = today + timedelta(days=days_until_reset) + + else: + reset_date = None + + return reset_date + def clean(self, *args, **kwargs): if self.is_compensatory_leave: if LeaveType.objects.filter(is_compensatory_leave=True).count() >= 1: @@ -321,25 +366,14 @@ class AvailableLeave(HorillaModel): def __str__(self): return f"{self.employee_id} | {self.leave_type_id}" - def forcasted_leaves(self): - forecasted_leave = {} - if self.leave_type_id.reset_based == "monthly": - today = datetime.now() - for i in range(1, 7): # Calculate for the next 6 months - next_month = today + relativedelta(months=i) - if self.leave_type_id.carryforward_max: - forecasted_leave[next_month.strftime("%Y-%m")] = ( - self.available_days - + min( - self.leave_type_id.carryforward_max, - (self.leave_type_id.total_days * i), - ) - ) - else: - forecasted_leave[next_month.strftime("%Y-%m")] = ( - self.available_days + (self.leave_type_id.total_days * i) - ) - return forecasted_leave + def forcasted_leaves(self, date): + if isinstance(date, str): + date = datetime.strptime(date, "%Y-%m-%d").date() + next_reset_date = self.leave_type_id.leave_type_next_reset_date() + if next_reset_date <= date: + return self.leave_type_id.total_days + + return 0 # Resetting carryforward days diff --git a/leave/templates/leave/leave_request/employee_available_leave_count.html b/leave/templates/leave/leave_request/employee_available_leave_count.html new file mode 100644 index 000000000..c117c6739 --- /dev/null +++ b/leave/templates/leave/leave_request/employee_available_leave_count.html @@ -0,0 +1,53 @@ +{% load i18n %} +{% load static %} + +
\ No newline at end of file diff --git a/leave/templates/leave/leave_request/leave_request_form.html b/leave/templates/leave/leave_request/leave_request_form.html index b161672b6..c503cd518 100644 --- a/leave/templates/leave/leave_request/leave_request_form.html +++ b/leave/templates/leave/leave_request/leave_request_form.html @@ -28,6 +28,7 @@ >