Merge branch 'nabinhait-return_improvements' into develop
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 132cb10..2208937 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -127,7 +127,7 @@
 			}
 		})
 
-		if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
+		if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')) and not self.is_return:
 			self.validate_rate_with_reference_doc([
 				["Purchase Order", "purchase_order", "po_detail"],
 				["Purchase Receipt", "purchase_receipt", "pr_detail"]
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
index ccad5ce..afcd61f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
@@ -7,7 +7,7 @@
 		"currency", "is_return"],
 	get_indicator: function(doc) {
 		if(cint(doc.is_return)==1) {
-			return [__("Return"), "darkgrey", "is_return,=,1"];
+			return [__("Return"), "darkgrey", "is_return,=,Yes"];
 		} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
 			if(frappe.datetime.get_diff(doc.due_date) < 0) {
 				return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<,Today"];
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 734684f..5e59078 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -64,6 +64,7 @@
 			if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
 				cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry).addClass("btn-primary");
 			}
+
 		}
 
 		// Show buttons only when pos view is active
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index f82590a..1274016 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -81,9 +81,14 @@
 
 		self.check_prev_docstatus()
 
+		if self.is_return:
+			# NOTE status updating bypassed for is_return
+			self.status_updater = []
+
+		self.update_status_updater_args()
+		self.update_prevdoc_status()
+
 		if not self.is_return:
-			self.update_status_updater_args()
-			self.update_prevdoc_status()
 			self.update_billing_status_for_zero_amount_refdoc("Sales Order")
 			self.check_credit_limit()
 
@@ -107,9 +112,14 @@
 		from erpnext.accounts.utils import remove_against_link_from_jv
 		remove_against_link_from_jv(self.doctype, self.name)
 
+		if self.is_return:
+			# NOTE status updating bypassed for is_return
+			self.status_updater = []
+
+		self.update_status_updater_args()
+		self.update_prevdoc_status()
+
 		if not self.is_return:
-			self.update_status_updater_args()
-			self.update_prevdoc_status()
 			self.update_billing_status_for_zero_amount_refdoc("Sales Order")
 
 		self.validate_c_form_on_cancel()
@@ -118,7 +128,7 @@
 
 	def update_status_updater_args(self):
 		if cint(self.update_stock):
-			self.status_updater.append({
+			self.status_updater.extend([{
 				'source_dt':'Sales Invoice Item',
 				'target_dt':'Sales Order Item',
 				'target_parent_dt':'Sales Order',
@@ -136,7 +146,21 @@
 				'overflow_type': 'delivery',
 				'extra_cond': """ and exists(select name from `tabSales Invoice`
 					where name=`tabSales Invoice Item`.parent and ifnull(update_stock, 0) = 1)"""
-			})
+			},
+			{
+				'source_dt': 'Sales Invoice Item',
+				'target_dt': 'Sales Order Item',
+				'join_field': 'so_detail',
+				'target_field': 'returned_qty',
+				'target_parent_dt': 'Sales Order',
+				# 'target_parent_field': 'per_delivered',
+				# 'target_ref_field': 'qty',
+				'source_field': '-1 * qty',
+				# 'percent_join_field': 'sales_order',
+				# 'overflow_type': 'delivery',
+				'extra_cond': """ and exists (select name from `tabSales Invoice` where name=`tabSales Invoice Item`.parent and update_stock=1 and is_return=1)"""
+			}
+		])
 
 	def set_missing_values(self, for_validate=False):
 		pos = self.set_pos_fields(for_validate)
@@ -273,7 +297,7 @@
 			},
 		})
 
