Merge branch 'master' into edge
diff --git a/hr/doctype/leave_application/leave_application_calendar.js b/hr/doctype/leave_application/leave_application_calendar.js
index eebd559..398664e 100644
--- a/hr/doctype/leave_application/leave_application_calendar.js
+++ b/hr/doctype/leave_application/leave_application_calendar.js
@@ -6,5 +6,12 @@
 		"title": "title",
 		"status": "status",
 	},
+	options: {
+		header: {
+			left: 'prev,next today',
+			center: 'title',
+			right: 'month'
+		}
+	},
 	get_events_method: "hr.doctype.leave_application.leave_application.get_events"
 })
\ No newline at end of file
diff --git a/selling/doctype/lead/get_leads.py b/selling/doctype/lead/get_leads.py
index 5b127e7..b0e6484 100644
--- a/selling/doctype/lead/get_leads.py
+++ b/selling/doctype/lead/get_leads.py
@@ -64,7 +64,7 @@
 		if mail.from_email == self.settings.email_id:
 			return
 		
-		add_sales_communication(mail.subject, mail.content, mail.form_email, 
+		add_sales_communication(mail.mail.get("subject", "[No Subject]"), mail.content, mail.from_email, 
 			mail.from_real_name, mail=mail, date=mail.date)
 
 def get_leads():
diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py
index 797462a..47d139f 100644
--- a/selling/doctype/sales_common/sales_common.py
+++ b/selling/doctype/sales_common/sales_common.py
@@ -384,36 +384,38 @@
 	def get_item_list(self, obj, is_stopped=0):
 		"""get item list"""
 		il = []
-		for d in getlist(obj.doclist,obj.fname):
-			reserved_wh, reserved_qty = '', 0		# used for delivery note
-			qty = flt(d.qty)
-			if is_stopped:
-				qty = flt(d.qty) > flt(d.delivered_qty) and flt(flt(d.qty) - flt(d.delivered_qty)) or 0
+		for d in getlist(obj.doclist, obj.fname):
+			reserved_warehouse = ""
+			reserved_qty_for_main_item = 0
+			
+			if obj.doc.doctype == "Sales Order":
+				reserved_warehouse = d.reserved_warehouse
+				if flt(d.qty) > flt(d.delivered_qty):
+					reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
 				
-			if d.prevdoc_doctype == 'Sales Order':
-				# used in delivery note to reduce reserved_qty 
-				# Eg.: if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
-				# But in this case reserved qty should only be reduced by 10 and not 12.
+			if obj.doc.doctype == "Delivery Note" and d.prevdoc_doctype == 'Sales Order':
+				# if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
+				# But in this case reserved qty should only be reduced by 10 and not 12
+				
+				already_delivered_qty = self.get_already_delivered_qty(obj.doc.name, 
+					d.prevdoc_docname, d.prevdoc_detail_docname)
+				so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname)
+				
+				if already_delivered_qty + d.qty > so_qty:
+					reserved_qty_for_main_item = -(so_qty - already_delivered_qty)
+				else:
+					reserved_qty_for_main_item = -flt(d.qty)
 
