[fix] Cleanup and fixes in update stock feature in Purchase Invoice
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 6d137a5..5af3e82 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -15,30 +15,30 @@
 				this.frm.set_df_property("credit_to", "print_hide", 0);
 			}
 		}
-		
-		hide_fields(this.frm.doc);
 	},
 
 	refresh: function(doc) {
 		this._super();
+		
+		hide_fields(this.frm.doc);
 
 		// Show / Hide button
 		this.show_general_ledger();
+		
+		if(doc.update_stock==1 && doc.docstatus==1) {
+			this.show_stock_ledger();
+		}
 
 		if(!doc.is_return && doc.docstatus==1) {
 			if(doc.outstanding_amount > 0) {
 				this.frm.add_custom_button(__('Payment'), this.make_bank_entry, __("Make"));
 				cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
 			}
-				
+			
 			if(doc.outstanding_amount >= 0 || Math.abs(flt(doc.outstanding_amount)) < flt(doc.grand_total)) {
 				cur_frm.add_custom_button(doc.update_stock ? __('Purchase Return') : __('Debit Note'), 
 					this.make_debit_note, __("Make"));
 			}
-			
-			if(doc.update_stock==1) {
-				this.show_stock_ledger();
-			}
 		}
 		
 		if(doc.docstatus===0) {
@@ -69,6 +69,8 @@
 				})
 			}, __("Get items from"));
 		}
+		
+		this.frm.toggle_reqd("supplier_warehouse", this.frm.doc.is_subcontracted==="Yes");
 	},
 
 	supplier: function() {
@@ -326,3 +328,29 @@
 	else
 		cur_frm.pformat.print_heading = __("Purchase Invoice");
 }
+
+frappe.ui.form.on("Purchase Invoice", {
+	onload: function(frm) {
+		$.each(["warehouse", "rejected_warehouse"], function(i, field) {
+			frm.set_query(field, "items", function() {
+				return {
+					filters: [["Warehouse", "company", "in", ["", cstr(frm.doc.company)]]]
+				}
+			})
+		})
+
+		frm.set_query("supplier_warehouse", function() {
+			return {
+				filters: [["Warehouse", "company", "in", ["", cstr(frm.doc.company)]]]
+			}
+		})
+	},
+	
+	is_subcontracted: function(frm) {
+		if (frm.doc.is_subcontracted === "Yes") {
+			erpnext.buying.get_default_bom(frm);
+		}
+		frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted==="Yes");
+	}
+})
+	
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 81d3867..43d14ed 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe.utils import cint, formatdate, flt, getdate
-from frappe import msgprint, _, throw
+from frappe import _, throw
 from erpnext.setup.utils import get_company_currency
 import frappe.defaults
 
@@ -13,7 +13,8 @@
 from erpnext.accounts.utils import get_account_currency, get_fiscal_year
 from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po
 from erpnext.controllers.stock_controller import get_warehouse_account
-
+from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
+from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
 
 form_grid_templates = {
 	"items": "templates/form_grid/item_grid.html"
@@ -51,7 +52,6 @@
 		if (self.is_paid == 1):
 			self.validate_cash()
 
-		self.check_active_purchase_items()
 		self.check_conversion_rate()
 		self.validate_credit_to_acc()
 		self.clear_unallocated_advances("Purchase Invoice Advance", "advances")
@@ -61,7 +61,6 @@
 		self.set_expense_account()
 		self.set_against_expense_account()
 		self.validate_write_off_account()
-		self.update_valuation_rate("items")
 		self.validate_multiple_billing("Purchase Receipt", "pr_detail", "amount", "items")
 		self.validate_fixed_asset_account()
 		self.create_remarks()
@@ -177,7 +176,6 @@
 				else:
 					item.expense_account = stock_not_billed_account
 					
-				item.cost_center = None
 			elif not item.expense_account:
 				throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name))
 
@@ -281,35 +279,38 @@
 			}
 		])
 	
-	def validate_purchase_receipt(self):
-		for item in self.get("items"):
-			if item.purchase_receipt:
-				frappe.throw(_("Stock cannot be updated against Purchase Receipt {0}").format(item.purchase_receipt))
+	def validate_purchase_receipt_if_update_stock(self):
+		if self.update_stock:
+			for item in self.get("items"):
+				if item.purchase_receipt:
+					frappe.throw(_("Stock cannot be updated against Purchase Receipt {0}")
+						.format(item.purchase_receipt))
 
 	def on_submit(self):
 		self.check_prev_docstatus()
+		self.update_status_updater_args()
+		
 		self.validate_asset()
 
 		frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
 			self.company, self.base_grand_total)
-
-		if (self.update_stock == 1):
-			# from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_stock_ledger
-			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")
-			self.update_status_updater_args()
-			self.update_prevdoc_status()
-
-		# this sequence because outstanding may get -negative
-		self.make_gl_entries()
-		
+			
 		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_billing_status_in_pr()
 
+		# Updating stock ledger should always be called after updating prevdoc status, 
+		# because updating ordered qty in bin depends upon updated ordered qty in PO
+		if self.update_stock == 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")
+			
+		# this sequence because outstanding may get -negative
+		self.make_gl_entries()
+
 		self.update_project()
 		
 	def validate_asset(self):
@@ -353,38 +354,32 @@
 		self.make_item_gl_entries(gl_entries)
 		self.make_tax_gl_entries(gl_entries)
 		
-		from erpnext.accounts.general_ledger import merge_similar_entries
 		gl_entries = merge_similar_entries(gl_entries)
 		
 		self.make_payment_gl_entries(gl_entries)
 
 		self.make_write_off_gl_entry(gl_entries)
+		
 		if gl_entries:
-			from erpnext.accounts.general_ledger import make_gl_entries
 			update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
 			
 			make_gl_entries(gl_entries,  cancel=(self.docstatus == 2),
 				update_outstanding=update_outstanding, merge_entries=False)
 			
 			if update_outstanding == "No":
-				from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
 				update_outstanding_amt(self.credit_to, "Supplier", self.supplier,
 					self.doctype, self.return_against if cint(self.is_return) else self.name)
 
-			if repost_future_gle and cint(self.update_stock) \
-				and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
-					from erpnext.controllers.stock_controller import update_gl_entries_after
-					items, warehouses = self.get_items_and_warehouses()
-					update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items)
+			if repost_future_gle and cint(self.update_stock) and self.auto_accounting_for_stock:
+				from erpnext.controllers.stock_controller import update_gl_entries_after
+				items, warehouses = self.get_items_and_warehouses()
+				update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items)
 					
-		elif self.docstatus == 2 and cint(self.update_stock) \
-			and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
-				from erpnext.accounts.general_ledger import delete_gl_entries
-				delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
+		elif self.docstatus == 2 and cint(self.update_stock) and self.auto_accounting_for_stock:
+			delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
 		
 
 	def make_supplier_gl_entry(self, gl_entries):
-		# parent's gl entry
 		if self.grand_total:
 			# Didnot use base_grand_total to book rounding loss gle
 			grand_total_in_company_currency = flt(self.grand_total * self.conversion_rate,
@@ -406,21 +401,62 @@
 	def make_item_gl_entries(self, gl_entries):
 		# item gl entries
 		stock_items = self.get_stock_items()
+		expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
+		warehouse_account = get_warehouse_account()
 		
 		for item in self.get("items"):
 			if flt(item.base_net_amount):
 				account_currency = get_account_currency(item.expense_account)
 				
-				gl_entries.append(
-					self.get_gl_dict({
-						"account": item.expense_account,
-						"against": self.supplier,
-						"debit": item.base_net_amount,
-						"debit_in_account_currency": item.base_net_amount \
-							if account_currency==self.company_currency else item.net_amount,
-						"cost_center": item.cost_center
-					}, account_currency)
-				)
+				if self.update_stock and self.auto_accounting_for_stock:
+					val_rate_db_precision = 6 if cint(item.precision("valuation_rate")) <= 6 else 9
+
+					# warehouse account
+					warehouse_debit_amount = flt(flt(item.valuation_rate, val_rate_db_precision) 
+						* flt(item.qty)	* flt(item.conversion_factor), item.precision("base_net_amount"))
+						
+					gl_entries.append(
+						self.get_gl_dict({
+							"account": item.expense_account,
+							"against": self.supplier,
+							"debit": warehouse_debit_amount,
+							"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+							"cost_center": item.cost_center
+						}, account_currency)
+					)
+					
+					# Amount added through landed-cost-voucher
+					if flt(item.landed_cost_voucher_amount):
+						gl_entries.append(self.get_gl_dict({
+							"account": expenses_included_in_valuation,
+							"against": item.expense_account,
+							"cost_center": item.cost_center,
+							"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+							"credit": flt(item.landed_cost_voucher_amount)
+						}))
+
+					# sub-contracting warehouse
+					if flt(item.rm_supp_cost):
+						supplier_warehouse_account = warehouse_account[self.supplier_warehouse]["name"]
+						gl_entries.append(self.get_gl_dict({
+							"account": supplier_warehouse_account,
+							"against": item.expense_account,
+							"cost_center": item.cost_center,
+							"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+							"credit": flt(item.rm_supp_cost)
+						}, warehouse_account[self.supplier_warehouse]["account_currency"]))
+				else:
+					gl_entries.append(
+						self.get_gl_dict({
+							"account": item.expense_account,
+							"against": self.supplier,
+							"debit": flt(item.base_net_amount, item.precision("base_net_amount")),
+							"debit_in_account_currency": (flt(item.base_net_amount, 
+								item.precision("base_net_amount")) if account_currency==self.company_currency 
+								else flt(item.net_amount, item.precision("net_amount"))),
+							"cost_center": item.cost_center
+						}, account_currency)
+					)
 				
 			if self.auto_accounting_for_stock and self.is_opening == "No" and \
 				item.item_code in stock_items and item.item_tax_amount:
@@ -435,13 +471,13 @@
 								self.get_gl_dict({
 									"account": self.stock_received_but_not_billed,
 									"against": self.supplier,
-									"debit": flt(item.item_tax_amount, self.precision("item_tax_amount", item)),
+									"debit": flt(item.item_tax_amount, item.precision("item_tax_amount")),
 									"remarks": self.remarks or "Accounting Entry for Stock"
 								})
 							)
 
 							self.negative_expense_to_be_booked += flt(item.item_tax_amount, \
-								self.precision("item_tax_amount", item))
+								item.precision("item_tax_amount"))
 
 	def make_tax_gl_entries(self, gl_entries):
 		# tax table gl entries
@@ -558,7 +594,9 @@
 
 	def on_cancel(self):
 		self.check_for_closed_status()
-
+		
+		self.update_status_updater_args()
+		
 		if not self.is_return:
 			from erpnext.accounts.utils import remove_against_link_from_jv
 			remove_against_link_from_jv(self.doctype, self.name)
@@ -567,6 +605,11 @@
 			self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
 			self.update_billing_status_in_pr()
 
+		# Updating stock ledger should always be called after updating prevdoc status, 
+		# because updating ordered qty in bin depends upon updated ordered qty in PO
+		if self.update_stock == 1:
+			self.update_stock_ledger()
+			
 		self.make_gl_entries_on_cancel()
 		self.update_project()
 		self.validate_asset()
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index c069174..9afcd21 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -6,7 +6,7 @@
 import unittest
 import frappe
 import frappe.model
-from frappe.utils import cint
+from frappe.utils import cint, flt
 import frappe.defaults
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
 	test_records as pr_test_records
@@ -120,20 +120,20 @@
 		set_perpetual_inventory(0)
 
 	def test_purchase_invoice_calculation(self):
-		wrapper = frappe.copy_doc(test_records[0])
-		wrapper.insert()
-		wrapper.load_from_db()
+		pi = frappe.copy_doc(test_records[0])
+		pi.insert()
+		pi.load_from_db()
 
 		expected_values = [
 			["_Test Item Home Desktop 100", 90, 59],
 			["_Test Item Home Desktop 200", 135, 177]
 		]
-		for i, item in enumerate(wrapper.get("items")):
+		for i, item in enumerate(pi.get("items")):
 			self.assertEqual(item.item_code, expected_values[i][0])
 			self.assertEqual(item.item_tax_amount, expected_values[i][1])
 			self.assertEqual(item.valuation_rate, expected_values[i][2])
 
-		self.assertEqual(wrapper.base_net_total, 1250)
+		self.assertEqual(pi.base_net_total, 1250)
 
 		# tax amounts
 		expected_values = [
@@ -147,7 +147,7 @@
 			["_Test Account Discount - _TC", 168.03, 1512.30],
 		]
 
-		for i, tax in enumerate(wrapper.get("taxes")):
+		for i, tax in enumerate(pi.get("taxes")):
 			self.assertEqual(tax.account_head, expected_values[i][0])
 			self.assertEqual(tax.tax_amount, expected_values[i][1])
 			self.assertEqual(tax.total, expected_values[i][2])
@@ -375,8 +375,28 @@
 		pi1 = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2, rate=50, update_stock=1)
 
 		actual_qty_2 = get_qty_after_transaction()
-
 		self.assertEquals(actual_qty_1 - 2, actual_qty_2)
+		
+		pi1.cancel()
+		self.assertEquals(actual_qty_1, get_qty_after_transaction())
+		
+		pi.cancel()
+		self.assertEquals(actual_qty_0, get_qty_after_transaction())
+		
+	def test_subcontracting_via_purchase_invoice(self):
+		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+		
+		make_stock_entry(item_code="_Test Item", target="_Test Warehouse 1 - _TC", qty=100, basic_rate=100)
+		make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse 1 - _TC", 
+			qty=100, basic_rate=100)
+		
+		pi = make_purchase_invoice(item_code="_Test FG Item", qty=10, rate=500, 
+			update_stock=1, is_subcontracted="Yes")
+		
+		self.assertEquals(len(pi.get("supplied_items")), 2)
+		
+		rm_supp_cost = sum([d.amount for d in pi.get("supplied_items")])
+		self.assertEquals(pi.get("items")[0].rm_supp_cost, flt(rm_supp_cost, 2))
 
 def make_purchase_invoice(**args):
 	pi = frappe.new_doc("Purchase Invoice")
@@ -389,6 +409,7 @@
 		pi.update_stock = 1
 	if args.is_paid:
 		pi.is_paid = 1
+		
 	if args.cash_bank_account:
 		pi.cash_bank_account=args.cash_bank_account
 		
@@ -398,6 +419,8 @@
 	pi.conversion_rate = args.conversion_rate or 1
 	pi.is_return = args.is_return
 	pi.return_against = args.return_against
+	pi.is_subcontracted = args.is_subcontracted
+	pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
 
 	pi.append("items", {
 		"item_code": args.item or args.item_code or "_Test Item",
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_records.json b/erpnext/accounts/doctype/purchase_invoice/test_records.json
index 4218828..7feca23 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_records.json
+++ b/erpnext/accounts/doctype/purchase_invoice/test_records.json
@@ -22,7 +22,8 @@
     "parentfield": "items",
     "qty": 10,
     "rate": 50,
-    "uom": "_Test UOM"
+    "uom": "_Test UOM",
+	"warehouse": "_Test Warehouse - _TC"
    },
    {
     "amount": 750,
@@ -37,7 +38,8 @@
     "parentfield": "items",
     "qty": 5,
     "rate": 150,
-    "uom": "_Test UOM"
+    "uom": "_Test UOM",
+	"warehouse": "_Test Warehouse - _TC"
    }
   ],
   "grand_total": 0,
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 265c38b..53747bf 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -81,14 +81,10 @@
 		self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items")
 		self.update_packing_list()
 
-	def on_submit(self):
-		if cint(self.update_stock) == 1:
-			self.update_stock_ledger()
-		else:
-			# Check for Approving Authority
-			if not self.recurring_id:
-				frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
-				 	self.company, self.base_grand_total, self)
+	def on_submit(self):			
+		if not self.recurring_id:
+			frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
+			 	self.company, self.base_grand_total, self)
 
 		self.check_prev_docstatus()
 
