From 26905bc14216d32c2361cc7091297fa5d612939f Mon Sep 17 00:00:00 2001 From: ervishnucs Date: Wed, 1 Jul 2026 20:02:55 +0530 Subject: [PATCH] fix: set conversion_rate on quotation created from customer --- erpnext/selling/doctype/customer/customer.py | 10 ++-- .../selling/doctype/customer/test_customer.py | 50 ++++++++++++++++++- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 5f993cb319b..ea11c3696cb 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -11,6 +11,7 @@ from frappe.contacts.address_and_contact import ( delete_contact_and_address, load_address_and_contact, ) +from frappe.model.document import Document from frappe.model.mapper import get_mapped_doc from frappe.model.naming import set_name_by_naming_series, set_name_from_naming_options from frappe.model.utils.rename_doc import update_linked_doctypes @@ -444,7 +445,7 @@ class Customer(TransactionBase): @frappe.whitelist() -def make_quotation(source_name, target_doc=None): +def make_quotation(source_name: str, target_doc: str | Document | None = None) -> Document: def set_missing_values(source, target): _set_missing_values(source, target) @@ -457,9 +458,6 @@ def make_quotation(source_name, target_doc=None): ) target_doc.quotation_to = "Customer" - target_doc.run_method("set_missing_values") - target_doc.run_method("set_other_charges") - target_doc.run_method("calculate_taxes_and_totals") price_list, currency = frappe.db.get_value( "Customer", {"name": source_name}, ["default_price_list", "default_currency"] @@ -469,6 +467,10 @@ def make_quotation(source_name, target_doc=None): if currency: target_doc.currency = currency + target_doc.run_method("set_missing_values") + target_doc.run_method("set_other_charges") + target_doc.run_method("calculate_taxes_and_totals") + return target_doc diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index 1a09518b01b..59838fb890a 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -5,19 +5,67 @@ import json import frappe -from frappe.utils import flt +from frappe.utils import flt, nowdate from erpnext.accounts.party import get_due_date from erpnext.exceptions import PartyDisabled, PartyFrozen from erpnext.selling.doctype.customer.customer import ( get_credit_limit, get_customer_outstanding, + make_quotation, parse_full_name, ) from erpnext.tests.utils import ERPNextTestSuite class TestCustomer(ERPNextTestSuite): + def test_quotation_from_customer_uses_actual_exchange_rate(self): + company = "_Test Company" + company_currency = frappe.get_cached_value("Company", company, "default_currency") + foreign_currency = "USD" if company_currency != "USD" else "EUR" + + frappe.defaults.set_user_default("company", company) + self.addCleanup(frappe.defaults.clear_user_default, "company") + + # Seed a deterministic rate so the test does not depend on the live exchange-rate API. + rate = 83.0 + exchange_filters = { + "date": nowdate(), + "from_currency": foreign_currency, + "to_currency": company_currency, + } + existing = frappe.db.exists("Currency Exchange", exchange_filters) + if existing: + frappe.db.set_value("Currency Exchange", existing, "exchange_rate", rate) + else: + exchange = frappe.get_doc( + { + "doctype": "Currency Exchange", + **exchange_filters, + "exchange_rate": rate, + "for_selling": 1, + "for_buying": 1, + } + ).insert() + self.addCleanup(frappe.delete_doc, "Currency Exchange", exchange.name, force=1) + + customer = frappe.get_doc( + { + "doctype": "Customer", + "customer_name": "_Test Customer FX Quotation", + "customer_type": "Company", + "default_currency": foreign_currency, + } + ).insert() + self.addCleanup(frappe.delete_doc, "Customer", customer.name, force=1) + + quotation = make_quotation(customer.name) + + self.assertEqual(quotation.currency, foreign_currency) + self.assertNotEqual(flt(quotation.conversion_rate), 1.0) + self.assertNotEqual(flt(quotation.conversion_rate), 0.0) + self.assertEqual(flt(quotation.conversion_rate), rate) + def test_get_customer_group_details(self): doc = frappe.new_doc("Customer Group") doc.customer_group_name = "_Testing Customer Group"