-				tot_qty, max_qty, tot_amt, max_amt, reserved_wh = self.get_curr_and_ref_doc_details(d.doctype, 'prevdoc_detail_docname', d.prevdoc_detail_docname, obj.doc.name, obj.doc.doctype)
-				if((flt(tot_qty) + flt(qty) > flt(max_qty))):
-					reserved_qty = -(flt(max_qty)-flt(tot_qty))
-				else:	
-					reserved_qty = - flt(qty)
-					
-			if obj.doc.doctype == 'Sales Order':
-				reserved_wh = d.reserved_warehouse
-						
 			if self.has_sales_bom(d.item_code):
 				for p in getlist(obj.doclist, 'packing_details'):
 					if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
 						# the packing details table's qty is already multiplied with parent's qty
 						il.append({
 							'warehouse': p.warehouse,
-							'reserved_warehouse': reserved_wh,
+							'reserved_warehouse': reserved_warehouse,
 							'item_code': p.item_code,
 							'qty': flt(p.qty),
-							'reserved_qty': (flt(p.qty)/qty)*(reserved_qty),
+							'reserved_qty': (flt(p.qty)/flt(d.qty)) * reserved_qty_for_main_item,
 							'uom': p.uom,
 							'batch_no': cstr(p.batch_no).strip(),
 							'serial_no': cstr(p.serial_no).strip(),
@@ -422,10 +424,10 @@
 			else:
 				il.append({
 					'warehouse': d.warehouse,
-					'reserved_warehouse': reserved_wh,
+					'reserved_warehouse': reserved_warehouse,
 					'item_code': d.item_code,
-					'qty': qty,
-					'reserved_qty': reserved_qty,
+					'qty': d.qty,
+					'reserved_qty': reserved_qty_for_main_item,
 					'uom': d.stock_uom,
 					'batch_no': cstr(d.batch_no).strip(),
 					'serial_no': cstr(d.serial_no).strip(),
@@ -433,27 +435,20 @@
 				})
 		return il
 
+	def get_already_delivered_qty(self, dn, so, so_detail):
+		qty = webnotes.conn.sql("""select sum(qty) from `tabDelivery Note Item` 
+			where prevdoc_detail_docname = %s and docstatus = 1 
+			and prevdoc_doctype = 'Sales Order' and prevdoc_docname = %s 
+			and parent != %s""", (so_detail, so, dn))
+		return qty and flt(qty[0][0]) or 0.0
 
-	def get_curr_and_ref_doc_details(self, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name, curr_parent_doctype):
-		""" Get qty, amount already billed or delivered against curr line item for current doctype
-			For Eg: SO-RV get total qty, amount from SO and also total qty, amount against that SO in RV
-		"""
-		#Get total qty, amt of current doctype (eg RV) except for qty, amt of this transaction
-		if curr_parent_doctype == 'Installation Note':
-			curr_det = webnotes.conn.sql("select sum(qty) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% (curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
-			qty, amt = curr_det and flt(curr_det[0][0]) or 0, 0
-		else:
-			curr_det = webnotes.conn.sql("select sum(qty), sum(amount) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% (curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
-			qty, amt = curr_det and flt(curr_det[0][0]) or 0, curr_det and flt(curr_det[0][1]) or 0
+	def get_so_qty_and_warehouse(self, so_detail):
+		so_item = webnotes.conn.sql("""select qty, reserved_warehouse from `tabSales Order Item`
+			where name = %s and docstatus = 1""", so_detail, as_dict=1)
+		so_qty = so_item and flt(so_item[0]["qty"]) or 0.0
+		so_warehouse = so_item and so_item[0]["reserved_warehouse"] or ""
+		return so_qty, so_warehouse
 
-		# get total qty of ref doctype
-		so_det = webnotes.conn.sql("select qty, amount, reserved_warehouse from `tabSales Order Item` where name = '%s' and docstatus = 1"% ref_tab_dn)
-		max_qty, max_amt, res_wh = so_det and flt(so_det[0][0]) or 0, so_det and flt(so_det[0][1]) or 0, so_det and cstr(so_det[0][2]) or ''
-		return qty, max_qty, amt, max_amt, res_wh
-
-
-	# Make Packing List from Sales BOM
-	# =======================================================================
 	def has_sales_bom(self, item_code):
 		return webnotes.conn.sql("select name from `tabSales BOM` where new_item_code=%s and docstatus != 2", item_code)
 	
diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py
index cebd7e0..8205afb 100644
--- a/selling/doctype/sales_order/sales_order.py
+++ b/selling/doctype/sales_order/sales_order.py
@@ -318,28 +318,28 @@
 
 	def stop_sales_order(self):
 		self.check_modified_date()
-		self.update_stock_ledger(update_stock = -1,clear = 1)
+		self.update_stock_ledger(update_stock = -1,is_stopped = 1)
 		webnotes.conn.set(self.doc, 'status', 'Stopped')
 		msgprint("""%s: %s has been Stopped. To make transactions against this Sales Order 
 			you need to Unstop it.""" % (self.doc.doctype, self.doc.name))
 
 	def unstop_sales_order(self):
 		self.check_modified_date()
-		self.update_stock_ledger(update_stock = 1,clear = 1)
+		self.update_stock_ledger(update_stock = 1,is_stopped = 1)
 		webnotes.conn.set(self.doc, 'status', 'Submitted')
 		msgprint("%s: %s has been Unstopped" % (self.doc.doctype, self.doc.name))
 
 
-	def update_stock_ledger(self, update_stock, clear = 0):
-		for d in self.get_item_list(clear):
+	def update_stock_ledger(self, update_stock, is_stopped = 0):
+		for d in self.get_item_list(is_stopped):
 			if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
 				if not d['reserved_warehouse']:
 					msgprint("""Please enter Reserved Warehouse for item %s 
 						as it is stock Item""" % d['item_code'], raise_exception=1)
-						
+				
 				args = {
 					"item_code": d['item_code'],
-					"reserved_qty": flt(update_stock) * flt(d['qty']),
+					"reserved_qty": flt(update_stock) * flt(d['reserved_qty']),
 					"posting_date": self.doc.transaction_date,
 					"voucher_type": self.doc.doctype,
 					"voucher_no": self.doc.name,
@@ -348,8 +348,8 @@
 				get_obj('Warehouse', d['reserved_warehouse']).update_bin(args)
 				
 				
-	def get_item_list(self, clear):
-		return get_obj('Sales Common').get_item_list( self, clear)
+	def get_item_list(self, is_stopped):
+		return get_obj('Sales Common').get_item_list( self, is_stopped)
 
 	def on_update(self):
 		pass
\ No newline at end of file
diff --git a/selling/doctype/sales_order/test_sales_order.py b/selling/doctype/sales_order/test_sales_order.py
new file mode 100644
index 0000000..5d820fe
--- /dev/null
+++ b/selling/doctype/sales_order/test_sales_order.py
@@ -0,0 +1,253 @@
+import webnotes
+from webnotes.utils import flt
+import unittest
+
+class TestSalesOrder(unittest.TestCase):
+	def create_so(self, so_doclist = None):
+		if not so_doclist:
+			so_doclist =test_records[0]
+			
+		w = webnotes.bean(copy=so_doclist)
+		w.insert()
+		w.submit()
+		return w
+		
+	def create_dn_against_so(self, so, delivered_qty=0):
+		from stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records
+		dn = webnotes.bean(webnotes.copy_doclist(dn_test_records[0]))
+		dn.doclist[1].item_code = so.doclist[1].item_code
+		dn.doclist[1].prevdoc_doctype = "Sales Order"
+		dn.doclist[1].prevdoc_docname = so.doc.name
+		dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name
+		if delivered_qty:
+			dn.doclist[1].qty = delivered_qty
+		dn.insert()
+		dn.submit()
+		return dn
+		
+	def get_bin_reserved_qty(self, item_code, warehouse):
+		return flt(webnotes.conn.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, 
+			"reserved_qty"))
+	
+	def delete_bin(self, item_code, warehouse):
+		bin = webnotes.conn.exists({"doctype": "Bin", "item_code": item_code, 
+			"warehouse": warehouse})
+		if bin:
+			webnotes.delete_doc("Bin", bin[0][0])
+			
+	def check_reserved_qty(self, item_code, warehouse, qty):
+		bin_reserved_qty = self.get_bin_reserved_qty(item_code, warehouse)
+		self.assertEqual(bin_reserved_qty, qty)
+		
+	def test_reserved_qty_for_so(self):
+		# reset bin
+		self.delete_bin(test_records[0][1]["item_code"], test_records[0][1]["reserved_warehouse"])
+		
+		# submit
+		so = self.create_so()
+		self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 10.0)
+		
+		# cancel
+		so.cancel()
+		self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 0.0)
+		
+	
+	def test_reserved_qty_for_partial_delivery(self):
+		# reset bin
+		self.delete_bin(test_records[0][1]["item_code"], test_records[0][1]["reserved_warehouse"])
+		
+		# submit so
+		so = self.create_so()
+		
+		# allow negative stock
+		webnotes.conn.set_default("allow_negative_stock", 1)
+		
+		# submit dn
+		dn = self.create_dn_against_so(so)
+		
+		self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 6.0)
+		
+		# stop so
+		so.load_from_db()
+		so.obj.stop_sales_order()
+		self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 0.0)
+		
+		# unstop so
+		so.load_from_db()
+		so.obj.unstop_sales_order()
+		self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 6.0)
+		
+		# cancel dn
+		dn.cancel()
+		self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 10.0)
+		
+	def test_reserved_qty_for_over_delivery(self):
+		# reset bin
+		self.delete_bin(test_records[0][1]["item_code"], test_records[0][1]["reserved_warehouse"])
+		
+		# submit so
+		so = self.create_so()
+		
+		# allow negative stock
+		webnotes.conn.set_default("allow_negative_stock", 1)
+		
+		# set over-delivery tolerance
+		webnotes.conn.set_value('Item', so.doclist[1].item_code, 'tolerance', 50)
+		
+		# submit dn
+		dn = self.create_dn_against_so(so, 15)
+		self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 0.0)
+
+		# cancel dn
+		dn.cancel()
+		self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 10.0)
+		
+	def test_reserved_qty_for_so_with_packing_list(self):
+		from stock.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records
+		
+		# change item in test so record
+		test_record = test_records[0][:]
+		test_record[1]["item_code"] = "_Test Sales BOM Item"
+		
+		# reset bin
+		self.delete_bin(sbom_test_records[0][1]["item_code"], test_record[1]["reserved_warehouse"])
+		self.delete_bin(sbom_test_records[0][2]["item_code"], test_record[1]["reserved_warehouse"])
+		
+		# submit
+		so = self.create_so(test_record)
+		
+		
+		self.check_reserved_qty(sbom_test_records[0][1]["item_code"], 
+			so.doclist[1].reserved_warehouse, 50.0)
+		self.check_reserved_qty(sbom_test_records[0][2]["item_code"], 
+			so.doclist[1].reserved_warehouse, 20.0)
+		
+		# cancel
+		so.cancel()
+		self.check_reserved_qty(sbom_test_records[0][1]["item_code"], 
+			so.doclist[1].reserved_warehouse, 0.0)
+		self.check_reserved_qty(sbom_test_records[0][2]["item_code"], 
+			so.doclist[1].reserved_warehouse, 0.0)
+			
+	def test_reserved_qty_for_partial_delivery_with_packing_list(self):
+		from stock.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records
+		
+		# change item in test so record
+		
+		test_record = webnotes.copy_doclist(test_records[0])
+		test_record[1]["item_code"] = "_Test Sales BOM Item"
+
+		# reset bin
+		self.delete_bin(sbom_test_records[0][1]["item_code"], test_record[1]["reserved_warehouse"])
+		self.delete_bin(sbom_test_records[0][2]["item_code"], test_record[1]["reserved_warehouse"])
+		
+		# submit
+		so = self.create_so(test_record)
+		
+		# allow negative stock
+		webnotes.conn.set_default("allow_negative_stock", 1)
+		
+		# submit dn
+		dn = self.create_dn_against_so(so)
+		
+		self.check_reserved_qty(sbom_test_records[0][1]["item_code"], 
+			so.doclist[1].reserved_warehouse, 30.0)
+		self.check_reserved_qty(sbom_test_records[0][2]["item_code"], 
+			so.doclist[1].reserved_warehouse, 12.0)
+				
+		# stop so
+		so.load_from_db()
+		so.obj.stop_sales_order()
+		
+		self.check_reserved_qty(sbom_test_records[0][1]["item_code"], 
+			so.doclist[1].reserved_warehouse, 0.0)
+		self.check_reserved_qty(sbom_test_records[0][2]["item_code"], 
+			so.doclist[1].reserved_warehouse, 0.0)
+		
+		# unstop so
+		so.load_from_db()
+		so.obj.unstop_sales_order()
+		self.check_reserved_qty(sbom_test_records[0][1]["item_code"], 
+			so.doclist[1].reserved_warehouse, 30.0)
+		self.check_reserved_qty(sbom_test_records[0][2]["item_code"], 
+			so.doclist[1].reserved_warehouse, 12.0)
+		
+		# cancel dn
+		dn.cancel()
+		self.check_reserved_qty(sbom_test_records[0][1]["item_code"], 
+			so.doclist[1].reserved_warehouse, 50.0)
+		self.check_reserved_qty(sbom_test_records[0][2]["item_code"], 
+			so.doclist[1].reserved_warehouse, 20.0)
+			
+	def test_reserved_qty_for_over_delivery_with_packing_list(self):
+		from stock.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records
+		
+		# change item in test so record
+		test_record = webnotes.copy_doclist(test_records[0])
+		test_record[1]["item_code"] = "_Test Sales BOM Item"
+
+		# reset bin
+		self.delete_bin(sbom_test_records[0][1]["item_code"], test_record[1]["reserved_warehouse"])
+		self.delete_bin(sbom_test_records[0][2]["item_code"], test_record[1]["reserved_warehouse"])
+		
+		# submit
+		so = self.create_so(test_record)
+		
+		# allow negative stock
+		webnotes.conn.set_default("allow_negative_stock", 1)
+		
+		# set over-delivery tolerance
+		webnotes.conn.set_value('Item', so.doclist[1].item_code, 'tolerance', 50)
+		
+		# submit dn
+		dn = self.create_dn_against_so(so, 15)
+		
+		self.check_reserved_qty(sbom_test_records[0][1]["item_code"], 
+			so.doclist[1].reserved_warehouse, 0.0)
+		self.check_reserved_qty(sbom_test_records[0][2]["item_code"], 
+			so.doclist[1].reserved_warehouse, 0.0)
+
+		# cancel dn
+		dn.cancel()
+		self.check_reserved_qty(sbom_test_records[0][1]["item_code"], 
+			so.doclist[1].reserved_warehouse, 50.0)
+		self.check_reserved_qty(sbom_test_records[0][2]["item_code"], 
+			so.doclist[1].reserved_warehouse, 20.0)
+
+test_dependencies = ["Sales BOM"]
+	
+test_records = [
+	[
+		{
+			"company": "_Test Company", 
+			"conversion_rate": 1.0, 
+			"currency": "INR", 
+			"customer": "_Test Customer", 
+			"customer_name": "_Test Customer",
+			"customer_group": "_Test Customer Group", 
+			"doctype": "Sales Order", 
+			"fiscal_year": "_Test Fiscal Year 2013", 
+			"order_type": "Sales",
+			"delivery_date": "2013-02-23",
+			"plc_conversion_rate": 1.0, 
+			"price_list_currency": "INR", 
+			"price_list_name": "_Test Price List", 
+			"territory": "_Test Territory", 
+			"transaction_date": "2013-02-21",
+			"grand_total": 500.0, 
+			"grand_total_export": 500.0, 
+		}, 
+		{
+			"description": "CPU", 
+			"doctype": "Sales Order Item", 
+			"item_code": "_Test Item Home Desktop 100", 
+			"item_name": "CPU", 
+			"parentfield": "sales_order_details", 
+			"qty": 10.0,
+			"basic_rate": 50.0,
+			"export_rate": 50.0,
+			"amount": 500.0,
+			"reserved_warehouse": "_Test Warehouse",
+		}
+	],	
+]
\ No newline at end of file
diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py
index b8d20fb..f54edf2 100644
--- a/stock/doctype/delivery_note/delivery_note.py
+++ b/stock/doctype/delivery_note/delivery_note.py
@@ -319,9 +319,9 @@
 			webnotes.msgprint("%s Packing Slip(s) Cancelled" % res[0][1])
 
 
