fix: Pricing rule not working for POS
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 1e11c4e..8c1ddbb 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -119,7 +119,7 @@
 #--------------------------------------------------------------------------------
 
 @frappe.whitelist()
-def apply_pricing_rule(args):
+def apply_pricing_rule(args, doc=None):
 	"""
 		args = {
 			"items": [{"doctype": "", "name": "", "item_code": "", "brand": "", "item_group": ""}, ...],
@@ -139,6 +139,7 @@
 			"ignore_pricing_rule": "something"
 		}
 	"""
+
 	if isinstance(args, string_types):
 		args = json.loads(args)
 
@@ -161,10 +162,11 @@
 	for item in item_list:
 		args_copy = copy.deepcopy(args)
 		args_copy.update(item)
-		data = get_pricing_rule_for_item(args_copy, item.get('price_list_rate'))
+		data = get_pricing_rule_for_item(args_copy, item.get('price_list_rate'), doc=doc)
 		out.append(data)
 		if set_serial_nos_based_on_fifo and not args.get('is_return'):
-			out.append(get_serial_no_for_item(args_copy))
+			out[0].update(get_serial_no_for_item(args_copy))
+
 	return out
 
 def get_serial_no_for_item(args):
@@ -182,6 +184,12 @@
 def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
 	from erpnext.accounts.doctype.pricing_rule.utils import get_pricing_rules
 
+	if isinstance(doc, string_types):
+		doc = json.loads(doc)
+
+	if doc:
+		doc = frappe.get_doc(doc)
+
 	if (args.get('is_free_item') or
 		args.get("parenttype") == "Material Request"): return {}
 
@@ -227,11 +235,11 @@
 	if pricing_rules:
 		rules = []
 
-		item_details.discount_percentage = 0
-		item_details.discount_amount = 0
 		for pricing_rule in pricing_rules:
 			if not pricing_rule or pricing_rule.get('suggestion'): continue
 
+			item_details.validate_applied_rule = pricing_rule.get("validate_applied_rule", 0)
+
 			rules.append(get_pricing_rule_details(args, pricing_rule))
 			if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
 				continue
@@ -243,8 +251,8 @@
 		item_details.has_pricing_rule = 1
 
 		# if discount is applied on the rate and not on price list rate
-		if price_list_rate:
-			set_discount_amount(price_list_rate, item_details)
+		# if price_list_rate:
+		# 	set_discount_amount(price_list_rate, item_details)
 
 		item_details.pricing_rules = ','.join([d.pricing_rule for d in rules])
 
@@ -264,7 +272,7 @@
 		'pricing_rule': pricing_rule.name,
 		'rate_or_discount': pricing_rule.rate_or_discount,
 		'margin_type': pricing_rule.margin_type,
-		'item_code': pricing_rule.item_code,
+		'item_code': pricing_rule.item_code or args.get("item_code"),
 		'child_docname': args.get('child_docname')
 	})
 
@@ -296,6 +304,9 @@
 			discount_field = "{0}_on_rate".format(field)
 			item_details[discount_field].append(pricing_rule.get(field, 0))
 		else:
+			if field not in item_details:
+				item_details.setdefault(field, 0)
+
 			item_details[field] += (pricing_rule.get(field, 0)
 				if pricing_rule else args.get(field, 0))
 
@@ -308,6 +319,7 @@
 			item_details.rate = rate
 
 def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
+	from erpnext.accounts.doctype.pricing_rule.utils import get_apply_on_and_items
 	for d in pricing_rules.split(','):
 		if not d: continue
 		pricing_rule = frappe.get_doc('Pricing Rule', d)
@@ -327,6 +339,11 @@
 			item_details.remove_free_item = (item_code if pricing_rule.get('same_item')
 				else pricing_rule.get('free_item'))
 
+		if pricing_rule.get("mixed_conditions") or pricing_rule.get("apply_rule_on_other"):
+			apply_on, items = get_apply_on_and_items(pricing_rule, item_details)
+			item_details.apply_on = apply_on
+			item_details.applied_on_items = ','.join(items)
+
 	item_details.pricing_rules = ''
 
 	return item_details
