Merge branch 'master' of github.com:webnotes/erpnext
diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py
index 244bd7a..438442c 100644
--- a/buying/doctype/purchase_order/purchase_order.py
+++ b/buying/doctype/purchase_order/purchase_order.py
@@ -18,12 +18,10 @@
 import webnotes
 
 from webnotes.utils import cstr, flt
-from webnotes.model.doc import addchild
 from webnotes.model.bean import getlist
 from webnotes.model.code import get_obj
 from webnotes import msgprint
 from buying.utils import get_last_purchase_details
-from setup.utils import get_company_currency
 
 sql = webnotes.conn.sql
 	
@@ -35,7 +33,6 @@
 		self.tname = 'Purchase Order Item'
 		self.fname = 'po_details'
 		
-		# Validate
 	def validate(self):
 		super(DocType, self).validate()
 		
@@ -64,6 +61,10 @@
 		# Check for stopped status
 		self.check_for_stopped_status(pc_obj)
 		
+		# sub-contracting
+		self.validate_for_subcontracting()
+		self.update_raw_materials_supplied("po_raw_material_details")
+		
 
 	def get_default_schedule_date(self):
 		get_obj(dt = 'Purchase Common').get_default_schedule_date(self)
@@ -79,7 +80,6 @@
 	def get_indent_details(self):
 		if self.doc.indent_no:
 			get_obj('DocType Mapper','Material Request-Purchase Order').dt_map('Material Request','Purchase Order',self.doc.indent_no, self.doc, self.doclist, "[['Material Request','Purchase Order'],['Material Request Item', 'Purchase Order Item']]")
-			pcomm = get_obj('Purchase Common')
 			for d in getlist(self.doclist, 'po_details'):
 				if d.item_code and not d.purchase_rate:
 					last_purchase_details = get_last_purchase_details(d.item_code, self.doc.name)
@@ -173,8 +173,6 @@
 			msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ")
 			raise Exception
 
-	# On Close
-	#-------------------------------------------------------------------------------------------------
 	def update_status(self, status):
 		self.check_modified_date()
 		# step 1:=> Set Status
@@ -186,8 +184,6 @@
 		# step 3:=> Acknowledge user
 		msgprint(self.doc.doctype + ": " + self.doc.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)))
 
-
-	# On Submit
 	def on_submit(self):
 		purchase_controller = webnotes.get_obj("Purchase Common")
 		purchase_controller.is_item_table_empty(self)
@@ -207,118 +203,31 @@
 		# Step 6 :=> Set Status
 		webnotes.conn.set(self.doc,'status','Submitted')
 	 
-	# On Cancel
-	# -------------------------------------------------------------------------------------------------------
 	def on_cancel(self):
 		pc_obj = get_obj(dt = 'Purchase Common')
 		
-		# 1.Check if PO status is stopped
+		# Check if PO status is stopped
 		pc_obj.check_for_stopped_status(cstr(self.doc.doctype), cstr(self.doc.name))
 		
 		self.check_for_stopped_status(pc_obj)
 		
-		# 2.Check if Purchase Receipt has been submitted against current Purchase Order
+		# Check if Purchase Receipt has been submitted against current Purchase Order
 		pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.doc.name, detail_doctype = 'Purchase Receipt Item')
 
-		# 3.Check if Purchase Invoice has been submitted against current Purchase Order
-		#pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Invoice', docname = self.doc.name, detail_doctype = 'Purchase Invoice Item')
-		
+		# Check if Purchase Invoice has been submitted against current Purchase Order
 		submitted = sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_order = '%s' and t1.docstatus = 1" % self.doc.name)
 		if submitted:
 			msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !")
 			raise Exception
 
-		# 4.Set Status as Cancelled
 		webnotes.conn.set(self.doc,'status','Cancelled')
-
-		# 5.Update Material Requests Pending Qty and accordingly it's Status 
 		pc_obj.update_prevdoc_detail(self,is_submit = 0)
-		
-		# 6.Update Bin	
 		self.update_bin( is_submit = 0, is_stopped = 0)
-		
-		# Step 7 :=> Update last purchase rate 
 		pc_obj.update_last_purchase_rate(self, is_submit = 0)