-	def update_stock_ledger(self, update_stock, is_stopped = 0):
+	def update_stock_ledger(self, update_stock):
 		self.values = []
-		for d in self.get_item_list(is_stopped):
+		for d in self.get_item_list():
 			if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
 				if not d['warehouse']:
 					msgprint("Please enter Warehouse for item %s as it is stock item"
@@ -344,8 +344,8 @@
 		get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values)
 
 
-	def get_item_list(self, is_stopped):
-	 return get_obj('Sales Common').get_item_list(self, is_stopped)
+	def get_item_list(self):
+	 return get_obj('Sales Common').get_item_list(self)
 
 
 	def make_sl_entry(self, d, wh, qty, in_value, update_stock):
diff --git a/stock/doctype/delivery_note/test_delivery_note.py b/stock/doctype/delivery_note/test_delivery_note.py
new file mode 100644
index 0000000..4666360
--- /dev/null
+++ b/stock/doctype/delivery_note/test_delivery_note.py
@@ -0,0 +1,36 @@
+test_records = [
+	[
+		{
+			"company": "_Test Company", 
+			"conversion_rate": 1.0, 
+			"currency": "INR", 
+			"customer": "_Test Customer", 
+			"customer_name": "_Test Customer",
+			"doctype": "Delivery Note", 
+			"fiscal_year": "_Test Fiscal Year 2013", 
+			"plc_conversion_rate": 1.0, 
+			"posting_date": "2013-02-21", 
+			"posting_time": "9:00:00", 
+			"price_list_currency": "INR", 
+			"price_list_name": "_Test Price List", 
+			"status": "Draft", 
+			"territory": "_Test Territory",
+			"grand_total": 500.0, 
+			"grand_total_export": 500.0,
+		}, 
+		{
+			"description": "CPU", 
+			"doctype": "Delivery Note Item", 
+			"item_code": "_Test Item Home Desktop 100", 
+			"item_name": "CPU", 
+			"parentfield": "delivery_note_details", 
+			"qty": 4.0, 
+			"basic_rate": 50.0,
+			"export_rate": 50.0,
+			"amount": 500.0,
+			"warehouse": "_Test Warehouse",
+			"stock_uom": "No."
+		}
+	]
+	
+]
\ No newline at end of file
diff --git a/stock/doctype/item/test_item.py b/stock/doctype/item/test_item.py
index 4238e14..853283e 100644
--- a/stock/doctype/item/test_item.py
+++ b/stock/doctype/item/test_item.py
@@ -145,4 +145,23 @@
 		"is_sub_contracted_item": "No",
 		"stock_uom": "_Test UOM"
 	}],
