Merge pull request #3683 from nabinhait/return

Sales / Purchase Return Enhancement
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 3d306fb..edee122 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 
-from frappe.utils import flt, fmt_money, getdate, formatdate, cstr
+from frappe.utils import flt, fmt_money, getdate, formatdate, cstr, cint
 from frappe import _
 
 from frappe.model.document import Document
@@ -139,9 +139,9 @@
 		if against_voucher_amount < 0:
 			bal = -bal
 
-	# Validation : Outstanding can not be negative
-	if bal < 0 and not on_cancel:
-		frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
+		# Validation : Outstanding can not be negative for JV
+		if bal < 0 and not on_cancel:
+			frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
 
 	# Update outstanding amt on against voucher
 	if against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 07dbf72..6a02706 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -21,10 +21,11 @@
 
 		// Show / Hide button
 		if(doc.docstatus==1 && doc.outstanding_amount > 0)
-			this.frm.add_custom_button(__('Make Payment Entry'), this.make_bank_entry,
-				frappe.boot.doctype_icons["Journal Entry"]);
+			this.frm.add_custom_button(__('Make Payment Entry'), this.make_bank_entry);
 
 		if(doc.docstatus==1) {
+			cur_frm.add_custom_button(__('Make Purchase Return'), this.make_purchase_return);
+			
 			cur_frm.add_custom_button(__('View Ledger'), function() {
 				frappe.route_options = {
 					"voucher_no": doc.name,
@@ -34,7 +35,7 @@
 					group_by_voucher: 0
 				};
 				frappe.set_route("query-report", "General Ledger");
-			}, "icon-table");
+			});
 		}
 
 		if(doc.docstatus===0) {
@@ -51,7 +52,7 @@
 							company: cur_frm.doc.company
 						}
 					})
-				}, "icon-download", "btn-default");
+				});
 
 			cur_frm.add_custom_button(__('From Purchase Receipt'),
 				function() {
@@ -64,7 +65,7 @@
 							company: cur_frm.doc.company
 						}
 					})
-				}, "icon-download", "btn-default");
+				});
 
 		}
 	},
@@ -109,7 +110,14 @@
 		$.each(this.frm.doc["items"] || [], function(i, row) {
 			if(row.purchase_receipt) frappe.model.clear_doc("Purchase Receipt", row.purchase_receipt)
 		})
-	}
+	},
+	
+	make_purchase_return: function() {
+		frappe.model.open_mapped_doc({
+			method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_purchase_return",
+			frm: cur_frm
+		})
+	},
 });
 
 cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 69b0708..f8101dc 100755
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -12,7 +12,7 @@
    "no_copy": 1, 
    "oldfieldname": "naming_series", 
    "oldfieldtype": "Select", 
-   "options": "PINV-", 
+   "options": "PINV-\nPINV-RET-", 
    "permlevel": 0, 
    "print_hide": 1, 
    "read_only": 0, 
@@ -155,6 +155,28 @@
    "search_index": 0
   }, 
   {
+   "fieldname": "is_return", 
+   "fieldtype": "Check", 
+   "label": "Is Return", 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
+   "depends_on": "is_return", 
+   "fieldname": "return_against", 
+   "fieldtype": "Link", 
+   "label": "Return Against Purchase Invoice", 
+   "no_copy": 0, 
+   "options": "Purchase Invoice", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
    "fieldname": "currency_and_price_list", 
    "fieldtype": "Section Break", 
    "label": "", 
@@ -940,7 +962,7 @@
  "icon": "icon-file-text", 
  "idx": 1, 
  "is_submittable": 1, 
- "modified": "2015-07-03 03:26:32.934540", 
+ "modified": "2015-07-24 11:49:59.762109", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Purchase Invoice", 
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 1ac0f5a..006470f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -37,14 +37,16 @@
 
 		super(PurchaseInvoice, self).validate()
 
-		self.po_required()
-		self.pr_required()
-		self.validate_supplier_invoice()
+		if not self.is_return:
+			self.po_required()
+			self.pr_required()
+			self.validate_supplier_invoice()
+			self.validate_advance_jv("advances", "purchase_order")
+			
 		self.check_active_purchase_items()
 		self.check_conversion_rate()
 		self.validate_credit_to_acc()
 		self.clear_unallocated_advances("Purchase Invoice Advance", "advances")
-		self.validate_advance_jv("advances", "purchase_order")
 		self.check_for_stopped_status()
 		self.validate_with_previous_doc()
 		self.validate_uom_is_integer("uom", "qty")
@@ -71,8 +73,9 @@
 		super(PurchaseInvoice, self).set_missing_values(for_validate)
 
 	def get_advances(self):
-		super(PurchaseInvoice, self).get_advances(self.credit_to, "Supplier", self.supplier,
-			"Purchase Invoice Advance", "advances", "debit", "purchase_order")
+		if not self.is_return:
+			super(PurchaseInvoice, self).get_advances(self.credit_to, "Supplier", self.supplier,
+				"Purchase Invoice Advance", "advances", "debit", "purchase_order")
 
 	def check_active_purchase_items(self):
 		for d in self.get('items'):
@@ -226,9 +229,11 @@
 
 		# this sequence because outstanding may get -negative
 		self.make_gl_entries()
-		self.update_against_document_in_jv()
-		self.update_prevdoc_status()
-		self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
+		if not self.is_return:
+			self.update_against_document_in_jv()
+			self.update_prevdoc_status()
+			self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
+			
 		self.update_project()
 
 	def make_gl_entries(self):
@@ -358,11 +363,12 @@
 			make_gl_entries(gl_entries, cancel=(self.docstatus == 2))
 
 	def on_cancel(self):
-		from erpnext.accounts.utils import remove_against_link_from_jv
-		remove_against_link_from_jv(self.doctype, self.name, "against_voucher")
+		if not self.is_return:
+			from erpnext.accounts.utils import remove_against_link_from_jv
+			remove_against_link_from_jv(self.doctype, self.name, "against_voucher")
 
-		self.update_prevdoc_status()
-		self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
+			self.update_prevdoc_status()
+			self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
 		self.make_gl_entries_on_cancel()
 		self.update_project()
 
@@ -403,3 +409,8 @@
 				and tabAccount.%(key)s LIKE '%(txt)s'
 				%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
 			'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
+
+@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 Invoice", source_name, target_doc)	
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 7f46b08..5f3d4c8 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -275,5 +275,58 @@
 		purchase_invoice.cancel()		
 		self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 0)
 		
+	def test_return_purchase_invoice(self):
+		set_perpetual_inventory()
+		
+		pi = make_purchase_invoice()
+		
+		return_pi = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2)
+		
+		
+		# check gl entries for return
+		gl_entries = frappe.db.sql("""select account, debit, credit
+			from `tabGL Entry` where voucher_type=%s and voucher_no=%s
+			order by account desc""", ("Purchase Invoice", return_pi.name), as_dict=1)
+
+		self.assertTrue(gl_entries)
+
+		expected_values = {
+			"Creditors - _TC": [100.0, 0.0],
+			"Stock Received But Not Billed - _TC": [0.0, 100.0],
+		}
+
+		for gle in gl_entries:
+			self.assertEquals(expected_values[gle.account][0], gle.debit)
+			self.assertEquals(expected_values[gle.account][1], gle.credit)
+		
+		set_perpetual_inventory(0)
+		
+def make_purchase_invoice(**args):
+	pi = frappe.new_doc("Purchase Invoice")
+	args = frappe._dict(args)
+	if args.posting_date:
+		pi.posting_date = args.posting_date
+	if args.posting_time:
+		pi.posting_time = args.posting_time
+	pi.company = args.company or "_Test Company"
+	pi.supplier = args.supplier or "_Test Supplier"
+	pi.currency = args.currency or "INR"
+	pi.is_return = args.is_return
+	pi.return_against = args.return_against
+	
+	pi.append("items", {
+		"item_code": args.item or args.item_code or "_Test Item",
+		"warehouse": args.warehouse or "_Test Warehouse - _TC",
+		"qty": args.qty or 5,
+		"rate": args.rate or 50,
+		"conversion_factor": 1.0,
+		"serial_no": args.serial_no,
+		"stock_uom": "_Test UOM"
+	})
+	if not args.do_not_save:
+		pi.insert()
+		if not args.do_not_submit:
+			pi.submit()
+	return pi
 
 test_records = frappe.get_test_records('Purchase Invoice')
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 5b2f348..fdc1a58 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -40,7 +40,9 @@
 		this._super();
 
 		cur_frm.dashboard.reset();
-
+		
+		this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
+		
 		if(doc.docstatus==1) {
 			cur_frm.add_custom_button('View Ledger', function() {
 				frappe.route_options = {
@@ -51,10 +53,7 @@
 					group_by_voucher: 0
 				};
 				frappe.set_route("query-report", "General Ledger");
-			}, "icon-table");
-
-			// var percent_paid = cint(flt(doc.base_grand_total - doc.outstanding_amount) / flt(doc.base_grand_total) * 100);
-			// cur_frm.dashboard.add_progress(percent_paid + "% Paid", percent_paid);
+			});
 
 			if(cint(doc.update_stock)!=1) {
 				// show Make Delivery Note button only if Sales Invoice is not created from Delivery Note
@@ -65,13 +64,15 @@
 					});
 
 				if(!from_delivery_note) {
-					cur_frm.add_custom_button(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'], "icon-truck")
+					cur_frm.add_custom_button(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'])
 				}
 			}
 
-			if(doc.outstanding_amount!=0) {
-				cur_frm.add_custom_button(__('Make Payment Entry'), cur_frm.cscript.make_bank_entry, "icon-money");
+			if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
+				cur_frm.add_custom_button(__('Make Payment Entry'), cur_frm.cscript.make_bank_entry);
 			}
+			
+			cur_frm.add_custom_button(__('Make Sales Return'), this.make_sales_return);
 		}
 
 		// Show buttons only when pos view is active
@@ -205,8 +206,14 @@
 
 	items_on_form_rendered: function() {
 		erpnext.setup_serial_no();
+	},
+	
+	make_sales_return: function() {
+		frappe.model.open_mapped_doc({
+			method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_sales_return",
+			frm: cur_frm
+		})
 	}
-
 });
 
 // for backward compatibility: combine new and previous states
@@ -283,16 +290,6 @@
 	});
 }
 
-cur_frm.fields_dict.debit_to.get_query = function(doc) {
-	return{
-		filters: {
-			'report_type': 'Balance Sheet',
-			'is_group': 0,
-			'company': doc.company
-		}
-	}
-}
-
 cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
 	return {
 		filters: [
@@ -399,4 +396,4 @@
 			['Account', 'account_type', '=', 'Receivable']
 		]
 	}
-});
+});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 25dd398..cd70a46 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -21,7 +21,7 @@
    "no_copy": 1, 
    "oldfieldname": "naming_series", 
    "oldfieldtype": "Select", 
-   "options": "SINV-", 
+   "options": "SINV-\nSINV-RET-", 
    "permlevel": 0, 
    "print_hide": 1, 
    "read_only": 0, 
@@ -156,7 +156,7 @@
    "oldfieldtype": "Date", 
    "permlevel": 0, 
    "read_only": 0, 
-   "reqd": 1, 
+   "reqd": 0, 
    "search_index": 0
   }, 
   {
@@ -170,6 +170,28 @@
    "read_only": 0
   }, 
   {
+   "fieldname": "is_return", 
+   "fieldtype": "Check", 
+   "label": "Is Return", 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
+   "depends_on": "is_return", 
+   "fieldname": "return_against", 
+   "fieldtype": "Link", 
+   "label": "Return Against Sales Invoice", 
+   "no_copy": 0, 
+   "options": "Sales Invoice", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
    "fieldname": "shipping_address_name", 
    "fieldtype": "Link", 
    "hidden": 1, 
@@ -1252,8 +1274,8 @@
  ], 
  "icon": "icon-file-text", 
  "idx": 1, 
- "is_submittable": 1,
- "modified": "2015-07-09 17:33:28.583808", 
+ "is_submittable": 1, 
+ "modified": "2015-07-24 11:48:07.544569", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Sales Invoice", 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 829478d..5a9ccea 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -80,14 +80,16 @@
 
 		self.check_prev_docstatus()
 
-		self.update_status_updater_args()
-		self.update_prevdoc_status()
-		self.update_billing_status_for_zero_amount_refdoc("Sales Order")
-		self.check_credit_limit()
+		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()
+			
 		# this sequence because outstanding may get -ve
 		self.make_gl_entries()
 
-		if not cint(self.is_pos) == 1:
+		if not cint(self.is_pos) == 1 and not self.is_return:
 			self.update_against_document_in_jv()
 
 		self.update_time_log_batch(self.name)
@@ -100,13 +102,15 @@
 			self.update_stock_ledger()
 
 		self.check_stop_sales_order("sales_order")
-
+		
 		from erpnext.accounts.utils import remove_against_link_from_jv
 		remove_against_link_from_jv(self.doctype, self.name, "against_invoice")
-
-		self.update_status_updater_args()
-		self.update_prevdoc_status()
-		self.update_billing_status_for_zero_amount_refdoc("Sales Order")
+		
+		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()
 
 		self.make_gl_entries_on_cancel()
@@ -199,8 +203,9 @@
 				self.set_taxes()
 
 	def get_advances(self):
