Merge branch 'master' of github.com:webnotes/erpnext
diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py
index 708700d..7742676 100644
--- a/stock/doctype/material_request/material_request.py
+++ b/stock/doctype/material_request/material_request.py
@@ -205,7 +205,7 @@
 		
 		self.doc.per_ordered = flt((per_ordered / flt(len(item_doclist))) * 100.0, 2)
 		webnotes.conn.set_value(self.doc.doctype, self.doc.name, "per_ordered", self.doc.per_ordered)
-			
+		
 def update_completed_qty(controller, caller_method):
 	if controller.doc.doctype == "Stock Entry":
 		material_request_map = {}
@@ -215,18 +215,43 @@
 				if d.material_request not in material_request_map:
 					material_request_map[d.material_request] = []
 				material_request_map[d.material_request].append(d.material_request_item)
-				webnotes.get_obj("Warehouse", d.t_warehouse).update_bin({
-					"item_code": d.item_code,
-					"indented_qty": (d.docstatus==2 and 1 or -1) * d.transfer_qty,
-					"posting_date": controller.doc.posting_date,
-				})
 			
 		for mr_name, mr_items in material_request_map.items():
 			mr_obj = webnotes.get_obj("Material Request", mr_name, with_children=1)
 			mr_doctype = webnotes.get_doctype("Material Request")
+			
 			if mr_obj.doc.status in ["Stopped", "Cancelled"]:
 				msgprint(_("Material Request") + ": %s, " % mr_obj.doc.name 
 					+ _(mr_doctype.get_label("status")) + " = %s. " % _(mr_obj.doc.status)
-					+ _("Cannot continue."), raise_exception=True)
+					+ _("Cannot continue."), raise_exception=webnotes.InvalidStatusError)
 				
-			mr_obj.update_completed_qty(mr_items)
\ No newline at end of file
+			_update_requested_qty(controller, mr_obj, mr_items)
+			
+			# update ordered percentage and qty
+			mr_obj.update_completed_qty(mr_items)
+			
+def _update_requested_qty(controller, mr_obj, mr_items):
+	"""update requested qty (before ordered_qty is updated)"""
+	for mr_item_name in mr_items:
+		mr_item = mr_obj.doclist.getone({"parentfield": "indent_details", "name": mr_item_name})
+		se_detail = controller.doclist.getone({"parentfield": "mtn_details",
+			"material_request": mr_obj.doc.name, "material_request_item": mr_item_name})
+	
+		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
+	
+		webnotes.get_obj("Warehouse", se_detail.t_warehouse).update_bin({
+			"item_code": se_detail.item_code,
+			"indented_qty": (se_detail.docstatus==2 and 1 or -1) * add_indented_qty,
+			"posting_date": controller.doc.posting_date,
+		})
diff --git a/stock/doctype/material_request/test_material_request.py b/stock/doctype/material_request/test_material_request.py
index 3c2f421..ae40858 100644
--- a/stock/doctype/material_request/test_material_request.py
+++ b/stock/doctype/material_request/test_material_request.py
@@ -3,6 +3,7 @@
 
 from __future__ import unicode_literals
 import webnotes, unittest
+from webnotes.utils import flt
 
 class TestMaterialRequest(unittest.TestCase):
 	def _test_expected(self, doclist, expected_values):
@@ -11,10 +12,10 @@
 				self.assertEquals(val, doclist[i].fields.get(fieldname))
 				
 	def _test_requested_qty(self, qty1, qty2):
-		self.assertEqual(webnotes.conn.get_value("Bin", {"item_code": "_Test Item Home Desktop 100",
-			"warehouse": "_Test Warehouse"}, "indented_qty"), qty1)
-		self.assertEqual(webnotes.conn.get_value("Bin", {"item_code": "_Test Item Home Desktop 200",
-			"warehouse": "_Test Warehouse"}, "indented_qty"), qty2)
+		self.assertEqual(flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item Home Desktop 100",
+			"warehouse": "_Test Warehouse"}, "indented_qty")), qty1)
+		self.assertEqual(flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item Home Desktop 200",
+			"warehouse": "_Test Warehouse"}, "indented_qty")), qty2)
 				
 	def test_completed_qty_for_purchase(self):
 		webnotes.conn.sql("""delete from `tabBin`""")
@@ -124,6 +125,95 @@
 		self._test_expected(mr.doclist, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}])
 		self._test_requested_qty(54.0, 3.0)
 		