-		
-#----------- code for Sub-contracted Items -------------------
-	#--------check for sub-contracted items and accordingly update PO raw material detail table--------
-	def update_rw_material_detail(self):
-		for d in getlist(self.doclist,'po_details'):
-			item_det = sql("select is_sub_contracted_item, is_purchase_item from `tabItem` where name = '%s'"%(d.item_code))
-			
-			if item_det[0][0] == 'Yes':
-				if item_det[0][1] == 'Yes':
-					if not self.doc.is_subcontracted:
-						msgprint("Please enter whether purchase order to be made for subcontracting or for purchasing in 'Is Subcontracted' field .")
-						raise Exception
-					if self.doc.is_subcontracted == 'Yes':
-						self.add_bom(d)
-					else:
-						self.doclist = self.doc.clear_table(self.doclist,'po_raw_material_details',1)
-						self.doc.save()
-				elif item_det[0][1] == 'No':
-					self.add_bom(d)
 				
-			self.delete_irrelevant_raw_material()
-			#---------------calculate amt in	Purchase Order Item Supplied-------------
-			
-	def add_bom(self, d):
-		#----- fetching default bom from Bill of Materials instead of Item Master --
-		bom_det = sql("""select t1.item, t2.item_code, t2.qty_consumed_per_unit, 
-			t2.moving_avg_rate, t2.value_as_per_mar, t2.stock_uom, t2.name, t2.parent 
-			from `tabBOM` t1, `tabBOM Item` t2 
-			where t2.parent = t1.name and t1.item = %s 
-				and ifnull(t1.is_default,0) = 1 and t1.docstatus = 1""", (d.item_code,))
-		
-		if not bom_det:
-			msgprint("No default BOM exists for item: %s" % d.item_code)
-			raise Exception
-		else:
-			#-------------- add child function--------------------
-			chgd_rqd_qty = []
-			for i in bom_det:
-				if i and not sql("select name from `tabPurchase Order Item Supplied` where reference_name = '%s' and bom_detail_no = '%s' and parent = '%s' " %(d.name, i[6], self.doc.name)):
-
-					rm_child = addchild(self.doc, 'po_raw_material_details', 'Purchase Order Item Supplied', self.doclist)
-
-					rm_child.reference_name = d.name
-					rm_child.bom_detail_no = i and i[6] or ''
-					rm_child.main_item_code = i and i[0] or ''
-					rm_child.rm_item_code = i and i[1] or ''
-					rm_child.stock_uom = i and i[5] or ''
-					rm_child.rate = i and flt(i[3]) or flt(i[4])
-					rm_child.conversion_factor = d.conversion_factor
-					rm_child.required_qty = flt(i	and flt(i[2]) or 0) * flt(d.qty) * flt(d.conversion_factor)
-					rm_child.amount = flt(flt(rm_child.consumed_qty)*flt(rm_child.rate))
-					rm_child.save()
-					chgd_rqd_qty.append(cstr(i[1]))
-				else:
-					act_qty = flt(i	and flt(i[2]) or 0) * flt(d.qty) * flt(d.conversion_factor)
-					for po_rmd in getlist(self.doclist, 'po_raw_material_details'):
-						if i and i[6] == po_rmd.bom_detail_no and (flt(act_qty) != flt(po_rmd.required_qty) or i[1] != po_rmd.rm_item_code):
-							chgd_rqd_qty.append(cstr(i[1]))
-							po_rmd.main_item_code = i[0]
-							po_rmd.rm_item_code = i[1]
-							po_rmd.stock_uom = i[5]
-							po_rmd.required_qty = flt(act_qty)
-							po_rmd.rate = i and flt(i[3]) or flt(i[4])
-							po_rmd.amount = flt(flt(po_rmd.consumed_qty)*flt(po_rmd.rate))
-							
-
-	# Delete irrelevant raw material from PR Raw material details
-	#--------------------------------------------------------------	
-	def delete_irrelevant_raw_material(self):
-		for d in getlist(self.doclist,'po_raw_material_details'):
-			if not sql("select name from `tabPurchase Order Item` where name = '%s' and parent = '%s'and item_code = '%s'" % (d.reference_name, self.doc.name, d.main_item_code)):
-				d.parent = 'old_par:'+self.doc.name
-				d.save()
-		
-	# On Update
-	# ----------------------------------------------------------------------------------------------------		
 	def on_update(self):
-		self.update_rw_material_detail()
+		pass
 		
-
 	def get_rate(self,arg):
 		return get_obj('Purchase Common').get_rate(arg,self)	
 	