-		super(SalesInvoice, self).get_advances(self.debit_to, "Customer", self.customer,
-			"Sales Invoice Advance", "advances", "credit", "sales_order")
+		if not self.is_return:
+			super(SalesInvoice, self).get_advances(self.debit_to, "Customer", self.customer,
+				"Sales Invoice Advance", "advances", "credit", "sales_order")
 
 	def get_company_abbr(self):
 		return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
@@ -285,6 +290,8 @@
 
 	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':
@@ -419,13 +426,16 @@
 	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") == "Yes" \
-					and d.warehouse:
+			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" and d.warehouse:
+				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")
+					"stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom"),
+					"incoming_rate": incoming_rate
 				}))
-
 		self.make_sl_entries(sl_entries)
 
 	def make_gl_entries(self, repost_future_gle=True):
@@ -435,8 +445,7 @@
 			from erpnext.accounts.general_ledger import make_gl_entries
 
 			# if POS and amount is written off, there's no outstanding and hence no need to update it
-			update_outstanding = cint(self.is_pos) and self.write_off_account \
-				and 'No' or 'Yes'
+			update_outstanding = "No" if (cint(self.is_pos) or self.write_off_account) else "Yes"
 
 			make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
 				update_outstanding=update_outstanding, merge_entries=False)
@@ -484,7 +493,7 @@
 					"against": self.against_income_account,
 					"debit": self.base_grand_total,
 					"remarks": self.remarks,
-					"against_voucher": self.name,
+					"against_voucher": self.return_against if cint(self.is_return) else self.name,
 					"against_voucher_type": self.doctype
 				})
 			)
@@ -519,7 +528,6 @@
 		# expense account gl entries
 		if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
 				and cint(self.update_stock):
-
 			gl_entries += super(SalesInvoice, self).get_gl_entries()
 
 	def make_pos_gl_entries(self, gl_entries):
@@ -533,7 +541,7 @@
 					"against": self.cash_bank_account,
 					"credit": self.paid_amount,
 					"remarks": self.remarks,
-					"against_voucher": self.name,
+					"against_voucher": self.return_against if cint(self.is_return) else self.name,
 					"against_voucher_type": self.doctype,
 				})
 			)
@@ -557,7 +565,7 @@
 					"against": self.write_off_account,
 					"credit": self.write_off_amount,
 					"remarks": self.remarks,
-					"against_voucher": self.name,
+					"against_voucher": self.return_against if cint(self.is_return) else self.name,
 					"against_voucher_type": self.doctype,
 				})
 			)
@@ -651,3 +659,9 @@
 	}, target_doc, set_missing_values)
 
 	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("Sales Invoice", source_name, target_doc)
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index cf752af..6d54f0a 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -4,11 +4,10 @@
 
 import frappe
 import unittest, copy
-import time
-from frappe.utils import nowdate, add_days
-from erpnext.accounts.utils import get_stock_and_account_difference
+from frappe.utils import nowdate, add_days, flt
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
 from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
+from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
 
 
 class TestSalesInvoice(unittest.TestCase):
@@ -772,6 +771,53 @@
 		si1 = create_sales_invoice(posting_date="2015-07-05")		
 		self.assertEqual(si1.due_date, "2015-08-31")
 		
+	def test_return_sales_invoice(self):
+		set_perpetual_inventory()
+		
+		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100)
+		
+		actual_qty_0 = get_qty_after_transaction()
+		
+		si = create_sales_invoice(qty=5, rate=500, update_stock=1)
+
+		actual_qty_1 = get_qty_after_transaction()
+		self.assertEquals(actual_qty_0 - 5, actual_qty_1)
+		
+		# outgoing_rate
+		outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Sales Invoice", 
+			"voucher_no": si.name}, "stock_value_difference") / 5
+		
+		# return entry
+		si1 = create_sales_invoice(is_return=1, return_against=si.name, qty=-2, rate=500, update_stock=1)
+
+		actual_qty_2 = get_qty_after_transaction()
+			
+		self.assertEquals(actual_qty_1 + 2, actual_qty_2)
+		
+		incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry", 
+			{"voucher_type": "Sales Invoice", "voucher_no": si1.name}, 
+			["incoming_rate", "stock_value_difference"])
+			
+		self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
+		
+		
+		# Check gl entry
+		gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice", 
+			"voucher_no": si1.name, "account": "_Test Warehouse - _TC"}, "debit")
+			
+		self.assertEquals(gle_warehouse_amount, stock_value_difference)
+		
+		party_credited = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice", 
+			"voucher_no": si1.name, "account": "Debtors - _TC", "party": "_Test Customer"}, "credit")
+			
+		self.assertEqual(party_credited, 1000)
+		
+		# Check outstanding amount
+		self.assertFalse(si1.outstanding_amount)
+		self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 1500)
+		
+		set_perpetual_inventory(0)
+		
 
 def create_sales_invoice(**args):
 	si = frappe.new_doc("Sales Invoice")
@@ -784,6 +830,10 @@
 	si.debit_to = args.debit_to or "Debtors - _TC"
 	si.update_stock = args.update_stock
 	si.is_pos = args.is_pos
+	si.is_return = args.is_return
+	si.return_against = args.return_against
+	si.currency="INR"
+	si.conversion_rate = 1
 
 	si.append("items", {
 		"item_code": args.item or args.item_code or "_Test Item",
diff --git a/erpnext/accounts/print_format/credit_note/credit_note.json b/erpnext/accounts/print_format/credit_note/credit_note.json
index de405e6..863d4aa 100644
--- a/erpnext/accounts/print_format/credit_note/credit_note.json
+++ b/erpnext/accounts/print_format/credit_note/credit_note.json
@@ -1,19 +1,19 @@
 {
- "creation": "2014-08-28 11:11:39.796473",
- "disabled": 0,
- "doc_type": "Journal Entry",
- "docstatus": 0,
- "doctype": "Print Format",
- "html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n    {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n        and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n    {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n    {%- for label, value in (\n        (_(\"Credit To\"), doc.pay_to_recd_from),\n        (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n        (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n        (_(\"Remarks\"), doc.remark)\n    ) -%}\n\n    <div class=\"row\">\n        <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n        <div class=\"col-xs-9\">{{ value }}</div>\n    </div>\n\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>\n</div>\n\n\n",
- "idx": 2,
- "modified": "2015-01-12 11:02:25.716825",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Credit Note",
- "owner": "Administrator",
- "parent": "Journal Entry",
- "parentfield": "__print_formats",
- "parenttype": "DocType",
- "print_format_type": "Server",
+ "creation": "2014-08-28 11:11:39.796473", 
+ "custom_format": 0, 
+ "disabled": 0, 
+ "doc_type": "Journal Entry", 
+ "docstatus": 0, 
+ "doctype": "Print Format", 
+ "html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n    {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n        and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n    {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n    {%- for label, value in (\n        (_(\"Credit To\"), doc.pay_to_recd_from),\n        (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n        (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n        (_(\"Remarks\"), doc.remark)\n    ) -%}\n\n    <div class=\"row\">\n        <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n        <div class=\"col-xs-9\">{{ value }}</div>\n    </div>\n\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>\n</div>\n\n\n", 
+ "idx": 2, 
+ "modified": "2015-07-22 17:42:01.560817", 
+ "modified_by": "Administrator", 
+ "name": "Credit Note", 
+ "owner": "Administrator", 
+ "parent": "Journal Entry", 
+ "parentfield": "__print_formats", 
+ "parenttype": "DocType", 
+ "print_format_type": "Server", 
  "standard": "Yes"
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/credit_note___negative_invoice/__init__.py b/erpnext/accounts/print_format/credit_note___negative_invoice/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/print_format/credit_note___negative_invoice/__init__.py
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
new file mode 100644
index 0000000..e7d7eab
--- /dev/null
+++ b/erpnext/accounts/print_format/credit_note___negative_invoice/credit_note___negative_invoice.json
@@ -0,0 +1,17 @@
+{
+ "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_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js
index 1b7d20a..19ad9ab 100644
--- a/erpnext/buying/doctype/purchase_common/purchase_common.js
+++ b/erpnext/buying/doctype/purchase_common/purchase_common.js
@@ -164,8 +164,10 @@
 			frappe.model.round_floats_in(this.frm.doc, ["base_grand_total", "total_advance", "write_off_amount"]);
 			this.frm.doc.total_amount_to_pay = flt(this.frm.doc.base_grand_total - this.frm.doc.write_off_amount,
 				precision("total_amount_to_pay"));
-			this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
-				precision("outstanding_amount"));
+			if (!this.frm.doc.is_return) {
+				this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
+					precision("outstanding_amount"));
+			}
 		}
 	}
 });
diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.py b/erpnext/buying/doctype/purchase_common/purchase_common.py
index 476aa92..1bf6f8f 100644
--- a/erpnext/buying/doctype/purchase_common/purchase_common.py
+++ b/erpnext/buying/doctype/purchase_common/purchase_common.py
@@ -41,8 +41,7 @@
 	def validate_for_items(self, obj):
 		items = []
 		for d in obj.get("items"):
-			# validation for valid qty
-			if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
+			if not d.qty:
 				frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
 
 			# udpate with latest quantities
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 20edbca..6049810 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -11,39 +11,32 @@
 		this._super();
 		// this.frm.dashboard.reset();
 
-		if(doc.docstatus == 1 && doc.status != 'Stopped'){
-			// cur_frm.dashboard.add_progress(cint(doc.per_received) + __("% Received"),
-			// 	doc.per_received);
-			// cur_frm.dashboard.add_progress(cint(doc.per_billed) + __("% Billed"),
-			// 	doc.per_billed);
-
+		if(doc.docstatus == 1 && doc.status != 'Stopped') {
 			if(flt(doc.per_received, 2) < 100) {
-				cur_frm.add_custom_button(__('Make Purchase Receipt'),
-					this.make_purchase_receipt);
+				cur_frm.add_custom_button(__('Make Purchase Receipt'), this.make_purchase_receipt);
+				
 				if(doc.is_subcontracted==="Yes") {
-					cur_frm.add_custom_button(__('Transfer Material to Supplier'),
-						function() { me.make_stock_entry() });
+					cur_frm.add_custom_button(__('Transfer Material to Supplier'), this.make_stock_entry);
 				}
 			}
 			if(flt(doc.per_billed, 2) < 100)
-				cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice,
-					frappe.boot.doctype_icons["Purchase Invoice"]);
+				cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice);
+			
 			if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100)
-				cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order'],
-					"icon-exclamation", "btn-default");
+				cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order']);
 
 		} else if(doc.docstatus===0) {
 			cur_frm.cscript.add_from_mappers();
 		}
 
 		if(doc.docstatus == 1 && doc.status == 'Stopped')
-			cur_frm.add_custom_button(__('Unstop Purchase Order'),
-				cur_frm.cscript['Unstop Purchase Order'], "icon-check");
+			cur_frm.add_custom_button(__('Unstop Purchase Order'), cur_frm.cscript['Unstop Purchase Order']);
 	},
 
 	make_stock_entry: function() {
 		var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; }),
-			me = this;
+		var me = this;
+		
 		if(items.length===1) {
 			me._make_stock_entry(items[0]);
 			return;
@@ -96,7 +89,7 @@
 						company: cur_frm.doc.company
 					}
 				})
-			}, "icon-download", "btn-default"
+			}
 		);
 
 		cur_frm.add_custom_button(__('From Supplier Quotation'),
@@ -110,7 +103,7 @@
 						company: cur_frm.doc.company
 					}
 				})
-			}, "icon-download", "btn-default"
+			}
 		);
 
 		cur_frm.add_custom_button(__('For Supplier'),
@@ -122,7 +115,7 @@
 						docstatus: ["!=", 2],
 					}
 				})
-			}, "icon-download", "btn-default"
+			}
 		);
 	},
 
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 98f2409..7610042 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -9,6 +9,7 @@
 from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year
 from erpnext.utilities.transaction_base import TransactionBase
 from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
+from erpnext.controllers.sales_and_purchase_return import validate_return
 
 class AccountsController(TransactionBase):
 	def validate(self):
@@ -17,10 +18,14 @@
 		self.validate_date_with_fiscal_year()
 		if self.meta.get_field("currency"):
 			self.calculate_taxes_and_totals()
-			self.validate_value("base_grand_total", ">=", 0)
+			if not self.meta.get_field("is_return") or not self.is_return:
+				self.validate_value("base_grand_total", ">=", 0)
+			
+			validate_return(self)
 			self.set_total_in_words()
 
-		self.validate_due_date()
+		if self.doctype in ("Sales Invoice", "Purchase Invoice") and not self.is_return:
+			self.validate_due_date()
 
 		if self.meta.get_field("is_recurring"):
 			validate_recurring_document(self)
@@ -74,6 +79,9 @@
 	def validate_due_date(self):
 		from erpnext.accounts.party import validate_due_date
 		if self.doctype == "Sales Invoice":
+			if not self.due_date:
+				frappe.throw(_("Due Date is mandatory"))
+			
 			validate_due_date(self.posting_date, self.due_date, "Customer", self.customer, self.company)
 		elif self.doctype == "Purchase Invoice":
 			validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company)
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 9867973..0b60473 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -26,8 +26,7 @@
 	def validate(self):
 		super(BuyingController, self).validate()
 		if getattr(self, "supplier", None) and not self.supplier_name:
