From fe98ca4ac69960780eda24aa4c8104357e07e610 Mon Sep 17 00:00:00 2001 From: Daniel Gergely Date: Tue, 11 Aug 2026 15:24:25 +0200 Subject: [PATCH 1/3] [T3374] FIX: don't crash when a communication job has no email template --- partner_communication/models/communication_job.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/partner_communication/models/communication_job.py b/partner_communication/models/communication_job.py index 673d9b064..328fd6a49 100644 --- a/partner_communication/models/communication_job.py +++ b/partner_communication/models/communication_job.py @@ -968,8 +968,8 @@ def _send_by_sms_asynchronous(self): def _notify_get_reply_to( self, default=None, records=None, company=None, doc_names=None ): - res = dict.fromkeys(self.ids) - for job in self: + res = dict.fromkeys(self.ids, default) + for job in self.filtered("email_template_id"): res.update(job.email_template_id._render_field("reply_to", job.ids)) return res From 34c7cccbdb9452a03ae083178e64e27adfae7206 Mon Sep 17 00:00:00 2001 From: Daniel Gergely Date: Tue, 11 Aug 2026 15:24:56 +0200 Subject: [PATCH 2/3] [T3374] FIX: let communication refresh delete its own attachments --- partner_communication/models/communication_attachment.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/partner_communication/models/communication_attachment.py b/partner_communication/models/communication_attachment.py index a55d938ee..f43bdd918 100644 --- a/partner_communication/models/communication_attachment.py +++ b/partner_communication/models/communication_attachment.py @@ -92,7 +92,9 @@ def create(self, vals): def unlink(self): attachments = self.mapped("attachment_id") super().unlink() - attachments.unlink() + # Deleting the ir.attachment is internal to deleting its wrapper record, + # which was already access-checked. + attachments.sudo().unlink() return True def print_attachments(self, output_tray=None): From aff5d8e27ff174c7a331eed4a36ecf995e4cc839 Mon Sep 17 00:00:00 2001 From: Daniel Gergely Date: Wed, 12 Aug 2026 11:55:30 +0200 Subject: [PATCH 3/3] [T3374] FIX: added HTTP timeouts to the GMC connector --- .../tools/onramp_connector.py | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/message_center_compassion/tools/onramp_connector.py b/message_center_compassion/tools/onramp_connector.py index 63283f40f..e83ed7de3 100644 --- a/message_center_compassion/tools/onramp_connector.py +++ b/message_center_compassion/tools/onramp_connector.py @@ -22,6 +22,11 @@ _logger = logging.getLogger(__name__) +# requests has no default timeout: without this a non-responding GMC blocks the +# worker until the Odoo time limit kills it (up to 8h), holding its queue channel. +# (connect, read) seconds. +GMC_TIMEOUT = (10, 60) + class OnrampConnector: """Singleton class to connect to U.S. Onramp in order to send @@ -113,14 +118,26 @@ def send_message( while not isinstance(r, requests.Response) and count < 5: try: if message_type in ("GET", "GET_RAW"): - r = self._session.get(url, headers=headers, params=params) + r = self._session.get( + url, headers=headers, params=params, timeout=GMC_TIMEOUT + ) elif message_type == "POST": r = self._session.post( - url, headers=headers, json=body, params=params, data=data + url, + headers=headers, + json=body, + params=params, + data=data, + timeout=GMC_TIMEOUT, ) elif message_type == "PUT": r = self._session.put( - url, headers=headers, json=body, params=params, data=data + url, + headers=headers, + json=body, + params=params, + data=data, + timeout=GMC_TIMEOUT, ) else: return {"code": 404, "Error": "No valid HTTP verb used"} @@ -181,7 +198,11 @@ def get_gmc_token(cls, env): "Content-type": "application/x-www-form-urlencoded", } response = requests.post( - provider, data=params_post, auth=(client, secret), headers=header_post + provider, + data=params_post, + auth=(client, secret), + headers=header_post, + timeout=GMC_TIMEOUT, ) try: token = response.json()