[Enhancement] Purchase return for rejected qty
diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js
index ccf7a2f..3083acb 100644
--- a/erpnext/buying/doctype/purchase_common/purchase_common.js
+++ b/erpnext/buying/doctype/purchase_common/purchase_common.js
@@ -138,20 +138,15 @@
 	},
 
 	qty: function(doc, cdt, cdn) {
+		var item = frappe.get_doc(cdt, cdn);
 		if ((doc.doctype == "Purchase Receipt") || (doc.doctype == "Purchase Invoice" && doc.update_stock)) {
-			var item = frappe.get_doc(cdt, cdn);
 			frappe.model.round_floats_in(item, ["qty", "received_qty"]);
 			if(!(item.received_qty || item.rejected_qty) && item.qty) {
 				item.received_qty = item.qty;
 			}
 
-			if(item.qty > item.received_qty) {
-				msgprint(__("Error: {0} > {1}", [__(frappe.meta.get_label(item.doctype, "qty", item.name)),
-							__(frappe.meta.get_label(item.doctype, "received_qty", item.name))]))
-				item.qty = item.rejected_qty = 0.0;
-			} else {
-				item.rejected_qty = flt(item.received_qty - item.qty, precision("rejected_qty", item));
-			}
+			frappe.model.round_floats_in(item, ["qty", "received_qty"]);
+			item.rejected_qty = flt(item.received_qty - item.qty, precision("rejected_qty", item));
 		}
 
 		this._super(doc, cdt, cdn);
@@ -160,26 +155,18 @@
 	},
 
 	received_qty: function(doc, cdt, cdn) {
-		var item = frappe.get_doc(cdt, cdn);
-		frappe.model.round_floats_in(item, ["qty", "received_qty"]);
-
-		item.qty = (item.qty < item.received_qty) ? item.qty : item.received_qty;
-		this.qty(doc, cdt, cdn);
+		this.calculate_accepted_qty(doc, cdt, cdn)
 	},
 
 	rejected_qty: function(doc, cdt, cdn) {
+		this.calculate_accepted_qty(doc, cdt, cdn)
+	},
+
+	calculate_accepted_qty: function(doc, cdt, cdn){
 		var item = frappe.get_doc(cdt, cdn);
 		frappe.model.round_floats_in(item, ["received_qty", "rejected_qty"]);
 
-		if(item.rejected_qty > item.received_qty) {
-			msgprint(__("Error: {0} > {1}", [__(frappe.meta.get_label(item.doctype, "rejected_qty", item.name)),
-						__(frappe.meta.get_label(item.doctype, "received_qty", item.name))]));
-			item.qty = item.rejected_qty = 0.0;
-		} else {
-
-			item.qty = flt(item.received_qty - item.rejected_qty, precision("qty", item));
-		}
-
+		item.qty = flt(item.received_qty - item.rejected_qty, precision("qty", item));
 		this.qty(doc, cdt, cdn);
 	},
 
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 88acfb7..f7181d7 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -37,7 +37,7 @@
 			self.validate_purchase_receipt_if_update_stock()
 
 		if self.doctype=="Purchase Receipt" or (self.doctype=="Purchase Invoice" and self.update_stock):
-			self.validate_purchase_return()
+			# self.validate_purchase_return()
 			self.validate_rejected_warehouse()
 			self.validate_accepted_rejected_qty()
 
@@ -346,7 +346,7 @@
 						})
 					sl_entries.append(sle)
 
-				if flt(d.rejected_qty) > 0:
+				if flt(d.rejected_qty) != 0:
 					sl_entries.append(self.get_sl_entries(d, {
 						"warehouse": d.rejected_warehouse,
 						"actual_qty": flt(d.rejected_qty) * flt(d.conversion_factor),
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 8d30247..ae03a35 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -53,13 +53,15 @@
 
 	valid_items = frappe._dict()
 
-	select_fields = "item_code, qty" if doc.doctype=="Purchase Invoice" \
-		else "item_code, qty, serial_no, batch_no"
+	select_fields = "item_code, qty, parenttype" if doc.doctype=="Purchase Invoice" \
+		else "item_code, qty, serial_no, batch_no, parenttype"
+
+	if doc.doctype in ['Purchase Invoice', 'Purchase Receipt']:
+		select_fields += ",rejected_qty, received_qty"
 
 	for d in frappe.db.sql("""select {0} from `tab{1} Item` where parent = %s"""
 		.format(select_fields, doc.doctype), doc.return_against, as_dict=1):
 			valid_items = get_ref_item_dict(valid_items, d)
-			
 
 	if doc.doctype in ("Delivery Note", "Sales Invoice"):
 		for d in frappe.db.sql("""select item_code, qty, serial_no, batch_no from `tabPacked Item`
@@ -73,21 +75,15 @@
 
 	items_returned = False
 	for d in doc.get("items"):
-		if flt(d.qty) < 0:
+		if flt(d.qty) < 0 or d.get('received_qty') < 0:
 			if d.item_code not in valid_items:
 				frappe.throw(_("Row # {0}: Returned Item {1} does not exists in {2} {3}")
 					.format(d.idx, d.item_code, doc.doctype, doc.return_against))
 			else:
 				ref = valid_items.get(d.item_code, frappe._dict())
-				already_returned_qty = flt(already_returned_items.get(d.item_code))
-				max_return_qty = flt(ref.qty) - already_returned_qty
+				validate_quantity(doc, d, ref, valid_items, already_returned_items)
 
-				if already_returned_qty >= ref.qty:
-					frappe.throw(_("Item {0} has already been returned").format(d.item_code), StockOverReturnError)
-				elif abs(d.qty) > max_return_qty:
-					frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
-						.format(d.idx, ref.qty, d.item_code), StockOverReturnError)
-				elif ref.batch_no and d.batch_no not in ref.batch_no:
+				if ref.batch_no and d.batch_no not in ref.batch_no:
 					frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}")
 						.format(d.idx, doc.doctype, doc.return_against))
 				elif ref.serial_no:
@@ -107,18 +103,45 @@
 
 	if not items_returned:
 		frappe.throw(_("Atleast one item should be entered with negative quantity in return document"))
-		
+
+def validate_quantity(doc, args, ref, valid_items, already_returned_items):
+	fields = ['qty']
+	if doc.doctype in ['Purchase Invoice', 'Purchase Receipt']:
+		fields.extend(['received_qty', 'rejected_qty'])
+
+	already_returned_data = already_returned_items.get(args.item_code) or {}
+
+	for column in fields:
+		return_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0
+		referenced_qty = ref.get(column)
+		max_return_qty = flt(referenced_qty) - return_qty
+		label = column.replace('_', ' ').title()
+
+		if flt(args.get(column)) > 0:
+			frappe.throw(_("{0} must be negative in return document").format(label))
+		elif return_qty >= referenced_qty and flt(args.get(column)) != 0:
+			frappe.throw(_("Item {0} has already been returned").format(args.item_code), StockOverReturnError)
+		elif abs(args.get(column)) > max_return_qty:
+			frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
+				.format(args.idx, referenced_qty, args.item_code), StockOverReturnError)
+
 def get_ref_item_dict(valid_items, ref_item_row):
 	from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
 	
 	valid_items.setdefault(ref_item_row.item_code, frappe._dict({
 		"qty": 0,
+		"rejected_qty": 0,
+		"received_qty": 0,
 		"serial_no": [],
 		"batch_no": []
 	}))
 	item_dict = valid_items[ref_item_row.item_code]
 	item_dict["qty"] += ref_item_row.qty
-	
+
+	if ref_item_row.parenttype in ['Purchase Invoice', 'Purchase Receipt']:
+		item_dict["received_qty"] += ref_item_row.received_qty
+		item_dict["rejected_qty"] += ref_item_row.rejected_qty
+
 	if ref_item_row.get("serial_no"):
 		item_dict["serial_no"] += get_serial_nos(ref_item_row.serial_no)
 		
@@ -128,16 +151,30 @@
 	return valid_items
 
 def get_already_returned_items(doc):
-	return frappe._dict(frappe.db.sql("""
-		select
-			child.item_code, sum(abs(child.qty)) as qty
+	column = 'child.item_code, sum(abs(child.qty)) as qty'
+	if doc.doctype in ['Purchase Invoice', 'Purchase Receipt']:
+		column += ', sum(abs(child.rejected_qty)) as rejected_qty, sum(abs(child.received_qty)) as received_qty'
+
+	data = frappe.db.sql("""
+		select {0}
 		from
-			`tab{0} Item` child, `tab{1}` par
+			`tab{1} Item` child, `tab{2}` par
 		where
 			child.parent = par.name and par.docstatus = 1
-			and par.is_return = 1 and par.return_against = %s and child.qty < 0
+			and par.is_return = 1 and par.return_against = %s
 		group by item_code
-	""".format(doc.doctype, doc.doctype), doc.return_against))
+	""".format(column, doc.doctype, doc.doctype), doc.return_against, as_dict=1)
+
+	items = {}
+
+	for d in data:
+		items.setdefault(d.item_code, frappe._dict({
+			"qty": d.get("qty"),
+			"received_qty": d.get("received_qty"),
+			"rejected_qty": d.get("rejected_qty")
+		}))
+
+	return items
 
 def make_return_doc(doctype, source_name, target_doc=None):
 	from frappe.model.mapper import get_mapped_doc
@@ -166,12 +203,18 @@
 	def update_item(source_doc, target_doc, source_parent):
 		target_doc.qty = -1* source_doc.qty
 		if doctype == "Purchase Receipt":
-			target_doc.received_qty = -1* source_doc.qty
+			target_doc.received_qty = -1* source_doc.received_qty
+			target_doc.rejected_qty = -1* source_doc.rejected_qty
+			target_doc.qty = -1* source_doc.qty
 			target_doc.purchase_order = source_doc.purchase_order
+			target_doc.rejected_warehouse = source_doc.rejected_warehouse
 		elif doctype == "Purchase Invoice":
-			target_doc.received_qty = -1* source_doc.qty
+			target_doc.received_qty = -1* source_doc.received_qty
+			target_doc.rejected_qty = -1* source_doc.rejected_qty
+			target_doc.qty = -1* source_doc.qty
 			target_doc.purchase_order = source_doc.purchase_order
 			target_doc.purchase_receipt = source_doc.purchase_receipt
+			target_doc.rejected_warehouse = source_doc.rejected_warehouse
 			target_doc.po_detail = source_doc.po_detail
 			target_doc.pr_detail = source_doc.pr_detail
 		elif doctype == "Delivery Note":