Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0412906
[ADD] connector_woocommerce
eantones Aug 25, 2025
75de66c
[REF] connector_woocommerce: move product attachment auxiliar fields …
eantones Aug 29, 2025
e01ad80
[TMP] connector_woocommerce: disable slug export on write temporarily
eantones Apr 9, 2025
dc6f152
[FIX] connector_woocommerce: all the external ids of the binding shou…
eantones Nov 18, 2025
256a9f3
[REF] connector_woocommerce: rename account_tax to odoo standard acco…
eantones Nov 18, 2025
de988c4
[FIX+REF] connector_woocommerce: missing export_batch channel
eantones Nov 18, 2025
8a87b1d
[IMP+FIX+REF] connector_woocommerce
eantones Dec 2, 2025
88e52dd
[IMP] connector_woocommerce: added log call in backend
eantones Dec 24, 2025
8afa876
[FIX] connector_woocommerce: wrong channel on export batch product
eantones Dec 26, 2025
effc6fe
[FIX] connector_woocommerce: missing channel product attribute value …
eantones Dec 27, 2025
1cb95e1
[IMP] connector_woocommerce: allow updating category slugs
eantones Jan 26, 2026
5d2722f
[REF] connector_woocommerce: rename some variables
eantones Jan 27, 2026
85b46e6
[IMP] connector_woocommerce: pre-commit auto fixes
deeniiz Mar 27, 2026
2eea45f
[MIG] connector_woocommerce: Migration to 18.0
deeniiz Mar 27, 2026
b3fd10c
[MIG] connector_woocommerce: Migration to 18.0
deeniiz Mar 30, 2026
47112e1
[MIG] connector_woocommerce: Migration to 18.0
deeniiz Mar 30, 2026
b780af4
[MIG] connector_woocommerce: Migration to 18.0
deeniiz Apr 1, 2026
a33d358
[MIG] connector_woocommerce: Migration to 18.0
deeniiz Apr 1, 2026
4d2724c
[MIG] connector_woocommerce: Migration to 18.0
deeniiz Apr 9, 2026
549e721
[MIG] connector_woocommerce: Migration to 18.0
deeniiz Apr 9, 2026
c3c41d3
[MIG] connector_woocommerce: Migration to 18.0
deeniiz Apr 15, 2026
cad20da
[DO NOT MERGE] test-requirements.txt
deeniiz Apr 7, 2026
f1f5f22
[FIX] connector_extension: fix conflict resolution during migration t…
deeniiz Apr 1, 2026
c6e5013
[FIX] connector_extension: remove cr.commit() from bind_export
deeniiz Apr 1, 2026
421dd88
[IMP] connector_extension: change strict parameter to False in dict z…
deeniiz Apr 7, 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
23 changes: 7 additions & 16 deletions connector_extension/components/binder.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import psycopg2

import odoo
from odoo import _, fields, models
from odoo.exceptions import ValidationError
from odoo.osv import expression
Expand Down Expand Up @@ -97,7 +96,7 @@ def id2dict(self, _id, in_field=True, alt_field=False):
if not isinstance(_id, (tuple | list)):
_id = [_id]
fields = self.get_id_fields(in_field=in_field, alt_field=alt_field)
return dict(zip(fields, _id, strict=True))
return dict(zip(fields, _id, strict=False))
else:
return None

Expand Down Expand Up @@ -280,7 +279,6 @@ def bind_import(self, external_data, values, sync_date, for_create=False):
**self.id2dict(external_id, in_field=True),
}
)
self.env.cr.commit() # pylint: disable=E8102

