EduPlan Pro: Automated Timetable Software
EduPlan Pro: Automated Timetable Software
PROBLEM STATEMENT:
Creating and managing school timetables manually is a highly complex
and time-consuming task that involves coordinating multiple constraints such as teacher
availability, class schedules, subject requirements, and room assignments. Manual
scheduling often leads to conflicts like overlapping periods, teacher overload, or
unbalanced workloads, making it inefficient and prone to human error. Additionally,
handling changes such as teacher absences or special events requires significant manual
adjustment, further increasing administrative workload. Therefore, there is a need for
an automated timetable management system that can intelligently generate conflict-free
schedules, manage teacher attendance and substitutions, and allow easy modification
and data storage through a user-friendly graphical interface. This system should ensure
accuracy, save time, and enhance the overall efficiency of school operations.
1|Page
CUSTOMIZABLE INPUTS
EduPlan Pro offers flexibility by allowing administrators to customize various settings
and parameters according to the institution’s structure and needs. The key customizable
inputs include:
Number of Working Days: Specify the working days (e.g., Monday to
Saturday).
Number of Periods per Day: Define the total number of class periods available
each day.
Class and Section Names: Add or manage multiple classes and their respective
sections.
Teacher Details: Enter teacher names, employee IDs, subjects, assigned classes,
and maximum number of periods per day.
Teacher Availability: Manage attendance and mark absences to automatically
handle substitutions.
Subjects and Categories: Define subjects under categories such as Science,
Language, Social Studies, etc.
School Configuration: Customize details like school name, academic year, and
visual theme using configuration files.
Export/Import Options: Export timetables to CSV files for backup and import
them back when needed.
These dynamic inputs ensure that the system remains adaptable and can efficiently serve
different school environments.
TECHNOLOGIES USED
>Programming Language
Python 3.10+ — The core programming language used for logic implementation
and GUI development.
>Frontend (Graphical User Interface)
Tkinter and ttk Themes: For building an interactive and visually appealing user
interface.
Pillow (PIL): Used for image handling, such as displaying school logos and
icons.
2|Page
>Backend (Database & Configuration)
MySQL: For managing all application data, including teachers, classes,
attendance, and timetables.
ConfigParser: For maintaining application configurations such as theme,
academic year, and school details.
CSV and JSON: For exporting/importing timetables and maintaining backups.
>Security & Validation
hashlib: For secure password hashing (SHA-256 encryption).
re (Regular Expressions): For validating inputs like email formats.
logging: To record activities and maintain error logs for debugging.
>Python Libraries & Modules
[Link], tkinter, configparser, PIL, csv, json, os, random, datetime,
hashlib, re, logging
Together, these technologies form a reliable, secure, and user-friendly scheduling
system capable of handling real-time school operations efficiently.
EXPECTED OUTCOMES
The primary objective of EduPlan Pro is to simplify timetable generation while ensuring
accuracy and efficiency. The expected outcomes include:
Automatic Timetable Generation: A complete and conflict-free timetable for
all classes and teachers.
Teacher Management: Easy addition, editing, and removal of teachers with
subject and workload tracking.
Data Storage and Security: Secure data handling using MySQL and encrypted
passwords.
User-Friendly Interface: Simplified navigation with responsive design and
theme customization.
Export/Import Support: Save or load timetables via CSV files for easy sharing
or backup.
Scalable Design: Adaptable for different institutions, class sizes, and academic
years.
3|Page
CHALLENGES FACED
Developing algorithms to prevent scheduling conflicts and balance teacher
workloads.
Integrating MySQL with Python for dynamic and persistent data handling.
Designing a modern and interactive GUI using Tkinter with ttk styling.
Managing real-time updates, such as handling teacher absences and generating
replacements.
Ensuring security and authentication using password hashing and access roles.
Implementing export/import functionality while maintaining data consistency.
LEARNING OPPORTUNITIES
Gained experience in database design and management with MySQL.
Learned about GUI programming and UX design principles using Tkinter.
Improved understanding of data encryption and software security techniques.
Enhanced knowledge of file handling, configuration management, and
modular coding.
Strengthened skills in software lifecycle management and documentation
writing.
Learned to apply problem-solving and logical thinking for real-world software
systems.
This project provided deep insight into both technical and practical aspects of
software development, preparing the developers for advanced programming and real-
world application design.
4|Page
INTRODUCTION
5|Page
LITERATURE SURVEY
INTRODUCTION
Timetable management is a vital process in every educational institution.
It involves assigning subjects, teachers, and classrooms in a way that ensures there are
no overlaps or conflicts. Traditionally, schools have relied on manual scheduling
methods, which require a lot of time, effort, and coordination. These manual systems
often lead to errors such as double-booked teachers or uneven workloads. With the
advancement of technology, automatic timetable generators have emerged as a solution
to overcome these problems by using programming and algorithms to automate
scheduling efficiently.
EXISTING SYSTEM
In most schools, timetable creation is still done manually or through simple spreadsheet
tools like Microsoft Excel. While this method is straightforward, it has several
limitations:
Time-Consuming: Preparing a timetable manually takes several hours or even
days, especially for schools with many classes and teachers.
Error-Prone: Mistakes such as overlapping classes, assigning one teacher to
multiple periods at the same time, or missing periods are common.
Lack of Flexibility: If any teacher is absent or changes occur, administrators need
to redo large portions of the timetable.
Difficult to Maintain: Manual records are harder to update, back up, or share
across departments.
No Data Analysis: Manual systems do not provide insights into teacher
workloads, subject distribution, or period usage.
Overall, the existing manual system is inefficient, difficult to manage, and unsuitable
for schools that require frequent updates or handle a large number of classes.
6|Page
PROPOSED SYSTEM
The proposed system, EduPlan Pro – Automatic Timetable Generator, overcomes
the challenges of manual scheduling by using automation, database integration, and
intelligent algorithms. It is developed using Python for the application logic and
MySQL for database management. The system uses a Graphical User Interface (GUI)
built with Tkinter and ttk themes to provide a simple and interactive experience for
users.
Key features of the proposed system include:
Automatic Timetable Generation: Creates conflict-free schedules by assigning
subjects and teachers automatically.
Teacher Management: Allows administrators to add, edit, and manage teacher
records, including subjects handled and maximum teaching hours.
Attendance Tracking: Enables marking teacher absences and tracking.
Data Export and Import: Supports CSV-based export and import of timetables
for easy sharing and backups.
Secure User Authentication: Includes admin and user login systems with
encrypted passwords for data protection.
Customization Options: Lets users configure school names, themes, and
academic years using configuration files.
Database Integration: Stores all data securely in MySQL, ensuring reliability
and ease of access.
The proposed system significantly reduces administrative effort, prevents scheduling
conflicts, and allows real-time updates whenever changes occur. It ensures fair
distribution of teacher workloads, provides permanent digital records, and enhances
overall efficiency in school management.
7|Page
SYSTEM REQUIREMENTS
Software Requirements
Operating System:
o Windows 10 or higher
o macOS Monterey or later
o Linux (Ubuntu 20.04 LTS or newer)
Programming Language:
o Python 3.8 or above
Required Python Libraries:
o Tkinter and ttk – For graphical user interface design
o Pillow (PIL) – For image handling (school logo, icons)
o [Link] – For MySQL database connection
o ConfigParser – For managing configuration files
8|Page
o CSV and JSON – For data import/export and backups
o hashlib – For password encryption using SHA-256
o logging – For system activity and error tracking
o os, random, datetime, re – For scheduling logic, file handling, and input
validation
Installation Command (for required packages):
pip install mysql-connector-python pillow
Database Requirements
Database System: MySQL
Database Name: eduplan_pro
Tables Included:
o users – Stores user login details and roles
o teachers – Stores teacher information and subject assignments
o classes – Stores class and section details
o timetables – Stores generated timetable data
o absences – Tracks teacher attendance
Additional Tools
MySQL Workbench: For managing and visualizing database tables.
Text Editor or IDE: PyCharm, Visual Studio Code, or IDLE for code editing.
Spreadsheet Software: Microsoft Excel or Google Sheets for viewing exported
CSV timetables.
System Compatibility
EduPlan Pro is lightweight and designed to work on most standard computers used in
schools and offices. It runs efficiently without requiring high-end hardware and does
not depend on an active internet connection unless remote access is configured.
9|Page
SOFTWARE DEVELOPMENT CYCLE
1. Requirement Analysis
In this initial phase, the objectives and needs of the project were clearly defined.
Discussions were held to understand the main problems in manual timetable creation,
such as scheduling conflicts, uneven teacher workloads, and difficulty in managing
substitutions. Based on this, the following requirements were finalized:
Automatic timetable generation without conflicts.
Teacher management and attendance tracking.
Export and import of timetables using CSV files.
Secure login system with user authentication.
User-friendly graphical interface for ease of use.
2. System Design
In the design phase, the system’s structure and layout were planned. The database
schema was created using MySQL, defining tables for teachers, classes, users, and
timetables. The GUI design was planned using Tkinter, focusing on simplicity and user
accessibility.
The design phase included:
Designing the database structure for storing information.
Creating UI mockups to visualize the application’s layout.
Planning the flow of operations, such as data input, timetable generation, and
output export.
Implementing configuration management using ConfigParser for custom themes
and school details.
10 | P a g e
3. Implementation (Coding)
Once the design was finalized, the actual coding of the project began using Python.
Each module was developed separately and tested for functionality. The main
components included:
GUI Development: Created using Tkinter and ttk themes for a professional look.
Database Connection: Established using [Link] to connect Python
with the MySQL database.
User Authentication: Implemented with SHA-256 encryption for secure login.
Timetable Logic: Developed to assign teachers, subjects, and classes
automatically without conflicts.
Attendance and Substitution: Added to manage absences and automatically
assign replacements.
Data Export/Import: Enabled through CSV files for easy data sharing and
backup.
4. Testing
After development, the application underwent thorough testing to ensure that all
modules worked correctly and met the specified requirements. The following types of
testing were performed:
Unit Testing: Individual modules, such as login, attendance, and timetable
generation, were tested separately.
Integration Testing: Verified that the database, GUI, and logic components
worked smoothly together.
System Testing: Checked the entire application for functionality and
performance.
User Testing: The system was tested by users to ensure ease of use and accurate
results.
11 | P a g e
5. Deployment
After successful testing, the system was deployed on local computers for school use.
The database was set up in MySQL, and the application files were installed. A user
manual was prepared to guide administrators and teachers on how to use the software.
Deployment ensured that the software was fully functional and accessible to users in a
real working environment.
6. Maintenance
Once deployed, the system required occasional updates and improvements based on
user feedback. Maintenance activities included:
Fixing minor bugs or errors identified during usage.
Updating the database or interface to add new features.
Enhancing security or improving system performance.
Regular maintenance ensures that the application continues to function efficiently and
remains compatible with newer versions of Python or MySQL.
12 | P a g e
SYSTEM ARCHITECTURE
EduPlan Pro is an automated timetable and school management system that integrates a
Python-based application layer with a MySQL relational database. The system
ensures efficient scheduling, substitution management, and administrative control
through a structured, modular, and secure architecture.
Its architecture follows a three-tier model — consisting of the Presentation Layer,
Application Layer, and Database Layer — each responsible for specific
functionalities that collectively enable seamless operation.
ARCHITECTURAL LAYERS
A. Presentation Layer (Frontend Interface)
>This layer represents the user interaction point of the system.
>Users: Administrators, Teachers, and potentially Students.
>Functions:
Login authentication (via username and password).
Dashboard for timetable visualization and management.
Teacher management (add, view, activate/deactivate).
Class and section overview.
Substitution and absence management interface.
>Technology Used:
Python GUI (Tkinter )
Collect user inputs and display system outputs.
Ensure validation before passing data to the application layer.
Provide a user-friendly experience for both administrators and faculty members.
B. Application Layer (Logic Controller)
The Application Layer acts as the intermediary between the user interface and the
database. It processes inputs, applies business logic, and manages communication with
the database server.
>Core Modules:
User Authentication Module – Validates credentials, manages sessions, and
enforces role-based access (admin, teacher, etc.).
13 | P a g e
Timetable Management Module – Generates, updates, and maintains daily and
weekly schedules based on class sections, teachers, and available periods.
Teacher Management Module – Handles teacher records, subject allocations,
and availability tracking.
Absence and Substitution Module – Logs teacher absences and automatically
assigns substitute teachers.
Class Management Module – Organizes class details such as strength, section,
room allocation, and academic year.
>Responsibilities:
Execute all business rules (e.g., preventing duplicate periods or over-
assignments).
Manage communication with the database using MySQL connectors.
Generate alerts or logs for administrative actions.
Ensure data consistency and handle concurrency when multiple updates occur
simultaneously.
C. Database Layer (Data Storage and Management)
The Database Layer forms the foundation of EduPlan Pro, responsible for data
persistence and relational integrity.
>Database Used: MySQL
>Key Entities:
Users Table – Stores login credentials, roles, and timestamps.
Teachers Table – Manages teacher profiles, subjects, and workloads.
Classes Table – Holds data on class names, sections, and academic years.
Timetables Table – Stores generated schedules linking classes, teachers, and
periods.
Absences Table – Tracks teacher absences and assigned substitutes.
>Data Integrity:
Enforced through primary keys, foreign keys, and unique constraints.
Referential integrity ensures relationships between classes, teachers, and
timetables are consistent.
14 | P a g e
>Security Measures:
Hashed password storage.
Controlled access for different roles.
Use of default and unique constraints to prevent data duplication.
15 | P a g e
SECURITY AND RELIABILITY
Authentication & Authorization: Role-based access (admin vs. teacher).
Data Encryption: Passwords stored as SHA-256 hashes.
Backup & Recovery: Regular database backups to prevent data loss.
Error Handling: Controlled exceptions for connection failures or invalid
operations.
Data Validation: Input sanitation at both application and database levels.
16 | P a g e
System architecture flowchart
17 | P a g e
CODE
import tkinter as tk
from tkinter import messagebox, simpledialog, ttk, filedialog
from datetime import datetime, timedelta
import [Link]
import random
import hashlib
import csv
import logging
import configparser
import json
import os
from PIL import Image, ImageTk
import re
# Configure logging
[Link](
filename='[Link]',
level=[Link],
format='%(asctime)s - %(levelname)s - %(message)s'
)
# Constants
DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
PERIODS = ["Period 1", "Period 2", "Period 3", "Period 4", "Period 5", "Period
6","Period 7","Period 8","Period 9"]
CLASSES = ["LKG", "UKG"] + [f"{i}th" for i in range(1, 13)]
18 | P a g e
SECTIONS = ["A", "B", "C", "D"]
SUBJECTS = ["Mathematics", "Physics", "Chemistry", "Biology", "English",
"History",
"Geography", "Computer Science", "Physical Education", "Art", "Music"]
SUBJECT_CATEGORIES = {
"Mathematics": "math",
"Physics": "science",
"Chemistry": "science",
"Biology": "science",
"English": "language",
"History": "social",
"Geography": "social",
"Computer Science": "tech",
"Physical Education": "sports",
"Art": "arts",
"Music": "arts"
}
ADMIN_USERNAME = "admin"
ADMIN_PASSWORD = "admin123"
DB_NAME = "eduplan_pro"
CONFIG_FILE = "eduplan_config.ini"
class ConfigManager:
def __init__(self, config_file=CONFIG_FILE):
[Link] = [Link]()
self.config_file = config_file
if not [Link](config_file):
self.create_default_config()
19 | P a g e
[Link](config_file)
def create_default_config(self):
[Link]['DEFAULT'] = {
'zoom_meeting_id': '',
'zoom_password': '',
'zoom_api_key': '',
'school_name': 'Peace On Green Earth Public School',
'academic_year': '2025-26',
'theme': 'light'
}
with open(self.config_file, 'w') as configfile:
[Link](configfile)
class DatabaseManager:
def __init__(self, db_name=DB_NAME):
self.db_name = db_name
20 | P a g e
try:
[Link] = [Link](host='localhost', user='root',
password='root')
[Link] = [Link]()
[Link]("CREATE DATABASE IF NOT EXISTS eduplan_pro")
[Link]()
[Link]()
[Link] = [Link](host='localhost', user='root',
password='root', database='eduplan_pro')
[Link] = [Link]()
self.create_tables()
self.insert_default_data()
except [Link] as err:
[Link](f"Database connection error: {err}")
raise
def create_tables(self):
tables = {
'users': '''CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(50) DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP,
is_active BOOLEAN DEFAULT 1
)''',
'teachers': '''CREATE TABLE IF NOT EXISTS teachers (
21 | P a g e
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) UNIQUE NOT NULL,
employee_id VARCHAR(100) UNIQUE,
subject VARCHAR(100) NOT NULL,
classes TEXT,
max_periods INTEGER DEFAULT 6,
assigned_periods INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT 1
)''',
'classes': '''CREATE TABLE IF NOT EXISTS classes (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
class_name VARCHAR(50) NOT NULL,
section VARCHAR(10) NOT NULL,
room_number VARCHAR(20),
strength INTEGER DEFAULT 0,
academic_year VARCHAR(20),
is_active BOOLEAN DEFAULT 1,
UNIQUE(class_name, section)
)''',
'timetables': '''CREATE TABLE IF NOT EXISTS timetables (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
class_name VARCHAR(50) NOT NULL,
section VARCHAR(10) NOT NULL,
day VARCHAR(20) NOT NULL,
period VARCHAR(20) NOT NULL,
teacher_id INTEGER,
subject_id INTEGER,
22 | P a g e
room_number VARCHAR(20),
is_substitution BOOLEAN DEFAULT 0,
FOREIGN KEY (teacher_id) REFERENCES teachers (id),
UNIQUE(class_name, section, day, period)
)''',
'absences': '''CREATE TABLE IF NOT EXISTS absences (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
teacher_id INTEGER,
absent_date DATE,
absent_day VARCHAR(20),
absent_period VARCHAR(20),
reason TEXT,
substitute_teacher_id INTEGER,
is_approved BOOLEAN DEFAULT 0,
FOREIGN KEY (teacher_id) REFERENCES teachers (id),
FOREIGN KEY (substitute_teacher_id) REFERENCES teachers (id)
)'''
}
23 | P a g e
[Link]("SHOW COLUMNS FROM teachers")
columns = [column[0] for column in [Link]()]
if 'classes' not in columns:
try:
[Link]("ALTER TABLE teachers ADD COLUMN classes
TEXT")
[Link]()
[Link]("Added 'classes' column to teachers table")
except [Link] as e:
[Link](f"Error adding classes column: {e}")
def insert_default_data(self):
try:
[Link]("SELECT COUNT(*) FROM users WHERE username =
%s", (ADMIN_USERNAME,))
if [Link]()[0] == 0:
admin_hash = hashlib.sha256(ADMIN_PASSWORD.encode()).hexdigest()
[Link]("INSERT INTO users (username, password_hash, role)
VALUES (%s, %s, %s)",
(ADMIN_USERNAME, admin_hash, 'admin'))
25 | P a g e
(class_name, section, "2025-26"))
[Link]()
except [Link] as e:
[Link](f"Error inserting default data: {e}")
[Link]()
raise
def close(self):
[Link]()
[Link]()
26 | P a g e
class SecurityManager:
@staticmethod
def hash_password(password):
return hashlib.sha256([Link]()).hexdigest()
@staticmethod
def verify_password(password, hash_value):
return SecurityManager.hash_password(password) == hash_value
@staticmethod
def validate_email(email):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return [Link](pattern, email) is not None
class EduPlanPro:
def __init__(self, root):
[Link] = root
[Link]("EduPlan Pro: Automatic Timetable Generator")
[Link]("1200x700")
[Link] = DatabaseManager()
[Link] = SecurityManager()
[Link] = ConfigManager()
self.current_user = None
self.current_user_id = None
self.current_user_role = None
self.logo_img = None
[Link] = [Link].get_setting('DEFAULT', 'theme')
27 | P a g e
self.bg_color = "#e3f2fd" if [Link] == 'light' else "#263238"
self.fg_color = "#1565c0" if [Link] == 'light' else "#90caf9"
[Link](bg=self.bg_color)
self.setup_styles()
self.create_login_screen()
self.update_clock()
def setup_styles(self):
[Link] = [Link]()
[Link].theme_use('clam')
[Link]('[Link]', font=('Segoe UI', 16, 'bold'),
background=self.bg_color, foreground=self.fg_color)
[Link]('[Link]', padding=8, font=('Segoe UI', 10),
background='#42a5f5', foreground='white')
[Link]('[Link]', background=[('active', '#1976d2')])
[Link]('TCombobox', font=('Segoe UI', 10), padding=5)
[Link]('TEntry', font=('Segoe UI', 10), padding=5)
[Link]('Treeview', font=('Segoe UI', 10), rowheight=25,
background='#ffffff' if [Link] == 'light' else '#37474f')
[Link]('[Link]', font=('Segoe UI', 10, 'bold'),
background='#bbdefb' if [Link] == 'light' else '#455a64')
def update_clock(self):
now = [Link]().strftime("%Y-%m-%d %H:%M:%S")
if hasattr(self, "clock_label"):
self.clock_label.config(text=now)
[Link](1000, self.update_clock)
def create_login_screen(self):
28 | P a g e
for widget in [Link].winfo_children():
[Link]()
if self.logo_img:
[Link](logo_frame, image=self.logo_img,
bg=self.bg_color).pack(side=[Link])
29 | P a g e
[Link](login_frame, text="EduPlan Pro", font=("Segoe UI", 24, "bold"),
bg="#ffffff" if [Link] == 'light' else "#37474f", fg=self.fg_color).pack(pady=10)
[Link](login_frame, text="Automatic Timetable Generator", font=("Segoe UI",
12), bg="#ffffff" if [Link] == 'light' else "#37474f", fg="#455a64" if [Link] ==
'light' else "#b0bec5").pack(pady=5)
30 | P a g e
[Link](button_frame, text="Login", command=[Link],
style='[Link]').pack(side=[Link], padx=5)
[Link](button_frame, text="Register",
command=self.show_registration_dialog,
style='[Link]').pack(side=[Link], padx=5)
[Link](button_frame, text="Upload Logo", command=self.choose_logo,
style='[Link]').pack(side=[Link], padx=5)
[Link](button_frame, text="About Software",
command=self.show_about_dialog, style='[Link]').pack(side=[Link],
padx=5)
def authenticate(self):
username = self.username_entry.get().strip()
password = self.password_entry.get().strip()
try:
query = "SELECT id, username, password_hash, role FROM users WHERE
username = %s AND is_active = 1"
result = [Link].execute_query(query, (username,), fetch=True)
31 | P a g e
self.create_main_dashboard()
else:
[Link]("Error", "Invalid username or password.")
except [Link] as e:
[Link]("Error", f"Database error: {e}")
[Link](f"Authentication error: {e}")
def show_registration_dialog(self):
dialog = [Link]([Link])
[Link]("Register")
[Link]("400x300")
[Link](bg="#ffffff" if [Link] == 'light' else "#37474f")
[Link]([Link])
dialog.grab_set()
32 | P a g e
[Link](form_frame, text="Password:", bg="#ffffff" if [Link] == 'light' else
"#37474f", fg="#455a64" if [Link] == 'light' else "#b0bec5").grid(row=1,
column=0, pady=5, sticky="e")
password_entry = [Link](form_frame, show="*", width=20, font=("Segoe UI",
10))
password_entry.grid(row=1, column=1, pady=5, padx=10)
def register():
username = username_entry.get().strip()
password = password_entry.get().strip()
if len(password) < 6:
[Link]("Error", "Password must be at least 6 characters.")
return
try:
check_query = "SELECT COUNT(*) FROM users WHERE username =
%s"
if [Link].execute_query(check_query, (username,), fetch=True)[0][0] > 0:
[Link]("Error", "Username already exists.")
return
password_hash = [Link].hash_password(password)
[Link].execute_query("INSERT INTO users (username, password_hash,
role) VALUES (%s, %s, %s)",
33 | P a g e
(username, password_hash, 'user'))
[Link]("Success", "User registered successfully!")
[Link]()
except [Link] as e:
[Link]("Error", f"Registration failed: {e}")
[Link](f"Registration error: {e}")
def show_about_dialog(self):
dialog = [Link]([Link])
[Link]("About EduPlan Pro")
[Link]("500x400")
[Link](bg="#ffffff" if [Link] == 'light' else "#37474f")
[Link]([Link])
dialog.grab_set()
34 | P a g e
info_text = """
EduPlan Pro is an advanced timetable management system designed for schools to
streamline scheduling and teacher management. Key features include:
Version: 1.0.0
Developed by: Kishore, Roopa, and Mohan
Story: Kishore, Roopa, and Mohan, three innovative students, created this app for their
Board project. Inspired by their own experiences with school scheduling chaos, they
combined Kishore's database expertise, Roopa's UI design flair, and Mohan's
algorithm prowess to build EduPlan Pro. Their goal was to make timetable
management easy and efficient for schools worldwide.
"""
[Link](info_frame, text=info_text, font=("Segoe UI", 10), bg="#ffffff" if
[Link] == 'light' else "#37474f", fg="#455a64" if [Link] == 'light' else
"#b0bec5", justify=[Link], wraplength=460).pack(pady=5)
terms_text = """
1. Use of this software is restricted to authorized users only.
35 | P a g e
2. Data entered into the system remains the property of the school.
3. The software is provided as-is, with no warranty for data loss.
4. Users are responsible for maintaining secure login credentials.
5. For support, contact support@[Link]
"""
[Link](terms_frame, text=terms_text, font=("Segoe UI", 10), bg="#ffffff" if
[Link] == 'light' else "#37474f", fg="#455a64" if [Link] == 'light' else
"#b0bec5", justify=[Link], wraplength=460).pack(pady=5)
def choose_logo(self):
file_path = [Link](filetypes=[("Image files", "*.png *.jpg
*.jpeg")])
if file_path:
try:
image = [Link](file_path)
image = [Link]((100, 100), [Link])
self.logo_img = [Link](image)
self.create_login_screen()
except Exception as e:
[Link]("Error", f"Failed to load logo: {e}")
[Link](f"Logo loading error: {e}")
def toggle_theme(self):
36 | P a g e
current_theme = [Link].get_setting('DEFAULT', 'theme')
new_theme = 'dark' if current_theme == 'light' else 'light'
[Link].set_setting('DEFAULT', 'theme', new_theme)
[Link] = new_theme
self.bg_color = "#e3f2fd" if [Link] == 'light' else "#263238"
self.fg_color = "#1565c0" if [Link] == 'light' else "#90caf9"
self.create_main_dashboard() if self.current_user else self.create_login_screen()
def create_main_dashboard(self):
for widget in [Link].winfo_children():
[Link]()
if self.logo_img:
[Link](logo_frame, image=self.logo_img, bg="#bbdefb" if [Link] ==
'light' else "#455a64").pack(side=[Link])
38 | P a g e
for i, class_name in enumerate(CLASSES):
btn = [Link](class_grid_frame, text=class_name, command=lambda
c=class_name: self.show_sections(c),
style='[Link]', width=8)
[Link](row=i//7, column=i%7, padx=2, pady=2)
actions = [
("Add Teacher", self.add_teacher),
("Manage Teachers", self.manage_teachers),
("Teacher Attendance", self.teacher_attendance),
("Auto Generate Timetable", self.auto_generate_timetable),
("Export Timetable", self.export_timetable),
("Import Timetable", self.import_timetable),
("About Software", self.show_about_dialog),
("Toggle Theme", self.toggle_theme),
("Logout", [Link])
]
try:
sections = [Link].execute_query("SELECT section FROM classes WHERE
class_name = %s AND is_active = 1",
(class_name,), fetch=True)
sections = [s[0] for s in sections]
40 | P a g e
[Link](row=i//2, column=i%2, padx=5, pady=5)
def add_teacher(self):
dialog = [Link]([Link])
[Link]("Add Teacher")
[Link]("450x500")
[Link](bg="#ffffff" if [Link] == 'light' else "#37474f")
[Link]([Link])
dialog.grab_set()
42 | P a g e
[Link](form_frame, text="Employee ID:", bg="#ffffff" if [Link] == 'light'
else "#37474f", fg="#455a64" if [Link] == 'light' else "#b0bec5").grid(row=1,
column=0, pady=5, sticky="e")
emp_id_entry = [Link](form_frame, width=25, font=("Segoe UI", 10))
emp_id_entry.grid(row=1, column=1, pady=5, padx=10)
def save_teacher():
name = name_entry.get().strip()
emp_id = emp_id_entry.get().strip()
43 | P a g e
subject = subject_combo.get().strip()
classes = classes_entry.get().strip()
max_periods = max_periods_entry.get().strip()
try:
max_periods = int(max_periods)
if max_periods <= 0 or max_periods > len(PERIODS):
[Link]("Error", f"Max periods must be between 1 and
{len(PERIODS)}.")
return
if classes:
class_list = [[Link]() for c in [Link](",")]
for c in class_list:
if c not in CLASSES:
[Link]("Error", f"Invalid class: {c}")
return
44 | P a g e
return
[Link].execute_query(
"INSERT INTO teachers (name, employee_id, subject, classes,
max_periods) VALUES (%s, %s, %s, %s, %s)",
(name, emp_id, subject, classes, max_periods)
)
[Link]("Success", "Teacher added successfully!")
[Link]()
except ValueError:
[Link]("Error", "Max periods must be a number.")
except [Link] as e:
[Link]("Error", f"Failed to add teacher: {e}")
[Link](f"Add teacher error: {e}")
def manage_teachers(self):
dialog = [Link]([Link])
[Link]("Manage Teachers")
[Link]("800x500")
[Link](bg="#ffffff" if [Link] == 'light' else "#37474f")
[Link]([Link])
45 | P a g e
dialog.grab_set()
try:
teachers = [Link].execute_query("SELECT id, name, employee_id, subject,
classes, max_periods FROM teachers WHERE is_active = 1", fetch=True)
for teacher in teachers:
[Link]("", [Link], values=teacher)
def delete_teacher():
selected = [Link]()
if not selected:
[Link]("Error", "Select a teacher to delete.")
return
46 | P a g e
if [Link]("Confirm", "Are you sure you want to delete this
teacher?"):
teacher_id = [Link](selected[0])['values'][0]
[Link].execute_query("UPDATE teachers SET is_active = 0 WHERE id
= %s", (teacher_id,))
[Link](selected[0])
[Link]("Success", "Teacher deleted successfully.")
def edit_teacher():
selected = [Link]()
if not selected:
[Link]("Error", "Select a teacher to edit.")
return
teacher_data = [Link](selected[0])['values']
self.edit_teacher_dialog(teacher_data, dialog)
47 | P a g e
def edit_teacher_dialog(self, teacher_data, parent_dialog):
dialog = [Link]([Link])
[Link]("Edit Teacher")
[Link]("450x500")
[Link](bg="#ffffff" if [Link] == 'light' else "#37474f")
[Link]([Link])
dialog.grab_set()
48 | P a g e
[Link](form_frame, text="Subject:", bg="#ffffff" if [Link] == 'light' else
"#37474f", fg="#455a64" if [Link] == 'light' else "#b0bec5").grid(row=2,
column=0, pady=5, sticky="e")
subject_combo = [Link](form_frame, values=SUBJECTS, width=22,
font=("Segoe UI", 10))
subject_combo.set(teacher_data[3])
subject_combo.grid(row=2, column=1, pady=5, padx=10)
def save_teacher():
name = name_entry.get().strip()
emp_id = emp_id_entry.get().strip()
subject = subject_combo.get().strip()
classes = classes_entry.get().strip()
max_periods = max_periods_entry.get().strip()
try:
max_periods = int(max_periods)
if max_periods <= 0 or max_periods > len(PERIODS):
[Link]("Error", f"Max periods must be between 1 and
{len(PERIODS)}.")
return
if classes:
class_list = [[Link]() for c in [Link](",")]
for c in class_list:
if c not in CLASSES:
[Link]("Error", f"Invalid class: {c}")
return
[Link].execute_query(
"UPDATE teachers SET name = %s, employee_id = %s, subject = %s,
classes = %s, max_periods = %s WHERE id = %s",
50 | P a g e
(name, emp_id, subject, classes, max_periods, teacher_data[0])
)
[Link]("Success", "Teacher updated successfully!")
[Link]()
parent_dialog.destroy()
self.manage_teachers()
except ValueError:
[Link]("Error", "Max periods must be a number.")
except [Link] as e:
[Link]("Error", f"Failed to update teacher: {e}")
[Link](f"Edit teacher error: {e}")
def teacher_attendance(self):
dialog = [Link]([Link])
[Link]("Teacher Attendance")
[Link]("800x500")
[Link](bg="#ffffff" if [Link] == 'light' else "#37474f")
[Link]([Link])
dialog.grab_set()
51 | P a g e
[Link](dialog, text="Teacher Attendance", font=("Segoe UI", 16, "bold"),
bg="#ffffff" if [Link] == 'light' else "#37474f", fg=self.fg_color).pack(pady=10)
try:
query = """
SELECT [Link], [Link], [Link], a.absent_date, a.absent_day,
a.absent_period,
CASE WHEN a.is_approved THEN 'Absent' ELSE 'Pending' END,
[Link]
FROM absences a
JOIN teachers t ON a.teacher_id = [Link]
WHERE t.is_active = 1
"""
records = [Link].execute_query(query, fetch=True)
for record in records:
[Link]("", [Link], values=record)
52 | P a g e
def mark_absence():
teacher_dialog = [Link](dialog)
teacher_dialog.title("Mark Absence")
teacher_dialog.geometry("400x500")
teacher_dialog.configure(bg="#ffffff" if [Link] == 'light' else "#37474f")
teacher_dialog.transient(dialog)
teacher_dialog.grab_set()
53 | P a g e
date_entry.insert(0, [Link]().strftime("%Y-%m-%d"))
date_entry.grid(row=1, column=1, pady=5, padx=10)
whole_day_var = [Link](value=False)
def toggle_period_combo():
if whole_day_var.get():
period_combo.config(state='disabled')
else:
period_combo.config(state='normal')
54 | P a g e
check = [Link](form_frame, text="Absent for whole day",
variable=whole_day_var,
command=toggle_period_combo, bg="#ffffff" if [Link]
== 'light' else "#37474f",
fg="#455a64" if [Link] == 'light' else "#b0bec5",
selectcolor="#ffffff" if [Link] == 'light' else "#37474f")
[Link](row=5, column=0, columnspan=2, pady=5, sticky="w")
def save_absence():
teacher_name = teacher_combo.get().strip()
absent_date = date_entry.get().strip()
absent_day = day_combo.get().strip()
absent_period = period_combo.get().strip()
reason = reason_entry.get().strip()
whole_day = whole_day_var.get()
try:
dt = [Link](absent_date, "%Y-%m-%d")
calculated_day = [Link]("%A")
if calculated_day != absent_day:
55 | P a g e
[Link]("Error", f"Selected day {absent_day} does
not match the date's day {calculated_day}.")
return
if whole_day:
periods = PERIODS
else:
periods = [absent_period]
if absent_period not in PERIODS:
[Link]("Error", "Invalid period selected.")
return
substituted = 0
for p in periods:
check_query = "SELECT COUNT(*) FROM absences WHERE
teacher_id = %s AND absent_date = %s AND absent_day = %s AND absent_period =
%s"
56 | P a g e
if [Link].execute_query(check_query, (teacher_id, absent_date,
absent_day, p), fetch=True)[0][0] > 0:
continue # Skip if already recorded
[Link].execute_query(
"INSERT INTO absences (teacher_id, absent_date, absent_day,
absent_period, reason, substitute_teacher_id, is_approved) VALUES (%s, %s, %s, %s,
%s, %s, %s)",
(teacher_id, absent_date, absent_day, p, reason, None, 1)
)
self.handle_substitution(teacher_id, absent_date, absent_day, p)
substituted += 1
57 | P a g e
button_frame = [Link](teacher_dialog, bg="#ffffff" if [Link] == 'light'
else "#37474f")
button_frame.pack(pady=20)
[Link](button_frame, text="Save", command=save_absence,
style='[Link]').pack(side=[Link], padx=5)
[Link](button_frame, text="Cancel", command=teacher_dialog.destroy,
style='[Link]').pack(side=[Link], padx=5)
58 | P a g e
try:
# Find classes affected by the teacher's absence on the specific day and period
query = """
SELECT class_name, section, subject_id
FROM timetables
WHERE teacher_id = %s AND day = %s AND period = %s
"""
affected_classes = [Link].execute_query(query, (teacher_id, absent_day,
absent_period), fetch=True)
if not affected_classes:
[Link](f"No classes assigned to teacher {teacher_id} on {absent_day},
{absent_period}.")
return
if not suitable_teachers:
# Level 2: same class, any subject, free, load < max
suitable_teachers = [
t for t in available_teachers
if t[0] not in busy_teacher_ids and
class_name in (t[3] or "").split(",") and
self.get_teacher_load(t[0], absent_day) < t[4] and
not self.is_teacher_absent(t[0], absent_date, absent_period)
]
level = 2
if suitable_teachers:
[Link](f"No same-subject substitute found for {class_name}
{section}, {absent_day}, {absent_period}. Using same-class any-subject teacher.")
60 | P a g e
if not suitable_teachers:
# Level 3: any, free, load < max
suitable_teachers = [
t for t in available_teachers
if t[0] not in busy_teacher_ids and
self.get_teacher_load(t[0], absent_day) < t[4] and
not self.is_teacher_absent(t[0], absent_date, absent_period)
]
level = 3
if suitable_teachers:
[Link](f"No class-qualified substitute found for {class_name}
{section}, {absent_day}, {absent_period}. Using any available teacher.")
if not suitable_teachers:
# Level 4: any, free, load <= max (allow at max)
suitable_teachers = [
t for t in available_teachers
if t[0] not in busy_teacher_ids and
self.get_teacher_load(t[0], absent_day) <= t[4] and
not self.is_teacher_absent(t[0], absent_date, absent_period)
]
level = 4
if suitable_teachers:
[Link](f"Assigning substitute at level 4 (allowing max load) for
{class_name} {section}, {absent_day}, {absent_period}.")
if not suitable_teachers:
61 | P a g e
# Level 5: reassign from lower priority class
level = 5
potential_teachers = [
t for t in available_teachers
if self.get_teacher_load(t[0], absent_day) < t[4] and
not self.is_teacher_absent(t[0], absent_date, absent_period)
] # no busy check
candidates = []
for t in potential_teachers:
query = "SELECT class_name, section FROM timetables WHERE
teacher_id = %s AND day = %s AND period = %s"
result = [Link].execute_query(query, (t[0], absent_day, absent_period),
fetch=True)
if result:
old_class, old_section = result[0]
old_level = self.get_class_level(old_class)
load_ratio = self.get_teacher_load(t[0], absent_day) / t[4] if t[4] > 0
else 0
same_category = 0 if SUBJECT_CATEGORIES.get(t[2], "other")
== category else 1
[Link]((t, old_class, old_section, old_level, load_ratio,
same_category))
if candidates:
# Select the one with min old_level, then min load_ratio, then min
same_category
[Link](key=lambda x: (x[3], x[4], x[5]))
selected_teacher, old_class, old_section, _, _, _ = candidates[0]
62 | P a g e
# Unassign the old slot
[Link].execute_query(
"UPDATE timetables SET teacher_id = NULL, is_substitution = 1
WHERE class_name = %s AND section = %s AND day = %s AND period = %s",
(old_class, old_section, absent_day, absent_period)
)
# Update absence
[Link].execute_query(
"UPDATE absences SET substitute_teacher_id = %s WHERE
teacher_id = %s AND absent_date = %s AND absent_day = %s AND absent_period =
%s",
(selected_teacher[0], teacher_id, absent_date, absent_day,
absent_period)
)
63 | P a g e
if not suitable_teachers and level != 5:
# No suitable substitute found
[Link].execute_query(
"UPDATE timetables SET teacher_id = NULL, is_substitution = 1
WHERE class_name = %s AND section = %s AND day = %s AND period = %s",
(class_name, section, absent_day, absent_period)
)
[Link].execute_query(
"UPDATE absences SET substitute_teacher_id = NULL WHERE
teacher_id = %s AND absent_date = %s AND absent_day = %s AND absent_period =
%s",
(teacher_id, absent_date, absent_day, absent_period)
)
[Link](f"No suitable substitute for {class_name} {section},
{absent_day}, {absent_period}. Slot marked as Unassigned.")
continue
if level != 5:
# Select the teacher
def select_key(x):
load_ratio = self.get_teacher_load(x[0], absent_day) / x[4] if x[4] > 0
else 0
same_category = 0 if SUBJECT_CATEGORIES.get(x[2], "other") ==
category else 1
return (load_ratio, same_category)
# Update timetable
64 | P a g e
[Link].execute_query(
"UPDATE timetables SET teacher_id = %s, is_substitution = 1
WHERE class_name = %s AND section = %s AND day = %s AND period = %s",
(selected_teacher[0], class_name, section, absent_day, absent_period)
)
# Update absence
[Link].execute_query(
"UPDATE absences SET substitute_teacher_id = %s WHERE
teacher_id = %s AND absent_date = %s AND absent_day = %s AND absent_period =
%s",
(selected_teacher[0], teacher_id, absent_date, absent_day,
absent_period)
)
65 | P a g e
def open_timetable_editor(self, class_name, section):
dialog = [Link]([Link])
[Link](f"Timetable Editor: {class_name} {section}")
[Link]("1000x600")
[Link](bg="#ffffff" if [Link] == 'light' else "#37474f")
[Link]([Link])
dialog.grab_set()
[Link]("Period", text="Period")
[Link]("Period", width=100)
for day in DAYS:
[Link](day, text=day)
[Link](day, width=150)
try:
timetable_data = {}
for period in PERIODS:
66 | P a g e
timetable_data[period] = {day: "" for day in DAYS}
for day in DAYS:
query = """
SELECT t.teacher_id, t.subject_id, t.room_number
FROM timetables t
WHERE t.class_name = %s AND [Link] = %s AND [Link] = %s AND
[Link] = %s
"""
results = [Link].execute_query(query, (class_name, section, day, period),
fetch=True)
if results:
teacher_id, subject_id, room = results[0]
teacher_name = [Link].execute_query("SELECT name FROM teachers
WHERE id = %s", (teacher_id,), fetch=True)[0][0] if teacher_id else "Unassigned"
subject = SUBJECTS[subject_id - 1]
timetable_data[period][day] = f"{teacher_name} ({subject})"
def edit_period(event):
item = [Link]()
if not item:
return
period = [Link](item)["values"][0]
col = tree.identify_column(event.x)
day = columns[int(col[1:]) - 1] if col != "#0" else None
if day == "Period":
67 | P a g e
return
self.edit_timetable_entry(class_name, section, day, period, dialog)
[Link]("<Double-1>", edit_period)
68 | P a g e
[Link](form_frame, text="Teacher:", bg="#ffffff" if [Link] == 'light' else
"#37474f", fg="#455a64" if [Link] == 'light' else "#b0bec5").grid(row=0,
column=0, pady=5, sticky="e")
teachers = [Link].execute_query("SELECT name FROM teachers WHERE
is_active = 1", fetch=True)
teacher_names = ["Unassigned"] + [t[0] for t in teachers]
teacher_combo = [Link](form_frame, values=teacher_names, width=22,
font=("Segoe UI", 10))
teacher_combo.grid(row=0, column=1, pady=5, padx=10)
def save_entry():
teacher_name = teacher_combo.get().strip()
subject = subject_combo.get().strip()
room = room_entry.get().strip()
if not subject:
[Link]("Error", "Subject is required.")
69 | P a g e
return
try:
teacher_id = None if teacher_name == "Unassigned" else
[Link].execute_query("SELECT id FROM teachers WHERE name = %s",
(teacher_name,), fetch=True)[0][0]
subject_id = [Link](subject) + 1
if teacher_id:
assigned_periods = [Link].execute_query(
"SELECT COUNT(*) FROM timetables WHERE teacher_id = %s
AND day = %s",
(teacher_id, day), fetch=True
)[0][0]
max_periods = [Link].execute_query(
"SELECT max_periods FROM teachers WHERE id = %s",
(teacher_id,), fetch=True
)[0][0]
if assigned_periods >= max_periods:
[Link]("Error", f"{teacher_name} has reached max
periods for {day}.")
return
absent_date = [Link]().strftime("%Y-%m-%d")
is_absent = [Link].execute_query(
"SELECT COUNT(*) FROM absences WHERE teacher_id = %s AND
absent_date = %s AND absent_period = %s AND is_approved = 1",
(teacher_id, absent_date, period), fetch=True
)[0][0]
70 | P a g e
if is_absent:
[Link]("Error", f"{teacher_name} is absent on
{absent_date} for {period}.")
return
[Link].execute_query(
"INSERT INTO timetables (class_name, section, day, period, teacher_id,
subject_id, room_number) VALUES (%s, %s, %s, %s, %s, %s, %s) ON DUPLICATE
KEY UPDATE teacher_id = VALUES(teacher_id), subject_id = VALUES(subject_id),
room_number = VALUES(room_number)",
(class_name, section, day, period, teacher_id, subject_id, room)
)
[Link]("Success", "Timetable entry updated.")
[Link]()
parent_dialog.destroy()
self.open_timetable_editor(class_name, section)
except [Link] as e:
[Link]("Error", f"Failed to update timetable: {e}")
[Link](f"Edit timetable error: {e}")
71 | P a g e
query = "SELECT COUNT(*) FROM timetables WHERE teacher_id = %s AND
day = %s"
return [Link].execute_query(query, (teacher_id, day), fetch=True)[0][0]
72 | P a g e
def auto_generate_timetable(self):
if not [Link]("Confirm", "This will overwrite existing timetables.
Proceed?"):
return
try:
[Link].execute_query("DELETE FROM timetables")
[Link].execute_query("UPDATE teachers SET assigned_periods = 0")
[Link]("Cleared existing timetables and reset teacher assignments.")
classes = [Link].execute_query(
"SELECT class_name, section FROM classes WHERE is_active = 1",
fetch=True
)
teachers = [Link].execute_query(
"SELECT id, name, subject, classes, max_periods, assigned_periods FROM
teachers WHERE is_active = 1",
fetch=True
)
teacher_data = [
{
'id': t[0],
'name': t[1],
'subject': t[2],
'classes': t[3].split(",") if t[3] else [],
'max_periods': t[4],
'total_assigned': 0
73 | P a g e
}
for t in teachers
]
if not available_teachers:
[Link](f"No available teachers for {class_name} {section},
{day}, {period}")
continue
available_teachers.sort(key=lambda x: x['total_assigned'])
prev_teacher_id = self.get_previous_period_teacher(class_name,
section, day, period_index)
74 | P a g e
preferred_teachers = [
t for t in available_teachers
if prev_teacher_id is None or t['id'] != prev_teacher_id
] or available_teachers
if not preferred_teachers:
[Link](f"No non-consecutive teachers available for
{class_name} {section}, {day}, {period}")
continue
selected_teacher = preferred_teachers[0]
subject_id = [Link](selected_teacher['subject']) + 1
[Link].execute_query(
"INSERT INTO timetables (class_name, section, day, period,
teacher_id, subject_id, room_number) "
"VALUES (%s, %s, %s, %s, %s, %s, %s)",
(class_name, section, day, period, selected_teacher['id'], subject_id,
f"Room {class_name}-{section}")
)
selected_teacher['total_assigned'] += 1
[Link].execute_query(
"UPDATE teachers SET assigned_periods = assigned_periods + 1
WHERE id = %s",
(selected_teacher['id'],)
)
[Link](f"Assigned {selected_teacher['name']}
({selected_teacher['subject']}) to "
f"{class_name} {section}, {day}, {period}")
75 | P a g e
# Re-apply approved absences substitutions
absences = [Link].execute_query(
"SELECT teacher_id, absent_date, absent_day, absent_period FROM
absences WHERE is_approved = 1", fetch=True
)
for teacher_id, absent_date, absent_day, absent_period in absences:
self.handle_substitution(teacher_id, absent_date, absent_day, absent_period)
def export_timetable(self):
file_path = [Link](defaultextension=".csv",
filetypes=[("CSV files", "*.csv")])
76 | P a g e
if not file_path:
return
try:
with open(file_path, mode='w', newline='') as file:
writer = [Link](file)
[Link](["Class", "Section", "Day", "Period", "Teacher", "Subject",
"Room"])
query = """
SELECT t.class_name, [Link], [Link], [Link], [Link], t.subject_id,
t.room_number
FROM timetables t
LEFT JOIN teachers te ON t.teacher_id = [Link]
"""
rows = [Link].execute_query(query, fetch=True)
[Link]([(row[0], row[1], row[2], row[3], row[4] or "Unassigned",
SUBJECTS[int(row[5])-1], row[6]) for row in rows])
[Link]("Success", "Timetable exported successfully!")
except Exception as e:
[Link]("Error", f"Failed to export timetable: {e}")
[Link](f"Export timetable error: {e}")
def import_timetable(self):
file_path = [Link](filetypes=[("CSV files", "*.csv")])
if not file_path:
return
try:
77 | P a g e
with open(file_path, mode='r') as file:
reader = [Link](file)
header = next(reader)
if header != ["Class", "Section", "Day", "Period", "Teacher", "Subject",
"Room"]:
[Link]("Error", "Invalid CSV format.")
return
teacher_id = None
if teacher_name != "Unassigned":
teacher_id_result = [Link].execute_query(
"SELECT id FROM teachers WHERE name = %s AND is_active =
1", (teacher_name,), fetch=True
)
if not teacher_id_result:
continue
teacher_id = teacher_id_result[0][0]
78 | P a g e
assigned_periods = [Link].execute_query(
"SELECT COUNT(*) FROM timetables WHERE teacher_id = %s
AND day = %s",
(teacher_id, day), fetch=True
)[0][0]
max_periods = [Link].execute_query(
"SELECT max_periods FROM teachers WHERE id = %s",
(teacher_id,), fetch=True
)[0][0]
if assigned_periods >= max_periods:
continue
subject_id = [Link](subject) + 1
[Link].execute_query(
"INSERT INTO timetables (class_name, section, day, period,
teacher_id, subject_id, room_number) VALUES (%s, %s, %s, %s, %s, %s, %s) ON
DUPLICATE KEY UPDATE teacher_id = VALUES(teacher_id), subject_id =
VALUES(subject_id), room_number = VALUES(room_number)",
(class_name, section, day, period, teacher_id, subject_id, room)
)
if teacher_id:
[Link].execute_query(
"UPDATE teachers SET assigned_periods = assigned_periods + 1
WHERE id = %s",
(teacher_id,)
)
[Link]("Success", "Timetable imported successfully!")
except Exception as e:
[Link]("Error", f"Failed to import timetable: {e}")
79 | P a g e
[Link](f"Import timetable error: {e}")
def logout(self):
self.current_user = None
self.current_user_id = None
self.current_user_role = None
self.create_login_screen()
def main():
root = [Link]()
app = EduPlanPro(root)
[Link]()
if __name__ == "__main__":
main()
80 | P a g e
OUTPUT SCREENSHOTS
81 | P a g e
82 | P a g e
83 | P a g e
84 | P a g e
85 | P a g e
86 | P a g e
87 | P a g e
88 | P a g e
89 | P a g e
90 | P a g e
91 | P a g e
92 | P a g e
93 | P a g e
94 | P a g e
95 | P a g e
96 | P a g e
EXPORTED TIMETABLE:
97 | P a g e
MYSQL-DATABASE
98 | P a g e
99 | P a g e
100 | P a g e
101 | P a g e
102 | P a g e
103 | P a g e
TESTING
Software testing is the process of evaluating software to detect errors and ensure
quality.
It checks whether the software meets specified requirements and functions
correctly.
Can be done manually or using automated tools.
Importance
Testing Strategies
Testing Levels
105 | P a g e
WHITEBOX TESTING
Definition: White-box testing is a software testing technique where the internal
structure, code, and logic of a program are tested.
Purpose:
Techniques Used:
Advantages:
Disadvantages:
106 | P a g e
White box testing for the EduPlan Pro – Automatic Timetable Generator was
carried out during the development phase to verify the internal logic and
functioning of each module. The testing focused on checking the correctness of
code execution, decision-making conditions, and data flow within the system.
During white box testing, print statements and log entries were used to trace
code execution paths, identify logic errors, and confirm expected outputs. Any
discovered bugs were corrected immediately to ensure reliable performance
before integration testing.
107 | P a g e
BLACK BOX TESTING
Definition: Black-box testing is a software testing technique that evaluates a
system's functionality without knowing its internal code, structure, or
implementation.
Purpose:
Techniques Used:
Equivalence Partitioning – Divides input data into valid and invalid groups for
testing.
Boundary Value Analysis – Tests values at the boundary limits (e.g., minimum
and maximum inputs).
Decision Table Testing – Uses tables to represent complex business logic and
test different input combinations.
State Transition Testing – Evaluates system behavior based on state changes.
Error Guessing – Relies on tester experience to predict and find potential
errors.
Advantages:
Disadvantages:
108 | P a g e
Black box testing for the EduPlan Pro – Automatic Timetable Generator was
conducted after the completion of the coding phase to ensure that the system met
all functional requirements and behaved correctly from a user’s perspective. The
testing focused on verifying inputs, outputs, and overall system functionality
without considering the internal code structure.
Login Module: Checked whether valid user credentials granted access and
invalid credentials displayed proper error messages.
Teacher Management: Tested adding, editing, and deleting teacher details to
ensure correct data entry and updates in the database.
Timetable Generation: Verified that the system produced a complete, conflict-
free timetable and handled invalid or incomplete inputs appropriately.
Attendance: Tested marking teacher absences
Export and Import Functions: Ensured timetables were correctly exported to
CSV format and re-imported without data loss or formatting issues.
Configuration Settings: Checked that changes in school name, academic year,
and theme were reflected accurately in the application interface.
Error Messages and Notifications: Verified that the system displayed proper
alerts and handled invalid actions gracefully without crashing.
All modules were tested with both valid and invalid input data to confirm the
system’s reliability, stability, and user-friendliness. The testing confirmed that the
software performed as expected under different user scenarios, ensuring accuracy
and usability before deployment.
109 | P a g e
SUSTAINABLE DEVELOPMENT GOALS
BEING ATTAINED IN OUR PROJECT
110 | P a g e
INTEGRATION OF STE(A)M
SCIENCE
The project applies scientific thinking through logical reasoning, observation, and
problem-solving. The process of analysing how timetables are created manually and
converting that process into a structured automated system demonstrates the
application of scientific methods. Hypothesis testing, experimentation, and iterative
improvements were used during development to ensure that the system produced
accurate, conflict-free results.
TECHNOLOGY
Technology forms the core of the project. The entire system is built using Python
programming, MySQL database management, and Tkinter for the graphical
interface. These technologies are combined to create a practical and efficient digital
tool that automates a real-world administrative process. The use of encryption for
security, database integration, and CSV handling reflects the application of modern
technological solutions to everyday school management problems.
ENGINEERING
Engineering principles are reflected in the system’s design, structure, and workflow.
The project follows the Software Development Life Cycle (SDLC), which is an
engineering-based approach to developing reliable software. Each module, from data
handling to timetable generation, was designed with precision to ensure efficiency and
reliability. The integration between different system components, such as GUI,
database, and logic modules, showcases engineering design thinking and structured
implementation.
ARTS
Artistic elements are integrated through the design and presentation of the graphical
user interface. The Tkinter-based GUI with customizable themes and colour schemes
adds an aesthetic appeal, making the software visually pleasing and easy to navigate.
111 | P a g e
Attention was given to layout arrangement, colour balance, and readability to enhance
the user experience. The inclusion of school logos and a modern interface design
combine creativity with functionality.
MATHEMATICS
Mathematics plays a critical role in timetable generation and optimization. Logical and
arithmetic operations are used to allocate teachers, subjects, and periods without
overlaps. Algorithms rely on mathematical logic to handle constraints such as teacher
workload, class capacity, and number of periods per day. Randomization and
validation techniques further ensure balanced and accurate scheduling. The project
thus applies mathematical reasoning to solve real scheduling challenges efficiently.
112 | P a g e
CONCLUSION
The EduPlan Pro – Automatic Timetable Generator project successfully
demonstrates the use of computer technology to automate and simplify the process of
timetable creation in schools. It eliminates the difficulties of manual scheduling by
introducing a system that automatically allocates teachers, subjects, and classes without
conflicts. This project aims to make timetable generation more efficient, accurate, and
convenient for school administrators, saving both time and effort.
The project was developed using Python for the main programming logic and MySQL
for database management, ensuring both reliability and scalability. A user-friendly
graphical interface was built using Tkinter, allowing easy interaction with the system.
Features such as teacher attendance tracking, automatic substitution, and CSV
export/import add flexibility and make the application suitable for real-world use in
schools and institutions.
The entire development process followed the Software Development Life Cycle
(SDLC) model, which helped ensure proper planning, design, implementation, testing,
and maintenance. Different modules of the project were thoroughly tested using white
box and black box testing to confirm functionality, accuracy, and system stability. These
testing methods helped identify and fix any issues before deployment, resulting in a
reliable and user-friendly software product.
The project also reflects a strong integration of STEAM (Science, Technology,
Engineering, Arts, and Mathematics) principles. Logical reasoning and problem-solving
represent the scientific aspect, while programming and database connectivity
demonstrate technology. Engineering principles were applied through systematic
software design, artistic elements were reflected in the interface layout and color
scheme, and mathematical reasoning was used in timetable generation and scheduling
algorithms.
In conclusion, EduPlan Pro successfully achieves its goal of automating timetable
generation while promoting effective learning and application of technical skills. It
provides a scalable and efficient solution that can be adapted for future improvements
such as online data synchronization or student attendance tracking. The project not only
showcases practical problem-solving through programming but also highlights how
technology can bring real improvements to educational administration.
113 | P a g e
FUTURE ENHANCEMENTS
Classes integration-Generation of time table for all classes even when one
teacher handles for more than one class
114 | P a g e
BIBILIOGRAPHY
o NCERT Computer Science Textbook for Class XI – National Council of
Educational Research and Training (NCERT), New Delhi.
Provided foundational knowledge on Python programming, algorithms,
flowcharts, and database concepts essential for developing the logic of the
project.
o NCERT Computer Science Textbook for Class XII – National Council of
Educational Research and Training (NCERT), New Delhi.
Offered deeper insights into database connectivity, file handling, MySQL
integration with Python, and software development methodologies, which were
applied throughout the project.
o Sumita Arora – Computer Science with Python, Class XI – Dhanpat Rai &
Co. Publications.
Helped in understanding Python fundamentals, control structures, data types,
and modular programming concepts used in the project’s core logic.
o Sumita Arora – Computer Science with Python, Class XII – Dhanpat Rai &
Co. Publications.
Provided detailed explanations on advanced Python topics such as file
handling, database connectivity, and project development practices that guided
the overall design of the system.
o Python Official Documentation – [Link]
Used as a reference for Python syntax, libraries, and functions implemented in
the project.
o MySQL Documentation – [Link]
Referred for understanding SQL commands, database creation, and integration
with Python through the MySQL connector.
o Tkinter and ttk Reference Guide –
[Link]
Used for designing and customizing the graphical user interface of the project.
o Online Programming Resources and Tutorials – W3Schools, GeeksforGeeks,
and Programiz.
Consulted for syntax clarification, GUI examples, and logic optimization during
the development and debugging phases.
115 | P a g e
116 | P a g e
117 | P a g e