From 19a2496f181d863fd0f9482908d9f0c090c8c511 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 00:51:14 +0000 Subject: [PATCH 1/3] Initial plan From c27e53a39c3f319b8f1618896b37d46e0587748d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 00:53:56 +0000 Subject: [PATCH 2/3] Optimize delete_attachment API to fix N+1 query pattern Co-authored-by: mrrobot47 <25586785+mrrobot47@users.noreply.github.com> --- next_crm/api/activities.py | 40 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/next_crm/api/activities.py b/next_crm/api/activities.py index 4d6c2e37c1..15f435ac38 100644 --- a/next_crm/api/activities.py +++ b/next_crm/api/activities.py @@ -679,25 +679,33 @@ def delete_attachment(filename, doctype=None, docname=None): deleted = False if doctype and docname: - notes = frappe.get_all( - "CRM Note", - filters={"parenttype": doctype, "parent": docname}, - fields=["name"], + # Find notes that have this attachment directly + notes_with_attachment = frappe.get_all( + "NCRM Attachments", + filters={"filename": filename}, + fields=["parent"], + pluck="parent", ) - for note in notes: - note_doc = frappe.get_doc("CRM Note", note.name) - original_count = len(note_doc.custom_note_attachments) - - updated_attachments = [ - row - for row in note_doc.custom_note_attachments - if row.filename != filename - ] + if notes_with_attachment: + # Filter to notes belonging to this document + notes_to_update = frappe.get_all( + "CRM Note", + filters={ + "name": ["in", notes_with_attachment], + "parenttype": doctype, + "parent": docname, + }, + fields=["name"], + pluck="name", + ) - if len(updated_attachments) != original_count: - note_doc.set("custom_note_attachments", updated_attachments) - note_doc.save() + for note_name in notes_to_update: + # Delete the attachment row directly + frappe.db.delete( + "NCRM Attachments", + {"parent": note_name, "filename": filename} + ) deleted = True try: From 98dc31e588dd3d194f5f8884affc268c7901398e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 00:55:35 +0000 Subject: [PATCH 3/3] Address code review feedback - use bulk delete operation Co-authored-by: mrrobot47 <25586785+mrrobot47@users.noreply.github.com> --- next_crm/api/activities.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/next_crm/api/activities.py b/next_crm/api/activities.py index 15f435ac38..4be661c3a2 100644 --- a/next_crm/api/activities.py +++ b/next_crm/api/activities.py @@ -700,11 +700,11 @@ def delete_attachment(filename, doctype=None, docname=None): pluck="name", ) - for note_name in notes_to_update: - # Delete the attachment row directly + if notes_to_update: + # Delete all matching attachment rows in a single operation frappe.db.delete( "NCRM Attachments", - {"parent": note_name, "filename": filename} + {"parent": ["in", notes_to_update], "filename": filename} ) deleted = True