Deprecated client side mapper: frappe.model.map. Fixes #1530
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_map.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice_map.js
deleted file mode 100644
index 79036f9..0000000
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_map.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-// License: GNU General Public License v3. See license.txt
-
-frappe.model.map_info["Sales Invoice"] = {
-	"Time Log Batch": {
-		table_map: {
-			"Sales Invoice Item": "Time Log Batch",
-		},
-		field_map: {
-			"Sales Invoice Item": {
-				"base_rate": "rate",
-				"time_log_batch": "name",
-				"qty": "total_hours",
-				"stock_uom": "=Hour",
-				"description": "=via Time Logs"
-			}
-		},
-	}
-}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee/employee.js b/erpnext/hr/doctype/employee/employee.js
index 5d365d0..39e0c70 100644
--- a/erpnext/hr/doctype/employee/employee.js
+++ b/erpnext/hr/doctype/employee/employee.js
@@ -20,7 +20,7 @@
 	refresh: function() {
 		var me = this;
 		erpnext.toggle_naming_series();
-		if(!this.frm.doc.__islocal) {
+		if(!this.frm.doc.__islocal && !this.frm.doc.salary_structure_exists) {
 			cur_frm.add_custom_button(__('Make Salary Structure'), function() {
 				me.make_salary_structure(this); });
 		}
@@ -58,35 +58,10 @@
 	},
 
 	make_salary_structure: function(btn) {
-		var me = this;
-		this.validate_salary_structure(btn, function(r) {
-			if(r.message) {
-				msgprint(__("Active Salary Sructure already exists for Employee {0}", [me.frm.doc.name]));
-			} else if(!r.exc) {
-				frappe.model.map({
-					source: me.frm.doc,
-					target: "Salary Structure"
-				});
-			}
+		frappe.model.open_mapped_doc({
+			method: "erpnext.hr.doctype.employee.employee.make_salary_structure",
+			source_name: cur_frm.doc.name
 		});
-	},
-
-	validate_salary_structure: function(btn, callback) {
-		var me = this;
-		return this.frm.call({
-			btn: btn,
-			method: "frappe.client.get_value",
-			args: {
-				doctype: "Salary Structure",
-				fieldname: "name",
-				filters: {
-					employee: me.frm.doc.name,
-					is_active: "Yes",
-					docstatus: ["!=", 2]
-				},
-			},
-			callback: callback
-		});
-	},
+	}
 });
 cur_frm.cscript = new erpnext.hr.EmployeeController({frm: cur_frm});
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index e1a060b..44c1752 100644
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -10,8 +10,21 @@
 import frappe.permissions
 from frappe.defaults import get_restrictions
 from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
 
 class Employee(Document):
+	def onload(self):
+		self.salary_structure_exists = frappe.db.get_value("Salary Structure",
+			{"employee": self.name, "is_active": "Yes", "docstatus": ["!=", 2]})
+
+	def as_dict(self):
+		doc = super(Employee, self).as_dict()
+
+		if hasattr(self, "salary_structure_exists"):
+			doc["salary_structure_exists"] = self.salary_structure_exists
+
+		return doc
+
 	def autoname(self):
 		naming_method = frappe.db.get_value("HR Settings", None, "emp_created_by")
 		if not naming_method:
@@ -203,3 +216,16 @@
 		dt = getdate(date_of_birth) + datetime.timedelta(21915)
 		ret = {'date_of_retirement': dt.strftime('%Y-%m-%d')}
 	return ret
