Validate item rate with reference document with tolerance 0.009
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 50a79ec..af144cb 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -124,20 +124,11 @@
 			}
 		})
 
-		if cint(frappe.defaults.get_global_default('maintain_same_rate')):
-			super(PurchaseInvoice, self).validate_with_previous_doc({
-				"Purchase Order Item": {
-					"ref_dn_field": "po_detail",
-					"compare_fields": [["rate", "="]],
-					"is_child_table": True,
-					"allow_duplicate_prev_row_id": True
-				},
-				"Purchase Receipt Item": {
-					"ref_dn_field": "pr_detail",
-					"compare_fields": [["rate", "="]],
-					"is_child_table": True
-				}
-			})
+		if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
+			self.validate_rate_with_reference_doc([
+				["Purchase Order", "purchase_order", "po_detail"], 
+				["Purchase Receipt", "purchase_receipt", "pr_detail"]
+			])
 
 	def set_against_expense_account(self):
 		auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 604370b..75d4e2d 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -263,20 +263,11 @@
 			},
 		})
 
-		if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')):
-			super(SalesInvoice, self).validate_with_previous_doc({
-				"Sales Order Item": {
-					"ref_dn_field": "so_detail",
-					"compare_fields": [["rate", "="]],
-					"is_child_table": True,
-					"allow_duplicate_prev_row_id": True
-				},
-				"Delivery Note Item": {
-					"ref_dn_field": "dn_detail",
-					"compare_fields": [["rate", "="]],
-					"is_child_table": True
-				}
-			})
+		if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
+			self.validate_rate_with_reference_doc([
+				["Sales Order", "sales_order", "so_detail"], 
+				["Delivery Note", "delivery_note", "dn_detail"]
+			])
 
 	def set_against_income_account(self):
 		"""Set against account for debit to account"""
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index f52f7e5..90a8a6c 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -108,11 +108,9 @@
 		if not self.installation_status: self.installation_status = 'Not Installed'
 
 	def validate_with_previous_doc(self):
-		items = self.get("items")
-
 		for fn in (("Sales Order", "against_sales_order", "so_detail"), 
 				("Sales Invoice", "against_sales_invoice", "si_detail")):
-			if filter(None, [getattr(d, fn[1], None) for d in items]):
+			if filter(None, [getattr(d, fn[1], None) for d in self.get("items")]):
 				super(DeliveryNote, self).validate_with_previous_doc({
 					fn[0]: {
 						"ref_dn_field": fn[1],
@@ -120,15 +118,10 @@
 							["currency", "="]],
 					},
 				})
-
-				if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')):
-					super(DeliveryNote, self).validate_with_previous_doc({
-						fn[0] + " Item": {
-							"ref_dn_field": fn[2],
-							"compare_fields": [["rate", "="]],
-							"is_child_table": True
-						}
-					})
+				
+		if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
+			self.validate_rate_with_reference_doc([["Sales Order", "sales_order", "so_detail"], 
+				["Sales Invoice", "sales_invoice", "si_detail"]])
 
 	def validate_proj_cust(self):
 		"""check for does customer belong to same project as entered.."""
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index e56cd1e..e782889 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -104,15 +104,8 @@
 			}
 		})
 
-		if cint(frappe.defaults.get_global_default('maintain_same_rate')):
-			super(PurchaseReceipt, self).validate_with_previous_doc({
-				"Purchase Order Item": {
-					"ref_dn_field": "prevdoc_detail_docname",
-					"compare_fields": [["rate", "="]],
-					"is_child_table": True
-				}
-			})
-
+		if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
+			self.validate_rate_with_reference_doc([["Purchase Order", "prevdoc_docname", "prevdoc_detail_docname"]])
 
 	def po_required(self):
 		if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index be74aeb..63e8f67 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import cstr, now_datetime, cint
+from frappe.utils import cstr, now_datetime, cint, flt
 import frappe.share
 
 from erpnext.controllers.status_updater import StatusUpdater
@@ -92,6 +92,17 @@
 				for field, condition in fields:
 					if prevdoc_values[field] is not None:
 						self.validate_value(field, condition, prevdoc_values[field], doc)
+						
+						
+	def validate_rate_with_reference_doc(self, ref_details):
+		for ref_dt, ref_dn_field, ref_link_field in ref_details:
+			for d in self.get("items"):
+				if d.get(ref_link_field):
+					ref_rate = frappe.db.get_value(ref_dt + " Item", d.get(ref_link_field), "rate")
+					
+					if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= .01:
+						frappe.throw(_("Row #{0}: Rate must be same with {1}: {2} ({3} / {4}) ")
+							.format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
 
 
 def delete_events(ref_type, ref_name):