-		if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
+		if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')) and not self.is_return:
 			self.validate_rate_with_reference_doc([
 				["Sales Order", "sales_order", "so_detail"],
 				["Delivery Note", "delivery_note", "dn_detail"]
@@ -294,8 +318,6 @@
 
 	def so_dn_required(self):
 		"""check in manage account if sales order / delivery note required or not."""
-		if self.is_return:
-			return
 		dic = {'Sales Order':'so_required','Delivery Note':'dn_required'}
 		for i in dic:
 			if frappe.db.get_value('Selling Settings', None, dic[i]) == 'Yes':
@@ -408,35 +430,11 @@
 
 	def check_prev_docstatus(self):
 		for d in self.get('items'):
-			if d.sales_order:
-				submitted = frappe.db.sql("""select name from `tabSales Order`
-					where docstatus = 1 and name = %s""", d.sales_order)
-				if not submitted:
-					frappe.throw(_("Sales Order {0} is not submitted").format(d.sales_order))
+			if d.sales_order and frappe.db.get_value("Sales Order", d.sales_order, "docstatus") != 1:
+				frappe.throw(_("Sales Order {0} is not submitted").format(d.sales_order))
 
-			if d.delivery_note:
-				submitted = frappe.db.sql("""select name from `tabDelivery Note`
-					where docstatus = 1 and name = %s""", d.delivery_note)
-				if not submitted:
-					throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
-
-	def update_stock_ledger(self):
-		sl_entries = []
-		for d in self.get_item_list():
-			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and d.warehouse and flt(d['qty']):
-				self.update_reserved_qty(d)
-
-				incoming_rate = 0
-				if cint(self.is_return) and self.return_against and self.docstatus==1:
-					incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code,
-						self.return_against)
-
-				sl_entries.append(self.get_sl_entries(d, {
-					"actual_qty": -1*flt(d.qty),
-					"stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom"),
-					"incoming_rate": incoming_rate
-				}))
-		self.make_sl_entries(sl_entries)
+			if d.delivery_note and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus") != 1:
+				throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
 
 	def make_gl_entries(self, repost_future_gle=True):
 		gl_entries = self.get_gl_entries()
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js
index 11c9789..55e8b21 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js
@@ -7,7 +7,7 @@
 		"currency", "is_return"],
 	get_indicator: function(doc) {
 		if(cint(doc.is_return)==1) {
-			return [__("Return"), "darkgrey", "is_return,=,1"];
+			return [__("Return"), "darkgrey", "is_return,=,Yes"];
 		} else if(flt(doc.outstanding_amount)==0) {
 			return [__("Paid"), "green", "outstanding_amount,=,0"]
 		} else if (flt(doc.outstanding_amount) > 0 && doc.due_date > frappe.datetime.get_today()) {
diff --git a/erpnext/accounts/print_format/credit_note___negative_invoice/__init__.py b/erpnext/accounts/print_format/credit_note___negative_invoice/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/print_format/credit_note___negative_invoice/__init__.py
+++ /dev/null
diff --git a/erpnext/accounts/print_format/credit_note___negative_invoice/credit_note___negative_invoice.json b/erpnext/accounts/print_format/credit_note___negative_invoice/credit_note___negative_invoice.json
deleted file mode 100644
index e7d7eab..0000000
--- a/erpnext/accounts/print_format/credit_note___negative_invoice/credit_note___negative_invoice.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "creation": "2015-07-22 17:45:22.220567", 
- "custom_format": 1, 
- "disabled": 0, 
- "doc_type": "Sales Invoice", 
- "docstatus": 0, 
- "doctype": "Print Format", 
- "font": "Default", 
- "html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 6in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Credit Note\") }}<br>\n</p>\n\n<hr>\n\n{%- for label, value in (\n    (_(\"Receipt No\"), doc.name),\n    (_(\"Date\"), doc.get_formatted(\"posting_date\")),\n\t(_(\"Customer\"), doc.customer_name),\n    (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"grand_total\", absolute_value=True) + \"</strong><br>\" + (doc.in_words or \"\")),\n\t(_(\"Against\"), doc.return_against),\n    (_(\"Remarks\"), doc.remarks)\n) -%}\n\n\t\t<div class=\"row\">\n\t\t    <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n\t\t    <div class=\"col-xs-8\">{{ value }}</div>\n\t\t</div>\n{%- endfor -%}\n\n<hr>\n<br>\n<p class=\"strong\">\n    {{ _(\"For\") }} {{ doc.company }},<br>\n    <br>\n    <br>\n    <br>\n        {{ _(\"Authorized Signatory\") }}\n</p>", 
- "modified": "2015-07-22 17:45:22.220567", 
- "modified_by": "Administrator", 
- "name": "Credit Note - Negative Invoice", 
- "owner": "Administrator", 
- "print_format_builder": 0, 
- "print_format_type": "Server", 
- "standard": "Yes"
-}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 9887ddb..58b1d19 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -9,6 +9,7 @@
 from frappe.model.mapper import get_mapped_doc
 from erpnext.controllers.buying_controller import BuyingController
 from erpnext.stock.doctype.item.item import get_last_purchase_details
+from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty
 
 
 form_grid_templates = {
@@ -136,20 +137,6 @@
 
 	def update_ordered_qty(self, po_item_rows=None):
 		"""update requested qty (before ordered_qty is updated)"""
-		from erpnext.stock.utils import get_bin
-
-		def _update_ordered_qty(item_code, warehouse):
-			ordered_qty = frappe.db.sql("""
-				select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor)
-				from `tabPurchase Order Item` po_item, `tabPurchase Order` po
-				where po_item.item_code=%s and po_item.warehouse=%s
-				and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name
-				and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse))
-
-			bin_doc = get_bin(item_code, warehouse)
-			bin_doc.ordered_qty = flt(ordered_qty[0][0]) if ordered_qty else 0
-			bin_doc.save()
-
 		item_wh_list = []
 		for d in self.get("items"):
 			if (not po_item_rows or d.name in po_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \
@@ -157,7 +144,9 @@
 				item_wh_list.append([d.item_code, d.warehouse])
 
 		for item_code, warehouse in item_wh_list:
-			_update_ordered_qty(item_code, warehouse)
+			update_bin_qty(item_code, warehouse, {
+				"ordered_qty": get_ordered_qty(item_code, warehouse)
+			})
 
 	def check_modified_date(self):
 		mod_db = frappe.db.sql("select modified from `tabPurchase Order` where name = %s",
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index bd86285..7faa2f3 100755
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -1004,6 +1004,27 @@
   }, 
   {
    "allow_on_submit": 0, 
+   "depends_on": "returned_qty", 
+   "fieldname": "returned_qty", 
+   "fieldtype": "Float", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Returned Qty", 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
    "fieldname": "billed_amt", 
    "fieldtype": "Currency", 
    "hidden": 0, 
@@ -1074,7 +1095,7 @@
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 1, 
- "modified": "2015-08-19 12:46:32.384796", 
+ "modified": "2015-08-25 06:42:00.898647", 
  "modified_by": "Administrator", 
  "module": "Buying", 
  "name": "Purchase Order Item", 
diff --git a/erpnext/change_log/current/sales_purchase_return.md b/erpnext/change_log/current/sales_purchase_return.md
new file mode 100644
index 0000000..0152d57
--- /dev/null
+++ b/erpnext/change_log/current/sales_purchase_return.md
@@ -0,0 +1,3 @@
+- Fixes in Sales and Purchase Return
+	- Update Delivered, Ordered and Returned Quantity based on Return transaction
+	- Allow different Rate in Return transaction
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index f429c67..f4895ca 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -11,10 +11,10 @@
 def validate_return(doc):
 	if not doc.meta.get_field("is_return") or not doc.is_return:
 		return
-		
+
 	validate_return_against(doc)
 	validate_returned_items(doc)
-			
+
 def validate_return_against(doc):
 	if not doc.return_against:
 		frappe.throw(_("{0} is mandatory for Return").format(doc.meta.get_label("return_against")))
@@ -24,49 +24,49 @@
 			filters["customer"] = doc.customer
 		elif doc.meta.get_field("supplier"):
 			filters["supplier"] = doc.supplier
-			
+
 		if not frappe.db.exists(filters):
 				frappe.throw(_("Invalid {0}: {1}")
 					.format(doc.meta.get_label("return_against"), doc.return_against))
 		else:
 			ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
-				
+
 			# validate posting date time
 			return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
 			ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
-			
+
 			if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime):
 				frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime)))
-			
+
 			# validate same exchange rate
 			if doc.conversion_rate != ref_doc.conversion_rate:
 				frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})")
 					.format(doc.doctype, doc.return_against, ref_doc.conversion_rate))
-					
+
 			# validate update stock
 			if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock:
 					frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}")
 						.format(doc.return_against))
-				
+
 def validate_returned_items(doc):
 	from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
-	
+
 	valid_items = frappe._dict()
-	
+
 	select_fields = "item_code, sum(qty) as qty, rate" if doc.doctype=="Purchase Invoice" \
 		else "item_code, sum(qty) as qty, rate, serial_no, batch_no"
-	
-	for d in frappe.db.sql("""select {0} from `tab{1} Item` where parent = %s 
+
+	for d in frappe.db.sql("""select {0} from `tab{1} Item` where parent = %s
 		group by item_code""".format(select_fields, doc.doctype), doc.return_against, as_dict=1):
-			valid_items.setdefault(d.item_code, d)	
-	
+			valid_items.setdefault(d.item_code, d)
+
 	if doc.doctype in ("Delivery Note", "Sales Invoice"):
-		for d in frappe.db.sql("""select item_code, sum(qty) as qty, serial_no, batch_no from `tabPacked Item` 
+		for d in frappe.db.sql("""select item_code, sum(qty) as qty, serial_no, batch_no from `tabPacked Item`
 			where parent = %s group by item_code""".format(doc.doctype), doc.return_against, as_dict=1):
 				valid_items.setdefault(d.item_code, d)
-			
+
 	already_returned_items = get_already_returned_items(doc)
-	
+
 	items_returned = False
 	for d in doc.get("items"):
 		if flt(d.qty) < 0:
@@ -77,15 +77,12 @@
 				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
-				
+
 				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.rate and flt(d.rate) != ref.rate:
-					frappe.throw(_("Row # {0}: Rate must be same as {1} {2}")
-						.format(d.idx, doc.doctype, doc.return_against))
 				elif ref.batch_no and d.batch_no != ref.batch_no:
 					frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}")
 						.format(d.idx, doc.doctype, doc.return_against))
@@ -99,24 +96,24 @@
 							if s not in ref_serial_nos:
 								frappe.throw(_("Row # {0}: Serial No {1} does not match with {2} {3}")
 									.format(d.idx, s, doc.doctype, doc.return_against))
-				
+
 			items_returned = True
-			
+
 	if not items_returned:
 		frappe.throw(_("Atleast one item should be entered with negative quantity in return document"))
-		
+
 def get_already_returned_items(doc):
 	return frappe._dict(frappe.db.sql("""
-		select 
+		select
 			child.item_code, sum(abs(child.qty)) as qty
-		from 
-			`tab{0} Item` child, `tab{1}` par 
-		where 
+		from
+			`tab{0} Item` child, `tab{1}` par
+		where
 			child.parent = par.name and par.docstatus = 1
-			and ifnull(par.is_return, 0) = 1 and par.return_against = %s and child.qty < 0 
+			and ifnull(par.is_return, 0) = 1 and par.return_against = %s and child.qty < 0
 		group by item_code
 	""".format(doc.doctype, doc.doctype), doc.return_against))
-	
+
 def make_return_doc(doctype, source_name, target_doc=None):
 	from frappe.model.mapper import get_mapped_doc
 	def set_missing_values(source, target):
@@ -126,25 +123,50 @@
 		doc.ignore_pricing_rule = 1
 		if doctype == "Sales Invoice":
 			doc.is_pos = 0
-			
+
+			# look for Print Heading "Credit Note"
+			if not doc.select_print_heading:
+				doc.select_print_heading = frappe.db.get_value("Print Heading", _("Credit Note"))
+
+		elif doctype == "Purchase Invoice":
+			# look for Print Heading "Debit Note"
+			doc.select_print_heading = frappe.db.get_value("Print Heading", _("Debit Note"))
+
 		for tax in doc.get("taxes"):
 			if tax.charge_type == "Actual":
 				tax.tax_amount = -1 * tax.tax_amount
-					
+
 		doc.run_method("calculate_taxes_and_totals")
-		
+
 	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.prevdoc_doctype = source_doc.prevdoc_doctype
+			target_doc.prevdoc_docname = source_doc.prevdoc_docname
+			target_doc.prevdoc_detail_docname = source_doc.prevdoc_detail_docname
 		elif doctype == "Purchase Invoice":
+			target_doc.purchase_order = source_doc.purchase_order
 			target_doc.purchase_receipt = source_doc.purchase_receipt
+			target_doc.po_detail = source_doc.po_detail
 			target_doc.pr_detail = source_doc.pr_detail
+		elif doctype == "Delivery Note":
+			target_doc.against_sales_order = source_doc.against_sales_order
+			target_doc.against_sales_invoice = source_doc.against_sales_invoice
+			target_doc.so_detail = source_doc.so_detail
+			target_doc.si_detail = source_doc.si_detail
+			target_doc.expense_account = source_doc.expense_account
+		elif doctype == "Sales Invoice":
+			target_doc.sales_order = source_doc.sales_order
+			target_doc.delivery_note = source_doc.delivery_note
+			target_doc.so_detail = source_doc.so_detail
+			target_doc.dn_detail = source_doc.dn_detail
+			target_doc.expense_account = source_doc.expense_account
 
 	doclist = get_mapped_doc(doctype, source_name,	{
 		doctype: {
 			"doctype": doctype,
-			
+
 			"validation": {
 				"docstatus": ["=", 1],
 			}
@@ -152,8 +174,6 @@
 		doctype +" Item": {
 			"doctype": doctype + " Item",
 			"field_map": {
-				"purchase_order": "purchase_order",
-				"purchase_receipt": "purchase_receipt",
 				"serial_no": "serial_no",
 				"batch_no": "batch_no"
 			},
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 9e2bf1d..569bb82 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -163,42 +163,17 @@
 	def get_item_list(self):
 		il = []
 		for d in self.get("items"):
-			reserved_warehouse = ""
-			reserved_qty_for_main_item = 0
-
 			if d.qty is None:
 				frappe.throw(_("Row {0}: Qty is mandatory").format(d.idx))
-
-			if self.doctype == "Sales Order":
-				reserved_warehouse = d.warehouse
-				if flt(d.qty) > flt(d.delivered_qty):
-					reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
-
-			elif (((self.doctype == "Delivery Note" and d.against_sales_order) 
-					or (self.doctype == "Sales Invoice" and d.sales_order and self.update_stock)) 
-					and not self.is_return):
-				# if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
-				# But in this case reserved qty should only be reduced by 10 and not 12
-
-				already_delivered_qty = self.get_already_delivered_qty(self.name,
-					d.against_sales_order if self.doctype=="Delivery Note" else d.sales_order, d.so_detail)
-				so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.so_detail)
-
-				if already_delivered_qty + d.qty > so_qty:
-					reserved_qty_for_main_item = -(so_qty - already_delivered_qty)
-				else:
-					reserved_qty_for_main_item = -flt(d.qty)
-					
+														
 			if self.has_product_bundle(d.item_code):
 				for p in self.get("packed_items"):
 					if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
 						# the packing details table's qty is already multiplied with parent's qty
 						il.append(frappe._dict({
 							'warehouse': p.warehouse,
-							'reserved_warehouse': reserved_warehouse,
 							'item_code': p.item_code,
 							'qty': flt(p.qty),
-							'reserved_qty': (flt(p.qty)/flt(d.qty)) * reserved_qty_for_main_item,
 							'uom': p.uom,
 							'batch_no': cstr(p.batch_no).strip(),
 							'serial_no': cstr(p.serial_no).strip(),
@@ -207,10 +182,8 @@
 			else:
 				il.append(frappe._dict({
 					'warehouse': d.warehouse,
-					'reserved_warehouse': reserved_warehouse,
 					'item_code': d.item_code,
 					'qty': d.qty,
-					'reserved_qty': reserved_qty_for_main_item,
 					'uom': d.stock_uom,
 					'stock_uom': d.stock_uom,
 					'batch_no': cstr(d.get("batch_no")).strip(),
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index c7d2439..9c67e9a 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -90,6 +90,10 @@
 		self.global_tolerance = None
 
 		for args in self.status_updater:
+			if "target_ref_field" not in args:
+				# if target_ref_field is not specified, the programmer does not want to validate qty / amount
+				continue
+
 			# get unique transactions to update
 			for d in self.get_all_children():
 				if d.doctype == args['source_dt'] and d.get(args["join_field"]):
@@ -140,8 +144,9 @@
 				.format(_(item["target_ref_field"].title()), item["reduce_by"]))
 
 	def update_qty(self, change_modified=True):
-		"""
-			Updates qty at row level
+		"""Updates qty or amount at row level
+
+			:param change_modified: If true, updates `modified` and `modified_by` for target parent doc
 		"""
 		for args in self.status_updater:
 			# condition to include current record (if submit or no if cancel)
@@ -150,58 +155,74 @@
 			else:
 				args['cond'] = ' and parent!="%s"' % self.name.replace('"', '\"')
 
-			args['modified_cond'] = ''
+			args['set_modified'] = ''
 			if change_modified:
-				args['modified_cond'] = ', modified = now()'
+				args['set_modified'] = ', modified = now(), modified_by = "{0}"'\
+					.format(frappe.db.escape(frappe.session.user))
 
-			# update quantities in child table
-			for d in self.get_all_children():
-				if d.doctype == args['source_dt']:
-					# updates qty in the child table
-					args['detail_id'] = d.get(args['join_field'])
+			self._update_children(args)
 
-					args['second_source_condition'] = ""
-					if args.get('second_source_dt') and args.get('second_source_field') \
-							and args.get('second_join_field'):
-						if not args.get("second_source_extra_cond"):
-							args["second_source_extra_cond"] = ""
+			if "percent_join_field" in args:
+				self._update_percent_field(args)
 
-						args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s)
-							from `tab%(second_source_dt)s`
-							where `%(second_join_field)s`="%(detail_id)s"
-							and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s), 0) """ % args
+	def _update_children(self, args):
+		"""Update quantities or amount in child table"""
+		for d in self.get_all_children():
+			if d.doctype != args['source_dt']:
+				continue
 
-					if args['detail_id']:
-						if not args.get("extra_cond"): args["extra_cond"] = ""
+			# updates qty in the child table
+			args['detail_id'] = d.get(args['join_field'])
 
-						frappe.db.sql("""update `tab%(target_dt)s`
-							set %(target_field)s = (select sum(%(source_field)s)
-								from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
-								and (docstatus=1 %(cond)s) %(extra_cond)s) %(second_source_condition)s
-							where name='%(detail_id)s'""" % args)
+			args['second_source_condition'] = ""
+			if args.get('second_source_dt') and args.get('second_source_field') \
+					and args.get('second_join_field'):
+				if not args.get("second_source_extra_cond"):
+					args["second_source_extra_cond"] = ""
 
-			# get unique transactions to update
-			for name in set([d.get(args['percent_join_field']) for d in self.get_all_children(args['source_dt'])]):
-				if name:
-					args['name'] = name
+				args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s)
+					from `tab%(second_source_dt)s`
+					where `%(second_join_field)s`="%(detail_id)s"
+					and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s), 0) """ % args
 
-					# update percent complete in the parent table
-					if args.get('target_parent_field'):
-						frappe.db.sql("""update `tab%(target_parent_dt)s`
-							set %(target_parent_field)s = (select sum(if(%(target_ref_field)s >
-								ifnull(%(target_field)s, 0), %(target_field)s,
-								%(target_ref_field)s))/sum(%(target_ref_field)s)*100
-								from `tab%(target_dt)s` where parent="%(name)s") %(modified_cond)s
-							where name='%(name)s'""" % args)
+			if args['detail_id']:
+				if not args.get("extra_cond"): args["extra_cond"] = ""
 
-					# update field
-					if args.get('status_field'):
-						frappe.db.sql("""update `tab%(target_parent_dt)s`
-							set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001,
-								'Not %(keyword)s', if(%(target_parent_field)s>=99.99,
-								'Fully %(keyword)s', 'Partly %(keyword)s'))
-							where name='%(name)s'""" % args)
+				frappe.db.sql("""update `tab%(target_dt)s`
+					set %(target_field)s = (select sum(%(source_field)s)
+						from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
+						and (docstatus=1 %(cond)s) %(extra_cond)s) %(second_source_condition)s
+					where name='%(detail_id)s'""" % args)
 
+	def _update_percent_field(self, args):
+		"""Update percent field in parent transaction"""
+		unique_transactions = set([d.get(args['percent_join_field']) for d in self.get_all_children(args['source_dt'])])
+
+		for name in unique_transactions:
+			if not name:
+				continue
+
+			args['name'] = name
+
+			# update percent complete in the parent table
+			if args.get('target_parent_field'):
+				frappe.db.sql("""update `tab%(target_parent_dt)s`
+					set %(target_parent_field)s = (select sum(if(%(target_ref_field)s >
+						ifnull(%(target_field)s, 0), %(target_field)s,
+						%(target_ref_field)s))/sum(%(target_ref_field)s)*100
+						from `tab%(target_dt)s` where parent="%(name)s") %(set_modified)s
+					where name='%(name)s'""" % args)
+
+			# update field
+			if args.get('status_field'):
+				frappe.db.sql("""update `tab%(target_parent_dt)s`
+					set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001,
+						'Not %(keyword)s', if(%(target_parent_field)s>=99.99,
+						'Fully %(keyword)s', 'Partly %(keyword)s'))
+					where name='%(name)s'""" % args)
+
+			if args.get("set_modified"):
+				frappe.get_doc(args["target_parent_dt"], name).notify_modified()
 
 	def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
 		ref_fieldname = ref_dt.lower().replace(" ", "_")
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index cfde04b..396d088 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -6,11 +6,9 @@
 from frappe.utils import cint, flt, cstr
 from frappe import msgprint, _
 import frappe.defaults
+from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
 
 from erpnext.controllers.accounts_controller import AccountsController
-from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
-from erpnext.stock.utils import update_bin
-
 
 class StockController(AccountsController):
 	def make_gl_entries(self, repost_future_gle=True):
@@ -229,23 +227,44 @@
 			incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
 
 		return incoming_rate
+			
+	def update_reserved_qty(self):
+		so_map = {}
+		for d in self.get("items"):
+			if d.so_detail:
+				if self.doctype == "Delivery Note" and d.against_sales_order:
+					so_map.setdefault(d.against_sales_order, []).append(d.so_detail)
+				elif self.doctype == "Sales Invoice" and d.sales_order and self.update_stock:
+					so_map.setdefault(d.sales_order, []).append(d.so_detail)
 
-	def update_reserved_qty(self, d):
-		if d['reserved_qty'] < 0 :
-			# Reduce reserved qty from reserved warehouse mentioned in so
-			if not d["reserved_warehouse"]:
-				frappe.throw(_("Delivery Warehouse is missing in Sales Order"))
+		for so, so_item_rows in so_map.items():
+			if so and so_item_rows:
+				sales_order = frappe.get_doc("Sales Order", so)
 
-			args = {
-				"item_code": d['item_code'],
-				"warehouse": d["reserved_warehouse"],
-				"voucher_type": self.doctype,
-				"voucher_no": self.name,
-				"reserved_qty": (self.docstatus==1 and 1 or -1)*flt(d['reserved_qty']),
-				"posting_date": self.posting_date,
-				"is_amended": self.amended_from and 'Yes' or 'No'
-			}
-			update_bin(args)
+				if sales_order.status in ["Stopped", "Cancelled"]:
+					frappe.throw(_("Sales Order {0} is cancelled or stopped").format(so), frappe.InvalidStatusError)
+				
+				sales_order.update_reserved_qty(so_item_rows)
+				
+	def update_stock_ledger(self):
+		self.update_reserved_qty()
+		
+		sl_entries = []
+		for d in self.get_item_list():
+			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 \
+					and d.warehouse and flt(d['qty']):
+				
+				incoming_rate = 0
+				if cint(self.is_return) and self.return_against and self.docstatus==1:
+					incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
+					
+				sl_entries.append(self.get_sl_entries(d, {
+					"actual_qty": -1*flt(d['qty']),
+					"stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom"),
+					"incoming_rate": incoming_rate
+				}))
+
+		self.make_sl_entries(sl_entries)
 
 def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
 		warehouse_account=None):
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 21656c6..8051841 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -191,5 +191,10 @@
 erpnext.patches.v5_4.cleanup_journal_entry #2015-08-14
 execute:frappe.db.sql("update `tabProduction Order` pro set description = (select description from tabItem where name=pro.production_item) where ifnull(description, '') = ''")
 erpnext.patches.v5_7.item_template_attributes
