from odoo import models, fields, api from odoo.exceptions import UserError class BankReconcileWizard(models.TransientModel): _name = 'bank.reconcile.wizard' _description = 'Bank Reconcile Wizard' bank_line_ids = fields.Many2many('account.bank.statement.line', string='Selected Bank Lines', readonly=True) journal_entry_id = fields.Many2one('account.move', string='Journal Entry to Reconcile', domain=[('state', '=', 'posted')]) journal_entry_line_id = fields.Many2one('account.move.line', string='Journal Entry Line to Reconcile', domain="[('move_id', '=', journal_entry_id), ('reconciled', '=', False)]") total_bank_line_amount = fields.Float(string='Total Bank Line Amount', compute='_compute_total_bank_line_amount', store=True) @api.onchange('journal_entry_id') def _onchange_journal_entry_id(self): """Reset journal entry line when journal entry changes""" if self.journal_entry_id: self.journal_entry_line_id = False else: self.journal_entry_line_id = False @api.depends('bank_line_ids') def _compute_total_bank_line_amount(self): """Compute total amount of selected bank lines""" for record in self: record.total_bank_line_amount = sum(line.amount for line in record.bank_line_ids) def action_reconcile(self): """Perform the reconciliation for each selected bank line""" if not self.journal_entry_id: raise UserError("Please select a journal entry to reconcile.") if not self.journal_entry_line_id: raise UserError("Please select a journal entry line to reconcile.") # Validate that the total of individual line amounts doesn't exceed the journal entry line amount journal_line_amount = self.journal_entry_line_id.debit or self.journal_entry_line_id.credit if len(self.bank_line_ids) > 1: total_bank_amount = sum(abs(line.amount) for line in self.bank_line_ids) if total_bank_amount > journal_line_amount: raise UserError(f"Total bank line amounts ({total_bank_amount}) cannot exceed the journal entry line amount ({journal_line_amount}).") # Process each selected bank line individually for bank_line in self.bank_line_ids: self._reconcile_single_line(bank_line, self.journal_entry_line_id) return {'type': 'ir.actions.act_window_close'} def _reconcile_single_line(self, bank_line, journal_entry_line): """Reconcile a single bank line with a journal entry line""" # Get the account from the journal entry line that will be on the opposite side reconcile_account = journal_entry_line.account_id # Use the individual bank line amount for each line reconcile_amount = abs(bank_line.amount) # According to requirement #5: if the bank line is debit, # then the new journal entry after reconcile will have that bank account in debit bank_account = bank_line.journal_id.default_account_id bank_line_amount = bank_line.amount # Determine if the bank line is debit (positive) or credit (negative) if bank_line_amount >= 0: # Bank line is debit (money coming in) # Bank account should be debited (requirement #5) debit_account = bank_account # The account from the selected journal entry line goes to credit (requirement #6) credit_account = reconcile_account else: # Bank line is credit (money going out) # Bank account should be credited credit_account = bank_account # The account from the selected journal entry line goes to debit debit_account = reconcile_account # Set the amounts - make sure they are balanced debit_amount = reconcile_amount credit_amount = reconcile_amount # Create a new journal entry for reconciliation with lines reconciling_move = self.env['account.move'].create({ 'journal_id': bank_line.journal_id.id, 'date': bank_line.date, 'ref': f'Reconciliation: {bank_line.name or "Bank Line"}', 'move_type': 'entry', 'line_ids': [ (0, 0, { 'account_id': debit_account.id, 'debit': debit_amount, 'credit': 0, 'name': f'Bank Reconciliation: {bank_line.name or ""}', }), (0, 0, { 'account_id': credit_account.id, 'debit': 0, 'credit': credit_amount, 'name': f'Bank Reconciliation: {bank_line.name or ""}', }) ] }) # Post the reconciling journal entry reconciling_move.action_post() # Link the bank line to the reconciling move bank_line.sudo().write({ 'move_id': reconciling_move.id, }) # Mark the bank line as reconciled in a separate operation bank_line.sudo().write({ 'is_reconciled': True, }) # Try to reconcile the selected journal entry line with the corresponding line in the reconciling move # Find the line in the reconciling move that has the same account as the journal entry line reconciling_line = reconciling_move.line_ids.filtered(lambda l: l.account_id.id == reconcile_account.id and l.credit > 0) # Try to reconcile the journal entry line with our reconciling line if reconciling_line: try: (journal_entry_line + reconciling_line).reconcile() except: # If reconcile fails, we'll just link the moves pass