Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[14.0] edi_oca: fix/imp jobs #855

Merged
merged 5 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions edi_exchange_template_oca/tests/test_edi_backend_output.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Copyright 2020 ACSONE SA/NV (<http://acsone.eu>)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
import base64

from lxml import etree

Expand Down Expand Up @@ -139,11 +138,12 @@ def test_get_template(self):
def test_generate_file(self):
output = self.backend.exchange_generate(self.record1)
expected = "{0.ref} - {0.name}".format(self.partner)
self.assertEqual(output.strip(), expected)
file_content = base64.b64decode(self.record1.exchange_file).decode()
self.assertEqual(output, "Exchange data generated")
file_content = self.record1._get_file_content()
self.assertEqual(file_content.strip(), expected)
output = self.backend.exchange_generate(self.record2)
doc = etree.fromstring(output)
file_content = self.record2._get_file_content()
doc = etree.fromstring(file_content)
self.assertEqual(doc.tag, "Record")
self.assertEqual(doc.attrib, {"ref": self.partner.ref})
self.assertEqual(doc.getchildren()[0].tag, "Name")
Expand All @@ -156,16 +156,17 @@ def test_prettify(self):
self.tmpl_out2.template_id.arch = (
'<t t-name="edi_exchange.test_output2"><root><a>1</a></root></t>'
)
result = self.tmpl_out2.exchange_generate(self.record2)
self.assertEqual(result, b"<root><a>1</a></root>")
output = self.tmpl_out2.exchange_generate(self.record2)
self.assertEqual(output, b"<root><a>1</a></root>")
self.tmpl_out2.prettify = True
result = self.tmpl_out2.exchange_generate(self.record2)
self.assertEqual(result, b"<root>\n <a>1</a>\n</root>\n")
output = self.tmpl_out2.exchange_generate(self.record2)
self.assertEqual(output, b"<root>\n <a>1</a>\n</root>\n")

def test_generate_file_report(self):
output = self.backend.exchange_generate(self.record3)
self.assertTrue(output)
self.assertEqual(output, "Exchange data generated")
file_content = self.record3._get_file_content()
self.assertEqual(
self.report._render([self.record3.res_id])[0].strip().decode("UTF-8"),
output.strip(),
file_content.strip(),
)
36 changes: 24 additions & 12 deletions edi_oca/models/edi_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from odoo import _, exceptions, fields, models, tools

from odoo.addons.component.exception import NoComponentError
from odoo.addons.queue_job.exception import RetryableJobError

from ..exceptions import EDIValidationError

Expand Down Expand Up @@ -229,6 +230,7 @@
except UnicodeDecodeError:
pass
if output:
message = exchange_record._exchange_status_message("generate_ok")
try:
self._validate_data(exchange_record, output)
except EDIValidationError:
Expand All @@ -239,8 +241,9 @@
{"edi_exchange_state": state, "exchange_error": error}
)
exchange_record.notify_action_complete("generate", message=message)
return output
return message

