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
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/16.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-16-0/odoo-pim-16-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=16.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:%2016.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 <malkobrosly@kencove.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/odoo-pim <https://github.com/OCA/odoo-pim/tree/16.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 <malkobrosly@kencove.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

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

{
"name": "Product Catalog Attribute Set",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"author": "Kencove, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/odoo-pim",
"depends": [
"web",
"product",
"product_catalog",
"pim",
],
"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/search_panel.xml",
"product_catalog_attribute_set/static/src/search_panel.esm.js",
],
},
"installable": True,
"application": True,
}
6 changes: 6 additions & 0 deletions product_catalog_attribute_set/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright 2025 Kencove (http://www.kencove.com).
# @author Mohamed Alkobrosli <malkobrosly@kencove.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import product_template
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 <malkobrosly@kencove.com>
# 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
16 changes: 16 additions & 0 deletions product_catalog_attribute_set/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2025 Kencove (http://www.kencove.com).
# @author Mohamed Alkobrosli <malkobrosly@kencove.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).


from odoo import models


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

def get_extra_attribute_values(self, extra_attribute=None):
self.ensure_one()
if extra_attribute:
return self[extra_attribute.name] if self[extra_attribute.name] else None
return None
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 \<<malkobrosly@kencove.com>\>
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