@@ -368,35 +385,6 @@
 
 	return doc
 
-@frappe.whitelist()
-def get_free_items(pricing_rules, item_row):
-	if isinstance(item_row, string_types):
-		item_row = json.loads(item_row)
-
-	free_items = []
-	pricing_rules = list(set(pricing_rules.split(',')))
-
-	for d in pricing_rules:
-		pr_doc = frappe.get_doc('Pricing Rule', d)
-		if pr_doc.price_or_product_discount == 'Product':
-			item = (item_row.get('item_code') if pr_doc.same_item
-				else pr_doc.free_item)
-			if not item: return free_items
-
-			doc = frappe.get_doc('Item', item)
-
-			free_items.append({
-				'item_code': item,
-				'item_name': doc.item_name,
-				'description': doc.description,
-				'qty': pr_doc.free_qty,
-				'uom': pr_doc.free_item_uom,
-				'rate': pr_doc.free_item_rate or 0,
-				'is_free_item': 1
-			})
-
-	return free_items
-
 def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):
 	items = [filters.get('value')]
 	if filters.get('apply_on') != 'Item Code':
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 5382baa..936f97c 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -4,10 +4,9 @@
 # For license information, please see license.txt
 
 from __future__ import unicode_literals
-import frappe
-import json
-import copy
+import frappe, copy, json
 from frappe import throw, _
+from six import string_types
 from frappe.utils import flt, cint, get_datetime
 from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
 from erpnext.stock.get_item_details import get_conversion_factor
@@ -39,7 +38,9 @@
 			if pricing_rule:
 				rules.append(pricing_rule)
 	else:
-		rules.append(filter_pricing_rules(args, pricing_rules, doc))
+		pricing_rule = filter_pricing_rules(args, pricing_rules, doc)
+		if pricing_rule:
+			rules.append(pricing_rule)
 
 	return rules
 
@@ -175,7 +176,7 @@
 		pr_doc = frappe.get_doc('Pricing Rule', pricing_rules[0].name)
 
 		if pricing_rules[0].mixed_conditions and doc:
-			stock_qty, amount = get_qty_and_rate_for_mixed_conditions(doc, pr_doc)
+			stock_qty, amount = get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args)
 
 		elif pricing_rules[0].is_cumulative:
 			items = [args.get(frappe.scrub(pr_doc.get('apply_on')))]
@@ -314,7 +315,7 @@
 
 	return filtered_rules or pricing_rules
 
-def get_qty_and_rate_for_mixed_conditions(doc, pr_doc):
+def get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args):
 	sum_qty, sum_amt = [0, 0]
 	items = get_pricing_rule_items(pr_doc) or []
 	apply_on = frappe.scrub(pr_doc.get('apply_on'))
@@ -324,8 +325,12 @@
 			if row.get(apply_on) not in items: continue
 
 			if pr_doc.mixed_conditions:
-				sum_qty += row.stock_qty
-				sum_amt += row.amount
+				amt = args.get('qty') * args.get("price_list_rate")
+				if args.get("item_code") != row.get("item_code"):
+					amt = row.get('qty') * row.get("price_list_rate")
+
+				sum_qty += row.get("stock_qty") or args.get("stock_qty")
+				sum_amt += amt
 
 		if pr_doc.is_cumulative:
 			data = get_qty_amount_data_for_cumulative(pr_doc, doc, items)
@@ -340,8 +345,8 @@
 	for d in get_pricing_rule_items(pr_doc):
 		for row in doc.items:
 			if d == row.get(frappe.scrub(pr_doc.apply_on)):
-				pricing_rules = filter_pricing_rules_for_qty_amount(row.stock_qty,
-					row.amount, pricing_rules, row)
+				pricing_rules = filter_pricing_rules_for_qty_amount(row.get("stock_qty"),
+					row.get("amount"), pricing_rules, row)
 
 				if pricing_rules and pricing_rules[0]:
 					return pricing_rules
