Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
9151557
[ADD] connector_extension: New Module
KNVx Mar 23, 2023
bd60b1c
[FIX] connector_extension: pre-commit, company name
eantones Apr 30, 2023
82afcce
[IMP] connector_extension: added generic get version on check connection
eantones May 1, 2023
e0d1b21
[FIX] connector_extension: id fields method returns the fields itself…
eantones May 15, 2023
498936b
[IMP] connector_extension: improvements
KNVx May 11, 2023
59dd9e2
[IMP] connector_extension: split into specific connectors
eantones Jun 20, 2023
d1de5ec
[ADD] connector_extension_sql: new module
eantones Jun 20, 2023
2aeca94
[ADD] connector_extension_mysql: new module
eantones Jun 20, 2023
7c54404
[ADD] connector_extension_mssql: new module
eantones Jun 20, 2023
6d464f0
[IMP] connector_extension: pre-commit stuff
eantones Jun 22, 2023
3a39b85
[FIX] connector_extension: sync_date parameter not found
eantones Jun 27, 2023
8894dc5
[FIX] connector_extension: unwrap_binding return a binding instead of…
KNVx Jun 26, 2023
c9e013d
[FIX] connector_extension: binding is nor returned on run when it's c…
KNVx Jul 6, 2023
7c898cb
[FIX] connector_extension: batch delayed disabled, enable again
eantones Jul 9, 2023
5a096fc
[FIX] connector_extension: names of components are wrong. delayed.chu…
KNVx Jul 10, 2023
28c884a
[IMP] connector_extension: added sync offset because sometimes in som…
eantones Jul 12, 2023
501292e
[IMP] connector_extension: removed useless code (__init__ _delay_impo…
KNVx Jul 19, 2023
846a7db
[IMP] connector_extension: Refactor get_external_dict_ids to remove f…
KNVx Jul 19, 2023
706b130
[FIX] connector_extension: filter by hash is mapping 'veloconnect_hash'
KNVx Jul 20, 2023
8f955b2
[IMP] connector_extension: Included page_size on backend
KNVx Jul 31, 2023
4817295
[IMP] connector_extension: included parameter unwrap in dict2id to re…
KNVx Jul 26, 2023
a06678f
[IMP] connector_extension: tools are included in common dir
KNVx Jul 20, 2023
19e8304
[IMP] connector_extension: Included trim_domain on tools. This functi…
KNVx Jul 24, 2023
4936151
[IMP] connector_extension: hooks created on importer on _create and _…
KNVx Aug 1, 2023
d268926
[IMP] connector_extension: pre-commit stuff
eantones Oct 2, 2023
cacc2f9
[IMP] connector_extension: Generic Batch Exporters created on exporter
KNVx Jul 19, 2023
e06f072
[IMP] connector_extension: adapter, backend, binding and mapper creat…
KNVx Aug 1, 2023
9ddea8c
[IMP] connector_extension: Created generic batch, chunk and record on…
KNVx Aug 1, 2023
39c03f7
[IMP] Connector_extension: Included hook on _lock to be inhereted
KNVx Aug 9, 2023
281f563
[IMP] Connector_extension: commit is done before binding creation
KNVx Aug 9, 2023
581c198
[IMP] connector_extension: License is updated to LPGL-3.0.
KNVx Oct 11, 2023
08ed1cd
[IMP] connector_extension: removed adapters woocommerce and wordpress…
KNVx Oct 16, 2023
b625028
[IMP] connector_extension: wrap_binding function on binder has been r…
KNVx Oct 16, 2023
c6f8eb4
[IMP] connector_extension: _usage in batch exporter and batch importe…
KNVx Oct 16, 2023
eb4e0ec
[IMP] connector_extension: run of exporter refactor. New decorator at…
KNVx Oct 16, 2023
ab5c842
[IMP] connector_extension: _description created on connector extensio…
KNVx Oct 19, 2023
22bc73c
[REF] connector_extension: Update copier template
eantones Oct 31, 2023
f0d59d8
[REF] connector_extension: pre-commit check
eantones Oct 31, 2023
7f113ea
[IMP] connector_extension: renamed binder exporter importer and mappe…
KNVx Oct 31, 2023
e994162
[IMP] connector_extension: refactored _get_external_record_alt and to…
KNVx Oct 24, 2023
f652568
[ADD] connector_extension: Commit in Importer to avoid listener/expor…
KNVx Oct 26, 2023
ab0c342
Revert "[IMP] connector_extension: run of exporter refactor. New deco…
KNVx Oct 30, 2023
097ab47
[IMP] connector_extension: refactored run and export dependencies
KNVx Oct 31, 2023
bc657ad
[FIX] connector_extension: id2dict returns an incorrect string when e…
KNVx Dec 19, 2023
527bd6c
[IMP]connector_extension: _convert_format is modified to don't restri…
KNVx Jan 4, 2024
4ba0f72
[IMP] connector_extension: binder is defined with self.binder_for
KNVx Jan 4, 2024
2b86b59
[IMP] connector_extension: use_data is a new parameter to use the ext…
KNVx Jan 4, 2024
7d022e6
[IMP] connector_extension: Import batch call run with the new paramet…
KNVx Jan 4, 2024
7722fe5
[IMP] connector_extension: binding included as a parameter in _after_…
KNVx Jan 23, 2024
190f5bb
[FIX] connector_extension: lock is done in all relations but it's no …
KNVx May 21, 2024
b6d3d2c
[FIX] connector_extension: wrap record throws an error because don't …
KNVx May 21, 2024
2d8831b
[IMP] connector_extension: hook to modify domain on wrap_record
KNVx Jul 12, 2024
fc9165b
[FIX] connector_extension: Incorrect error message without parameters…
KNVx Jul 17, 2024
7ea3659
[IMP] connector_extension: included function on tools to convert rgb …
KNVx Jul 30, 2024
015f78b
[IMP] connector_extension: removed _find_binding and improved wrap_re…
KNVx Jul 17, 2024
551188a
[IMP] connector_extension: included deleter and listener to delete ex…
KNVx Jul 31, 2024
2498d70
[IMP] connector_extension: improved resync to force to export all the…
KNVx Aug 8, 2024
7101e75
[IMP] connector_extension
deeniiz Jul 29, 2025
a5c7c4a
Revert "[IMP] connector_extension"
eantones Aug 11, 2025
30acfdf
[IMP] connector_extension
deeniiz Jul 29, 2025
b87a310
[REF] connector_extension: added binder hook for binding export value…
eantones Nov 18, 2025
47f2092
[IMP+FIX+REF] connector_extension
eantones Dec 2, 2025
6589e3d
[IMP] connector_extension: added log call in backend
eantones Dec 24, 2025
8555e8a
[IMP] connector_extension: pre-commit auto fixes
deeniiz Mar 31, 2026
a59a839
[MIG] connector_extension: Migration to 18.0
deeniiz Mar 31, 2026
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
86 changes: 86 additions & 0 deletions connector_extension/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
===================
Connector Extension
===================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:39b64c10f88d1224bc1e05fc967b018cce54a165a66cc8fd65dbf1c03f196c2d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-NuoBiT%2Fodoo--addons-lightgray.png?logo=github
:target: https://github.com/NuoBiT/odoo-addons/tree/18.0/connector_extension
:alt: NuoBiT/odoo-addons

|badge1| |badge2| |badge3|

The "connector_extension" module is an add-on for the Odoo ERP system
that enhances the functionality of the base "connector" module. This
extension provides additional features, tools, and integrations, making
it easier for developers to create, manage, and maintain connections
between Odoo and various third-party systems, APIs, or services.

The module aims to simplify the connector development process by
providing a robust and flexible framework. The "connector_extension"
module allows developers to focus on implementing specific business
logic and requirements, while the extension handles common tasks.

- Extended connector framework: The module extends the base connector
framework by providing new classes, methods, and utilities for easier
integration with third-party systems.
- Reusable components: Pre-built components for handling common tasks
such error handling, and data synchronization.
- Enhanced data mapping: Advanced data mapping capabilities to transform
and adapt data between Odoo and external systems seamlessly.
- Scalability and performance improvements: Optimized for handling large
datasets and concurrent connections, ensuring smooth and efficient
data synchronization.
- Linking with existing records: Enables linking with existing records,
using alternate keys, which allows for easier data management and
reduced redundancy.

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/NuoBiT/odoo-addons/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/NuoBiT/odoo-addons/issues/new?body=module:%20connector_extension%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* NuoBiT Solutions SL

Contributors
------------

- `NuoBiT <https://www.nuobit.com>`__:

- Kilian Niubo kniubo@nuobit.com
- Eric Antones eantones@nuobit.com

Maintainers
-----------

This module is part of the `NuoBiT/odoo-addons <https://github.com/NuoBiT/odoo-addons/tree/18.0/connector_extension>`_ project on GitHub.

You are welcome to contribute.
2 changes: 2 additions & 0 deletions connector_extension/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import components
from . import models
17 changes: 17 additions & 0 deletions connector_extension/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright NuoBiT Solutions SL - Kilian Niubo <kniubo@nuobit.com>
# Copyright NuoBiT Solutions SL - Eric Antones <eantones@nuobit.com>
# Copyright 2025 NuoBiT Solutions SL - Deniz Gallo <dgallo@nuobit.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)

{
"name": "Connector Extension",
"summary": "This module extends the connector module",
"version": "18.0.1.0.0",
"author": "NuoBiT Solutions SL",
"license": "LGPL-3",
"category": "Connector",
"website": "https://github.com/NuoBiT/odoo-addons",
"depends": ["connector"],
# The dependency on queue_context is necessary so that
# when a job calls another job, the company is not lost
}
168 changes: 168 additions & 0 deletions connector_extension/common/tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Copyright NuoBiT Solutions SL - Eric Antones <eantones@nuobit.com>
# Copyright NuoBiT Solutions SL - Kilian Niubo <kniubo@nuobit.com>
# Copyright 2025 NuoBiT Solutions SL - Deniz Gallo <dgallo@nuobit.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)
import datetime
import hashlib
import re
import unicodedata

from odoo import _
from odoo.exceptions import ValidationError


def list2hash(_list):
_hash = hashlib.sha256()
for e in _list:
if isinstance(e, int):
e9 = str(e)
elif isinstance(e, str):
e9 = e
elif isinstance(e, float):
e9 = str(e)
elif e is None:
e9 = ""
else:
raise Exception(f"Unexpected type for a key: type {type(e)}")
_hash.update(e9.encode("utf8"))
return _hash.hexdigest()


def domain_to_normalized_dict(self, domain):
"""Convert, if possible, standard Odoo domain to a dictionary.
To do so it is necessary to convert all operators to
equal '=' operator.
"""
res = {}
for elem in domain:
if len(elem) != 3:
raise ValidationError(_("Wrong domain clause format %s") % elem)
field, op, value = elem
if op == "=":
if field in res:
raise ValidationError(_("Duplicated field %s") % field)
res[field] = self._normalize_value(value)
elif op == "!=":
if not isinstance(value, bool):
raise ValidationError(
_("Not equal operation not supported for non boolean fields")
)
if field in res:
raise ValidationError(_("Duplicated field %s") % field)
res[field] = self._normalize_value(not value)
elif op == "in":
if not isinstance(value, (tuple | list)):
raise ValidationError(
_(
"Operator '%(OPERATOR)s' only supports "
"tuples or lists, not %(TYPES)s"
)
% {
"OPERATOR": op,
"TYPES": type(value),
}
)
if field in res:
raise ValidationError(_("Duplicated field %s") % field)
res[field] = self._normalize_value(value)
elif op in (">", ">=", "<", "<="):
if not isinstance(value, (datetime.date | datetime.datetime | int)):
raise ValidationError(
_("Type %(value_type)s not supported for operator %(operator)s")
% {"value_type": type(value), "operator": op}
)
if op in (">", "<"):
adj = 1
if isinstance(value, (datetime.date | datetime.datetime)):
adj = datetime.timedelta(days=adj)
if op == "<":
op, value = "<=", value - adj
else:
op, value = ">=", value + adj

res[field] = self._normalize_value(value)
else:
raise ValidationError(_("Operator %s not supported") % op)

return res


def convert_item_to_json(item, ct, namespace):
jitem = {}
for path, func, key, multi in ct:
if key in jitem:
raise ValidationError(_("Key %s already exists") % key)
value = item.xpath(path, namespaces=namespace)
if not value:
jitem[key] = None
else:
if multi:
jitem[key] = func(value)
else:
if len(value) > 1:
raise ValidationError(_("Multiple values found for '%s'") % path)
else:
jitem[key] = func(value[0])
return jitem


def convert_to_json(data, ct, namespace):
res = []
for d in data:
res.append(convert_item_to_json(d, ct, namespace))
return res


def slugify(value):
if not value:
return None
return (
unicodedata.normalize("NFKD", value)
.encode("ascii", "ignore")
.decode("ascii")
.lower()
.replace(" ", "")
)


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)):
if len(d) == 3 and isinstance(d[2], str):
trimmed_domain.append((d[0], d[1], d[2].strip()))
elif len(d) == 3 and isinstance(d[2], (list | tuple)):
trimmed_value = [
value.strip() if isinstance(value, str) else value for value in d[2]
]
trimmed_domain.append((d[0], d[1], trimmed_value))
else:
trimmed_domain.append(d)
else:
raise Exception(f"Unexpected domain format: {d}")
return trimmed_domain


def color_rgb2hex(data):
def conv_rgb(match):
rgb_hex_l = []
groups = match.groups()
for value, percent in zip(groups[0::2], groups[1::2], strict=True):
if percent:
hex_value = round(float(value) * 255 / 100)
else:
hex_value = int(value)
rgb_hex_l.append(f"{hex_value:02X}")
return f'#{"".join(rgb_hex_l)}'

return re.sub(
r"rgb\( *([0-9.]+) *(%?) *, *([0-9.]+) *(%?) *, *([0-9.]+) *(%?) *\)",
conv_rgb,
data,
flags=re.IGNORECASE,
)
9 changes: 9 additions & 0 deletions connector_extension/components/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from . import adapter
from . import binder
from . import synchronizer
from . import export_deleter
from . import exporter
from . import importer
from . import import_deleter
from . import listener
from . import mapper
Loading
Loading