diff --git a/addons/website/models/website.py b/addons/website/models/website.py index df51c95e313..581ef97a380 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -8,7 +8,7 @@ import hashlib import requests import re -from lxml import html +from lxml import etree from werkzeug import urls from werkzeug.datastructures import OrderedMultiDict from werkzeug.exceptions import NotFound @@ -287,6 +287,9 @@ class Website(models.Model): endpoint = website_api_endpoint + route return iap_tools.iap_jsonrpc(endpoint, params=params) + def get_cta_data(self, website_purpose, website_type): + return {'cta_btn_text': False, 'cta_btn_href': '/contactus'} + @api.model def configurator_init(self): r = dict() @@ -348,10 +351,15 @@ class Website(models.Model): result = self.env['website'].new_page(name=feature_id.name, add_menu=True, template=feature_id.page_view_id.key) pages_views[feature_id.iap_page_code] = result['view_id'] - modules._button_immediate_function(lambda self: self.button_install()) + modules.button_immediate_install() + + # Force to refresh env after install of modules + self._cr.commit() + api.Environment.reset() + self.env = api.Environment(modules._cr, modules._uid, modules._context) return pages_views - def configure_page(page_code, snippet_list, pages_views): + def configure_page(page_code, snippet_list, pages_views, cta_data): if page_code == 'homepage': page_view_id = website.homepage_id.view_id else: @@ -362,8 +370,7 @@ class Website(models.Model): try: view_id = self.env['website'].with_context(website_id=website.id).viewref(snippet) if view_id: - rendered_snippet = pycompat.to_text(view_id._render()) - el = html.fragment_fromstring(rendered_snippet) + el = etree.fromstring(view_id._render(values=cta_data)) # Add the data-snippet attribute to identify the snippet # for compatibility code @@ -382,8 +389,7 @@ class Website(models.Model): shape_el = el.xpath("//*[hasclass('o_we_shape')]") if shape_el: shape_el[0].attrib['class'] += ' o_footer_extra_shape_mapping' - - rendered_snippet = pycompat.to_text(html.tostring(el)) + rendered_snippet = pycompat.to_text(etree.tostring(el)) rendered_snippets.append(rendered_snippet) except ValueError as e: logger.warning(e) @@ -433,6 +439,9 @@ class Website(models.Model): # modules pages_views = set_features(kwargs.get('selected_features')) + # We need to refresh the environment of website because set_features installed some new module + # and we need the overrides of these new menus e.g. for .get_cta_data() + website = self.env['website'].browse(website.id) # Load suggestion from iap for selected pages requested_pages = list(pages_views.keys()) @@ -443,10 +452,53 @@ class Website(models.Model): } custom_resources = self._website_api_rpc('/api/website/1/configurator/custom_resources/%s' % kwargs.get('industry_id'), params) + # Update CTA + cta_data = website.get_cta_data(kwargs.get('website_purpose'), kwargs.get('website_type')) + if cta_data['cta_btn_text']: + xpath_view = 'website.snippets' + parent_view = self.env['website'].with_context(website_id=website.id).viewref(xpath_view) + self.env['ir.ui.view'].create({ + 'name': parent_view.key + ' CTA', + 'key': parent_view.key + "_cta", + 'inherit_id': parent_view.id, + 'website_id': website.id, + 'type': 'qweb', + 'priority': 32, + 'arch_db': """ + + + %s + + + %s + + + """ % (cta_data['cta_btn_href'], cta_data['cta_btn_text']) + }) + header_ids = [ + 'website.template_header_default_oe_structure_header_default_1', + 'website.template_header_hamburger_oe_structure_header_hamburger_1', + 'website.template_header_slogan_oe_structure_header_slogan_2', + 'website.template_header_boxed_oe_structure_header_boxed_2', + 'website.template_header_image_oe_structure_header_image_2', + ] + for header_id in header_ids: + try: + view_id = self.env['website'].viewref(header_id) + if view_id: + el = etree.fromstring(view_id.arch_db) + btn_cta_el = el.xpath("//a[hasclass('btn_cta')]") + if btn_cta_el: + btn_cta_el[0].attrib['href'] = cta_data['cta_btn_href'] + btn_cta_el[0].text = cta_data['cta_btn_text'] + view_id.with_context(website_id=website.id).write({'arch_db': etree.tostring(el)}) + except ValueError as e: + logger.warning(e) + # Update pages pages = custom_resources.get('pages', {}) for page_code, snippet_list in pages.items(): - configure_page(page_code, snippet_list, pages_views) + configure_page(page_code, snippet_list, pages_views, cta_data) images = custom_resources.get('images', []) set_images(images) diff --git a/addons/website/models/website_configurator_feature.py b/addons/website/models/website_configurator_feature.py index 28a06798883..5baa70af470 100644 --- a/addons/website/models/website_configurator_feature.py +++ b/addons/website/models/website_configurator_feature.py @@ -16,7 +16,7 @@ class WebsiteConfiguratorFeature(models.Model): description = fields.Char(translate=True) icon = fields.Char() iap_page_code = fields.Char(help='Page code used to tell IAP website_service for which page a snippet list should be generated') - website_types_preselection = fields.Char(help='Comma-separated list of website type for which this feature should be pre-selected') + website_types_preselection = fields.Char(help='Comma-separated list of website type/purpose for which this feature should be pre-selected') type = fields.Selection([('page', "Page"), ('app', "App")], compute='_compute_type') page_view_id = fields.Many2one('ir.ui.view', ondelete='cascade') module_id = fields.Many2one('ir.module.module', ondelete='cascade') diff --git a/addons/website/static/src/components/configurator/configurator.js b/addons/website/static/src/components/configurator/configurator.js index 79bed367c81..02883528972 100644 --- a/addons/website/static/src/components/configurator/configurator.js +++ b/addons/website/static/src/components/configurator/configurator.js @@ -24,7 +24,8 @@ const WEBSITE_PURPOSES = { 1: {id: 1, label: _lt("get leads"), name: 'get_leads'}, 2: {id: 2, label: _lt("develop the brand"), name: 'develop_brand'}, 3: {id: 3, label: _lt("sell more"), name: 'sell_more'}, - 4: {id: 4, label: _lt("inform customers"), name: 'inform_customers'} + 4: {id: 4, label: _lt("inform customers"), name: 'inform_customers'}, + 5: {id: 5, label: _lt("schedule appointments"), name: 'schedule_appointments'} }; const PALETTE_NAMES = [ @@ -354,6 +355,10 @@ const actions = { state.selectedType = id; }, selectWebsitePurpose({state}, id) { + Object.values(state.features).filter((feature) => feature.module_state !== 'installed').forEach((feature) => { + // need to check id, since we set to undefined in mount() to avoid the auto next screen on back button + feature.selected |= id && feature.website_types_preselection.includes(WEBSITE_PURPOSES[id].name); + }); state.selectedPurpose = id; }, selectIndustry({state}, id) { @@ -475,6 +480,8 @@ async function applyConfigurator(self, themeName) { industry_id: self.state.selectedIndustry, selected_palette: selectedPalette, theme_name: themeName, + website_purpose: WEBSITE_PURPOSES[self.state.selectedPurpose].name, + website_type: WEBSITE_TYPES[self.state.selectedType].name, }; const resp = await rpc.query({ model: 'website', diff --git a/addons/website/views/snippets/s_banner.xml b/addons/website/views/snippets/s_banner.xml index a99666823c8..7cc6a07de67 100644 --- a/addons/website/views/snippets/s_banner.xml +++ b/addons/website/views/snippets/s_banner.xml @@ -9,7 +9,7 @@

