This repository was archived by the owner on Mar 3, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generalise modele from DW and upgrade to 17.0
- Loading branch information
1 parent
ef53536
commit 5e09e2e
Showing
10 changed files
with
335 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Product Simple Variant Builder | ||
============================== | ||
Simple wizard to build dynamic variants from a product template. | ||
|
||
See the Attributes & Variants tab on the product page to see the button. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import wizards |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "product_simple_variant_builder", | ||
"summary": """ | ||
Simple wizard to build dynamic variants from a product template""", | ||
"author": "Glo Networks", | ||
"website": "https://glo.systems", | ||
"category": "Inventory", | ||
"version": "17.0.1.0.0", | ||
"depends": ["product", "product_variant_configurator"], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"wizards/wizard_simple_create_variant.xml", | ||
"views/product_template_view.xml", | ||
], | ||
"demo": [], | ||
"license": "Other proprietary", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
access_wizard_simple_create_variant,wizard_simple_create_variant,model_wizard_simple_create_variant,base.group_user,1,1,1,1 | ||
access_wizard_simple_create_variant_line,wizard_simple_create_variant_line,model_wizard_simple_create_variant_line,base.group_user,1,1,1,1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import test_product_variant_creation |
88 changes: 88 additions & 0 deletions
88
product_simple_variant_builder/tests/test_product_variant_creation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Copyright 2022 ForgeFlow S.L. <https://forgeflow.com> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from odoo.tests.common import TransactionCase | ||
|
||
|
||
class TestProductVariantConfiguratorManualCreation(TransactionCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
super().setUpClass() | ||
# ENVIRONMENTS | ||
cls.product_attribute = cls.env["product.attribute"] | ||
cls.product_attribute_value = cls.env["product.attribute.value"] | ||
cls.attribute_line_model = cls.env["product.template.attribute.line"] | ||
cls.wizard_variant_manual_creation = cls.env["wizard.simple.create.variant"] | ||
cls.product_configuration_attribute = cls.env["product.configurator.attribute"] | ||
cls.product_template = cls.env["product.template"].with_context( | ||
check_variant_creation=True | ||
) | ||
# Instances: product attribute | ||
cls.attribute1 = cls.product_attribute.create({"name": "Test Attribute 1"}) | ||
# Instances: product attribute value | ||
cls.value1 = cls.product_attribute_value.create( | ||
{"name": "Value 1", "attribute_id": cls.attribute1.id} | ||
) | ||
cls.value2 = cls.product_attribute_value.create( | ||
{"name": "Value 2", "attribute_id": cls.attribute1.id} | ||
) | ||
|
||
def test_product_attribute_manual_creation(self): | ||
# create product with attribute and "Variant creation" option is | ||
# set on "Don't create automatically" | ||
self.product_template1 = self.product_template.create( | ||
{"name": "Product template 1", "no_create_variants": "yes"} | ||
) | ||
self.attribute_line_model.with_context(check_variant_creation=True).create( | ||
{ | ||
"product_tmpl_id": self.product_template1.id, | ||
"attribute_id": self.attribute1.id, | ||
"value_ids": [(6, 0, [self.value1.id, self.value2.id])], | ||
} | ||
) | ||
self.assertEqual(self.product_template1.product_variant_count, 1) | ||
variants = self.product_template1.product_variant_ids | ||
self.assertEqual( | ||
variants.product_template_attribute_value_ids.product_attribute_value_id.id, | ||
False, | ||
) | ||
variant_creation_wizard1 = self.wizard_variant_manual_creation.with_context( | ||
active_id=self.product_template1.id | ||
).create({}) | ||
variant_creation_wizard1._onchange_product_tmpl() | ||
self.assertEqual( | ||
variant_creation_wizard1.line_ids.attribute_id.id, self.attribute1.id | ||
) | ||
variant_creation_wizard1.line_ids.write( | ||
{ | ||
"selected_value_ids": [(6, 0, [self.value1.id])], | ||
"attribute_value_ids": [(6, 0, [self.value1.id])], | ||
} | ||
) | ||
variant_creation_wizard1.action_create_variants() | ||
self.assertEqual(self.product_template1.product_variant_count, 1) | ||
self.assertEqual( | ||
variants.product_template_attribute_value_ids.product_attribute_value_id.id, | ||
self.value1.id, | ||
) | ||
|
||
variant_creation_wizard2 = self.wizard_variant_manual_creation.with_context( | ||
active_id=self.product_template1.id | ||
).create({}) | ||
variant_creation_wizard2._onchange_product_tmpl() | ||
self.assertEqual( | ||
variant_creation_wizard2.line_ids.attribute_id.id, self.attribute1.id | ||
) | ||
variant_creation_wizard2.line_ids.write( | ||
{ | ||
"selected_value_ids": [(6, 0, [self.value2.id])], | ||
"attribute_value_ids": [(6, 0, [self.value2.id])], | ||
} | ||
) | ||
variant_creation_wizard2.action_create_variants() | ||
self.assertEqual(self.product_template1.product_variant_count, 2) | ||
variants = self.product_template1.product_variant_ids | ||
self.assertEqual( | ||
variants.product_template_attribute_value_ids.product_attribute_value_id.ids, | ||
[self.value1.id, self.value2.id], | ||
) |
16 changes: 16 additions & 0 deletions
16
product_simple_variant_builder/views/product_template_view.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?xml version='1.0' encoding='utf-8'?> | ||
<odoo> | ||
<record id="product_template_only_form_view" model="ir.ui.view"> | ||
<field name="name">product_template_only_form_view</field> | ||
<field name="model">product.template</field> | ||
<field name="inherit_id" ref="product.product_template_only_form_view" /> | ||
<field name="arch" type="xml"> | ||
<xpath expr="//page[@name='variants']" position="inside"> | ||
<field name="has_configurable_attributes" invisible="1" /> | ||
<button name="%(wizard_simple_create_variant_action)d" type="action" | ||
string="Create Variant" | ||
attrs="{'invisible': [('has_configurable_attributes', '=', False)]}" /> | ||
</xpath> | ||
</field> | ||
</record> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import wizard_simple_create_variant |
161 changes: 161 additions & 0 deletions
161
product_simple_variant_builder/wizards/wizard_simple_create_variant.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
# Copyright 2022 ForgeFlow S.L. <https://forgeflow.com> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
from itertools import product | ||
|
||
from odoo import api, fields, models | ||
|
||
|
||
class WizardSimpleCreateVariant(models.TransientModel): | ||
_name = "wizard.simple.create.variant" | ||
_description = "Simple Create Variant Wizard" | ||
|
||
product_tmpl_id = fields.Many2one( | ||
comodel_name="product.template", string="Template", readonly=True | ||
) | ||
variants_to_create = fields.Integer(compute="_compute_variants_to_create") | ||
line_ids = fields.One2many( | ||
comodel_name="wizard.create.variant.line", | ||
inverse_name="wizard_id", | ||
string="Lines", | ||
required=False, | ||
) | ||
|
||
@api.depends( | ||
"product_tmpl_id", | ||
"line_ids.selected_value_ids", | ||
) | ||
def _compute_variants_to_create(self): | ||
for rec in self: | ||
combinations = rec._get_combinations() | ||
rec.variants_to_create = len(combinations) | ||
|
||
def _get_combinations(self): | ||
self.ensure_one() | ||
selected_items = [ | ||
line.selected_value_ids.ids | ||
for line in self.line_ids | ||
if line.selected_value_ids | ||
] | ||
return list(selected_items and product(*selected_items)) | ||
|
||
@api.model | ||
def default_get(self, fields_list): | ||
values = super().default_get(fields_list) | ||
values["product_tmpl_id"] = self.env.context.get("active_id") | ||
return values | ||
|
||
@api.onchange("product_tmpl_id") | ||
def _onchange_product_tmpl(self): | ||
line_model = self.env["wizard.create.variant.line"] | ||
if self.product_tmpl_id: | ||
lines = line_model.browse() | ||
pending_variants = self.product_tmpl_id.attribute_line_ids | ||
for line_data in [ | ||
{ | ||
"attribute_id": attribute_line.attribute_id.id, | ||
"required": attribute_line.required, | ||
"attribute_value_ids": [ | ||
(6, 0, [int(v_id) for v_id in attribute_line.value_ids.ids]) | ||
], | ||
} | ||
for attribute_line in pending_variants | ||
]: | ||
lines |= line_model.new(line_data) | ||
self.line_ids = lines | ||
|
||
def action_create_variants(self): | ||
"""Create variant of product based on selected attributes values in wizard""" | ||
product_model = self.env["product.product"] | ||
attribute_value_model = self.env["product.template.attribute.value"] | ||
current_variants_to_create = [] | ||
current_variants_to_activate = product_model.browse() | ||
variants_to_show = product_model.browse() | ||
product_tmpl = self.product_tmpl_id | ||
all_variants = product_tmpl.with_context( | ||
active_test=False | ||
).product_variant_ids.sorted(lambda p: (p.active, -p.id)) | ||
existing_variants = { | ||
variant.product_template_attribute_value_ids: variant | ||
for variant in all_variants | ||
} | ||
for combination_ids in self._get_combinations(): | ||
combination = attribute_value_model.browse() | ||
for value in product_tmpl.valid_product_template_attribute_line_ids.mapped( | ||
"product_template_value_ids" | ||
): | ||
if value.product_attribute_value_id.id in combination_ids: | ||
combination |= value | ||
is_combination_possible = product_tmpl._is_combination_possible_by_config( | ||
combination, ignore_no_variant=False | ||
) | ||
if not is_combination_possible: | ||
continue | ||
if combination in existing_variants: | ||
current_variants_to_activate += existing_variants[combination] | ||
elif ( | ||
existing_variants | ||
and len(existing_variants) == 1 | ||
and not all_variants.product_template_attribute_value_ids | ||
): | ||
variants_to_show += all_variants | ||
all_variants.write( | ||
{"product_template_attribute_value_ids": [(6, 0, combination.ids)]} | ||
) | ||
else: | ||
current_variants_to_create.append( | ||
{ | ||
"product_tmpl_id": product_tmpl.id, | ||
"product_template_attribute_value_ids": [ | ||
(6, 0, combination.ids) | ||
], | ||
"active": product_tmpl.active, | ||
} | ||
) | ||
if current_variants_to_activate: | ||
variants_to_show |= current_variants_to_activate | ||
current_variants_to_activate.write({"active": True}) | ||
if current_variants_to_create: | ||
variants_to_show |= product_model.create(current_variants_to_create) | ||
if variants_to_show: | ||
action = self.env.ref("product.product_variant_action").read()[0] | ||
action.update( | ||
{ | ||
"domain": [("id", "in", variants_to_show.ids)], | ||
"context": { | ||
"search_default_product_tmpl_id": [product_tmpl.id], | ||
"default_product_tmpl_id": product_tmpl.id, | ||
"create": False, | ||
}, | ||
} | ||
) | ||
return action | ||
return {"type": "ir.actions.act_window_close"} | ||
|
||
|
||
class WizardCreateVariantLine(models.TransientModel): | ||
_name = "wizard.create.variant.line" | ||
_description = "Wizard Create Variant Line" | ||
|
||
wizard_id = fields.Many2one( | ||
comodel_name="wizard.create.variant", | ||
string="Wizard", | ||
required=False, | ||
) | ||
attribute_id = fields.Many2one( | ||
comodel_name="product.attribute", string="Attribute", required=False | ||
) | ||
attribute_value_ids = fields.Many2many( | ||
comodel_name="product.attribute.value", | ||
relation="wizard_create_variant_line_value_rel", | ||
column1="wizard_line_id", | ||
column2="value_id", | ||
string="Attribute Values", | ||
) | ||
selected_value_ids = fields.Many2many( | ||
comodel_name="product.attribute.value", | ||
relation="wizard_create_variant_line_selected_value_rel", | ||
column1="wizard_line_id", | ||
column2="value_id", | ||
string="Selected Values", | ||
) | ||
required = fields.Boolean(string="Required?", required=False) |
42 changes: 42 additions & 0 deletions
42
product_simple_variant_builder/wizards/wizard_simple_create_variant.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?xml version='1.0' encoding='utf-8'?> | ||
<odoo> | ||
<record id="wizard_simple_create_variant_form" model="ir.ui.view"> | ||
<field name="name">wizard_create_variant_form</field> | ||
<field name="model">wizard.simple.create.variant</field> | ||
<field name="arch" type="xml"> | ||
<form string="Variant Creation"> | ||
<sheet> | ||
<group name="product_info"> | ||
<field name="product_tmpl_id" /> | ||
<field name="variants_to_create" /> | ||
</group> | ||
<field name="line_ids" nolabel="1"> | ||
<tree editable="top" create="false" delete="false"> | ||
<field name="attribute_id" readonly="1" force_save="1" /> | ||
<field name="required" readonly="1" force_save="1" /> | ||
<field name="attribute_value_ids" widget="many2many_tags" invisible="1" /> | ||
<field name="selected_value_ids" | ||
attrs="{'required': [('required', '=', True)]}" | ||
widget="many2many_tags" | ||
domain="[('id', 'in', attribute_value_ids or [])]" | ||
options="{'no_create': True}" /> | ||
</tree> | ||
</field> | ||
</sheet> | ||
<footer> | ||
<button string="Create Variants" name="action_create_variants" type="object" | ||
class="btn-primary" /> | ||
<button string="Cancel" class="btn-secondary" special="cancel" /> | ||
</footer> | ||
</form> | ||
</field> | ||
</record> | ||
|
||
<record id="wizard_simple_create_variant_action" model="ir.actions.act_window"> | ||
<field name="name">Simple Variant Creation</field> | ||
<field name="type">ir.actions.act_window</field> | ||
<field name="res_model">wizard.simple.create.variant</field> | ||
<field name="view_mode">form</field> | ||
<field name="target">new</field> | ||
</record> | ||
</odoo> |