Files
Odoo-Modules/Fusion Accounting/models/account_move_line.py
2026-02-22 01:22:18 -05:00

104 lines
4.1 KiB
Python

# Fusion Accounting - Move Line Extensions
# Bank-line exclusion flag, tax-closing safeguards, and report shadowing
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.tools import SQL
class FusionAccountMoveLine(models.Model):
"""Extends journal items with a computed bank-line exclusion flag,
guards against tax manipulation on closing entries, and provides
utilities for building temporary shadow tables used by analytic
and budget reports."""
_name = "account.move.line"
_inherit = "account.move.line"
# ---- Fields ----
exclude_bank_lines = fields.Boolean(
compute='_compute_exclude_bank_lines',
store=True,
)
# ---- Computed ----
@api.depends('journal_id')
def _compute_exclude_bank_lines(self):
"""Flag lines whose account differs from their journal's
default account, used to filter non-bank entries in bank
journal views."""
for ml in self:
ml.exclude_bank_lines = (
ml.account_id != ml.journal_id.default_account_id
)
# ---- Constraints ----
@api.constrains('tax_ids', 'tax_tag_ids')
def _check_taxes_on_closing_entries(self):
"""Prevent taxes from being added to tax-closing move lines."""
for ml in self:
if ml.move_id.tax_closing_report_id and (ml.tax_ids or ml.tax_tag_ids):
raise UserError(
_("Tax lines are not permitted on tax-closing entries.")
)
# ---- Tax Computation Override ----
@api.depends('product_id', 'product_uom_id', 'move_id.tax_closing_report_id')
def _compute_tax_ids(self):
"""Skip automatic tax computation for lines on tax-closing
moves, which might otherwise trigger the constraint above."""
non_closing_lines = self.filtered(
lambda ln: not ln.move_id.tax_closing_report_id
)
(self - non_closing_lines).tax_ids = False
super(FusionAccountMoveLine, non_closing_lines)._compute_tax_ids()
# ---- Report Shadow Table Utility ----
@api.model
def _prepare_aml_shadowing_for_report(self, change_equivalence_dict):
"""Build SQL fragments for creating a temporary table that
mirrors ``account_move_line`` but substitutes selected columns
with alternative expressions (e.g. analytic or budget data).
:param change_equivalence_dict:
Mapping ``{field_name: sql_expression}`` where each value
replaces the corresponding column in the shadow table.
:returns:
A tuple ``(insert_columns, select_expressions)`` of SQL
objects suitable for ``INSERT INTO ... SELECT ...``.
"""
field_metadata = self.env['account.move.line'].fields_get()
self.env.cr.execute(
"SELECT column_name FROM information_schema.columns "
"WHERE table_name='account_move_line'"
)
db_columns = {
row[0] for row in self.env.cr.fetchall() if row[0] in field_metadata
}
select_parts = []
for col_name in db_columns:
if col_name in change_equivalence_dict:
select_parts.append(SQL(
"%(src)s AS %(alias)s",
src=change_equivalence_dict[col_name],
alias=SQL('"account_move_line.%s"', SQL(col_name)),
))
else:
col_meta = field_metadata[col_name]
if col_meta.get("translate"):
pg_type = SQL('jsonb')
else:
pg_type = SQL(
self.env['account.move.line']._fields[col_name].column_type[0]
)
select_parts.append(SQL(
"CAST(NULL AS %(pg_type)s) AS %(alias)s",
pg_type=pg_type,
alias=SQL('"account_move_line.%s"', SQL(col_name)),
))
insert_cols = SQL(', ').join(SQL.identifier(c) for c in db_columns)
select_clause = SQL(', ').join(select_parts)
return insert_cols, select_clause