Report presentation currency (#12670)

* Add new Select to filters

* get the currencies from database rather than hardcoded

* label report columns:
- If presentation currency is available in filters, use it or
- If company is available in filters, use it or
- use default company currency

* add new function - get_currency

* tweak new function `get_currency`

* add new function `convert` to convert a value to another currency

* add new function `convert_to_presentation_currency`

* clean up `get_currency` first pass

* memoise the exchange rates

* limit fetched GL entries to to_date

* check if account type is p&l or not and use appropriate exchange rate based on that

* change EXCHANGE RATE to a dict, use for memoisation

* rename EXCHANGE_RATE

* cache exchange rates and use them as needed

* add docstrings

* add presentation currency logic to financial statement reports

* move new functions from `general_ledger.py` to new module

* clean up

* PEP 8 clean up

* move function to util.py

* PEP 8 clean up

* remove presentation currency option from cashflow

* adjust currency as needed

* allow users to save presentation currency in Accounts Settings

* add new function `get_presentation_currency_list`

* refactor query_report modules with no promises

* Revert "allow users to save presentation currency in Accounts Settings"

This reverts commit 3b58a6296c.

* show print page in correct currency

* Update utils.py
This commit is contained in:
tundebabzy
2018-02-12 10:34:50 +01:00
committed by Nabin Hait
parent 621740efd9
commit c89782502c
10 changed files with 279 additions and 101 deletions

View File

@@ -3,10 +3,13 @@
from __future__ import unicode_literals
import frappe
from erpnext import get_company_currency, get_default_company
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
from frappe.utils import getdate, cstr, flt, fmt_money
from frappe import _, _dict
from erpnext.accounts.utils import get_account_currency
def execute(filters=None):
account_details = {}
@@ -29,6 +32,7 @@ def execute(filters=None):
return columns, res
def validate_filters(filters, account_details):
if not filters.get('company'):
frappe.throw(_('{0} is mandatory').format(_('Company')))
@@ -37,7 +41,7 @@ def validate_filters(filters, account_details):
frappe.throw(_("Account {0} does not exists").format(filters.account))
if filters.get("account") and filters.get("group_by_account") \
and account_details[filters.account].is_group == 0:
and account_details[filters.account].is_group == 0:
frappe.throw(_("Can not filter based on Account, if grouped by Account"))
if filters.get("voucher_no") and filters.get("group_by_voucher"):
@@ -56,6 +60,7 @@ def validate_party(filters):
elif not frappe.db.exists(party_type, party):
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
def set_account_currency(filters):
if not (filters.get("account") or filters.get("party")):
return filters
@@ -66,8 +71,13 @@ def set_account_currency(filters):
if filters.get("account"):
account_currency = get_account_currency(filters.account)
elif filters.get("party"):
gle_currency = frappe.db.get_value("GL Entry", {"party_type": filters.party_type,
"party": filters.party, "company": filters.company}, "account_currency")
gle_currency = frappe.db.get_value(
"GL Entry", {
"party_type": filters.party_type, "party": filters.party, "company": filters.company
},
"account_currency"
)
if gle_currency:
account_currency = gle_currency
else:
@@ -90,29 +100,39 @@ def get_result(filters, account_details):
return result
def get_gl_entries(filters):
currency_map = get_currency(filters)
select_fields = """, sum(debit_in_account_currency) as debit_in_account_currency,
sum(credit_in_account_currency) as credit_in_account_currency""" \
if filters.get("show_in_account_currency") else ""
group_by_condition = "group by voucher_type, voucher_no, account, cost_center" \
if filters.get("group_by_voucher") else "group by name"
gl_entries = frappe.db.sql("""
gl_entries = frappe.db.sql(
"""
select
posting_date, account, party_type, party,
sum(debit) as debit, sum(credit) as credit,
voucher_type, voucher_no, cost_center, project,
against_voucher_type, against_voucher,
against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening {select_fields}
from `tabGL Entry`
where company=%(company)s {conditions}
{group_by_condition}
order by posting_date, account"""\
.format(select_fields=select_fields, conditions=get_conditions(filters),
group_by_condition=group_by_condition), filters, as_dict=1)
order by posting_date, account
""".format(
select_fields=select_fields, conditions=get_conditions(filters),
group_by_condition=group_by_condition
),
filters, as_dict=1)
if filters.get('presentation_currency'):
return convert_to_presentation_currency(gl_entries, currency_map)
else:
return gl_entries
return gl_entries
def get_conditions(filters):
conditions = []
@@ -132,16 +152,20 @@ def get_conditions(filters):
if not (filters.get("account") or filters.get("party") or filters.get("group_by_account")):
conditions.append("posting_date >=%(from_date)s")
conditions.append("posting_date <=%(to_date)s")
if filters.get("project"):
conditions.append("project=%(project)s")
from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("GL Entry")
if match_conditions: conditions.append(match_conditions)
if match_conditions:
conditions.append(match_conditions)
return "and {}".format(" and ".join(conditions)) if conditions else ""
def get_data_with_opening_closing(filters, account_details, gl_entries):
data = []
gle_map = initialize_gle_map(gl_entries)
@@ -178,14 +202,15 @@ def get_data_with_opening_closing(filters, account_details, gl_entries):
return data
def get_totals_dict():
def _get_debit_credit_dict(label):
return _dict(
account = "'{0}'".format(label),
debit = 0.0,
credit = 0.0,
debit_in_account_currency = 0.0,
credit_in_account_currency = 0.0
account="'{0}'".format(label),
debit=0.0,
credit=0.0,
debit_in_account_currency=0.0,
credit_in_account_currency=0.0
)
return _dict(
opening = _get_debit_credit_dict(_('Opening')),
@@ -193,12 +218,14 @@ def get_totals_dict():
closing = _get_debit_credit_dict(_('Closing (Opening + Total)'))
)
def initialize_gle_map(gl_entries):
gle_map = frappe._dict()
for gle in gl_entries:
gle_map.setdefault(gle.account, _dict(totals = get_totals_dict(), entries = []))
gle_map.setdefault(gle.account, _dict(totals=get_totals_dict(), entries=[]))
return gle_map
def get_accountwise_gle(filters, gl_entries, gle_map):
totals = get_totals_dict()
entries = []
@@ -210,13 +237,12 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
data[key].debit_in_account_currency += flt(gle.debit_in_account_currency)
data[key].credit_in_account_currency += flt(gle.credit_in_account_currency)
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
for gle in gl_entries:
if gle.posting_date < from_date or cstr(gle.is_opening) == "Yes":
update_value_in_dict(gle_map[gle.account].totals, 'opening', gle)
update_value_in_dict(totals, 'opening', gle)
update_value_in_dict(gle_map[gle.account].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle)
@@ -233,6 +259,7 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
return totals, entries
def get_result_as_list(data, filters):
balance, balance_in_account_currency = 0, 0
inv_details = get_supplier_invoice_details()
@@ -272,6 +299,15 @@ def get_balance(row, balance, debit_field, credit_field):
return balance
def get_columns(filters):
if filters.get("presentation_currency"):
currency = filters["presentation_currency"]
else:
if filters.get("company"):
currency = get_company_currency(filters["company"])
else:
company = get_default_company()
currency = get_company_currency(company)
columns = [
{
"label": _("Posting Date"),
@@ -287,47 +323,25 @@ def get_columns(filters):
"width": 180
},
{
"label": _("Debit"),
"label": _("Debit ({0})".format(currency)),
"fieldname": "debit",
"fieldtype": "Float",
"width": 100
},
{
"label": _("Credit"),
"label": _("Credit ({0})".format(currency)),
"fieldname": "credit",
"fieldtype": "Float",
"width": 100
},
{
"label": _("Balance (Dr - Cr)"),
"label": _("Balance ({0})".format(currency)),
"fieldname": "balance",
"fieldtype": "Float",
"width": 130
}
]
if filters.get("show_in_account_currency"):
columns.extend([
{
"label": _("Debit") + " (" + filters.account_currency + ")",
"fieldname": "debit_in_account_currency",
"fieldtype": "Float",
"width": 100
},
{
"label": _("Credit") + " (" + filters.account_currency + ")",
"fieldname": "credit_in_account_currency",
"fieldtype": "Float",
"width": 100
},
{
"label": _("Balance") + " (" + filters.account_currency + ")",
"fieldname": "balance_in_account_currency",
"fieldtype": "Data",
"width": 100
}
])
columns.extend([
{
"label": _("Voucher Type"),