-
Notifications
You must be signed in to change notification settings - Fork 36
[ADD] account_reconcile_bg: background processing for large bank reconciliations #400
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| Account Reconcile Background | ||
| ============================ | ||
|
|
||
| This module enables background processing for bank reconciliation operations when dealing with large payment batches, preventing timeouts and improving user experience. | ||
|
|
||
| **Table of contents** | ||
|
|
||
| .. contents:: | ||
| :local: | ||
|
|
||
| Overview | ||
| ======== | ||
|
|
||
| When reconciling large payment batches (e.g., multiple payments included in a single batch) with a bank statement line, the operation can take a long time and may cause timeouts. This module solves this problem by automatically processing large reconciliations in the background, allowing users to continue working while the reconciliation completes. | ||
|
|
||
| Features | ||
| ======== | ||
|
|
||
| * **Automatic Background Processing**: Large reconciliations are automatically sent to background processing | ||
| * **Configurable Threshold**: System parameter to control when background processing kicks in (default: 50 lines) | ||
| * **User Notifications**: Users receive notifications when background reconciliation completes | ||
| * **No UI Blocking**: Users can continue reconciling other transactions while large batches process | ||
| * **Seamless Integration**: Works transparently with existing bank reconciliation workflow | ||
|
|
||
| How It Works | ||
| ============ | ||
|
|
||
| The module monitors the number of lines being reconciled in the bank reconciliation widget: | ||
|
|
||
| 1. When validating a reconciliation, it counts the number of source lines | ||
| 2. If the count is **below the threshold** (default 50), the reconciliation proceeds normally (synchronous) | ||
| 3. If the count is **above the threshold**, the reconciliation is enqueued as a background job | ||
| 4. The user receives an immediate success notification and can continue working | ||
| 5. When the background job completes, the user is notified via internal message | ||
|
|
||
| Configuration | ||
| ============= | ||
|
|
||
| The threshold for background processing can be configured via system parameters: | ||
|
|
||
| * Navigate to **Settings > Technical > Parameters > System Parameters** | ||
| * Find or create the parameter ``account_reconcile_bg.lines_threshold`` | ||
| * Default value: ``50`` | ||
| * Set to a higher value to process larger reconciliations synchronously | ||
| * Set to a lower value to send more reconciliations to background | ||
|
|
||
| Technical Details | ||
| ================= | ||
|
|
||
| Dependencies | ||
| ------------ | ||
|
|
||
| * ``account_accountant``: Odoo Enterprise accounting module with bank reconciliation | ||
| * ``base_bg``: Background job processing system | ||
|
|
||
| Model Inheritance | ||
| ----------------- | ||
|
|
||
| The module inherits from ``bank.rec.widget`` and overrides: | ||
|
|
||
| * ``_js_action_validate()``: Detects large reconciliations and routes to background | ||
| * ``_validate_in_background()``: Enqueues the job using base_bg | ||
| * ``_do_validate()``: Executes the actual validation in background | ||
|
|
||
| Credits | ||
| ======= | ||
|
|
||
| Authors | ||
| ------- | ||
|
|
||
| * ADHOC SA | ||
|
|
||
| Contributors | ||
| ------------ | ||
|
|
||
| * ADHOC SA | ||
|
|
||
| Maintainers | ||
| ----------- | ||
|
|
||
| This module is maintained by ADHOC SA. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
| from . import models |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| ############################################################################## | ||
| # | ||
| # Copyright (C) 2026 ADHOC SA (http://www.adhoc.com.ar) | ||
| # All Rights Reserved. | ||
| # | ||
| # This program is free software: you can redistribute it and/or modify | ||
| # it under the terms of the GNU Affero General Public License as | ||
| # published by the Free Software Foundation, either version 3 of the | ||
| # License, or (at your option) any later version. | ||
| # | ||
| # This program is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU Affero General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU Affero General Public License | ||
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| # | ||
| ############################################################################## | ||
| { | ||
| "name": "Account Reconcile Background", | ||
| "version": "18.0.1.0.0", | ||
| "category": "Accounting", | ||
| "author": "ADHOC SA", | ||
| "website": "https://www.adhoc.com.ar", | ||
| "license": "AGPL-3", | ||
| "summary": "Process bank reconciliation in background for large payment batches", | ||
| "depends": [ | ||
| "account_accountant", | ||
| "base_bg", | ||
| ], | ||
| "data": [ | ||
| "data/ir_config_parameter_data.xml", | ||
| ], | ||
| "installable": True, | ||
| "auto_install": False, | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <odoo> | ||
|
|
||
| <!-- Parámetro de configuración para el umbral de líneas --> | ||
| <record id="config_lines_threshold" model="ir.config_parameter"> | ||
| <field name="key">account_reconcile_bg.lines_threshold</field> | ||
| <field name="value">100</field> | ||
| </record> | ||
|
|
||
| </odoo> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
| from . import bank_rec_widget | ||
| from . import account_bank_statement_line | ||
| from . import account_move_line | ||
| from . import bg_job |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ############################################################################## | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # For copyright and license notices, see __manifest__.py file in module root | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # directory | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ############################################################################## | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import logging | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from markupsafe import Markup | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from odoo import _, api, fields, models | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from odoo.exceptions import UserError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class AccountBankStatementLine(models.Model): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _inherit = "account.bank.statement.line" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reconciliation_in_background = fields.Boolean( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string="Reconciliation in Background", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| readonly=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| help="Indicates that this line is being reconciled in background", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _bg_validate_reconciliation(self, selected_aml_ids=None): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Método ejecutado en background para validar la conciliación. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Se llama desde el job de base_bg. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :param selected_aml_ids: IDs de las líneas seleccionadas por el usuario | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.ensure_one() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _logger = logging.getLogger(__name__) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Preparar datos para mensaje | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| base_url = self.env["ir.config_parameter"].sudo().get_param("web.base.url") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| st_line_url = f"{base_url}/odoo/account.bank.statement.line/{self.id}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| st_line_name = self.name or f"Line {self.id}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Crear el widget de conciliación | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wizard = self.env["bank.rec.widget"].with_context(default_st_line_id=self.id).new({}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _logger.info(f"[BG] Wizard created for st_line {self.id}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Agregar las líneas al widget correctamente usando el método interno | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if selected_aml_ids: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| amls = self.env["account.move.line"].browse(selected_aml_ids) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wizard._action_add_new_amls(amls, allow_partial=False) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Ejecutar la validación con el context manager | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with wizard._action_validate_method(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wizard._action_validate() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wizard._action_validate() | |
| wizard._action_validate() | |
| return self.env._( | |
| "Reconciliation completed for statement line %s." | |
| ) % self.display_name |
Copilot
AI
Apr 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
El job en background solo reconstruye el widget con default_st_line_id, pero no persiste ni reinyecta la selección del usuario (AMLs elegidas en el widget) antes de validar. Esto puede hacer que el job concilie algo distinto, no concilie nada, o falle, porque no está reproduciendo el estado con el que el usuario presionó "Validar". Recomendación: al encolar, guardar/pasar los selected_aml_ids (o el payload necesario) y en _bg_validate_reconciliation reconstruir line_ids/selección antes de ejecutar _action_validate().
| def _bg_validate_reconciliation(self): | |
| """ | |
| Método ejecutado en background para validar la conciliación. | |
| Se llama desde el job de base_bg. | |
| """ | |
| self.ensure_one() | |
| try: | |
| # Crear el widget de conciliación | |
| wizard = self.env["bank.rec.widget"].with_context(default_st_line_id=self.id).new({}) | |
| # Ejecutar la validación | |
| with wizard._action_validate_method(): | |
| wizard._action_validate() | |
| finally: | |
| # Siempre limpiar el flag al terminar (éxito o error) | |
| self.write({"reconciliation_in_background": False}) | |
| reconciliation_selected_aml_ids = fields.Json( | |
| readonly=True, | |
| help="Technical field used to preserve the AML selection for background reconciliation", | |
| ) | |
| def _bg_get_selected_aml_ids(self, selected_aml_ids=None): | |
| self.ensure_one() | |
| aml_ids = ( | |
| selected_aml_ids | |
| if selected_aml_ids is not None | |
| else self.reconciliation_selected_aml_ids | |
| ) or [] | |
| return [int(aml_id) for aml_id in aml_ids if aml_id] | |
| def _bg_apply_selected_aml_ids_to_widget(self, wizard, selected_aml_ids): | |
| self.ensure_one() | |
| if not selected_aml_ids or not wizard.line_ids: | |
| return | |
| selected_aml_ids = set(selected_aml_ids) | |
| matched_lines = self.env[wizard.line_ids._name] | |
| for line in wizard.line_ids: | |
| aml_id = False | |
| for field_name in ("aml_id", "move_line_id", "account_move_line_id"): | |
| if field_name in line._fields and line[field_name]: | |
| aml_id = line[field_name].id | |
| break | |
| if aml_id and aml_id in selected_aml_ids: | |
| matched_lines |= line | |
| if not matched_lines: | |
| return | |
| if "is_selected" in matched_lines._fields: | |
| (wizard.line_ids - matched_lines).write({"is_selected": False}) | |
| matched_lines.write({"is_selected": True}) | |
| else: | |
| wizard.line_ids = matched_lines | |
| def _bg_validate_reconciliation(self, selected_aml_ids=None): | |
| """ | |
| Método ejecutado en background para validar la conciliación. | |
| Se llama desde el job de base_bg. | |
| """ | |
| self.ensure_one() | |
| selected_aml_ids = self._bg_get_selected_aml_ids(selected_aml_ids) | |
| try: | |
| # Crear el widget de conciliación | |
| wizard = self.env["bank.rec.widget"].with_context( | |
| default_st_line_id=self.id | |
| ).new({}) | |
| # Reinyectar la selección original del usuario antes de validar | |
| self._bg_apply_selected_aml_ids_to_widget(wizard, selected_aml_ids) | |
| # Ejecutar la validación | |
| with wizard._action_validate_method(): | |
| wizard._action_validate() | |
| finally: | |
| # Siempre limpiar el flag al terminar (éxito o error) | |
| self.write( | |
| { | |
| "reconciliation_in_background": False, | |
| "reconciliation_selected_aml_ids": False, | |
| } | |
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| ############################################################################## | ||
| # For copyright and license notices, see __manifest__.py file in module root | ||
| # directory | ||
| ############################################################################## | ||
| from odoo import fields, models | ||
|
|
||
|
|
||
| class AccountMoveLine(models.Model): | ||
| _inherit = "account.move.line" | ||
|
|
||
| reconciliation_in_background = fields.Boolean( | ||
| string="Reconciliation in Background", | ||
| default=False, | ||
| readonly=True, | ||
| help="Indicates that this line is being reconciled in background", | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| ############################################################################## | ||
| # For copyright and license notices, see __manifest__.py file in module root | ||
| # directory | ||
| ############################################################################## | ||
| import logging | ||
|
|
||
| from odoo import _, models | ||
| from odoo.exceptions import UserError | ||
|
|
||
|
|
||
| class BankRecWidget(models.Model): | ||
| _inherit = "bank.rec.widget" | ||
|
|
||
| def _js_action_validate(self): | ||
| """ | ||
| Override para procesar conciliaciones grandes en background. | ||
| Si hay muchas líneas (> threshold), usa base_bg para procesarlo en 2do plano. | ||
| """ | ||
| self.ensure_one() | ||
|
|
||
| # Verificar si ya está procesando en background | ||
| if self.st_line_id.reconciliation_in_background: | ||
| raise UserError( | ||
| _("This reconciliation is already being processed in background. Please wait until it finishes.") | ||
| ) | ||
|
|
||
| # Invalidar caché y refrescar para obtener el estado actual desde la BD | ||
| self.selected_aml_ids.invalidate_recordset(fnames=["reconciliation_in_background"]) | ||
|
|
||
| # Verificar si alguna de las líneas seleccionadas ya está en background (en cualquier extracto) | ||
| lines_in_bg = self.selected_aml_ids.filtered("reconciliation_in_background") | ||
| if lines_in_bg: | ||
| raise UserError( | ||
| _( | ||
| "Some of the selected payment lines (%s) are already being reconciled in background on another statement. " | ||
| "Please wait until they finish or select different lines." | ||
| ) | ||
| % len(lines_in_bg) | ||
| ) | ||
|
|
||
| # Obtener el umbral de líneas desde parámetros del sistema (default: 50) | ||
| threshold = int(self.env["ir.config_parameter"].sudo().get_param("account_reconcile_bg.lines_threshold", "50")) | ||
|
|
||
| # Contar las líneas seleccionadas para conciliar | ||
| lines_count = len(self.selected_aml_ids) | ||
|
Comment on lines
+41
to
+45
|
||
|
|
||
| # DEBUG: Log para verificar | ||
|
|
||
| # Si hay pocas líneas, ejecutar el proceso normal de manera sincrónica | ||
| if lines_count < threshold: | ||
| return super()._js_action_validate() | ||
|
Comment on lines
+47
to
+51
|
||
|
|
||
| # Si hay muchas líneas, procesar en background | ||
| return self._validate_in_background() | ||
|
|
||
| def _validate_in_background(self): | ||
| """ | ||
| Encola la validación de conciliación en background usando base_bg. | ||
| Nota: Como bank.rec.widget no se persiste, encolamos usando st_line_id. | ||
| """ | ||
| self.ensure_one() | ||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
| # Marcar la línea de extracto y las líneas de pago como procesando en background | ||
| self.st_line_id.write({"reconciliation_in_background": True}) | ||
| self.selected_aml_ids.write({"reconciliation_in_background": True}) | ||
|
|
||
| # Flush para asegurar que los cambios se escriben inmediatamente en la BD | ||
| # Esto previene condiciones de carrera donde otro usuario podría conciliar las mismas líneas | ||
| self.env.flush_all() | ||
|
|
||
| # Capturar los IDs antes de encolar | ||
| selected_ids = self.selected_aml_ids.ids | ||
| _logger.info(f"[account_reconcile_bg] Capturing selected_aml_ids: {selected_ids}") | ||
|
|
||
| try: | ||
| # Encolar el job usando la línea de extracto (modelo persistente) | ||
| _action, _jobs = self.env["base.bg"].bg_enqueue_records( | ||
| self.st_line_id, | ||
| "_bg_validate_reconciliation", | ||
| threshold=1, # Un job por línea | ||
| name=_("Bank Reconciliation: %s") % self.st_line_id.name, | ||
| priority=5, # Alta prioridad | ||
| selected_aml_ids=selected_ids, # Pasar solo los IDs (lista de enteros) | ||
| ) | ||
| _logger.info("[account_reconcile_bg] Job enqueued successfully") | ||
| except Exception: | ||
| # Si falla al encolar, limpiar los flags | ||
| self.st_line_id.write({"reconciliation_in_background": False}) | ||
| self.selected_aml_ids.write({"reconciliation_in_background": False}) | ||
| raise | ||
|
|
||
| # Enviar notificación al usuario usando el bus | ||
| self.env["bus.bus"]._sendone( | ||
| self.env.user.partner_id, | ||
| "simple_notification", | ||
| { | ||
| "type": "success", | ||
| "message": _( | ||
| "This reconciliation is being processed in background. You will be notified when it's done." | ||
| ), | ||
| }, | ||
| ) | ||
|
|
||
| # Configurar el comando para el widget | ||
| self.return_todo_command = {"done": True} | ||
|
|
||
| # Retornar vacío - el widget usa return_todo_command | ||
| return | ||
|
|
||
| def _do_validate(self): | ||
| """ | ||
| Método que ejecuta la validación real en background. | ||
| Se llama desde el job de base_bg. | ||
| """ | ||
| self.ensure_one() | ||
| # Ejecutar la validación usando el método context manager | ||
| with self._action_validate_method(): | ||
| self._action_validate() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
La documentación técnica indica que el job ejecuta
bank.rec.widget._do_validate(), pero el código en realidad encolaaccount.bank.statement.line._bg_validate_reconciliation()y no usa_do_validate. Esto hace que el README quede inconsistente con la implementación (y también con la guía de tests). Sugerencia: actualizar el README para reflejar el método/modelo real del job, o cambiar el código para que el job invoque efectivamente_do_validatesi ese era el diseño.