1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/account_consolidation/models/consolidation_journal.py
2024-12-10 09:04:09 +07:00

200 lines
9.8 KiB
Python

# -*- coding: utf-8 -*-
import collections
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
class ConsolidationJournal(models.Model):
_name = "consolidation.journal"
_description = "Consolidation Journal"
_order = 'company_period_id asc, id asc'
name = fields.Char(string='Name', required=True)
period_id = fields.Many2one('consolidation.period', string="Analysis Period", ondelete="cascade")
chart_id = fields.Many2one('consolidation.chart', string="Chart", required=True, ondelete='cascade')
company_period_id = fields.Many2one('consolidation.company_period', string="Company Period", required=False,
copy=False)
state = fields.Selection(related="period_id.state", readonly=True)
# CHART currency id
currency_id = fields.Many2one('res.currency', related="period_id.chart_id.currency_id", readonly=True)
composition_id = fields.Many2one('consolidation.period.composition', string="Consolidation Period",
required=False, copy=False)
line_ids = fields.One2many('consolidation.journal.line', 'journal_id', 'Consolidation items')
auto_generated = fields.Boolean(default=False, string="Automatically Generated", readonly=True, copy=False)
balance = fields.Monetary(compute="_compute_balance", string="Balance", readonly=True)
# Originating company period or composition fields
originating_currency_id = fields.Many2one('res.currency', compute="_compute_originating_fields", readonly=True)
rate_consolidation = fields.Float(compute="_compute_originating_fields", string='Consolidation Rate', readonly=True)
currencies_are_different = fields.Boolean(compute="_compute_currencies_are_different", readonly=True)
# CONSTRAINTS
@api.constrains('company_period_id', 'composition_id')
def _check_unique_origin(self):
"""
Check that the journal have only been generated by a company period OR a composition OR neither.
"""
for record in self:
if record.company_period_id and record.composition_id:
raise ValidationError(_('A journal entry should only be linked to a company period OR to a analysis period of another consolidation!'))
@api.constrains('period_id')
def _check_not_locked_period(self):
"""
Prevent the addition of journals to a already closed analysis period.
"""
for record in self:
if record.period_id and record.period_id.state == 'closed':
raise ValidationError(_('You cannot add journals to a closed period!'))
@api.constrains('period_id', 'chart_id')
def _check_chart_id(self):
for record in self:
if record.period_id and record.chart_id != record.period_id.chart_id:
raise ValidationError(_("When setting a period on a consolidation journal, the selected consolidation chart for the journal cannot be different from the one of the chosen period."))
# COMPUTEDS
@api.depends('line_ids')
def _compute_balance(self):
"""
Compute the total balance of the journal
"""
JournalLine = self.env['consolidation.journal.line']
journal_lines = JournalLine._read_group([('journal_id', 'in', self.ids)], ['journal_id'],
['amount:sum'])
amounts = {journal.id: amount for journal, amount in journal_lines}
for record in self:
record.balance = amounts.get(record.id, 0)
@api.depends('company_period_id', 'composition_id')
def _compute_originating_fields(self):
"""
Compute the fields which are base on the origin of the journal (composition_id or company_period_id) :
rate_consolidation and originating_currency_id.
:return:
"""
for record in self:
if record.company_period_id:
record.originating_currency_id = record.company_period_id.currency_company_id
record.rate_consolidation = record.company_period_id.rate_consolidation
else:
record.originating_currency_id = record.composition_id.using_chart_currency_id
record.rate_consolidation = record.composition_id.rate_consolidation
@api.depends('originating_currency_id', 'currency_id')
def _compute_currencies_are_different(self):
"""
Compute if the currencies (the one from the origin and the one from the record itself) are different.
"""
for record in self:
record.currencies_are_different = record.currency_id != record.originating_currency_id
@api.onchange('period_id')
def _onchange_period_id(self):
if self.period_id:
self.chart_id = self.period_id.chart_id
# ACTIONS
def action_generate_journal_lines(self):
"""
Re(generate) all the journals of the recordset. It won't affect journals linked to closed analysis periods.
"""
self.check_access_rule('write')
self.check_access_rights('write')
for record in self:
if record.state == 'closed':
continue
record.line_ids.with_context(allow_unlink=True).unlink()
origin = record.company_period_id or record.composition_id
# compute journal lines in sudo since it needs to browse several companies
journal_line_values = origin.sudo()._get_journal_lines_values()
record.write({'line_ids': [(0, 0, value) for value in journal_line_values]})
class ConsolidationJournalLine(models.Model):
_name = "consolidation.journal.line"
_description = "Consolidation journal line"
note = fields.Text(string='Description', required=False)
journal_id = fields.Many2one('consolidation.journal', string="Journal", ondelete='restrict', required=True)
account_id = fields.Many2one('consolidation.account', string="Consolidated Account", required=True)
group_id = fields.Many2one('consolidation.group', related="account_id.group_id",
string="Group", store=True)
period_id = fields.Many2one('consolidation.period', related="journal_id.period_id",
string="Period", store=True)
auto_generated = fields.Boolean(related="journal_id.auto_generated")
currency_amount = fields.Monetary(string="Currency Amount", currency_field='chart_currency_id')
journal_originating_currency_id = fields.Many2one('res.currency', related="journal_id.originating_currency_id",
readonly=True)
amount = fields.Monetary(string="Amount", currency_field='chart_currency_id')
chart_currency_id = fields.Many2one('res.currency', related="account_id.chart_id.currency_id", readonly=True)
# GENERATED FROM when the journal is generated by a company period (AUDIT)
move_line_ids = fields.Many2many('account.move.line')
@api.constrains('account_id', 'journal_id')
def _check_conditional_unicity(self):
"""
Check that the journal line is unique by account and autogenerated journal
EXCEPT if the account is in historical currency mode.
"""
existings = {}
for record in self:
if record.journal_id and record.account_id and record.journal_id.auto_generated and record.account_id.currency_mode != 'hist':
domain = [('account_id', '=', record.account_id.id), ('journal_id', '=', record.journal_id.id)]
if record.id:
domain.append(('id', '!=', record.id))
if existings.get((record.journal_id, record.account_id), False) or record.search(domain):
raise ValidationError(_('Only one entry by account should be created for a generated journal entry!'))
existings[(record.journal_id, record.account_id)] = True
# ORM OVERRIDES
def write(self, vals):
if self.journal_id and self.journal_id.auto_generated:
raise UserError(_("You can't edit an auto-generated journal entry."))
return super().write(vals)
@api.ondelete(at_uninstall=False)
def _unlink_except_autogenerated(self):
if not self.env.context.get('allow_unlink', False) and self.journal_id and self.journal_id.auto_generated:
raise UserError(_("You can't delete an auto-generated journal entry."))
# GRID OVERRIDES
@api.model
def grid_update_cell(self, domain, measure_field_name, value):
account_id = self._context.get("default_account_id", False)
journal_id = self._context.get("default_journal_id", False)
if not (account_id and journal_id):
return # The grid view is just editable if account is in the row and journal_id is in the column
journal = self.env["consolidation.journal"].browse(journal_id)
if journal.auto_generated:
raise UserError(_("You can't edit an auto-generated journal entry."))
self.create([{
"account_id": account_id,
"journal_id": journal_id,
"note": "Trial balance adjustment",
measure_field_name: value,
}])
# PROTECTEDS
def _journal_is_editable(self, row_domain, column_field, column_value):
"""
Determine if a journal is editable based on a cell, even if no journal line object is linked to it.
:param row_domain: the row's domain
:type row_domain: list
:param column_field: the column field
:type column_field: str
:param column_value: the value for column_field determining the column
:return: True if editable, False otherwise
:rtype: bool
"""
if column_field == 'journal_id':
res = self.env['consolidation.journal'].search([('id', '=', column_value)])
return len(res) == 1 and not res[0].auto_generated
return True