Initial V1 Backup
This commit is contained in:
234
migrate_current_global.py
Normal file
234
migrate_current_global.py
Normal file
@@ -0,0 +1,234 @@
|
||||
"""
|
||||
Migration Script: Make CURRENT baseline global (not session-specific)
|
||||
Run this once to update your database schema
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
# Database path
|
||||
DB_PATH = os.path.join(os.path.dirname(__file__), 'database', 'scanlook.db')
|
||||
|
||||
def run_migration():
|
||||
print("Starting migration...")
|
||||
print(f"Database: {DB_PATH}")
|
||||
|
||||
# Backup first!
|
||||
backup_path = DB_PATH + '.backup_before_current_migration'
|
||||
import shutil
|
||||
shutil.copy2(DB_PATH, backup_path)
|
||||
print(f"✅ Backup created: {backup_path}")
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
# Step 1: Create new global CURRENT table
|
||||
print("\nStep 1: Creating new BaselineInventory_Current table...")
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS BaselineInventory_Current_New (
|
||||
current_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
lot_number TEXT NOT NULL,
|
||||
item TEXT NOT NULL,
|
||||
description TEXT,
|
||||
system_location TEXT,
|
||||
system_bin TEXT NOT NULL,
|
||||
system_quantity REAL NOT NULL,
|
||||
upload_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(lot_number, system_bin)
|
||||
)
|
||||
''')
|
||||
print("✅ New CURRENT table created")
|
||||
|
||||
# Step 2: Copy latest CURRENT data
|
||||
print("\nStep 2: Copying latest CURRENT data...")
|
||||
cursor.execute('''
|
||||
INSERT OR IGNORE INTO BaselineInventory_Current_New
|
||||
(lot_number, item, description, system_location, system_bin, system_quantity, upload_timestamp)
|
||||
SELECT
|
||||
lot_number,
|
||||
item,
|
||||
description,
|
||||
system_location,
|
||||
system_bin,
|
||||
system_quantity,
|
||||
uploaded_timestamp
|
||||
FROM BaselineInventory_Current
|
||||
WHERE is_deleted = 0
|
||||
AND baseline_version = (SELECT MAX(baseline_version) FROM BaselineInventory_Current WHERE is_deleted = 0)
|
||||
''')
|
||||
rows = cursor.rowcount
|
||||
print(f"✅ Copied {rows} CURRENT baseline records")
|
||||
|
||||
# Step 3: Drop old CURRENT table
|
||||
print("\nStep 3: Dropping old CURRENT table...")
|
||||
cursor.execute('DROP TABLE IF EXISTS BaselineInventory_Current')
|
||||
print("✅ Old CURRENT table dropped")
|
||||
|
||||
# Step 4: Rename new table
|
||||
print("\nStep 4: Renaming new CURRENT table...")
|
||||
cursor.execute('ALTER TABLE BaselineInventory_Current_New RENAME TO BaselineInventory_Current')
|
||||
print("✅ Table renamed")
|
||||
|
||||
# Step 5: Create new ScanEntries without CURRENT columns
|
||||
print("\nStep 5: Creating new ScanEntries table (without CURRENT columns)...")
|
||||
cursor.execute('''
|
||||
CREATE TABLE ScanEntries_New (
|
||||
entry_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
session_id INTEGER NOT NULL,
|
||||
location_count_id INTEGER NOT NULL,
|
||||
lot_number TEXT NOT NULL,
|
||||
item TEXT,
|
||||
description TEXT,
|
||||
scanned_location TEXT NOT NULL,
|
||||
actual_weight REAL NOT NULL,
|
||||
scanned_by INTEGER NOT NULL,
|
||||
scan_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
master_status TEXT,
|
||||
master_expected_location TEXT,
|
||||
master_expected_weight REAL,
|
||||
master_variance_lbs REAL,
|
||||
master_variance_pct REAL,
|
||||
|
||||
duplicate_status TEXT DEFAULT '00',
|
||||
duplicate_info TEXT,
|
||||
|
||||
comment TEXT,
|
||||
is_deleted INTEGER DEFAULT 0,
|
||||
deleted_by INTEGER,
|
||||
deleted_timestamp DATETIME,
|
||||
modified_timestamp DATETIME,
|
||||
|
||||
FOREIGN KEY (session_id) REFERENCES CountSessions(session_id),
|
||||
FOREIGN KEY (location_count_id) REFERENCES LocationCounts(location_count_id),
|
||||
FOREIGN KEY (scanned_by) REFERENCES Users(user_id),
|
||||
FOREIGN KEY (deleted_by) REFERENCES Users(user_id)
|
||||
)
|
||||
''')
|
||||
print("✅ New ScanEntries table created")
|
||||
|
||||
# Step 6: Copy scan data
|
||||
print("\nStep 6: Copying scan data...")
|
||||
cursor.execute('''
|
||||
INSERT INTO ScanEntries_New
|
||||
SELECT
|
||||
entry_id,
|
||||
session_id,
|
||||
location_count_id,
|
||||
lot_number,
|
||||
item,
|
||||
description,
|
||||
scanned_location,
|
||||
actual_weight,
|
||||
scanned_by,
|
||||
scan_timestamp,
|
||||
master_status,
|
||||
master_expected_location,
|
||||
master_expected_weight,
|
||||
master_variance_lbs,
|
||||
master_variance_pct,
|
||||
duplicate_status,
|
||||
duplicate_info,
|
||||
comment,
|
||||
is_deleted,
|
||||
deleted_by,
|
||||
deleted_timestamp,
|
||||
modified_timestamp
|
||||
FROM ScanEntries
|
||||
''')
|
||||
rows = cursor.rowcount
|
||||
print(f"✅ Copied {rows} scan entries")
|
||||
|
||||
# Step 7: Drop old and rename
|
||||
print("\nStep 7: Replacing old ScanEntries table...")
|
||||
cursor.execute('DROP TABLE ScanEntries')
|
||||
cursor.execute('ALTER TABLE ScanEntries_New RENAME TO ScanEntries')
|
||||
print("✅ ScanEntries table updated")
|
||||
|
||||
# Step 8: Recreate indexes
|
||||
print("\nStep 8: Recreating indexes...")
|
||||
cursor.execute('CREATE INDEX idx_scanentries_session ON ScanEntries(session_id)')
|
||||
cursor.execute('CREATE INDEX idx_scanentries_location ON ScanEntries(location_count_id)')
|
||||
cursor.execute('CREATE INDEX idx_scanentries_lot ON ScanEntries(lot_number)')
|
||||
cursor.execute('CREATE INDEX idx_scanentries_deleted ON ScanEntries(is_deleted)')
|
||||
print("✅ Indexes created")
|
||||
|
||||
# Step 9: Create new CountSessions
|
||||
print("\nStep 9: Creating new CountSessions table...")
|
||||
cursor.execute('''
|
||||
CREATE TABLE CountSessions_New (
|
||||
session_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
session_name TEXT NOT NULL,
|
||||
session_type TEXT NOT NULL CHECK(session_type IN ('cycle_count', 'full_physical')),
|
||||
created_by INTEGER NOT NULL,
|
||||
created_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
master_baseline_timestamp DATETIME,
|
||||
current_baseline_timestamp DATETIME,
|
||||
status TEXT DEFAULT 'active' CHECK(status IN ('active', 'completed', 'archived')),
|
||||
branch TEXT DEFAULT 'Main',
|
||||
FOREIGN KEY (created_by) REFERENCES Users(user_id)
|
||||
)
|
||||
''')
|
||||
print("✅ New CountSessions table created")
|
||||
|
||||
# Step 10: Copy session data
|
||||
print("\nStep 10: Copying session data...")
|
||||
cursor.execute('''
|
||||
INSERT INTO CountSessions_New
|
||||
SELECT
|
||||
session_id,
|
||||
session_name,
|
||||
session_type,
|
||||
created_by,
|
||||
created_timestamp,
|
||||
master_baseline_timestamp,
|
||||
current_baseline_timestamp,
|
||||
status,
|
||||
branch
|
||||
FROM CountSessions
|
||||
''')
|
||||
rows = cursor.rowcount
|
||||
print(f"✅ Copied {rows} sessions")
|
||||
|
||||
# Step 11: Replace CountSessions
|
||||
print("\nStep 11: Replacing old CountSessions table...")
|
||||
cursor.execute('DROP TABLE CountSessions')
|
||||
cursor.execute('ALTER TABLE CountSessions_New RENAME TO CountSessions')
|
||||
print("✅ CountSessions table updated")
|
||||
|
||||
# Commit all changes
|
||||
conn.commit()
|
||||
print("\n" + "="*50)
|
||||
print("🎉 MIGRATION COMPLETE!")
|
||||
print("="*50)
|
||||
print("\nChanges made:")
|
||||
print(" ✅ BaselineInventory_Current is now GLOBAL (not session-specific)")
|
||||
print(" ✅ Removed CURRENT columns from ScanEntries")
|
||||
print(" ✅ Removed current_baseline_version from CountSessions")
|
||||
print(" ✅ CURRENT data will now always show latest via JOIN")
|
||||
print("\nNext steps:")
|
||||
print(" 1. Replace app.py with updated version")
|
||||
print(" 2. Restart Flask")
|
||||
print(" 3. Test uploading CURRENT baseline")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ ERROR: {e}")
|
||||
print("Rolling back...")
|
||||
conn.rollback()
|
||||
print("Migration failed. Database unchanged.")
|
||||
print(f"Backup available at: {backup_path}")
|
||||
raise
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("="*50)
|
||||
print("CURRENT Baseline Migration")
|
||||
print("="*50)
|
||||
response = input("\nThis will modify your database structure. Continue? (yes/no): ")
|
||||
if response.lower() == 'yes':
|
||||
run_migration()
|
||||
else:
|
||||
print("Migration cancelled.")
|
||||
Reference in New Issue
Block a user