Merge pull request #2378 from nabinhait/fix1

Requested and ordered qty calculation
diff --git a/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.json b/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.json
index 2944b4b..5c0a72a 100755
--- a/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.json
+++ b/erpnext/accounts/print_format/payment_receipt_voucher/payment_receipt_voucher.json
@@ -3,9 +3,9 @@
  "doc_type": "Journal Voucher", 
  "docstatus": 0, 
  "doctype": "Print Format", 
- "html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\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\", _(\"Payment Receipt Note\")) -%}{%- endif -%}\n    {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n    {%- for label, value in (\n        (_(\"Received On\"), frappe.utils.formatdate(doc.voucher_date)),\n        (_(\"Received From\"), doc.pay_to_recd_from),\n        (_(\"Amount\"), \"<strong>\" + doc.total_amount + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n        (_(\"Remarks\"), doc.remark)\n    ) -%}\n    <div class=\"row\">\n        <div class=\"col-sm-3\"><label class=\"text-right\">{{ label }}</label></div>\n        <div class=\"col-sm-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", 
+ "html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\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\", _(\"Payment Receipt Note\")) -%}{%- endif -%}\n    {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n    {%- for label, value in (\n        (_(\"Received On\"), frappe.utils.formatdate(doc.voucher_date)),\n        (_(\"Received From\"), doc.pay_to_recd_from),\n        (_(\"Amount\"), \"<strong>\" + doc.total_amount or 0 + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n        (_(\"Remarks\"), doc.remark)\n    ) -%}\n    <div class=\"row\">\n        <div class=\"col-sm-3\"><label class=\"text-right\">{{ label }}</label></div>\n        <div class=\"col-sm-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", 
  "idx": 1, 
- "modified": "2014-08-29 15:55:34.248384", 
+ "modified": "2014-11-04 11:25:57.560873", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Payment Receipt Voucher", 
diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.py b/erpnext/buying/doctype/purchase_common/purchase_common.py
index 68a6e93..2cf8673 100644
--- a/erpnext/buying/doctype/purchase_common/purchase_common.py
+++ b/erpnext/buying/doctype/purchase_common/purchase_common.py
@@ -3,15 +3,13 @@
 
 from __future__ import unicode_literals
 import frappe
-
-from frappe.utils import cstr, flt
+from frappe.utils import flt
 from frappe import _
 
 from erpnext.stock.doctype.item.item import get_last_purchase_details
 from erpnext.controllers.buying_controller import BuyingController
 
 class PurchaseCommon(BuyingController):
-
 	def update_last_purchase_rate(self, obj, is_submit):
 		"""updates last_purchase_rate in item table for each item"""
 
@@ -123,27 +121,6 @@
 				else:
 					chk_dupl_itm.append(f)
 