@@ -99,7 +95,12 @@
 		self.update_status_updater_args()
 		self.update_prevdoc_status()
 		self.update_billing_status_in_dn()
-
+		
+		# Updating stock ledger should always be called after updating prevdoc status, 
+		# because updating reserved qty in bin depends upon updated delivered qty in SO
+		if self.update_stock == 1:
+			self.update_stock_ledger()
+		
 		# this sequence because outstanding may get -ve
 		self.make_gl_entries()
 
@@ -117,9 +118,6 @@
 		self.update_time_log_batch(None)
 
 	def on_cancel(self):
-		if cint(self.update_stock) == 1:
-			self.update_stock_ledger()
-
 		self.check_close_sales_order("sales_order")
 
 		from erpnext.accounts.utils import remove_against_link_from_jv
@@ -137,6 +135,11 @@
 			self.update_billing_status_for_zero_amount_refdoc("Sales Order")
 
 		self.validate_c_form_on_cancel()
+		
+		# Updating stock ledger should always be called after updating prevdoc status, 
+		# because updating reserved qty in bin depends upon updated delivered qty in SO
+		if self.update_stock == 1:
+			self.update_stock_ledger()
 
 		self.make_gl_entries_on_cancel()
 
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 94dd070..c24bcdc 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -45,6 +45,32 @@
 
 		po.load_from_db()
 		self.assertEquals(po.get("items")[0].received_qty, 4)
+		
+	def test_ordered_qty_against_pi_with_update_stock(self):
+		existing_ordered_qty = get_ordered_qty()
+
+		po = create_purchase_order()
+		
+		self.assertEqual(get_ordered_qty(), existing_ordered_qty + 10)
+
+		frappe.db.set_value('Item', '_Test Item', 'tolerance', 50)
+
+		pi = make_purchase_invoice(po.name)
+		pi.update_stock = 1
+		pi.items[0].qty = 12
+		pi.insert()
+		pi.submit()
+		
+		self.assertEqual(get_ordered_qty(), existing_ordered_qty)
+
+		po.load_from_db()
+		self.assertEquals(po.get("items")[0].received_qty, 12)
+
+		pi.cancel()
+		self.assertEqual(get_ordered_qty(), existing_ordered_qty + 10)
+
+		po.load_from_db()
+		self.assertEquals(po.get("items")[0].received_qty, 0)
 
 	def test_make_purchase_invoice(self):
 		po = create_purchase_order(do_not_submit=True)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 7691ff5..594a576 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -146,14 +146,6 @@
 		"""set missing item values"""
 		from erpnext.stock.get_item_details import get_item_details
 
-		if self.doctype == "Purchase Invoice":
-			auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
-
-			if auto_accounting_for_stock:
-				stock_not_billed_account = self.get_company_default("stock_received_but_not_billed")
-
-			stock_items = self.get_stock_items()
-
 		if hasattr(self, "items"):
 			parent_dict = {}
 			for fieldname in self.meta.get_valid_columns():
@@ -200,14 +192,8 @@
 							item.rate = flt(item.price_list_rate *
 								(1.0 - (flt(item.discount_percentage) / 100.0)), item.precision("rate"))
 
-					if self.doctype == "Purchase Invoice":
-						if auto_accounting_for_stock and item.item_code in stock_items \
-							and self.is_opening == 'No' \
-							and (not item.po_detail or not frappe.db.get_value("Purchase Order Item",
-								item.po_detail, "delivered_by_supplier")):
-
-								item.expense_account = stock_not_billed_account
-								item.cost_center = None
+			if self.doctype == "Purchase Invoice":
+				self.set_expense_account()
 
 	def set_taxes(self):
 		if not self.meta.get_field("taxes"):
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 9c9f1c3..74a3d69 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -33,10 +33,10 @@
 		self.validate_stock_or_nonstock_items()
 		self.validate_warehouse()
 		
-		if self.doctype=="Purchase Invoice" and getattr(self, "update_stock"):
-			self.validate_purchase_receipt()
+		if self.doctype=="Purchase Invoice":
+			self.validate_purchase_receipt_if_update_stock()
 		
-		if self.doctype=="Purchase Receipt" or (self.doctype=="Purchase Invoice" and getattr(self, "update_stock")):
+		if self.doctype=="Purchase Receipt" or (self.doctype=="Purchase Invoice" and self.update_stock):
 			self.validate_purchase_return()
 			self.validate_rejected_warehouse()
 			self.validate_accepted_rejected_qty()
@@ -48,11 +48,13 @@
 			self.validate_for_subcontracting()
 			self.create_raw_materials_supplied("supplied_items")
 			self.set_landed_cost_voucher_amount()
+		
+		if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
 			self.update_valuation_rate("items")
 
 	def set_missing_values(self, for_validate=False):
 		super(BuyingController, self).set_missing_values(for_validate)
-
+		
 		self.set_supplier_from_item_default()
 		self.set_price_list_currency("Buying")
 
@@ -118,7 +120,6 @@
 			if item.item_code and item.qty and item.item_code in stock_items:
 				item_proportion = flt(item.base_net_amount) / stock_items_amount if stock_items_amount \
 					else flt(item.qty) / stock_items_qty
-
 				if i == (last_stock_item_idx - 1):
 					item.item_tax_amount = flt(valuation_amount_adjustment,
 						self.precision("item_tax_amount", item))
