Merge pull request #38205 from vorasmit/partial-cancel

fix: partial cancel of gle and ple (backport #35609)
This commit is contained in:
ruthra kumar
2023-11-22 10:27:05 +05:30
committed by GitHub
3 changed files with 93 additions and 6 deletions

View File

@@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import json
import unittest
import frappe
@@ -21,6 +22,7 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import (
create_sales_invoice,
create_sales_invoice_against_cost_center,
)
from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.setup.doctype.employee.test_employee import make_employee
@@ -1219,6 +1221,76 @@ class TestPaymentEntry(FrappeTestCase):
so.reload()
self.assertEqual(so.advance_paid, so.rounded_total)
def test_partial_cancel_for_payment_entry(self):
si = create_sales_invoice()
pe = get_payment_entry(si.doctype, si.name)
pe.save()
pe.submit()
# Additional GL Entry
tax_amount = 10
reference_row = pe.references[0]
gl_args = {
"party_type": pe.party_type,
"party": pe.party,
"against_voucher_type": reference_row.reference_doctype,
"against_voucher": reference_row.reference_name,
"voucher_detail_no": reference_row.name,
}
gl_dicts = []
gl_dicts.extend(
[
pe.get_gl_dict(
{
"account": pe.paid_to,
"credit": tax_amount,
"credit_in_account_currency": tax_amount,
**gl_args,
}
),
pe.get_gl_dict(
{
"account": pe.paid_from,
"debit": tax_amount,
"debit_in_account_currency": tax_amount,
**gl_args,
}
),
]
)
make_gl_entries(gl_dicts)
# Assert PLEs Before
self.assertPLEntries(
pe,
[
{"amount": -100.0, "against_voucher_no": si.name},
{"amount": 10.0, "against_voucher_no": si.name},
],
)
# Partially cancel Payment Entry
make_reverse_gl_entries(gl_dicts, partial_cancel=True)
self.assertPLEntries(pe, [{"amount": -100.0, "against_voucher_no": si.name}])
def assertPLEntries(self, payment_doc, expected_pl_entries):
pl_entries = frappe.get_all(
"Payment Ledger Entry",
filters={
"voucher_type": payment_doc.doctype,
"voucher_no": payment_doc.name,
"delinked": 0,
},
fields=["amount", "against_voucher_no"],
)
out_str = json.dumps(sorted(pl_entries, key=json.dumps))
expected_out_str = json.dumps(sorted(expected_pl_entries, key=json.dumps))
self.assertEqual(out_str, expected_out_str)
def create_payment_entry(**args):
payment_entry = frappe.new_doc("Payment Entry")

View File

@@ -556,7 +556,12 @@ def get_round_off_account_and_cost_center(
def make_reverse_gl_entries(
gl_entries=None, voucher_type=None, voucher_no=None, adv_adj=False, update_outstanding="Yes"
gl_entries=None,
voucher_type=None,
voucher_no=None,
adv_adj=False,
update_outstanding="Yes",
partial_cancel=False,
):
"""
Get original gl entries of the voucher
@@ -576,14 +581,19 @@ def make_reverse_gl_entries(
if gl_entries:
create_payment_ledger_entry(
gl_entries, cancel=1, adv_adj=adv_adj, update_outstanding=update_outstanding
gl_entries,
cancel=1,
adv_adj=adv_adj,
update_outstanding=update_outstanding,
partial_cancel=partial_cancel,
)
validate_accounting_period(gl_entries)
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
is_opening = any(d.get("is_opening") == "Yes" for d in gl_entries)
validate_against_pcv(is_opening, gl_entries[0]["posting_date"], gl_entries[0]["company"])
set_as_cancel(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"])
if not partial_cancel:
set_as_cancel(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"])
for entry in gl_entries:
new_gle = copy.deepcopy(entry)

View File

@@ -1617,6 +1617,7 @@ def get_payment_ledger_entries(gl_entries, cancel=0):
due_date=gle.due_date,
voucher_type=gle.voucher_type,
voucher_no=gle.voucher_no,
voucher_detail_no=gle.voucher_detail_no,
against_voucher_type=gle.against_voucher_type
if gle.against_voucher_type
else gle.voucher_type,
@@ -1638,7 +1639,7 @@ def get_payment_ledger_entries(gl_entries, cancel=0):
def create_payment_ledger_entry(
gl_entries, cancel=0, adv_adj=0, update_outstanding="Yes", from_repost=0
gl_entries, cancel=0, adv_adj=0, update_outstanding="Yes", from_repost=0, partial_cancel=False
):
if gl_entries:
ple_map = get_payment_ledger_entries(gl_entries, cancel=cancel)
@@ -1648,7 +1649,7 @@ def create_payment_ledger_entry(
ple = frappe.get_doc(entry)
if cancel:
delink_original_entry(ple)
delink_original_entry(ple, partial_cancel=partial_cancel)
ple.flags.ignore_permissions = 1
ple.flags.adv_adj = adv_adj
@@ -1695,7 +1696,7 @@ def update_voucher_outstanding(voucher_type, voucher_no, account, party_type, pa
ref_doc.set_status(update=True)
def delink_original_entry(pl_entry):
def delink_original_entry(pl_entry, partial_cancel=False):
if pl_entry:
ple = qb.DocType("Payment Ledger Entry")
query = (
@@ -1715,6 +1716,10 @@ def delink_original_entry(pl_entry):
& (ple.against_voucher_no == pl_entry.against_voucher_no)
)
)
if partial_cancel:
query = query.where(ple.voucher_detail_no == pl_entry.voucher_detail_no)
query.run()