[FIX] LEAVE: #779

This commit is contained in:
Horilla
2025-09-18 10:58:57 +05:30
parent 2edf95e105
commit aa1a288dd7
2 changed files with 94 additions and 35 deletions

View File

@@ -1,6 +1,7 @@
import calendar
from datetime import datetime, timedelta
from datetime import date, datetime, timedelta
import pandas as pd
from django.apps import apps
from django.db.models import Q
@@ -158,3 +159,41 @@ def filter_conditional_leave_request(request):
else:
leave_request_ids.append(instance.leave_request_id.id)
return LeaveRequest.objects.filter(pk__in=leave_request_ids)
def parse_excel_date(value):
"""
Convert Excel date values into a valid Python date object.
Supports multiple formats: YYYY-MM-DD, DD-MM-YYYY, DD Month YYYY, MM/DD/YYYY, etc.
"""
if not value or pd.isna(value):
return None
if isinstance(value, date):
# Already a date (from Excel or pandas)
return value
if isinstance(value, datetime):
# Datetime object → convert to date
return value.date()
if isinstance(value, str):
value = value.strip()
# Try multiple formats
date_formats = [
"%Y-%m-%d", # 2025-07-22
"%d-%m-%Y", # 22-07-2025
"%d/%m/%Y", # 22/07/2025
"%m/%d/%Y", # 07/22/2025
"%d %B %Y", # 22 July 2025
"%d %B, %Y", # 22 July, 2025
"%d-%b-%Y", # 22-Jul-2025
]
for fmt in date_formats:
try:
return datetime.strptime(value, fmt).date()
except ValueError:
continue
# If nothing matches, return None (caller should handle error)
return None

View File

@@ -60,6 +60,7 @@ from leave.methods import (
company_leave_dates_list,
filter_conditional_leave_request,
holiday_dates_list,
parse_excel_date,
)
from leave.models import *
from leave.models import leave_requested_dates
@@ -1776,6 +1777,10 @@ def assign_leave_type_excel(_request):
columns = [
"Employee Badge ID",
"Leave Type",
"Available Days", # 779
"Carryforward Days",
"Total Leave Days",
"Assigned Date",
]
data_frame = pd.DataFrame(columns=columns)
response = HttpResponse(content_type="application/ms-excel")
@@ -1801,9 +1806,9 @@ def assign_leave_type_import(request):
"Leave Type": [],
"Badge ID Error": [],
"Leave Type Error": [],
"Assigned Error": [],
"Available Days": [],
"Carry Forward Days": [],
"Assigned Date Error": [],
"Other Errors": [],
}
@@ -1817,62 +1822,77 @@ def assign_leave_type_import(request):
emp.badge_id.lower(): emp for emp in Employee.objects.all() if emp.badge_id
}
leave_types = {lt.name.lower(): lt for lt in LeaveType.objects.all()}
available_leaves = {
existing = {
(al.leave_type_id.id, al.employee_id.id): al
for al in AvailableLeave.objects.all()
}
assign_leave_list = []
error_list = []
assign_leave_list, error_list = [], []
for assign_leave in assign_leave_dicts:
badge_id = assign_leave.get("Employee Badge ID", "").strip().lower()
assign_leave_type = assign_leave.get("Leave Type", "").strip().lower()
available_days = assign_leave.get("Available Days", "0")
cfd = assign_leave.get("Carry Forward Days", "0")
for row in assign_leave_dicts:
badge_id = str(row.get("Employee Badge ID", "")).strip().lower()
leave_type_name = str(row.get("Leave Type", "")).strip().lower()
employee = employees.get(badge_id)
leave_type = leave_types.get(assign_leave_type)
leave_type = leave_types.get(leave_type_name)
errors = []
if employee is None:
errors.append(_("This badge id does not exist."))
if leave_type is None:
errors.append(_("This leave type does not exist."))
if errors:
assign_leave[
"Badge ID Error" if "badge id" in errors[0] else "Leave Type Error"
] = " ".join(force_str(error) for error in errors)
error_list.append(assign_leave)
if not employee:
row["Badge ID Error"] = _("This badge id does not exist.")
error_list.append(row)
continue
if not leave_type:
row["Leave Type Error"] = _("This leave type does not exist.")
error_list.append(row)
continue
# Check if leave type has already been assigned to the employee
if (leave_type.id, employee.id) in available_leaves:
assign_leave["Assigned Error"] = _(
if (leave_type.id, employee.id) in existing:
row["Assigned Error"] = _(
"Leave type has already been assigned to the employee."
)
error_list.append(assign_leave)
error_list.append(row)
continue
# If no errors, create the AvailableLeave instance
if available_days == 0:
# Extract optional fields # 779
available_days = row.get("Available Days")
carryforward_days = row.get("Carryforward Days")
total_leave_days = row.get("Total Leave Days")
assigned_date_raw = row.get("Assigned Date")
# Apply defaults when missing
if pd.isna(available_days) or available_days == "":
available_days = leave_type.total_days
if pd.isna(carryforward_days) or carryforward_days == "":
carryforward_days = 0
if pd.isna(total_leave_days) or total_leave_days == "":
total_leave_days = available_days + carryforward_days
assigned_date = parse_excel_date(assigned_date_raw) or (
timezone.now().date()
if isinstance(assigned_date_raw, float)
and math.isnan(assigned_date_raw)
else None
)
if not assigned_date:
row["Other Errors"] = _(
"Invalid date format. Please use YYYY-MM-DD or a supported format."
)
error_list.append(row)
continue
available_leave = AvailableLeave(
leave_type_id=leave_type,
employee_id=employee,
available_days=available_days,
available_days=float(available_days),
carryforward_days=float(carryforward_days),
total_leave_days=float(total_leave_days),
assigned_date=assigned_date,
)
if cfd:
available_leave.carryforward_days = cfd
if carryforward_days:
available_leave.expired_date = leave_type.carryforward_expire_date
try:
available_leave.reset_date = leave_type.leave_type_next_reset_date()
except:
except Exception:
pass
available_leave.assigned_date = datetime.today()
available_leave.total_leave_days = (
available_leave.carryforward_days + available_leave.available_days
)
assign_leave_list.append(available_leave)
# Bulk create available leaves