You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The delete_attachment() function loads full CRM Note documents using frappe.get_doc() in a loop when checking for attachment references. This is inefficient when a lead/opportunity has many notes.
Impact Analysis
CPU Impact: Medium - Full document deserialization per note
Memory Impact: Medium - Full documents loaded into memory
Database Impact: Medium - N+1 queries for document loading
User Experience Impact: Low - Only affects delete operations
frappe.get_doc() in a loop instead of targeted query
Full document loaded when only checking/modifying child table
No early exit when attachment is found and deleted
Proposed Solution
Use direct database operations to find and remove attachment references:
@frappe.whitelist()defdelete_attachment(filename, doctype=None, docname=None):
""" Delete a file attachment by its File.name. If doctype & docname are provided, also remove its reference from CRM Notes' custom_note_attachments child table. """deleted=Falseifdoctypeanddocname:
# First, check if any CRM Note references this attachment# Use direct query instead of loading full documentsattachment_refs=frappe.db.sql(""" SELECT nca.name, nca.parent FROM `tabNCRM Attachments` nca INNER JOIN `tabCRM Note` cn ON cn.name = nca.parent WHERE cn.parenttype = %s AND cn.parent = %s AND nca.filename = %s """, (doctype, docname, filename), as_dict=True)
ifattachment_refs:
# Delete the attachment references directlyforrefinattachment_refs:
frappe.db.delete("NCRM Attachments", {"name": ref["name"]})
deleted=True# Delete the filetry:
frappe.delete_doc("File", filename)
deleted=Trueexceptfrappe.DoesNotExistError:
frappe.throw(_("File with ID '{0}' not found.").format(filename))
exceptfrappe.LinkExistsError:
frappe.throw(
_("Cannot delete file because it's still linked with another document.")
)
exceptExceptionase:
frappe.log_error(f"Failed to delete file: {e}", "Delete Attachment Error")
frappe.throw(_("An unexpected error occurred while deleting the file."))
ifdeleted:
return {"message": _("File deleted successfully.")}
else:
frappe.throw(
_("File was not deleted. Possibly already removed or not linked correctly.")
)
Implementation Steps
Replace the loop with a SQL JOIN query to find attachment references
Delete child table rows directly instead of loading parent documents
Reduce from O(n) document loads to 2 database operations
Metadata
next_crm/api/activities.py:681-701Problem Description
The
delete_attachment()function loads full CRM Note documents usingfrappe.get_doc()in a loop when checking for attachment references. This is inefficient when a lead/opportunity has many notes.Impact Analysis
Code Location
Root Cause
frappe.get_doc()in a loop instead of targeted queryProposed Solution
Use direct database operations to find and remove attachment references:
Implementation Steps
Related Issues