<script t-if="not translatable" type="text/javascript" src="/website/static/lib/ace/ace.js"></script>
<script type="text/javascript" src="/website/static/lib/vkbeautify/vkbeautify.0.99.00.beta.js"></script>
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
+ <link rel='stylesheet' href="/web/static/lib/jquery.ui/css/smoothness/jquery-ui-1.9.1.custom.css"/>
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
<script type="text/javascript" src="/website/static/lib/MutationObservers/test/sidetable.js"></script>
<script type="text/javascript" src='/website/static/lib/nearest/jquery.nearest.js'></script>
'data': [
'website_sale_data.xml',
'views/website_sale.xml',
+ 'views/website_sale_backend.xml',
'security/ir.model.access.csv',
'security/website_sale.xml',
],
from openerp.addons.website.models import website
import random
import uuid
+import urllib
+import simplejson
def get_order(order_id=None):
order_obj = request.registry.get('sale.order')
_order = 'website_sequence desc, website_published desc'
+ def get_attribute_ids(self):
+ attributes_obj = request.registry.get('product.attribute')
+ attributes_ids = attributes_obj.search(request.cr, request.uid, [(1, "=", 1)], context=request.context)
+ return attributes_obj.browse(request.cr, request.uid, attributes_ids, context=request.context)
+
def get_categories(self):
domain = [('parent_id', '=', False)]
product_ids = [id for id in product_ids if id in product_obj.search(request.cr, request.uid, [("id", 'in', product_ids)], context=request.context)]
return product_obj.browse(request.cr, request.uid, product_ids, context=request.context)
- @website.route(['/shop/', '/shop/category/<cat_id>/', '/shop/category/<cat_id>/page/<int:page>/', '/shop/page/<int:page>/'], type='http', auth="public", multilang=True)
- def category(self, cat_id=0, page=0, **post):
+ def has_search_attributes(self, attribute_id, value_id=None):
+ if request.httprequest.args.get('attributes'):
+ attributes = simplejson.loads(request.httprequest.args['attributes'])
+ else:
+ attributes = []
+ for key_val in attributes:
+ if key_val[0] == attribute_id and (not value_id or value_id in key_val[1:]):
+ return key_val
+ return False
+
+ @website.route(['/shop/attributes/'], type='http', auth="public", multilang=True)
+ def attributes(self, **post):
+ attributes = []
+ index = []
+ for key, val in post.items():
+ cat = key.split("-")
+ if len(cat) < 3 or cat[2] in ('max','minmem','maxmem'):
+ continue
+ cat_id = int(cat[1])
+ if cat[2] == 'min':
+ minmem = float(post.pop("att-%s-minmem" % cat[1]))
+ maxmem = float(post.pop("att-%s-maxmem" % cat[1]))
+ _max = int(post.pop("att-%s-max" % cat[1]))
+ _min = int(val)
+ if (minmem != _min or maxmem != _max) and cat_id not in index:
+ attributes.append([cat_id , [_min, _max] ])
+ index.append(cat_id)
+ elif cat_id not in index:
+ attributes.append([ cat_id, int(cat[2]) ])
+ index.append(cat_id)
+ else:
+ attributes[index.index(cat_id)].append( int(cat[2]) )
+ post.pop(key)
+
+ return request.redirect("/shop/?attributes=%s&%s" % (simplejson.dumps(attributes).replace(" ", ""), urllib.urlencode(post)))
+
+ def attributes_to_ids(self, attributes):
+ req = "SELECT product_id FROM product_attribute_product WHERE (1 = 1) "
+ for key_val in attributes:
+
+ req += "AND (attribute_id = %s AND (" % int(key_val[0])
+ if isinstance(key_val[1], list):
+ req += "value >= %s AND value <= %s" % (int(key_val[1][0]), int(key_val[1][1]))
+ else:
+ nb = 0
+ for val in key_val[1:]:
+ if nb:
+ req += " OR "
+ req += "value_id = %s" % int(val)
+ nb += 1
+ req += ")) "
+ req += "GROUP BY product_id"
+
+ request.cr.execute(req)
+ return [r[0] for r in request.cr.fetchall()]
+
+ @website.route(['/shop/', '/shop/page/<int:page>/'], type='http', auth="public", multilang=True)
+ def category(self, category=0, page=0, **post):
if 'promo' in post:
self.change_pricelist(post.get('promo'))
product_obj = request.registry.get('product.template')
domain = [("sale_ok", "=", True)]
- #domain += [('website_published', '=', True)]
if post.get("search"):
domain += ['|', '|', '|',
('description', 'ilike', "%%%s%%" % post.get("search")),
('website_description', 'ilike', "%%%s%%" % post.get("search")),
('product_variant_ids.public_categ_id.name', 'ilike', "%%%s%%" % post.get("search"))]
- if cat_id:
- cat_id = int(cat_id)
+ if post.get('category'):
+ cat_id = int(post.get('category'))
domain += [('product_variant_ids.public_categ_id.id', 'child_of', cat_id)] + domain
+ if post.get('attributes'):
+ attributes = simplejson.loads(post['attributes'])
+ if attributes:
+ ids = self.attributes_to_ids(attributes)
+ domain += [('id', 'in', ids or [0] )]
+
step = 20
product_count = len(product_obj.search(request.cr, request.uid, domain, context=request.context))
- pager = request.website.pager(url="/shop/category/%s/" % cat_id, total=product_count, page=page, step=step, scope=7, url_args=post)
+ pager = request.website.pager(url="/shop/%s" % post, total=product_count, page=page, step=step, scope=7, url_args=post)
request.context['pricelist'] = self.get_pricelist()
styles = style_obj.browse(request.cr, request.uid, style_ids, context=request.context)
values = {
- 'get_categories': self.get_categories,
- 'category_id': cat_id,
+ 'Ecommerce': self,
'product_ids': product_ids,
'product_ids_for_holes': fill_hole,
- 'get_bin_packing_products': self.get_bin_packing_products,
- 'get_products': self.get_products,
- 'search': post.get("search"),
+ 'search': post or dict(),
'pager': pager,
'styles': styles,
- 'style_in_product': lambda style, product: style.id in [s.id for s in product.website_style_ids]
+ 'style_in_product': lambda style, product: style.id in [s.id for s in product.website_style_ids],
}
return request.website.render("website_sale.products", values)
@website.route(['/shop/product/<int:product_id>/'], type='http', auth="public", multilang=True)
- def product(self, cat_id=0, product_id=0, **post):
+ def product(self, product_id=0, **post):
if 'promo' in post:
self.change_pricelist(post.get('promo'))
product = product_obj.browse(request.cr, request.uid, product_id, context=request.context)
values = {
- 'category_id': post.get('category_id') and int(post.get('category_id')) or None,
+ 'Ecommerce': self,
'category': category,
- 'search': post.get("search"),
- 'get_categories': self.get_categories,
'category_list': category_list,
'main_object': product,
'product': product,
+ 'search': post or dict(),
}
return request.website.render("website_sale.product", values)
import website_styles
import product
+import product_attributes
import website_sale
import website
});
});
+
+ $(".js_slider").each(function() {
+ var $slide = $(this);
+ var $slider = $('<div>'+
+ '<input type="hidden" name="att-'+$slide.data("id")+'-minmem" value="'+$slide.data("min")+'"/>'+
+ '<input type="hidden" name="att-'+$slide.data("id")+'-maxmem" value="'+$slide.data("max")+'"/>'+
+ '</div>');
+ var $min = $("<input readonly name='att-"+$slide.data("id")+"-min'/>")
+ .css("border", "0").css("width", "50%")
+ .val($slide.data("min"));
+ var $max = $("<input readonly name='att-"+$slide.data("id")+"-max'/>")
+ .css("border", "0").css("width", "50%").css("text-align", "right")
+ .val($slide.data("max"));
+ $slide.append($min);
+ $slide.append($max);
+ $slide.append($slider);
+ $slider.slider({
+ range: true,
+ min: +$slide.data("min"),
+ max: +$slide.data("max"),
+ values: [
+ $slide.data("value-min") ? +$slide.data("value-min") : +$slide.data("min"),
+ $slide.data("value-max") ? +$slide.data("value-max") : +$slide.data("max")
+ ],
+ slide: function( event, ui ) {
+ $min.val( ui.values[ 0 ] );
+ $max.val( ui.values[ 1 ] );
+ }
+ });
+ $min.val( $slider.slider( "values", 0 ) );
+ $max.val( $slider.slider( "values", 1 ) );
+ });
});
<openerp>
<data>
- <record id="product_normal_form_view" model="ir.ui.view">
- <field name="name">product.normal.form.inherit</field>
- <field name="model">product.product</field>
- <field name="inherit_id" ref="product.product_normal_form_view"/>
- <field name="arch" type="xml">
- <!-- add state field in header -->
- <xpath expr="//sheet" position="before">
- <div class="oe_form_box_info oe_text_center" attrs="{'invisible': [('sale_ok', '=', False)]}">
- <p attrs="{'invisible': [('website_published', '=', True)]}">
- This product is <b>not available</b> for public user in your ecommerce.
- </p>
- <p attrs="{'invisible': [('website_published', '=', False)]}">
- This product is <b>available</b> for public user in your ecommerce.
- </p>
- <p>Website view: <field class="oe_inline" name="website_url" widget="url"/></p>
- </div>
- </xpath>
-
- <group name="sale" position="inside">
- <group name="website" string="Website">
- <field name="website_published"/>
- <field name="suggested_product_ids" widget="many2many_tags"/>
- <field name="website_style_ids" widget="many2many_tags"/>
- </group>
- </group>
- </field>
- </record>
-
- <record model="ir.ui.view" id="product_pricelist_view">
- <field name="name">product.pricelist.website.form</field>
- <field name="model">product.pricelist</field>
- <field name="inherit_id" ref="product.product_pricelist_view"/>
- <field name="arch" type="xml">
- <field name="active" position="after">
- <field name="code"/>
- </field>
- </field>
- </record>
-
- <record model="ir.ui.view" id="product_template_form_view">
- <field name="name">product.template.product.website.form</field>
- <field name="model">product.template</field>
- <field name="inherit_id" ref="product.product_template_form_view"/>
- <field name="arch" type="xml">
- <!-- add state field in header -->
- <xpath expr="//sheet" position="before">
- <div class="oe_form_box_info oe_text_center" attrs="{'invisible': [('sale_ok', '=', False)]}">
- <p attrs="{'invisible': [('website_published', '=', True)]}">
- This product is <b>not available</b> for public user in your ecommerce.
- </p>
- <p attrs="{'invisible': [('website_published', '=', False)]}">
- This product is <b>available</b> for public user in your ecommerce.
- </p>
- <p>Website view: <field class="oe_inline" name="website_url" widget="url"/></p>
- </div>
- </xpath>
-
- <xpath expr="//group[@string='Product Type']" position="inside">
- <field name="website_published"/>
- </xpath>
- <xpath expr="//page[@string='Information']" position="inside">
- <group colspan="4" string="Products On Ecommerce">
- <field name="suggested_product_ids" widget="many2many_tags"/>
- <field name="website_style_ids" widget="many2many_tags"/>
- </group>
- </xpath>
- </field>
- </record>
-
<!-- Layout add nav and footer -->
<template id="header" inherit_id="website.layout" name="Custom Header">
</li>
</xpath>
</template>
+
<!-- List of categories -->
<template id="categories_recursive">
- <li t-att-class="category.id == category_id and 'active' or ''">
- <a t-att-class="category.id not in categ[1] and 'unpublish' or ''" t-href="/shop/category/#{ category.id }/" t-field="category.name"></a>
+ <li t-att-class="category.id == search.get('category') and 'active' or ''">
+ <a t-att-class="category.id not in categ[1] and 'unpublish' or ''" t-href="/shop/?category=#{ category.id }" t-field="category.name" t-keep-query="search,facettes"></a>
<ul t-if="category.child_id" class="nav nav-pills nav-stacked nav-hierarchy">
<t t-foreach="category.child_id" t-as="category">
<t t-if="category.id in categ[1] or editable">
<div class="ribbon">Promo</div>
</div>
<div class="oe_product_description">
- <a t-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&category_id=%s' % category_id) or ''}">
+ <a t-href="/shop/product/#{ product.id }/" t-keep-query="category,search,facettes">
<b t-field="product.name"/>
</a>
</div>
</b>
</div>
<div class="oe_product_image text-center">
- <a t-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&category_id=%s' % category_id) or ''}">
+ <a t-href="/shop/product/#{ product.id }/" t-keep-query="category,search,facettes">
<img class="img" t-att-src="product.img('image')"/>
</a>
</div>
<div class="col-sm-4">
<h1>Our Products</h1>
</div><div class="col-sm-2 pagination text-center">
- <a t-if="editable" t-href="/shop/#{ category_id and ('category/%s/' % category_id) or ''}add_product/" class="btn btn-primary btn-default">New Product</a>
+ <a t-if="editable" t-href="/shop/add_product/" class="btn btn-primary btn-default" t-keep-query="category,search,facettes">New Product</a>
</div><div class="col-sm-6">
<t t-call="website.pager">
<t t-set="classname">pull-right</t>
</t>
- <form t-action="/shop/#{ category_id and ('category/%s/' % category_id) or ''}" method="get" class="pull-right pagination form-inline" style="padding-right: 5px;">
+ <form t-action="/shop/" method="get" class="pull-right pagination form-inline" style="padding-right: 5px;" t-keep-query="category,search,facettes">
<div class="form-group">
- <input type="text" name="search" class="search-query form-control" placeholder="Search..." t-att-value="search or ''"/>
+ <input type="text" name="search" class="search-query form-control" placeholder="Search..." t-att-value="search.get('search') or ''"/>
</div>
</form>
</div>
<div class="col-md-12" id="products_grid">
<table width="100%">
<tbody>
- <t t-set="table_products" t-value="get_bin_packing_products(product_ids, product_ids_for_holes, 4)"/>
+ <t t-set="table_products" t-value="Ecommerce.get_bin_packing_products(product_ids, product_ids_for_holes, 4)"/>
<tr t-foreach="table_products" 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']"
+ t-attf-width="#{td_product['x']*25}%"
t-att-rowspan="td_product['y']"
t-attf-class="oe_product oe-height-#{td_product['y']*2} #{ td_product['class'] }">
<template id="list_view" inherit_option_id="website_sale.products" name="List View">
<xpath expr="//div[@id='products_grid']/table" position="replace">
<div class="row">
- <t t-set="products" t-value="get_products(product_ids)"/>
+ <t t-set="products" t-value="Ecommerce.get_products(product_ids)"/>
<t t-foreach="products" t-as="product">
<div class="col-md-12 oe_list_products oe-height-1">
<t t-call="website_sale.products_cart"/>
<div class="col-sm-5">
<ol class="breadcrumb">
<li><a t-href="/shop">Products</a></li>
- <li t-if="category"><a t-att-href="'/shop/category/%s' % (category_id,)"><span t-field="category.name"/></a></li>
+ <li t-if="search.get('category')"><a t-att-href="'/shop/" t-keep-query="category,search,facettes"><span t-field="category.name"/></a></li>
<li class="active"><span t-field="product.name"></span></li>
</ol>
</div><div class="col-sm-3">
</li>
</t>
</div><div class="col-sm-3 col-sm-offset-1">
- <form t-action="/shop/#{ category_id and ('category/%s/' % category_id) or ''}" method="get" class="pull-right">
+ <form t-action="/shop/" method="get" class="pull-right" t-keep-query="category,search,facettes">
<div class="input-group">
+ <t t-if="search">
+ <t foreach="search.items()" t-as="key">
+ <input t-att-name="key[0]" t-att-value="key[1]"/>
+ </t>
+ </t>
<span class="input-group-addon"><span class="glyphicon glyphicon-search"/></span>
<input type="text" name="search" class="search-query form-control" placeholder="Search..." t-att-value="search or ''"/>
</div>
<template id="products_categories" inherit_option_id="website_sale.products" name="Product Categories">
<xpath expr="//div[@id='products_grid']" position="before">
- <div class="col-md-3">
+ <div id="categories" class="col-md-3">
<ul class="nav nav-pills nav-stacked mt16">
- <li t-att-class=" '' if category_id else 'active' "><a t-href="/shop/">All Products</a></li>
- <t t-set="categ" t-value="get_categories()"/>
+ <li t-att-class=" '' if search.get('category') else 'active' "><a t-href="/shop/">All Products</a></li>
+ <t t-set="categ" t-value="Ecommerce.get_categories()"/>
<t t-foreach="categ[0]" t-as="category">
<t t-call="website_sale.categories_recursive"/>
</t>
</xpath>
</template>
+ <template id="products_attributes" inherit_option_id="website_sale.products_categories" name="Product Attributes">
+ <xpath expr="//div[@id='categories']" position="inside">
+ <form t-action="/shop/attributes/" method="post" t-keep-query="category,search,attributes">
+ <ul class="nav nav-pills nav-stacked mt16">
+ <t t-set="attribute_ids" t-value="Ecommerce.get_attribute_ids()"/>
+ <t t-foreach="attribute_ids" t-as="attribute_id">
+ <li t-if="attribute_id.value_ids and attribute_id.type == 'distinct'">
+ <div t-field="attribute_id.name"/>
+ <ul class="nav nav-pills nav-stacked">
+ <t t-foreach="attribute_id.value_ids" t-as="value_id">
+ <li t-att-class="Ecommerce.has_search_attributes(attribute_id.id, value_id.id) and 'active' or ''">
+ <label style="margin: 0 20px;">
+ <input type="checkbox" t-att-name="'att-%s-%s' % (attribute_id.id, value_id.id)"
+ t-att-checked="Ecommerce.has_search_attributes(attribute_id.id, value_id.id) and 'checked' or ''"/>
+ <span style="font-weight: normal" t-field="value_id.name"/>
+ </label>
+ </li>
+ </t>
+ </ul>
+ </li>
+ <li t-if="attribute_id.type == 'float' and attribute_id.float_min != attribute_id.float_max">
+ <div t-field="attribute_id.name"/>
+ <t t-set="attribute" t-value="Ecommerce.has_search_attributes(attribute_id.id)"/>
+ <div style="margin: 0 20px;" class="js_slider"
+ t-att-data-id="attribute_id.id"
+ t-att-data-value-min="attribute and attribute[1][0] or attribute_id.float_min"
+ t-att-data-value-max="attribute and attribute[1][1] or attribute_id.float_max"
+ t-att-data-min="attribute_id.float_min"
+ t-att-data-max="attribute_id.float_max"></div>
+ </li>
+ </t>
+ </ul>
+ <button class="btn btn-xs btn-primary mt16">Apply filter</button>
+ </form>
+ </xpath>
+ </template>
<template id="suggested_products_list" inherit_id="website_sale.mycart" inherit_option_id="website_sale.mycart" name="Suggested Products in list view">
<xpath expr="//table[@id='mycart_products']" position="after">