From 5508465c83ab33256588f9902856806e08980e05 Mon Sep 17 00:00:00 2001 From: PRV Date: Mon, 25 Oct 2021 22:18:56 +0530 Subject: [PATCH] [WIP][T-01839]product_configurator: remove price calculation from session and also get value from get_attribute_value_extra_prices --- product_configurator/models/product.py | 54 +++---------- product_configurator/models/product_config.py | 1 - product_configurator/tests/__init__.py | 6 +- product_configurator/tests/test_product.py | 79 ++++++++++++++----- .../wizard/product_configurator.py | 5 +- .../wizard/product_configurator.py | 1 - .../data/config_form_templates.xml | 27 +------ .../models/sale_order.py | 60 +------------- .../static/src/js/website_config_tour.js | 79 +++++++++++-------- .../tests/test_product_config.py | 11 +++ .../tests/test_sale_order.py | 44 ++++++++++- 11 files changed, 175 insertions(+), 192 deletions(-) diff --git a/product_configurator/models/product.py b/product_configurator/models/product.py index e8da7de312..ef160bf1a8 100644 --- a/product_configurator/models/product.py +++ b/product_configurator/models/product.py @@ -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()) diff --git a/product_configurator/models/product_config.py b/product_configurator/models/product_config.py index 2f480c8fd5..795b8242e1 100644 --- a/product_configurator/models/product_config.py +++ b/product_configurator/models/product_config.py @@ -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 diff --git a/product_configurator/tests/__init__.py b/product_configurator/tests/__init__.py index 296985b7ad..435b31b0a0 100644 --- a/product_configurator/tests/__init__.py +++ b/product_configurator/tests/__init__.py @@ -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 diff --git a/product_configurator/tests/test_product.py b/product_configurator/tests/test_product.py index 6ff27aaadb..5b44263f9c 100644 --- a/product_configurator/tests/test_product.py +++ b/product_configurator/tests/test_product.py @@ -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\ @@ -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, } ) @@ -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, @@ -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)], } ) @@ -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, + } + ) diff --git a/product_configurator/wizard/product_configurator.py b/product_configurator/wizard/product_configurator.py index 540ff4fc14..46058a383e 100644 --- a/product_configurator/wizard/product_configurator.py +++ b/product_configurator/wizard/product_configurator.py @@ -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() diff --git a/product_configurator_sale/wizard/product_configurator.py b/product_configurator_sale/wizard/product_configurator.py index 3cfb90f745..300a3ac417 100644 --- a/product_configurator_sale/wizard/product_configurator.py +++ b/product_configurator_sale/wizard/product_configurator.py @@ -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(), } ) diff --git a/website_product_configurator/data/config_form_templates.xml b/website_product_configurator/data/config_form_templates.xml index 009f799015..9fbdacf12a 100644 --- a/website_product_configurator/data/config_form_templates.xml +++ b/website_product_configurator/data/config_form_templates.xml @@ -617,7 +617,7 @@ - - diff --git a/website_product_configurator/models/sale_order.py b/website_product_configurator/models/sale_order.py index dc3fa9598e..26b89c81f7 100644 --- a/website_product_configurator/models/sale_order.py +++ b/website_product_configurator/models/sale_order.py @@ -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 @@ -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) @@ -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( @@ -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 @@ -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( diff --git a/website_product_configurator/static/src/js/website_config_tour.js b/website_product_configurator/static/src/js/website_config_tour.js index 288dede7b5..326cf39526 100644 --- a/website_product_configurator/static/src/js/website_config_tour.js +++ b/website_product_configurator/static/src/js/website_config_tour.js @@ -26,14 +26,13 @@ odoo.define("website_product_configurator.tour_configuration", function (require }, { content: "click to select fuel", - trigger: "div.tab-pane.container.fade.active.in select:first", - extra_trigger: ".nav-item.config_step.active a:contains(Engine)", + trigger: ".tab-pane.fade.container.show.active select", run: function () { $( - ".tab-pane.container.fade.active.in select:first option:contains(Gasoline)" + ".tab-pane.fade.container.show.active select:first option:contains(Gasoline)" )[0].selected = true; $( - ".tab-pane.container.fade.active.in select:first option:contains(Gasoline)" + ".tab-pane.fade.container.show.active select:first option:contains(Gasoline)" ) .closest("select") .change(); @@ -42,13 +41,13 @@ odoo.define("website_product_configurator.tour_configuration", function (require { content: "click to select engine", trigger: - ".tab-pane.container.fade.active.in select.form-control.config_attribute.required_config_attrib", + ".tab-pane.fade.container.show.active select.form-control.config_attribute.cfg-select.required_config_attrib", run: function () { $( - ".tab-pane.container.fade.active.in select.form-control.config_attribute.required_config_attrib option:contains(218i)" + ".tab-pane.fade.container.show.active select > option:contains(218i)" )[0].selected = true; $( - ".tab-pane.container.fade.active.in select.form-control.config_attribute.required_config_attrib option:contains(218i)" + ".tab-pane.fade.container.show.active select > option:contains(218i)" ) .closest("select") .change(); @@ -56,18 +55,18 @@ odoo.define("website_product_configurator.tour_configuration", function (require }, { content: "click on continue", - trigger: "#form_action span:contains(Continue)", + trigger: "span:contains(Continue)", + run: "click", }, { content: "click to select color", - extra_trigger: ".nav-item.config_step.active a:contains(Body)", - trigger: "div.tab-pane.container.fade.active.in select:first", + trigger: ".tab-pane.fade.container.show.active select", run: function () { $( - ".tab-pane.container.fade.active.in select:first option:contains(Silver)" + ".tab-pane.fade.container.show.active select:first option:contains(Silver)" )[0].selected = true; $( - ".tab-pane.container.fade.active.in select:first option:contains(Silver)" + ".tab-pane.fade.container.show.active select:first option:contains(Silver)" ) .closest("select") .change(); @@ -76,13 +75,13 @@ odoo.define("website_product_configurator.tour_configuration", function (require { content: "click to select rims", trigger: - "div.tab-pane.container.fade.active.in select.form-control.config_attribute.required_config_attrib", + ".tab-pane.fade.container.show.active select.form-control.config_attribute.cfg-select.required_config_attrib", run: function () { $( - ".tab-pane.container.fade.active.in select.form-control.config_attribute.required_config_attrib option:contains(V-spoke 16)" + ".tab-pane.fade.container.show.active select > option:contains(V-spoke 16)" )[0].selected = true; $( - ".tab-pane.container.fade.active.in select.form-control.config_attribute.required_config_attrib option:contains(V-spoke 16)" + ".tab-pane.fade.container.show.active select > option:contains(V-spoke 16)" ) .closest("select") .change(); @@ -90,18 +89,19 @@ odoo.define("website_product_configurator.tour_configuration", function (require }, { content: "click on continue", - trigger: "#form_action span:contains(Continue)", + extra_trigger: ".nav-item.config_step a:contains(Lines)", + trigger: "span:contains(Continue)", + run: "click", }, { content: "click to select Lines", - extra_trigger: ".nav-item.config_step.active a:contains(Lines)", - trigger: ".tab-pane.container.fade.active.in select:first", + trigger: ".tab-pane.fade.container.show.active select", run: function () { $( - ".tab-pane.container.fade.active.in select:first option:contains(Sport Line)" + ".tab-pane.fade.container.show.active select option:contains(Sport Line)" )[0].selected = true; $( - ".tab-pane.container.fade.active.in select:first option:contains(Sport Line)" + ".tab-pane.fade.container.show.active select option:contains(Sport Line)" ) .closest("select") .change(); @@ -109,18 +109,18 @@ odoo.define("website_product_configurator.tour_configuration", function (require }, { content: "click on continue", - trigger: "#form_action span:contains(Continue)", + trigger: "span:contains(Continue)", + run: "click", }, { content: "click to select tapistry", - extra_trigger: ".nav-item.config_step.active a:contains(Interior)", - trigger: "div.tab-pane.container.fade.active.in select:first", + trigger: ".tab-pane.fade.container.show.active select", run: function () { $( - ".tab-pane.container.fade.active.in select:first option:contains(Black)" + ".tab-pane.fade.container.show.active select option:contains(Black)" )[0].selected = true; $( - ".tab-pane.container.fade.active.in select:first option:contains(Black)" + ".tab-pane.fade.container.show.active select option:contains(Black)" ) .closest("select") .change(); @@ -128,18 +128,18 @@ odoo.define("website_product_configurator.tour_configuration", function (require }, { content: "click on continue", - trigger: "#form_action span:contains(Continue)", + trigger: "span:contains(Continue)", + run: "click", }, { content: "click to select Transmission", - extra_trigger: ".nav-item.config_step.active a:contains(Extras)", - trigger: "div.tab-pane.container.fade.active.in select:first", + trigger: ".tab-pane.fade.container.show.active select", run: function () { $( - '.tab-pane.container.fade.active.in select:first option:contains("Automatic (Steptronic)")' + '.tab-pane.fade.container.show.active select:first option:contains("Automatic (Steptronic)")' )[0].selected = true; $( - '.tab-pane.container.fade.active.in select:first option:contains("Automatic (Steptronic)")' + '.tab-pane.fade.container.show.active select:first option:contains("Automatic (Steptronic)")' ) .closest("select") .change(); @@ -148,13 +148,13 @@ odoo.define("website_product_configurator.tour_configuration", function (require { content: "click to select Options", trigger: - "div.tab-pane.container.fade.active.in select.form-control.config_attribute.required_config_attrib", + ".tab-pane.fade.container.show.active select.form-control.config_attribute.cfg-select.required_config_attrib", run: function () { $( - ".tab-pane.container.fade.active.in select.form-control.config_attribute.required_config_attrib option:contains(Armrest)" + ".tab-pane.fade.container.show.active select > option:contains(Armrest)" )[0].selected = true; $( - ".tab-pane.container.fade.active.in select.form-control.config_attribute.required_config_attrib option:contains(Armrest)" + ".tab-pane.fade.container.show.active select > option:contains(Armrest)" ) .closest("select") .change(); @@ -162,7 +162,18 @@ odoo.define("website_product_configurator.tour_configuration", function (require }, { content: "click on continue", - trigger: "#form_action span:contains(Continue)", + trigger: "span:contains(Continue)", + run: "click", + }, + { + content: "click on add to cart", + trigger: "#add_to_cart", + run: "click", + }, + { + content: "proceed to checkout product", + trigger: 'a[href*="/shop/checkout"]', + run: "click", }, ] ); diff --git a/website_product_configurator/tests/test_product_config.py b/website_product_configurator/tests/test_product_config.py index 9da5685df0..a7faa3a716 100644 --- a/website_product_configurator/tests/test_product_config.py +++ b/website_product_configurator/tests/test_product_config.py @@ -26,6 +26,17 @@ def test_get_website_template(self): "We do not return the correct view_id", ) + # set template id false + self.env["ir.config_parameter"].sudo().set_param( + "product_configurator.default_configuration_step_website_view_id", False + ) + dafault_template_xml_id = self.configStepLine.get_website_template() + self.assertEqual( + dafault_template_xml_id, + "website_product_configurator.config_form_select", + "Default Template xml id is not set.", + ) + class TestProductConfig(TestProductConfiguratorValues): def test_remove_inactive_config_sessions(self): diff --git a/website_product_configurator/tests/test_sale_order.py b/website_product_configurator/tests/test_sale_order.py index 5190c9e620..e2a126c934 100644 --- a/website_product_configurator/tests/test_sale_order.py +++ b/website_product_configurator/tests/test_sale_order.py @@ -33,9 +33,6 @@ def setUp(self): ], } ) - self.sale_order.order_line._onchange_discount() - self.sale_order.order_line._get_display_price(self.product) - self.sale_order.order_line.product_uom_change() def test_cart_update(self): product_id = ( @@ -62,6 +59,47 @@ def test_cart_update(self): cart_update.get("quantity"), self.sale_order.order_line.product_uom_qty ) + self.sale_order.write({"order_line": False}) + self.sale_order._cart_update( + product_id=product_id, + set_qty=1, + add_qty=1, + ) + self.assertTrue(self.sale_order.order_line, "No Sale Order Line created.") + + self.sale_order._cart_update( + product_id=product_id, + line_id=self.sale_order.order_line.id, + set_qty=-1, + add_qty=1, + ) + self.assertFalse( + self.sale_order.order_line, + "Order Line is exist for quantity is less than equal zero.", + ) + + self.sale_order._cart_update( + line_id=self.sale_order.order_line.id, + product_id=product_id, + add_qty="test", + ) + self.assertEqual( + self.sale_order.order_line.product_uom_qty, + 1, + "If wrong value is added then 1 quantity is deducted from Order Line.", + ) + + self.sale_order._cart_update( + line_id=self.sale_order.order_line.id, + product_id=product_id, + set_qty="test", + ) + self.assertEqual( + self.sale_order.order_line.product_uom_qty, + 1, + "If wrong value is added then Order Line quantity as it is.", + ) + def test_get_real_price_currency(self): price, rule_id = self.sale_order.pricelist_id.get_product_price_rule( self.sale_order.order_line.product_id,