Skip to content

Commit

Permalink
Merge pull request OCA#16 from yibudak/16.0sync
Browse files Browse the repository at this point in the history
16.0sync
  • Loading branch information
yibudak authored Dec 4, 2024
2 parents eba7d1a + 2bccfaa commit 60e2447
Show file tree
Hide file tree
Showing 68 changed files with 1,075 additions and 694 deletions.
51 changes: 22 additions & 29 deletions connector_odoo/components/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def _export_record(self, external_id, job_options=None, **kwargs):
delayable = external_id.with_delay(
channel=self.model._unique_channel_name,
priority=self.model._priority,
**job_options or {}
**job_options or {},
)
delayable.export_record(self.backend_record, **kwargs)

Expand All @@ -163,6 +163,13 @@ class OdooExporter(AbstractComponent):
def __init__(self, working_context):
super(OdooExporter, self).__init__(working_context)
self.binding = None
self.job_uuid = None

def _connect_with_job(self, context_dict):
"""Save job_uuid in context to match write external odoo id to the job"""
if job_uuid := context_dict.get("job_uuid"):
self.job_uuid = job_uuid
return True

def _lock(self):
"""Lock the binding record.
Expand Down Expand Up @@ -192,9 +199,18 @@ def _lock(self):
seconds=5,
)

# def _has_to_skip(self):
# """Return True if the export can be skipped"""
# return False
def _link_queue_job(self, binding):
# Add relation between job and binding, so we can monitor the process
if binding and self.job_uuid:
job_id = self.env["queue.job"].search([("uuid", "=", self.job_uuid)])
if job_id:
job_id.write(
{
"odoo_binding_model_name": binding.odoo_id._name,
"odoo_binding_id": binding.odoo_id.id,
}
)
self.env.cr.commit() # Commit in case of a failure in the next steps

@contextmanager
def _retry_unique_violation(self):
Expand Down Expand Up @@ -354,25 +370,6 @@ def _map_data(self):
"""
return self.mapper.map_record(self.binding)

def _validate_create_data(self, data):
"""Check if the values to import are correct
Pro-actively check before the ``Model.create`` if some fields
are missing or invalid
Raise `InvalidDataError`
"""
return

def _validate_update_data(self, data):
"""Check if the values to import are correct
Pro-actively check before the ``Model.update`` if some fields
are missing or invalid
Raise `InvalidDataError`
"""
return

def _create_data(self, map_record, fields=None, **kwargs):
"""Get the data to pass to :py:meth:`_create`"""
# datas = ast.literal_eval(
Expand All @@ -384,8 +381,6 @@ def _create_data(self, map_record, fields=None, **kwargs):

def _create(self, data):
"""Create the Odoo record"""
# special check on data before export
self._validate_create_data(data)
return self.backend_adapter.create(data)

def _update_data(self, map_record, fields=None, **kwargs):
Expand All @@ -395,8 +390,6 @@ def _update_data(self, map_record, fields=None, **kwargs):
def _update(self, data):
"""Update an Odoo record"""
assert self.external_id
# special check on data before export
self._validate_update_data(data)
self.backend_adapter.write(self.external_id, data)

def _run(self, fields=None):
Expand All @@ -406,8 +399,8 @@ def _run(self, fields=None):
if not self.external_id:
fields = None # should be created with all the fields

# if self._has_to_skip():
# return _("Export skipped.")
# Add relation between job and binding, so we can monitor the process
# self._link_queue_job(self.binding)

# run some logic before the export
self._before_export()
Expand Down
87 changes: 63 additions & 24 deletions connector_odoo/components/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
from odoo.tools import frozendict

from odoo.addons.component.core import AbstractComponent
from odoo.addons.connector.exception import IDMissingInBackend
from odoo.addons.connector.exception import IDMissingInBackend, RetryableJobError
from odoo.addons.queue_job.exception import NothingToDoJob
from psycopg2.extras import Json

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -154,6 +155,19 @@ def _must_skip(self):
# data.update({"external_id": binding.external_id})
# return binding

