[FIX] website: set inherit_id on child COW for view validation
Before this commit: 1. If a view A is being inherited by a view B and C and the view C is doing an xpath on B (but inherit A), then copying the tree to make it specific would crash. Indeed, when copying C, the view inheritance check (while doing the xml check) would break since C would be tested against the generic tree and not the new specific tree. 2. If a generic view being written with a website_id in the context had already a specific child, we would copy both its specific child and generic child for the same key instead of simply copying the specific one. This happens if we triggered previously a COW on a child view, then only that view had been made specific (and is still in the generic tree). Then, when cloning the parent, we need to copy and make specific all the hierarchy but ignore the generic elements if they already have a specific one. Now: 1. Fixed with adding the inherit_id on the copy vals 2. Fixed with filtering children_ids with filter_duplicate() before cloning the children tree opw-1908308 Closes #27914 closes odoo/odoo#28405
This commit is contained in:
@@ -51,11 +51,14 @@ class View(models.Model):
|
||||
], limit=1)
|
||||
if not website_specific_view:
|
||||
# Set key to avoid copy() to generate an unique key as we want the specific view to have the same key
|
||||
website_specific_view = view.copy({'website_id': current_website_id, 'key': view.key})
|
||||
copy_vals = {'website_id': current_website_id, 'key': view.key}
|
||||
if vals.get('inherit_id'):
|
||||
copy_vals['inherit_id'] = vals['inherit_id']
|
||||
website_specific_view = view.copy(copy_vals)
|
||||
view._create_website_specific_pages_for_view(website_specific_view,
|
||||
view.env['website'].browse(current_website_id))
|
||||
|
||||
for inherit_child in view.inherit_children_ids:
|
||||
for inherit_child in view.inherit_children_ids.filter_duplicate():
|
||||
# COW won't be triggered if there is already a website_id on the view, we should copy the view ourself
|
||||
if inherit_child.website_id.id == current_website_id:
|
||||
inherit_child.copy({'inherit_id': website_specific_view.id, 'key': inherit_child.key})
|
||||
|
||||
@@ -520,3 +520,43 @@ class TestCowViewSaving(common.TransactionCase):
|
||||
base_arch_w1 = self.base_view.with_context(website_id=1).read_combined(['arch'])['arch']
|
||||
self.assertEqual('Hello World' in base_arch, True)
|
||||
self.assertEqual(base_arch, base_arch_w1, "Reading a top level view with or without a website_id in the context should render that exact view..") # ..even if there is a specific view for that one, as read_combined is supposed to render specific inherited view over generic but not specific top level instead of generic top level
|
||||
|
||||
def test_cow_cross_inherit(self):
|
||||
View = self.env['ir.ui.view']
|
||||
total_views = View.search_count([])
|
||||
|
||||
main_view = View.create({
|
||||
'name': 'Main View',
|
||||
'type': 'qweb',
|
||||
'arch': '<body>GENERIC<div>A</div></body>',
|
||||
'key': 'website.main_view',
|
||||
}).with_context(load_all_views=True)
|
||||
|
||||
View.create({
|
||||
'name': 'Child View',
|
||||
'mode': 'extension',
|
||||
'inherit_id': main_view.id,
|
||||
'arch': '<xpath expr="//div" position="replace"><div>VIEW<p>B</p></div></xpath>',
|
||||
'key': 'website.child_view',
|
||||
})
|
||||
|
||||
child_view_2 = View.with_context(load_all_views=True).create({
|
||||
'name': 'Child View 2',
|
||||
'mode': 'extension',
|
||||
'inherit_id': main_view.id,
|
||||
'arch': '<xpath expr="//p" position="replace"><span>C</span></xpath>',
|
||||
'key': 'website.child_view_2',
|
||||
})
|
||||
|
||||
# These line doing `write()` are the real tests, it should not be changed and should not crash on xpath.
|
||||
child_view_2.with_context(website_id=1).write({'arch': '<xpath expr="//p" position="replace"><span>D</span></xpath>'})
|
||||
self.assertEqual(total_views + 3 + 1, View.search_count([]), "It should have created the 3 initial generic views and created a child_view_2 specific view")
|
||||
main_view.with_context(website_id=1).write({'arch': '<body>SPECIFIC<div>Z</div></body>'})
|
||||
self.assertEqual(total_views + 3 + 3, View.search_count([]), "It should have duplicated the Main View tree as a specific tree and then removed the specific view from the generic tree as no more needed")
|
||||
|
||||
generic_view = View.with_context(website_id=None).get_view_id('website.main_view')
|
||||
specific_view = View.with_context(website_id=1).get_view_id('website.main_view')
|
||||
generic_view_arch = View.browse(generic_view).with_context(load_all_views=True).read_combined(['arch'])['arch']
|
||||
specific_view_arch = View.browse(specific_view).with_context(load_all_views=True, website_id=1).read_combined(['arch'])['arch']
|
||||
self.assertEqual(generic_view_arch == '<body>GENERIC<div>VIEW<span>C</span></div></body>', True)
|
||||
self.assertEqual(specific_view_arch == '<body>SPECIFIC<div>VIEW<span>D</span></div></body>', True, "Writing on top level view hierarchy with a website in context should write on the view and clone it's inherited views")
|
||||
|
||||
Reference in New Issue
Block a user