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
112 changes: 112 additions & 0 deletions website_sale_hide_no_variant_attributes/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=======================================
Website Sale Hide No Variant Attributes
=======================================

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

.. |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/license-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-OCA%2Fe--commerce-lightgray.png?logo=github
:target: https://github.com/OCA/e-commerce/tree/19.0/website_sale_hide_no_variant_attributes
:alt: OCA/e-commerce
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/e-commerce-19-0/e-commerce-19-0-website_sale_hide_no_variant_attributes
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/e-commerce&target_branch=19.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module keeps attributes that never generate a variant (attributes
with their *Variant Creation* setting on *Never*, e.g. purely
informational specs) out of the website product page's variant selector,
and out of the combination-exclusion rules used to gray out incompatible
options.

Without this module, an informational attribute's value can still
exclude a real, variant-defining value through a configured *Exclude
for* rule, even though the informational attribute itself is never shown
to the shopper as a selectable option — resulting in a visible option
being grayed out because of an attribute the shopper cannot see, with a
tooltip naming it.

**Table of contents**

.. contents::
:local:

Usage
=====

This module requires no configuration: it applies automatically to every
product attribute whose *Variant Creation* is set to *Never*.

1. On a product, add an attribute with *Variant Creation* set to *Never*
(e.g. an informational spec such as a material or a care
instruction), alongside your normal variant-defining attributes.
2. Optionally, configure an *Exclude for* rule on one of that
attribute's values, targeting one of the variant-defining values.
3. Open the product page on the website: the informational attribute no
longer appears in the variant selector, and the variant-defining
value targeted by its exclusion rule is no longer grayed out because
of it.
4. Add the product to the cart: the hidden informational attribute never
blocks *Add to Cart*, even when its excluded or default value would
have conflicted with the one visibly selected.

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/e-commerce/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/OCA/e-commerce/issues/new?body=module:%20website_sale_hide_no_variant_attributes%0Aversion:%2019.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
-------

* Camptocamp

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

- `Camptocamp <https://www.camptocamp.com/>`__:

- Ricardoalso <ricardo.almeidasoares@camptocamp.com>

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

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/e-commerce <https://github.com/OCA/e-commerce/tree/19.0/website_sale_hide_no_variant_attributes>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions website_sale_hide_no_variant_attributes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
26 changes: 26 additions & 0 deletions website_sale_hide_no_variant_attributes/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2026 Camptocamp SA (https://www.camptocamp.com).
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Website Sale Hide No Variant Attributes",
"summary": "Exclude non-variant-defining attributes from the variant "
"selector and its exclusion rules",
"version": "19.0.1.0.0",
"development_status": "Beta",
"category": "Website",
"website": "https://github.com/OCA/e-commerce",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"website_sale",
],
"data": [
"views/variant_templates.xml",
],
"assets": {
"web.assets_tests": [
"website_sale_hide_no_variant_attributes/static/tests/**/*",
],
},
}
1 change: 1 addition & 0 deletions website_sale_hide_no_variant_attributes/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import product_template
84 changes: 84 additions & 0 deletions website_sale_hide_no_variant_attributes/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Copyright 2026 Camptocamp SA (https://www.camptocamp.com).
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import models


class ProductTemplate(models.Model):
_inherit = "product.template"

def _get_attribute_exclusions(
self, parent_combination=None, parent_name=None, combination_ids=None
):
result = super()._get_attribute_exclusions(
parent_combination=parent_combination,
parent_name=parent_name,
combination_ids=combination_ids,
)
no_variant_ptav_ids = set(
self.attribute_line_ids.filtered(
lambda line: line.attribute_id.create_variant == "no_variant"
).product_template_value_ids.ids
)
if not no_variant_ptav_ids:
return result

result["exclusions"] = {
ptav_id: (
[]
if ptav_id in no_variant_ptav_ids
else [
excluded_id
for excluded_id in excluded_ids
if excluded_id not in no_variant_ptav_ids
]
)
for ptav_id, excluded_ids in result["exclusions"].items()
}
result["parent_exclusions"] = {
parent_ptav_id: [
excluded_id
for excluded_id in excluded_ids
if excluded_id not in no_variant_ptav_ids
]
for parent_ptav_id, excluded_ids in result["parent_exclusions"].items()
}
result["mapped_attribute_names"] = {
ptav_id: name
for ptav_id, name in result["mapped_attribute_names"].items()
if ptav_id not in no_variant_ptav_ids
}
return result

def _get_combination_info(
self,
combination=False,
product_id=False,
add_qty=1.0,
uom_id=False,
only_template=False,
):
combination_info = super()._get_combination_info(
combination=combination,
product_id=product_id,
add_qty=add_qty,
uom_id=uom_id,
only_template=only_template,
)
if combination_info.get("is_combination_possible"):
return combination_info
# Since no_variant attributes are never shown to the shopper (see the
# website_sale.variants override), they can never be submitted or
# corrected from the website, so they must not be able to block Add
# to Cart either: a missing or template-picked no_variant value would
# otherwise fail the exact-attribute-match/exclusion check in
# `_is_combination_possible` with no way for the shopper to fix it.
resolved_combination = (
combination_info.get("combination")
or self.env["product.template.attribute.value"]
)
combination_info["is_combination_possible"] = self._is_combination_possible(
combination=resolved_combination._without_no_variant_attributes(),
ignore_no_variant=True,
)
return combination_info
3 changes: 3 additions & 0 deletions website_sale_hide_no_variant_attributes/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- [Camptocamp](https://www.camptocamp.com/):
- Ricardoalso \<<ricardo.almeidasoares@camptocamp.com>\>
10 changes: 10 additions & 0 deletions website_sale_hide_no_variant_attributes/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
This module keeps attributes that never generate a variant (attributes with
their *Variant Creation* setting on *Never*, e.g. purely informational specs)
out of the website product page's variant selector, and out of the
combination-exclusion rules used to gray out incompatible options.

Without this module, an informational attribute's value can still exclude a
real, variant-defining value through a configured *Exclude for* rule, even
though the informational attribute itself is never shown to the shopper as a
selectable option — resulting in a visible option being grayed out because of
an attribute the shopper cannot see, with a tooltip naming it.
14 changes: 14 additions & 0 deletions website_sale_hide_no_variant_attributes/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
This module requires no configuration: it applies automatically to every
product attribute whose *Variant Creation* is set to *Never*.

1. On a product, add an attribute with *Variant Creation* set to *Never*
(e.g. an informational spec such as a material or a care instruction),
alongside your normal variant-defining attributes.
2. Optionally, configure an *Exclude for* rule on one of that attribute's
values, targeting one of the variant-defining values.
3. Open the product page on the website: the informational attribute no
longer appears in the variant selector, and the variant-defining value
targeted by its exclusion rule is no longer grayed out because of it.
4. Add the product to the cart: the hidden informational attribute never
blocks *Add to Cart*, even when its excluded or default value would have
conflicted with the one visibly selected.
Loading
Loading