diff --git a/buying/doctype/purchase_order/test_purchase_order.py b/buying/doctype/purchase_order/test_purchase_order.py
new file mode 100644
index 0000000..bd27f07
--- /dev/null
+++ b/buying/doctype/purchase_order/test_purchase_order.py
@@ -0,0 +1,65 @@
+# ERPNext - web based ERP (http://erpnext.com)
+# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+# 
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+from __future__ import unicode_literals
+import unittest
+import webnotes
+import webnotes.defaults
+from webnotes.utils import cint
+
+class TestPurchaseOrder(unittest.TestCase):
+	def test_subcontracting(self):
+		po = webnotes.bean(copy=test_records[0])
+		po.insert()		
+		self.assertEquals(len(po.doclist.get({"parentfield": "po_raw_material_details"})), 2)
+
+
+test_dependencies = ["BOM"]
+
+test_records = [
+	[
+		{
+			"company": "_Test Company", 
+			"conversion_rate": 1.0, 
+			"currency": "INR", 
+			"doctype": "Purchase Order", 
+			"fiscal_year": "_Test Fiscal Year 2013", 
+			"transaction_date": "2013-02-12", 
+			"is_subcontracted": "Yes",
+			"supplier": "_Test Supplier",
+			"supplier_name": "_Test Supplier",
+			"net_total": 5000.0, 
+			"grand_total": 5000.0,
+			"grand_total_import": 5000.0,
+			
+		}, 
+		{
+			"conversion_factor": 1.0, 
+			"description": "_Test FG Item", 
+			"doctype": "Purchase Order Item", 
+			"item_code": "_Test FG Item", 
+			"item_name": "_Test FG Item", 
+			"parentfield": "po_details", 
+			"qty": 10.0,
+			"import_rate": 500.0,
+			"amount": 5000.0,
+			"warehouse": "_Test Warehouse", 
+			"stock_uom": "Nos", 
+			"uom": "_Test UOM",
+		}
+	],
+]
\ No newline at end of file
diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py
index 8b247cc..2f3128c 100644
--- a/controllers/buying_controller.py
+++ b/controllers/buying_controller.py
@@ -342,6 +342,67 @@
 					) / flt(d.conversion_factor)
 			else:
 				d.valuation_rate = 0.0
+				
+	def validate_for_subcontracting(self):
+		if not self.doc.is_subcontracted and self.sub_contracted_items:
+			webnotes.msgprint(_("""Please enter whether %s is made for subcontracting or purchasing,
+			 	in 'Is Subcontracted' field""" % self.doc.doctype), raise_exception=1)
+			
+		if self.doc.doctype == "Purchase Receipt" and self.doc.is_subcontracted=="Yes" \
+			and not self.doc.supplier_warehouse:
+				webnotes.msgprint(_("Supplier Warehouse mandatory subcontracted purchase receipt"), 
+					raise_exception=1)
+										
+	def update_raw_materials_supplied(self, raw_material_table):
+		self.doclist = self.doc.clear_table(self.doclist, raw_material_table)
+		if self.doc.is_subcontracted=="Yes":
+			for item in self.doclist.get({"parentfield": self.fname}):
+				if item.item_code in self.sub_contracted_items:
+					self.add_bom_items(item, raw_material_table)
+
+	def add_bom_items(self, d, raw_material_table):
+		bom_items = self.get_items_from_default_bom(d.item_code)
+		raw_materials_cost = 0
+		for item in bom_items:
+			required_qty = flt(item.qty_consumed_per_unit) * flt(d.qty) * flt(d.conversion_factor)
+			rm_doclist = {
+				"parentfield": raw_material_table,
+				"doctype": self.doc.doctype + " Item Supplied",
+				"reference_name": d.name,
+				"bom_detail_no": item.name,
+				"main_item_code": d.item_code,
+				"rm_item_code": item.item_code,
+				"stock_uom": item.stock_uom,
+				"required_qty": required_qty,
+				"conversion_factor": d.conversion_factor,
+				"rate": item.rate,
+				"amount": required_qty * flt(item.rate)
+			}
+			if self.doc.doctype == "Purchase Receipt":
+				rm_doclist.update({
+					"consumed_qty": required_qty,
+					"description": item.description,
+				})
+				
+			self.doclist.append(rm_doclist)
+			
+			raw_materials_cost += required_qty * flt(item.rate)
+			
+		if self.doc.doctype == "Purchase Receipt":
+			d.rm_supp_cost = raw_materials_cost
+
+	def get_items_from_default_bom(self, item_code):
+		# print webnotes.conn.sql("""select name from `tabBOM` where item = '_Test FG Item'""")
+		bom_items = webnotes.conn.sql("""select t2.item_code, t2.qty_consumed_per_unit, 
+			t2.rate, t2.stock_uom, t2.name, t2.description 
+			from `tabBOM` t1, `tabBOM Item` t2 
+			where t2.parent = t1.name and t1.item = %s and t1.is_default = 1 
+			and t1.docstatus = 1 and t1.is_active = 1""", item_code, as_dict=1)
+		if not bom_items:
+			msgprint(_("No default BOM exists for item: ") + item_code, raise_exception=1)
+		
+		return bom_items
+
 	
 	@property
 	def precision(self):