+
+@frappe.whitelist()
+def make_salary_structure(source_name, target=None):
+	target = get_mapped_doc("Employee", source_name, {
+		"Employee": {
+			"doctype": "Salary Structure",
+			"field_map": {
+				"name": "employee"
+			}
+		}
+	})
+	target.make_earn_ded_table()
+	return target
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index e4235ea..e50a99c 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -4,18 +4,18 @@
 cur_frm.add_fetch('employee', 'company', 'company');
 
 cur_frm.cscript.onload = function(doc, dt, dn){
-  e_tbl = doc.earning_details || [];
-  d_tbl = doc.deduction_details || [];
-  if (e_tbl.length == 0 && d_tbl.length == 0)
-    return $c_obj(doc,'make_earn_ded_table','', function(r, rt) { refresh_many(['earning_details', 'deduction_details']);});
+	e_tbl = doc.earning_details || [];
+	d_tbl = doc.deduction_details || [];
+	if (e_tbl.length == 0 && d_tbl.length == 0)
+		return $c_obj(doc,'make_earn_ded_table','', function(r, rt) { refresh_many(['earning_details', 'deduction_details']);});
 }
 
 cur_frm.cscript.refresh = function(doc, dt, dn){
-  if((!doc.__islocal) && (doc.is_active == 'Yes')){
-    cur_frm.add_custom_button(__('Make Salary Slip'), cur_frm.cscript['Make Salary Slip']);  
-  }
+	if((!doc.__islocal) && (doc.is_active == 'Yes')){
+		cur_frm.add_custom_button(__('Make Salary Slip'), cur_frm.cscript['Make Salary Slip']);
+	}
 
-  cur_frm.toggle_enable('employee', doc.__islocal);
+	cur_frm.toggle_enable('employee', doc.__islocal);
 }
 
 cur_frm.cscript['Make Salary Slip'] = function() {
@@ -26,39 +26,39 @@
 }
 
 cur_frm.cscript.employee = function(doc, dt, dn){
-  if (doc.employee)
-    return get_server_fields('get_employee_details','','',doc,dt,dn);
+	if (doc.employee)
+		return get_server_fields('get_employee_details','','',doc,dt,dn);
 }
 
 cur_frm.cscript.modified_value = function(doc, cdt, cdn){
-  calculate_totals(doc, cdt, cdn);
+	calculate_totals(doc, cdt, cdn);
 }
 
 cur_frm.cscript.d_modified_amt = function(doc, cdt, cdn){
-  calculate_totals(doc, cdt, cdn);
+	calculate_totals(doc, cdt, cdn);
 }
 
 var calculate_totals = function(doc, cdt, cdn) {
-  var tbl1 = doc.earning_details || [];
-  var tbl2 = doc.deduction_details || [];
-  
-  var total_earn = 0; var total_ded = 0;
-  for(var i = 0; i < tbl1.length; i++){
-    total_earn += flt(tbl1[i].modified_value);
-  }
-  for(var j = 0; j < tbl2.length; j++){
-    total_ded += flt(tbl2[j].d_modified_amt);
-  }
-  doc.total_earning = total_earn;
-  doc.total_deduction = total_ded;
-  doc.net_pay = flt(total_earn) - flt(total_ded);
-  refresh_many(['total_earning', 'total_deduction', 'net_pay']);
+	var tbl1 = doc.earning_details || [];
+	var tbl2 = doc.deduction_details || [];
+
+	var total_earn = 0; var total_ded = 0;
+	for(var i = 0; i < tbl1.length; i++){
+		total_earn += flt(tbl1[i].modified_value);
+	}
+	for(var j = 0; j < tbl2.length; j++){
+		total_ded += flt(tbl2[j].d_modified_amt);
+	}
+	doc.total_earning = total_earn;
+	doc.total_deduction = total_ded;
+	doc.net_pay = flt(total_earn) - flt(total_ded);
+	refresh_many(['total_earning', 'total_deduction', 'net_pay']);
 }
 
 cur_frm.cscript.validate = function(doc, cdt, cdn) {
-  calculate_totals(doc, cdt, cdn);
+	calculate_totals(doc, cdt, cdn);
 }
 
 cur_frm.fields_dict.employee.get_query = function(doc,cdt,cdn) {
-  return{ query: "erpnext.controllers.queries.employee_query" } 
-}
\ No newline at end of file
+	return{ query: "erpnext.controllers.queries.employee_query" }
+}
diff --git a/erpnext/projects/doctype/time_log_batch/time_log_batch.js b/erpnext/projects/doctype/time_log_batch/time_log_batch.js
index 3065f33..c2d3535 100644
--- a/erpnext/projects/doctype/time_log_batch/time_log_batch.js
+++ b/erpnext/projects/doctype/time_log_batch/time_log_batch.js
@@ -23,16 +23,16 @@
 			"Billed": __("This Time Log Batch has been billed."),
 			"Cancelled": __("This Time Log Batch has been cancelled.")
 		}[doc.status]);
-		
+
 		if(doc.status=="Submitted") {
-			cur_frm.add_custom_button(__("Make Sales Invoice"), function() { cur_frm.cscript.make_invoice() }, 
+			cur_frm.add_custom_button(__("Make Sales Invoice"), function() { cur_frm.cscript.make_invoice() },
 				"icon-file-alt");
 		}
 	},
 	make_invoice: function() {
-		frappe.model.map({
-			source: cur_frm.doc,
-			target: "Sales Invoice"
+		frappe.model.open_mapped_doc({
+			method: "erpnext.projects.doctype.time_log_batch.time_log_batch.make_sales_invoice",
+			source_name: cur_frm.doc.name
 		});
 	}
-});
\ No newline at end of file
+});
diff --git a/erpnext/projects/doctype/time_log_batch/time_log_batch.py b/erpnext/projects/doctype/time_log_batch/time_log_batch.py
index 6d9ce14..0724bc7 100644
--- a/erpnext/projects/doctype/time_log_batch/time_log_batch.py
+++ b/erpnext/projects/doctype/time_log_batch/time_log_batch.py
@@ -8,6 +8,7 @@
 from frappe import _
 
 from frappe.model.document import Document
+from frappe.model.mapper import get_mapped_doc
 
 class TimeLogBatch(Document):
 
@@ -58,3 +59,24 @@
 			tl.sales_invoice = self.sales_invoice
 			tl.ignore_validate_update_after_submit = True
 			tl.save()
+
+@frappe.whitelist()
+def make_sales_invoice(source_name, target=None):
+	def update_item(source_doc, target_doc, source_parent):
+		target_doc.stock_uom = "Hour"
+		target_doc.description = "via Time Logs"
+
+	target = frappe.new_doc("Sales Invoice")
+	target.append("entries", get_mapped_doc("Time Log Batch", source_name, {
+		"Time Log Batch": {
+			"doctype": "Sales Invoice Item",
+			"field_map": {
+				"rate": "base_rate",
+				"name": "time_log_batch",
+				"total_hours": "qty",
+			},
+			"postprocess": update_item
+		}
+	}))
+
+	return target