From effb34bbfa4144590ab4075cfcb603c50ca5c561 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 25 Apr 2023 20:26:50 +0530 Subject: [PATCH 1/2] refactor: don't book exch gain/loss for sales/purchase orders --- .../doctype/payment_entry/payment_entry.py | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index ee4d4d29e2..59641e58e1 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -654,6 +654,28 @@ class PaymentEntry(AccountsController): self.precision("base_received_amount"), ) + def calculate_base_allocated_amount_for_reference(self, d) -> float: + base_allocated_amount = 0 + if d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"): + # When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type. + # This is so there are no Exchange Gain/Loss generated for such doctypes + + exchange_rate = 1 + if self.payment_type == "Receive": + exchange_rate = self.source_exchange_rate + elif self.payment_type == "Pay": + exchange_rate = self.target_exchange_rate + + base_allocated_amount += flt( + flt(d.allocated_amount) * flt(exchange_rate), self.precision("base_paid_amount") + ) + else: + base_allocated_amount += flt( + flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("base_paid_amount") + ) + + return base_allocated_amount + def set_total_allocated_amount(self): if self.payment_type == "Internal Transfer": return @@ -662,9 +684,7 @@ class PaymentEntry(AccountsController): for d in self.get("references"): if d.allocated_amount: total_allocated_amount += flt(d.allocated_amount) - base_total_allocated_amount += flt( - flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("base_paid_amount") - ) + base_total_allocated_amount += self.calculate_base_allocated_amount_for_reference(d) self.total_allocated_amount = abs(total_allocated_amount) self.base_total_allocated_amount = abs(base_total_allocated_amount) @@ -881,9 +901,7 @@ class PaymentEntry(AccountsController): } ) - allocated_amount_in_company_currency = flt( - flt(d.allocated_amount) * flt(d.exchange_rate), self.precision("paid_amount") - ) + allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d) gle.update( { From ce4e18c8d232bbf19fea74e6e6133b773d21f3d5 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 1 May 2023 13:54:15 +0530 Subject: [PATCH 2/2] test: Sales/Purchase Orders will not book Exchange gain/loss --- .../payment_entry/test_payment_entry.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index 67049c47ad..68f333dc29 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -51,6 +51,38 @@ class TestPaymentEntry(FrappeTestCase): so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid") self.assertEqual(so_advance_paid, 0) + def test_payment_against_sales_order_usd_to_inr(self): + so = make_sales_order( + customer="_Test Customer USD", currency="USD", qty=1, rate=100, do_not_submit=True + ) + so.conversion_rate = 50 + so.submit() + pe = get_payment_entry("Sales Order", so.name) + pe.source_exchange_rate = 55 + pe.received_amount = 5500 + pe.insert() + pe.submit() + + # there should be no difference amount + pe.reload() + self.assertEqual(pe.difference_amount, 0) + self.assertEqual(pe.deductions, []) + + expected_gle = dict( + (d[0], d) + for d in [["_Test Receivable USD - _TC", 0, 5500, so.name], ["Cash - _TC", 5500.0, 0, None]] + ) + + self.validate_gl_entries(pe.name, expected_gle) + + so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid") + self.assertEqual(so_advance_paid, 100) + + pe.cancel() + + so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid") + self.assertEqual(so_advance_paid, 0) + def test_payment_entry_for_blocked_supplier_invoice(self): supplier = frappe.get_doc("Supplier", "_Test Supplier") supplier.on_hold = 1