+execute:frappe.delete_doc_if_exists("DocType", "Manage Variants")
+execute:frappe.delete_doc_if_exists("DocType", "Manage Variants Item")
 erpnext.patches.v4_2.repost_reserved_qty #2015-08-20
 erpnext.patches.v5_4.update_purchase_cost_against_project
+erpnext.patches.v5_8.update_order_reference_in_return_entries
+erpnext.patches.v5_8.add_credit_note_print_heading
+execute:frappe.delete_doc_if_exists("Print Format", "Credit Note - Negative Invoice")
diff --git a/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py b/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py
index 4a4266e..5a421d1 100644
--- a/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py
+++ b/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py
@@ -5,7 +5,7 @@
 import frappe
 
 def execute():
-	from erpnext.utilities.repost_stock import set_stock_balance_as_per_serial_no
+	from erpnext.stock.stock_balance import set_stock_balance_as_per_serial_no
 	frappe.db.auto_commit_on_many_writes = 1
 
 	set_stock_balance_as_per_serial_no()
diff --git a/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py b/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py
index 73a56a8..0df5801 100644
--- a/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py
+++ b/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py
@@ -6,7 +6,7 @@
 from frappe.utils import flt
 
 def execute():
-	from erpnext.utilities.repost_stock import repost
+	from erpnext.stock.stock_balance import repost
 	repost(allow_zero_rate=True, only_actual=True)
 	
 	frappe.reload_doctype("Account")
