mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-14 15:11:52 +00:00
Merge pull request #56213 from mihir-kandoi/pg-customer-name-pg-extract
fix(selling): make Customer name de-duplication work on Postgres
This commit is contained in:
@@ -15,7 +15,7 @@ from frappe.model.document import Document
|
||||
from frappe.model.naming import set_name_by_naming_series, set_name_from_naming_options
|
||||
from frappe.model.utils.rename_doc import update_linked_doctypes
|
||||
from frappe.query_builder import CustomFunction, Field, functions
|
||||
from frappe.query_builder.functions import Cast, Coalesce, Max, Substring
|
||||
from frappe.query_builder.functions import Cast, Coalesce, Max
|
||||
from frappe.utils import cint, cstr, flt, get_formatted_email, today
|
||||
from frappe.utils.user import get_users_with_role
|
||||
|
||||
@@ -128,9 +128,15 @@ class Customer(TransactionBase):
|
||||
Customer = frappe.qb.DocType("Customer")
|
||||
|
||||
if frappe.db.db_type == "postgres":
|
||||
# Postgres: extract trailing digits (e.g. "Customer - 3") and cast to int.
|
||||
# NOTE: PostgreSQL is strict about types; MySQL's UNSIGNED cast does not exist.
|
||||
extracted_part = Substring(Customer.name, r"\d+$")
|
||||
# Postgres: extract the TRAILING digits (e.g. "Customer - 3" -> "3") and cast to int.
|
||||
# A non-numeric trailing token (e.g. "Customer - Foo") strips to an empty string, which
|
||||
# NULLIF turns into NULL: MAX() then skips it and COALESCE floors to 0, matching
|
||||
# MariaDB's CAST(... AS UNSIGNED) -> 0. (pypika's Substring is start/length, not a
|
||||
# regex, so it can't be used here; UNSIGNED also doesn't exist on postgres, and a raw
|
||||
# CAST of a non-numeric token to INTEGER would raise instead of yielding NULL.)
|
||||
regexp_replace = CustomFunction("regexp_replace", ["source", "pattern", "replacement"])
|
||||
nullif = CustomFunction("NULLIF", ["expr", "value"])
|
||||
extracted_part = nullif(regexp_replace(Customer.name, r"^.*?(\d*)$", r"\1"), "")
|
||||
casted_part = Cast(extracted_part, "INTEGER")
|
||||
else:
|
||||
# MariaDB/MySQL: keep existing behavior.
|
||||
|
||||
@@ -20,6 +20,21 @@ from erpnext.tests.utils import ERPNextTestSuite
|
||||
|
||||
|
||||
class TestCustomer(ERPNextTestSuite):
|
||||
def test_get_customer_name_dedupes_with_numeric_suffix(self):
|
||||
# When a customer name already exists, get_customer_name appends "- <max trailing number + 1>".
|
||||
# The Postgres branch extracts the trailing digits with regexp_replace/NULLIF/CAST (pypika's
|
||||
# Substring cannot do regex extraction); this exercises that path on both engines.
|
||||
base = "_Test PG Dedup Customer"
|
||||
for nm in (base, f"{base} - 3"):
|
||||
if not frappe.db.exists("Customer", nm):
|
||||
frappe.get_doc(
|
||||
{"doctype": "Customer", "customer_name": nm, "customer_type": "Individual"}
|
||||
).insert()
|
||||
self.addCleanup(frappe.delete_doc, "Customer", nm, force=1)
|
||||
|
||||
doc = frappe.get_doc({"doctype": "Customer", "customer_name": base, "customer_type": "Individual"})
|
||||
self.assertEqual(doc.get_customer_name(), f"{base} - 4")
|
||||
|
||||
def test_get_customer_group_details(self):
|
||||
doc = frappe.new_doc("Customer Group")
|
||||
doc.customer_group_name = "_Testing Customer Group"
|
||||
|
||||
Reference in New Issue
Block a user