import pandas as pd import json from openpyxl import load_workbook from send_email import send_email from filelock import FileLock import datetime """ TODO make it work with the new template TODO update names to be more clear TODO try to remove pandas """ def ReadDatabase(): """ Reads the Database to retrieve available interview slots ``REQUIRES``: None ``PROMISES``: JSON (Available interview slots) ``Developed by``: Ahmad, Brock ``Contact``: ahmad.ahmad1@ucalgary.ca, darkicewolf50@gmail.com """ year_donation = int(str(datetime.datetime.now().year)[2:]) + 1 # gets the last two digits of the current year then adds 1 for the current season # name based off the 2025 naming system file_path = f"OR{year_donation}-L-Interview Data.xlsx" lock_path = f"OR{year_donation}-L-Interview Data.xlsx.lock" # Use a file-based lock for thread-safe and process-safe access with FileLock(lock_path): # Load the Excel file into a pandas DataFrame with specific columns df = pd.read_excel(file_path, usecols=['Date', 'Start Time', 'Slot', 'Interviewee Name', 'Interviewee Email', 'Meeting Duration']) # Initialize the dictionary to store structured data for available slots interview_data = {} # Process each row in the DataFrame to structure data by date and time for _, row in df.iterrows(): # Convert Date and Start Time to string format for easier comparison date = str(row['Date']).split(" ")[0] # Format date to YYYY-MM-DD start_time = str(row['Start Time']) # Calculate the slot capacity and current number of interviewees slot_capacity = int(row['Slot']) if not pd.isna(row['Slot']) else 0 interviewee_names = [name.strip() for name in str(row['Interviewee Name']).split(',') if name.strip()] interviewee_count = len(interviewee_names) if interviewee_names != ["nan"] else 0 # Check if there are available slots for more interviewees if interviewee_count < slot_capacity: # Organize data by date and time, keeping track of available slots and meeting duration if date not in interview_data: interview_data[date] = {} interview_data[date][start_time] = { 'Meeting Duration': row['Meeting Duration'], 'Available Slots': slot_capacity - interviewee_count } return interview_data def AppendAppointment(date, start_time, interviewee_name, interviewee_email): """ Appends a new appointment with the interviewee's name and email if the slot is available. ``REQUIRES``: ``str`` date, ``str`` start_time, ``str`` interviewee_name, ``str`` interviewee_email ``PROMISES``: ``None`` Updates the Excel file with the new interviewee's name and email if there is an available slot. Returns Bool. ``Developed by``: Ahmad, Brock ``Contact``: ahmad.ahmad1@ucalgary.ca, darkicewolf50@gmail.com """ year_donation = int(str(datetime.datetime.now().year)[2:]) + 1 # gets the last two digits of the current year then adds 1 for the current season # name based off the 2025 naming system file_path = f"OR{year_donation}-L-Interview Data.xlsx" lock_path = f"OR{year_donation}-L-Interview Data.xlsx.lock" available_slots = ReadDatabase() # Check if the requested slot is available in the `available_slots` structure if date in available_slots and start_time in available_slots[date]: with FileLock(lock_path): # Ensure process-safe access to the file # Load workbook and select "Sheet1" for updating appointments workbook = load_workbook(file_path) sheet = workbook["Interview Timetable"] df = pd.read_excel(file_path) # Find and update the row that matches the provided date and start time for index, row in df.iterrows(): row_date = str(row['Date']).split(" ")[0] row_start_time = str(row['Start Time']) if row_date == date and row_start_time == start_time: # Current entries for names and emails, and append new data with comma and space current_names = str(row['Interviewee Name']).strip() current_emails = str(row['Interviewee Email']).strip() updated_names = f"{current_names}, {interviewee_name}" if current_names != "nan" else interviewee_name updated_emails = f"{current_emails}, {interviewee_email}" if current_emails != "nan" else interviewee_email # Update the cells with new names and emails name_cell = sheet.cell(row=index + 2, column=df.columns.get_loc('Interviewee Name') + 1) email_cell = sheet.cell(row=index + 2, column=df.columns.get_loc('Interviewee Email') + 1) name_cell.value = updated_names email_cell.value = updated_emails workbook.save(file_path) send_email(interviewee_email, interviewee_name, date, start_time) return True # If no slots available, return that the slot is unavailable return False def run_tests(): """ Executes test cases to verify appointment scheduling and slot availability. ``REQUIRES``: None ``PROMISES``: Prints test outcomes to validate successful booking or slot unavailability. """ print("Available Slots:") available_slots = ReadDatabase() print(json.dumps(available_slots, indent=4)) # Test Case 1: Append to an available slot on 2024-09-16 at 10:30:00 date_1 = "2024-09-16" start_time_1 = "10:30:00" interviewee_name_1 = "Alice Johnson" interviewee_email_1 = "ahmadmuhammadofficial@gmail.com" print(f"\nTest Case 1: Trying to book {date_1} at {start_time_1} for {interviewee_name_1} ({interviewee_email_1})") AppendAppointment(date_1, start_time_1, interviewee_name_1, interviewee_email_1) # Test Case 2: Append to an available slot on 2024-09-17 at 13:30:00 date_2 = "2024-09-17" start_time_2 = "13:30:00" interviewee_name_2 = "Bob Smith" interviewee_email_2 = "bob.smith@example.com" print(f"\nTest Case 2: Trying to book {date_2} at {start_time_2} for {interviewee_name_2} ({interviewee_email_2})") AppendAppointment(date_2, start_time_2, interviewee_name_2, interviewee_email_2) # Test Case 3: Attempting to book at 10:30:00 on 2024-09-16 for a different interviewee date_3 = "2024-09-16" start_time_3 = "10:30:00" interviewee_name_3 = "Charlie Brown" interviewee_email_3 = "charlie.brown@example.com" print(f"\nTest Case 3: Trying to book {date_3} at {start_time_3} for {interviewee_name_3} ({interviewee_email_3})") AppendAppointment(date_3, start_time_3, interviewee_name_3, interviewee_email_3) # Run tests if __name__ == "__main__": run_tests()