FG Scan form validation improvements with warehouse module updates

- Fixed 3 JavaScript syntax errors in fg_scan.html (lines 951, 840-950, 1175-1215)
- Restored form field validation with proper null safety checks
- Re-enabled auto-advance between form fields
- Re-enabled CP code auto-complete with hyphen detection
- Updated validation error messages with clear format specifications and examples
- Added autocomplete='off' to all input fields
- Removed auto-prefix correction feature
- Updated warehouse routes and modules for box assignment workflow
- Added/improved database initialization scripts
- Updated requirements.txt dependencies

Format specifications implemented:
- Operator Code: OP + 2 digits (example: OP01, OP99)
- CP Code: CP + 8 digits + hyphen + 4 digits (example: CP00000000-0001)
- OC1/OC2 Codes: OC + 2 digits (example: OC01, OC99)
- Defect Code: 3 digits only
This commit is contained in:
Quality App Developer
2026-01-30 10:50:06 +02:00
parent ac24e20fe1
commit b15cc93b9d
48 changed files with 16452 additions and 607 deletions

View File

@@ -1,59 +1,172 @@
#!/usr/bin/env python3
"""
Database initialization script
Creates required tables for the application
Run this script to initialize the database
Comprehensive Database Initialization Script
Creates all required tables and initializes default data
Includes schema verification to check existing databases for correctness
This script should be run once when the application starts
"""
import pymysql
import os
import sys
import logging
import hashlib
from app.config import Config
from pathlib import Path
from app.db_schema_verifier import SchemaVerifier
logging.basicConfig(level=logging.INFO)
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='[%(asctime)s] %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Database configuration from environment or Config
try:
from app.config import Config
DB_HOST = Config.DB_HOST
DB_PORT = Config.DB_PORT
DB_USER = Config.DB_USER
DB_PASSWORD = Config.DB_PASSWORD
DB_NAME = Config.DB_NAME
except ImportError:
# Fallback to environment variables if Config not available
DB_HOST = os.getenv('DB_HOST', 'mariadb')
DB_PORT = int(os.getenv('DB_PORT', '3306'))
DB_USER = os.getenv('DB_USER', 'quality_user')
DB_PASSWORD = os.getenv('DB_PASSWORD', 'quality_pass')
DB_NAME = os.getenv('DB_NAME', 'quality_db')
def hash_password(password):
"""Hash password using SHA256"""
return hashlib.sha256(password.encode()).hexdigest()
def create_database():
"""Create the database if it doesn't exist"""
def execute_sql(conn, sql, params=None, description=""):
"""Execute SQL statement and log result"""
try:
conn = pymysql.connect(
user=Config.DB_USER,
password=Config.DB_PASSWORD,
host=Config.DB_HOST,
port=Config.DB_PORT
)
cursor = conn.cursor()
if params:
cursor.execute(sql, params)
else:
cursor.execute(sql)
# Create database
cursor.execute(f"CREATE DATABASE IF NOT EXISTS `{Config.DB_NAME}`")
logger.info(f"Database {Config.DB_NAME} created or already exists")
if description:
logger.info(f"{description}")
cursor.close()
return True
except pymysql.Error as e:
if "already exists" in str(e).lower() or "duplicate" in str(e).lower():
if description:
logger.info(f"{description} (already exists)")
return True
logger.error(f"✗ SQL Error: {e}")
return False
except Exception as e:
logger.error(f"✗ Unexpected Error: {e}")
return False
def check_and_repair_database():
"""
Check existing database for correct structure
Repair any missing tables, columns, or reference data
"""
logger.info("Step 0: Checking existing database structure...")
try:
# First check if database exists
conn = pymysql.connect(
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD
)
cursor = conn.cursor()
cursor.execute(f"SHOW DATABASES LIKE %s", (DB_NAME,))
if not cursor.fetchone():
# Database doesn't exist, skip verification
logger.info(" Database doesn't exist yet, skipping structure check")
conn.close()
return True
cursor.close()
conn.close()
# Database exists, now connect to it and verify/repair structure
conn = pymysql.connect(
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD,
database=DB_NAME
)
# Run schema verification and repair
verifier = SchemaVerifier(conn)
success, summary = verifier.verify_and_repair()
# Log the summary
for line in summary.split('\n'):
if line.strip():
logger.info(f" {line}")
conn.close()
return success
except pymysql.Error as e:
if "Unknown database" in str(e):
logger.info(" Database doesn't exist yet, skipping structure check")
return True
logger.error(f"✗ Database check failed: {e}")
return False
except Exception as e:
logger.error(f"Error creating database: {e}")
raise
logger.error(f"✗ Database check error: {e}")
return False
def create_database():
"""Create the database if it doesn't exist"""
logger.info("Step 1: Creating database...")
try:
conn = pymysql.connect(
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD
)
cursor = conn.cursor()
cursor.execute(f"CREATE DATABASE IF NOT EXISTS `{DB_NAME}`")
cursor.close()
conn.close()
logger.info(f"✓ Database '{DB_NAME}' created or already exists")
return True
except Exception as e:
logger.error(f"✗ Failed to create database: {e}")
return False
def create_tables():
"""Create application tables"""
"""Create all application tables"""
logger.info("\nStep 2: Creating tables...")
try:
conn = pymysql.connect(
user=Config.DB_USER,
password=Config.DB_PASSWORD,
host=Config.DB_HOST,
port=Config.DB_PORT,
database=Config.DB_NAME
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD,
database=DB_NAME
)
cursor = conn.cursor()
# Users table
cursor.execute("""
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) UNIQUE NOT NULL,
@@ -64,11 +177,10 @@ def create_tables():
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""")
logger.info("Table 'users' created or already exists")
""", description="Table 'users'")
# User credentials table
cursor.execute("""
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS user_credentials (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
@@ -77,11 +189,10 @@ def create_tables():
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""")
logger.info("Table 'user_credentials' created or already exists")
""", description="Table 'user_credentials'")
# Quality inspections table
cursor.execute("""
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS quality_inspections (
id INT AUTO_INCREMENT PRIMARY KEY,
inspection_type VARCHAR(100),
@@ -93,11 +204,10 @@ def create_tables():
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (inspector_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""")
logger.info("Table 'quality_inspections' created or already exists")
""", description="Table 'quality_inspections'")
# Settings table
cursor.execute("""
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS application_settings (
id INT AUTO_INCREMENT PRIMARY KEY,
setting_key VARCHAR(255) UNIQUE NOT NULL,
@@ -106,11 +216,52 @@ def create_tables():
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""")
logger.info("Table 'application_settings' created or already exists")
""", description="Table 'application_settings'")
# QZ Tray Pairing Keys table
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS qz_pairing_keys (
id INT AUTO_INCREMENT PRIMARY KEY,
printer_name VARCHAR(255) NOT NULL,
pairing_key VARCHAR(255) UNIQUE NOT NULL,
valid_until DATE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""", description="Table 'qz_pairing_keys'")
# API Keys table
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS api_keys (
id INT AUTO_INCREMENT PRIMARY KEY,
key_name VARCHAR(255) NOT NULL,
key_type VARCHAR(100) NOT NULL,
api_key VARCHAR(255) UNIQUE NOT NULL,
is_active TINYINT(1) DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""", description="Table 'api_keys'")
# Backup Schedules table
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS backup_schedules (
id INT AUTO_INCREMENT PRIMARY KEY,
schedule_name VARCHAR(255) NOT NULL,
frequency VARCHAR(50) NOT NULL COMMENT 'daily or weekly',
day_of_week VARCHAR(20) COMMENT 'Monday, Tuesday, etc for weekly schedules',
time_of_day TIME NOT NULL COMMENT 'HH:MM format',
backup_type VARCHAR(50) DEFAULT 'full' COMMENT 'full or data_only',
is_active TINYINT(1) DEFAULT 1,
last_run DATETIME,
next_run DATETIME,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""", description="Table 'backup_schedules'")
# Roles table
cursor.execute("""
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS roles (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL,
@@ -119,11 +270,10 @@ def create_tables():
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""")
logger.info("Table 'roles' created or already exists")
""", description="Table 'roles'")
# User modules (which modules a user has access to)
cursor.execute("""
# User modules table
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS user_modules (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
@@ -132,11 +282,10 @@ def create_tables():
UNIQUE KEY unique_user_module (user_id, module_name),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""")
logger.info("Table 'user_modules' created or already exists")
""", description="Table 'user_modules'")
# User permissions (granular permissions)
cursor.execute("""
# User permissions table
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS user_permissions (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
@@ -149,11 +298,10 @@ def create_tables():
UNIQUE KEY unique_permission (user_id, module_name, section_name, action_name),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""")
logger.info("Table 'user_permissions' created or already exists")
""", description="Table 'user_permissions'")
# Worker-Manager bindings (for warehouse module hierarchy)
cursor.execute("""
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS worker_manager_bindings (
id INT AUTO_INCREMENT PRIMARY KEY,
manager_id INT NOT NULL,
@@ -167,27 +315,120 @@ def create_tables():
FOREIGN KEY (worker_id) REFERENCES users(id) ON DELETE CASCADE,
CHECK (manager_id != worker_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""")
logger.info("Table 'worker_manager_bindings' created or already exists")
""", description="Table 'worker_manager_bindings'")
# Warehouse Locations table
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS warehouse_locations (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
location_code VARCHAR(12) NOT NULL UNIQUE,
size INT,
description VARCHAR(250),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""", description="Table 'warehouse_locations'")
# Boxes Crates table (for quick box checkpoint)
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS boxes_crates (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
box_number VARCHAR(20) NOT NULL UNIQUE,
status ENUM('open', 'closed') DEFAULT 'open',
location_id BIGINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by INT,
FOREIGN KEY (location_id) REFERENCES warehouse_locations(id) ON DELETE SET NULL,
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
INDEX idx_box_number (box_number),
INDEX idx_status (status),
INDEX idx_location_id (location_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""", description="Table 'boxes_crates'")
# Box Contents table (CP-to-Box mapping)
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS box_contents (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
box_id BIGINT NOT NULL,
cp_code VARCHAR(50) NOT NULL,
quantity INT DEFAULT 1,
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (box_id) REFERENCES boxes_crates(id) ON DELETE CASCADE,
INDEX idx_box_id (box_id),
INDEX idx_cp_code (cp_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""", description="Table 'box_contents'")
# FG Scan Orders table
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS scanfg_orders (
id INT AUTO_INCREMENT PRIMARY KEY,
operator_code VARCHAR(50),
CP_full_code VARCHAR(50),
OC1_code VARCHAR(50),
OC2_code VARCHAR(50),
quality_code VARCHAR(10),
date DATE,
time TIME,
approved_quantity INT DEFAULT 0,
rejected_quantity INT DEFAULT 0,
box_id BIGINT,
location_id BIGINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (box_id) REFERENCES boxes_crates(id) ON DELETE SET NULL,
FOREIGN KEY (location_id) REFERENCES warehouse_locations(id) ON DELETE SET NULL,
INDEX idx_cp_code (CP_full_code),
INDEX idx_operator (operator_code),
INDEX idx_date (date),
INDEX idx_box_id (box_id),
INDEX idx_location_id (location_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""", description="Table 'scanfg_orders'")
# CP Location History table (audit trail)
execute_sql(conn, """
CREATE TABLE IF NOT EXISTS cp_location_history (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
cp_code VARCHAR(50) NOT NULL,
box_id BIGINT NOT NULL,
from_location_id BIGINT,
to_location_id BIGINT NOT NULL,
moved_by INT,
moved_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
reason VARCHAR(100),
FOREIGN KEY (box_id) REFERENCES boxes_crates(id) ON DELETE CASCADE,
FOREIGN KEY (from_location_id) REFERENCES warehouse_locations(id) ON DELETE SET NULL,
FOREIGN KEY (to_location_id) REFERENCES warehouse_locations(id) ON DELETE CASCADE,
FOREIGN KEY (moved_by) REFERENCES users(id) ON DELETE SET NULL,
INDEX idx_cp_code (cp_code),
INDEX idx_box_id (box_id),
INDEX idx_moved_at (moved_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
""", description="Table 'cp_location_history'")
conn.commit()
cursor.close()
conn.close()
logger.info("All tables created successfully")
logger.info("All tables created successfully")
return True
except Exception as e:
logger.error(f"Error creating tables: {e}")
raise
logger.error(f"✗ Failed to create tables: {e}")
return False
def insert_default_user():
"""Insert default admin user and roles"""
def insert_default_data():
"""Insert default roles and admin user"""
logger.info("\nStep 3: Inserting default data...")
try:
conn = pymysql.connect(
user=Config.DB_USER,
password=Config.DB_PASSWORD,
host=Config.DB_HOST,
port=Config.DB_PORT,
database=Config.DB_NAME
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD,
database=DB_NAME
)
cursor = conn.cursor()
@@ -201,72 +442,198 @@ def insert_default_user():
('warehouse_worker', 'Worker - Warehouse - Input-only warehouse access', 35),
]
logger.info(" Creating roles...")
for role_name, role_desc, role_level in roles:
cursor.execute(
"SELECT id FROM roles WHERE name = %s",
(role_name,)
)
if not cursor.fetchone():
try:
cursor.execute(
"INSERT INTO roles (name, description, level) VALUES (%s, %s, %s)",
(role_name, role_desc, role_level)
)
logger.info(f"Role '{role_name}' created")
logger.info(f"Role '{role_name}' created")
except pymysql.Error as e:
if "duplicate" in str(e).lower():
logger.info(f" ✓ Role '{role_name}' already exists")
else:
logger.warning(f" ⚠ Role '{role_name}': {e}")
# Check if admin user exists
cursor.execute("SELECT id FROM users WHERE username = 'admin'")
admin_result = cursor.fetchone()
if admin_result:
logger.info("Admin user already exists")
cursor.close()
conn.close()
return
if not admin_result:
logger.info(" Creating default admin user...")
cursor.execute(
"INSERT INTO users (username, email, full_name, role, is_active) VALUES (%s, %s, %s, %s, 1)",
('admin', 'admin@quality-app.local', 'Administrator', 'admin')
)
# Get admin user ID
cursor.execute("SELECT id FROM users WHERE username = 'admin'")
admin_id = cursor.fetchone()[0]
# Insert admin password
password_hash = hash_password('admin123')
cursor.execute(
"INSERT INTO user_credentials (user_id, password_hash) VALUES (%s, %s)",
(admin_id, password_hash)
)
logger.info(" ✓ Admin user created (username: admin, password: admin123)")
# Grant admin user access to all modules
logger.info(" Granting module access to admin user...")
modules = ['quality', 'settings']
for module in modules:
try:
cursor.execute(
"INSERT IGNORE INTO user_modules (user_id, module_name) VALUES (%s, %s)",
(admin_id, module)
)
logger.info(f" ✓ Module '{module}' granted to admin")
except pymysql.Error as e:
logger.warning(f" ⚠ Module '{module}': {e}")
else:
logger.info(" ✓ Admin user already exists")
# Insert admin user
cursor.execute("""
INSERT INTO users (username, email, full_name, role, is_active)
VALUES (%s, %s, %s, %s, 1)
""", ('admin', 'admin@quality-app.local', 'Administrator', 'admin'))
# Insert default warehouse locations
logger.info(" Creating default warehouse locations...")
warehouse_locations = [
('FG_INCOMING', 'Finished Goods Incoming', 'Initial receiving area for finished goods from production'),
('TRUCK_LOADING', 'Truck Loading Area', 'Loading and staging area for truck shipments'),
]
# Get admin user ID
cursor.execute("SELECT id FROM users WHERE username = 'admin'")
admin_id = cursor.fetchone()[0]
for location_code, location_name, description in warehouse_locations:
try:
cursor.execute(
"INSERT IGNORE INTO warehouse_locations (location_code, size, description) VALUES (%s, %s, %s)",
(location_code, 100, description)
)
logger.info(f" ✓ Warehouse location '{location_code}' created ({location_name})")
except pymysql.Error as e:
if "duplicate" in str(e).lower():
logger.info(f" ✓ Warehouse location '{location_code}' already exists")
else:
logger.warning(f" ⚠ Warehouse location '{location_code}': {e}")
# Insert admin password (default: admin123)
password_hash = hash_password('admin123')
cursor.execute("""
INSERT INTO user_credentials (user_id, password_hash)
VALUES (%s, %s)
""", (admin_id, password_hash))
# Insert default application settings
logger.info(" Creating default application settings...")
default_settings = [
('app_name', 'Quality App v2', 'string'),
('app_version', '2.0.0', 'string'),
('session_timeout', '480', 'integer'),
('backup_retention_days', '30', 'integer'),
('backup_auto_cleanup', '0', 'boolean'),
]
# Grant admin user access to all modules
modules = ['quality', 'settings']
for module in modules:
cursor.execute("""
INSERT IGNORE INTO user_modules (user_id, module_name)
VALUES (%s, %s)
""", (admin_id, module))
for setting_key, setting_value, setting_type in default_settings:
try:
cursor.execute(
"INSERT IGNORE INTO application_settings (setting_key, setting_value, setting_type) VALUES (%s, %s, %s)",
(setting_key, setting_value, setting_type)
)
logger.info(f" ✓ Setting '{setting_key}' initialized")
except pymysql.Error as e:
logger.warning(f" ⚠ Setting '{setting_key}': {e}")
conn.commit()
cursor.close()
conn.close()
logger.info("✓ Default data inserted successfully")
return True
logger.info("Default admin user created (username: admin, password: admin123)")
logger.warning("IMPORTANT: Change the default admin password after first login!")
except Exception as e:
logger.error(f"Error inserting default user: {e}")
raise
logger.error(f"✗ Failed to insert default data: {e}")
return False
def verify_database():
"""Verify all tables were created"""
logger.info("\nStep 4: Verifying database...")
try:
conn = pymysql.connect(
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD,
database=DB_NAME
)
cursor = conn.cursor()
cursor.execute("SHOW TABLES")
tables = [row[0] for row in cursor.fetchall()]
required_tables = [
'users',
'user_credentials',
'quality_inspections',
'application_settings',
'roles',
'user_modules',
'user_permissions'
]
logger.info(f" Database tables: {', '.join(tables)}")
missing = [t for t in required_tables if t not in tables]
if missing:
logger.error(f" ✗ Missing tables: {', '.join(missing)}")
conn.close()
return False
# Count records
cursor.execute("SELECT COUNT(*) FROM roles")
role_count = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(*) FROM users")
user_count = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(*) FROM user_credentials")
cred_count = cursor.fetchone()[0]
logger.info(f" ✓ All {len(required_tables)} required tables exist")
logger.info(f" ✓ Roles: {role_count}")
logger.info(f" ✓ Users: {user_count}")
logger.info(f" ✓ User credentials: {cred_count}")
conn.close()
return True
except Exception as e:
logger.error(f"✗ Verification failed: {e}")
return False
def main():
"""Main initialization flow"""
logger.info("=" * 60)
logger.info("Database Initialization Script")
logger.info("=" * 60)
logger.info(f"Target: {DB_USER}@{DB_HOST}:{DB_PORT}/{DB_NAME}\n")
steps = [
("Check/repair existing database", check_and_repair_database),
("Create database", create_database),
("Create tables", create_tables),
("Insert default data", insert_default_data),
("Verify database", verify_database),
]
failed = []
for step_name, step_func in steps:
try:
if not step_func():
failed.append(step_name)
except Exception as e:
logger.error(f"{step_name} failed: {e}")
failed.append(step_name)
logger.info("\n" + "=" * 60)
if failed:
logger.error(f"✗ FAILED: {', '.join(failed)}")
logger.info("=" * 60)
return 1
else:
logger.info("✓ Database initialization completed successfully!")
logger.info("=" * 60)
return 0
if __name__ == '__main__':
logger.info("Starting database initialization...")
try:
create_database()
create_tables()
insert_default_user()
logger.info("Database initialization completed successfully!")
except Exception as e:
logger.error(f"Database initialization failed: {e}")
exit(1)
sys.exit(main())