[cleanup] link methods made common
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index 9a3d58c..a4ee326 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -8,7 +8,7 @@
 from frappe.model.naming import make_autoname
 from erpnext.utilities.address_and_contact import load_address_and_contact
 from erpnext.utilities.transaction_base import TransactionBase
-from erpnext.accounts.party import validate_party_accounts, get_timeline_data
+from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this
 from erpnext.accounts.party_status import get_party_status
 
 class Supplier(TransactionBase):
@@ -18,7 +18,6 @@
 	def onload(self):
 		"""Load address and contacts in `__onload`"""
 		load_address_and_contact(self, "supplier")
-		self.set_onload('links', self.meta.get_links_setup())
 
 	def autoname(self):
 		supp_master_name = frappe.defaults.get_global_default('supp_master_name')
@@ -83,15 +82,4 @@
 	def update_supplier_address(self, newdn, set_field):
 		frappe.db.sql("""update `tabAddress` set address_title=%(newdn)s
 			{set_field} where supplier=%(newdn)s"""\
-			.format(set_field=set_field), ({"newdn": newdn}))
-
-@frappe.whitelist()
-def get_dashboard_data(name):
-	'''load dashboard related data'''
-	frappe.has_permission(doc=frappe.get_doc('Supplier', name), throw=True)
-
-	from frappe.desk.notifications import get_open_count
-	return {
-		'count': get_open_count('Supplier', name),
-		'timeline_data': get_timeline_data('Supplier', name),
-	}
+			.format(set_field=set_field), ({"newdn": newdn}))
\ No newline at end of file
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 8f687d1..7661925 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -32,29 +32,29 @@
 		self.set_qty_as_per_stock_uom()
 		self.validate_stock_or_nonstock_items()
 		self.validate_warehouse()
-		
+
 		if self.doctype=="Purchase Invoice":
 			self.validate_purchase_receipt_if_update_stock()
-		
+
 		if self.doctype=="Purchase Receipt" or (self.doctype=="Purchase Invoice" and self.update_stock):
 			self.validate_purchase_return()
 			self.validate_rejected_warehouse()
 			self.validate_accepted_rejected_qty()
-			
+
 			pc_obj = frappe.get_doc('Purchase Common')
 			pc_obj.validate_for_items(self)
-			
+
 			#sub-contracting
 			self.validate_for_subcontracting()
 			self.create_raw_materials_supplied("supplied_items")
 			self.set_landed_cost_voucher_amount()
-		
+
 		if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
 			self.update_valuation_rate("items")
 
 	def set_missing_values(self, for_validate=False):
 		super(BuyingController, self).set_missing_values(for_validate)
-		
+
 		self.set_supplier_from_item_default()
 		self.set_price_list_currency("Buying")
 
