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"},
]
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: