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

[FIX][14.0] extra price/price computation for configurable products #52

Merged
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
54 changes: 12 additions & 42 deletions product_configurator/models/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,47 +579,17 @@ def write(self, vals):

return super(ProductProduct, self).write(vals)

def get_products_with_session(self, config_session_map=None):
products_to_update = self.env["product.product"]
if not config_session_map:
return products_to_update
config_session_products = self.filtered(lambda p: p.config_ok)
for cfg_product in config_session_products:
if cfg_product.id not in config_session_map.keys():
continue
product_session = self.env["product.config.session"].browse(
config_session_map.get(cfg_product.id)
)
if (
not product_session.exists()
or product_session.product_id != cfg_product
):
continue
products_to_update += cfg_product
return products_to_update

@api.depends_context("product_sessions")
def _compute_product_price(self):
session_map = self.env.context.get("product_sessions", ())
if isinstance(session_map, tuple):
session_map = dict(session_map)
config_session_products = self.get_products_with_session(session_map.copy())
standard_products = self - config_session_products
for cfg_product in config_session_products:
product_session = self.env["product.config.session"].browse(
session_map.get(cfg_product.id)
)
cfg_product.price = product_session.price
super(ProductProduct, standard_products)._compute_product_price()

def price_compute(self, price_type, uom=False, currency=False, company=False):
standard_products = self.filtered(lambda a: not a.config_ok)
res = {}
def _compute_product_price_extra(self):
standard_products = self.filtered(lambda product: not product.config_ok)
config_products = self - standard_products
if standard_products:
res = super(ProductProduct, standard_products).price_compute(
price_type, uom=uom, currency=currency, company=company
super(ProductProduct, standard_products)._compute_product_price_extra()
for product in config_products:
attribute_value_obj = self.env["product.attribute.value"]
value_ids = (
product.product_template_attribute_value_ids.product_attribute_value_id
)
config_products = self - standard_products
for config_product in config_products:
res[config_product.id] = config_product.price
return res
extra_prices = attribute_value_obj.get_attribute_value_extra_prices(
product_tmpl_id=product.product_tmpl_id.id, pt_attr_value_ids=value_ids
)
product.price_extra = sum(extra_prices.values())
1 change: 0 additions & 1 deletion product_configurator/models/product_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,6 @@ def update_config(self, attr_val_dict=None, custom_val_dict=None):
def write(self, vals):
"""Validate configuration when writing new values to session"""
# TODO: Issue warning when writing to value_ids or custom_val_ids

res = super(ProductConfigSession, self).write(vals)
if not self.product_tmpl_id:
return res
Expand Down
6 changes: 4 additions & 2 deletions product_configurator/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# from . import test_product_configurator_test_cases
from . import test_product_configurator_test_cases

# from . import test_create
# from . import test_configuration_rules
# from . import test_product
from . import test_product

# from . import test_product_attribute
# from . import test_product_config
# from . import test_wizard
79 changes: 58 additions & 21 deletions product_configurator/tests/test_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_04_toggle_config(self):
Method: toggle_config()",
)
self.product_tmpl_id.toggle_config()
varient_value = self.product_tmpl_id.create_variant_ids()
varient_value = self.product_tmpl_id._create_variant_ids()
self.assertIsNone(
varient_value,
"Error: If its return none\
Expand All @@ -158,7 +158,6 @@ def test_05_unlink(self):
{
"__attribute-{}".format(self.attr_fuel.id): self.value_gasoline.id,
"__attribute-{}".format(self.attr_engine.id): self.value_218i.id,
"__attribute-{}".format(self.attr_engine.id): self.value_218d.id,
"__attribute-{}".format(self.attr_color.id): self.value_red.id,
}
)
Expand Down Expand Up @@ -384,25 +383,54 @@ def test_12_reconfigure_product(self):
)
product_config_wizard.action_next_step()
value_ids = self.value_gasoline + self.value_218d + self.value_silver
# val_ids = self.value_gasoline + self.value_218i + self.value_red
# pta_val_ids = self.env["product.template.attribute.value"].search(
# [
# ("product_tmpl_id", "=", self.product_tmpl_id.id),
# ("product_attribute_value_id", "in", value_ids.ids),
# ]
# )
new_variant = self.product_tmpl_id.product_variant_ids.filtered(
lambda variant: variant.attribute_value_ids == value_ids
lambda variant: variant.product_template_attribute_value_ids == value_ids
)
self.assertTrue(
self.assertFalse(
new_variant.id,
"Error: if varient id not exists\
Method: reconfigure_product()",
)

def test_13_compute_product_weight_extra(self):
product_product = self._get_product_id()
# _compute_product_weight_extra
productAttPrice = self.env["product.template.attribute.value"].create(
product_id = self.env.ref("product.product_delivery_01")
product_template_attribute_value_ids = self.env.ref(
"product.product_4_attribute_1_value_2"
)
product_template_attribute_value_ids.write(
{
"product_tmpl_id": self.config_product.id,
"product_attribute_value_id": self.value_gasoline.id,
"weight_extra": 45,
"weight_extra": 50.0,
}
)
product_id._compute_product_weight_extra()
product_id.write(
{
"product_template_attribute_value_ids": product_template_attribute_value_ids
}
)
self.assertEqual(
product_template_attribute_value_ids.weight_extra,
50.0,
product_id.weight_extra,
)

# _compute_product_weight_extra
product_product = self._get_product_id()
productAttPrice = self.env["product.template.attribute.value"].search(
[
("product_tmpl_id", "=", self.config_product.id),
("product_attribute_value_id", "=", self.value_gasoline.id),
]
)
productAttPrice.weight_extra = 45
product_product._compute_product_weight_extra()
self.assertEqual(
productAttPrice.weight_extra,
product_product.weight_extra,
Expand Down Expand Up @@ -620,22 +648,19 @@ def test_18_check_duplicate_product(self):
}
)
product_config_wizard.action_next_step()
val_ids = self.value_gasoline + self.value_218i + self.value_red
pta_val_ids = self.env["product.template.attribute.value"].search(
[
("product_tmpl_id", "=", self.product_tmpl_id.id),
("product_attribute_value_id", "in", val_ids.ids),
]
)
with self.assertRaises(ValidationError):
self.env["product.product"].create(
{
"name": "Test Configuration",
"product_tmpl_id": self.product_tmpl_id.id,
"attribute_value_ids": [
(
6,
0,
[
self.value_gasoline.id,
self.value_218i.id,
self.value_red.id,
],
)
],
"product_template_attribute_value_ids": [(6, 0, pta_val_ids.ids)],
}
)

Expand Down Expand Up @@ -693,3 +718,15 @@ def test_24_search_weight(self):
"Error: If value False\
Method: _search_weight()",
)

def test_25_check_config_line_domain(self):
product_config_line = self.env.ref(
"product_configurator.product_config_line_218_lines"
)
with self.assertRaises(ValidationError):
self.env["product.template"].create(
{
"name": "template_test",
"config_line_ids": product_config_line,
}
)
5 changes: 2 additions & 3 deletions product_configurator/wizard/product_configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -913,12 +913,11 @@ def action_next_step(self):
raise ValidationError(
_("Product Template does not have any attribute lines defined")
)

next_step = self.config_session_id.get_next_step(
state=self.state,
product_tmpl_id=self.product_tmpl_id,
value_ids=self.value_ids,
custom_value_ids=self.custom_value_ids,
value_ids=self.config_session_id.value_ids,
custom_value_ids=self.config_session_id.custom_value_ids,
)
if not next_step:
return self.action_config_done()
Expand Down
1 change: 0 additions & 1 deletion product_configurator_sale/wizard/product_configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ def _get_order_line_vals(self, product_id):
line_vals.update(
{
"config_session_id": self.config_session_id.id,
"price_unit": self.config_session_id.price,
"name": product._get_mako_tmpl_name(),
}
)
Expand Down
27 changes: 1 addition & 26 deletions website_product_configurator/data/config_form_templates.xml
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@
<t t-set="curr_pl" t-value="website.get_current_pricelist()" />
<t
t-set="price"
t-value="product_variant.with_context(product_sessions=((product_variant.id, cfg_session_id.id),), pricelist=curr_pl.id).price"
t-value="product_variant.with_context(pricelist=curr_pl.id).price"
/>
<b
class="oe_price"
Expand Down Expand Up @@ -966,29 +966,4 @@
</xpath>
</template>

