From 37a57813faa52b03802dcd651057ead6796fa612 Mon Sep 17 00:00:00 2001 From: Kanchan Chauhan Date: Wed, 8 Mar 2017 12:06:22 +0530 Subject: [PATCH] Multiple Salary Fixes --- erpnext/hr/doctype/salary_slip/salary_slip.py | 55 ++++++++++++------- .../salary_structure/salary_structure.py | 37 +++++++++++-- 2 files changed, 67 insertions(+), 25 deletions(-) diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 15d5df8ff05..b8382ecb23a 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -49,13 +49,13 @@ class SalarySlip(TransactionBase): 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 @@ class SalarySlip(TransactionBase): amount = eval(d.formula, None, data) if amount: data[d.abbr] = amount + return amount except NameError as err: @@ -97,17 +98,20 @@ class SalarySlip(TransactionBase): '''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 @@ class SalarySlip(TransactionBase): 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 @@ class SalarySlip(TransactionBase): 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 @@ class SalarySlip(TransactionBase): 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 22697f08a2a..12f8335b4d3 100644 --- a/erpnext/hr/doctype/salary_structure/salary_structure.py +++ b/erpnext/hr/doctype/salary_structure/salary_structure.py @@ -16,7 +16,7 @@ class SalaryStructure(Document): 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 @@ class SalaryStructure(Document): 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):