From 80e87a8ceac229d8c1c53d0f30c1aaed0731cf67 Mon Sep 17 00:00:00 2001 From: Yolann Sabaux Date: Thu, 29 Sep 2022 09:33:17 +0000 Subject: [PATCH] [FIX] website_event_booth_sale: display price correction Steps to reproduce: - Create a price list with different currency and discount with "show price and discount to the customer" - On the website select this pricelist and try to select the booth Issue: The displayed price will not be the correct one Note: This is an issue discovered during the correction of https://github.com/odoo/odoo/pull/101375 (forward-port of https://github.com/odoo/odoo/pull/85640) It allows to have the correct price depending of the currency of the pricelist applied. Now the unlink of the rate makes the new rate directlt effective. There is no need of having a `new_company` anymore. Summary: - view modification in `website_event_booth_sale` -> price of selected booth, simplification of comparison for the `` - view modification in `website_event_sale` : simplification of comparison for the `` - backend test modification in `website_event_[booth_]sale` common: addapt the rate; take out useless `new_env`; simplified pricelists creation - tour test addition: added the tour for essential use cases in event and event_booth; simplified the command so it is more readable related ticket: opw-2766997 closes odoo/odoo#106593 closes odoo/odoo#107768 X-original-commit: 43c9d9892f593a41c7fe139dada0ce3f79f6f287 Signed-off-by: Thibault Delavallee (tde) Signed-off-by: Nicolas Lempereur (nle) Signed-off-by: Yolann Sabaux (yosa) --- .../website_event_booth_sale/__manifest__.py | 2 +- .../WebsiteEventBoothSaleTourMethods.js | 58 ++++++++++++++ .../website_event_booth_sale_pricelists.js | 78 +++++++++++++++++++ .../tests/test_event_booth_sale.py | 7 +- ...test_website_event_booth_sale_pricelist.py | 8 +- .../views/event_booth_templates.xml | 2 +- .../helpers/WebsiteEventSaleTourMethods.js | 76 ++++++++++++++++++ .../tours/website_event_sale_pricelists.js | 57 ++++++++++++++ addons/website_event_sale/tests/common.py | 42 ++++++---- .../tests/test_frontend_buy_tickets.py | 5 +- .../test_website_event_sale_pricelist.py | 8 +- 11 files changed, 316 insertions(+), 27 deletions(-) create mode 100644 addons/website_event_booth_sale/static/tests/tours/helpers/WebsiteEventBoothSaleTourMethods.js create mode 100644 addons/website_event_booth_sale/static/tests/tours/website_event_booth_sale_pricelists.js create mode 100644 addons/website_event_sale/static/tests/tours/helpers/WebsiteEventSaleTourMethods.js create mode 100644 addons/website_event_sale/static/tests/tours/website_event_sale_pricelists.js diff --git a/addons/website_event_booth_sale/__manifest__.py b/addons/website_event_booth_sale/__manifest__.py index f31ba71a69c..a0910ad87c2 100644 --- a/addons/website_event_booth_sale/__manifest__.py +++ b/addons/website_event_booth_sale/__manifest__.py @@ -18,7 +18,7 @@ Use the e-commerce to sell your event booths. '/website_event_booth_sale/static/src/js/booth_register.js', ], 'web.assets_tests': [ - '/website_event_booth_sale/static/tests/tours/website_event_booth.js', + '/website_event_booth_sale/static/tests/tours/**/**.js' ], }, 'license': 'LGPL-3', diff --git a/addons/website_event_booth_sale/static/tests/tours/helpers/WebsiteEventBoothSaleTourMethods.js b/addons/website_event_booth_sale/static/tests/tours/helpers/WebsiteEventBoothSaleTourMethods.js new file mode 100644 index 00000000000..a3f85169d87 --- /dev/null +++ b/addons/website_event_booth_sale/static/tests/tours/helpers/WebsiteEventBoothSaleTourMethods.js @@ -0,0 +1,58 @@ +odoo.define('website_event_booth_sale.tour.WebsiteEventBoothSaleTourMethods', function (require) { + 'use strict'; + + const { changePricelist, checkPriceCart } = require('website_event_sale.tour.WebsiteEventSaleTourMethods'); + + function checkPriceBooth(eventName, price, priceSelected) { + return [ + { + content: "Go to page Event", + trigger: '.nav-link:contains("Event")', + }, + { + content: 'Open "Test Event Booths" event', + trigger: `h5.card-title span:contains(${eventName})`, + }, + { + content: 'Go to "Get A Booth" page', + trigger: 'li.nav-item a:has(span:contains("Get A Booth"))', + }, + { + content: 'Select the booth', + trigger: '.o_wbooth_booths input[name="event_booth_ids"]', + run: function () { + $('.o_wbooth_booths input[name="event_booth_ids"]:lt(1)').click(); + }, + }, + { + content: "Verify Price displayed", + trigger: `.oe_currency_value:contains(${price})`, + run: function () {}, // it's a check + }, + { + content: "Verify Price of selected booth", + trigger: `div.o_wbooth_booth_total_price span.oe_currency_value:contains(${priceSelected})`, + run: function () {}, // it's a check + }, + ] + } + function checkPriceDiscountBooth(eventName, price, priceSelected, discount) { + return [ + ...checkPriceBooth(eventName, price, priceSelected), + { + content: "Verify Price before discount", + trigger: `del:contains(${discount})`, + run: function () {}, // it's a check + }, + ] + } + const getPriceListChecksSteps = function ({pricelistName, eventName, price, priceSelected, priceCart, priceBeforeDiscount=false}) { + const checkPriceSteps = priceBeforeDiscount ? checkPriceDiscountBooth(eventName, price, priceSelected, priceBeforeDiscount) : checkPriceBooth(eventName, price, priceSelected); + return [ + ...changePricelist(pricelistName), + ...checkPriceSteps, + ...checkPriceCart(priceCart), + ] + } + return { getPriceListChecksSteps } +}); diff --git a/addons/website_event_booth_sale/static/tests/tours/website_event_booth_sale_pricelists.js b/addons/website_event_booth_sale/static/tests/tours/website_event_booth_sale_pricelists.js new file mode 100644 index 00000000000..218fc0b5241 --- /dev/null +++ b/addons/website_event_booth_sale/static/tests/tours/website_event_booth_sale_pricelists.js @@ -0,0 +1,78 @@ +/** @odoo-module **/ + +import tour from 'web_tour.tour'; +import { getPriceListChecksSteps } from 'website_event_booth_sale.tour.WebsiteEventBoothSaleTourMethods'; + +tour.register('event_booth_sale_pricelists_different_currencies', { + test: true, + url: '/event', +}, [ + // Init: registering the booth + { + content: 'Open "Test Event Booths" event', + trigger: 'h5.card-title span:contains("Test Event Booths")', + }, + { + content: 'Go to "Get A Booth" page', + trigger: 'li.nav-item a:has(span:contains("Get A Booth"))', + }, + { + content: 'Select the booth', + trigger: '.o_wbooth_booths input[name="event_booth_ids"]', + run: function () { + $('.o_wbooth_booths input[name="event_booth_ids"]:lt(1)').click(); + }, + }, + { + content: 'Confirm the booth by clicking the submit button', + trigger: 'button.o_wbooth_registration_submit', + }, + { + content: 'Fill in your contact information', + trigger: 'input[name="contact_name"]', + run: function () { + $('input[name="contact_name"]').val('John Doe'); + $('input[name="contact_email"]').val('jdoe@example.com'); + }, + }, + { + content: 'Submit your informations', + trigger: 'button[type="submit"]', + }, + { + content: 'Confirm Order', + extra_trigger: 'h3:contains("Billing Address")', + trigger: '.btn:contains("Confirm")', + run: function () {}, + }, + ...getPriceListChecksSteps({ + pricelistName: "EUR With Discount Included", + eventName: "Test Event Booths", + price: "90.00", + priceSelected: "90", + priceCart: "99.00", + }), + ...getPriceListChecksSteps({ + pricelistName: "EUR Without Discount Included", + eventName: "Test Event Booths", + price: "90.00", + priceSelected: "90", + priceCart: "99.00", + priceBeforeDiscount: "100.00", + }), + ...getPriceListChecksSteps({ + pricelistName: "EX With Discount Included", + eventName: "Test Event Booths", + price: "900.00", + priceSelected: "900", + priceCart: "990.00", + }), + ...getPriceListChecksSteps({ + pricelistName: "EX Without Discount Included", + eventName: "Test Event Booths", + price: "900.00", + priceSelected: "900", + priceCart: "990.00", + priceBeforeDiscount: "1,000.00", + }), +]); diff --git a/addons/website_event_booth_sale/tests/test_event_booth_sale.py b/addons/website_event_booth_sale/tests/test_event_booth_sale.py index 2647c596361..7abea399d87 100644 --- a/addons/website_event_booth_sale/tests/test_event_booth_sale.py +++ b/addons/website_event_booth_sale/tests/test_event_booth_sale.py @@ -4,12 +4,14 @@ from datetime import datetime, timedelta from odoo import Command, fields +from odoo.addons.website_event_sale.tests.common import TestWebsiteEventSaleCommon from odoo.tests import HttpCase from odoo.tests.common import tagged + @tagged('post_install', '-at_install') -class TestWebsiteEventBoothSale(HttpCase): +class TestWebsiteEventBoothSale(HttpCase, TestWebsiteEventSaleCommon): def setUp(self): super().setUp() @@ -61,3 +63,6 @@ class TestWebsiteEventBoothSale(HttpCase): def test_tour(self): self.start_tour('/event', 'website_event_booth_tour', login='portal') + + def test_booth_pricelists_different_currencies(self): + self.start_tour("/web", 'event_booth_sale_pricelists_different_currencies', login='admin') diff --git a/addons/website_event_booth_sale/tests/test_website_event_booth_sale_pricelist.py b/addons/website_event_booth_sale/tests/test_website_event_booth_sale_pricelist.py index b2d86cd7e08..0e5a84e5e09 100644 --- a/addons/website_event_booth_sale/tests/test_website_event_booth_sale_pricelist.py +++ b/addons/website_event_booth_sale/tests/test_website_event_booth_sale_pricelist.py @@ -38,7 +38,7 @@ class TestWebsiteBoothPriceList(TestEventBoothSaleCommon, TestWebsiteEventSaleCo }) # set pricelist to 0 - currency: company self.pricelist.write({ - 'currency_id': self.new_company.currency_id.id, + 'currency_id': self.env.company.currency_id.id, 'discount_policy': 'with_discount', 'item_ids': [(5, 0, 0), (0, 0, { 'applied_on': '3_global', @@ -50,7 +50,7 @@ class TestWebsiteBoothPriceList(TestEventBoothSaleCommon, TestWebsiteEventSaleCo with MockRequest(self.env, sale_order_id=self.so.id, website=self.current_website): self.WebsiteSaleController.pricelist(promo=None) self.so._cart_update(line_id=so_line.id, product_id=self.event_booth_product.id, set_qty=1) - self.assertEqual(so_line.price_reduce, 40) + self.assertEqual(so_line.price_reduce_taxexcl, 40) # set pricelist to 10% - without discount self.pricelist.write({ @@ -66,7 +66,7 @@ class TestWebsiteBoothPriceList(TestEventBoothSaleCommon, TestWebsiteEventSaleCo with MockRequest(self.env, sale_order_id=self.so.id, website=self.current_website): self.WebsiteSaleController.pricelist(promo=None) self.so._cart_update(line_id=so_line.id, product_id=self.event_booth_product.id, set_qty=1) - self.assertEqual(so_line.price_reduce, 360, 'Incorrect amount based on the pricelist "Without Discount" and its currency.') + self.assertEqual(so_line.price_reduce_taxexcl, 360, 'Incorrect amount based on the pricelist "Without Discount" and its currency.') # set pricelist to 10% - with discount self.pricelist.write({ @@ -76,4 +76,4 @@ class TestWebsiteBoothPriceList(TestEventBoothSaleCommon, TestWebsiteEventSaleCo with MockRequest(self.env, sale_order_id=self.so.id, website=self.current_website): self.WebsiteSaleController.pricelist(promo=None) self.so._cart_update(line_id=so_line.id, product_id=self.event_booth_product.id, set_qty=1) - self.assertEqual(so_line.price_reduce, 360, 'Incorrect amount based on the pricelist "With Discount" and its currency.') + self.assertEqual(so_line.price_reduce_taxexcl, 360, 'Incorrect amount based on the pricelist "With Discount" and its currency.') diff --git a/addons/website_event_booth_sale/views/event_booth_templates.xml b/addons/website_event_booth_sale/views/event_booth_templates.xml index 7b17b7220d0..840479159a9 100644 --- a/addons/website_event_booth_sale/views/event_booth_templates.xml +++ b/addons/website_event_booth_sale/views/event_booth_templates.xml @@ -21,7 +21,7 @@ event.company_id.sudo().currency_id._convert( - booth_category.price_reduce_taxeinc if env.user.has_group('account.group_show_line_subtotals_tax_included') else booth_category.price_reduce, + booth_category.price_reduce_taxinc if env.user.has_group('account.group_show_line_subtotals_tax_included') else booth_category.price_reduce, website.get_current_pricelist().currency_id, event.company_id, datetime.date.today() diff --git a/addons/website_event_sale/static/tests/tours/helpers/WebsiteEventSaleTourMethods.js b/addons/website_event_sale/static/tests/tours/helpers/WebsiteEventSaleTourMethods.js new file mode 100644 index 00000000000..d93832b91f1 --- /dev/null +++ b/addons/website_event_sale/static/tests/tours/helpers/WebsiteEventSaleTourMethods.js @@ -0,0 +1,76 @@ +odoo.define('website_event_sale.tour.WebsiteEventSaleTourMethods', function (require) { + 'use strict'; + + function changePricelist(pricelistName) { + return [ + { + content: "Go to page Shop", + trigger: '.nav-link:contains("Shop")', + }, + { + content: "Toggle Pricelist", + trigger: '.o_pricelist_dropdown > .dropdown-toggle', + run: 'click', + }, + { + content: `Activate Pricelist ${pricelistName}`, + trigger: `.dropdown-item:contains(${pricelistName})`, + run: 'click', + }, + { + content: 'Wait for pricelist to load', + trigger: `.dropdown-toggle:contains(${pricelistName})`, + run: function () {}, + }, + ]; + } + function checkPriceEvent(eventName, price) { + return [ + { + content: "Go to page Event", + trigger: '.nav-link:contains("Event")', + }, + { + content: "Open the Pycon event", + trigger: `.o_wevent_events_list a:contains(${eventName})`, + }, + { + content: "Verify Price", + trigger: `.oe_currency_value:contains(${price})`, + run: function () {}, // it's a check + }, + ] + } + function checkPriceDiscountEvent(eventName, price, discount) { + return [ + ...checkPriceEvent(eventName, price), + { + content: "Verify Price before discount", + trigger: `del:contains(${discount})`, + run: function () {}, // it's a check + }, + ] + } + function checkPriceCart(price) { + return [ + { + content: "Go to page Cart", + trigger: '.fa-shopping-cart', + }, + { + content: "Verify Price", + trigger: `[id=order_total] .oe_currency_value:contains(${price})`, + run: function () {}, // it's a check + }, + ] + } + const getPriceListChecksSteps = function ({pricelistName, eventName, price, priceBeforeDiscount=false}) { + const checkPriceSteps = priceBeforeDiscount ? checkPriceDiscountEvent(eventName, price, priceBeforeDiscount) : checkPriceEvent(eventName, price); + return [ + ...changePricelist(pricelistName), + ...checkPriceSteps, + ...checkPriceCart(price), + ] + } + return { getPriceListChecksSteps, changePricelist, checkPriceCart } +}); diff --git a/addons/website_event_sale/static/tests/tours/website_event_sale_pricelists.js b/addons/website_event_sale/static/tests/tours/website_event_sale_pricelists.js new file mode 100644 index 00000000000..fd87ca2ae75 --- /dev/null +++ b/addons/website_event_sale/static/tests/tours/website_event_sale_pricelists.js @@ -0,0 +1,57 @@ +odoo.define('website_event_sale.tour.event_sale_pricelists_different_currencies', function (require) { + 'use strict'; + + const tour = require('web_tour.tour'); + const { getPriceListChecksSteps } = require('website_event_sale.tour.WebsiteEventSaleTourMethods'); + + tour.register('event_sale_pricelists_different_currencies', { + test: true, + url: '/event', + },[ + // Register for tickets + { + content: "Open the Pycon event", + trigger: '.o_wevent_events_list a:contains("Pycon")', + }, + { + content: "Register", + trigger: '.btn-primary:contains("Register")', + }, + { + content: "Fill attendees details", + trigger: 'form[id="attendee_registration"] .btn:contains("Continue")', + run: function () { + $("input[name='1-name']").val("Great Name"); + $("input[name='1-phone']").val("111 111"); + $("input[name='1-email']").val("great@name.com"); + }, + }, + { + content: "Validate attendees details", + extra_trigger: "input[name='1-name'], input[name='2-name']", + trigger: 'button:contains("Continue")', + }, + ...getPriceListChecksSteps({ + pricelistName: "EUR With Discount Included", + eventName: "Pycon", + price: "90.00", + }), + ...getPriceListChecksSteps({ + pricelistName: "EUR Without Discount Included", + eventName: "Pycon", + price: "90.00", + priceBeforeDiscount: "100.00", + }), + ...getPriceListChecksSteps({ + pricelistName: "EX With Discount Included", + eventName: "Pycon", + price: "900.00", + }), + ...getPriceListChecksSteps({ + pricelistName: "EX Without Discount Included", + eventName: "Pycon", + price: "900.00", + priceBeforeDiscount: "1,000.00", + }), + ]); +}); diff --git a/addons/website_event_sale/tests/common.py b/addons/website_event_sale/tests/common.py index 989d388091c..f824e054b8f 100644 --- a/addons/website_event_sale/tests/common.py +++ b/addons/website_event_sale/tests/common.py @@ -13,33 +13,28 @@ class TestWebsiteEventSaleCommon(TransactionCase): def setUpClass(cls): super(TestWebsiteEventSaleCommon, cls).setUpClass() - cls.env.ref('base.USD').write({'active': False}) cls.currency_test = cls.env['res.currency'].create({ 'name': 'eventX', - 'rate': 10, 'rounding': 0.01, 'symbol': 'EX', }) - cls.partner = cls.env['res.partner'].create({'name': 'test'}) - cls.new_company = cls.env['res.company'].create({ - 'currency_id': cls.env.ref('base.EUR').id, - 'name': 'Great Company EUR', - 'partner_id': cls.partner.id, - }) - cls.env['res.currency.rate'].create({ - 'company_id': cls.new_company.id, + cls.env['res.currency.rate'].search([]).unlink() + cls.rate = cls.env['res.currency.rate'].create({ + 'company_id': cls.env.company.id, 'currency_id': cls.currency_test.id, 'name': '2022-01-01', 'rate': 10, }) - + cls.zero_tax = cls.env['account.tax'].sudo().create({ + 'name': 'Tax 0', + 'amount': 0, + }) cls.product_event = cls.env['product.product'].create({ - 'company_id': cls.new_company.id, - 'currency_id': cls.env.ref('base.EUR').id, 'detailed_type': 'event', 'list_price': 100, 'name': 'Event Registration No Company Assigned', + 'taxes_id': [(6, 0, cls.zero_tax.ids)], }) cls.event = cls.env['event.event'].create({ @@ -57,11 +52,28 @@ class TestWebsiteEventSaleCommon(TransactionCase): }]) cls.current_website = cls.env['website'].get_current_website() - cls.current_website.company_id = cls.new_company cls.pricelist = cls.current_website.get_current_pricelist() cls.so = cls.env['sale.order'].create({ - 'company_id': cls.new_company.id, + 'company_id': cls.env.company.id, 'partner_id': cls.partner.id, 'pricelist_id': cls.pricelist.id, }) + + def create_pricelist(currency, name, policy): + return cls.env['product.pricelist'].create({ + 'currency_id': currency.id, + 'discount_policy': policy, + 'item_ids': [(5, 0, 0), (0, 0, { + 'applied_on': '3_global', + 'compute_price': 'percentage', + 'percent_price': 10, + })], + 'name': name, + 'selectable': True, + }) + + cls.pricelist_with_discount = create_pricelist(currency=cls.env.company.currency_id, name='EUR With Discount Included', policy='with_discount') + cls.pricelist_without_discount = create_pricelist(currency=cls.env.company.currency_id, name='EUR Without Discount Included', policy='without_discount') + cls.ex_pricelist_with_discount = create_pricelist(currency=cls.currency_test, name='EX With Discount Included', policy='with_discount') + cls.ex_pricelist_without_discount = create_pricelist(currency=cls.currency_test, name='EX Without Discount Included', policy='without_discount') diff --git a/addons/website_event_sale/tests/test_frontend_buy_tickets.py b/addons/website_event_sale/tests/test_frontend_buy_tickets.py index 3578aa417fd..42b416d1b6e 100644 --- a/addons/website_event_sale/tests/test_frontend_buy_tickets.py +++ b/addons/website_event_sale/tests/test_frontend_buy_tickets.py @@ -6,11 +6,12 @@ import odoo.tests from datetime import timedelta from odoo.addons.base.tests.common import HttpCaseWithUserDemo +from odoo.addons.website_event_sale.tests.common import TestWebsiteEventSaleCommon from odoo.fields import Datetime @odoo.tests.common.tagged('post_install', '-at_install') -class TestUi(HttpCaseWithUserDemo): +class TestUi(HttpCaseWithUserDemo, TestWebsiteEventSaleCommon): def setUp(self): super().setUp() @@ -124,4 +125,6 @@ class TestUi(HttpCaseWithUserDemo): self.start_tour("/", 'event_buy_last_ticket') + def test_pricelists_different_currencies(self): + self.start_tour("/", 'event_sale_pricelists_different_currencies', login='admin') # TO DO - add public test with new address when convert to web.tour format. diff --git a/addons/website_event_sale/tests/test_website_event_sale_pricelist.py b/addons/website_event_sale/tests/test_website_event_sale_pricelist.py index e2f9ba9d5eb..d7f16cfc7e3 100644 --- a/addons/website_event_sale/tests/test_website_event_sale_pricelist.py +++ b/addons/website_event_sale/tests/test_website_event_sale_pricelist.py @@ -28,7 +28,7 @@ class TestWebsiteEventPriceList(TestWebsiteEventSaleCommon): }) # set pricelist to 0 - currency: company self.pricelist.write({ - 'currency_id': self.new_company.currency_id.id, + 'currency_id': self.env.company.currency_id.id, 'discount_policy': 'with_discount', 'item_ids': [(5, 0, 0), (0, 0, { 'applied_on': '3_global', @@ -40,7 +40,7 @@ class TestWebsiteEventPriceList(TestWebsiteEventSaleCommon): with MockRequest(self.env, sale_order_id=self.so.id, website=self.current_website): self.WebsiteSaleController.pricelist(promo=None) self.so._cart_update(line_id=so_line.id, product_id=self.ticket.product_id.id, set_qty=1) - self.assertEqual(so_line.price_reduce, 100) + self.assertEqual(so_line.price_reduce_taxexcl, 100) # set pricelist to 10% - without discount self.pricelist.write({ @@ -56,7 +56,7 @@ class TestWebsiteEventPriceList(TestWebsiteEventSaleCommon): with MockRequest(self.env, sale_order_id=self.so.id, website=self.current_website): self.WebsiteSaleController.pricelist(promo=None) self.so._cart_update(line_id=so_line.id, product_id=self.ticket.product_id.id, set_qty=1) - self.assertEqual(so_line.price_reduce, 900, 'Incorrect amount based on the pricelist and its currency.') + self.assertEqual(so_line.price_reduce_taxexcl, 900, 'Incorrect amount based on the pricelist and its currency.') # set pricelist to 10% - with discount self.pricelist.write({ @@ -66,4 +66,4 @@ class TestWebsiteEventPriceList(TestWebsiteEventSaleCommon): with MockRequest(self.env, sale_order_id=self.so.id, website=self.current_website): self.WebsiteSaleController.pricelist(promo=None) self.so._cart_update(line_id=so_line.id, product_id=self.ticket.product_id.id, set_qty=1) - self.assertEqual(so_line.price_reduce, 900, 'Incorrect amount based on the pricelist and its currency.') + self.assertEqual(so_line.price_reduce_taxexcl, 900, 'Incorrect amount based on the pricelist and its currency.')