I have the following code to create bulk time off data it gets employee name and info of time off period and type of time off and it writes to an excel file. it gets employee list from the file hr.employee.xlsx which also contains another column called contract_name it has data in form of e.g. 8-8-8-8-8 (start 08:00 - vzw) as you see there are 5 numbers address each day from monday to friday no work, at weekend. it also says start 08:00 which means emploeyee starts at 08 am and his shift ends at 08:00 + 8 = 16:00. i want to implement a feature to my existing code. when an employee is selected it should read this contract_name and should show only the working hours as available hours with 30 min interval for that employee. here is the code: import os
from pathlib import Path
import tkinter as tk
import customtkinter as ctk
from CTkScrollableDropdown import *
from tkinter import ttk
from PIL import ImageTk, Image
from ttkwidgets import CheckboxTreeview
from tkinter import messagebox
from tkcalendar import DateEntry
import random
import string
from datetime import datetime, timedelta
import pandas as pd


# Function to Generate a Random 20-character ID
def generate_random_id():
    return ''.join(random.choices(string.ascii_letters + string.digits, k=20))

# Declare Paths for Future Use
# Get the Downlads Path for Storing the Excel File
downloads_path = str(Path.home() / "Downloads")

# Get the Path for read_me.txt File
help_path=os.path.abspath("")+ "\\read_me.txt"
f = open(help_path, "r")
read_me_text = f.read()

# Get the Path for Excel File Stores Employee Names
name_path = F"{downloads_path}\\hr.employee.xlsx"

# Assign Color Palette Strings
p_blue="#0D3B66"
p_cream="#FAF0CA"
p_yellow_l="#F4D35E"
p_yellow_d="#EE964B"
p_red="#DB3A34"
p_green="#606C38"
p_green_d="#283618"

# Function to Create the Excel File
def create_excel(data):
    # New Dataframe for Fresh Created Time-Off Data
    df_new = pd.DataFrame(data, columns=["id", "employee_id", "holiday_status_id", "date_from", "date_to"])
    # Use Destination Path to Check Whether Previously Created Excel File Exist
    file_path = F"{downloads_path}\\time_off_data.xlsx"
    # Merge Old and New Dataframes by Dropping Duplicates to Avoid Conflict
    if os.path.exists(file_path):
        df_ex = pd.read_excel(file_path)
        df_merge = pd.concat([df_ex, df_new]).drop_duplicates(["employee_id", "holiday_status_id", "date_from", "date_to"])
        df_merge.to_excel(file_path, index=False)
    else:
        df_new.to_excel(file_path, index=False)
    messagebox.showinfo("Success", "Time-Off Data Created!")
    
# Function to Check Weekend Days
def check_weekend(datetime):
    week_days = datetime.strftime("%A") 
    if week_days == "Saturday":
        return False
    if week_days == "Sunday":
        return False
    else:
        return True

# Function to Handle the Submission Process
def submit_data():
    # Pass the values from user's inputs
    name = entry.get()
    if not name:
        messagebox.showerror("Error", "Please select an employee!")
        return
        
    time_off_type = time_off_option.get()
    start_date = f"{cal_start.get()} {start_hour_option.get()}" 
    end_date = f"{cal_end.get()} {end_hour_option.get()}"

    # Set error messageboxes for faulty inputs
    if not name or not time_off_type or not start_date or not end_date:
        messagebox.showerror("Error", "All fields must be filled!")
        return

    if end_date<start_date:
        messagebox.showerror("Error", "End Date can't be set earlier than Start Date")
        return

    try:
        start_dt = datetime.strptime(start_date, "%Y-%m-%d %H:%M")
        end_dt = datetime.strptime(end_date, "%Y-%m-%d %H:%M")
    except ValueError:
        messagebox.showerror("Error", "Please enter valid dates in YYYY-MM-DD HH:MM format!")
        return

    # Apply weekly option
    if radio_var.get()==2:
        end_recurring_date = cal_recurring.get()
        if not end_recurring_date:
            messagebox.showerror("Error", "Please provide the recurring end date!")
            return
        try:
            recurring_end_dt = datetime.strptime(end_recurring_date, "%Y-%m-%d")
        except ValueError:
            messagebox.showerror("Error", "Please enter a valid recurring end date in YYYY-MM-DD format!")
            return

        data = []
        current_start = start_dt
        current_end = end_dt

        while current_start.date()<= recurring_end_dt.date():#current_start <= recurring_end_dt:
            random_id = generate_random_id()
            data.append([random_id, name, time_off_type, current_start, current_end])
            current_start += timedelta(weeks=1)
            current_end += timedelta(weeks=1)
        show_confirmation_window(data, root)
        
     # Apply daily option   
    if radio_var.get()==3:
        end_recurring_date = cal_recurring.get()
        if not end_recurring_date:
            messagebox.showerror("Error", "Please provide the recurring end date!")
            return
        try:
            recurring_end_dt = datetime.strptime(end_recurring_date, "%Y-%m-%d")
        except ValueError:
            messagebox.showerror("Error", "Please enter a valid recurring end date in YYYY-MM-DD format!")
            return

        data = []
        current_start = start_dt
        current_end = end_dt

        while current_start.date()<= recurring_end_dt.date():
            random_id = generate_random_id()
            if check_weekend(current_start):
                data.append([random_id, name, time_off_type, current_start, current_end])
            current_start += timedelta(days=1)
            current_end += timedelta(days=1)
        show_confirmation_window(data, root)
        
    # Apply once option
    if radio_var.get()==1:
        random_id = generate_random_id()
        data = [[random_id, name, time_off_type, start_dt, end_dt]]
        show_confirmation_window(data, root)
   