-	def get_qty(self, curr_doctype, ref_tab_fname, ref_tab_dn, ref_doc_tname, transaction, curr_parent_name):
-		# Get total Quantities of current doctype (eg. PR) except for qty of this transaction
-		#------------------------------
-		# please check as UOM changes from Material Request - Purchase Order ,so doing following else uom should be same .
-		# i.e. in PO uom is NOS then in PR uom should be NOS
-		# but if in Material Request uom KG it can change in PO
-
-		get_qty = (transaction == 'Material Request - Purchase Order') and 'qty * conversion_factor' or 'qty'
-		qty = frappe.db.sql("""select sum(%s) from `tab%s` where %s = %s and
-			docstatus = 1 and parent != %s""" % (get_qty, curr_doctype, ref_tab_fname, '%s', '%s'),
-			(ref_tab_dn, curr_parent_name))
-		qty = qty and flt(qty[0][0]) or 0
-
-		# get total qty of ref doctype
-		#--------------------
-		max_qty = frappe.db.sql("""select qty from `tab%s` where name = %s
-			and docstatus = 1""" % (ref_doc_tname, '%s'), ref_tab_dn)
-		max_qty = max_qty and flt(max_qty[0][0]) or 0
-
-		return cstr(qty)+'~~~'+cstr(max_qty)
-
 	def check_for_stopped_status(self, doctype, docname):
 		stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
 			status = 'Stopped'""" % (doctype, '%s'), docname)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 0bfd3e5..9b473c1 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -96,50 +96,45 @@
 				check_list.append(d.prevdoc_docname)
 				pc_obj.check_for_stopped_status( d.prevdoc_doctype, d.prevdoc_docname)
 
+	def update_requested_qty(self):
+		material_request_map = {}
+		for d in self.get("po_details"):
+			if d.prevdoc_doctype and d.prevdoc_doctype == "Material Request" and d.prevdoc_detail_docname:
+				material_request_map.setdefault(d.prevdoc_docname, []).append(d.prevdoc_detail_docname)
 
-	def update_bin(self, is_submit, is_stopped = 0):
-		from erpnext.stock.utils import update_bin
-		pc_obj = frappe.get_doc('Purchase Common')
-		for d in self.get('po_details'):
-			#1. Check if is_stock_item == 'Yes'
-			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes":
-				# this happens when item is changed from non-stock to stock item
-				if not d.warehouse:
-					continue
+		for mr, mr_item_rows in material_request_map.items():
+			if mr and mr_item_rows:
+				mr_obj = frappe.get_doc("Material Request", mr)
 
-				ind_qty, po_qty = 0, flt(d.qty) * flt(d.conversion_factor)
-				if is_stopped:
-					po_qty = flt(d.qty) > flt(d.received_qty) and \
-						flt( flt(flt(d.qty) - flt(d.received_qty))*flt(d.conversion_factor)) or 0
+				if mr_obj.status in ["Stopped", "Cancelled"]:
+					frappe.throw(_("Material Request {0} is cancelled or stopped").format(mr), frappe.InvalidStatusError)
 
-				# No updates in Material Request on Stop / Unstop
-				if cstr(d.prevdoc_doctype) == 'Material Request' and not is_stopped:
-					# get qty and pending_qty of prevdoc
-					curr_ref_qty = pc_obj.get_qty(d.doctype, 'prevdoc_detail_docname',
-					 	d.prevdoc_detail_docname, 'Material Request Item',
-						'Material Request - Purchase Order', self.name)
-					max_qty, qty, curr_qty = flt(curr_ref_qty.split('~~~')[1]), \
-					 	flt(curr_ref_qty.split('~~~')[0]), 0
+				mr_obj.update_requested_qty(mr_item_rows)
 
-					if flt(qty) + flt(po_qty) > flt(max_qty):
-						curr_qty = flt(max_qty) - flt(qty)
-						# special case as there is no restriction
-						# for Material Request - Purchase Order
-						curr_qty = curr_qty > 0 and curr_qty or 0
-					else:
-						curr_qty = flt(po_qty)
+	def update_ordered_qty(self, po_item_rows=None):
+		"""update requested qty (before ordered_qty is updated)"""
+		from erpnext.stock.utils import get_bin
 
-					ind_qty = -flt(curr_qty)
+		def _update_ordered_qty(item_code, warehouse):
+			ordered_qty = frappe.db.sql("""
+				select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor)
+				from `tabPurchase Order Item` po_item, `tabPurchase Order` po
+				where po_item.item_code=%s and po_item.warehouse=%s
+				and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name
+				and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse))
 