def _link_queue_job(self, binding):
# Add relation between job and binding, so we can monitor the process
if binding and self.job_uuid:
job_id = self.env["queue.job"].search([("uuid", "=", self.job_uuid)])
if job_id:
job_id.write(
{
"odoo_binding_model_name": binding.odoo_id._name,
"odoo_binding_id": binding.odoo_id.id,
}
)
self.env.cr.commit() # Commit in case of a failure in the next steps

def _get_binding(self):
return self.binder.to_internal(self.external_id)

Expand Down Expand Up @@ -194,6 +208,42 @@ def _update(self, binding, data):
_logger.info("%d updated from Odoo %s", binding, self.external_id)
return

def _translate_fields(self, binding):
"""
Update translations for translatable fields with Odoo 16.0's new
update_field_translations method. `translated_fields` is a dictionary
that contains the translations for each field. Example:
{field_name: {lang: new_value}}
Also we need to check if the field has translate=True in the model.
"""
if not (binding and self.odoo_record.get("translated_fields")):
return False

for field, translations in self.odoo_record["translated_fields"].items():
target_field = binding._fields.get(field)
if target_field and target_field.translate:
if target_field.type != "html":
binding.update_field_translations(field, translations)
else: # HTML field requires a different approach
source_lang = self.backend_record.default_lang_id.code
for lang, value in translations.items():
if value:
binding.odoo_id._cr.execute(
f"""
UPDATE "{binding.odoo_id._table}"
SET "{field}" = NULLIF(
jsonb_strip_nulls(%s || COALESCE("{field}", '{{}}'::jsonb) || %s),
'{{}}'::jsonb)
WHERE id = %s
""",
(
Json({source_lang: binding[field]}),
Json({lang: value}),
binding.odoo_id.id,
),
)
return True

def _commit(self):
"""Committing the current transaction will also execute compute methods.
We want to pass the additional context to the compute methods. That's why
Expand Down Expand Up @@ -240,15 +290,6 @@ def _after_import(self, binding, force=False):
"""
return True

def _get_binding_odoo_id_changed(self, binding):
# It is possible that OpenERP/Odoo deletes and creates records
# instead of editing the information.
#
# e.g. In OpenERP it happens with ir.translation.
#
# This method will get the binding if needed
return binding

def set_lock(self, external_id):
lock_name = "import({}, {}, {}, {})".format(
self.backend_record._name,
Expand Down Expand Up @@ -296,20 +337,8 @@ def run(self, external_id, force=False):
_logger.info("Already up-to-date")
return _("Already up-to-date.")

if not binding:
binding = self._get_binding_odoo_id_changed(binding)
# self._link_queue_job(binding)

# Add relation between job and binding, so we can monitor the import
if binding and self.job_uuid:
job_id = self.env["queue.job"].search([("uuid", "=", self.job_uuid)])
if job_id:
job_id.write(
{
"odoo_binding_model_name": binding.odoo_id._name,
"odoo_binding_id": binding.odoo_id.id,
}
)
self.env.cr.commit() # Commit in case of a failure in the next steps
self._before_import()

# import the missing linked resources
Expand All @@ -333,7 +362,17 @@ def run(self, external_id, force=False):
self.external_id, e
)
)
raise # Todo: raise RetryableJobError
raise RetryableJobError(
"An error occurred while connecting the record {}: {}".format(
self.external_id, e
),
seconds=5,
)

_logger.info(
"Translating Fields ({}: {})".format(self.work.model_name, external_id)
)
self._translate_fields(binding)

_logger.info("Binding ({}: {})".format(self.work.model_name, external_id))
self.binder.bind(self.external_id, binding)
Expand Down
130 changes: 0 additions & 130 deletions connector_odoo/components/legacy_adapter.py

This file was deleted.

Loading

0 comments on commit 60e2447

Please sign in to comment.