Merge branch 'develop' of github.com:frappe/erpnext into v4-hotfix
diff --git a/erpnext/accounts/doctype/pos_setting/test_pos_setting.py b/erpnext/accounts/doctype/pos_setting/test_pos_setting.py
deleted file mode 100644
index d563be9..0000000
--- a/erpnext/accounts/doctype/pos_setting/test_pos_setting.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-
-import frappe
-test_records = frappe.get_test_records('Pos Setting')
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_setting/test_records.json b/erpnext/accounts/doctype/pos_setting/test_records.json
deleted file mode 100644
index 0d382a7..0000000
--- a/erpnext/accounts/doctype/pos_setting/test_records.json
+++ /dev/null
@@ -1,16 +0,0 @@
-[
- {
-  "cash_bank_account": "_Test Account Bank Account - _TC",
-  "company": "_Test Company",
-  "cost_center": "_Test Cost Center - _TC",
-  "currency": "INR",
-  "doctype": "POS Setting",
-  "expense_account": "_Test Account Cost for Goods Sold - _TC",
-  "income_account": "Sales - _TC",
-  "name": "_Test POS Setting",
-  "naming_series": "_T-POS Setting-",
-  "selling_price_list": "_Test Price List",
-  "territory": "_Test Territory",
-  "warehouse": "_Test Warehouse - _TC"
- }
-]
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 2a0bc24..85e5782 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -6,6 +6,8 @@
 from frappe.utils import flt
 from erpnext.accounts.utils import get_stock_and_account_difference
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
+from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
+
 
 class TestSalesInvoice(unittest.TestCase):
 	def make(self):
@@ -365,27 +367,30 @@
 			561.8)
 
 	def test_time_log_batch(self):
-		tlb = frappe.get_doc("Time Log Batch", "_T-Time Log Batch-00001")
+		delete_time_log_and_batch()
+		time_log = create_time_log()
+		tlb = create_time_log_batch(time_log)
+
+		tlb = frappe.get_doc("Time Log Batch", tlb.name)
 		tlb.submit()
 
 		si = frappe.get_doc(frappe.copy_doc(test_records[0]))
-		si.get("entries")[0].time_log_batch = "_T-Time Log Batch-00001"
+		si.get("entries")[0].time_log_batch = tlb.name
 		si.insert()
 		si.submit()
 
-		self.assertEquals(frappe.db.get_value("Time Log Batch", "_T-Time Log Batch-00001",
-		 	"status"), "Billed")
+		self.assertEquals(frappe.db.get_value("Time Log Batch", tlb.name, "status"), "Billed")
 
-		self.assertEquals(frappe.db.get_value("Time Log", "_T-Time Log-00001", "status"),
-			"Billed")
+		self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Billed")
 
 		si.cancel()
 
-		self.assertEquals(frappe.db.get_value("Time Log Batch", "_T-Time Log Batch-00001",
-			"status"), "Submitted")
+		self.assertEquals(frappe.db.get_value("Time Log Batch", tlb.name, "status"), "Submitted")
 
-		self.assertEquals(frappe.db.get_value("Time Log", "_T-Time Log-00001", "status"),
-			"Batched for Billing")
+		self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Batched for Billing")
+
+		frappe.delete_doc("Sales Invoice", si.name)
+		delete_time_log_and_batch()
 
 	def test_sales_invoice_gl_entry_without_aii(self):
 		self.clear_stock_account_balance()
@@ -423,9 +428,9 @@
 	def test_pos_gl_entry_with_aii(self):
 		self.clear_stock_account_balance()
 		set_perpetual_inventory()
+		self.make_pos_setting()
 
 		self._insert_purchase_receipt()
-		self._insert_pos_settings()
 
 		pos = copy.deepcopy(test_records[1])
 		pos["is_pos"] = 1
@@ -479,6 +484,26 @@
 
 		set_perpetual_inventory(0)
 
