diff --git a/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.js b/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.js index 2a8ce91575..9af3ee9ddc 100644 --- a/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.js +++ b/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.js @@ -78,7 +78,7 @@ var calculate_all = function(doc) { if(cint(tbl[i].amount) > 0) { total_amount += flt(tbl[i].amount); } - if(tbl[i].is_pro_rata_applicable == 1){ + if(tbl[i].pay_against_benefit_claim != 1){ pro_rata_dispensed_amount += flt(tbl[i].amount); } } diff --git a/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py b/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py index e09376965d..45e2d653ec 100644 --- a/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py +++ b/erpnext/hr/doctype/employee_benefit_application/employee_benefit_application.py @@ -9,7 +9,7 @@ from frappe.utils import date_diff, getdate, rounded, add_days, cstr, cint from frappe.model.document import Document from erpnext.hr.doctype.payroll_period.payroll_period import get_payroll_period_days from erpnext.hr.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure -from erpnext.hr.utils import get_sal_slip_total_benefit_given, get_holidays_for_employee +from erpnext.hr.utils import get_sal_slip_total_benefit_given, get_holidays_for_employee, get_previous_claimed_amount class EmployeeBenefitApplication(Document): def validate(self): @@ -17,9 +17,22 @@ class EmployeeBenefitApplication(Document): if self.max_benefits <= 0: frappe.throw(_("Employee {0} has no maximum benefit amount").format(self.employee)) self.validate_max_benefit_for_component() + self.validate_prev_benefit_claim() if self.remainig_benefits > 0: self.validate_remaining_benefit_amount() + def validate_prev_benefit_claim(self): + if self.employee_benefits: + for benefit in self.employee_benefits: + if benefit.pay_against_benefit_claim == 1: + payroll_period = frappe.get_doc("Payroll Period", self.payroll_period) + benefit_claimed = get_previous_claimed_amount(self.employee, payroll_period, component = benefit.earning_component) + benefit_given = get_sal_slip_total_benefit_given(self.employee, payroll_period, component = benefit.earning_component) + benefit_claim_remining = benefit_claimed - benefit_given + if benefit_claimed > 0 and benefit_claim_remining > benefit.amount: + frappe.throw(_("An amount of {0} already claimed for the component {1},\ + set the amount equal or greater than {2}").format(benefit_claimed, benefit.earning_component, benefit_claim_remining)) + def validate_remaining_benefit_amount(self): # check salary structure earnings have flexi component (sum of max_benefit_amount) # without pro-rata which satisfy the remainig_benefits @@ -37,8 +50,8 @@ class EmployeeBenefitApplication(Document): if salary_structure.earnings: for earnings in salary_structure.earnings: if earnings.is_flexible_benefit == 1 and earnings.salary_component not in benefit_components: - is_pro_rata_applicable, max_benefit_amount = frappe.db.get_value("Salary Component", earnings.salary_component, ["is_pro_rata_applicable", "max_benefit_amount"]) - if is_pro_rata_applicable == 1: + pay_against_benefit_claim, max_benefit_amount = frappe.db.get_value("Salary Component", earnings.salary_component, ["pay_against_benefit_claim", "max_benefit_amount"]) + if pay_against_benefit_claim != 1: pro_rata_amount += max_benefit_amount else: non_pro_rata_amount += max_benefit_amount @@ -113,7 +126,7 @@ def get_max_benefits_remaining(employee, on_date, payroll_period): sal_struct = frappe.get_doc("Salary Structure", sal_struct_name) for sal_struct_row in sal_struct.get("earnings"): salary_component = frappe.get_doc("Salary Component", sal_struct_row.salary_component) - if salary_component.depends_on_lwp == 1 and salary_component.is_pro_rata_applicable == 1: + if salary_component.depends_on_lwp == 1 and salary_component.pay_against_benefit_claim != 1: have_depends_on_lwp = True benefit_amount = get_benefit_pro_rata_ratio_amount(sal_struct, salary_component.max_benefit_amount) amount_per_day = benefit_amount / payroll_period_days @@ -188,8 +201,8 @@ def get_benefit_pro_rata_ratio_amount(sal_struct, component_max): total_pro_rata_max = 0 benefit_amount = 0 for sal_struct_row in sal_struct.get("earnings"): - is_pro_rata_applicable, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["is_pro_rata_applicable", "max_benefit_amount"]) - if sal_struct_row.is_flexible_benefit == 1 and is_pro_rata_applicable == 1: + pay_against_benefit_claim, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["pay_against_benefit_claim", "max_benefit_amount"]) + if sal_struct_row.is_flexible_benefit == 1 and pay_against_benefit_claim != 1: total_pro_rata_max += max_benefit_amount if total_pro_rata_max > 0: benefit_amount = component_max * sal_struct.max_benefits / total_pro_rata_max diff --git a/erpnext/hr/doctype/employee_benefit_application_detail/employee_benefit_application_detail.json b/erpnext/hr/doctype/employee_benefit_application_detail/employee_benefit_application_detail.json index eba9b19e38..480ec5b623 100644 --- a/erpnext/hr/doctype/employee_benefit_application_detail/employee_benefit_application_detail.json +++ b/erpnext/hr/doctype/employee_benefit_application_detail/employee_benefit_application_detail.json @@ -53,8 +53,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_from": "earning_component.is_pro_rata_applicable", - "fieldname": "is_pro_rata_applicable", + "fetch_from": "earning_component.pay_against_benefit_claim", + "fieldname": "pay_against_benefit_claim", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, @@ -63,7 +63,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Is Pro-rata Applicable", + "label": "Pay Against Benefit Claim", "length": 0, "no_copy": 0, "options": "", @@ -157,7 +157,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-26 12:00:37.588822", + "modified": "2018-06-13 17:34:57.783584", "modified_by": "Administrator", "module": "HR", "name": "Employee Benefit Application Detail", 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 a59aaea1a2..59b6a6c670 100644 --- a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.json +++ b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.json @@ -43,7 +43,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -77,7 +77,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -87,38 +87,39 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_from": "employee.department", - "fieldname": "department", - "fieldtype": "Link", - "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": "Department", - "length": 0, - "no_copy": 0, - "options": "Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "fetch_from": "employee.department", + "fieldname": "department", + "fieldtype": "Link", + "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": "Department", + "length": 0, + "no_copy": 0, + "options": "Department", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "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, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "columns": 0, "default": "Today", "fieldname": "claim_date", @@ -143,7 +144,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -174,7 +175,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -207,7 +208,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -241,7 +242,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -251,8 +252,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_from": "earning_component.is_pro_rata_applicable", - "fieldname": "is_pro_rata_applicable", + "fetch_from": "earning_component.pay_against_benefit_claim", + "fieldname": "pay_against_benefit_claim", "fieldtype": "Check", "hidden": 1, "ignore_user_permissions": 0, @@ -261,7 +262,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Is Pro-Rata Applicable", + "label": "Pay Against Benefit Claim", "length": 0, "no_copy": 0, "options": "", @@ -269,7 +270,7 @@ "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -307,7 +308,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -340,7 +341,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -372,7 +373,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -403,7 +404,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -435,7 +436,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 } ], @@ -449,7 +450,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-26 12:43:21.082282", + "modified": "2018-06-18 11:14:59.895298", "modified_by": "Administrator", "module": "HR", "name": "Employee Benefit Claim", @@ -542,4 +543,4 @@ "title_field": "employee_name", "track_changes": 1, "track_seen": 0 -} +} \ 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 69e19bc01f..6f57bd6156 100644 --- a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py +++ b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py @@ -7,7 +7,7 @@ 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 -from erpnext.hr.utils import get_payroll_period +from erpnext.hr.utils import get_payroll_period, get_previous_claimed_amount from erpnext.hr.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure class EmployeeBenefitClaim(Document): @@ -21,12 +21,12 @@ class EmployeeBenefitClaim(Document): self.validate_max_benefit_for_component(payroll_period) self.validate_max_benefit_for_sal_struct(max_benefits) self.validate_benefit_claim_amount(max_benefits, payroll_period) - if not self.is_pro_rata_applicable: + if self.pay_against_benefit_claim: self.validate_non_pro_rata_benefit_claim(max_benefits, payroll_period) def validate_benefit_claim_amount(self, max_benefits, payroll_period): claimed_amount = self.claimed_amount - claimed_amount += self.get_previous_claimed_amount(payroll_period) + claimed_amount += get_previous_claimed_amount(self.employee, payroll_period) if max_benefits < claimed_amount: frappe.throw(_("Maximum benefit of employee {0} exceeds {1} by the sum {2} of previous claimed\ amount").format(self.employee, max_benefits, claimed_amount-max_benefits)) @@ -37,7 +37,7 @@ class EmployeeBenefitClaim(Document): def validate_max_benefit_for_component(self, payroll_period): claimed_amount = self.claimed_amount - claimed_amount += self.get_previous_claimed_amount(payroll_period, self.earning_component) + claimed_amount += get_previous_claimed_amount(self.employee, payroll_period, component = self.earning_component) if claimed_amount > self.max_amount_eligible: frappe.throw(_("Maximum amount eligible for the component {0} exceeds {1}").format(self.earning_component, self.max_amount_eligible)) @@ -51,7 +51,7 @@ class EmployeeBenefitClaim(Document): if not pro_rata_amount: pro_rata_amount = 0 - claimed_amount += self.get_previous_claimed_amount(payroll_period, True) + claimed_amount += get_previous_claimed_amount(self.employee, payroll_period, non_pro_rata = True) if max_benefits < pro_rata_amount + claimed_amount: frappe.throw(_("Maximum benefit of employee {0} exceeds {1} by the sum {2} of benefit application pro-rata component\ amount and previous claimed amount").format(self.employee, max_benefits, pro_rata_amount+claimed_amount-max_benefits)) @@ -63,13 +63,13 @@ class EmployeeBenefitClaim(Document): total_pro_rata_max = 0 benefit_amount_total = 0 for sal_struct_row in sal_struct.get("earnings"): - is_pro_rata_applicable, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["is_pro_rata_applicable", "max_benefit_amount"]) - if sal_struct_row.is_flexible_benefit == 1 and is_pro_rata_applicable == 1: + pay_against_benefit_claim, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["pay_against_benefit_claim", "max_benefit_amount"]) + if sal_struct_row.is_flexible_benefit == 1 and pay_against_benefit_claim != 1: total_pro_rata_max += max_benefit_amount if total_pro_rata_max > 0: for sal_struct_row in sal_struct.get("earnings"): - is_pro_rata_applicable, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["is_pro_rata_applicable", "max_benefit_amount"]) - if sal_struct_row.is_flexible_benefit == 1 and is_pro_rata_applicable == 1: + pay_against_benefit_claim, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["pay_against_benefit_claim", "max_benefit_amount"]) + if sal_struct_row.is_flexible_benefit == 1 and pay_against_benefit_claim != 1: component_max = max_benefit_amount benefit_amount = component_max * sal_struct.max_benefits / total_pro_rata_max if benefit_amount > component_max: @@ -91,35 +91,11 @@ class EmployeeBenefitClaim(Document): return frappe.db.get_value("Employee Benefit Application", application, "pro_rata_dispensed_amount") return False - def get_previous_claimed_amount(self, payroll_period, non_pro_rata=False, component=False): - total_claimed_amount = 0 - query = """ - select sum(claimed_amount) as 'total_amount' - from `tabEmployee Benefit Claim` - where employee=%(employee)s - and docstatus = 1 - and (claim_date between %(start_date)s and %(end_date)s) - """ - if non_pro_rata: - query += "and is_pro_rata_applicable = 0" - if component: - query += "and earning_component = %(component)s" - - sum_of_claimed_amount = frappe.db.sql(query, { - 'employee': self.employee, - 'start_date': payroll_period.start_date, - 'end_date': payroll_period.end_date, - 'component': component - }, as_dict=True) - if sum_of_claimed_amount and sum_of_claimed_amount[0].total_amount > 0: - total_claimed_amount = sum_of_claimed_amount[0].total_amount - return total_claimed_amount - def get_benefit_claim_amount(employee, start_date, end_date, struct_row): benefit_claim_details = frappe.db.sql(""" select claimed_amount from `tabEmployee Benefit Claim` where employee=%(employee)s - and docstatus = 1 and is_pro_rata_applicable = 0 + and docstatus = 1 and pay_against_benefit_claim = 1 and earning_component = %(earning_component)s and (claim_date between %(start_date)s and %(end_date)s) """, { diff --git a/erpnext/hr/doctype/salary_component/salary_component.json b/erpnext/hr/doctype/salary_component/salary_component.json index fd6fb17d2d..e3543bff73 100644 --- a/erpnext/hr/doctype/salary_component/salary_component.json +++ b/erpnext/hr/doctype/salary_component/salary_component.json @@ -540,7 +540,7 @@ "collapsible": 0, "columns": 0, "depends_on": "is_flexible_benefit", - "fieldname": "is_pro_rata_applicable", + "fieldname": "pay_against_benefit_claim", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, @@ -549,7 +549,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Is Pro-rata Applicable", + "label": "Pay Against Benefit Claim", "length": 0, "no_copy": 0, "permlevel": 0, @@ -1002,7 +1002,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-06-19 11:37:27.521796", + "modified": "2018-06-19 11:37:37.521796", "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 47f1cc4b07..94f80e11da 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -87,7 +87,7 @@ class SalarySlip(TransactionBase): self.update_component_row(frappe._dict(tax_row), amount, "deductions") def add_employee_flexi_benefits(self, struct_row): - if frappe.db.get_value("Salary Component", struct_row.salary_component, "is_pro_rata_applicable") == 1: + if frappe.db.get_value("Salary Component", struct_row.salary_component, "pay_against_benefit_claim") != 1: benefit_component_amount = get_benefit_component_amount(self.employee, self.start_date, self.end_date, struct_row, self._salary_structure_doc, self.payment_days, self.total_working_days) if benefit_component_amount: self.update_component_row(struct_row, benefit_component_amount, "earnings") diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index d8636ede09..42cf0a9761 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -353,3 +353,27 @@ def calculate_hra_exemption_for_period(doc): # Don't delete this method, used for localization # Indian HRA Exemption Calculation return {} + +def get_previous_claimed_amount(employee, payroll_period, non_pro_rata=False, component=False): + total_claimed_amount = 0 + query = """ + select sum(claimed_amount) as 'total_amount' + from `tabEmployee Benefit Claim` + where employee=%(employee)s + and docstatus = 1 + and (claim_date between %(start_date)s and %(end_date)s) + """ + if non_pro_rata: + query += "and pay_against_benefit_claim = 1" + if component: + query += "and earning_component = %(component)s" + + sum_of_claimed_amount = frappe.db.sql(query, { + 'employee': employee, + 'start_date': payroll_period.start_date, + 'end_date': payroll_period.end_date, + 'component': component + }, as_dict=True) + if sum_of_claimed_amount and sum_of_claimed_amount[0].total_amount > 0: + total_claimed_amount = sum_of_claimed_amount[0].total_amount + return total_claimed_amount