update
This commit is contained in:
parent
e0c0e834fe
commit
4692b037a0
@ -67,6 +67,16 @@ parser.add_argument(
|
||||
action="store_true",
|
||||
help="Force delete cascade all records instead of archiving",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--soft",
|
||||
action="store_true",
|
||||
help="Just archive the records instead of deleting",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--refresh-cache",
|
||||
action="store_true",
|
||||
help="Refersh the related models cache",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
db_name = args.db_name
|
||||
@ -85,18 +95,24 @@ color_log.Show(INFO, ("Available databases:", odoo.db.list()))
|
||||
try:
|
||||
odoo.login(db_name, USERNAME, PASSWORD)
|
||||
color_log.Show(
|
||||
0,
|
||||
f"Connected to Odoo at {HOST}:{PORT}, Database: {db_name}, Model: {base_model}",
|
||||
OK, f"Connected to {HOST}:{PORT}, DB: {db_name}, Model: {base_model}"
|
||||
)
|
||||
except odoorpc.error.RPCError as e:
|
||||
color_log.Show(FAIL, f"Login failed: {e} (check credentials or database)")
|
||||
exit(1)
|
||||
except Exception as e:
|
||||
color_log.Show(FAIL, f"Fail to Connect to Odoo Server {e}")
|
||||
color_log.Show(FAIL, f"Connection error: {e} (check host/port)")
|
||||
exit(1)
|
||||
|
||||
# Convert DOMAIN from string to list
|
||||
try:
|
||||
domain_filter = ast.literal_eval(domain_str)
|
||||
except Exception as e:
|
||||
color_log.Show(FAIL, f"Invalid DOMAIN format: {e}")
|
||||
if not isinstance(domain_filter, list) or not all(
|
||||
isinstance(t, (tuple, list)) and len(t) == 3 for t in domain_filter
|
||||
):
|
||||
raise ValueError("Domain must be a list of 3-tuples")
|
||||
except (ValueError, SyntaxError) as e:
|
||||
color_log.Show(FAIL, f"Invalid domain format: {e}")
|
||||
exit(1)
|
||||
|
||||
|
||||
@ -136,6 +152,7 @@ def get_related_fields(db_name, base_model):
|
||||
if os.path.exists(cache_file):
|
||||
with open(cache_file, "r") as f:
|
||||
related_models = json.load(f)
|
||||
color_log.Show(INFO, f"Loaded related models for {base_model} from cache.")
|
||||
return related_models
|
||||
|
||||
color_log.Show(INFO, f"Fetching related models for {base_model} from Odoo...")
|
||||
@ -145,7 +162,6 @@ def get_related_fields(db_name, base_model):
|
||||
all_model_ids = odoo.env["ir.model"].search([])
|
||||
all_models = odoo.env["ir.model"].read(all_model_ids, ["model"])
|
||||
model_names = [model["model"] for model in all_models]
|
||||
|
||||
# Use multiprocessing to fetch related fields
|
||||
with mp.Pool(processes=process_size) as pool:
|
||||
results = pool.starmap(
|
||||
@ -169,6 +185,7 @@ def get_related_fields(db_name, base_model):
|
||||
return {}
|
||||
|
||||
|
||||
# Experimental function
|
||||
def delete_records_cascade(
|
||||
record_ids, model_name, process_count, related_models, db_name
|
||||
):
|
||||
@ -211,7 +228,9 @@ def delete_records_cascade(
|
||||
)
|
||||
process_count += 1
|
||||
except odoorpc.error.RPCError as e:
|
||||
color_log.Show(NOTICE, f"Access denied for model {related_model}: {e}")
|
||||
color_log.Show(
|
||||
NOTICE, f"Access denied for model {related_model}: {e}"
|
||||
)
|
||||
skipped_models_cache.add(related_model) # Add to cache
|
||||
break # Skip further processing for this model
|
||||
except Exception as e:
|
||||
@ -244,6 +263,33 @@ def delete_records_cascade(
|
||||
color_log.Show(FAIL, f"Error deleting {model_name} records: {e}")
|
||||
|
||||
|
||||
def unreference_records(record_id, model_name, process_count, related_models):
|
||||
"""Force delete a record and its related records."""
|
||||
for related_model, fields in related_models.items():
|
||||
related_model_obj = odoo.env[related_model]
|
||||
for field in fields:
|
||||
try:
|
||||
# Find records in the related model that reference the record_id
|
||||
related_ids = related_model_obj.search([(field, "=", record_id)])
|
||||
if related_ids:
|
||||
# Unreference the record_id by setting the field to False
|
||||
related_model_obj.browse(related_ids).write({field: False})
|
||||
color_log.Show(
|
||||
OK,
|
||||
f"Unreferenced {record_id} in {related_model} ({field}) for {len(related_ids)} records.",
|
||||
)
|
||||
except odoorpc.error.RPCError as e:
|
||||
color_log.Show(
|
||||
NOTICE,
|
||||
f"Access denied while unreferencing {record_id} in {related_model} ({field}): {e}",
|
||||
)
|
||||
except Exception as e:
|
||||
color_log.Show(
|
||||
NOTICE,
|
||||
f"Error while unreferencing {record_id} in {related_model} ({field}): {e}",
|
||||
)
|
||||
|
||||
|
||||
# Function to delete records in parallel
|
||||
def delete_record(batch, model_name, process_count, related_models):
|
||||
"""Process a batch of records - archive or delete based on references."""
|
||||
@ -266,17 +312,35 @@ def delete_record(batch, model_name, process_count, related_models):
|
||||
color_log.Show(
|
||||
INFO, f"{process_count}: Archived {model_name} ID {record_id}"
|
||||
)
|
||||
else:
|
||||
if (not is_referenced and not args.soft) or args.force:
|
||||
model.unlink([record_id])
|
||||
deleted_count += 1
|
||||
color_log.Show(
|
||||
INFO, f"{process_count}: Deleted {model_name} ID {record_id}"
|
||||
)
|
||||
except Exception as e:
|
||||
skipped_count += 1
|
||||
color_log.Show(
|
||||
INFO, f"{process_count}: Skipped {model_name} ID {record_id}: {e}"
|
||||
)
|
||||
if args.force:
|
||||
try:
|
||||
unreference_records(
|
||||
record_id, model_name, process_count, related_models
|
||||
)
|
||||
model.unlink([record_id])
|
||||
archived_count += 1
|
||||
color_log.Show(
|
||||
INFO,
|
||||
f"{process_count}: Force deleted {model_name} ID {record_id}",
|
||||
)
|
||||
except Exception as e:
|
||||
skipped_count += 1
|
||||
color_log.Show(
|
||||
NOTICE,
|
||||
f"{process_count}: Skipped {model_name} ID {record_id} after force delete attempt: {e}",
|
||||
)
|
||||
else:
|
||||
skipped_count += 1
|
||||
color_log.Show(
|
||||
INFO, f"{process_count}: Skipped {model_name} ID {record_id}: {e}"
|
||||
)
|
||||
|
||||
color_log.Show(
|
||||
OK,
|
||||
@ -304,29 +368,16 @@ def main():
|
||||
for i in range(0, len(record_ids), process_size)
|
||||
]
|
||||
processes = []
|
||||
if args.force:
|
||||
delete_records_cascade(record_ids, base_model, 0, related_models, db_name)
|
||||
# for i, batch in enumerate(batch_list, start=1):
|
||||
# process = mp.Process(
|
||||
# target=delete_records_cascade,
|
||||
# args=(batch, base_model, f"Process-{i}", related_models,db_name),
|
||||
# )
|
||||
# processes.append(process)
|
||||
# process.start()
|
||||
|
||||
# for process in processes:
|
||||
# process.join()
|
||||
else:
|
||||
for i, batch in enumerate(batch_list, start=1):
|
||||
process = mp.Process(
|
||||
target=delete_record,
|
||||
args=(batch, base_model, f"Process-{i}", related_models),
|
||||
)
|
||||
processes.append(process)
|
||||
process.start()
|
||||
|
||||
for process in processes:
|
||||
process.join()
|
||||
for i, batch in enumerate(batch_list, start=1):
|
||||
# delete_record(batch, base_model, f"Process-{i}", related_models)
|
||||
process = mp.Process(
|
||||
target=delete_record,
|
||||
args=(batch, base_model, f"Process-{i}", related_models),
|
||||
)
|
||||
processes.append(process)
|
||||
process.start()
|
||||
for process in processes:
|
||||
process.join()
|
||||
|
||||
color_log.Show(OK, "Record deletion process completed.")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user