| Server IP : 65.108.144.40 / Your IP : 216.73.217.165 Web Server : Apache/2.4.52 (Ubuntu) System : Linux ubuntu-8gb-hel1-1 5.15.0-173-generic #183-Ubuntu SMP Fri Mar 6 13:29:34 UTC 2026 x86_64 User : dev ( 1000) PHP Version : 8.2.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /var/www/erp/leave/ |
Upload File : |
import calendar
import contextlib
import datetime as dt
import sys
from datetime import datetime, timedelta
from urllib import request
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from dateutil.relativedelta import relativedelta
from django.urls import reverse
from notifications.signals import notify
from django.db.models import Q
import logging
logger = logging.getLogger(__name__)
logger = logging.getLogger('django')
today = datetime.now()
def leave_reset():
from leave.models import LeaveType
today_date = today.date()
leave_types = LeaveType.objects.filter(reset=True)
# Looping through filtered leave types with reset is true
for leave_type in leave_types:
# Looping through all available leaves
available_leaves = leave_type.employee_available_leave.all()
for available_leave in available_leaves:
reset_date = available_leave.reset_date
expired_date = available_leave.expired_date
if reset_date == today_date:
available_leave.update_carryforward()
# new_reset_date = available_leave.set_reset_date(assigned_date=today_date,available_leave = available_leave)
new_reset_date = available_leave.set_reset_date(
assigned_date=today_date, available_leave=available_leave
)
available_leave.reset_date = new_reset_date
available_leave.save()
if expired_date and expired_date <= today_date:
new_expired_date = available_leave.set_expired_date(
available_leave=available_leave, assigned_date=today_date
)
available_leave.expired_date = new_expired_date
available_leave.save()
if (
leave_type.carryforward_expire_date
and leave_type.carryforward_expire_date <= today_date
):
leave_type.carryforward_expire_date = leave_type.set_expired_date(
today_date
)
leave_type.save()
# Custom auto leave approve method
def auto_approve_leave_requests():
from leave.models import AvailableLeave, LeaveRequest
today_date = today.date()
# Query for pending leave requests
leave_requests = LeaveRequest.objects.filter(status="requested")
logger.info("Auto approve function executed (line 66)")
logger.info(f"""{leave_requests}""")
for leave_request in leave_requests:
employee_id = leave_request.employee_id
leave_type_id = leave_request.leave_type_id
available_leave = AvailableLeave.objects.get(
leave_type_id=leave_type_id, employee_id=employee_id
)
total_available_leave = available_leave.available_days + available_leave.carryforward_days
# if (not (total_available_leave >= leave_request.requested_days)) and leave_request.status != "approved":
# leave_request.status = "rejected"
# super(AvailableLeave, available_leave).save()
# leave_request.save()
# logger.info(f"""Rejected leave for {employee_id}, {leave_type_id}""")
if total_available_leave >= leave_request.requested_days and today_date - timedelta(days=1) >= leave_request.start_date and leave_request.status != "approved":
# Approve the leave request
leave_request.status = "approved"
if leave_request.requested_days > available_leave.available_days:
leave = leave_request.requested_days - available_leave.available_days
leave_request.approved_available_days = available_leave.available_days
available_leave.available_days = 0
available_leave.carryforward_days -= leave
leave_request.approved_carryforward_days = leave
else:
available_leave.available_days -= leave_request.requested_days
leave_request.approved_available_days = leave_request.requested_days
super(AvailableLeave, available_leave).save()
leave_request.save()
logger.info(f"""Approved leave for {employee_id}, {leave_type_id}""")
# Method to delete unwanted leave type
def delete_leave_type_on_tag_change(employee_id,leave_type):
from leave.models import AvailableLeave
# Check if the employee has the 'Leave Type' available and is assigned to them
available_leave = AvailableLeave.objects.filter(
leave_type_id=leave_type,
employee_id=employee_id
).exists()
if available_leave:
# Delete the leave type record for the employee if it exists
AvailableLeave.objects.filter(
leave_type_id=leave_type,
employee_id=employee_id
).delete()
# custom function for update leave for employee
def update_leave_for_employee(employee_info, leave_type, reset_interval, reset_date_field):
"""
Generalized function to update the available leave for an employee.
"""
from leave.models import AvailableLeave
from leave.models import LeaveType
employee_id = employee_info.employee_id
joining_date = employee_info.date_joining
tag_is_intern_or_trainee = employee_info.tags.filter(title__in=["Intern", "Trainee"]).exists()
tag_is_full_time = employee_info.tags.filter(title="Full Time").exists()
tag_is_probation = employee_info.tags.filter(title="Probation").exists()
casual_type_id = LeaveType.objects.get(name="Casual Leave")
earn_type_id = LeaveType.objects.get(name="Earn Leave")
today = datetime.now()
current_date = today.date()
# Get the available leave for the employee
is_leave_type = AvailableLeave.objects.filter(
leave_type_id=leave_type, employee_id=employee_id
).exists()
if is_leave_type:
available_leave = AvailableLeave.objects.get(
leave_type_id=leave_type, employee_id=employee_id
)
if available_leave:
next_reset = getattr(available_leave, reset_date_field, None)
total_leave_taken = available_leave.leave_taken()
logger.info("Executed update leave function at 143 line")
logger.info(f"""Name {employee_id}""")
try:
logger.info(f"""{current_date} >= {next_reset} : {current_date >= next_reset}""")
except Exception:
logger.info(f"""{current_date} >= {next_reset}""")
logger.info(f"""tag_is_intern_or_trainee : {tag_is_intern_or_trainee}""")
if next_reset is None and available_leave.assigned_date is not None:
if joining_date == current_date or ((joining_date + timedelta(days=1)) == current_date):
setattr(available_leave, reset_date_field, joining_date + reset_interval)
elif tag_is_full_time and available_leave.leave_type_id == earn_type_id:
if (joining_date + relativedelta(month=3)).year < current_date.year:
next_reset = current_date.replace(year=current_date.year,month=1,day=1) + timedelta(days=45)
else:
next_reset = available_leave.assigned_date + timedelta(days=45)
setattr(available_leave, reset_date_field, next_reset)
elif tag_is_full_time and available_leave.leave_type_id == casual_type_id:
next_reset = current_date.replace(year=current_date.year+1,month=1,day=1)
setattr(available_leave, reset_date_field, next_reset)
else:
next_reset = joining_date.replace(year=current_date.year, month=current_date.month)
setattr(available_leave, reset_date_field, next_reset)
available_leave.save()
# Check if it's time to increment leave days
elif current_date >= next_reset:
logger.info("Inside the current_date >= next_reset condition at 171 line")
if tag_is_full_time:
if available_leave.leave_type_id == earn_type_id:
logger.info("Executed earn leave condition at 174 line")
available_leave.available_days += 1.0
condition_date = datetime(current_date.year,1,1) + timedelta(days=45)*8
if current_date == condition_date.date():
resetting_date = current_date.replace(year=current_date.year + 1, month=2, day=15)
setattr(available_leave, reset_date_field, resetting_date)
else:
setattr(available_leave, reset_date_field, next_reset + reset_interval)
available_leave.save()
elif available_leave.leave_type_id == casual_type_id:
available_leave.available_days = 6.0
setattr(available_leave, reset_date_field, next_reset + reset_interval)
available_leave.save()
elif tag_is_intern_or_trainee:
logger.info("Executed intern leave condition at 189 line")
next_reset = joining_date.replace(year=current_date.year, month=current_date.month + 1)
available_leave.available_days = 1.0
setattr(available_leave, reset_date_field, next_reset)
available_leave.save()
elif tag_is_probation and ((total_leave_taken + available_leave.available_days + available_leave.carryforward_days) < 3.0) and not (next_reset >= joining_date + relativedelta(months=3)):
logger.info("Executed Probation leave condition at 196 line(Jan-June)")
available_leave.available_days += 1.0
next_reset = joining_date.replace(year=current_date.year, month=current_date.month + 1)
setattr(available_leave, reset_date_field, next_reset)
available_leave.save()
elif tag_is_probation and (next_reset == joining_date + relativedelta(months=3)) and joining_date.month <= 6:
logger.info("Executed Probation leave condition at 203 line(Jan-June applied)")
available_leave.available_days += 3.0
resetting_date = current_date.replace(year=current_date.year + 1, month=1, day=1)
setattr(available_leave, reset_date_field, resetting_date)
available_leave.save()
elif tag_is_probation and (next_reset >= joining_date + relativedelta(months=3)) and joining_date.month > 6:
logger.info("Executed Probation leave condition at 210 line(July-Dec)")
if (joining_date + relativedelta(month=3)).year == joining_date.year:
resetting_date = current_date.replace(year=current_date.year + 1, month=1, day=1)
setattr(available_leave, reset_date_field, resetting_date)
available_leave.save()
elif (joining_date + relativedelta(month=3)).year > joining_date.year:
available_leave.available_days += ((12 - current_date.month) * 0.5)
if available_leave.available_days > 6:
available_leave.available_days = 6
resetting_date = current_date.replace(year=current_date.year + 1, month=1, day=1)
setattr(available_leave, reset_date_field, resetting_date)
available_leave.save()
available_leave.save()
elif current_date == current_date.replace(year=current_date.year,month=1,day=1) and tag_is_full_time:
if available_leave.leave_type_id == earn_type_id:
resetting_date = current_date.replace(year=current_date.year, month=2, day=15)
setattr(available_leave, reset_date_field, resetting_date)
if available_leave.available_days > 5.0:
available_leave.available_days = 5.0
available_leave.save()
elif not is_leave_type:
available_leave = AvailableLeave(
leave_type_id=leave_type,
employee_id=employee_id,
available_days=leave_type.total_days,
)
if tag_is_intern_or_trainee or tag_is_probation:
next_reset = joining_date.replace(year=current_date.year, month=current_date.month + 1)
setattr(available_leave, reset_date_field, next_reset)
if tag_is_probation:
available_leave.available_days = 1
available_leave.save()
elif tag_is_full_time and available_leave.leave_type_id == earn_type_id:
next_reset = available_leave.assigned_date + timedelta(days=45)
setattr(available_leave, reset_date_field, next_reset)
available_leave.save()
elif tag_is_full_time and available_leave.leave_type_id == casual_type_id:
available_leave.available_days = ((12 - available_leave.assigned_date.month) * 0.5)
next_reset = current_date.replace(year=current_date.year + 1,month=1,day=1)
setattr(available_leave, reset_date_field, next_reset)
available_leave.save()
# custom 45 days leave increment by 1 for full time employee
def increment_earned_leave():
"""
This function finds all full-time employees with Full Time tag and increments their available Earn leave
by 1 for every 45 days.
"""
from base.models import EmployeeType
from employee.models import EmployeeWorkInformation
from leave.models import LeaveType
# Get the Full Time Employee Type
full_time_type_id = EmployeeType.objects.get(employee_type="Full Time")
leave_type_id = LeaveType.objects.get(name="Earn Leave")
logger.info("Earned function executed")
# Get all employees who are full time and have a joining date
employees = EmployeeWorkInformation.objects.filter(employee_type_id=full_time_type_id, date_joining__isnull=False)
for employee_info in employees:
emp_tag = employee_info.tags.filter(title="Full Time").exists()
if emp_tag:
update_leave_for_employee(
employee_info, leave_type_id, timedelta(days=45), "next_earn_leave_reset_date"
)
def fulltime_casual_leave():
"""
This function finds all full-time employees with Full Time tag and increments their available casual leave
by 6 for every year.
"""
from base.models import EmployeeType
from employee.models import EmployeeWorkInformation
from leave.models import LeaveType
# Get the Full Time Employee Type
full_time_type_id = EmployeeType.objects.get(employee_type="Full Time")
leave_type_id = LeaveType.objects.get(name="Casual Leave")
leave_type_id2 = LeaveType.objects.get(name="Intern Casual Leave")
logger.info("Full-time Casual function executed")
# Get all employees who are full time and have a joining date
employees = EmployeeWorkInformation.objects.filter(employee_type_id=full_time_type_id, date_joining__isnull=False)
for employee_info in employees:
emp_tag = employee_info.tags.filter(title="Full Time").exists()
if emp_tag:
delete_leave_type_on_tag_change(employee_info.employee_id,leave_type_id2)
update_leave_for_employee(
employee_info, leave_type_id, relativedelta(years=1), "reset_date"
)
# custom Probation period days leave increment by 0.5 for full time employee who have probation tag
def probation_casual_leave():
"""
This function finds all Full Time employees with Probation tag and increments their available casual leave
by 1 for probation period and than add 3 after their probation period if they lie in (Jan-June) range else only 3 for probation period.
"""
from base.models import EmployeeType
from employee.models import EmployeeWorkInformation
from leave.models import LeaveType
# Get the Full Time Employee Type
full_time_type_id = EmployeeType.objects.get(employee_type="Full Time")
leave_type_id = LeaveType.objects.get(name="Casual Leave")
leave_type_id2 = LeaveType.objects.get(name="Intern Casual Leave")
leave_type_id3 = LeaveType.objects.get(name="Earn Leave")
logger.info("Probation function executed")
# Get all employees who are full time and have a joining date
employees = EmployeeWorkInformation.objects.filter(employee_type_id=full_time_type_id, date_joining__isnull=False)
for employee_info in employees:
emp_tag = employee_info.tags.filter(title="Probation").exists()
if emp_tag:
delete_leave_type_on_tag_change(employee_info.employee_id,leave_type_id2)
delete_leave_type_on_tag_change(employee_info.employee_id,leave_type_id3)
update_leave_for_employee(
employee_info, leave_type_id, relativedelta(months=1), "reset_date"
)
# Custom Intern Casual Leaves Flow Method (same for Trainee)
def intern_casual_leave():
"""
This function will find all Intern & Trainee employees with tag and increments their available Inter Casual leave
by 1 from the date of joining + reset their old balance to 0.
"""
from base.models import EmployeeType
from employee.models import EmployeeWorkInformation
from leave.models import LeaveType
# Get the Full Time Employee Type
intern_type_id = EmployeeType.objects.get(employee_type="Intern")
trainee_type_id = EmployeeType.objects.get(employee_type="Trainee")
leave_type_id = LeaveType.objects.get(name="Intern Casual Leave")
logger.info("Intern function executed")
# Get all employees who are Intern and Trainee
employees = EmployeeWorkInformation.objects.filter( Q(employee_type_id=intern_type_id) | Q(employee_type_id=trainee_type_id),
date_joining__isnull=False )
for employee_info in employees:
emp_tag = employee_info.tags.filter(title="Intern").exists() or employee_info.tags.filter(title="Trainee").exists()
if emp_tag:
update_leave_for_employee(
employee_info, leave_type_id, relativedelta(months=1), "reset_date"
)
if not any(
cmd in sys.argv
for cmd in ["makemigrations", "migrate", "compilemessages", "flush", "shell"]
):
"""
Initializes and starts background tasks using APScheduler when the server is running.
"""
scheduler = BackgroundScheduler()
scheduler.add_job(leave_reset, "interval", seconds=20, max_instances=1)
scheduler.add_job(probation_casual_leave, "interval", hours=5, max_instances=6)
scheduler.add_job(intern_casual_leave, "interval", hours=4, max_instances=6)
scheduler.add_job(auto_approve_leave_requests, "interval", hours=3, max_instances=1)
scheduler.add_job(increment_earned_leave, "interval", hours=7, max_instances=6)
scheduler.add_job(fulltime_casual_leave, "interval", hours=11, max_instances=6)
scheduler.start()