|
| 1 | +############################################################################## |
| 2 | +# For copyright and license notices, see __manifest__.py file in module root |
| 3 | +# directory |
| 4 | +############################################################################## |
| 5 | +import logging |
| 6 | + |
| 7 | +from odoo import _, models |
| 8 | +from odoo.exceptions import UserError |
| 9 | + |
| 10 | + |
| 11 | +class BankRecWidget(models.Model): |
| 12 | + _inherit = "bank.rec.widget" |
| 13 | + |
| 14 | + def _js_action_validate(self): |
| 15 | + """ |
| 16 | + Override para procesar conciliaciones grandes en background. |
| 17 | + Si hay muchas líneas (> threshold), usa base_bg para procesarlo en 2do plano. |
| 18 | + """ |
| 19 | + self.ensure_one() |
| 20 | + |
| 21 | + # Verificar si ya está procesando en background |
| 22 | + if self.st_line_id.reconciliation_in_background: |
| 23 | + raise UserError( |
| 24 | + _("This reconciliation is already being processed in background. Please wait until it finishes.") |
| 25 | + ) |
| 26 | + |
| 27 | + # Invalidar caché y refrescar para obtener el estado actual desde la BD |
| 28 | + self.selected_aml_ids.invalidate_recordset(fnames=["reconciliation_in_background"]) |
| 29 | + |
| 30 | + # Verificar si alguna de las líneas seleccionadas ya está en background (en cualquier extracto) |
| 31 | + lines_in_bg = self.selected_aml_ids.filtered("reconciliation_in_background") |
| 32 | + if lines_in_bg: |
| 33 | + raise UserError( |
| 34 | + _( |
| 35 | + "Some of the selected payment lines (%s) are already being reconciled in background on another statement. " |
| 36 | + "Please wait until they finish or select different lines." |
| 37 | + ) |
| 38 | + % len(lines_in_bg) |
| 39 | + ) |
| 40 | + |
| 41 | + # Obtener el umbral de líneas desde parámetros del sistema (default: 50) |
| 42 | + threshold = int(self.env["ir.config_parameter"].sudo().get_param("account_reconcile_bg.lines_threshold", "50")) |
| 43 | + |
| 44 | + # Contar las líneas seleccionadas para conciliar |
| 45 | + lines_count = len(self.selected_aml_ids) |
| 46 | + |
| 47 | + # DEBUG: Log para verificar |
| 48 | + |
| 49 | + # Si hay pocas líneas, ejecutar el proceso normal de manera sincrónica |
| 50 | + if lines_count < threshold: |
| 51 | + return super()._js_action_validate() |
| 52 | + |
| 53 | + # Si hay muchas líneas, procesar en background |
| 54 | + return self._validate_in_background() |
| 55 | + |
| 56 | + def _validate_in_background(self): |
| 57 | + """ |
| 58 | + Encola la validación de conciliación en background usando base_bg. |
| 59 | + Nota: Como bank.rec.widget no se persiste, encolamos usando st_line_id. |
| 60 | + """ |
| 61 | + self.ensure_one() |
| 62 | + |
| 63 | + _logger = logging.getLogger(__name__) |
| 64 | + |
| 65 | + # Marcar la línea de extracto y las líneas de pago como procesando en background |
| 66 | + self.st_line_id.write({"reconciliation_in_background": True}) |
| 67 | + self.selected_aml_ids.write({"reconciliation_in_background": True}) |
| 68 | + |
| 69 | + # Flush para asegurar que los cambios se escriben inmediatamente en la BD |
| 70 | + # Esto previene condiciones de carrera donde otro usuario podría conciliar las mismas líneas |
| 71 | + self.env.flush_all() |
| 72 | + |
| 73 | + # Capturar los IDs antes de encolar |
| 74 | + selected_ids = self.selected_aml_ids.ids |
| 75 | + _logger.info(f"[account_reconcile_bg] Capturing selected_aml_ids: {selected_ids}") |
| 76 | + |
| 77 | + try: |
| 78 | + # Encolar el job usando la línea de extracto (modelo persistente) |
| 79 | + _action, _jobs = self.env["base.bg"].bg_enqueue_records( |
| 80 | + self.st_line_id, |
| 81 | + "_bg_validate_reconciliation", |
| 82 | + threshold=1, # Un job por línea |
| 83 | + name=_("Bank Reconciliation: %s") % self.st_line_id.name, |
| 84 | + priority=5, # Alta prioridad |
| 85 | + selected_aml_ids=selected_ids, # Pasar solo los IDs (lista de enteros) |
| 86 | + ) |
| 87 | + _logger.info("[account_reconcile_bg] Job enqueued successfully") |
| 88 | + except Exception: |
| 89 | + # Si falla al encolar, limpiar los flags |
| 90 | + self.st_line_id.write({"reconciliation_in_background": False}) |
| 91 | + self.selected_aml_ids.write({"reconciliation_in_background": False}) |
| 92 | + raise |
| 93 | + |
| 94 | + # Enviar notificación al usuario usando el bus |
| 95 | + self.env["bus.bus"]._sendone( |
| 96 | + self.env.user.partner_id, |
| 97 | + "simple_notification", |
| 98 | + { |
| 99 | + "type": "success", |
| 100 | + "message": _( |
| 101 | + "This reconciliation is being processed in background. You will be notified when it's done." |
| 102 | + ), |
| 103 | + }, |
| 104 | + ) |
| 105 | + |
| 106 | + # Configurar el comando para el widget |
| 107 | + self.return_todo_command = {"done": True} |
| 108 | + |
| 109 | + # Retornar vacío - el widget usa return_todo_command |
| 110 | + return |
| 111 | + |
| 112 | + def _do_validate(self): |
| 113 | + """ |
| 114 | + Método que ejecuta la validación real en background. |
| 115 | + Se llama desde el job de base_bg. |
| 116 | + """ |
| 117 | + self.ensure_one() |
| 118 | + # Ejecutar la validación usando el método context manager |
| 119 | + with self._action_validate_method(): |
| 120 | + self._action_validate() |
0 commit comments