218 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Python
		
	
	
| # Copyright 2015 Antiun Ingenieria S.L. - Antonio Espinosa
 | |
| # Copyright 2017 Jairo Llopis <jairo.llopis@tecnativa.com>
 | |
| # Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
 | |
| # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
 | |
| 
 | |
| import logging
 | |
| 
 | |
| from odoo import api, models, fields
 | |
| from odoo.tools import config
 | |
| 
 | |
| 
 | |
| MODULE = "website_multi_theme"
 | |
| LAYOUT_KEY = MODULE + ".auto_layout_website_%d"
 | |
| ASSETS_KEY = MODULE + ".auto_assets_website_%d"
 | |
| VIEW_KEY = MODULE + ".auto_view_%d_%d"
 | |
| _logger = logging.getLogger(__name__)
 | |
| 
 | |
| 
 | |
| class Website(models.Model):
 | |
|     _inherit = "website"
 | |
| 
 | |
|     multi_theme_id = fields.Many2one(
 | |
|         string="Multiwebsite theme",
 | |
|         comodel_name='website.theme',
 | |
|         domain=[("has_assets", "=", True)],
 | |
|         help="Multiwebsite-compatible theme for this website",
 | |
|         default=lambda self: self.env.ref('website_multi_theme.theme_default',
 | |
|                                           raise_if_not_found=False)
 | |
|     )
 | |
|     multi_theme_view_ids = fields.One2many(
 | |
|         comodel_name="ir.ui.view",
 | |
|         inverse_name="website_id",
 | |
|         domain=[("origin_view_id", "!=", False),
 | |
|                 "|", ("active", "=", True), ("active", "=", False)],
 | |
|         string="Multiwebsite views",
 | |
|         help="Views generated by the multiwebsite theme just for this website",
 | |
|     )
 | |
| 
 | |
|     @api.model
 | |
|     def create(self, vals):
 | |
|         result = super(Website, self).create(vals)
 | |
|         if "multi_theme_id" in vals:
 | |
|             result._multi_theme_activate()
 | |
|         return result
 | |
| 
 | |
|     def write(self, vals):
 | |
|         result = super(Website, self).write(vals)
 | |
|         if "multi_theme_id" in vals:
 | |
|             self._multi_theme_activate()
 | |
|         return result
 | |
| 
 | |
|     @api.multi
 | |
|     def _find_duplicated_view_for_website(self, origin_view):
 | |
|         self.ensure_one()
 | |
|         xmlid = VIEW_KEY % (self.id, origin_view.id)
 | |
|         return self.env.ref(xmlid, raise_if_not_found=False)
 | |
| 
 | |
|     @api.multi
 | |
|     def _duplicate_view_for_website(self, pattern, xmlid, override_key):
 | |
|         """Duplicate a view pattern and enable it only for current website.
 | |
| 
 | |
|         :param ir.ui.view pattern:
 | |
|             Original view that will be copied for current website.
 | |
| 
 | |
|         :param str xmlid:
 | |
|             The XML ID of the generated record.
 | |
| 
 | |
|         :param bool override_key:
 | |
|             Indicates wether the view key should be overriden. If ``True``,
 | |
|             it will become the same as :param:`xmlid`. Otherwise, the key will
 | |
|             be copied from :param:`pattern` as it would happen normally.
 | |
| 
 | |
|         :return ir.ui.view:
 | |
|             The duplicated view.
 | |
|         """
 | |
|         self.ensure_one()
 | |
|         # Return the pre-existing copy if any
 | |
|         try:
 | |
|             result = self.env.ref(xmlid)
 | |
|         except ValueError:
 | |
|             pass
 | |
|         else:
 | |
|             # If we develop and want xml reloading, update view arch always
 | |
|             if "xml" in config.get("dev_mode"):
 | |
|                 result.arch = pattern.arch
 | |
|             return result
 | |
|         # Copy patterns only for current website
 | |
|         key = xmlid if override_key else pattern.key
 | |
|         result = pattern.copy({
 | |
|             "active": pattern.was_active,
 | |
|             "arch_fs": False,
 | |
|             "key": key,
 | |
|             "name": '%s (Website #%s)' % (pattern.name, self.id),
 | |
|             "website_id": self.id,
 | |
|             "origin_view_id": pattern.id,
 | |
|         })
 | |
|         # Assign external IDs to new views
 | |
|         module, name = xmlid.split(".")
 | |
|         self.env["ir.model.data"].with_context(
 | |
|             duplicate_view_for_website=True
 | |
|         ).create({
 | |
|             "model": result._name,
 | |
|             "module": module,
 | |
|             "name": name,
 | |
|             "noupdate": True,
 | |
|             "res_id": result.id,
 | |
|         })
 | |
