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,
 | 
						|
            )
 |