@@ -85,7 +85,7 @@
 				from `tabLanded Cost Item`
 				where docstatus = 1 and purchase_receipt_item = %s""", d.name)
 			d.landed_cost_voucher_amount = lc_voucher_amount[0][0] if lc_voucher_amount else 0.0
-			
+
 	def set_total_in_words(self):
 		from frappe.utils import money_in_words
 		company_currency = get_company_currency(self.company)
@@ -286,7 +286,7 @@
 				if not d.conversion_factor:
 					frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
 				d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
-	
+
 	def validate_purchase_return(self):
 		for d in self.get("items"):
 			if self.is_return and flt(d.rejected_qty) != 0:
@@ -299,7 +299,7 @@
 			if flt(d.rejected_qty) and not d.rejected_warehouse:
 				if self.rejected_warehouse:
 					d.rejected_warehouse = self.rejected_warehouse
-				
+
 				if not d.rejected_warehouse:
 					frappe.throw(_("Row #{0}: Rejected Warehouse is mandatory against rejected Item {1}").format(d.idx, d.item_code))
 
@@ -318,10 +318,10 @@
 			# Check Received Qty = Accepted Qty + Rejected Qty
 			if ((flt(d.qty) + flt(d.rejected_qty)) != flt(d.received_qty)):
 				frappe.throw(_("Accepted + Rejected Qty must be equal to Received quantity for Item {0}").format(d.item_code))
-	
+
 	def update_stock_ledger(self, allow_negative_stock=False, via_landed_cost_voucher=False):
 		self.update_ordered_qty()
-		
+
 		sl_entries = []
 		stock_items = self.get_stock_items()
 
@@ -335,10 +335,10 @@
 						"serial_no": cstr(d.serial_no).strip()
 					})
 					if self.is_return:
-						original_incoming_rate = frappe.db.get_value("Stock Ledger Entry", 
-							{"voucher_type": "Purchase Receipt", "voucher_no": self.return_against, 
+						original_incoming_rate = frappe.db.get_value("Stock Ledger Entry",
+							{"voucher_type": "Purchase Receipt", "voucher_no": self.return_against,
 							"item_code": d.item_code}, "incoming_rate")
-							
+
 						sle.update({
 							"outgoing_rate": original_incoming_rate
 						})
@@ -361,14 +361,14 @@
 		self.make_sl_entries_for_supplier_warehouse(sl_entries)
 		self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock,
 			via_landed_cost_voucher=via_landed_cost_voucher)
-			
+
 	def update_ordered_qty(self):
 		po_map = {}
 		for d in self.get("items"):
 			if self.doctype=="Purchase Receipt" \
 				and d.prevdoc_doctype=="Purchase Order" and d.prevdoc_detail_docname:
 					po_map.setdefault(d.prevdoc_docname, []).append(d.prevdoc_detail_docname)
-			
+
 			elif self.doctype=="Purchase Invoice" and d.purchase_order and d.po_detail:
 				po_map.setdefault(d.purchase_order, []).append(d.po_detail)
 
@@ -381,7 +381,7 @@
 						frappe.InvalidStatusError)
 
 				po_obj.update_ordered_qty(po_item_rows)
-	
+
 	def make_sl_entries_for_supplier_warehouse(self, sl_entries):
 		if hasattr(self, 'supplied_items'):
 			for d in self.get('supplied_items'):
@@ -392,4 +392,4 @@
 					"warehouse": self.supplier_warehouse,
 					"actual_qty": -1*flt(d.consumed_qty),
 				}))
-	
+
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 578e7b7..593b0fb 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -18,9 +18,6 @@
 
 
 class Employee(Document):
-	def onload(self):
-		self.set_onload('links', self.meta.get_links_setup())
-
 	def autoname(self):
 		naming_method = frappe.db.get_value("HR Settings", None, "emp_created_by")
 		if not naming_method:
@@ -157,22 +154,7 @@
 	def on_trash(self):
 		delete_events(self.doctype, self.name)
 
-	def get_timeline_data(self):
-		'''returns timeline data based on attendance'''
-		return
-
-@frappe.whitelist()
-def get_dashboard_data(name):
-	'''load dashboard related data'''
-	frappe.has_permission(doc=frappe.get_doc('Employee', name), throw=True)
-
-	from frappe.desk.notifications import get_open_count
-	return {
-		'count': get_open_count('Employee', name),
-		'timeline_data': get_timeline_data(name),
-	}
-
-def get_timeline_data(name):
+def get_timeline_data(doctype, name):
 	'''Return timeline for attendance'''
 	return dict(frappe.db.sql('''select unix_timestamp(att_date), count(*)
 		from `tabAttendance` where employee=%s
@@ -187,7 +169,7 @@
 	if date_of_birth:
 		try:
 			retirement_age = int(frappe.db.get_single_value("HR Settings", "retirement_age") or 60)
-			dt = add_years(getdate(date_of_birth),retirement_age)			
+			dt = add_years(getdate(date_of_birth),retirement_age)
 			ret = {'date_of_retirement': dt.strftime('%Y-%m-%d')}
 		except ValueError:
 			# invalid date
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index e7280f4..9736553 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -18,7 +18,6 @@
 		if not self.get('__unsaved') and not self.get("tasks"):
 			self.load_tasks()
 
-		self.set_onload('links', self.meta.get_links_setup())
 		self.set_onload('activity_summary', frappe.db.sql('''select activity_type, sum(hours) as total_hours
 			from `tabTime Sheet Detail` where project=%s group by activity_type order by total_hours desc''', self.name, as_dict=True))
 
@@ -152,19 +151,7 @@
 				frappe.sendmail(user.user, subject=_("Project Collaboration Invitation"), content=content.format(*messages))
 				user.welcome_email_sent=1
 
-
-@frappe.whitelist()
-def get_dashboard_data(name):
-	'''load dashboard related data'''
-	frappe.has_permission(doc=frappe.get_doc('Project', name), throw=True)
-
-	from frappe.desk.notifications import get_open_count
-	return {
-		'count': get_open_count('Project', name),
-		'timeline_data': get_timeline_data(name)
-	}
-
-def get_timeline_data(name):
+def get_timeline_data(doctype, name):
 	'''Return timeline for attendance'''
 	return dict(frappe.db.sql('''select unix_timestamp(from_time), count(*)
 		from `tabTime Sheet Detail` where project=%s
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 591b9c1..ee3f6e6 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -10,7 +10,7 @@
 from frappe.desk.reportview import build_match_conditions
 from erpnext.utilities.transaction_base import TransactionBase
 from erpnext.utilities.address_and_contact import load_address_and_contact
-from erpnext.accounts.party import validate_party_accounts, get_timeline_data
+from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this
 from erpnext.accounts.party_status import get_party_status
 
 class Customer(TransactionBase):
@@ -20,7 +20,6 @@
 	def onload(self):
 		"""Load address and contacts in `__onload`"""
 		load_address_and_contact(self, "customer")
-		self.set_onload('links', self.meta.get_links_setup())
 
 	def autoname(self):
 		cust_master_name = frappe.defaults.get_global_default('cust_master_name')
@@ -129,17 +128,6 @@
 			.format(set_field=set_field), ({"newdn": newdn}))
 
 
-@frappe.whitelist()
-def get_dashboard_data(name):
-	'''load dashboard related data'''
-	frappe.has_permission(doc=frappe.get_doc('Customer', name), throw=True)
-
-	from frappe.desk.notifications import get_open_count
-	return {
-		'count': get_open_count('Customer', name),
-		'timeline_data': get_timeline_data('Customer', name),
-	}
-
 def get_customer_list(doctype, txt, searchfield, start, page_len, filters):
 	if frappe.db.get_default("cust_master_name") == "Customer Name":
 		fields = ["name", "customer_group", "territory"]
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 367d114..2f346bc 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -28,7 +28,6 @@
 	def onload(self):
 		super(Item, self).onload()
 		self.set_onload('sle_exists', self.check_if_sle_exists())
-		self.set_onload('links', self.meta.get_links_setup())
 
 	def autoname(self):
 		if frappe.db.get_default("item_naming_by")=="Naming Series":
@@ -632,19 +631,7 @@
 				frappe.throw(_("Item variant {0} exists with same attributes")
 					.format(variant), ItemVariantExistsError)
 
-
-@frappe.whitelist()
-def get_dashboard_data(name):
-	'''load dashboard related data'''
-	frappe.has_permission(doc=frappe.get_doc('Item', name), throw=True)
-
-	from frappe.desk.notifications import get_open_count
-	return {
-		'count': get_open_count('Item', name),
-		'timeline_data': get_timeline_data(name),
-	}
-
-def get_timeline_data(name):
+def get_timeline_data(doctype, name):
 	'''returns timeline data based on stock ledger entry'''
 	return dict(frappe.db.sql('''select unix_timestamp(posting_date), count(*)
 		from `tabStock Ledger Entry` where item_code=%s
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index fea0d7e..1f0fe34 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -43,6 +43,8 @@
 		var me = this;
 		this._super();
 
+		this.frm.dashboard.reset();
+
 		if(doc.docstatus==0) {
 			cur_frm.add_custom_button(__("Get Items from BOM"),
 				cur_frm.cscript.get_items_from_bom, "icon-sitemap", "btn-default");
@@ -50,6 +52,8 @@
 
 		if(doc.docstatus == 1 && doc.status != 'Stopped') {
 
+			this.frm.dashboard.show_dashboard();
+
 			if(flt(doc.per_ordered, 2) < 100) {
 				// make
 				if(doc.material_request_type === "Material Transfer" && doc.status === "Submitted")
@@ -76,19 +80,6 @@
 					cur_frm.add_custom_button(__("Production Order"),
 					this.raise_production_orders, __("Make"));
 
-				// show
-
-				if(doc.material_request_type === "Purchase" && doc.docstatus==1) {
-					me.frm.add_custom_button(__("Request for Quotation"),
-						function() { frappe.set_route('List', 'Request for Quotation',
-						{'material_request': doc.name})}, __("Show"));
-
-					me.frm.add_custom_button(__("Supplier Quotation"),
-						function() { frappe.set_route('List', 'Supplier Quotation',
-						{'material_request': doc.name})}, __("Show"));
-
-				}
-
 				cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
 
 				// stop
diff --git a/erpnext/stock/doctype/material_request/material_request_links.py b/erpnext/stock/doctype/material_request/material_request_links.py
new file mode 100644
index 0000000..7f12490
--- /dev/null
+++ b/erpnext/stock/doctype/material_request/material_request_links.py
@@ -0,0 +1,15 @@
+from frappe import _
+
+links = {
+	'fieldname': 'material_request',
+	'non_standard_fieldnames': {
+		'Supplier Quotation': 'prevdoc_detail_docname',
+		'Purchase Order': 'prevdoc_detail_docname',
+	},
+	'transactions': [
+		{
+			'label': _('Documents'),
+			'items': ['Request for Quotation', 'Supplier Quotation', 'Purchase Order']
+		},
+	]
+}
\ No newline at end of file