diff --git a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.js b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.js index 99d7809d1a1..64fde037633 100644 --- a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.js +++ b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.js @@ -10,7 +10,7 @@ frappe.ui.form.on('Employee Benefit Claim', { is_flexible_benefit: true, disabled: false } - } - }) + }; + }); } }); diff --git a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.json b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.json index 00d5159c512..9da7cdb53b5 100644 --- a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.json +++ b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.json @@ -188,6 +188,7 @@ "label": "Max Amount Eligible", "length": 0, "no_copy": 0, + "options": "earning_component.max_benefit_amount", "permlevel": 0, "precision": "", "print_hide": 0, @@ -201,6 +202,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_pro_rata_applicable", + "fieldtype": "Check", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Pro-Rata Applicable", + "length": 0, + "no_copy": 0, + "options": "earning_component.is_pro_rata_applicable", + "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, @@ -367,7 +400,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-14 15:38:41.538646", + "modified": "2018-05-16 17:21:25.598531", "modified_by": "Administrator", "module": "HR", "name": "Employee Benefit Claim", @@ -460,4 +493,4 @@ "title_field": "employee_name", "track_changes": 1, "track_seen": 0 -} \ No newline at end of file +} \ No newline at end of file diff --git a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py index 551d1accd5a..39b3540e06a 100644 --- a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py +++ b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py @@ -4,7 +4,62 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.model.document import Document +from erpnext.hr.doctype.employee_benefit_application.employee_benefit_application import get_max_benefits class EmployeeBenefitClaim(Document): - pass + def validate(self): + if not self.is_pro_rata_applicable: + self.validate_max_benefit_for_sal_struct() + # TODO: Validate all cases + + def validate_max_benefit_for_sal_struct(self): + max_benefits = get_max_benefits(self.employee, self.claim_date) + if self.claimed_amount > max_benefits: + frappe.throw(_("Maximum benefit amount of employee {0} exceeds {1}").format(self.employee, max_benefits)) + + +def get_employee_benefit_claim(salary_slip): + employee_benefits = frappe.db.sql(""" + select name from `tabEmployee Benefit Claim` + where employee=%(employee)s + and docstatus = 1 and is_pro_rata_applicable = 0 + and (claim_date between %(start_date)s and %(end_date)s) + """, { + 'employee': salary_slip.employee, + 'start_date': salary_slip.start_date, + 'end_date': salary_slip.end_date + }) + + if employee_benefits: + salary_components_array = [] + for employee_benefit in employee_benefits: + struct_row = {} + salary_components_dict = {} + group_component_amount = {} + + employee_benefit_claim = frappe.get_doc("Employee Benefit Claim", employee_benefit[0]) + amount = employee_benefit_claim.claimed_amount + sc = frappe.get_doc("Salary Component", employee_benefit_claim.earning_component) + + salary_component = sc + if sc.earning_component_group and not sc.is_group and not sc.flexi_default: + salary_component = frappe.get_doc("Salary Component", sc.earning_component_group) + if group_component_amount and group_component_amount.has_key(sc.earning_component_group): + group_component_amount[sc.earning_component_group] += amount + else: + group_component_amount[sc.earning_component_group] = amount + amount = group_component_amount[sc.earning_component_group] + + struct_row['depends_on_lwp'] = salary_component.depends_on_lwp + struct_row['salary_component'] = salary_component.name + struct_row['abbr'] = salary_component.salary_component_abbr + struct_row['do_not_include_in_total'] = salary_component.do_not_include_in_total + salary_components_dict['amount'] = amount + salary_components_dict['struct_row'] = struct_row + salary_components_array.append(salary_components_dict) + + if len(salary_components_array) > 0: + return salary_components_array + return False diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 0da3094cd3b..5f284789fac 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -15,6 +15,7 @@ from frappe.utils.background_jobs import enqueue from erpnext.hr.doctype.additional_salary_component.additional_salary_component import get_additional_salary_component from erpnext.hr.doctype.employee_benefit_application.employee_benefit_application import get_employee_benefit_application, get_amount from erpnext.hr.doctype.payroll_period.payroll_period import get_payroll_period_days +from erpnext.hr.doctype.employee_benefit_claim.employee_benefit_claim import get_employee_benefit_claim class SalarySlip(TransactionBase): def autoname(self): @@ -65,16 +66,18 @@ class SalarySlip(TransactionBase): if additional_components: for additional_component in additional_components: additional_component = frappe._dict(additional_component) - self.update_component_row(frappe._dict(additional_component.struct_row), additional_component.amount, "earnings") + amount = self.update_amount_for_other_component(frappe._dict(additional_component.struct_row).salary_component, additional_component.amount) + self.update_component_row(frappe._dict(additional_component.struct_row), amount, "earnings") - employee_benefits = get_employee_benefit_application(self) - if employee_benefits: - for employee_benefit in employee_benefits: - benefit_component = frappe._dict(employee_benefit) - self.update_component_row(frappe._dict(benefit_component.struct_row), benefit_component.amount, "earnings") - else: - max_benefits = self._salary_structure_doc.get("max_benefits") - if max_benefits > 0: + max_benefits = self._salary_structure_doc.get("max_benefits") + if max_benefits > 0: + employee_benefits = get_employee_benefit_application(self) + if employee_benefits: + for employee_benefit in employee_benefits: + benefit_component = frappe._dict(employee_benefit) + amount = self.update_amount_for_other_component(frappe._dict(benefit_component.struct_row).salary_component, benefit_component.amount) + self.update_component_row(frappe._dict(benefit_component.struct_row), amount, "earnings") + else: default_flexi_compenent = frappe.db.exists( 'Salary Component', { @@ -86,11 +89,26 @@ class SalarySlip(TransactionBase): if default_flexi_compenent: flexi_struct_row = self.create_flexi_struct_row(default_flexi_compenent) payroll_period_days = get_payroll_period_days(self.start_date, self.end_date, self.company) - amount = get_amount(payroll_period_days, self.start_date, self.end_date, max_benefits) + amount = self.update_amount_for_other_component(default_flexi_compenent, get_amount(payroll_period_days, self.start_date, self.end_date, max_benefits)) self.update_component_row(flexi_struct_row, amount, "earnings") else: frappe.throw(_("Configure default flexible benefit salary component for apply pro-rata benefit")) + benefit_claims = get_employee_benefit_claim(self) + if benefit_claims: + for benefit_claim in benefit_claims: + benefit_component = frappe._dict(benefit_claim) + amount = self.update_amount_for_other_component(frappe._dict(benefit_component.struct_row).salary_component, benefit_component.amount) + self.update_component_row(frappe._dict(benefit_component.struct_row), amount, "earnings") + + def update_amount_for_other_component(self, salary_component, new_amount): + amount = new_amount + for d in self.get("earnings"): + if d.salary_component == salary_component: + d.amount += new_amount + amount = d.amount + return amount + def create_flexi_struct_row(self, default_flexi_compenent): salary_component = frappe.get_doc("Salary Component", default_flexi_compenent) flexi_struct_row = {} @@ -211,8 +229,9 @@ class SalarySlip(TransactionBase): 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 docstatus = 1 and salary_structure in (select name from `tabSalary Structure` - where docstatus = 1 and is_active = 'Yes'%s) + where is_active = 'Yes'%s) """% ('%s', '%s', '%s','%s','%s', cond),(self.employee, self.start_date, joining_date, self.end_date, relieving_date)) if st_name: