Multiple Salary Fixes
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 15d5df8..b8382ec 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -49,13 +49,13 @@
self._salary_structure_doc = frappe.get_doc('Salary Structure', self.salary_structure)
data = self.get_data_for_eval()
+
for key in ('earnings', 'deductions'):
for struct_row in self._salary_structure_doc.get(key):
amount = self.eval_condition_and_formula(struct_row, data)
if amount:
self.update_component_row(struct_row, amount, key)
-
def update_component_row(self, struct_row, amount, key):
component_row = None
for d in self.get(key):
@@ -83,6 +83,7 @@
amount = eval(d.formula, None, data)
if amount:
data[d.abbr] = amount
+
return amount
except NameError as err:
@@ -97,17 +98,20 @@
'''Returns data for evaluating formula'''
data = frappe._dict()
- for d in self._salary_structure_doc.employees:
- if d.employee == self.employee:
- data.update(frappe.get_doc("Salary Structure Employee", {"employee": self.employee}).as_dict())
+ data.update(frappe.get_doc("Salary Structure Employee", {"employee": self.employee}).as_dict())
data.update(frappe.get_doc("Employee", self.employee).as_dict())
data.update(self.as_dict())
# set values for components
salary_components = frappe.get_all("Salary Component", fields=["salary_component_abbr"])
- for salary_component in salary_components:
- data[salary_component.salary_component_abbr] = 0
+ for sc in salary_components:
+ data.setdefault(sc.salary_component_abbr, 0)
+
+ for key in ('earnings', 'deductions'):
+ for d in self.get(key):
+ data[d.abbr] = d.amount
+
return data
@@ -173,13 +177,16 @@
def pull_sal_struct(self):
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
- make_salary_slip(self._salary_structure_doc.name, self)
if self.salary_slip_based_on_timesheet:
self.salary_structure = self._salary_structure_doc.name
self.hour_rate = self._salary_structure_doc.hour_rate
self.total_working_hours = sum([d.working_hours or 0.0 for d in self.timesheets]) or 0.0
- self.add_earning_for_hourly_wages(self._salary_structure_doc.salary_component)
+ wages_amount = self.hour_rate * self.total_working_hours
+
+ self.add_earning_for_hourly_wages(self, self._salary_structure_doc.salary_component, wages_amount)
+
+ make_salary_slip(self._salary_structure_doc.name, self)
def process_salary_structure(self):
'''Calculate salary after salary structure details have been updated'''
@@ -188,18 +195,21 @@
self.get_leave_details()
self.calculate_net_pay()
- def add_earning_for_hourly_wages(self, salary_component):
- default_type = False
- for data in self.earnings:
- if data.salary_component == salary_component:
- data.amount = self.hour_rate * self.total_working_hours
- default_type = True
+ def add_earning_for_hourly_wages(self, doc, salary_component, amount):
+ row_exists = False
+ for row in doc.earnings:
+ if row.salary_component == salary_component:
+ row.amount = amount
+ row_exists = True
break
- if not default_type:
- earnings = self.append('earnings', {})
- earnings.salary_component = salary_component
- earnings.amount = self.hour_rate * self.total_working_hours
+ if not row_exists:
+ wages_row = {
+ "salary_component": salary_component,
+ "abbr": frappe.db.get_value("Salary Component", salary_component, "salary_component_abbr"),
+ "amount": self.hour_rate * self.total_working_hours
+ }
+ doc.append('earnings', wages_row)
def pull_emp_details(self):
emp = frappe.db.get_value("Employee", self.employee, ["bank_name", "bank_ac_no"], as_dict=1)
@@ -307,8 +317,15 @@
frappe.throw(_("Salary Slip of employee {0} already created for time sheet {1}").format(self.employee, data.time_sheet))
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)
+
for d in self.get(component_type):
- if cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet:
+ if ((cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet) or\
+ getdate(self.start_date) < joining_date or getdate(self.end_date) > relieving_date):
+
d.amount = rounded((flt(d.default_amount) * flt(self.payment_days)
/ cint(self.total_working_days)), self.precision("amount", component_type))
elif not self.payment_days and not self.salary_slip_based_on_timesheet:
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py
index 22697f0..12f8335 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.py
@@ -16,7 +16,7 @@
self.validate_amount()
for e in self.get('employees'):
set_employee_name(e)
- self.validate_joining_date()
+ self.validate_date()
def get_ss_values(self,employee):
basic_info = frappe.db.sql("""select bank_name, bank_ac_no
@@ -29,12 +29,37 @@
if flt(self.net_pay) < 0 and self.salary_slip_based_on_timesheet:
frappe.throw(_("Net pay cannot be negative"))
- def validate_joining_date(self):
- for e in self.get('employees'):
- joining_date = getdate(frappe.db.get_value("Employee", e.employee, "date_of_joining"))
- if e.from_date and getdate(e.from_date) < joining_date:
+ def validate_date(self):
+ for employee in self.get('employees'):
+ joining_date, relieving_date = frappe.db.get_value("Employee", employee.employee,
+ ["date_of_joining", "relieving_date"])
+ if employee.from_date and getdate(employee.from_date) < joining_date:
frappe.throw(_("From Date {0} for Employee {1} cannot be before employee's joining Date {2}")
- .format(e.from_date, e.employee, joining_date))
+ .format(employee.from_date, employee.employee, joining_date))
+
+ st_name = frappe.db.sql("""select parent from `tabSalary Structure Employee`
+ where
+ employee=%(employee)s
+ 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'))
+ or (from_date between %(from_date)s and %(to_date)s)
+ )
+ and (
+ exists (select name from `tabSalary Structure`
+ where name = `tabSalary Structure Employee`.parent and is_active = 'Yes')
+ )
+ and parent != %(salary_struct)s""",
+ {
+ 'employee': employee.employee,
+ 'from_date': employee.from_date,
+ 'to_date': (employee.to_date or '2199-12-31'),
+ 'salary_struct': self.name
+ })
+
+ if st_name:
+ frappe.throw(_("Active Salary Structure {0} found for employee {1} for the given dates")
+ .format(st_name[0][0], employee.employee))
@frappe.whitelist()
def make_salary_slip(source_name, target_doc = None, employee = None, as_print = False, print_format = None):