mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-15 15:45:01 +00:00
Merge pull request #49281 from diptanilsaha/reporting_currency
feat: adding reporting_currency and dr/cr in reporting currency fields in GL Entry and Account Closing Balance
This commit is contained in:
@@ -11,6 +11,9 @@
|
||||
"cost_center",
|
||||
"debit",
|
||||
"credit",
|
||||
"reporting_currency_exchange_rate",
|
||||
"debit_in_reporting_currency",
|
||||
"credit_in_reporting_currency",
|
||||
"account_currency",
|
||||
"debit_in_account_currency",
|
||||
"credit_in_account_currency",
|
||||
@@ -124,12 +127,30 @@
|
||||
"fieldname": "is_period_closing_voucher_entry",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Period Closing Voucher Entry"
|
||||
},
|
||||
{
|
||||
"fieldname": "debit_in_reporting_currency",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Debit Amount in Reporting Currency",
|
||||
"options": "Company:company:reporting_currency"
|
||||
},
|
||||
{
|
||||
"fieldname": "credit_in_reporting_currency",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Credit Amount in Reporting Currency",
|
||||
"options": "Company:company:reporting_currency"
|
||||
},
|
||||
{
|
||||
"fieldname": "reporting_currency_exchange_rate",
|
||||
"fieldtype": "Float",
|
||||
"label": "Reporting Currency Exchange Rate",
|
||||
"precision": "9"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-list",
|
||||
"in_create": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:05:56.710541",
|
||||
"modified": "2025-08-22 19:13:50.400404",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account Closing Balance",
|
||||
@@ -158,7 +179,8 @@
|
||||
"role": "Auditor"
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import cint, cstr
|
||||
from frappe.utils import cint, cstr, flt
|
||||
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||
get_accounting_dimensions,
|
||||
)
|
||||
from erpnext.exceptions import ReportingCurrencyExchangeNotFoundError
|
||||
from erpnext.setup.utils import get_exchange_rate
|
||||
|
||||
|
||||
class AccountClosingBalance(Document):
|
||||
@@ -26,12 +29,15 @@ class AccountClosingBalance(Document):
|
||||
cost_center: DF.Link | None
|
||||
credit: DF.Currency
|
||||
credit_in_account_currency: DF.Currency
|
||||
credit_in_reporting_currency: DF.Currency
|
||||
debit: DF.Currency
|
||||
debit_in_account_currency: DF.Currency
|
||||
debit_in_reporting_currency: DF.Currency
|
||||
finance_book: DF.Link | None
|
||||
is_period_closing_voucher_entry: DF.Check
|
||||
period_closing_voucher: DF.Link | None
|
||||
project: DF.Link | None
|
||||
reporting_currency_exchange_rate: DF.Float
|
||||
# end: auto-generated types
|
||||
|
||||
pass
|
||||
@@ -55,6 +61,7 @@ def make_closing_entries(closing_entries, voucher_name, company, closing_date):
|
||||
"closing_date": closing_date,
|
||||
}
|
||||
)
|
||||
set_amount_in_reporting_currency(cle, company, closing_date)
|
||||
cle.flags.ignore_permissions = True
|
||||
cle.flags.ignore_links = True
|
||||
cle.submit()
|
||||
@@ -144,3 +151,29 @@ def get_previous_closing_entries(company, closing_date, accounting_dimensions):
|
||||
entries = query.run(as_dict=1)
|
||||
|
||||
return entries
|
||||
|
||||
|
||||
def set_amount_in_reporting_currency(cle, company, closing_date):
|
||||
default_currency, reporting_currency = frappe.get_cached_value(
|
||||
"Company", company, ["default_currency", "reporting_currency"]
|
||||
)
|
||||
|
||||
reporting_currency_exchange_rate = get_exchange_rate(default_currency, reporting_currency, closing_date)
|
||||
if not reporting_currency_exchange_rate:
|
||||
frappe.throw(
|
||||
title=_("Reporting Currency Exchange Not Found"),
|
||||
msg=_(
|
||||
"Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually."
|
||||
).format(default_currency, reporting_currency, closing_date),
|
||||
exc=ReportingCurrencyExchangeNotFoundError,
|
||||
)
|
||||
debit_in_reporting_currency = flt(cle.get("debit", 0) * reporting_currency_exchange_rate)
|
||||
credit_in_reporting_currency = flt(cle.get("credit", 0) * reporting_currency_exchange_rate)
|
||||
|
||||
cle.update(
|
||||
{
|
||||
"reporting_currency_exchange_rate": reporting_currency_exchange_rate,
|
||||
"debit_in_reporting_currency": debit_in_reporting_currency,
|
||||
"credit_in_reporting_currency": credit_in_reporting_currency,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -29,14 +29,17 @@
|
||||
"against_voucher",
|
||||
"voucher_detail_no",
|
||||
"transaction_exchange_rate",
|
||||
"reporting_currency_exchange_rate",
|
||||
"amounts_section",
|
||||
"debit_in_account_currency",
|
||||
"debit",
|
||||
"debit_in_transaction_currency",
|
||||
"debit_in_reporting_currency",
|
||||
"column_break_bm1w",
|
||||
"credit_in_account_currency",
|
||||
"credit",
|
||||
"credit_in_transaction_currency",
|
||||
"credit_in_reporting_currency",
|
||||
"dimensions_section",
|
||||
"cost_center",
|
||||
"column_break_lmnm",
|
||||
@@ -353,13 +356,31 @@
|
||||
{
|
||||
"fieldname": "column_break_8abq",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "debit_in_reporting_currency",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Debit Amount in Reporting Currency",
|
||||
"options": "Company:company:reporting_currency"
|
||||
},
|
||||
{
|
||||
"fieldname": "credit_in_reporting_currency",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Credit Amount in Reporting Currency",
|
||||
"options": "Company:company:reporting_currency"
|
||||
},
|
||||
{
|
||||
"fieldname": "reporting_currency_exchange_rate",
|
||||
"fieldtype": "Float",
|
||||
"label": "Reporting Currency Exchange Rate",
|
||||
"precision": "9"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-list",
|
||||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"links": [],
|
||||
"modified": "2025-03-21 15:29:11.221890",
|
||||
"modified": "2025-08-22 12:57:17.750252",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "GL Entry",
|
||||
@@ -390,8 +411,9 @@
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"search_fields": "voucher_no,account,posting_date,against_voucher",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ from erpnext.accounts.party import (
|
||||
validate_party_gle_currency,
|
||||
)
|
||||
from erpnext.accounts.utils import OUTSTANDING_DOCTYPES, get_account_currency, get_fiscal_year
|
||||
from erpnext.exceptions import InvalidAccountCurrency
|
||||
from erpnext.exceptions import InvalidAccountCurrency, ReportingCurrencyExchangeNotFoundError
|
||||
from erpnext.setup.utils import get_exchange_rate
|
||||
|
||||
exclude_from_linked_with = True
|
||||
|
||||
@@ -42,9 +43,11 @@ class GLEntry(Document):
|
||||
cost_center: DF.Link | None
|
||||
credit: DF.Currency
|
||||
credit_in_account_currency: DF.Currency
|
||||
credit_in_reporting_currency: DF.Currency
|
||||
credit_in_transaction_currency: DF.Currency
|
||||
debit: DF.Currency
|
||||
debit_in_account_currency: DF.Currency
|
||||
debit_in_reporting_currency: DF.Currency
|
||||
debit_in_transaction_currency: DF.Currency
|
||||
due_date: DF.Date | None
|
||||
finance_book: DF.Link | None
|
||||
@@ -57,6 +60,7 @@ class GLEntry(Document):
|
||||
posting_date: DF.Date | None
|
||||
project: DF.Link | None
|
||||
remarks: DF.Text | None
|
||||
reporting_currency_exchange_rate: DF.Float
|
||||
to_rename: DF.Check
|
||||
transaction_currency: DF.Link | None
|
||||
transaction_date: DF.Date | None
|
||||
@@ -88,6 +92,8 @@ class GLEntry(Document):
|
||||
self.validate_party()
|
||||
self.validate_currency()
|
||||
|
||||
self.set_amount_in_reporting_currency()
|
||||
|
||||
def on_update(self):
|
||||
adv_adj = self.flags.adv_adj
|
||||
if not self.flags.from_repost and self.voucher_type != "Period Closing Voucher":
|
||||
@@ -292,6 +298,25 @@ class GLEntry(Document):
|
||||
if self.party_type and self.party:
|
||||
validate_party_gle_currency(self.party_type, self.party, self.company, self.account_currency)
|
||||
|
||||
def set_amount_in_reporting_currency(self):
|
||||
default_currency, reporting_currency = frappe.get_cached_value(
|
||||
"Company", self.company, ["default_currency", "reporting_currency"]
|
||||
)
|
||||
transaction_date = self.transaction_date or self.posting_date
|
||||
self.reporting_currency_exchange_rate = get_exchange_rate(
|
||||
default_currency, reporting_currency, transaction_date
|
||||
)
|
||||
if not self.reporting_currency_exchange_rate:
|
||||
frappe.throw(
|
||||
title=_("Reporting Currency Exchange Not Found"),
|
||||
msg=_(
|
||||
"Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually."
|
||||
).format(default_currency, reporting_currency, transaction_date),
|
||||
exc=ReportingCurrencyExchangeNotFoundError,
|
||||
)
|
||||
self.debit_in_reporting_currency = flt(self.debit * self.reporting_currency_exchange_rate)
|
||||
self.credit_in_reporting_currency = flt(self.credit * self.reporting_currency_exchange_rate)
|
||||
|
||||
def validate_and_set_fiscal_year(self):
|
||||
if not self.fiscal_year:
|
||||
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
|
||||
|
||||
@@ -24,3 +24,7 @@ class InvalidAccountDimensionError(frappe.ValidationError):
|
||||
|
||||
class MandatoryAccountDimensionError(frappe.ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class ReportingCurrencyExchangeNotFoundError(frappe.ValidationError):
|
||||
pass
|
||||
|
||||
@@ -436,3 +436,4 @@ erpnext.patches.v16_0.update_serial_no_reference_name
|
||||
erpnext.patches.v16_0.set_invoice_type_in_pos_settings
|
||||
erpnext.patches.v15_0.update_fieldname_in_accounting_dimension_filter
|
||||
erpnext.patches.v16_0.make_workstation_operating_components #1
|
||||
erpnext.patches.v16_0.set_reporting_currency
|
||||
|
||||
159
erpnext/patches/v16_0/set_reporting_currency.py
Normal file
159
erpnext/patches/v16_0/set_reporting_currency.py
Normal file
@@ -0,0 +1,159 @@
|
||||
import frappe
|
||||
from frappe.utils import getdate
|
||||
from frappe.utils.nestedset import get_descendants_of
|
||||
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.setup.utils import get_exchange_rate
|
||||
|
||||
|
||||
def execute():
|
||||
set_company_reporting_currency()
|
||||
set_amounts_in_reporting_currency_on_gle_and_acb()
|
||||
|
||||
|
||||
def set_company_reporting_currency():
|
||||
root_companies = frappe.db.get_all(
|
||||
"Company", fields=["name", "default_currency"], filters={"parent_company": ""}, order_by="lft"
|
||||
)
|
||||
|
||||
for d in root_companies:
|
||||
company_subtree = get_descendants_of("Company", d.name)
|
||||
company_subtree.append(d.name)
|
||||
|
||||
update_company_subtree_reporting_currency(company_subtree, d.default_currency)
|
||||
|
||||
|
||||
def update_company_subtree_reporting_currency(companies, currency):
|
||||
Company = frappe.qb.DocType("Company")
|
||||
|
||||
frappe.qb.update(Company).set(Company.reporting_currency, currency).where(
|
||||
Company.name.isin(companies)
|
||||
).run()
|
||||
|
||||
|
||||
def set_amounts_in_reporting_currency_on_gle_and_acb():
|
||||
# get all the companies
|
||||
companies = frappe.db.get_all(
|
||||
"Company", fields=["name", "default_currency", "reporting_currency"], order_by="lft"
|
||||
)
|
||||
|
||||
# get current fiscal year
|
||||
current_fiscal_year = get_fiscal_year(getdate(), as_dict=1, raise_on_missing=False)
|
||||
|
||||
if not current_fiscal_year:
|
||||
return
|
||||
|
||||
previous_fiscal_year = frappe.db.get_value(
|
||||
"Fiscal Year",
|
||||
filters={"year_end_date": ("<", current_fiscal_year.year_start_date)},
|
||||
fieldname=["name", "year_start_date", "year_end_date"],
|
||||
order_by="year_end_date desc",
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
for d in companies:
|
||||
posting_dates = get_posting_closing_date(d, current_fiscal_year, previous_fiscal_year)
|
||||
exchange_rate_available = check_exchange_rate_availability(d, posting_dates)
|
||||
if not exchange_rate_available:
|
||||
continue
|
||||
set_reporting_currency_by_doctype("GL Entry", d, posting_dates.get("GL Entry"))
|
||||
|
||||
set_reporting_currency_by_doctype(
|
||||
"Account Closing Balance", d, posting_dates.get("Account Closing Balance")
|
||||
)
|
||||
|
||||
|
||||
def get_posting_closing_date(company_details, current_fiscal_year, previous_fiscal_year=None):
|
||||
posting_dates = {}
|
||||
posting_dates["GL Entry"] = get_closing_posting_dates(
|
||||
"GL Entry", company_details.get("name"), current_fiscal_year
|
||||
)
|
||||
|
||||
posting_dates["Account Closing Balance"] = get_closing_posting_dates(
|
||||
"Account Closing Balance", company_details.get("name"), current_fiscal_year
|
||||
)
|
||||
|
||||
if previous_fiscal_year:
|
||||
prev_fy_last_pcv_closing_date = frappe.db.get_value(
|
||||
"Period Closing Voucher",
|
||||
filters={"fiscal_year": previous_fiscal_year.name, "company": company_details.get("name")},
|
||||
fieldname=["transaction_date"],
|
||||
order_by="period_start_date desc",
|
||||
)
|
||||
|
||||
if prev_fy_last_pcv_closing_date:
|
||||
prev_fy_acb_closing_dates = get_closing_posting_dates(
|
||||
"Account Closing Balance",
|
||||
company_details.get("name"),
|
||||
closing_date=prev_fy_last_pcv_closing_date,
|
||||
)
|
||||
posting_dates.setdefault("Account Closing Balance", [])
|
||||
posting_dates["Account Closing Balance"].extend(prev_fy_acb_closing_dates)
|
||||
|
||||
return posting_dates
|
||||
|
||||
|
||||
def check_exchange_rate_availability(company_details, posting_dates):
|
||||
exchange_rate_available = True
|
||||
for doctype, values in posting_dates.items():
|
||||
if not exchange_rate_available:
|
||||
return False
|
||||
date_column = "posting_date" if doctype == "GL Entry" else "closing_date"
|
||||
for d in values:
|
||||
exchange_rate = get_exchange_rate(
|
||||
company_details.get("default_currency"),
|
||||
company_details.get("reporting_currency"),
|
||||
d[date_column],
|
||||
)
|
||||
|
||||
if not exchange_rate:
|
||||
exchange_rate_available = False
|
||||
break
|
||||
|
||||
return exchange_rate_available
|
||||
|
||||
|
||||
def set_reporting_currency_by_doctype(doctype, company_details, posting_closing_dates):
|
||||
date_column = "posting_date" if doctype == "GL Entry" else "closing_date"
|
||||
for d in posting_closing_dates:
|
||||
exchange_rate = get_exchange_rate(
|
||||
company_details.get("default_currency"),
|
||||
company_details.get("reporting_currency"),
|
||||
d[date_column],
|
||||
)
|
||||
|
||||
set_reporting_currency_on_individual_documents(
|
||||
doctype, company_details.get("name"), d[date_column], exchange_rate
|
||||
)
|
||||
|
||||
|
||||
def get_closing_posting_dates(doctype, company, fiscal_year=None, closing_date=None):
|
||||
dt = frappe.qb.DocType(doctype)
|
||||
|
||||
date_column = "posting_date" if doctype == "GL Entry" else "closing_date"
|
||||
query = frappe.qb.from_(dt).select(dt[date_column]).where(dt.company == company).groupby(dt[date_column])
|
||||
|
||||
if doctype == "GL Entry" and fiscal_year:
|
||||
query = query.where(dt.fiscal_year == fiscal_year.name)
|
||||
|
||||
if doctype == "Account Closing Balance":
|
||||
if fiscal_year:
|
||||
query = query.where(dt.closing_date[fiscal_year.year_start_date : fiscal_year.year_end_date])
|
||||
if closing_date:
|
||||
query = query.where(dt.closing_date == closing_date)
|
||||
|
||||
posting_closing_dates = query.run(as_dict=1)
|
||||
|
||||
return posting_closing_dates
|
||||
|
||||
|
||||
def set_reporting_currency_on_individual_documents(doctype, company, posting_closing_date, exchange_rate):
|
||||
dt = frappe.qb.DocType(doctype)
|
||||
|
||||
date_column = "posting_date" if doctype == "GL Entry" else "closing_date"
|
||||
|
||||
frappe.qb.update(dt).set(dt.reporting_currency_exchange_rate, exchange_rate).set(
|
||||
dt.debit_in_reporting_currency, exchange_rate * dt.debit
|
||||
).set(dt.credit_in_reporting_currency, exchange_rate * dt.credit).where(
|
||||
(dt.company == company) & (dt[date_column] == posting_closing_date)
|
||||
).run()
|
||||
@@ -17,6 +17,9 @@ frappe.ui.form.on("Company", {
|
||||
frm.toggle_enable("default_currency", !r.message);
|
||||
});
|
||||
}
|
||||
if (frm.doc.__islocal) {
|
||||
frm.set_value("reporting_currency", "");
|
||||
}
|
||||
},
|
||||
setup: function (frm) {
|
||||
frm.__rename_queue = "long";
|
||||
@@ -156,6 +159,10 @@ frappe.ui.form.on("Company", {
|
||||
}
|
||||
}
|
||||
|
||||
if (frm.doc.__islocal) {
|
||||
frm.set_value("reporting_currency", "");
|
||||
}
|
||||
|
||||
erpnext.company.set_chart_of_accounts_options(frm.doc);
|
||||
},
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"domain",
|
||||
"date_of_establishment",
|
||||
"parent_company",
|
||||
"reporting_currency",
|
||||
"company_info",
|
||||
"company_logo",
|
||||
"date_of_incorporation",
|
||||
@@ -835,6 +836,14 @@
|
||||
"fieldtype": "Select",
|
||||
"label": "Reconciliation Takes Effect On",
|
||||
"options": "Advance Payment Date\nOldest Of Invoice Or Advance\nReconciliation Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "reporting_currency",
|
||||
"fieldtype": "Link",
|
||||
"label": "Reporting Currency",
|
||||
"options": "Currency",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-building",
|
||||
|
||||
@@ -91,6 +91,7 @@ class Company(NestedSet):
|
||||
"Advance Payment Date", "Oldest Of Invoice Or Advance", "Reconciliation Date"
|
||||
]
|
||||
registration_details: DF.Code | None
|
||||
reporting_currency: DF.Link | None
|
||||
rgt: DF.Int
|
||||
round_off_account: DF.Link | None
|
||||
round_off_cost_center: DF.Link | None
|
||||
@@ -153,6 +154,7 @@ class Company(NestedSet):
|
||||
self.check_parent_changed()
|
||||
self.set_chart_of_accounts()
|
||||
self.validate_parent_company()
|
||||
self.set_reporting_currency()
|
||||
|
||||
def validate_abbr(self):
|
||||
if not self.abbr:
|
||||
@@ -490,6 +492,14 @@ class Company(NestedSet):
|
||||
if not is_group:
|
||||
frappe.throw(_("Parent Company must be a group company"))
|
||||
|
||||
def set_reporting_currency(self):
|
||||
self.reporting_currency = self.default_currency
|
||||
if self.parent_company:
|
||||
parent_reporting_currency = frappe.db.get_value(
|
||||
"Company", self.parent_company, ["reporting_currency"]
|
||||
)
|
||||
self.reporting_currency = parent_reporting_currency
|
||||
|
||||
def set_default_accounts(self):
|
||||
default_accounts = {
|
||||
"default_cash_account": "Cash",
|
||||
@@ -681,7 +691,7 @@ class Company(NestedSet):
|
||||
frappe.db.sql("delete from tabBOM where company=%s", self.name)
|
||||
for dt in ("BOM Operation", "BOM Item", "BOM Scrap Item", "BOM Explosion Item"):
|
||||
frappe.db.sql(
|
||||
"delete from `tab{}` where parent in ({})" "".format(dt, ", ".join(["%s"] * len(boms))),
|
||||
"delete from `tab{}` where parent in ({})".format(dt, ", ".join(["%s"] * len(boms))),
|
||||
tuple(boms),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user