account-reconcile/account_reconcile_oca/models/account_account_reconcile.py

199 lines
6.7 KiB
Python

# Copyright 2023 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class CharId(fields.Id):
type = "string"
column_type = ("varchar", fields.pg_varchar())
class AccountAccountReconcile(models.Model):
_name = "account.account.reconcile"
_description = "Account Account Reconcile"
_inherit = "account.reconcile.abstract"
_auto = False
reconcile_data_info = fields.Serialized(inverse="_inverse_reconcile_data_info")
partner_id = fields.Many2one("res.partner", readonly=True)
account_id = fields.Many2one("account.account", readonly=True)
name = fields.Char(readonly=True)
is_reconciled = fields.Boolean(readonly=True)
@property
def _table_query(self):
return "%s %s %s %s %s" % (
self._select(),
self._from(),
self._where(),
self._groupby(),
self._having(),
)
def _select(self):
account_account_name_field = (
self.env["ir.model.fields"]
.sudo()
.search([("model", "=", "account.account"), ("name", "=", "name")])
)
account_name = (
f"a.name ->> '{self.env.user.lang}'"
if account_account_name_field.translate
else "a.name"
)
return f"""
SELECT
min(aml.id) as id,
MAX({account_name}) as name,
CASE
WHEN a.account_type in ('asset_receivable', 'liability_payable')
THEN aml.partner_id
ELSE NULL
END as partner_id,
a.id as account_id,
FALSE as is_reconciled,
aml.currency_id as currency_id,
a.company_id,
false as foreign_currency_id
"""
def _from(self):
return """
FROM
account_account a
INNER JOIN account_move_line aml ON aml.account_id = a.id
INNER JOIN account_move am ON am.id = aml.move_id
"""
def _where(self):
return """
WHERE a.reconcile
AND am.state = 'posted'
AND aml.amount_residual != 0
"""
def _groupby(self):
return """
GROUP BY
a.id,
CASE
WHEN a.account_type in ('asset_receivable', 'liability_payable')
THEN aml.partner_id
ELSE NULL
END,
aml.currency_id,
a.company_id
"""
def _having(self):
return """
HAVING
SUM(aml.debit) > 0
AND SUM(aml.credit) > 0
"""
def _compute_reconcile_data_info(self):
data_obj = self.env["account.account.reconcile.data"]
for record in self:
if self.env.context.get("default_account_move_lines"):
data = {
"data": [],
"counterparts": self.env.context.get("default_account_move_lines"),
}
record.reconcile_data_info = self._recompute_data(data)
continue
data_record = data_obj.search(
[("user_id", "=", self.env.user.id), ("reconcile_id", "=", record.id)]
)
if data_record:
record.reconcile_data_info = data_record.data
else:
record.reconcile_data_info = {"data": [], "counterparts": []}
def _inverse_reconcile_data_info(self):
data_obj = self.env["account.account.reconcile.data"]
for record in self:
data_record = data_obj.search(
[("user_id", "=", self.env.user.id), ("reconcile_id", "=", record.id)]
)
if data_record:
data_record.data = record.reconcile_data_info
else:
data_obj.create(
{
"reconcile_id": record.id,
"user_id": self.env.user.id,
"data": record.reconcile_data_info,
}
)
@api.onchange("add_account_move_line_id")
def _onchange_add_account_move_line(self):
if self.add_account_move_line_id:
data = self.reconcile_data_info
if self.add_account_move_line_id.id not in data["counterparts"]:
data["counterparts"].append(self.add_account_move_line_id.id)
else:
del data["counterparts"][
data["counterparts"].index(self.add_account_move_line_id.id)
]
self.reconcile_data_info = self._recompute_data(data)
self.add_account_move_line_id = False
@api.onchange("manual_reference", "manual_delete")
def _onchange_manual_reconcile_reference(self):
self.ensure_one()
data = self.reconcile_data_info
counterparts = []
for line in data["data"]:
if line["reference"] == self.manual_reference:
if self.manual_delete:
continue
counterparts.append(line["id"])
data["counterparts"] = counterparts
self.reconcile_data_info = self._recompute_data(data)
self.manual_delete = False
self.manual_reference = False
def _recompute_data(self, data):
new_data = {"data": [], "counterparts": data["counterparts"]}
counterparts = data["counterparts"]
amount = 0.0
for line_id in counterparts:
max_amount = amount if line_id == counterparts[-1] else 0
lines = self._get_reconcile_line(
self.env["account.move.line"].browse(line_id),
"other",
is_counterpart=True,
max_amount=max_amount,
move=True,
)
new_data["data"] += lines
amount += sum(line["amount"] for line in lines)
return new_data
def clean_reconcile(self):
self.ensure_one()
self.reconcile_data_info = {"data": [], "counterparts": []}
def reconcile(self):
lines = self.env["account.move.line"].browse(
self.reconcile_data_info["counterparts"]
)
lines.reconcile()
data_record = self.env["account.account.reconcile.data"].search(
[("user_id", "=", self.env.user.id), ("reconcile_id", "=", self.id)]
)
data_record.unlink()
class AccountAccountReconcileData(models.TransientModel):
_name = "account.account.reconcile.data"
_description = "Reconcile data model to store user info"
user_id = fields.Many2one("res.users", required=True)
reconcile_id = fields.Integer(required=True)
data = fields.Serialized()