mirror of
https://github.com/frappe/erpnext.git
synced 2026-03-31 19:02:21 +02:00
fix: exchange gain/loss GL's should be removed if advance is cancelled (#34529)
* fix: report GL for invoice when advance has different exchange rate If deferred revenue/expense is enabled for any item, don't repost. * test: cancelling advance should remove exchange gain/loss If there are no deferred revenue/expense cancelling advance should cancel the exchange gain/loss booked due to different exchange rates of payment and its linked invoice
This commit is contained in:
@@ -7,7 +7,7 @@ from functools import reduce
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import ValidationError, _, scrub, throw
|
from frappe import ValidationError, _, scrub, throw
|
||||||
from frappe.utils import cint, comma_or, flt, getdate, nowdate
|
from frappe.utils import cint, comma_or, flt, get_link_to_form, getdate, nowdate
|
||||||
from six import iteritems, string_types
|
from six import iteritems, string_types
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
@@ -168,8 +168,31 @@ class PaymentEntry(AccountsController):
|
|||||||
for reference in self.references:
|
for reference in self.references:
|
||||||
if reference.reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
if reference.reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||||
doc = frappe.get_doc(reference.reference_doctype, reference.reference_name)
|
doc = frappe.get_doc(reference.reference_doctype, reference.reference_name)
|
||||||
|
|
||||||
|
repost_required = False
|
||||||
|
for adv_reference in doc.get("advances"):
|
||||||
|
if adv_reference.exchange_gain_loss != 0:
|
||||||
|
repost_required = True
|
||||||
|
break
|
||||||
|
if repost_required:
|
||||||
|
for item in doc.get("items"):
|
||||||
|
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
|
||||||
|
frappe.msgprint(
|
||||||
|
_(
|
||||||
|
"Linked Invoice {0} has Exchange Gain/Loss GL entries due to this Payment. Submit a Journal manually to reverse its effects."
|
||||||
|
).format(get_link_to_form(doc.doctype, doc.name))
|
||||||
|
)
|
||||||
|
repost_required = False
|
||||||
|
|
||||||
doc.delink_advance_entries(self.name)
|
doc.delink_advance_entries(self.name)
|
||||||
|
|
||||||
|
if repost_required:
|
||||||
|
doc.reload()
|
||||||
|
doc.docstatus = 2
|
||||||
|
doc.make_gl_entries()
|
||||||
|
doc.docstatus = 1
|
||||||
|
doc.make_gl_entries()
|
||||||
|
|
||||||
def set_missing_values(self):
|
def set_missing_values(self):
|
||||||
if self.payment_type == "Internal Transfer":
|
if self.payment_type == "Internal Transfer":
|
||||||
for field in (
|
for field in (
|
||||||
|
|||||||
@@ -3470,6 +3470,78 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
"Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice", unlink_enabled
|
"Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice", unlink_enabled
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_gain_loss_on_advance_cancellation(self):
|
||||||
|
unlink_enabled = frappe.db.get_single_value(
|
||||||
|
"Accounts Settings", "unlink_payment_on_cancellation_of_invoice"
|
||||||
|
)
|
||||||
|
|
||||||
|
frappe.db.set_single_value("Accounts Settings", "unlink_payment_on_cancellation_of_invoice", 1)
|
||||||
|
|
||||||
|
pe = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Payment Entry",
|
||||||
|
"payment_type": "Receive",
|
||||||
|
"party_type": "Customer",
|
||||||
|
"party": "_Test Customer USD",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"paid_from_account_currency": "USD",
|
||||||
|
"paid_to_account_currency": "INR",
|
||||||
|
"source_exchange_rate": 70,
|
||||||
|
"target_exchange_rate": 1,
|
||||||
|
"reference_no": "1",
|
||||||
|
"reference_date": nowdate(),
|
||||||
|
"received_amount": 70,
|
||||||
|
"paid_amount": 1,
|
||||||
|
"paid_from": "_Test Receivable USD - _TC",
|
||||||
|
"paid_to": "_Test Cash - _TC",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
pe.insert()
|
||||||
|
pe.submit()
|
||||||
|
|
||||||
|
si = create_sales_invoice(
|
||||||
|
customer="_Test Customer USD",
|
||||||
|
debit_to="_Test Receivable USD - _TC",
|
||||||
|
currency="USD",
|
||||||
|
conversion_rate=75,
|
||||||
|
do_not_save=1,
|
||||||
|
rate=1,
|
||||||
|
)
|
||||||
|
si = si.save()
|
||||||
|
|
||||||
|
si.append(
|
||||||
|
"advances",
|
||||||
|
{
|
||||||
|
"reference_type": "Payment Entry",
|
||||||
|
"reference_name": pe.name,
|
||||||
|
"advance_amount": 1,
|
||||||
|
"allocated_amount": 1,
|
||||||
|
"ref_exchange_rate": 70,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
si.save()
|
||||||
|
si.submit()
|
||||||
|
expected_gle = [
|
||||||
|
["_Test Receivable USD - _TC", 75.0, 5.0],
|
||||||
|
["Exchange Gain/Loss - _TC", 5.0, 0.0],
|
||||||
|
["Sales - _TC", 0.0, 75.0],
|
||||||
|
]
|
||||||
|
check_gl_entries(self, si.name, expected_gle, nowdate())
|
||||||
|
|
||||||
|
# cancel advance payment
|
||||||
|
pe.reload()
|
||||||
|
pe.cancel()
|
||||||
|
|
||||||
|
expected_gle_after = [
|
||||||
|
["_Test Receivable USD - _TC", 75.0, 0.0],
|
||||||
|
["Sales - _TC", 0.0, 75.0],
|
||||||
|
]
|
||||||
|
check_gl_entries(self, si.name, expected_gle_after, nowdate())
|
||||||
|
|
||||||
|
frappe.db.set_single_value(
|
||||||
|
"Accounts Settings", "unlink_payment_on_cancellation_of_invoice", unlink_enabled
|
||||||
|
)
|
||||||
|
|
||||||
def test_batch_expiry_for_sales_invoice_return(self):
|
def test_batch_expiry_for_sales_invoice_return(self):
|
||||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||||
from erpnext.stock.doctype.item.test_item import make_item
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
|
|||||||
Reference in New Issue
Block a user