# -*- coding: UTF-8 -*- from odoo import api, fields, models, _, Command from odoo.exceptions import UserError class AccountBankStatement(models.Model): _inherit = "account.bank.statement" # _description = "Bank Statement" # _order = "first_line_index desc" # _check_company_auto = True state = fields.Selection(string='Status', required=True, readonly=True, copy=False, selection=[ ('open', 'New'), ('posted', 'Processing'), ('confirm', 'Validated'), ], default='open', help="The current state of your bank statement:" "- New: Fully editable with draft Journal Entries." "- Processing: No longer editable with posted Journal entries, ready for the reconciliation." "- Validated: All lines are reconciled. There is nothing left to process.") all_lines_reconciled = fields.Boolean(compute='_compute_all_lines_reconciled', help="Technical field indicating if all statement lines are fully reconciled.") line_ids = fields.One2many('account.bank.statement.line', 'statement_id', string='Statement lines', states={'confirm': [('readonly', True)]}, copy=True) move_line_count = fields.Integer(compute="_get_move_line_count") move_line_ids = fields.One2many('account.move.line', 'statement_id', string='Entry lines', states={'confirm': [('readonly', True)]}) country_code = fields.Char(related='company_id.country_id.code') previous_statement_id = fields.Many2one('account.bank.statement', help='technical field to compute starting balance correctly', compute='_get_previous_statement', store=True) is_valid_balance_start = fields.Boolean(string="Is Valid Balance Start", store=True, compute="_compute_is_valid_balance_start", help="Technical field to display a warning message in case starting balance is different than previous ending balance") journal_type = fields.Selection(related='journal_id.type', help="Technical field used for usability purposes") cashbox_start_id = fields.Many2one('account.bank.statement.cashbox', string="Starting Cashbox") cashbox_end_id = fields.Many2one('account.bank.statement.cashbox', string="Ending Cashbox") @api.depends('line_ids.is_reconciled') def _compute_all_lines_reconciled(self): for statement in self: statement.all_lines_reconciled = all(st_line.is_reconciled for st_line in statement.line_ids) @api.depends('move_line_ids') def _get_move_line_count(self): for statement in self: statement.move_line_count = len(statement.move_line_ids) @api.depends('date', 'journal_id') def _get_previous_statement(self): for st in self: # Search for the previous statement domain = [('date', '<=', st.date), ('journal_id', '=', st.journal_id.id)] # The reason why we have to perform this test is because we have two use case here: # First one is in case we are creating a new record, in that case that new record does # not have any id yet. However if we are updating an existing record, the domain date <= st.date # will find the record itself, so we have to add a condition in the search to ignore self.id if not isinstance(st.id, models.NewId): domain.extend(['|', '&', ('id', '<', st.id), ('date', '=', st.date), '&', ('id', '!=', st.id), ('date', '!=', st.date)]) previous_statement = self.search(domain, limit=1) st.previous_statement_id = previous_statement.id @api.depends('balance_start', 'previous_statement_id') def _compute_is_valid_balance_start(self): for bnk in self: bnk.is_valid_balance_start = ( bnk.currency_id.is_zero( bnk.balance_start - bnk.previous_statement_id.balance_end_real ) if bnk.previous_statement_id else True ) def button_post(self): ''' Move the bank statements from 'draft' to 'posted'. ''' if any(statement.state != 'open' for statement in self): raise UserError(_("Only new statements can be posted.")) self._check_balance_end_real_same_as_computed() for statement in self: if not statement.name: statement._set_next_sequence() self.write({'state': 'posted'}) self.line_ids.move_id._post(soft=False) def button_validate_or_action(self): if self.journal_type == 'cash' and not self.currency_id.is_zero(self.difference): return self.env['ir.actions.act_window']._for_xml_id('account.action_view_account_bnk_stmt_check') return self.button_validate() def button_reopen(self): ''' Move the bank statements back to the 'open' state. ''' if any(statement.state == 'draft' for statement in self): raise UserError(_("Only validated statements can be reset to new.")) self.write({'state': 'open'}) self.line_ids.move_id.button_draft() self.line_ids.button_undo_reconciliation() def button_reprocess(self): """Move the bank statements back to the 'posted' state.""" if any(statement.state != 'confirm' for statement in self): raise UserError(_("Only Validated statements can be reset to new.")) self.write({'state': 'posted', 'date_done': False}) def button_journal_entries(self): return { 'name': _('Journal Entries'), 'view_mode': 'tree,form', 'res_model': 'account.move', 'view_id': False, 'type': 'ir.actions.act_window', 'domain': [('id', 'in', self.line_ids.move_id.ids)], 'context': { 'journal_id': self.journal_id.id, } } def open_cashbox_id(self): self.ensure_one() context = dict(self.env.context or {}) if context.get('balance'): context['statement_id'] = self.id if context['balance'] == 'start': cashbox_id = self.cashbox_start_id.id elif context['balance'] == 'close': cashbox_id = self.cashbox_end_id.id else: cashbox_id = False action = { 'name': _('Cash Control'), 'view_mode': 'form', 'res_model': 'account.bank.statement.cashbox', 'view_id': self.env.ref('account.view_account_bnk_stmt_cashbox_footer').id, 'type': 'ir.actions.act_window', 'res_id': cashbox_id, 'context': context, 'target': 'new' } return action