diff --git a/addons/website/tests/test_qweb.py b/addons/website/tests/test_qweb.py index 8cba2d150c0..b752d641f40 100644 --- a/addons/website/tests/test_qweb.py +++ b/addons/website/tests/test_qweb.py @@ -2,10 +2,9 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import re -import werkzeug -import odoo from odoo import tools +from odoo.addons.website.tools import MockRequest from odoo.modules.module import get_module_resource from odoo.tests.common import TransactionCase @@ -66,42 +65,6 @@ class TestQweb(TransactionCase): "user_id": demo.id, }).encode('utf8')) -class MockObject(object): - _log_call = [] - def __init__(self, *args, **kwargs): - self.__dict__ = kwargs - def __call__(self, *args, **kwargs): - self._log_call.append((args, kwargs)) - return self - def __getitem__(self, index): - return self - -def werkzeugRaiseNotFound(*args, **kwargs): - raise werkzeug.exceptions.NotFound() - -class MockRequest(object): - """ Class with context manager mocking odoo.http.request for tests """ - def __init__(self, env, website=None, context=None, multilang=True, routing=True): - app = MockObject(routing={ - 'type': 'http', - 'website': True, - 'multilang': multilang, - }) - app.get_db_router = app.bind = app.match = app - if not routing: - app.match = werkzeugRaiseNotFound - self.request = MockObject( - env=env, context=context or {}, db=None, debug=False, - website=website, httprequest=MockObject( - path='/hello/', - app=app - ) - ) - odoo.http._request_stack.push(self.request) - def __enter__(self): - return self.request - def __exit__(self, exc_type, exc_value, traceback): - odoo.http._request_stack.pop() class TestQwebProcessAtt(TransactionCase): def setUp(self): @@ -128,7 +91,7 @@ class TestQwebProcessAtt(TransactionCase): self._test_att('/a', {'href': '/a'}) def test_process_att_no_website(self): - with MockRequest(self.env) as request: + with MockRequest(self.env): # no website so URL rewriting self._test_att('/', {'href': '/'}) self._test_att('/en_US/', {'href': '/en_US/'}) @@ -137,7 +100,7 @@ class TestQwebProcessAtt(TransactionCase): self._test_att('/a', {'href': '/a'}) def test_process_att_monolang_route(self): - with MockRequest(self.env, website=self.website, multilang=False) as request: + with MockRequest(self.env, website=self.website, multilang=False): # lang not changed in URL but CDN enabled self._test_att('/a', {'href': 'http://test.cdn/a'}) self._test_att('/en_US/a', {'href': 'http://test.cdn/en_US/a'}) @@ -145,19 +108,19 @@ class TestQwebProcessAtt(TransactionCase): self._test_att('/en_US/b', {'href': '/en_US/b'}) def test_process_att_no_request_lang(self): - with MockRequest(self.env, self.website) as request: + with MockRequest(self.env, website=self.website): self._test_att('/', {'href': '/'}) self._test_att('/en_US/', {'href': '/'}) self._test_att('/fr_FR/', {'href': '/fr_FR/'}) def test_process_att_with_request_lang(self): - with MockRequest(self.env, self.website, context={'lang': 'fr_FR'}) as request: + with MockRequest(self.env, website=self.website, context={'lang': 'fr_FR'}): self._test_att('/', {'href': '/fr_FR/'}) self._test_att('/en_US/', {'href': '/'}) self._test_att('/fr_FR/', {'href': '/fr_FR/'}) def test_process_att_matching_cdn_and_lang(self): - with MockRequest(self.env, self.website) as request: + with MockRequest(self.env, website=self.website): # lang prefix is added before CDN self._test_att('/a', {'href': 'http://test.cdn/a'}) self._test_att('/en_US/a', {'href': 'http://test.cdn/a'}) @@ -167,13 +130,13 @@ class TestQwebProcessAtt(TransactionCase): self._test_att('/fr_FR/b', {'href': '/fr_FR/b'}) def test_process_att_no_route(self): - with MockRequest(self.env, self.website, context={'lang': 'fr_FR'}, routing=False) as request: + with MockRequest(self.env, website=self.website, context={'lang': 'fr_FR'}, routing=False): # default on multilang=True if route is not /{module}/static/ self._test_att('/web/static/hi', {'href': '/web/static/hi'}) self._test_att('/my-page', {'href': '/fr_FR/my-page'}) def test_process_att_url_crap(self): - with MockRequest(self.env, self.website) as request: + with MockRequest(self.env, website=self.website) as request: # #{fragment} is stripped from URL when testing route self._test_att('/x#y?z', {'href': '/x#y?z'}) self.assertEqual( diff --git a/addons/website/tools.py b/addons/website/tools.py new file mode 100644 index 00000000000..fde1e94651d --- /dev/null +++ b/addons/website/tools.py @@ -0,0 +1,60 @@ +# -*- encoding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import odoo +import werkzeug + +from odoo.tools import DotDict + + +class MockObject(object): + _log_call = [] + + def __init__(self, *args, **kwargs): + self.__dict__ = kwargs + + def __call__(self, *args, **kwargs): + self._log_call.append((args, kwargs)) + return self + + def __getitem__(self, index): + return self + + +def werkzeugRaiseNotFound(*args, **kwargs): + raise werkzeug.exceptions.NotFound() + + +class MockRequest(object): + """ Class with context manager mocking odoo.http.request for tests """ + def __init__(self, env, **kw): + app = MockObject(routing={ + 'type': 'http', + 'website': True, + 'multilang': kw.get('multilang', True), + }) + app.get_db_router = app.bind = app.match = app + if not kw.get('routing', True): + app.match = werkzeugRaiseNotFound + self.request = DotDict({ + 'context': kw.get('context', {}), + 'db': None, + 'debug': False, + 'env': env, + 'httprequest': { + 'path': '/hello/', + 'app': app, + }, + 'redirect': werkzeug.utils.redirect, + 'session': { + 'sale_order_id': kw.get('sale_order_id'), + }, + 'website': kw.get('website'), + }) + odoo.http._request_stack.push(self.request) + + def __enter__(self): + return self.request + + def __exit__(self, exc_type, exc_value, traceback): + odoo.http._request_stack.pop() diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 88a8bb27fa5..8b37915e6be 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -605,7 +605,9 @@ class WebsiteSale(ProductConfiguratorController): new_values['customer'] = True new_values['team_id'] = request.website.salesteam_id and request.website.salesteam_id.id new_values['user_id'] = request.website.salesperson_id and request.website.salesperson_id.id - new_values['website_id'] = request.website.id + + if request.website.specific_user_account: + new_values['website_id'] = request.website.id if order.partner_id.id == request.website.user_id.sudo().partner_id.id: # If the partner is public, we assign the company of the website diff --git a/addons/website_sale/tests/test_sale_process.py b/addons/website_sale/tests/test_sale_process.py index ae3f63e436f..6609b4e4d9c 100644 --- a/addons/website_sale/tests/test_sale_process.py +++ b/addons/website_sale/tests/test_sale_process.py @@ -1,7 +1,11 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. + import odoo.tests +from odoo.addons.website_sale.controllers.main import WebsiteSale +from odoo.addons.website.tools import MockRequest + @odoo.tests.tagged('post_install', '-at_install') class TestUi(odoo.tests.HttpCase): @@ -14,4 +18,28 @@ class TestUi(odoo.tests.HttpCase): def test_03_demo_checkout(self): self.phantom_js("/", "odoo.__DEBUG__.services['web_tour.tour'].run('shop_buy_product')", "odoo.__DEBUG__.services['web_tour.tour'].tours.shop_buy_product.ready", login="demo") - # TO DO - add public test with new address when convert to web.tour format. + +@odoo.tests.tagged('post_install', '-at_install') +class TestWebsiteSaleCheckoutAddress(odoo.tests.TransactionCase): + def test_01_edit_billing_address(self): + website = self.env['website'].browse(1) + p = self.env.user.partner_id + so = self.env['sale.order'].create({ + 'partner_id': p.id, + 'website_id': website.id, + 'order_line': [(0, 0, { + 'product_id': self.env['product.product'].create({'name': 'Product A', 'list_price': 100}).id, + 'name': 'Product A', + })] + }) + country_id = self.env['res.country'].search([], limit=1).id + + WebsiteSaleController = WebsiteSale() + with MockRequest(self.env, website=website, sale_order_id=so.id): + WebsiteSaleController.address(name='website_sale test user', email='email@email.email', street='ooo', city='ooo', country_id=country_id, submitted=1, partner_id=p.id) + self.assertFalse(p.website_id, "Partner should not have a website set on him after editing billing.") + + website.specific_user_account = True + with MockRequest(self.env, website=website, sale_order_id=so.id): + WebsiteSaleController.address(name='website_sale test user', email='email@email.email', street='ooo', city='ooo', country_id=country_id, submitted=1, partner_id=p.id) + self.assertEqual(p.website_id, website, "Partner should have a website set on him after editing billing.") diff --git a/addons/website_sale/tests/test_website_sale_pricelist.py b/addons/website_sale/tests/test_website_sale_pricelist.py index eb3b9d5d1f6..9190ebc7dc5 100644 --- a/addons/website_sale/tests/test_website_sale_pricelist.py +++ b/addons/website_sale/tests/test_website_sale_pricelist.py @@ -5,6 +5,7 @@ try: except ImportError: from mock import patch from odoo.tests.common import HttpCase, TransactionCase +from odoo.tools import DotDict ''' /!\/!\ Calling `get_pricelist_available` after setting `property_product_pricelist` on @@ -154,13 +155,6 @@ def simulate_frontend_context(self, website_id=1): self.addCleanup(patcher.stop) -class DotDict(dict): - """dot.notation access to dictionary attributes""" - def __getattr__(*args): - val = dict.get(*args) - return DotDict(val) if type(val) is dict else val - - class TestWebsitePriceListAvailable(TransactionCase): # This is enough to avoid a mock (request.session/website do not exist during test) def get_pricelist_available(self, show_visible=False, website_id=1, country_code=None, website_sale_current_pl=None): diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py index 762c07e535c..7d465356e10 100644 --- a/odoo/tools/misc.py +++ b/odoo/tools/misc.py @@ -1242,3 +1242,14 @@ def wrap_module(module, attr_list): raise AttributeError(attrib) # module and attr_list are in the closure return WrappedModule() + + +class DotDict(dict): + """Helper for dot.notation access to dictionary attributes + E.g. + foo = DotDict({'bar': False}) + return foo.bar + """ + def __getattr__(self, attrib): + val = self.get(attrib) + return DotDict(val) if type(val) is dict else val