@@ -229,7 +230,7 @@
 			rm.amount = required_qty * flt(rm.rate)
 			raw_materials_cost += flt(rm.amount)
 
-		if self.doctype == "Purchase Receipt":
+		if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
 			item.rm_supp_cost = raw_materials_cost
 
 	def cleanup_raw_materials_supplied(self, parent_items, raw_material_table):
@@ -319,6 +320,8 @@
 				frappe.throw(_("Accepted + Rejected Qty must be equal to Received quantity for Item {0}").format(d.item_code))
 	
 	def update_stock_ledger(self, allow_negative_stock=False, via_landed_cost_voucher=False):
+		self.update_ordered_qty()
+		
 		sl_entries = []
 		stock_items = self.get_stock_items()
 
@@ -354,6 +357,26 @@
 		self.make_sl_entries_for_supplier_warehouse(sl_entries)
 		self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock,
 			via_landed_cost_voucher=via_landed_cost_voucher)
+			
+	def update_ordered_qty(self):
+		po_map = {}
+		for d in self.get("items"):
+			if self.doctype=="Purchase Receipt" \
+				and d.prevdoc_doctype=="Purchase Order" and d.prevdoc_detail_docname:
+					po_map.setdefault(d.prevdoc_docname, []).append(d.prevdoc_detail_docname)
+			
+			elif self.doctype=="Purchase Invoice" and d.purchase_order and d.po_detail:
+				po_map.setdefault(d.purchase_order, []).append(d.po_detail)
+
+		for po, po_item_rows in po_map.items():
+			if po and po_item_rows:
+				po_obj = frappe.get_doc("Purchase Order", po)
+
+				if po_obj.status in ["Closed", "Cancelled"]:
+					frappe.throw(_("{0} {1} is cancelled or closed").format(_("Purchase Order"), po),
+						frappe.InvalidStatusError)
+
+				po_obj.update_ordered_qty(po_item_rows)
 	
 	def make_sl_entries_for_supplier_warehouse(self, sl_entries):
 		if hasattr(self, 'supplied_items'):
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 3c9efa1..b9b94f5 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -7,6 +7,7 @@
 from erpnext.setup.utils import get_company_currency
 from frappe import _, throw
 from erpnext.stock.get_item_details import get_bin_details
+from erpnext.stock.utils import get_incoming_rate
 
 from erpnext.controllers.stock_controller import StockController
 
@@ -228,6 +229,79 @@
 				status = frappe.db.get_value("Sales Order", d.get(ref_fieldname), "status")
 				if status == "Closed":
 					frappe.throw(_("Sales Order {0} is {1}").format(d.get(ref_fieldname), status))
+					
+	def update_reserved_qty(self):
+		so_map = {}
+		for d in self.get("items"):
+			if d.so_detail:
+				if self.doctype == "Delivery Note" and d.against_sales_order:
+					so_map.setdefault(d.against_sales_order, []).append(d.so_detail)
+				elif self.doctype == "Sales Invoice" and d.sales_order and self.update_stock:
+					so_map.setdefault(d.sales_order, []).append(d.so_detail)
+
+		for so, so_item_rows in so_map.items():
+			if so and so_item_rows:
+				sales_order = frappe.get_doc("Sales Order", so)
+
+				if sales_order.status in ["Closed", "Cancelled"]:
+					frappe.throw(_("{0} {1} is cancelled or closed").format(_("Sales Order"), so),
+						frappe.InvalidStatusError)
+
+				sales_order.update_reserved_qty(so_item_rows)
+
+	def update_stock_ledger(self):
+		self.update_reserved_qty()
+
+		sl_entries = []
+		for d in self.get_item_list():
+			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty):
+				return_rate = 0
+				if cint(self.is_return) and self.return_against and self.docstatus==1:
+					return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
+
+				# On cancellation or if return entry submission, make stock ledger entry for
+				# target warehouse first, to update serial no values properly
+
+				if d.warehouse and ((not cint(self.is_return) and self.docstatus==1)
+					or (cint(self.is_return) and self.docstatus==2)):
+						sl_entries.append(self.get_sl_entries(d, {
+							"actual_qty": -1*flt(d.qty),
+							"incoming_rate": return_rate
+						}))
+
+				if d.target_warehouse:
+					target_warehouse_sle = self.get_sl_entries(d, {
+						"actual_qty": flt(d.qty),
+						"warehouse": d.target_warehouse
+					})
+
+					if self.docstatus == 1:
+						if not cint(self.is_return):
+							args = frappe._dict({
+								"item_code": d.item_code,
+								"warehouse": d.warehouse,
+								"posting_date": self.posting_date,
+								"posting_time": self.posting_time,
+								"qty": -1*flt(d.qty),
+								"serial_no": d.serial_no
+							})
+							target_warehouse_sle.update({
+								"incoming_rate": get_incoming_rate(args)
+							})
+						else:
+							target_warehouse_sle.update({
+								"outgoing_rate": return_rate
+							})
+					sl_entries.append(target_warehouse_sle)
+
+				if d.warehouse and ((not cint(self.is_return) and self.docstatus==2)
+					or (cint(self.is_return) and self.docstatus==1)):
+						sl_entries.append(self.get_sl_entries(d, {
+							"actual_qty": -1*flt(d.qty),
+							"incoming_rate": return_rate
+						}))
+
+		self.make_sl_entries(sl_entries)
 
 def check_active_sales_items(obj):
 	for d in obj.get("items"):
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index bd1f258..845a4d0 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -8,8 +8,6 @@
 import frappe.defaults
 from erpnext.accounts.utils import get_fiscal_year
 from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