-			self.supplier_name = frappe.db.get_value("Supplier",
-				self.supplier, "supplier_name")
+			self.supplier_name = frappe.db.get_value("Supplier", self.supplier, "supplier_name")
 		self.is_item_table_empty()
 		self.set_qty_as_per_stock_uom()
 		self.validate_stock_or_nonstock_items()
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
new file mode 100644
index 0000000..899d1c1
--- /dev/null
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -0,0 +1,138 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.utils import flt, get_datetime, format_datetime
+
+class StockOverReturnError(frappe.ValidationError): pass
+
+
+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")))
+	else:
+		filters = {"doctype": doc.doctype, "docstatus": 1, "company": doc.company}
+		if doc.meta.get_field("customer"):
+			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):
+	valid_items = frappe._dict()
+	for d in frappe.db.sql("""select item_code, sum(qty) as qty, rate from `tab{0} Item` 
+		where parent = %s group by item_code""".format(doc.doctype), doc.return_against, as_dict=1):
+			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 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:
+			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
+				
+				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))
+				
+			
+			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 
+			child.item_code, sum(abs(child.qty)) as qty
+		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 
+		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):
+		doc = frappe.get_doc(target)
+		doc.is_return = 1
+		doc.return_against = source.name
+		doc.ignore_pricing_rule = 1
+		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
+		elif doctype == "Purchase Invoice":
+			target_doc.purchase_receipt = source_doc.purchase_receipt
+			target_doc.pr_detail = source_doc.pr_detail
+
+	doclist = get_mapped_doc(doctype, source_name,	{
+		doctype: {
+			"doctype": doctype,
+			
+			"validation": {
+				"docstatus": ["=", 1],
+			}
+		},
+		doctype +" Item": {
+			"doctype": doctype + " Item",
+			"fields": {
+				"purchase_order": "purchase_order",
+				"purchase_receipt": "purchase_receipt"
+			},
+			"postprocess": update_item
+		},
+	}, target_doc, set_missing_values)
+
+	return doclist
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index b2a9f03..5ad0a25 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -110,15 +110,14 @@
 		from frappe.utils import money_in_words
 		company_currency = get_company_currency(self.company)
 
-		disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None,
-			"disable_rounded_total"))
+		disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
 
 		if self.meta.get_field("base_in_words"):
 			self.base_in_words = money_in_words(disable_rounded_total and
-				self.base_grand_total or self.base_rounded_total, company_currency)
+				abs(self.base_grand_total) or abs(self.base_rounded_total), company_currency)
 		if self.meta.get_field("in_words"):
 			self.in_words = money_in_words(disable_rounded_total and
-				self.grand_total or self.rounded_total, self.currency)
+				abs(self.grand_total) or abs(self.rounded_total), self.currency)
 
 	def calculate_commission(self):
 		if self.meta.get_field("commission_rate"):
@@ -175,7 +174,7 @@
 				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:
+			elif self.doctype == "Delivery Note" and d.against_sales_order 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
 
@@ -211,7 +210,7 @@
 					'qty': d.qty,
 					'reserved_qty': reserved_qty_for_main_item,
 					'uom': d.stock_uom,
-                                        'stock_uom': d.stock_uom,
+					'stock_uom': d.stock_uom,
 					'batch_no': cstr(d.get("batch_no")).strip(),
 					'serial_no': cstr(d.get("serial_no")).strip(),
 					'name': d.name
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 6678007..19440e2 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -216,6 +216,17 @@
 				tuple(item_codes))
 
 		return serialized_items
+		
+	def get_incoming_rate_for_sales_return(self, item_code, against_document):
+		incoming_rate = 0.0
+		if against_document and item_code:
+			incoming_rate = frappe.db.sql("""select abs(ifnull(stock_value_difference, 0) / actual_qty)
+				from `tabStock Ledger Entry`
+				where voucher_type = %s and voucher_no = %s and item_code = %s limit 1""",
+				(self.doctype, against_document, item_code))
+			incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
+
+		return incoming_rate
 
 def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
 		warehouse_account=None):
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index e77a9a6..f22b624 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -77,6 +77,9 @@
 			if not self.discount_amount_applied:
 				validate_taxes_and_charges(tax)
 				validate_inclusive_tax(tax, self.doc)
+				
+			if self.doc.meta.get_field("is_return") and self.doc.is_return and tax.charge_type == "Actual":
+				tax.tax_amount = -1 * tax.tax_amount
 
 			tax.item_wise_tax_detail = {}
 			tax_fields = ["total", "tax_amount_after_discount_amount",
@@ -396,13 +399,15 @@
 		# total_advance is only for non POS Invoice
 
 		if self.doc.doctype == "Sales Invoice":
-			self.doc.round_floats_in(self.doc, ["base_grand_total", "total_advance", "write_off_amount", "paid_amount"])
-			total_amount_to_pay = self.doc.base_grand_total - self.doc.write_off_amount
-			self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance - self.doc.paid_amount,
-				self.doc.precision("outstanding_amount"))
+			if not self.doc.is_return:
+				self.doc.round_floats_in(self.doc, ["base_grand_total", "total_advance", "write_off_amount", "paid_amount"])
+				total_amount_to_pay = self.doc.base_grand_total - self.doc.write_off_amount
+				self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance - self.doc.paid_amount,
+					self.doc.precision("outstanding_amount"))
 		else:
 			self.doc.round_floats_in(self.doc, ["total_advance", "write_off_amount"])
 			self.doc.total_amount_to_pay = flt(self.doc.base_grand_total - self.doc.write_off_amount,
 				self.doc.precision("total_amount_to_pay"))
-			self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance,
-				self.doc.precision("outstanding_amount"))
+			if not self.doc.is_return:
+				self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance,
+					self.doc.precision("outstanding_amount"))
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 4a26d6d..07c2d56 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -13,8 +13,9 @@
 			this.apply_discount_amount();
 
 		// Advance calculation applicable to Sales /Purchase Invoice
-		if(in_list(["Sales Invoice", "Purchase Invoice"], this.frm.doc.doctype) && this.frm.doc.docstatus < 2) {
-			this.calculate_total_advance(update_paid_amount);
+		if(in_list(["Sales Invoice", "Purchase Invoice"], this.frm.doc.doctype)
+			 && this.frm.doc.docstatus < 2 && !this.frm.doc.is_return) {
+				 this.calculate_total_advance(update_paid_amount);
 		}
 
 		// Sales person's commission
@@ -93,6 +94,10 @@
 			tax_fields = ["total", "tax_amount_after_discount_amount",
 				"tax_amount_for_current_item", "grand_total_for_current_item",
 				"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]
+			
+			if (frappe.meta.get_docfield(me.frm.doc.doctype, "is_return") && me.frm.doc.is_return 
+					&& tax.charge_type == "Actual")
+				tax.tax_amount = -1 * tax.tax_amount;
 
 			if (cstr(tax.charge_type) != "Actual" &&
 				!(me.discount_amount_applied && me.frm.doc.apply_discount_on=="Grand Total"))
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 0a75dad..01e5781 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -46,6 +46,23 @@
 				}
 			});
 		}
+		
+		if(this.frm.fields_dict["return_against"]) {
+			this.frm.set_query("return_against", function(doc) {
+				var filters = {
+					"docstatus": 1,
+					"is_return": 0,
+					"company": doc.company
+				};
+				if (me.frm.fields_dict["customer"] && doc.customer) filters["customer"] = doc.customer;
+				if (me.frm.fields_dict["supplier"] && doc.supplier) filters["supplier"] = doc.supplier;
+	
+				return {
+					filters: filters
+				}
+			});
+		}
+		
 	},
 
 	onload_post_render: function() {
@@ -354,7 +371,8 @@
 	plc_conversion_rate: function() {
 		if(this.frm.doc.price_list_currency === this.get_company_currency()) {
 			this.frm.set_value("plc_conversion_rate", 1.0);
-		} else if(this.frm.doc.price_list_currency === this.frm.doc.currency && 			this.frm.doc.plc_conversion_rate && cint(this.frm.doc.plc_conversion_rate) != 1 &&
+		} else if(this.frm.doc.price_list_currency === this.frm.doc.currency 
+			&& this.frm.doc.plc_conversion_rate && cint(this.frm.doc.plc_conversion_rate) != 1 &&
 			cint(this.frm.doc.plc_conversion_rate) != cint(this.frm.doc.conversion_rate)) {
 				this.frm.set_value("conversion_rate", this.frm.doc.plc_conversion_rate);
 		}
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index fcdae4d..d06d550 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -18,35 +18,31 @@
 
 				// delivery note
 				if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1)
-					cur_frm.add_custom_button(__('Make Delivery'), this.make_delivery_note, "icon-truck");
+					cur_frm.add_custom_button(__('Make Delivery'), this.make_delivery_note);
 
 				// indent
 				if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1)
 					cur_frm.add_custom_button(__('Make ') + __('Material Request'),
-						this.make_material_request, "icon-ticket");
+						this.make_material_request);
 
 				// sales invoice
 				if(flt(doc.per_billed, 2) < 100) {
-					cur_frm.add_custom_button(__('Make Invoice'), this.make_sales_invoice,
-						frappe.boot.doctype_icons["Sales Invoice"]);
+					cur_frm.add_custom_button(__('Make Invoice'), this.make_sales_invoice);
 				}
 
 				// stop
 				if(flt(doc.per_delivered, 2) < 100 || doc.per_billed < 100)
-					cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Sales Order'],
-						"icon-exclamation", "btn-default")
+					cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Sales Order'])
 
 						// maintenance
 						if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
-							cur_frm.add_custom_button(__('Make Maint. Visit'),
-								this.make_maintenance_visit, null, "btn-default");
-							cur_frm.add_custom_button(__('Make Maint. Schedule'),
-								this.make_maintenance_schedule, null, "btn-default");
+							cur_frm.add_custom_button(__('Make Maint. Visit'), this.make_maintenance_visit);
+							cur_frm.add_custom_button(__('Make Maint. Schedule'), this.make_maintenance_schedule);
 						}
 
 			} else {
 				// un-stop
-				cur_frm.add_custom_button(__('Unstop'), cur_frm.cscript['Unstop Sales Order'], "icon-check");
+				cur_frm.add_custom_button(__('Unstop'), cur_frm.cscript['Unstop Sales Order']);
 			}
 		}
 
@@ -64,7 +60,7 @@
 							company: cur_frm.doc.company
 						}
 					})
-				}, "icon-download", "btn-default");
+				});
 		}
 
 		this.order_type(doc);
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index f3cd8a7..e8d8fd5 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -210,7 +210,7 @@
 		// NOTE:
 		// paid_amount and write_off_amount is only for POS Invoice
 		// total_advance is only for non POS Invoice
-		if(this.frm.doc.doctype == "Sales Invoice" && this.frm.doc.docstatus==0) {
+		if(this.frm.doc.doctype == "Sales Invoice" && this.frm.doc.docstatus==0 && !this.frm.doc.is_return) {
 			frappe.model.round_floats_in(this.frm.doc, ["base_grand_total", "total_advance", "write_off_amount",
 				"paid_amount"]);
 			var total_amount_to_pay = this.frm.doc.base_grand_total - this.frm.doc.write_off_amount
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 631009f..794d6fd 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -24,14 +24,15 @@
 			cur_frm.add_custom_button(__('Make Installation Note'), this.make_installation_note);
 
 		if (doc.docstatus==1) {
-
+			cur_frm.add_custom_button(__('Make Sales Return'), this.make_sales_return);
+				
 			this.show_stock_ledger();
 			this.show_general_ledger();
 		}
 
 		if(doc.docstatus==0 && !doc.__islocal) {
 			cur_frm.add_custom_button(__('Make Packing Slip'),
-				cur_frm.cscript['Make Packing Slip'], frappe.boot.doctype_icons["Packing Slip"], "btn-default");
+				cur_frm.cscript['Make Packing Slip'], frappe.boot.doctype_icons["Packing Slip"]);
 		}
 
 		erpnext.stock.delivery_note.set_print_hide(doc, dt, dn);
@@ -55,7 +56,7 @@
 							company: cur_frm.doc.company
 						}
 					})
-				}, "icon-download", "btn-default");
+				});
 		}
 
 	},
@@ -73,6 +74,13 @@
 			frm: cur_frm
 		});
 	},
+	
+	make_sales_return: function() {
+		frappe.model.open_mapped_doc({
+			method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_return",
+			frm: cur_frm
+		})
+	},
 
 	tc_name: function() {
 		this.get_terms();
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index 72a7227..0ca85c9 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -29,7 +29,7 @@
    "no_copy": 1, 
    "oldfieldname": "naming_series", 
    "oldfieldtype": "Select", 
-   "options": "DN-", 
+   "options": "DN-\nDN-RET-", 
    "permlevel": 0, 
    "print_hide": 1, 
    "read_only": 0, 
@@ -206,6 +206,28 @@
    "width": "100px"
   }, 
   {
+   "fieldname": "is_return", 
+   "fieldtype": "Check", 
+   "label": "Is Return", 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
+   "depends_on": "is_return", 
+   "fieldname": "return_against", 
+   "fieldtype": "Link", 
+   "label": "Return Against Delivery Note", 
+   "no_copy": 0, 
+   "options": "Delivery Note", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
    "fieldname": "cusrrency_and_price_list", 
    "fieldtype": "Section Break", 
    "label": "", 
@@ -1070,7 +1092,7 @@
  "idx": 1, 
  "in_create": 0, 
  "is_submittable": 1, 
- "modified": "2015-07-13 05:28:29.814096", 
+ "modified": "2015-07-24 11:49:15.056249", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Delivery Note", 
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 90a8a6c..e305882 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -84,7 +84,7 @@
 
 	def so_required(self):
 		"""check in manage account if sales order required or not"""
-		if frappe.db.get_value("Selling Settings", None, 'so_required') == 'Yes':
+		if not self.is_return and 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))
@@ -175,17 +175,15 @@
 		# Check for Approving Authority
 		frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.company, self.base_grand_total, self)
 