def _prepare_binding_export_values(self, relation, external_data):
external_id = self.dict2id(external_data, in_field=False)
Expand Down Expand Up @@ -313,13 +311,6 @@ def bind_export(self, external_data, relation):
with self._retry_unique_violation():
values = self._prepare_binding_export_values(relation, 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, relation):
Expand Down Expand Up @@ -478,15 +469,15 @@ def to_binding_from_internal_key(self, relation):
:param relation: odoo object, not a binding and without binding
:return: binding
"""
export_mapper = self.component(usage="export.mapper")
mapper_external_data = export_mapper.map_record(relation)
ext_alt_id = getattr(self, self._external_alt_field, None)
if not ext_alt_id:
id_values = {}
else:
if isinstance(ext_alt_id, str):
ext_alt_id = [ext_alt_id]

export_mapper = self.component(usage="export.mapper")
mapper_external_data = export_mapper.map_record(relation)
id_fields = mapper_external_data._mapper.get_target_fields(
mapper_external_data, fields=ext_alt_id
)
Expand Down Expand Up @@ -537,7 +528,7 @@ def to_binding_from_internal_key(self, relation):
import_mapper_exists = False
if not import_mapper_exists:
binding = self.bind_export(record, relation)
binding[self._sync_date_field] = fields.Datetime.now()
# binding[self._sync_date_field] = fields.Datetime.now()
if not binding:
raise InvalidDataError(
f"The binding with external id {external_id} "
Expand All @@ -563,9 +554,9 @@ def get_external_dict_ids(self, relation, check_external_id=True):
external_id = self.to_external(relation, wrap=False)
if check_external_id:
assert external_id, (
f"Unexpected error on {relation._name}:"
"The backend id cannot be obtained."
"At this stage, the backend record should have "
f"Error on {relation._name}:"
"The external id cannot be obtained."
"At this stage, the external record should have "
"been already linked via "
"._export_dependencies. "
)
Expand Down
64 changes: 64 additions & 0 deletions connector_woocommerce/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
=====================
Connector WooCommerce
=====================

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

.. |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-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-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_woocommerce
:alt: NuoBiT/odoo-addons

|badge1| |badge2| |badge3|

Connector WooCommerce

**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_woocommerce%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
- Deniz Gallo dgallo@nuobit.com

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

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

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

{
"name": "Connector WooCommerce",
"version": "18.0.1.0.0",
"author": "NuoBiT Solutions SL",
"license": "AGPL-3",
"category": "Connector",
"website": "https://github.com/NuoBiT/odoo-addons",
"external_dependencies": {
"python": [
"woocommerce",
],
},
"depends": [
"account_payment_sale",
"connector_extension_woocommerce",
"connector_wordpress",
"sale_stock",
"website_sale_extra_fields",
"website_sale_stock_variant",
],
"data": [
"data/ir_cron.xml",
"data/queue_data.xml",
"data/queue_job_function_data.xml",
"security/connector_woocommerce.xml",
"security/ir.model.access.csv",
"views/woocommerce_backend_view.xml",
"views/sale_order_view.xml",
"views/product_template.xml",
"views/woocommerce_product_template.xml",
"views/product_attribute.xml",
"views/product_attribute_value.xml",
"views/product_public_category.xml",
"views/product_product.xml",
"views/res_partner_views.xml",
"views/connector_woocommerce_menu.xml",
],
"installable": True,
}
8 changes: 8 additions & 0 deletions connector_woocommerce/components/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from . import core
from . import adapter
from . import binder
from . import export_deleter
from . import exporter
from . import export_mapper
from . import importer
from . import import_mapper
38 changes: 38 additions & 0 deletions connector_woocommerce/components/adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright NuoBiT Solutions - Kilian Niubo <kniubo@nuobit.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from woocommerce import API as API

from odoo.addons.component.core import AbstractComponent


class ConnectorWooCommerceAdapter(AbstractComponent):
_name = "connector.woocommerce.adapter"
_inherit = [
"connector.extension.woocommerce.adapter.crud",
"base.woocommerce.connector",
]

_description = "WooCommerce Adapter (abstract)"

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.wcapi = API(
url=self.backend_record.url,
consumer_key=self.backend_record.consumer_key,
consumer_secret=self.backend_record.consumer_secret,
version="wc/v3",
verify_ssl=self.backend_record.verify_ssl,
timeout=30,
)

def prepare_meta_data(self, data):
meta_data = []
for field in self._prepare_meta_data_fields():
if field in data:
meta_data.append({"key": field, "value": data[field]})
data.pop(field)
return meta_data

def _prepare_meta_data_fields(self):
return []
12 changes: 12 additions & 0 deletions connector_woocommerce/components/binder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright NuoBiT Solutions - Kilian Niubo <kniubo@nuobit.com>
# Copyright 2026 NuoBiT Solutions SL - Deniz Gallo <dgallo@nuobit.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from odoo.addons.component.core import AbstractComponent


class WooCommerceBinder(AbstractComponent):
_name = "woocommerce.binder"
_inherit = ["connector.extension.binder", "base.woocommerce.connector"]

_default_binding_field = "woocommerce_bind_ids"
12 changes: 12 additions & 0 deletions connector_woocommerce/components/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright NuoBiT Solutions - Kilian Niubo <kniubo@nuobit.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from odoo.addons.component.core import AbstractComponent


class BaseWooCommerceConnector(AbstractComponent):
_name = "base.woocommerce.connector"
_inherit = "base.connector"
_collection = "woocommerce.backend"

_description = "Base WooCommerce Connector Component"
31 changes: 31 additions & 0 deletions connector_woocommerce/components/export_deleter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright NuoBiT Solutions - Kilian Niubo <kniubo@nuobit.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

import logging

from odoo.addons.component.core import AbstractComponent

_logger = logging.getLogger(__name__)


class WooCommerceRecordDirectExportDeleter(AbstractComponent):
"""Base Deleter for WooCommerce"""

_name = "woocommerce.record.direct.export.deleter"
_inherit = [
"connector.extension.record.direct.export.deleter",
"base.woocommerce.connector",
]


class WooCommerceBatchExportDeleter(AbstractComponent):
"""The role of a BatchDeleter is to delete for a list of
items to delete, then it can either delete them directly or delay
the delete of each item separately.
"""

_name = "woocommerce.batch.export.deleter"
_inherit = [
"connector.extension.batch.export.deleter",
"base.woocommerce.connector",
]
14 changes: 14 additions & 0 deletions connector_woocommerce/components/export_mapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright NuoBiT Solutions - Kilian Niubo <kniubo@nuobit.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from odoo.addons.component.core import AbstractComponent


class WooCommerceExportMapper(AbstractComponent):
_name = "woocommerce.export.mapper"
_inherit = ["connector.extension.export.mapper", "base.woocommerce.connector"]


class WooCommerceExportMapChild(AbstractComponent):
_name = "woocommerce.map.child.export"
_inherit = ["connector.extension.map.child.export", "base.woocommerce.connector"]
33 changes: 33 additions & 0 deletions connector_woocommerce/components/exporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright NuoBiT Solutions - Eric Antones <eantones@nuobit.com>
# Copyright NuoBiT Solutions - Kilian Niubo <kniubo@nuobit.com>
# Copyright 2026 NuoBiT Solutions SL - Deniz Gallo <dgallo@nuobit.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

import logging

from odoo.addons.component.core import AbstractComponent

_logger = logging.getLogger(__name__)


class WooCommerceRecordDirectExporter(AbstractComponent):
"""Base Exporter for WooCommerce"""

_name = "woocommerce.record.direct.exporter"
_inherit = [
"connector.extension.record.direct.exporter",
"base.woocommerce.connector",
]


class WooCommerceBatchExporter(AbstractComponent):
"""The role of a BatchExporter is to search for a list of
items to export, then it can either export them directly or delay
the export of each item separately.
"""

_name = "woocommerce.batch.exporter"
_inherit = [
"connector.extension.batch.exporter",
"base.woocommerce.connector",
]
14 changes: 14 additions & 0 deletions connector_woocommerce/components/import_mapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright NuoBiT Solutions - Kilian Niubo <kniubo@nuobit.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from odoo.addons.component.core import AbstractComponent


class WooCommerceImportMapper(AbstractComponent):
_name = "woocommerce.import.mapper"
_inherit = ["connector.extension.import.mapper", "base.woocommerce.connector"]


class WooCommerceImportMapChild(AbstractComponent):
_name = "woocommerce.map.child.import"
_inherit = ["connector.extension.map.child.import", "base.woocommerce.connector"]
32 changes: 32 additions & 0 deletions connector_woocommerce/components/importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright NuoBiT Solutions - Eric Antones <eantones@nuobit.com>
# Copyright NuoBiT Solutions - Kilian Niubo <kniubo@nuobit.com>
# Copyright 2026 NuoBiT Solutions SL - Deniz Gallo <dgallo@nuobit.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
import logging

from odoo.addons.component.core import AbstractComponent

_logger = logging.getLogger(__name__)


class WooCommerceDirectImporter(AbstractComponent):
"""Base importer for WooCommerce"""

_name = "woocommerce.record.direct.importer"
_inherit = [
"connector.extension.record.direct.importer",
"base.woocommerce.connector",
]


class WooCommerceBatchImporter(AbstractComponent):
"""The role of a BatchImporter is to search for a list of
items to import, then it can either import them directly or delay
the import of each item separately.
"""

_name = "woocommerce.batch.importer"
_inherit = [
"connector.extension.batch.importer",
"base.woocommerce.connector",
]
Loading
Loading