diff --git a/erpnext/patches/v4_2/repost_reserved_qty.py b/erpnext/patches/v4_2/repost_reserved_qty.py
index a2cd4d8..74f4b79 100644
--- a/erpnext/patches/v4_2/repost_reserved_qty.py
+++ b/erpnext/patches/v4_2/repost_reserved_qty.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe
-from erpnext.utilities.repost_stock import update_bin_qty, get_reserved_qty
+from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty
 
 def execute():
 	repost_for = frappe.db.sql("""
diff --git a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py
index 240b11d..7bb49e6 100644
--- a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py
+++ b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py
@@ -5,7 +5,7 @@
 import frappe
 
 def execute():
-	from erpnext.utilities.repost_stock import update_bin_qty, get_indented_qty, get_ordered_qty
+	from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty, get_ordered_qty
 
 	count=0
 	for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse from
diff --git a/erpnext/patches/v5_0/repost_requested_qty.py b/erpnext/patches/v5_0/repost_requested_qty.py
index 8c1d6f7..6af71f3 100644
--- a/erpnext/patches/v5_0/repost_requested_qty.py
+++ b/erpnext/patches/v5_0/repost_requested_qty.py
@@ -5,7 +5,7 @@
 import frappe
 
 def execute():
-	from erpnext.utilities.repost_stock import update_bin_qty, get_indented_qty
+	from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
 
 	count=0
 	for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse 
diff --git a/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py b/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py
index 251dd56..6eb3994 100644
--- a/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py
+++ b/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe
-from erpnext.utilities.repost_stock import repost_actual_qty
+from erpnext.stock.stock_balance import repost_actual_qty
 
 def execute():
 	cancelled_invoices = frappe.db.sql_list("""select name from `tabSales Invoice` 
diff --git a/erpnext/patches/v5_7/item_template_attributes.py b/erpnext/patches/v5_7/item_template_attributes.py
index e93bfe4..c0e6851 100644
--- a/erpnext/patches/v5_7/item_template_attributes.py
+++ b/erpnext/patches/v5_7/item_template_attributes.py
@@ -55,9 +55,6 @@
 		template.set('attributes', attributes)
 		template.save()
 
-	frappe.delete_doc("DocType", "Manage Variants")
-	frappe.delete_doc("DocType", "Manage Variants Item")
-
 # patch old style
 def migrate_item_variants():
 	for item in frappe.get_all("Item", filters={"has_variants": 1}):
diff --git a/erpnext/patches/v5_8/__init__.py b/erpnext/patches/v5_8/__init__.py
new file mode 100644
index 0000000..baffc48
--- /dev/null
+++ b/erpnext/patches/v5_8/__init__.py
@@ -0,0 +1 @@
+from __future__ import unicode_literals
diff --git a/erpnext/patches/v5_8/add_credit_note_print_heading.py b/erpnext/patches/v5_8/add_credit_note_print_heading.py
new file mode 100644
index 0000000..476cbc8
--- /dev/null
+++ b/erpnext/patches/v5_8/add_credit_note_print_heading.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+def execute():
+	for print_heading in (_("Credit Note"), _("Debit Note")):
+		if not frappe.db.exists("Print Heading", print_heading):
+			frappe.get_doc({
+				"doctype": "Print Heading",
+				"print_heading": print_heading
+			}).insert()
diff --git a/erpnext/patches/v5_8/update_order_reference_in_return_entries.py b/erpnext/patches/v5_8/update_order_reference_in_return_entries.py
new file mode 100644
index 0000000..c6cfceb
--- /dev/null
+++ b/erpnext/patches/v5_8/update_order_reference_in_return_entries.py
@@ -0,0 +1,85 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	# sales return
+	return_entries = list(frappe.db.sql("""
+		select dn.name as name, dn_item.name as row_id, dn.return_against,
+			dn_item.item_code, "Delivery Note" as doctype
+		from `tabDelivery Note Item` dn_item, `tabDelivery Note` dn
+		where dn_item.parent=dn.name and dn.is_return=1 and dn.docstatus < 2
+	""", as_dict=1))
+
+	return_entries += list(frappe.db.sql("""
+		select si.name as name, si_item.name as row_id, si.return_against,
+			si_item.item_code, "Sales Invoice" as doctype, update_stock
+		from `tabSales Invoice Item` si_item, `tabSales Invoice` si
+		where si_item.parent=si.name and si.is_return=1 and si.docstatus < 2
+	""", as_dict=1))
+
+	for d in return_entries:
+		ref_field = "against_sales_order" if d.doctype == "Delivery Note" else "sales_order"
+		order_details = frappe.db.sql("""
+			select {ref_field} as sales_order, so_detail,
+				(select transaction_date from `tabSales Order` where name=item.{ref_field}) as sales_order_date
+			from `tab{doctype} Item` item
+			where
+				parent=%s
+				and item_code=%s
+				and ifnull(so_detail, '') !=''
+			order by sales_order_date DESC limit 1
+		""".format(ref_field=ref_field, doctype=d.doctype), (d.return_against, d.item_code), as_dict=1)
+
+		if order_details:
+			frappe.db.sql("""
+				update `tab{doctype} Item`
+				set {ref_field}=%s, so_detail=%s
+				where name=%s
+			""".format(doctype=d.doctype, ref_field=ref_field),
+			(order_details[0].sales_order, order_details[0].so_detail, d.row_id))
+
+			if (d.doctype=="Sales Invoice" and d.update_stock) or d.doctype=="Delivery Note":
+				doc = frappe.get_doc(d.doctype, d.name)
+				doc.update_reserved_qty()
+
+				if d.doctype=="Sales Invoice":
+					doc.status_updater = []
+					doc.update_status_updater_args()
+
+				doc.update_prevdoc_status()
+
+	#--------------------------
+	# purchase return
+	return_entries = frappe.db.sql("""
+		select pr.name as name, pr_item.name as row_id, pr.return_against, pr_item.item_code
+		from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr
+		where pr_item.parent=pr.name and pr.is_return=1 and pr.docstatus < 2
+	""", as_dict=1)
+
+	for d in return_entries:
+		order_details = frappe.db.sql("""
+			select prevdoc_docname as purchase_order, prevdoc_detail_docname as po_detail,
+				(select transaction_date from `tabPurchase Order` where name=item.prevdoc_detail_docname) as purchase_order_date
+			from `tabPurchase Receipt Item` item
+			where
+				parent=%s
+				and item_code=%s
+				and ifnull(prevdoc_detail_docname, '') !=''
+				and ifnull(prevdoc_doctype, '') = 'Purchase Order' and ifnull(prevdoc_detail_docname, '') != ''
+			order by purchase_order_date DESC limit 1
+		""", (d.return_against, d.item_code), as_dict=1)
+
+		if order_details:
+			frappe.db.sql("""
+				update `tabPurchase Receipt Item`
+				set prevdoc_doctype='Purchase Order', prevdoc_docname=%s, prevdoc_detail_docname=%s
+				where name=%s
+			""", (order_details[0].purchase_order, order_details[0].po_detail, d.row_id))
+
+			pr = frappe.get_doc("Purchase Receipt", d.name)
+			pr.update_ordered_qty()
+			pr.update_prevdoc_status()
+
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index ba10702..66794c9 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -88,6 +88,7 @@
 		this.set_dynamic_labels();
 		erpnext.pos.make_pos_btn(this.frm);
 		this.setup_sms();
+		this.make_show_payments_btn();
 	},
 
 	apply_default_taxes: function() {
@@ -123,6 +124,22 @@
 		var sms_man = new SMSManager(this.frm.doc);
 	},
 
+	make_show_payments_btn: function() {
+		var me = this;
+		if (in_list(["Purchase Invoice", "Sales Invoice"], this.frm.doctype)) {
+			if(this.frm.doc.outstanding_amount !== this.frm.doc.base_grand_total) {
+				this.frm.add_custom_button(__("Show Payments"), function() {
+					frappe.route_options = {
+						"Journal Entry Account.reference_type": me.frm.doc.doctype,
+						"Journal Entry Account.reference_name": me.frm.doc.name
+					};
+
+					frappe.set_route("List", "Journal Entry");
+				});
+			}
+		}
+	},
+
 	hide_currency_and_price_list: function() {
 		if(this.frm.doc.conversion_rate == 1 && this.frm.doc.docstatus > 0) {
 			hide_field("currency_and_price_list");
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index b05c009..dd21f05 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -8,6 +8,7 @@
 from frappe.utils import cstr, flt, getdate, comma_and
 from frappe import _
 from frappe.model.mapper import get_mapped_doc
+from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty
 
 from erpnext.controllers.selling_controller import SellingController
 
@@ -151,7 +152,7 @@
 		super(SalesOrder, self).on_submit()
 
 		self.check_credit_limit()
-		self.update_stock_ledger(update_stock = 1)
+		self.update_reserved_qty()
 
 		frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.base_grand_total, self)
 
@@ -164,7 +165,7 @@
 			frappe.throw(_("Stopped order cannot be cancelled. Unstop to cancel."))
 
 		self.check_nextdoc_docstatus()
-		self.update_stock_ledger(update_stock = -1)
+		self.update_reserved_qty()
 
 		self.update_prevdoc_status('cancel')
 
@@ -213,32 +214,38 @@
 
 	def stop_sales_order(self):
 		self.check_modified_date()
-		self.update_stock_ledger(-1)
 		frappe.db.set(self, 'status', 'Stopped')
+		self.update_reserved_qty()
 		frappe.msgprint(_("{0} {1} status is Stopped").format(self.doctype, self.name))
 		self.notify_modified()
 
 	def unstop_sales_order(self):
 		self.check_modified_date()
-		self.update_stock_ledger(1)
 		frappe.db.set(self, 'status', 'Submitted')
+		self.update_reserved_qty()
 		frappe.msgprint(_("{0} {1} status is Unstopped").format(self.doctype, self.name))
+				
+	def update_reserved_qty(self, so_item_rows=None):
+		"""update requested qty (before ordered_qty is updated)"""
+		item_wh_list = []
+		def _valid_for_reserve(item_code, warehouse):
+			if item_code and warehouse and [item_code, warehouse] not in item_wh_list \
+				and frappe.db.get_value("Item", item_code, "is_stock_item"):
+					item_wh_list.append([item_code, warehouse])
+		
+		for d in self.get("items"):
+			if (not so_item_rows or d.name in so_item_rows):
+				_valid_for_reserve(d.item_code, d.warehouse)
+						
+				if self.has_product_bundle(d.item_code):
+					for p in self.get("packed_items"):
+						if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
+							_valid_for_reserve(p.item_code, p.warehouse)
 
-
-	def update_stock_ledger(self, update_stock):
-		from erpnext.stock.utils import update_bin
-		for d in self.get_item_list():
-			if frappe.db.get_value("Item", d['item_code'], "is_stock_item")==1:
-				args = {
-					"item_code": d['item_code'],
-					"warehouse": d['reserved_warehouse'],
-					"reserved_qty": flt(update_stock) * flt(d['reserved_qty']),
-					"posting_date": self.transaction_date,
-					"voucher_type": self.doctype,
-					"voucher_no": self.name,
-					"is_amended": self.amended_from and 'Yes' or 'No'
-				}
-				update_bin(args)
+		for item_code, warehouse in item_wh_list:
+			update_bin_qty(item_code, warehouse, {
+				"reserved_qty": get_reserved_qty(item_code, warehouse)
+			})
 
 	def on_update(self):
 		pass
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index 0d0d50d..af80617 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -842,6 +842,27 @@
   }, 
   {
    "allow_on_submit": 0, 
+   "depends_on": "returned_qty", 
+   "fieldname": "returned_qty", 
+   "fieldtype": "Float", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Returned Qty", 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
    "fieldname": "billed_amt", 
    "fieldtype": "Currency", 
    "hidden": 0, 
@@ -960,7 +981,7 @@
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 1, 
- "modified": "2015-08-19 12:46:32.930498", 
+ "modified": "2015-08-25 06:42:11.062909", 
  "modified_by": "Administrator", 
  "module": "Selling", 
  "name": "Sales Order Item", 
diff --git a/erpnext/setup/page/setup_wizard/install_fixtures.py b/erpnext/setup/page/setup_wizard/install_fixtures.py
index dd3ec3a..6ecd9ff 100644
--- a/erpnext/setup/page/setup_wizard/install_fixtures.py
+++ b/erpnext/setup/page/setup_wizard/install_fixtures.py
@@ -41,15 +41,15 @@
 		{'doctype': 'Expense Claim Type', 'name': _('Travel'), 'expense_type': _('Travel')},
 
 		# leave type
-		{'doctype': 'Leave Type', 'leave_type_name': _('Casual Leave'), 'name': _('Casual Leave'), 
+		{'doctype': 'Leave Type', 'leave_type_name': _('Casual Leave'), 'name': _('Casual Leave'),
 			'is_encash': 1, 'is_carry_forward': 1, 'max_days_allowed': '3', 'include_holiday': 1},
-		{'doctype': 'Leave Type', 'leave_type_name': _('Compensatory Off'), 'name': _('Compensatory Off'), 
+		{'doctype': 'Leave Type', 'leave_type_name': _('Compensatory Off'), 'name': _('Compensatory Off'),
 			'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1},
-		{'doctype': 'Leave Type', 'leave_type_name': _('Sick Leave'), 'name': _('Sick Leave'), 
+		{'doctype': 'Leave Type', 'leave_type_name': _('Sick Leave'), 'name': _('Sick Leave'),
 			'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1},
-		{'doctype': 'Leave Type', 'leave_type_name': _('Privilege Leave'), 'name': _('Privilege Leave'), 
+		{'doctype': 'Leave Type', 'leave_type_name': _('Privilege Leave'), 'name': _('Privilege Leave'),
 			'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1},
-		{'doctype': 'Leave Type', 'leave_type_name': _('Leave Without Pay'), 'name': _('Leave Without Pay'), 
+		{'doctype': 'Leave Type', 'leave_type_name': _('Leave Without Pay'), 'name': _('Leave Without Pay'),
 			'is_encash': 0, 'is_carry_forward': 0, 'is_lwp':1, 'include_holiday': 1},
 
 		# Employment Type
@@ -173,6 +173,8 @@
 		{"doctype": "Offer Term", "offer_term": _("Notice Period")},
 		{"doctype": "Offer Term", "offer_term": _("Incentives")},
 
+		{'doctype': "Print Heading", 'print_heading': _("Credit Note")},
+		{'doctype': "Print Heading", 'print_heading': _("Debit Note")}
 	]
 
 	from erpnext.setup.page.setup_wizard.fixtures import industry_type
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 5e11962..1ac1cf4 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -47,6 +47,19 @@
 			'source_field': 'qty',
 			'percent_join_field': 'against_sales_invoice',
 			'overflow_type': 'delivery'
+		},
+		{
+			'source_dt': 'Delivery Note Item',
+			'target_dt': 'Sales Order Item',
+			'join_field': 'so_detail',
+			'target_field': 'returned_qty',
+			'target_parent_dt': 'Sales Order',
+			# 'target_parent_field': 'per_delivered',
+			# 'target_ref_field': 'qty',
+			'source_field': '-1 * qty',
+			# 'percent_join_field': 'against_sales_order',
+			# 'overflow_type': 'delivery',
+			'extra_cond': """ and exists (select name from `tabDelivery Note` where name=`tabDelivery Note Item`.parent and is_return=1)"""
 		}]
 
 	def onload(self):
@@ -83,7 +96,7 @@
 
 	def so_required(self):
 		"""check in manage account if sales order required or not"""
-		if not self.is_return and frappe.db.get_value("Selling Settings", None, 'so_required') == 'Yes':
+		if frappe.db.get_value("Selling Settings", None, 'so_required') == 'Yes':
 			 for d in self.get('items'):
 				 if not d.against_sales_order:
 					 frappe.throw(_("Sales Order required for Item {0}").format(d.item_code))
@@ -118,7 +131,7 @@
 					},
 				})
 
-		if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
+		if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')) and not self.is_return:
 			self.validate_rate_with_reference_doc([["Sales Order", "sales_order", "so_detail"],
 				["Sales Invoice", "sales_invoice", "si_detail"]])
 
@@ -174,10 +187,10 @@
 		# Check for Approving Authority
 		frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.company, self.base_grand_total, self)
 
-		if not self.is_return:
-			# update delivered qty in sales order
-			self.update_prevdoc_status()
+		# update delivered qty in sales order
+		self.update_prevdoc_status()
 
+		if not self.is_return:
 			self.check_credit_limit()
 
 		self.update_stock_ledger()
@@ -190,8 +203,7 @@
 		self.check_stop_sales_order("against_sales_order")
 		self.check_next_docstatus()
 
-		if not self.is_return:
-			self.update_prevdoc_status()
+		self.update_prevdoc_status()
 
 		self.update_stock_ledger()
 
@@ -242,25 +254,6 @@
 				ps.cancel()
 			frappe.msgprint(_("Packing Slip(s) cancelled"))
 
-
-	def update_stock_ledger(self):
-		sl_entries = []
-		for d in self.get_item_list():
-			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 \
-					and d.warehouse and flt(d['qty']):
-				self.update_reserved_qty(d)
-				
-				incoming_rate = 0
-				if cint(self.is_return) and self.return_against and self.docstatus==1:
-					incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
-					
-				sl_entries.append(self.get_sl_entries(d, {
-					"actual_qty": -1*flt(d['qty']),
-					"incoming_rate": incoming_rate
-				}))
-
-		self.make_sl_entries(sl_entries)
-
 def get_list_context(context=None):
 	from erpnext.controllers.website_list_for_contact import get_list_context
 	list_context = get_list_context(context)
@@ -374,8 +367,8 @@
 
 	return doclist
 
-	
+
 @frappe.whitelist()
 def make_sales_return(source_name, target_doc=None):
 	from erpnext.controllers.sales_and_purchase_return import make_return_doc
-	return make_return_doc("Delivery Note", source_name, target_doc)
\ No newline at end of file
+	return make_return_doc("Delivery Note", source_name, target_doc)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
index dce6863..d79015e 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
@@ -3,7 +3,7 @@
 		"transporter_name", "grand_total", "is_return"],
 	get_indicator: function(doc) {
 		if(cint(doc.is_return)==1) {
-			return [__("Return"), "darkgrey", "is_return,=,1"];
+			return [__("Return"), "darkgrey", "is_return,=,Yes"];
 		}
 	}
 };
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index 18138c0..e764b6a 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -912,7 +912,7 @@
    "in_filter": 0, 
    "in_list_view": 1, 
    "label": "Against Sales Order", 
