Merge pull request #3968 from rmehta/task-not-mandatory

[minor] task not mandatory for Time Log and Expense Claim #3904
diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.js b/erpnext/accounts/page/accounts_browser/accounts_browser.js
index 77a87ff..157a924 100644
--- a/erpnext/accounts/page/accounts_browser/accounts_browser.js
+++ b/erpnext/accounts/page/accounts_browser/accounts_browser.js
@@ -42,13 +42,13 @@
 		wrapper.page.add_menu_item(__('New Company'), function() { newdoc('Company'); }, true);
 	}
 
-	wrapper.page.set_secondary_action(__('Refresh'), function() {
+	wrapper.page.add_menu_item(__('Refresh'), function() {
 			wrapper.$company_select.change();
 		});
 
 	wrapper.page.set_primary_action(__('New'), function() {
 		erpnext.account_chart && erpnext.account_chart.make_new();
-	});
+	}, "octicon octicon-plus");
 
 	// company-select
 	wrapper.$company_select = wrapper.page.add_select("Company", [])
@@ -121,7 +121,8 @@
 					label: __("Add Child"),
 					click: function() {
 						me.make_new()
-					}
+					},
+					btnClass: "hidden-xs"
 				},
 				{
 					condition: function(node) {
@@ -137,8 +138,8 @@
 							"company": me.company
 						};
 						frappe.set_route("query-report", "General Ledger");
-					}
-
+					},
+					btnClass: "hidden-xs"
 				},
 				{
 					condition: function(node) { return !node.root && me.can_write },
@@ -147,7 +148,8 @@
 						frappe.model.rename_doc(me.ctype, node.label, function(new_name) {
 							node.reload();
 						});
-					}
+					},
+					btnClass: "hidden-xs"
 				},
 				{
 					condition: function(node) { return !node.root && me.can_delete },
@@ -156,7 +158,8 @@
 						frappe.model.delete_doc(me.ctype, node.label, function() {
 							node.parent.remove();
 						});
-					}
+					},
+					btnClass: "hidden-xs"
 				}
 			],
 			onrender: function(node) {
diff --git a/erpnext/change_log/current/activity_type.md b/erpnext/change_log/current/activity_type.md
new file mode 100644
index 0000000..1fa158f
--- /dev/null
+++ b/erpnext/change_log/current/activity_type.md
@@ -0,0 +1,2 @@
+- Set default costing rate and billing rate in **Activity Type**
+- Task not mandatory in **Time Log** and **Expense Claim**
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json
index 2bd20b8..e3293ed 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.json
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.json
@@ -456,12 +456,13 @@
    "unique": 0
   }, 
   {
-   "allow_on_submit": 0, 
+   "allow_on_submit": 1, 
    "bold": 0, 
    "collapsible": 0, 
+   "default": "{employee_name}", 
    "fieldname": "title", 
    "fieldtype": "Data", 
-   "hidden": 0, 
+   "hidden": 1, 
    "ignore_user_permissions": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
@@ -535,13 +536,33 @@
  "is_submittable": 1, 
  "issingle": 0, 
  "istable": 0, 
- "modified": "2015-05-02 07:42:25.202983", 
+ "modified": "2015-09-01 07:11:25.759637", 
  "modified_by": "Administrator", 
  "module": "HR", 
  "name": "Expense Claim", 
  "owner": "harshada@webnotestech.com", 
  "permissions": [
   {
+   "amend": 1, 
+   "apply_user_permissions": 0, 
+   "cancel": 1, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "HR Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 1, 
+   "write": 1
+  }, 
+  {
    "amend": 0, 
    "apply_user_permissions": 1, 
    "cancel": 0, 
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index 112a626..ef15e78 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -20,22 +20,27 @@
 		validate_fiscal_year(self.posting_date, self.fiscal_year, _("Posting Date"), self)
 		self.validate_sanctioned_amount()
 		self.validate_expense_approver()
-		self.validate_task()
 		self.calculate_total_amount()
 		set_employee_name(self)
+		if self.task and not self.project:
+			self.project = frappe.db.get_value("Task", self.task, "project")
 
 	def on_submit(self):
 		if self.approval_status=="Draft":
 			frappe.throw(_("""Approval Status must be 'Approved' or 'Rejected'"""))
-		if self.task:
-			self.update_task()
-			
+		self.update_task_and_project()
+
 	def on_cancel(self):
+		self.update_task_and_project()
+
+	def update_task_and_project(self):
 		if self.task:
 			self.update_task()
-			
+		elif self.project:
+			frappe.get_doc("Project", self.project).update_project()
+
 	def calculate_total_amount(self):
-		self.total_claimed_amount = 0 
+		self.total_claimed_amount = 0
 		self.total_sanctioned_amount = 0
 		for d in self.get('expenses'):
 			self.total_claimed_amount += flt(d.claim_amount)
@@ -45,26 +50,22 @@
 		if self.exp_approver and "Expense Approver" not in frappe.get_roles(self.exp_approver):
 			frappe.throw(_("{0} ({1}) must have role 'Expense Approver'")\
 				.format(get_fullname(self.exp_approver), self.exp_approver), InvalidExpenseApproverError)
-	
+
 	def update_task(self):
 		task = frappe.get_doc("Task", self.task)
 		task.update_total_expense_claim()
 		task.save()
 
-	def validate_task(self):
-		if self.project and not self.task:
-			frappe.throw(_("Task is mandatory if Expense Claim is against a Project"))
-
 	def validate_sanctioned_amount(self):
 		for d in self.get('expenses'):
 			if flt(d.sanctioned_amount) > flt(d.claim_amount):
 				frappe.throw(_("Sanctioned Amount cannot be greater than Claim Amount in Row {0}.").format(d.idx))
-				
+
 
 @frappe.whitelist()
 def get_expense_approver(doctype, txt, searchfield, start, page_len, filters):
 	return frappe.db.sql("""
-		select u.name, concat(u.first_name, ' ', u.last_name) 
+		select u.name, concat(u.first_name, ' ', u.last_name)
 		from tabUser u, tabUserRole r
 		where u.name = r.parent and r.role = 'Expense Approver' and u.name like %s
-	""", ("%" + txt + "%"))
\ No newline at end of file
+	""", ("%" + txt + "%"))
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index a9091fb..b21f2a1 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -11,44 +11,47 @@
 	def test_total_expense_claim_for_project(self):
 		frappe.db.sql("""delete from `tabTask` where project = "_Test Project 1" """)
 		frappe.db.sql("""delete from `tabProject` where name = "_Test Project 1" """)
-		
+		frappe.db.sql("""delete from `tabExpense Claim`""")
+		frappe.db.sql("""delete from `tabExpense Claim Detail`""")
+
 		frappe.get_doc({
 			"project_name": "_Test Project 1",
 			"doctype": "Project",
 			"tasks" :
 				[{ "title": "_Test Project Task 1", "status": "Open" }]
 		}).save()
-		
-		task_name = frappe.db.get_value("Task",{"project": "_Test Project 1"})
+
+		task_name = frappe.db.get_value("Task", {"project": "_Test Project 1"})
+
 		expense_claim = frappe.get_doc({
 			 "doctype": "Expense Claim",
 			 "employee": "_T-Employee-0001",
 			 "approval_status": "Approved",
 			 "project": "_Test Project 1",
 			 "task": task_name,
-			 "expenses": 
+			 "expenses":
 			 	[{ "expense_type": "Food", "claim_amount": 300, "sanctioned_amount": 200 }]
 		})
 		expense_claim.submit()
-		
+
 		self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
 		self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
-		
+
 		expense_claim2 = frappe.get_doc({
 			 "doctype": "Expense Claim",
 			 "employee": "_T-Employee-0001",
 			 "approval_status": "Approved",
 			 "project": "_Test Project 1",
 			 "task": task_name,
-			 "expenses": 
+			 "expenses":
 			 	[{ "expense_type": "Food", "claim_amount": 600, "sanctioned_amount": 500 }]
 		})
 		expense_claim2.submit()
-		
+
 		self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 700)
 		self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 700)
-		
+
 		expense_claim2.cancel()
-		
+
 		self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
 		self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 5f7dd91..0941b4f 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -201,3 +201,4 @@
 
 # V6.0
 erpnext.patches.v6_0.set_default_title # 2015-09-03
+erpnext.patches.v6_0.default_activity_rate
diff --git a/erpnext/patches/v6_0/default_activity_rate.py b/erpnext/patches/v6_0/default_activity_rate.py
new file mode 100644
index 0000000..90a7a8c
--- /dev/null
+++ b/erpnext/patches/v6_0/default_activity_rate.py
@@ -0,0 +1,11 @@
+import frappe
+
+def execute():
+	for cost in frappe.db.get_list("Activity Cost", filters = {"employee": ""},
+		fields = ("name", "activity_type", "costing_rate", "billing_rate")):
+		activity_type = frappe.get_doc("Activity Type", cost.activity_type)
+		activity_type.costing_rate = cost.costing_rate
+		activity_type.billing_rate = cost.billing_rate
+		activity_type.save()
+
+		frappe.delete_doc("Activity Cost", cost.name)
diff --git a/erpnext/projects/doctype/activity_cost/activity_cost.json b/erpnext/projects/doctype/activity_cost/activity_cost.json
index f6898f8..88f9116 100644
--- a/erpnext/projects/doctype/activity_cost/activity_cost.json
+++ b/erpnext/projects/doctype/activity_cost/activity_cost.json
@@ -7,7 +7,7 @@
  "custom": 0, 
  "docstatus": 0, 
  "doctype": "DocType", 
- "document_type": "Master", 
+ "document_type": "Setup", 
  "fields": [
   {
    "allow_on_submit": 0, 
@@ -219,7 +219,7 @@
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 0, 
- "modified": "2015-06-16 03:12:25.644839", 
+ "modified": "2015-08-31 06:43:42.804365", 
  "modified_by": "Administrator", 
  "module": "Projects", 
  "name": "Activity Cost", 
diff --git a/erpnext/projects/doctype/activity_type/activity_type.js b/erpnext/projects/doctype/activity_type/activity_type.js
new file mode 100644
index 0000000..f7bb9a5
--- /dev/null
+++ b/erpnext/projects/doctype/activity_type/activity_type.js
@@ -0,0 +1,8 @@
+frappe.ui.form.on("Activity Type", {
+	refresh: function(frm) {
+		frm.add_custom_button("Activity Cost per Employee", function() {
+			frappe.route_options = {"activity_type": frm.doc.name};
+			frappe.set_route("List", "Activity Cost");
+		});
+	}
+});
diff --git a/erpnext/projects/doctype/activity_type/activity_type.json b/erpnext/projects/doctype/activity_type/activity_type.json
index 63aa088..4cb6c43 100644
--- a/erpnext/projects/doctype/activity_type/activity_type.json
+++ b/erpnext/projects/doctype/activity_type/activity_type.json
@@ -7,7 +7,7 @@
  "custom": 0, 
  "docstatus": 0, 
  "doctype": "DocType", 
- "document_type": "Master", 
+ "document_type": "Setup", 
  "fields": [
   {
    "allow_on_submit": 0, 
@@ -29,6 +29,71 @@
    "search_index": 0, 
    "set_only_once": 0, 
    "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "costing_rate", 
+   "fieldtype": "Currency", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Default Costing Rate", 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "column_break_3", 
+   "fieldtype": "Column Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "billing_rate", 
+   "fieldtype": "Currency", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Default Billing Rate", 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
   }
  ], 
  "hide_heading": 0, 
@@ -40,7 +105,7 @@
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 0, 
- "modified": "2015-02-18 13:05:23.608066", 
+ "modified": "2015-08-31 06:39:04.527080", 
  "modified_by": "Administrator", 
  "module": "Projects", 
  "name": "Activity Type", 
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index de1c3f8..8e126aa 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -46,8 +46,6 @@
 		"""sync tasks and remove table"""
 		if self.flags.dont_sync_tasks: return
 
-
-		task_added_or_deleted = False
 		task_names = []
 		for t in self.tasks:
 			if t.task_id:
@@ -55,7 +53,6 @@
 			else:
 				task = frappe.new_doc("Task")
 				task.project = self.name
-				task_added_or_deleted = True
 
 			task.update({
 				"subject": t.title,
@@ -73,14 +70,15 @@
 		# delete
 		for t in frappe.get_all("Task", ["name"], {"project": self.name, "name": ("not in", task_names)}):
 			frappe.delete_doc("Task", t.name)
-			task_added_or_deleted = True
 
-		if task_added_or_deleted:
-			self.update_project()
+		self.update_percent_complete()
+		self.update_costing()
 
 	def update_project(self):
 		self.update_percent_complete()
 		self.update_costing()
+		self.flags.dont_sync_tasks = True
+		self.save()
 
 	def update_percent_complete(self):
 		total = frappe.db.sql("""select count(*) from tabTask where project=%s""", self.name)[0][0]
@@ -91,18 +89,31 @@
 			self.percent_complete = flt(completed) / total * 100
 
 	def update_costing(self):
-		total_cost = frappe.db.sql("""select sum(ifnull(total_costing_amount, 0)) as costing_amount,
-			sum(ifnull(total_billing_amount, 0)) as billing_amount, sum(ifnull(total_expense_claim, 0)) as expense_claim,
-			min(act_start_date) as start_date, max(act_end_date) as end_date, sum(actual_time) as time
-			from `tabTask` where project = %s""", self.name, as_dict=1)[0]
+		from_time_log = frappe.db.sql("""select
+			sum(ifnull(costing_amount, 0)) as costing_amount,
+			sum(ifnull(billing_amount, 0)) as billing_amount,
+			min(from_time) as start_date,
+			max(to_time) as end_date,
+			sum(hours) as time
+			from `tabTime Log` where project = %s and docstatus = 1""", self.name, as_dict=1)[0]
 
-		self.total_costing_amount = total_cost.costing_amount
-		self.total_billing_amount = total_cost.billing_amount
-		self.total_expense_claim = total_cost.expense_claim
-		self.actual_start_date = total_cost.start_date
-		self.actual_end_date = total_cost.end_date
-		self.actual_time = total_cost.time
-		self.gross_margin = flt(total_cost.billing_amount) - flt(total_cost.costing_amount)
+		from_expense_claim = frappe.db.sql("""select
+			sum(ifnull(total_sanctioned_amount, 0)) as total_sanctioned_amount
+			from `tabExpense Claim` where project = %s and approval_status='Approved'
+			and docstatus = 1""",
+			self.name, as_dict=1)[0]
+
+		self.actual_start_date = from_time_log.start_date
+		self.actual_end_date = from_time_log.end_date
+
+		self.total_costing_amount = from_time_log.costing_amount
+		self.total_billing_amount = from_time_log.billing_amount
+		self.actual_time = from_time_log.time
+
+		self.total_expense_claim = from_expense_claim.total_sanctioned_amount
+
+		self.gross_margin = flt(self.total_billing_amount) - flt(self.total_costing_amount)
+
 		if self.total_billing_amount:
 			self.per_gross_margin = (self.gross_margin / flt(self.total_billing_amount)) *100
 
diff --git a/erpnext/projects/doctype/project/project_list.js b/erpnext/projects/doctype/project/project_list.js
index b0d1ae8..437bf60 100644
--- a/erpnext/projects/doctype/project/project_list.js
+++ b/erpnext/projects/doctype/project/project_list.js
@@ -3,7 +3,7 @@
 	filters:[["status","=", "Open"]],
 	get_indicator: function(doc) {
 		if(doc.status=="Open" && doc.percent_complete) {
-			return [__("{0}% Complete", [doc.percent_complete]), "orange", "percent_complete,>,0|status,=,Open"];
+			return [__("{0}% Complete", [cint(doc.percent_complete)]), "orange", "percent_complete,>,0|status,=,Open"];
 		} else {
 			return [__(doc.status), frappe.utils.guess_colour(doc.status), "status,=," + doc.status];
 		}
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 28cfcd3..e5b3355 100644
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -57,7 +57,7 @@
 
 	def update_time_and_costing(self):
 		tl = frappe.db.sql("""select min(from_time) as start_date, max(to_time) as end_date,
-			 sum(billing_amount) as total_billing_amount, sum(costing_amount) as total_costing_amount,
+			sum(billing_amount) as total_billing_amount, sum(costing_amount) as total_costing_amount,
 			sum(hours) as time from `tabTime Log` where task = %s and docstatus=1"""
 			,self.name, as_dict=1)[0]
 		if self.status == "Open":
@@ -70,10 +70,7 @@
 
 	def update_project(self):
 		if self.project and not self.flags.from_project:
-			project = frappe.get_doc("Project", self.project)
-			project.flags.dont_sync_tasks = True
-			project.update_project()
-			project.save()
+			frappe.get_doc("Project", self.project).update_project()
 
 	def check_recursion(self):
 		if self.flags.ignore_recursion_check: return
diff --git a/erpnext/projects/doctype/time_log/test_time_log.py b/erpnext/projects/doctype/time_log/test_time_log.py
index 9bdf588..1894e37 100644
--- a/erpnext/projects/doctype/time_log/test_time_log.py
+++ b/erpnext/projects/doctype/time_log/test_time_log.py
@@ -26,21 +26,21 @@
 		prod_order.set_production_order_operations()
 		prod_order.save()
 
-		time_log = make_time_log_test_record(for_manufacturing= 1, production_order= prod_order.name, qty= 1, 
+		time_log = make_time_log_test_record(for_manufacturing= 1, production_order= prod_order.name, qty= 1,
 			employee= "_T-Employee-0003", do_not_save= True, simulate=1)
 
 		self.assertRaises(NotSubmittedError, time_log.save)
 
 	def test_time_log_on_holiday(self):
-		prod_order = make_prod_order_test_record(item= "_Test FG Item 2", qty= 1, 
+		prod_order = make_prod_order_test_record(item= "_Test FG Item 2", qty= 1,
 			planned_start_date= now(), do_not_save= True)
 		prod_order.set_production_order_operations()
 		prod_order.save()
 		prod_order.submit()
 
 		time_log = make_time_log_test_record(from_time= "2013-02-01 10:00:00", to_time= "2013-02-01 20:00:00",
-			for_manufacturing= 1, production_order= prod_order.name, qty= 1, 
-			operation= prod_order.operations[0].operation, operation_id= prod_order.operations[0].name, 
+			for_manufacturing= 1, production_order= prod_order.name, qty= 1,
+			operation= prod_order.operations[0].operation, operation_id= prod_order.operations[0].name,
 			workstation= "_Test Workstation 1", do_not_save= True)
 
 		self.assertRaises(WorkstationHolidayError , time_log.save)
@@ -61,59 +61,81 @@
 			employee="_T-Employee-0006",do_not_save= True)
 		self.assertRaises(NegativeHoursError, time_log.save)
 
+	def test_default_activity_cost(self):
+		activity_type = frappe.get_doc("Activity Type", "_Test Activity Type")
+		activity_type.billing_rate = 20
+		activity_type.costing_rate = 15
+		activity_type.save()
+
+		project_name = "_Test Project for Activity Type"
+
+		frappe.db.sql("delete from `tabTime Log` where project=%s or employee='_T-Employee-0002'", project_name)
+		frappe.delete_doc("Project", project_name)
+		project = frappe.get_doc({"doctype": "Project", "project_name": project_name}).insert()
+
+		make_time_log_test_record(employee="_T-Employee-0002", hours=2,
+			activity_type = "_Test Activity Type", project = project.name)
+
+		project = frappe.get_doc("Project", project.name)
+		self.assertTrue(project.total_costing_amount, 30)
+		self.assertTrue(project.total_billing_amount, 40)
+
 	def test_total_activity_cost_for_project(self):
 		frappe.db.sql("""delete from `tabTask` where project = "_Test Project 1" """)
 		frappe.db.sql("""delete from `tabProject` where name = "_Test Project 1" """)
-		
+		frappe.db.sql("""delete from `tabTime Log` where name = "_Test Project 1" """)
+
 		if not frappe.db.exists('Activity Cost', {"activity_type": "_Test Activity Type"}):
 			activity_cost = frappe.get_doc({
 				"doctype": "Activity Cost",
-				"employee": "",
+				"employee": "_T-Employee-0002",
 				"activity_type": "_Test Activity Type",
 				"billing_rate": 100,
 				"costing_rate": 50
 			})
 			activity_cost.insert()
-		
+
 		frappe.get_doc({
 			"project_name": "_Test Project 1",
 			"doctype": "Project",
 			"tasks" :
 				[{ "title": "_Test Project Task 1", "status": "Open" }]
 		}).save()
-		
+
 		task_name = frappe.db.get_value("Task",{"project": "_Test Project 1"})
-		
-		time_log = make_time_log_test_record(employee="_T-Employee-0002", hours=2, task= task_name)
+
+		time_log = make_time_log_test_record(employee="_T-Employee-0002", hours=2,
+			task=task_name)
 		self.assertEqual(time_log.costing_rate, 50)
 		self.assertEqual(time_log.costing_amount, 100)
 		self.assertEqual(time_log.billing_rate, 100)
 		self.assertEqual(time_log.billing_amount, 200)
-		
+
 		self.assertEqual(frappe.db.get_value("Task", task_name, "total_billing_amount"), 200)
 		self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_billing_amount"), 200)
-		
-		time_log2 = make_time_log_test_record(employee="_T-Employee-0003", hours=2, task= task_name)
+
+		time_log2 = make_time_log_test_record(employee="_T-Employee-0002",
+			hours=2, task= task_name, from_time = now_datetime() + datetime.timedelta(hours= 3))
 		self.assertEqual(frappe.db.get_value("Task", task_name, "total_billing_amount"), 400)
 		self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_billing_amount"), 400)
-		
+
 		time_log2.cancel()
-		
+
 		self.assertEqual(frappe.db.get_value("Task", task_name, "total_billing_amount"), 200)
 		self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_billing_amount"), 200)
 		time_log.cancel()
-		
+
 test_ignore = ["Time Log Batch", "Sales Invoice"]
 
 def make_time_log_test_record(**args):
 	args = frappe._dict(args)
 
 	time_log = frappe.new_doc("Time Log")
-	
+
 	time_log.from_time = args.from_time or now_datetime()
 	time_log.hours = args.hours or 1
 	time_log.to_time = args.to_time or time_log.from_time + datetime.timedelta(hours= time_log.hours)
-	
+
 	time_log.project = args.project
 	time_log.task = args.task
 	time_log.for_manufacturing = args.for_manufacturing
@@ -126,7 +148,7 @@
 	time_log.billable = args.billable or 1
 	time_log.employee = args.employee
 	time_log.user = args.user
-	
+
 	if not args.do_not_save:
 		if args.simulate:
 			while True:
@@ -141,4 +163,4 @@
 		if not args.do_not_submit:
 			time_log.submit()
 
-	return time_log
\ No newline at end of file
+	return time_log
diff --git a/erpnext/projects/doctype/time_log/time_log.js b/erpnext/projects/doctype/time_log/time_log.js
index 776a75b..5fce970 100644
--- a/erpnext/projects/doctype/time_log/time_log.js
+++ b/erpnext/projects/doctype/time_log/time_log.js
@@ -17,6 +17,8 @@
 	if (frm.doc.__islocal && !frm.doc.user) {
 		frm.set_value("user", user);
 	}
+
+	frm.toggle_reqd("activity_type", !frm.doc.for_manufacturing);
 });
 
 
diff --git a/erpnext/projects/doctype/time_log/time_log.json b/erpnext/projects/doctype/time_log/time_log.json
index e349859..76bc0ef 100644
--- a/erpnext/projects/doctype/time_log/time_log.json
+++ b/erpnext/projects/doctype/time_log/time_log.json
@@ -8,7 +8,7 @@
  "description": "Log of Activities performed by users against Tasks that can be used for tracking time, billing.", 
  "docstatus": 0, 
  "doctype": "DocType", 
- "document_type": "Master", 
+ "document_type": "Setup", 
  "fields": [
   {
    "allow_on_submit": 0, 
@@ -185,6 +185,29 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "depends_on": "eval:!doc.for_manufacturing", 
+   "fieldname": "activity_type", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Activity Type", 
+   "no_copy": 0, 
+   "options": "Activity Type", 
+   "permlevel": 0, 
+   "print_hide": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
    "depends_on": "", 
    "fieldname": "project", 
    "fieldtype": "Link", 
@@ -231,29 +254,6 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "depends_on": "eval:!doc.for_manufacturing", 
-   "fieldname": "activity_type", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "label": "Activity Type", 
-   "no_copy": 0, 
-   "options": "Activity Type", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "read_only": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
    "fieldname": "section_break_12", 
    "fieldtype": "Section Break", 
    "hidden": 0, 
@@ -618,7 +618,7 @@
    "ignore_user_permissions": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
-   "label": "Costing Rate (per hour)", 
+   "label": "Costing Rate based on Activity Type (per hour)", 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
@@ -686,7 +686,7 @@
    "ignore_user_permissions": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
-   "label": "Billing Rate (per hour)", 
+   "label": "Billing Rate based on Activity Type (per hour)", 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
@@ -812,7 +812,7 @@
    "unique": 0
   }, 
   {
-   "allow_on_submit": 0, 
+   "allow_on_submit": 1, 
    "bold": 0, 
    "collapsible": 0, 
    "fieldname": "title", 
@@ -843,7 +843,7 @@
  "is_submittable": 1, 
  "issingle": 0, 
  "istable": 0, 
- "modified": "2015-04-14 09:07:28.468792", 
+ "modified": "2015-08-31 06:34:07.703583", 
  "modified_by": "Administrator", 
  "module": "Projects", 
  "name": "Time Log", 
diff --git a/erpnext/projects/doctype/time_log/time_log.py b/erpnext/projects/doctype/time_log/time_log.py
index ed89307..cde733d 100644
--- a/erpnext/projects/doctype/time_log/time_log.py
+++ b/erpnext/projects/doctype/time_log/time_log.py
@@ -26,16 +26,16 @@
 		self.check_workstation_timings()
 		self.validate_production_order()
 		self.validate_manufacturing()
-		self.validate_task()
+		self.set_project_if_missing()
 		self.update_cost()
 
 	def on_submit(self):
 		self.update_production_order()
-		self.update_task()
+		self.update_task_and_project()
 
 	def on_cancel(self):
 		self.update_production_order()
-		self.update_task()
+		self.update_task_and_project()
 
 	def before_update_after_submit(self):
 		self.set_status()
@@ -57,14 +57,17 @@
 			self.status="Billed"
 
 	def set_title(self):
+		"""Set default title for the Time Log"""
+		if self.title:
+			return
+
+		from frappe.utils import get_fullname
 		if self.production_order:
 			self.title = _("{0} for {1}").format(self.operation, self.production_order)
-		elif self.task:
-			self.title = _("{0} for {1}").format(self.activity_type, self.task)
-		elif self.project:
-			self.title = _("{0} for {1}").format(self.activity_type, self.project)
+		elif self.activity_type and (self.task or self.project):
+			self.title = _("{0} for {1}").format(self.activity_type, self.task or self.project)
 		else:
-			self.title = self.activity_type
+			self.title = self.task or self.project or get_fullname(frappe.session.user)
 
 	def validate_overlap(self):
 		"""Checks if 'Time Log' entries overlap for a user, workstation. """
@@ -111,6 +114,11 @@
 			from frappe.utils import time_diff_in_seconds
 			self.hours = flt(time_diff_in_seconds(self.to_time, self.from_time)) / 3600
 
+	def set_project_if_missing(self):
+		"""Set project if task is set"""
+		if self.task and not self.project:
+			self.project = frappe.db.get_value("Task", self.task, "project")
+
 	def validate_time_log_for(self):
 		if not self.for_manufacturing:
 			for fld in ["production_order", "operation", "workstation", "completed_qty"]:
@@ -221,25 +229,26 @@
 	def update_cost(self):
 		rate = get_activity_cost(self.employee, self.activity_type)
 		if rate:
-			self.costing_rate = rate.get('costing_rate')
-			self.billing_rate = rate.get('billing_rate')
+			self.costing_rate = flt(rate.get('costing_rate'))
+			self.billing_rate = flt(rate.get('billing_rate'))
 			self.costing_amount = self.costing_rate * self.hours
 			if self.billable:
 				self.billing_amount = self.billing_rate * self.hours
 			else:
 				self.billing_amount = 0
 
-	def validate_task(self):
-		# if a time log is being created against a project without production order
-		if (self.project and not self.production_order) and not self.task:
-			frappe.throw(_("Task is Mandatory if Time Log is against a project"))
+	def update_task_and_project(self):
+		"""Update costing rate in Task or Project if either is set"""
 
-	def update_task(self):
-		if self.task and frappe.db.exists("Task", self.task):
+		if self.task:
 			task = frappe.get_doc("Task", self.task)
 			task.update_time_and_costing()
 			task.save()
 
+		elif self.project:
+			frappe.get_doc("Project", self.project).update_project()
+
+
 @frappe.whitelist()
 def get_events(start, end, filters=None):
 	"""Returns events for Gantt / Calendar view rendering.
@@ -270,9 +279,10 @@
 
 @frappe.whitelist()
 def get_activity_cost(employee=None, activity_type=None):
-	rate = frappe.db.sql("""select costing_rate, billing_rate from `tabActivity Cost` where employee= %s
-		and activity_type= %s""", (employee, activity_type), as_dict=1)
+	rate = frappe.db.get_values("Activity Cost", {"employee": employee,
+		"activity_type": activity_type}, ["costing_rate", "billing_rate"], as_dict=True)
 	if not rate:
-		rate = frappe.db.sql("""select costing_rate, billing_rate from `tabActivity Cost` where ifnull(employee, '')=''
-			and activity_type= %s""", (activity_type), as_dict=1)
+		rate = frappe.db.get_values("Activity Type", {"activity_type": activity_type},
+			["costing_rate", "billing_rate"], as_dict=True)
+
 	return rate[0] if rate else {}
diff --git a/erpnext/selling/page/sales_browser/sales_browser.js b/erpnext/selling/page/sales_browser/sales_browser.js
index 98d34be..a99fe72 100644
--- a/erpnext/selling/page/sales_browser/sales_browser.js
+++ b/erpnext/selling/page/sales_browser/sales_browser.js
@@ -7,7 +7,7 @@
 		single_column: true,
 	});
 
-	wrapper.page.set_secondary_action(__('Refresh'), function() {
+	wrapper.page.add_menu_item(__('Refresh'), function() {
 			wrapper.make_tree();
 		});
 
@@ -57,7 +57,7 @@
 
 		me.page.set_primary_action(__("New"), function() {
 			me.new_node();
-		});
+		}, "octicon octicon-plus");
 
 		this.tree = new frappe.ui.Tree({
 			parent: $(parent),
@@ -80,7 +80,8 @@
 					condition: function(node) { return me.can_create && node.expandable; },
 					click: function(node) {
 						me.new_node();
-					}
+					},
+					btnClass: "hidden-xs"
 				},
 				{
 					label:__("Rename"),
@@ -89,7 +90,8 @@
 						frappe.model.rename_doc(me.ctype, node.label, function(new_name) {
 							node.$a.html(new_name);
 						});
-					}
+					},
+					btnClass: "hidden-xs"
 				},
 				{
 					label:__("Delete"),
@@ -98,7 +100,8 @@
 						frappe.model.delete_doc(me.ctype, node.label, function() {
 							node.parent.remove();
 						});
-					}
+					},
+					btnClass: "hidden-xs"
 				}
 
 			]