[ADD] website functionalities like...
- Page layout (Pre-header, Post-footer, etc...) - products page layout - product quick view - producta share option - product ribbon - product discription - product limit per page
This commit is contained in:
parent
8f01116341
commit
78fdb9318a
@ -22,7 +22,7 @@
|
||||
<t t-set="head" t-value="head_website + (head or '')"/>
|
||||
|
||||
<div id="wrapwrap" t-att-class="pageName or ''">
|
||||
<header>
|
||||
<header class="oe_structure">
|
||||
<div class="navbar navbar-default navbar-static-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
@ -52,7 +52,7 @@
|
||||
<main>
|
||||
<t t-raw="0"/>
|
||||
</main>
|
||||
<footer >
|
||||
<footer class="oe_structure">
|
||||
<div id="footer">
|
||||
</div>
|
||||
</footer>
|
||||
|
@ -80,6 +80,15 @@ class Website(Home):
|
||||
|
||||
raise request.not_found()
|
||||
|
||||
@http.route(['/website/menu/render'], type='json', auth="user", website=True)
|
||||
def menu_render(self, **kwargs):
|
||||
menu = request.env['website.menu'].browse(
|
||||
int(kwargs['menu_id']))
|
||||
value = {
|
||||
'menu': menu,
|
||||
}
|
||||
return request.env['ir.ui.view'].render_template(kwargs['template'], value)
|
||||
|
||||
#------------------------------------------------------
|
||||
# Login - overwrite of the web login so that regular users are redirected to the backend
|
||||
# while portal users are redirected to the frontend by default
|
||||
|
@ -17,7 +17,8 @@ from flectra.addons.portal.controllers.portal import pager
|
||||
from flectra.tools import pycompat
|
||||
from flectra.http import request
|
||||
from flectra.osv.expression import FALSE_DOMAIN
|
||||
from flectra.tools.translate import _
|
||||
|
||||
from flectra.tools.translate import _, html_translate
|
||||
from flectra.exceptions import Warning
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -670,6 +671,11 @@ class Website(models.Model):
|
||||
return self.env.ref('website.backend_dashboard').read()[0]
|
||||
return self.env.ref('website.action_website').read()[0]
|
||||
|
||||
@api.multi
|
||||
def get_website_menus(self, website_id):
|
||||
menus = request.env['website.menu'].search([('parent_id', '=', False), ('website_id', '=', website_id)])
|
||||
if menus:
|
||||
return menus
|
||||
|
||||
class SeoMetadata(models.AbstractModel):
|
||||
|
||||
@ -902,6 +908,7 @@ class Menu(models.Model):
|
||||
parent_left = fields.Integer('Parent Left', index=True)
|
||||
parent_right = fields.Integer('Parent Rigth', index=True)
|
||||
is_visible = fields.Boolean(compute='_compute_visible', string='Is Visible')
|
||||
menu_view = fields.Many2one('ir.ui.view', domain=[('type', '=', 'qweb')], string='Menu View')
|
||||
|
||||
@api.one
|
||||
def _compute_visible(self):
|
||||
|
@ -5,6 +5,7 @@ var core = require('web.core');
|
||||
var Dialog = require('web.Dialog');
|
||||
var widgets = require('web_editor.widget');
|
||||
var options = require('web_editor.snippets.options');
|
||||
var ajax = require('web.ajax');
|
||||
|
||||
var _t = core._t;
|
||||
var qweb = core.qweb;
|
||||
@ -935,4 +936,22 @@ options.registry.gallery_img = options.Class.extend({
|
||||
});
|
||||
},
|
||||
});
|
||||
options.registry.js_menu = options.Class.extend({
|
||||
selected_menu: function (type,value){
|
||||
if(type != true)
|
||||
return
|
||||
var menu = eval(value);
|
||||
var section=this.$target.find('.menu_view');
|
||||
section.empty();
|
||||
console.info(section)
|
||||
ajax.jsonRpc('/website/menu/render', 'call', {'template': menu[1], 'menu_id':menu[0]}
|
||||
).then(function (result) {
|
||||
$(result).appendTo(section);
|
||||
}).fail(function () {
|
||||
self.$('.o_website_links_code_error').show();
|
||||
self.$('.o_website_links_code_error').html(
|
||||
"<div>ServerError</div><p>We are not able to render template.</p>");
|
||||
}) ;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -14,6 +14,16 @@
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<template id="s_menu" name="Menu Snippets">
|
||||
<section class="s_menu">
|
||||
<div class="container">
|
||||
<div class="row menu_view">
|
||||
<h2 style="color: rgb(193, 191, 177);text-align: center;">Select Top Menu From Option</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<template id="s_banner" name="Slider">
|
||||
<div id="myCarousel" class="carousel slide s_banner" data-interval="10000" style="height: 400px;">
|
||||
<!-- Indicators -->
|
||||
@ -683,6 +693,7 @@
|
||||
<div class="o_panel_body">
|
||||
<t t-snippet="website.s_title" t-thumbnail="/website/static/src/img/blocks/block_title.png"/>
|
||||
<t t-snippet="website.s_cover" t-thumbnail="/website/static/src/img/blocks/block_banner.png"/>
|
||||
<t t-snippet="website.s_menu" t-thumbnail="/website/static/src/img/blocks/block_menu.png"/>
|
||||
<t t-snippet="website.s_text_image" t-thumbnail="/website/static/src/img/blocks/block_text_image.png"/>
|
||||
<t t-snippet="website.s_image_text" t-thumbnail="/website/static/src/img/blocks/block_image_text.png"/>
|
||||
<t t-snippet="website.s_big_message" t-thumbnail="/website/static/src/img/blocks/block_jumbotron.png"/>
|
||||
@ -752,6 +763,21 @@
|
||||
<template id="snippet_options">
|
||||
<t t-call="web_editor.snippet_options"/>
|
||||
|
||||
<div data-js='js_menu' data-selector=".s_menu">
|
||||
<t t-set="top_menu"
|
||||
t-value="website.get_website_menus(website.id) if website else None" />
|
||||
<li class="dropdown-submenu">
|
||||
<a tabindex="-2" href="#"><i class="fa fa-magic"/>Select Top Menu</a>
|
||||
<ul class="dropdown-menu">
|
||||
<t t-foreach="top_menu" t-as="menu">
|
||||
<li t-att-data-selected_menu="[menu.id,menu.menu_view.key]"
|
||||
t-att-data-view="menu.menu_view.key"><a
|
||||
href="#"><span t-esc="menu.name"/></a></li>
|
||||
</t>
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<div data-js='gallery' data-selector=".o_gallery">
|
||||
<li data-add-images="true" data-no-preview="true"><a href="#"><i class="fa fa-plus-circle"/>Add images</a></li>
|
||||
<li data-remove-all-images="true" data-no-preview="true"><a href="#"><i class="fa fa-trash"/>Remove all images</a></li>
|
||||
|
@ -114,6 +114,16 @@
|
||||
</t>
|
||||
<t t-set="x_icon" t-value="'/web/image/website/%s/favicon/' % website.id"/>
|
||||
</xpath>
|
||||
<xpath expr="//header" position="before">
|
||||
<pre-header>
|
||||
<div id="pre-header" class="oe_structure oe_empty"/>
|
||||
</pre-header>
|
||||
</xpath>
|
||||
<xpath expr="//footer" position="after">
|
||||
<post-footer>
|
||||
<div id="post-footer" class="oe_structure oe_empty"/>
|
||||
</post-footer>
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-set='head_website']" position="replace">
|
||||
<t t-set="head_website">
|
||||
<meta t-if="main_object and 'website_indexed' in main_object
|
||||
@ -204,6 +214,39 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="menu_snippets" name="Menu View">
|
||||
<nav>
|
||||
<div class="container">
|
||||
<div class="navbar-header"/>
|
||||
<ul id="nav_menu" class="nav navbar-nav navbar-right">
|
||||
<t t-foreach="menu.child_id" t-as="submenu">
|
||||
<t t-call="website.recursive_menu_snippets"/>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<template id="recursive_menu_snippets" name="Recursive Menu">
|
||||
<li t-if="not submenu.child_id">
|
||||
<a t-att-href="submenu.url" t-ignore="true"
|
||||
t-att-target="submenu.new_window or '_blank'">
|
||||
<span t-esc="submenu.name"/>
|
||||
</a>
|
||||
</li>
|
||||
<li t-if="submenu.child_id" >
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<span t-esc="submenu.name"/>
|
||||
<span class="caret" t-ignore="true"/>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<t t-foreach="submenu.child_id" t-as="submenu">
|
||||
<t t-call="website.submenus"/>
|
||||
</t>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<template id="layout_footer_copyright" inherit_id="website.layout" name="Footer Copyright">
|
||||
<xpath expr="//footer" position="inside">
|
||||
<div class="container mt16 mb8">
|
||||
|
@ -261,5 +261,57 @@
|
||||
action="website.ir_actions_server_website_dashboard"
|
||||
parent="website.menu_website_configuration"/>
|
||||
|
||||
<record id="website_menu_form" model="ir.ui.view">
|
||||
<field name="name">website.menu.form</field>
|
||||
<field name="model">website.menu</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Website menu">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="website_id"
|
||||
options="{'no_create': True}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="url"/>
|
||||
<field name="new_window"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="menu_view"
|
||||
attrs="{'invisible':[('parent_id', '!=', False)]}"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="website.action_website_menu" model="ir.actions.act_window">
|
||||
<field name="name">Website Menu</field>
|
||||
<field name="res_model">website.menu</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="context">{'search_default_my_websites':1}</field>
|
||||
</record>
|
||||
|
||||
<record id="website.menu_tree" model="ir.ui.view">
|
||||
<field name="name">website.menu.tree</field>
|
||||
<field name="model">website.menu</field>
|
||||
<field name="field_parent">child_id</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Website menu">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="website_id" options="{'no_create': True}"/>
|
||||
<field name="name"/>
|
||||
<field name="url"/>
|
||||
<field name="new_window"/>
|
||||
<field name="parent_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_website_menu"
|
||||
name="Website Menu"
|
||||
sequence="1"
|
||||
action="website.action_website_menu"
|
||||
parent="website.menu_website_configuration"/>
|
||||
|
||||
</data>
|
||||
</flectra>
|
||||
|
@ -67,10 +67,6 @@ class TableCompute(object):
|
||||
for y2 in range(y):
|
||||
for x2 in range(x):
|
||||
self.table[(pos // PPR) + y2][(pos % PPR) + x2] = False
|
||||
self.table[pos // PPR][pos % PPR] = {
|
||||
'product': p, 'x': x, 'y': y,
|
||||
'class': " ".join(x.html_class for x in p.website_style_ids if x.html_class)
|
||||
}
|
||||
if index <= ppg:
|
||||
maxy = max(maxy, y + (pos // PPR))
|
||||
index += 1
|
||||
@ -86,6 +82,15 @@ class TableCompute(object):
|
||||
return rows
|
||||
|
||||
|
||||
class WebsiteProductLimit(http.Controller):
|
||||
|
||||
@http.route(['/shop/product_limit'], type='json', auth="public")
|
||||
def change_limit(self, value):
|
||||
global PPG
|
||||
PPG = int(value)
|
||||
return True
|
||||
|
||||
|
||||
class WebsiteSaleForm(WebsiteForm):
|
||||
|
||||
@http.route('/website_form/shop.sale.order', type='http', auth="public", methods=['POST'], website=True)
|
||||
@ -159,7 +164,7 @@ class WebsiteSale(http.Controller):
|
||||
# id is added to be sure that order is a unique sort key
|
||||
return 'website_published desc,%s , id desc' % post.get('order', 'website_sequence desc')
|
||||
|
||||
def _get_search_domain(self, search, category, attrib_values):
|
||||
def _get_search_domain(self, search, category, attrib_values, tag_values, brand_values):
|
||||
domain = request.website.sale_product_domain()
|
||||
if search:
|
||||
for srch in search.split(" "):
|
||||
@ -188,6 +193,12 @@ class WebsiteSale(http.Controller):
|
||||
if not request.env.user.has_group('website.group_website_publisher'):
|
||||
domain += [('website_ids', 'in', request.website.id)]
|
||||
|
||||
if tag_values:
|
||||
domain += [('tag_ids', 'in', tag_values)]
|
||||
|
||||
if brand_values:
|
||||
domain += [('brand_id', 'in', brand_values)]
|
||||
|
||||
return domain
|
||||
|
||||
@http.route([
|
||||
@ -211,7 +222,17 @@ class WebsiteSale(http.Controller):
|
||||
attributes_ids = {v[0] for v in attrib_values}
|
||||
attrib_set = {v[1] for v in attrib_values}
|
||||
|
||||
domain = self._get_search_domain(search, category, attrib_values)
|
||||
# For Tags
|
||||
tag_list = request.httprequest.args.getlist('tags')
|
||||
tag_values = [list(map(str, v)) for v in tag_list if v]
|
||||
tag_set = set([int(v[0]) for v in tag_values])
|
||||
|
||||
# For Brands
|
||||
brand_list = request.httprequest.args.getlist('brands')
|
||||
brand_values = [list(map(str, v)) for v in brand_list if v]
|
||||
brand_set = set([int(v[0]) for v in brand_values])
|
||||
|
||||
domain = self._get_search_domain(search, category, attrib_values, list(tag_set), list(brand_set))
|
||||
|
||||
keep = QueryURL('/shop', category=category and int(category), search=search, attrib=attrib_list, order=post.get('order'))
|
||||
|
||||
@ -249,12 +270,26 @@ class WebsiteSale(http.Controller):
|
||||
products = Product.search(domain, limit=ppg, offset=pager['offset'], order=self._get_search_order(post))
|
||||
|
||||
ProductAttribute = request.env['product.attribute']
|
||||
ProductBrand = request.env['product.brand']
|
||||
ProductTag = request.env['product.tags']
|
||||
if products:
|
||||
# get all products without limit
|
||||
selected_products = Product.search(domain, limit=False)
|
||||
attributes = ProductAttribute.search([('attribute_line_ids.product_tmpl_id', 'in', selected_products.ids)])
|
||||
attributes = ProductAttribute.search([('attribute_line_ids.product_tmpl_id', 'in', products.ids)])
|
||||
prod_brands = []
|
||||
prod_tags = []
|
||||
for product in products:
|
||||
if product.brand_id:
|
||||
prod_brands.append(product.brand_id.id)
|
||||
if product.tag_ids:
|
||||
for tag_id in product.tag_ids.ids:
|
||||
prod_tags.append(tag_id)
|
||||
brands = ProductBrand.browse(list(set(prod_brands)))
|
||||
tags = ProductTag.browse(list(set(prod_tags)))
|
||||
else:
|
||||
attributes = ProductAttribute.browse(attributes_ids)
|
||||
brands = ProductBrand.browse(brand_set)
|
||||
tags = ProductTag.browse(tag_set)
|
||||
|
||||
limits = request.env['product.view.limit'].search([])
|
||||
|
||||
values = {
|
||||
'search': search,
|
||||
@ -264,6 +299,8 @@ class WebsiteSale(http.Controller):
|
||||
'pager': pager,
|
||||
'pricelist': pricelist,
|
||||
'products': products,
|
||||
'tag_set': tag_set,
|
||||
'brand_set': brand_set,
|
||||
'search_count': product_count, # common for all searchbox
|
||||
'bins': TableCompute().process(products, ppg),
|
||||
'rows': PPR,
|
||||
@ -271,7 +308,11 @@ class WebsiteSale(http.Controller):
|
||||
'attributes': attributes,
|
||||
'compute_currency': compute_currency,
|
||||
'keep': keep,
|
||||
'limits': limits,
|
||||
'parent_category_ids': parent_category_ids,
|
||||
'get_attribute_value_ids': self.get_attribute_value_ids,
|
||||
'tags': tags,
|
||||
'brands': brands,
|
||||
}
|
||||
if category:
|
||||
values['main_object'] = category
|
||||
@ -305,6 +346,7 @@ class WebsiteSale(http.Controller):
|
||||
product_context['pricelist'] = pricelist.id
|
||||
product = product.with_context(product_context)
|
||||
|
||||
|
||||
values = {
|
||||
'search': search,
|
||||
'category': category,
|
||||
@ -976,28 +1018,6 @@ class WebsiteSale(http.Controller):
|
||||
})
|
||||
return "/shop/product/%s?enable_editor=1" % slug(product.product_tmpl_id)
|
||||
|
||||
@http.route(['/shop/change_styles'], type='json', auth="public")
|
||||
def change_styles(self, id, style_id):
|
||||
product = request.env['product.template'].browse(id)
|
||||
|
||||
remove = []
|
||||
active = False
|
||||
style_id = int(style_id)
|
||||
for style in product.website_style_ids:
|
||||
if style.id == style_id:
|
||||
remove.append(style.id)
|
||||
active = True
|
||||
break
|
||||
|
||||
style = request.env['product.style'].browse(style_id)
|
||||
|
||||
if remove:
|
||||
product.write({'website_style_ids': [(3, rid) for rid in remove]})
|
||||
if not active:
|
||||
product.write({'website_style_ids': [(4, style.id)]})
|
||||
|
||||
return not active
|
||||
|
||||
@http.route(['/shop/change_sequence'], type='json', auth="public")
|
||||
def change_sequence(self, id, sequence):
|
||||
product_tmpl = request.env['product.template'].browse(id)
|
||||
|
@ -18,15 +18,6 @@
|
||||
<field name="state">open</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale.image_promo" model="product.style">
|
||||
<field name="name">Sale Ribbon</field>
|
||||
<field name="html_class">oe_ribbon_promo</field>
|
||||
</record>
|
||||
<record id="website_sale.image_full" model="product.style">
|
||||
<field name="name">Image Full</field>
|
||||
<field name="html_class">oe_image_full</field>
|
||||
</record>
|
||||
|
||||
<record model="crm.team" id="sales_team.salesteam_website_sales">
|
||||
<field name="active" eval="True"/>
|
||||
<field name="dashboard_graph_model">sale.report</field>
|
||||
@ -64,4 +55,15 @@
|
||||
]"/>
|
||||
</function>
|
||||
</data>
|
||||
<data noupdate="0">
|
||||
<record id="product_limit_20" model="product.view.limit">
|
||||
<field name="name">20</field>
|
||||
</record>
|
||||
<record id="product_limit_40" model="product.view.limit">
|
||||
<field name="name">40</field>
|
||||
</record>
|
||||
<record id="product_limit_60" model="product.view.limit">
|
||||
<field name="name">60</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
||||
|
@ -11,7 +11,6 @@
|
||||
<field name="website_size_x">2</field>
|
||||
<field name="website_size_y">2</field>
|
||||
<field name="website_sequence">3</field>
|
||||
<field name="website_style_ids" eval="[(6,0,[ref('website_sale.image_full')])]"/>
|
||||
<field name="website_description" type="html">
|
||||
<section class="mt16 mb16 oe_dark">
|
||||
<div class="container">
|
||||
@ -59,7 +58,6 @@
|
||||
<record id="product.product_product_5b" model="product.product">
|
||||
<field name="website_published" eval="True"/>
|
||||
<field name="website_size_x">2</field>
|
||||
<field name="website_style_ids" eval="[(6,0,[ref('website_sale.image_promo')])]"/>
|
||||
<field name="website_description" type="html">
|
||||
<section class="mt16 mb16">
|
||||
<div class="container">
|
||||
@ -165,7 +163,6 @@
|
||||
<record id="product.product_product_6" model="product.product">
|
||||
<field name="website_published" eval="True"/>
|
||||
<field name="website_sequence">4</field>
|
||||
<field name="website_style_ids" eval="[(6,0,[ref('website_sale.image_full')])]"/>
|
||||
<field name="description_sale">Color: White
|
||||
Capacity: 16GB
|
||||
Connectivity: Wifi
|
||||
@ -273,7 +270,6 @@ iOS7
|
||||
</section>
|
||||
</field>
|
||||
<field name="website_sequence">4</field>
|
||||
<field name="website_style_ids" eval="[(6,0,[ref('website_sale.image_full')])]"/>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_7" model="product.product">
|
||||
|
@ -8,6 +8,42 @@ from flectra.tools.translate import html_translate
|
||||
from flectra.tools import float_is_zero
|
||||
|
||||
|
||||
class ProductTags(models.Model):
|
||||
_name = 'product.tags'
|
||||
_order = 'sequence'
|
||||
|
||||
sequence = fields.Integer(help="Gives the sequence order when "
|
||||
"displaying a list of rules.")
|
||||
name = fields.Char(string='Name', required=True, translate=True)
|
||||
|
||||
_sql_constraints = [('name_uniq', 'unique (name)',
|
||||
"Tag name already exists !")]
|
||||
|
||||
|
||||
class ProductBrand(models.Model):
|
||||
_name = 'product.brand'
|
||||
_description = 'Product Brands'
|
||||
_order = 'sequence'
|
||||
|
||||
sequence = fields.Integer(help="Gives the sequence order when displaying "
|
||||
"a list of rules.")
|
||||
name = fields.Char(string='Name', required=True, translate=True)
|
||||
brand_image = fields.Binary(string='Brand Image')
|
||||
|
||||
_sql_constraints = [('name_uniq', 'unique (name)',
|
||||
'Brand name already exists !')]
|
||||
|
||||
|
||||
class ProductRibbon(models.Model):
|
||||
_name = 'product.ribbon'
|
||||
_description = 'Product Brand'
|
||||
_order = 'name'
|
||||
|
||||
name = fields.Char(string='Name', size=20, required=True, translate=True)
|
||||
ribbon_color_back = fields.Char(string='Background Color', required=True)
|
||||
ribbon_color_text = fields.Char(string='Font Color', required=True)
|
||||
|
||||
|
||||
class ProductStyle(models.Model):
|
||||
_name = "product.style"
|
||||
|
||||
@ -59,6 +95,18 @@ class ProductPricelist(models.Model):
|
||||
return res
|
||||
|
||||
|
||||
class WebsiteProductLimit(models.Model):
|
||||
_name = 'product.view.limit'
|
||||
_order = 'sequence'
|
||||
|
||||
sequence = fields.Integer(help="Gives the sequence order when "
|
||||
"displaying a list of rules.")
|
||||
name = fields.Integer(string='Limit', required=True)
|
||||
|
||||
_sql_constraints = [('name', 'unique(name)', 'This must be unique!')]
|
||||
|
||||
|
||||
|
||||
class ProductPublicCategory(models.Model):
|
||||
_name = "product.public.category"
|
||||
_inherit = ["website.seo.metadata"]
|
||||
@ -152,7 +200,6 @@ class ProductTemplate(models.Model):
|
||||
'An algorithm figures out a list of accessories based on all the products added to cart.')
|
||||
website_size_x = fields.Integer('Size X', default=1)
|
||||
website_size_y = fields.Integer('Size Y', default=1)
|
||||
website_style_ids = fields.Many2many('product.style', string='Styles')
|
||||
website_sequence = fields.Integer('Website Sequence', help="Determine the display order in the Website E-commerce",
|
||||
default=lambda self: self._default_website_sequence())
|
||||
public_categ_ids = fields.Many2many('product.public.category', string='Website Product Category',
|
||||
@ -169,6 +216,9 @@ class ProductTemplate(models.Model):
|
||||
string='Websites', copy=False,
|
||||
help='List of websites in which '
|
||||
'Product is published.')
|
||||
ribbon_id = fields.Many2one('product.ribbon', string='Product Ribbon')
|
||||
brand_id = fields.Many2one('product.brand', string="Product's Brand")
|
||||
tag_ids = fields.Many2many('product.tags', string='Product Tags')
|
||||
|
||||
def _website_price(self):
|
||||
# First filter out the ones that have no variant:
|
||||
|
@ -6,7 +6,6 @@ access_product_category_pos_manager,product.public.category manager,model_produc
|
||||
access_product_public_category_public,product.category.public,model_product_public_category,,1,0,0,0
|
||||
access_product_pricelist_public,product.pricelist.public,product.model_product_pricelist,,1,0,0,0
|
||||
access_product_pricelist_item_public,product.pricelist.item.public,product.model_product_pricelist_item,,1,0,0,0
|
||||
access_product_style,product.style.public,website_sale.model_product_style,,1,0,0,0
|
||||
access_product_supplierinfo,product.supplierinfo.public,product.model_product_supplierinfo,,1,0,0,0
|
||||
access_product_attribute_public,product.attribute public,product.model_product_attribute,,1,0,0,0
|
||||
access_product_attribute_value_public,product.attribute value public,product.model_product_attribute_value,,1,0,0,0
|
||||
@ -20,3 +19,7 @@ access_product_image_public,product.image public,model_product_image,,1,0,0,0
|
||||
access_product_image_publisher,product.image wbesite publisher,model_product_image,website.group_website_publisher,1,1,1,1
|
||||
access_product_image_sale,product.image sale,model_product_image,sales_team.group_sale_manager,1,1,1,1
|
||||
access_website_product_pricelist,access_website_product_pricelist,model_website_product_pricelist,,1,0,0,0
|
||||
access_product_view_limit,access_product_view_limit,model_product_view_limit,,1,0,0,0
|
||||
access_product_ribbon,product_ribbon,model_product_ribbon,,1,0,0,0
|
||||
access_product_tags,access_product_tags,model_product_tags,,1,0,0,0
|
||||
access_product_brand,access_product_brand,model_product_brand,,1,0,0,0
|
||||
|
|
31
addons/website_sale/static/src/js/products_view_limit.js
Normal file
31
addons/website_sale/static/src/js/products_view_limit.js
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
Part of Odoo Module Developed by 73lines
|
||||
See LICENSE file for full copyright and licensing details.
|
||||
*/
|
||||
flectra.define('website_product_misc_options_73lines.products_view_limit', function (require) {
|
||||
"use strict";
|
||||
|
||||
var website = require('website.website');
|
||||
var ajax = require('web.ajax');
|
||||
|
||||
$(function(){
|
||||
var previous_limit = localStorage['active_limit'];
|
||||
if (previous_limit) {
|
||||
for (var i = 0; i < $('.product_limit_link').length; i++) {
|
||||
if (previous_limit == $('.product_limit_link')[i].getAttribute('value')) {
|
||||
$('.product_limit_link')[i].classList.add('active');
|
||||
}
|
||||
}
|
||||
$('.product_limit_link.active').parent().addClass('active')
|
||||
}
|
||||
$('.product_limit_link').click(function(type){
|
||||
if(type['type'] !== "click") return;
|
||||
ajax.jsonRpc('/shop/product_limit', 'call', {'value': $(this)[0].getAttribute('value')});
|
||||
location.reload();
|
||||
$(this).parent().siblings().removeClass('active');
|
||||
$(this).parent().addClass('active');
|
||||
localStorage['active_limit'] = $(this)[0].getAttribute('value');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
43
addons/website_sale/static/src/js/products_view_switcher.js
Normal file
43
addons/website_sale/static/src/js/products_view_switcher.js
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Part of Odoo Module Developed by 73lines
|
||||
See LICENSE file for full copyright and licensing details.
|
||||
*/
|
||||
flectra.define('website_sale.products_view_switcher', function (require) {
|
||||
"use strict";
|
||||
|
||||
var ajax = require('web.ajax');
|
||||
var Widget = require('web.Widget');
|
||||
var website = require('website.website');
|
||||
var base = require('web_editor.base');
|
||||
|
||||
$(function(){
|
||||
$('.grid_view').attr('disabled', 'disabled');
|
||||
var previous_view_type = localStorage['active_view'];
|
||||
if (previous_view_type == 'grid_view') {
|
||||
$('div#grid_list').removeClass("oe_list").addClass('oe_grid oe-height-4');
|
||||
$('.grid_view').attr('disabled', 'disabled');
|
||||
$('.list_view').removeAttr('disabled');
|
||||
}
|
||||
if (previous_view_type == 'list_view') {
|
||||
$('div#grid_list').removeClass("oe_grid oe-height-4").addClass('oe_list');
|
||||
$('.list_view').attr('disabled', 'disabled');
|
||||
$('.grid_view').removeAttr('disabled');
|
||||
}
|
||||
|
||||
$('.grid_view').click(function(type){
|
||||
if(type['type'] !== "click") return;
|
||||
$('div#grid_list').removeClass("oe_list").addClass('oe_grid oe-height-4');
|
||||
$('.grid_view').attr('disabled', 'disabled');
|
||||
$('.list_view').removeAttr('disabled');
|
||||
localStorage['active_view'] = 'grid_view';
|
||||
});
|
||||
$('.list_view').click(function(type){
|
||||
if(type['type'] !== "click") return;
|
||||
$('div#grid_list').removeClass("oe_grid oe-height-4").addClass('oe_list');
|
||||
$('.list_view').attr('disabled', 'disabled');
|
||||
$('.grid_view').removeAttr('disabled');
|
||||
localStorage['active_view'] = 'list_view';
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -80,19 +80,6 @@ options.registry.website_sale = options.Class.extend({
|
||||
if (size_y >= 4) $select = $select.add($size.find('tr:eq(3) td:lt('+size_x+')'));
|
||||
$select.addClass("selected");
|
||||
|
||||
this._rpc({
|
||||
model: 'product.style',
|
||||
method: 'search_read',
|
||||
}).then(function (data) {
|
||||
var $ul = self.$el.find('ul[name="style"]');
|
||||
for (var k in data) {
|
||||
$ul.append(
|
||||
$('<li data-style="'+data[k]['id']+'" data-toggle-class="'+data[k]['html_class']+'" data-no-preview="true"/>')
|
||||
.append( $('<a/>').text(data[k]['name']) ));
|
||||
}
|
||||
self._setActive();
|
||||
});
|
||||
|
||||
this.bind_resize();
|
||||
},
|
||||
reload: function () {
|
||||
@ -141,13 +128,7 @@ options.registry.website_sale = options.Class.extend({
|
||||
});
|
||||
},
|
||||
style: function (previewMode, value, $li) {
|
||||
this._rpc({
|
||||
route: '/shop/change_styles',
|
||||
params: {
|
||||
id: this.product_tmpl_id,
|
||||
style_id: value,
|
||||
},
|
||||
});
|
||||
|
||||
},
|
||||
go_to: function (previewMode, value) {
|
||||
this._rpc({
|
||||
|
130
addons/website_sale/static/src/less/website_sale.less
Normal file
130
addons/website_sale/static/src/less/website_sale.less
Normal file
@ -0,0 +1,130 @@
|
||||
/* ribbon */
|
||||
.oe_product .ribbon-wrap {
|
||||
width: 85px;
|
||||
height: 88px;
|
||||
z-index: 100;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* quick view start */
|
||||
.quick-view .fancybox {
|
||||
-webkit-transition: all 0.6s ease;
|
||||
transition: all 0.6s ease;
|
||||
}
|
||||
.quick-view .fancybox {
|
||||
opacity: 0.7;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
background: #EEEEEE;
|
||||
border-radius: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding: 7px;
|
||||
float: none;
|
||||
color: #000000;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
width: 32px;
|
||||
text-transform: uppercase;
|
||||
line-height: 1.42857;
|
||||
}
|
||||
.quick-view .fancybox .icon {
|
||||
margin-right: 10px;
|
||||
margin-left: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.quick-view .fancybox:hover {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.quick {
|
||||
top: 0;
|
||||
height: auto;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 6;
|
||||
opacity: 1;
|
||||
transition: 0.3s all ease 0s;
|
||||
-webkit-transition: 0.3s all ease 0s;
|
||||
}
|
||||
.quick .quick-view-bgr {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.quick .quick-view-bgr a {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
position: absolute;
|
||||
}
|
||||
.product-single:hover .quick {
|
||||
opacity: 1;
|
||||
z-index: 20;
|
||||
}
|
||||
.oe_grid:hover .quick {
|
||||
opacity: 1;
|
||||
z-index: 20;
|
||||
}
|
||||
.oe_list:hover .quick {
|
||||
opacity: 1;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.quick-view-product{
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.modal-lg .product_price {
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.quick-modal .modal-content {
|
||||
border-radius: 0px;
|
||||
}
|
||||
.quick-modal .modal-header {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
.quick-modal .modal-footer {
|
||||
border-top: 0px;
|
||||
}
|
||||
|
||||
/* quick view end */
|
||||
|
||||
/* share Option start */
|
||||
.share_buttons {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.oe_share_facebook, .oe_share_facebook:hover {
|
||||
color: #3b5998 !important;
|
||||
}
|
||||
|
||||
.oe_share_twitter, .oe_share_twitter:hover {
|
||||
color: #326ada !important;
|
||||
}
|
||||
|
||||
.oe_share_google, .oe_share_google:hover {
|
||||
color: #dd4b39 !important;
|
||||
}
|
||||
|
||||
.oe_share_mail, .oe_share_mail:hover {
|
||||
color: #666666 !important;
|
||||
}
|
||||
/* share Option end */
|
@ -58,4 +58,4 @@
|
||||
.o_top_margin {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
@ -72,7 +72,9 @@
|
||||
<field name="public_categ_ids" widget="many2many_tags" string="eCommerce Categories"/>
|
||||
<field name="alternative_product_ids" widget="many2many_tags"/>
|
||||
<field name="accessory_product_ids" widget="many2many_tags"/>
|
||||
<field name="website_style_ids" widget="many2many_tags" groups="base.group_no_one"/>
|
||||
<field name="ribbon_id"/>
|
||||
<field name="tag_ids" widget="many2many_tags"/>
|
||||
<field name="brand_id" options="{'no_create': True}"/>
|
||||
</group>
|
||||
<field name="website_ids"/>
|
||||
</group>
|
||||
@ -222,4 +224,155 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Product Limit Tree View -->
|
||||
<record id="portfolio_category_tree_view" model="ir.ui.view">
|
||||
<field name="name">product.view.limit.per.page.tree</field>
|
||||
<field name="model">product.view.limit</field>
|
||||
<field name="field_parent" eval="False" />
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Product Veiw Limit per Page" editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Product Limit Action -->
|
||||
<record id="website_product_limit_action" model="ir.actions.act_window">
|
||||
<field name="name">Website Products View Limit</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">product.view.limit</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to define a new Product View Limit per Page in Shop.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Product Ribbon Form View -->
|
||||
<record id="product_ribbon_form_view" model="ir.ui.view">
|
||||
<field name="name">Product Ribbon Form View</field>
|
||||
<field name="model">product.ribbon</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Product Ribbon">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" />
|
||||
<field name="ribbon_color_back"/>
|
||||
<field name="ribbon_color_text"/>
|
||||
</group>
|
||||
<div class="alert alert-danger mt16" style="font-size:15px;">
|
||||
You can add Color Name | Hex Code in Ribbon's Background | Font color field.
|
||||
</div>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Product Tags Tree View -->
|
||||
<record id="product_tag_tree_view" model="ir.ui.view">
|
||||
<field name="name">Product Tags Tree</field>
|
||||
<field name="model">product.tags</field>
|
||||
<field name="field_parent" eval="False" />
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Product Tags" editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Product Brand From View -->
|
||||
<record id="product_by_brand_form_view" model="ir.ui.view">
|
||||
<field name="name">product.brand.form</field>
|
||||
<field name="model">product.brand</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Product Brands">
|
||||
<sheet>
|
||||
<field name="brand_image" widget="image" class="oe_avatar"/>
|
||||
<div class="oe_title">
|
||||
<label class="oe_edit_only" for="name" string="Brand Name"/>
|
||||
<h1><field name="name" placeholder="Brand Name"/></h1>
|
||||
</div>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Product Brand Tree View -->
|
||||
<record id="product_by_brand_tree_view" model="ir.ui.view">
|
||||
<field name="name">product.brand.tree</field>
|
||||
<field name="model">product.brand</field>
|
||||
<field name="field_parent" eval="False" />
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Product Brands">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="product_brand_kanban_view" model="ir.ui.view">
|
||||
<field name="name">Product By Brand</field>
|
||||
<field name="model">product.brand</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban>
|
||||
<field name="brand_image"/>
|
||||
<field name="name"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click">
|
||||
<div class="o_kanban_image">
|
||||
<img t-att-src="kanban_image('product.brand', 'brand_image')"/>
|
||||
</div>
|
||||
<div class="oe_kanban_details">
|
||||
<strong><field name="name"/></strong>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Product Brand Action -->
|
||||
<record id="product_by_brand_action" model="ir.actions.act_window">
|
||||
<field name="name">Brands</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">product.brand</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click here to define a new product brand.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Product Tags Action -->
|
||||
<record id="product_tags_action" model="ir.actions.act_window">
|
||||
<field name="name">Tags</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">product.tags</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click here to define a new product tag.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Product Brands Menu -->
|
||||
<menuitem action="product_by_brand_action" id="menu_product_by_brand"
|
||||
parent="website_sale.menu_catalog"/>
|
||||
|
||||
<!-- Product Tags Menu -->
|
||||
<menuitem action="product_tags_action" id="menu_product_tags" name="Tags"
|
||||
parent="website_sale.menu_catalog"/>
|
||||
|
||||
</flectra>
|
||||
|
@ -131,6 +131,10 @@
|
||||
action="base.action_partner_customer_form"
|
||||
parent="menu_orders" sequence="4"/>
|
||||
|
||||
<!-- Product Limit Menu -->
|
||||
<menuitem action="website_product_limit_action" id="menu_view_limit"
|
||||
name="Website Product View Limit" parent="website_sale.menu_ecommerce_settings"/>
|
||||
|
||||
|
||||
<!-- <menuitem id="menu_orders_invoices" name="Invoices" parent="menu_orders" action="action_invoices_ecommerce" sequence="4"/> -->
|
||||
|
||||
|
@ -12,12 +12,15 @@
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/website_sale/static/src/css/website_sale.css" />
|
||||
<link rel="stylesheet" href="/website_sale/static/src/css/website_mail.css" />
|
||||
<link rel="stylesheet" href="/website_sale/static/src/less/website_sale.less"/>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_utils.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_payment.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_validate.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_tour_buy.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_tracking.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/products_view_switcher.js"></script>
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/products_view_limit.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
@ -78,17 +81,55 @@
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- View Switcher Icons Template -->
|
||||
<template id="product_view_switcher" name="Product View Switcher">
|
||||
<div class="btn-group switch-grp">
|
||||
<button class="btn btn-default view-switcher grid_view"
|
||||
data-toggle="tooltip" title="Grid View">
|
||||
<span class="fa fa-th-large" />
|
||||
</button>
|
||||
<button class="btn btn-default view-switcher list_view"
|
||||
data-toggle="tooltip" title="List View">
|
||||
<span class="fa fa-bars" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- View Limit Template -->
|
||||
<template id="product_limit" name="Product View Limit">
|
||||
<div t-if="limits" class="product_limit dropdown btn-group">
|
||||
<button class="btn btn-default dropdown-toggle active_limit"
|
||||
type="button" data-toggle="dropdown">
|
||||
<b>
|
||||
<t t-esc="PPG" />
|
||||
</b>
|
||||
<span class="perPage"> Per Page </span>
|
||||
<span class="caret"/>
|
||||
</button>
|
||||
<ul class="dropdown-menu limit_list">
|
||||
<li t-foreach="limits" t-as="limit">
|
||||
<a class="product_limit_link" t-att-value="limit['name']">
|
||||
<t t-esc="limit['name']" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Product item used by /shop and /shop/cart -->
|
||||
<template id="products_item" name="Products item">
|
||||
<form action="/shop/cart/update" method="post">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
|
||||
<div itemscope="itemscope" itemtype="http://schema.org/Product">
|
||||
<div class="ribbon-wrapper">
|
||||
<div class="ribbon btn btn-danger">Sale</div>
|
||||
<div class="ribbon-wrap">
|
||||
<div class="ribbon"
|
||||
t-attf-style="background-color:#{product.ribbon_id.ribbon_color_back or product.ribbon_id.ribbon_color_back};color:#{product.ribbon_id.ribbon_color_text or product.ribbon_id.ribbon_color_text};">
|
||||
<span t-esc="product.ribbon_id.name"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_product_image">
|
||||
<a itemprop="url" t-att-href="keep('/shop/product/%s' % slug(product), page=(pager['page']['num'] if pager['page']['num']>1 else None))">
|
||||
<span itemprop="image" t-attf-content="{{request.httprequest.url_root}}web/image/product.template/{{product.id}}/image" t-field="product.image" t-options="{'widget': 'image', 'resize': None if product_image_big else '300x300', 'zoom': 'image'}" t-att-alt="product.name" />
|
||||
<img class="img img-responsive image-center thumb-hover" itemprop="image" t-att-alt="product.name" t-att-prod-id="product.id" t-att-title="product.name" t-attf-src="#{base_url}#{ website.image_url(product, 'image', '300x300')}"/>
|
||||
</a>
|
||||
</div>
|
||||
<t t-if="show_publish">
|
||||
@ -178,32 +219,21 @@
|
||||
</t>
|
||||
<t t-call="website_sale.pricelist_list" />
|
||||
<t t-call="website.pager" />
|
||||
<t t-call="website_sale.product_view_switcher" />
|
||||
<t t-call="website_sale.product_limit" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="hidden" id="products_grid_before"></div>
|
||||
<div class="col-md-12" id="products_grid">
|
||||
<table width="100%">
|
||||
<tbody>
|
||||
<tr t-ignore="true">
|
||||
<td t-foreach="range(0,rows)" t-as="row" t-attf-width="#{100/rows}%"></td>
|
||||
</tr>
|
||||
<tr t-foreach="bins" t-as="tr_product">
|
||||
<t t-foreach="tr_product" t-as="td_product">
|
||||
<t t-if="td_product">
|
||||
<t t-set="product" t-value="td_product['product']" />
|
||||
<td t-att-colspan="td_product['x'] != 1 and td_product['x']" t-att-rowspan="td_product['y'] != 1 and td_product['y']" t-attf-class="oe_product oe_grid oe-height-#{td_product['y']*2} #{ td_product['class'] }">
|
||||
<div class="oe_product_cart" t-att-data-publish="website in product.website_ids and 'on' or 'off'">
|
||||
<t t-set="product_image_big" t-value="td_product['x']+td_product['y'] > 2" />
|
||||
<t t-call="website_sale.products_item" />
|
||||
</div>
|
||||
</td>
|
||||
</t>
|
||||
<td t-if="not td_product" class="oe-height-2" />
|
||||
</t>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<t t-foreach="products" t-as="product">
|
||||
<div id="grid_list"
|
||||
class="col-md-4 oe_product oe_grid oe_product_cart oe-height-4"
|
||||
t-att-data-publish="website in product.website_ids and 'on' or 'off'">
|
||||
<t t-call="website_sale.products_item">
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="not bins">
|
||||
<div class="text-center text-muted oe_product">
|
||||
<h3 class="css_editable_display">No product defined.</h3>
|
||||
@ -362,15 +392,14 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="products_list_view" inherit_id="website_sale.products" active="False" customize_show="True" name="List View">
|
||||
<xpath expr="//div[@id='products_grid']//table" position="replace">
|
||||
<t t-foreach="products" t-as="product">
|
||||
<div class="oe_product oe_list oe_product_cart" t-att-data-publish="website in product.website_ids and 'on' or 'off'">
|
||||
<t t-call="website_sale.products_item">
|
||||
<t t-set="show_publish" t-value="True" />
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<template id="products_list_view" inherit_id="website_sale.products" name="List View" active="False">
|
||||
<xpath expr="//div[@id='products_grid']/t/div[@id='grid_list']" position="replace">
|
||||
<div class="oe_product oe_list oe_product_cart"
|
||||
t-att-data-publish="website in product.website_ids and 'on' or 'off'">
|
||||
<t t-call="website_sale.products_item">
|
||||
<t t-set="show_publish" t-value="True" />
|
||||
</t>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
@ -482,8 +511,60 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="product_description_reviews" class="mt8">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active" id="li-full-desc">
|
||||
<a href="#full-desc" data-toggle="tab">
|
||||
<strong>Description</strong>
|
||||
</a>
|
||||
</li>
|
||||
<t t-if="product.attribute_line_ids">
|
||||
<li role="presentation" class="" id="product_specification_tab">
|
||||
<a href="#product-additional-info" aria-controls="full" role="tab"
|
||||
data-toggle="tab" aria-expanded="true">
|
||||
<strong>Specifications</strong>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade in active" id="full-desc">
|
||||
<div itemprop="description" t-field="product.website_description"
|
||||
class="oe_structure mt16" id="product_full_description" />
|
||||
</div>
|
||||
<div class="tab-pane fade" id="product-additional-info">
|
||||
<div t-if="product.attribute_line_ids">
|
||||
<div id="product_attribute_details" class="mt32 mb32">
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
<tr t-foreach="product.attribute_line_ids" t-as="pfl">
|
||||
<td class="col-md-4">
|
||||
<strong>
|
||||
<p t-esc="pfl.attribute_id.name" style="margin: 0 0 0px;" />
|
||||
</strong>
|
||||
</td>
|
||||
<td>
|
||||
<p style="margin: 0 0 0px;">
|
||||
<t t-set="i" t-value="0" />
|
||||
<t t-foreach="pfl.value_ids" t-as="pfv">
|
||||
<t t-esc="pfv.name" />
|
||||
<span t-if="i != len(pfl.value_ids)-1">
|
||||
,
|
||||
</span>
|
||||
<t t-set="i" t-value="i+1" />
|
||||
</t>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div itemprop="description" t-field="product.website_description" class="oe_structure mt16" id="product_full_description" />
|
||||
<t t-set="head">
|
||||
<!-- Facebook and linkedin sharing data -->
|
||||
<meta property="og:type" content="website" />
|
||||
@ -543,19 +624,19 @@
|
||||
|
||||
<!-- Product options: OpenChatter -->
|
||||
<template id="product_comment" inherit_id="website_sale.product" active="False" customize_show="True" name="Discussion and Rating">
|
||||
<xpath expr="//div[@t-field='product.website_description']" position="after">
|
||||
<div class="o_shop_discussion_rating">
|
||||
<section class="container mt16 mb16">
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="product"/>
|
||||
<t t-set="display_rating" t-value="True"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<xpath expr="//li[@id='li-full-desc']" position="after">
|
||||
<li id="li-comment">
|
||||
<a href="#full-comment" data-toggle="tab">
|
||||
<strong>Discussion and Rating</strong>
|
||||
</a>
|
||||
</li>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='full-desc']" position="after">
|
||||
<div class="tab-pane fade" id="full-comment">
|
||||
<t t-call="portal.message_thread">
|
||||
<t t-set="object" t-value="product"/>
|
||||
<t t-set="display_rating" t-value="True"/>
|
||||
</t>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
@ -1654,4 +1735,186 @@
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Give Space besides Add to Cart button -->
|
||||
<template id="product_side_block" inherit_id="website_sale.product"
|
||||
name="Product Side Block" active="False" customize_show="True">
|
||||
<xpath expr="//div[hasclass('col-sm-7')]" position="attributes">
|
||||
<attribute name="class">col-sm-5</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='product_details']" position="attributes">
|
||||
<attribute name="class">col-sm-5 col-lg-3 col-lg-offset-1
|
||||
</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//section[@id='product_detail']/div[2]" position="inside">
|
||||
<div class="col-sm-2 col-lg-3 oe_structure">
|
||||
<h4> Put Your Content Here Like Images,Carousel,Ecommerce Terms
|
||||
etc...
|
||||
</h4>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="quick_view_products_item" inherit_id="website_sale.products_item"
|
||||
active="True" customize_show="True" name="Product Quick View">
|
||||
<xpath expr="//div[hasclass('oe_product_image')]/a[1]" position="after">
|
||||
<div t-attf-class="quick" t-if="product.website_published and website in product.website_ids">
|
||||
<div class="quick-view-bgr">
|
||||
<a class="quick-view btn btn-primary" t-attf-href="##{ product.id }"
|
||||
role="button" data-toggle="modal" title="Quick view">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div t-att-id="product.id" class="modal fade in quick-modal" aria-hidden="true"
|
||||
role="dialog" tabindex="-1" t-if="product.website_published">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">X
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body col-md-12">
|
||||
<div class="col-md-5 col-md-offset-1">
|
||||
<a itemprop="url"
|
||||
t-att-href="keep('/shop/product/%s' % slug(product), page=(pager['page']['num'] if pager['page']['num']>1 else None))">
|
||||
<img itemprop="image" class="img img-responsive quick-view-product"
|
||||
t-att-src="website.image_url(product, 'image')" t-att-alt="product.name" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-5 col-md-offset-1">
|
||||
<div class="col-md-12 text-left">
|
||||
<h2 class="mt16 mb16">
|
||||
<strong t-field="product.display_name" />
|
||||
</h2>
|
||||
<div class="text-muted">
|
||||
<div t-field="product.description_sale" class="mt16 mb16" />
|
||||
<div class="js_attributes" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12 mt16 mb16">
|
||||
<div class="css_quantity input-group oe_website_spinner"
|
||||
contenteditable="false">
|
||||
<a t-attf-href="#" class="mb8 input-group-addon js_add_cart_json">
|
||||
<i class="fa fa-minus"></i>
|
||||
</a>
|
||||
<input type="text" class="form-control" data-min="1"
|
||||
name="add_qty" value="1" />
|
||||
<a t-attf-href="#"
|
||||
class="mb8 input-group-addon float_left js_add_cart_json">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12 text-left">
|
||||
<t t-set="attribute_value_ids" t-value="get_attribute_value_ids(product)" />
|
||||
<form action="/shop/cart/update" class="js_add_cart_variants"
|
||||
t-att-data-attribute_value_ids="product.product_variant_ids.ids"
|
||||
method="POST">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
|
||||
<div class="js_product" t-if="product.product_variant_ids">
|
||||
<t t-placeholder="select">
|
||||
<input type="hidden" class="product_id" name="product_id"
|
||||
t-att-value="product.product_variant_id.id if len(product.product_variant_ids) == 1 else '0'" />
|
||||
<t t-call="website_sale.variants">
|
||||
<t t-set="ul_class" t-value="'nav-stacked'" />
|
||||
</t>
|
||||
</t>
|
||||
<h1><t t-call="website_sale.product_price" /></h1>
|
||||
<p t-if="len(product.product_variant_ids) > 1" class="css_not_available_msg bg-danger"
|
||||
style="padding: 15px;">This combination does not exist.</p>
|
||||
<a id="add_to_cart"
|
||||
class="btn btn-primary btn-md mt8 js_check_product a-submit"
|
||||
href="#">Add to Cart</a>
|
||||
<a itemprop="url" class="btn btn-success btn-md mt8"
|
||||
t-att-href="keep('/shop/product/%s' % slug(product), page=(pager['page']['num'] if pager['page']['num']>1 else None))">
|
||||
More Info
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Enable Share Options in Product Page -->
|
||||
<template id="product_share_button" inherit_id="website_sale.product"
|
||||
name="Product Share Options" customize_show="True" active="False">
|
||||
<xpath expr="//form[hasclass('js_add_cart_variants')]" position="after">
|
||||
<hr/>
|
||||
<div class="oe_share s_share">
|
||||
<h2>
|
||||
<a target="_Blank" class="oe_share_google share_buttons" data-toggle="tooltip" title="Google"
|
||||
href="https://plus.google.com/share?url={url}">
|
||||
<i class="fa fa-google-plus-square"/>
|
||||
</a>
|
||||
<a target="_Blank" class="oe_share_facebook share_buttons" data-toggle="tooltip" title="Facebook"
|
||||
href="https://www.facebook.com/sharer/sharer.php?u={url}">
|
||||
<i class="fa fa-facebook-square"/>
|
||||
</a>
|
||||
<a target="_Blank" class="oe_share_twitter share_buttons" data-toggle="tooltip" title="Twitter"
|
||||
href="https://twitter.com/intent/tweet?text={title}&url={url}">
|
||||
<i class="fa fa-twitter"/>
|
||||
</a>
|
||||
<a href="mailto:?body={url}&subject={title}" class="oe_share_mail share_buttons"
|
||||
data-toggle="tooltip" title="Mail">
|
||||
<i class="fa fa-envelope-o"/>
|
||||
</a>
|
||||
</h2>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Product Tags Filter -->
|
||||
<template id="website_product_tags" inherit_id="website_sale.products_attributes"
|
||||
active="False" customize_show="True" name="Product Tags's Filter">
|
||||
<xpath expr="//form[hasclass('js_attributes')]" position="inside">
|
||||
<t t-if="tags">
|
||||
<div id="tags_div">
|
||||
<div class="filter_title">
|
||||
<strong>Tags</strong>
|
||||
</div>
|
||||
<t t-foreach="tags" t-as="tag">
|
||||
<label class="product-tag btn btn-primary btn-xs mb8">
|
||||
<input type="checkbox" name="tags" class="hidden product_tags"
|
||||
t-att-title="tag.name" t-att-value="'%s' % (tag.id)"
|
||||
t-att-checked="'checked' if tag.id in tag_set else None" />
|
||||
<span style="font-weight: normal" t-field="tag.name" />
|
||||
</label>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Product Brands Filter -->
|
||||
<template id="website_product_brands" inherit_id="website_sale.products_attributes"
|
||||
active="True" customize_show="True" name="Product Brand's Filter">
|
||||
<xpath expr="//form[hasclass('js_attributes')]" position="inside">
|
||||
<t t-if="brands">
|
||||
<div id="brands_div">
|
||||
<div class="filter_title">
|
||||
<strong>Brands</strong>
|
||||
</div>
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<t t-foreach="brands" t-as="brand">
|
||||
<li class="brand_list">
|
||||
<label style="margin: 0 40px;">
|
||||
<input type="checkbox" name="brands"
|
||||
t-att-value="brand.id" t-att-checked="'checked' if brand.id in brand_set else None" />
|
||||
<span style="font-weight: normal" t-field="brand.name" />
|
||||
</label>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</flectra>
|
||||
|
Loading…
Reference in New Issue
Block a user