+	[{
+		"doctype": "Item",
+		"item_code": "_Test Sales BOM Item",
+		"item_name": "_Test Sales BOM Item",
+		"description": "_Test Sales BOM Item",
+		"item_group": "_Test Item Group Desktops",
+		"is_stock_item": "No",
+		"is_asset_item": "No",
+		"has_batch_no": "No",
+		"has_serial_no": "No",
+		"is_purchase_item": "Yes",
+		"is_sales_item": "Yes",
+		"is_service_item": "No",
+		"is_sample_item": "No",
+		"inspection_required": "No",
+		"is_pro_applicable": "No",
+		"is_sub_contracted_item": "No",
+		"stock_uom": "_Test UOM"
+	}],
 ]
\ No newline at end of file
diff --git a/stock/doctype/sales_bom/test_sales_bom.py b/stock/doctype/sales_bom/test_sales_bom.py
new file mode 100644
index 0000000..850616f
--- /dev/null
+++ b/stock/doctype/sales_bom/test_sales_bom.py
@@ -0,0 +1,20 @@
+test_records = [
+	[
+		{
+			"doctype": "Sales BOM", 
+			"new_item_code": "_Test Sales BOM Item"
+		}, 
+		{
+			"doctype": "Sales BOM Item", 
+			"item_code": "_Test Item", 
+			"parentfield": "sales_bom_items", 
+			"qty": 5.0
+		}, 
+		{
+			"doctype": "Sales BOM Item", 
+			"item_code": "_Test Item Home Desktop 100", 
+			"parentfield": "sales_bom_items", 
+			"qty": 2.0
+		}
+	],
+]
\ No newline at end of file