account_edi/tests/common.py

135 lines
5.9 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from contextlib import contextmanager
from unittest.mock import patch
import base64
def _generate_mocked_needs_web_services(needs_web_services):
return lambda edi_format: needs_web_services
def _mocked_get_move_applicability(edi_format, move):
return {
'post': edi_format._post_invoice_edi,
'cancel': edi_format._cancel_invoice_edi,
}
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_cancel_success(edi_format, invoices):
return {invoice: {'success': True} for invoice in invoices}
class AccountEdiTestCommon(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None, edi_format_ref=None):
super().setUpClass(chart_template_ref=chart_template_ref)
# ==== EDI ====
if edi_format_ref:
cls.edi_format = cls.env.ref(edi_format_ref)
else:
with cls.mock_edi(cls, _needs_web_services_method=_generate_mocked_needs_web_services(True)):
cls.edi_format = cls.env['account.edi.format'].sudo().create({
'name': 'Test EDI format',
'code': 'test_edi',
})
cls.journal = cls.company_data['default_journal_sale']
cls.journal.edi_format_ids = [(6, 0, cls.edi_format.ids)]
####################################################
# EDI helpers
####################################################
def _create_fake_edi_attachment(self):
return self.env['ir.attachment'].create({
'name': '_create_fake_edi_attachment.xml',
'datas': base64.encodebytes(b"<?xml version='1.0' encoding='UTF-8'?><Invoice/>"),
'mimetype': 'application/xml'
})
@contextmanager
def with_custom_method(self, method_name, method_content):
path = f'odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat.{method_name}'
with patch(path, new=method_content, create=not hasattr(self.env['account.edi.format'], method_name)):
yield
@contextmanager
def mock_edi(self,
_get_move_applicability_method=_mocked_get_move_applicability,
_needs_web_services_method=_generate_mocked_needs_web_services(False),
_check_move_configuration_method=_mocked_check_move_configuration_success,
):
try:
with 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._check_move_configuration',
new=_check_move_configuration_method), \
patch('odoo.addons.account_edi.models.account_edi_format.AccountEdiFormat._get_move_applicability',
new=_get_move_applicability_method):
yield
finally:
pass
def edi_cron(self):
self.env['account.edi.document'].sudo().search([('state', 'in', ('to_send', 'to_cancel'))])._process_documents_web_services(with_commit=False)
def assert_generated_file_equal(self, invoice, expected_values, applied_xpath=None):
invoice.action_post()
invoice.edi_document_ids._process_documents_web_services(with_commit=False) # synchronous are called in post, but there's no CRON in tests for asynchronous
attachment = invoice._get_edi_attachment(self.edi_format)
if not attachment:
raise ValueError('No attachment was generated after posting EDI')
xml_content = base64.b64decode(attachment.with_context(bin_size=False).datas)
current_etree = self.get_xml_tree_from_string(xml_content)
expected_etree = self.get_xml_tree_from_string(expected_values)
if applied_xpath:
expected_etree = self.with_applied_xpath(expected_etree, applied_xpath)
self.assertXmlTreeEqual(current_etree, expected_etree)
def create_edi_document(self, edi_format, state, move=None, move_type=None):
""" Creates a document based on an existing invoice or creates one, too.
:param edi_format: The edi_format of the document.
:param state: The state of the document.
:param move: The move of the document or None to create a new one.
:param move_type: If move is None, the type of the invoice to create, defaults to 'out_invoice'.
"""
move = move or self.init_invoice(move_type or 'out_invoice', products=self.product_a)
return self.env['account.edi.document'].create({
'edi_format_id': edi_format.id,
'move_id': move.id,
'state': state
})
def _process_documents_web_services(self, moves, formats_to_return=None):
""" Generates and returns EDI files for the specified moves.
formats_to_return is an optional parameter used to pass a set of codes from
the formats we want to return the files for (in case we want to test specific formats).
Other formats will still generate documents, they simply won't be returned.
"""
moves.edi_document_ids._process_documents_web_services(with_commit=False)
documents_to_return = moves.edi_document_ids
if formats_to_return != None:
documents_to_return = documents_to_return.filtered(lambda x: x.edi_format_id.code in formats_to_return)
attachments = documents_to_return.attachment_id
data_str_list = []
for attachment in attachments.with_context(bin_size=False):
data_str_list.append(base64.decodebytes(attachment.datas))
return data_str_list