Sell Online. Easily.

This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.

- Contact Us + Contact Us
diff --git a/addons/website/views/snippets/s_call_to_action.xml b/addons/website/views/snippets/s_call_to_action.xml index 5247606344b..4b610066860 100644 --- a/addons/website/views/snippets/s_call_to_action.xml +++ b/addons/website/views/snippets/s_call_to_action.xml @@ -11,7 +11,7 @@

- Contact us + Contact us

diff --git a/addons/website/views/snippets/s_cover.xml b/addons/website/views/snippets/s_cover.xml index caaa0c2a76c..0afcd95aef1 100644 --- a/addons/website/views/snippets/s_cover.xml +++ b/addons/website/views/snippets/s_cover.xml @@ -9,7 +9,7 @@

Catchy Headline

Write one or two paragraphs describing your product, services or a specific feature.
To be successful your content needs to be useful to your readers.

- Contact us + Contact us

diff --git a/addons/website/views/snippets/snippets.xml b/addons/website/views/snippets/snippets.xml index 7c2ebd05241..41767ef4edd 100644 --- a/addons/website/views/snippets/snippets.xml +++ b/addons/website/views/snippets/snippets.xml @@ -11,6 +11,8 @@ + + /contactus
Mega Menu
diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index aab81b13f8c..6053846dc1d 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -125,6 +125,11 @@ Header + + + /contactus + + Footer @@ -273,7 +278,7 @@ @@ -349,7 +354,7 @@ @@ -697,7 +702,7 @@ @@ -926,7 +931,7 @@ @@ -1043,7 +1048,7 @@ diff --git a/addons/website_event/models/website.py b/addons/website_event/models/website.py index bb34800aa26..dd12ffb3fcc 100644 --- a/addons/website_event/models/website.py +++ b/addons/website_event/models/website.py @@ -12,3 +12,10 @@ class Website(models.Model): suggested_controllers = super(Website, self).get_suggested_controllers() suggested_controllers.append((_('Events'), url_for('/event'), 'website_event')) return suggested_controllers + + def get_cta_data(self, website_purpose, website_type): + cta_data = super(Website, self).get_cta_data(website_purpose, website_type) + if website_purpose == 'sell_more' and website_type == 'event': + cta_btn_text = _('Next Events') + return {'cta_btn_text': cta_btn_text, 'cta_btn_href': '/event'} + return cta_data