account-financial-reporting/account_financial_report/report/general_ledger.py
2024-12-03 14:04:00 +01:00

932 lines
37 KiB
Python

# ?? 2016 Julien Coux (Camptocamp)
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
# Copyright 2022 Tecnativa - V??ctor Mart??nez
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import calendar
import datetime
import operator
from flectra import _, api, models
from flectra.tools import float_is_zero
class GeneralLedgerReport(models.AbstractModel):
_name = "report.account_financial_report.general_ledger"
_description = "General Ledger Report"
_inherit = "report.account_financial_report.abstract_report"
def _get_analytic_data(self, account_ids):
analytic_accounts = self.env["account.analytic.account"].browse(account_ids)
analytic_data = {}
for account in analytic_accounts:
analytic_data.update({account.id: {"name": account.name}})
return analytic_data
def _get_taxes_data(self, taxes_ids):
taxes = self.env["account.tax"].browse(taxes_ids)
taxes_data = {}
for tax in taxes:
taxes_data.update(
{
tax.id: {
"id": tax.id,
"amount": tax.amount,
"amount_type": tax.amount_type,
"display_name": tax.display_name,
}
}
)
if tax.amount_type == "percent" or tax.amount_type == "division":
taxes_data[tax.id]["string"] = "%"
else:
taxes_data[tax.id]["string"] = ""
taxes_data[tax.id]["tax_name"] = (
tax.display_name
+ " ("
+ str(tax.amount)
+ taxes_data[tax.id]["string"]
+ ")"
)
return taxes_data
def _get_account_type_domain(self, grouped_by):
"""To avoid set all possible types, set in or not in as operator of the types
we are interested in. In v15 we used the internal_type field (type of
account.account.type)."""
at_op = "in" if grouped_by != "taxes" else "not in"
return [
("account_type", at_op, ["asset_receivable", "liability_payable"]),
]
def _get_acc_prt_accounts_ids(self, company_id, grouped_by):
accounts_domain = [
("company_id", "=", company_id),
] + self._get_account_type_domain(grouped_by)
acc_prt_accounts = self.env["account.account"].search(accounts_domain)
return acc_prt_accounts.ids
def _get_initial_balances_bs_ml_domain(
self, account_ids, company_id, date_from, base_domain, grouped_by, acc_prt=False
):
accounts_domain = [
("company_id", "=", company_id),
("include_initial_balance", "=", True),
]
if account_ids:
accounts_domain += [("id", "in", account_ids)]
domain = []
domain += base_domain
domain += [("date", "<", date_from)]
accounts = self.env["account.account"].search(accounts_domain)
domain += [("account_id", "in", accounts.ids)]
if acc_prt:
domain += self._get_account_type_domain(grouped_by)
return domain
def _get_initial_balances_pl_ml_domain(
self, account_ids, company_id, date_from, fy_start_date, base_domain
):
accounts_domain = [
("company_id", "=", company_id),
("include_initial_balance", "=", False),
]
if account_ids:
accounts_domain += [("id", "in", account_ids)]
domain = []
domain += base_domain
domain += [("date", "<", date_from), ("date", ">=", fy_start_date)]
accounts = self.env["account.account"].search(accounts_domain)
domain += [("account_id", "in", accounts.ids)]
return domain
def _get_accounts_initial_balance(self, initial_domain_bs, initial_domain_pl):
gl_initial_acc_bs = self.env["account.move.line"].read_group(
domain=initial_domain_bs,
fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"],
groupby=["account_id"],
)
gl_initial_acc_pl = self.env["account.move.line"].read_group(
domain=initial_domain_pl,
fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"],
groupby=["account_id"],
)
gl_initial_acc = gl_initial_acc_bs + gl_initial_acc_pl
return gl_initial_acc
def _get_initial_balance_fy_pl_ml_domain(
self, account_ids, company_id, fy_start_date, base_domain
):
accounts_domain = [
("company_id", "=", company_id),
("include_initial_balance", "=", False),
]
if account_ids:
accounts_domain += [("id", "in", account_ids)]
domain = []
domain += base_domain
domain += [("date", "<", fy_start_date)]
accounts = self.env["account.account"].search(accounts_domain)
domain += [("account_id", "in", accounts.ids)]
return domain
def _get_pl_initial_balance(
self, account_ids, company_id, fy_start_date, foreign_currency, base_domain
):
domain = self._get_initial_balance_fy_pl_ml_domain(
account_ids, company_id, fy_start_date, base_domain
)
initial_balances = self.env["account.move.line"].read_group(
domain=domain,
fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"],
groupby=["account_id"],
)
pl_initial_balance = {
"debit": 0.0,
"credit": 0.0,
"balance": 0.0,
"bal_curr": 0.0,
}
for initial_balance in initial_balances:
pl_initial_balance["debit"] += initial_balance["debit"]
pl_initial_balance["credit"] += initial_balance["credit"]
pl_initial_balance["balance"] += initial_balance["balance"]
pl_initial_balance["bal_curr"] += initial_balance["amount_currency"]
return pl_initial_balance
def _get_gl_initial_acc(
self, account_ids, company_id, date_from, fy_start_date, base_domain, grouped_by
):
initial_domain_bs = self._get_initial_balances_bs_ml_domain(
account_ids, company_id, date_from, base_domain, grouped_by
)
initial_domain_pl = self._get_initial_balances_pl_ml_domain(
account_ids, company_id, date_from, fy_start_date, base_domain
)
return self._get_accounts_initial_balance(initial_domain_bs, initial_domain_pl)
def _prepare_gen_ld_data_item(self, gl):
res = {}
for key_bal in ["init_bal", "fin_bal"]:
res[key_bal] = {}
for key_field in ["credit", "debit", "balance", "bal_curr"]:
field_name = key_field if key_field != "bal_curr" else "amount_currency"
res[key_bal][key_field] = gl[field_name]
return res
def _prepare_gen_ld_data(self, gl_initial_acc, domain, grouped_by):
data = {}
for gl in gl_initial_acc:
acc_id = gl["account_id"][0]
data[acc_id] = self._prepare_gen_ld_data_item(gl)
data[acc_id]["id"] = acc_id
if grouped_by:
data[acc_id][grouped_by] = False
method = "_prepare_gen_ld_data_group_%s" % grouped_by
if not hasattr(self, method):
return data
return getattr(self, method)(data, domain, grouped_by)
def _prepare_gen_ld_data_group_partners(self, data, domain, grouped_by):
gl_initial_acc_prt = self.env["account.move.line"].read_group(
domain=domain,
fields=[
"account_id",
"partner_id",
"debit",
"credit",
"balance",
"amount_currency:sum",
],
groupby=["account_id", "partner_id"],
lazy=False,
)
if gl_initial_acc_prt:
for gl in gl_initial_acc_prt:
if not gl["partner_id"]:
prt_id = 0
prt_name = _("Missing Partner")
else:
prt_id = gl["partner_id"][0]
prt_name = gl["partner_id"][1]
acc_id = gl["account_id"][0]
data[acc_id][prt_id] = self._prepare_gen_ld_data_item(gl)
data[acc_id][prt_id]["id"] = prt_id
data[acc_id][prt_id]["name"] = prt_name
data[acc_id][grouped_by] = True
return data
def _prepare_gen_ld_data_group_taxes(self, data, domain, grouped_by):
gl_initial_acc_prt = self.env["account.move.line"].read_group(
domain=domain,
fields=[
"account_id",
"debit",
"credit",
"balance",
"amount_currency:sum",
"tax_line_id",
],
groupby=["account_id"],
lazy=False,
)
if gl_initial_acc_prt:
for gl in gl_initial_acc_prt:
if "tax_line_id" in gl and gl["tax_line_id"]:
tax_id = gl["tax_line_id"][0]
tax_name = gl["tax_line_id"][1]
else:
tax_id = 0
tax_name = "Missing Tax"
acc_id = gl["account_id"][0]
data[acc_id][tax_id] = self._prepare_gen_ld_data_item(gl)
data[acc_id][tax_id]["id"] = tax_id
data[acc_id][tax_id]["name"] = tax_name
data[acc_id][grouped_by] = True
return data
def _get_initial_balance_data(
self,
account_ids,
partner_ids,
company_id,
date_from,
foreign_currency,
only_posted_moves,
unaffected_earnings_account,
fy_start_date,
cost_center_ids,
extra_domain,
grouped_by,
):
# If explicit list of accounts is provided,
# don't include unaffected earnings account
if account_ids:
unaffected_earnings_account = False
base_domain = []
if company_id:
base_domain += [("company_id", "=", company_id)]
if partner_ids:
base_domain += [("partner_id", "in", partner_ids)]
if only_posted_moves:
base_domain += [("move_id.state", "=", "posted")]
else:
base_domain += [("move_id.state", "in", ["posted", "draft"])]
if cost_center_ids:
base_domain += [("analytic_account_ids", "in", cost_center_ids)]
if extra_domain:
base_domain += extra_domain
gl_initial_acc = self._get_gl_initial_acc(
account_ids, company_id, date_from, fy_start_date, base_domain, grouped_by
)
domain = self._get_initial_balances_bs_ml_domain(
account_ids, company_id, date_from, base_domain, grouped_by, acc_prt=True
)
data = self._prepare_gen_ld_data(gl_initial_acc, domain, grouped_by)
accounts_ids = list(data.keys())
unaffected_id = unaffected_earnings_account
if unaffected_id:
if unaffected_id not in accounts_ids:
accounts_ids.append(unaffected_id)
data[unaffected_id] = self._initialize_data(foreign_currency)
data[unaffected_id]["id"] = unaffected_id
data[unaffected_id]["mame"] = ""
data[unaffected_id][grouped_by] = False
pl_initial_balance = self._get_pl_initial_balance(
account_ids, company_id, fy_start_date, foreign_currency, base_domain
)
for key_bal in ["init_bal", "fin_bal"]:
fields_balance = ["credit", "debit", "balance"]
if foreign_currency:
fields_balance.append("bal_curr")
for field_name in fields_balance:
data[unaffected_id][key_bal][field_name] += pl_initial_balance[
field_name
]
return data
@api.model
def _get_move_line_data(self, move_line):
move_line_data = {
"id": move_line["id"],
"date": move_line["date"],
"entry": move_line["move_name"],
"entry_id": move_line["move_id"][0],
"journal_id": move_line["journal_id"][0],
"account_id": move_line["account_id"][0],
"partner_id": move_line["partner_id"][0]
if move_line["partner_id"]
else False,
"partner_name": move_line["partner_id"][1]
if move_line["partner_id"]
else "",
"ref": "" if not move_line["ref"] else move_line["ref"],
"name": "" if not move_line["name"] else move_line["name"],
"tax_ids": move_line["tax_ids"],
"tax_line_id": move_line["tax_line_id"],
"debit": move_line["debit"],
"credit": move_line["credit"],
"balance": move_line["balance"],
"bal_curr": move_line["amount_currency"],
"rec_id": move_line["full_reconcile_id"][0]
if move_line["full_reconcile_id"]
else False,
"rec_name": move_line["full_reconcile_id"][1]
if move_line["full_reconcile_id"]
else "",
"currency_id": move_line["currency_id"],
"analytic_distribution": move_line["analytic_distribution"] or {},
}
if (
move_line_data["ref"] == move_line_data["name"]
or move_line_data["ref"] == ""
):
ref_label = move_line_data["name"]
elif move_line_data["name"] == "":
ref_label = move_line_data["ref"]
else:
ref_label = move_line_data["ref"] + " - " + move_line_data["name"]
move_line_data.update({"ref_label": ref_label})
return move_line_data
@api.model
def _get_period_domain(
self,
account_ids,
partner_ids,
company_id,
only_posted_moves,
date_to,
date_from,
cost_center_ids,
):
domain = [
("display_type", "not in", ["line_note", "line_section"]),
("date", ">=", date_from),
("date", "<=", date_to),
]
if account_ids:
domain += [("account_id", "in", account_ids)]
if company_id:
domain += [("company_id", "=", company_id)]
if partner_ids:
domain += [("partner_id", "in", partner_ids)]
if only_posted_moves:
domain += [("move_id.state", "=", "posted")]
else:
domain += [("move_id.state", "in", ["posted", "draft"])]
if cost_center_ids:
domain += [("analytic_account_ids", "in", cost_center_ids)]
return domain
def _initialize_data(self, foreign_currency):
res = {}
for key_bal in ["init_bal", "fin_bal"]:
res[key_bal] = {}
for key_field in ["balance", "credit", "debit"]:
res[key_bal][key_field] = 0.0
if foreign_currency:
res[key_bal]["bal_curr"] = 0.0
return res
def _get_reconciled_after_date_to_ids(self, full_reconcile_ids, date_to):
full_reconcile_ids = list(full_reconcile_ids)
domain = [
("max_date", ">", date_to),
("full_reconcile_id", "in", full_reconcile_ids),
]
fields = ["full_reconcile_id"]
reconciled_after_date_to = self.env["account.partial.reconcile"].search_read(
domain=domain, fields=fields
)
rec_after_date_to_ids = list(
map(operator.itemgetter("full_reconcile_id"), reconciled_after_date_to)
)
rec_after_date_to_ids = [i[0] for i in rec_after_date_to_ids]
return rec_after_date_to_ids
def _prepare_ml_items(self, move_line, grouped_by):
res = []
if grouped_by == "partners":
item_id = move_line["partner_id"][0] if move_line["partner_id"] else 0
item_name = (
move_line["partner_id"][1]
if move_line["partner_id"]
else _("Missing Partner")
)
res.append({"id": item_id, "name": item_name})
elif grouped_by == "taxes":
if move_line["tax_line_id"]:
item_id = move_line["tax_line_id"][0]
item_name = move_line["tax_line_id"][1]
res.append({"id": item_id, "name": item_name})
elif move_line["tax_ids"]:
for tax_id in move_line["tax_ids"]:
tax_item = self.env["account.tax"].browse(tax_id)
res.append({"id": tax_item.id, "name": tax_item.name})
else:
res.append({"id": 0, "name": "Missing Tax"})
else:
res.append({"id": 0, "name": ""})
return res
def _get_period_ml_data(
self,
account_ids,
partner_ids,
company_id,
foreign_currency,
only_posted_moves,
date_from,
date_to,
gen_ld_data,
cost_center_ids,
extra_domain,
grouped_by,
):
domain = self._get_period_domain(
account_ids,
partner_ids,
company_id,
only_posted_moves,
date_to,
date_from,
cost_center_ids,
)
if extra_domain:
domain += extra_domain
ml_fields = self._get_ml_fields()
move_lines = self.env["account.move.line"].search_read(
domain=domain, fields=ml_fields, order="date,move_name"
)
journal_ids = set()
full_reconcile_ids = set()
taxes_ids = set()
analytic_ids = set()
full_reconcile_data = {}
acc_prt_account_ids = self._get_acc_prt_accounts_ids(company_id, grouped_by)
for move_line in move_lines:
journal_ids.add(move_line["journal_id"][0])
for tax_id in move_line["tax_ids"]:
taxes_ids.add(tax_id)
for analytic_account in move_line["analytic_distribution"] or {}:
analytic_ids.add(int(analytic_account))
if move_line["full_reconcile_id"]:
rec_id = move_line["full_reconcile_id"][0]
if rec_id not in full_reconcile_ids:
full_reconcile_data.update(
{
rec_id: {
"id": rec_id,
"name": move_line["full_reconcile_id"][1],
}
}
)
full_reconcile_ids.add(rec_id)
acc_id = move_line["account_id"][0]
ml_id = move_line["id"]
if acc_id not in gen_ld_data.keys():
gen_ld_data[acc_id] = self._initialize_data(foreign_currency)
gen_ld_data[acc_id]["id"] = acc_id
gen_ld_data[acc_id]["mame"] = move_line["account_id"][1]
if grouped_by:
gen_ld_data[acc_id][grouped_by] = False
if acc_id in acc_prt_account_ids:
item_ids = self._prepare_ml_items(move_line, grouped_by)
for item in item_ids:
item_id = item["id"]
if item_id not in gen_ld_data[acc_id]:
if grouped_by:
gen_ld_data[acc_id][grouped_by] = True
gen_ld_data[acc_id][item_id] = self._initialize_data(
foreign_currency
)
gen_ld_data[acc_id][item_id]["id"] = item_id
gen_ld_data[acc_id][item_id]["name"] = item["name"]
gen_ld_data[acc_id][item_id][ml_id] = self._get_move_line_data(
move_line
)
gen_ld_data[acc_id][item_id]["fin_bal"]["credit"] += move_line[
"credit"
]
gen_ld_data[acc_id][item_id]["fin_bal"]["debit"] += move_line[
"debit"
]
gen_ld_data[acc_id][item_id]["fin_bal"]["balance"] += move_line[
"balance"
]
if foreign_currency:
gen_ld_data[acc_id][item_id]["fin_bal"][
"bal_curr"
] += move_line["amount_currency"]
else:
gen_ld_data[acc_id][ml_id] = self._get_move_line_data(move_line)
gen_ld_data[acc_id]["fin_bal"]["credit"] += move_line["credit"]
gen_ld_data[acc_id]["fin_bal"]["debit"] += move_line["debit"]
gen_ld_data[acc_id]["fin_bal"]["balance"] += move_line["balance"]
if foreign_currency:
gen_ld_data[acc_id]["fin_bal"]["bal_curr"] += move_line[
"amount_currency"
]
journals_data = self._get_journals_data(list(journal_ids))
accounts_data = self._get_accounts_data(gen_ld_data.keys())
taxes_data = self._get_taxes_data(list(taxes_ids))
analytic_data = self._get_analytic_data(list(analytic_ids))
rec_after_date_to_ids = self._get_reconciled_after_date_to_ids(
full_reconcile_data.keys(), date_to
)
return (
gen_ld_data,
accounts_data,
journals_data,
full_reconcile_data,
taxes_data,
analytic_data,
rec_after_date_to_ids,
)
@api.model
def _recalculate_cumul_balance(
self, move_lines, last_cumul_balance, rec_after_date_to_ids
):
for move_line in move_lines:
move_line["balance"] += last_cumul_balance
last_cumul_balance = move_line["balance"]
if move_line["rec_id"] in rec_after_date_to_ids:
move_line["rec_name"] = "(" + _("future") + ") " + move_line["rec_name"]
return move_lines
def _create_account(self, account, acc_id, gen_led_data, rec_after_date_to_ids):
move_lines = []
for ml_id in gen_led_data[acc_id].keys():
if not isinstance(ml_id, int):
account.update({ml_id: gen_led_data[acc_id][ml_id]})
else:
move_lines += [gen_led_data[acc_id][ml_id]]
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
move_lines = self._recalculate_cumul_balance(
move_lines,
gen_led_data[acc_id]["init_bal"]["balance"],
rec_after_date_to_ids,
)
account.update({"move_lines": move_lines})
return account
def _create_account_not_show_item(
self, account, acc_id, gen_led_data, rec_after_date_to_ids, grouped_by
):
move_lines = []
for prt_id in gen_led_data[acc_id].keys():
if not isinstance(prt_id, int):
account.update({prt_id: gen_led_data[acc_id][prt_id]})
elif isinstance(gen_led_data[acc_id][prt_id], dict):
for ml_id in gen_led_data[acc_id][prt_id].keys():
if isinstance(ml_id, int):
move_lines += [gen_led_data[acc_id][prt_id][ml_id]]
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
move_lines = self._recalculate_cumul_balance(
move_lines,
gen_led_data[acc_id]["init_bal"]["balance"],
rec_after_date_to_ids,
)
account.update({"move_lines": move_lines, grouped_by: False})
return account
def _get_list_grouped_item(
self, data, account, rec_after_date_to_ids, hide_account_at_0, rounding
):
list_grouped = []
for data_id in data.keys():
group_item = {}
move_lines = []
if not isinstance(data_id, int):
account.update({data_id: data[data_id]})
else:
for ml_id in data[data_id].keys():
if not isinstance(ml_id, int):
group_item.update({ml_id: data[data_id][ml_id]})
else:
move_lines += [data[data_id][ml_id]]
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
move_lines = self._recalculate_cumul_balance(
move_lines,
data[data_id]["init_bal"]["balance"],
rec_after_date_to_ids,
)
group_item.update({"move_lines": move_lines})
if (
hide_account_at_0
and float_is_zero(
data[data_id]["init_bal"]["balance"],
precision_rounding=rounding,
)
and group_item["move_lines"] == []
):
continue
list_grouped += [group_item]
return account, list_grouped
def _create_general_ledger(
self,
gen_led_data,
accounts_data,
grouped_by,
rec_after_date_to_ids,
hide_account_at_0,
):
general_ledger = []
rounding = self.env.company.currency_id.rounding
for acc_id in gen_led_data.keys():
account = {}
account.update(
{
"code": accounts_data[acc_id]["code"],
"name": accounts_data[acc_id]["name"],
"type": "account",
"currency_id": accounts_data[acc_id]["currency_id"],
"centralized": accounts_data[acc_id]["centralized"],
"grouped_by": grouped_by,
}
)
if grouped_by and not gen_led_data[acc_id][grouped_by]:
account = self._create_account(
account, acc_id, gen_led_data, rec_after_date_to_ids
)
if (
hide_account_at_0
and float_is_zero(
gen_led_data[acc_id]["init_bal"]["balance"],
precision_rounding=rounding,
)
and account["move_lines"] == []
):
continue
else:
if grouped_by:
account, list_grouped = self._get_list_grouped_item(
gen_led_data[acc_id],
account,
rec_after_date_to_ids,
hide_account_at_0,
rounding,
)
account.update({"list_grouped": list_grouped})
if (
hide_account_at_0
and float_is_zero(
gen_led_data[acc_id]["init_bal"]["balance"],
precision_rounding=rounding,
)
and account["list_grouped"] == []
):
continue
else:
account = self._create_account_not_show_item(
account, acc_id, gen_led_data, rec_after_date_to_ids, grouped_by
)
if (
hide_account_at_0
and float_is_zero(
gen_led_data[acc_id]["init_bal"]["balance"],
precision_rounding=rounding,
)
and account["move_lines"] == []
):
continue
general_ledger += [account]
return general_ledger
@api.model
def _calculate_centralization(self, centralized_ml, move_line, date_to):
jnl_id = move_line["journal_id"]
month = move_line["date"].month
if jnl_id not in centralized_ml.keys():
centralized_ml[jnl_id] = {}
if month not in centralized_ml[jnl_id].keys():
centralized_ml[jnl_id][month] = {}
last_day_month = calendar.monthrange(move_line["date"].year, month)
date = datetime.date(move_line["date"].year, month, last_day_month[1])
if date > date_to:
date = date_to
centralized_ml[jnl_id][month].update(
{
"journal_id": jnl_id,
"ref_label": "Centralized entries",
"date": date,
"debit": 0.0,
"credit": 0.0,
"balance": 0.0,
"bal_curr": 0.0,
"partner_id": False,
"rec_id": 0,
"entry_id": False,
"tax_ids": [],
"tax_line_id": False,
"full_reconcile_id": False,
"id": False,
"currency_id": False,
"analytic_distribution": {},
}
)
centralized_ml[jnl_id][month]["debit"] += move_line["debit"]
centralized_ml[jnl_id][month]["credit"] += move_line["credit"]
centralized_ml[jnl_id][month]["balance"] += (
move_line["debit"] - move_line["credit"]
)
centralized_ml[jnl_id][month]["bal_curr"] += move_line["bal_curr"]
return centralized_ml
@api.model
def _get_centralized_ml(self, account, date_to, grouped_by):
centralized_ml = {}
if isinstance(date_to, str):
date_to = datetime.datetime.strptime(date_to, "%Y-%m-%d").date()
if grouped_by and account[grouped_by]:
for item in account["list_grouped"]:
for move_line in item["move_lines"]:
centralized_ml = self._calculate_centralization(
centralized_ml,
move_line,
date_to,
)
else:
for move_line in account["move_lines"]:
centralized_ml = self._calculate_centralization(
centralized_ml,
move_line,
date_to,
)
list_centralized_ml = []
for jnl_id in centralized_ml.keys():
list_centralized_ml += list(centralized_ml[jnl_id].values())
return list_centralized_ml
# flake8: noqa: C901
def _get_report_values(self, docids, data):
wizard_id = data["wizard_id"]
company = self.env["res.company"].browse(data["company_id"])
company_id = data["company_id"]
date_to = data["date_to"]
date_from = data["date_from"]
partner_ids = data["partner_ids"]
account_ids = data["account_ids"]
cost_center_ids = data["cost_center_ids"]
grouped_by = data["grouped_by"]
hide_account_at_0 = data["hide_account_at_0"]
foreign_currency = data["foreign_currency"]
only_posted_moves = data["only_posted_moves"]
unaffected_earnings_account = data["unaffected_earnings_account"]
fy_start_date = data["fy_start_date"]
extra_domain = data["domain"]
gen_ld_data = self._get_initial_balance_data(
account_ids,
partner_ids,
company_id,
date_from,
foreign_currency,
only_posted_moves,
unaffected_earnings_account,
fy_start_date,
cost_center_ids,
extra_domain,
grouped_by,
)
centralize = data["centralize"]
(
gen_ld_data,
accounts_data,
journals_data,
full_reconcile_data,
taxes_data,
analytic_data,
rec_after_date_to_ids,
) = self._get_period_ml_data(
account_ids,
partner_ids,
company_id,
foreign_currency,
only_posted_moves,
date_from,
date_to,
gen_ld_data,
cost_center_ids,
extra_domain,
grouped_by,
)
general_ledger = self._create_general_ledger(
gen_ld_data,
accounts_data,
grouped_by,
rec_after_date_to_ids,
hide_account_at_0,
)
if centralize:
for account in general_ledger:
if account["centralized"]:
centralized_ml = self._get_centralized_ml(
account, date_to, grouped_by
)
account["move_lines"] = centralized_ml
account["move_lines"] = self._recalculate_cumul_balance(
account["move_lines"],
gen_ld_data[account["id"]]["init_bal"]["balance"],
rec_after_date_to_ids,
)
if grouped_by and account[grouped_by]:
account[grouped_by] = False
del account["list_grouped"]
general_ledger = sorted(general_ledger, key=lambda k: k["code"])
# Set the bal_curr of the initial balance to 0 if it does not correspond
# (reducing the corresponding of the bal_curr of the initial balance).
for gl_item in general_ledger:
if not foreign_currency:
continue
if (
not gl_item["currency_id"]
or gl_item["currency_id"] != company.currency_id
):
gl_item["fin_bal"]["bal_curr"] -= gl_item["init_bal"]["bal_curr"]
gl_item["init_bal"]["bal_curr"] = 0
if "list_grouped" in gl_item:
for lg_item in gl_item["list_grouped"]:
lg_item["fin_bal"]["bal_curr"] -= lg_item["init_bal"][
"bal_curr"
]
lg_item["init_bal"]["bal_curr"] = 0
# Set the fin_bal_currency_id value if the account does not have it set
# and there are move lines in a currency different from that of
# the company (USD for example).
for gl_item in general_ledger:
fin_bal_currency_ids = []
fin_bal_currency_id = gl_item["currency_id"]
if gl_item["currency_id"] or not foreign_currency:
continue
gl_item["fin_bal"]["bal_curr"] = gl_item["init_bal"]["bal_curr"]
if "move_lines" in gl_item:
for ml in gl_item["move_lines"]:
ml_currency_id = (
ml["currency_id"][0] if ml["currency_id"] else False
)
if ml_currency_id and ml_currency_id != company.currency_id.id:
gl_item["fin_bal"]["bal_curr"] += ml["bal_curr"]
if ml_currency_id not in fin_bal_currency_ids:
fin_bal_currency_ids.append(ml_currency_id)
elif "list_grouped" in gl_item:
fin_bal_currency_ids = []
for lg_item in gl_item["list_grouped"]:
lg_item["fin_bal"]["bal_curr"] = lg_item["init_bal"]["bal_curr"]
for ml in lg_item["move_lines"]:
ml_currency_id = (
ml["currency_id"][0] if ml["currency_id"] else False
)
if ml_currency_id and ml_currency_id != company.currency_id.id:
lg_item["fin_bal"]["bal_curr"] += ml["bal_curr"]
gl_item["fin_bal"]["bal_curr"] += ml["bal_curr"]
if ml_currency_id not in fin_bal_currency_ids:
fin_bal_currency_ids.append(ml_currency_id)
# If there is only 1 currency, we set that one as fin_bal_currency_id
# The use of different move lines with different currencies (EUR + GBP)
# will be excluded. We use a different field to avoid showing the initial
# balance and/or distorting data.
if not gl_item["currency_id"] and len(fin_bal_currency_ids) == 1:
fin_bal_currency_id = fin_bal_currency_ids[0]
gl_item["fin_bal_currency_id"] = fin_bal_currency_id
return {
"doc_ids": [wizard_id],
"doc_model": "general.ledger.report.wizard",
"docs": self.env["general.ledger.report.wizard"].browse(wizard_id),
"foreign_currency": data["foreign_currency"],
"company_name": company.display_name,
"company_currency": company.currency_id,
"currency_name": company.currency_id.name,
"date_from": data["date_from"],
"date_to": data["date_to"],
"only_posted_moves": data["only_posted_moves"],
"hide_account_at_0": data["hide_account_at_0"],
"show_cost_center": data["show_cost_center"],
"general_ledger": general_ledger,
"accounts_data": accounts_data,
"journals_data": journals_data,
"full_reconcile_data": full_reconcile_data,
"taxes_data": taxes_data,
"centralize": centralize,
"analytic_data": analytic_data,
"filter_partner_ids": True if partner_ids else False,
"currency_model": self.env["res.currency"],
}
def _get_ml_fields(self):
return self.COMMON_ML_FIELDS + [
"analytic_distribution",
"full_reconcile_id",
"tax_line_id",
"currency_id",
"credit",
"debit",
"amount_currency",
"balance",
"tax_ids",
"move_name",
]