|         _logger.debug(
 | |
|             "Duplicated %s as %s with xmlid %s for %s with arch:\n%s",
 | |
|             pattern.display_name,
 | |
|             result.display_name,
 | |
|             xmlid,
 | |
|             self.display_name,
 | |
|             result.arch,
 | |
|         )
 | |
|         return result
 | |
| 
 | |
|     def _multi_theme_activate(self):
 | |
|         """Activate current multi theme for current websites."""
 | |
|         main_assets_frontend = (
 | |
|             self.env.ref("web.assets_frontend") |
 | |
|             self.env.ref("website.assets_frontend"))
 | |
|         main_layout = self.env.ref("website.layout")
 | |
|         main_views = main_assets_frontend | main_layout
 | |
|         # Patterns that will be duplicated to enable multi themes
 | |
|         assets_pattern = self.env.ref("website_multi_theme.assets_pattern")
 | |
|         layout_pattern = self.env.ref("website_multi_theme.layout_pattern")
 | |
|         for website in self:
 | |
|             if not website.multi_theme_id:
 | |
|                 default_theme = self.env.ref(
 | |
|                     'website_multi_theme.theme_default',
 | |
|                     raise_if_not_found=False,
 | |
|                 )
 | |
|                 if not default_theme:
 | |
|                     _logger.info(
 | |
|                         "Deleting multi website theme views for %s: %s",
 | |
|                         website.display_name,
 | |
|                         website.multi_theme_view_ids,
 | |
|                     )
 | |
|                     website.multi_theme_view_ids.unlink()
 | |
|                     continue
 | |
|                 else:
 | |
|                     website.multi_theme_id = default_theme
 | |
| 
 | |
|             # Duplicate multi theme patterns for this website
 | |
|             custom_assets = website._duplicate_view_for_website(
 | |
|                 assets_pattern,
 | |
|                 ASSETS_KEY % website.id,
 | |
|                 True
 | |
|             )
 | |
|             custom_layout = website._duplicate_view_for_website(
 | |
|                 layout_pattern,
 | |
|                 LAYOUT_KEY % website.id,
 | |
|                 True
 | |
|             )
 | |
|             # Update custom base views arch to latest pattern
 | |
|             custom_assets.arch = assets_pattern.arch
 | |
|             custom_layout.arch = layout_pattern.arch.format(
 | |
|                 theme_view=custom_assets.key,
 | |
|             )
 | |
|             # These custom base views must be active
 | |
|             custom_views = custom_assets | custom_layout
 | |
|             custom_views.update({
 | |
|                 "active": True,
 | |
|             })
 | |
|             # Duplicate all theme's views for this website
 | |
|             for origin_view in website\
 | |
|                     .multi_theme_id\
 | |
|                     .get_assets()\
 | |
|                     .mapped("view_id"):
 | |
|                 copied_view = website._duplicate_view_for_website(
 | |
|                     origin_view,
 | |
|                     VIEW_KEY % (website.id, origin_view.id),
 | |
|                     False
 | |
|                 )
 | |
|                 # Applied views must inherit from custom assets or layout
 | |
|                 new_parent = None
 | |
|                 if copied_view.inherit_id & main_views:
 | |
|                     if copied_view.inherit_id & main_assets_frontend:
 | |
|                         new_parent = custom_assets
 | |
|                     elif copied_view.inherit_id & main_layout:
 | |
|                         new_parent = custom_layout
 | |
|                 else:
 | |
|                     parent_view = copied_view.inherit_id
 | |
| 
 | |
|                     # check if parent was copied, so we need inherit that
 | |
|                     # instead of original parent, which is deactivated and not
 | |
|                     # used
 | |
|                     copied_parent = website._find_duplicated_view_for_website(
 | |
|                         parent_view
 | |
|                     )
 | |
| 
 | |
|                     if copied_parent:
 | |
|                         new_parent = copied_parent
 | |
| 
 | |
|                 if new_parent:
 | |
|                     copied_view._replace_parent(new_parent)
 | |
| 
 | |
|                 custom_views |= copied_view
 | |
|             # Delete any custom view that should exist no more
 | |
|             views_to_remove = website.multi_theme_view_ids - custom_views
 | |
|             # Removed views could be a copied parent for others
 | |
|             # So, replace to original parent first
 | |
|             views_to_replace_parent = \
 | |
|                 self.env['ir.ui.view']\
 | |
|                     .with_context(active_test=False)\
 | |
|                     .search([
 | |
|                         ('inherit_id', 'in', views_to_remove.ids)
 | |
|                     ])
 | |
|             for view in views_to_replace_parent:
 | |
|                 view._replace_parent(view.inherit_id.origin_view_id)
 | |
|             views_to_remove.unlink()
 | |
|             _logger.info(
 | |
|                 "Updated multi website theme views for %s: %s",
 | |
|                 website.display_name,
 | |
|                 website.multi_theme_view_ids,
 | |
|             )
 |