-from erpnext.stock.utils import get_incoming_rate
-
 from erpnext.controllers.accounts_controller import AccountsController
 
 class StockController(AccountsController):
@@ -230,79 +228,6 @@
 			incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
 
 		return incoming_rate
-
-	def update_reserved_qty(self):
-		so_map = {}
-		for d in self.get("items"):
-			if d.so_detail:
-				if self.doctype == "Delivery Note" and d.against_sales_order:
-					so_map.setdefault(d.against_sales_order, []).append(d.so_detail)
-				elif self.doctype == "Sales Invoice" and d.sales_order and self.update_stock:
-					so_map.setdefault(d.sales_order, []).append(d.so_detail)
-
-		for so, so_item_rows in so_map.items():
-			if so and so_item_rows:
-				sales_order = frappe.get_doc("Sales Order", so)
-
-				if sales_order.status in ["Closed", "Cancelled"]:
-					frappe.throw(_("{0} {1} is cancelled or closed").format(_("Sales Order"), so),
-						frappe.InvalidStatusError)
-
-				sales_order.update_reserved_qty(so_item_rows)
-
-	def update_stock_ledger(self):
-		self.update_reserved_qty()
-
-		sl_entries = []
-		for d in self.get_item_list():
-			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty):
-				return_rate = 0
-				if cint(self.is_return) and self.return_against and self.docstatus==1:
-					return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
-
-				# On cancellation or if return entry submission, make stock ledger entry for
-				# target warehouse first, to update serial no values properly
-
-				if d.warehouse and ((not cint(self.is_return) and self.docstatus==1)
-					or (cint(self.is_return) and self.docstatus==2)):
-						sl_entries.append(self.get_sl_entries(d, {
-							"actual_qty": -1*flt(d.qty),
-							"incoming_rate": return_rate
-						}))
-
-				if d.target_warehouse:
-					target_warehouse_sle = self.get_sl_entries(d, {
-						"actual_qty": flt(d.qty),
-						"warehouse": d.target_warehouse
-					})
-
-					if self.docstatus == 1:
-						if not cint(self.is_return):
-							args = frappe._dict({
-								"item_code": d.item_code,
-								"warehouse": d.warehouse,
-								"posting_date": self.posting_date,
-								"posting_time": self.posting_time,
-								"qty": -1*flt(d.qty),
-								"serial_no": d.serial_no
-							})
-							target_warehouse_sle.update({
-								"incoming_rate": get_incoming_rate(args)
-							})
-						else:
-							target_warehouse_sle.update({
-								"outgoing_rate": return_rate
-							})
-					sl_entries.append(target_warehouse_sle)
-
-				if d.warehouse and ((not cint(self.is_return) and self.docstatus==2)
-					or (cint(self.is_return) and self.docstatus==1)):
-						sl_entries.append(self.get_sl_entries(d, {
-							"actual_qty": -1*flt(d.qty),
-							"incoming_rate": return_rate
-						}))
-
-		self.make_sl_entries(sl_entries)
 		
 	def validate_warehouse(self):
 		from erpnext.stock.utils import validate_warehouse_company
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 469e327..ccc4629 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -196,7 +196,7 @@
 erpnext.patches.v5_7.item_template_attributes
 execute:frappe.delete_doc_if_exists("DocType", "Manage Variants")
 execute:frappe.delete_doc_if_exists("DocType", "Manage Variants Item")
-erpnext.patches.v4_2.repost_reserved_qty #2015-08-20
+erpnext.patches.v4_2.repost_reserved_qty #2016-04-15
 erpnext.patches.v5_4.update_purchase_cost_against_project
 erpnext.patches.v5_8.update_order_reference_in_return_entries
 erpnext.patches.v5_8.add_credit_note_print_heading
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 7ac8941..5fa2d7e 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -126,6 +126,34 @@
 
 		dn.cancel()
 		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10)
+		
+	def test_reserved_qty_for_over_delivery_via_sales_invoice(self):
+		# set over-delivery tolerance
+		frappe.db.set_value('Item', "_Test Item", 'tolerance', 50)
+
+		existing_reserved_qty = get_reserved_qty()
+
+		so = make_sales_order()
+		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10)
+
+		si = make_sales_invoice(so.name)
+		si.update_stock = 1
+		si.get("items")[0].qty = 12
+		si.insert()
+		si.submit()
+		
+		self.assertEqual(get_reserved_qty(), existing_reserved_qty)
+		
+		so.load_from_db()
+		self.assertEqual(so.get("items")[0].delivered_qty, 12)
+		self.assertEqual(so.per_delivered, 100)
+
+		si.cancel()
+		self.assertEqual(get_reserved_qty(), existing_reserved_qty + 10)
+		
+		so.load_from_db()
+		self.assertEqual(so.get("items")[0].delivered_qty, 0)
+		self.assertEqual(so.per_delivered, 0)
 
 	def test_reserved_qty_for_partial_delivery_with_packing_list(self):
 		existing_reserved_qty_item1 = get_reserved_qty("_Test Item")
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 63abaa5..6712ee8 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -191,6 +191,8 @@
 		if not self.is_return:
 			self.check_credit_limit()
 
