mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-14 04:15:10 +00:00
Merge pull request #38205 from vorasmit/partial-cancel
fix: partial cancel of gle and ple (backport #35609)
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user