@@ -752,6 +753,7 @@
+
Sample
diff --git a/addons/website/models/website_snippet_filter.py b/addons/website/models/website_snippet_filter.py
index a2a8c82e86c..447581d7996 100644
--- a/addons/website/models/website_snippet_filter.py
+++ b/addons/website/models/website_snippet_filter.py
@@ -8,6 +8,7 @@ from odoo.osv import expression
from odoo.tools import html_escape as escape
from lxml import etree as ET
import logging
+from random import randint
_logger = logging.getLogger(__name__)
@@ -49,17 +50,22 @@ class WebsiteSnippetFilter(models.Model):
if not field_name.strip():
raise ValidationError(_("Empty field name in %r") % (record.field_names))
- def render(self, template_key, limit, search_domain=[]):
+ def render(self, template_key, limit, search_domain=None, with_sample=False):
"""Renders the website dynamic snippet items"""
self.ensure_one()
assert '.dynamic_filter_template_' in template_key, _("You can only use template prefixed by dynamic_filter_template_ ")
+ if search_domain is None:
+ search_domain = []
if self.website_id and self.env['website'].get_current_website() != self.website_id:
return ''
records = self._prepare_values(limit, search_domain)
+ is_sample = with_sample and not records
+ if is_sample:
+ records = self._prepare_sample()
View = self.env['ir.ui.view'].sudo().with_context(inherit_branding=False)
- content = View._render_template(template_key, dict(records=records)).decode('utf-8')
+ content = View._render_template(template_key, dict(records=records, is_sample=is_sample)).decode('utf-8')
return [ET.tostring(el) for el in ET.fromstring('%s' % content).getchildren()]
def _prepare_values(self, limit=None, search_domain=None):
@@ -95,6 +101,100 @@ class WebsiteSnippetFilter(models.Model):
_logger.warning("The provided domain %s in 'ir.actions.server' generated a MissingError in '%s'", search_domain, self._name)
return []
+ def _get_field_name_and_type(self, model, field_name):
+ """
+ Separates the name and the widget type
+
+ @param model: Model to which the field belongs, without it type is deduced from field_name
+ @param field_name: Name of the field possibly followed by a colon and a forced field type
+
+ @return Tuple containing the field name and the field type
+ """
+ field_name, _, field_widget = field_name.partition(":")
+ field = model._fields.get(field_name) if model else None
+ if field:
+ field_type = field.type
+ elif 'image' in field_name:
+ field_type = 'image'
+ elif 'price' in field_name:
+ field_type = 'monetary'
+ else:
+ field_type = 'text'
+ return field_name, field_widget or field_type
+
+ def _prepare_sample(self, length=4):
+ """
+ Generates sample data and returns it the right format for render.
+
+ @param length: Number of sample records to generate
+
+ @return Array of objets with a value associated to each name in field_names
+ """
+ if not length:
+ return []
+ sample = []
+ model = self.env[self.filter_id.model_id] if self.filter_id else (
+ self.action_server_id.model_id if self.action_server_id else None)
+ sample_data = self._get_hardcoded_sample(model)
+ for index in range(0, length):
+ single_sample_data = sample_data[index % len(sample_data)].copy()
+ self._fill_sample(single_sample_data, model, index)
+ data = self._get_rendering_data_structure()
+ for field_name in self.field_names.split(","):
+ field_name, field_widget = self._get_field_name_and_type(model, field_name)
+ value = single_sample_data[field_name]
+ if field_widget == 'binary':
+ data['image_fields'][field_name] = self.escape_falsy_as_empty(value)
+ elif field_widget == 'image':
+ data['image_fields'][field_name] = value
+ elif field_widget == 'monetary':
+ FieldMonetary = self.env['ir.qweb.field.monetary']
+ website_currency = self._get_website_currency()
+ data['fields'][field_name] = FieldMonetary.value_to_html(
+ value,
+ {'display_currency': website_currency}
+ )
+ elif 'ir.qweb.field.%s' % field_widget in self.env:
+ data['fields'][field_name] = self.env['ir.qweb.field.%s' % field_widget].value_to_html(
+ value, {})
+ else:
+ data['fields'][field_name] = self.escape_falsy_as_empty(value)
+ data['fields']['call_to_action_url'] = ''
+ sample.append(data)
+ return sample
+
+ def _fill_sample(self, sample, model, index):
+ """
+ Fills the sample for the given model
+
+ @param sample: Data structure to fill with values for each name in field_names
+ @param model: Model to which the sample belongs
+ @param index: Index of the sample within the dataset
+ """
+ for field_name in self.field_names.split(","):
+ field_name, field_widget = self._get_field_name_and_type(model, field_name)
+ if field_name not in sample:
+ if field_widget == 'binary':
+ sample[field_name] = None
+ elif field_widget == 'image':
+ sample[field_name] = '/web/image'
+ elif field_widget == 'monetary':
+ sample[field_name] = randint(100, 10000) / 10.0
+ elif field_widget in ('integer', 'float'):
+ sample[field_name] = index
+ else:
+ sample[field_name] = _('Sample %s', index + 1)
+
+ def _get_hardcoded_sample(self, model):
+ """
+ Returns a hard-coded sample
+
+ @param model: Model of the currently rendered view
+
+ @return Sample data records with field values
+ """
+ return [{}]
+
@api.model
def _get_rendering_data_structure(self):
return {
diff --git a/addons/website/static/src/snippets/s_dynamic_snippet/000.js b/addons/website/static/src/snippets/s_dynamic_snippet/000.js
index d6a3e0ffca4..53ae9bf7dca 100644
--- a/addons/website/static/src/snippets/s_dynamic_snippet/000.js
+++ b/addons/website/static/src/snippets/s_dynamic_snippet/000.js
@@ -110,7 +110,8 @@ const DynamicSnippet = publicWidget.Widget.extend({
'filter_id': parseInt(this.$el.get(0).dataset.filterId),
'template_key': this.$el.get(0).dataset.templateKey,
'limit': parseInt(this.$el.get(0).dataset.numberOfRecords),
- 'search_domain': this._getSearchDomain()
+ 'search_domain': this._getSearchDomain(),
+ 'with_sample': this.editableMode,
},
})
.then(
diff --git a/addons/website_sale/models/website_snippet_filter.py b/addons/website_sale/models/website_snippet_filter.py
index 7b8206b1928..d528e175d75 100644
--- a/addons/website_sale/models/website_snippet_filter.py
+++ b/addons/website_sale/models/website_snippet_filter.py
@@ -10,3 +10,30 @@ class WebsiteSnippetFilter(models.Model):
def _get_website_currency(self):
pricelist = self.env['website'].get_current_website().get_current_pricelist()
return pricelist.currency_id
+
+ def _get_hardcoded_sample(self, model):
+ samples = super()._get_hardcoded_sample(model)
+ if model and model.model == 'product.product':
+ data = [{
+ 'image_512': '/product/static/img/product_chair.png',
+ 'display_name': _('Chair'),
+ 'description_sale': _('Sit comfortably'),
+ }, {
+ 'image_512': '/product/static/img/product_lamp.png',
+ 'display_name': _('Lamp'),
+ 'description_sale': _('Lightbulb sold separately'),
+ }, {
+ 'image_512': '/product/static/img/product_product_20-image.png',
+ 'display_name': _('Whiteboard'),
+ 'description_sale': _('With three feet'),
+ }, {
+ 'image_512': '/product/static/img/product_product_27-image.png',
+ 'display_name': _('Drawer'),
+ 'description_sale': _('On wheels'),
+ }]
+ merged = []
+ for index in range(0, max(len(samples), len(data))):
+ merged.append({**samples[index % len(samples)], **data[index % len(data)]})
+ # merge definitions
+ samples = merged
+ return samples