diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index 29d83783d0..c681c897fc 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "field:title", @@ -71,6 +72,7 @@ "section_break_13", "threshold_percentage", "priority", + "condition", "column_break_66", "apply_multiple_pricing_rules", "apply_discount_on_rate", @@ -550,11 +552,18 @@ "fieldtype": "Link", "label": "Promotional Scheme", "options": "Promotional Scheme" + }, + { + "description": "Simple Python Expression, Example: territory != 'All Territories'", + "fieldname": "condition", + "fieldtype": "Code", + "label": "Condition" } ], "icon": "fa fa-gift", "idx": 1, - "modified": "2019-12-18 17:29:22.957077", + "links": [], + "modified": "2020-08-26 12:24:44.740734", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index aa6194cbc3..454776e4e7 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -6,9 +6,10 @@ from __future__ import unicode_literals import frappe import json import copy +import re + from frappe import throw, _ from frappe.utils import flt, cint, getdate - from frappe.model.document import Document from six import string_types @@ -30,6 +31,7 @@ class PricingRule(Document): self.validate_max_discount() self.validate_price_list_with_currency() self.validate_dates() + self.validate_condition() if not self.margin_type: self.margin_rate_or_amount = 0.0 @@ -140,6 +142,10 @@ class PricingRule(Document): if self.valid_from and self.valid_upto and getdate(self.valid_from) > getdate(self.valid_upto): frappe.throw(_("Valid from date must be less than valid upto date")) + def validate_condition(self): + if self.condition and ("=" in self.condition) and re.match("""[\w\.:_]+\s*={1}\s*[\w\.@'"]+""", self.condition): + frappe.throw(_("Invalid condition expression")) + #-------------------------------------------------------------------------------- @frappe.whitelist() diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 2bf0b72563..3555ca895f 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -429,7 +429,34 @@ class TestPricingRule(unittest.TestCase): details = get_item_details(args) self.assertTrue(details) - + + def test_pricing_rule_for_condition(self): + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule") + + make_pricing_rule(selling=1, margin_type="Percentage", \ + condition="customer=='_Test Customer 1' and is_return==0", discount_percentage=10) + + # Incorrect Customer and Correct is_return value + si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 2", is_return=0) + si.items[0].price_list_rate = 1000 + si.submit() + item = si.items[0] + self.assertEquals(item.rate, 100) + + # Correct Customer and Incorrect is_return value + si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=1, qty=-1) + si.items[0].price_list_rate = 1000 + si.submit() + item = si.items[0] + self.assertEquals(item.rate, 100) + + # Correct Customer and correct is_return value + si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=0) + si.items[0].price_list_rate = 1000 + si.submit() + item = si.items[0] + self.assertEquals(item.rate, 900) + def make_pricing_rule(**args): args = frappe._dict(args) @@ -448,7 +475,8 @@ def make_pricing_rule(**args): "discount_percentage": args.discount_percentage or 0.0, "rate": args.rate or 0.0, "margin_type": args.margin_type, - "margin_rate_or_amount": args.margin_rate_or_amount or 0.0 + "margin_rate_or_amount": args.margin_rate_or_amount or 0.0, + "condition": args.condition or '' }) apply_on = doc.apply_on.replace(' ', '_').lower() diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 53b0cf7bba..25840d4fb7 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -37,6 +37,8 @@ def get_pricing_rules(args, doc=None): rules = [] + pricing_rules = filter_pricing_rule_based_on_condition(pricing_rules, doc) + if not pricing_rules: return [] if apply_multiple_pricing_rules(pricing_rules): @@ -51,6 +53,23 @@ def get_pricing_rules(args, doc=None): return rules +def filter_pricing_rule_based_on_condition(pricing_rules, doc=None): + filtered_pricing_rules = [] + if doc: + for pricing_rule in pricing_rules: + if pricing_rule.condition: + try: + if frappe.safe_eval(pricing_rule.condition, None, doc.as_dict()): + filtered_pricing_rules.append(pricing_rule) + except: + pass + else: + filtered_pricing_rules.append(pricing_rule) + else: + filtered_pricing_rules = pricing_rules + + return filtered_pricing_rules + def _get_pricing_rules(apply_on, args, values): apply_on_field = frappe.scrub(apply_on)