summaryrefslogtreecommitdiff
path: root/addons/account_edi_extended/tests
diff options
context:
space:
mode:
Diffstat (limited to 'addons/account_edi_extended/tests')
-rw-r--r--addons/account_edi_extended/tests/__init__.py5
-rw-r--r--addons/account_edi_extended/tests/common.py114
-rw-r--r--addons/account_edi_extended/tests/test_edi.py157
3 files changed, 276 insertions, 0 deletions
diff --git a/addons/account_edi_extended/tests/__init__.py b/addons/account_edi_extended/tests/__init__.py
new file mode 100644
index 00000000..eea5d7ed
--- /dev/null
+++ b/addons/account_edi_extended/tests/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import common
+from . import test_edi
diff --git a/addons/account_edi_extended/tests/common.py b/addons/account_edi_extended/tests/common.py
new file mode 100644
index 00000000..3bb2ff6f
--- /dev/null
+++ b/addons/account_edi_extended/tests/common.py
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo.addons.account_edi.tests.common import AccountEdiTestCommon
+from contextlib import contextmanager
+from unittest.mock import patch
+import base64
+
+# TODO for the test to work, we need a chart template (COA) but we don't have any and don't want to add dependency (create empty coa ?)
+
+
+def _generate_mocked_needs_web_services(needs_web_services):
+ return lambda edi_format: needs_web_services
+
+
+def _generate_mocked_support_batching(support_batching):
+ return lambda edi_format, move, state, company: support_batching
+
+
+def _mocked_get_batch_key(edi_format, move, state):
+ return ()
+
+
+def _mocked_check_move_configuration_success(edi_format, move):
+ return []
+
+
+def _mocked_check_move_configuration_fail(edi_format, move):
+ return ['Fake error (mocked)']
+
+
+def _mocked_post(edi_format, invoices, test_mode):
+ res = {}
+ for invoice in invoices:
+ attachment = edi_format.env['ir.attachment'].create({
+ 'name': 'mock_simple.xml',
+ 'datas': base64.encodebytes(b"<?xml version='1.0' encoding='UTF-8'?><Invoice/>"),
+ 'mimetype': 'application/xml'
+ })
+ res[invoice] = {'attachment': attachment}
+ return res
+
+
+def _mocked_post_two_steps(edi_format, invoices, test_mode):
+ # For this test, we use the field ref to know if the first step is already done or not.
+ # Typically, a technical field for the reference of the upload to the web-service will
+ # be saved on the invoice.
+ invoices_no_ref = invoices.filtered(lambda i: not i.ref)
+ if len(invoices_no_ref) == len(invoices): # first step
+ invoices_no_ref.ref = 'test_ref'
+ return {invoice: {} for invoice in invoices}
+ elif len(invoices_no_ref) == 0: # second step
+ res = {}
+ for invoice in invoices:
+ attachment = edi_format.env['ir.attachment'].create({
+ 'name': 'mock_simple.xml',
+ 'datas': base64.encodebytes(b"<?xml version='1.0' encoding='UTF-8'?><Invoice/>"),
+ 'mimetype': 'application/xml'
+ })
+ res[invoice] = {'attachment': attachment}
+ return res
+ else:
+ raise ValueError('wrong use of "_mocked_post_two_steps"')
+
+
+def _mocked_cancel_success(edi_format, invoices, test_mode):
+ return {invoice: {'success': True} for invoice in invoices}
+
+
+def _mocked_cancel_failed(edi_format, invoices, test_mode):
+ return {invoice: {'error': 'Faked error (mocked)'} for invoice in invoices}
+
+
+class AccountEdiExtendedTestCommon(AccountEdiTestCommon):
+
+ @contextmanager
+ def mock_edi(self,
+ _is_required_for_invoice_method=lambda edi_format, invoice: True,
+ _is_required_for_payment_method=lambda edi_format, invoice: True,
+ _support_batching_method=_generate_mocked_support_batching(False),
+ _get_batch_key_method=_mocked_get_batch_key,
+ _needs_web_services_method=_generate_mocked_needs_web_services(False),
+ _check_move_configuration_method=_mocked_check_move_configuration_success,
+ _post_invoice_edi_method=_mocked_post,
+ _cancel_invoice_edi_method=_mocked_cancel_success,
+ _post_payment_edi_method=_mocked_post,
+ _cancel_payment_edi_method=_mocked_cancel_success,
+ ):
+
+ try:
+ with patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._is_required_for_invoice',
+ new=_is_required_for_invoice_method), \
+ patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._is_required_for_payment',
+ new=_is_required_for_payment_method), \
+ patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._needs_web_services',
+ new=_needs_web_services_method), \
+ patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._support_batching',
+ new=_support_batching_method), \
+ patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._get_batch_key',
+ new=_get_batch_key_method), \
+ patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._check_move_configuration',
+ new=_check_move_configuration_method), \
+ patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._post_invoice_edi',
+ new=_post_invoice_edi_method), \
+ patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._cancel_invoice_edi',
+ new=_cancel_invoice_edi_method), \
+ patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._post_payment_edi',
+ new=_post_payment_edi_method), \
+ patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._cancel_payment_edi',
+ new=_cancel_payment_edi_method):
+
+ yield
+ finally:
+ pass
diff --git a/addons/account_edi_extended/tests/test_edi.py b/addons/account_edi_extended/tests/test_edi.py
new file mode 100644
index 00000000..164a6c88
--- /dev/null
+++ b/addons/account_edi_extended/tests/test_edi.py
@@ -0,0 +1,157 @@
+
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo.addons.account_edi_extended.tests.common import AccountEdiExtendedTestCommon, _mocked_post, _mocked_post_two_steps, _generate_mocked_needs_web_services, _mocked_cancel_failed, _generate_mocked_support_batching
+
+
+class TestAccountEdi(AccountEdiExtendedTestCommon):
+
+ @classmethod
+ def setUpClass(cls, chart_template_ref=None, edi_format_ref=None):
+ super().setUpClass(chart_template_ref=chart_template_ref, edi_format_ref=edi_format_ref)
+
+ cls.invoice = cls.init_invoice('out_invoice', products=cls.product_a + cls.product_b)
+
+ def test_edi_flow(self):
+ with self.mock_edi():
+ doc = self.invoice._get_edi_document(self.edi_format)
+ self.assertFalse(doc)
+ self.invoice.action_post()
+ doc = self.invoice._get_edi_document(self.edi_format)
+ self.assertEqual(len(doc), 1)
+ self.assertEqual(doc.state, 'sent')
+ self.invoice.button_draft()
+ self.invoice.button_cancel()
+ self.assertEqual(doc.state, 'cancelled')
+
+ def test_edi_flow_two_steps(self):
+ with self.mock_edi(_post_invoice_edi_method=_mocked_post_two_steps,
+ _needs_web_services_method=_generate_mocked_needs_web_services(True)):
+ doc = self.invoice._get_edi_document(self.edi_format)
+ self.assertFalse(doc)
+ self.invoice.action_post()
+ doc = self.invoice._get_edi_document(self.edi_format)
+ self.assertEqual(len(doc), 1)
+ self.assertEqual(doc.state, 'to_send')
+ doc._process_documents_web_services(with_commit=False)
+ self.assertEqual(doc.state, 'to_send')
+ doc._process_documents_web_services(with_commit=False)
+ self.assertEqual(doc.state, 'sent')
+
+ def test_edi_flow_request_cancel_success(self):
+ with self.mock_edi(_needs_web_services_method=_generate_mocked_needs_web_services(True)):
+ self.assertEqual(self.invoice.state, 'draft')
+ self.invoice.action_post()
+ doc = self.invoice._get_edi_document(self.edi_format)
+ self.assertEqual(doc.state, 'to_send')
+ self.assertEqual(self.invoice.state, 'posted')
+ doc._process_documents_web_services(with_commit=False)
+ self.assertEqual(doc.state, 'sent')
+ self.assertEqual(self.invoice.state, 'posted')
+ self.invoice.button_cancel_posted_moves()
+ self.assertEqual(doc.state, 'to_cancel')
+ self.assertEqual(self.invoice.state, 'posted')
+ doc._process_documents_web_services()
+ self.assertEqual(doc.state, 'cancelled')
+ self.assertEqual(self.invoice.state, 'cancel')
+
+ def test_edi_flow_request_cancel_failed(self):
+ with self.mock_edi(_needs_web_services_method=_generate_mocked_needs_web_services(True),
+ _cancel_invoice_edi_method=_mocked_cancel_failed):
+ self.assertEqual(self.invoice.state, 'draft')
+ self.invoice.action_post()
+ doc = self.invoice._get_edi_document(self.edi_format)
+ self.assertEqual(doc.state, 'to_send')
+ self.assertEqual(self.invoice.state, 'posted')
+ doc._process_documents_web_services(with_commit=False)
+ self.assertEqual(doc.state, 'sent')
+ self.assertEqual(self.invoice.state, 'posted')
+ self.invoice.button_cancel_posted_moves()
+ self.assertEqual(doc.state, 'to_cancel')
+ self.assertEqual(self.invoice.state, 'posted')
+ # Call off edi Cancellation
+ self.invoice.button_abandon_cancel_posted_posted_moves()
+ self.assertEqual(doc.state, 'sent')
+ self.assertFalse(doc.error)
+
+ # Failed cancel
+ self.invoice.button_cancel_posted_moves()
+ self.assertEqual(doc.state, 'to_cancel')
+ self.assertEqual(self.invoice.state, 'posted')
+ doc._process_documents_web_services()
+ self.assertEqual(doc.state, 'to_cancel')
+ self.assertEqual(self.invoice.state, 'posted')
+
+ # Call off edi Cancellation
+ self.invoice.button_abandon_cancel_posted_posted_moves()
+ self.assertEqual(doc.state, 'sent')
+ self.assertIsNotNone(doc.error)
+
+ def test_edi_flow_two_step_cancel_with_call_off_request(self):
+ def _mock_cancel(edi_format, invoices, test_mode):
+ invoices_no_ref = invoices.filtered(lambda i: not i.ref)
+ if len(invoices_no_ref) == len(invoices): # first step
+ invoices_no_ref.ref = 'test_ref_cancel'
+ return {invoice: {} for invoice in invoices}
+ elif len(invoices_no_ref) == 0: # second step
+ for invoice in invoices:
+ invoice.ref = None
+ return {invoice: {'success': True} for invoice in invoices}
+ else:
+ raise ValueError('wrong use of "_mocked_post_two_steps"')
+
+ def _is_needed_for_invoice(edi_format, invoice):
+ return not bool(invoice.ref)
+
+ with self.mock_edi(_needs_web_services_method=_generate_mocked_needs_web_services(True),
+ _is_required_for_invoice_method=_is_needed_for_invoice,
+ _cancel_invoice_edi_method=_mock_cancel):
+ self.invoice.action_post()
+ doc = self.invoice._get_edi_document(self.edi_format)
+ doc._process_documents_web_services(with_commit=False)
+ self.assertEqual(doc.state, 'sent')
+
+ # Request Cancellation
+ self.invoice.button_cancel_posted_moves()
+ doc._process_documents_web_services(with_commit=False) # first step of cancel
+ self.assertEqual(doc.state, 'to_cancel')
+
+ # Call off edi Cancellation
+ self.invoice.button_abandon_cancel_posted_posted_moves()
+ self.assertEqual(doc.state, 'to_cancel')
+
+ # If we cannot call off edi cancellation, only solution is to post again
+ doc._process_documents_web_services(with_commit=False) # second step of cancel
+ self.assertEqual(doc.state, 'cancelled')
+ self.invoice.action_post()
+ doc._process_documents_web_services(with_commit=False)
+ self.assertEqual(doc.state, 'sent')
+
+ def test_batches(self):
+ def _get_batch_key_method(edi_format, move, state):
+ return (move.ref)
+
+ with self.mock_edi(_get_batch_key_method=_get_batch_key_method,
+ _support_batching_method=_generate_mocked_support_batching(True)):
+ edi_docs = self.env['account.edi.document']
+ doc1 = self.create_edi_document(self.edi_format, 'to_send')
+ edi_docs |= doc1
+ doc2 = self.create_edi_document(self.edi_format, 'to_send')
+ edi_docs |= doc2
+ doc3 = self.create_edi_document(self.edi_format, 'to_send')
+ edi_docs |= doc3
+
+ to_process = edi_docs._prepare_jobs()
+ self.assertEqual(len(to_process), 1)
+
+ doc1.move_id.ref = 'batch1'
+ doc2.move_id.ref = 'batch2'
+ doc3.move_id.ref = 'batch3'
+
+ to_process = edi_docs._prepare_jobs()
+ self.assertEqual(len(to_process), 3)
+
+ doc2.move_id.ref = 'batch1'
+ to_process = edi_docs._prepare_jobs()
+ self.assertEqual(len(to_process), 2)