Files
ihrm/leave/models.py

793 lines
29 KiB
Python
Raw Normal View History

2023-05-10 15:06:57 +05:30
import calendar
2023-11-03 10:27:03 +05:30
from collections.abc import Iterable
2023-08-01 16:48:48 +05:30
from datetime import datetime, timedelta
import math
import operator
import sys
2023-08-14 14:47:15 +05:30
from django.db import models
from django.utils import timezone
2023-09-25 15:52:50 +05:30
from django.core.exceptions import ValidationError
2023-08-01 16:48:48 +05:30
from dateutil.relativedelta import relativedelta
2023-05-10 15:06:57 +05:30
from django.utils.translation import gettext_lazy as _
from base import thread_local_middleware
from base.models import Company, MultipleApprovalCondition
2023-12-01 15:36:51 +05:30
from base.horilla_company_manager import HorillaCompanyManager
2023-08-01 16:48:48 +05:30
from employee.models import Employee
from horilla_audit.models import HorillaAuditInfo, HorillaAuditLog
2023-08-14 14:47:15 +05:30
from .methods import calculate_requested_days
from django.core.files.storage import default_storage
from django.conf import settings
from horilla_audit.methods import get_diff
2023-05-10 15:06:57 +05:30
operator_mapping = {
"equal": operator.eq,
"notequal": operator.ne,
"lt": operator.lt,
"gt": operator.gt,
"le": operator.le,
"ge": operator.ge,
"icontains": operator.contains,
}
2023-05-10 15:06:57 +05:30
# Create your models here.
2023-08-01 16:48:48 +05:30
BREAKDOWN = [
("full_day", _("Full Day")),
("first_half", _("First Half")),
("second_half", _("Second Half")),
]
2023-05-10 15:06:57 +05:30
CHOICES = [("yes", "Yes"), ("no", "No")]
2023-08-01 16:48:48 +05:30
RESET_BASED = [
("yearly", _("Yearly")),
("monthly", _("Monthly")),
("weekly", _("Weekly")),
]
MONTHS = [
("1", _("Jan")),
("2", _("Feb")),
("3", _("Mar")),
("4", _("Apr")),
("5", _("May")),
("6", _("Jun")),
("7", _("Jul")),
("8", _("Aug")),
("9", _("Sep")),
("10", _("Oct")),
("11", _("Nov")),
("12", _("Dec")),
2023-08-01 16:48:48 +05:30
]
DAYS = [
("last day", _("Last Day")),
2023-08-01 16:48:48 +05:30
("1", "1st"),
("2", "2nd"),
("3", "3rd"),
("4", "4th"),
("5", "5th"),
("6", "6th"),
("7", "7th"),
("8", "8th"),
("9", "9th"),
("10", "10th"),
("11", "11th"),
("12", "12th"),
("13", "13th"),
("14", "14th"),
("15", "15th"),
("16", "16th"),
("17", "17th"),
("18", "18th"),
("19", "19th"),
("20", "20th"),
("21", "21th"),
("22", "22th"),
("23", "23th"),
("24", "24th"),
("25", "25th"),
("26", "26th"),
("27", "27th"),
("28", "28th"),
("29", "29th"),
("30", "30th"),
("31", "31th"),
]
2023-05-10 15:06:57 +05:30
TIME_PERIOD = [("day", _("Day")), ("month", _("Month")), ("year", _("Year"))]
PAYMENT = [("paid", _("Paid")), ("unpaid", _("Unpaid"))]
2023-08-01 16:48:48 +05:30
CARRYFORWARD_TYPE = [
("no carryforward", _("No Carry Forward")),
("carryforward", _("Carry Forward")),
("carryforward expire", _("Carry Forward with Expire")),
]
2023-05-10 15:06:57 +05:30
ACCRUAL_PLAN = [("job_position", _("Job Position")), ("job_role", _("Job Role"))]
2023-08-01 16:48:48 +05:30
LEAVE_STATUS = (
("requested", _("Requested")),
("approved", _("Approved")),
("cancelled", _("Cancelled")),
("rejected", _("Rejected")),
2023-08-01 16:48:48 +05:30
)
2023-05-10 15:06:57 +05:30
2023-11-08 16:58:23 +05:30
LEAVE_ALLOCATION_STATUS = (
("requested", _("Requested")),
("approved", _("Approved")),
("rejected", _("Rejected")),
)
2023-05-10 15:06:57 +05:30
2023-08-01 16:48:48 +05:30
WEEKS = [
("0", _("First Week")),
("1", _("Second Week")),
("2", _("Third Week")),
("3", _("Fourth Week")),
2023-08-14 14:47:15 +05:30
("4", _("Fifth Week")),
2023-08-01 16:48:48 +05:30
]
2023-05-10 15:06:57 +05:30
2023-08-01 16:48:48 +05:30
WEEK_DAYS = [
2023-08-14 14:47:15 +05:30
("0", _("Monday")),
("1", _("Tuesday")),
("2", _("Wednesday")),
("3", _("Thursday")),
("4", _("Friday")),
("5", _("Saturday")),
("6", _("Sunday")),
2023-08-01 16:48:48 +05:30
]
2023-05-10 15:06:57 +05:30
class LeaveType(models.Model):
2023-08-01 16:48:48 +05:30
icon = models.ImageField(null=True, blank=True, upload_to="leave/leave_icon")
2023-05-10 15:06:57 +05:30
name = models.CharField(max_length=30, null=False)
color = models.CharField(null=True, max_length=30)
2023-08-01 16:48:48 +05:30
payment = models.CharField(max_length=30, choices=PAYMENT, default="unpaid")
2023-05-10 15:06:57 +05:30
count = models.IntegerField(null=True, default=1)
2023-08-01 16:48:48 +05:30
period_in = models.CharField(max_length=30, choices=TIME_PERIOD, default="day")
2023-05-10 15:06:57 +05:30
total_days = models.IntegerField(null=True, default=1)
reset = models.BooleanField(default=False)
reset_based = models.CharField(
2023-08-01 16:48:48 +05:30
max_length=30,
choices=RESET_BASED,
blank=True,
null=True,
)
2023-05-10 15:06:57 +05:30
reset_month = models.CharField(max_length=30, choices=MONTHS, blank=True)
2023-08-01 16:48:48 +05:30
reset_day = models.CharField(max_length=30, choices=DAYS, null=True, blank=True)
2023-05-10 15:06:57 +05:30
reset_weekend = models.CharField(
2023-08-01 16:48:48 +05:30
max_length=10, null=True, blank=True, choices=WEEK_DAYS
)
2023-05-10 15:06:57 +05:30
carryforward_type = models.CharField(
2023-08-01 16:48:48 +05:30
max_length=30, choices=CARRYFORWARD_TYPE, default="no carryforward"
)
carryforward_max = models.FloatField(null=True, blank=True)
2023-05-10 15:06:57 +05:30
carryforward_expire_in = models.IntegerField(null=True, blank=True)
carryforward_expire_period = models.CharField(
2023-08-01 16:48:48 +05:30
max_length=30, choices=TIME_PERIOD, null=True, blank=True
)
2023-05-10 15:06:57 +05:30
require_approval = models.CharField(
2023-08-01 16:48:48 +05:30
max_length=30, choices=CHOICES, null=True, blank=True
)
2023-09-25 15:52:50 +05:30
require_attachment = models.CharField(
max_length=30,
choices=CHOICES,
null=True,
blank=True,
verbose_name=_("Require Attachment"),
2023-09-25 15:52:50 +05:30
)
2023-08-01 16:48:48 +05:30
exclude_company_leave = models.CharField(max_length=30, choices=CHOICES)
exclude_holiday = models.CharField(max_length=30, choices=CHOICES)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
2023-12-01 15:36:51 +05:30
)
objects = HorillaCompanyManager(related_company_field="company_id")
class Meta:
ordering = ["-id"]
def get_avatar(self):
"""
Method will retun the api to the avatar or path to the profile image
"""
url = f"https://ui-avatars.com/api/?name={self.name}&background=random"
if self.icon:
full_filename = settings.MEDIA_ROOT + self.icon.name
if default_storage.exists(full_filename):
url = self.icon.url
return url
def save(self, *args, **kwargs):
if (
self.carryforward_type != "no carryforward"
and self.carryforward_max is None
):
self.carryforward_max = math.inf
super().save(*args, **kwargs)
2023-05-10 15:06:57 +05:30
def __str__(self):
return self.name
class Holiday(models.Model):
name = models.CharField(max_length=30, null=False, verbose_name=_("Name"))
start_date = models.DateField(verbose_name=_("Start Date"))
end_date = models.DateField(null=True, blank=True, verbose_name=_("End Date"))
recurring = models.BooleanField(default=False, verbose_name=_("Recurring"))
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
2023-12-01 15:36:51 +05:30
)
objects = HorillaCompanyManager(related_company_field="company_id")
2023-05-10 15:06:57 +05:30
def __str__(self):
return self.name
class CompanyLeave(models.Model):
based_on_week = models.CharField(
2023-08-01 16:48:48 +05:30
max_length=100, choices=WEEKS, blank=True, null=True
)
2023-05-10 15:06:57 +05:30
based_on_week_day = models.CharField(max_length=100, choices=WEEK_DAYS)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
2023-12-01 15:36:51 +05:30
)
objects = models.Manager()
objects = HorillaCompanyManager(related_company_field="company_id")
2023-05-10 15:06:57 +05:30
class Meta:
2023-08-01 16:48:48 +05:30
unique_together = ("based_on_week", "based_on_week_day")
2023-05-10 15:06:57 +05:30
def __str__(self):
return f"{dict(WEEK_DAYS).get(self.based_on_week_day)} | {dict(WEEKS).get(self.based_on_week)}"
class AvailableLeave(models.Model):
employee_id = models.ForeignKey(
Employee,
on_delete=models.CASCADE,
related_name="available_leave",
verbose_name=_("Employee"),
)
2023-05-10 15:06:57 +05:30
leave_type_id = models.ForeignKey(
2023-08-01 16:48:48 +05:30
LeaveType,
2023-09-25 15:52:50 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
related_name="employee_available_leave",
blank=True,
null=True,
verbose_name=_("Leave type"),
2023-08-01 16:48:48 +05:30
)
available_days = models.FloatField(default=0, verbose_name=_("Available Days"))
carryforward_days = models.FloatField(
default=0, verbose_name=_("Carryforward Days")
)
total_leave_days = models.FloatField(default=0, verbose_name=_("Total Leave Days"))
assigned_date = models.DateField(
default=timezone.now, verbose_name=_("Assigned Date")
)
reset_date = models.DateField(
blank=True, null=True, verbose_name=_("Leave Reset Date")
)
expired_date = models.DateField(
blank=True, null=True, verbose_name=_("CarryForward Expired Date")
2023-08-01 16:48:48 +05:30
)
2023-12-01 15:36:51 +05:30
objects = HorillaCompanyManager(
related_company_field="employee_id__employee_work_info__company_id"
)
history = HorillaAuditLog(
related_name="history_set",
bases=[
HorillaAuditInfo,
],
)
2023-05-10 15:06:57 +05:30
class Meta:
2023-08-01 16:48:48 +05:30
unique_together = ("leave_type_id", "employee_id")
2023-05-10 15:06:57 +05:30
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)
forecasted_leave[next_month.strftime("%Y-%m")] = self.available_days + (
self.leave_type_id.total_days * i
)
return forecasted_leave
# Resetting carryforward days
2023-08-01 16:48:48 +05:30
def update_carryforward(self):
if self.leave_type_id.carryforward_type != "no carryforward":
if self.leave_type_id.carryforward_max >= self.total_leave_days:
self.carryforward_days = self.total_leave_days
2023-08-01 16:48:48 +05:30
else:
self.carryforward_days = self.leave_type_id.carryforward_max
self.available_days = self.leave_type_id.total_days
2023-08-01 16:48:48 +05:30
# Setting the reset date for carryforward leaves
2023-08-14 14:47:15 +05:30
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))
2023-08-01 16:48:48 +05:30
else:
reset_date = assigned_date + relativedelta(days=7)
else:
reset_month = int(available_leave.leave_type_id.reset_month)
2023-08-14 14:47:15 +05:30
reset_day = available_leave.leave_type_id.reset_day
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:
reset_date = assigned_date + relativedelta(
years=1, month=reset_month, day=31
)
2023-08-01 16:48:48 +05:30
else:
2023-08-14 14:47:15 +05:30
temp_date = assigned_date + relativedelta(
years=0, month=reset_month, day=int(reset_day)
)
if assigned_date < temp_date:
reset_date = temp_date
2023-08-01 16:48:48 +05:30
else:
2023-08-14 14:47:15 +05:30
# nth_day = int(reset_day)
reset_date = assigned_date + relativedelta(
years=1, month=reset_month, day=int(reset_day)
)
2023-08-01 16:48:48 +05:30
return reset_date
# Setting the expiration date for carryforward leaves
def set_expired_date(self, available_leave, assigned_date):
period = available_leave.leave_type_id.carryforward_expire_in
if available_leave.leave_type_id.carryforward_expire_period == "day":
expired_date = assigned_date + relativedelta(days=period)
elif available_leave.leave_type_id.carryforward_expire_period == "month":
expired_date = assigned_date + relativedelta(months=period)
else:
expired_date = assigned_date + relativedelta(years=period)
available_leave.carryforward_days = 0
available_leave.available_days = available_leave.leave_type_id.total_days
return expired_date
2023-05-10 15:06:57 +05:30
def save(self, *args, **kwargs):
2023-08-01 16:48:48 +05:30
# if self.assigned_date == datetime.now().date() or self.assigned_date.date() == datetime.now().date():
if self.reset_date is None:
# Check whether the reset is enabled
if self.leave_type_id.reset:
reset_date = self.set_reset_date(
assigned_date=self.assigned_date, available_leave=self
)
self.reset_date = reset_date
# assigning expire date
if self.leave_type_id.carryforward_type == "carryforward expire":
expired_date = self.set_expired_date(
assigned_date=self.assigned_date, available_leave=self
)
self.expired_date = expired_date
self.total_leave_days = max(self.available_days + self.carryforward_days, 0)
self.carryforward_days = max(self.carryforward_days, 0)
2023-05-10 15:06:57 +05:30
super().save(*args, **kwargs)
2023-05-10 15:06:57 +05:30
class LeaveRequest(models.Model):
employee_id = models.ForeignKey(
Employee, on_delete=models.CASCADE, verbose_name=_("Employee")
)
leave_type_id = models.ForeignKey(
LeaveType, on_delete=models.PROTECT, verbose_name=_("Leave Type")
)
start_date = models.DateField(null=False, verbose_name=_("Start Date"))
2023-05-10 15:06:57 +05:30
start_date_breakdown = models.CharField(
max_length=30,
choices=BREAKDOWN,
default="full_day",
verbose_name=_("Start Date Breakdown"),
2023-08-01 16:48:48 +05:30
)
end_date = models.DateField(null=True, blank=True, verbose_name=_("End Date"))
2023-05-10 15:06:57 +05:30
end_date_breakdown = models.CharField(
max_length=30,
choices=BREAKDOWN,
default="full_day",
verbose_name=_("End Date Breakdown"),
)
requested_days = models.FloatField(
blank=True, null=True, verbose_name=_("Requested Days")
)
description = models.TextField(verbose_name=_("Description"),max_length=255)
attachment = models.FileField(
null=True,
blank=True,
upload_to="leave/leave_attachment",
verbose_name=_("Attachment"),
)
status = models.CharField(
max_length=30,
choices=LEAVE_STATUS,
default="requested",
verbose_name=_("Status"),
)
requested_date = models.DateField(
default=timezone.now, verbose_name=_("Created Date")
2023-08-01 16:48:48 +05:30
)
created_by = models.ForeignKey(
Employee,
on_delete=models.PROTECT,
blank=True,
null=True,
related_name="leave_request_created",
verbose_name=_("Created By"),
2023-08-01 16:48:48 +05:30
)
2023-07-07 11:06:16 +05:30
approved_available_days = models.FloatField(default=0)
approved_carryforward_days = models.FloatField(default=0)
created_at = models.DateTimeField(auto_now_add="True")
reject_reason = models.TextField(blank=True, verbose_name=_("Reject Reason"),max_length=255)
history = HorillaAuditLog(
related_name="history_set",
bases=[
HorillaAuditInfo,
],
)
2023-12-01 15:36:51 +05:30
objects = HorillaCompanyManager(
related_company_field="employee_id__employee_work_info__company_id"
)
def tracking(self):
return get_diff(self)
2023-05-10 15:06:57 +05:30
def __str__(self):
return f"{self.employee_id} | {self.leave_type_id} | {self.status}"
def get_penalties_count(self):
"""
This method is used to return the total penalties in the late early instance
"""
return self.penaltyaccount_set.count()
2023-05-10 15:06:57 +05:30
def requested_dates(self):
"""
:return: this functions returns a list of dates from start date to end date.
"""
request_start_date = self.start_date
request_end_date = self.end_date
if request_end_date is None:
request_end_date = self.start_date
requested_days = request_end_date - request_start_date
requested_dates = []
for i in range(requested_days.days + 1):
date = request_start_date + timedelta(i)
requested_dates.append(date)
return requested_dates
def holiday_dates(self):
"""
:return: this functions returns a list of all holiday dates.
"""
holiday_dates = []
holidays = Holiday.objects.all()
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(self):
"""
:return: This function returns a list of all company leave dates"""
company_leaves = CompanyLeave.objects.all()
company_leave_dates = []
for company_leave in company_leaves:
year = self.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)
2023-08-14 14:47:15 +05:30
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)
2023-05-10 15:06:57 +05:30
else:
# Set Monday as the first day of the week
calendar.setfirstweekday(0)
month_calendar = calendar.monthcalendar(year, month)
for week in month_calendar:
2023-08-14 14:47:15 +05:30
if week[int(based_on_week_day)] != 0:
2023-05-10 15:06:57 +05:30
date = datetime.strptime(
2023-08-14 14:47:15 +05:30
f"{year}-{month:02}-{week[int(based_on_week_day)]:02}",
2023-08-01 16:48:48 +05:30
"%Y-%m-%d",
).date()
2023-05-10 15:06:57 +05:30
if date not in company_leave_dates:
company_leave_dates.append(date)
2023-08-14 14:47:15 +05:30
return company_leave_dates
2023-05-10 15:06:57 +05:30
2023-08-01 16:48:48 +05:30
def save(self, *args, **kwargs):
self.requested_days = calculate_requested_days(
self.start_date,
self.end_date,
self.start_date_breakdown,
self.end_date_breakdown,
)
if (
self.leave_type_id.exclude_company_leave == "yes"
and self.leave_type_id.exclude_holiday == "yes"
):
2023-05-10 15:06:57 +05:30
self.exclude_all_leaves()
else:
self.exclude_leaves()
super().save(*args, **kwargs)
department_id = self.employee_id.employee_work_info.department_id
requested_days = self.requested_days
applicable_condition = False
conditions = MultipleApprovalCondition.objects.filter(
department=department_id
).order_by("condition_value")
if conditions:
for condition in conditions:
operator = condition.condition_operator
if operator == "range":
start_value = float(condition.condition_start_value)
end_value = float(condition.condition_end_value)
if start_value <= requested_days <= end_value:
applicable_condition = condition
break
else:
operator_func = operator_mapping.get(condition.condition_operator)
condition_value = type(requested_days)(condition.condition_value)
if operator_func(requested_days, condition_value):
applicable_condition = condition
break
if applicable_condition and self.status == "requested":
LeaveRequestConditionApproval.objects.filter(leave_request_id=self).delete()
sequence = 0
managers = applicable_condition.approval_managers()
for manager in managers:
sequence += 1
LeaveRequestConditionApproval.objects.create(
sequence=sequence,
leave_request_id=self,
manager_id=manager,
)
2023-05-10 15:06:57 +05:30
def exclude_all_leaves(self):
requested_dates = self.requested_dates()
holiday_dates = self.holiday_dates()
company_leave_dates = self.company_leave_dates()
total_leaves = list(set(holiday_dates + company_leave_dates))
total_leave_count = sum(
requested_date in total_leaves for requested_date in requested_dates
)
self.requested_days = self.requested_days - total_leave_count
2023-08-01 16:48:48 +05:30
2023-05-10 15:06:57 +05:30
def exclude_leaves(self):
holiday_count = 0
2023-08-01 16:48:48 +05:30
if self.leave_type_id.exclude_holiday == "yes":
2023-05-10 15:06:57 +05:30
requested_dates = self.requested_dates()
holiday_dates = self.holiday_dates()
for requested_date in requested_dates:
if requested_date in holiday_dates:
holiday_count += 1
self.requested_days = self.requested_days - holiday_count
2023-08-01 16:48:48 +05:30
if self.leave_type_id.exclude_company_leave == "yes":
2023-05-10 15:06:57 +05:30
requested_dates = self.requested_dates()
company_leave_dates = self.company_leave_dates()
company_leave_count = sum(
requested_date in company_leave_dates
for requested_date in requested_dates
)
self.requested_days = self.requested_days - company_leave_count
def no_approval(self):
employee_id = self.employee_id
leave_type_id = self.leave_type_id
2023-08-01 16:48:48 +05:30
available_leave = AvailableLeave.objects.get(
leave_type_id=leave_type_id, employee_id=employee_id
)
2023-05-10 15:06:57 +05:30
if self.requested_days > available_leave.available_days:
leave = self.requested_days - available_leave.available_days
self.approved_available_days = available_leave.available_days
available_leave.available_days = 0
2023-08-01 16:48:48 +05:30
available_leave.carryforward_days = (
available_leave.carryforward_days - leave
)
self.approved_carryforward_days = leave
2023-05-10 15:06:57 +05:30
else:
2023-08-01 16:48:48 +05:30
available_leave.available_days = (
available_leave.available_days - self.requested_days
)
2023-05-10 15:06:57 +05:30
self.approved_available_days = self.requested_days
self.status = "approved"
available_leave.save()
2023-11-02 12:25:48 +05:30
def multiple_approvals(self, *args, **kwargs):
approvals = LeaveRequestConditionApproval.objects.filter(leave_request_id=self)
requested_query = approvals.filter(is_approved=False).order_by("sequence")
approved_query = approvals.filter(is_approved=True).order_by("sequence")
managers = []
for manager in approvals:
managers.append(manager.manager_id)
if approvals.exists():
result = {
"managers": managers,
"approved": approved_query,
"requested": requested_query,
"approvals": approvals,
}
else:
result = False
return result
def is_approved(self):
request = getattr(thread_local_middleware._thread_locals, "request", None)
if request:
employee = Employee.objects.filter(employee_user_id=request.user).first()
condition_approval = LeaveRequestConditionApproval.objects.filter(
leave_request_id=self, manager_id=employee.id
).first()
if condition_approval:
return not condition_approval.is_approved
else:
return True
class LeaverequestFile(models.Model):
file = models.FileField(upload_to="leave/request_files")
class LeaverequestComment(models.Model):
"""
LeaverequestComment Model
"""
request_id = models.ForeignKey(LeaveRequest, on_delete=models.CASCADE)
employee_id = models.ForeignKey(Employee, on_delete=models.CASCADE)
files = models.ManyToManyField(LeaverequestFile, blank=True)
comment = models.TextField(null=True, verbose_name=_("Comment"),max_length=255)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name=_("Created At"),
null=True,
)
def __str__(self) -> str:
return f"{self.comment}"
2023-11-02 12:25:48 +05:30
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(max_length=255)
2023-11-02 12:25:48 +05:30
attachment = models.FileField(
null=True, blank=True, upload_to="leave/leave_attachment"
)
status = models.CharField(
max_length=30, choices=LEAVE_ALLOCATION_STATUS, default="requested"
)
2023-11-02 12:25:48 +05:30
created_at = models.DateTimeField(auto_now="True")
reject_reason = models.TextField(blank=True,max_length=255)
history = HorillaAuditLog(
related_name="history_set",
bases=[
HorillaAuditInfo,
],
)
2023-12-01 15:36:51 +05:30
objects = HorillaCompanyManager(
related_company_field="employee_id__employee_work_info__company_id"
)
2023-11-03 10:27:03 +05:30
def __str__(self):
return f"{self.employee_id}| {self.leave_type_id}| {self.id}"
2023-11-03 10:27:03 +05:30
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.skip_history = False
def tracking(self):
return get_diff(self)
def allocate_tracking(self):
"""
This method is used to return the tracked history of the instance
"""
try:
histories = get_diff(self)[:2]
for history in histories:
if history["type"] == "Changes":
for update in history["changes"]:
if update["field_name"] == "requested_days":
return update
except:
return None
class LeaveallocationrequestComment(models.Model):
"""
LeaveallocationrequestComment Model
"""
request_id = models.ForeignKey(LeaveAllocationRequest, on_delete=models.CASCADE)
employee_id = models.ForeignKey(Employee, on_delete=models.CASCADE)
files = models.ManyToManyField(LeaverequestFile, blank=True)
comment = models.TextField(null=True, verbose_name=_("Comment"),max_length=255)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name=_("Created At"),
null=True,
)
def __str__(self) -> str:
return f"{self.comment}"
class LeaveRequestConditionApproval(models.Model):
sequence = models.IntegerField()
is_approved = models.BooleanField(default=False)
is_rejected = models.BooleanField(default=False)
leave_request_id = models.ForeignKey(LeaveRequest, on_delete=models.CASCADE)
manager_id = models.ForeignKey(Employee, on_delete=models.CASCADE)