+	def test_completed_qty_for_over_transfer(self):
+		webnotes.conn.sql("""delete from `tabBin`""")
+		
+		# submit material request of type Purchase
+		mr = webnotes.bean(copy=test_records[0])
+		mr.doc.material_request_type = "Transfer"
+		mr.insert()
+		mr.submit()
+
+		# check if per complete is None
+		self._test_expected(mr.doclist, [{"per_ordered": None}, {"ordered_qty": None}, {"ordered_qty": None}])
+		
+		self._test_requested_qty(54.0, 3.0)
+		
+		# map a stock entry
+		se_doclist = webnotes.map_doclist([["Material Request", "Stock Entry"], 
+			["Material Request Item", "Stock Entry Detail"]], mr.doc.name)
+		se_doclist[0].fields.update({
+			"posting_date": "2013-03-01",
+			"posting_time": "00:00"
+		})
+		se_doclist[1].fields.update({
+			"qty": 60.0,
+			"transfer_qty": 60.0,
+			"s_warehouse": "_Test Warehouse 1",
+			"incoming_rate": 1.0
+		})
+		se_doclist[2].fields.update({
+			"qty": 3.0,
+			"transfer_qty": 3.0,
+			"s_warehouse": "_Test Warehouse 1",
+			"incoming_rate": 1.0
+		})
+		
+		# check for stopped status of Material Request
+		se = webnotes.bean(copy=se_doclist)
+		se.insert()
+		mr.obj.update_status('Stopped')
+		self.assertRaises(webnotes.ValidationError, se.submit)
+		self.assertRaises(webnotes.ValidationError, se.cancel)
+		
+		mr.obj.update_status('Submitted')
+		se = webnotes.bean(copy=se_doclist)
+		se.insert()
+		se.submit()
+		
+		# check if per complete is as expected
+		mr.load_from_db()
+		self._test_expected(mr.doclist, [{"per_ordered": 100}, {"ordered_qty": 60.0}, {"ordered_qty": 3.0}])
+		self._test_requested_qty(0.0, 0.0)
+		
+		# check if per complete is as expected for Stock Entry cancelled
+		se.cancel()
+		mr.load_from_db()
+		self._test_expected(mr.doclist, [{"per_ordered": 0}, {"ordered_qty": 0}, {"ordered_qty": 0}])
+		self._test_requested_qty(54.0, 3.0)
+		
+	def test_incorrect_mapping_of_stock_entry(self):
+		# submit material request of type Purchase
+		mr = webnotes.bean(copy=test_records[0])
+		mr.doc.material_request_type = "Transfer"
+		mr.insert()
+		mr.submit()
+
+		# map a stock entry
+		se_doclist = webnotes.map_doclist([["Material Request", "Stock Entry"], 
+			["Material Request Item", "Stock Entry Detail"]], mr.doc.name)
+		se_doclist[0].fields.update({
+			"posting_date": "2013-03-01",
+			"posting_time": "00:00"
+		})
+		se_doclist[1].fields.update({
+			"qty": 60.0,
+			"transfer_qty": 60.0,
+			"s_warehouse": "_Test Warehouse",
+			"t_warehouse": "_Test Warehouse 1",
+			"incoming_rate": 1.0
+		})
+		se_doclist[2].fields.update({
+			"qty": 3.0,
+			"transfer_qty": 3.0,
+			"s_warehouse": "_Test Warehouse 1",
+			"incoming_rate": 1.0
+		})
+		
+		# check for stopped status of Material Request
+		se = webnotes.bean(copy=se_doclist)
+		self.assertRaises(webnotes.MappingMismatchError, se.insert)
+		
 test_records = [
 	[
 		{
diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py
index 78d06ce..05d7460 100644
--- a/stock/doctype/stock_entry/stock_entry.py
+++ b/stock/doctype/stock_entry/stock_entry.py
@@ -52,6 +52,8 @@
 		self.validate_finished_goods()
 		self.validate_return_reference_doc()
 		
+		self.validate_with_material_request()
+		
 	def on_submit(self):
 		self.update_serial_no(1)
 		self.update_stock_ledger(0)
@@ -580,6 +582,18 @@
 			'supplier_name' : res and res[0][0] or '',
 			'supplier_address' : addr and addr[0] or ''}
 		return ret
+		
+	def validate_with_material_request(self):
+		for item in self.doclist.get({"parentfield": "mtn_details"}):
+			if item.material_request:
+				mreq_item = webnotes.conn.get_value("Material Request Item", 
+					{"name": item.material_request_item, "parent": item.material_request},
+					["item_code", "warehouse", "idx"], as_dict=True)
+				if mreq_item.item_code != item.item_code or mreq_item.warehouse != item.t_warehouse:
+					msgprint(_("Row #") + (" %d: " % item.idx) + _("does not match")
+						+ " " + _("Row #") + (" %d %s " % (mreq_item.idx, _("of")))
+						+ _("Material Request") + (" - %s" % item.material_request), 
+						raise_exception=webnotes.MappingMismatchError)
 
 @webnotes.whitelist()
 def get_production_order_details(production_order):