Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update status of gratuity record referenced in fnf #2518

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@


class FullandFinalStatement(Document):
def on_change(self):
for payable in self.payables:
if payable.component == "Gratuity":
if frappe.db.exists("Gratuity", payable.reference_document):
gratuity = frappe.get_doc("Gratuity", payable.reference_document)
if self.status == "Paid":
amount = payable.amount if self.docstatus == 1 else 0
gratuity.db_set("paid_amount", amount)
if self.docstatus == 2:
gratuity.set_status(cancel=True)

Copy link
Member

@ruchamahabal ruchamahabal Dec 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Skip the db.exists call since doc deletion is not allowed if it has some linking
  2. on_change will run on validate + deletion & db_set calls too. We just need this to run on on_submit and on_cancel
  3. gratuity.set_status needs to be called in both the cases. On updating paid amount or cancelling FnF too
  4. Reduce nesting in the function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Rucha!
Changes implemented:

  • refactor code for updating status of gratuity records
  • set_status is called on linked gratuity docs whenever the FNF is canceled or its payment status is updated via the update_full_and_final_statement_status function.

Copy link
Member

@ruchamahabal ruchamahabal Jan 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a few changes:

set_status is called on linked gratuity docs whenever the FNF is canceled

Removed this. Realized that payment is handled via JV so cancelling FnF -> cancel JV (linked document cancellation) -> update status for gratuity. Not really needed on FnF cancellation too

Added a filter in FnF child table to prevent cancelled document selection.

def before_insert(self):
self.get_outstanding_statements()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def test_check_bootstraped_data_asset_movement_and_jv_creation(self):
"Leave Encashment",
]

receivable_bootstraped_component = ["Employee Advance", "Loan"]
receivable_bootstraped_component = self.fnf.get_receivable_component()

# checking payables and receivables bootstraped value
self.assertEqual([payable.component for payable in self.fnf.payables], payables_bootstraped_component)
Expand Down
13 changes: 10 additions & 3 deletions hrms/payroll/doctype/gratuity/gratuity.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def gratuity_settings(self):

return self._gratuity_settings

def set_status(self, update=False):
def set_status(self, update=False, cancel=False):
status = {"0": "Draft", "1": "Submitted", "2": "Cancelled"}[cstr(self.docstatus or 0)]

if self.docstatus == 1:
Expand All @@ -47,17 +47,24 @@ def set_status(self, update=False):
else:
status = "Unpaid"

if update:
self.db_set("status", status)
if update and self.status != status:
if self.status != status:
self.db_set("status", status)
else:
self.status = status

if cancel and self.docstatus != 2:
self.db_set("docstatus", 2)

def on_submit(self):
if self.pay_via_salary_slip:
self.create_additional_salary()
else:
self.create_gl_entries()

def on_change(self):
self.set_status(update=True)

def on_cancel(self):
self.ignore_linked_doctypes = ["GL Entry"]
self.create_gl_entries(cancel=True)
Expand Down
47 changes: 47 additions & 0 deletions hrms/payroll/doctype/gratuity/test_gratuity.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,52 @@ def test_gratuity_amount_consistent_irrespective_of_payment_days(self):
)
self.assertEqual(gratuity.amount, 190000.0)

@set_holiday_list("Salary Slip Test Holiday List", "_Test Company")
def test_settle_gratuity_via_fnf_statement(self):
from hrms.hr.doctype.full_and_final_statement.test_full_and_final_statement import (
create_full_and_final_statement,
)

create_salary_slip(self.employee)
setup_gratuity_rule("Rule Under Limited Contract (UAE)")
set_mode_of_payment_account()

# create gratuity
gratuity = create_gratuity(
expense_account="Payment Account - _TC", mode_of_payment="Cash", employee=self.employee
)
gratuity.reload()

# create Full and Final Statement and add gratuity as Payables
fnf = create_full_and_final_statement(self.employee)
fnf.payables = []
fnf.receivables = []
fnf.append(
"payables",
{
"component": "Gratuity",
"reference_document_type": "Gratuity",
"reference_document": gratuity.name,
"amount": gratuity.amount,
"account": gratuity.payable_account,
"status": "Settled",
},
)
fnf.save()
fnf.create_journal_entry()

# mark fnf as paid and submit it
fnf.status = "Paid"
fnf.save()
fnf.submit()

gratuity.reload()
self.assertEqual(gratuity.status, "Paid")

fnf.cancel()
gratuity.reload()
self.assertEqual(gratuity.status, "Cancelled")


def setup_gratuity_rule(name: str) -> dict:
from hrms.regional.united_arab_emirates.setup import setup
Expand Down Expand Up @@ -201,6 +247,7 @@ def create_gratuity(**args):
gratuity.expense_account = args.expense_account or "Payment Account - _TC"
gratuity.payable_account = args.payable_account or get_payable_account("_Test Company")
gratuity.mode_of_payment = args.mode_of_payment or "Cash"
gratuity.cost_center = args.cost_center or "Main - _TC"

gratuity.save()
gratuity.submit()
Expand Down
Loading