-		# update delivered qty in sales order
-		self.update_prevdoc_status()
+		if not self.is_return:
+			# update delivered qty in sales order
+			self.update_prevdoc_status()
 
-		self.check_credit_limit()
+			self.check_credit_limit()
 
-		# create stock ledger entry
 		self.update_stock_ledger()
-
 		self.make_gl_entries()
 
-		# set DN status
 		frappe.db.set(self, 'status', 'Submitted')
 
 
@@ -193,7 +191,8 @@
 		self.check_stop_sales_order("against_sales_order")
 		self.check_next_docstatus()
 
-		self.update_prevdoc_status()
+		if not self.is_return:
+			self.update_prevdoc_status()
 
 		self.update_stock_ledger()
 
@@ -251,9 +250,14 @@
 			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" \
 					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)
@@ -387,3 +391,9 @@
 	}, target_doc)
 
 	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
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 978e968..eb80014 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -13,8 +13,10 @@
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
 	import get_gl_entries, set_perpetual_inventory
 from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
-from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, make_serialized_item
+from erpnext.stock.doctype.stock_entry.test_stock_entry \
+	import make_stock_entry, make_serialized_item, get_qty_after_transaction
 from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, SerialNoStatusError
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
 
 class TestDeliveryNote(unittest.TestCase):
 	def test_over_billing_against_dn(self):
@@ -175,9 +177,155 @@
 		self.assertRaises(SerialNoStatusError, dn.submit)
 
 	def check_serial_no_values(self, serial_no, field_values):
+		serial_no = frappe.get_doc("Serial No", serial_no)
 		for field, value in field_values.items():
-			self.assertEquals(cstr(frappe.db.get_value("Serial No", serial_no, field)), value)
+			self.assertEquals(cstr(serial_no.get(field)), value)
+			
+	def test_sales_return_for_non_bundled_items(self):
+		set_perpetual_inventory()
+		
+		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100)
+		
+		actual_qty_0 = get_qty_after_transaction()
+		
+		dn = create_delivery_note(qty=5, rate=500)
 
+		actual_qty_1 = get_qty_after_transaction()
+		self.assertEquals(actual_qty_0 - 5, actual_qty_1)
+		
+		# outgoing_rate
+		outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note", 
+			"voucher_no": dn.name}, "stock_value_difference") / 5
+		
+		# return entry
+		dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-2, rate=500)
+
+		actual_qty_2 = get_qty_after_transaction()
+			
+		self.assertEquals(actual_qty_1 + 2, actual_qty_2)
+		
+		incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry", 
+			{"voucher_type": "Delivery Note", "voucher_no": dn1.name}, 
+			["incoming_rate", "stock_value_difference"])
+			
+		self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
+		
+		gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note", 
+			"voucher_no": dn1.name, "account": "_Test Warehouse - _TC"}, "debit")
+			
+		self.assertEquals(gle_warehouse_amount, stock_value_difference)
+		
+		set_perpetual_inventory(0)
+		
+	def test_return_single_item_from_bundled_items(self):
+		set_perpetual_inventory()
+		
+		create_stock_reconciliation(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, rate=100)
+		create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC", 
+			qty=50, rate=100)
+				
+		dn = create_delivery_note(item_code="_Test Product Bundle Item", qty=5, rate=500)
+
+		# Qty after delivery
+		actual_qty_1 = get_qty_after_transaction()
+		self.assertEquals(actual_qty_1,  25)
+		
+		# outgoing_rate
+		outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Delivery Note", 
+			"voucher_no": dn.name, "item_code": "_Test Item"}, "stock_value_difference") / 25
+		
+		# return 'test item' from packed items
+		dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-10, rate=500)
+
+		# qty after return
+		actual_qty_2 = get_qty_after_transaction()
+		self.assertEquals(actual_qty_2, 35)
+		
+		# Check incoming rate for return entry
+		incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry", 
+			{"voucher_type": "Delivery Note", "voucher_no": dn1.name}, 
+			["incoming_rate", "stock_value_difference"])
+			
+		self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
+		
+		# Check gl entry for warehouse
+		gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note", 
+			"voucher_no": dn1.name, "account": "_Test Warehouse - _TC"}, "debit")
+			
+		self.assertEquals(gle_warehouse_amount, stock_value_difference)
+		
+		set_perpetual_inventory(0)
+		
+	def test_return_entire_bundled_items(self):
+		set_perpetual_inventory()
+		
+		create_stock_reconciliation(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, rate=100)
+		create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC", 
+			qty=50, rate=100)
+		
+		dn = create_delivery_note(item_code="_Test Product Bundle Item", qty=5, rate=500)
+		
+		#  return bundled item
+		dn1 = create_delivery_note(item_code='_Test Product Bundle Item', is_return=1, 
+			return_against=dn.name, qty=-2, rate=500)
+
+		# qty after return
+		actual_qty = get_qty_after_transaction()
+		self.assertEquals(actual_qty, 35)
+		
+		# Check incoming rate for return entry
+		incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
+			{"voucher_type": "Delivery Note", "voucher_no": dn1.name},
+			["incoming_rate", "stock_value_difference"])
+
+		self.assertEquals(incoming_rate, 100)
+
+		# Check gl entry for warehouse
+		gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
+			"voucher_no": dn1.name, "account": "_Test Warehouse - _TC"}, "debit")
+			
+		self.assertEquals(gle_warehouse_amount, 1400)
+		
+		set_perpetual_inventory(0)
+		
+	def test_return_for_serialized_items(self):
+		se = make_serialized_item()
+		serial_no = get_serial_nos(se.get("items")[0].serial_no)[0]
+
+		dn = create_delivery_note(item_code="_Test Serialized Item With Series", rate=500, serial_no=serial_no)
+
+		self.check_serial_no_values(serial_no, {
+			"status": "Delivered",
+			"warehouse": "",
+			"delivery_document_no": dn.name
+		})
+
+		# return entry
+		dn1 = create_delivery_note(item_code="_Test Serialized Item With Series", 
+			is_return=1, return_against=dn.name, qty=-1, rate=500, serial_no=serial_no)
+
+		self.check_serial_no_values(serial_no, {
+			"status": "Sales Returned",
+			"warehouse": "_Test Warehouse - _TC",
+			"delivery_document_no": ""
+		})
+				
+		dn1.cancel()
+		
+		self.check_serial_no_values(serial_no, {
+			"status": "Delivered",
+			"warehouse": "",
+			"delivery_document_no": dn.name
+		})
+		
+		dn.cancel()
+		
+		self.check_serial_no_values(serial_no, {
+			"status": "Available",
+			"warehouse": "_Test Warehouse - _TC",
+			"delivery_document_no": "",
+			"purchase_document_no": se.name
+		})
 
 def create_delivery_note(**args):
 	dn = frappe.new_doc("Delivery Note")
@@ -190,6 +338,8 @@
 	dn.company = args.company or "_Test Company"
 	dn.customer = args.customer or "_Test Customer"
 	dn.currency = args.currency or "INR"
+	dn.is_return = args.is_return
+	dn.return_against = args.return_against
 
 	dn.append("items", {
 		"item_code": args.item or args.item_code or "_Test Item",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index fe41b4f..13e104e 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -31,9 +31,10 @@
 
 		if(this.frm.doc.docstatus == 1) {
 			if(this.frm.doc.__onload && !this.frm.doc.__onload.billing_complete) {
-				cur_frm.add_custom_button(__('Make Purchase Invoice'), this.make_purchase_invoice,
-					frappe.boot.doctype_icons["Purchase Invoice"]);
+				cur_frm.add_custom_button(__('Make Purchase Invoice'), this.make_purchase_invoice);
 			}
+			
+			cur_frm.add_custom_button(__('Make Purchase Return'), this.make_purchase_return);
 
 			this.show_stock_ledger();
 			this.show_general_ledger();
@@ -51,7 +52,7 @@
 							company: cur_frm.doc.company
 						}
 					})
-				}, "icon-download", "btn-default");
+				});
 		}
 
 		this.frm.toggle_reqd("supplier_warehouse", this.frm.doc.is_subcontracted==="Yes");
@@ -105,6 +106,13 @@
 			frm: cur_frm
 		})
 	},
