Merge pull request #35604 from pps190/fix-reconcile-invoice-return

fix: reconcile invoice against credit note.
This commit is contained in:
ruthra kumar 2023-06-23 17:44:25 +05:30 committed by GitHub
commit 2f638ae32a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 7 deletions

View File

@ -336,6 +336,7 @@ class PaymentReconciliation(Document):
entry_list = []
dr_or_cr_notes = []
difference_entries = []
for row in self.get("allocation"):
reconciled_entry = []
if row.invoice_number and row.allocated_amount:
@ -348,13 +349,15 @@ class PaymentReconciliation(Document):
reconciled_entry.append(payment_details)
if payment_details.difference_amount:
self.make_difference_entry(payment_details)
difference_entries.append(
self.make_difference_entry(payment_details, do_not_save_and_submit=bool(dr_or_cr_notes))
)
if entry_list:
reconcile_against_document(entry_list, skip_ref_details_update_for_pe)
if dr_or_cr_notes:
reconcile_dr_cr_note(dr_or_cr_notes, self.company)
reconcile_dr_cr_note(dr_or_cr_notes, difference_entries, self.company)
@frappe.whitelist()
def reconcile(self):
@ -382,7 +385,7 @@ class PaymentReconciliation(Document):
self.get_unreconciled_entries()
def make_difference_entry(self, row):
def make_difference_entry(self, row, do_not_save_and_submit=False):
journal_entry = frappe.new_doc("Journal Entry")
journal_entry.voucher_type = "Exchange Gain Or Loss"
journal_entry.company = self.company
@ -430,8 +433,11 @@ class PaymentReconciliation(Document):
journal_entry.append("accounts", journal_account)
journal_entry.save()
journal_entry.submit()
if not do_not_save_and_submit:
journal_entry.save()
journal_entry.submit()
return journal_entry
def get_payment_details(self, row, dr_or_cr):
return frappe._dict(
@ -597,7 +603,14 @@ class PaymentReconciliation(Document):
return condition
def reconcile_dr_cr_note(dr_cr_notes, company):
def reconcile_dr_cr_note(dr_cr_notes, difference_entries, company):
def find_difference_entry(voucher_type, voucher_no):
for jv in difference_entries:
accounts = iter(jv.accounts)
for account in accounts:
if account.reference_type == voucher_type and account.reference_name == voucher_no:
return next(accounts)
for inv in dr_cr_notes:
voucher_type = "Credit Note" if inv.voucher_type == "Sales Invoice" else "Debit Note"
@ -642,5 +655,9 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
],
}
)
if difference_entry := find_difference_entry(inv.against_voucher_type, inv.against_voucher):
jv.append("accounts", difference_entry)
jv.flags.ignore_mandatory = True
jv.submit()

View File

@ -11,10 +11,13 @@ from frappe.utils import add_days, flt, nowdate
from erpnext import get_default_cost_center
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.party import get_party_account
from erpnext.stock.doctype.item.test_item import create_item
test_dependencies = ["Item"]
class TestPaymentReconciliation(FrappeTestCase):
def setUp(self):
@ -163,7 +166,9 @@ class TestPaymentReconciliation(FrappeTestCase):
def create_payment_reconciliation(self):
pr = frappe.new_doc("Payment Reconciliation")
pr.company = self.company
pr.party_type = "Customer"
pr.party_type = (
self.party_type if hasattr(self, "party_type") and self.party_type else "Customer"
)
pr.party = self.customer
pr.receivable_payable_account = get_party_account(pr.party_type, pr.party, pr.company)
pr.from_invoice_date = pr.to_invoice_date = pr.from_payment_date = pr.to_payment_date = nowdate()
@ -890,6 +895,42 @@ class TestPaymentReconciliation(FrappeTestCase):
self.assertEqual(pr.allocation[0].allocated_amount, 85)
self.assertEqual(pr.allocation[0].difference_amount, 0)
def test_reconciliation_purchase_invoice_against_return(self):
pi = make_purchase_invoice(
supplier="_Test Supplier USD", currency="USD", conversion_rate=50
).submit()
pi_return = frappe.get_doc(pi.as_dict())
pi_return.name = None
pi_return.docstatus = 0
pi_return.is_return = 1
pi_return.conversion_rate = 80
pi_return.items[0].qty = -pi_return.items[0].qty
pi_return.submit()
self.company = "_Test Company"
self.party_type = "Supplier"
self.customer = "_Test Supplier USD"
pr = self.create_payment_reconciliation()
pr.get_unreconciled_entries()
invoices = []
payments = []
for invoice in pr.invoices:
if invoice.invoice_number == pi.name:
invoices.append(invoice.as_dict())
break
for payment in pr.payments:
if payment.reference_name == pi_return.name:
payments.append(payment.as_dict())
break
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
# Should not raise frappe.exceptions.ValidationError: Total Debit must be equal to Total Credit.
pr.reconcile()
def make_customer(customer_name, currency=None):
if not frappe.db.exists("Customer", customer_name):