@@ -395,17 +400,15 @@
 def validate_pricing_rules(doc):
 	validate_pricing_rule_on_transactions(doc)
 
-	if not doc.pricing_rules: return
-
 	for d in doc.items:
 		validate_pricing_rule_on_items(doc, d)
 
 	doc.calculate_taxes_and_totals()
 
-def validate_pricing_rule_on_items(doc, item_row):
+def validate_pricing_rule_on_items(doc, item_row, do_not_validate = False):
 	value = 0
-	for pr_row in get_applied_pricing_rules(doc, item_row):
-		pr_doc = frappe.get_doc('Pricing Rule', pr_row.pricing_rule)
+	for pricing_rule in get_applied_pricing_rules(doc, item_row):
+		pr_doc = frappe.get_doc('Pricing Rule', pricing_rule)
 
 		if pr_doc.get('apply_on') == 'Transaction': continue
 
@@ -416,7 +419,7 @@
 				if not pr_doc.get(field): continue
 
 				value += pr_doc.get(field)
-			apply_pricing_rule(doc, pr_doc, pr_row, item_row, value)
+			apply_pricing_rule(doc, pr_doc, item_row, value, do_not_validate)
 
 def validate_pricing_rule_on_transactions(doc):
 	conditions = "apply_on = 'Transaction'"
@@ -451,8 +454,8 @@
 				apply_pricing_rule_for_free_items(doc, d)
 
 def get_applied_pricing_rules(doc, item_row):
-	return [d for d in doc.pricing_rules
-		if d.child_docname == item_row.name]
+	return (item_row.get("pricing_rules").split(',')
+		if item_row.get("pricing_rules") else [])
 
 def apply_pricing_rule_for_free_items(doc, pricing_rule):
 	if pricing_rule.get('free_item'):
@@ -471,7 +474,37 @@
 
 			doc.set_missing_values()
 
-def apply_pricing_rule(doc, pr_doc, pr_row, item_row, value):
+def apply_pricing_rule(doc, pr_doc, item_row, value, do_not_validate=False):
+	apply_on, items = get_apply_on_and_items(pr_doc, item_row)
+
+	rule_applied = {}
+
+	for item in doc.get("items"):
+		if not item.pricing_rules:
+			item.pricing_rules = item_row.pricing_rules
+
+		if item.get(apply_on) in items:
+			for field in ['discount_percentage', 'discount_amount', 'rate']:
+				if not pr_doc.get(field): continue
+
+				key = (item.name, item.pricing_rules)
+				if not pr_doc.validate_applied_rule:
+					rule_applied[key] = 1
+					item.set(field, value)
+				elif item.get(field) < value:
+					if not do_not_validate and item.idx == item_row.idx:
+						rule_applied[key] = 0
+						frappe.msgprint(_("Row {0}: user has not applied rule <b>{1}</b> on the item <b>{2}</b>")
+							.format(item.idx, pr_doc.title, item.item_code))
+
+	if rule_applied and doc.pricing_rules:
+		for d in doc.pricing_rules:
+			key = (d.child_docname, d.pricing_rule)
+			if key in rule_applied:
+				d.rule_applied = 1
+
+def get_apply_on_and_items(pr_doc, item_row):
+	# for mixed or other items conditions
 	apply_on = frappe.scrub(pr_doc.get('apply_on'))
 	items = (get_pricing_rule_items(pr_doc)
 		if pr_doc.mixed_conditions else [item_row.get(apply_on)])
@@ -480,23 +513,22 @@
 		apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
 		items = [pr_doc.get(apply_on)]
 
-	rule_applied = 1
-	if item_row.get(apply_on) in items:
-		for field in ['discount_percentage', 'discount_amount', 'rate']:
-			if not pr_doc.get(field): continue
-
-			if not pr_doc.validate_applied_rule:
-				item_row.set(field, value)
-			elif item_row.get(field) < value:
-				rule_applied = 0
-				frappe.msgprint(_("Row {0}: user has not applied rule <b>{1}</b> on the item <b>{2}</b>")
-					.format(item_row.idx, pr_doc.title, item_row.item_code))
-
-			pr_row.rule_applied = rule_applied
+	return apply_on, items
 
 def get_pricing_rule_items(pr_doc):
 	apply_on = frappe.scrub(pr_doc.get('apply_on'))
 
 	pricing_rule_apply_on = apply_on_table.get(pr_doc.get('apply_on'))
 
