From 76b31d9269f0ba123563ad2d62b0afabb6e42c84 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 1 Jul 2026 11:55:42 +0530 Subject: [PATCH] fix(crm): scope create_customer rollback so a contact/address failure keeps the Customer create_customer wrapped customer.insert() + create_contacts() + create_address() in one try whose except did a full frappe.db.rollback(), so a failure while linking contacts/address discarded the Customer just created (MariaDB kept it pre-migration). Split the try: the customer insert keeps its full rollback (safe -- nothing precedes it), and contact/address linking runs under a savepoint so its failure rolls back only the links, preserving the Customer and healing the Postgres txn. Co-Authored-By: Claude Opus 4.8 --- erpnext/crm/frappe_crm_api.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/erpnext/crm/frappe_crm_api.py b/erpnext/crm/frappe_crm_api.py index a13109181a1..ca7dc56b556 100644 --- a/erpnext/crm/frappe_crm_api.py +++ b/erpnext/crm/frappe_crm_api.py @@ -154,15 +154,23 @@ def create_customer(customer_data: dict | None = None): customer.set(field, customer_data.get(field)) customer.insert(ignore_permissions=True) customer_name = customer.name - - contacts = frappe.parse_json(customer_data.get("contacts")) - create_contacts(contacts, customer_name, "Customer", customer_name) - create_address("Customer", customer_name, customer_data.get("address")) - return customer_name except Exception: frappe.db.rollback() frappe.log_error(frappe.get_traceback(), "Error while creating customer against Frappe CRM Deal") - pass + return + + # Link contacts/address under a savepoint so a failure here does NOT discard the Customer just + # created (a full rollback would; MariaDB kept it pre-migration). Linking is best-effort. + frappe.db.savepoint("crm_customer_links") + try: + contacts = frappe.parse_json(customer_data.get("contacts")) + create_contacts(contacts, customer_name, "Customer", customer_name) + create_address("Customer", customer_name, customer_data.get("address")) + except Exception: + frappe.db.rollback(save_point="crm_customer_links") + frappe.log_error(frappe.get_traceback(), "Error while linking contacts/address to new Customer") + + return customer_name def validate_frappe_crm_sync():