-				# Update ordered_qty and indented_qty in bin
-				args = {
-					"item_code": d.item_code,
-					"warehouse": d.warehouse,
-					"ordered_qty": (is_submit and 1 or -1) * flt(po_qty),
-					"indented_qty": (is_submit and 1 or -1) * flt(ind_qty),
-					"posting_date": self.transaction_date
-				}
-				update_bin(args)
+			bin_doc = get_bin(item_code, warehouse)
+			bin_doc.ordered_qty = flt(ordered_qty[0][0]) if ordered_qty else 0
+			bin_doc.save()
+
+		item_wh_list = []
+		for d in self.get("po_details"):
+			if (not po_item_rows or d.name in po_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \
+					and frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" and d.warehouse:
+				item_wh_list.append([d.item_code, d.warehouse])
+
+		for item_code, warehouse in item_wh_list:
+			_update_ordered_qty(item_code, warehouse)
 
 	def check_modified_date(self):
 		mod_db = frappe.db.sql("select modified from `tabPurchase Order` where name = %s",
@@ -152,13 +147,11 @@
 
 	def update_status(self, status):
 		self.check_modified_date()
-		# step 1:=> Set Status
 		frappe.db.set(self,'status',cstr(status))
 
-		# step 2:=> Update Bin
-		self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
+		self.update_requested_qty()
+		self.update_ordered_qty()
 
-		# step 3:=> Acknowledge user
 		msgprint(_("Status of {0} {1} is now {2}").format(self.doctype, self.name, status))
 
 	def on_submit(self):
@@ -167,7 +160,8 @@
 		purchase_controller = frappe.get_doc("Purchase Common")
 
 		self.update_prevdoc_status()
-		self.update_bin(is_submit = 1, is_stopped = 0)
+		self.update_requested_qty()
+		self.update_ordered_qty()
 
 		frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
 			self.company, self.grand_total)
@@ -192,8 +186,13 @@
 			throw(_("Purchase Invoice {0} is already submitted").format(", ".join(submitted)))
 
 		frappe.db.set(self,'status','Cancelled')
+
 		self.update_prevdoc_status()
-		self.update_bin( is_submit = 0, is_stopped = 0)
+
+		# Must be called after updating ordered qty in Material Request
+		self.update_requested_qty()
+		self.update_ordered_qty()
+
 		pc_obj.update_last_purchase_rate(self, is_submit = 0)
 
 	def on_update(self):
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 842409f..fc31a9a 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -29,8 +29,7 @@
 		frappe.get_doc(pr).insert()
 
 	def test_ordered_qty(self):
-		frappe.db.sql("delete from tabBin")
-
+		existing_ordered_qty = self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC")
 		from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
 
 		po = frappe.copy_doc(test_records[0]).insert()
@@ -43,8 +42,7 @@
 		po.get("po_details")[0].item_code = "_Test Item"
 		po.submit()
 
-		self.assertEquals(frappe.db.get_value("Bin", {"item_code": "_Test Item",
-			"warehouse": "_Test Warehouse - _TC"}, "ordered_qty"), 10)
+		self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 10)
 
 		pr = make_purchase_receipt(po.name)
 
@@ -56,8 +54,9 @@
 		pr.insert()
 		pr.submit()
 
-		self.assertEquals(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item",
-			"warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 6.0)
+		po.load_from_db()
+		self.assertEquals(po.get("po_details")[0].received_qty, 4)
+		self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 6)
 
 		frappe.db.set_value('Item', '_Test Item', 'tolerance', 50)
 
@@ -68,8 +67,16 @@
 		pr1.insert()
 		pr1.submit()
 
-		self.assertEquals(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item",
-			"warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 0.0)
+		po.load_from_db()
+		self.assertEquals(po.get("po_details")[0].received_qty, 12)
+		self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty)
+
+		pr1.load_from_db()
+		pr1.cancel()
+
+		po.load_from_db()
+		self.assertEquals(po.get("po_details")[0].received_qty, 4)
+		self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 6)
 
 	def test_make_purchase_invoice(self):
 		from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
@@ -111,6 +118,9 @@
 		from erpnext.controllers.tests.test_recurring_document import test_recurring_document
 		test_recurring_document(self, test_records)
 