-	return [item.get(apply_on) for item in pr_doc.get(pricing_rule_apply_on)] or []
\ No newline at end of file
+	return [item.get(apply_on) for item in pr_doc.get(pricing_rule_apply_on)] or []
+
+@frappe.whitelist()
+def validate_pricing_rule_for_different_cond(doc):
+	if isinstance(doc, string_types):
+		doc = json.loads(doc)
+
+	doc = frappe.get_doc(doc)
+	for d in doc.get("items"):
+		validate_pricing_rule_on_items(doc, d, True)
+
+	return doc
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index b2c1de5..cf4ec49 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -25,9 +25,6 @@
 		frm.set_indicator_formatter('item_code',
 			function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
 
-		frm.set_indicator_formatter('pricing_rule',
-			function(doc) { return (doc.rule_applied) ? "green" : "red" })
-
 		frm.set_query("blanket_order", "items", function() {
 			return {
 				filters: {
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 602f9b8..27c31eb 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -282,7 +282,7 @@
 					if self.doctype in ["Purchase Invoice", "Sales Invoice"] and item.meta.get_field('is_fixed_asset'):
 						item.set('is_fixed_asset', ret.get('is_fixed_asset', 0))
 
-					if ret.get("pricing_rules"):
+					if ret.get("pricing_rules") and not ret.get("validate_applied_rule", 0):
 						# if user changed the discount percentage then set user's discount percentage ?
 						item.set("pricing_rules", ret.get("pricing_rules"))
 						item.set("discount_percentage", ret.get("discount_percentage"))
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index f647913..62b8155 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -158,6 +158,11 @@
 				};
 			});
 		}
+
+		if(frappe.meta.get_docfield(this.frm.doc.doctype, "pricing_rules")) {
+			this.frm.set_indicator_formatter('pricing_rule',
+				function(doc) { return (doc.rule_applied) ? "green" : "red" });
+		}
 	},
 	onload: function() {
 		var me = this;
@@ -422,6 +427,7 @@
 					method: "erpnext.stock.get_item_details.get_item_details",
 					child: item,
 					args: {
+						doc: me.frm.doc,
 						args: {
 							item_code: item.item_code,
 							barcode: item.barcode,
@@ -456,7 +462,7 @@
 							cost_center: item.cost_center,
 							tax_category: me.frm.doc.tax_category,
 							item_tax_template: item.item_tax_template,
-							child_docname: item.name
+							child_docname: item.name,
 						}
 					},
 
@@ -482,7 +488,7 @@
 									}
 								},
 								() => me.conversion_factor(doc, cdt, cdn, true),
-								() => me.update_free_items(item)
+								() => me.validate_pricing_rule(item)
 							]);
 						}
 					}
@@ -1116,7 +1122,7 @@
 				callback: function(r) {
 					if (!r.exc && r.message) {
 						r.message.forEach(row_item => {
-							me.update_free_items(row_item);
+							me.validate_pricing_rule(row_item);
 						});
 						me._set_values_for_item_list(r.message);
 						me.calculate_taxes_and_totals();
@@ -1139,14 +1145,12 @@
 
 		return this.frm.call({
 			method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.apply_pricing_rule",
-			args: {	args: args },
+			args: {	args: args, doc: me.frm.doc },
 			callback: function(r) {
 				if (!r.exc && r.message) {
 					me._set_values_for_item_list(r.message);
 					if(item) me.set_gross_profit(item);
-					if(calculate_taxes_and_totals) me.calculate_taxes_and_totals();
 					if(me.frm.doc.apply_discount_on) me.frm.trigger("apply_discount_on")
-					me.update_free_items(item);
 				}
 			}
 		});
@@ -1200,7 +1204,6 @@
 					"warehouse": d.warehouse,
 					"serial_no": d.serial_no,
 					"price_list_rate": d.price_list_rate,
-					"discount_percentage": d.discount_percentage || 0.0,
 					"conversion_factor": d.conversion_factor || 1.0
 				});
 
