From 01beb6f39195d4d8ee7ffd8ddaffc3f037914ac7 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Mon, 4 Jul 2022 23:14:26 +0530 Subject: [PATCH 1/2] fix: components in the same table don't get updated value of prev payment-days based component --- erpnext/payroll/doctype/salary_slip/salary_slip.py | 6 ++++-- erpnext/payroll/doctype/salary_slip/test_salary_slip.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index e4c816c8fb4..f652125337b 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -626,7 +626,7 @@ class SalarySlip(TransactionBase): for struct_row in self._salary_structure_doc.get(component_type): amount = self.eval_condition_and_formula(struct_row, data) if amount is not None and struct_row.statistical_component == 0: - self.update_component_row(struct_row, amount, component_type) + self.update_component_row(struct_row, amount, component_type, data=data) def get_data_for_eval(self): """Returns data for evaluating formula""" @@ -780,7 +780,7 @@ class SalarySlip(TransactionBase): self.update_component_row(tax_row, tax_amount, "deductions") def update_component_row( - self, component_data, amount, component_type, additional_salary=None, is_recurring=0 + self, component_data, amount, component_type, additional_salary=None, is_recurring=0, data=None ): component_row = None for d in self.get(component_type): @@ -850,6 +850,8 @@ class SalarySlip(TransactionBase): component_row.amount = amount self.update_component_amount_based_on_payment_days(component_row) + if data: + data[component_row.abbr] = component_row.amount def update_component_amount_based_on_payment_days(self, component_row): joining_date, relieving_date = self.get_joining_and_relieving_dates() diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 1f17138d0c8..425a03b3ba6 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -1119,6 +1119,7 @@ def make_earning_salary_component( "formula": "BS*.5", "type": "Earning", "amount_based_on_formula": 1, + "depends_on_payment_days": 0, }, {"salary_component": "Leave Encashment", "abbr": "LE", "type": "Earning"}, ] From a28c7cf0943649e29447c191b64de64524848f36 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 12 Jul 2022 11:39:00 +0530 Subject: [PATCH 2/2] fix: Validate payment-days-based dependent component --- .../salary_structure/salary_structure.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.py b/erpnext/payroll/doctype/salary_structure/salary_structure.py index ed2a863b3dc..bebf0303798 100644 --- a/erpnext/payroll/doctype/salary_structure/salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/salary_structure.py @@ -1,6 +1,7 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt +import re import frappe from frappe import _ @@ -18,6 +19,7 @@ class SalaryStructure(Document): self.strip_condition_and_formula_fields() self.validate_max_benefits_with_flexi() self.validate_component_based_on_tax_slab() + self.validate_payment_days_based_dependent_component() def set_missing_values(self): overwritten_fields = [ @@ -58,6 +60,35 @@ 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_payment_days_based_dependent_component(self): + abbreviations = self.get_component_abbreviations() + for component_type in ("earnings", "deductions"): + for row in self.get(component_type): + if ( + row.formula + and row.depends_on_payment_days + # check if the formula contains any of the payment days components + and any(re.search(r"\b" + abbr + r"\b", row.formula) for abbr in abbreviations) + ): + message = _("Row #{0}: The {1} Component has the options {2} and {3} enabled.").format( + row.idx, + frappe.bold(row.salary_component), + frappe.bold("Amount based on formula"), + frappe.bold("Depends On Payment Days"), + ) + message += "

" + _( + "Disable {0} for the {1} component, to prevent the amount from being deducted twice, as its formula already uses a payment-days-based component." + ).format( + frappe.bold("Depends On Payment Days"), frappe.bold(row.salary_component) + ) + frappe.throw(message, title=_("Payment Days Dependency")) + + def get_component_abbreviations(self): + abbr = [d.abbr for d in self.earnings if d.depends_on_payment_days] + abbr += [d.abbr for d in self.deductions if d.depends_on_payment_days] + + return abbr + def strip_condition_and_formula_fields(self): # remove whitespaces from condition and formula fields for row in self.earnings: