import ast from odoo import models # Journal types that represent liquidity accounts (bank, cash, credit card) LIQUIDITY_JOURNAL_TYPES = ('bank', 'cash', 'credit') class AccountJournal(models.Model): """Extends account.journal to add bank reconciliation dashboard actions. Provides methods that link the journal dashboard cards to the bank reconciliation widget and related views, enabling quick navigation from the Accounting dashboard. """ _inherit = 'account.journal' # ------------------------------------------------------------------------- # Reconciliation actions # ------------------------------------------------------------------------- def action_open_reconcile(self): """Open the appropriate reconciliation view for this journal. For liquidity journals (bank / cash / credit), opens the bank reconciliation widget filtered to show only unmatched statement lines belonging to this journal. For all other journal types (sale, purchase, general …), opens the list of posted but unreconciled journal items so the user can manually reconcile them. Returns: dict: A window action descriptor. """ self.ensure_one() if self.type in LIQUIDITY_JOURNAL_TYPES: reconcile_ctx = { 'default_journal_id': self.id, 'search_default_journal_id': self.id, 'search_default_not_matched': True, } stmt_line_model = self.env['account.bank.statement.line'] return stmt_line_model._action_open_bank_reconciliation_widget( default_context=reconcile_ctx, ) # Non-liquidity journals: show unreconciled move lines xml_ref = 'fusion_accounting.action_move_line_posted_unreconciled' return self.env['ir.actions.act_window']._for_xml_id(xml_ref) def action_open_to_check(self): """Open bank reconciliation showing only items flagged for review. Navigates to the bank reconciliation widget with the *to check* search filter enabled so the user sees only statement lines that were flagged during import or matching. Returns: dict: A window action descriptor. """ self.ensure_one() review_ctx = { 'default_journal_id': self.id, 'search_default_journal_id': self.id, 'search_default_to_check': True, } stmt_line_model = self.env['account.bank.statement.line'] return stmt_line_model._action_open_bank_reconciliation_widget( default_context=review_ctx, ) def action_open_bank_transactions(self): """Open a flat list of all bank transactions for this journal. Unlike the default kanban-first reconciliation view, this method forces the list view to appear first, giving the user a tabular overview of every transaction. Returns: dict: A window action descriptor. """ self.ensure_one() txn_ctx = { 'default_journal_id': self.id, 'search_default_journal_id': self.id, } stmt_line_model = self.env['account.bank.statement.line'] return stmt_line_model._action_open_bank_reconciliation_widget( default_context=txn_ctx, kanban_first=False, ) def action_open_reconcile_statement(self): """Open bank reconciliation for a single statement. The target statement id is expected in the environment context under the key ``statement_id``. This is typically set by a button on the bank statement form or dashboard. Returns: dict: A window action descriptor. """ target_statement_id = self.env.context.get('statement_id') stmt_ctx = { 'search_default_statement_id': target_statement_id, } stmt_line_model = self.env['account.bank.statement.line'] return stmt_line_model._action_open_bank_reconciliation_widget( default_context=stmt_ctx, ) # ------------------------------------------------------------------------- # Dashboard open_action override # ------------------------------------------------------------------------- def open_action(self): """Route the dashboard click to the bank reconciliation widget. When the user clicks on a liquidity journal card in the Accounting dashboard and no specific ``action_name`` has been provided in the context, redirect to the bank reconciliation widget filtered for this journal's default account. For every other case the standard behaviour is preserved by delegating to ``super()``. Returns: dict: A window action descriptor. """ is_liquidity = self.type in LIQUIDITY_JOURNAL_TYPES has_explicit_action = self.env.context.get('action_name') if is_liquidity and not has_explicit_action: self.ensure_one() account_filter = [ ('line_ids.account_id', '=', self.default_account_id.id), ] widget_ctx = { 'default_journal_id': self.id, 'search_default_journal_id': self.id, } stmt_line_model = self.env['account.bank.statement.line'] return stmt_line_model._action_open_bank_reconciliation_widget( extra_domain=account_filter, default_context=widget_ctx, ) return super().open_action() # ------------------------------------------------------------------------- # Dashboard data helpers # ------------------------------------------------------------------------- def _fill_general_dashboard_data(self, dashboard_data): """Augment general-journal dashboard data with tax periodicity flag. For journals of type *general*, adds the boolean key ``is_account_tax_periodicity_journal`` that indicates whether the journal is the company's designated tax-closing journal. Args: dashboard_data (dict): Mapping of journal id -> dashboard data dict, mutated in place. """ super()._fill_general_dashboard_data(dashboard_data) general_journals = self.filtered(lambda j: j.type == 'general') for jrnl in general_journals: tax_journal = jrnl.company_id._get_tax_closing_journal() is_tax_periodicity = jrnl == tax_journal dashboard_data[jrnl.id]['is_account_tax_periodicity_journal'] = is_tax_periodicity # ------------------------------------------------------------------------- # General Ledger shortcut # ------------------------------------------------------------------------- def action_open_bank_balance_in_gl(self): """Open the General Ledger report pre-filtered to this journal's bank account. Loads the General Ledger action and injects the default account code filter so the report immediately displays only the lines relevant to the journal's primary account. Returns: dict: A window action descriptor for the General Ledger report. """ self.ensure_one() gl_action_ref = 'fusion_accounting.action_account_report_general_ledger' gl_action = self.env['ir.actions.actions']._for_xml_id(gl_action_ref) # Merge the account filter into the existing action context existing_ctx = ast.literal_eval(gl_action.get('context', '{}')) existing_ctx['default_filter_accounts'] = self.default_account_id.code gl_action['context'] = existing_ctx return gl_action