Salary Structure Refactor, Formula on Salary Component Master (#13967)

* Salary structure refactor

* Salary Structure Assignment - filters applied

* Formula on Salary Component Master

* Salary Structure - filter updated, Salary Component - fields re-arranged

* Payroll Entry - get_employee_list fix

* Salary Structure Assignment - Validate Duplicate Assignment

* Salary Structure Assignment - filters for salary structure
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
index 1025bc7..e1b841f 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
@@ -40,15 +40,16 @@
 				{"company": self.company, "salary_slip_based_on_timesheet":self.salary_slip_based_on_timesheet})
 
 		if sal_struct:
-			cond += "and t2.parent IN %(sal_struct)s "
+			cond += "and t2.salary_structure IN %(sal_struct)s "
 			emp_list = frappe.db.sql("""
 				select
 					t1.name as employee, t1.employee_name, t1.department, t1.designation
 				from
-					`tabEmployee` t1, `tabSalary Structure Employee` t2
+					`tabEmployee` t1, `tabSalary Structure Assignment` t2
 				where
 					t1.docstatus!=2
 					and t1.name = t2.employee
+					and t2.docstatus = 1
 			%s """% cond, {"sal_struct": sal_struct}, as_dict=True)
 			return emp_list
 
diff --git a/erpnext/hr/doctype/salary_component/salary_component.json b/erpnext/hr/doctype/salary_component/salary_component.json
index 27b4bef..5f875a9 100644
--- a/erpnext/hr/doctype/salary_component/salary_component.json
+++ b/erpnext/hr/doctype/salary_component/salary_component.json
@@ -610,6 +610,320 @@
    "set_only_once": 0, 
    "translatable": 0, 
    "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 1, 
+   "columns": 0, 
+   "fieldname": "condition_and_formula", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Condition and Formula", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "condition", 
+   "fieldtype": "Code", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Condition", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ", 
+   "fieldname": "statistical_component", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Statistical Component", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "depends_on_lwp", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Depends on Leave Without Pay", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "do_not_include_in_total", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Do not include in total", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "1", 
+   "fieldname": "amount_based_on_formula", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Amount based on formula", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "eval:doc.amount_based_on_formula!==0", 
+   "fieldname": "formula", 
+   "fieldtype": "Code", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Formula", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "eval:doc.amount_based_on_formula!==1", 
+   "fieldname": "amount", 
+   "fieldtype": "Currency", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Amount", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "column_break_28", 
+   "fieldtype": "Column Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "help", 
+   "fieldtype": "HTML", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Help", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "<h3>Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condtion. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base &lt; 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS &gt; 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
   }
  ], 
  "has_web_view": 0, 
@@ -623,7 +937,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2018-04-27 13:23:34.503504", 
+ "modified": "2018-05-09 17:35:11.073733", 
  "modified_by": "Administrator", 
  "module": "HR", 
  "name": "Salary Component", 
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 75eb73b..99de580 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -104,8 +104,8 @@
 		'''Returns data for evaluating formula'''
 		data = frappe._dict()
 
-		data.update(frappe.get_doc("Salary Structure Employee",
-			{"employee": self.employee, "parent": self.salary_structure}).as_dict())
+		data.update(frappe.get_doc("Salary Structure Assignment",
+			{"employee": self.employee, "salary_structure": self.salary_structure}).as_dict())
 
 		data.update(frappe.get_doc("Employee", self.employee).as_dict())
 		data.update(self.as_dict())
@@ -166,10 +166,10 @@
 		if self.payroll_frequency:
 			cond = """and payroll_frequency = '%(payroll_frequency)s'""" % {"payroll_frequency": self.payroll_frequency}
 