+		frappe.db.sql("delete from `tabPOS Setting`")
+
+	def make_pos_setting(self):
+		pos_setting = frappe.get_doc({
+			"cash_bank_account": "_Test Account Bank Account - _TC",
+			"company": "_Test Company",
+			"cost_center": "_Test Cost Center - _TC",
+			"currency": "INR",
+			"doctype": "POS Setting",
+			"expense_account": "_Test Account Cost for Goods Sold - _TC",
+			"income_account": "Sales - _TC",
+			"name": "_Test POS Setting",
+			"naming_series": "_T-POS Setting-",
+			"selling_price_list": "_Test Price List",
+			"territory": "_Test Territory",
+			"warehouse": "_Test Warehouse - _TC"
+		})
+
+		pos_setting.insert()
+
 	def test_si_gl_entry_with_aii_and_update_stock_with_warehouse_but_no_account(self):
 		self.clear_stock_account_balance()
 		set_perpetual_inventory()
@@ -604,14 +629,6 @@
 		dn.submit()
 		return dn
 
-	def _insert_pos_settings(self):
-		from erpnext.accounts.doctype.pos_setting.test_pos_setting \
-			import test_records as pos_setting_test_records
-		frappe.db.sql("""delete from `tabPOS Setting`""")
-
-		ps = frappe.copy_doc(pos_setting_test_records[0])
-		ps.insert()
-
 	def test_sales_invoice_with_advance(self):
 		from erpnext.accounts.doctype.journal_voucher.test_journal_voucher \
 			import test_records as jv_test_records
@@ -843,5 +860,5 @@
 
 		self.assertRaises(SerialNoStatusError, si.submit)
 
-test_dependencies = ["Journal Voucher", "POS Setting", "Contact", "Address"]
+test_dependencies = ["Journal Voucher", "Contact", "Address"]
 test_records = frappe.get_test_records('Sales Invoice')
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 43276e5..ad56d8f 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -256,7 +256,7 @@
 
 			rm_supplied_idx += 1
 
-			raw_materials_cost += required_qty * flt(item.rate)
+			raw_materials_cost += required_qty * flt(bom_item.rate)
 
 		if self.doctype == "Purchase Receipt":
 			item.rm_supp_cost = raw_materials_cost
diff --git a/erpnext/projects/doctype/time_log/test_time_log.py b/erpnext/projects/doctype/time_log/test_time_log.py
index 7aadf5c..4a312ad 100644
--- a/erpnext/projects/doctype/time_log/test_time_log.py
+++ b/erpnext/projects/doctype/time_log/test_time_log.py
@@ -5,11 +5,17 @@
 import unittest
 
 from erpnext.projects.doctype.time_log.time_log import OverlapError
+from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
 
 class TestTimeLog(unittest.TestCase):
 	def test_duplication(self):
+		frappe.db.sql("delete from `tabTime Log`")
+		frappe.get_doc(frappe.copy_doc(test_records[0])).insert()
+
 		ts = frappe.get_doc(frappe.copy_doc(test_records[0]))
 		self.assertRaises(OverlapError, ts.insert)
 
+		frappe.db.sql("delete from `tabTime Log`")
+
 test_records = frappe.get_test_records('Time Log')
 test_ignore = ["Time Log Batch", "Sales Invoice"]
diff --git a/erpnext/projects/doctype/time_log_batch/test_records.json b/erpnext/projects/doctype/time_log_batch/test_records.json
deleted file mode 100644
index d386000..0000000
--- a/erpnext/projects/doctype/time_log_batch/test_records.json
+++ /dev/null
@@ -1,14 +0,0 @@
-[
- {
-  "doctype": "Time Log Batch", 
-  "rate": "500", 
-  "time_log_batch_details": [
-   {
-    "doctype": "Time Log Batch Detail", 
-    "parentfield": "time_log_batch_details", 
-    "parenttype": "Time Log Batch", 
-    "time_log": "_T-Time Log-00001"
-   }
-  ]
- }
-]
\ No newline at end of file
diff --git a/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py b/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py
index dceaee7..de57f28 100644
--- a/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py
+++ b/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py
@@ -4,36 +4,57 @@
 import frappe, unittest
 
 class TimeLogBatchTest(unittest.TestCase):
