Skip to content
Open
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
55 changes: 41 additions & 14 deletions edi_core_oca/models/edi_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from odoo.exceptions import UserError

from ..exceptions import EDINotImplementedError, EDIValidationError
from ..utils import EdiExchangeActionResult

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -126,8 +127,12 @@ def exchange_generate(self, exchange_record, store=True, force=False, **kw):
# Remove file to regenerate
exchange_record.exchange_file = False
self._check_exchange_generate(exchange_record, force=force)
output = self._exchange_generate(exchange_record, **kw)
message = None
action_result = self._ensure_action_result(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

each _exchange_$action should take care of returning the wrapped result.
Here you should not wrap.
Also I wouldn't pass default_message.
Just do message = result.message or exchange_record._exchange_status_message("generate_ok")

self._exchange_generate(exchange_record, **kw),
default_message=exchange_record._exchange_status_message("generate_ok"),
)
output = action_result.output
message = action_result.message
encoding = exchange_record.type_id.encoding or "UTF-8"
encoding_error_handler = (
exchange_record.type_id.encoding_out_error_handler or "strict"
Expand All @@ -142,7 +147,6 @@ def exchange_generate(self, exchange_record, store=True, force=False, **kw):
}
)
if output:
message = exchange_record._exchange_status_message("generate_ok")
try:
with self.env.cr.savepoint():
self._validate_data(exchange_record, output)
Expand Down Expand Up @@ -203,7 +207,16 @@ def _check_exchange_generate(self, exchange_record, force=False):
def _exchange_generate(self, exchange_record, **kw):
exchange_function = self._get_exec_handler(exchange_record, "generate")
ctx = self._get_record_env_ctx(exchange_record, "generate")
return exchange_function(exchange_record.with_context(**ctx), **kw)
result = exchange_function(exchange_record.with_context(**ctx), **kw)
return self._ensure_action_result(
result,
default_message=exchange_record._exchange_status_message("generate_ok"),
)

def _ensure_action_result(self, result, default_message=None):
if isinstance(result, EdiExchangeActionResult):
return result
return EdiExchangeActionResult(output=result, message=default_message)

# TODO: add tests
def _validate_data(self, exchange_record, value=None, **kw):
Expand Down Expand Up @@ -244,7 +257,9 @@ def exchange_send(self, exchange_record):
res = ""
try:
with self.env.cr.savepoint():
self._exchange_send(exchange_record)
send_result = self._ensure_action_result(
self._exchange_send(exchange_record)
)
_logger.debug("%s sent", exchange_record.identifier)
except self._send_retryable_exceptions() as err:
traceback = _get_exception_traceback()
Expand All @@ -269,15 +284,18 @@ def exchange_send(self, exchange_record):
res = "__sql_error__"
raise
else:
# TODO: maybe the send handler should return desired message and state
message = exchange_record._exchange_status_message("send_ok")
message = (
send_result.message
or send_result.output

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you want the output as a message you must return it as the message

or exchange_record._exchange_status_message("send_ok")
)
error = traceback = None
state = (
"output_sent_and_processed"
if self.output_sent_processed_auto
else "output_sent"
)
res = message
res = send_result.output or message

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

read above