+		# Updating stock ledger should always be called after updating prevdoc status, 
+		# because updating reserved qty in bin depends upon updated delivered qty in SO
 		self.update_stock_ledger()
 		self.make_gl_entries()
 
@@ -201,6 +203,8 @@
 		self.update_prevdoc_status()
 		self.update_billing_status()
 
+		# Updating stock ledger should always be called after updating prevdoc status, 
+		# because updating reserved qty in bin depends upon updated delivered qty in SO
 		self.update_stock_ledger()
 
 		self.cancel_packing_slips()
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 81708ce..c58607f 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -14,9 +14,6 @@
 		set_perpetual_inventory(1)
 		pr = frappe.copy_doc(pr_test_records[0])
 		pr.submit()
-		
-		pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(),
-			posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - _TC", is_paid=1)
 
 		last_sle = frappe.db.get_value("Stock Ledger Entry", {
 				"voucher_type": pr.doctype,
@@ -24,16 +21,12 @@
 				"item_code": "_Test Item",
 				"warehouse": "_Test Warehouse - _TC"
 			},
-			fieldname=["qty_after_transaction", "stock_value"],
-			as_dict=1)
+			fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
 
-		self.submit_landed_cost_voucher(pr, pi)
+		self.submit_landed_cost_voucher("Purchase Receipt", pr.name)
 
 		pr_lc_value = frappe.db.get_value("Purchase Receipt Item", {"parent": pr.name}, "landed_cost_voucher_amount")
 		self.assertEquals(pr_lc_value, 25.0)
-		
-		pi_lc_value = frappe.db.get_value("Purchase Invoice Item", {"parent": pi.name}, "landed_cost_voucher_amount")
-		self.assertEquals(pi_lc_value, 25.0)
 
 		last_sle_after_landed_cost = frappe.db.get_value("Stock Ledger Entry", {
 				"voucher_type": pr.doctype,
@@ -41,8 +34,7 @@
 				"item_code": "_Test Item",
 				"warehouse": "_Test Warehouse - _TC"
 			},
-			fieldname=["qty_after_transaction", "stock_value"],
-			as_dict=1)
+			fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
 
 		self.assertEqual(last_sle.qty_after_transaction, last_sle_after_landed_cost.qty_after_transaction)
 
@@ -68,7 +60,56 @@
 			self.assertEquals(expected_values[gle.account][1], gle.credit)
 
 		set_perpetual_inventory(0)
+		
+	def test_landed_cost_voucher_against_purchase_invoice(self):
+		set_perpetual_inventory(1)
+		
+		pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(),
+			posting_time=frappe.utils.nowtime())
 
+		last_sle = frappe.db.get_value("Stock Ledger Entry", {
+				"voucher_type": pi.doctype,
+				"voucher_no": pi.name,
+				"item_code": "_Test Item",
+				"warehouse": "_Test Warehouse - _TC"
+			},
+			fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
+
+		self.submit_landed_cost_voucher("Purchase Invoice", pi.name)
+		
+		pi_lc_value = frappe.db.get_value("Purchase Invoice Item", {"parent": pi.name}, 
+			"landed_cost_voucher_amount")
+			
+		self.assertEquals(pi_lc_value, 50.0)
+
+		last_sle_after_landed_cost = frappe.db.get_value("Stock Ledger Entry", {
+				"voucher_type": pi.doctype,
+				"voucher_no": pi.name,
+				"item_code": "_Test Item",
+				"warehouse": "_Test Warehouse - _TC"
+			},
+			fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
+
+		self.assertEqual(last_sle.qty_after_transaction, last_sle_after_landed_cost.qty_after_transaction)
+
+		self.assertEqual(last_sle_after_landed_cost.stock_value - last_sle.stock_value, 50.0)
+
+		gl_entries = get_gl_entries("Purchase Invoice", pi.name)
+
+		self.assertTrue(gl_entries)
+
+		expected_values = {
+			pi.get("items")[0].warehouse: [300.0, 0.0],
+			"Creditors - _TC": [0.0, 250.0],
+			"Expenses Included In Valuation - _TC": [0.0, 50.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_landed_cost_voucher_for_serialized_item(self):
 		set_perpetual_inventory(1)
 		frappe.db.sql("delete from `tabSerial No` where name in ('SN001', 'SN002', 'SN003', 'SN004', 'SN005')")
@@ -80,40 +121,33 @@
 
 		serial_no_rate = frappe.db.get_value("Serial No", "SN001", "purchase_rate")
 
-		self.submit_landed_cost_voucher(pr)
+		self.submit_landed_cost_voucher("Purchase Receipt", pr.name)
 
 		serial_no = frappe.db.get_value("Serial No", "SN001",
 			["warehouse", "purchase_rate"], as_dict=1)
 
-		self.assertEquals(serial_no.purchase_rate - serial_no_rate, 7.5)
+		self.assertEquals(serial_no.purchase_rate - serial_no_rate, 5.0)
 		self.assertEquals(serial_no.warehouse, "_Test Warehouse - _TC")
 
 		set_perpetual_inventory(0)
 
-	def submit_landed_cost_voucher(self, pr, pi=None):
+	def submit_landed_cost_voucher(self, receipt_document_type, receipt_document):
+		ref_doc = frappe.get_doc(receipt_document_type, receipt_document)
+		
 		lcv = frappe.new_doc("Landed Cost Voucher")
 		lcv.company = "_Test Company"
 		lcv.set("purchase_receipts", [{
-			"receipt_document_type": "Purchase Receipt",
-			"receipt_document": pr.name,
-			"supplier": pr.supplier,
-			"posting_date": pr.posting_date,
-			"grand_total": pr.base_grand_total
+			"receipt_document_type": receipt_document_type,
+			"receipt_document": receipt_document,
+			"supplier": ref_doc.supplier,
+			"posting_date": ref_doc.posting_date,
+			"grand_total": ref_doc.base_grand_total
 		}])
 		
-		if pi:
-			lcv.append("purchase_receipts", {
-				"receipt_document_type": "Purchase Invoice",
-				"receipt_document": pi.name,
-				"supplier": pi.supplier,
-				"posting_date": pi.posting_date,
-				"grand_total": pi.base_grand_total
-			})
-		
 		lcv.set("taxes", [{
 			"description": "Insurance Charges",
 			"account": "_Test Account Insurance Charges - _TC",
-			"amount": 75.0
+			"amount": 50
 		}])
 
 		lcv.insert()
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 332dc63..9b9581b 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -21,6 +21,20 @@
 				"batch_no": doc.batch_no
 			}
 		}
+
+		$.each(["warehouse", "rejected_warehouse"], function(i, field) {
+			frm.set_query(field, "items", function() {
+				return {
+					filters: [["Warehouse", "company", "in", ["", cstr(frm.doc.company)]]]
+				}
+			})
+		})
+		
+		frm.set_query("supplier_warehouse", function() {
+			return {
+				filters: [["Warehouse", "company", "in", ["", cstr(frm.doc.company)]]]
+			}
+		})
 	}
 });
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index bad1228..1babf2e 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 
-from frappe.utils import cstr, flt, cint
+from frappe.utils import flt, cint
 
 from frappe import _
 import frappe.defaults