diff --git a/selling/doctype/customer/test_customer.py b/selling/doctype/customer/test_customer.py
index 09e2f5d..551b03f 100644
--- a/selling/doctype/customer/test_customer.py
+++ b/selling/doctype/customer/test_customer.py
@@ -1,3 +1,4 @@
+
 test_records = [
 	[{
 		"doctype": "Customer",
diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py
index 2f8835f..12da0a6 100644
--- a/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -122,7 +122,7 @@
 
 		# sub-contracting
 		self.validate_for_subcontracting()
-		self.update_raw_materials_supplied()
+		self.update_raw_materials_supplied("pr_raw_material_details")
 		
 		self.update_valuation_rate("purchase_receipt_details")
 
@@ -289,59 +289,6 @@
 		
 		self.make_gl_entries()
 
-	def validate_for_subcontracting(self):
-		if not self.doc.is_subcontracted and self.sub_contracted_items:
-			webnotes.msgprint(_("""Please enter whether Purchase Recipt is made for subcontracting 
-				or purchasing, in 'Is Subcontracted' field"""), raise_exception=1)
-			
-		if self.doc.is_subcontracted=="Yes" and not self.doc.supplier_warehouse:
-			webnotes.msgprint(_("Please Enter Supplier Warehouse for subcontracted Items"), 
-				raise_exception=1)
-				
-	def update_raw_materials_supplied(self):
-		self.doclist = self.doc.clear_table(self.doclist, 'pr_raw_material_details')
-		if self.doc.is_subcontracted=="Yes":
-			for item in self.doclist.get({"parentfield": "purchase_receipt_details"}):
-				if item.item_code in self.sub_contracted_items:
-					self.add_bom_items(item)
-
-	def add_bom_items(self, d):
-		bom_items = self.get_items_from_default_bom(d.item_code)
-		raw_materials_cost = 0
-		for item in bom_items:
-			required_qty = flt(item.qty_consumed_per_unit) * flt(d.qty) * flt(d.conversion_factor)
-			self.doclist.append({
-				"parentfield": "pr_raw_material_details",
-				"doctype": "Purchase Receipt Item Supplied",
-				"reference_name": d.name,
-				"bom_detail_no": item.name,
-				"main_item_code": d.item_code,
-				"rm_item_code": item.item_code,
-				"description": item.description,
-				"stock_uom": item.stock_uom,
-				"required_qty": required_qty,
-				"consumed_qty": required_qty,
-				"conversion_factor": d.conversion_factor,
-				"rate": item.rate,
-				"amount": required_qty * flt(item.rate)
-			})
-			
-			raw_materials_cost += required_qty * flt(item.rate)
-			
-		d.rm_supp_cost = raw_materials_cost
-
-	def get_items_from_default_bom(self, item_code):
-		# print webnotes.conn.sql("""select name from `tabBOM` where item = '_Test FG Item'""")
-		bom_items = sql("""select t2.item_code, t2.qty_consumed_per_unit, 
-			t2.rate, t2.stock_uom, t2.name, t2.description 
-			from `tabBOM` t1, `tabBOM Item` t2 
-			where t2.parent = t1.name and t1.item = %s and t1.is_default = 1 
-			and t1.docstatus = 1 and t1.is_active = 1""", item_code, as_dict=1)
-		if not bom_items:
-			msgprint(_("No default BOM exists for item: ") + item_code, raise_exception=1)
-		
-		return bom_items
-
 	def bk_flush_supp_wh(self, is_submit):
 		for d in getlist(self.doclist, 'pr_raw_material_details'):
 			# negative quantity is passed as raw material qty has to be decreased