<template
id="cart_lines_json_price"
inherit_id="website_sale.cart_lines"
name="Shopping Cart Lines"
>
<xpath
expr="//table[hasclass('js_cart_lines')]//tbody//td[hasclass('td-price')]"
position="attributes"
>
<attribute name="t-if">not line.config_session_id</attribute>
</xpath>
<xpath
expr="//table[hasclass('js_cart_lines')]//tbody//td[hasclass('td-price')]"
position="after"
>
<td t-if="line.config_session_id" class="text-center td-price" name="price">
<span
t-field="line.with_context(product_sessions=((line.product_id.id, line.config_session_id.id),)).product_id.price"
style="white-space: nowrap;"
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"
/>
</td>
</xpath>
</template>

</odoo>
60 changes: 1 addition & 59 deletions website_product_configurator/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging

from odoo import _, api, models
from odoo import _, models
from odoo.exceptions import UserError, ValidationError
from odoo.http import request

Expand Down Expand Up @@ -46,11 +46,9 @@ def _cart_update(
config_session_id
)
product = config_session.product_id
session_map = ((product.id, config_session_id),)
ctx = {
"current_sale_line": line_id,
"default_config_session_id": config_session_id,
"product_sessions": session_map,
}
self = self.with_context(ctx)
SaleOrderLineSudo = SaleOrderLineSudo.with_context(ctx)
Expand Down Expand Up @@ -191,32 +189,6 @@ def _cart_update(
"option_ids": list(set(option_lines.ids)),
}

def _website_product_id_change(self, order_id, product_id, qty=0):
session_map = self.env.context.get("product_sessions", ())
ctx = self._context.copy()
if not session_map:
current_sale_line = self.env.context.get("current_sale_line")
sale_line = False
if current_sale_line:
sale_line = self.env["sale.order.line"].browse(int(current_sale_line))
if sale_line:
session_map = ((sale_line.product_id.id, sale_line.cfg_session_id.id),)
ctx["product_sessions"] = session_map
if isinstance(session_map, tuple):
session_map = dict(session_map)

self = self.with_context(ctx)
values = super(SaleOrder, self)._website_product_id_change(
order_id=order_id, product_id=product_id, qty=qty
)
if session_map.get(product_id, False):
config_session = self.env["product.config.session"].browse(
session_map.get(product_id)
)
if not config_session.exists():
return values
return values

def _cart_find_product_line(self, product_id=None, line_id=None, **kwargs):
"""Include Config session in search."""
order_line = super(SaleOrder, self)._cart_find_product_line(
Expand All @@ -227,11 +199,6 @@ def _cart_find_product_line(self, product_id=None, line_id=None, **kwargs):
return order_line

config_session_id = kwargs.get("config_session_id", False)
if not config_session_id:
session_map = self.env.context.get("product_sessions", ())
if isinstance(session_map, tuple):
session_map = dict(session_map)
config_session_id = session_map.get(product_id, False)
if not config_session_id:
return order_line

Expand All @@ -248,31 +215,6 @@ def create(self, vals):
res = super(SaleOrderLine, self).create(vals)
return res

@api.onchange(
"product_id", "price_unit", "product_uom", "product_uom_qty", "tax_id"
)
def _onchange_discount(self):
if self.config_session_id:
self = self.with_context(
product_sessions=((self.product_id.id, self.config_session_id.id),)
)
return super(SaleOrderLine, self)._onchange_discount()

def _get_display_price(self, product):
if self.config_session_id:
session_map = ((self.product_id.id, self.config_session_id.id),)
self = self.with_context(product_sessions=session_map)
product = product.with_context(product_sessions=session_map)
res = super(SaleOrderLine, self)._get_display_price(product=product)
return res

@api.onchange("product_uom", "product_uom_qty")
def product_uom_change(self):
if self.config_session_id:
session_map = ((self.product_id.id, self.config_session_id.id),)
self = self.with_context(product_sessions=session_map)
super(SaleOrderLine, self).product_uom_change()

def _get_real_price_currency(self, product, rule_id, qty, uom, pricelist_id):
if not product.config_ok:
return super(SaleOrderLine, self)._get_real_price_currency(
Expand Down
Loading