You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
6.2 KiB
Python

# -*- coding: utf-8 -*-
from odoo import _, api, fields, models
from dateutil.relativedelta import relativedelta
class AccountBankStatement(models.Model):
_inherit = 'account.bank.statement'
def action_open_bank_reconcile_widget(self):
self.ensure_one()
return self.env['account.bank.statement.line']._action_open_bank_reconciliation_widget(
name=self.name,
default_context={
'default_statement_id': self.id,
'default_journal_id': self.journal_id.id,
},
extra_domain=[('statement_id', '=', self.id)]
)
class AccountBankStatementLine(models.Model):
_inherit = 'account.bank.statement.line'
# Technical field holding the date of the last time the cron tried to auto-reconcile the statement line. Used to
# optimize the bank matching process"
cron_last_check = fields.Datetime()
def action_save_close(self):
return {'type': 'ir.actions.act_window_close'}
def action_save_new(self):
action = self.env['ir.actions.act_window']._for_xml_id('account_accountant.action_bank_statement_line_form_bank_rec_widget')
action['context'] = {'default_journal_id': self._context['default_journal_id']}
return action
@api.model
def _action_open_bank_reconciliation_widget(self, extra_domain=None, default_context=None, name=None):
context = default_context or {}
return {
'name': name or _("Bank Reconciliation"),
'type': 'ir.actions.act_window',
'res_model': 'account.bank.statement.line',
'context': context,
'search_view_id': [self.env.ref('account_accountant.view_bank_statement_line_search_bank_rec_widget').id, 'search'],
'view_mode': 'kanban,list',
'views': [
(self.env.ref('account_accountant.view_bank_statement_line_kanban_bank_rec_widget').id, 'kanban'),
(self.env.ref('account_accountant.view_bank_statement_line_tree_bank_rec_widget').id, 'list'),
],
'domain': [('state', '!=', 'cancel')] + (extra_domain or []),
}
def action_open_recon_st_line(self):
self.ensure_one()
return self.env['account.bank.statement.line']._action_open_bank_reconciliation_widget(
name=self.name,
default_context={
'default_statement_id': self.statement_id.id,
'default_journal_id': self.journal_id.id,
'default_st_line_id': self.id,
'search_default_id': self.id,
},
)
@api.model
def _cron_try_auto_reconcile_statement_lines(self, batch_size=None):
""" Method called by the CRON to reconcile the statement lines automatically.
:param batch_size: The maximum number of statement lines that could be processed at once by the CRON to avoid
a timeout. If specified, the CRON will be trigger again asap using a CRON trigger in case
there is still some statement lines to process.
"""
self.env['account.reconcile.model'].flush_model()
# Check the companies having at least one reconcile model using the 'auto_reconcile' feature.
query_obj = self.env['account.reconcile.model']._search([
('auto_reconcile', '=', True),
('rule_type', 'in', ('writeoff_suggestion', 'invoice_matching')),
])
query_obj.order = 'company_id'
query_str, query_params = query_obj.select('DISTINCT company_id')
self._cr.execute(query_str, query_params)
configured_company_ids = [r[0] for r in self._cr.fetchall()]
if not configured_company_ids:
return
# Find the bank statement lines that are not reconciled and try to reconcile them automatically.
# The ones that are never be processed by the CRON before are processed first.
limit = batch_size + 1 if batch_size else None
has_more_st_lines_to_reconcile = False
datetime_now = fields.Datetime.now()
companies = self.env['res.company'].browse(configured_company_ids)
lock_dates = companies.filtered('fiscalyear_lock_date').mapped('fiscalyear_lock_date')
st_date_from_limit = max([datetime_now.date() - relativedelta(months=3)] + lock_dates)
self.env['account.bank.statement.line'].flush_model()
domain = [
('is_reconciled', '=', False),
('date', '>', st_date_from_limit),
('company_id', 'in', configured_company_ids),
]
query_obj = self._search(domain, order='cron_last_check DESC, id', limit=limit)
query_str, query_params = query_obj.select('account_bank_statement_line.id')
self._cr.execute(query_str, query_params)
st_line_ids = [r[0] for r in self._cr.fetchall()]
if batch_size and len(st_line_ids) > batch_size:
st_line_ids = st_line_ids[:batch_size]
has_more_st_lines_to_reconcile = True
st_lines = self.env['account.bank.statement.line'].browse(st_line_ids)
nb_auto_reconciled_lines = 0
for st_line in st_lines:
wizard = self.env['bank.rec.widget'].with_context(default_st_line_id=st_line.id).new({})
wizard._action_trigger_matching_rules()
if wizard.state == 'valid' and wizard.matching_rules_allow_auto_reconcile:
wizard.button_validate(async_action=False)
st_line.move_id.message_post(body=_(
"This bank transaction has been automatically validated using the reconciliation model '%s'.",
', '.join(st_line.move_id.line_ids.reconcile_model_id.mapped('name')),
))
nb_auto_reconciled_lines += 1
st_lines.write({'cron_last_check': datetime_now})
# The configuration seems effective since some lines has been automatically reconciled right now and there is
# some statement lines left.
if nb_auto_reconciled_lines and has_more_st_lines_to_reconcile:
self.env.ref('account_accountant.auto_reconcile_bank_statement_line')._trigger()