Merge branch 'develop' into pricing_rule_on_condition
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index 29d8378..c681c89 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 aa6194c..454776e 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -6,9 +6,10 @@
 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 @@
 		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 @@
 		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 2bf0b72..3555ca8 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 @@
 		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 @@
 		"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 53b0cf7b..25840d4 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -37,6 +37,8 @@
 
 	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 @@
 
 	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)