diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 717546b0f93..be3bbdbb437 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -4,6 +4,7 @@ import frappe from frappe import _, msgprint +from frappe.model.meta import get_field_precision from frappe.query_builder import Case from frappe.query_builder.custom import ConstantColumn from frappe.query_builder.functions import Sum @@ -127,17 +128,32 @@ def _execute(filters=None, additional_table_columns=None): row.update({frappe.scrub(tax_acc): tax_amount}) # total tax, grand total, rounded total & outstanding amount + + outstanding_precision = ( + get_field_precision( + frappe.get_meta("Purchase Invoice").get_field("outstanding_amount"), + currency=company_currency, + ) + or 2 + ) row.update( { "total_tax": total_tax, "grand_total": inv.base_grand_total, "rounded_total": inv.base_rounded_total, - "outstanding_amount": inv.outstanding_amount, } ) if inv.doctype == "Purchase Invoice": - row.update({"debit": inv.base_grand_total, "credit": 0.0}) + row.update( + { + "debit": inv.base_grand_total, + "credit": 0.0, + "outstanding_amount": flt( + (inv.outstanding_amount * (inv.conversion_rate or 1)), outstanding_precision + ), + } + ) else: row.update({"debit": 0.0, "credit": inv.base_grand_total}) data.append(row) @@ -410,6 +426,7 @@ def get_invoices(filters, additional_query_columns): pi.base_rounded_total, pi.outstanding_amount, pi.mode_of_payment, + pi.conversion_rate, ) .where(pi.docstatus == 1) ) diff --git a/erpnext/accounts/report/purchase_register/test_purchase_register.py b/erpnext/accounts/report/purchase_register/test_purchase_register.py index f72035496a7..0784dfb5589 100644 --- a/erpnext/accounts/report/purchase_register/test_purchase_register.py +++ b/erpnext/accounts/report/purchase_register/test_purchase_register.py @@ -2,7 +2,7 @@ # MIT License. See license.txt import frappe -from frappe.utils import add_months, today +from frappe.utils import add_months, flt, today from erpnext.accounts.report.purchase_register.purchase_register import execute from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt @@ -90,6 +90,35 @@ class TestPurchaseRegister(ERPNextTestSuite): self.assertEqual(first_row.total_tax, 100) self.assertEqual(first_row.grand_total, 1100) + def test_purchase_currency_conversion(self): + usd_creditors = frappe.get_doc( + { + "doctype": "Account", + "account_name": "USD Creditors", + "parent_account": "Accounts Payable - _TC", + "company": "_Test Company", + "account_type": "Payable", + "root_type": "Liability", + "report_type": "Balance Sheet", + "account_currency": "USD", + } + ).insert() + foreign_invoice = make_purchase_invoice() + foreign_invoice.db_set("currency", "USD") + foreign_invoice.db_set("conversion_rate", 80) + foreign_invoice.db_set("credit_to", usd_creditors.name) + foreign_invoice.db_set("outstanding_amount", 100.236) + local_invoice = make_purchase_invoice() + local_invoice.db_set("currency", "INR") + local_invoice.db_set("conversion_rate", 1) + local_invoice.db_set("outstanding_amount", 200.456) + columns, data, *_ = execute(frappe._dict({"company": foreign_invoice.company})) + outstanding_precision = 2 + + data_by_name = {x.get("voucher_no"): x.get("outstanding_amount") for x in data} + self.assertEqual(data_by_name.get(foreign_invoice.name), flt((100.236 * 80), outstanding_precision)) + self.assertEqual(data_by_name.get(local_invoice.name), flt(200.456, outstanding_precision)) + def test_purchase_register_ledger_view(self): filters = frappe._dict( company="_Test Company 6", diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index f76bbc6c6ef..80195ff884b 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -141,17 +141,31 @@ def _execute(filters, additional_table_columns=None): # total tax, grand total, outstanding amount & rounded total + outstanding_precision = ( + get_field_precision( + frappe.get_meta("Sales Invoice").get_field("outstanding_amount"), + currency=company_currency, + ) + or 2 + ) row.update( { "tax_total": total_tax, "grand_total": inv.base_grand_total, "rounded_total": inv.base_rounded_total, - "outstanding_amount": inv.outstanding_amount, } ) if inv.doctype == "Sales Invoice": - row.update({"debit": inv.base_grand_total, "credit": 0.0}) + row.update( + { + "debit": inv.base_grand_total, + "credit": 0.0, + "outstanding_amount": flt( + (inv.outstanding_amount * (inv.conversion_rate or 1)), outstanding_precision + ), + } + ) else: row.update({"debit": 0.0, "credit": inv.base_grand_total}) data.append(row) @@ -448,6 +462,7 @@ def get_invoices(filters, additional_query_columns): si.is_internal_customer, si.represents_company, si.company, + si.conversion_rate, ) .where(si.docstatus == 1) ) diff --git a/erpnext/accounts/report/sales_register/test_sales_register.py b/erpnext/accounts/report/sales_register/test_sales_register.py index f3ed2641633..cf38bc521f7 100644 --- a/erpnext/accounts/report/sales_register/test_sales_register.py +++ b/erpnext/accounts/report/sales_register/test_sales_register.py @@ -1,9 +1,10 @@ import frappe -from frappe.utils import getdate, today +from frappe.utils import add_days, flt, getdate, today from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.report.sales_register.sales_register import execute from erpnext.accounts.test.accounts_mixin import AccountsTestMixin +from erpnext.selling.doctype.customer.test_customer import make_customer from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.tests.utils import ERPNextTestSuite @@ -249,3 +250,25 @@ class TestItemWiseSalesRegister(ERPNextTestSuite, AccountsTestMixin): } result_output = {k: v for k, v in filtered_output[0].items() if k in expected_result} self.assertDictEqual(result_output, expected_result) + + def test_outstanding_currency_conversion(self): + foreign_invoice = create_sales_invoice( + customer="_Test Customer", + posting_date=add_days(today(), -1), + qty=1, + rate=100, + ) + foreign_invoice.db_set("currency", "USD") + foreign_invoice.db_set("conversion_rate", 80) + foreign_invoice.db_set("outstanding_amount", 100.236) + make_customer("_Test Customer2") + local_invoice = create_sales_invoice( + customer="_Test Customer2", currency="INR", conversion_rate=1, qty=1, rate=200 + ) + local_invoice.db_set("outstanding_amount", 200.456) + columns, data, *_ = execute(frappe._dict({"company": foreign_invoice.company})) + outstanding_precision = 2 + + data_by_name = {x.get("voucher_no"): x.get("outstanding_amount") for x in data} + self.assertEqual(data_by_name.get(foreign_invoice.name), flt((100.236 * 80), outstanding_precision)) + self.assertEqual(data_by_name.get(local_invoice.name), flt(200.456, outstanding_precision))