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
3 changes: 2 additions & 1 deletion attribute_set/tests/test_build_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ def setUpClass(cls):
cls.loader = FakeModelLoader(cls.env, cls.__module__)
cls.loader.backup_registry()
from .models import ResCountry, ResPartner
from ..models.attribute_set_owner import AttributeSetOwnerMixin

cls.loader.update_registry((ResPartner, ResCountry))
cls.loader.update_registry((AttributeSetOwnerMixin, ResPartner, ResCountry))

# Create a new inherited view with the 'attributes' placeholder.
cls.view = cls.env["ir.ui.view"].create(
Expand Down
76 changes: 76 additions & 0 deletions product_catalog_attribute_set/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
=============================
Product Catalog Attribute Set
=============================

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

.. |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-OCA%2Fodoo--pim-lightgray.png?logo=github
:target: https://github.com/OCA/odoo-pim/tree/18.0/product_catalog_attribute_set
:alt: OCA/odoo-pim
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/odoo-pim-18-0/odoo-pim-18-0-product_catalog_attribute_set
: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/odoo-pim&target_branch=18.0
:alt: Try me on Runboat

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

A module to show OCA attribute sets in product's catalog kanban view.

**Table of contents**

.. contents::
:local:

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/odoo-pim/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/odoo-pim/issues/new?body=module:%20product_catalog_attribute_set%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
-------

* Kencove

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

- Mohamed Alkobrosli <[email protected]>

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/odoo-pim <https://github.com/OCA/odoo-pim/tree/18.0/product_catalog_attribute_set>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
5 changes: 5 additions & 0 deletions product_catalog_attribute_set/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2025 Kencove (http://www.kencove.com).
# @author Mohamed Alkobrosli <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import models
30 changes: 30 additions & 0 deletions product_catalog_attribute_set/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright 2025 Kencove (http://www.kencove.com).
# @author Mohamed Alkobrosli <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Product Catalog Attribute Set",
"version": "18.0.1.0.0",
"license": "AGPL-3",
"author": "Kencove, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/odoo-pim",
"depends": [
"web",
"product",
"pim",
"website_attribute_set",
],
"data": [
"views/product_views.xml",
],
"assets": {
"web.assets_backend": [
"product_catalog_attribute_set/static/src/search_model.esm.js",
"product_catalog_attribute_set/static/src/kanban_model.esm.js",
"product_catalog_attribute_set/static/src/search_panel.xml",
"product_catalog_attribute_set/static/src/search_panel.esm.js",
],
},
"installable": True,
"application": True,
}
5 changes: 5 additions & 0 deletions product_catalog_attribute_set/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2025 Kencove (http://www.kencove.com).
# @author Mohamed Alkobrosli <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import product_product
147 changes: 147 additions & 0 deletions product_catalog_attribute_set/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Copyright 2025 Kencove (http://www.kencove.com).
# @author Mohamed Alkobrosli <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).


from collections import Counter

from lxml import etree

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


class ProductProduct(models.Model):
_inherit = "product.product"

@api.model
def _get_extra_attributes(self):
"""Override Attribute's method _build_attribute_eview() to build an
attribute eview with the mixin model's attributes"""
domain = [
("attribute_set_ids", "!=", False),
("model", "=", "product.template"),
("nature", "=", "custom"),
]
attributes = self.env["attribute.attribute"].sudo().search(domain)
return attributes

def _create_filter_attributes(self, attributes, parent, index):
for attribute in attributes:
if attribute.ttype == "many2many":
field_node = etree.Element(
"field",
name=attribute.name,
icon="fa-th-list",
enable_counters="1",
select="multi",
)
parent.insert(index + 1, field_node)
index += 1
elif attribute.ttype in ("many2one"):
field_node = etree.Element(
"field",
name=attribute.name,
icon="fa-th-list",
)
parent.insert(index + 1, field_node)
index += 1
return parent

def _create_search_attributes(self, attributes, parent, index):
for attribute in attributes:
field_node = etree.Element(
"field",
name=attribute.name,
)
parent.insert(index + 1, field_node)
index += 1
return parent

def _insert_extra_search_attribute(self, arch, separator, is_filter=False):
"""Replace attributes' placeholders with real fields in form view arch."""
eview = etree.fromstring(arch)
form_name = eview.get("string")
placeholder = eview.xpath(f"//separator[@name='{separator}']")
if len(placeholder) != 1:
raise ValidationError(
_(
"""It is impossible to add Attributes on "%(name)s" xml
view as there is
not one "<separator name="%(separator)s" />" in it.
""",
name=form_name,
separator=separator,
)
)
attributes = self._get_extra_attributes()
parent = placeholder[0].getparent()
index = parent.index(placeholder[0])
if is_filter:
parent = self._create_filter_attributes(attributes, parent, index)
else:
parent = self._create_search_attributes(attributes, parent, index)
# Remove the placeholder
parent.remove(placeholder[0])
return etree.tostring(eview, pretty_print=True)

def get_view(self, view_id=None, view_type="search", **options):
result = super().get_view(view_id=view_id, view_type=view_type, **options)
if view_type == "search":
form_arch = result.get("arch")
if form_arch:
# Add attributes in filter sidebar
result["arch"] = self._insert_extra_search_attribute(
result["arch"],
separator="attributes_filter_placeholder",
is_filter=True,
)
# Add attributes in search panel
result["arch"] = self._insert_extra_search_attribute(
result["arch"], separator="attributes_search_placeholder"
)
return result

def extra_attr_vals(self, all_products, attr):
"""
Return a list of each attribute value or a list of
lists having id, value if value of type attribute.option
"""
count = 0
vals_list = []
for product in all_products:
if product[attr.name]:
count += 1
product_tmpl_id = product.product_tmpl_id
val = product_tmpl_id.get_extra_attribute_values(attr)
if val:
if isinstance(val, models.BaseModel) and len(val) >= 1:
for v in val:
vals_list.append(v.name)
else:
vals_list.append(val)
counter = Counter(vals_list)
# Convert to list of [value, count]
result = [[val, count] for val, count in counter.items()]
return result, count

def catalog_extra_attrs(self):
product = self.env["product.product"].sudo()
all_attrs = self._get_extra_attributes()
filtered_attrs = all_attrs.filtered(
lambda r: r.ttype not in ["many2many", "many2one"]
)
all_products = product.search([])
attrs_data = []
for attr in filtered_attrs:
vals, count = self.extra_attr_vals(all_products, attr)
attr_data = {
"id": attr.id,
"name": attr.name,
"display_name": attr.field_description,
"count": count,
}
if vals:
attr_data["vals"] = vals
attrs_data.append(attr_data)
return attrs_data
3 changes: 3 additions & 0 deletions product_catalog_attribute_set/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
1 change: 1 addition & 0 deletions product_catalog_attribute_set/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Mohamed Alkobrosli \<<[email protected]>\>
1 change: 1 addition & 0 deletions product_catalog_attribute_set/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A module to show OCA attribute sets in product's catalog kanban view.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading