From b4aae9dea18d720e85cc568abfc2826ad075c8f9 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 23 Jun 2026 08:58:30 +0530 Subject: [PATCH] fix(crm): render Lead Details address consistently across engines The Lead Details report concatenated address_line1 and address_line2 with CONCAT_WS. An unfilled optional Data field is stored as '' on MariaDB but as NULL on PostgreSQL; CONCAT_WS keeps the empty string (leaving a trailing ", ") on MariaDB while Postgres drops the NULL, so the same lead rendered a different address on each engine. Wrap both parts in NULLIF(part, '') so empty values are treated as NULL on both engines: the report now produces the same clean address (no trailing separator) everywhere. --- .../crm/report/lead_details/lead_details.py | 6 ++-- .../report/lead_details/test_lead_details.py | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 erpnext/crm/report/lead_details/test_lead_details.py diff --git a/erpnext/crm/report/lead_details/lead_details.py b/erpnext/crm/report/lead_details/lead_details.py index def3e28af74..7155c53e82a 100644 --- a/erpnext/crm/report/lead_details/lead_details.py +++ b/erpnext/crm/report/lead_details/lead_details.py @@ -4,7 +4,7 @@ import frappe from frappe import _ -from frappe.query_builder.functions import Concat_ws, Date +from frappe.query_builder.functions import Concat_ws, Date, NullIf def execute(filters=None): @@ -93,7 +93,9 @@ def get_data(filters): lead.phone, lead.owner, lead.company, - (Concat_ws(", ", address.address_line1, address.address_line2)).as_("address"), + (Concat_ws(", ", NullIf(address.address_line1, ""), NullIf(address.address_line2, ""))).as_( + "address" + ), address.pincode, address.city, address.state, diff --git a/erpnext/crm/report/lead_details/test_lead_details.py b/erpnext/crm/report/lead_details/test_lead_details.py new file mode 100644 index 00000000000..ec5d9a802a2 --- /dev/null +++ b/erpnext/crm/report/lead_details/test_lead_details.py @@ -0,0 +1,36 @@ +# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +import frappe +from frappe.utils import add_days, today + +from erpnext.crm.report.lead_details.lead_details import get_data +from erpnext.tests.utils import ERPNextTestSuite + + +class TestLeadDetailsReport(ERPNextTestSuite): + def test_address_column_omits_empty_line(self): + """An empty address_line2 is '' on MariaDB but NULL on Postgres; CONCAT_WS + keeps the empty string (trailing ', ') on MariaDB while Postgres drops it. + The report must render the same clean address on both engines.""" + lead = frappe.get_doc( + {"doctype": "Lead", "lead_name": "_Test PG Lead Address", "company": "_Test Company"} + ).insert() + frappe.get_doc( + { + "doctype": "Address", + "address_title": "_Test PG Lead Address", + "address_type": "Billing", + "address_line1": "221B Baker Street", + "address_line2": "", + "city": "London", + "country": "United Kingdom", + "links": [{"link_doctype": "Lead", "link_name": lead.name}], + } + ).insert() + + filters = frappe._dict( + company="_Test Company", from_date=add_days(today(), -1), to_date=add_days(today(), 1) + ) + row = next(r for r in get_data(filters) if r.get("name") == lead.name) + self.assertEqual(row.get("address"), "221B Baker Street")