+	def _get_ordered_qty(self, item_code, warehouse):
+		return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "ordered_qty"))
+
 
 test_dependencies = ["BOM", "Item Price"]
 
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 25be39d..2d7d4e5 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -47,8 +47,8 @@
 		"on_update": "erpnext.home.make_comment_feed"
 	},
 	"Stock Entry": {
-		"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_qty",
-		"on_cancel": "erpnext.stock.doctype.material_request.material_request.update_completed_qty"
+		"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty",
+		"on_cancel": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty"
 	},
 	"User": {
 		"validate": "erpnext.hr.doctype.employee.employee.validate_employee_role",
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index d75a99c..d9a6b64 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -87,3 +87,4 @@
 execute:frappe.delete_doc("DocType", "Purchase Request Item")
 erpnext.patches.v4_2.recalculate_bom_cost
 erpnext.patches.v4_2.fix_gl_entries_for_stock_transactions
+erpnext.patches.v4_2.update_requested_and_ordered_qty
diff --git a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py
new file mode 100644
index 0000000..e44133e
--- /dev/null
+++ b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	from erpnext.utilities.repost_stock import update_bin_qty, get_indented_qty, get_ordered_qty
+
+	count=0
+	for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse from
+		(select item_code, warehouse from tabBin
+		union
+		select item_code, warehouse from `tabStock Ledger Entry`) a"""):
+			try:
+				count += 1
+				update_bin_qty(item_code, warehouse, {
+					"indented_qty": get_indented_qty(item_code, warehouse),
+					"ordered_qty": get_ordered_qty(item_code, warehouse)
+				})
+				if count / 200 == 0:
+					frappe.db.commit()
+			except:
+				frappe.db.rollback()
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index eeda2ce..cb9552d 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -79,30 +79,9 @@
 		# NOTE: Since Item BOM and FG quantities are combined, using current data, it cannot be validated
 		# Though the creation of Material Request from a Production Plan can be rethought to fix this
 
-	def update_bin(self, is_submit, is_stopped):
-		""" Update Quantity Requested for Purchase in Bin for Material Request of type 'Purchase'"""
-
-		from erpnext.stock.utils import update_bin
-		for d in self.get('indent_details'):
-			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes":
-				if not d.warehouse:
-					frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code))
-
-				qty =flt(d.qty)
-				if is_stopped:
-					qty = (d.qty > d.ordered_qty) and flt(flt(d.qty) - flt(d.ordered_qty)) or 0
-
-				args = {
-					"item_code": d.item_code,
-					"warehouse": d.warehouse,
-					"indented_qty": (is_submit and 1 or -1) * flt(qty),
-					"posting_date": self.transaction_date
-				}
-				update_bin(args)
-
 	def on_submit(self):
 		frappe.db.set(self, 'status', 'Submitted')
-		self.update_bin(is_submit = 1, is_stopped = 0)
+		self.update_requested_qty()
 
 	def check_modified_date(self):
 		mod_db = frappe.db.sql("""select modified from `tabMaterial Request` where name = %s""",
@@ -115,23 +94,18 @@
 
 	def update_status(self, status):
 		self.check_modified_date()
-		self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
+		self.update_requested_qty()
 		frappe.db.set(self, 'status', cstr(status))
 		frappe.msgprint(_("Status updated to {0}").format(_(status)))
 
 	def on_cancel(self):
-		# Step 1:=> Get Purchase Common Obj
 		pc_obj = frappe.get_doc('Purchase Common')
 
-		# Step 2:=> Check for stopped status
 		pc_obj.check_for_stopped_status(self.doctype, self.name)
-
-		# Step 3:=> Check if Purchase Order has been submitted against current Material Request
 		pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Order', docname = self.name, detail_doctype = 'Purchase Order Item')
-		# Step 4:=> Update Bin
-		self.update_bin(is_submit = 0, is_stopped = (cstr(self.status) == 'Stopped') and 1 or 0)
 
-		# Step 5:=> Set Status
+		self.update_requested_qty()
+
 		frappe.db.set(self,'status','Cancelled')
 
 	def update_completed_qty(self, mr_items=None):
@@ -162,56 +136,47 @@
 		self.per_ordered = flt((per_ordered / flt(len(item_doclist))) * 100.0, 2)
 		frappe.db.set_value(self.doctype, self.name, "per_ordered", self.per_ordered)
 
-def update_completed_qty(doc, method):
-	if doc.doctype == "Stock Entry":
+	def update_requested_qty(self, mr_item_rows=None):
+		"""update requested qty (before ordered_qty is updated)"""
+		from erpnext.stock.utils import get_bin
+
+		def _update_requested_qty(item_code, warehouse):
+			requested_qty = frappe.db.sql("""select sum(mr_item.qty - ifnull(mr_item.ordered_qty, 0))
+				from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
+				where mr_item.item_code=%s and mr_item.warehouse=%s
+				and mr_item.qty > ifnull(mr_item.ordered_qty, 0) and mr_item.parent=mr.name
+				and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
+
+			bin_doc = get_bin(item_code, warehouse)
+			bin_doc.indented_qty = flt(requested_qty[0][0]) if requested_qty else 0
+			bin_doc.save()
+
+		item_wh_list = []
+		for d in self.get("indent_details"):
+			if (not mr_item_rows or d.name in mr_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \
+					and frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" and d.warehouse:
+				item_wh_list.append([d.item_code, d.warehouse])
+
+		for item_code, warehouse in item_wh_list:
+			_update_requested_qty(item_code, warehouse)
+
+def update_completed_and_requested_qty(stock_entry, method):
+	if stock_entry.doctype == "Stock Entry":
 		material_request_map = {}
 
-		for d in doc.get("mtn_details"):
+		for d in stock_entry.get("mtn_details"):
 			if d.material_request:
 				material_request_map.setdefault(d.material_request, []).append(d.material_request_item)
 
-		for mr_name, mr_items in material_request_map.items():
-			mr_obj = frappe.get_doc("Material Request", mr_name)
+		for mr, mr_item_rows in material_request_map.items():
+			if mr and mr_item_rows:
+				mr_obj = frappe.get_doc("Material Request", mr)
 
-			if mr_obj.status in ["Stopped", "Cancelled"]:
-				frappe.throw(_("Material Request {0} is cancelled or stopped").format(mr_obj.name),
-					frappe.InvalidStatusError)
+				if mr_obj.status in ["Stopped", "Cancelled"]:
+					frappe.throw(_("Material Request {0} is cancelled or stopped").format(mr), frappe.InvalidStatusError)
 
-			_update_requested_qty(doc, mr_obj, mr_items)
-
-			# update ordered percentage and qty
-			mr_obj.update_completed_qty(mr_items)
-
-def _update_requested_qty(doc, mr_obj, mr_items):
-	"""update requested qty (before ordered_qty is updated)"""
-	from erpnext.stock.utils import update_bin
-	for mr_item_name in mr_items:
-		mr_item = mr_obj.get("indent_details", {"name": mr_item_name})
-		se_detail = doc.get("mtn_details", {"material_request": mr_obj.name,
-			"material_request_item": mr_item_name})
-
-		if mr_item and se_detail:
-			mr_item = mr_item[0]
-			se_detail = se_detail[0]
-			mr_item.ordered_qty = flt(mr_item.ordered_qty)
-			mr_item.qty = flt(mr_item.qty)
-			se_detail.transfer_qty = flt(se_detail.transfer_qty)
-
-			if se_detail.docstatus == 2 and mr_item.ordered_qty > mr_item.qty \
-					and se_detail.transfer_qty == mr_item.ordered_qty:
-				add_indented_qty = mr_item.qty
-			elif se_detail.docstatus == 1 and \
-					mr_item.ordered_qty + se_detail.transfer_qty > mr_item.qty:
-				add_indented_qty = mr_item.qty - mr_item.ordered_qty
-			else:
-				add_indented_qty = se_detail.transfer_qty
-
-			update_bin({
-				"item_code": se_detail.item_code,
-				"warehouse": se_detail.t_warehouse,
-				"indented_qty": (se_detail.docstatus==2 and 1 or -1) * add_indented_qty,
-				"posting_date": doc.posting_date,
-			})
+				mr_obj.update_completed_qty(mr_item_rows)
+				mr_obj.update_requested_qty(mr_item_rows)
 
 def set_missing_values(source, target_doc):
 	target_doc.run_method("set_missing_values")
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index 04b7793..ab1d3cc 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -58,12 +58,6 @@
 		self.assertEquals(se.doctype, "Stock Entry")
 		self.assertEquals(len(se.get("mtn_details")), len(mr.get("indent_details")))
 
-	def _test_requested_qty(self, qty1, qty2):
-		self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 100",
-			"warehouse": "_Test Warehouse - _TC"}, "indented_qty")), qty1)
-		self.assertEqual(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 200",
-			"warehouse": "_Test Warehouse - _TC"}, "indented_qty")), qty2)
-
 	def _insert_stock_entry(self, qty1, qty2):
 		se = frappe.get_doc({
 				"company": "_Test Company",
@@ -103,7 +97,8 @@
 		se.submit()
 
 	def test_completed_qty_for_purchase(self):
-		frappe.db.sql("""delete from `tabBin`""")
+		existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		existing_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
 
 		# submit material request of type Purchase
 		mr = frappe.copy_doc(test_records[0])
@@ -115,8 +110,6 @@
 		self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
 		self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
 
-		self._test_requested_qty(54.0, 3.0)
-
 		# map a purchase order
 		from erpnext.stock.doctype.material_request.material_request import make_purchase_order
 		po_doc = make_purchase_order(mr.name)
@@ -149,7 +142,12 @@
 		self.assertEquals(mr.per_ordered, 50)
 		self.assertEquals(mr.get("indent_details")[0].ordered_qty, 27.0)
 		self.assertEquals(mr.get("indent_details")[1].ordered_qty, 1.5)
-		self._test_requested_qty(27.0, 1.5)
+
+		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
+
+		self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 27.0)
+		self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 1.5)
 
 		po.cancel()
 		# check if per complete is as expected