-   "no_copy": 0, 
+   "no_copy": 1, 
    "options": "Sales Order", 
    "permlevel": 0, 
    "print_hide": 1, 
@@ -932,7 +932,7 @@
    "in_filter": 0, 
    "in_list_view": 0, 
    "label": "Against Sales Invoice", 
-   "no_copy": 0, 
+   "no_copy": 1, 
    "options": "Sales Invoice", 
    "permlevel": 0, 
    "print_hide": 1, 
@@ -1039,7 +1039,7 @@
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 1, 
- "modified": "2015-08-19 12:46:31.447022", 
+ "modified": "2015-08-25 07:15:19.811365", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Delivery Note Item", 
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 659fb1b..08350af 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -269,7 +269,7 @@
 		frappe.db.set_value("Item", newdn, "last_purchase_rate", last_purchase_rate)
 
 	def recalculate_bin_qty(self, newdn):
-		from erpnext.utilities.repost_stock import repost_stock
+		from erpnext.stock.stock_balance import repost_stock
 		frappe.db.auto_commit_on_many_writes = 1
 		existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index fd6f943..e418366 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -10,9 +10,11 @@
 from frappe.utils import cstr, flt, getdate
 from frappe import _
 from frappe.model.mapper import get_mapped_doc
+from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
 
 from erpnext.controllers.buying_controller import BuyingController
 
