Criptomart/red-supermercados-coop#6 stock_valuation_layer_category_groupby: add group_by parent categories

This commit is contained in:
Luis 2025-12-10 12:57:05 +01:00
parent 51a53f54ba
commit 9d426ff176
5 changed files with 157 additions and 17 deletions

View file

@ -2,40 +2,60 @@
## Description
This module allows grouping by product category in the stock valuation layer reports.
This module allows grouping by product category at different hierarchy levels in the stock valuation layer reports.
### Problem
By default, the `categ_id` field in `stock.valuation.layer` is a related field without storage (`store=False`). This means it cannot be used for grouping in reports and pivot views, even though it can be used for filtering and searching.
Additionally, when dealing with hierarchical category structures (e.g., Food > Dairy > Cheese > Cheddar), it's often useful to group by different levels of the hierarchy.
### Solution
This module makes the `categ_id` field stored (`store=True`) and indexed, which enables:
- Grouping by product category in list views
- Grouping by product category in pivot views
- Grouping by product category in graph views
This module makes the `categ_id` field stored (`store=True`) and indexed, and adds computed fields for each category hierarchy level (up to 4 levels), enabling:
- Grouping by product category (full path) in list, pivot, and graph views
- Grouping by category level 1 (top-level category)
- Grouping by category level 2 (second-level category)
- Grouping by category level 3 (third-level category)
- Grouping by category level 4 (fourth-level category)
- Better performance when filtering by category
## Installation
1. Install the module from the Apps menu
2. The field will be automatically populated for existing records
2. The fields will be automatically populated for existing records
## Usage
After installation:
1. Go to Inventory > Reporting > Inventory Valuation
2. Switch to Pivot or Graph view
3. Click on "Measures" or group options
4. You will now see "Product Category" available for grouping
3. Click on "Group By" options
4. You will now see multiple category grouping options:
- **Product Category**: Groups by the full category (leaf node)
- **Category Level 1**: Groups by top-level category
- **Category Level 2**: Groups by second-level category
- **Category Level 3**: Groups by third-level category
- **Category Level 4**: Groups by fourth-level category
### Example
If you have a category structure like:
- Food (Level 1)
- Dairy (Level 2)
- Cheese (Level 3)
- Cheddar (Level 4)
You can now group your inventory valuation by "Food" (Level 1), "Dairy" (Level 2), "Cheese" (Level 3), or "Cheddar" (Level 4) as needed.
## Technical Details
The module extends `stock.valuation.layer` model and modifies the `categ_id` field to:
- `store=True`: Store the value in the database
- `index=True`: Add database index for better performance
The module extends `stock.valuation.layer` model and:
- Modifies the `categ_id` field to: `store=True` and `index=True`
- Adds computed stored fields: `categ_level_1_id`, `categ_level_2_id`, `categ_level_3_id`, `categ_level_4_id`
- Uses the `parent_path` field from `product.category` to determine hierarchy levels
The field remains a related field, so it will automatically update when the product category changes.
All fields are indexed for better performance and are automatically updated when product categories change.
## Bug Tracker

View file

@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-04 17:24+0000\n"
"PO-Revision-Date: 2025-12-04 17:24+0000\n"
"POT-Creation-Date: 2025-12-10 17:24+0000\n"
"PO-Revision-Date: 2025-12-10 17:24+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@ -21,6 +21,30 @@ msgstr ""
msgid "Product Category"
msgstr "Categoría de producto"
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__categ_level_1_id
#: model_terms:ir.ui.view,arch_db:stock_valuation_layer_category_groupby.view_inventory_valuation_search_category
msgid "Category Level 1"
msgstr "Categoría Nivel 1"
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__categ_level_2_id
#: model_terms:ir.ui.view,arch_db:stock_valuation_layer_category_groupby.view_inventory_valuation_search_category
msgid "Category Level 2"
msgstr "Categoría Nivel 2"
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__categ_level_3_id
#: model_terms:ir.ui.view,arch_db:stock_valuation_layer_category_groupby.view_inventory_valuation_search_category
msgid "Category Level 3"
msgstr "Categoría Nivel 3"
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__categ_level_4_id
#: model_terms:ir.ui.view,arch_db:stock_valuation_layer_category_groupby.view_inventory_valuation_search_category
msgid "Category Level 4"
msgstr "Categoría Nivel 4"
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__smart_search
msgid "Smart Search"

