Files
ihrm/base/models.py

766 lines
22 KiB
Python
Raw Normal View History

2023-08-01 16:48:48 +05:30
"""
models.py
This module is used to register django models
"""
2023-05-10 15:06:57 +05:30
import django
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
2023-08-01 16:48:48 +05:30
from django.db import models
from simple_history.models import HistoricalRecords
2023-08-07 13:02:24 +05:30
from django.template import defaultfilters
2023-05-10 15:06:57 +05:30
# Create your models here.
2023-08-01 16:48:48 +05:30
2023-05-10 15:06:57 +05:30
def validate_time_format(value):
2023-08-01 16:48:48 +05:30
"""
2023-05-10 15:06:57 +05:30
this method is used to validate the format of duration like fields.
2023-08-01 16:48:48 +05:30
"""
2023-05-10 15:06:57 +05:30
if len(value) > 6:
raise ValidationError(_("Invalid format, it should be HH:MM format"))
try:
hour, minute = value.split(":")
hour = int(hour)
minute = int(minute)
if len(str(hour)) > 3 or minute not in range(60):
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Invalid time, excepted HH:MM"))
2023-05-10 15:06:57 +05:30
except ValueError as e:
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Invalid format, excepted HH:MM")) from e
2023-05-10 15:06:57 +05:30
class Company(models.Model):
2023-08-01 16:48:48 +05:30
"""
Company model
"""
2023-05-10 15:06:57 +05:30
company = models.CharField(max_length=50)
hq = models.BooleanField(default=False)
address = models.TextField()
country = models.CharField(max_length=50)
state = models.CharField(max_length=50)
city = models.CharField(max_length=50)
zip = models.CharField(max_length=20)
2023-08-01 16:48:48 +05:30
icon = models.FileField(
upload_to="base/icon",
null=True,
)
objects = models.Manager()
2023-05-10 15:06:57 +05:30
class Meta:
2023-08-01 16:48:48 +05:30
"""
Meta class to add additional options
"""
2023-11-17 14:30:30 +05:30
verbose_name = _("Company")
verbose_name_plural = _("Companies")
2023-08-01 16:48:48 +05:30
unique_together = ["company", "address"]
app_label = "base"
2023-05-10 15:06:57 +05:30
def __str__(self) -> str:
2023-08-01 16:48:48 +05:30
return str(self.company)
2023-05-10 15:06:57 +05:30
class Department(models.Model):
2023-08-01 16:48:48 +05:30
"""
Department model
"""
department = models.CharField(max_length=50, blank=False, unique=True)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
2023-08-01 16:48:48 +05:30
objects = models.Manager()
2023-05-10 15:06:57 +05:30
2023-11-17 14:30:30 +05:30
class Meta:
verbose_name = _("Department")
verbose_name_plural = _("Departments")
2023-05-10 15:06:57 +05:30
def __str__(self):
2023-08-01 16:48:48 +05:30
return str(self.department)
2023-05-10 15:06:57 +05:30
class JobPosition(models.Model):
2023-08-01 16:48:48 +05:30
"""
JobPosition model
"""
2023-05-10 15:06:57 +05:30
job_position = models.CharField(max_length=50, blank=False, null=False, unique=True)
department_id = models.ForeignKey(
2023-08-01 16:48:48 +05:30
Department,
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
blank=True,
related_name="job_position",
2023-08-07 13:02:24 +05:30
verbose_name=_("Department"),
2023-08-01 16:48:48 +05:30
)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
2023-08-01 16:48:48 +05:30
objects = models.Manager()
2023-11-17 14:30:30 +05:30
class Meta:
"""
Meta class to add additional options
"""
verbose_name = _("Job Position")
verbose_name_plural = _("Job Positions")
2023-05-10 15:06:57 +05:30
def __str__(self):
2023-08-01 16:48:48 +05:30
return str(self.job_position)
2023-05-10 15:06:57 +05:30
class JobRole(models.Model):
2023-08-01 16:48:48 +05:30
"""JobRole model"""
job_position_id = models.ForeignKey(
2023-09-20 14:54:33 +05:30
JobPosition, on_delete=models.PROTECT, verbose_name=_("Job Position")
2023-08-01 16:48:48 +05:30
)
job_role = models.CharField(max_length=50, blank=False, null=True)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
2023-08-01 16:48:48 +05:30
objects = models.Manager()
2023-05-10 15:06:57 +05:30
class Meta:
2023-08-01 16:48:48 +05:30
"""
Meta class to add additional options
"""
2023-11-17 14:30:30 +05:30
verbose_name = _("Job Role")
verbose_name_plural = _("Job Roles")
2023-08-01 16:48:48 +05:30
unique_together = ("job_position_id", "job_role")
2023-05-10 15:06:57 +05:30
def __str__(self):
2023-08-01 16:48:48 +05:30
return f"{self.job_role} - {self.job_position_id.job_position}"
2023-05-10 15:06:57 +05:30
class WorkType(models.Model):
2023-08-01 16:48:48 +05:30
"""
WorkType model
"""
2023-05-10 15:06:57 +05:30
work_type = models.CharField(max_length=50)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
2023-08-01 16:48:48 +05:30
objects = models.Manager()
2023-11-17 14:30:30 +05:30
class Meta:
"""
Meta class to add additional options
"""
verbose_name = _("Work Type")
verbose_name_plural = _("Work Types")
2023-05-10 15:06:57 +05:30
def __str__(self) -> str:
2023-08-01 16:48:48 +05:30
return str(self.work_type)
2023-05-10 15:06:57 +05:30
class RotatingWorkType(models.Model):
2023-08-01 16:48:48 +05:30
"""
RotatingWorkType model
"""
2023-05-10 15:06:57 +05:30
name = models.CharField(max_length=50)
2023-08-01 16:48:48 +05:30
work_type1 = models.ForeignKey(
WorkType,
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
related_name="work_type1",
verbose_name=_("Work Type 1"),
)
work_type2 = models.ForeignKey(
WorkType,
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
related_name="work_type2",
verbose_name=_("Work Type 2"),
)
employee_id = models.ManyToManyField(
2023-08-07 13:02:24 +05:30
"employee.Employee",
through="RotatingWorkTypeAssign",
verbose_name=_("Employee"),
2023-08-01 16:48:48 +05:30
)
objects = models.Manager()
2023-05-10 15:06:57 +05:30
2023-11-17 14:30:30 +05:30
class Meta:
"""
Meta class to add additional options
"""
verbose_name = _("Rotating Work Type")
verbose_name_plural = _("Rotating Work Types")
2023-05-10 15:06:57 +05:30
def __str__(self) -> str:
2023-08-01 16:48:48 +05:30
return str(self.name)
2023-05-10 15:06:57 +05:30
def clean(self):
if self.work_type1 == self.work_type2:
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Choose different work type"))
2023-05-10 15:06:57 +05:30
DAY_DATE = [(str(i), str(i)) for i in range(1, 32)]
2023-08-01 16:48:48 +05:30
DAY_DATE.append(("last", _("Last Day")))
DAY = [
("monday", _("Monday")),
("tuesday", _("Tuesday")),
("wednesday", _("Wednesday")),
("thursday", _("Thursday")),
("friday", _("Friday")),
("saturday", _("Saturday")),
("sunday", _("Sunday")),
2023-05-10 15:06:57 +05:30
]
BASED_ON = [
2023-08-01 16:48:48 +05:30
("after", _("After")),
("weekly", _("Weekend")),
("monthly", _("Monthly")),
2023-05-10 15:06:57 +05:30
]
2023-08-01 16:48:48 +05:30
2023-05-10 15:06:57 +05:30
class RotatingWorkTypeAssign(models.Model):
2023-08-01 16:48:48 +05:30
"""
RotatingWorkTypeAssign model
"""
employee_id = models.ForeignKey(
"employee.Employee",
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
null=True,
2023-08-07 13:02:24 +05:30
verbose_name=_("Employee"),
2023-08-01 16:48:48 +05:30
)
rotating_work_type_id = models.ForeignKey(
RotatingWorkType, on_delete=models.PROTECT, verbose_name=_("Rotating Work Type")
2023-08-07 13:02:24 +05:30
)
start_date = models.DateField(
default=django.utils.timezone.now, verbose_name=_("Start Date")
2023-08-01 16:48:48 +05:30
)
next_change_date = models.DateField(null=True, verbose_name=_("Next Switch"))
2023-08-01 16:48:48 +05:30
current_work_type = models.ForeignKey(
WorkType,
null=True,
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
related_name="current_work_type",
verbose_name=_("Current Work Type"),
2023-08-01 16:48:48 +05:30
)
next_work_type = models.ForeignKey(
WorkType,
null=True,
on_delete=models.PROTECT,
related_name="next_work_type",
verbose_name=_("Next Work Type"),
2023-08-01 16:48:48 +05:30
)
based_on = models.CharField(
max_length=10,
choices=BASED_ON,
null=False,
blank=False,
verbose_name=_("Based On"),
)
rotate_after_day = models.IntegerField(
default=7, verbose_name=_("Rotate After Day")
)
rotate_every_weekend = models.CharField(
max_length=10,
default="monday",
choices=DAY,
blank=True,
null=True,
verbose_name=_("Rotate Every Weekend"),
)
rotate_every = models.CharField(
max_length=10,
default="1",
choices=DAY_DATE,
verbose_name=_("Rotate Every Month"),
)
2023-05-10 15:06:57 +05:30
is_active = models.BooleanField(default=True)
2023-08-01 16:48:48 +05:30
objects = models.Manager()
2023-05-10 15:06:57 +05:30
class Meta:
2023-08-01 16:48:48 +05:30
"""
Meta class to add additional options
"""
2023-11-17 14:30:30 +05:30
verbose_name = _("Rotating Work Type Assign")
verbose_name_plural = _("Rotating Work Type Assigns")
2023-08-01 16:48:48 +05:30
ordering = ["-next_change_date", "-employee_id__employee_first_name"]
2023-05-10 15:06:57 +05:30
def clean(self):
if self.is_active and self.employee_id is not None:
# Check if any other active record with the same parent already exists
2023-08-01 16:48:48 +05:30
siblings = RotatingWorkTypeAssign.objects.filter(
is_active=True, employee_id=self.employee_id
)
2023-05-10 15:06:57 +05:30
if siblings.exists() and siblings.first().id != self.id:
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Only one active record allowed per employee"))
2023-05-10 15:06:57 +05:30
if self.start_date < django.utils.timezone.now().date():
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Date must be greater than or equal to today"))
2023-05-10 15:06:57 +05:30
class EmployeeType(models.Model):
2023-08-01 16:48:48 +05:30
"""
EmployeeType model
"""
2023-05-10 15:06:57 +05:30
employee_type = models.CharField(max_length=50)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
2023-08-01 16:48:48 +05:30
objects = models.Manager()
2023-05-10 15:06:57 +05:30
2023-11-17 14:30:30 +05:30
class Meta:
"""
Meta class to add additional options
"""
verbose_name = _("Employee Type")
verbose_name_plural = _("Employee Types")
2023-05-10 15:06:57 +05:30
def __str__(self) -> str:
2023-08-01 16:48:48 +05:30
return str(self.employee_type)
2023-05-10 15:06:57 +05:30
class EmployeeShiftDay(models.Model):
2023-08-01 16:48:48 +05:30
"""
EmployeeShiftDay model
"""
2023-05-10 15:06:57 +05:30
day = models.CharField(max_length=20, choices=DAY)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
2023-08-01 16:48:48 +05:30
objects = models.Manager()
2023-11-17 14:30:30 +05:30
class Meta:
"""
Meta class to add additional options
"""
verbose_name = _("Employee Shift Day")
verbose_name_plural = _("Employee Shift Days")
2023-05-10 15:06:57 +05:30
def __str__(self) -> str:
return str(_(self.day).capitalize())
2023-05-10 15:06:57 +05:30
2023-08-01 16:48:48 +05:30
class EmployeeShift(models.Model):
"""
EmployeeShift model
"""
employee_shift = models.CharField(
max_length=50,
null=False,
blank=False,
)
days = models.ManyToManyField(EmployeeShiftDay, through="EmployeeShiftSchedule")
weekly_full_time = models.CharField(
2023-08-07 13:02:24 +05:30
max_length=6,
default="40:00",
null=True,
blank=True,
validators=[validate_time_format],
2023-08-01 16:48:48 +05:30
)
full_time = models.CharField(
max_length=6, default="200:00", validators=[validate_time_format]
)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
2023-08-01 16:48:48 +05:30
objects = models.Manager()
2023-05-10 15:06:57 +05:30
2023-11-17 14:30:30 +05:30
class Meta:
"""
Meta class to add additional options
"""
verbose_name = _("Employee Shift")
verbose_name_plural = _("Employee Shifts")
2023-05-10 15:06:57 +05:30
def __str__(self) -> str:
2023-08-01 16:48:48 +05:30
return str(self.employee_shift)
2023-05-10 15:06:57 +05:30
class EmployeeShiftSchedule(models.Model):
2023-08-01 16:48:48 +05:30
"""
EmployeeShiftSchedule model
"""
day = models.ForeignKey(
2023-09-20 14:54:33 +05:30
EmployeeShiftDay, on_delete=models.PROTECT, related_name="day_schedule"
2023-08-01 16:48:48 +05:30
)
2023-05-10 15:06:57 +05:30
shift_id = models.ForeignKey(
2023-09-20 14:54:33 +05:30
EmployeeShift, on_delete=models.PROTECT, verbose_name=_("Shift")
2023-08-01 16:48:48 +05:30
)
minimum_working_hour = models.CharField(
default="08:15", max_length=5, validators=[validate_time_format]
)
2023-05-10 15:06:57 +05:30
start_time = models.TimeField(null=True)
2023-08-01 16:48:48 +05:30
end_time = models.TimeField(null=True)
2023-08-07 13:02:24 +05:30
is_night_shift = models.BooleanField(default=False)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT
)
2023-08-01 16:48:48 +05:30
objects = models.Manager()
2023-05-10 15:06:57 +05:30
class Meta:
2023-08-01 16:48:48 +05:30
"""
Meta class to add additional options
"""
2023-11-17 14:30:30 +05:30
verbose_name = _("Employee Shift Schedule")
verbose_name_plural = _("Employee Shift Schedules")
2023-08-01 16:48:48 +05:30
unique_together = [["shift_id", "day"]]
2023-05-10 15:06:57 +05:30
def __str__(self) -> str:
2023-08-01 16:48:48 +05:30
return f"{self.shift_id.employee_shift} {self.day}"
2023-08-07 13:02:24 +05:30
def save(self, *args, **kwargs):
if self.start_time and self.end_time:
self.is_night_shift = self.start_time > self.end_time
super().save(*args, **kwargs)
2023-05-10 15:06:57 +05:30
class RotatingShift(models.Model):
2023-08-01 16:48:48 +05:30
"""
RotatingShift model
"""
name = models.CharField(max_length=50)
employee_id = models.ManyToManyField(
2023-08-07 13:02:24 +05:30
"employee.Employee", through="RotatingShiftAssign", verbose_name=_("Employee")
2023-08-01 16:48:48 +05:30
)
shift1 = models.ForeignKey(
EmployeeShift,
related_name="shift1",
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
verbose_name=_("Shift 1"),
)
shift2 = models.ForeignKey(
EmployeeShift,
related_name="shift2",
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
verbose_name=_("Shift 2"),
)
objects = models.Manager()
2023-05-10 15:06:57 +05:30
2023-11-17 14:30:30 +05:30
class Meta:
"""
Meta class to add additional options
"""
verbose_name = _("Rotating Shift")
verbose_name_plural = _("Rotating Shifts")
2023-05-10 15:06:57 +05:30
def __str__(self) -> str:
2023-08-01 16:48:48 +05:30
return str(self.name)
2023-05-10 15:06:57 +05:30
def clean(self):
if self.shift1 == self.shift2:
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Choose different shifts"))
2023-05-10 15:06:57 +05:30
class RotatingShiftAssign(models.Model):
2023-08-01 16:48:48 +05:30
"""
RotatingShiftAssign model
"""
employee_id = models.ForeignKey(
2023-09-20 14:54:33 +05:30
"employee.Employee", on_delete=models.PROTECT, verbose_name=_("Employee")
2023-08-01 16:48:48 +05:30
)
rotating_shift_id = models.ForeignKey(
2023-09-20 14:54:33 +05:30
RotatingShift, on_delete=models.PROTECT, verbose_name=_("Rotating Shift")
2023-08-01 16:48:48 +05:30
)
2023-08-07 13:02:24 +05:30
start_date = models.DateField(
default=django.utils.timezone.now, verbose_name=_("Start Date")
2023-08-01 16:48:48 +05:30
)
next_change_date = models.DateField(null=True, verbose_name=_("Next Switch"))
2023-08-01 16:48:48 +05:30
current_shift = models.ForeignKey(
EmployeeShift,
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
null=True,
related_name="current_shift",
verbose_name=_("Current Shift"),
2023-08-01 16:48:48 +05:30
)
next_shift = models.ForeignKey(
EmployeeShift,
on_delete=models.PROTECT,
null=True,
related_name="next_shift",
verbose_name=_("Next Shift"),
)
based_on = models.CharField(
max_length=10,
choices=BASED_ON,
null=False,
blank=False,
verbose_name=_("Based On"),
)
rotate_after_day = models.IntegerField(
null=True, blank=True, default=7, verbose_name=_("Rotate After Day")
)
rotate_every_weekend = models.CharField(
max_length=10,
default="monday",
choices=DAY,
blank=True,
null=True,
verbose_name=_("Rotate Every Weekend"),
)
rotate_every = models.CharField(
max_length=10,
blank=True,
null=True,
default="1",
choices=DAY_DATE,
verbose_name=_("Rotate Every Month"),
2023-08-01 16:48:48 +05:30
)
is_active = models.BooleanField(default=True)
objects = models.Manager()
2023-05-10 15:06:57 +05:30
class Meta:
2023-08-01 16:48:48 +05:30
"""
Meta class to add additional options
"""
2023-11-17 14:30:30 +05:30
verbose_name = _("Rotating Shift Assign")
verbose_name_plural = _("Rotating Shift Assigns")
2023-08-01 16:48:48 +05:30
ordering = ["-next_change_date", "-employee_id__employee_first_name"]
2023-05-10 15:06:57 +05:30
def clean(self):
if self.is_active and self.employee_id is not None:
# Check if any other active record with the same parent already exists
2023-08-01 16:48:48 +05:30
siblings = RotatingShiftAssign.objects.filter(
is_active=True, employee_id=self.employee_id
)
2023-05-10 15:06:57 +05:30
if siblings.exists() and siblings.first().id != self.id:
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Only one active record allowed per employee"))
2023-05-10 15:06:57 +05:30
if self.start_date < django.utils.timezone.now().date():
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Date must be greater than or equal to today"))
2023-05-10 15:06:57 +05:30
class WorkTypeRequest(models.Model):
2023-08-01 16:48:48 +05:30
"""
WorkTypeRequest model
"""
employee_id = models.ForeignKey(
"employee.Employee",
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
null=True,
related_name="work_type_request",
2023-08-07 13:02:24 +05:30
verbose_name=_("Employee"),
2023-08-01 16:48:48 +05:30
)
work_type_id = models.ForeignKey(
WorkType,
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
related_name="requested_work_type",
verbose_name=_("Requesting Work Type"),
2023-08-01 16:48:48 +05:30
)
previous_work_type_id = models.ForeignKey(
WorkType,
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
null=True,
blank=True,
related_name="previous_work_type",
verbose_name=_("Previous Work Type"),
2023-08-01 16:48:48 +05:30
)
requested_date = models.DateField(
null=True, default=django.utils.timezone.now, verbose_name=_("Requested Date")
)
requested_till = models.DateField(
null=True, blank=True, verbose_name=_("Requested Till")
)
is_permanent_work_type = models.BooleanField(
default=True, verbose_name=_("Permanent Request")
)
description = models.TextField(null=True, verbose_name=_("Description"))
approved = models.BooleanField(default=False, verbose_name=_("Approved"))
canceled = models.BooleanField(default=False, verbose_name=_("Canceled"))
2023-05-10 15:06:57 +05:30
work_type_changed = models.BooleanField(default=False)
2023-08-01 16:48:48 +05:30
is_active = models.BooleanField(default=True)
objects = models.Manager()
2023-05-10 15:06:57 +05:30
class Meta:
2023-08-01 16:48:48 +05:30
"""
Meta class to add additional options
"""
2023-11-17 14:30:30 +05:30
verbose_name = _("Work Type Request")
verbose_name_plural = _("Work Type Requests")
2023-08-01 16:48:48 +05:30
permissions = (
("approve_worktyperequest", "Approve Work Type Request"),
("cancel_worktyperequest", "Cancel Work Type Request"),
)
ordering = [
"requested_date",
]
def is_any_work_type_request_exists(self):
approved_work_type_requests_range = WorkTypeRequest.objects.filter(
employee_id=self.employee_id,
approved=True,
canceled=False,
requested_date__range=[self.requested_date, self.requested_till],
requested_till__range=[self.requested_date, self.requested_till],
).exclude(id=self.id)
if approved_work_type_requests_range:
return True
approved_work_type_requests = WorkTypeRequest.objects.filter(
employee_id=self.employee_id,
approved=True,
canceled=False,
requested_date__lte=self.requested_date,
requested_till__gte=self.requested_date,
).exclude(id=self.id)
if approved_work_type_requests:
return True
if self.requested_till:
approved_work_type_requests_2 = WorkTypeRequest.objects.filter(
employee_id=self.employee_id,
approved=True,
canceled=False,
requested_date__lte=self.requested_till,
requested_till__gte=self.requested_till,
).exclude(id=self.id)
if approved_work_type_requests_2:
return True
approved_permanent_req = WorkTypeRequest.objects.filter(
employee_id=self.employee_id,
approved=True,
canceled=False,
requested_date__exact=self.requested_date,
)
if approved_permanent_req:
return True
return False
2023-08-01 16:48:48 +05:30
2023-05-10 15:06:57 +05:30
def clean(self):
if self.requested_date < django.utils.timezone.now().date():
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Date must be greater than or equal to today"))
2023-05-10 15:06:57 +05:30
if self.requested_till and self.requested_till < self.requested_date:
2023-08-01 16:48:48 +05:30
raise ValidationError(
_("End date must be greater than or equal to start date")
)
if self.is_any_work_type_request_exists():
raise ValidationError(
_("A work type request already exists during this time period.")
)
2023-05-10 15:06:57 +05:30
class ShiftRequest(models.Model):
2023-08-01 16:48:48 +05:30
"""
ShiftRequest model
"""
employee_id = models.ForeignKey(
"employee.Employee",
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
null=True,
related_name="shift_request",
2023-08-07 13:02:24 +05:30
verbose_name=_("Employee"),
2023-08-01 16:48:48 +05:30
)
shift_id = models.ForeignKey(
EmployeeShift,
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
related_name="requested_shift",
verbose_name=_("Requesting Shift"),
2023-08-01 16:48:48 +05:30
)
previous_shift_id = models.ForeignKey(
EmployeeShift,
2023-09-20 14:54:33 +05:30
on_delete=models.PROTECT,
2023-08-01 16:48:48 +05:30
null=True,
blank=True,
related_name="previous_shift",
verbose_name=_("Previous Shift"),
)
requested_date = models.DateField(
null=True, default=django.utils.timezone.now, verbose_name=_("Requested Date")
)
requested_till = models.DateField(
null=True, blank=True, verbose_name=_("Requested Till")
)
description = models.TextField(null=True, verbose_name=_("Description"))
is_permanent_shift = models.BooleanField(
default=True, verbose_name=_("Permanent Request")
2023-08-01 16:48:48 +05:30
)
approved = models.BooleanField(default=False, verbose_name=_("Approved"))
canceled = models.BooleanField(default=False, verbose_name=_("Canceled"))
2023-05-10 15:06:57 +05:30
shift_changed = models.BooleanField(default=False)
2023-08-01 16:48:48 +05:30
is_active = models.BooleanField(default=True)
objects = models.Manager()
2023-05-10 15:06:57 +05:30
class Meta:
2023-08-01 16:48:48 +05:30
"""
Meta class to add additional options
"""
2023-11-17 14:30:30 +05:30
verbose_name = _("Shift Request")
verbose_name_plural = _("Shift Requests")
2023-08-01 16:48:48 +05:30
permissions = (
("approve_shiftrequest", "Approve Shift Request"),
("cancel_shiftrequest", "Cancel Shift Request"),
)
ordering = [
"requested_date",
]
2023-05-10 15:06:57 +05:30
def clean(self):
if self.requested_date < django.utils.timezone.now().date():
2023-08-01 16:48:48 +05:30
raise ValidationError(_("Date must be greater than or equal to today"))
2023-05-10 15:06:57 +05:30
if self.requested_till and self.requested_till < self.requested_date:
2023-08-01 16:48:48 +05:30
raise ValidationError(
_("End date must be greater than or equal to start date")
)
if self.is_any_request_exists():
raise ValidationError(
_("A shift request already exists during this time period.")
)
def is_any_request_exists(self):
approved_shift_requests_range = ShiftRequest.objects.filter(
employee_id=self.employee_id,
approved=True,
canceled=False,
requested_date__range=[self.requested_date, self.requested_till],
requested_till__range=[self.requested_date, self.requested_till],
).exclude(id=self.id)
if approved_shift_requests_range:
return True
approved_shift_requests = ShiftRequest.objects.filter(
employee_id=self.employee_id,
approved=True,
canceled=False,
requested_date__lte=self.requested_date,
requested_till__gte=self.requested_date,
).exclude(id=self.id)
if approved_shift_requests:
return True
if self.requested_till:
approved_shift_requests_2 = ShiftRequest.objects.filter(
employee_id=self.employee_id,
approved=True,
canceled=False,
requested_date__lte=self.requested_till,
requested_till__gte=self.requested_till,
).exclude(id=self.id)
if approved_shift_requests_2:
return True
approved_permanent_req = ShiftRequest.objects.filter(
employee_id=self.employee_id,
approved=True,
canceled=False,
requested_date__exact=self.requested_date,
)
if approved_permanent_req:
return True
return False
2023-05-10 15:06:57 +05:30
def save(self, *args, **kwargs):
2023-08-01 16:48:48 +05:30
super().save(*args, **kwargs)
2023-05-10 15:06:57 +05:30
def __str__(self):
2023-08-01 16:48:48 +05:30
return f"{self.employee_id}"