Skip to content

Commit

Permalink
revert: fix(Salary Structure Assignment: Preview Salary Slip): Calcul…
Browse files Browse the repository at this point in the history
…ation of earnings whose formula is dependent on deductions and so on (#2161)
  • Loading branch information
ruchamahabal authored Sep 5, 2024
1 parent b7ba4f5 commit 7260edf
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 91 deletions.
30 changes: 2 additions & 28 deletions hrms/payroll/doctype/salary_slip/salary_slip.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# License: GNU General Public License v3. See license.txt


import ast
import unicodedata
from datetime import date

Expand Down Expand Up @@ -792,33 +791,12 @@ def set_gross_pay_and_base_gross_pay():
if self.salary_structure:
self.calculate_component_amounts("deductions")

deduction_abbrs = [d.abbr for d in self.deductions]
self.update_dependent_components_recursively("earnings", deduction_abbrs)

set_gross_pay_and_base_gross_pay()
self.update_dependent_components_recursively("deductions", ["gross_pay", "base_gross_pay"])

set_loan_repayment(self)

self.set_precision_for_component_amounts()
self.set_net_pay()
self.compute_income_tax_breakup()

def update_dependent_components_recursively(
self, component_type: str, updated_var: str | list[str]
) -> None:
def is_var_updated(var: str | list[str]) -> bool:
return var == updated_var if isinstance(updated_var, str) else var in updated_var

other_component_type = "deductions" if component_type == "earnings" else "earnings"

for d in self._salary_structure_doc.get(component_type):
if d.amount_based_on_formula and d.formula:
for var in get_variables_from_formula(d.formula):
if is_var_updated(var):
self.add_structure_component(d, component_type)
self.update_dependent_components_recursively(other_component_type, d.abbr)

def set_net_pay(self):
self.total_deduction = self.get_component_totals("deductions")
self.base_total_deduction = flt(
Expand Down Expand Up @@ -2308,6 +2286,8 @@ def _safe_eval(code: str, eval_globals: dict | None = None, eval_locals: dict |


def _check_attributes(code: str) -> None:
import ast

from frappe.utils.safe_exec import UNSAFE_ATTRIBUTES

unsafe_attrs = set(UNSAFE_ATTRIBUTES).union(["__"]) - {"format"}
Expand Down Expand Up @@ -2346,9 +2326,3 @@ def email_salary_slips(names) -> None:
for name in names:
salary_slip = frappe.get_doc("Salary Slip", name)
salary_slip.email_salary_slip()


def get_variables_from_formula(formula: str) -> list[str]:
# compile expects a string
formula = cstr(formula)
return [node.id for node in ast.walk(ast.parse(formula, mode="eval")) if isinstance(node, ast.Name)]
63 changes: 0 additions & 63 deletions hrms/payroll/doctype/salary_slip/test_salary_slip.py
Original file line number Diff line number Diff line change
Expand Up @@ -1634,69 +1634,6 @@ def test_variable_tax_component(self):
self.assertEqual(test_tds.accounts[0].company, salary_slip.company)
self.assertListEqual(tax_component, ["_Test TDS"])

def test_circular_dependency_in_formula(self):
from hrms.payroll.doctype.salary_structure.test_salary_structure import (
create_salary_structure_assignment,
)

earnings = [
{
"salary_component": "Dependent Earning",
"abbr": "DE",
"type": "Earning",
"depends_on_payment_days": 0,
"amount_based_on_formula": 1,
"formula": "ID * 10",
},
]
make_salary_component(earnings, False, company_list=[])

deductions = [
{
"salary_component": "Independent Deduction",
"abbr": "ID",
"type": "Deduction",
"amount": 500,
},
{
"salary_component": "Dependent Deduction",
"abbr": "DD",
"type": "Deduction",
"amount_based_on_formula": 1,
"formula": "DE / 5\nif DE > 0\n else 0",
},
]
make_salary_component(deductions, False, company_list=[])

details = {
"doctype": "Salary Structure",
"name": "Test Salary Structure for Circular Dependency",
"company": "_Test Company",
"payroll_frequency": "Monthly",
"payment_account": get_random("Account", filters={"account_currency": "USD"}),
"currency": "INR",
}
salary_structure = frappe.get_doc(details)

for entry in earnings:
salary_structure.append("earnings", entry)
for entry in deductions:
salary_structure.append("deductions", entry)

salary_structure.insert()
salary_structure.submit()

emp = make_employee("[email protected]", company="_Test Company")

create_salary_structure_assignment(emp, salary_structure.name, currency="INR")
salary_slip = make_salary_slip(
salary_structure.name, employee=emp, posting_date=getdate(), for_preview=1
)

self.assertEqual(salary_slip.gross_pay, 5000)
self.assertEqual(salary_slip.earnings[0].amount, 5000)
self.assertEqual(salary_slip.deductions[1].amount, 1000)


class TestSalarySlipSafeEval(FrappeTestCase):
def test_safe_eval_for_salary_slip(self):
Expand Down

0 comments on commit 7260edf

Please sign in to comment.