[IMP] account_financial_report: multiple fixes and improvements

This commit is contained in:
Jordi Ballester Alomar
2020-05-01 08:14:01 +02:00
committed by chaule97
parent cbaabca8ae
commit e4377eb3bb
17 changed files with 830 additions and 942 deletions

View File

@@ -6,7 +6,6 @@ import operator
from datetime import date, datetime
from odoo import api, models
from odoo.osv import expression
from odoo.tools import float_is_zero
@@ -31,137 +30,113 @@ class OpenItemsReport(models.AbstractModel):
).render(rcontext)
return result
def _get_account_partial_reconciled(self, move_lines_data, date_at_object):
reconciled_ids = []
for move_line in move_lines_data:
if move_line["reconciled"]:
reconciled_ids += [move_line["id"]]
domain = [("max_date", ">=", date_at_object)]
domain += expression.OR(
[
[("debit_move_id", "in", reconciled_ids)],
[("credit_move_id", "in", reconciled_ids)],
]
)
def _get_account_partial_reconciled(self, company_id, date_at_object):
domain = [("max_date", ">", date_at_object), ("company_id", "=", company_id)]
fields = ["debit_move_id", "credit_move_id", "amount"]
accounts_partial_reconcile = self.env["account.partial.reconcile"].search_read(
domain=domain, fields=fields
)
debit_accounts_partial_amount = {}
credit_accounts_partial_amount = {}
debit_amount = {}
credit_amount = {}
for account_partial_reconcile_data in accounts_partial_reconcile:
debit_move_id = account_partial_reconcile_data["debit_move_id"][0]
credit_move_id = account_partial_reconcile_data["credit_move_id"][0]
if debit_move_id not in debit_accounts_partial_amount.keys():
debit_accounts_partial_amount[debit_move_id] = 0.0
debit_accounts_partial_amount[
debit_move_id
] += account_partial_reconcile_data["amount"]
if credit_move_id not in credit_accounts_partial_amount.keys():
credit_accounts_partial_amount[credit_move_id] = 0.0
credit_accounts_partial_amount[
credit_move_id
] += account_partial_reconcile_data["amount"]
if debit_move_id not in debit_amount.keys():
debit_amount[debit_move_id] = 0.0
debit_amount[debit_move_id] += account_partial_reconcile_data["amount"]
if credit_move_id not in credit_amount.keys():
credit_amount[credit_move_id] = 0.0
credit_amount[credit_move_id] += account_partial_reconcile_data["amount"]
account_partial_reconcile_data.update(
{"debit_move_id": debit_move_id, "credit_move_id": credit_move_id}
)
return (
accounts_partial_reconcile,
debit_accounts_partial_amount,
credit_accounts_partial_amount,
)
return accounts_partial_reconcile, debit_amount, credit_amount
@api.model
def _get_query_domain(
self,
account_ids,
partner_ids,
date_at_object,
target_move,
company_id,
date_from,
def _get_new_move_lines_domain(
self, new_ml_ids, account_ids, company_id, partner_ids, target_moves
):
query = """
WHERE aml.account_id in %s and aml.company_id = %s
""" % (
tuple(account_ids) if len(account_ids) > 1 else "(%s)" % account_ids[0],
company_id,
)
if date_from:
query += " and aml.date >= '%s'" % date_from
domain = [
("account_id", "in", account_ids),
("company_id", "=", company_id),
("id", "in", new_ml_ids),
]
if partner_ids:
query += " and aml.partner_id in {}".format(tuple(partner_ids))
if target_move == "posted":
query += " and am.state = 'posted'"
if date_at_object >= date.today():
query += " and aml.reconciled IS FALSE"
else:
query += (
""" and ((aml.reconciled IS FALSE OR aml.date >= '%s')
OR aml.full_reconcile_id IS NOT NULL)"""
% date_at_object
)
return query
domain += [("partner_id", "in", partner_ids)]
if target_moves == "posted":
domain += [("move_id.state", "=", "posted")]
return domain
@api.model
def _get_query(
def _recalculate_move_lines(
self,
move_lines,
debit_ids,
credit_ids,
debit_amount,
credit_amount,
ml_ids,
account_ids,
partner_ids,
date_at_object,
target_move,
company_id,
date_from,
partner_ids,
target_moves,
):
aml_fields = [
debit_ids = set(debit_ids)
credit_ids = set(credit_ids)
in_credit_but_not_in_debit = credit_ids - debit_ids
reconciled_ids = list(debit_ids) + list(in_credit_but_not_in_debit)
reconciled_ids = set(reconciled_ids)
ml_ids = set(ml_ids)
new_ml_ids = reconciled_ids - ml_ids
new_ml_ids = list(new_ml_ids)
new_domain = self._get_new_move_lines_domain(
new_ml_ids, account_ids, company_id, partner_ids, target_moves
)
ml_fields = [
"id",
"name",
"date",
"move_id",
"journal_id",
"account_id",
"partner_id",
"ref",
"date_maturity",
"amount_residual",
"amount_currency",
"amount_residual_currency",
"date_maturity",
"ref",
"debit",
"credit",
"currency_id",
"reconciled",
"full_reconcile_id",
"currency_id",
"amount_currency",
"amount_residual_currency",
]
query = ""
# SELECT
for field in aml_fields:
if not query:
query = "SELECT aml.%s" % field
else:
query += ", aml.%s" % field
# name from res_partner
query += ", rp.name as partner_name"
# name from res_currency
query += ", rc.name as currency_name"
# state and name from account_move
query += ", am.state, am.name as move_name"
# FROM
query += """
FROM account_move_line as aml
LEFT JOIN res_partner as rp
ON aml.partner_id = rp.id
LEFT JOIN res_currency as rc
ON aml.currency_id = rc.id
LEFT JOIN account_move as am
ON am.id = aml.move_id
"""
# WHERE
query += self._get_query_domain(
account_ids, partner_ids, date_at_object, target_move, company_id, date_from
new_move_lines = self.env["account.move.line"].search_read(
domain=new_domain, fields=ml_fields
)
return query
move_lines = move_lines + new_move_lines
for move_line in move_lines:
ml_id = move_line["id"]
if ml_id in debit_ids:
move_line["amount_residual"] += debit_amount[ml_id]
if ml_id in credit_ids:
move_line["amount_residual"] -= credit_amount[ml_id]
return move_lines
@api.model
def _get_move_lines_domain(
self, company_id, account_ids, partner_ids, target_move, date_from
):
domain = [
("account_id", "in", account_ids),
("company_id", "=", company_id),
("reconciled", "=", False),
]
if partner_ids:
domain += [("partner_id", "in", partner_ids)]
if target_move == "posted":
domain += [("move_id.state", "=", "posted")]
if date_from:
domain += [("date", ">", date_from)]
return domain
def _get_accounts_data(self, accounts_ids):
accounts = self.env["account.account"].browse(accounts_ids)
@@ -188,7 +163,6 @@ class OpenItemsReport(models.AbstractModel):
journals_data.update({journal.id: {"id": journal.id, "code": journal.code}})
return journals_data
# flake8: noqa: C901
def _get_data(
self,
account_ids,
@@ -198,69 +172,80 @@ class OpenItemsReport(models.AbstractModel):
company_id,
date_from,
):
query = self._get_query(
account_ids, partner_ids, date_at_object, target_move, company_id, date_from
domain = self._get_move_lines_domain(
company_id, account_ids, partner_ids, target_move, date_from
)
self._cr.execute(query)
move_lines_data = self._cr.dictfetchall()
account_ids = map(lambda r: r["account_id"], move_lines_data)
accounts_data = self._get_accounts_data(list(account_ids))
journal_ids = map(lambda r: r["journal_id"], move_lines_data)
journals_data = self._get_journals_data(list(journal_ids))
ml_fields = [
"id",
"name",
"date",
"move_id",
"journal_id",
"account_id",
"partner_id",
"amount_residual",
"date_maturity",
"ref",
"debit",
"credit",
"reconciled",
"currency_id",
"amount_currency",
"amount_residual_currency",
]
move_lines = self.env["account.move.line"].search_read(
domain=domain, fields=ml_fields
)
journals_ids = set()
partners_ids = set()
partners_data = {}
if date_at_object < date.today():
(
accounts_partial_reconcile,
debit_accounts_partial_amount,
credit_accounts_partial_amount,
) = self._get_account_partial_reconciled(move_lines_data, date_at_object)
if accounts_partial_reconcile:
debit_ids = map(
operator.itemgetter("debit_move_id"), accounts_partial_reconcile
acc_partial_rec,
debit_amount,
credit_amount,
) = self._get_account_partial_reconciled(company_id, date_at_object)
if acc_partial_rec:
ml_ids = list(map(operator.itemgetter("id"), move_lines))
debit_ids = list(
map(operator.itemgetter("debit_move_id"), acc_partial_rec)
)
credit_ids = map(
operator.itemgetter("credit_move_id"), accounts_partial_reconcile
credit_ids = list(
map(operator.itemgetter("credit_move_id"), acc_partial_rec)
)
for move_line in move_lines_data:
if move_line["id"] in debit_ids:
move_line["amount_residual"] += debit_accounts_partial_amount[
move_line["id"]
]
if move_line["id"] in credit_ids:
move_line["amount_residual"] -= credit_accounts_partial_amount[
move_line["id"]
]
moves_lines_to_remove = []
for move_line in move_lines_data:
if move_line["date"] > date_at_object or float_is_zero(
move_line["amount_residual"], precision_digits=2
):
moves_lines_to_remove.append(move_line)
if len(moves_lines_to_remove) > 0:
for move_line_to_remove in moves_lines_to_remove:
move_lines_data.remove(move_line_to_remove)
partners_data = {0: {"id": 0, "name": "Missing Partner"}}
move_lines = self._recalculate_move_lines(
move_lines,
debit_ids,
credit_ids,
debit_amount,
credit_amount,
ml_ids,
account_ids,
company_id,
partner_ids,
target_move,
)
move_lines = [
move_line
for move_line in move_lines
if move_line["date"] <= date_at_object
and not float_is_zero(move_line["amount_residual"], precision_digits=2)
]
open_items_move_lines_data = {}
for move_line in move_lines_data:
no_partner = True
for move_line in move_lines:
journals_ids.add(move_line["journal_id"][0])
acc_id = move_line["account_id"][0]
# Partners data
if move_line["partner_id"]:
no_partner = False
partners_data.update(
{
move_line["partner_id"]: {
"id": move_line["partner_id"],
"name": move_line["partner_name"],
"currency_id": accounts_data[move_line["account_id"]][
"currency_id"
],
}
}
)
prt_id = move_line["partner_id"][0]
prt_name = move_line["partner_id"][1]
else:
partners_data[0]["currency_id"] = accounts_data[
move_line["account_id"]
]["currency_id"]
prt_id = 0
prt_name = "Missing Partner"
if prt_id not in partners_ids:
partners_data.update({prt_id: {"id": prt_id, "name": prt_name}})
partners_ids.add(prt_id)
# Move line update
original = 0
@@ -269,39 +254,51 @@ class OpenItemsReport(models.AbstractModel):
original = move_line["credit"] * (-1)
if not float_is_zero(move_line["debit"], precision_digits=2):
original = move_line["debit"]
if move_line["ref"] == move_line["name"]:
if move_line["ref"]:
ref_label = move_line["ref"]
else:
ref_label = ""
elif not move_line["ref"]:
ref_label = move_line["name"]
elif not move_line["name"]:
ref_label = move_line["ref"]
else:
ref_label = move_line["ref"] + str(" - ") + move_line["name"]
move_line.update(
{
"date": move_line["date"].strftime("%d/%m/%Y"),
"date": move_line["date"],
"date_maturity": move_line["date_maturity"]
and move_line["date_maturity"].strftime("%d/%m/%Y"),
"original": original,
"partner_id": 0 if no_partner else move_line["partner_id"],
"partner_name": "" if no_partner else move_line["partner_name"],
"ref": "" if not move_line["ref"] else move_line["ref"],
"account": accounts_data[move_line["account_id"]]["code"],
"journal": journals_data[move_line["journal_id"]]["code"],
"partner_id": prt_id,
"partner_name": prt_name,
"ref_label": ref_label,
"journal_id": move_line["journal_id"][0],
"move_name": move_line["move_id"][1],
"currency_id": move_line["currency_id"][0]
if move_line["currency_id"]
else False,
"currency_name": move_line["currency_id"][1]
if move_line["currency_id"]
else False,
}
)
# Open Items Move Lines Data
if move_line["account_id"] not in open_items_move_lines_data.keys():
open_items_move_lines_data[move_line["account_id"]] = {
move_line["partner_id"]: [move_line]
}
if acc_id not in open_items_move_lines_data.keys():
open_items_move_lines_data[acc_id] = {prt_id: [move_line]}
else:
if (
move_line["partner_id"]
not in open_items_move_lines_data[move_line["account_id"]].keys()
):
open_items_move_lines_data[move_line["account_id"]][
move_line["partner_id"]
] = [move_line]
if prt_id not in open_items_move_lines_data[acc_id].keys():
open_items_move_lines_data[acc_id][prt_id] = [move_line]
else:
open_items_move_lines_data[move_line["account_id"]][
move_line["partner_id"]
].append(move_line)
open_items_move_lines_data[acc_id][prt_id].append(move_line)
journals_data = self._get_journals_data(list(journals_ids))
accounts_data = self._get_accounts_data(open_items_move_lines_data.keys())
return (
move_lines_data,
move_lines,
partners_data,
journals_data,
accounts_data,
@@ -325,19 +322,31 @@ class OpenItemsReport(models.AbstractModel):
return total_amount
@api.model
def _get_open_items_no_partners(self, open_items_move_lines_data):
def _order_open_items_by_date(
self, open_items_move_lines_data, show_partner_details
):
new_open_items = {}
for acc_id in open_items_move_lines_data.keys():
new_open_items[acc_id] = {}
move_lines = []
for prt_id in open_items_move_lines_data[acc_id]:
for move_line in open_items_move_lines_data[acc_id][prt_id]:
move_lines += [move_line]
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
new_open_items[acc_id] = move_lines
if not show_partner_details:
for acc_id in open_items_move_lines_data.keys():
new_open_items[acc_id] = {}
move_lines = []
for prt_id in open_items_move_lines_data[acc_id]:
for move_line in open_items_move_lines_data[acc_id][prt_id]:
move_lines += [move_line]
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
new_open_items[acc_id] = move_lines
else:
for acc_id in open_items_move_lines_data.keys():
new_open_items[acc_id] = {}
for prt_id in open_items_move_lines_data[acc_id]:
new_open_items[acc_id][prt_id] = {}
move_lines = []
for move_line in open_items_move_lines_data[acc_id][prt_id]:
move_lines += [move_line]
move_lines = sorted(move_lines, key=lambda k: (k["date"]))
new_open_items[acc_id][prt_id] = move_lines
return new_open_items
@api.multi
def _get_report_values(self, docids, data):
wizard_id = data["wizard_id"]
company = self.env["res.company"].browse(data["company_id"])
@@ -361,10 +370,9 @@ class OpenItemsReport(models.AbstractModel):
)
total_amount = self._calculate_amounts(open_items_move_lines_data)
if not show_partner_details:
open_items_move_lines_data = self._get_open_items_no_partners(
open_items_move_lines_data
)
open_items_move_lines_data = self._order_open_items_by_date(
open_items_move_lines_data, show_partner_details
)
return {
"doc_ids": [wizard_id],
"doc_model": "open.items.report.wizard",
@@ -376,6 +384,7 @@ class OpenItemsReport(models.AbstractModel):
"date_at": date_at_object.strftime("%d/%m/%Y"),
"hide_account_at_0": data["hide_account_at_0"],
"target_move": data["target_move"],
"journals_data": journals_data,
"partners_data": partners_data,
"accounts_data": accounts_data,
"total_amount": total_amount,