@@ -1241,6 +1244,8 @@
 			// if pricing rule set as blank from an existing value, apply price_list
 			if(!me.frm.doc.ignore_pricing_rule && existing_pricing_rule && !d.pricing_rules) {
 				me.apply_price_list(frappe.get_doc(d.doctype, d.name));
+			} else {
+				me.validate_pricing_rule(frappe.get_doc(d.doctype, d.name));
 			}
 		}
 
@@ -1288,41 +1293,29 @@
 		});
 	},
 
-	update_free_items: function(item) {
-		var me = this;
+	validate_pricing_rule: function(item) {
+		let me = this;
+		const fields = ["discount_percentage", "discount_amount", "pricing_rules"];
 
 		if (item.pricing_rules) {
 			frappe.call({
-				method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.get_free_items",
+				method: "erpnext.accounts.doctype.pricing_rule.utils.validate_pricing_rule_for_different_cond",
 				args: {
-					pricing_rules: item.pricing_rules,
-					item_row: item
+					doc: me.frm.doc
 				},
 				callback: function(r) {
-					let items = [];
-					let child = '';
-
-					me.frm.doc.items.map(d => {
-						items[d.item_code] = d;
-					});
-
-					if(r.message && r.message.length) {
-						r.message.forEach(d => {
-							// If free item is already exists
-
-							if(d.item_code in items &&
-								d.is_free_item && items[d.item_code].is_free_item) {
-								child = items[d.item_code];
-							} else {
-								child = frappe.model.add_child(me.frm.doc, item.doctype, "items");
-							}
-
-							$.each(d, function(k, v) {
-								child[k] = v;
+					if (r.message) {
+						r.message.items.forEach(d => {
+							me.frm.doc.items.forEach(row => {
+								if(d.name == row.name) {
+									fields.forEach(f => {
+										row[f] = d[f];
+									});
+								}
 							});
-
-							me.frm.script_manager.trigger("price_list_rate", child.doctype, child.name);
 						});
+
+						me.trigger_price_list_rate();
 					}
 				}
 			});
@@ -1337,9 +1330,29 @@
 
 			me.frm.doc.items = items;
 			refresh_field('items');
+		} else if(item.applied_on_items && item.apply_on) {
+			const applied_on_items = item.applied_on_items.split(',');
+			me.frm.doc.items.forEach(row => {
+				if(applied_on_items.includes(row[item.apply_on])) {
+					fields.forEach(f => {
+						row[f] = 0;
+					});
+				}
+			});
+
+			me.trigger_price_list_rate();
 		}
 	},
 
+	trigger_price_list_rate: function() {
+		var me  = this;
+
+		this.frm.doc.items.forEach(child_row => {
+			me.frm.script_manager.trigger("price_list_rate",
+				child_row.doctype, child_row.name);
+		})
+	},
+
 	validate_company_and_party: function() {
 		var me = this;
 		var valid = true;
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index f5e21d1..b098fde 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -233,9 +233,13 @@
 			} else {
 				this.update_item_in_frm(item, field, value)
 					.then(() => {
-						// update cart
-						this.update_cart_data(item);
-						this.set_form_action();
+						this.frm.doc.items.forEach(item_row => {
+							// update cart
+							frappe.run_serially([
+								() => this.update_cart_data(item_row),
+								() => this.set_form_action()
+							]);
+						});
 					});
 			}
 			return;
@@ -256,7 +260,9 @@
 					.then(() => {
 						this.frm.script_manager.trigger('qty', item.doctype, item.name)
 							.then(() => {
-								this.update_cart_data(item);
+								this.frm.doc.items.forEach(item => {
+									this.update_cart_data(item);
+								});
 							});
 					});
 			},