Finance_app / migrate.py
ErhaTechnologies's picture
Update migrate.py
5a0f5f0 verified
Raw
History Blame Contribute Delete
7.34 kB
import os
import bcrypt
from datetime import datetime
from sqlalchemy import text, inspect
from database import engine
def run_migrations():
print("Running database migrations...")
run_engine_migrations(engine)
def run_db_migrations(engine_param):
print("Running SQLAlchemy engine migrations...")
run_engine_migrations(engine_param)
def run_engine_migrations(engine):
# Get database inspector
inspector = inspect(engine)
# 0. Seed default user if not exists (in users table)
if "users" in inspector.get_table_names():
try:
with engine.connect() as conn:
result = conn.execute(text("SELECT id FROM users WHERE id = 1")).fetchone()
if not result:
hashed_pass = bcrypt.hashpw(b"admin123", bcrypt.gensalt()).decode('utf-8')
conn.execute(
text("INSERT INTO users (id, email, hashed_password, company_name, created_at) VALUES (1, :email, :password, :company, :created)"),
{
"email": "admin@founder.os",
"password": hashed_pass,
"company": "Erha Technologies",
"created": datetime.utcnow()
}
)
conn.commit()
print("Migration: Inserted default admin user.")
except Exception as e:
print(f"Error seeding default user: {e}")
# 1. Migrate clients table
if "clients" in inspector.get_table_names():
columns_clients = [c['name'] for c in inspector.get_columns('clients')]
migrations_clients = [
("description", "TEXT"),
("is_active", "BOOLEAN DEFAULT TRUE"),
("advance_payment", "FLOAT DEFAULT 0.0"),
("remaining_payment", "FLOAT DEFAULT 0.0"),
("joining_date", "TIMESTAMP"),
("company", "VARCHAR(255)"),
("address", "TEXT")
]
for col_name, col_type in migrations_clients:
if col_name not in columns_clients:
try:
with engine.begin() as conn:
conn.execute(text(f"ALTER TABLE clients ADD COLUMN {col_name} {col_type}"))
print(f"Migration: Added column '{col_name}' ({col_type}) to 'clients' table.")
except Exception as e:
print(f"Error adding '{col_name}' to 'clients': {e}")
# 2. Migrate employees table
if "employees" in inspector.get_table_names():
columns_employees = [c['name'] for c in inspector.get_columns('employees')]
migrations_employees = [
("bank_account_number", "VARCHAR(255)"),
("bank_name", "VARCHAR(255)"),
("account_title", "VARCHAR(255)"),
("starting_salary", "FLOAT DEFAULT 0.0")
]
for col_name, col_type in migrations_employees:
if col_name not in columns_employees:
try:
with engine.begin() as conn:
conn.execute(text(f"ALTER TABLE employees ADD COLUMN {col_name} {col_type}"))
print(f"Migration: Added column '{col_name}' ({col_type}) to 'employees' table.")
if col_name == "starting_salary":
with engine.begin() as conn:
conn.execute(text("UPDATE employees SET starting_salary = base_salary WHERE starting_salary IS NULL OR starting_salary = 0.0"))
except Exception as e:
print(f"Error adding '{col_name}' to 'employees': {e}")
# 3. Add user_id column to all entity tables for multi-tenancy
tables_to_migrate = ["clients", "employees", "bank_accounts", "invoices", "payroll", "revenues", "expenses", "security_config", "personal_expenses"]
for table in tables_to_migrate:
if table in inspector.get_table_names():
columns = [c['name'] for c in inspector.get_columns(table)]
if "user_id" not in columns:
try:
with engine.begin() as conn:
conn.execute(text(f"ALTER TABLE {table} ADD COLUMN user_id INTEGER DEFAULT 1"))
print(f"Migration: Added 'user_id' column to '{table}' table.")
except Exception as e:
print(f"Error adding 'user_id' to '{table}': {e}")
# 4. Add employee_id, payroll_id and created_at columns to expenses table
if "expenses" in inspector.get_table_names():
columns_expenses = [c['name'] for c in inspector.get_columns('expenses')]
migrations_expenses = [
("employee_id", "INTEGER"),
("payroll_id", "INTEGER"),
("created_at", "TIMESTAMP"),
("target_month", "VARCHAR(50)"),
("target_year", "INTEGER")
]
for col_name, col_type in migrations_expenses:
if col_name not in columns_expenses:
try:
with engine.begin() as conn:
conn.execute(text(f"ALTER TABLE expenses ADD COLUMN {col_name} {col_type}"))
print(f"Migration: Added column '{col_name}' ({col_type}) to 'expenses' table.")
except Exception as e:
print(f"Error adding '{col_name}' to 'expenses': {e}")
# 5. Add invoice_id, payroll_id, expense_id, revenue_id columns to transactions table
if "transactions" in inspector.get_table_names():
columns_txn = [c['name'] for c in inspector.get_columns('transactions')]
migrations_tx = [
("invoice_id", "INTEGER"),
("payroll_id", "INTEGER"),
("expense_id", "INTEGER"),
("revenue_id", "INTEGER")
]
for col_name, col_type in migrations_tx:
if col_name not in columns_txn:
try:
with engine.begin() as conn:
conn.execute(text(f"ALTER TABLE transactions ADD COLUMN {col_name} {col_type}"))
print(f"Migration: Added column '{col_name}' ({col_type}) to 'transactions' table.")
except Exception as e:
print(f"Error adding '{col_name}' to 'transactions': {e}")
# 6. Migrate salary_increments table
if "salary_increments" in inspector.get_table_names():
columns_inc = [c['name'] for c in inspector.get_columns('salary_increments')]
migrations_inc = [
("old_salary", "FLOAT DEFAULT 0.0"),
("new_salary", "FLOAT DEFAULT 0.0"),
("increment_amount", "FLOAT DEFAULT 0.0"),
("date", "TIMESTAMP")
]
for col_name, col_type in migrations_inc:
if col_name not in columns_inc:
try:
with engine.begin() as conn:
conn.execute(text(f"ALTER TABLE salary_increments ADD COLUMN {col_name} {col_type}"))
print(f"Migration: Added column '{col_name}' ({col_type}) to 'salary_increments' table.")
except Exception as e:
print(f"Error adding '{col_name}' to 'salary_increments': {e}")
print("Migrations completed successfully.")
if __name__ == "__main__":
run_migrations()