View file

@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-12-04 17:24+0000\n"
"PO-Revision-Date: 2025-12-04 17:24+0000\n"
"POT-Creation-Date: 2025-12-10 17:24+0000\n"
"PO-Revision-Date: 2025-12-10 17:24+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@ -21,6 +21,30 @@ msgstr ""
msgid "Product Category"
msgstr ""
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__categ_level_1_id
#: model_terms:ir.ui.view,arch_db:stock_valuation_layer_category_groupby.view_inventory_valuation_search_category
msgid "Category Level 1"
msgstr ""
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__categ_level_2_id
#: model_terms:ir.ui.view,arch_db:stock_valuation_layer_category_groupby.view_inventory_valuation_search_category
msgid "Category Level 2"
msgstr ""
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__categ_level_3_id
#: model_terms:ir.ui.view,arch_db:stock_valuation_layer_category_groupby.view_inventory_valuation_search_category
msgid "Category Level 3"
msgstr ""
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__categ_level_4_id
#: model_terms:ir.ui.view,arch_db:stock_valuation_layer_category_groupby.view_inventory_valuation_search_category
msgid "Category Level 4"
msgstr ""
#. module: stock_valuation_layer_category_groupby
#: model:ir.model.fields,field_description:stock_valuation_layer_category_groupby.field_stock_valuation_layer__smart_search
msgid "Smart Search"

View file

@ -1,7 +1,7 @@
# Copyright 2025 Criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
from odoo import api, fields, models
class StockValuationLayer(models.Model):
@ -9,3 +9,55 @@ class StockValuationLayer(models.Model):
# Make categ_id stored to allow grouping in reports
categ_id = fields.Many2one(store=True, index=True)
# Category hierarchy levels for grouping
categ_level_1_id = fields.Many2one(
comodel_name="product.category",
string="Category Level 1",
compute="_compute_category_levels",
store=True,
index=True,
)
categ_level_2_id = fields.Many2one(
comodel_name="product.category",
string="Category Level 2",
compute="_compute_category_levels",
store=True,
index=True,
)
categ_level_3_id = fields.Many2one(
comodel_name="product.category",
string="Category Level 3",
compute="_compute_category_levels",
store=True,
index=True,
)
categ_level_4_id = fields.Many2one(
comodel_name="product.category",
string="Category Level 4",
compute="_compute_category_levels",
store=True,
index=True,
)
@api.depends("categ_id", "categ_id.parent_path")
def _compute_category_levels(self):
"""Compute category hierarchy levels for better grouping options."""
for layer in self:
if not layer.categ_id or not layer.categ_id.parent_path:
layer.categ_level_1_id = False
layer.categ_level_2_id = False
layer.categ_level_3_id = False
layer.categ_level_4_id = False
continue
# parent_path format: "1/2/3/" where each number is a category ID
path_ids = [
int(x) for x in layer.categ_id.parent_path.split("/") if x.isdigit()
]
# Assign levels based on hierarchy
layer.categ_level_1_id = path_ids[0] if len(path_ids) >= 1 else False
layer.categ_level_2_id = path_ids[1] if len(path_ids) >= 2 else False
layer.categ_level_3_id = path_ids[2] if len(path_ids) >= 3 else False
layer.categ_level_4_id = path_ids[3] if len(path_ids) >= 4 else False

View file

@ -13,6 +13,26 @@
name="group_by_categ_id"
context="{'group_by': 'categ_id'}"
/>
<filter
string="Category Level 1"
name="group_by_categ_level_1"
context="{'group_by': 'categ_level_1_id'}"
/>
<filter
string="Category Level 2"
name="group_by_categ_level_2"
context="{'group_by': 'categ_level_2_id'}"
/>
<filter
string="Category Level 3"
name="group_by_categ_level_3"
context="{'group_by': 'categ_level_3_id'}"
/>
<filter
string="Category Level 4"
name="group_by_categ_level_4"
context="{'group_by': 'categ_level_4_id'}"
/>
</filter>
</field>
</record>