mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-07 23:31:20 +00:00
fix: error messages while evaluating formulas and handle line boundaries (#35989)
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
This commit is contained in:
@@ -46,6 +46,7 @@ from erpnext.payroll.doctype.payroll_period.payroll_period import (
|
|||||||
get_payroll_period,
|
get_payroll_period,
|
||||||
get_period_factor,
|
get_period_factor,
|
||||||
)
|
)
|
||||||
|
from erpnext.payroll.utils import prepare_error_msg, sanitize_expression
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
|
|
||||||
|
|
||||||
@@ -726,32 +727,53 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
return data, default_data
|
return data, default_data
|
||||||
|
|
||||||
def eval_condition_and_formula(self, d, data):
|
def eval_condition_and_formula(self, struct_row, data):
|
||||||
try:
|
try:
|
||||||
condition = d.condition.strip().replace("\n", " ") if d.condition else None
|
condition = sanitize_expression(struct_row.condition)
|
||||||
if condition:
|
if condition:
|
||||||
if not frappe.safe_eval(condition, self.whitelisted_globals, data):
|
if not frappe.safe_eval(condition, self.whitelisted_globals, data):
|
||||||
return None
|
return None
|
||||||
amount = d.amount
|
amount = struct_row.amount
|
||||||
if d.amount_based_on_formula:
|
if struct_row.amount_based_on_formula:
|
||||||
formula = d.formula.strip().replace("\n", " ") if d.formula else None
|
formula = sanitize_expression(struct_row.formula)
|
||||||
if formula:
|
if formula:
|
||||||
amount = flt(frappe.safe_eval(formula, self.whitelisted_globals, data), d.precision("amount"))
|
amount = flt(
|
||||||
|
frappe.safe_eval(formula, self.whitelisted_globals, data), struct_row.precision("amount")
|
||||||
|
)
|
||||||
if amount:
|
if amount:
|
||||||
data[d.abbr] = amount
|
data[struct_row.abbr] = amount
|
||||||
|
|
||||||
return amount
|
return amount
|
||||||
|
|
||||||
except NameError as err:
|
except NameError as ne:
|
||||||
frappe.throw(
|
message = prepare_error_msg(
|
||||||
_("{0} <br> This error can be due to missing or deleted field.").format(err),
|
row=struct_row,
|
||||||
title=_("Name error"),
|
error=ne,
|
||||||
|
expression=formula or condition,
|
||||||
|
description=_("This error can be due to missing or deleted field."),
|
||||||
)
|
)
|
||||||
except SyntaxError as err:
|
|
||||||
frappe.throw(_("Syntax error in formula or condition: {0}").format(err))
|
frappe.throw(message, title=_("Name error"))
|
||||||
|
|
||||||
|
except SyntaxError as se:
|
||||||
|
message = prepare_error_msg(
|
||||||
|
row=struct_row,
|
||||||
|
error=se,
|
||||||
|
expression=formula or condition,
|
||||||
|
description=_("Please check the syntax of your formula."),
|
||||||
|
)
|
||||||
|
|
||||||
|
frappe.throw(message, title=_("Syntax error"))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
frappe.throw(_("Error in formula or condition: {0}").format(e))
|
message = prepare_error_msg(
|
||||||
raise
|
row=struct_row,
|
||||||
|
error=e,
|
||||||
|
expression=formula or condition,
|
||||||
|
description=_("This error can be due to invalid formula or condition."),
|
||||||
|
)
|
||||||
|
|
||||||
|
frappe.throw(message, title=_("Error in formula or condition"))
|
||||||
|
|
||||||
def add_employee_benefits(self, payroll_period):
|
def add_employee_benefits(self, payroll_period):
|
||||||
for struct_row in self._salary_structure_doc.get("earnings"):
|
for struct_row in self._salary_structure_doc.get("earnings"):
|
||||||
|
|||||||
66
erpnext/payroll/utils.py
Normal file
66
erpnext/payroll/utils.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import get_link_to_form
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_expression(string: Optional[str] = None) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Sanitizes an expression string by removing leading/trailing spaces, newlines, and line boundaries.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
string (Optional[str]): The input string to be sanitized (default: None).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[str]: The sanitized string or None if the input string is empty or None.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
expression = "\r\n gross_pay > 10000\n "
|
||||||
|
sanitized_expr = sanitize_expression(expression)
|
||||||
|
"""
|
||||||
|
if not string:
|
||||||
|
return None
|
||||||
|
|
||||||
|
parts = string.strip().splitlines()
|
||||||
|
string = " ".join(parts)
|
||||||
|
|
||||||
|
return string
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_error_msg(*, row: dict, error: str, expression: str, description: str) -> str:
|
||||||
|
"""
|
||||||
|
Prepares an error message string with formatted information about the error.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
row (dict): A dictionary representing the row data.
|
||||||
|
error (str): The error message.
|
||||||
|
expression (str): The expression that caused the error.
|
||||||
|
description (str): Additional description or hint for the error (optional).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted error message string.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
row = {
|
||||||
|
"parenttype": "Salary Structure",
|
||||||
|
"parent": "Salary Structure-00001",
|
||||||
|
"parentfield": "earnings",
|
||||||
|
"idx": 1
|
||||||
|
}
|
||||||
|
error = "SyntaxError: invalid syntax"
|
||||||
|
expression = " 200 if (gross_pay>10000 and month!= 'Feb')) else 0 "
|
||||||
|
description = "Check the syntax of the expression."
|
||||||
|
error_msg = prepare_error_msg(row=row, error=error, expression=expression, description=description)
|
||||||
|
"""
|
||||||
|
msg = _("Error in {0} while evaluating the {1} {2} at row {3}").format(
|
||||||
|
row.parentfield.title(), row.parenttype, get_link_to_form(row.parenttype, row.parent), row.idx
|
||||||
|
)
|
||||||
|
msg += "<br><br>{0}: {1}<br><br>{2}: {3}".format(
|
||||||
|
frappe.bold(_("Expression:")), expression, frappe.bold(_("Error:")), error
|
||||||
|
)
|
||||||
|
|
||||||
|
if description:
|
||||||
|
msg += "<br><br>{0}: {1}".format(frappe.bold(_("Hint:")), description)
|
||||||
|
|
||||||
|
return msg
|
||||||
Reference in New Issue
Block a user