Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
96 changes: 96 additions & 0 deletions connector_woocommerce_wpml/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
==========================
Connector WooCommerce WMPL
==========================

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

.. |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_wpml
:alt: NuoBiT/odoo-addons

|badge1| |badge2| |badge3|

- This module works with plugin WordPress Multi Language.
- https://wpml.org/

**Table of contents**

.. contents::
:local:

Configuration
=============

Required WooCommerce Plugin
---------------------------

This module requires the **WooCommerce WPML API REST Extension** plugin
to function properly.

Plugin URL:
https://github.com/nuobit/woocommerce-wpml-api-rest-extension

This plugin is necessary to work around several bugs in the WPML REST
API related to:

- Language parameter handling
- Retrieving language-specific product data
- Setting and updating content per language

Without this extension, the connector will not be able to properly
synchronize multilingual content between Odoo and WooCommerce.

Known issues / Roadmap
======================

For a better maintenance, we can try to use a mixin component to define
the common methods and properties.

- binding: woocommerce_lang field and sql_constrains
woocommerce_internal_uniq overwriting the common for all
- export_mapper: Include the translation_of and lang?

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_wpml%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
- 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_wpml>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions connector_woocommerce_wpml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
28 changes: 28 additions & 0 deletions connector_woocommerce_wpml/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 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)

{
"name": "Connector WooCommerce WMPL",
"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": [
"connector_woocommerce",
"connector_wordpress_wpml",
],
"data": [
"views/woocommerce_backend_view.xml",
"views/product_attribute_value.xml",
"views/product_product.xml",
"views/product_public_category.xml",
"views/product_template.xml",
],
}
9 changes: 9 additions & 0 deletions connector_woocommerce_wpml/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from . import product
from . import product_wpml_mixin
from . import backend
from . import binding
from . import product_attribute_value
from . import product_product
from . import product_public_category
from . import product_template
from . import sale_order
1 change: 1 addition & 0 deletions connector_woocommerce_wpml/models/backend/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import backend
28 changes: 28 additions & 0 deletions connector_woocommerce_wpml/models/backend/backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 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 import _, api, models
from odoo.exceptions import ValidationError

_logger = logging.getLogger(__name__)


class WooCommerceBackend(models.Model):
_inherit = "woocommerce.backend"

@api.constrains("lang_ids")
def check_lang_ids(self):
for rec in self:
for lang in rec.lang_ids:
if not lang.wordpress_wpml_lang_code:
raise ValidationError(
_(
"The language %(lang)s has no WPML code, please define "
"this code in language before using it."
)
% {
"lang": lang.name,
}
)
1 change: 1 addition & 0 deletions connector_woocommerce_wpml/models/binding/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import binding
25 changes: 25 additions & 0 deletions connector_woocommerce_wpml/models/binding/binding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2025 NuoBiT Solutions - Eric Antones <eantones@nuobit.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class WoocommerceWPMLBindingMixin(models.AbstractModel):
_name = "woocommerce.wpml.binding.mixin"
_description = "WooCommerce WPML Binding Mixin"

woocommerce_lang = fields.Char(
string="Language",
required=True,
)

# overwrite the constraint of the parent with the lang field
# the names should be this one to be sure they overwrite the parents
_sql_constraints = [
(
"internal_uniq",
"unique(backend_id, odoo_id, woocommerce_lang)",
"A binding already exists with the same language, "
"hence with the same Internal (Odoo) ID.",
),
]
1 change: 1 addition & 0 deletions connector_woocommerce_wpml/models/product/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import export_mapper
11 changes: 11 additions & 0 deletions connector_woocommerce_wpml/models/product/export_mapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# 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 WooCommerceProductExportMapper(AbstractComponent):
_inherit = "woocommerce.product.export.mapper"

def _get_lang_doc(self, obj):
return obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import adapter
from . import binder
from . import binding
from . import export_mapper
from . import exporter
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 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 Component


class WooCommerceProductAttributeValueAdapter(Component):
_name = "woocommerce.product.attribute.value.adapter"
_inherit = [
"woocommerce.product.attribute.value.adapter",
"woocommerce.product.wpml.mixin.adapter",
]

def _get_search_fields(self):
return self.wpml_get_search_fields()

# def _domain_to_normalized_dict(self, real_domain):
# return self.wpml_domain_to_normalized_dict(real_domain)

def _extract_domain_clauses(self, domain, search_fields):
return self.wpml_extract_domain_clauses(domain, search_fields)
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 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 Component


class WooCommerceProductAttributeValueBinder(Component):
_name = "woocommerce.product.attribute.value.binder"
_inherit = [
"woocommerce.product.attribute.value.binder",
"woocommerce.product.wpml.mixin.binder",
]

@property
def external_alt_id(self):
return super().external_alt_id + ["lang"]

def get_binding_domain(self, record):
return self.wpml_get_binding_domain(record)

def _additional_external_binding_fields(self, external_data, relation):
return self.wpml_additional_external_binding_fields(external_data, relation)

def wpml_additional_external_binding_fields(self, external_data, relation):
return {
**super().wpml_additional_external_binding_fields(external_data, relation),
"woocommerce_master_lang": relation._context["first_lang"],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright NuoBiT Solutions - Kilian Niubo <kniubo@nuobit.com>
# Copyright 2025 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)

from odoo import _, api, fields, models
from odoo.exceptions import ValidationError

from ..binding.binding import WoocommerceWPMLBindingMixin


class WooCommerceProductAttributeValue(models.Model):
_name = "woocommerce.product.attribute.value"
_inherit = [
"woocommerce.product.attribute.value",
"woocommerce.wpml.binding.mixin",
]

# TODO: add this to the mixin
woocommerce_master_lang = fields.Boolean(
string="WooCommerce Master Language",
readonly=True,
required=True,
default=False,
)

_sql_constraints = WoocommerceWPMLBindingMixin._sql_constraints

@api.constrains("woocommerce_master_lang", "backend_id", "odoo_id")
def _check_woocommerce_master_lang(self):
for rec in self:
master_bindings = rec.odoo_id.woocommerce_bind_ids.filtered(
lambda x, rec=rec: x.backend_id == rec.backend_id
and x.woocommerce_master_lang
)
if len(master_bindings) != 1:
raise ValidationError(
_(
"It should always be one and exactly one binding with"
" master language enabled"
)
)
Loading
Loading