# TODO: unify to all other checkes that return something
def _check_exchange_generate(self, exchange_record, force=False):
exchange_record.ensure_one()
if (
Expand Down Expand Up @@ -288,10 +291,11 @@
# In case already sent: skip sending and check the state
check = self._output_check_send(exchange_record)
if not check:
return False
return "Nothing to do. Likely already sent."

Check warning on line 294 in edi_oca/models/edi_backend.py

View check run for this annotation

Codecov / codecov/patch

edi_oca/models/edi_backend.py#L294

Added line #L294 was not covered by tests
state = exchange_record.edi_exchange_state
error = False
message = None
res = ""
try:
self._exchange_send(exchange_record)
except self._swallable_exceptions():
Expand All @@ -300,7 +304,12 @@
error = _get_exception_msg()
state = "output_error_on_send"
message = exchange_record._exchange_status_message("send_ko")
res = False
res = f"Error: {error}"
except self._send_retryable_exceptions() as err:
error = _get_exception_msg()
raise RetryableJobError(
error, **exchange_record._job_retry_params()
) from err
else:
# TODO: maybe the send handler should return desired message and state
message = exchange_record._exchange_status_message("send_ok")
Expand All @@ -310,7 +319,7 @@
if self.output_sent_processed_auto
else "output_sent"
)
res = True
res = message
finally:
exchange_record.write(
{
Expand All @@ -333,6 +342,10 @@
exceptions.ValidationError,
)

def _send_retryable_exceptions(self):
# IOError is a base class for all connection errors
return (IOError,)

def _output_check_send(self, exchange_record):
if exchange_record.direction != "output":
raise exceptions.UserError(
Expand Down Expand Up @@ -456,22 +469,21 @@
# In case already processed: skip processing and check the state
check = self._exchange_process_check(exchange_record)
if not check:
return False
return "Nothing to do. Likely already processed."

Check warning on line 472 in edi_oca/models/edi_backend.py

View check run for this annotation

Codecov / codecov/patch

edi_oca/models/edi_backend.py#L472

Added line #L472 was not covered by tests
old_state = state = exchange_record.edi_exchange_state
error = False
message = None
try:
self._exchange_process(exchange_record)
res = self._exchange_process(exchange_record)
except self._swallable_exceptions():
if self.env.context.get("_edi_process_break_on_error"):
raise
error = _get_exception_msg()
state = "input_processed_error"
res = False
res = f"Error: {error}"
else:
error = None
state = "input_processed"
res = True
finally:
exchange_record.write(
{
Expand Down Expand Up @@ -505,7 +517,7 @@
# In case already processed: skip processing and check the state
check = self._exchange_receive_check(exchange_record)
if not check:
return False
return "Nothing to do. Likely already received."
state = exchange_record.edi_exchange_state
error = False
message = None
Expand All @@ -519,19 +531,19 @@
error = _get_exception_msg()
state = "validate_error"
message = exchange_record._exchange_status_message("validate_ko")
res = False
res = f"Validation error: {error}"
except self._swallable_exceptions():
if self.env.context.get("_edi_receive_break_on_error"):
raise
error = _get_exception_msg()
state = "input_receive_error"
message = exchange_record._exchange_status_message("receive_ko")
res = False
res = f"Input error: {error}"

Check warning on line 541 in edi_oca/models/edi_backend.py

View check run for this annotation

Codecov / codecov/patch

edi_oca/models/edi_backend.py#L541

Added line #L541 was not covered by tests
else:
message = exchange_record._exchange_status_message("receive_ok")
error = None
state = "input_received"
res = True
res = message
finally:
exchange_record.write(
{
Expand Down
13 changes: 11 additions & 2 deletions edi_oca/models/edi_exchange_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,14 @@
def _exchange_status_messages(self):
return {
# status: message
"generate_ok": _("Exchange data generated"),
"send_ok": _("Exchange sent"),
"send_ko": _(
"An error happened while sending. Please check exchange record info."
),
"process_ok": _("Exchange processed successfully "),
"process_ok": _("Exchange processed successfully"),
"process_ko": _("Exchange processed with errors"),
"receive_ok": _("Exchange received successfully "),
"receive_ok": _("Exchange received successfully"),
"receive_ko": _("Exchange not received"),
"ack_received": _("ACK file received."),
"ack_missing": _("ACK file is required for this exchange but not found."),
Expand Down Expand Up @@ -571,3 +572,11 @@
params = self._job_delay_params()
params.update(kw)
return super().with_delay(**params)

def delayable(self, **kw):
params = self._job_delay_params()
params.update(kw)
return super().delayable(**params)

Check warning on line 579 in edi_oca/models/edi_exchange_record.py

View check run for this annotation

Codecov / codecov/patch

edi_oca/models/edi_exchange_record.py#L577-L579

Added lines #L577 - L579 were not covered by tests

def _job_retry_params(self):
return {}
59 changes: 55 additions & 4 deletions edi_oca/tests/test_backend_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
# @author: Simone Orsi <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import mock
from requests.exceptions import ConnectionError as ReqConnectionError

from odoo.addons.queue_job.exception import RetryableJobError
from odoo.addons.queue_job.tests.common import JobMixin

from .common import EDIBackendCommonTestCase
Expand All @@ -19,27 +23,74 @@ def test_output(self):
"res_id": self.partner.id,
}
record = self.backend.create_record("test_csv_output", vals)
self.backend.with_delay().exchange_generate(record)
self.assertEqual(record.edi_exchange_state, "new")
job = self.backend.with_delay().exchange_generate(record)
created = job_counter.search_created()
self.assertEqual(len(created), 1)
self.assertEqual(
created.name, "Generate output content for given exchange record."
)
self.backend.with_delay().exchange_send(record)
with mock.patch.object(
type(self.backend), "_exchange_generate"
) as mocked_generate, mock.patch.object(
type(self.backend), "_validate_data"
) as mocked_validate:
mocked_generate.return_value = "filecontent"
mocked_validate.return_value = None
res = job.perform()
self.assertEqual(res, "Exchange data generated")
self.assertEqual(record.edi_exchange_state, "output_pending")
job = self.backend.with_delay().exchange_send(record)
created = job_counter.search_created()
with mock.patch.object(type(self.backend), "_exchange_send") as mocked:
mocked.return_value = "ok"
res = job.perform()
self.assertEqual(res, "Exchange sent")
self.assertEqual(record.edi_exchange_state, "output_sent")
self.assertEqual(created[0].name, "Send exchange file.")

def test_output_fail_retry(self):
job_counter = self.job_counter()
vals = {
"model": self.partner._name,
"res_id": self.partner.id,
"edi_exchange_state": "output_pending",
}
record = self.backend.create_record("test_csv_output", vals)
record._set_file_content("ABC")
job = self.backend.with_delay().exchange_send(record)
job_counter.search_created()
with mock.patch.object(type(self.backend), "_exchange_send") as mocked:
mocked.side_effect = ReqConnectionError("Connection broken")
with self.assertRaises(RetryableJobError):
job.perform()

def test_input(self):
job_counter = self.job_counter()
vals = {
"model": self.partner._name,
"res_id": self.partner.id,
}
record = self.backend.create_record("test_csv_input", vals)
self.backend.with_delay().exchange_receive(record)
job = self.backend.with_delay().exchange_receive(record)
created = job_counter.search_created()
self.assertEqual(len(created), 1)
self.assertEqual(created.name, "Retrieve an incoming document.")
self.backend.with_delay().exchange_process(record)
with mock.patch.object(
type(self.backend), "_exchange_receive"
) as mocked_receive, mock.patch.object(
type(self.backend), "_validate_data"
) as mocked_validate:
mocked_receive.return_value = "filecontent"
mocked_validate.return_value = None
res = job.perform()
# the state is not input_pending hence there's nothing to do
self.assertEqual(res, "Nothing to do. Likely already received.")
record.edi_exchange_state = "input_pending"
res = job.perform()
# the state is not input_pending hence there's nothing to do
self.assertEqual(res, "Exchange received successfully")
self.assertEqual(record.edi_exchange_state, "input_received")
job = self.backend.with_delay().exchange_process(record)
created = job_counter.search_created()
self.assertEqual(created[0].name, "Process an incoming document.")
3 changes: 3 additions & 0 deletions edi_oca/tests/test_exchange_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

from freezegun import freeze_time

from odoo.tools import mute_logger

from .common import EDIBackendCommonTestCase


Expand All @@ -23,6 +25,7 @@ def test_ack_for(self):
self.exchange_type_out_ack.ack_for_type_ids.ids,
)

@mute_logger("odoo.sql_db")
def test_same_code_same_backend(self):
with self.assertRaises(Exception) as err:
self.exchange_type_in.copy({"code": "test_csv_input"})
Expand Down
Loading