Skip to content
This repository was archived by the owner on Mar 3, 2025. It is now read-only.

Commit

Permalink
Generalise modele from DW and upgrade to 17.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ellbristow committed May 14, 2024
1 parent ef53536 commit 5e09e2e
Show file tree
Hide file tree
Showing 10 changed files with 335 additions and 0 deletions.
5 changes: 5 additions & 0 deletions product_simple_variant_builder/README.rst
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.
1 change: 1 addition & 0 deletions product_simple_variant_builder/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import wizards
17 changes: 17 additions & 0 deletions product_simple_variant_builder/__manifest__.py
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",
}
3 changes: 3 additions & 0 deletions product_simple_variant_builder/security/ir.model.access.csv
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
1 change: 1 addition & 0 deletions product_simple_variant_builder/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_product_variant_creation
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 product_simple_variant_builder/views/product_template_view.xml
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>
1 change: 1 addition & 0 deletions product_simple_variant_builder/wizards/__init__.py
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 product_simple_variant_builder/wizards/wizard_simple_create_variant.py
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)
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>

0 comments on commit 5e09e2e

Please sign in to comment.