-	def setUp(self):
-		for name in frappe.db.sql_list("select name from `tabTime Log Batch` where docstatus=1"):
-			frappe.get_doc("Time Log Batch", name).cancel()
-			frappe.delete_doc("Time Log Batch", name)
-
-		for name in frappe.db.sql_list("select name from `tabTime Log` where docstatus=1"):
-			frappe.get_doc("Time Log", name).cancel()
-			frappe.delete_doc("Time Log", name)
-
 	def test_time_log_status(self):
-		from erpnext.projects.doctype.time_log.test_time_log import test_records as time_log_records
-		time_log = frappe.copy_doc(time_log_records[0])
-		time_log.update({
-			"from_time": "2013-01-02 10:00:00.000000",
-			"to_time": "2013-01-02 11:00:00.000000",
-			"docstatus": 0
-		})
-		time_log.insert()
-		time_log.submit()
+		delete_time_log_and_batch()
+		time_log = create_time_log()
 
-		self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Submitted")
-		tlb = frappe.copy_doc(test_records[0])
-		tlb.get("time_log_batch_details")[0].time_log = time_log.name
-		tlb.insert()
-		tlb.submit()
+		self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Submitted")
 
-		self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Batched for Billing")
+		tlb = create_time_log_batch(time_log)
+
+		self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Batched for Billing")
 		tlb.cancel()
-		self.assertEquals(frappe.db.get_value("Time Log", time_log.name, "status"), "Submitted")
+		self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Submitted")
 
-test_records = frappe.get_test_records('Time Log Batch')
-test_dependencies = ["Time Log"]
+		delete_time_log_and_batch()
+
+def delete_time_log_and_batch():
+	for name in frappe.db.sql_list("select name from `tabTime Log Batch` where docstatus=1"):
+		frappe.get_doc("Time Log Batch", name).cancel()
+		frappe.delete_doc("Time Log Batch", name)
+
+	for name in frappe.db.sql_list("select name from `tabTime Log` where docstatus=1"):
+		frappe.get_doc("Time Log", name).cancel()
+		frappe.delete_doc("Time Log", name)
+
+def create_time_log():
+	from erpnext.projects.doctype.time_log.test_time_log import test_records as time_log_records
+	time_log = frappe.copy_doc(time_log_records[0])
+	time_log.update({
+		"from_time": "2013-01-02 10:00:00.000000",
+		"to_time": "2013-01-02 11:00:00.000000",
+		"docstatus": 0
+	})
+	time_log.insert()
+	time_log.submit()
+	return time_log.name
+
+def create_time_log_batch(time_log):
+	tlb = frappe.get_doc({
+		"doctype": "Time Log Batch",
+		"rate": "500",
+		"time_log_batch_details": [
+			{
+			"doctype": "Time Log Batch Detail",
+			"parentfield": "time_log_batch_details",
+			"parenttype": "Time Log Batch",
+			"time_log": time_log
+			}
+		]
+	})
+
+	tlb.insert()
+	tlb.submit()
+	return tlb
+
 test_ignore = ["Sales Invoice"]
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 0aa3acc..77de44d 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -94,8 +94,9 @@
 		pr.run_method("calculate_taxes_and_totals")
 		pr.insert()
 
-		self.assertEquals(pr.get("purchase_receipt_details")[0].rm_supp_cost, 70000.0)
 		self.assertEquals(len(pr.get("pr_raw_material_details")), 2)
+		self.assertEquals(pr.get("purchase_receipt_details")[0].rm_supp_cost, 70000.0)
+
 
 	def test_serial_no_supplier(self):
 		pr = frappe.copy_doc(test_records[0])
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 4739d21..fc60fce 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -256,7 +256,7 @@
 
 		# insert a pos invoice with update stock
 		si = frappe.copy_doc(sales_invoice_test_records[1])
-		si.is_pos = si.update_stock = 1
+		si.update_stock = 1
 		si.get("entries")[0].warehouse = "_Test Warehouse - _TC"
 		si.get("entries")[0].item_code = item_code
 		si.get("entries")[0].qty = 5.0
