diff --git a/account_mass_reconcile_as_job/models/base_reconciliation.py b/account_mass_reconcile_as_job/models/base_reconciliation.py index 9cefebd3..2a8fa0c7 100644 --- a/account_mass_reconcile_as_job/models/base_reconciliation.py +++ b/account_mass_reconcile_as_job/models/base_reconciliation.py @@ -4,7 +4,7 @@ import ast import logging -from odoo import models +from odoo import api, models _logger = logging.getLogger(__name__) @@ -12,12 +12,6 @@ _logger = logging.getLogger(__name__) class MassReconcileBase(models.AbstractModel): _inherit = "mass.reconcile.base" - # WARNING: this has limitation as it creates a job based on an object wizard - # when the transient model will be garbadge collected the job won't - # be able to run anymore. - # FIXME: move or copy wizard data configuration in a standard model or refactor - # to have it as a parameter. - def _reconcile_lines(self, lines, allow_partial=False): as_job = ( self.env["ir.config_parameter"] @@ -30,14 +24,22 @@ class MassReconcileBase(models.AbstractModel): as_job = False if as_job and self.env.context.get("reconcile_lines_as_job", True): + wiz_data = self.copy_data()[0] self.with_delay().reconcile_lines_as_job( lines, - allow_partial=allow_partial + allow_partial=allow_partial, + wiz_creation_data=(self._name, wiz_data), ) # Report is not available with reconcile jobs return False, False else: return super()._reconcile_lines(lines, allow_partial=allow_partial) - def reconcile_lines_as_job(self, lines, allow_partial=False): - self.with_context(reconcile_lines_as_job=False)._reconcile_lines(lines, allow_partial=allow_partial) + @api.model + def reconcile_lines_as_job( + self, lines, allow_partial=False, wiz_creation_data=False + ): + new_wiz = self.env[wiz_creation_data[0]].create(wiz_creation_data[1]) + return new_wiz.with_context(reconcile_lines_as_job=False)._reconcile_lines( + lines, allow_partial=allow_partial + ) diff --git a/account_mass_reconcile_as_job/tests/__init__.py b/account_mass_reconcile_as_job/tests/__init__.py index 111a97bc..0ff08edc 100644 --- a/account_mass_reconcile_as_job/tests/__init__.py +++ b/account_mass_reconcile_as_job/tests/__init__.py @@ -1 +1,2 @@ from . import test_mass_reconcile_as_job +from . import test_scenario_reconcile_as_job diff --git a/account_mass_reconcile_as_job/tests/test_scenario_reconcile_as_job.py b/account_mass_reconcile_as_job/tests/test_scenario_reconcile_as_job.py new file mode 100644 index 00000000..bcd39821 --- /dev/null +++ b/account_mass_reconcile_as_job/tests/test_scenario_reconcile_as_job.py @@ -0,0 +1,112 @@ +# Copyright 2022 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from odoo.tests import tagged + +from odoo.addons.account_mass_reconcile.tests.test_scenario_reconcile import ( + TestScenarioReconcile, +) +from odoo.addons.queue_job.tests.common import trap_jobs + + +@tagged("post_install", "-at_install") +class TestScenarioReconcileAsJob(TestScenarioReconcile): + def test_scenario_reconcile_as_job(self): + self.env["ir.config_parameter"].sudo().set_param( + "account.mass.reconcile.as.job", True + ) + invoice = self.create_invoice() + self.assertEqual("posted", invoice.state) + + receivalble_account_id = invoice.partner_id.property_account_receivable_id.id + # create payment + payment = self.env["account.payment"].create( + { + "partner_type": "customer", + "payment_type": "inbound", + "partner_id": invoice.partner_id.id, + "destination_account_id": receivalble_account_id, + "amount": 50.0, + "journal_id": self.bank_journal.id, + } + ) + payment.action_post() + + # create the mass reconcile record + mass_rec = self.mass_rec_obj.create( + { + "name": "mass_reconcile_1", + "account": invoice.partner_id.property_account_receivable_id.id, + "reconcile_method": [(0, 0, {"name": "mass.reconcile.simple.partner"})], + } + ) + with trap_jobs() as trap: + # call the automatic reconcilation method + mass_rec.run_reconcile() + trap.assert_jobs_count(1) + trap.assert_enqueued_job( + self.env["account.mass.reconcile"].reconcile_as_job, + args=(), + ) + job = trap.enqueued_jobs[0] + self.assertEqual(job.state, "pending") + trap.perform_enqueued_jobs() + self.assertEqual("paid", invoice.payment_state) + + def test_scenario_reconcile_lines_as_job(self): + self.env["ir.config_parameter"].sudo().set_param( + "account.mass.reconcile.as.job", True + ) + self.env["ir.config_parameter"].sudo().set_param( + "account.mass.reconcile.lines.as.job", True + ) + invoice = self.create_invoice() + self.assertEqual("posted", invoice.state) + + receivalble_account_id = invoice.partner_id.property_account_receivable_id.id + # create payment + payment = self.env["account.payment"].create( + { + "partner_type": "customer", + "payment_type": "inbound", + "partner_id": invoice.partner_id.id, + "destination_account_id": receivalble_account_id, + "amount": 50.0, + "journal_id": self.bank_journal.id, + } + ) + payment.action_post() + + # create the mass reconcile record + mass_rec = self.mass_rec_obj.create( + { + "name": "mass_reconcile_1", + "account": invoice.partner_id.property_account_receivable_id.id, + "reconcile_method": [(0, 0, {"name": "mass.reconcile.simple.partner"})], + } + ) + with trap_jobs() as trap: + self.assertFalse(self.env["mass.reconcile.simple.partner"].search([])) + # call the automatic reconcilation method + mass_rec.run_reconcile() + trap.assert_jobs_count(1) + trap.assert_enqueued_job( + self.env["account.mass.reconcile"].reconcile_as_job, + args=(), + ) + job = trap.enqueued_jobs[0] + self.assertEqual(job.state, "pending") + self.assertFalse(self.env["mass.reconcile.simple.partner"].search([])) + trap.perform_enqueued_jobs() + trap.assert_jobs_count(2) + job_2 = trap.enqueued_jobs[1] + # Cannot use assert_enqueue_job with all the parameters + self.assertEqual(job_2.model_name, "mass.reconcile.simple.partner") + self.assertEqual(job_2.method_name, "reconcile_lines_as_job") + self.assertEqual(job_2.state, "pending") + # Delete existing wizard to make sure the job can still after after + # the wizard is garbage collected + wiz = self.env["mass.reconcile.simple.partner"].search([]) + self.assertTrue(wiz) + wiz.unlink() + trap.perform_enqueued_jobs() + self.assertEqual("paid", invoice.payment_state)