@@ -158,11 +156,15 @@
 		self.assertEquals(mr.get("indent_details")[0].ordered_qty, None)
 		self.assertEquals(mr.get("indent_details")[1].ordered_qty, None)
 
-		self._test_requested_qty(54.0, 3.0)
+		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
+
+		self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
+		self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
 
 	def test_completed_qty_for_transfer(self):
-		frappe.db.sql("""delete from `tabBin`""")
-		frappe.db.sql("""delete from `tabStock Ledger Entry`""")
+		existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		existing_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
 
 		# submit material request of type Purchase
 		mr = frappe.copy_doc(test_records[0])
@@ -175,7 +177,11 @@
 		self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
 		self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
 
-		self._test_requested_qty(54.0, 3.0)
+		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
+
+		self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
+		self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
 
 		from erpnext.stock.doctype.material_request.material_request import make_stock_entry
 
@@ -226,7 +232,11 @@
 		self.assertEquals(mr.get("indent_details")[0].ordered_qty, 27.0)
 		self.assertEquals(mr.get("indent_details")[1].ordered_qty, 1.5)
 
-		self._test_requested_qty(27.0, 1.5)
+		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
+
+		self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 27.0)
+		self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 1.5)
 
 		# check if per complete is as expected for Stock Entry cancelled
 		se.cancel()
