830 lines
26 KiB
Python
830 lines
26 KiB
Python
"""
|
|
models.py
|
|
|
|
This module is used to register django models
|
|
"""
|
|
import django
|
|
from django.core.exceptions import ValidationError
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.db import models
|
|
from base.horilla_company_manager import HorillaCompanyManager
|
|
|
|
|
|
# Create your models here.
|
|
|
|
|
|
def validate_time_format(value):
|
|
"""
|
|
this method is used to validate the format of duration like fields.
|
|
"""
|
|
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):
|
|
raise ValidationError(_("Invalid time, excepted HH:MM"))
|
|
except ValueError as e:
|
|
raise ValidationError(_("Invalid format, excepted HH:MM")) from e
|
|
|
|
|
|
class Company(models.Model):
|
|
"""
|
|
Company model
|
|
"""
|
|
|
|
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)
|
|
icon = models.FileField(
|
|
upload_to="base/icon",
|
|
null=True,
|
|
)
|
|
objects = models.Manager()
|
|
date_format = models.CharField(max_length=30, blank=True, null=True)
|
|
time_format = models.CharField(max_length=20, blank=True, null=True)
|
|
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Company")
|
|
verbose_name_plural = _("Companies")
|
|
unique_together = ["company", "address"]
|
|
app_label = "base"
|
|
|
|
def __str__(self) -> str:
|
|
return str(self.company)
|
|
|
|
|
|
from base.thread_local_middleware import _thread_locals
|
|
|
|
from django import forms
|
|
class Department(models.Model):
|
|
"""
|
|
Department model
|
|
"""
|
|
|
|
department = models.CharField(max_length=50, blank=False)
|
|
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
|
|
|
|
objects = HorillaCompanyManager()
|
|
|
|
class Meta:
|
|
verbose_name = _("Department")
|
|
verbose_name_plural = _("Departments")
|
|
|
|
def clean(self, *args, **kwargs):
|
|
super().clean(*args, **kwargs)
|
|
request = getattr(_thread_locals, "request", None)
|
|
if request and request.POST:
|
|
company = request.POST.getlist('company_id', None)
|
|
department = request.POST.get('department', None)
|
|
if Department.objects.filter(company_id__id__in=company,department = department).exclude(id= self.id).exists():
|
|
raise ValidationError(
|
|
"This department already exists in this company"
|
|
)
|
|
return
|
|
|
|
def save(self, *args, **kwargs):
|
|
super().save(*args, **kwargs)
|
|
self.clean(*args, **kwargs)
|
|
return self
|
|
|
|
def __str__(self):
|
|
return str(self.department)
|
|
|
|
|
|
class JobPosition(models.Model):
|
|
"""
|
|
JobPosition model
|
|
"""
|
|
|
|
job_position = models.CharField(max_length=50, blank=False, null=False, unique=True)
|
|
department_id = models.ForeignKey(
|
|
Department,
|
|
on_delete=models.PROTECT,
|
|
related_name="job_position",
|
|
verbose_name=_("Department"),
|
|
)
|
|
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
|
|
|
|
objects = HorillaCompanyManager("department_id__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Job Position")
|
|
verbose_name_plural = _("Job Positions")
|
|
|
|
def __str__(self):
|
|
return str(self.job_position)
|
|
|
|
|
|
class JobRole(models.Model):
|
|
"""JobRole model"""
|
|
|
|
job_position_id = models.ForeignKey(
|
|
JobPosition, on_delete=models.PROTECT, verbose_name=_("Job Position")
|
|
)
|
|
job_role = models.CharField(max_length=50, blank=False, null=True)
|
|
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
|
|
|
|
objects = HorillaCompanyManager("job_position_id__department_id__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Job Role")
|
|
verbose_name_plural = _("Job Roles")
|
|
unique_together = ("job_position_id", "job_role")
|
|
|
|
def __str__(self):
|
|
return f"{self.job_role} - {self.job_position_id.job_position}"
|
|
|
|
|
|
class WorkType(models.Model):
|
|
"""
|
|
WorkType model
|
|
"""
|
|
|
|
work_type = models.CharField(max_length=50)
|
|
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
|
|
|
|
objects = HorillaCompanyManager()
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Work Type")
|
|
verbose_name_plural = _("Work Types")
|
|
|
|
def __str__(self) -> str:
|
|
return str(self.work_type)
|
|
|
|
def clean(self, *args, **kwargs):
|
|
super().clean(*args, **kwargs)
|
|
request = getattr(_thread_locals, "request", None)
|
|
if request and request.POST:
|
|
company = request.POST.getlist('company_id', None)
|
|
work_type = request.POST.get('work_type', None)
|
|
if WorkType.objects.filter(company_id__id__in=company,work_type = work_type).exclude(id= self.id).exists():
|
|
raise ValidationError(
|
|
"This work type already exists in this company"
|
|
)
|
|
return
|
|
|
|
def save(self, *args, **kwargs):
|
|
super().save(*args, **kwargs)
|
|
self.clean(*args, **kwargs)
|
|
return self
|
|
|
|
|
|
class RotatingWorkType(models.Model):
|
|
"""
|
|
RotatingWorkType model
|
|
"""
|
|
|
|
name = models.CharField(max_length=50)
|
|
work_type1 = models.ForeignKey(
|
|
WorkType,
|
|
on_delete=models.PROTECT,
|
|
related_name="work_type1",
|
|
verbose_name=_("Work Type 1"),
|
|
)
|
|
work_type2 = models.ForeignKey(
|
|
WorkType,
|
|
on_delete=models.PROTECT,
|
|
related_name="work_type2",
|
|
verbose_name=_("Work Type 2"),
|
|
)
|
|
employee_id = models.ManyToManyField(
|
|
"employee.Employee",
|
|
through="RotatingWorkTypeAssign",
|
|
verbose_name=_("Employee"),
|
|
)
|
|
objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Rotating Work Type")
|
|
verbose_name_plural = _("Rotating Work Types")
|
|
|
|
def __str__(self) -> str:
|
|
return str(self.name)
|
|
|
|
def clean(self):
|
|
if self.work_type1 == self.work_type2:
|
|
raise ValidationError(_("Choose different work type"))
|
|
|
|
|
|
DAY_DATE = [(str(i), str(i)) for i in range(1, 32)]
|
|
DAY_DATE.append(("last", _("Last Day")))
|
|
DAY = [
|
|
("monday", _("Monday")),
|
|
("tuesday", _("Tuesday")),
|
|
("wednesday", _("Wednesday")),
|
|
("thursday", _("Thursday")),
|
|
("friday", _("Friday")),
|
|
("saturday", _("Saturday")),
|
|
("sunday", _("Sunday")),
|
|
]
|
|
BASED_ON = [
|
|
("after", _("After")),
|
|
("weekly", _("Weekend")),
|
|
("monthly", _("Monthly")),
|
|
]
|
|
|
|
|
|
class RotatingWorkTypeAssign(models.Model):
|
|
"""
|
|
RotatingWorkTypeAssign model
|
|
"""
|
|
|
|
employee_id = models.ForeignKey(
|
|
"employee.Employee",
|
|
on_delete=models.PROTECT,
|
|
null=True,
|
|
verbose_name=_("Employee"),
|
|
)
|
|
rotating_work_type_id = models.ForeignKey(
|
|
RotatingWorkType, on_delete=models.PROTECT, verbose_name=_("Rotating Work Type")
|
|
)
|
|
start_date = models.DateField(
|
|
default=django.utils.timezone.now, verbose_name=_("Start Date")
|
|
)
|
|
next_change_date = models.DateField(null=True, verbose_name=_("Next Switch"))
|
|
current_work_type = models.ForeignKey(
|
|
WorkType,
|
|
null=True,
|
|
on_delete=models.PROTECT,
|
|
related_name="current_work_type",
|
|
verbose_name=_("Current Work Type"),
|
|
)
|
|
next_work_type = models.ForeignKey(
|
|
WorkType,
|
|
null=True,
|
|
on_delete=models.PROTECT,
|
|
related_name="next_work_type",
|
|
verbose_name=_("Next Work Type"),
|
|
)
|
|
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"),
|
|
)
|
|
|
|
is_active = models.BooleanField(default=True)
|
|
objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Rotating Work Type Assign")
|
|
verbose_name_plural = _("Rotating Work Type Assigns")
|
|
ordering = ["-next_change_date", "-employee_id__employee_first_name"]
|
|
|
|
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
|
|
siblings = RotatingWorkTypeAssign.objects.filter(
|
|
is_active=True, employee_id=self.employee_id
|
|
)
|
|
if siblings.exists() and siblings.first().id != self.id:
|
|
raise ValidationError(_("Only one active record allowed per employee"))
|
|
if self.start_date < django.utils.timezone.now().date():
|
|
raise ValidationError(_("Date must be greater than or equal to today"))
|
|
|
|
|
|
class EmployeeType(models.Model):
|
|
"""
|
|
EmployeeType model
|
|
"""
|
|
|
|
employee_type = models.CharField(max_length=50)
|
|
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
|
|
|
|
objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Employee Type")
|
|
verbose_name_plural = _("Employee Types")
|
|
|
|
def __str__(self) -> str:
|
|
return str(self.employee_type)
|
|
|
|
def clean(self, *args, **kwargs):
|
|
super().clean(*args, **kwargs)
|
|
request = getattr(_thread_locals, "request", None)
|
|
if request and request.POST:
|
|
company = request.POST.getlist('company_id', None)
|
|
employee_type = request.POST.get('employee_type', None)
|
|
if EmployeeType.objects.filter(company_id__id__in=company,employee_type = employee_type).exclude(id= self.id).exists():
|
|
raise ValidationError(
|
|
"This employee type already exists in this company"
|
|
)
|
|
return
|
|
|
|
def save(self, *args, **kwargs):
|
|
super().save(*args, **kwargs)
|
|
self.clean(*args, **kwargs)
|
|
return self
|
|
|
|
|
|
class EmployeeShiftDay(models.Model):
|
|
"""
|
|
EmployeeShiftDay model
|
|
"""
|
|
|
|
day = models.CharField(max_length=20, choices=DAY)
|
|
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
|
|
|
|
objects = HorillaCompanyManager()
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Employee Shift Day")
|
|
verbose_name_plural = _("Employee Shift Days")
|
|
|
|
def __str__(self) -> str:
|
|
return str(_(self.day).capitalize())
|
|
|
|
|
|
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(
|
|
max_length=6,
|
|
default="40:00",
|
|
null=True,
|
|
blank=True,
|
|
validators=[validate_time_format],
|
|
)
|
|
full_time = models.CharField(
|
|
max_length=6, default="200:00", validators=[validate_time_format]
|
|
)
|
|
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
|
|
|
|
objects = HorillaCompanyManager("employee_shift__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Employee Shift")
|
|
verbose_name_plural = _("Employee Shifts")
|
|
|
|
def __str__(self) -> str:
|
|
return str(self.employee_shift)
|
|
|
|
def clean(self, *args, **kwargs):
|
|
super().clean(*args, **kwargs)
|
|
request = getattr(_thread_locals, "request", None)
|
|
if request and request.POST:
|
|
company = request.POST.getlist('company_id', None)
|
|
employee_shift = request.POST.get('employee_shift', None)
|
|
if EmployeeShift.objects.filter(company_id__id__in=company,employee_shift = employee_shift).exclude(id= self.id).exists():
|
|
raise ValidationError(
|
|
"This employee shift already exists in this company"
|
|
)
|
|
return
|
|
|
|
def save(self, *args, **kwargs):
|
|
super().save(*args, **kwargs)
|
|
self.clean(*args, **kwargs)
|
|
return self
|
|
|
|
|
|
class EmployeeShiftSchedule(models.Model):
|
|
"""
|
|
EmployeeShiftSchedule model
|
|
"""
|
|
|
|
day = models.ForeignKey(
|
|
EmployeeShiftDay, on_delete=models.PROTECT, related_name="day_schedule"
|
|
)
|
|
shift_id = models.ForeignKey(
|
|
EmployeeShift, on_delete=models.PROTECT, verbose_name=_("Shift")
|
|
)
|
|
minimum_working_hour = models.CharField(
|
|
default="08:15", max_length=5, validators=[validate_time_format]
|
|
)
|
|
start_time = models.TimeField(null=True)
|
|
end_time = models.TimeField(null=True)
|
|
is_night_shift = models.BooleanField(default=False)
|
|
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
|
|
|
|
objects = HorillaCompanyManager("shift_id__employee_shift__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Employee Shift Schedule")
|
|
verbose_name_plural = _("Employee Shift Schedules")
|
|
unique_together = [["shift_id", "day"]]
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.shift_id.employee_shift} {self.day}"
|
|
|
|
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)
|
|
|
|
|
|
class RotatingShift(models.Model):
|
|
"""
|
|
RotatingShift model
|
|
"""
|
|
|
|
name = models.CharField(max_length=50)
|
|
employee_id = models.ManyToManyField(
|
|
"employee.Employee", through="RotatingShiftAssign", verbose_name=_("Employee")
|
|
)
|
|
shift1 = models.ForeignKey(
|
|
EmployeeShift,
|
|
related_name="shift1",
|
|
on_delete=models.PROTECT,
|
|
verbose_name=_("Shift 1"),
|
|
)
|
|
shift2 = models.ForeignKey(
|
|
EmployeeShift,
|
|
related_name="shift2",
|
|
on_delete=models.PROTECT,
|
|
verbose_name=_("Shift 2"),
|
|
)
|
|
objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Rotating Shift")
|
|
verbose_name_plural = _("Rotating Shifts")
|
|
|
|
def __str__(self) -> str:
|
|
return str(self.name)
|
|
|
|
def clean(self):
|
|
if self.shift1 == self.shift2:
|
|
raise ValidationError(_("Choose different shifts"))
|
|
|
|
|
|
class RotatingShiftAssign(models.Model):
|
|
"""
|
|
RotatingShiftAssign model
|
|
"""
|
|
|
|
employee_id = models.ForeignKey(
|
|
"employee.Employee", on_delete=models.PROTECT, verbose_name=_("Employee")
|
|
)
|
|
rotating_shift_id = models.ForeignKey(
|
|
RotatingShift, on_delete=models.PROTECT, verbose_name=_("Rotating Shift")
|
|
)
|
|
start_date = models.DateField(
|
|
default=django.utils.timezone.now, verbose_name=_("Start Date")
|
|
)
|
|
next_change_date = models.DateField(null=True, verbose_name=_("Next Switch"))
|
|
current_shift = models.ForeignKey(
|
|
EmployeeShift,
|
|
on_delete=models.PROTECT,
|
|
null=True,
|
|
related_name="current_shift",
|
|
verbose_name=_("Current Shift"),
|
|
)
|
|
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"),
|
|
)
|
|
is_active = models.BooleanField(default=True)
|
|
objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Rotating Shift Assign")
|
|
verbose_name_plural = _("Rotating Shift Assigns")
|
|
ordering = ["-next_change_date", "-employee_id__employee_first_name"]
|
|
|
|
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
|
|
siblings = RotatingShiftAssign.objects.filter(
|
|
is_active=True, employee_id=self.employee_id
|
|
)
|
|
if siblings.exists() and siblings.first().id != self.id:
|
|
raise ValidationError(_("Only one active record allowed per employee"))
|
|
if self.start_date < django.utils.timezone.now().date():
|
|
raise ValidationError(_("Date must be greater than or equal to today"))
|
|
|
|
|
|
class WorkTypeRequest(models.Model):
|
|
"""
|
|
WorkTypeRequest model
|
|
"""
|
|
|
|
employee_id = models.ForeignKey(
|
|
"employee.Employee",
|
|
on_delete=models.PROTECT,
|
|
null=True,
|
|
related_name="work_type_request",
|
|
verbose_name=_("Employee"),
|
|
)
|
|
work_type_id = models.ForeignKey(
|
|
WorkType,
|
|
on_delete=models.PROTECT,
|
|
related_name="requested_work_type",
|
|
verbose_name=_("Requesting Work Type"),
|
|
)
|
|
previous_work_type_id = models.ForeignKey(
|
|
WorkType,
|
|
on_delete=models.PROTECT,
|
|
null=True,
|
|
blank=True,
|
|
related_name="previous_work_type",
|
|
verbose_name=_("Previous Work Type"),
|
|
)
|
|
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"))
|
|
work_type_changed = models.BooleanField(default=False)
|
|
is_active = models.BooleanField(default=True)
|
|
objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Work Type Request")
|
|
verbose_name_plural = _("Work Type Requests")
|
|
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
|
|
|
|
def clean(self):
|
|
if self.requested_date < django.utils.timezone.now().date():
|
|
raise ValidationError(_("Date must be greater than or equal to today"))
|
|
if self.requested_till and self.requested_till < self.requested_date:
|
|
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.")
|
|
)
|
|
|
|
|
|
class ShiftRequest(models.Model):
|
|
"""
|
|
ShiftRequest model
|
|
"""
|
|
|
|
employee_id = models.ForeignKey(
|
|
"employee.Employee",
|
|
on_delete=models.PROTECT,
|
|
null=True,
|
|
related_name="shift_request",
|
|
verbose_name=_("Employee"),
|
|
)
|
|
shift_id = models.ForeignKey(
|
|
EmployeeShift,
|
|
on_delete=models.PROTECT,
|
|
related_name="requested_shift",
|
|
verbose_name=_("Requesting Shift"),
|
|
)
|
|
previous_shift_id = models.ForeignKey(
|
|
EmployeeShift,
|
|
on_delete=models.PROTECT,
|
|
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")
|
|
)
|
|
approved = models.BooleanField(default=False, verbose_name=_("Approved"))
|
|
canceled = models.BooleanField(default=False, verbose_name=_("Canceled"))
|
|
shift_changed = models.BooleanField(default=False)
|
|
is_active = models.BooleanField(default=True)
|
|
objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add additional options
|
|
"""
|
|
|
|
verbose_name = _("Shift Request")
|
|
verbose_name_plural = _("Shift Requests")
|
|
permissions = (
|
|
("approve_shiftrequest", "Approve Shift Request"),
|
|
("cancel_shiftrequest", "Cancel Shift Request"),
|
|
)
|
|
ordering = [
|
|
"requested_date",
|
|
]
|
|
|
|
def clean(self):
|
|
if self.requested_date < django.utils.timezone.now().date():
|
|
raise ValidationError(_("Date must be greater than or equal to today"))
|
|
if self.requested_till and self.requested_till < self.requested_date:
|
|
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
|
|
|
|
def save(self, *args, **kwargs):
|
|
super().save(*args, **kwargs)
|
|
|
|
def __str__(self):
|
|
return f"{self.employee_id}"
|