502 lines
18 KiB
Python
502 lines
18 KiB
Python
import calendar
|
|
import sys
|
|
from datetime import date, datetime, timedelta
|
|
|
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
from django.urls import reverse
|
|
|
|
from notifications.signals import notify
|
|
|
|
|
|
def update_rotating_work_type_assign(rotating_work_type, new_date):
|
|
"""
|
|
Here will update the employee work information details and send notification
|
|
"""
|
|
from django.contrib.auth.models import User
|
|
|
|
employee = rotating_work_type.employee_id
|
|
employee_work_info = employee.employee_work_info
|
|
work_type1 = rotating_work_type.rotating_work_type_id.work_type1
|
|
work_type2 = rotating_work_type.rotating_work_type_id.work_type2
|
|
additional_work_types = (
|
|
rotating_work_type.rotating_work_type_id.additional_work_types()
|
|
)
|
|
if additional_work_types is None:
|
|
total_rotate_work_types = [work_type1, work_type2]
|
|
else:
|
|
total_rotate_work_types = [work_type1, work_type2] + list(additional_work_types)
|
|
next_work_type_index = rotating_work_type.additional_data.get(
|
|
"next_work_type_index", 0
|
|
)
|
|
next_work_type = total_rotate_work_types[next_work_type_index]
|
|
if next_work_type_index < len(total_rotate_work_types) - 1:
|
|
next_work_type_index += 1
|
|
else:
|
|
next_work_type_index = 0
|
|
|
|
rotating_work_type.additional_data["next_work_type_index"] = next_work_type_index
|
|
employee_work_info.work_type_id = rotating_work_type.next_work_type
|
|
employee_work_info.save()
|
|
rotating_work_type.next_change_date = new_date
|
|
rotating_work_type.current_work_type = rotating_work_type.next_work_type
|
|
rotating_work_type.next_work_type = next_work_type
|
|
rotating_work_type.save()
|
|
bot = User.objects.filter(username="Horilla Bot").first()
|
|
if bot is not None:
|
|
employee = rotating_work_type.employee_id
|
|
notify.send(
|
|
bot,
|
|
recipient=employee.employee_user_id,
|
|
verb="Your Work Type has been changed.",
|
|
verb_ar="لقد تغير نوع عملك.",
|
|
verb_de="Ihre Art der Arbeit hat sich geändert.",
|
|
verb_es="Su tipo de trabajo ha sido cambiado.",
|
|
verb_fr="Votre type de travail a été modifié.",
|
|
icon="infinite",
|
|
redirect=reverse("employee-profile"),
|
|
)
|
|
return
|
|
|
|
|
|
def work_type_rotate_after(rotating_work_work_type):
|
|
"""
|
|
This method for rotate work type based on after day
|
|
"""
|
|
date_today = datetime.now()
|
|
switch_date = rotating_work_work_type.next_change_date
|
|
if switch_date.strftime("%Y-%m-%d") == date_today.strftime("%Y-%m-%d"):
|
|
new_date = date_today + timedelta(days=rotating_work_work_type.rotate_after_day)
|
|
update_rotating_work_type_assign(rotating_work_work_type, new_date)
|
|
return
|
|
|
|
|
|
def work_type_rotate_weekend(rotating_work_type):
|
|
"""
|
|
This method for rotate work type based on weekend
|
|
"""
|
|
date_today = datetime.now()
|
|
switch_date = rotating_work_type.next_change_date
|
|
if switch_date.strftime("%Y-%m-%d") == date_today.strftime("%Y-%m-%d"):
|
|
day = datetime.now().strftime("%A").lower()
|
|
switch_day = rotating_work_type.rotate_every_weekend
|
|
if day == switch_day:
|
|
new_date = date_today + timedelta(days=7)
|
|
update_rotating_work_type_assign(rotating_work_type, new_date)
|
|
return
|
|
|
|
|
|
def work_type_rotate_every(rotating_work_type):
|
|
"""
|
|
This method for rotate work type based on every month
|
|
"""
|
|
date_today = datetime.now()
|
|
switch_date = rotating_work_type.next_change_date
|
|
day_date = rotating_work_type.rotate_every
|
|
if switch_date.strftime("%Y-%m-%d") == date_today.strftime("%Y-%m-%d"):
|
|
if day_date == switch_date.strftime("%d").lstrip("0"):
|
|
new_date = date_today.replace(month=date_today.month + 1)
|
|
update_rotating_work_type_assign(rotating_work_type, new_date)
|
|
elif day_date == "last":
|
|
year = date_today.strftime("%Y")
|
|
month = date_today.strftime("%m")
|
|
last_day = calendar.monthrange(int(year), int(month) + 1)[1]
|
|
new_date = datetime(int(year), int(month) + 1, last_day)
|
|
update_rotating_work_type_assign(rotating_work_type, new_date)
|
|
return
|
|
|
|
|
|
def rotate_work_type():
|
|
"""
|
|
This method will identify the based on condition to the rotating shift assign
|
|
and redirect to the chunk method to execute.
|
|
"""
|
|
from base.models import RotatingWorkTypeAssign
|
|
|
|
rotating_work_types = RotatingWorkTypeAssign.objects.filter(is_active=True)
|
|
for rotating_work_type in rotating_work_types:
|
|
based_on = rotating_work_type.based_on
|
|
if based_on == "after":
|
|
work_type_rotate_after(rotating_work_type)
|
|
elif based_on == "weekly":
|
|
work_type_rotate_weekend(rotating_work_type)
|
|
elif based_on == "monthly":
|
|
work_type_rotate_every(rotating_work_type)
|
|
return
|
|
|
|
|
|
def update_rotating_shift_assign(rotating_shift, new_date):
|
|
"""
|
|
Here will update the employee work information and send notification
|
|
"""
|
|
from django.contrib.auth.models import User
|
|
|
|
next_shift_index = 0
|
|
employee = rotating_shift.employee_id
|
|
employee_work_info = employee.employee_work_info
|
|
rotating_shift_id = rotating_shift.rotating_shift_id
|
|
shift1 = rotating_shift_id.shift1
|
|
shift2 = rotating_shift_id.shift2
|
|
additional_shifts = rotating_shift_id.additional_shifts()
|
|
if additional_shifts is None:
|
|
total_rotate_shifts = [shift1, shift2]
|
|
else:
|
|
total_rotate_shifts = [shift1, shift2] + list(additional_shifts)
|
|
next_shift_index = rotating_shift.additional_data.get("next_shift_index")
|
|
next_shift = total_rotate_shifts[next_shift_index]
|
|
if next_shift_index < len(total_rotate_shifts) - 1:
|
|
next_shift_index += 1
|
|
else:
|
|
next_shift_index = 0 # Wrap around to the beginning of the list
|
|
rotating_shift.additional_data["next_shift_index"] = next_shift_index
|
|
employee_work_info.shift_id = rotating_shift.next_shift
|
|
employee_work_info.save()
|
|
rotating_shift.next_change_date = new_date
|
|
rotating_shift.current_shift = rotating_shift.next_shift
|
|
rotating_shift.next_shift = next_shift
|
|
rotating_shift.save()
|
|
bot = User.objects.filter(username="Horilla Bot").first()
|
|
if bot is not None:
|
|
employee = rotating_shift.employee_id
|
|
notify.send(
|
|
bot,
|
|
recipient=employee.employee_user_id,
|
|
verb="Your shift has been changed.",
|
|
verb_ar="تم تغيير التحول الخاص بك.",
|
|
verb_de="Ihre Schicht wurde geändert.",
|
|
verb_es="Tu turno ha sido cambiado.",
|
|
verb_fr="Votre quart de travail a été modifié.",
|
|
icon="infinite",
|
|
redirect=reverse("employee-profile"),
|
|
)
|
|
return
|
|
|
|
|
|
def shift_rotate_after_day(rotating_shift, today):
|
|
"""
|
|
This method for rotate shift based on after day
|
|
"""
|
|
switch_date = rotating_shift.next_change_date
|
|
if switch_date == today:
|
|
new_date = today + timedelta(days=rotating_shift.rotate_after_day)
|
|
update_rotating_shift_assign(rotating_shift, new_date)
|
|
return
|
|
|
|
|
|
def shift_rotate_weekend(rotating_shift, today):
|
|
"""
|
|
This method for rotate shift based on weekend
|
|
"""
|
|
switch_date = rotating_shift.next_change_date
|
|
if switch_date == today:
|
|
day = today.strftime("%A").lower()
|
|
switch_day = rotating_shift.rotate_every_weekend
|
|
if day == switch_day:
|
|
new_date = today + timedelta(days=7)
|
|
update_rotating_shift_assign(rotating_shift, new_date)
|
|
return
|
|
|
|
|
|
def shift_rotate_every(rotating_shift, today):
|
|
"""
|
|
This method for rotate shift based on every month
|
|
"""
|
|
switch_date = rotating_shift.next_change_date
|
|
day_date = rotating_shift.rotate_every
|
|
if switch_date == today:
|
|
if day_date == switch_date.strftime("%d").lstrip("0"):
|
|
new_date = today.replace(month=today.month + 1)
|
|
update_rotating_shift_assign(rotating_shift, new_date)
|
|
elif day_date == "last":
|
|
year = today.year
|
|
month = today.month
|
|
last_day = calendar.monthrange(int(year), int(month) + 1)[1]
|
|
new_date = datetime(int(year), int(month) + 1, last_day)
|
|
update_rotating_shift_assign(rotating_shift, new_date)
|
|
return
|
|
|
|
|
|
def rotate_shift():
|
|
"""
|
|
This method will identify the based on condition to the rotating shift assign
|
|
and redirect to the chunk method to execute.
|
|
"""
|
|
from base.models import RotatingShiftAssign
|
|
|
|
rotating_shifts = RotatingShiftAssign.objects.filter(is_active=True)
|
|
today = datetime.now().date()
|
|
r_shifts = rotating_shifts.filter(start_date__lte=today)
|
|
rotating_shifts_modified = None
|
|
for r_shift in r_shifts:
|
|
emp_shift = rotating_shifts.filter(
|
|
employee_id=r_shift.employee_id, start_date__lte=today
|
|
).exclude(id=r_shift.id)
|
|
rotating_shifts_modified = rotating_shifts.exclude(
|
|
id__in=emp_shift.values_list("id", flat=True)
|
|
)
|
|
emp_shift.update(is_active=False)
|
|
|
|
for rotating_shift in rotating_shifts_modified:
|
|
based_on = rotating_shift.based_on
|
|
# after day condition
|
|
if based_on == "after":
|
|
shift_rotate_after_day(rotating_shift, today)
|
|
# weekly condition
|
|
elif based_on == "weekly":
|
|
shift_rotate_weekend(rotating_shift, today)
|
|
# monthly condition
|
|
elif based_on == "monthly":
|
|
shift_rotate_every(rotating_shift, today)
|
|
|
|
return
|
|
|
|
|
|
def switch_shift():
|
|
"""
|
|
This method change employees shift information regards to the shift request
|
|
"""
|
|
from django.contrib.auth.models import User
|
|
|
|
from base.models import ShiftRequest
|
|
|
|
today = date.today()
|
|
|
|
shift_requests = ShiftRequest.objects.filter(
|
|
canceled=False, approved=True, requested_date__exact=today, shift_changed=False
|
|
)
|
|
if shift_requests:
|
|
for request in shift_requests:
|
|
work_info = request.employee_id.employee_work_info
|
|
# updating requested shift to the employee work information.
|
|
work_info.shift_id = request.shift_id
|
|
work_info.save()
|
|
request.approved = True
|
|
request.shift_changed = True
|
|
request.save()
|
|
bot = User.objects.filter(username="Horilla Bot").first()
|
|
if bot is not None:
|
|
employee = request.employee_id
|
|
notify.send(
|
|
bot,
|
|
recipient=employee.employee_user_id,
|
|
verb="Shift Changes notification",
|
|
verb_ar="التحول تغيير الإخطار",
|
|
verb_de="Benachrichtigung über Schichtänderungen",
|
|
verb_es="Notificación de cambios de turno",
|
|
verb_fr="Notification des changements de quart de travail",
|
|
icon="refresh",
|
|
redirect=reverse("employee-profile"),
|
|
)
|
|
return
|
|
|
|
|
|
def undo_shift():
|
|
"""
|
|
This method undo previous employees shift information regards to the shift request
|
|
"""
|
|
from django.contrib.auth.models import User
|
|
|
|
from base.models import ShiftRequest
|
|
|
|
today = date.today()
|
|
# here will get all the active shift requests
|
|
shift_requests = ShiftRequest.objects.filter(
|
|
canceled=False,
|
|
approved=True,
|
|
requested_till__lt=today,
|
|
is_active=True,
|
|
shift_changed=True,
|
|
)
|
|
if shift_requests:
|
|
for request in shift_requests:
|
|
work_info = request.employee_id.employee_work_info
|
|
work_info.shift_id = request.previous_shift_id
|
|
work_info.save()
|
|
# making the instance in-active
|
|
request.is_active = False
|
|
request.save()
|
|
bot = User.objects.filter(username="Horilla Bot").first()
|
|
if bot is not None:
|
|
employee = request.employee_id
|
|
notify.send(
|
|
bot,
|
|
recipient=employee.employee_user_id,
|
|
verb="Shift changes notification, Requested date expired.",
|
|
verb_ar="التحول يغير الإخطار ، التاريخ المطلوب انتهت صلاحيته.",
|
|
verb_de="Benachrichtigung über Schichtänderungen, gewünschtes Datum abgelaufen.",
|
|
verb_es="Notificación de cambios de turno, Fecha solicitada vencida.",
|
|
verb_fr="Notification de changement d'équipe, la date demandée a expiré.",
|
|
icon="refresh",
|
|
redirect=reverse("employee-profile"),
|
|
)
|
|
return
|
|
|
|
|
|
def switch_work_type():
|
|
"""
|
|
This method change employees work type information regards to the work type request
|
|
"""
|
|
from django.contrib.auth.models import User
|
|
|
|
from base.models import WorkTypeRequest
|
|
|
|
today = date.today()
|
|
work_type_requests = WorkTypeRequest.objects.filter(
|
|
canceled=False,
|
|
approved=True,
|
|
requested_date__exact=today,
|
|
work_type_changed=False,
|
|
)
|
|
for request in work_type_requests:
|
|
work_info = request.employee_id.employee_work_info
|
|
# updating requested work type to the employee work information.
|
|
work_info.work_type_id = request.work_type_id
|
|
work_info.save()
|
|
request.approved = True
|
|
request.work_type_changed = True
|
|
request.save()
|
|
bot = User.objects.filter(username="Horilla Bot").first()
|
|
if bot is not None:
|
|
employee = request.employee_id
|
|
notify.send(
|
|
bot,
|
|
recipient=employee.employee_user_id,
|
|
verb="Work Type Changes notification",
|
|
verb_ar="إخطار تغييرات نوع العمل",
|
|
verb_de="Benachrichtigung über Änderungen des Arbeitstyps",
|
|
verb_es="Notificación de cambios de tipo de trabajo",
|
|
verb_fr="Notification de changement de type de travail",
|
|
icon="swap-horizontal",
|
|
redirect=reverse("employee-profile"),
|
|
)
|
|
return
|
|
|
|
|
|
def undo_work_type():
|
|
"""
|
|
This method undo previous employees work type information regards to the work type request
|
|
"""
|
|
from django.contrib.auth.models import User
|
|
|
|
from base.models import WorkTypeRequest
|
|
|
|
today = date.today()
|
|
# here will get all the active work type requests
|
|
work_type_requests = WorkTypeRequest.objects.filter(
|
|
canceled=False,
|
|
approved=True,
|
|
requested_till__lt=today,
|
|
is_active=True,
|
|
work_type_changed=True,
|
|
)
|
|
for request in work_type_requests:
|
|
work_info = request.employee_id.employee_work_info
|
|
# updating employee work information's work type to previous work type
|
|
work_info.work_type_id = request.previous_work_type_id
|
|
work_info.save()
|
|
# making the instance is in-active
|
|
request.is_active = False
|
|
request.save()
|
|
bot = User.objects.filter(username="Horilla Bot").first()
|
|
if bot is not None:
|
|
employee = request.employee_id
|
|
notify.send(
|
|
bot,
|
|
recipient=employee.employee_user_id,
|
|
verb="Work type changes notification, Requested date expired.",
|
|
verb_ar="إعلام بتغيير نوع العمل ، انتهاء صلاحية التاريخ المطلوب.",
|
|
verb_de="Benachrichtigung über Änderungen des Arbeitstyps, angefordertes Datum abgelaufen.",
|
|
verb_es="Notificación de cambios de tipo de trabajo, fecha solicitada vencida.",
|
|
verb_fr="Notification de changement de type de travail, la date demandée a expiré.",
|
|
icon="swap-horizontal",
|
|
redirect=reverse("employee-profile"),
|
|
)
|
|
return
|
|
|
|
|
|
def recurring_holiday():
|
|
from .models import Holidays
|
|
|
|
recurring_holidays = Holidays.objects.filter(recurring=True)
|
|
today = datetime.now()
|
|
# Looping through all recurring holiday
|
|
for recurring_holiday in recurring_holidays:
|
|
start_date = recurring_holiday.start_date
|
|
end_date = recurring_holiday.end_date
|
|
new_start_date = date(start_date.year + 1, start_date.month, start_date.day)
|
|
new_end_date = date(end_date.year + 1, end_date.month, end_date.day)
|
|
# Checking that end date is not none
|
|
if end_date is None:
|
|
# checking if that start date is day before today
|
|
if start_date == (today - timedelta(days=1)).date():
|
|
recurring_holiday.start_date = new_start_date
|
|
elif end_date == (today - timedelta(days=1)).date():
|
|
recurring_holiday.start_date = new_start_date
|
|
recurring_holiday.end_date = new_end_date
|
|
recurring_holiday.save()
|
|
|
|
|
|
if not any(
|
|
cmd in sys.argv
|
|
for cmd in ["makemigrations", "migrate", "compilemessages", "flush", "shell"]
|
|
):
|
|
scheduler = BackgroundScheduler()
|
|
|
|
# Add jobs with next_run_time set to the end of the previous job
|
|
try:
|
|
scheduler.add_job(rotate_shift, "interval", hours=4, id="job1")
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
scheduler.add_job(
|
|
rotate_work_type,
|
|
"interval",
|
|
hours=4,
|
|
id="job2",
|
|
)
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
scheduler.add_job(
|
|
undo_shift,
|
|
"interval",
|
|
hours=4,
|
|
id="job3",
|
|
)
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
scheduler.add_job(
|
|
switch_shift,
|
|
"interval",
|
|
hours=4,
|
|
id="job4",
|
|
)
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
scheduler.add_job(
|
|
undo_work_type,
|
|
"interval",
|
|
hours=4,
|
|
id="job6",
|
|
)
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
scheduler.add_job(
|
|
switch_work_type,
|
|
"interval",
|
|
hours=4,
|
|
id="job5",
|
|
)
|
|
except:
|
|
pass
|
|
|
|
scheduler.add_job(recurring_holiday, "interval", hours=4)
|
|
scheduler.start()
|