256 lines
12 KiB
Python
256 lines
12 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import logging
|
|
from collections import OrderedDict
|
|
|
|
from lxml import etree
|
|
|
|
from odoo.fields import Command
|
|
from odoo.tests import HttpCase, TransactionCase, loaded_demo_data, tagged
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
@tagged('-at_install', 'post_install')
|
|
class TestWebsiteSaleComparison(TransactionCase):
|
|
|
|
def test_01_website_sale_comparison_remove(self):
|
|
""" This tour makes sure the product page still works after the module
|
|
`website_sale_comparison` has been removed.
|
|
|
|
Technically it tests the removal of copied views by the base method
|
|
`_remove_copied_views`. The problematic view that has to be removed is
|
|
`product_attributes_body` because it has a reference to `add_to_compare`.
|
|
"""
|
|
Website0 = self.env['website'].with_context(website_id=None)
|
|
Website1 = self.env['website'].with_context(website_id=1)
|
|
|
|
# Create a generic inherited view, with a key not starting with
|
|
# `website_sale_comparison` otherwise the unlink will work just based on
|
|
# the key, but we want to test also for `MODULE_UNINSTALL_FLAG`.
|
|
product_attributes_body = Website0.viewref('website_sale_comparison.product_attributes_body')
|
|
test_view_key = 'my_test.my_key'
|
|
self.env['ir.ui.view'].with_context(website_id=None).create({
|
|
'name': 'test inherited view',
|
|
'key': test_view_key,
|
|
'inherit_id': product_attributes_body.id,
|
|
'arch': '<div/>',
|
|
})
|
|
|
|
# Retrieve the generic view
|
|
product = Website0.viewref('website_sale.product')
|
|
# Trigger COW to create specific views of the whole tree
|
|
product.with_context(website_id=1).write({'name': 'Trigger COW'})
|
|
|
|
# Verify initial state: the specific views exist
|
|
self.assertEqual(Website1.viewref('website_sale.product').website_id.id, 1)
|
|
self.assertEqual(Website1.viewref('website_sale_comparison.product_attributes_body').website_id.id, 1)
|
|
self.assertEqual(Website1.viewref(test_view_key).website_id.id, 1)
|
|
|
|
# Remove the module (use `module_uninstall` because it is enough to test
|
|
# what we want here, no need/can't use `button_immediate_uninstall`
|
|
# because it would commit the test transaction)
|
|
website_sale_comparison = self.env['ir.module.module'].search([('name', '=', 'website_sale_comparison')])
|
|
website_sale_comparison.module_uninstall()
|
|
|
|
# Check that the generic view is correctly removed
|
|
self.assertFalse(Website0.viewref('website_sale_comparison.product_attributes_body', raise_if_not_found=False))
|
|
# Check that the specific view is correctly removed
|
|
self.assertFalse(Website1.viewref('website_sale_comparison.product_attributes_body', raise_if_not_found=False))
|
|
|
|
# Check that the generic inherited view is correctly removed
|
|
self.assertFalse(Website0.viewref(test_view_key, raise_if_not_found=False))
|
|
# Check that the specific inherited view is correctly removed
|
|
self.assertFalse(Website1.viewref(test_view_key, raise_if_not_found=False))
|
|
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestWebsiteSaleComparisonUi(HttpCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
|
|
cls.attribute_varieties = cls.env['product.attribute'].create({
|
|
'name': 'Grape Varieties',
|
|
'sequence': 2,
|
|
'value_ids': [
|
|
Command.create({
|
|
'name': n,
|
|
'sequence': i,
|
|
}) for i, n in enumerate(['Cabernet Sauvignon', 'Merlot', 'Cabernet Franc', 'Petit Verdot'])
|
|
],
|
|
})
|
|
cls.attribute_vintage = cls.env['product.attribute'].create({
|
|
'name': 'Vintage',
|
|
'sequence': 1,
|
|
'value_ids': [
|
|
Command.create({
|
|
'name': n,
|
|
'sequence': i,
|
|
}) for i, n in enumerate(['2018', '2017', '2016', '2015'])
|
|
],
|
|
})
|
|
cls.values_varieties = cls.attribute_varieties.value_ids
|
|
cls.values_vintage = cls.attribute_vintage.value_ids
|
|
cls.template_margaux = cls.env['product.template'].create({
|
|
'name': "Château Margaux",
|
|
'website_published': True,
|
|
'list_price': 0,
|
|
'attribute_line_ids': [
|
|
Command.create({
|
|
'attribute_id': cls.attribute_vintage.id,
|
|
'value_ids': [Command.set(cls.values_vintage.ids)]
|
|
})
|
|
]
|
|
})
|
|
cls.attribute_line_vintage = cls.template_margaux.attribute_line_ids
|
|
cls.attribute_line_varieties = cls.env['product.template.attribute.line'].create([{
|
|
'product_tmpl_id': cls.template_margaux.id,
|
|
'attribute_id': cls.attribute_varieties.id,
|
|
'value_ids': [(6, 0, v.ids)],
|
|
} for v in cls.values_varieties])
|
|
cls.variants_margaux = cls.template_margaux._get_possible_variants_sorted()
|
|
|
|
for variant, price in zip(cls.variants_margaux, [487.32, 394.05, 532.44, 1047.84]):
|
|
variant.product_template_attribute_value_ids.filtered(lambda ptav: ptav.attribute_id == cls.attribute_vintage).price_extra = price
|
|
|
|
def test_01_admin_tour_product_comparison(self):
|
|
attribute = self.env['product.attribute'].create({
|
|
'name': 'Color',
|
|
'sequence': 10,
|
|
'display_type': 'color',
|
|
'value_ids': [
|
|
Command.create({
|
|
'name': 'Red',
|
|
}),
|
|
Command.create({
|
|
'name': 'Pink',
|
|
}),
|
|
Command.create({
|
|
'name': 'Blue'
|
|
})
|
|
]
|
|
})
|
|
self.env['product.template'].create([{
|
|
'name': 'Color T-Shirt',
|
|
'list_price': 20.0,
|
|
'website_sequence': 1,
|
|
'is_published': True,
|
|
'type': 'service',
|
|
'invoice_policy': 'delivery',
|
|
'attribute_line_ids': [
|
|
Command.create({
|
|
'attribute_id': attribute.id,
|
|
'value_ids': attribute.value_ids,
|
|
})
|
|
]
|
|
}, {
|
|
'name': 'Color Pants',
|
|
'list_price': 20.0,
|
|
'website_sequence': 1,
|
|
'is_published': True,
|
|
'type': 'service',
|
|
'invoice_policy': 'delivery',
|
|
'attribute_line_ids': [
|
|
Command.create({
|
|
'attribute_id': attribute.id,
|
|
'value_ids': attribute.value_ids,
|
|
})
|
|
]
|
|
}, {
|
|
'name': 'Color Shoes',
|
|
'list_price': 20.0,
|
|
'website_sequence': 1,
|
|
'is_published': True,
|
|
'type': 'service',
|
|
'invoice_policy': 'delivery',
|
|
'attribute_line_ids': [
|
|
Command.create({
|
|
'attribute_id': attribute.id,
|
|
'value_ids': attribute.value_ids,
|
|
})
|
|
]
|
|
}])
|
|
self.start_tour("/", 'product_comparison', login='admin')
|
|
|
|
def test_02_attribute_multiple_lines(self):
|
|
# Case product page with "Product attributes table" disabled (website_sale standard case)
|
|
self.env['website'].viewref('website_sale_comparison.product_attributes_body').active = False
|
|
res = self.url_open('/shop/%d' % self.template_margaux.id)
|
|
self.assertEqual(res.status_code, 200)
|
|
root = etree.fromstring(res.content, etree.HTMLParser())
|
|
|
|
tr_varieties_simple_att = root.xpath('//div[@id="product_attributes_simple"]//tr')[0]
|
|
text = etree.tostring(tr_varieties_simple_att, encoding='unicode', method='text')
|
|
self.assertEqual(text.replace(' ', '').replace('\n', ''), "GrapeVarieties:CabernetSauvignon,Merlot,CabernetFranc,PetitVerdot")
|
|
|
|
# Case product page with "Product attributes table" enabled
|
|
self.env['website'].viewref('website_sale_comparison.product_attributes_body').active = True
|
|
res = self.url_open('/shop/%d' % self.template_margaux.id)
|
|
self.assertEqual(res.status_code, 200)
|
|
root = etree.fromstring(res.content, etree.HTMLParser())
|
|
|
|
tr_vintage = root.xpath('//div[@id="product_specifications"]//tr')[0]
|
|
text_vintage = etree.tostring(tr_vintage, encoding='unicode', method='text')
|
|
self.assertEqual(text_vintage.replace(' ', '').replace('\n', ''), "Vintage2018,2017,2016,2015")
|
|
|
|
tr_varieties = root.xpath('//div[@id="product_specifications"]//tr')[1]
|
|
text_varieties = etree.tostring(tr_varieties, encoding='unicode', method='text')
|
|
self.assertEqual(text_varieties.replace(' ', '').replace('\n', ''), "GrapeVarietiesCabernetSauvignon,Merlot,CabernetFranc,PetitVerdot")
|
|
|
|
# Case compare page
|
|
res = self.url_open('/shop/compare?products=%s' % ','.join(str(id) for id in self.variants_margaux.ids))
|
|
self.assertEqual(res.status_code, 200)
|
|
root = etree.fromstring(res.content, etree.HTMLParser())
|
|
|
|
table = root.xpath('//table[@id="o_comparelist_table"]')[0]
|
|
|
|
products = table.xpath('//a[@class="o_product_comparison_table"]')
|
|
self.assertEqual(len(products), 4)
|
|
for product, name in zip(products, ['ChâteauMargaux(2018)', 'ChâteauMargaux(2017)', 'ChâteauMargaux(2016)', 'ChâteauMargaux(2015)']):
|
|
text = etree.tostring(product, encoding='unicode', method='text')
|
|
self.assertEqual(text.replace(' ', '').replace('\n', ''), name)
|
|
|
|
tr_vintage = table.xpath('tbody/tr')[0]
|
|
text_vintage = etree.tostring(tr_vintage, encoding='unicode', method='text')
|
|
self.assertEqual(text_vintage.replace(' ', '').replace('\n', ''), "Vintage2018,2017,2016,20152018,2017,2016,20152018,2017,2016,20152018,2017,2016,2015")
|
|
|
|
tr_varieties = table.xpath('tbody/tr')[1]
|
|
text_varieties = etree.tostring(tr_varieties, encoding='unicode', method='text')
|
|
self.assertEqual(text_varieties.replace(' ', '').replace('\n', ''), "GrapeVarieties" + 4 * "CabernetSauvignon,Merlot,CabernetFranc,PetitVerdot")
|
|
|
|
def test_03_category_order(self):
|
|
"""Test that categories are shown in the correct order when the
|
|
attributes are in a different order."""
|
|
category_vintage = self.env['product.attribute.category'].create({
|
|
'name': 'Vintage',
|
|
'sequence': 2,
|
|
})
|
|
category_varieties = self.env['product.attribute.category'].create({
|
|
'name': 'Varieties',
|
|
'sequence': 1,
|
|
})
|
|
self.attribute_vintage.category_id = category_vintage
|
|
self.attribute_varieties.category_id = category_varieties
|
|
|
|
prep_categories = self.template_margaux.valid_product_template_attribute_line_ids._prepare_categories_for_display()
|
|
self.assertEqual(prep_categories, OrderedDict([
|
|
(category_varieties, self.attribute_line_varieties),
|
|
(category_vintage, self.attribute_line_vintage),
|
|
]))
|
|
|
|
prep_categories = self.variants_margaux[0]._prepare_categories_for_display()
|
|
self.assertEqual(prep_categories, OrderedDict([
|
|
(category_varieties, OrderedDict([
|
|
(self.attribute_varieties, OrderedDict([
|
|
(self.template_margaux.product_variant_id, self.attribute_line_varieties.value_ids)
|
|
]))
|
|
])),
|
|
(category_vintage, OrderedDict([
|
|
(self.attribute_vintage, OrderedDict([
|
|
(self.template_margaux.product_variant_id, self.attribute_line_vintage.value_ids)
|
|
]))
|
|
])),
|
|
]))
|