@@ -81,22 +81,6 @@
 				 if not d.prevdoc_docname:
 					 frappe.throw(_("Purchase Order number required for Item {0}").format(d.item_code))
 
-	def update_ordered_qty(self):
-		po_map = {}
-		for d in self.get("items"):
-			if d.prevdoc_doctype and d.prevdoc_doctype == "Purchase Order" and d.prevdoc_detail_docname:
-				po_map.setdefault(d.prevdoc_docname, []).append(d.prevdoc_detail_docname)
-
-		for po, po_item_rows in po_map.items():
-			if po and po_item_rows:
-				po_obj = frappe.get_doc("Purchase Order", po)
-
-				if po_obj.status in ["Closed", "Cancelled"]:
-					frappe.throw(_("{0} {1} is cancelled or closed").format(_("Purchase Order"), po),
-						frappe.InvalidStatusError)
-
-				po_obj.update_ordered_qty(po_item_rows)
-
 	def get_already_received_qty(self, po, po_detail):
 		qty = frappe.db.sql("""select sum(qty) from `tabPurchase Receipt Item`
 			where prevdoc_detail_docname = %s and docstatus = 1
@@ -129,19 +113,20 @@
 		purchase_controller = frappe.get_doc("Purchase Common")
 
 		# Check for Approving Authority
-		frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.company, self.base_grand_total)
+		frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, 
+			self.company, self.base_grand_total)
 
 		# Set status as Submitted
 		frappe.db.set(self, 'status', 'Submitted')
 
 		self.update_prevdoc_status()
-		self.update_ordered_qty()
-
 		self.update_billing_status()
 
 		if not self.is_return:
 			purchase_controller.update_last_purchase_rate(self, 1)
 
+		# Updating stock ledger should always be called after updating prevdoc status, 
+		# because updating ordered qty in bin depends upon updated ordered qty in PO
 		self.update_stock_ledger()
 
 		from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
@@ -171,17 +156,15 @@
 
 		frappe.db.set(self,'status','Cancelled')
 
-		self.update_stock_ledger()
-
-		self.update_prevdoc_status()
-		# Must be called after updating received qty in PO
-		self.update_ordered_qty()
-
+		self.update_prevdoc_status()		
 		self.update_billing_status()
 
 		if not self.is_return:
 			pc_obj.update_last_purchase_rate(self, 0)
-
+		
+		# Updating stock ledger should always be called after updating prevdoc status, 
+		# because updating ordered qty in bin depends upon updated ordered qty in PO
+		self.update_stock_ledger()
 		self.make_gl_entries_on_cancel()
 
 	def get_current_stock(self):
@@ -256,13 +239,11 @@
 						}, warehouse_account[self.supplier_warehouse]["account_currency"]))
 
 					# divisional loss adjustment
-					sle_valuation_amount = flt(flt(d.valuation_rate, val_rate_db_precision) * flt(d.qty) * flt(d.conversion_factor),
-							self.precision("base_net_amount", d))
-
-					distributed_amount = flt(flt(d.base_net_amount, self.precision("base_net_amount", d))) + \
+					distributed_amount = flt(flt(d.base_net_amount, d.precision("base_net_amount"))) + \
 						flt(d.landed_cost_voucher_amount) + flt(d.rm_supp_cost) + flt(d.item_tax_amount)
 
-					divisional_loss = flt(distributed_amount - sle_valuation_amount, self.precision("base_net_amount", d))
+					divisional_loss = flt(distributed_amount - stock_value_diff, 
+						d.precision("base_net_amount"))
 					if divisional_loss:
 						gl_entries.append(self.get_gl_dict({
 							"account": stock_rbnb,