@@ -235,11 +245,15 @@
 		self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
 		self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
 
-		self._test_requested_qty(54.0, 3.0)
+		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
+
+		self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
+		self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
 
 	def test_completed_qty_for_over_transfer(self):
-		frappe.db.sql("""delete from `tabBin`""")
-		frappe.db.sql("""delete from `tabStock Ledger Entry`""")
+		existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		existing_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
 
 		# submit material request of type Purchase
 		mr = frappe.copy_doc(test_records[0])
@@ -252,8 +266,6 @@
 		self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
 		self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
 
-		self._test_requested_qty(54.0, 3.0)
-
 		# map a stock entry
 		from erpnext.stock.doctype.material_request.material_request import make_stock_entry
 
@@ -297,7 +309,12 @@
 		self.assertEquals(mr.per_ordered, 100)
 		self.assertEquals(mr.get("indent_details")[0].ordered_qty, 60.0)
 		self.assertEquals(mr.get("indent_details")[1].ordered_qty, 3.0)
-		self._test_requested_qty(0.0, 0.0)
+
+		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
+
+		self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1)
+		self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2)
 
 		# check if per complete is as expected for Stock Entry cancelled
 		se.cancel()
@@ -306,7 +323,11 @@
 		self.assertEquals(mr.get("indent_details")[0].ordered_qty, 0)
 		self.assertEquals(mr.get("indent_details")[1].ordered_qty, 0)
 
