Course: INST326 — Object-Oriented Programming
Section: 0104
Group: 56
Authors: Myles Sartor, Dany Drammeh, Inmar Lizama
Date: November 21, 2024
GitHub Repository: INST326_Project03_56_Group
- Project Overview
- Problem Context
- Features
- Requirements
- Installation and Setup
- How to Run
- Application Layout
- How It Works
- Class Structure and OOP Design
- Scheduling Logic
- Payroll Calculation
- Group Development Workflow
- Limitations and Future Improvements
This project is a desktop GUI application for managing caregiver schedules and payroll, built using Python and Tkinter. It was developed as a group project for INST326 and addresses a real-world scheduling challenge: coordinating multiple caregivers across daily AM and PM shifts, seven days a week. The application allows administrators to add and manage caregivers, set per-caregiver weekly availability preferences, automatically generate a weekly schedule based on those preferences, export the schedule as an HTML file, and produce a scrollable payroll report with weekly and monthly pay totals.
The application was designed in response to a specific real-world need: scheduling caregivers for a 93-year-old individual who requires 12 hours of care per day, divided into two 6-hour shifts. Currently, scheduling was managed manually on a physical monthly calendar that had to be photocopied and distributed. This program digitalizes and automates that process, making it broadly applicable to small businesses, care facilities, clubs, or any organization with recurring shift-based scheduling needs.
Scheduling parameters:
- Care required 7 days a week
- Two shifts per day: AM (7:00 AM to 1:00 PM) and PM (1:00 PM to 7:00 PM)
- Each shift is 6 hours long
- Up to 8 caregivers, some paid and some unpaid (family)
- Availability varies by caregiver and can include exceptions
- Add, update, and delete caregiver records (name, phone, email, pay rate, hours)
- Set per-caregiver weekly availability for each shift using a dropdown menu (Preferred, Available, Unavailable)
- Automatically generate a weekly schedule that prioritizes "Preferred" caregivers before "Available" ones
- Export the generated schedule as an HTML file saved to a user-specified location
- View a scrollable payroll report with individual weekly and monthly pay, plus aggregate totals
- Update individual caregiver hours independently of the schedule generation
- Selectable Listbox for navigating and editing caregiver records
- Entry fields auto-populate when a caregiver is selected from the list
- Python 3.x (3.6+ recommended)
- Standard library only — no external packages required:
tkinter(built-in; on Linux may requiresudo apt-get install python3-tk)calendar(built-in)tkinter.filedialog(built-in, part of tkinter)
- Download or clone the repository from GitHub:
https://github.com/my1e2/INST326_Project03_56_Group - Open the notebook
Project03_56.ipynbin Jupyter Notebook or JupyterLab, or extract the code into a standalone.pyfile. - No external data files are required on first launch.
Open the notebook and run the code cell. The Tkinter window will launch as a separate desktop window titled "Caregiver Manager". The notebook kernel must remain active while the application is running.
To run as a standalone script:
python caregiver_manager.pyThe application entry point uses the standard Python guard:
if __name__ == "__main__":
app = CaregiverManager()
app.run()The main window (900x900 pixels) contains:
+------------------+---------------------------+
| Name: [____] | |
| Phone: [____] | Caregiver Listbox |
| Email: [____] | (selectable, 50x15) |
| Pay Rate:[____] | |
| Hours: [____] | |
+------------------+---------------------------+
| [ Update Caregiver ] |
| [ Delete Caregiver ] |
| [ Set Availability ] |
| [ Generate Schedule ] |
| [ Pay Report ] |
| [ Update Hours ] |
| [ Add Caregiver ] |
+----------------------------------------------+
- Left column: labeled entry fields for caregiver attributes
- Right column: scrollable Listbox showing all caregiver names
- Button column: action buttons that operate on the selected caregiver or the full roster
Selecting a caregiver in the Listbox automatically populates the entry fields with that caregiver's current data, ready for editing.
New caregivers are created by filling in the five entry fields (Name, Phone, Email, Pay Rate, Hours) and clicking "Add Caregiver". A Caregiver object is instantiated and appended to self.caregivers. The Listbox is refreshed and entry fields are cleared.
Selecting a caregiver from the Listbox triggers the add_attributes() method via a <<ListboxSelect>> event binding, which populates all entry fields with that caregiver's current values. Clicking "Update Caregiver" calls caregiver.update_details() to write the new values back to the object. Clicking "Delete Caregiver" removes the caregiver from the list entirely using list.pop().
Clicking "Set Availability" while a caregiver is selected opens a Toplevel child window for that caregiver. The window displays a 7-row grid (one row per day of the week) with two dropdown menus per row (one for the AM shift, one for the PM shift). Each dropdown offers three options:
Preferred— caregiver actively wants this shiftAvailable— caregiver can take the shift if needed (default)Unavailable— caregiver cannot work this shift
Each dropdown is backed by a StringVar initialized to the caregiver's current availability value for that day and shift. Clicking "Save" reads all StringVar values, constructs a 7x2 nested list, and calls caregiver.set_availability() to store it. The window is then closed.
Availability is stored internally as:
self.availability = [["Available"] * 2 for _ in range(7)] # 7 days, 2 shiftsClicking "Generate Schedule" calls generate_schedule(), which:
- Resets all caregiver hours to 0
- Iterates over every day (0–6) and every shift (0 = AM, 1 = PM)
- For each slot, collects all caregivers marked as "Preferred" for that day/shift
- If any preferred caregivers exist, selects the first one
- If none are preferred, selects the first "Available" caregiver
- If neither preferred nor available caregivers exist, the slot is left empty
- Assigns the selected caregiver's name to the schedule slot and increments their hours by 6
if preferred:
selected = preferred[0]
elif available:
selected = available[0]
else:
selected = None
if selected:
schedule[day][shift] = selected.name
selected.hours += 6After the schedule is built, create_html_calendar() is called.
create_html_calendar() constructs an HTML table representing the weekly schedule. Each row corresponds to a day of the week and contains columns for Day, AM Shift, and PM Shift:
<table border='1'>
<tr><th>Day</th><th>AM Shift</th><th>PM Shift</th></tr>
<tr><td>Monday</td><td>CaregiverName</td><td>CaregiverName</td></tr>
...
</table>A filedialog.asksaveasfilename() dialog prompts the user to choose a file name and save location. The HTML is written to the specified path. This file can be opened in any web browser or shared directly with caregivers.
Clicking "Pay Report" opens a new Tk window with a scrollable Text widget. For each caregiver, the report displays:
- Name
- Weekly hours worked
- Weekly gross pay (
hours * pay_rate, rounded to 2 decimal places) - Monthly gross pay (weekly pay multiplied by 4)
Aggregate weekly and monthly totals for all caregivers are appended at the bottom. The text area is set to read-only (state="disabled") after the report is inserted to prevent accidental editing.
The "Update Hours" button allows the administrator to manually override a caregiver's hours without regenerating the full schedule. The selected caregiver's hours field is updated using the value in the "Weekly Hours" entry field, validated with a try/except block to ensure a numeric value is provided.
The base class representing any person in the system:
| Attribute | Type | Description |
|---|---|---|
name |
str | Full name |
phone |
str | Phone number |
email |
str | Email address |
Person.__init__() accepts and stores these three attributes. It serves as the parent class for Caregiver and establishes a reusable identity layer that could be extended to other staff roles.
Inherits from Person and extends it with scheduling and payroll attributes:
| Attribute | Type | Description |
|---|---|---|
pay_rate |
float | Hourly pay rate in USD (default: 20.0) |
hours |
float | Weekly hours worked (used for payroll calculation) |
availability |
list[list] | 7x2 nested list of availability strings per day/shift |
Key methods:
| Method | Description |
|---|---|
update_details() |
Updates name, phone, email, and pay rate in a single call |
set_availability() |
Replaces the full availability matrix with a new 7x2 list |
calculate_weekly_pay() |
Returns self.hours * self.pay_rate (used for payroll) |
Inheritance is used here to demonstrate the OOP principle of specialization: every Caregiver is-a Person, but with additional domain-specific behavior.
The top-level application class that owns the main Tkinter window and all GUI widgets:
| Attribute | Type | Description |
|---|---|---|
master |
tk.Tk | The root window |
caregivers |
list | In-memory list of all Caregiver objects |
name_var |
StringVar | Tkinter variable bound to the Name entry field |
phone_var |
StringVar | Tkinter variable bound to the Phone entry field |
email_var |
StringVar | Tkinter variable bound to the Email entry field |
pay_rate_var |
StringVar | Tkinter variable bound to Pay Rate entry (default: 20.0) |
hours_var |
StringVar | Tkinter variable bound to Hours entry (default: 0) |
caregiver_list |
Listbox | Scrollable widget displaying caregiver names |
This class encapsulates the entire application state and all event handling, following the principle that the GUI layer manages user interaction while delegating data concerns to Person and Caregiver.
The scheduler uses a greedy first-fit algorithm:
- For each of the 14 weekly time slots (7 days x 2 shifts), scan all caregivers
- Collect all whose availability for that slot is "Preferred"; assign the first one found
- If none are preferred, fall back to the first "Available" caregiver
- If no caregiver is available, the slot is assigned an empty string
This is a deterministic, priority-based approach. It does not attempt to balance workloads or avoid scheduling the same caregiver for consecutive shifts. The hours counter is incremented by 6 for each assignment and resets to 0 at the start of every generate_schedule() call.
Pay is calculated as:
Weekly Gross Pay = hours * pay_rate
Monthly Gross Pay = Weekly Gross Pay * 4
This is a simplified estimate that assumes exactly 4 weeks per month. All monetary values are displayed with two decimal places. The calculate_weekly_pay() method on the Caregiver class performs this calculation, although the payroll_report() method in CaregiverManager also computes it inline. Caregivers with a pay rate of 0.0 (unpaid family members) will appear in the report with $0.00 pay values.
This project was developed collaboratively using Git and GitHub:
- One group member (Myles Sartor) hosted the group repository at
https://github.com/my1e2/INST326_Project03_56_Group - Individual branches were created for each group member
- Each member implemented their assigned portion of the application on their branch
- Branches were merged back into
mainupon completion - Iteration and debugging were performed after merging to resolve integration issues
Group members and their areas of contribution are tracked in the GitHub repository's commit and branch history.
- Caregiver data is not persisted between sessions. Adding JSON or SQLite storage for caregiver records and availability would allow the program to be used across multiple sessions without re-entering all data.
- The scheduling algorithm selects the first matching caregiver from the list without considering workload balance. A more sophisticated approach (e.g., round-robin or least-hours-first) would distribute hours more equitably.
- The program does not prevent a single caregiver from being assigned to both shifts on the same day, which may not be desirable in all scheduling contexts.
- Monthly pay is approximated as weekly pay multiplied by 4. A more accurate calculation would account for the actual number of weeks in the given month.
- The HTML calendar displays a single weekly schedule rather than a full monthly calendar. Integrating the Python
calendarmodule (which was imported but not used in the final version) to generate a proper monthly grid would better match the original problem statement. - There is no input validation on the Name, Phone, or Email fields — empty or malformed entries can be submitted.
- The payroll report opens as a new root
Tk()window rather than aToplevelchild window. UsingToplevelwould follow Tkinter best practices and avoid potential issues with having two root windows. - No export option is provided for the payroll report. Adding a "Save as TXT" or "Save as PDF" button would improve usability.