Spaces:
Paused
Paused
from datetime import datetime, timedelta, date | |
import pandas as pd | |
from factory.data.generators import earliest_monday_on_or_after | |
from constraint_solvers.timetable.working_hours import ( | |
SLOTS_PER_WORKING_DAY, | |
MORNING_SLOTS, | |
slot_to_datetime, | |
) | |
def schedule_to_dataframe(schedule) -> pd.DataFrame: | |
""" | |
Convert an EmployeeSchedule to a pandas DataFrame. | |
Args: | |
schedule (EmployeeSchedule): The schedule to convert. | |
Returns: | |
pd.DataFrame: The converted DataFrame. | |
""" | |
data: list[dict[str, str]] = [] | |
# Get base date from schedule info if available | |
base_date = None | |
if hasattr(schedule, "schedule_info"): | |
if hasattr(schedule.schedule_info, "base_date"): | |
base_date = schedule.schedule_info.base_date | |
# Process each task in the schedule | |
for task in schedule.tasks: | |
# Get employee name or "Unassigned" if no employee assigned | |
employee: str = task.employee.name if task.employee else "Unassigned" | |
# Calculate start and end times (naive local time) | |
start_time: datetime = slot_to_datetime(task.start_slot, base_date) | |
end_time: datetime = slot_to_datetime( | |
task.start_slot + task.duration_slots, base_date | |
) | |
# Add task data to list with availability flags | |
data.append( | |
{ | |
"Project": getattr(task, "project_id", ""), | |
"Sequence": getattr(task, "sequence_number", 0), | |
"Employee": employee, | |
"Task": task.description, | |
"Start": start_time, | |
"End": end_time, | |
"Duration (hours)": task.duration_slots / 2, # Convert slots to hours | |
"Required Skill": task.required_skill, | |
"Pinned": getattr(task, "pinned", False), # Include pinned status | |
# Check if task falls on employee's unavailable date | |
"Unavailable": employee != "Unassigned" | |
and hasattr(task.employee, "unavailable_dates") | |
and start_time.date() in task.employee.unavailable_dates, | |
# Check if task falls on employee's undesired date | |
"Undesired": employee != "Unassigned" | |
and hasattr(task.employee, "undesired_dates") | |
and start_time.date() in task.employee.undesired_dates, | |
# Check if task falls on employee's desired date | |
"Desired": employee != "Unassigned" | |
and hasattr(task.employee, "desired_dates") | |
and start_time.date() in task.employee.desired_dates, | |
} | |
) | |
return pd.DataFrame(data) | |
def employees_to_dataframe(schedule) -> pd.DataFrame: | |
""" | |
Convert an EmployeeSchedule to a pandas DataFrame. | |
Args: | |
schedule (EmployeeSchedule): The schedule to convert. | |
""" | |
def format_dates(dates_list, max_display=3): | |
"""Helper function to format dates for display""" | |
if not dates_list: | |
return "None" | |
try: | |
sorted_dates = sorted(dates_list) | |
if len(sorted_dates) <= max_display: | |
return ", ".join(d.strftime("%m/%d") for d in sorted_dates) | |
else: | |
displayed = ", ".join( | |
d.strftime("%m/%d") for d in sorted_dates[:max_display] | |
) | |
return f"{displayed} (+{len(sorted_dates) - max_display} more)" | |
except Exception: | |
return f"{len(dates_list)} dates" | |
data: list[dict[str, str]] = [] | |
for emp in schedule.employees: | |
try: | |
first, last = emp.name.split(" ", 1) if " " in emp.name else (emp.name, "") | |
# Safely get preference dates with fallback to empty sets | |
unavailable_dates = getattr(emp, "unavailable_dates", set()) | |
undesired_dates = getattr(emp, "undesired_dates", set()) | |
desired_dates = getattr(emp, "desired_dates", set()) | |
data.append( | |
{ | |
"First Name": first, | |
"Last Name": last, | |
"Skills": ", ".join(sorted(emp.skills)), | |
"Unavailable Dates": format_dates(unavailable_dates), | |
"Undesired Dates": format_dates(undesired_dates), | |
"Desired Dates": format_dates(desired_dates), | |
"Total Preferences": f"{len(unavailable_dates)} unavailable, {len(undesired_dates)} undesired, {len(desired_dates)} desired", | |
} | |
) | |
except Exception as e: | |
# Fallback for any employee that causes issues | |
data.append( | |
{ | |
"First Name": str(emp.name), | |
"Last Name": "", | |
"Skills": ", ".join(sorted(getattr(emp, "skills", []))), | |
"Unavailable Dates": "Error loading", | |
"Undesired Dates": "Error loading", | |
"Desired Dates": "Error loading", | |
"Total Preferences": "Error loading preferences", | |
} | |
) | |
return pd.DataFrame(data) | |