finally:
if res != "__sql_error__":
exchange_record.write(
Expand Down Expand Up @@ -329,7 +347,8 @@ def _output_check_send(self, exchange_record):
def _exchange_send(self, exchange_record):
exchange_function = self._get_exec_handler(exchange_record, "send")
ctx = self._get_record_env_ctx(exchange_record, "send")
return exchange_function(exchange_record.with_context(**ctx))
result = exchange_function(exchange_record.with_context(**ctx))
return self._ensure_action_result(result)

def _cron_check_output_exchange_sync(self, **kw):
for backend in self:
Expand Down Expand Up @@ -475,7 +494,9 @@ def exchange_process(self, exchange_record):
res = None
try:
with self.env.cr.savepoint():
res = self._exchange_process(exchange_record)
process_result = self._exchange_process(exchange_record)
res = process_result.output
message = process_result.message
except self._swallable_exceptions() as err:
if self.env.context.get("_edi_process_break_on_error"):
raise
Expand Down Expand Up @@ -517,7 +538,8 @@ def exchange_process(self, exchange_record):
def _exchange_process(self, exchange_record):
exchange_function = self._get_exec_handler(exchange_record, "process")
ctx = self._get_record_env_ctx(exchange_record, "process")
return exchange_function(exchange_record.with_context(**ctx))
result = exchange_function(exchange_record.with_context(**ctx))
return self._ensure_action_result(result)

def exchange_receive(self, exchange_record):
"""Retrieve an incoming document."""
Expand All @@ -533,7 +555,11 @@ def exchange_receive(self, exchange_record):
res = None
try:
with self.env.cr.savepoint():
content = self._exchange_receive(exchange_record)
receive_result = self._ensure_action_result(
self._exchange_receive(exchange_record)
)
content = receive_result.output
message = receive_result.message
# Ignore result of FileNotFoundError/OSError
if content is not None:
exchange_record._set_file_content(content)
Expand All @@ -556,7 +582,7 @@ def exchange_receive(self, exchange_record):
res = "__sql_error__"
raise
else:
message = exchange_record._exchange_status_message("receive_ok")
message = message or exchange_record._exchange_status_message("receive_ok")
error = traceback = None
state = "input_received"
res = message
Expand Down Expand Up @@ -598,7 +624,8 @@ def _exchange_receive_check(self, exchange_record):
def _exchange_receive(self, exchange_record):
exchange_function = self._get_exec_handler(exchange_record, "receive")
ctx = self._get_record_env_ctx(exchange_record, "receive")
return exchange_function(exchange_record.with_context(**ctx))
result = exchange_function(exchange_record.with_context(**ctx))
return self._ensure_action_result(result)

def _cron_check_input_exchange_sync(self, **kw):
for backend in self:
Expand Down
37 changes: 37 additions & 0 deletions edi_core_oca/tests/test_backend_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from odoo.exceptions import UserError
from odoo.orm.model_classes import add_to_registry

from ..utils import EdiExchangeActionResult
from .common import EDIBackendCommonTestCase


Expand Down Expand Up @@ -54,6 +55,31 @@ def test_generate_record_output(self):
self.record.with_context(fake_output="yeah!").action_exchange_generate()
self.assertEqual(self.record._get_file_content(), "yeah!")

def test_exchange_generate_wraps_legacy_result(self):
result = self.record.with_context(
fake_output="yeah!"
).backend_id._exchange_generate(self.record)
self.assertEqual(result.output, "yeah!")
self.assertEqual(
result.message, self.record._exchange_status_message("generate_ok")
)

def test_generate_record_output_with_custom_action_result_message(self):
with mock.patch.object(type(self.backend), "_exchange_generate") as mocked:
mocked.return_value = EdiExchangeActionResult(
output="yeah!", message="Generated with custom message"
)
message = self.record.action_exchange_generate()
self.assertEqual(message, "Generated with custom message")
self.assertEqual(self.record._get_file_content(), "yeah!")

def test_generate_record_output_with_legacy_override_string(self):
with mock.patch.object(type(self.backend), "_exchange_generate") as mocked:
mocked.return_value = "yeah!"
message = self.record.action_exchange_generate()
self.assertEqual(message, self.record._exchange_status_message("generate_ok"))
self.assertEqual(self.record._get_file_content(), "yeah!")

def test_generate_record_output_pdf(self):
pdf_content = tools.file_open(
"addons/edi_core_oca/tests/result.pdf", mode="rb"
Expand All @@ -77,6 +103,17 @@ def test_send_record(self):
"2020-10-21 10:00:00",
)

def test_send_record_with_custom_action_result(self):
self.record.write({"edi_exchange_state": "output_pending"})
self.record._set_file_content(f"TEST {self.record.id}")
with mock.patch.object(type(self.backend), "_exchange_send") as mocked:
mocked.return_value = EdiExchangeActionResult(
output="send-payload", message="Sent with custom message"
)
res = self.record.action_exchange_send()
self.assertEqual(res, "send-payload")
self.assertRecordValues(self.record, [{"edi_exchange_state": "output_sent"}])

def test_send_record_with_error(self):
self.record.write({"edi_exchange_state": "output_pending"})
self.record._set_file_content(f"TEST {self.record.id}")
Expand Down
8 changes: 8 additions & 0 deletions edi_core_oca/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

import hashlib
from dataclasses import dataclass
from typing import Any


@dataclass
class EdiExchangeActionResult:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class EdiExchangeActionResult:
class EDIExchangeActionResult:

output: Any = None
message: str | None = None


def normalize_string(cls, a_string, sep="_"):
Expand Down
12 changes: 9 additions & 3 deletions edi_queue_oca/tests/test_backend_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def _get_related_jobs(self, record):
action = record.action_view_related_queue_jobs()
return self.env["queue.job"].search(action["domain"])

def test_output(self):
def _test_output_return(self, message, expected_message):
job_counter = self.job_counter()
vals = {
"model": self.partner._name,
Expand Down Expand Up @@ -84,15 +84,21 @@ def test_output(self):
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"
mocked.return_value = message
res = job.perform()
self.assertEqual(res, "Exchange sent")
self.assertEqual(res, expected_message)
self.assertEqual(record.edi_exchange_state, "output_sent")
self.assertEqual(created[0].name, "Send exchange file.")
# Check related jobs
record.invalidate_recordset()
self.assertEqual(created, self._get_related_jobs(record))

def test_output_with_specific_return(self):
self._test_output_return("specific return message", "specific return message")

def test_output_no_return(self):
self._test_output_return("", "Exchange sent")

def test_output_fail_retry(self):
job_counter = self.job_counter()
vals = {
Expand Down
Loading