def show_confirmation_window(data, root, existing_top=None, existing_table=None, existing_check_vars=None):
    # Function to add another employee
    def add_another_employee():
        # Reset the live search bar
        new_employee = entry.get()
        if not new_employee:
            messagebox.showerror("Error", "Please select an employee!")
            return

        checked_data = [row for i, row in enumerate(data) if check_vars[i].get()]
        
        # Copy the selections and add new employee data
        new_data = []
        for row in checked_data:
            random_id = generate_random_id()
            new_data.append([random_id, new_employee, row[2], row[3], row[4]])

        combined_data = checked_data + new_data
        # combined_data = pd.concat([checked_data, new_data]).drop_duplicates(["employee_id", "holiday_status_id", "date_from", "date_to"])

         # Remove duplicates based on Name, Type, Start, and End (excluding ID)
        unique_combined_data = {}
        for item in combined_data:
            key = (item[1], item[2], item[3], item[4])  # Tuple of Name, Type, Start, End
            unique_combined_data[key] = item

        # Dict.values() extracts unique rows
        unique_combined_data = list(unique_combined_data.values())

        # Destroy the existing confirmation window
        top.destroy()

        # Create a new window with updated data
        show_confirmation_window(unique_combined_data, root)

    # Check if we are updating an existing window
    if existing_top and existing_table and existing_check_vars:
        top = existing_top
        table = existing_table
        check_vars = existing_check_vars
    else:
        # Get master window position
        root_x = root.winfo_rootx()
        root_y = root.winfo_rooty()
        # Add offset
        win_x = root_x + 568
        win_y = root_y - 31

        # Toplevel Window to Display Time off Data List
        top = ctk.CTkToplevel(root)
        top.wm_iconbitmap()
        top.after(300, lambda: top.iconphoto(False, root.iconpath))
        top.geometry("950x500" + f'+{win_x}+{win_y}')
        top.title("Confirm Time-Off Entries")

        # Frame to Contain Treeview Widget
        frame = ctk.CTkFrame(top)
        frame.pack(fill="both", expand=True, padx=20)  #, pady=15

        # Style for Column Headings
        style = ttk.Style(top)
        style.theme_use("alt")
        style.configure("Treeview", foreground=p_green_d, background=p_cream, fieldbackground=p_cream, font=("Bahnschrift", 11))
        style.configure("Treeview.Heading", background=p_green, foreground=p_cream, font=("Bahnschrift", 13), hover=False)

        # Table to display rows (without ID in columns but still accessible in the data)
        table = CheckboxTreeview(frame, columns=("Name", "Type", "Start", "End"))

        # Set the headings without showing the "ID"
        table.heading("Name", text="Employer Name")
        table.heading("Type", text="Type of Time Off")
        table.heading("Start", text="Start Date & Time")
        table.heading("End", text="End Date & Time")

        check_vars = []

        # Label to host widgets for adding new employee
        label_add_entry = ctk.CTkLabel(top)
        # label_add_entry.pack(padx=15, pady=15)
        label_add_entry.pack(padx=20, pady=15, side="top") #, side="bottom"
        
        # Entry Box Widget Combined with Scrollable Dropdown Widget
        entry = ctk.CTkEntry(master=label_add_entry, width=290, fg_color=p_cream, text_color=p_green_d, font=("Bahnschrift", 15))
        entry.grid(row=0, column=0, padx=2) #, padx=10
        
        CTkScrollableDropdown(entry, values=name_list, command=lambda e: (entry.delete(0, 'end'), entry.insert(0, e)),
                              fg_color=p_cream, text_color=p_cream, hover_color=p_green, autocomplete=True, font=("Bahnschrift", 12, "bold"))
        
        # Add Another Employee button
        add_employee_button = ctk.CTkButton(master=label_add_entry, text="Apply to an Another Employee", command=add_another_employee, width=290, fg_color=p_green,
                                            hover_color=p_red, text_color=p_cream)
        add_employee_button.configure(font=("Bahnschrift", 15, "bold"))
        add_employee_button.grid(row=0, column=1, padx=2) #, padx=10

        # Confirmation button
        confirm_button = ctk.CTkButton(master=label_add_entry, text="Confirm & Save", command=lambda: [save_confirmed_rows(data, check_vars), top.destroy()], fg_color=p_green,
                                       hover_color=p_red, text_color=p_cream, width=290)
        confirm_button.configure(font=("Bahnschrift", 15, "bold"))
        # confirm_button.pack(pady=15)
        confirm_button.grid(row=0, column=2, padx=2)

    # Add data to the table without displaying the "ID" column
    for i, row in enumerate(data):
        check_var = tk.BooleanVar(value=True)
        check_vars.append(check_var)
        table.insert("", "end", values=(row[1], row[2], row[3], row[4]), tags=(f"row{i}",))
        table.tag_bind(f"row{i}", "<<TreeviewSelect>>", lambda e, var=check_var: var.set(not var.get()))
        table.check_all()
        if (i % 2) == 0: 
            table.tag_configure(f"row{i}", background=p_yellow_l)
        else:
            table.tag_configure(f"row{i}", background=p_yellow_d)

    table.column("# 0", width=50)
    table.pack(expand=True, fill='both', padx=10, pady=10)

