import sys import os import time sys.path.append(os.getcwd()) # Try to import odoo, if not found, assume we are in odoo-bin shell or need path try: import odoo from odoo import api, SUPERUSER_ID from odoo.tools import config except ImportError as e: # Check if due to missing dependency like passlib if "No module named" in str(e): print("!" * 80) print(f"ERROR: Missing dependency: {e}") print("Please run this script using the Python executable that runs Odoo.") print("Example: /path/to/venv/bin/python unlink_bom_operations.py") print("!" * 80) sys.exit(1) # Fallback: assume running from odoo root (where odoo/ folder is generic repo structure) current_dir = os.path.dirname(os.path.abspath(__file__)) # If we are in root and 'odoo' folder exists which contains the package strings # We might need to add 'odoo' (the repo root) to path? # No, typically 'odoo' package is in 'odoo/' subdir of repo. # So we need to add .../odoo19/odoo to sys.path to find odoo package. # Try adding current_dir/odoo to path if os.path.exists(os.path.join(current_dir, 'odoo')): sys.path.append(os.path.join(current_dir, 'odoo')) else: sys.path.append(current_dir) import odoo from odoo import api, SUPERUSER_ID from odoo.tools import config def unlink_operations(): print("Starting BOM Operation Unlink Script...") import argparse parser = argparse.ArgumentParser(description='Unlink operations from BOMs remotely.') parser.add_argument('db_name', help='Database name') parser.add_argument('-c', '--config', help='Path to odoo.conf', default=None) args = parser.parse_args() db_name = args.db_name # Load config if provided or default exists conf_path = args.config if conf_path: if os.path.exists(conf_path): config.parse_config(['-c', conf_path]) else: print(f"WARNING: Config file '{conf_path}' not found.") elif os.path.exists('odoo.conf'): config.parse_config(['-c', 'odoo.conf']) print(f"Connecting to database: {db_name}") try: registry = odoo.registry(db_name) except AttributeError: from odoo.modules.registry import Registry registry = Registry.new(db_name) with registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) print("\nSearching for BOMs...") boms = env['mrp.bom'].search([]) print(f"Found {len(boms)} total BOMs.") count = 0 modified_count = 0 for bom in boms: count += 1 if count % 100 == 0: print(f"Processed {count}/{len(boms)}...") if bom.operation_ids: op_count = len(bom.operation_ids) print(f" [MODIFY] BOM: {bom.display_name} (ID: {bom.id}) - Unlinking {op_count} operations.") # (5, 0, 0) command removes all records from the relation (deletes them if owned) bom.write({'operation_ids': [(5, 0, 0)]}) modified_count += 1 print(f"\nSummary: Modified {modified_count} BOMs out of {len(boms)}.") print("\n---------------------------------------------------") print("Dry run complete. No changes have been committed yet.") print("WARNING: This will permanently remove operations from the modified BOMs.") user_input = input("Do you want to COMMIT these changes to the database? (yes/no): ") if user_input.lower() == 'yes': cr.commit() print("Changes COMMITTED.") else: cr.rollback() print("Operation CANCELLED (Rolled back).") print("Done.") if __name__ == '__main__': unlink_operations()