diff --git a/addons/account_edi/data/cron.xml b/addons/account_edi/data/cron.xml
index 1567942b8dc..1f47dbd7d02 100644
--- a/addons/account_edi/data/cron.xml
+++ b/addons/account_edi/data/cron.xml
@@ -3,9 +3,9 @@
EDI : Perform web services operations
code
- model.search([('state', 'in', ('to_send', 'to_cancel'))])._process_documents_web_services(job_count=20)
+ model._cron_process_documents_web_services(job_count=20)
1
- hours
+ days
-1
False
diff --git a/addons/account_edi/models/account_edi_document.py b/addons/account_edi/models/account_edi_document.py
index 6a44e7f3ea7..57eb1db13f5 100644
--- a/addons/account_edi/models/account_edi_document.py
+++ b/addons/account_edi/models/account_edi_document.py
@@ -190,13 +190,16 @@ class AccountEdiDocument(models.Model):
self._process_job(documents, doc_type)
def _process_documents_web_services(self, job_count=None, with_commit=True):
- """ Post and cancel all the documents that need a web service. This is called by CRON.
+ ''' Post and cancel all the documents that need a web service.
- :param job_count: Limit to the number of jobs to process among the ones that are available for treatment.
- """
- jobs = self.filtered(lambda d: d.edi_format_id._needs_web_services())._prepare_jobs()
- jobs = jobs[0:job_count or len(jobs)]
- for documents, doc_type in jobs:
+ :param job_count: The maximum number of jobs to process if specified.
+ :param with_commit: Flag indicating a commit should be made between each job.
+ :return: The number of remaining jobs to process.
+ '''
+ all_jobs = self.filtered(lambda d: d.edi_format_id._needs_web_services())._prepare_jobs()
+ jobs_to_process = all_jobs[0:job_count] if job_count else all_jobs
+
+ for documents, doc_type in jobs_to_process:
move_to_cancel = documents.filtered(lambda doc: doc.attachment_id \
and doc.state == 'to_cancel' \
and doc.move_id.is_invoice(include_receipts=True) \
@@ -220,5 +223,20 @@ class AccountEdiDocument(models.Model):
else:
raise e
else:
- if with_commit and len(jobs) > 1:
+ if with_commit and len(jobs_to_process) > 1:
self.env.cr.commit()
+
+ return len(all_jobs) - len(jobs_to_process)
+
+ @api.model
+ def _cron_process_documents_web_services(self, job_count=None):
+ ''' Method called by the EDI cron processing all web-services.
+
+ :param job_count: Limit explicitely the number of web service calls. If not provided, process all.
+ '''
+ edi_documents = self.search([('state', 'in', ('to_send', 'to_cancel'))])
+ nb_remaining_jobs = edi_documents._process_documents_web_services(job_count=job_count)
+
+ # Mark the CRON to be triggered again asap since there is some remaining jobs to process.
+ if nb_remaining_jobs > 0:
+ self.env.ref('account_edi.ir_cron_edi_network')._trigger()
diff --git a/addons/account_edi/models/account_move.py b/addons/account_edi/models/account_move.py
index 1db21d29058..44f24199779 100644
--- a/addons/account_edi/models/account_move.py
+++ b/addons/account_edi/models/account_move.py
@@ -261,6 +261,7 @@ class AccountMove(models.Model):
self.env['account.edi.document'].create(edi_document_vals_list)
posted.edi_document_ids._process_documents_no_web_services()
+ self.env.ref('account_edi.ir_cron_edi_network')._trigger()
return posted
def button_cancel(self):
@@ -271,6 +272,7 @@ class AccountMove(models.Model):
self.edi_document_ids.filtered(lambda doc: doc.attachment_id).write({'state': 'to_cancel', 'error': False, 'blocking_level': False})
self.edi_document_ids.filtered(lambda doc: not doc.attachment_id).write({'state': 'cancelled', 'error': False, 'blocking_level': False})
self.edi_document_ids._process_documents_no_web_services()
+ self.env.ref('account_edi.ir_cron_edi_network')._trigger()
return res
@@ -353,7 +355,7 @@ class AccountMove(models.Model):
def action_process_edi_web_services(self):
docs = self.edi_document_ids.filtered(lambda d: d.state in ('to_send', 'to_cancel') and d.blocking_level != 'error')
- docs._process_documents_web_services(with_commit=False)
+ docs._process_documents_web_services()
def action_retry_edi_documents_error(self):
self.edi_document_ids.write({'error': False, 'blocking_level': False})
diff --git a/addons/account_edi/tests/test_edi.py b/addons/account_edi/tests/test_edi.py
index bfd8f6f8518..04df5f12879 100644
--- a/addons/account_edi/tests/test_edi.py
+++ b/addons/account_edi/tests/test_edi.py
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from odoo import Command
from odoo.addons.account_edi.tests.common import AccountEdiTestCommon, _mocked_post_two_steps, _generate_mocked_needs_web_services, _mocked_cancel_failed, _generate_mocked_support_batching
from unittest.mock import patch
+from odoo.addons.base.tests.test_ir_cron import CronMixinCase
-class TestAccountEdi(AccountEdiTestCommon):
+class TestAccountEdi(AccountEdiTestCommon, CronMixinCase):
@classmethod
def setUpClass(cls, chart_template_ref=None, edi_format_ref=None):
@@ -93,7 +95,7 @@ class TestAccountEdi(AccountEdiTestCommon):
self.invoice.button_cancel_posted_moves()
self.assertEqual(doc.state, 'to_cancel')
self.assertEqual(self.invoice.state, 'posted')
- doc._process_documents_web_services()
+ doc._process_documents_web_services(with_commit=False)
self.assertEqual(doc.state, 'cancelled')
self.assertEqual(self.invoice.state, 'cancel')
@@ -120,7 +122,7 @@ class TestAccountEdi(AccountEdiTestCommon):
self.invoice.button_cancel_posted_moves()
self.assertEqual(doc.state, 'to_cancel')
self.assertEqual(self.invoice.state, 'posted')
- doc._process_documents_web_services()
+ doc._process_documents_web_services(with_commit=False)
self.assertEqual(doc.state, 'to_cancel')
self.assertEqual(self.invoice.state, 'posted')
@@ -196,3 +198,32 @@ class TestAccountEdi(AccountEdiTestCommon):
doc2.move_id.ref = 'batch1'
to_process = edi_docs._prepare_jobs()
self.assertEqual(len(to_process), 2)
+
+ def test_cron_triggers(self):
+ with self.capture_triggers('account_edi.ir_cron_edi_network') as capt, \
+ self.mock_edi(_needs_web_services_method=_generate_mocked_needs_web_services(True)):
+ self.invoice._get_edi_document(self.edi_format)
+ self.invoice.action_post()
+ capt.records.ensure_one()
+
+ def test_cron_self_trigger(self):
+ # Process single job by CRON call (and thus, disable the auto-commit).
+ edi_cron = self.env.ref('account_edi.ir_cron_edi_network')
+ edi_cron.code = 'model._cron_process_documents_web_services(job_count=1)'
+
+ # Create invoices.
+ invoices = self.env['account.move'].create([{
+ 'move_type': 'out_invoice',
+ 'invoice_date': '2019-01-01',
+ 'date': '2019-01-01',
+ 'partner_id': self.partner_a.id,
+ 'invoice_line_ids': [Command.create({'product_id': self.product_a.id})],
+ } for i in range(4)])
+
+ with self.capture_triggers('account_edi.ir_cron_edi_network') as capt, \
+ self.mock_edi(_needs_web_services_method=_generate_mocked_needs_web_services(True)):
+ invoices.action_post()
+
+ self.env.ref('account_edi.ir_cron_edi_network').method_direct_trigger()
+ self.assertEqual(len(capt.records), 2, "Not all records have been processed in this run, the cron should "
+ "re-trigger itself to process some more later")