+
 form_grid_templates = {
 	"items": "templates/form_grid/material_request_grid.html"
 }
@@ -136,19 +138,6 @@
 
 	def update_requested_qty(self, mr_item_rows=None):
 		"""update requested qty (before ordered_qty is updated)"""
-		from erpnext.stock.utils import get_bin
-
-		def _update_requested_qty(item_code, warehouse):
-			requested_qty = frappe.db.sql("""select sum(mr_item.qty - ifnull(mr_item.ordered_qty, 0))
-				from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
-				where mr_item.item_code=%s and mr_item.warehouse=%s
-				and mr_item.qty > ifnull(mr_item.ordered_qty, 0) and mr_item.parent=mr.name
-				and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
-
-			bin_doc = get_bin(item_code, warehouse)
-			bin_doc.indented_qty = flt(requested_qty[0][0]) if requested_qty else 0
-			bin_doc.save()
-
 		item_wh_list = []
 		for d in self.get("items"):
 			if (not mr_item_rows or d.name in mr_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \
@@ -156,7 +145,9 @@
 				item_wh_list.append([d.item_code, d.warehouse])
 
 		for item_code, warehouse in item_wh_list:
-			_update_requested_qty(item_code, warehouse)
+			update_bin_qty(item_code, warehouse, {
+				"indented_qty": get_indented_qty(item_code, warehouse)
+			})
 
 def update_completed_and_requested_qty(stock_entry, method):
 	if stock_entry.doctype == "Stock Entry":
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 2979c12..58f165c 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -29,6 +29,19 @@
 			'source_field': 'qty',
 			'percent_join_field': 'prevdoc_docname',
 			'overflow_type': 'receipt'
+		},
+		{
+			'source_dt': 'Purchase Receipt Item',
+			'target_dt': 'Purchase Order Item',
+			'join_field': 'prevdoc_detail_docname',
+			'target_field': 'returned_qty',
+			'target_parent_dt': 'Purchase Order',
+			# 'target_parent_field': 'per_received',
+			# 'target_ref_field': 'qty',
+			'source_field': '-1 * qty',
+			# 'percent_join_field': 'prevdoc_docname',
+			# 'overflow_type': 'receipt',
+			'extra_cond': """ and exists (select name from `tabPurchase Receipt` where name=`tabPurchase Receipt Item`.parent and is_return=1)"""
 		}]
 
 	def onload(self):
@@ -68,12 +81,12 @@
 				from `tabLanded Cost Item`
 				where docstatus = 1 and purchase_receipt_item = %s""", d.name)
 			d.landed_cost_voucher_amount = lc_voucher_amount[0][0] if lc_voucher_amount else 0.0
