Merge pull request #27863 from rohitwaghchaure/multi-currency-issue-for-consolidated-report
fix: consolidated report not consider company currency
This commit is contained in:
commit
3f99a87e3d
@ -8,6 +8,8 @@ from frappe import _, throw
|
|||||||
from frappe.utils import cint, cstr
|
from frappe.utils import cint, cstr
|
||||||
from frappe.utils.nestedset import NestedSet, get_ancestors_of, get_descendants_of
|
from frappe.utils.nestedset import NestedSet, get_ancestors_of, get_descendants_of
|
||||||
|
|
||||||
|
import erpnext
|
||||||
|
|
||||||
|
|
||||||
class RootNotEditable(frappe.ValidationError): pass
|
class RootNotEditable(frappe.ValidationError): pass
|
||||||
class BalanceMismatchError(frappe.ValidationError): pass
|
class BalanceMismatchError(frappe.ValidationError): pass
|
||||||
@ -196,7 +198,7 @@ class Account(NestedSet):
|
|||||||
"company": company,
|
"company": company,
|
||||||
# parent account's currency should be passed down to child account's curreny
|
# parent account's currency should be passed down to child account's curreny
|
||||||
# if it is None, it picks it up from default company currency, which might be unintended
|
# if it is None, it picks it up from default company currency, which might be unintended
|
||||||
"account_currency": self.account_currency,
|
"account_currency": erpnext.get_company_currency(company),
|
||||||
"parent_account": parent_acc_name_map[company]
|
"parent_account": parent_acc_name_map[company]
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -207,8 +209,7 @@ class Account(NestedSet):
|
|||||||
# update the parent company's value in child companies
|
# update the parent company's value in child companies
|
||||||
doc = frappe.get_doc("Account", child_account)
|
doc = frappe.get_doc("Account", child_account)
|
||||||
parent_value_changed = False
|
parent_value_changed = False
|
||||||
for field in ['account_type', 'account_currency',
|
for field in ['account_type', 'freeze_account', 'balance_must_be']:
|
||||||
'freeze_account', 'balance_must_be']:
|
|
||||||
if doc.get(field) != self.get(field):
|
if doc.get(field) != self.get(field):
|
||||||
parent_value_changed = True
|
parent_value_changed = True
|
||||||
doc.set(field, self.get(field))
|
doc.set(field, self.get(field))
|
||||||
|
@ -103,8 +103,11 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
|||||||
column.is_tree = true;
|
column.is_tree = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = default_formatter(value, row, column, data);
|
if (data && data.account && column.apply_currency_formatter) {
|
||||||
|
data.currency = erpnext.get_currency(column.company_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
value = default_formatter(value, row, column, data);
|
||||||
if (!data.parent_account) {
|
if (!data.parent_account) {
|
||||||
value = $(`<span>${value}</span>`);
|
value = $(`<span>${value}</span>`);
|
||||||
|
|
||||||
|
@ -7,8 +7,9 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint, flt, getdate
|
from frappe.utils import cint, flt, getdate
|
||||||
|
|
||||||
|
import erpnext
|
||||||
|
from collections import defaultdict
|
||||||
from erpnext.accounts.report.balance_sheet.balance_sheet import (
|
from erpnext.accounts.report.balance_sheet.balance_sheet import (
|
||||||
check_opening_balance,
|
|
||||||
get_chart_data,
|
get_chart_data,
|
||||||
get_provisional_profit_loss,
|
get_provisional_profit_loss,
|
||||||
)
|
)
|
||||||
@ -31,7 +32,7 @@ from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement
|
|||||||
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import (
|
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import (
|
||||||
get_report_summary as get_pl_summary,
|
get_report_summary as get_pl_summary,
|
||||||
)
|
)
|
||||||
from erpnext.accounts.report.utils import convert_to_presentation_currency
|
from erpnext.accounts.report.utils import convert, convert_to_presentation_currency
|
||||||
|
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
@ -42,7 +43,7 @@ def execute(filters=None):
|
|||||||
|
|
||||||
fiscal_year = get_fiscal_year_data(filters.get('from_fiscal_year'), filters.get('to_fiscal_year'))
|
fiscal_year = get_fiscal_year_data(filters.get('from_fiscal_year'), filters.get('to_fiscal_year'))
|
||||||
companies_column, companies = get_companies(filters)
|
companies_column, companies = get_companies(filters)
|
||||||
columns = get_columns(companies_column)
|
columns = get_columns(companies_column, filters)
|
||||||
|
|
||||||
if filters.get('report') == "Balance Sheet":
|
if filters.get('report') == "Balance Sheet":
|
||||||
data, message, chart, report_summary = get_balance_sheet_data(fiscal_year, companies, columns, filters)
|
data, message, chart, report_summary = get_balance_sheet_data(fiscal_year, companies, columns, filters)
|
||||||
@ -73,21 +74,24 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
|
|||||||
provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity,
|
provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity,
|
||||||
companies, filters.get('company'), company_currency, True)
|
companies, filters.get('company'), company_currency, True)
|
||||||
|
|
||||||
message, opening_balance = check_opening_balance(asset, liability, equity)
|
message, opening_balance = prepare_companywise_opening_balance(asset, liability, equity, companies)
|
||||||
|
|
||||||
if opening_balance and round(opening_balance,2) !=0:
|
if opening_balance:
|
||||||
unclosed ={
|
unclosed = {
|
||||||
"account_name": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'",
|
"account_name": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'",
|
||||||
"account": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'",
|
"account": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'",
|
||||||
"warn_if_negative": True,
|
"warn_if_negative": True,
|
||||||
"currency": company_currency
|
"currency": company_currency
|
||||||
}
|
}
|
||||||
for company in companies:
|
|
||||||
unclosed[company] = opening_balance
|
|
||||||
if provisional_profit_loss:
|
|
||||||
provisional_profit_loss[company] = provisional_profit_loss[company] - opening_balance
|
|
||||||
|
|
||||||
unclosed["total"]=opening_balance
|
for company in companies:
|
||||||
|
unclosed[company] = opening_balance.get(company)
|
||||||
|
if provisional_profit_loss and provisional_profit_loss.get(company):
|
||||||
|
provisional_profit_loss[company] = (
|
||||||
|
flt(provisional_profit_loss[company]) - flt(opening_balance.get(company))
|
||||||
|
)
|
||||||
|
|
||||||
|
unclosed["total"] = opening_balance.get(company)
|
||||||
data.append(unclosed)
|
data.append(unclosed)
|
||||||
|
|
||||||
if provisional_profit_loss:
|
if provisional_profit_loss:
|
||||||
@ -102,6 +106,37 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
|
|||||||
|
|
||||||
return data, message, chart, report_summary
|
return data, message, chart, report_summary
|
||||||
|
|
||||||
|
def prepare_companywise_opening_balance(asset_data, liability_data, equity_data, companies):
|
||||||
|
opening_balance = {}
|
||||||
|
for company in companies:
|
||||||
|
opening_value = 0
|
||||||
|
|
||||||
|
# opening_value = Aseet - liability - equity
|
||||||
|
for data in [asset_data, liability_data, equity_data]:
|
||||||
|
account_name = get_root_account_name(data[0].root_type, company)
|
||||||
|
opening_value += get_opening_balance(account_name, data, company)
|
||||||
|
|
||||||
|
opening_balance[company] = opening_value
|
||||||
|
|
||||||
|
if opening_balance:
|
||||||
|
return _("Previous Financial Year is not closed"), opening_balance
|
||||||
|
|
||||||
|
return '', {}
|
||||||
|
|
||||||
|
def get_opening_balance(account_name, data, company):
|
||||||
|
for row in data:
|
||||||
|
if row.get('account_name') == account_name:
|
||||||
|
return row.get('company_wise_opening_bal', {}).get(company, 0.0)
|
||||||
|
|
||||||
|
def get_root_account_name(root_type, company):
|
||||||
|
return frappe.get_all(
|
||||||
|
'Account',
|
||||||
|
fields=['account_name'],
|
||||||
|
filters = {'root_type': root_type, 'is_group': 1,
|
||||||
|
'company': company, 'parent_account': ('is', 'not set')},
|
||||||
|
as_list=1
|
||||||
|
)[0][0]
|
||||||
|
|
||||||
def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
||||||
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
|
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
|
||||||
company_currency = get_company_currency(filters)
|
company_currency = get_company_currency(filters)
|
||||||
@ -193,30 +228,37 @@ def get_account_type_based_data(account_type, companies, fiscal_year, filters):
|
|||||||
data["total"] = total
|
data["total"] = total
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def get_columns(companies):
|
def get_columns(companies, filters):
|
||||||
columns = [{
|
columns = [
|
||||||
|
{
|
||||||
"fieldname": "account",
|
"fieldname": "account",
|
||||||
"label": _("Account"),
|
"label": _("Account"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Account",
|
"options": "Account",
|
||||||
"width": 300
|
"width": 300
|
||||||
}]
|
}, {
|
||||||
|
|
||||||
columns.append({
|
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"label": _("Currency"),
|
"label": _("Currency"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Currency",
|
"options": "Currency",
|
||||||
"hidden": 1
|
"hidden": 1
|
||||||
})
|
}
|
||||||
|
]
|
||||||
|
|
||||||
for company in companies:
|
for company in companies:
|
||||||
|
apply_currency_formatter = 1 if not filters.presentation_currency else 0
|
||||||
|
currency = filters.presentation_currency
|
||||||
|
if not currency:
|
||||||
|
currency = erpnext.get_company_currency(company)
|
||||||
|
|
||||||
columns.append({
|
columns.append({
|
||||||
"fieldname": company,
|
"fieldname": company,
|
||||||
"label": company,
|
"label": f'{company} ({currency})',
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
"width": 150
|
"width": 150,
|
||||||
|
"apply_currency_formatter": apply_currency_formatter,
|
||||||
|
"company_name": company
|
||||||
})
|
})
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
@ -236,6 +278,8 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i
|
|||||||
start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None
|
start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None
|
||||||
end_date = filters.period_end_date
|
end_date = filters.period_end_date
|
||||||
|
|
||||||
|
filters.end_date = end_date
|
||||||
|
|
||||||
gl_entries_by_account = {}
|
gl_entries_by_account = {}
|
||||||
for root in frappe.db.sql("""select lft, rgt from tabAccount
|
for root in frappe.db.sql("""select lft, rgt from tabAccount
|
||||||
where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1):
|
where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1):
|
||||||
@ -244,9 +288,10 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i
|
|||||||
end_date, root.lft, root.rgt, filters,
|
end_date, root.lft, root.rgt, filters,
|
||||||
gl_entries_by_account, accounts_by_name, accounts, ignore_closing_entries=False)
|
gl_entries_by_account, accounts_by_name, accounts, ignore_closing_entries=False)
|
||||||
|
|
||||||
calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters)
|
calculate_values(accounts_by_name, gl_entries_by_account, companies, filters, fiscal_year)
|
||||||
accumulate_values_into_parents(accounts, accounts_by_name, companies)
|
accumulate_values_into_parents(accounts, accounts_by_name, companies)
|
||||||
out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency)
|
|
||||||
|
out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters)
|
||||||
|
|
||||||
if out:
|
if out:
|
||||||
add_total_row(out, root_type, balance_must_be, companies, company_currency)
|
add_total_row(out, root_type, balance_must_be, companies, company_currency)
|
||||||
@ -257,7 +302,10 @@ def get_company_currency(filters=None):
|
|||||||
return (filters.get('presentation_currency')
|
return (filters.get('presentation_currency')
|
||||||
or frappe.get_cached_value('Company', filters.company, "default_currency"))
|
or frappe.get_cached_value('Company', filters.company, "default_currency"))
|
||||||
|
|
||||||
def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters):
|
def calculate_values(accounts_by_name, gl_entries_by_account, companies, filters, fiscal_year):
|
||||||
|
start_date = (fiscal_year.year_start_date
|
||||||
|
if filters.filter_based_on == 'Fiscal Year' else filters.period_start_date)
|
||||||
|
|
||||||
for entries in gl_entries_by_account.values():
|
for entries in gl_entries_by_account.values():
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
if entry.account_number:
|
if entry.account_number:
|
||||||
@ -266,15 +314,32 @@ def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_d
|
|||||||
account_name = entry.account_name
|
account_name = entry.account_name
|
||||||
|
|
||||||
d = accounts_by_name.get(account_name)
|
d = accounts_by_name.get(account_name)
|
||||||
|
|
||||||
if d:
|
if d:
|
||||||
|
debit, credit = 0, 0
|
||||||
for company in companies:
|
for company in companies:
|
||||||
# check if posting date is within the period
|
# check if posting date is within the period
|
||||||
if (entry.company == company or (filters.get('accumulated_in_group_company'))
|
if (entry.company == company or (filters.get('accumulated_in_group_company'))
|
||||||
and entry.company in companies.get(company)):
|
and entry.company in companies.get(company)):
|
||||||
d[company] = d.get(company, 0.0) + flt(entry.debit) - flt(entry.credit)
|
parent_company_currency = erpnext.get_company_currency(d.company)
|
||||||
|
child_company_currency = erpnext.get_company_currency(entry.company)
|
||||||
|
|
||||||
|
debit, credit = flt(entry.debit), flt(entry.credit)
|
||||||
|
|
||||||
|
if (not filters.get('presentation_currency')
|
||||||
|
and entry.company != company
|
||||||
|
and parent_company_currency != child_company_currency
|
||||||
|
and filters.get('accumulated_in_group_company')):
|
||||||
|
debit = convert(debit, parent_company_currency, child_company_currency, filters.end_date)
|
||||||
|
credit = convert(credit, parent_company_currency, child_company_currency, filters.end_date)
|
||||||
|
|
||||||
|
d[company] = d.get(company, 0.0) + flt(debit) - flt(credit)
|
||||||
|
|
||||||
if entry.posting_date < getdate(start_date):
|
if entry.posting_date < getdate(start_date):
|
||||||
d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit)
|
d['company_wise_opening_bal'][company] += (flt(debit) - flt(credit))
|
||||||
|
|
||||||
|
if entry.posting_date < getdate(start_date):
|
||||||
|
d["opening_balance"] = d.get("opening_balance", 0.0) + flt(debit) - flt(credit)
|
||||||
|
|
||||||
def accumulate_values_into_parents(accounts, accounts_by_name, companies):
|
def accumulate_values_into_parents(accounts, accounts_by_name, companies):
|
||||||
"""accumulate children's values in parent accounts"""
|
"""accumulate children's values in parent accounts"""
|
||||||
@ -282,17 +347,18 @@ def accumulate_values_into_parents(accounts, accounts_by_name, companies):
|
|||||||
if d.parent_account:
|
if d.parent_account:
|
||||||
account = d.parent_account_name
|
account = d.parent_account_name
|
||||||
|
|
||||||
if not accounts_by_name.get(account):
|
# if not accounts_by_name.get(account):
|
||||||
continue
|
# continue
|
||||||
|
|
||||||
for company in companies:
|
for company in companies:
|
||||||
accounts_by_name[account][company] = \
|
accounts_by_name[account][company] = \
|
||||||
accounts_by_name[account].get(company, 0.0) + d.get(company, 0.0)
|
accounts_by_name[account].get(company, 0.0) + d.get(company, 0.0)
|
||||||
|
|
||||||
|
accounts_by_name[account]['company_wise_opening_bal'][company] += d.get('company_wise_opening_bal', {}).get(company, 0.0)
|
||||||
|
|
||||||
accounts_by_name[account]["opening_balance"] = \
|
accounts_by_name[account]["opening_balance"] = \
|
||||||
accounts_by_name[account].get("opening_balance", 0.0) + d.get("opening_balance", 0.0)
|
accounts_by_name[account].get("opening_balance", 0.0) + d.get("opening_balance", 0.0)
|
||||||
|
|
||||||
|
|
||||||
def get_account_heads(root_type, companies, filters):
|
def get_account_heads(root_type, companies, filters):
|
||||||
accounts = get_accounts(root_type, filters)
|
accounts = get_accounts(root_type, filters)
|
||||||
|
|
||||||
@ -353,7 +419,7 @@ def get_accounts(root_type, filters):
|
|||||||
`tabAccount` where company = %s and root_type = %s
|
`tabAccount` where company = %s and root_type = %s
|
||||||
""" , (filters.get('company'), root_type), as_dict=1)
|
""" , (filters.get('company'), root_type), as_dict=1)
|
||||||
|
|
||||||
def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency):
|
def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters):
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
for d in accounts:
|
for d in accounts:
|
||||||
@ -367,10 +433,13 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com
|
|||||||
"parent_account": _(d.parent_account),
|
"parent_account": _(d.parent_account),
|
||||||
"indent": flt(d.indent),
|
"indent": flt(d.indent),
|
||||||
"year_start_date": start_date,
|
"year_start_date": start_date,
|
||||||
|
"root_type": d.root_type,
|
||||||
"year_end_date": end_date,
|
"year_end_date": end_date,
|
||||||
"currency": company_currency,
|
"currency": filters.presentation_currency,
|
||||||
|
"company_wise_opening_bal": d.company_wise_opening_bal,
|
||||||
"opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1)
|
"opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1)
|
||||||
})
|
})
|
||||||
|
|
||||||
for company in companies:
|
for company in companies:
|
||||||
if d.get(company) and balance_must_be == "Credit":
|
if d.get(company) and balance_must_be == "Credit":
|
||||||
# change sign based on Debit or Credit, since calculation is done using (debit - credit)
|
# change sign based on Debit or Credit, since calculation is done using (debit - credit)
|
||||||
@ -385,6 +454,7 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com
|
|||||||
|
|
||||||
row["has_value"] = has_value
|
row["has_value"] = has_value
|
||||||
row["total"] = total
|
row["total"] = total
|
||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
@ -447,6 +517,7 @@ def get_account_details(account):
|
|||||||
'is_group', 'account_name', 'account_number', 'parent_account', 'lft', 'rgt'], as_dict=1)
|
'is_group', 'account_name', 'account_number', 'parent_account', 'lft', 'rgt'], as_dict=1)
|
||||||
|
|
||||||
def validate_entries(key, entry, accounts_by_name, accounts):
|
def validate_entries(key, entry, accounts_by_name, accounts):
|
||||||
|
# If an account present in the child company and not in the parent company
|
||||||
if key not in accounts_by_name:
|
if key not in accounts_by_name:
|
||||||
args = get_account_details(entry.account)
|
args = get_account_details(entry.account)
|
||||||
|
|
||||||
@ -456,12 +527,23 @@ def validate_entries(key, entry, accounts_by_name, accounts):
|
|||||||
args.update({
|
args.update({
|
||||||
'lft': parent_args.lft + 1,
|
'lft': parent_args.lft + 1,
|
||||||
'rgt': parent_args.rgt - 1,
|
'rgt': parent_args.rgt - 1,
|
||||||
|
'indent': 3,
|
||||||
'root_type': parent_args.root_type,
|
'root_type': parent_args.root_type,
|
||||||
'report_type': parent_args.report_type
|
'report_type': parent_args.report_type,
|
||||||
|
'parent_account_name': parent_args.account_name,
|
||||||
|
'company_wise_opening_bal': defaultdict(float)
|
||||||
})
|
})
|
||||||
|
|
||||||
accounts_by_name.setdefault(key, args)
|
accounts_by_name.setdefault(key, args)
|
||||||
accounts.append(args)
|
|
||||||
|
idx = len(accounts)
|
||||||
|
# To identify parent account index
|
||||||
|
for index, row in enumerate(accounts):
|
||||||
|
if row.parent_account_name == args.parent_account_name:
|
||||||
|
idx = index
|
||||||
|
break
|
||||||
|
|
||||||
|
accounts.insert(idx+1, args)
|
||||||
|
|
||||||
def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
||||||
additional_conditions = []
|
additional_conditions = []
|
||||||
@ -491,7 +573,6 @@ def add_total_row(out, root_type, balance_must_be, companies, company_currency):
|
|||||||
for company in companies:
|
for company in companies:
|
||||||
total_row.setdefault(company, 0.0)
|
total_row.setdefault(company, 0.0)
|
||||||
total_row[company] += row.get(company, 0.0)
|
total_row[company] += row.get(company, 0.0)
|
||||||
row[company] = 0.0
|
|
||||||
|
|
||||||
total_row.setdefault("total", 0.0)
|
total_row.setdefault("total", 0.0)
|
||||||
total_row["total"] += flt(row["total"])
|
total_row["total"] += flt(row["total"])
|
||||||
@ -511,6 +592,7 @@ def filter_accounts(accounts, depth=10):
|
|||||||
account_name = d.account_number + ' - ' + d.account_name
|
account_name = d.account_number + ' - ' + d.account_name
|
||||||
else:
|
else:
|
||||||
account_name = d.account_name
|
account_name = d.account_name
|
||||||
|
d['company_wise_opening_bal'] = defaultdict(float)
|
||||||
accounts_by_name[account_name] = d
|
accounts_by_name[account_name] = d
|
||||||
|
|
||||||
parent_children_map.setdefault(d.parent_account or None, []).append(d)
|
parent_children_map.setdefault(d.parent_account or None, []).append(d)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user