forked from Mapan/odoo17e
200 lines
9.8 KiB
Python
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
|