-		st_name = frappe.db.sql("""select parent from `tabSalary Structure Employee`
+		st_name = frappe.db.sql("""select salary_structure from `tabSalary Structure Assignment`
 			where employee=%s and (from_date <= %s or from_date <= %s)
 			and (to_date is null or to_date >= %s or to_date >= %s)
-			and parent in (select name from `tabSalary Structure`
+			and salary_structure in (select name from `tabSalary Structure`
 				where is_active = 'Yes'%s)
 			"""% ('%s', '%s', '%s','%s','%s', cond),(self.employee, self.start_date, joining_date, self.end_date, relieving_date))
 
@@ -327,7 +327,7 @@
 	def sum_components(self, component_type, total_field):
 		joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
 			["date_of_joining", "relieving_date"])
-		
+
 		if not relieving_date:
 			relieving_date = getdate(self.end_date)
 
@@ -463,4 +463,4 @@
 	if linked_ss:
 		for ss in linked_ss:
 			ss_doc = frappe.get_doc("Salary Slip", ss)
-			frappe.db.set_value("Salary Slip", ss_doc.name, "journal_entry", "")
\ No newline at end of file
+			frappe.db.set_value("Salary Slip", ss_doc.name, "journal_entry", "")
diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
index cced29d..ae58298 100644
--- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
@@ -7,6 +7,7 @@
 import erpnext
 import calendar
 from erpnext.accounts.utils import get_fiscal_year
+from frappe.utils.make_random import get_random
 from frappe.utils import getdate, nowdate, add_days, add_months, flt
 from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
 from erpnext.hr.doctype.payroll_entry.test_payroll_entry import get_salary_component_account
@@ -272,33 +273,31 @@
 		frappe.get_doc({
 			"doctype": "Salary Structure",
 			"name": sal_struct,
-			"company": erpnext.get_default_company(),
-			"employees": get_employee_details(employee),
+			"company": "_Test Company",
 			"earnings": get_earnings_component(),
 			"deductions": get_deductions_component(),
 			"payroll_frequency": payroll_frequency,
-			"payment_account": frappe.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name")
+			"payment_account": get_random("Account")
 		}).insert()
 
-	elif not frappe.db.get_value("Salary Structure Employee",{'parent':sal_struct, 'employee':employee},'name'):
+		create_salary_structure_assignment(employee, sal_struct)
+
+	elif not frappe.db.get_value("Salary Structure Assignment",{'salary_structure':sal_struct, 'employee':employee},'name'):
 		sal_struct = frappe.get_doc("Salary Structure", sal_struct)
-		sal_struct.append("employees", {"employee": employee,
-			"employee_name": employee,
-			"base": 32000,
-			"variable": 3200,
-			"from_date": add_months(nowdate(),-1)
-			})
-		sal_struct.save()
+		create_salary_structure_assignment(employee, sal_struct)
 		sal_struct = sal_struct.name
 	return sal_struct
 
-def get_employee_details(employee):
-	return [{"employee": employee,
-			"base": 50000,
-			"variable": 5000,
-			"from_date": add_months(nowdate(),-1)
-			}
-		]
+def create_salary_structure_assignment(employee, salary_structure):
+	salary_structure_assignment = frappe.new_doc("Salary Structure Assignment")
+	salary_structure_assignment.employee = employee
+	salary_structure_assignment.base = 50000
+	salary_structure_assignment.variable = 5000
+	salary_structure_assignment.from_date = add_months(nowdate(), -1)
+	salary_structure_assignment.salary_structure = salary_structure
+	salary_structure_assignment.company = erpnext.get_default_company()
+	salary_structure_assignment.save(ignore_permissions=True)
+	return salary_structure_assignment
 
 def get_earnings_component():
 	return [
@@ -353,4 +352,4 @@
 					"formula": 'base*.1',
 					"idx": 3
 				}
-			]
\ No newline at end of file
+			]
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index 3de01cd..6f5c923 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -165,5 +165,46 @@
 
 	deductions_remove: function(frm) {
 		calculate_totals(frm.doc);
+	},
+
+	salary_component: function(frm, cdt, cdn) {
+		var child = locals[cdt][cdn];
+		if(child.salary_component){
+			frappe.call({
+				method: "frappe.client.get",
+				args: {
+					doctype: "Salary Component",
+					name: child.salary_component
+				},
+				callback: function(data) {
+					if(data.message){
+						var result = data.message;
+						frappe.model.set_value(cdt, cdn, 'condition',result.condition);
+						frappe.model.set_value(cdt, cdn, 'amount_based_on_formula',result.amount_based_on_formula);
+						if(result.amount_based_on_formula == 1){
+							frappe.model.set_value(cdt, cdn, 'formula',result.formula);
+						}
+						else{
+							frappe.model.set_value(cdt, cdn, 'amount',result.amount);
+						}
+						frappe.model.set_value(cdt, cdn, 'statistical_component',result.statistical_component);
+						frappe.model.set_value(cdt, cdn, 'depends_on_lwp',result.depends_on_lwp);
+						frappe.model.set_value(cdt, cdn, 'do_not_include_in_total',result.do_not_include_in_total);
+						refresh_field("earnings");
+						refresh_field("deductions");
+					}
+				}
+			});
+		}
+	},
+
+	amount_based_on_formula: function(frm, cdt, cdn) {
+		var child = locals[cdt][cdn];
+		if(child.amount_based_on_formula == 1){
+			frappe.model.set_value(cdt, cdn, 'amount', null);
+		}
+		else{
+			frappe.model.set_value(cdt, cdn, 'formula', null);
+		}
 	}
 })
diff --git a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js
index e7c6598..af4ca3a 100644
--- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js
+++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js
@@ -11,9 +11,36 @@
 				}
 			}
 		});
+		frm.set_query("salary_structure", function() {
+			return {
+				filters: {
+					company: frm.doc.company,
+					is_active: "Yes",
+					docstatus: 1
+				}
+			}
+		});
 	},
-
-	refresh: function(frm) {
-
+	employee: function(frm) {
+		if(frm.doc.employee){
+			frappe.call({
+				method: "frappe.client.get_value",
+				args:{
+					doctype: "Employee",
+					fieldname: "company",
+					filters:{
+						name: frm.doc.employee
+					}
+				},
+				callback: function(data) {
+					if(data.message){
+						frm.set_value("company", data.message.company);
+					}
+				}
+			});
+		}
+		else{
+			frm.set_value("company", null);
+		}
 	}
 });
diff --git a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py
index c9269d7..ee2920b 100644
--- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py
+++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py
@@ -11,6 +11,7 @@
 class SalaryStructureAssignment(Document):
 	def validate(self):
 		self.validate_dates()
+		self.validate_duplicate_assignments()
 
 	def validate_dates(self):
 		joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
@@ -33,10 +34,14 @@
 					.format(self.to_date, relieving_date))
 
 	def validate_duplicate_assignments(self):
+		if not self.name:
+ 			# hack! if name is null, it could cause problems with !=
+ 			self.name = "New "+self.doctype
 		assignment = frappe.db.sql("""
 			select name from `tabSalary Structure Assignment`
 			where employee=%(employee)s
-			and name != %(salary_struct)s
+			and name != %(name)s
+			and docstatus != 2
 			and (
 				(%(from_date)s between from_date and ifnull(to_date, '2199-12-31'))
 				or (%(to_date)s between from_date and ifnull(to_date, '2199-12-31'))
@@ -45,8 +50,8 @@
 				'employee': self.employee,
 				'from_date': self.from_date,
 				'to_date': (self.to_date or '2199-12-31'),
-				'salary_struct': self.salary_struct
+				'name': self.name
 			})
 
 		if assignment:
-			frappe.throw(_("Active Salary Structure Assignment {0} found for employee {1} for the given dates").format(assignment[0][0], self.employee))
\ No newline at end of file
+			frappe.throw(_("Active Salary Structure Assignment {0} found for employee {1} for the given dates").format(assignment[0][0], self.employee))
diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py
index 2458db0..d2017c5 100644
--- a/erpnext/projects/doctype/timesheet/test_timesheet.py
+++ b/erpnext/projects/doctype/timesheet/test_timesheet.py
@@ -118,30 +118,21 @@
 
 
 def make_salary_structure(employee):
-	name = frappe.db.get_value('Salary Structure Employee', {'employee': employee}, 'parent')
+	name = frappe.db.get_value('Salary Structure Assignment', {'employee': employee}, 'salary_structure')
 	if name:
 		salary_structure = frappe.get_doc('Salary Structure', name)
 	else:
 		salary_structure = frappe.new_doc("Salary Structure")
 		salary_structure.name = "Timesheet Salary Structure Test"
 		salary_structure.salary_slip_based_on_timesheet = 1
-		salary_structure.from_date = add_days(nowdate(), -30)
 		salary_structure.salary_component = "Basic"
 		salary_structure.hour_rate = 50.0
 		salary_structure.company = "_Test Company"
 		salary_structure.payment_account = get_random("Account")
 
-		salary_structure.set('employees', [])
 		salary_structure.set('earnings', [])
 		salary_structure.set('deductions', [])
 
-		es = salary_structure.append('employees', {
-			"employee": employee,
-			"base": 1200,
-			"from_date": add_months(nowdate(),-1)
-		})
-
-
 		es = salary_structure.append('earnings', {
 			"salary_component": "_Test Allowance",
 			"amount": 100
@@ -154,6 +145,14 @@
 
 		salary_structure.save(ignore_permissions=True)
 
+		salary_structure_assignment = frappe.new_doc("Salary Structure Assignment")
+		salary_structure_assignment.employee = employee
+		salary_structure_assignment.base = 1200
+		salary_structure_assignment.from_date = add_months(nowdate(), -1)
+		salary_structure_assignment.salary_structure = salary_structure.name
+		salary_structure_assignment.company = "_Test Company"
+		salary_structure_assignment.save(ignore_permissions=True)
+
 	return salary_structure
 
 def make_timesheet(employee, simulate=False, billable = 0, activity_type="_Test Activity Type", project=None, task=None, company=None):