Skip to content

Employee Advance Returned Amount Incorrectly Updated via Additional Salary #3645

@elshafei-developer

Description

@elshafei-developer

Information about bug

When repaying an unclaimed amount from an employee’s salary through the “Deduction from Salary” button on the Employee Advance form, the system creates an Additional Salary record.
This Additional Salary entry is linked to the same Employee Advance, and it triggers a method to update the Returned Amount field in the Employee Advance record.

The method responsible is:

# File: hrms/payroll/doctype/additional_salary/additional_salary.py
def update_return_amount_in_employee_advance(self):
    if self.ref_doctype == "Employee Advance" and self.ref_docname:
        return_amount = frappe.db.get_value("Employee Advance", self.ref_docname, "return_amount")

        if self.docstatus == 2:
            return_amount -= self.amount
        else:
            return_amount += self.amount

        frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", return_amount)
        advance = frappe.get_doc("Employee Advance", self.ref_docname)
        advance.set_status(update=True)

the Problem

The Employee Advance DocType is defined as an Advance Payment DocType in hrms/hooks.py:

advance_payment_doctypes = ["Leave Encashment", "Gratuity", "Employee Advance"]

This means any payment or receivable transaction related to this DocType automatically creates an Advance Payment Ledger Entry.

	# File: erpnext/erpnext/accounts/doctype/advance_payment_ledger_entry/advance_payment_ledger_entry.py
	def on_update(self):
		if (
			self.against_voucher_type in get_advance_payment_doctypes()
			and self.flags.update_outstanding == "Yes"
			and not frappe.flags.is_reverse_depr_entry
		):
			update_voucher_outstanding(self.against_voucher_type, self.against_voucher_no, None, None, None)

Consequently

  • When a Journal Entry or Payment Entry is submitted (example: using Payroll Entry ), it generates an Advance Payment Ledger Entry.
  • When that Document is canceled, the corresponding ledger entry is DeLinked.

However, because the Additional Salary also updates the Employee Advance Returned Amount directly, both mechanisms modify the same field, leading to data inconsistency.

  • If the Journal Entry or Payment Entry is canceled, the system will trigger the set_total_advance_paid function in theEmployee Advance to update the Returned Amount.
  • Users may not realize that this Employee Advance was linked to an Additional Salary and may create another Additional Salary for the same advance, resulting in duplicate deductions or incorrect accounting entries.
Employee.Advance.Issue.mp4

Actual Behavior

  • The update_return_amount_in_employee_advance() method in Additional Salary directly modifies the Returned Amount field.
  • This causes duplicate and inaccurate updates when Payroll Entry is submitted or canceled.

Expected Behavior

  • The Returned Amount in Employee Advance should only be updated inside the set_total_advance_paid function in the Employee Advance.
  • No direct updates from Additional Salary logic should occur.

Version

ERPNext: v15.82.2 (version-15)
Frappe Framework: v15.85.1 (version-15)
Frappe HR: v15.50.3 (version-15)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions