0% found this document useful (0 votes)
4 views73 pages

Computer Science Code

The document outlines a complete final version of a Railway Management System project for Class 12, including database configuration, constants for coaches and seats, utility and validation functions, and database functions for managing users, trains, and bookings. It provides detailed code for creating and managing the database schema, including tables for users, trains, routes, and bookings. The system is designed to facilitate train management and passenger bookings.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views73 pages

Computer Science Code

The document outlines a complete final version of a Railway Management System project for Class 12, including database configuration, constants for coaches and seats, utility and validation functions, and database functions for managing users, trains, and bookings. It provides detailed code for creating and managing the database schema, including tables for users, trains, routes, and bookings. The system is designed to facilitate train management and passenger bookings.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

# ============================================================

# RAILWAY MANAGEMENT SYSTEM - CLASS 12 PROJECT


# (COMPLETE FINAL VERSION - UPDATED)
# ============================================================

import [Link]
import random
from datetime import datetime, timedelta, date, time

# ============================================================
# DATABASE CONFIGURATION
# ============================================================

HOST = "localhost"
USER = "root"
PASSWORD = "MYSQL" # Enter your MySQL password here
DB_NAME = "RailWay"

# ============================================================
# CONSTANTS - COACH & SEATS
# ============================================================

SEATS_PER_COACH = {
'1st-AC': 18,
'2nd-AC': 46,
'3rd-AC': 64,
'SL': 72
}

COACH_PREFIX = {
'1st-AC': 'A',
'2nd-AC': 'B',
'3rd-AC': 'C',
'SL': 'D'
}

CLASS_NAMES = {
'1st-AC': 'First AC',
'2nd-AC': 'Second AC',
'3rd-AC': 'Third AC',
'SL': 'Sleeper'
}

# ============================================================
# UTILITY FUNCTIONS
# ============================================================

def print_line(char="=", length=80):


print(char * length)

def print_header(title):
print()
print_line("=")
print([Link](80))
1
print_line("=")

def print_subheader(title):
print()
print_line("-", 60)
print([Link](60))
print_line("-", 60)

def press_enter():
input("\n>>> Press ENTER to continue...")

def print_table(headers, rows):


if not rows:
print("\n[ No data available ]")
return

col_widths = []
for i in range(len(headers)):
max_width = len(str(headers[i]))
for row in rows:
if i < len(row):
cell_len = len(str(row[i])) if row[i] is not None else 4
if cell_len > max_width:
max_width = cell_len
col_widths.append(max_width + 2)

print("+" + "+".join(["-" * w for w in col_widths]) + "+")

header_row = "|"
for i, h in enumerate(headers):
header_row += str(h).center(col_widths[i]) + "|"
print(header_row)

print("+" + "+".join(["=" * w for w in col_widths]) + "+")

for row in rows:


data_row = "|"
for i in range(len(headers)):
if i < len(row):
val = str(row[i]) if row[i] is not None else "N/A"
else:
val = "N/A"
data_row += [Link](col_widths[i]) + "|"
print(data_row)

print("+" + "+".join(["-" * w for w in col_widths]) + "+")

def print_dict_table(data_dict):
rows = [(k, v) for k, v in data_dict.items()]
print_table(["Field", "Value"], rows)

# ============================================================
# VALIDATION FUNCTIONS
# ============================================================
2
def is_junction_station(station_id):
"""Check if a station is a junction"""
conn = connect_with_db()
cursor = [Link]()
[Link]("SELECT station_name FROM stations WHERE station_id = %s", (station_id
result = [Link]()
[Link]()
[Link]()

if result:
station_name = result[0].lower()
return "junction" in station_name
return False

def count_junctions_in_route(train_id):
"""Count number of junction stations in a train route"""
conn = connect_with_db()
cursor = [Link]()
[Link]("""
SELECT COUNT(*) FROM train_routes tr
JOIN stations s ON tr.station_id = s.station_id
WHERE tr.train_id = %s AND LOWER(s.station_name) LIKE '%junction%'
""", (train_id,))
count = [Link]()[0]
[Link]()
[Link]()
return count

def get_junction_count_for_stations(station_ids):
"""Count junctions in a list of station IDs"""
if not station_ids:
return 0

conn = connect_with_db()
cursor = [Link]()

placeholders = ','.join(['%s'] * len(station_ids))


[Link](f"""
SELECT COUNT(*) FROM stations
WHERE station_id IN ({placeholders}) AND LOWER(station_name) LIKE '%junction%'
""", tuple(station_ids))

count = [Link]()[0]
[Link]()
[Link]()
return count

MAX_JUNCTIONS = 4 # Maximum junctions allowed per train

def validate_username(username):
if len(username) < 3:
return False, "Username must be at least 3 characters."
if not username[0].isalpha():
3
return False, "Username must start with a letter."
if not [Link]():
return False, "Username can only contain letters and numbers."
return True, ""

def validate_train_name(train_name):
if not train_name:
return False, "Train name cannot be empty."
if not train_name[0].isalpha():
return False, "Train name must start with a letter."
for char in train_name:
if [Link]():
return False, "Train name cannot contain numbers."
return True, ""

def check_train_name_exists(train_name, exclude_date=None):


conn = connect_with_db()
cursor = [Link]()
if exclude_date:
[Link]("""
SELECT train_id FROM trains
WHERE LOWER(train_name) = LOWER(%s) AND journey_start_date = %s
""", (train_name, exclude_date))
else:
[Link]("SELECT train_id FROM trains WHERE LOWER(train_name) = LOWER(%s)"
result = [Link]()
[Link]()
[Link]()
return result is not None

def check_train_number_date_exists(train_number, journey_date):


"""Check if train number + date combination exists"""
conn = connect_with_db()
cursor = [Link]()
[Link]("""
SELECT train_id FROM trains
WHERE train_number = %s AND journey_start_date = %s
""", (train_number, journey_date))
result = [Link]()
[Link]()
[Link]()
return result is not None

def validate_train_number(train_no):
if train_no.isdigit() and len(train_no) == 5:
return True
return False

def get_valid_train_number(prompt="Enter 5-digit train number: "):


while True:
train_no = input(prompt).strip()
if validate_train_number(train_no):
return train_no
print("ERROR: Train number must be exactly 5 digits.")
4
def get_valid_integer(prompt, min_val=None, max_val=None):
while True:
try:
value = int(input(prompt))
if min_val is not None and value < min_val:
print(f"ERROR: Value must be at least {min_val}.")
continue
if max_val is not None and value > max_val:
print(f"ERROR: Value must be at most {max_val}.")
continue
return value
except ValueError:
print("ERROR: Please enter a valid number.")

def get_valid_float(prompt, min_val=None):


while True:
try:
value = float(input(prompt))
if min_val is not None and value < min_val:
print(f"ERROR: Value must be at least {min_val}.")
continue
return value
except ValueError:
print("ERROR: Please enter a valid number.")

def get_valid_time_12hr():
while True:
try:
hour = get_valid_integer(" Hour (1-12): ", 1, 12)
minute = get_valid_integer(" Minute (0-59): ", 0, 59)

while True:
ampm = input(" AM or PM: ").strip().upper()
if ampm in ["AM", "PM"]:
break
print(" ERROR: Enter AM or PM only.")

if ampm == "AM":
hour_24 = 0 if hour == 12 else hour
else:
hour_24 = 12 if hour == 12 else hour + 12

return f"{hour_24:02d}:{minute:02d}:00"
except Exception:
print("ERROR: Invalid time. Try again.")

def time_str_to_minutes(time_str):
if time_str is None:
return 0
if isinstance(time_str, timedelta):
return int(time_str.total_seconds() // 60)
parts = str(time_str).split(":")
return int(parts[0]) * 60 + int(parts[1])
5
def convert_to_12hr(time_obj):
if time_obj is None:
return "N/A"

if isinstance(time_obj, timedelta):
total_seconds = int(time_obj.total_seconds())
hours = total_seconds // 3600
minutes = (total_seconds % 3600) // 60
elif isinstance(time_obj, str):
parts = time_obj.split(":")
hours = int(parts[0])
minutes = int(parts[1])
else:
hours = time_obj.hour
minutes = time_obj.minute

if hours == 0:
return f"12:{minutes:02d} AM"
elif hours < 12:
return f"{hours}:{minutes:02d} AM"
elif hours == 12:
return f"12:{minutes:02d} PM"
else:
return f"{hours - 12}:{minutes:02d} PM"

def get_valid_date(prompt="Enter date", allow_past=False):


while True:
try:
print(f"\n{prompt}:")
day = get_valid_integer(" Day (1-31): ", 1, 31)
month = get_valid_integer(" Month (1-12): ", 1, 12)
year = get_valid_integer(" Year (e.g., 2025): ", 2020, 2035)

entered_date = date(year, month, day)


today = [Link]()

if not allow_past and entered_date < today:


print("ERROR: Date cannot be in the past!")
continue

return entered_date.strftime("%Y-%m-%d")
except ValueError:
print("ERROR: Invalid date. Please check values.")

def get_travel_date():
print("\nTravel Date (Press ENTER for today):")

while True:
date_input = input(" Enter date (DD-MM-YYYY) or press ENTER: ").strip()

if not date_input:
return [Link]().strftime("%Y-%m-%d")

6
try:
parts = date_input.split("-")
if len(parts) == 3:
day, month, year = int(parts[0]), int(parts[1]), int(parts[2])
entered_date = date(year, month, day)
today = [Link]()

if entered_date < today:


print("ERROR: Cannot book for past dates!")
print("Press ENTER for today or enter a future date.")
continue

max_date = today + timedelta(days=120)


if entered_date > max_date:
print(f"ERROR: Maximum 120 days advance booking!")
print(f"Max date: {max_date.strftime('%d-%m-%Y')}")
continue

return entered_date.strftime("%Y-%m-%d")
else:
print("ERROR: Invalid format! Use DD-MM-YYYY")
continue
except ValueError:
print("ERROR: Invalid date! Use DD-MM-YYYY")
continue

def get_yes_no(prompt):
while True:
choice = input(prompt + " (Y/N): ").strip().upper()
if choice in ["Y", "YES"]:
return True
elif choice in ["N", "NO"]:
return False
print("ERROR: Enter Y or N.")

# ============================================================
# DATABASE FUNCTIONS
# ============================================================

def connect_without_db():
return [Link](host=HOST, user=USER, password=PASSWORD)

def connect_with_db():
return [Link](host=HOST, user=USER, password=PASSWORD, database=DB_N

def check_database_exists():
conn = connect_without_db()
cursor = [Link]()
[Link]("SHOW DATABASES LIKE %s", (DB_NAME,))
result = [Link]()
[Link]()
[Link]()
return result is not None

7
def create_database():
conn = connect_without_db()
cursor = [Link]()
[Link](f"CREATE DATABASE {DB_NAME}")
[Link]()
[Link]()
[Link]()
print(f"Database '{DB_NAME}' created!")

def create_tables():
conn = connect_with_db()
cursor = [Link]()

[Link]("""
CREATE TABLE IF NOT EXISTS users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(50) NOT NULL,
full_name VARCHAR(100),
security_question VARCHAR(200),
security_answer VARCHAR(100),
role VARCHAR(10) DEFAULT 'user',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")

[Link]("""
CREATE TABLE IF NOT EXISTS states (
state_id INT AUTO_INCREMENT PRIMARY KEY,
state_name VARCHAR(100) NOT NULL UNIQUE
)
""")

[Link]("""
CREATE TABLE IF NOT EXISTS cities (
city_id INT AUTO_INCREMENT PRIMARY KEY,
city_name VARCHAR(100) NOT NULL,
state_id INT,
FOREIGN KEY (state_id) REFERENCES states(state_id)
)
""")

[Link]("""
CREATE TABLE IF NOT EXISTS stations (
station_id INT AUTO_INCREMENT PRIMARY KEY,
station_code VARCHAR(10) NOT NULL UNIQUE,
station_name VARCHAR(100) NOT NULL,
city_id INT,
platform_count INT DEFAULT 5,
FOREIGN KEY (city_id) REFERENCES cities(city_id)
)
""")

# Train number + date combination should be unique (same train can run on different d
8
[Link]("""
CREATE TABLE IF NOT EXISTS trains (
train_id INT AUTO_INCREMENT PRIMARY KEY,
train_number VARCHAR(5) NOT NULL,
train_name VARCHAR(100) NOT NULL,
start_station_id INT,
end_station_id INT,
total_distance INT DEFAULT 0,
journey_start_date DATE,
start_platform INT DEFAULT 1,
end_platform INT DEFAULT 1,
train_status VARCHAR(50) DEFAULT 'Yet to Start',
is_active BOOLEAN DEFAULT TRUE,
FOREIGN KEY (start_station_id) REFERENCES stations(station_id),
FOREIGN KEY (end_station_id) REFERENCES stations(station_id),
UNIQUE KEY unique_train_date (train_number, journey_start_date)
)
""")

[Link]("""
CREATE TABLE IF NOT EXISTS train_routes (
route_id INT AUTO_INCREMENT PRIMARY KEY,
train_id INT,
station_id INT,
stop_number INT,
arrival_time TIME,
departure_time TIME,
day_number INT DEFAULT 1,
distance_from_start INT DEFAULT 0,
platform_number INT DEFAULT 1,
halt_minutes INT DEFAULT 2,
FOREIGN KEY (train_id) REFERENCES trains(train_id) ON DELETE CASCADE,
FOREIGN KEY (station_id) REFERENCES stations(station_id)
)
""")

[Link]("""
CREATE TABLE IF NOT EXISTS train_classes (
class_id INT AUTO_INCREMENT PRIMARY KEY,
train_id INT,
class_code VARCHAR(10) NOT NULL,
class_name VARCHAR(50),
num_coaches INT DEFAULT 1,
total_seats INT DEFAULT 0,
available_seats INT DEFAULT 0,
base_fare DECIMAL(10, 2) DEFAULT 0,
FOREIGN KEY (train_id) REFERENCES trains(train_id) ON DELETE CASCADE,
UNIQUE KEY unique_train_class (train_id, class_code)
)
""")

[Link]("""
CREATE TABLE IF NOT EXISTS train_live_status (
status_id INT AUTO_INCREMENT PRIMARY KEY,
9
train_id INT UNIQUE,
current_station_id INT,
current_stop_number INT DEFAULT 1,
delay_minutes INT DEFAULT 0,
last_updated DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (train_id) REFERENCES trains(train_id) ON DELETE CASCADE,
FOREIGN KEY (current_station_id) REFERENCES stations(station_id)
)
""")

# Updated bookings table to store individual passenger details


[Link]("""
CREATE TABLE IF NOT EXISTS bookings (
booking_id INT AUTO_INCREMENT PRIMARY KEY,
pnr_number VARCHAR(10) UNIQUE,
user_id INT,
train_id INT,
class_code VARCHAR(10),
from_station_id INT,
to_station_id INT,
journey_date DATE,
booking_datetime DATETIME DEFAULT CURRENT_TIMESTAMP,
total_seats INT DEFAULT 1,
total_fare DECIMAL(10, 2),
platform_number INT,
coach_name VARCHAR(5),
booking_status VARCHAR(20) DEFAULT 'Confirmed',
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE SET NULL,
FOREIGN KEY (train_id) REFERENCES trains(train_id),
FOREIGN KEY (from_station_id) REFERENCES stations(station_id),
FOREIGN KEY (to_station_id) REFERENCES stations(station_id)
)
""")

# New table for individual passengers


[Link]("""
CREATE TABLE IF NOT EXISTS booking_passengers (
passenger_id INT AUTO_INCREMENT PRIMARY KEY,
booking_id INT,
passenger_name VARCHAR(100),
passenger_age INT,
passenger_gender VARCHAR(10),
seat_number VARCHAR(10),
status VARCHAR(20) DEFAULT 'Confirmed',
FOREIGN KEY (booking_id) REFERENCES bookings(booking_id) ON DELETE CASCADE
)
""")

[Link]()
[Link]()
[Link]()
print("Tables created/verified!")

def insert_default_data():
10
conn = connect_with_db()
cursor = [Link]()

[Link]("SELECT user_id FROM users WHERE username = 'admin'")


if not [Link]():
[Link]("""
INSERT INTO users (username, password, full_name, security_question, security
VALUES ('admin', 'admin@123', 'System Administrator', 'School name?', 'BIS',
""")
print("\nDefault Admin Created:")
print(" Username: admin")
print(" Password: admin@123")

[Link]("SELECT COUNT(*) FROM states")


if [Link]()[0] == 0:
states = [
'Andhra Pradesh', 'Assam', 'Bihar', 'Chhattisgarh', 'Delhi',
'Goa', 'Gujarat', 'Haryana', 'Jharkhand', 'Karnataka',
'Kerala', 'Madhya Pradesh', 'Maharashtra', 'Odisha', 'Punjab',
'Rajasthan', 'Tamil Nadu', 'Telangana', 'Uttar Pradesh', 'West Bengal'
]
for state in states:
[Link]("INSERT INTO states (state_name) VALUES (%s)", (state,))

cities_stations = {
'Maharashtra': [
('Mumbai', [('CSMT', 'Chhatrapati Shivaji Terminus'), ('BCT', 'Mumbai Cen
('Pune', [('PUNE', 'Pune Junction')]),
('Nagpur', [('NGP', 'Nagpur Junction')])
],
'Delhi': [
('New Delhi', [('NDLS', 'New Delhi'), ('DLI', 'Old Delhi'), ('NZM', 'Hazr
],
'Karnataka': [
('Bengaluru', [('SBC', 'KSR Bengaluru'), ('YPR', 'Yesvantpur Junction'
('Mysuru', [('MYS', 'Mysuru Junction')])
],
'Tamil Nadu': [
('Chennai', [('MAS', 'Chennai Central'), ('MS', 'Chennai Egmore')]),
('Coimbatore', [('CBE', 'Coimbatore Junction')])
],
'West Bengal': [
('Kolkata', [('HWH', 'Howrah Junction'), ('KOAA', 'Kolkata')])
],
'Gujarat': [
('Ahmedabad', [('ADI', 'Ahmedabad Junction')]),
('Surat', [('ST', 'Surat')]),
('Vadodara', [('BRC', 'Vadodara Junction')])
],
'Rajasthan': [
('Jaipur', [('JP', 'Jaipur Junction')]),
('Jodhpur', [('JU', 'Jodhpur Junction')])
],
'Uttar Pradesh': [
11
('Lucknow', [('LKO', 'Lucknow NR')]),
('Kanpur', [('CNB', 'Kanpur Central')]),
('Varanasi', [('BSB', 'Varanasi Junction')]),
('Agra', [('AGC', 'Agra Cantt')])
],
'Madhya Pradesh': [
('Bhopal', [('BPL', 'Bhopal Junction')]),
('Indore', [('INDB', 'Indore Junction')])
],
'Kerala': [
('Thiruvananthapuram', [('TVC', 'Thiruvananthapuram Central')]),
('Kochi', [('ERS', 'Ernakulam Junction')])
],
'Telangana': [
('Hyderabad', [('SC', 'Secunderabad Junction'), ('HYB', 'Hyderabad Deccan
],
'Andhra Pradesh': [
('Visakhapatnam', [('VSKP', 'Visakhapatnam')]),
('Vijayawada', [('BZA', 'Vijayawada Junction')])
],
'Punjab': [
('Amritsar', [('ASR', 'Amritsar Junction')])
],
'Bihar': [
('Patna', [('PNBE', 'Patna Junction')])
],
'Odisha': [
('Bhubaneswar', [('BBS', 'Bhubaneswar')])
],
'Jharkhand': [
('Ranchi', [('RNC', 'Ranchi')]),
('Jamshedpur', [('TATA', 'Tatanagar Junction')])
],
'Assam': [
('Guwahati', [('GHY', 'Guwahati')])
],
'Haryana': [
('Ambala', [('UMB', 'Ambala Cantt')])
],
'Goa': [
('Madgaon', [('MAO', 'Madgaon Junction')])
]
}

for state_name, cities in cities_stations.items():


[Link]("SELECT state_id FROM states WHERE state_name = %s", (state_na
state_row = [Link]()
if state_row:
state_id = state_row[0]
for city_name, stations in cities:
[Link]("INSERT INTO cities (city_name, state_id) VALUES (%s,
city_id = [Link]
for station_code, station_name in stations:
[Link]("""
12
INSERT INTO stations (station_code, station_name, city_id, pl
VALUES (%s, %s, %s, %s)
""", (station_code, station_name, city_id, [Link](5,

print("Default data inserted!")

[Link]()
[Link]()
[Link]()

def initialize_database():
print_header("DATABASE INITIALIZATION")

if check_database_exists():
print(f"Database '{DB_NAME}' found.")
else:
print(f"Database '{DB_NAME}' not found.")
if get_yes_no("Create database?"):
create_database()
else:
print("Exiting...")
exit()

create_tables()
insert_default_data()
print("\nDatabase ready!")
press_enter()

# ============================================================
# STATION FUNCTIONS
# ============================================================

def select_state():
conn = connect_with_db()
cursor = [Link]()
[Link]("SELECT state_id, state_name FROM states ORDER BY state_name")
states = [Link]()
[Link]()
[Link]()

if not states:
print("No states available.")
return None

print_subheader("SELECT STATE")
print_table(["ID", "State Name"], states)

while True:
state_id = get_valid_integer("\nEnter State ID: ")
for s in states:
if s[0] == state_id:
return state_id
print("Invalid State ID.")

13
def select_city(state_id):
conn = connect_with_db()
cursor = [Link]()
[Link]("SELECT city_id, city_name FROM cities WHERE state_id = %s ORDER BY ci
cities = [Link]()
[Link]()
[Link]()

if not cities:
print("No cities available.")
return None

print_subheader("SELECT CITY")
print_table(["ID", "City Name"], cities)

while True:
city_id = get_valid_integer("\nEnter City ID: ")
for c in cities:
if c[0] == city_id:
return city_id
print("Invalid City ID.")

def select_station(city_id):
conn = connect_with_db()
cursor = [Link]()
[Link]("SELECT station_id, station_code, station_name FROM stations WHERE cit
stations = [Link]()
[Link]()
[Link]()

if not stations:
print("No stations available.")
return None

print_subheader("SELECT STATION")
print_table(["ID", "Code", "Station Name"], stations)

while True:
station_id = get_valid_integer("\nEnter Station ID: ")
for s in stations:
if s[0] == station_id:
return station_id
print("Invalid Station ID.")

def select_station_full(prompt_text=""):
if prompt_text:
print(f"\n>>> {prompt_text}")

state_id = select_state()
if not state_id:
return None

city_id = select_city(state_id)
if not city_id:
14
return None

return select_station(city_id)

def get_station_info(station_id):
conn = connect_with_db()
cursor = [Link]()
[Link]("""
SELECT s.station_id, s.station_code, s.station_name, c.city_name, st.state_name,
FROM stations s
JOIN cities c ON s.city_id = c.city_id
JOIN states st ON c.state_id = st.state_id
WHERE s.station_id = %s
""", (station_id,))
result = [Link]()
[Link]()
[Link]()
return result

def get_station_name(station_id):
info = get_station_info(station_id)
if info:
return f"{info[2]} ({info[1]})"
return "Unknown"

def get_station_display_name(station_id):
info = get_station_info(station_id)
if info:
return f"{info[2]} ({info[1]}) - {info[3]}, {info[4]}"
return "Unknown Station"

def check_station_in_route(train_id, station_id):


conn = connect_with_db()
cursor = [Link]()
[Link]("SELECT route_id FROM train_routes WHERE train_id = %s AND station_id
result = [Link]()
[Link]()
[Link]()
return result is not None

# ============================================================
# USER AUTHENTICATION
# ============================================================

def check_username_exists(username):
conn = connect_with_db()
cursor = [Link]()
[Link]("SELECT user_id FROM users WHERE username = %s", (username,))
result = [Link]()
[Link]()
[Link]()
return result is not None

def create_user(username, password, full_name, security_question, security_answer, role=


15
conn = connect_with_db()
cursor = [Link]()
[Link]("""
INSERT INTO users (username, password, full_name, security_question, security_ans
VALUES (%s, %s, %s, %s, %s, %s)
""", (username, password, full_name, security_question, security_answer, role))
[Link]()
user_id = [Link]
[Link]()
[Link]()
return user_id

def validate_login(username, password, role=None):


conn = connect_with_db()
cursor = [Link]()

if role:
[Link]("""
SELECT user_id, username, full_name, role FROM users
WHERE username = %s AND password = %s AND role = %s
""", (username, password, role))
else:
[Link]("""
SELECT user_id, username, full_name, role FROM users
WHERE username = %s AND password = %s
""", (username, password))

result = [Link]()
[Link]()
[Link]()

if result:
return {'user_id': result[0], 'username': result[1], 'full_name': result[2],
return None

def forgot_password(role=None):
print_header("FORGOT PASSWORD")

username = input("\nEnter username: ").strip()

conn = connect_with_db()
cursor = [Link]()

if role:
[Link]("""
SELECT user_id, full_name, password, security_question, security_answer
FROM users WHERE username = %s AND role = %s
""", (username, role))
else:
[Link]("""
SELECT user_id, full_name, password, security_question, security_answer
FROM users WHERE username = %s
""", (username,))

16
user_data = [Link]()

if not user_data:
print("\nUser not found!")
[Link]()
[Link]()
return False

user_id, full_name, current_password, security_question, security_answer = user_data

print(f"\nUser: {full_name}")
print(f"Security Question: {security_question}")

for attempt in range(3):


user_answer = input(f"\nAnswer (Attempt {attempt+1}/3): ").strip()

if user_answer.lower() == security_answer.lower():
print("\n✓ Verified!")
print("\n1. View password")
print("2. Reset password")
print("0. Cancel")

choice = input("\nChoice: ").strip()

if choice == "1":
print(f"\nYour password: {current_password}")
elif choice == "2":
while True:
new_pass = input("New password (min 4 chars): ").strip()
if len(new_pass) < 4:
print("Too short!")
continue
confirm = input("Confirm: ").strip()
if new_pass != confirm:
print("Don't match!")
continue

[Link]("UPDATE users SET password = %s WHERE user_id = %s"


[Link]()
print("✓ Password reset!")
break

[Link]()
[Link]()
return True
else:
print("✗ Wrong answer!")

print("\nMax attempts exceeded!")


[Link]()
[Link]()
return False

def signup_user():
17
print_header("USER SIGNUP")

while True:
username = input("Username: ").strip()
valid, msg = validate_username(username)
if not valid:
print(f"ERROR: {msg}")
continue
if check_username_exists(username):
print("ERROR: Username exists!")
continue
break

while True:
password = input("Password (min 4 chars): ").strip()
if len(password) < 4:
print("ERROR: Too short!")
continue
confirm = input("Confirm password: ").strip()
if password != confirm:
print("ERROR: Don't match!")
continue
break

full_name = input("Full name: ").strip()

print("\nSecurity questions:")
print("1. Mother's maiden name?")
print("2. Pet's name?")
print("3. School name?")
print("4. Favorite movie?")
print("5. Custom")

choice = get_valid_integer("Choose (1-5): ", 1, 5)

questions = {
1: "What is your mother's maiden name?",
2: "What is your pet's name?",
3: "What is your school name?",
4: "What is your favorite movie?"
}

security_question = input("Custom question: ").strip() if choice == 5 else questions[


security_answer = input("Answer: ").strip()

user_id = create_user(username, password, full_name, security_question, security_answ

print_header("SIGNUP SUCCESSFUL")
print(f"User ID: {user_id}")
print(f"Username: {username}")

def login_with_forgot_option(role=None, role_name="User"):


print_header(f"{role_name.upper()} LOGIN")

18
username = input("Username: ").strip()
password = input("Password: ").strip()

user = validate_login(username, password, role)

if user:
print(f"\n✓ Welcome, {user['full_name']}!")
return user
else:
print("\n✗ Invalid credentials!")
print("\n1. Try again")
print("2. Forgot Password")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
return login_with_forgot_option(role, role_name)
elif choice == "2":
forgot_password(role)
return None

# ============================================================
# TRAIN STATUS FUNCTIONS
# ============================================================

def calculate_train_status(train_id):
"""Calculate train status based on current date/time with departed logic"""
conn = connect_with_db()
cursor = [Link]()

[Link]("SELECT journey_start_date, start_station_id FROM trains WHERE train_i


train_info = [Link]()

if not train_info:
[Link]()
[Link]()
return "Unknown", None, None

journey_date = train_info[0]

if journey_date is None:
[Link]("UPDATE trains SET train_status = 'Not Scheduled' WHERE train_id =
[Link]()
[Link]()
[Link]()
return "Not Scheduled", None, None

if isinstance(journey_date, str):
journey_date = [Link](journey_date, "%Y-%m-%d").date()

today = [Link]()
now = [Link]()

19
[Link]("""
SELECT tr.stop_number, tr.arrival_time, tr.departure_time, tr.day_number, [Link]
FROM train_routes tr
JOIN stations s ON tr.station_id = s.station_id
WHERE tr.train_id = %s ORDER BY tr.stop_number
""", (train_id,))
routes = [Link]()

if not routes:
[Link]("UPDATE trains SET train_status = 'No Route' WHERE train_id = %s"
[Link]()
[Link]()
[Link]()
return "No Route", None, None

last_stop = routes[-1]
last_day = last_stop[3]
journey_end_date = journey_date + timedelta(days=last_day - 1)

current_stop = 1
current_station_name = routes[0][4]

if today < journey_date:


days_until = (journey_date - today).days
status = f"Yet to Start (in {days_until} day{'s' if days_until > 1 else ''})"
current_stop = 1
elif today > journey_end_date:
status = "Journey Completed"
current_stop = len(routes)
current_station_name = routes[-1][4]
else:
days_from_start = (today - journey_date).days + 1
current_time = [Link]()
current_minutes = current_time.hour * 60 + current_time.minute

status = "Running"
departed_from = None
at_station = None

for i, route in enumerate(routes):


route_day = route[3]
arr_time = route[1]
dep_time = route[2]
station_name = route[4]

if route_day < days_from_start:


# All stations on previous days have been passed
departed_from = station_name
current_stop = route[0]
elif route_day == days_from_start:
arr_minutes = time_str_to_minutes(arr_time) if arr_time else 0
dep_minutes = time_str_to_minutes(dep_time) if dep_time else 1440

if dep_time and current_minutes > dep_minutes:


20
# Train has departed from this station
departed_from = station_name
current_stop = route[0]
elif arr_time and current_minutes >= arr_minutes and (not dep_time or
# Train is at this station
at_station = station_name
current_stop = route[0]
break # Found current position, no need to continue

[Link]("SELECT delay_minutes FROM train_live_status WHERE train_id = %s"


delay_row = [Link]()
delay = delay_row[0] if delay_row else 0

if at_station:
status = f"At {at_station}"
current_station_name = at_station
elif departed_from:
status = f"Departed from {departed_from}"
current_station_name = departed_from
else:
status = "Running"

if delay > 0:
status += f" (Late by {delay} min)"
elif delay < 0:
status += f" (Early by {abs(delay)} min)"

[Link]("UPDATE trains SET train_status = %s WHERE train_id = %s", (status, tr

[Link]("""
UPDATE train_live_status SET current_stop_number = %s, last_updated = NOW()
WHERE train_id = %s
""", (current_stop, train_id))

[Link]()
[Link]()
[Link]()

return status, current_stop, current_station_name

# ============================================================
# TRAIN DISPLAY FUNCTIONS
# ============================================================

def get_train_by_number(train_number):
"""Get any train by number (returns first match)"""
conn = connect_with_db()
cursor = [Link]()
[Link]("""
SELECT train_id, train_number, train_name, start_station_id, end_station_id,
train_status, is_active, total_distance, journey_start_date, start_platfor
FROM trains WHERE train_number = %s ORDER BY journey_start_date DESC LIMIT 1
""", (train_number,))
result = [Link]()
21
[Link]()
[Link]()
return result

def get_train_by_number_and_date(train_number, journey_date):


"""Get specific train by number and date"""
conn = connect_with_db()
cursor = [Link]()
[Link]("""
SELECT train_id, train_number, train_name, start_station_id, end_station_id,
train_status, is_active, total_distance, journey_start_date, start_platfor
FROM trains WHERE train_number = %s AND journey_start_date = %s
""", (train_number, journey_date))
result = [Link]()
[Link]()
[Link]()
return result

def get_train_by_id(train_id):
conn = connect_with_db()
cursor = [Link]()
[Link]("""
SELECT train_id, train_number, train_name, start_station_id, end_station_id,
train_status, is_active, total_distance, journey_start_date, start_platfor
FROM trains WHERE train_id = %s
""", (train_id,))
result = [Link]()
[Link]()
[Link]()
return result

def show_train_basic(train_id):
train = get_train_by_id(train_id)
if not train:
return

print_subheader(f"TRAIN: {train[1]} - {train[2]}")


print(f"From: {get_station_name(train[3])}")
print(f"To: {get_station_name(train[4])}")
print(f"Date: {train[8] if train[8] else 'Not Set'}")
print(f"Distance: {train[7]} km")

def show_train_routes_only(train_id):
conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT tr.stop_number, s.station_code, s.station_name,
tr.arrival_time, tr.departure_time, tr.day_number,
tr.distance_from_start, tr.platform_number, tr.station_id
FROM train_routes tr
JOIN stations s ON tr.station_id = s.station_id
WHERE tr.train_id = %s ORDER BY tr.stop_number
""", (train_id,))
22
routes = [Link]()

# Count junctions
junction_count = count_junctions_in_route(train_id)

[Link]()
[Link]()

if routes:
print_subheader(f"ROUTE DETAILS (Junctions: {junction_count}/{MAX_JUNCTIONS})"
headers = ["Stop", "Code", "Station", "Arrival", "Departure", "Day", "Distance"
rows = []
for r in routes:
arr = convert_to_12hr(r[3]) if r[3] else "Origin"
dep = convert_to_12hr(r[4]) if r[4] else "Terminus"
is_junc = "Yes" if "junction" in r[2].lower() else "No"
[Link]((r[0], r[1], r[2], arr, dep, f"Day {r[5]}", f"{r[6]} km", r[7
print_table(headers, rows)

return routes

def show_train_classes_only(train_id):
conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT class_code, class_name, num_coaches, total_seats, available_seats, base_fa
FROM train_classes WHERE train_id = %s ORDER BY class_code
""", (train_id,))
classes = [Link]()
[Link]()
[Link]()

if classes:
print_subheader("CLASS DETAILS")
headers = ["Class", "Name", "Coaches", "Total", "Available", "Booked", "Fare"
rows = []
for c in classes:
booked = c[3] - c[4]
[Link]((c[0], c[1], c[2], c[3], c[4], booked, f"Rs.{c[5]}"))
print_table(headers, rows)

return classes

def show_train_fare_only(train_id):
train = get_train_by_id(train_id)
if train:
print(f"\nTotal Distance: {train[7]} km")

conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT class_code, class_name, base_fare
23
FROM train_classes WHERE train_id = %s ORDER BY class_code
""", (train_id,))
classes = [Link]()
[Link]()
[Link]()

if classes:
print_subheader("FARE DETAILS")
print_table(["Class", "Name", "Base Fare"], [(c[0], c[1], f"Rs.{c[2]}") for c

def show_train_coaches_only(train_id):
conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT class_code, class_name, num_coaches, total_seats, available_seats
FROM train_classes WHERE train_id = %s ORDER BY class_code
""", (train_id,))
classes = [Link]()
[Link]()
[Link]()

if classes:
print_subheader("COACH DETAILS")
headers = ["Class", "Name", "Coaches", "Seats/Coach", "Total", "Available", "Book
rows = []
for c in classes:
seats_per = SEATS_PER_COACH.get(c[0], 50)
booked = c[3] - c[4]
[Link]((c[0], c[1], c[2], seats_per, c[3], c[4], booked))
print_table(headers, rows)

def view_train_info(train_number):
train = get_train_by_number(train_number)

if not train:
print("\nTrain not found!")
return False

train_id = train[0]
status, current_stop, current_station = calculate_train_status(train_id)

print_header(f"TRAIN: {train[1]} - {train[2]}")

basic_info = {
"Train Number": train[1],
"Train Name": train[2],
"From": get_station_display_name(train[3]),
"To": get_station_display_name(train[4]),
"Journey Date": str(train[8]) if train[8] else "Not Set",
"Distance": f"{train[7]} km",
"Status": status,
"Active": "Yes" if train[6] else "No"
}
24
print_subheader("BASIC INFORMATION")
print_dict_table(basic_info)

show_train_classes_only(train_id)
show_train_routes_only(train_id)

return True

def view_all_trains():
print_header("ALL TRAINS")

conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT t.train_id, t.train_number, t.train_name,
s1.station_name, s2.station_name,
t.journey_start_date, t.total_distance, t.is_active, t.train_status
FROM trains t
JOIN stations s1 ON t.start_station_id = s1.station_id
JOIN stations s2 ON t.end_station_id = s2.station_id
ORDER BY t.journey_start_date, t.train_number
""")
trains = [Link]()
[Link]()
[Link]()

if not trains:
print("\nNo trains found!")
return

print(f"\nTotal Trains: {len(trains)}")


print(f"(Max {MAX_JUNCTIONS} junctions allowed per train)\n")

rows = []
for t in trains:
status = "Active" if t[7] else "Inactive"
date_str = str(t[5]) if t[5] else "Not Set"

# Count junctions for this train


junc_count = count_junctions_in_route(t[0])

[Link]((t[1], t[2], t[3][:15], t[4][:15], date_str, f"{t[6]} km", f"{junc_co

print_table(["Number", "Name", "From", "To", "Date", "Distance", "Junctions", "Active

# ============================================================
# TRAIN MANAGEMENT FUNCTIONS
# ============================================================

def add_train_manual():
print_header("ADD TRAIN - MANUAL")

print(f"\n*** Note: Maximum {MAX_JUNCTIONS} junction stations allowed per train ***\n
25
while True:
train_name = input("Train Name: ").strip()
valid, msg = validate_train_name(train_name)
if not valid:
print(f"ERROR: {msg}")
continue
if check_train_name_exists(train_name):
print("ERROR: Train name already exists!")
continue
break

while True:
train_number = get_valid_train_number("5-digit Train Number: ")
break

# Track junction count


junction_count = 0
selected_stations = []

print("\n--- SELECT ORIGIN STATION ---")


start_station_id = select_station_full("Select ORIGIN")
if not start_station_id:
return

selected_stations.append(start_station_id)
if is_junction_station(start_station_id):
junction_count += 1
print(f" (Junction station - {junction_count}/{MAX_JUNCTIONS} junctions used)"

start_name = get_station_name(start_station_id)

print("\n--- SELECT DESTINATION STATION ---")


while True:
end_station_id = select_station_full("Select DESTINATION")
if not end_station_id:
return

if start_station_id == end_station_id:
print("ERROR: Same as origin station!")
continue

# Check junction limit


if is_junction_station(end_station_id):
if junction_count >= MAX_JUNCTIONS:
print(f"ERROR: Maximum {MAX_JUNCTIONS} junctions allowed! This is a junct
print("Please select a non-junction station.")
continue
junction_count += 1
print(f" (Junction station - {junction_count}/{MAX_JUNCTIONS} junctions used

break

selected_stations.append(end_station_id)
26
end_name = get_station_name(end_station_id)

# Get journey date and validate train_number + date combination


while True:
journey_date = get_valid_date("Train journey START date")
if check_train_number_date_exists(train_number, journey_date):
print(f"ERROR: Train {train_number} already exists for date {journey_date}!"
print("Please choose a different date or train number.")
continue
break

print(f"\n--- DEPARTURE from {start_name} ---")


start_departure = get_valid_time_12hr()
start_dep_minutes = time_str_to_minutes(start_departure)

start_platform = get_valid_integer(f"Platform at {start_name}: ", 1, 15)

print(f"\n--- ARRIVAL at {end_name} ---")


end_arrival = get_valid_time_12hr()
end_arr_minutes = time_str_to_minutes(end_arrival)

if end_arr_minutes > start_dep_minutes:


print("\nArrival day:")
print("1. Same day (Day 1)")
print("2. Next day (Day 2)")
print("3. Later")
day_choice = get_valid_integer("Choose: ", 1, 3)
if day_choice == 1:
end_day = 1
elif day_choice == 2:
end_day = 2
else:
end_day = get_valid_integer("Day number: ", 2, 7)
else:
print("\nArrival must be next day or later.")
end_day = get_valid_integer("Day number (min 2): ", 2, 7)

end_platform = get_valid_integer(f"Platform at {end_name}: ", 1, 15)

total_distance = get_valid_integer("Total distance (km): ", 1)

conn = connect_with_db()
cursor = [Link]()

[Link]("""
INSERT INTO trains (train_number, train_name, start_station_id, end_station_id,
total_distance, journey_start_date, start_platform, end_platfo
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
""", (train_number, train_name, start_station_id, end_station_id,
total_distance, journey_date, start_platform, end_platform))

train_id = [Link]

[Link]("""
27
INSERT INTO train_routes (train_id, station_id, stop_number, departure_time,
day_number, distance_from_start, platform_number)
VALUES (%s, %s, 1, %s, 1, 0, %s)
""", (train_id, start_station_id, start_departure, start_platform))

[Link]("""
INSERT INTO train_routes (train_id, station_id, stop_number, arrival_time,
day_number, distance_from_start, platform_number)
VALUES (%s, %s, 2, %s, %s, %s, %s)
""", (train_id, end_station_id, end_arrival, end_day, total_distance, end_platform))

[Link]("""
INSERT INTO train_live_status (train_id, current_station_id, current_stop_number)
VALUES (%s, %s, 1)
""", (train_id, start_station_id))

[Link]()

print_subheader("ADD COACH & FARE DETAILS")

for cls in ['1st-AC', '2nd-AC', '3rd-AC', 'SL']:


seats_per = SEATS_PER_COACH[cls]
print(f"\n--- {CLASS_NAMES[cls]} ({cls}) [{seats_per} seats/coach] ---")

num_coaches = get_valid_integer(f"Number of {cls} coaches (0 if none): ", 0,

if num_coaches > 0:
total_seats = num_coaches * seats_per
base_fare = get_valid_float(f"Base fare for {cls} (Rs.): ", 0)

[Link]("""
INSERT INTO train_classes (train_id, class_code, class_name, num_coaches,
total_seats, available_seats, base_fare)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""", (train_id, cls, CLASS_NAMES[cls], num_coaches, total_seats, total_seats,

print(f" ✓ {num_coaches} coaches, {total_seats} seats, Rs.{base_fare}")

[Link]()
[Link]()
[Link]()

print_header("TRAIN ADDED!")
print(f"Number: {train_number}")
print(f"Name: {train_name}")
print(f"Date: {journey_date}")
print(f"Route: {start_name} → {end_name}")
print(f"Junctions: {junction_count}/{MAX_JUNCTIONS}")

def add_train_automatic():
print_header("ADD TRAIN - AUTOMATIC")

conn = connect_with_db()
cursor = [Link]()
28
journey_date = ([Link]() + timedelta(days=[Link](1, 30))).strftime("%Y-%m

# Generate unique train number for this date


while True:
train_number = str([Link](10000, 99999))
if not check_train_number_date_exists(train_number, journey_date):
break

# Generate unique train name


prefixes = ["Rajdhani", "Shatabdi", "Duronto", "Garib Rath", "Superfast", "Jan Shatab
suffixes = ["Express", "Mail", "Special", "Fast"]

while True:
train_name = f"{[Link](prefixes)} {[Link](suffixes)}"
if not check_train_name_exists(train_name):
break
train_name = f"{[Link](prefixes)} {[Link](suffixes)} {[Link]
if not check_train_name_exists(train_name):
break

# Get all stations


[Link]("SELECT station_id, station_name FROM stations ORDER BY RAND()")
all_stations_data = [Link]()

if len(all_stations_data) < 6:
print("Not enough stations!")
[Link]()
[Link]()
return

# Separate junctions and non-junctions


junction_stations = []
non_junction_stations = []

for s in all_stations_data:
if "junction" in s[1].lower():
junction_stations.append(s[0])
else:
non_junction_stations.append(s[0])

# Select stations respecting MAX_JUNCTIONS limit


selected_stations = []
junction_count = 0

# We need at least 6 stations (start + 4 mid + end)


all_available = junction_stations + non_junction_stations
[Link](all_available)

for station_id in all_available:


if len(selected_stations) >= 8: # Max 8 stations
break

is_junction = station_id in junction_stations


29
if is_junction:
if junction_count < MAX_JUNCTIONS:
selected_stations.append(station_id)
junction_count += 1
else:
selected_stations.append(station_id)

if len(selected_stations) < 6:
print("Not enough valid stations!")
[Link]()
[Link]()
return

start_station_id = selected_stations[0]
end_station_id = selected_stations[1]
mid_stations = selected_stations[2:min(8, len(selected_stations))]
num_mid_stations = min(len(mid_stations), 6)
mid_stations = mid_stations[:num_mid_stations]

total_distance = [Link](500, 2500)

start_hour = [Link](5, 22)


start_min = [Link]([0, 15, 30, 45])
start_departure = f"{start_hour:02d}:{start_min:02d}:00"
start_dep_minutes = start_hour * 60 + start_min

avg_speed = [Link](50, 70)


total_journey_minutes = (total_distance / avg_speed) * 60

end_minutes = start_dep_minutes + int(total_journey_minutes)


end_day = 1
while end_minutes >= 1440:
end_minutes -= 1440
end_day += 1

end_hour = end_minutes // 60
end_min = end_minutes % 60
end_arrival = f"{end_hour:02d}:{end_min:02d}:00"

start_platform = [Link](1, 8)
end_platform = [Link](1, 8)

[Link]("""
INSERT INTO trains (train_number, train_name, start_station_id, end_station_id,
total_distance, journey_start_date, start_platform, end_platfo
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
""", (train_number, train_name, start_station_id, end_station_id,
total_distance, journey_date, start_platform, end_platform))

train_id = [Link]

total_stops = num_mid_stations + 2

30
mid_distances = []
for i in range(num_mid_stations):
min_dist = (i + 1) * (total_distance // (num_mid_stations + 2))
max_dist = (i + 2) * (total_distance // (num_mid_stations + 2))
mid_distances.append([Link](min_dist, max_dist))

time_per_segment = total_journey_minutes / (num_mid_stations + 1)

[Link]("""
INSERT INTO train_routes (train_id, station_id, stop_number, arrival_time, depart
day_number, distance_from_start, platform_number, halt_m
VALUES (%s, %s, 1, NULL, %s, 1, 0, %s, 0)
""", (train_id, start_station_id, start_departure, start_platform))

current_minutes = start_dep_minutes
current_day = 1

for i, mid_station_id in enumerate(mid_stations):


stop_number = i + 2

travel_time = int(time_per_segment * 0.9)


current_minutes += travel_time

while current_minutes >= 1440:


current_minutes -= 1440
current_day += 1

arr_hour = current_minutes // 60
arr_min = current_minutes % 60
arrival_time = f"{arr_hour:02d}:{arr_min:02d}:00"

halt_time = [Link](2, 10)


current_minutes += halt_time

while current_minutes >= 1440:


current_minutes -= 1440
current_day += 1

dep_hour = current_minutes // 60
dep_min = current_minutes % 60
departure_time = f"{dep_hour:02d}:{dep_min:02d}:00"

mid_platform = [Link](1, 8)
mid_distance = mid_distances[i]

[Link]("""
INSERT INTO train_routes (train_id, station_id, stop_number, arrival_time, de
day_number, distance_from_start, platform_number, ha
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
""", (train_id, mid_station_id, stop_number, arrival_time, departure_time,
current_day, mid_distance, mid_platform, halt_time))

[Link]("""
INSERT INTO train_routes (train_id, station_id, stop_number, arrival_time, depart
31
day_number, distance_from_start, platform_number, halt_m
VALUES (%s, %s, %s, %s, NULL, %s, %s, %s, 0)
""", (train_id, end_station_id, num_mid_stations + 2, end_arrival, end_day, total_dis

[Link]("""
INSERT INTO train_live_status (train_id, current_station_id, current_stop_number)
VALUES (%s, %s, 1)
""", (train_id, start_station_id))

fare_ranges = {
'1st-AC': (1500, 4000),
'2nd-AC': (800, 2500),
'3rd-AC': (500, 1500),
'SL': (200, 700)
}

for cls in ['1st-AC', '2nd-AC', '3rd-AC', 'SL']:


num_coaches = [Link](1, 3) if cls != 'SL' else [Link](4, 8)
total_seats = num_coaches * SEATS_PER_COACH[cls]
base_fare = [Link](fare_ranges[cls][0], fare_ranges[cls][1])

[Link]("""
INSERT INTO train_classes (train_id, class_code, class_name, num_coaches,
total_seats, available_seats, base_fare)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""", (train_id, cls, CLASS_NAMES[cls], num_coaches, total_seats, total_seats, bas

[Link]()

# Count actual junctions in the created train


actual_junction_count = count_junctions_in_route(train_id)

print_header("TRAIN CREATED!")
print(f"\nNumber: {train_number}")
print(f"Name: {train_name}")
print(f"Date: {journey_date}")
print(f"Distance: {total_distance} km")
print(f"Stops: {total_stops}")
print(f"Junctions: {actual_junction_count}/{MAX_JUNCTIONS}")

print_subheader("ROUTE")
[Link]("""
SELECT tr.stop_number, s.station_code, s.station_name,
tr.arrival_time, tr.departure_time, tr.day_number, tr.distance_from_start
FROM train_routes tr
JOIN stations s ON tr.station_id = s.station_id
WHERE tr.train_id = %s ORDER BY tr.stop_number
""", (train_id,))
routes = [Link]()

rows = []
for r in routes:
arr = convert_to_12hr(r[3]) if r[3] else "Origin"
dep = convert_to_12hr(r[4]) if r[4] else "Terminus"
32
is_junc = "Yes" if "junction" in r[2].lower() else "No"
[Link]((r[0], r[1], r[2], arr, dep, f"Day {r[5]}", f"{r[6]} km", is_junc))

print_table(["Stop", "Code", "Station", "Arrival", "Departure", "Day", "Distance"

[Link]()
[Link]()

def copy_train():
print_header("COPY EXISTING TRAIN")

print("1. By Train Number")


print("2. Search by Stations")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
train_number = get_valid_train_number()
source_train = get_train_by_number(train_number)
if not source_train:
print("Not found!")
return
source_train_id = source_train[0]
elif choice == "2":
print("\n--- SELECT START STATION ---")
start_station_id = select_station_full()
if not start_station_id:
return

print("\n--- SELECT END STATION ---")


end_station_id = select_station_full()
if not end_station_id:
return

conn = connect_with_db()
cursor = [Link]()
[Link]("""
SELECT train_id, train_number, train_name, journey_start_date
FROM trains WHERE start_station_id = %s AND end_station_id = %s
""", (start_station_id, end_station_id))
trains = [Link]()
[Link]()
[Link]()

if not trains:
print("No trains found!")
return

print_subheader("MATCHING TRAINS")
print_table(["ID", "Number", "Name", "Date"], trains)

source_train_id = get_valid_integer("\nTrain ID to copy: ")


source_train = get_train_by_id(source_train_id)
33
if not source_train:
print("Invalid ID!")
return
else:
return

source_train_name = source_train[2]
source_train_number = source_train[1]
source_train_date = source_train[8]

print_subheader("SOURCE TRAIN")
view_train_info(source_train[1])

if not get_yes_no("\nCopy this train?"):


return

# Ask about train name


print("\n--- TRAIN NAME ---")
print(f"Source: {source_train_name}")
print("\n1. Keep same name (for same train different date)")
print("2. Enter new name")

name_choice = input("\nChoice (1/2): ").strip()

if name_choice == "2":
while True:
new_name = input("New train name: ").strip()
valid, msg = validate_train_name(new_name)
if not valid:
print(f"ERROR: {msg}")
continue
if check_train_name_exists(new_name):
print("ERROR: Name exists!")
continue
break
else:
new_name = source_train_name

# Ask about train number


print("\n--- TRAIN NUMBER ---")
print(f"Source: {source_train_number}")
print("\n1. Keep same number (for same train different date)")
print("2. Generate new number")
print("3. Enter custom number")

num_choice = input("\nChoice (1/2/3): ").strip()

if num_choice == "3":
while True:
new_number = get_valid_train_number("Enter 5-digit train number: ")
break
elif num_choice == "1":
new_number = source_train_number
else:
34
while True:
new_number = str([Link](10000, 99999))
# Will validate with date later
break

# Get new date - validate with train number


print("\n--- JOURNEY DATE ---")

# Get existing dates for this train number


conn = connect_with_db()
cursor = [Link]()
[Link]("""
SELECT journey_start_date FROM trains WHERE train_number = %s ORDER BY journey_st
""", (new_number,))
existing_dates = [row[0] for row in [Link]()]
[Link]()
[Link]()

if existing_dates:
print(f"\nExisting dates for train {new_number}:")
for d in existing_dates:
print(f" - {d}")

while True:
new_date = get_valid_date("Enter NEW journey date")

if check_train_number_date_exists(new_number, new_date):
print(f"ERROR: Train {new_number} already exists for {new_date}!")
continue
break

print(f"\nNew Train Number: {new_number}")


print(f"New Train Name: {new_name}")
print(f"New Date: {new_date}")

if not get_yes_no("\nConfirm copy?"):


print("Cancelled!")
return

conn = connect_with_db()
cursor = [Link]()

[Link]("""
INSERT INTO trains (train_number, train_name, start_station_id, end_station_id,
total_distance, journey_start_date, start_platform, end_platfo
SELECT %s, %s, start_station_id, end_station_id,
total_distance, %s, start_platform, end_platform
FROM trains WHERE train_id = %s
""", (new_number, new_name, new_date, source_train_id))

new_train_id = [Link]

[Link]("""
INSERT INTO train_routes (train_id, station_id, stop_number, arrival_time, depart
35
day_number, distance_from_start, platform_number, halt_m
SELECT %s, station_id, stop_number, arrival_time, departure_time,
day_number, distance_from_start, platform_number, halt_minutes
FROM train_routes WHERE train_id = %s
""", (new_train_id, source_train_id))

[Link]("""
INSERT INTO train_classes (train_id, class_code, class_name, num_coaches,
total_seats, available_seats, base_fare)
SELECT %s, class_code, class_name, num_coaches,
total_seats, total_seats, base_fare
FROM train_classes WHERE train_id = %s
""", (new_train_id, source_train_id))

[Link]("""
INSERT INTO train_live_status (train_id, current_station_id, current_stop_number)
SELECT %s, current_station_id, 1 FROM train_live_status WHERE train_id = %s
""", (new_train_id, source_train_id))

[Link]()

if get_yes_no("\nModify details?"):
while True:
print("\n1. Edit timings")
print("2. Edit fare")
print("3. Edit coaches")
print("4. Add mid station")
print("5. Delete mid station")
print("0. Done")

mod = input("\nChoice: ").strip()

if mod == "1":
edit_train_timings(new_train_id)
elif mod == "2":
edit_train_fare_by_id(new_train_id)
elif mod == "3":
edit_train_coaches(new_train_id)
elif mod == "4":
add_mid_station(new_train_id)
elif mod == "5":
delete_mid_station(new_train_id)
elif mod == "0":
break

[Link]()
[Link]()

print_header("TRAIN COPIED!")
print(f"Number: {new_number}")
print(f"Name: {new_name}")
print(f"Date: {new_date}")

def add_mid_station(train_id):
36
conn = connect_with_db()
cursor = [Link]()

# Check current junction count


current_junction_count = count_junctions_in_route(train_id)

[Link]("""
SELECT tr.stop_number, s.station_code, s.station_name,
tr.arrival_time, tr.departure_time, tr.day_number,
tr.station_id, tr.distance_from_start
FROM train_routes tr
JOIN stations s ON tr.station_id = s.station_id
WHERE tr.train_id = %s ORDER BY tr.stop_number
""", (train_id,))
routes = [Link]()

if len(routes) < 2:
print("Route incomplete!")
[Link]()
[Link]()
return

show_train_basic(train_id)
print(f"\n*** Junctions: {current_junction_count}/{MAX_JUNCTIONS} ***")

print_subheader("CURRENT ROUTE")
rows = []
for r in routes:
arr = convert_to_12hr(r[3]) if r[3] else "Origin"
dep = convert_to_12hr(r[4]) if r[4] else "Terminus"
is_junc = "Yes" if "junction" in r[2].lower() else "No"
[Link]((r[0], r[1], r[2], arr, dep, f"Day {r[5]}", f"{r[7]} km", is_junc))
print_table(["Stop", "Code", "Station", "Arrival", "Departure", "Day", "Distance"

print("\nEnter station CODE after which to add:")


after_code = input("Station Code: ").strip().upper()

after_route = None
for r in routes:
if r[1].upper() == after_code:
after_route = r
break

if not after_route:
print("Not found!")
[Link]()
[Link]()
return

if after_route[0] == routes[-1][0]:
print("Cannot add after terminus!")
[Link]()
[Link]()
return
37
next_route = None
for r in routes:
if r[0] == after_route[0] + 1:
next_route = r
break

print("\n--- SELECT NEW STATION ---")

# Show junction warning if at limit


if current_junction_count >= MAX_JUNCTIONS:
print(f"\n*** WARNING: Junction limit ({MAX_JUNCTIONS}) reached! ***")
print("*** You can only add NON-junction stations! ***\n")

while True:
new_station_id = select_station_full()
if not new_station_id:
[Link]()
[Link]()
return

if check_station_in_route(train_id, new_station_id):
print("ERROR: Station already in route!")
continue

# Check junction limit


if is_junction_station(new_station_id):
if current_junction_count >= MAX_JUNCTIONS:
print(f"ERROR: Maximum {MAX_JUNCTIONS} junctions allowed!")
print("This is a junction station. Please select a non-junction station."
continue
else:
print(f" (Junction station - will use {current_junction_count + 1}/{MAX_

break

new_station_name = get_station_name(new_station_id)

after_distance = after_route[7] if after_route[7] else 0


next_distance = next_route[7] if next_route[7] else 0
after_day = after_route[5]
next_day = next_route[5]

after_dep_min = time_str_to_minutes(after_route[4]) if after_route[4] else 0


next_arr_min = time_str_to_minutes(next_route[3]) if next_route[3] else 1440

print(f"\n--- TIMING FOR {new_station_name} ---")

while True:
print("\nArrival time:")
arrival_time = get_valid_time_12hr()
arr_min = time_str_to_minutes(arrival_time)

print("Departure time:")
38
departure_time = get_valid_time_12hr()
dep_min = time_str_to_minutes(departure_time)

day_number = get_valid_integer(f"Day number ({after_day}-{next_day}): ", after_da

valid = True

if day_number == after_day and arr_min <= after_dep_min:


print("ERROR: Arrival must be after previous departure!")
valid = False

if day_number == next_day and dep_min >= next_arr_min:


print("ERROR: Departure must be before next arrival!")
valid = False

if arr_min > dep_min and day_number == day_number:


print("ERROR: Departure before arrival!")
valid = False

if valid:
break

while True:
distance = get_valid_integer(f"Distance ({after_distance+1} to {next_distance-1}

if distance <= after_distance:


print(f"ERROR: Must be > {after_distance} km!")
continue
if distance >= next_distance:
print(f"ERROR: Must be < {next_distance} km!")
continue
break

platform = get_valid_integer("Platform: ", 1, 15)

[Link]("""
UPDATE train_routes SET stop_number = stop_number + 1
WHERE train_id = %s AND stop_number > %s
""", (train_id, after_route[0]))

[Link]("""
INSERT INTO train_routes (train_id, station_id, stop_number, arrival_time, depart
day_number, distance_from_start, platform_number)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
""", (train_id, new_station_id, after_route[0] + 1, arrival_time, departure_time,
day_number, distance, platform))

[Link]()

# Show updated junction count


new_junction_count = count_junctions_in_route(train_id)

[Link]()
[Link]()
39
print(f"\n✓ {new_station_name} added!")
print(f" Junctions: {new_junction_count}/{MAX_JUNCTIONS}")

def delete_mid_station(train_id):
conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT tr.stop_number, s.station_code, s.station_name
FROM train_routes tr
JOIN stations s ON tr.station_id = s.station_id
WHERE tr.train_id = %s ORDER BY tr.stop_number
""", (train_id,))
routes = [Link]()

if len(routes) <= 2:
print("Cannot delete - only 2 stations!")
[Link]()
[Link]()
return

show_train_basic(train_id)
print_subheader("CURRENT ROUTE")
print_table(["Stop", "Code", "Station"], routes)

del_code = input("\nStation CODE to delete: ").strip().upper()

del_stop = None
for r in routes:
if r[1].upper() == del_code:
del_stop = r[0]
break

if not del_stop:
print("Not found!")
[Link]()
[Link]()
return

if del_stop == routes[0][0] or del_stop == routes[-1][0]:


print("Cannot delete start/end!")
[Link]()
[Link]()
return

if get_yes_no(f"Delete {del_code}?"):
[Link]("DELETE FROM train_routes WHERE train_id = %s AND stop_number = %s
(train_id, del_stop))

[Link]("SELECT route_id FROM train_routes WHERE train_id = %s ORDER BY st


route_ids = [Link]()

for idx, (rid,) in enumerate(route_ids, 1):


40
[Link]("UPDATE train_routes SET stop_number = %s WHERE route_id = %s"

[Link]()
print("✓ Deleted!")

[Link]()
[Link]()

def edit_train_timings(train_id):
conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT tr.route_id, tr.stop_number, s.station_name, s.station_code,
tr.arrival_time, tr.departure_time, tr.day_number
FROM train_routes tr
JOIN stations s ON tr.station_id = s.station_id
WHERE tr.train_id = %s ORDER BY tr.stop_number
""", (train_id,))
routes = [Link]()

if not routes:
print("No routes!")
[Link]()
[Link]()
return

show_train_basic(train_id)
print_subheader("CURRENT TIMINGS")
rows = []
for r in routes:
arr = convert_to_12hr(r[4]) if r[4] else "Origin"
dep = convert_to_12hr(r[5]) if r[5] else "Terminus"
[Link]((r[1], r[2], r[3], arr, dep, f"Day {r[6]}"))
print_table(["Stop", "Station", "Code", "Arrival", "Departure", "Day"], rows)

stop_no = get_valid_integer("\nStop number to edit: ", 1, len(routes))

selected = None
for r in routes:
if r[1] == stop_no:
selected = r
break

if not selected:
print("Invalid!")
[Link]()
[Link]()
return

print(f"\nEditing: {selected[2]} ({selected[3]})")

if stop_no > 1:
print("\nNew Arrival:")
41
new_arrival = get_valid_time_12hr()
[Link]("UPDATE train_routes SET arrival_time = %s WHERE route_id = %s"
(new_arrival, selected[0]))

if stop_no < len(routes):


print("\nNew Departure:")
new_departure = get_valid_time_12hr()
[Link]("UPDATE train_routes SET departure_time = %s WHERE route_id = %s"
(new_departure, selected[0]))

new_day = get_valid_integer(f"Day (current {selected[6]}): ", 1, 7)


[Link]("UPDATE train_routes SET day_number = %s WHERE route_id = %s",
(new_day, selected[0]))

[Link]()
[Link]()
[Link]()
print("✓ Updated!")

def edit_train_fare_by_id(train_id):
conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT class_code, class_name, base_fare FROM train_classes
WHERE train_id = %s ORDER BY class_code
""", (train_id,))
classes = [Link]()

if not classes:
print("No classes!")
[Link]()
[Link]()
return

show_train_basic(train_id)
print_subheader("FARE DETAILS")
print_table(["Class", "Name", "Fare"], [(c[0], c[1], f"Rs.{c[2]}") for c in classes])

class_code = input("\nClass to edit: ").strip().upper()

current = None
for c in classes:
if c[0].upper() == class_code.upper():
current = c
class_code = c[0]
break

if not current:
print("Invalid!")
[Link]()
[Link]()
return

42
print(f"Current: Rs.{current[2]}")
new_fare = get_valid_float("New fare: Rs.", 0)

[Link]("UPDATE train_classes SET base_fare = %s WHERE train_id = %s AND class


(new_fare, train_id, class_code))
[Link]()
[Link]()
[Link]()
print("✓ Updated!")

def edit_train_coaches(train_id):
conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT class_code, class_name, num_coaches, total_seats, available_seats
FROM train_classes WHERE train_id = %s ORDER BY class_code
""", (train_id,))
classes = [Link]()

if not classes:
print("No classes!")
[Link]()
[Link]()
return

show_train_basic(train_id)
print_subheader("COACH DETAILS")
rows = []
for c in classes:
seats_per = SEATS_PER_COACH.get(c[0], 50)
booked = c[3] - c[4]
[Link]((c[0], c[1], c[2], seats_per, c[3], c[4], booked))
print_table(["Class", "Name", "Coaches", "Seats/Coach", "Total", "Available", "Booked

class_code = input("\nClass to edit: ").strip().upper()

current = None
for c in classes:
if c[0].upper() == class_code.upper():
current = c
class_code = c[0]
break

if not current:
print("Invalid!")
[Link]()
[Link]()
return

booked = current[3] - current[4]


seats_per = SEATS_PER_COACH.get(current[0], 50)
min_coaches = (booked // seats_per) + (1 if booked % seats_per > 0 else 0)

43
print(f"\nCurrent: {current[2]} coaches, {booked} booked")

new_coaches = get_valid_integer(f"New coaches (min {max(1, min_coaches)}): ", max

new_total = new_coaches * seats_per


new_available = new_total - booked

[Link]("""
UPDATE train_classes SET num_coaches = %s, total_seats = %s, available_seats = %s
WHERE train_id = %s AND class_code = %s
""", (new_coaches, new_total, new_available, train_id, class_code))

[Link]()
[Link]()
[Link]()
print(f"✓ Updated!")

def edit_train_routes():
print_header("EDIT TRAIN ROUTES")

train_number = get_valid_train_number()
train = get_train_by_number(train_number)

if not train:
print("Not found!")
return

train_id = train[0]

while True:
show_train_basic(train_id)
show_train_routes_only(train_id)

print("\n1. Add Mid Station")


print("2. Delete Mid Station")
print("3. Edit Timing")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
add_mid_station(train_id)
elif choice == "2":
delete_mid_station(train_id)
elif choice == "3":
edit_train_timings(train_id)
elif choice == "0":
break

press_enter()

def edit_train_fare():
print_header("EDIT TRAIN FARE")

44
train_number = get_valid_train_number()
train = get_train_by_number(train_number)

if not train:
print("Not found!")
return

edit_train_fare_by_id(train[0])

def edit_train_seats():
print_header("EDIT TRAIN COACHES")

train_number = get_valid_train_number()
train = get_train_by_number(train_number)

if not train:
print("Not found!")
return

edit_train_coaches(train[0])

# ============================================================
# BOOKING FUNCTIONS
# ============================================================

def generate_pnr():
conn = connect_with_db()
cursor = [Link]()
max_attempts = 100
attempts = 0

while attempts < max_attempts:


pnr = str([Link](1000000000, 9999999999))
[Link]("SELECT booking_id FROM bookings WHERE pnr_number = %s", (pnr,))
if not [Link]():
[Link]()
[Link]()
return pnr
attempts += 1

# Fallback: use timestamp-based PNR


[Link]()
[Link]()
timestamp = int([Link]().timestamp() * 1000)
return str(timestamp)[-10:] # Last 10 digits

def get_passenger_details(num_passengers):
passengers = []

print_subheader(f"ENTER DETAILS FOR {num_passengers} PASSENGER(S)")

for i in range(num_passengers):
print(f"\n--- Passenger {i + 1} ---")

45
name = input(" Name: ").strip()
while not name:
print(" Name cannot be empty!")
name = input(" Name: ").strip()

age = get_valid_integer(" Age: ", 1, 120)

while True:
gender = input(" Gender (M/F/O): ").strip().upper()
if gender in ['M', 'F', 'O']:
gender_full = {'M': 'Male', 'F': 'Female', 'O': 'Other'}[gender]
break
print(" Enter M/F/O!")

[Link]({
'name': name,
'age': age,
'gender': gender_full
})

return passengers

def assign_coach_and_seats(train_id, class_code, num_seats):


conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT num_coaches, total_seats, available_seats FROM train_classes
WHERE train_id = %s AND class_code = %s
""", (train_id, class_code))
class_info = [Link]()
[Link]()
[Link]()

if not class_info:
return "A1", [str(i) for i in range(1, num_seats + 1)]

num_coaches, total_seats, available = class_info


booked = total_seats - available
seats_per_coach = SEATS_PER_COACH.get(class_code, 50)

# Find which coach to assign


coach_num = (booked // seats_per_coach) + 1
if coach_num > num_coaches:
coach_num = num_coaches

coach_prefix = COACH_PREFIX.get(class_code, 'X')


coach_name = f"{coach_prefix}{coach_num}"

# Calculate seat numbers within the coach


seats_booked_in_coach = booked % seats_per_coach
start_seat = seats_booked_in_coach + 1

# Check if all requested seats fit in current coach


46
if start_seat + num_seats - 1 > seats_per_coach:
# Seats will span multiple coaches - just assign sequentially
seat_numbers = [str(i) for i in range(start_seat, start_seat + num_seats)]
else:
# All seats in one coach
seat_numbers = [str(i) for i in range(start_seat, start_seat + num_seats)]

return coach_name, seat_numbers

def select_boarding_station(train_id, routes):


"""Select boarding station from train route"""
print_subheader("SELECT BOARDING STATION")

print("\nAvailable stations:")
for i, r in enumerate(routes[:-1]): # Exclude last station
arr = convert_to_12hr(r[3]) if r[3] else "Origin"
dep = convert_to_12hr(r[4]) if r[4] else "N/A"
print(f" {r[0]}. {r[2]} ({r[1]}) - Dep: {dep}")

while True:
stop_no = get_valid_integer("\nBoarding station (stop number): ", 1, len(routes)
for r in routes[:-1]: # Only check in non-last stations
if r[0] == stop_no:
return r[8], r # station_id and route info
print("Invalid! Cannot board at terminus station.")

def select_destination_station(train_id, routes, from_stop):


"""Select destination station from train route (after boarding)"""
print_subheader("SELECT DESTINATION STATION")

print("\nAvailable stations:")
available_destinations = []
for r in routes:
if r[0] > from_stop:
arr = convert_to_12hr(r[3]) if r[3] else "N/A"
print(f" {r[0]}. {r[2]} ({r[1]}) - Arr: {arr}")
available_destinations.append(r)

if not available_destinations:
print("No destination stations available!")
return None, None

while True:
stop_no = get_valid_integer("\nDestination station (stop number): ", from_stop +
for r in available_destinations:
if r[0] == stop_no:
return r[8], r # station_id and route info
print("Invalid!")

def check_train_available_for_booking(train_id, journey_date, from_station_id):


"""Check if train is available for booking on given date from given station"""
conn = connect_with_db()
cursor = [Link]()

47
# Get train info
[Link]("""
SELECT journey_start_date, (SELECT MAX(day_number) FROM train_routes WHERE train_
FROM trains WHERE train_id = %s AND is_active = TRUE
""", (train_id, train_id))
train = [Link]()

if not train:
[Link]()
[Link]()
return False, "Train not active or not found"

start_date = train[0]
max_day = train[1]

# Convert to date objects


booking_date = [Link](journey_date, "%Y-%m-%d").date()
start_date = [Link](start_date, "%Y-%m-%d").date() if isinstance(start_dat

# Calculate end date of the train journey


end_date = start_date + timedelta(days=max_day - 1)

# Check if booking_date is within the train's journey period


if booking_date < start_date or booking_date > end_date:
[Link]()
[Link]()
return False, f"Train runs from {start_date} to {end_date}, not on {booking_date}

# Calculate day number for the booking date


day_number = (booking_date - start_date).days + 1 # 1-indexed day number

# Check if boarding station exists on this day


[Link]("""
SELECT station_id FROM train_routes
WHERE train_id = %s AND day_number = %s
""", (train_id, day_number))
stations_on_day = [row[0] for row in [Link]()]

if from_station_id not in stations_on_day:


[Link]()
[Link]()
return False, f"Boarding station not in route on day {day_number}"

# Check if train has departed from boarding station


[Link]("""
SELECT departure_time FROM train_routes
WHERE train_id = %s AND station_id = %s AND day_number = %s
""", (train_id, from_station_id, day_number))
dep_time = [Link]()[0]

if dep_time:
# Calculate actual departure date from boarding station
actual_dep_date = start_date + timedelta(days=day_number - 1)
today = [Link]()
48
# Check if train has departed (only if departure is today or in the past)
if today > actual_dep_date:
[Link]()
[Link]()
return False, "Train already departed"

# Only check time if the departure is TODAY


if today == actual_dep_date:
dep_minutes = time_str_to_minutes(dep_time)
now = [Link]()
current_minutes = [Link] * 60 + [Link]
if current_minutes > dep_minutes:
[Link]()
[Link]()
return False, "Train already departed from this station"
# If departure is in the future, it's available regardless of current time

[Link]()
[Link]()
return True, "Available"

def book_ticket_by_train_no(user=None):
print_header("BOOK BY TRAIN NUMBER")

train_number = get_valid_train_number()

# Get travel date first


journey_date = get_travel_date()
print(f"\nSearching train {train_number} for {journey_date}...")

# Find train for this date


train = get_train_by_number_and_date(train_number, journey_date)

if not train:
# Check if train exists at all
any_train = get_train_by_number(train_number)
if any_train:
print(f"\nTrain {train_number} does not run on {journey_date}.")
print(f"Train runs on: {any_train[8]}")
else:
print("\nTrain not found!")
return

if not train[6]:
print("Train not active!")
return

train_id = train[0]

# Show train info


view_train_info(train_number)

# Get route for station selection


49
conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT tr.stop_number, s.station_code, s.station_name,
tr.arrival_time, tr.departure_time, tr.day_number,
tr.distance_from_start, tr.platform_number, tr.station_id
FROM train_routes tr
JOIN stations s ON tr.station_id = s.station_id
WHERE tr.train_id = %s ORDER BY tr.stop_number
""", (train_id,))
routes = [Link]()

if len(routes) < 2:
print("Invalid route!")
[Link]()
[Link]()
return

# Select boarding station


from_station_id, from_route = select_boarding_station(train_id, routes)

# Check availability from this station


available, msg = check_train_available_for_booking(train_id, journey_date, from_stati
if not available:
print(f"\nERROR: {msg}")
[Link]()
[Link]()
return

# Select destination station


to_station_id, to_route = select_destination_station(train_id, routes, from_route[

print(f"\nJourney: {from_route[2]} → {to_route[2]}")

if not get_yes_no("\nProceed?"):
[Link]()
[Link]()
return

# Get available classes


[Link]("""
SELECT class_code, class_name, available_seats, base_fare
FROM train_classes WHERE train_id = %s AND available_seats > 0
ORDER BY class_code
""", (train_id,))
classes = [Link]()

if not classes:
print("No seats!")
[Link]()
[Link]()
return

50
print_subheader("AVAILABLE CLASSES")
print_table(["Class", "Name", "Available", "Fare"],
[(c[0], c[1], c[2], f"Rs.{c[3]}") for c in classes])

while True:
class_code = input("\nClass: ").strip().upper()
selected = None
for c in classes:
if c[0].upper() == class_code.upper():
selected = c
class_code = c[0]
break
if selected:
break
print("Invalid!")

# Get number of seats


print_subheader("BOOKING DETAILS")
max_seats = min(6, selected[2])
num_seats = get_valid_integer(f"Number of passengers (1-{max_seats}): ", 1, max_seats

# Get passenger details


passengers = get_passenger_details(num_seats)

# Calculate fare per passenger (base fare is for entire journey, no distance-based di
fare_per_passenger = float(selected[3])
total_fare = fare_per_passenger * num_seats

# Get coach and seats


coach_name, seat_numbers = assign_coach_and_seats(train_id, class_code, num_seats)

# Get platform
platform = from_route[7]

pnr = generate_pnr()

# Create passenger details string


passenger_details = " | ".join([f"{p['name']} ({p['age']}/{p['gender'][0]})" for p

# Calculate travel distance for display


from_distance = from_route[6]
to_distance = to_route[6]
travel_distance = to_distance - from_distance

print_header("BOOKING SUMMARY")
details = {
"PNR": pnr,
"Train": f"{train[1]} - {train[2]}",
"Class": f"{class_code} ({selected[1]})",
"Date": journey_date,
"Passengers": passenger_details,
"Total Seats": num_seats,
"From": f"{from_route[2]} ({from_route[1]})",
"To": f"{to_route[2]} ({to_route[1]})",
51
"Distance": f"{travel_distance} km",
"Platform": platform,
"Coach": coach_name,
"Seat(s)": ", ".join(seat_numbers),
"Fare per Passenger": f"Rs.{fare_per_passenger:.2f}",
"Total Fare": f"Rs.{total_fare:.2f}"
}
print_dict_table(details)

if not get_yes_no("\nConfirm?"):
print("Cancelled!")
[Link]()
[Link]()
return

user_id = user['user_id'] if user else None

# Insert booking
[Link]("""
INSERT INTO bookings (pnr_number, user_id, train_id, class_code, from_station_id,
journey_date, total_seats, total_fare, platform_number, coac
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 'Confirmed')
""", (pnr, user_id, train_id, class_code, from_station_id, to_station_id, journey_dat
num_seats, total_fare, platform, coach_name))

booking_id = [Link]

# Insert passengers
for i, passenger in enumerate(passengers):
[Link]("""
INSERT INTO booking_passengers (booking_id, passenger_name, passenger_age, pa
VALUES (%s, %s, %s, %s, %s, 'Confirmed')
""", (booking_id, passenger['name'], passenger['age'], passenger['gender'], seat_

# Update available seats


[Link]("""
UPDATE train_classes SET available_seats = available_seats - %s
WHERE train_id = %s AND class_code = %s
""", (num_seats, train_id, class_code))

[Link]()
[Link]()
[Link]()

print_header("BOOKING CONFIRMED!")
print(f"\n PNR: {pnr}")
print(" Save this PNR!")

def search_train_and_book(user=None):
print_header("SEARCH & BOOK TRAIN")

print("\n--- BOARDING STATION ---")


from_station = select_station_full()
if not from_station:
52
return

print("\n--- DESTINATION STATION ---")


to_station = select_station_full()
if not to_station:
return

if from_station == to_station:
print("Same station!")
return

# Get travel date first


journey_date = get_travel_date()
journey_date_obj = [Link](journey_date, "%Y-%m-%d").date()

print(f"\nSearching trains for {journey_date}...")


print(f"From: {get_station_name(from_station)}")
print(f"To: {get_station_name(to_station)}")

conn = connect_with_db()
cursor = [Link]()

# Find trains that pass through both stations in correct order


[Link]("""
SELECT DISTINCT t.train_id, t.train_number, t.train_name,
r1.departure_time, r2.arrival_time, t.journey_start_date,
r1.day_number, r1.stop_number as from_stop, r2.stop_number as to_stop,
t.total_distance, r1.distance_from_start as from_dist, r2.distance_from_st
FROM trains t
JOIN train_routes r1 ON t.train_id = r1.train_id AND r1.station_id = %s
JOIN train_routes r2 ON t.train_id = r2.train_id AND r2.station_id = %s
WHERE r1.stop_number < r2.stop_number
AND t.is_active = TRUE
AND t.journey_start_date = %s
ORDER BY r1.departure_time
""", (from_station, to_station, journey_date))

all_trains = [Link]()

# Filter available trains


available_trains = []
today = [Link]()

for t in all_trains:
train_date = t[5]
if isinstance(train_date, str):
train_date = [Link](train_date, "%Y-%m-%d").date()

dep_day = t[6]
dep_time = t[3]

# Calculate actual departure date from boarding station


actual_dep_date = train_date + timedelta(days=dep_day - 1)

53
# Check if train has departed
if today > actual_dep_date:
continue

# Only check time if the actual departure date is TODAY


if today == actual_dep_date:
dep_minutes = time_str_to_minutes(dep_time)
now = [Link]()
current_minutes = [Link] * 60 + [Link]
if current_minutes > dep_minutes:
continue
# If departure is in the future, don't check current time

# Check available seats


[Link]("""
SELECT SUM(available_seats) FROM train_classes WHERE train_id = %s
""", (t[0],))
seats = [Link]()[0]
if not seats or seats <= 0:
continue

available_trains.append(t)

if not available_trains:
print(f"\nNo available trains for {journey_date}!")
[Link]()
[Link]()
return

print_subheader(f"AVAILABLE TRAINS ({len(available_trains)})")

rows = []
for t in available_trains:
dep = convert_to_12hr(t[3]) if t[3] else "N/A"
arr = convert_to_12hr(t[4]) if t[4] else "N/A"
distance = t[11] - t[10] # to_dist - from_dist

[Link]("""
SELECT class_code, available_seats FROM train_classes
WHERE train_id = %s AND available_seats > 0
""", (t[0],))
seats_info = [Link]()
seats_str = ", ".join([f"{s[0]}:{s[1]}" for s in seats_info]) if seats_info else

[Link]((t[1], t[2], dep, arr, f"{distance} km", seats_str))

print_table(["Number", "Name", "Departure", "Arrival", "Distance", "Available"], rows

# Select train
print("\n" + "-" * 50)
train_no = get_valid_train_number("Enter train number to book: ")

selected_train = None
for t in available_trains:
54
if t[1] == train_no:
selected_train = t
break

if not selected_train:
print("Invalid train!")
[Link]()
[Link]()
return

train_id = selected_train[0]
travel_distance = selected_train[11] - selected_train[10]

# Get available classes


[Link]("""
SELECT class_code, class_name, available_seats, base_fare
FROM train_classes WHERE train_id = %s AND available_seats > 0
ORDER BY class_code
""", (train_id,))
classes = [Link]()

if not classes:
print("No seats!")
[Link]()
[Link]()
return

print_subheader("AVAILABLE CLASSES")
print_table(["Class", "Name", "Available", "Fare"],
[(c[0], c[1], c[2], f"Rs.{c[3]}") for c in classes])

while True:
class_code = input("\nClass: ").strip().upper()
selected = None
for c in classes:
if c[0].upper() == class_code.upper():
selected = c
class_code = c[0]
break
if selected:
break
print("Invalid!")

# Get number of seats


print_subheader("BOOKING DETAILS")
max_seats = min(6, selected[2])
num_seats = get_valid_integer(f"Number of passengers (1-{max_seats}): ", 1, max_seats

# Get passenger details


passengers = get_passenger_details(num_seats)

# Calculate fare per passenger (base fare is for entire journey, no distance-based di
fare_per_passenger = float(selected[3])
total_fare = fare_per_passenger * num_seats
55
# Get coach and seats
coach_name, seat_numbers = assign_coach_and_seats(train_id, class_code, num_seats)

# Get platform
[Link]("""
SELECT platform_number FROM train_routes
WHERE train_id = %s AND station_id = %s
""", (train_id, from_station))
platform_row = [Link]()
platform = platform_row[0] if platform_row else 1

pnr = generate_pnr()

passenger_details = " | ".join([f"{p['name']} ({p['age']}/{p['gender'][0]})" for p

print_header("BOOKING SUMMARY")
train = get_train_by_id(train_id)
details = {
"PNR": pnr,
"Train": f"{train[1]} - {train[2]}",
"Class": f"{class_code} ({selected[1]})",
"Date": journey_date,
"Passengers": passenger_details,
"Total Seats": num_seats,
"From": get_station_name(from_station),
"To": get_station_name(to_station),
"Distance": f"{travel_distance} km",
"Platform": platform,
"Coach": coach_name,
"Seat(s)": ", ".join(seat_numbers),
"Fare per Passenger": f"Rs.{fare_per_passenger:.2f}",
"Total Fare": f"Rs.{total_fare:.2f}"
}
print_dict_table(details)

if not get_yes_no("\nConfirm?"):
print("Cancelled!")
[Link]()
[Link]()
return

user_id = user['user_id'] if user else None

[Link]("""
INSERT INTO bookings (pnr_number, user_id, train_id, class_code, from_station_id,
journey_date, total_seats, total_fare, platform_number, coac
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 'Confirmed')
""", (pnr, user_id, train_id, class_code, from_station, to_station, journey_date,
num_seats, total_fare, platform, coach_name))

booking_id = [Link]

for i, passenger in enumerate(passengers):


56
[Link]("""
INSERT INTO booking_passengers (booking_id, passenger_name, passenger_age, pa
VALUES (%s, %s, %s, %s, %s, 'Confirmed')
""", (booking_id, passenger['name'], passenger['age'], passenger['gender'], seat_

[Link]("""
UPDATE train_classes SET available_seats = available_seats - %s
WHERE train_id = %s AND class_code = %s
""", (num_seats, train_id, class_code))

[Link]()
[Link]()
[Link]()

print_header("BOOKING CONFIRMED!")
print(f"\n PNR: {pnr}")
print(" Save this PNR!")

def cancel_booking(user=None):
print_header("CANCEL BOOKING")

pnr = input("PNR: ").strip()

conn = connect_with_db()
cursor = [Link]()

# Get booking details


if user:
[Link]("""
SELECT b.booking_id, b.pnr_number, t.train_number, t.train_name,
b.class_code, b.total_seats, b.journey_date, b.booking_status, [Link]
s1.station_name, s2.station_name
FROM bookings b
JOIN trains t ON b.train_id = t.train_id
JOIN stations s1 ON b.from_station_id = s1.station_id
JOIN stations s2 ON b.to_station_id = s2.station_id
WHERE b.pnr_number = %s AND b.user_id = %s
""", (pnr, user['user_id']))
else:
[Link]("""
SELECT b.booking_id, b.pnr_number, t.train_number, t.train_name,
b.class_code, b.total_seats, b.journey_date, b.booking_status, [Link]
s1.station_name, s2.station_name
FROM bookings b
JOIN trains t ON b.train_id = t.train_id
JOIN stations s1 ON b.from_station_id = s1.station_id
JOIN stations s2 ON b.to_station_id = s2.station_id
WHERE b.pnr_number = %s
""", (pnr,))

booking = [Link]()

if not booking:
print("Booking not found!")
57
[Link]()
[Link]()
return

if booking[7] == 'Cancelled':
print("Booking already cancelled!")
[Link]()
[Link]()
return

booking_id = booking[0]

# Get passengers
[Link]("""
SELECT passenger_id, passenger_name, passenger_age, passenger_gender, seat_number
FROM booking_passengers WHERE booking_id = %s
""", (booking_id,))
passengers = [Link]()

confirmed_passengers = [p for p in passengers if p[5] == 'Confirmed']

print_subheader("BOOKING DETAILS")
print(f"PNR: {booking[1]}")
print(f"Train: {booking[2]} - {booking[3]}")
print(f"Class: {booking[4]}")
print(f"Date: {booking[6]}")
print(f"From: {booking[9]}")
print(f"To: {booking[10]}")
print(f"Status: {booking[7]}")

print_subheader("PASSENGERS")
rows = []
for i, p in enumerate(passengers, 1):
[Link]((i, p[1], p[2], p[3], p[4], p[5]))
print_table(["#", "Name", "Age", "Gender", "Seat", "Status"], rows)

if len(confirmed_passengers) == 0:
print("\nNo confirmed passengers to cancel!")
[Link]()
[Link]()
return

# Cancellation options
print("\n--- CANCELLATION OPTIONS ---")
print("1. Cancel entire booking (all passengers)")
if len(confirmed_passengers) > 1:
print("2. Cancel specific passenger(s)")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "0":
[Link]()
[Link]()
58
return

if choice == "1":
# Cancel entire booking
if get_yes_no("\nCancel ENTIRE booking?"):
[Link]("UPDATE bookings SET booking_status = 'Cancelled' WHERE bookin
[Link]("UPDATE booking_passengers SET status = 'Cancelled' WHERE book

# Restore seats
[Link]("""
UPDATE train_classes SET available_seats = available_seats + %s
WHERE train_id = %s AND class_code = %s
""", (len(confirmed_passengers), booking[8], booking[4]))

[Link]()
print("\n✓ Entire booking cancelled!")

elif choice == "2" and len(confirmed_passengers) > 1:


# Cancel specific passengers
print("\nEnter passenger number(s) to cancel (comma separated):")
print("Example: 1,3 or just 2")

cancel_input = input("Passenger(s) to cancel: ").strip()

try:
cancel_nums = [int([Link]()) for x in cancel_input.split(",")]
except:
print("Invalid input!")
[Link]()
[Link]()
return

passengers_to_cancel = []
for num in cancel_nums:
if 1 <= num <= len(passengers):
p = passengers[num - 1]
if p[5] == 'Confirmed':
passengers_to_cancel.append(p)

if not passengers_to_cancel:
print("No valid passengers selected!")
[Link]()
[Link]()
return

print("\nPassengers to cancel:")
for p in passengers_to_cancel:
print(f" - {p[1]} (Seat: {p[4]})")

if get_yes_no("\nConfirm cancellation?"):
for p in passengers_to_cancel:
[Link]("UPDATE booking_passengers SET status = 'Cancelled' WHERE

# Restore seats
59
[Link]("""
UPDATE train_classes SET available_seats = available_seats + %s
WHERE train_id = %s AND class_code = %s
""", (len(passengers_to_cancel), booking[8], booking[4]))

# Update booking
[Link]("""
UPDATE bookings SET total_seats = total_seats - %s
WHERE booking_id = %s
""", (len(passengers_to_cancel), booking_id))

# Check if all passengers cancelled


[Link]("""
SELECT COUNT(*) FROM booking_passengers
WHERE booking_id = %s AND status = 'Confirmed'
""", (booking_id,))
remaining = [Link]()[0]

if remaining == 0:
[Link]("UPDATE bookings SET booking_status = 'Cancelled' WHERE bo
else:
[Link]("UPDATE bookings SET booking_status = 'Partial' WHERE book

[Link]()
print(f"\n✓ {len(passengers_to_cancel)} passenger(s) cancelled!")

[Link]()
[Link]()

def my_bookings(user):
print_header("MY BOOKINGS")

conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT b.booking_id, b.pnr_number, t.train_number, t.train_name, b.class_code,
b.journey_date, b.total_seats, b.total_fare,
s1.station_name, s2.station_name, b.platform_number,
b.coach_name, b.booking_status
FROM bookings b
JOIN trains t ON b.train_id = t.train_id
JOIN stations s1 ON b.from_station_id = s1.station_id
JOIN stations s2 ON b.to_station_id = s2.station_id
WHERE b.user_id = %s
ORDER BY b.booking_datetime DESC
""", (user['user_id'],))

bookings = [Link]()

if not bookings:
print("No bookings found!")
[Link]()
[Link]()
60
return

print(f"Total Bookings: {len(bookings)}\n")

for i, b in enumerate(bookings, 1):


booking_id = b[0]
status_symbol = "✓" if b[12] == 'Confirmed' else ("◐" if b[12] == 'Partial' else

print_line("=", 60)
print(f" {status_symbol} BOOKING #{i} - {b[12].upper()}")
print_line("=", 60)

print(f"\n PNR Number : {b[1]}")


print(f" Train : {b[2]} - {b[3]}")
print(f" Class : {b[4]}")
print(f" Journey Date : {b[5]}")
print(f" From : {b[8]}")
print(f" To : {b[9]}")
print(f" Platform : {b[10]}")
print(f" Coach : {b[11]}")

# Get passengers
[Link]("""
SELECT passenger_name, passenger_age, passenger_gender, seat_number, status
FROM booking_passengers WHERE booking_id = %s
""", (booking_id,))
passengers = [Link]()

confirmed_count = sum(1 for p in passengers if p[4] == 'Confirmed')


cancelled_count = sum(1 for p in passengers if p[4] == 'Cancelled')

print(f" Total Seats : {b[6]}")


print(f" Confirmed : {confirmed_count}")
if cancelled_count > 0:
print(f" Cancelled : {cancelled_count}")
print(f" Total Fare : Rs.{b[7]}")

print(f"\n Passengers:")
for p in passengers:
p_status = "✓" if p[4] == 'Confirmed' else "✗"
print(f" {p_status} {p[0]} ({p[1]}/{p[2][0]}) - Seat: {p[3]} [{p[4]}]"

print()

[Link]()
[Link]()

def track_train():
print_header("TRACK TRAIN")

train_number = get_valid_train_number()

train = get_train_by_number(train_number)
if not train:
61
print("Train not found!")
return

train_id = train[0]
status, current_stop, current_station = calculate_train_status(train_id)

print_header(f"TRAIN: {train[1]} - {train[2]}")

print(f"\nJourney Date: {train[8]}")


print(f"From: {get_station_name(train[3])}")
print(f"To: {get_station_name(train[4])}")
print(f"\n>>> CURRENT STATUS: {status}")

if current_station:
print(f">>> Current/Last Station: {current_station}")

# Show route with current position


conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT tr.stop_number, s.station_code, s.station_name,
tr.arrival_time, tr.departure_time, tr.day_number
FROM train_routes tr
JOIN stations s ON tr.station_id = s.station_id
WHERE tr.train_id = %s ORDER BY tr.stop_number
""", (train_id,))
routes = [Link]()
[Link]()
[Link]()

if routes:
print_subheader("ROUTE STATUS")
rows = []
for r in routes:
arr = convert_to_12hr(r[3]) if r[3] else "Origin"
dep = convert_to_12hr(r[4]) if r[4] else "Terminus"

# Mark current position


if current_stop and r[0] == current_stop:
position = ">>> HERE"
elif current_stop and r[0] < current_stop:
position = "✓ Passed"
else:
position = "Upcoming"

[Link]((r[0], r[1], r[2], arr, dep, f"Day {r[5]}", position))

print_table(["Stop", "Code", "Station", "Arrival", "Departure", "Day", "Status"

# ============================================================
# SETTINGS FUNCTIONS
# ============================================================

62
def change_full_name(user):
print_subheader("CHANGE NAME")
print(f"Current: {user['full_name']}")

new_name = input("New name: ").strip()


if not new_name:
print("Cannot be empty!")
return

conn = connect_with_db()
cursor = [Link]()
[Link]("UPDATE users SET full_name = %s WHERE user_id = %s", (new_name, user[
[Link]()
[Link]()
[Link]()

user['full_name'] = new_name
print("✓ Updated!")

def change_username(user):
print_subheader("CHANGE USERNAME")
print(f"Current: {user['username']}")

while True:
new_username = input("New username: ").strip()
valid, msg = validate_username(new_username)
if not valid:
print(f"ERROR: {msg}")
continue
if new_username == user['username']:
print("Same as current!")
continue
if check_username_exists(new_username):
print("Already taken!")
continue
break

conn = connect_with_db()
cursor = [Link]()
[Link]("UPDATE users SET username = %s WHERE user_id = %s", (new_username, us
[Link]()
[Link]()
[Link]()

user['username'] = new_username
print("✓ Updated!")

def change_password(user):
print_subheader("CHANGE PASSWORD")

conn = connect_with_db()
cursor = [Link]()
[Link]("SELECT password FROM users WHERE user_id = %s", (user['user_id'],))
current = [Link]()[0]
63
entered = input("Current password: ").strip()
if entered != current:
print("Wrong!")
[Link]()
[Link]()
return

while True:
new_pass = input("New password: ").strip()
if len(new_pass) < 4:
print("Too short!")
continue
confirm = input("Confirm: ").strip()
if new_pass != confirm:
print("Don't match!")
continue
break

[Link]("UPDATE users SET password = %s WHERE user_id = %s", (new_pass, user[


[Link]()
[Link]()
[Link]()
print("✓ Updated!")

def change_security_qa(user):
print_subheader("CHANGE SECURITY Q&A")

print("\n1. Mother's maiden name?")


print("2. Pet's name?")
print("3. School name?")
print("4. Favorite movie?")
print("5. Custom")

choice = get_valid_integer("Choose: ", 1, 5)

questions = {
1: "What is your mother's maiden name?",
2: "What is your pet's name?",
3: "What is your school name?",
4: "What is your favorite movie?"
}

question = input("Custom question: ").strip() if choice == 5 else questions[choice]


answer = input("Answer: ").strip()

conn = connect_with_db()
cursor = [Link]()
[Link]("UPDATE users SET security_question = %s, security_answer = %s WHERE u
(question, answer, user['user_id']))
[Link]()
[Link]()
[Link]()
print("✓ Updated!")
64
def settings_menu(user):
while True:
print_header(f"SETTINGS - {user['username']}")
print("1. Change Full Name")
print("2. Change Username")
print("3. Change Password")
print("4. Change Security Q&A")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
change_full_name(user)
elif choice == "2":
change_username(user)
elif choice == "3":
change_password(user)
elif choice == "4":
change_security_qa(user)
elif choice == "0":
break

press_enter()

# ============================================================
# ADMIN USER MANAGEMENT
# ============================================================

def view_user_info():
print_subheader("VIEW USER")

conn = connect_with_db()
cursor = [Link]()

[Link]("SELECT COUNT(*) FROM users WHERE role = 'user'")


print(f"Total users: {[Link]()[0]}")

username = input("\nUsername: ").strip()

[Link]("""
SELECT user_id, username, full_name, password, security_question, security_answer
FROM users WHERE username = %s
""", (username,))
user = [Link]()
[Link]()
[Link]()

if not user:
print("Not found!")
return

print_dict_table({
"ID": user[0],
65
"Username": user[1],
"Name": user[2],
"Password": user[3],
"Security Q": user[4],
"Security A": user[5],
"Role": user[6]
})

def delete_user():
print_subheader("DELETE USER")

conn = connect_with_db()
cursor = [Link]()

[Link]("SELECT COUNT(*) FROM users WHERE role = 'user'")


print(f"Total: {[Link]()[0]}")

username = input("\nUsername: ").strip()

if [Link]() == 'admin':
print("Cannot delete admin!")
[Link]()
[Link]()
return

[Link]("SELECT user_id, full_name, role FROM users WHERE username = %s", (use
user = [Link]()

if not user:
print("Not found!")
[Link]()
[Link]()
return

if user[2] == 'admin':
print("Cannot delete admin!")
[Link]()
[Link]()
return

if get_yes_no(f"Delete {user[1]}?"):
[Link]("DELETE FROM users WHERE user_id = %s", (user[0],))
[Link]()
print("✓ Deleted!")

[Link]()
[Link]()

def add_user_admin():
print_subheader("ADD USER")
signup_user()

def list_all_users():
print_subheader("ALL USERS")
66
conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT user_id, username, full_name, role, created_at
FROM users ORDER BY user_id
""")
users = [Link]()
[Link]()
[Link]()

if not users:
print("No users found!")
return

rows = []
for u in users:
[Link]((u[0], u[1], u[2], u[3], str(u[4])[:10] if u[4] else "N/A"))

print_table(["ID", "Username", "Full Name", "Role", "Created"], rows)

def user_management_menu():
while True:
print_header("USER MANAGEMENT")
print("1. View All Users")
print("2. View User Details")
print("3. Delete User")
print("4. Add User")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
list_all_users()
elif choice == "2":
view_user_info()
elif choice == "3":
delete_user()
elif choice == "4":
add_user_admin()
elif choice == "0":
break

press_enter()

# ============================================================
# MENU FUNCTIONS
# ============================================================

def train_settings_menu():
while True:
print_header("TRAIN SETTINGS")
print("1. View All Trains")
67
print("2. View Train Details")
print("3. Add Train")
print("4. Edit Routes")
print("5. Edit Fare")
print("6. Edit Coaches")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
view_all_trains()
elif choice == "2":
train_no = get_valid_train_number()
view_train_info(train_no)
elif choice == "3":
print("\n1. Manual")
print("2. Automatic")
print("3. Copy Existing")
print("0. Back")
sub = input("\nChoice: ").strip()
if sub == "1":
add_train_manual()
elif sub == "2":
add_train_automatic()
elif sub == "3":
copy_train()
elif choice == "4":
edit_train_routes()
elif choice == "5":
edit_train_fare()
elif choice == "6":
edit_train_seats()
elif choice == "0":
break

press_enter()

def booking_menu(user=None):
while True:
print_header("BOOKING")
print("1. Book Ticket")
print("2. Cancel Booking")
if user:
print("3. My Bookings")
else:
print("3. View Booking by PNR")
print("4. My Bookings")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
print("\n1. By Train Number")
print("2. Search by Stations")
68
print("0. Back")
sub = input("\nChoice: ").strip()
if sub == "1":
book_ticket_by_train_no(user)
elif sub == "2":
search_train_and_book(user)
elif choice == "2":
cancel_booking(user)
elif choice == "3":
if user:
my_bookings(user)
else:
view_booking_by_pnr()
elif choice == "4" and not user:
my_bookings(user='NULL')
elif choice == "0":
break

press_enter()

def view_booking_by_pnr():
print_subheader("VIEW BOOKING")

pnr = input("PNR: ").strip()

conn = connect_with_db()
cursor = [Link]()

[Link]("""
SELECT b.booking_id, b.pnr_number, t.train_number, t.train_name,
b.class_code, b.journey_date, b.total_seats, b.total_fare,
s1.station_name, s2.station_name, b.platform_number,
b.coach_name, b.booking_status
FROM bookings b
JOIN trains t ON b.train_id = t.train_id
JOIN stations s1 ON b.from_station_id = s1.station_id
JOIN stations s2 ON b.to_station_id = s2.station_id
WHERE b.pnr_number = %s
""", (pnr,))

booking = [Link]()

if not booking:
print("Booking not found!")
[Link]()
[Link]()
return

booking_id = booking[0]

print_subheader(f"BOOKING - {booking[12]}")

print(f"\n PNR Number : {booking[1]}")


print(f" Train : {booking[2]} - {booking[3]}")
69
print(f" Class : {booking[4]}")
print(f" Journey Date : {booking[5]}")
print(f" From : {booking[8]}")
print(f" To : {booking[9]}")
print(f" Platform : {booking[10]}")
print(f" Coach : {booking[11]}")

# Get passengers
[Link]("""
SELECT passenger_name, passenger_age, passenger_gender, seat_number, status
FROM booking_passengers WHERE booking_id = %s
""", (booking_id,))
passengers = [Link]()

confirmed_count = sum(1 for p in passengers if p[4] == 'Confirmed')


cancelled_count = sum(1 for p in passengers if p[4] == 'Cancelled')

print(f" Total Seats : {booking[6]}")


print(f" Confirmed : {confirmed_count}")
if cancelled_count > 0:
print(f" Cancelled : {cancelled_count}")
print(f" Total Fare : Rs.{booking[7]}")
print(f" Status : {booking[12]}")

print(f"\n Passengers:")
for p in passengers:
p_status = "✓" if p[4] == 'Confirmed' else "✗"
print(f" {p_status} {p[0]} ({p[1]}/{p[2][0]}) - Seat: {p[3]} [{p[4]}]")

[Link]()
[Link]()

def admin_menu(admin_user):
while True:
print_header(f"ADMIN - {admin_user['full_name']}")
print("1. Train Settings")
print("2. Booking")
print("3. User Management")
print("4. My Settings")
print("0. Logout")

choice = input("\nChoice: ").strip()

if choice == "1":
train_settings_menu()
elif choice == "2":
booking_menu(None)
elif choice == "3":
user_management_menu()
elif choice == "4":
settings_menu(admin_user)
elif choice == "0":
print("Logging out...")
break
70
else:
print_header("WRONG CHOICE")

def user_menu(user):
while True:
print_header(f"USER - {user['full_name']}")
print("1. Booking")
print("2. Track Train")
print("3. Settings")
print("0. Logout")

choice = input("\nChoice: ").strip()

if choice == "1":
booking_menu(user)
elif choice == "2":
track_train()
press_enter()
elif choice == "3":
settings_menu(user)
elif choice == "0":
print("Logging out...")
break
else:
print_header("WRONG CHOICE")

def admin_login_menu():
while True:
print_header("ADMIN LOGIN")
print("1. Login")
print("2. Forgot Password")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
user = login_with_forgot_option('admin', 'Admin')
if user:
press_enter()
admin_menu(user)
elif choice == "2":
forgot_password('admin')
elif choice == "0":
break
else:
print_header("WRONG CHOICE")

press_enter()

def user_login_menu():
while True:
print_header("USER LOGIN / SIGNUP")
print("1. Login")
print("2. Signup")
71
print("3. Forgot Password")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
user = login_with_forgot_option('user', 'User')
if user:
press_enter()
user_menu(user)
elif choice == "2":
signup_user()
elif choice == "3":
forgot_password('user')
elif choice == "0":
break
else:
print_header("WRONG CHOICE")

press_enter()

def login_menu():
while True:
print_header("LOGIN / SIGNUP")
print("1. Admin Login")
print("2. User Login / Signup")
print("0. Back")

choice = input("\nChoice: ").strip()

if choice == "1":
admin_login_menu()
elif choice == "2":
user_login_menu()
elif choice == "0":
break
else:
print_header("WRONG CHOICE")

def main_menu():
while True:
print_header("RAILWAY MANAGEMENT SYSTEM")
print("\n1. Login / Signup")
print("0. Exit")

choice = input("\nChoice: ").strip()

if choice == "1":
login_menu()
elif choice == "0":
print_header("THANK YOU!")
print(" Goodbye!")
break

72
# ============================================================
# MAIN PROGRAM
# ============================================================

if __name__ == "__main__":
print_header("RAILWAY MANAGEMENT SYSTEM")
print(" Starting...")

try:
initialize_database()
main_menu()
except [Link] as err:
print(f"\nDatabase Error: {err}")
print("Please check your MySQL connection settings.")
except KeyboardInterrupt:
print("\n\nProgram interrupted. Goodbye!")
except Exception as e:
print(f"\nError: {e}")

73

You might also like