""" Inventory Counts Module - Database Migrations Contains schema for all inventory counting tables """ def get_schema(): """ Returns the complete schema SQL for this module. This is used when the module is installed. """ return """ -- CountSessions Table CREATE TABLE IF NOT EXISTS CountSessions ( 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) ); -- BaselineInventory_Master Table (Session-specific, immutable) CREATE TABLE IF NOT EXISTS BaselineInventory_Master ( baseline_id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL, lot_number TEXT NOT NULL, item TEXT NOT NULL, description TEXT, system_location TEXT NOT NULL, system_bin TEXT NOT NULL, system_quantity REAL NOT NULL, uploaded_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (session_id) REFERENCES CountSessions(session_id) ); -- BaselineInventory_Current Table (GLOBAL - shared across all sessions) CREATE TABLE IF NOT EXISTS BaselineInventory_Current ( 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) ); -- LocationCounts Table CREATE TABLE IF NOT EXISTS LocationCounts ( location_count_id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL, location_name TEXT NOT NULL, counted_by INTEGER NOT NULL, start_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, end_timestamp DATETIME, status TEXT DEFAULT 'not_started' CHECK(status IN ('not_started', 'in_progress', 'completed')), expected_lots_master INTEGER DEFAULT 0, lots_found INTEGER DEFAULT 0, lots_missing INTEGER DEFAULT 0, is_deleted INTEGER DEFAULT 0, FOREIGN KEY (session_id) REFERENCES CountSessions(session_id), FOREIGN KEY (counted_by) REFERENCES Users(user_id) ); -- ScanEntries Table CREATE TABLE IF NOT EXISTS ScanEntries ( 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 baseline comparison master_status TEXT CHECK(master_status IN ('match', 'wrong_location', 'ghost_lot', 'missing')), master_expected_location TEXT, master_expected_weight REAL, master_variance_lbs REAL, master_variance_pct REAL, -- Duplicate detection duplicate_status TEXT DEFAULT '00' CHECK(duplicate_status IN ('00', '01', '03', '04')), duplicate_info TEXT, -- Metadata 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) ); -- MissingLots Table CREATE TABLE IF NOT EXISTS MissingLots ( missing_id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL, location_count_id INTEGER, lot_number TEXT NOT NULL, item TEXT, master_expected_location TEXT NOT NULL, master_expected_quantity REAL NOT NULL, current_system_location TEXT, current_system_quantity REAL, marked_by INTEGER NOT NULL, marked_timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, found_later TEXT DEFAULT 'N' CHECK(found_later IN ('Y', 'N')), found_location TEXT, FOREIGN KEY (session_id) REFERENCES CountSessions(session_id), FOREIGN KEY (location_count_id) REFERENCES LocationCounts(location_count_id), FOREIGN KEY (marked_by) REFERENCES Users(user_id) ); -- Indexes CREATE INDEX IF NOT EXISTS idx_baseline_master_lot ON BaselineInventory_Master(session_id, lot_number); CREATE INDEX IF NOT EXISTS idx_baseline_master_loc ON BaselineInventory_Master(session_id, system_location); CREATE INDEX IF NOT EXISTS idx_scanentries_session ON ScanEntries(session_id); CREATE INDEX IF NOT EXISTS idx_scanentries_location ON ScanEntries(location_count_id); CREATE INDEX IF NOT EXISTS idx_scanentries_lot ON ScanEntries(lot_number); CREATE INDEX IF NOT EXISTS idx_scanentries_deleted ON ScanEntries(is_deleted); CREATE INDEX IF NOT EXISTS idx_location_counts ON LocationCounts(session_id, status); """ def get_migrations(): """ Returns list of migrations specific to this module. Format: [(version, name, up_function), ...] """ def migration_001_add_is_deleted_to_locationcounts(conn): """Add is_deleted column to LocationCounts table""" cursor = conn.cursor() # Check if column exists cursor.execute('PRAGMA table_info(LocationCounts)') columns = [row[1] for row in cursor.fetchall()] if 'is_deleted' not in columns: cursor.execute('ALTER TABLE LocationCounts ADD COLUMN is_deleted INTEGER DEFAULT 0') print(" Added is_deleted column to LocationCounts") return [ (1, 'add_is_deleted_to_locationcounts', migration_001_add_is_deleted_to_locationcounts), ]