import sys import os import argparse import logging def main(): parser = argparse.ArgumentParser(description="Drop Zombie Constraint 'product_pricelist_res_config_settin_res_config_settings_id_fkey'") parser.add_argument("odoo_bin_path", help="Path to odoo-bin executable (e.g. odoo/odoo-bin)") parser.add_argument("conf_path", help="Path to odoo.conf") parser.add_argument("db_name", help="Database name") args = parser.parse_args() odoo_bin_path = os.path.abspath(args.odoo_bin_path) conf_path = os.path.abspath(args.conf_path) db_name = args.db_name # Add Odoo to sys.path odoo_root = os.path.dirname(odoo_bin_path) if odoo_root not in sys.path: sys.path.append(odoo_root) # Change CWD to config directory to handle relative paths in config os.chdir(os.path.dirname(conf_path)) try: import odoo from odoo import api, SUPERUSER_ID except ImportError: print(f"Error: Could not import 'odoo' module from {odoo_root}. Make sure odoo-bin path is correct.") sys.exit(1) print(f"Initializing Odoo Environment for database: {db_name}...") try: odoo.tools.config.parse_config(['-c', conf_path]) registry = odoo.registry(db_name) except Exception as e: print(f"Error initializing Odoo: {e}") return with registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) print("Connected to Odoo.") # Define the problematic constraint connection constraint_name = 'product_pricelist_res_config_settin_res_config_settings_id_fkey' # Check if exists cr.execute(""" SELECT conrelid::regclass::text FROM pg_constraint WHERE conname = %s """, (constraint_name,)) result = cr.fetchone() if result: table_name = result[0] print(f"Found constraint '{constraint_name}' on table '{table_name}'.") try: print(f"Dropping table '{table_name}'...") cr.execute(f"DROP TABLE IF EXISTS {table_name} CASCADE") print("Table dropped.") # Double check constraint cr.execute("SELECT count(*) FROM pg_constraint WHERE conname = %s", (constraint_name,)) if cr.fetchone()[0] == 0: print("Constraint successfully removed.") cr.commit() else: print("WARNING: Constraint still exists! Rolled back.") cr.rollback() except Exception as e: print(f"Error dropping table/constraint: {e}") cr.rollback() else: print(f"Constraint '{constraint_name}' not found. Database is likely clean.") # Also invoke the hook logic just in case the name varies? # The hook used 'DROP TABLE IF EXISTS product_pricelist_res_config_settings_rel CASCADE' # Let's try that too. print("Attempting to drop 'product_pricelist_res_config_settings_rel' blindly just in case...") cr.execute("DROP TABLE IF EXISTS product_pricelist_res_config_settings_rel CASCADE") print("Done.") cr.commit() if __name__ == "__main__": main()