From 5483e439f3a550d8e26e1c09972e5db1d9599cc3 Mon Sep 17 00:00:00 2001 From: Jatin3128 Date: Tue, 11 Aug 2026 11:02:29 +0530 Subject: [PATCH] fix: scope Opportunity party validation to Customer only validate_party_frozen_disabled only enforces Customer/Supplier/Employee, so passing opportunity_from straight through silently no-op'd for Lead and Prospect. Made the Customer-only scope explicit instead of relying on that implicit fallthrough. Lead.disabled is not enforced anywhere else in the codebase (lead_query, the picker used for this same field, only filters status/docstatus), so deliberately not extending validation to Lead-sourced Opportunities. (cherry picked from commit 8c0a94541708a6d10be19900a45305be24063ac9) --- erpnext/crm/doctype/opportunity/opportunity.py | 3 ++- erpnext/crm/doctype/opportunity/test_opportunity.py | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 6bed0e7fd9c..f3bb41dfcf4 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -351,7 +351,8 @@ class Opportunity(TransactionBase, CRMNote): return True def validate_party(self) -> None: - validate_party_frozen_disabled(self.company, self.opportunity_from, self.party_name) + if self.opportunity_from == "Customer": + validate_party_frozen_disabled(self.company, "Customer", self.party_name) def validate_cust_name(self): if self.party_name: diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py index 3bae3224c10..90a6be0943b 100644 --- a/erpnext/crm/doctype/opportunity/test_opportunity.py +++ b/erpnext/crm/doctype/opportunity/test_opportunity.py @@ -80,6 +80,15 @@ class TestOpportunity(ERPNextTestSuite): frappe.db.set_value("Customer", "_Test Customer", "disabled", 0) make_opportunity(with_items=0) + def test_disabled_lead_not_blocked(self): + # Lead.disabled isn't enforced anywhere else (e.g. the Lead picker query only + # excludes Converted leads), so it shouldn't block Opportunity creation either. + lead_doc = make_lead() + frappe.db.set_value("Lead", lead_doc.name, "disabled", 1) + + opp_doc = make_opportunity(opportunity_from="Lead", lead=lead_doc.name) + self.assertEqual(opp_doc.party_name, lead_doc.name) + def test_carry_forward_of_email_and_comments(self): frappe.db.set_single_value("CRM Settings", "carry_forward_communication_and_comments", 1) lead_doc = make_lead()