diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
index 857ee0e7187..c9762282a7d 100644
--- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py
@@ -5,6 +5,8 @@
import frappe
from frappe import _
from frappe.model.document import Document
+from frappe.query_builder import Criterion
+from frappe.query_builder.functions import IfNull
pricing_rule_fields = [
"apply_on",
@@ -91,22 +93,50 @@ class PromotionalScheme(Document):
if self.is_new():
return
- transaction_exists = False
- docnames = []
+ invalid_pricing_rule = self.get_invalid_pricing_rules()
- # If user has changed applicable for
- if self.get_doc_before_save() and self.get_doc_before_save().applicable_for == self.applicable_for:
+ if not invalid_pricing_rule:
return
- docnames = frappe.get_all("Pricing Rule", filters={"promotional_scheme": self.name})
+ if frappe.db.exists(
+ "Pricing Rule Detail",
+ {
+ "pricing_rule": ["in", invalid_pricing_rule],
+ "docstatus": ["<", 2],
+ },
+ ):
+ raise_for_transaction_exists(self.name)
- for docname in docnames:
- if frappe.db.exists("Pricing Rule Detail", {"pricing_rule": docname.name, "docstatus": ("<", 2)}):
- raise_for_transaction_exists(self.name)
+ for doc in invalid_pricing_rule:
+ frappe.delete_doc("Pricing Rule", doc)
- if docnames and not transaction_exists:
- for docname in docnames:
- frappe.delete_doc("Pricing Rule", docname.name)
+ frappe.msgprint(
+ _("The following invalid Pricing Rules are deleted:")
+ + "
- "
+ + "
- ".join(invalid_pricing_rule)
+ + "
"
+ )
+
+ def get_invalid_pricing_rules(self):
+ pr = frappe.qb.DocType("Pricing Rule")
+ conditions = []
+ conditions.append(pr.promotional_scheme == self.name)
+
+ if self.applicable_for:
+ applicable_for = frappe.scrub(self.applicable_for)
+ applicable_for_list = [d.get(applicable_for) for d in self.get(applicable_for)]
+
+ conditions.append(
+ (IfNull(pr.applicable_for, "") != self.applicable_for)
+ | (
+ (IfNull(pr.applicable_for, "") == self.applicable_for)
+ & IfNull(pr[applicable_for], "").notin(applicable_for_list)
+ )
+ )
+ else:
+ conditions.append(IfNull(pr.applicable_for, "") != "")
+
+ return frappe.qb.from_(pr).select(pr.name).where(Criterion.all(conditions)).run(pluck=True)
def on_update(self):
self.validate()
diff --git a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
index 0d08fd98139..c4a5fcf4b0a 100644
--- a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
+++ b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py
@@ -90,6 +90,31 @@ class TestPromotionalScheme(unittest.TestCase):
price_rules = frappe.get_all("Pricing Rule", filters={"promotional_scheme": ps.name})
self.assertEqual(price_rules, [])
+ def test_change_applicable_for_values_in_promotional_scheme(self):
+ ps = make_promotional_scheme(applicable_for="Customer", customer="_Test Customer")
+ ps.append("customer", {"customer": "_Test Customer 2"})
+ ps.save()
+
+ price_rules = frappe.get_all(
+ "Pricing Rule", filters={"promotional_scheme": ps.name, "applicable_for": "Customer"}
+ )
+ self.assertTrue(len(price_rules), 2)
+
+ ps.set("customer", [])
+ ps.append("customer", {"customer": "_Test Customer 2"})
+ ps.save()
+
+ price_rules = frappe.get_all(
+ "Pricing Rule",
+ filters={
+ "promotional_scheme": ps.name,
+ "applicable_for": "Customer",
+ "customer": "_Test Customer",
+ },
+ )
+ self.assertEqual(price_rules, [])
+ frappe.delete_doc("Promotional Scheme", ps.name)
+
def test_min_max_amount_configuration(self):
ps = make_promotional_scheme()
ps.price_discount_slabs[0].min_amount = 10