-		self._test_requested_qty(54.0, 3.0)
+		current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
+		current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
+
+		self.assertEquals(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
+		self.assertEquals(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
 
 	def test_incorrect_mapping_of_stock_entry(self):
 		# submit material request of type Purchase
@@ -348,5 +369,9 @@
 		mr.company = "_Test Company 1"
 		self.assertRaises(InvalidWarehouseCompany, mr.insert)
 
+	def _get_requested_qty(self, item_code, warehouse):
+		return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "indented_qty"))
+
+
 test_dependencies = ["Currency Exchange"]
 test_records = frappe.get_test_records('Material Request')
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 13495a0..f38ee5d 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -8,7 +8,6 @@
 
 from frappe import _
 import frappe.defaults
-from erpnext.stock.utils import update_bin
 
 from erpnext.controllers.buying_controller import BuyingController
 
@@ -157,29 +156,19 @@
 		self.make_sl_entries(sl_entries)
 
 	def update_ordered_qty(self):
-		stock_items = self.get_stock_items()
+		po_map = {}
 		for d in self.get("purchase_receipt_details"):
-			if d.item_code in stock_items and d.warehouse \
-					and cstr(d.prevdoc_doctype) == 'Purchase Order':
+			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)
 
-				already_received_qty = self.get_already_received_qty(d.prevdoc_docname,
-					d.prevdoc_detail_docname)
-				po_qty, ordered_warehouse = self.get_po_qty_and_warehouse(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 not ordered_warehouse:
-					frappe.throw(_("Warehouse is missing in Purchase Order"))
+				if po_obj.status in ["Stopped", "Cancelled"]:
+					frappe.throw(_("Material Request {0} is cancelled or stopped").format(po), frappe.InvalidStatusError)
 
-				if already_received_qty + d.qty > po_qty:
-					ordered_qty = - (po_qty - already_received_qty) * flt(d.conversion_factor)
-				else:
-					ordered_qty = - flt(d.qty) * flt(d.conversion_factor)
-
-				update_bin({
-					"item_code": d.item_code,
-					"warehouse": ordered_warehouse,
-					"posting_date": self.posting_date,
-					"ordered_qty": flt(ordered_qty) if self.docstatus==1 else -flt(ordered_qty)
-				})
+				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`
@@ -265,11 +254,13 @@
 
 		frappe.db.set(self,'status','Cancelled')
 
-		self.update_ordered_qty()
-
 		self.update_stock_ledger()
 
 		self.update_prevdoc_status()
+
+		# Must be called after updating received qty in PO
+		self.update_ordered_qty()
+
 		pc_obj.update_last_purchase_rate(self, 0)
 
 		self.make_gl_entries_on_cancel()
diff --git a/erpnext/utilities/repost_stock.py b/erpnext/utilities/repost_stock.py
index f1ba179..b63493e 100644
--- a/erpnext/utilities/repost_stock.py
+++ b/erpnext/utilities/repost_stock.py
@@ -93,11 +93,11 @@
 	return flt(reserved_qty[0][0]) if reserved_qty else 0
 
 def get_indented_qty(item_code, warehouse):
-	indented_qty = frappe.db.sql("""select sum(pr_item.qty - ifnull(pr_item.ordered_qty, 0))
-		from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr
-		where pr_item.item_code=%s and pr_item.warehouse=%s
-		and pr_item.qty > ifnull(pr_item.ordered_qty, 0) and pr_item.parent=pr.name
-		and pr.status!='Stopped' and pr.docstatus=1""", (item_code, warehouse))
+	indented_qty = frappe.db.sql("""select sum(mr_item.qty - ifnull(mr_item.ordered_qty, 0))
+		from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
+		where mr_item.item_code=%s and mr_item.warehouse=%s
+		and mr_item.qty > ifnull(mr_item.ordered_qty, 0) and mr_item.parent=mr.name
+		and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
 
 	return flt(indented_qty[0][0]) if indented_qty else 0