From 3e28b1322274e97b8977573e28776f2817cf20a2 Mon Sep 17 00:00:00 2001 From: Eric Antones Date: Tue, 18 Nov 2025 12:42:04 +0100 Subject: [PATCH 1/2] [REF] connector_extension: added binder hook for binding export values and added docstrings --- connector_extension/common/tools.py | 5 +++++ connector_extension/components/binder.py | 22 ++++++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/connector_extension/common/tools.py b/connector_extension/common/tools.py index 2e10462b7..81ce86a84 100644 --- a/connector_extension/common/tools.py +++ b/connector_extension/common/tools.py @@ -124,6 +124,11 @@ def slugify(value): def trim_domain(domain): + """ + Takes an Odoo-style domain (a Python list of clauses) and returns a new domain where + any string values in the third position of 3‑element clauses have leading/trailing + whitespace removed. + """ trimmed_domain = [] for d in domain: if isinstance(d, (list, tuple)): diff --git a/connector_extension/components/binder.py b/connector_extension/components/binder.py index 70048a5b2..29b22c558 100644 --- a/connector_extension/components/binder.py +++ b/connector_extension/components/binder.py @@ -275,6 +275,16 @@ def bind_import(self, external_data, values, sync_date, for_create=False): } ) + def _prepare_binding_export_values(self, relation_id, external_data): + external_id = self.dict2id(external_data, in_field=False) + return { + self._backend_field: self.backend_record.id, + self._odoo_field: relation_id, + self._sync_date_field: fields.Datetime.now(), + **self.id2dict(external_id, in_field=True), + **self._additional_external_binding_fields(external_data), + } + def bind_export(self, external_data, relation): """Create the link between an external ID and an Odoo ID @@ -295,17 +305,9 @@ def bind_export(self, external_data, relation): else: relation_id = relation - external_id = self.dict2id(external_data, in_field=False) with self._retry_unique_violation(): - binding = self.model.with_context(connector_no_export=True).create( - { - self._backend_field: self.backend_record.id, - self._odoo_field: relation_id, - self._sync_date_field: fields.Datetime.now(), - **self.id2dict(external_id, in_field=True), - **self._additional_external_binding_fields(external_data), - } - ) + values = self._prepare_binding_export_values(relation_id, external_data) + binding = self.model.with_context(connector_no_export=True).create(values) # Eager commit to avoid having 2 jobs # exporting at the same time. The constraint # will pop if an other job already created From 8ddca89079e4515774aa7502fbdfd975383aa6a7 Mon Sep 17 00:00:00 2001 From: ??? Date: Wed, 1 Apr 2026 11:16:28 +0200 Subject: [PATCH 2/2] [FIX] connector_extension: remove cr.commit() from bind_export In Odoo 18, queue_job forbids commits during job execution via _prevent_commit to avoid releasing the job lock prematurely. The cr.commit() in bind_export was an optimization for concurrent binding creation that is no longer compatible. The _retry_unique_violation context manager still handles race conditions via PostgreSQL's UNIQUE constraint without needing an explicit commit. --- connector_extension/components/binder.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/connector_extension/components/binder.py b/connector_extension/components/binder.py index 29b22c558..afcf21922 100644 --- a/connector_extension/components/binder.py +++ b/connector_extension/components/binder.py @@ -18,7 +18,6 @@ import psycopg2 -import odoo from odoo import _, fields, models from odoo.exceptions import ValidationError from odoo.osv import expression @@ -308,13 +307,6 @@ def bind_export(self, external_data, relation): with self._retry_unique_violation(): values = self._prepare_binding_export_values(relation_id, external_data) binding = self.model.with_context(connector_no_export=True).create(values) - # Eager commit to avoid having 2 jobs - # exporting at the same time. The constraint - # will pop if an other job already created - # the same binding. It will be caught and - # raise a RetryableJobError. - if not odoo.tools.config["test_enable"]: - self.env.cr.commit() # pylint: disable=E8102 return binding def _additional_external_binding_fields(self, external_data):