@@ -663,6 +663,7 @@
 
 	def test_serial_no_not_exists(self):
 		self._clear_stock_account_balance()
+		frappe.db.sql("delete from `tabSerial No` where name in ('ABCD', 'EFGH')")
 		se = frappe.copy_doc(test_records[0])
 		se.purpose = "Material Issue"
 		se.get("mtn_details")[0].item_code = "_Test Serialized Item"
@@ -823,8 +824,6 @@
 	se.submit()
 	return se
 
-test_records = frappe.get_test_records('Stock Entry')
-
 def make_stock_entry(item, source, target, qty, incoming_rate=None):
 	s = frappe.new_doc("Stock Entry")
 	if source and target:
@@ -845,3 +844,5 @@
 	s.insert()
 	s.submit()
 	return s
+
+test_records = frappe.get_test_records('Stock Entry')
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 4bc34d6..fe65f22 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -47,7 +47,7 @@
 			self.reconciliation_json = json.dumps(data)
 
 		def _get_msg(row_num, msg):
-			return _("Row # ") + ("%d: " % (row_num+head_row_no+2)) + _(msg)
+			return _("Row # {0}: ").format(row_num+head_row_no+2) + msg
 
 		self.validation_messages = []
 		item_warehouse_combinations = []
@@ -60,27 +60,30 @@
 		for row_num, row in enumerate(rows):
 			# find duplicates
 			if [row[0], row[1]] in item_warehouse_combinations:
-				self.validation_messages.append(_get_msg(row_num, "Duplicate entry"))
+				self.validation_messages.append(_get_msg(row_num, _("Duplicate entry")))
 			else:
 				item_warehouse_combinations.append([row[0], row[1]])
 
 			self.validate_item(row[0], row_num+head_row_no+2)
-			# note: warehouse will be validated through link validation
+
+			# validate warehouse
+			if not frappe.db.get_value("Warehouse", row[1]):
+				self.validation_messages.append(_get_msg(row_num, _("Warehouse not found in the system")))
 
 			# if both not specified
 			if row[2] == "" and row[3] == "":
 				self.validation_messages.append(_get_msg(row_num,
-					"Please specify either Quantity or Valuation Rate or both"))
+					_("Please specify either Quantity or Valuation Rate or both")))
 
 			# do not allow negative quantity
 			if flt(row[2]) < 0:
 				self.validation_messages.append(_get_msg(row_num,
-					"Negative Quantity is not allowed"))
+					_("Negative Quantity is not allowed")))
 
 			# do not allow negative valuation
 			if flt(row[3]) < 0:
 				self.validation_messages.append(_get_msg(row_num,
-					"Negative Valuation Rate is not allowed"))
+					_("Negative Valuation Rate is not allowed")))
 
 		# throw all validation messages
 		if self.validation_messages:
@@ -97,6 +100,8 @@
 
 		try:
 			item = frappe.get_doc("Item", item_code)
+			if not item:
+				raise frappe.ValidationError, (_("Item: {0} not found in the system").format(item_code))
 
 			# end of life and stock item
 			validate_end_of_life(item_code, item.end_of_life, verbose=0)
@@ -104,12 +109,13 @@
 
 			# item should not be serialized
 			if item.has_serial_no == "Yes":
-				raise frappe.ValidationError, _("Serialized Item {0} cannot be updated using Stock Reconciliation").format(item_code)
+				raise frappe.ValidationError, _("Serialized Item {0} cannot be updated \
+					using Stock Reconciliation").format(item_code)
 
 			# item managed batch-wise not allowed
 			if item.has_batch_no == "Yes":
-				frappe.throw(_("Item: {0} managed batch-wise, can not be reconciled using \
-					Stock Reconciliation, instead use Stock Entry").format(item_code))
+				raise frappe.ValidationError, _("Item: {0} managed batch-wise, can not be reconciled using \
+					Stock Reconciliation, instead use Stock Entry").format(item_code)
 
 			# docstatus should be < 2
 			validate_cancelled_item(item_code, item.docstatus, verbose=0)