# This function saves only the confirmed rows
def save_confirmed_rows(data, check_vars):
    # Filter rows based on checked boxes
    confirmed_rows = [row for i, row in enumerate(data) if check_vars[i].get()]
    create_excel(confirmed_rows)



    
# Main GUI creation
if __name__ == "__main__":
    # Initialize the GUI
    ctk.set_appearance_mode("dark")
    ctk.set_default_color_theme("dark-blue")
    root = ctk.CTk()
    root.iconpath = ImageTk.PhotoImage(file=os.path.abspath("")+"\\image2nd.ico")
    root.wm_iconbitmap()
    root.iconphoto(False, root.iconpath)
    root.title("Bulk Time-Off by M.Cetin")
    root.geometry("575x350")
    root.resizable(False, False)
    
    # Employee Name Live Search
    # Array for Employee Names
    df_name = pd.read_excel(name_path)
    name_list = df_name['name'].to_numpy()
    # Label for Widget
    entry_name = tk.StringVar(value="Employee Name")
    label_name=ctk.CTkLabel(root, text="Employee Search", text_color=p_cream)
    label_name.configure(font=("Bahnschrift", 15, "bold"))
    label_name.grid(row = 0, column = 0, padx=10, pady=10, sticky = "w")
    
    # # Entry Box Widget Combined with Scrollable Dropdown Widget
    entry = ctk.CTkEntry(root,textvariable=entry_name, width=240, fg_color=p_cream, text_color=p_green_d, font=("Bahnschrift", 15))
    entry.grid(row = 0, column = 1, padx=10, pady=10)

    CTkScrollableDropdown(entry, values=name_list, command=lambda e: (entry.delete(0, 'end'), entry.insert(0, e)),  # Clear and insert
                        fg_color=p_cream, text_color=p_cream, hover_color=p_green, autocomplete=True, font=("Bahnschrift", 12, "bold"))

    # Time Off Type Selection
    time_off_type_values=["Geboorteverlof", "Familiaal verlof", "Feestdag", "Moederschapverlof", "Opleiding", "Ouderscapverlof",
                          "Recuperatie overuren", "Schoolvakantie", "Toegestaan afwezig", "Verlofaanvraag", "Ziektemelding", "Ziekteverlof"]
    # Label for Widget
    label_time_off_type = ctk.CTkLabel(root, text="Type of Time-Off:", text_color=p_cream)
    label_time_off_type.configure(font=("Bahnschrift", 15, "bold"))
    label_time_off_type.grid(row = 1, column = 0, sticky = "w", padx=10, pady=10)
    
    # Option Menu for Time off Selection
    time_off_option = tk.StringVar(value="Opleiding")
    time_off_menu = ctk.CTkOptionMenu(root,variable=time_off_option, width=240, values=time_off_type_values, dropdown_fg_color=p_yellow_l, fg_color=p_yellow_l,
                                      button_color=p_yellow_d, hover=True, button_hover_color=p_green, dropdown_text_color=p_green_d, 
                                      dropdown_hover_color=p_yellow_d, text_color=p_green_d)
    time_off_menu.configure(font=("Bahnschrift", 15, "bold"), dropdown_font=("Bahnschrift", 15, "bold"))
    time_off_menu.grid(row = 1, column = 1, sticky = "w", padx=10, pady=10)

    # Create Custom Style for DateEntry Widgets
    style = ttk.Style(root)
    style.theme_use("alt")   # Theme to be changed alt , classic, clam
    style.configure("cal.DateEntry", foreground=p_cream, fieldbackground=p_green, background=p_green_d,  buttoncolor=p_green, arrowcolor=p_cream, font=("Bahnschrift", 15))

    # Available Hour Options
    hour_values=["06:00", "06:30", "07:00", "07:30", "08:00", "08:30", "09:00", "09:30", "10:00", "10:30", "11:00", "11:30", "12:00",
              "12:30", "13:00", "13:30", "14:00", "14:30", "15:00", "15:30", "16:00", "16:30", "17:00", "17:30", "18:00", "18:30"]

    # Start Date Input
    # Label for Widget
    label_start_date = ctk.CTkLabel(root, text="Start Date", text_color=p_cream)
    label_start_date.configure(font=("Bahnschrift", 15, "bold"))
    label_start_date.grid(row = 2, column = 0, sticky = "w", padx=10, pady=10) 
    # DateEntry for Calender to Pick Start Date
    cal_start = DateEntry(root,style="cal.DateEntry", background=p_green_d, headersbackground =p_green, headersforeground=p_cream, normalbackground=p_cream, 
                          othermonthwebackground=p_yellow_d, weekendbackground=p_yellow_d, othermonthbackground=p_yellow_l, date_pattern="yyyy-mm-dd",
                         selectbackground=p_red)
    cal_start.grid(row = 2, column = 1, padx=10, pady=10)
    # Option Menu for Hour of Start Date
    start_hour_option = tk.StringVar(value="08:00")
    start_hour_menu = ctk.CTkOptionMenu(root, variable=start_hour_option, values=hour_values, dropdown_fg_color=p_yellow_l, fg_color=p_yellow_l,
                                      button_color=p_yellow_d, hover=True, button_hover_color=p_green, dropdown_text_color=p_green_d, 
                                      dropdown_hover_color=p_yellow_d, text_color=p_green_d)
    start_hour_menu.configure(font=("Bahnschrift", 15, "bold"), dropdown_font=("Bahnschrift", 15, "bold"))
    start_hour_menu.grid(row = 2, column = 2, sticky = "w", padx=10, pady=10)

    # End Date Input
    # Label for Widget
    label_end_date = ctk.CTkLabel(root, text="End Date", text_color=p_cream)
    label_end_date.configure(font=("Bahnschrift", 15, "bold"))
    label_end_date.grid(row = 3, column = 0, sticky = "w", padx=10, pady=10) 
    # DateEntry for Calender to Pick End Date
    cal_end = DateEntry(root,style="cal.DateEntry", background=p_green_d, headersbackground =p_green, headersforeground=p_cream, normalbackground=p_cream, 
                          othermonthwebackground=p_yellow_d, weekendbackground=p_yellow_d, othermonthbackground=p_yellow_l, date_pattern="yyyy-mm-dd",
                         selectbackground=p_red)
    cal_end.grid(row = 3, column = 1, padx=10, pady=10) 
    # Option Menu for Hour of End Date
    end_hour_option = tk.StringVar(value="17:00")
    end_hour_menu = ctk.CTkOptionMenu(root, variable=end_hour_option, values=hour_values, dropdown_fg_color=p_yellow_l, fg_color=p_yellow_l,
                                      button_color=p_yellow_d, hover=True, button_hover_color=p_green, dropdown_text_color=p_green_d, 
                                      dropdown_hover_color=p_yellow_d, text_color=p_green_d)
    end_hour_menu.configure(font=("Bahnschrift", 15, "bold"), dropdown_font=("Bahnschrift", 15, "bold"))
    end_hour_menu.grid(row = 3, column = 2, sticky = "w", padx=10, pady=10)

    # Radiobuttons for Selecting Recurrency Option
    radio_var = tk.IntVar(value=1)
    radiobutton_1 = ctk.CTkRadioButton(root, text="Apply once", variable= radio_var, value=1, hover=True, hover_color=p_red,
                                        border_color=p_green, fg_color=p_red, text_color=p_cream, text_color_disabled=p_green,
                                        border_width_checked=5, border_width_unchecked=3, radiobutton_width=15, radiobutton_height=15) 
    radiobutton_2 = ctk.CTkRadioButton(root, text="Apply for each week", variable= radio_var, value=2, hover=True, hover_color=p_red,
                                        border_color=p_green, fg_color=p_red, text_color=p_cream, text_color_disabled=p_green,
                                        border_width_checked=5, border_width_unchecked=3, radiobutton_width=15, radiobutton_height=15)
    radiobutton_3 = ctk.CTkRadioButton(root, text="Apply for each day", variable= radio_var, value=3, hover=True, hover_color=p_red,
                                        border_color=p_green, fg_color=p_red, text_color=p_cream, text_color_disabled=p_green,
                                        border_width_checked=5, border_width_unchecked=3, radiobutton_width=15, radiobutton_height=15)
    radiobutton_1.configure(font=("Bahnschrift", 15, "bold"))
    radiobutton_2.configure(font=("Bahnschrift", 15, "bold"))
    radiobutton_3.configure(font=("Bahnschrift", 15, "bold"))
    radiobutton_1.grid(row = 4, column = 0, padx=10, pady=10)
    radiobutton_2.grid(row = 4, column = 1, padx=10, pady=10)
    radiobutton_3.grid(row = 4, column = 2, padx=10, pady=10)

    # End Date for Recurring Option
    # Label for Widget
    label_end_recurring_date = ctk.CTkLabel(root, text="End Recurring Date", text_color=p_cream)
    label_end_recurring_date.configure(font=("Bahnschrift", 15, "bold"))
    label_end_recurring_date.grid(row = 5, column = 0, sticky = "w", padx=10, pady=10)
    # DateEntry for Calender to Pick Recurring Date
    cal_recurring = DateEntry(root,style="cal.DateEntry", background=p_green_d, headersbackground =p_green, headersforeground=p_cream, normalbackground=p_cream, 
                          othermonthwebackground=p_yellow_d, weekendbackground=p_yellow_d, othermonthbackground=p_yellow_l, date_pattern="yyyy-mm-dd",
                         selectbackground=p_red)
    cal_recurring.grid(row = 5, column = 1, padx=10, pady=10)
 
    # Toplevel Window to Project read_me.txt File
    def read_me_top():
        #Get master window position
        root_x = root.winfo_rootx()
        root_y = root.winfo_rooty()    
        # add offset
        win_x = root_x - 9
        win_y = root_y + 351
        #Create the window
        top = ctk.CTkToplevel()
        top.wm_iconbitmap()
        top.after(200, lambda: top.iconphoto(False, root.iconpath))
        top.title("READ ME")
        top.geometry("575x200"+f'+{win_x}+{win_y}')
        top.resizable(False, False)
        top.attributes('-topmost', True)

        # Scrollable Frame for the Text
        s_frame = ctk.CTkScrollableFrame(top, scrollbar_button_color=p_green)
        s_frame.pack(fill="both", expand=True, padx=5, pady=5)

        # Label Inside the Frame to Project read_me.txt File
        label_read = ctk.CTkLabel(s_frame,text=str(read_me_text), corner_radius=3, fg_color=p_cream,text_color=p_green_d, wraplength=500)
        label_read.configure(font=("Bahnschrift", 15), justify="left")
        label_read.pack(expand=True, fill="both", padx=5, pady=5)

    # Button for Toplevel READ ME Event
    button_help = ctk.CTkButton(root, text="?",corner_radius=10, fg_color=p_red, text_color=p_cream, width=30, command=read_me_top)
    button_help.configure(font=("Bahnschrift", 15, "bold"))
    button_help.grid(row = 6, column = 0, padx=10, pady=10, sticky = "w")

    # Submit Button
    submit_button = ctk.CTkButton(root, text="Create Time-Off Data", command=submit_data, corner_radius=10, fg_color = p_blue, text_color=p_cream, hover_color=p_red)
    submit_button.configure(font=("Bahnschrift", 15, "bold"))
    submit_button.grid(row = 6, column = 1, padx=10, pady=10)
   
    root.mainloop()