+	
+	make_purchase_return: function() {
+		frappe.model.open_mapped_doc({
+			method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_return",
+			frm: cur_frm
+		})
+	},
 
 	tc_name: function() {
 		this.get_terms();
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 6e344b6..8e32281 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -21,13 +21,14 @@
    "width": "50%"
   }, 
   {
+   "default": "", 
    "fieldname": "naming_series", 
    "fieldtype": "Select", 
    "label": "Series", 
    "no_copy": 1, 
    "oldfieldname": "naming_series", 
    "oldfieldtype": "Select", 
-   "options": "PREC-", 
+   "options": "PREC-\nPREC-RET-", 
    "permlevel": 0, 
    "print_hide": 1, 
    "reqd": 1
@@ -131,6 +132,28 @@
    "width": "100px"
   }, 
   {
+   "fieldname": "is_return", 
+   "fieldtype": "Check", 
+   "label": "Is Return", 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
+   "depends_on": "is_return", 
+   "fieldname": "return_against", 
+   "fieldtype": "Link", 
+   "label": "Return Against Purchase Receipt", 
+   "no_copy": 0, 
+   "options": "Purchase Receipt", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
    "fieldname": "currency_and_price_list", 
    "fieldtype": "Section Break", 
    "label": "", 
@@ -854,7 +877,7 @@
  "icon": "icon-truck", 
  "idx": 1, 
  "is_submittable": 1, 
- "modified": "2015-07-13 05:28:27.389559", 
+ "modified": "2015-07-24 11:49:35.580382", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Purchase Receipt", 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index e782889..034eb07 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -44,6 +44,7 @@
 		self.set_status()
 		self.po_required()
 		self.validate_with_previous_doc()
+		self.validate_purchase_return()
 		self.validate_rejected_warehouse()
 		self.validate_accepted_rejected_qty()
 		self.validate_inspection()
@@ -60,12 +61,20 @@
 		self.set_landed_cost_voucher_amount()
 		self.update_valuation_rate("items")
 
+
 	def set_landed_cost_voucher_amount(self):
 		for d in self.get("items"):
 			lc_voucher_amount = frappe.db.sql("""select sum(ifnull(applicable_charges, 0))
 				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):
 		for d in self.get("items"):
@@ -108,7 +117,7 @@
 			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':
+		if not self.is_return and 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))
@@ -123,11 +132,20 @@
 
 				if pr_qty:
 					val_rate_db_precision = 6 if cint(self.precision("valuation_rate", d)) <= 6 else 9
-					sl_entries.append(self.get_sl_entries(d, {
+					rate = flt(d.valuation_rate, val_rate_db_precision)
+					sle = self.get_sl_entries(d, {
 						"actual_qty": flt(pr_qty),
-						"serial_no": cstr(d.serial_no).strip(),
-						"incoming_rate": flt(d.valuation_rate, val_rate_db_precision)
-					}))
+						"serial_no": cstr(d.serial_no).strip()
+					})
+					if self.is_return:
+						sle.update({
+							"outgoing_rate": rate
+						})
+					else:
+						sle.update({
+							"incoming_rate": rate
+						})
+					sl_entries.append(sle)
 
 				if flt(d.rejected_qty) > 0:
 					sl_entries.append(self.get_sl_entries(d, {
@@ -176,7 +194,6 @@
 				"item_code": d.rm_item_code,
 				"warehouse": self.supplier_warehouse,
 				"actual_qty": -1*flt(d.consumed_qty),
-				"incoming_rate": 0
 			}))
 
 	def validate_inspection(self):
@@ -207,17 +224,16 @@
 		# 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()
 
 		from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
 		update_serial_nos_after_submit(self, "items")
 
-		purchase_controller.update_last_purchase_rate(self, 1)
-
 		self.make_gl_entries()
 
 	def check_next_docstatus(self):
@@ -244,12 +260,13 @@
 
 		self.update_stock_ledger()
 
-		self.update_prevdoc_status()
+		if not self.is_return:
+			self.update_prevdoc_status()
 
-		# Must be called after updating received qty in PO
-		self.update_ordered_qty()
+			# Must be called after updating received qty in PO
+			self.update_ordered_qty()
 
-		pc_obj.update_last_purchase_rate(self, 0)
+			pc_obj.update_last_purchase_rate(self, 0)
 
 		self.make_gl_entries_on_cancel()
 
@@ -417,7 +434,7 @@
 			"doctype": "Purchase Invoice",
 			"validation": {
 				"docstatus": ["=", 1],
-			}
+			},
 		},
 		"Purchase Receipt Item": {
 			"doctype": "Purchase Invoice Item",
@@ -449,3 +466,8 @@
 			invoiced_qty_map[pr_detail] += qty
 
 	return invoiced_qty_map
+
+@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
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 141bcd4..343d51a 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -6,7 +6,7 @@
 import unittest
 import frappe
 import frappe.defaults
-from frappe.utils import cint, flt
+from frappe.utils import cint, flt, cstr
 
 class TestPurchaseReceipt(unittest.TestCase):
 	def test_make_purchase_invoice(self):
@@ -119,6 +119,65 @@
 		for serial_no in rejected_serial_nos:
 			self.assertEquals(frappe.db.get_value("Serial No", serial_no, "warehouse"),
 				pr.get("items")[0].rejected_warehouse)
+				
+	def test_purchase_return(self):
+		set_perpetual_inventory()
+		
+		pr = make_purchase_receipt()
+		
+		return_pr = make_purchase_receipt(is_return=1, return_against=pr.name, qty=-2)
+		
+		# check sle
+		outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt", 
+			"voucher_no": return_pr.name}, "outgoing_rate")
+			
+		self.assertEqual(outgoing_rate, 50)
+		
+		
+		# check gl entries for return
+		gl_entries = get_gl_entries("Purchase Receipt", return_pr.name)
+
+		self.assertTrue(gl_entries)
+
+		expected_values = {
+			"_Test Warehouse - _TC": [0.0, 100.0],
+			"Stock Received But Not Billed - _TC": [100.0, 0.0],
+		}
+
+		for gle in gl_entries:
+			self.assertEquals(expected_values[gle.account][0], gle.debit)
+			self.assertEquals(expected_values[gle.account][1], gle.credit)
+		
+		set_perpetual_inventory(0)
+		
+	def test_purchase_return_for_serialized_items(self):
+		def _check_serial_no_values(serial_no, field_values):
+			serial_no = frappe.get_doc("Serial No", serial_no)
+			for field, value in field_values.items():
+				self.assertEquals(cstr(serial_no.get(field)), value)
+		
+		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+		
+		pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
+		
+		serial_no = get_serial_nos(pr.get("items")[0].serial_no)[0]
+		
+		_check_serial_no_values(serial_no, {
+			"status": "Available",
+			"warehouse": "_Test Warehouse - _TC",
+			"purchase_document_no": pr.name
+		})
+		
+		return_pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=-1, 
+			is_return=1, return_against=pr.name, serial_no=serial_no)
+			
+		_check_serial_no_values(serial_no, {
+			"status": "Purchase Returned",
+			"warehouse": "",
+			"purchase_document_no": pr.name,
+			"delivery_document_no": return_pr.name
+		})
+		
 
 def get_gl_entries(voucher_type, voucher_no):
 	return frappe.db.sql("""select account, debit, credit
@@ -142,6 +201,8 @@
 	pr.is_subcontracted = args.is_subcontracted or "No"
 	pr.supplier_warehouse = "_Test Warehouse 1 - _TC"
 	pr.currency = args.currency or "INR"
+	pr.is_return = args.is_return
+	pr.return_against = args.return_against
 	
 	pr.append("items", {
 		"item_code": args.item or args.item_code or "_Test Item",
diff --git a/erpnext/stock/doctype/serial_no/serial_no.json b/erpnext/stock/doctype/serial_no/serial_no.json
index 8ffe7ed..97754e9 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.json
+++ b/erpnext/stock/doctype/serial_no/serial_no.json
@@ -244,7 +244,7 @@
    "in_filter": 1, 
    "label": "Delivery Document Type", 
    "no_copy": 1, 
-   "options": "\nDelivery Note\nSales Invoice\nStock Entry", 
+   "options": "\nDelivery Note\nSales Invoice\nStock Entry\nPurchase Receipt", 
    "permlevel": 0, 
    "read_only": 1
   }, 
@@ -418,7 +418,7 @@
  "icon": "icon-barcode", 
  "idx": 1, 
  "in_create": 0, 
- "modified": "2015-07-13 05:28:27.961178", 
+ "modified": "2015-07-24 03:55:29.946944", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Serial No", 
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index bac5441..6b5054b 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -33,10 +33,7 @@
 		self.validate_warehouse()
 		self.validate_item()
 		self.on_stock_ledger_entry()
-
-		valid_purchase_document_type = ("Purchase Receipt", "Stock Entry", "Serial No")
-		self.validate_value("purchase_document_type", "in", valid_purchase_document_type)
-
+		
 	def set_maintenance_status(self):
 		if not self.warranty_expiry_date and not self.amc_expiry_date:
 			self.maintenance_status = None
@@ -81,20 +78,19 @@
 	def set_status(self, last_sle):
 		if last_sle:
 			if last_sle.voucher_type == "Stock Entry":
-				document_type = frappe.db.get_value("Stock Entry", last_sle.voucher_no,
-					"purpose")
+				document_type = frappe.db.get_value("Stock Entry", last_sle.voucher_no, "purpose")
 			else:
 				document_type = last_sle.voucher_type
 
 			if last_sle.actual_qty > 0:
-				if document_type == "Sales Return":
+				if document_type in ("Delivery Note", "Sales Invoice", "Sales Return"):
 					self.status = "Sales Returned"
 				else:
 					self.status = "Available"
 			else:
-				if document_type == "Purchase Return":
+				if document_type in ("Purchase Receipt", "Purchase Invoice", "Purchase Return"):
 					self.status = "Purchase Returned"
-				elif last_sle.voucher_type in ("Delivery Note", "Sales Invoice"):
+				elif document_type in ("Delivery Note", "Sales Invoice"):
 					self.status = "Delivered"
 				else:
 					self.status = "Not Available"
@@ -123,9 +119,10 @@
 			self.delivery_document_no = delivery_sle.voucher_no
 			self.delivery_date = delivery_sle.posting_date
 			self.delivery_time = delivery_sle.posting_time
-			self.customer, self.customer_name = \
-				frappe.db.get_value(delivery_sle.voucher_type, delivery_sle.voucher_no,
-					["customer", "customer_name"])
+			if delivery_sle.voucher_type  in ("Delivery Note", "Sales Invoice"):
+				self.customer, self.customer_name = \
+					frappe.db.get_value(delivery_sle.voucher_type, delivery_sle.voucher_no,
+						["customer", "customer_name"])
 			if self.warranty_period:
 				self.warranty_expiry_date	= add_days(cstr(delivery_sle.posting_date),
 					cint(self.warranty_period))
@@ -235,10 +232,10 @@
 							frappe.throw(_("Serial No {0} does not belong to Warehouse {1}").format(serial_no,
 								sle.warehouse), SerialNoWarehouseError)
 
-						if sle.voucher_type in ("Delivery Note", "Sales Invoice") \
+						if sle.voucher_type in ("Delivery Note", "Sales Invoice") and sle.is_cancelled=="No" \
 							and sr.status != "Available":
-							frappe.throw(_("Serial No {0} status must be 'Available' to Deliver").format(serial_no),
-								SerialNoStatusError)
+								frappe.throw(_("Serial No {0} status must be 'Available' to Deliver").format(serial_no),
+									SerialNoStatusError)
 
 				elif sle.actual_qty < 0:
 					# transfer out
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 6958ea0..8526117 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -7,20 +7,7 @@
 erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
 	setup: function() {
 		var me = this;
-
-		this.frm.fields_dict.delivery_note_no.get_query = function() {
-			return { query: "erpnext.stock.doctype.stock_entry.stock_entry.query_sales_return_doc" };
-		};
-
-		this.frm.fields_dict.sales_invoice_no.get_query =
-			this.frm.fields_dict.delivery_note_no.get_query;
-
-		this.frm.fields_dict.purchase_receipt_no.get_query = function() {
-			return {
-				filters:{ 'docstatus': 1 }
-			};
-		};
-
+		
 		this.frm.fields_dict.bom_no.get_query = function() {
 			return {
 				filters:{ 'docstatus': 1 }
@@ -28,20 +15,7 @@
 		};
 
 		this.frm.fields_dict.items.grid.get_field('item_code').get_query = function() {
-			if(in_list(["Sales Return", "Purchase Return"], me.frm.doc.purpose) &&
-				me.get_doctype_docname()) {
-					return {
-						query: "erpnext.stock.doctype.stock_entry.stock_entry.query_return_item",
-						filters: {
-							purpose: me.frm.doc.purpose,
-							delivery_note_no: me.frm.doc.delivery_note_no,
-							sales_invoice_no: me.frm.doc.sales_invoice_no,
-							purchase_receipt_no: me.frm.doc.purchase_receipt_no
-						}
-					};
-			} else {
-				return erpnext.queries.item({is_stock_item: "Yes"});
-			}
+			return erpnext.queries.item({is_stock_item: "Yes"});
 		};
 
 		this.frm.set_query("purchase_order", function() {
@@ -84,19 +58,6 @@
 		this.toggle_enable_bom();
 		this.show_stock_ledger();
 		this.show_general_ledger();
-
-		if(this.frm.doc.docstatus === 1 && frappe.boot.user.can_create.indexOf("Journal Entry")!==-1
-			&& this.frm.doc.__onload.credit_debit_note_exists == 0 ) {
-			if(this.frm.doc.purpose === "Sales Return") {
-				this.frm.add_custom_button(__("Make Credit Note"),
-					function() { me.make_return_jv(); }, frappe.boot.doctype_icons["Journal Entry"]);
-				this.add_excise_button();
-			} else if(this.frm.doc.purpose === "Purchase Return") {
-				this.frm.add_custom_button(__("Make Debit Note"),
-					function() { me.make_return_jv(); }, frappe.boot.doctype_icons["Journal Entry"]);
-				this.add_excise_button();
-			}
-		}
 	},
 
 	on_submit: function() {
@@ -111,15 +72,10 @@
 		var me = this;
 
 		if(cint(frappe.defaults.get_default("auto_accounting_for_stock")) && this.frm.doc.company) {
-			var account_for = "stock_adjustment_account";
-
-			if (this.frm.doc.purpose == "Purchase Return")
-				account_for = "stock_received_but_not_billed";
-
 			return this.frm.call({
 				method: "erpnext.accounts.utils.get_company_default",
 				args: {
-					"fieldname": account_for,
+					"fieldname": "stock_adjustment_account",
 					"company": this.frm.doc.company
 				},
 				callback: function(r) {
@@ -192,35 +148,6 @@
 		this.frm.toggle_enable("bom_no", !in_list(["Manufacture", "Material Transfer for Manufacture"], this.frm.doc.purpose));
 	},
 
-	get_doctype_docname: function() {
-		if(this.frm.doc.purpose === "Sales Return") {
-			if(this.frm.doc.delivery_note_no && this.frm.doc.sales_invoice_no) {
-				// both specified
-				msgprint(__("You can not enter both Delivery Note No and Sales Invoice No. Please enter any one."));
-
-			} else if(!(this.frm.doc.delivery_note_no || this.frm.doc.sales_invoice_no)) {
-				// none specified
-				msgprint(__("Please enter Delivery Note No or Sales Invoice No to proceed"));
-
-			} else if(this.frm.doc.delivery_note_no) {
-				return {doctype: "Delivery Note", docname: this.frm.doc.delivery_note_no};
-
-			} else if(this.frm.doc.sales_invoice_no) {
-				return {doctype: "Sales Invoice", docname: this.frm.doc.sales_invoice_no};
-
-			}
-		} else if(this.frm.doc.purpose === "Purchase Return") {
-			if(this.frm.doc.purchase_receipt_no) {
-				return {doctype: "Purchase Receipt", docname: this.frm.doc.purchase_receipt_no};
-
-			} else {
-				// not specified
-				msgprint(__("Please enter Purchase Receipt No to proceed"));
-
-			}
-		}
-	},
-
 	add_excise_button: function() {
 		if(frappe.boot.sysdefaults.country === "India")
 			this.frm.add_custom_button(__("Make Excise Invoice"), function() {
@@ -231,37 +158,16 @@
 			}, frappe.boot.doctype_icons["Journal Entry"], "btn-default");
 	},
 
-	make_return_jv: function() {
-		if(this.get_doctype_docname()) {
-			return this.frm.call({
-				method: "make_return_jv",
-				args: {
-					stock_entry: this.frm.doc.name
-				},
-				callback: function(r) {
-					if(!r.exc) {
-						var doclist = frappe.model.sync(r.message);
-						frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
-
-					}
-				}
-			});
-		}
-	},
-
 	items_add: function(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
-		this.frm.script_manager.copy_from_first_row("items", row,
-			["expense_account", "cost_center"]);
+		this.frm.script_manager.copy_from_first_row("items", row, ["expense_account", "cost_center"]);
 
 		if(!row.s_warehouse) row.s_warehouse = this.frm.doc.from_warehouse;
 		if(!row.t_warehouse) row.t_warehouse = this.frm.doc.to_warehouse;
 	},
 
-	source_mandatory: ["Material Issue", "Material Transfer", "Purchase Return", "Subcontract",
-		"Material Transfer for Manufacture"],
-	target_mandatory: ["Material Receipt", "Material Transfer", "Sales Return", "Subcontract",
-		"Material Transfer for Manufacture"],
+	source_mandatory: ["Material Issue", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"],
+	target_mandatory: ["Material Receipt", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"],
 
 	from_warehouse: function(doc) {
 		var me = this;
@@ -295,92 +201,21 @@
 
 	items_on_form_rendered: function(doc, grid_row) {
 		erpnext.setup_serial_no();
-	},
-
-	customer: function() {
-		this.get_party_details({
-			party: this.frm.doc.customer,
-			party_type:"Customer",
-			doctype: this.frm.doc.doctype
-		});
-	},
-
-	supplier: function() {
-		this.get_party_details({
-			party: this.frm.doc.supplier,
-			party_type:"Supplier",
-			doctype: this.frm.doc.doctype
-		});
-	},
-
-	get_party_details: function(args) {
-		var me = this;
-		frappe.call({
-			method: "erpnext.accounts.party.get_party_details",
-			args: args,
-			callback: function(r) {
-				if(r.message) {
-					me.frm.set_value({
-						"customer_name": r.message["customer_name"],
-						"customer_address": r.message["address_display"]
-					});
-				}
-			}
-		});
-	},
-
-	delivery_note_no: function() {
-		this.get_party_details_from_against_voucher({
-			ref_dt: "Delivery Note",
-			ref_dn: this.frm.doc.delivery_note_no
-		})
-	},
-
-	sales_invoice_no: function() {
-		this.get_party_details_from_against_voucher({
-			ref_dt: "Sales Invoice",
-			ref_dn: this.frm.doc.sales_invoice_no
-		})
-	},
-
-	purchase_receipt_no: function() {
-		this.get_party_details_from_against_voucher({
-			ref_dt: "Purchase Receipt",
-			ref_dn: this.frm.doc.purchase_receipt_no
-		})
-	},
-
-	get_party_details_from_against_voucher: function(args) {
-		return this.frm.call({
-			method: "erpnext.stock.doctype.stock_entry.stock_entry.get_party_details",
-			args: args,
-		})
 	}
-
 });
 
 cur_frm.script_manager.make(erpnext.stock.StockEntry);
 
 cur_frm.cscript.toggle_related_fields = function(doc) {
-	disable_from_warehouse = inList(["Material Receipt", "Sales Return"], doc.purpose);
-	disable_to_warehouse = inList(["Material Issue", "Purchase Return"], doc.purpose);
+	cur_frm.toggle_enable("from_warehouse", doc.purpose!='Material Receipt');
+	cur_frm.toggle_enable("to_warehouse", doc.purpose!='Material Issue');
 
-	cur_frm.toggle_enable("from_warehouse", !disable_from_warehouse);
-	cur_frm.toggle_enable("to_warehouse", !disable_to_warehouse);
-
-	cur_frm.fields_dict["items"].grid.set_column_disp("s_warehouse", !disable_from_warehouse);
-	cur_frm.fields_dict["items"].grid.set_column_disp("t_warehouse", !disable_to_warehouse);
+	cur_frm.fields_dict["items"].grid.set_column_disp("s_warehouse", doc.purpose!='Material Receipt');
+	cur_frm.fields_dict["items"].grid.set_column_disp("t_warehouse", doc.purpose!='Material Issue');
 
 	cur_frm.cscript.toggle_enable_bom();
 
-	if(doc.purpose == 'Purchase Return') {
-		doc.customer = doc.customer_name = doc.customer_address =
-			doc.delivery_note_no = doc.sales_invoice_no = null;
-		doc.bom_no = doc.production_order = doc.fg_completed_qty = null;
-	} else if(doc.purpose == 'Sales Return') {
-		doc.supplier=doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no=null;
-		doc.bom_no = doc.production_order = doc.fg_completed_qty = null;
-	} else if (doc.purpose == 'Subcontract') {
+	if (doc.purpose == 'Subcontract') {
 		doc.customer = doc.customer_name = doc.customer_address =
 			doc.delivery_note_no = doc.sales_invoice_no = null;
 	} else {
@@ -388,7 +223,7 @@
 			doc.delivery_note_no = doc.sales_invoice_no = doc.supplier =
 			doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no = null;
 	}
-	if(in_list(["Material Receipt", "Sales Return", "Purchase Return"], doc.purpose)) {
+	if(doc.purpose == "Material Receipt") {
 		cur_frm.set_value("from_bom", 0);
 	}
 }
@@ -505,8 +340,6 @@
 }
 
 cur_frm.cscript.validate = function(doc, cdt, cdn) {
-	if($.inArray(cur_frm.doc.purpose, ["Purchase Return", "Sales Return"])!==-1)
-		validated = cur_frm.cscript.get_doctype_docname() ? true : false;
 	cur_frm.cscript.validate_items(doc);
 }
 
@@ -526,14 +359,6 @@
 	erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
 }
 
-cur_frm.fields_dict.customer.get_query = function(doc, cdt, cdn) {
-	return { query: "erpnext.controllers.queries.customer_query" }
-}
-
-cur_frm.fields_dict.supplier.get_query = function(doc, cdt, cdn) {
-	return { query: "erpnext.controllers.queries.supplier_query" }
-}
-
 cur_frm.cscript.company = function(doc, cdt, cdn) {
 	if(doc.company) {
 		erpnext.get_fiscal_year(doc.company, doc.posting_date, function() {
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 06dec58..3c39d42 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -54,7 +54,7 @@
    "no_copy": 0, 
    "oldfieldname": "purpose", 
    "oldfieldtype": "Select", 
-   "options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nMaterial Transfer for Manufacture\nManufacture\nRepack\nSubcontract\nSales Return\nPurchase Return", 
+   "options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nMaterial Transfer for Manufacture\nManufacture\nRepack\nSubcontract", 
    "permlevel": 0, 
    "print_hide": 0, 
    "read_only": 0, 
@@ -678,7 +678,7 @@
  "is_submittable": 1, 
  "issingle": 0, 
  "max_attachments": 0, 
- "modified": "2015-07-13 05:28:26.085266", 
+ "modified": "2015-07-22 18:47:20.328749", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Stock Entry", 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index cae0571..1b01f3a 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -4,10 +4,8 @@
 from __future__ import unicode_literals
 import frappe
 import frappe.defaults
-
-from frappe.utils import cstr, cint, flt, comma_or, get_datetime, getdate
-
 from frappe import _
+from frappe.utils import cstr, cint, flt, comma_or, get_datetime, getdate
 from erpnext.stock.utils import get_incoming_rate
 from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError
 from erpnext.controllers.queries import get_match_cond
@@ -15,8 +13,6 @@
 from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
 from erpnext.accounts.utils import validate_fiscal_year
 
-class NotUpdateStockError(frappe.ValidationError): pass
-class StockOverReturnError(frappe.ValidationError): pass
 class IncorrectValuationRateError(frappe.ValidationError): pass
 class DuplicateEntryForProductionOrderError(frappe.ValidationError): pass
 class OperationsNotCompleteError(frappe.ValidationError): pass
@@ -37,13 +33,6 @@
 				item.update(get_available_qty(item.item_code,
 					item.s_warehouse))
 
-		count = frappe.db.exists({
-			"doctype": "Journal Entry",
-			"stock_entry":self.name,
-			"docstatus":1
-		})
-		self.get("__onload").credit_debit_note_exists = 1 if count else 0
-
 	def validate(self):
 		self.pro_doc = None
 		if self.production_order:
@@ -61,7 +50,6 @@
 		self.get_stock_and_rate()
 		self.validate_bom()
 		self.validate_finished_goods()
-		self.validate_return_reference_doc()
 		self.validate_with_material_request()
 		self.validate_valuation_rate()
 		self.set_total_incoming_outgoing_value()
@@ -84,16 +72,13 @@
 
 	def validate_purpose(self):
 		valid_purposes = ["Material Issue", "Material Receipt", "Material Transfer", "Material Transfer for Manufacture",
-			"Manufacture", "Repack", "Subcontract", "Sales Return", "Purchase Return"]
+			"Manufacture", "Repack", "Subcontract"]
 		if self.purpose not in valid_purposes:
 			frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes)))
 
-		if self.purpose in ("Manufacture", "Repack", "Sales Return") and not self.difference_account:
+		if self.purpose in ("Manufacture", "Repack") and not self.difference_account:
 			self.difference_account = frappe.db.get_value("Company", self.company, "default_expense_account")
 
-		if self.purpose in ("Purchase Return") and not self.difference_account:
-			frappe.throw(_("Difference Account mandatory for purpose '{0}'").format(self.purpose))
-
 	def set_transfer_qty(self):
 		for item in self.get("items"):
 			if not flt(item.qty):
@@ -122,7 +107,7 @@
 			if not item.transfer_qty:
 				item.transfer_qty = item.qty * item.conversion_factor
 
-			if (self.purpose in ("Material Transfer", "Sales Return", "Purchase Return", "Material Transfer for Manufacture")
+			if (self.purpose in ("Material Transfer", "Material Transfer for Manufacture")
 				and not item.serial_no
 				and item.item_code in serialized_items):
 				frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),
@@ -131,8 +116,8 @@
 	def validate_warehouse(self):
 		"""perform various (sometimes conditional) validations on warehouse"""
 
-		source_mandatory = ["Material Issue", "Material Transfer", "Purchase Return", "Subcontract", "Material Transfer for Manufacture"]
-		target_mandatory = ["Material Receipt", "Material Transfer", "Sales Return", "Subcontract", "Material Transfer for Manufacture"]
+		source_mandatory = ["Material Issue", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"]
+		target_mandatory = ["Material Receipt", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"]
 
 		validate_for_manufacture_repack = any([d.bom_no for d in self.get("items")])
 
@@ -289,8 +274,8 @@
 
 			# get incoming rate
 			if not d.bom_no:
-				if not flt(d.incoming_rate) or d.s_warehouse or self.purpose == "Sales Return" or force:
-					incoming_rate = flt(self.get_incoming_rate(args), self.precision("incoming_rate", d))
+				if not flt(d.incoming_rate) or d.s_warehouse or force:
+					incoming_rate = flt(get_incoming_rate(args), self.precision("incoming_rate", d))
 					if incoming_rate > 0:
 						d.incoming_rate = incoming_rate
 
@@ -334,27 +319,6 @@
 
 		return operation_cost_per_unit + (flt(self.additional_operating_cost) / flt(qty))
 
-	def get_incoming_rate(self, args):
-		incoming_rate = 0
-		if self.purpose == "Sales Return":
-			incoming_rate = self.get_incoming_rate_for_sales_return(args)
-		else:
-			incoming_rate = get_incoming_rate(args)
-
-		return incoming_rate
-
-	def get_incoming_rate_for_sales_return(self, args):
-		incoming_rate = 0.0
-		if (self.delivery_note_no or self.sales_invoice_no) and args.get("item_code"):
-			incoming_rate = frappe.db.sql("""select abs(ifnull(stock_value_difference, 0) / actual_qty)
-				from `tabStock Ledger Entry`
-				where voucher_type = %s and voucher_no = %s and item_code = %s limit 1""",
-				((self.delivery_note_no and "Delivery Note" or "Sales Invoice"),
-				self.delivery_note_no or self.sales_invoice_no, args.item_code))
-			incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
-
-		return incoming_rate
-
 	def validate_purchase_order(self):
 		"""Throw exception if more raw material is transferred against Purchase Order than in
 		the raw materials supplied table"""
@@ -401,55 +365,6 @@
 				frappe.throw(_("Finished Item {0} must be entered for Manufacture type entry")
 					.format(production_item))
 
-	def validate_return_reference_doc(self):
-		"""validate item with reference doc"""
-		ref = get_return_doc_and_details(self)
-
-		if ref.doc:
-			# validate docstatus
-			if ref.doc.docstatus != 1:
-				frappe.throw(_("{0} {1} must be submitted").format(ref.doc.doctype, ref.doc.name),
-					frappe.InvalidStatusError)
-
-			# update stock check
-			if ref.doc.doctype == "Sales Invoice" and cint(ref.doc.update_stock) != 1:
-				frappe.throw(_("'Update Stock' for Sales Invoice {0} must be set").format(ref.doc.name), NotUpdateStockError)
-
-			# posting date check
-			ref_posting_datetime = "%s %s" % (ref.doc.posting_date, ref.doc.posting_time or "00:00:00")
-
-			if get_datetime(ref_posting_datetime) < get_datetime(ref_posting_datetime):
-				from frappe.utils.dateutils import datetime_in_user_format
-				frappe.throw(_("Posting timestamp must be after {0}")
-					.format(datetime_in_user_format(ref_posting_datetime)))
-
-			stock_items = get_stock_items_for_return(ref.doc, ref.parentfields)
-			already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname)
-
-			for item in self.get("items"):
-				# validate if item exists in the ref doc and that it is a stock item
-				if item.item_code not in stock_items:
-					frappe.throw(_("Item {0} does not exist in {1} {2}").format(item.item_code, ref.doc.doctype, ref.doc.name),
-						frappe.DoesNotExistError)
-
-				# validate quantity <= ref item's qty - qty already returned
-				if self.purpose == "Purchase Return":
-					ref_item_qty = sum([flt(d.qty)*flt(d.conversion_factor) for d in ref.doc.get({"item_code": item.item_code})])
-				elif self.purpose == "Sales Return":
-					ref_item_qty = sum([flt(d.qty) for d in ref.doc.get({"item_code": item.item_code})])
-				returnable_qty = ref_item_qty - flt(already_returned_item_qty.get(item.item_code))
-				if not returnable_qty:
-					frappe.throw(_("Item {0} has already been returned").format(item.item_code), StockOverReturnError)
-				elif item.transfer_qty > returnable_qty:
-					frappe.throw(_("Cannot return more than {0} for Item {1}").format(returnable_qty, item.item_code),
-						StockOverReturnError)
-
-	def get_already_returned_item_qty(self, ref_fieldname):
-		return dict(frappe.db.sql("""select item_code, sum(transfer_qty) as qty
-			from `tabStock Entry Detail` where parent in (
-				select name from `tabStock Entry` where `%s`=%s and docstatus=1)
-			group by item_code""" % (ref_fieldname, "%s"), (self.get(ref_fieldname),)))
-
 	def update_stock_ledger(self):
 		sl_entries = []
 		for d in self.get('items'):
@@ -512,6 +427,7 @@
 			(args.get('item_code')), as_dict = 1)
 		if not item:
 			frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get("item_code")))
+			
 		item = item[0]
 
 		ret = {
@@ -559,7 +475,7 @@
 
 			ret = {
 				"actual_qty" : get_previous_sle(args).get("qty_after_transaction") or 0,
-				"incoming_rate" : self.get_incoming_rate(args)
+				"incoming_rate" : get_incoming_rate(args)
 			}
 		return ret
 
@@ -736,15 +652,6 @@
 						if getdate(self.posting_date) > getdate(expiry_date):
 							frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code))
 
-@frappe.whitelist()
-def get_party_details(ref_dt, ref_dn):
-	if ref_dt in ["Delivery Note", "Sales Invoice"]:
-		res = frappe.db.get_value(ref_dt, ref_dn,
-			["customer", "customer_name", "address_display as customer_address"], as_dict=1)
-	else:
-		res = frappe.db.get_value(ref_dt, ref_dn,
-			["supplier", "supplier_name", "address_display as supplier_address"], as_dict=1)
-	return res or {}
 
 @frappe.whitelist()
 def get_production_order_details(production_order):
@@ -754,264 +661,3 @@
 		from `tabProduction Order` where name = %s""", production_order, as_dict=1)
 
 	return res and res[0] or {}
-
-def query_sales_return_doc(doctype, txt, searchfield, start, page_len, filters):
-	conditions = ""
-	if doctype == "Sales Invoice":
-		conditions = "and update_stock=1"
-
-	return frappe.db.sql("""select name, customer, customer_name
-		from `tab%s` where docstatus = 1
-			and (`%s` like %%(txt)s
-				or `customer` like %%(txt)s) %s %s
-		order by name, customer, customer_name
-		limit %s""" % (doctype, searchfield, conditions,
-		get_match_cond(doctype), "%(start)s, %(page_len)s"),
-		{"txt": "%%%s%%" % txt, "start": start, "page_len": page_len},
-		as_list=True)
-
-def query_purchase_return_doc(doctype, txt, searchfield, start, page_len, filters):
-	return frappe.db.sql("""select name, supplier, supplier_name
-		from `tab%s` where docstatus = 1
-			and (`%s` like %%(txt)s
-				or `supplier` like %%(txt)s) %s
-		order by name, supplier, supplier_name
-		limit %s""" % (doctype, searchfield, get_match_cond(doctype),
-		"%(start)s, %(page_len)s"),	{"txt": "%%%s%%" % txt, "start":
-		start, "page_len": page_len}, as_list=True)
-
-def query_return_item(doctype, txt, searchfield, start, page_len, filters):
-	txt = txt.replace("%", "")
-
-	ref = get_return_doc_and_details(filters)
-
-	stock_items = get_stock_items_for_return(ref.doc, ref.parentfields)
-
-	result = []
-	for item in ref.doc.get_all_children():
-		if getattr(item, "item_code", None) in stock_items:
-			item.item_name = cstr(item.item_name)
-			item.description = cstr(item.description)
-			if (txt in item.item_code) or (txt in item.item_name) or (txt in item.description):
-				val = [
-					item.item_code,
-					(len(item.item_name) > 40) and (item.item_name[:40] + "...") or item.item_name,
-					(len(item.description) > 40) and (item.description[:40] + "...") or \
-						item.description
-				]
-				if val not in result:
-					result.append(val)
-
-	return result[start:start+page_len]
-
-def get_stock_items_for_return(ref_doc, parentfields):
-	"""return item codes filtered from doc, which are stock items"""
-	if isinstance(parentfields, basestring):
-		parentfields = [parentfields]
-
-	all_items = list(set([d.item_code for d in
-		ref_doc.get_all_children() if d.get("item_code")]))
-	stock_items = frappe.db.sql_list("""select name from `tabItem`
-		where is_stock_item='Yes' and name in (%s)""" % (", ".join(["%s"] * len(all_items))),
-		tuple(all_items))
-
-	return stock_items
-
-def get_return_doc_and_details(args):
-	ref = frappe._dict()
-
-	# get ref_doc
-	if args.get("purpose") in return_map:
-		for fieldname, val in return_map[args.get("purpose")].items():
-			if args.get(fieldname):
-				ref.fieldname = fieldname
-				ref.doc = frappe.get_doc(val[0], args.get(fieldname))
-				ref.parentfields = val[1]
-				break
-
-	return ref
-
-return_map = {
-	"Sales Return": {
-		# [Ref DocType, [Item tables' parentfields]]
-		"delivery_note_no": ["Delivery Note", ["items", "packed_items"]],
-		"sales_invoice_no": ["Sales Invoice", ["items", "packed_items"]]
-	},
-	"Purchase Return": {
-		"purchase_receipt_no": ["Purchase Receipt", ["items"]]
-	}
-}
-
-@frappe.whitelist()
-def make_return_jv(stock_entry):
-	se = frappe.get_doc("Stock Entry", stock_entry)
-	if not se.purpose in ["Sales Return", "Purchase Return"]:
-		return
-
-	ref = get_return_doc_and_details(se)
-
-	if ref.doc.doctype == "Delivery Note":
-		result = make_return_jv_from_delivery_note(se, ref)
-	elif ref.doc.doctype == "Sales Invoice":
-		result = make_return_jv_from_sales_invoice(se, ref)
-	elif ref.doc.doctype == "Purchase Receipt":
-		result = make_return_jv_from_purchase_receipt(se, ref)
-
-	# create jv doc and fetch balance for each unique row item
-	jv = frappe.new_doc("Journal Entry")
-	jv.update({
-		"posting_date": se.posting_date,
-		"voucher_type": se.purpose == "Sales Return" and "Credit Note" or "Debit Note",
-		"fiscal_year": se.fiscal_year,
-		"company": se.company,
-		"stock_entry": se.name
-	})
-
-	from erpnext.accounts.utils import get_balance_on
-	for r in result:
-		jv.append("accounts", {
-			"account": r.get("account"),
-			"party_type": r.get("party_type"),
-			"party": r.get("party"),
-			"balance": get_balance_on(r.get("account"), se.posting_date) if r.get("account") else 0
-		})
-
-	return jv
-
-def make_return_jv_from_sales_invoice(se, ref):
-	# customer account entry
-	parent = {
-		"account": ref.doc.debit_to,
-		"party_type": "Customer",
-		"party": ref.doc.customer
-	}
-
-	# income account entries
-	children = []
-	for se_item in se.get("items"):
-		# find item in ref.doc
-		ref_item = ref.doc.get({"item_code": se_item.item_code})[0]
-
-		account = get_sales_account_from_item(ref.doc, ref_item)
-
-		if account not in children:
-			children.append(account)
-
-	return [parent] + [{"account": account} for account in children]
-
-def get_sales_account_from_item(doc, ref_item):
-	account = None
-	if not getattr(ref_item, "income_account", None):
-		if ref_item.parent_item:
-			parent_item = doc.get("items", {"item_code": ref_item.parent_item})[0]
-			account = parent_item.income_account
-	else:
-		account = ref_item.income_account
-
-	return account
-
-def make_return_jv_from_delivery_note(se, ref):
-	invoices_against_delivery = get_invoice_list("Sales Invoice Item", "delivery_note",
-		ref.doc.name)
-
-	if not invoices_against_delivery:
-		sales_orders_against_delivery = [d.against_sales_order for d in ref.doc.get_all_children() if getattr(d, "against_sales_order", None)]
-
-		if sales_orders_against_delivery:
-			invoices_against_delivery = get_invoice_list("Sales Invoice Item", "sales_order",
-				sales_orders_against_delivery)
-
-	if not invoices_against_delivery:
-		return []
-
-	packing_item_parent_map = dict([[d.item_code, d.parent_item] for d in ref.doc.get(ref.parentfields[1])])
-
-	parent = {}
-	children = []
-
-	for se_item in se.get("items"):
-		for sales_invoice in invoices_against_delivery:
-			si = frappe.get_doc("Sales Invoice", sales_invoice)
-
-			if se_item.item_code in packing_item_parent_map:
-				ref_item = si.get({"item_code": packing_item_parent_map[se_item.item_code]})
-			else:
-				ref_item = si.get({"item_code": se_item.item_code})
-
-			if not ref_item:
-				continue
-
-			ref_item = ref_item[0]
-
-			account = get_sales_account_from_item(si, ref_item)
-
-			if account not in children:
-				children.append(account)
-
-			if not parent:
-				parent = {
-					"account": si.debit_to,
-					"party_type": "Customer",
-					"party": si.customer
-				}
-
-			break
-
-	result = [parent] + [{"account": account} for account in children]
-
-	return result
-
-def get_invoice_list(doctype, link_field, value):
-	if isinstance(value, basestring):
-		value = [value]
-
-	return frappe.db.sql_list("""select distinct parent from `tab%s`
-		where docstatus = 1 and `%s` in (%s)""" % (doctype, link_field,
-			", ".join(["%s"]*len(value))), tuple(value))
-
-def make_return_jv_from_purchase_receipt(se, ref):
-	invoice_against_receipt = get_invoice_list("Purchase Invoice Item", "purchase_receipt",
-		ref.doc.name)
-
-	if not invoice_against_receipt:
-		purchase_orders_against_receipt = [d.prevdoc_docname for d in
-			ref.doc.get("items", {"prevdoc_doctype": "Purchase Order"})
-			if getattr(d, "prevdoc_docname", None)]
-
-		if purchase_orders_against_receipt:
-			invoice_against_receipt = get_invoice_list("Purchase Invoice Item", "purchase_order",
-				purchase_orders_against_receipt)
-
-	if not invoice_against_receipt:
-		return []
-
-	parent = {}
-	children = []
-
-	for se_item in se.get("items"):
-		for purchase_invoice in invoice_against_receipt:
-			pi = frappe.get_doc("Purchase Invoice", purchase_invoice)
-			ref_item = pi.get({"item_code": se_item.item_code})
-
-			if not ref_item:
-				continue
-
-			ref_item = ref_item[0]
-
-			account = ref_item.expense_account
-
-			if account not in children:
-				children.append(account)
-
-			if not parent:
-				parent = {
-					"account": pi.credit_to,
-					"party_type": "Supplier",
-					"party": pi.supplier
-				}
-
-			break
-
-	result = [parent] + [{"account": account} for account in children]
-
-	return result
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 70d6413..d283c3d 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -4,15 +4,12 @@
 from __future__ import unicode_literals
 import frappe, unittest
 import frappe.defaults
-from frappe.utils import flt, nowdate, nowtime, getdate
+from frappe.utils import flt, nowdate, nowtime
 from erpnext.stock.doctype.serial_no.serial_no import *
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
-	import set_perpetual_inventory, make_purchase_receipt
+	import set_perpetual_inventory
 from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
-from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice
 from erpnext.stock.stock_ledger import get_previous_sle
-from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so
-from erpnext.stock.doctype.stock_entry.stock_entry import make_return_jv, NotUpdateStockError
 from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
 
 def get_sle(**args):
@@ -303,263 +300,6 @@
 			self.assertEquals(expected_gl_entries[i][1], gle[1])
 			self.assertEquals(expected_gl_entries[i][2], gle[2])
 
-	def _test_sales_invoice_return(self, item_code, delivered_qty, returned_qty):
-		from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
-
-		si = create_sales_invoice(item_code=item_code, qty=delivered_qty)
-
-		se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=returned_qty,
-			purpose="Sales Return", sales_invoice_no=si.name, do_not_save=True)
-		self.assertRaises(NotUpdateStockError, se.insert)
-
-		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=200, incoming_rate=100)
-
-		# check currency available qty in bin
-		actual_qty_0 = get_qty_after_transaction()
-
-		# insert a pos invoice with update stock
-		si = create_sales_invoice(update_stock=1, item_code=item_code, qty=5)
-
-		# check available bin qty after invoice submission
-		actual_qty_1 = get_qty_after_transaction()
-
-		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1)
-
-		# check if item is validated
-		se = make_stock_entry(item_code="_Test Item Home Desktop 200", target="_Test Warehouse - _TC",
-			qty=returned_qty, purpose="Sales Return", sales_invoice_no=si.name, do_not_save=True)
-
-		self.assertRaises(frappe.DoesNotExistError, se.insert)
-
-		# try again
-		se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
-			qty=returned_qty, purpose="Sales Return", sales_invoice_no=si.name)
-
-		# check if available qty is increased
-		actual_qty_2 = get_qty_after_transaction()
-
-		self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2)
-
-		return se
-
-	def test_sales_invoice_return_of_non_packing_item(self):
-		self._test_sales_invoice_return("_Test Item", 5, 2)
-
-	def test_sales_invoice_return_of_packing_item(self):
-		self._test_sales_invoice_return("_Test Product Bundle Item", 25, 20)
-
-	def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty):
-		from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
-
-		from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
-
-		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100)
-
-		actual_qty_0 = get_qty_after_transaction()
-		# make a delivery note based on this invoice
-		dn = create_delivery_note(item_code="_Test Item",
-			warehouse="_Test Warehouse - _TC", qty=delivered_qty)
-
-		actual_qty_1 = get_qty_after_transaction()
-
-		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1)
-
-		si = make_sales_invoice(dn.name)
-		si.insert()
-		si.submit()
-
-		# insert and submit stock entry for sales return
-		se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
-			qty=returned_qty, purpose="Sales Return", delivery_note_no=dn.name)
-
-		actual_qty_2 = get_qty_after_transaction()
-		self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2)
-
-		return se
-
-	def test_delivery_note_return_of_non_packing_item(self):
-		self._test_delivery_note_return("_Test Item", 5, 2)
-
-	def test_delivery_note_return_of_packing_item(self):
-		self._test_delivery_note_return("_Test Product Bundle Item", 25, 20)
-
-	def _test_sales_return_jv(self, se):
-		jv = make_return_jv(se.name)
-
-		self.assertEqual(len(jv.get("accounts")), 2)
-		self.assertEqual(jv.get("voucher_type"), "Credit Note")
-		self.assertEqual(jv.get("posting_date"), getdate(se.posting_date))
-		self.assertEqual(jv.get("accounts")[0].get("account"), "Debtors - _TC")
-		self.assertEqual(jv.get("accounts")[0].get("party_type"), "Customer")
-		self.assertEqual(jv.get("accounts")[0].get("party"), "_Test Customer")
-		self.assertEqual(jv.get("accounts")[1].get("account"), "Sales - _TC")
-
-	def test_make_return_jv_for_sales_invoice_non_packing_item(self):
-		se = self._test_sales_invoice_return("_Test Item", 5, 2)
-		self._test_sales_return_jv(se)
-
-	def test_make_return_jv_for_sales_invoice_packing_item(self):
-		se = self._test_sales_invoice_return("_Test Product Bundle Item", 25, 20)
-		self._test_sales_return_jv(se)
-
-	def test_make_return_jv_for_delivery_note_non_packing_item(self):
-		se = self._test_delivery_note_return("_Test Item", 5, 2)
-		self._test_sales_return_jv(se)
-
-		se = self._test_delivery_note_return_against_sales_order("_Test Item", 5, 2)
-		self._test_sales_return_jv(se)
-
-	def test_make_return_jv_for_delivery_note_packing_item(self):
-		se = self._test_delivery_note_return("_Test Product Bundle Item", 25, 20)
-		self._test_sales_return_jv(se)
-
-		se = self._test_delivery_note_return_against_sales_order("_Test Product Bundle Item", 25, 20)
-		self._test_sales_return_jv(se)
-
-	def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty):
-		from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
-
-		actual_qty_0 = get_qty_after_transaction()
-
-		so = make_sales_order(qty=50)
-
-		dn = create_dn_against_so(so.name, delivered_qty)
-
-		actual_qty_1 = get_qty_after_transaction()
-		self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1)
-
-		si = make_sales_invoice(so.name)
-		si.insert()
-		si.submit()
-
-		# insert and submit stock entry for sales return
-		se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
-			qty=returned_qty, purpose="Sales Return", delivery_note_no=dn.name)
-
-		actual_qty_2 = get_qty_after_transaction()
-		self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2)
-
-		return se
-
-	def test_purchase_receipt_return(self):
-		actual_qty_0 = get_qty_after_transaction()
-
-		# submit purchase receipt
-		pr = make_purchase_receipt(item_code="_Test Item", warehouse="_Test Warehouse - _TC", qty=5)
-
-		actual_qty_1 = get_qty_after_transaction()
-
-		self.assertEquals(actual_qty_0 + 5, actual_qty_1)
-
-		pi_doc = make_purchase_invoice(pr.name)
-
-		pi = frappe.get_doc(pi_doc)
-		pi.posting_date = pr.posting_date
-		pi.credit_to = "_Test Payable - _TC"
-		for d in pi.get("items"):
-			d.expense_account = "_Test Account Cost for Goods Sold - _TC"
-			d.cost_center = "_Test Cost Center - _TC"
-
-		for d in pi.get("taxes"):
-			d.cost_center = "_Test Cost Center - _TC"
-
-		pi.insert()
-		pi.submit()
-
-		# submit purchase return
-		se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",
-			qty=5, purpose="Purchase Return", purchase_receipt_no=pr.name)
-
-		actual_qty_2 = get_qty_after_transaction()
-
-		self.assertEquals(actual_qty_1 - 5, actual_qty_2)
-
-		return se, pr.name
-
-	def test_over_stock_return(self):
-		from erpnext.stock.doctype.stock_entry.stock_entry import StockOverReturnError
-
-		# out of 10, 5 gets returned
-		prev_se, pr_docname = self.test_purchase_receipt_return()
-
-		se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",
-			qty=6, purpose="Purchase Return", purchase_receipt_no=pr_docname, do_not_save=True)
-
-		self.assertRaises(StockOverReturnError, se.insert)
-
-	def _test_purchase_return_jv(self, se):
-		jv = make_return_jv(se.name)
-
-		self.assertEqual(len(jv.get("accounts")), 2)
-		self.assertEqual(jv.get("voucher_type"), "Debit Note")
-		self.assertEqual(jv.get("posting_date"), getdate(se.posting_date))
-		self.assertEqual(jv.get("accounts")[0].get("account"), "_Test Payable - _TC")
-		self.assertEqual(jv.get("accounts")[0].get("party"), "_Test Supplier")
-		self.assertEqual(jv.get("accounts")[1].get("account"), "_Test Account Cost for Goods Sold - _TC")
-
-	def test_make_return_jv_for_purchase_receipt(self):
-		se, pr_name = self.test_purchase_receipt_return()
-		self._test_purchase_return_jv(se)
-
-		se, pr_name = self._test_purchase_return_return_against_purchase_order()
-		self._test_purchase_return_jv(se)
-
-	def _test_purchase_return_return_against_purchase_order(self):
-
-		actual_qty_0 = get_qty_after_transaction()
-
-		from erpnext.buying.doctype.purchase_order.test_purchase_order \
-			import test_records as purchase_order_test_records
-
-		from erpnext.buying.doctype.purchase_order.purchase_order import \
-			make_purchase_receipt, make_purchase_invoice
-
-		# submit purchase receipt
-		po = frappe.copy_doc(purchase_order_test_records[0])
-		po.transaction_date = nowdate()
-		po.is_subcontracted = None
-		po.get("items")[0].item_code = "_Test Item"
-		po.get("items")[0].rate = 50
-		po.insert()
-		po.submit()
-
-		pr_doc = make_purchase_receipt(po.name)
-
-		pr = frappe.get_doc(pr_doc)
-		pr.posting_date = po.transaction_date
-		pr.insert()
-		pr.submit()
-
-		actual_qty_1 = get_qty_after_transaction()
-
-		self.assertEquals(actual_qty_0 + 10, actual_qty_1)
-
-		pi_doc = make_purchase_invoice(po.name)
-
-		pi = frappe.get_doc(pi_doc)
-		pi.posting_date = pr.posting_date
-		pi.credit_to = "_Test Payable - _TC"
-		for d in pi.get("items"):
-			d.expense_account = "_Test Account Cost for Goods Sold - _TC"
-			d.cost_center = "_Test Cost Center - _TC"
-		for d in pi.get("taxes"):
-			d.cost_center = "_Test Cost Center - _TC"
-
-		pi.run_method("calculate_taxes_and_totals")
-		pi.bill_no = "NA"
-		pi.insert()
-		pi.submit()
-
-		# submit purchase return
-		se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",
-			qty=5, purpose="Purchase Return", purchase_receipt_no=pr.name)
-
-		actual_qty_2 = get_qty_after_transaction()
-
-		self.assertEquals(actual_qty_1 - 5, actual_qty_2)
-
-		return se, pr.name
-
 	def test_serial_no_not_reqd(self):
 		se = frappe.copy_doc(test_records[0])
 		se.get("items")[0].serial_no = "ABCD"
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index 780bcc9..bb6f409 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
@@ -151,6 +151,15 @@
    "read_only": 1
   }, 
   {
+   "fieldname": "outgoing_rate", 
+   "fieldtype": "Currency", 
+   "label": "Outgoing Rate", 
+   "options": "Company:company:default_currency", 
+   "permlevel": 0, 
+   "precision": "", 
+   "read_only": 1
+  }, 
+  {
    "fieldname": "stock_uom", 
    "fieldtype": "Link", 
    "label": "Stock UOM", 
@@ -266,7 +275,7 @@
  "icon": "icon-list", 
  "idx": 1, 
  "in_create": 1, 
- "modified": "2015-07-13 05:28:27.826340", 
+ "modified": "2015-07-16 16:37:54.452944", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Stock Ledger Entry", 
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index eaa82dd..dde3386 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -107,8 +107,6 @@
 		"valuation_rate": args.rate
 	})
 
-	sr.insert()
-
 	sr.submit()
 	return sr
 
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 954a03b..a5deb30 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -109,7 +109,7 @@
 	def build(self):
 		# includes current entry!
 		entries_to_fix = self.get_sle_after_datetime()
-
+		
 		for sle in entries_to_fix:
 			self.process_sle(sle)
 
@@ -230,19 +230,21 @@
 					self.valuation_rate = new_stock_value / new_stock_qty
 
 	def get_moving_average_values(self, sle):
-		incoming_rate = flt(sle.incoming_rate)
 		actual_qty = flt(sle.actual_qty)
-
-		if flt(sle.actual_qty) > 0:
+		
+		if actual_qty > 0 or flt(sle.outgoing_rate) > 0:
+			rate = flt(sle.incoming_rate) if actual_qty > 0 else flt(sle.outgoing_rate)
+			
 			if self.qty_after_transaction < 0 and not self.valuation_rate:
 				# if negative stock, take current valuation rate as incoming rate
-				self.valuation_rate = incoming_rate
+				self.valuation_rate = rate
 
 			new_stock_qty = abs(self.qty_after_transaction) + actual_qty
-			new_stock_value = (abs(self.qty_after_transaction) * self.valuation_rate) + (actual_qty * incoming_rate)
+			new_stock_value = (abs(self.qty_after_transaction) * self.valuation_rate) + (actual_qty * rate)
 
 			if new_stock_qty:
 				self.valuation_rate = new_stock_value / flt(new_stock_qty)
+							
 		elif not self.valuation_rate and self.qty_after_transaction <= 0:
 			self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse, self.allow_zero_rate)
 
@@ -251,6 +253,7 @@
 	def get_fifo_values(self, sle):
 		incoming_rate = flt(sle.incoming_rate)
 		actual_qty = flt(sle.actual_qty)
+		outgoing_rate = flt(sle.outgoing_rate)
 
 		if actual_qty > 0:
 			if not self.stock_queue:
@@ -278,16 +281,34 @@
 						_rate = 0
 					self.stock_queue.append([0, _rate])
 
-				batch = self.stock_queue[0]
+				index = None
+				if outgoing_rate > 0:
+					# Find the entry where rate matched with outgoing rate
+					for i, v in enumerate(self.stock_queue):
+						if v[1] == outgoing_rate:
+							index = i
+							break
+							
+					# If no entry found with outgoing rate, collapse stack
+					if index == None:
+						new_stock_value = sum((d[0]*d[1] for d in self.stock_queue)) - qty_to_pop*outgoing_rate
+						new_stock_qty = sum((d[0] for d in self.stock_queue)) - qty_to_pop
+						self.stock_queue = [[new_stock_qty, new_stock_value/new_stock_qty if new_stock_qty > 0 else outgoing_rate]]
+						break
+				else:
+					index = 0
+
+				# select first batch or the batch with same rate
+				batch = self.stock_queue[index]
 
 				if qty_to_pop >= batch[0]:
 					# consume current batch
 					qty_to_pop = qty_to_pop - batch[0]
-					self.stock_queue.pop(0)
+					self.stock_queue.pop(index)
 					if not self.stock_queue and qty_to_pop:
 						# stock finished, qty still remains to be withdrawn
 						# negative stock, keep in as a negative batch
-						self.stock_queue.append([-qty_to_pop, batch[1]])
+						self.stock_queue.append([-qty_to_pop, outgoing_rate or batch[1]])
 						break
 
 				else:
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 50b0319..6c9b9a4 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -3,12 +3,12 @@
 
 from __future__ import unicode_literals
 import frappe
+import frappe.share
 from frappe import _
 from frappe.utils import cstr, now_datetime, cint, flt
-import frappe.share
-
 from erpnext.controllers.status_updater import StatusUpdater
 
+class UOMMustBeIntegerError(frappe.ValidationError): pass
 
 class TransactionBase(StatusUpdater):
 	def load_notification_message(self):
@@ -109,8 +109,6 @@
 	frappe.delete_doc("Event", frappe.db.sql_list("""select name from `tabEvent`
 		where ref_type=%s and ref_name=%s""", (ref_type, ref_name)), for_reload=True)
 
-class UOMMustBeIntegerError(frappe.ValidationError): pass
-
 def validate_uom_is_integer(doc, uom_field, qty_fields, child_dt=None):
 	if isinstance(qty_fields, basestring):
 		qty_fields = [qty_fields]