diff --git a/crm/api/doc.py b/crm/api/doc.py index 4c326b2f..0ceee0a0 100644 --- a/crm/api/doc.py +++ b/crm/api/doc.py @@ -750,7 +750,11 @@ def getCounts(d, doctype): @frappe.whitelist() def get_linked_docs_of_document(doctype, docname): - doc = frappe.get_doc(doctype, docname) + try: + doc = frappe.get_doc(doctype, docname) + except frappe.DoesNotExistError: + return [] + linked_docs = get_linked_docs(doc) dynamic_linked_docs = get_dynamic_linked_docs(doc) @@ -759,7 +763,14 @@ def get_linked_docs_of_document(doctype, docname): docs_data = [] for doc in linked_docs: - data = frappe.get_doc(doc["reference_doctype"], doc["reference_docname"]) + if not doc.get("reference_doctype") or not doc.get("reference_docname"): + continue + + try: + data = frappe.get_doc(doc["reference_doctype"], doc["reference_docname"]) + except (frappe.DoesNotExistError, frappe.ValidationError): + continue + title = data.get("title") if data.doctype == "CRM Call Log": title = f"Call from {data.get('from')} to {data.get('to')}" @@ -767,6 +778,9 @@ def get_linked_docs_of_document(doctype, docname): if data.doctype == "CRM Deal": title = data.get("organization") + if data.doctype == "CRM Notification": + title = data.get("message") + docs_data.append( { "doc": data.doctype, @@ -779,25 +793,51 @@ def get_linked_docs_of_document(doctype, docname): def remove_doc_link(doctype, docname): - linked_doc_data = frappe.get_doc(doctype, docname) - linked_doc_data.update( - { - "reference_doctype": None, - "reference_docname": None, - } - ) - linked_doc_data.save(ignore_permissions=True) + if not doctype or not docname: + return + + try: + linked_doc_data = frappe.get_doc(doctype, docname) + if doctype == "CRM Notification": + delete_notification_type = { + "notification_type_doctype": "", + "notification_type_doc": "", + } + delete_references = { + "reference_doctype": "", + "reference_name": "", + } + if linked_doc_data.get("notification_type_doctype") == linked_doc_data.get("reference_doctype"): + delete_references.update(delete_notification_type) + + linked_doc_data.update(delete_references) + else: + linked_doc_data.update( + { + "reference_doctype": "", + "reference_docname": "", + } + ) + linked_doc_data.save(ignore_permissions=True) + except (frappe.DoesNotExistError, frappe.ValidationError): + pass def remove_contact_link(doctype, docname): - linked_doc_data = frappe.get_doc(doctype, docname) - linked_doc_data.update( - { - "contact": None, - "contacts": [], - } - ) - linked_doc_data.save(ignore_permissions=True) + if not doctype or not docname: + return + + try: + linked_doc_data = frappe.get_doc(doctype, docname) + linked_doc_data.update( + { + "contact": None, + "contacts": [], + } + ) + linked_doc_data.save(ignore_permissions=True) + except (frappe.DoesNotExistError, frappe.ValidationError): + pass @frappe.whitelist() @@ -806,13 +846,19 @@ def remove_linked_doc_reference(items, remove_contact=None, delete=False): items = frappe.parse_json(items) for item in items: - if remove_contact: - remove_contact_link(item["doctype"], item["docname"]) - else: - remove_doc_link(item["doctype"], item["docname"]) + if not item.get("doctype") or not item.get("docname"): + continue - if delete: - frappe.delete_doc(item["doctype"], item["docname"]) + try: + if remove_contact: + remove_contact_link(item["doctype"], item["docname"]) + else: + remove_doc_link(item["doctype"], item["docname"]) + if delete: + frappe.delete_doc(item["doctype"], item["docname"]) + except (frappe.DoesNotExistError, frappe.ValidationError): + # Skip if document doesn't exist or has validation errors + continue return "success" @@ -821,19 +867,40 @@ def remove_linked_doc_reference(items, remove_contact=None, delete=False): def delete_bulk_docs(doctype, items, delete_linked=False): from frappe.desk.reportview import delete_bulk + if not doctype: + frappe.throw("Doctype is required") + + if not items: + frappe.throw("Items are required") + items = frappe.parse_json(items) + if not isinstance(items, list): + frappe.throw("Items must be a list") + for doc in items: - linked_docs = get_linked_docs_of_document(doctype, doc) - for linked_doc in linked_docs: - remove_linked_doc_reference( - [ - { - "doctype": linked_doc["reference_doctype"], - "docname": linked_doc["reference_docname"], - } - ], - remove_contact=doctype == "Contact", - delete=delete_linked, + try: + if not frappe.db.exists(doctype, doc): + frappe.log_error(f"Document {doctype} {doc} does not exist", "Bulk Delete Error") + continue + + linked_docs = get_linked_docs_of_document(doctype, doc) + for linked_doc in linked_docs: + if not linked_doc.get("reference_doctype") or not linked_doc.get("reference_docname"): + continue + + remove_linked_doc_reference( + [ + { + "doctype": linked_doc["reference_doctype"], + "docname": linked_doc["reference_docname"], + } + ], + remove_contact=doctype == "Contact", + delete=delete_linked, + ) + except Exception as e: + frappe.log_error( + f"Error processing linked docs for {doctype} {doc}: {str(e)}", "Bulk Delete Error" ) if len(items) > 10: diff --git a/frontend/src/components/BulkDeleteLinkedDocModal.vue b/frontend/src/components/BulkDeleteLinkedDocModal.vue index b27273b5..26b19323 100644 --- a/frontend/src/components/BulkDeleteLinkedDocModal.vue +++ b/frontend/src/components/BulkDeleteLinkedDocModal.vue @@ -13,7 +13,7 @@