assign-sa-to-group-of-employees
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index 4a111e7..033938d 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -58,6 +58,9 @@
doc.company = frm.doc.company;
frappe.set_route('Form', 'Salary Structure Assignment', doc.name);
});
+ frm.add_custom_button(__("Assign to Employees"),function () {
+ frm.trigger('assign_to_employees')
+ })
}
let fields_read_only = ["is_tax_applicable", "is_flexible_benefit", "variable_based_on_taxable_salary"];
fields_read_only.forEach(function(field) {
@@ -65,6 +68,43 @@
});
},
+ assign_to_employees:function (frm) {
+ var d = new frappe.ui.Dialog({
+ title: __("Assign to Employees"),
+ fields: [
+ {fieldname: "sec_break", fieldtype: "Section Break", label: __("Filter Employees By (Optional)")},
+ {fieldname: "grade", fieldtype: "Link", options: "Employee Grade", label: __("Employee Grade")},
+ {fieldname:'department', fieldtype:'Link', options: 'Department', label: __('Department')},
+ {fieldname:'designation', fieldtype:'Link', options: 'Designation', label: __('Designation')},
+ {fieldname:"employee", fieldtype: "Link", options: "Employee", label: __("Employee")},
+ {fieldname:'base_variable', fieldtype:'Section Break'},
+ {fieldname:'from_date', fieldtype:'Date', label: __('From Date'), "reqd": 1},
+ {fieldname:'base_col_br', fieldtype:'Column Break'},
+ {fieldname:'base', fieldtype:'Currency', label: __('Base')},
+ {fieldname:'variable', fieldtype:'Currency', label: __('Variable')}
+ ],
+ primary_action: function() {
+ var data = d.get_values();
+
+ frappe.call({
+ doc: frm.doc,
+ method: "assign_salary_structure",
+ args: data,
+ callback: function(r) {
+ if(!r.exc) {
+ d.hide();
+ frm.reload_doc();
+ }
+ }
+ });
+ },
+ primary_action_label: __('Assign')
+ });
+
+
+ d.show();
+ },
+
salary_slip_based_on_timesheet: function(frm) {
frm.trigger("toggle_fields")
},
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py
index a36d820..7ead140 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.py
@@ -65,6 +65,76 @@
if not have_a_flexi and flt(self.max_benefits) > 0:
frappe.throw(_("Salary Structure should have flexible benefit component(s) to dispense benefit amount"))
+ def get_employees(self, **kwargs):
+ conditions, values = [], []
+ for field, value in kwargs.items():
+ if value:
+ conditions.append("{0}=%s".format(field))
+ values.append(value)
+
+ condition_str = " and " + " and ".join(conditions) if conditions else ""
+
+ employees = frappe.db.sql_list("select name from tabEmployee where status='Active' {condition}"
+ .format(condition=condition_str), tuple(values))
+
+ return employees
+
+ @frappe.whitelist()
+ def assign_salary_structure(self, grade=None, department=None, designation=None,employee=None,
+ from_date=None, base=None,variable=None):
+ employees = self.get_employees(grade= grade,department= department,designation= designation,name=employee)
+
+ if employees:
+ if len(employees) > 20:
+ frappe.enqueue(assign_salary_structure_for_employees, timeout=600,
+ employees=employees, salary_structure=self,from_date=from_date, base=base,variable=variable)
+ else:
+ assign_salary_structure_for_employees(employees, self,from_date=from_date, base=base,variable=variable)
+ else:
+ frappe.msgprint(_("No Employee Found"))
+
+
+
+def assign_salary_structure_for_employees(employees, salary_structure,from_date=None, base=None,variable=None):
+ salary_structures_assignments = []
+ existing_assignments_for = get_existing_assignments(employees, salary_structure.name,from_date)
+ count=0
+ for employee in employees:
+ if employee in existing_assignments_for:
+ continue
+ count +=1
+
+ salary_structures_assignment = create_salary_structures_assignment(employee, salary_structure, from_date, base, variable)
+ salary_structures_assignments.append(salary_structures_assignment)
+ frappe.publish_progress(count*100/len(set(employees) - set(existing_assignments_for)), title = _("Assigning Structures..."))
+
+ if salary_structures_assignments:
+ frappe.msgprint(_("Structures have been assigned successfully"))
+
+
+def create_salary_structures_assignment(employee, salary_structure, from_date, base, variable):
+ assignment = frappe.new_doc("Salary Structure Assignment")
+ assignment.employee = employee
+ assignment.salary_structure = salary_structure.name
+ assignment.from_date = from_date
+ assignment.base = base
+ assignment.variable = variable
+ assignment.save(ignore_permissions = True)
+ assignment.submit()
+ return assignment.name
+
+
+def get_existing_assignments(employees, salary_structure,from_date):
+ salary_structures_assignments = frappe.db.sql_list("""
+ select distinct employee from `tabSalary Structure Assignment`
+ where salary_structure=%s and employee in (%s)
+ and from_date=%s and docstatus=1
+ """ % ('%s', ', '.join(['%s']*len(employees)),'%s'), [salary_structure] + employees+[from_date])
+ if salary_structures_assignments:
+ frappe.msgprint(_("Skipping Salary Structure Assignment for the following employees, as Salary Structure Assignment records already exists against them. {0}")
+ .format("\n".join(salary_structures_assignments)))
+ return salary_structures_assignments
+
@frappe.whitelist()
def make_salary_slip(source_name, target_doc = None, employee = None, as_print = False, print_format = None):
def postprocess(source, target):
diff --git a/erpnext/hr/doctype/salary_structure/test_salary_structure.py b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
index 1a16db7..1a660d9 100644
--- a/erpnext/hr/doctype/salary_structure/test_salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
@@ -71,6 +71,19 @@
for row in salary_structure.deductions:
self.assertFalse(("\n" in row.formula) or ("\n" in row.condition))
+ def test_salary_structures_assignment(self):
+ salary_structure = make_salary_structure("Salary Structure Sample", "Monthly")
+ employee = "test_assign_stucture@salary.com"
+ employee_doc_name = make_employee(employee)
+ # clear the already assigned stuctures
+ frappe.db.sql('''delete from `tabSalary Structure Assignment` where employee=%s and salary_structure=%s ''',
+ ("test_assign_stucture@salary.com",salary_structure.name))
+ #test structure_assignment
+ salary_structure.assign_salary_structure(employee=employee_doc_name,from_date='2013-01-01',base=5000,variable=200)
+ salary_structure_assignment = frappe.get_doc("Salary Structure Assignment",{'employee':employee_doc_name, 'from_date':'2013-01-01'})
+ self.assertEqual(salary_structure_assignment.docstatus, 1)
+ self.assertEqual(salary_structure_assignment.base, 5000)
+ self.assertEqual(salary_structure_assignment.variable, 200)
def make_salary_structure(salary_structure, payroll_frequency, employee=None, dont_submit=False, other_details=None, test_tax=False):
if test_tax: