Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADD] product_category_global_info: add required attribute in global … #658

Draft
wants to merge 1 commit into
base: 18.0
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions product_category_global_info/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import tests
19 changes: 19 additions & 0 deletions product_category_global_info/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
'name': "Product Category Global Info",
'version': '1.0',
'summary': 'Extends product category with global info fields and a new tab grouping attributes by category.',
'description': """
This module extends the product category form by:
- Adding a boolean field "Show on Global Info"
- Adding a many2many field to map required attributes
It also adds a new tab called "Global Info" that displays category and attribute information grouped by product category.
""",
'author':'Odoo S.A.',
'category': 'Productivity',
'depends': ['stock', 'sale_management'],
'data': [
'views/product_category_global_info.xml',
'views/sale_order_view_inherit.xml',
],
'license': 'AGPL-3'
}
2 changes: 2 additions & 0 deletions product_category_global_info/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import product_category
from . import sale_order_line
18 changes: 18 additions & 0 deletions product_category_global_info/models/product_category.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from odoo import fields, models


class ProductCategory(models.Model):
_inherit = 'product.category'

show_on_global_info = fields.Boolean(
string="Show on Global info",
help="If checked, this category will appear in the 'Global Info' tab of Sale Orders.",
default=False,
store=True
)

required_attribute_ids = fields.Many2many(
comodel_name="product.attribute",
string="Required Attribute",
help="Attributes that must be specified for products in this category."
)
44 changes: 44 additions & 0 deletions product_category_global_info/models/sale_order_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from odoo import Command, api, fields, models


class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'

product_category_id = fields.Many2one(
comodel_name='product.category',
string="Product Category",
compute="_compute_product_category",
store=True
)

attribute_ids = fields.Many2many(
comodel_name='product.attribute',
string="Attributes"
)

attribute_value_ids = fields.Many2many(
comodel_name='product.attribute.value',
string="Attribute Value"
)

@api.depends('product_id')
def _compute_product_category(self):
for line in self:
if line.product_id and line.product_id.categ_id.show_on_global_info:
line.product_category_id = line.product_id.categ_id
else:
line.product_category_id = False

@api.onchange('product_category_id')
def _onchange_product_category(self):
if self.product_category_id:
required_attributes = self.product_category_id.required_attribute_ids
default_attribute_values = []
default_attributes = []

for attribute in required_attributes:
selected_value = self.product_template_attribute_value_ids.filtered(lambda v: v.attribute_id == attribute)
default_attributes.append(attribute.id)
default_attribute_values.append(selected_value.product_attribute_value_id.id)
self.attribute_ids = Command.set([default_attributes])
self.attribute_value_ids = Command.set([default_attribute_values])
1 change: 1 addition & 0 deletions product_category_global_info/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_required_attributes
86 changes: 86 additions & 0 deletions product_category_global_info/tests/test_required_attributes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from odoo.tests.common import TransactionCase
from odoo.tests import tagged
from odoo import Command

@tagged("post_install", "-at_install")
class TestRequiredAttributes(TransactionCase):

@classmethod
def setUpClass(cls):
super(TestRequiredAttributes, cls).setUpClass()

cls.test_required_attribute = cls.env["product.attribute"].create({
"name": "Required Attribute"
})
cls.test_required_values = cls.env["product.attribute.value"].create([
{
"name": "Required Attribute 1",
"attribute_id": cls.test_required_attribute.id
},
{
"name": "Required Attribute 2",
"attribute_id": cls.test_required_attribute.id
},
{
"name": "Required Attribute 3",
"attribute_id": cls.test_required_attribute.id
}
])

cls.test_attribute = cls.env["product.attribute"].create({
"name": "Normal Attribute"
})
cls.test_attribute_values = cls.env["product.attribute.value"].create([
{
"name": "Attribute 1",
"attribute_id": cls.test_attribute.id
},
{
"name": "Attribute 2",
"attribute_id": cls.test_attribute.id
},
{
"name": "Attribute 3",
"attribute_id": cls.test_attribute.id
}
])

cls.category = cls.env['product.category'].create([{
'name': 'Test Category',
'show_on_global_info': True,
'required_attribute_ids': [Command.set([cls.test_required_attribute.id])]
}])

cls.product = cls.env["product.product"].create({
"name": "Test Product",
"categ_id": cls.category.id,
"attribute_line_ids": [Command.create({
"attribute_id": cls.test_required_attribute.id,
"value_ids": [Command.set(cls.test_required_values.ids)]
}), Command.create({
"attribute_id": cls.test_attribute.id,
"value_ids": [Command.set(cls.test_attribute_values.ids)]
})]
})


cls.sale_order = cls.env["sale.order"].create({"partner_id": cls.env.ref("base.res_partner_1").id})
cls.sale_order_line = cls.env["sale.order.line"].create({
"order_id": cls.sale_order.id,
"product_id": cls.product.id
})

def test_category_fields(self):
self.assertTrue(self.category.show_on_global_info, "Category should have 'show_on_global_info' set to True")
self.assertEqual(len(self.category.required_attribute_ids), 1, "Category should have one required attributes (test_required_attribute)")

def test_product_attributes(self):
product_attributes = self.product.attribute_line_ids.mapped("attribute_id.name")
self.assertIn("Required Attribute", product_attributes, "Product should have 'Required Attribute' in attribute")
self.assertIn("Normal Attribute", product_attributes, "Product should have 'Normal Attribute' in attribute")

def test_sale_order_line_global_info(self):
if self.sale_order_line.product_id.categ_id.show_on_global_info:
displayed_attributes = self.sale_order_line.product_id.categ_id.required_attribute_ids.mapped("name")
self.assertIn("Required Attribute", displayed_attributes, "Global info should show 'Required Attribute'")
self.assertNotIn("Normal Attribute", displayed_attributes, "Global info should NOT show 'Normal Attribute'")
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<odoo>
<record id="view_product_category_form_inherit" model="ir.ui.view">
<field name="name">product.category.form.inherit</field>
<field name="model">product.category</field>
<field name="inherit_id" ref="stock.product_category_form_view_inherit"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='removal_strategy_id']" position="after">
<field name="show_on_global_info"/>
<field name="required_attribute_ids" widget="many2many_tags"/>
</xpath>
</field>
</record>
</odoo>
47 changes: 47 additions & 0 deletions product_category_global_info/views/sale_order_view_inherit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<odoo>

<record id="view_sale_order_line_list_global_info" model="ir.ui.view">
<field name="name">sale.order.line.list.global.info</field>
<field name="model">sale.order.line</field>
<field name="arch" type="xml">
<list default_group_by="product_category_id" create="false" delete="false">
<field name="product_category_id" string="Product Category"/>
<field name="attribute_ids" widget="many2many_tags" string="Attributes"/>
<field name="attribute_value_ids" widget="many2many_tags" string="Attribute Values"/>
</list>
</field>
</record>

<record id="view_sale_order_global_info" model="ir.ui.view">
<field name="name">sale.order.global.info.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//notebook" position="inside">
<page string="Global Info">
<field name="order_line" context="{'list_view_ref': 'product_category_global_info.view_sale_order_line_list_global_info'}"/>
</page>
</xpath>
</field>
</record>

<record id="view_sale_order_global_info_search" model="ir.ui.view">
<field name="name">sale.order.global.info.search</field>
<field name="model">sale.order.line</field>
<field name="arch" type="xml">
<search>
<filter name="group_by_product_category" context="{'group_by': 'product_category_id'}"/>
</search>
</field>
</record>

<record id="sale_order_view_global_info" model="ir.actions.act_window">
<field name="name">Global Info</field>
<field name="res_model">sale.order.line</field>
<field name="view_id" ref="view_sale_order_line_list_global_info"/>
<field name="search_view_id" ref="view_sale_order_global_info_search"/>
<field name="view_mode">list</field>
<field name="context">{'search_default_group_by_product_category': 1}</field>
</record>

</odoo>