-			
+
 	def validate_purchase_return(self):
 		for d in self.get("items"):
 			if self.is_return and flt(d.rejected_qty) != 0:
 				frappe.throw(_("Row #{0}: Rejected Qty can not be entered in Purchase Return").format(d.idx))
-				
+
 			# validate rate with ref PR
 
 	def validate_rejected_warehouse(self):
@@ -113,11 +126,11 @@
 			}
 		})
 
-		if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
+		if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')) and not self.is_return:
 			self.validate_rate_with_reference_doc([["Purchase Order", "prevdoc_docname", "prevdoc_detail_docname"]])
 
 	def po_required(self):
-		if not self.is_return and frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
+		if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
 			 for d in self.get('items'):
 				 if not d.prevdoc_docname:
 					 frappe.throw(_("Purchase Order number required for Item {0}").format(d.item_code))
@@ -221,9 +234,10 @@
 		# Set status as Submitted
 		frappe.db.set(self, 'status', 'Submitted')
 
+		self.update_prevdoc_status()
+		self.update_ordered_qty()
+
 		if not self.is_return:
-			self.update_prevdoc_status()
-			self.update_ordered_qty()
 			purchase_controller.update_last_purchase_rate(self, 1)
 
 		self.update_stock_ledger()
@@ -257,12 +271,11 @@
 
 		self.update_stock_ledger()
 
+		self.update_prevdoc_status()
+		# Must be called after updating received qty in PO
+		self.update_ordered_qty()
+
 		if not self.is_return:
-			self.update_prevdoc_status()
-
-			# Must be called after updating received qty in PO
-			self.update_ordered_qty()
-
 			pc_obj.update_last_purchase_rate(self, 0)
 
 		self.make_gl_entries_on_cancel()
@@ -291,7 +304,7 @@
 				if warehouse_account.get(d.warehouse):
 
 					val_rate_db_precision = 6 if cint(d.precision("valuation_rate")) <= 6 else 9
-					
+
 					# warehouse account
 					gl_entries.append(self.get_gl_dict({
 						"account": warehouse_account[d.warehouse],
@@ -466,4 +479,4 @@
 @frappe.whitelist()
 def make_purchase_return(source_name, target_doc=None):
 	from erpnext.controllers.sales_and_purchase_return import make_return_doc
-	return make_return_doc("Purchase Receipt", source_name, target_doc)
\ No newline at end of file
+	return make_return_doc("Purchase Receipt", source_name, target_doc)
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
index 64d5456..838fbb0 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
@@ -3,7 +3,7 @@
 		"transporter_name", "is_return"],
 	get_indicator: function(doc) {
 		if(cint(doc.is_return)==1) {
-			return [__("Return"), "darkgrey", "is_return,=,1"];
+			return [__("Return"), "darkgrey", "is_return,=,Yes"];
 		}
 	}
 };
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index fb15195..0df0ba2 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -33,7 +33,7 @@
 		self.validate_warehouse()
 		self.validate_item()
 		self.on_stock_ledger_entry()
-		
+
 	def set_maintenance_status(self):
 		if not self.warranty_expiry_date and not self.amc_expiry_date:
 			self.maintenance_status = None
@@ -209,7 +209,7 @@
 				frappe.throw(_("Serial No {0} quantity {1} cannot be a fraction").format(sle.item_code, sle.actual_qty))
 
 			if len(serial_nos) and len(serial_nos) != abs(cint(sle.actual_qty)):
-				frappe.throw(_("{0} Serial Numbers required for Item {0}. Only {0} provided.").format(sle.actual_qty, sle.item_code, len(serial_nos)),
+				frappe.throw(_("{0} Serial Numbers required for Item {1}. You have provided {2}.").format(sle.actual_qty, sle.item_code, len(serial_nos)),
 					SerialNoQtyError)
 
 			if len(serial_nos) != len(set(serial_nos)):
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index 5a39763..610c7b8 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -140,7 +140,7 @@
 			self.recalculate_bin_qty(newdn)
 
 	def recalculate_bin_qty(self, newdn):
-		from erpnext.utilities.repost_stock import repost_stock
+		from erpnext.stock.stock_balance import repost_stock
 		frappe.db.auto_commit_on_many_writes = 1
 		existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index d08c63c..0cec77b 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -257,6 +257,10 @@
 def validate_conversion_rate(args, meta):
 	from erpnext.controllers.accounts_controller import validate_conversion_rate
 
+	if (not args.conversion_rate
+		and args.currency==frappe.db.get_value("Company", args.company, "default_currency")):
+		args.conversion_rate = 1.0
+
 	# validate currency conversion rate
 	validate_conversion_rate(args.currency, args.conversion_rate,
 		meta.get_label("conversion_rate"), args.company)
diff --git a/erpnext/utilities/repost_stock.py b/erpnext/stock/stock_balance.py
similarity index 100%
rename from erpnext/utilities/repost_stock.py
rename to erpnext/stock/stock_balance.py