summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@openerp.com>2013-09-26 13:23:07 +0200
committerChristophe Matthieu <chm@openerp.com>2013-09-26 13:23:07 +0200
commitf2a97662cd0a256e24c9bf48a44c2295e5d0ff4e (patch)
tree4ee4771c57fc6befce3b62200e81648aa53a8ed4
parente7a469f8bc5f4fe8004ebd877da6b8a85dfd0737 (diff)
parentc66c5d5b6af1d0e7acefd675b5bd03cfce512056 (diff)
[IMP] website_sale: add a bin packing method for sort and displayed products in the ecomerce. Fix some inherit of products. improve publish button
bzr revid: chm@openerp.com-20130926112307-xqwih3zlvlsmqq7j
-rw-r--r--addons/website/controllers/main.py9
-rw-r--r--addons/website/static/src/css/website.css23
-rw-r--r--addons/website/static/src/css/website.sass22
-rw-r--r--addons/website/static/src/js/website.js27
-rw-r--r--addons/website/views/views.xml14
-rw-r--r--addons/website_blog/views/website_blog_templates.xml4
-rw-r--r--addons/website_contract/views/website_contract.xml4
-rw-r--r--addons/website_crm_partner_assign/views/website_crm_partner_assign.xml4
-rw-r--r--addons/website_event/views/website_event.xml6
-rw-r--r--addons/website_hr/views/website_hr.xml2
-rw-r--r--addons/website_membership/views/website_membership.xml4
-rw-r--r--addons/website_sale/__init__.py1
-rw-r--r--addons/website_sale/controllers/main.py161
-rw-r--r--addons/website_sale/product.py17
-rw-r--r--addons/website_sale/static/src/css/website_sale.css5
-rw-r--r--addons/website_sale/static/src/css/website_sale.sass4
-rw-r--r--addons/website_sale/static/src/js/website_sale.js5
-rw-r--r--addons/website_sale/views/website_sale.xml116
-rw-r--r--addons/website_sale/website_sale_data.xml50
-rw-r--r--addons/website_sale/website_sale_demo.xml12
-rw-r--r--addons/website_sale/website_styles.py30
21 files changed, 397 insertions, 123 deletions
diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py
index 88c8b85f321..427381ac781 100644
--- a/addons/website/controllers/main.py
+++ b/addons/website/controllers/main.py
@@ -258,17 +258,16 @@ class Website(openerp.addons.web.controllers.main.Home):
pass
return request.make_response(image_data, headers)
- @website.route(['/website/publish/'], type='http', auth="public")
- def publish(self, **post):
- _id = int(post['id'])
- _object = request.registry[post['object']]
+ @website.route(['/website/publish'], type='json', auth="public")
+ def publish(self, id, object):
+ _id = int(id)
+ _object = request.registry[object]
obj = _object.browse(request.cr, request.uid, _id)
_object.write(request.cr, request.uid, [_id],
{'website_published': not obj.website_published},
context=request.context)
obj = _object.browse(request.cr, request.uid, _id)
-
return obj.website_published and "1" or "0"
@website.route(['/website/kanban/'], type='http', auth="public")
diff --git a/addons/website/static/src/css/website.css b/addons/website/static/src/css/website.css
index 5a064a40a9e..d3d275aac71 100644
--- a/addons/website/static/src/css/website.css
+++ b/addons/website/static/src/css/website.css
@@ -352,27 +352,12 @@ ul.nav-stacked > li > a {
}
/* ---- PUBLISH ---- */
-a[data-publish] {
- text-decoration: none !important;
- z-index: 2;
-}
-a[data-publish] .label {
- padding: 5px 8px;
-}
-a[data-publish] .css_unpublish, a[data-publish] .css_publish, a[data-publish] .css_unpublished, a[data-publish] .css_published {
- display: none;
-}
-a[data-publish][data-publish='off'] .css_unpublished, a[data-publish][data-publish='off']:hover .css_publish {
- display: inline;
-}
-a[data-publish][data-publish='off']:hover .css_unpublished {
+.dropdown .css_unpublish, .dropdown .css_publish {
display: none;
}
-a[data-publish][data-publish='on'] .css_published, a[data-publish][data-publish='on']:hover .css_unpublish {
- display: inline;
-}
-a[data-publish][data-publish='on']:hover .css_published {
- display: none;
+
+.dropdown.css_publish .css_unpublish, .dropdown.css_unpublish .css_publish {
+ display: block;
}
.unpublish {
diff --git a/addons/website/static/src/css/website.sass b/addons/website/static/src/css/website.sass
index cb0e93d9170..5e3468d9f33 100644
--- a/addons/website/static/src/css/website.sass
+++ b/addons/website/static/src/css/website.sass
@@ -267,23 +267,11 @@ ul.nav-stacked > li > a
text-transform: uppercase
/* ---- PUBLISH ---- */
-a[data-publish]
- text-decoration: none !important
- z-index: 2
- .label
- padding: 5px 8px
- .css_unpublish, .css_publish, .css_unpublished, .css_published
- display: none
- &[data-publish='off']
- .css_unpublished, &:hover .css_publish
- display: inline
- &:hover .css_unpublished
- display: none
- &[data-publish='on']
- .css_published, &:hover .css_unpublish
- display: inline
- &:hover .css_published
- display: none
+
+.dropdown .css_unpublish, .dropdown .css_publish
+ display: none
+.dropdown.css_publish .css_unpublish, .dropdown.css_unpublish .css_publish
+ display: block
.unpublish
opacity: 0.5
diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js
index b26a0a7e76c..c652ed1c459 100644
--- a/addons/website/static/src/js/website.js
+++ b/addons/website/static/src/js/website.js
@@ -116,19 +116,24 @@
dom_ready.then(function () {
/* ----- PUBLISHING STUFF ---- */
- $('[data-publish]:has(.js_publish)').each(function () {
- $(this).attr("data-publish", $(".js_publish li.active", this).size() ? "on" : 'off');
+ $('[data-publish]:has(.js_publish_management)').each(function () {
+ $(this).attr("data-publish", $(".js_publish_management .btn-success", this).size() ? "on" : 'off');
});
- $(document).on('click', '.js_publish a.js_publish_btn', function (e) {
- var $li = $(this).parent("li");
- var $data = $li.parents(".js_publish:first");
- var publish = $li.hasClass("active");
- $li.toggleClass("active");
- $.post('/website/publish', {'id': $data.data('id'), 'object': $data.data('object')}, function (result) {
- $li.toggleClass("active", !!+result);
- $li.parents("[data-publish]").attr("data-publish", +result ? 'on' : 'off');
- });
+ $(document).on('click', '.js_publish_management .js_publish_btn', function (e) {
+ var $data = $(this).parents(".js_publish_management:first");
+ var $btn = $data.find('.btn:first');
+ var publish = $btn.hasClass("btn-success");
+
+ $data.toggleClass("css_unpublish css_publish");
+ $btn.removeClass("btn-default btn-success");
+
+ openerp.jsonRpc('/website/publish', 'call', {'id': +$data.data('id'), 'object': $data.data('object')})
+ .then(function (result) {
+ $btn.toggleClass("btn-default", !+result).toggleClass("btn-success", !!+result);
+ $data.toggleClass("css_unpublish", !+result).toggleClass("css_publish", !!+result);
+ $data.parents("[data-publish]").attr("data-publish", +result ? 'on' : 'off');
+ });
});
/* ----- KANBAN WEBSITE ---- */
diff --git a/addons/website/views/views.xml b/addons/website/views/views.xml
index c57b69e5b58..f550234949e 100644
--- a/addons/website/views/views.xml
+++ b/addons/website/views/views.xml
@@ -338,13 +338,17 @@
</ul>
</template>
- <template id="publish">
+ <template id="publish_management">
<t t-if="editable" t-ignore="true">
- <div class="dropdown js_publish pull-right" t-att-data-id="object.id" t-att-data-object="object._name">
- <a class="btn btn-default" id="dopprod" role="button" data-toggle="dropdown"> Manage <span class="caret"></span></a>
+ <div t-attf-class="dropdown js_publish_management pull-right #{object.id and object.website_published and 'css_publish' or 'css_unpublish'}" t-att-data-id="object.id" t-att-data-object="object._name">
+ <a t-attf-class="btn btn-#{object.id and object.website_published and 'success' or 'default'}" id="dopprod" role="button" data-toggle="dropdown"> Publish options <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dopprod">
- <li t-att-class="object.id and object.website_published and 'active' or ''"><a href="#" class="js_publish_btn">Publish</a></li>
- <li><a t-att-href="'/admin/#model=%s&amp;id=%s' % (object._name, object.id)">Manage Products</a></li>
+ <t t-raw="0"/>
+ <li>
+ <a href="#" class="js_publish_btn css_unpublish">Unpublish</a>
+ <a href="#" class="js_publish_btn css_publish">Publish</a>
+ </li>
+ <li><a t-att-href="'/admin/#model=%s&amp;id=%s' % (object._name, object.id)">Manage</a></li>
</ul>
</div>
</t>
diff --git a/addons/website_blog/views/website_blog_templates.xml b/addons/website_blog/views/website_blog_templates.xml
index 09fdd38c1db..907d17b1aa1 100644
--- a/addons/website_blog/views/website_blog_templates.xml
+++ b/addons/website_blog/views/website_blog_templates.xml
@@ -36,7 +36,7 @@
<template id="view_blog_post" name="Blog Post">
<div>
<t t-call="website_mail.follow"><t t-set="object" t-value="blog_post"/></t>
- <t t-call="website.publish"><t t-set="object" t-value="blog_post"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="blog_post"/></t>
</div><div class="clearfix"/>
<h2 class="text-center" t-field="blog_post.name"/>
@@ -80,7 +80,7 @@
<ul class="media-list" id="comments">
<li t-foreach="blog_post.website_message_ids" t-as="message" class="media">
<div class="media-body well well-sm">
- <t t-call="website.publish"><t t-set="object" t-value="message"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="message"/></t>
<t t-raw="message.body"/>
<small class="pull-left text-muted text-left">
<t t-field="message.author_id"/> on <t t-field="message.date"/>
diff --git a/addons/website_contract/views/website_contract.xml b/addons/website_contract/views/website_contract.xml
index 3aca9dd8145..4863ddbafa2 100644
--- a/addons/website_contract/views/website_contract.xml
+++ b/addons/website_contract/views/website_contract.xml
@@ -62,7 +62,7 @@
<div>
<div t-foreach="partner_ids" t-as="partner" class="media thumbnail" data-publish="">
- <t t-call="website.publish"><t t-set="object" t-value="partner"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="partner"/></t>
<a class="pull-left" t-attf-href="/references/#{ partner.id }/">
<img class="media-object" t-att-src="partner.img('image_small')"/>
</a>
@@ -95,7 +95,7 @@
<template id="details" name="Reference Detail">
<t t-call="website_contract.layout">
<t t-set="ref_content">
- <t t-call="website.publish"><t t-set="object" t-value="partner_id"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="partner_id"/></t>
<h1 class="col-md-12 text-center" t-field="partner_id.name"/>
<div class="col-md-4">
<div class="text-center">
diff --git a/addons/website_crm_partner_assign/views/website_crm_partner_assign.xml b/addons/website_crm_partner_assign/views/website_crm_partner_assign.xml
index 2fca6e9a296..418b8e7565a 100644
--- a/addons/website_crm_partner_assign/views/website_crm_partner_assign.xml
+++ b/addons/website_crm_partner_assign/views/website_crm_partner_assign.xml
@@ -76,7 +76,7 @@
<h3 class="text-center well"><span t-field="partner.grade_id"/> Partners</h3>
</t>
<div class="media thumbnail" data-publish="">
- <t t-call="website.publish"><t t-set="object" t-value="partner"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="partner"/></t>
<a class="pull-left" t-attf-href="/partners/#{ partner.id }/">
<img class="media-object" t-att-src="partner.img('image_small')"/>
</a>
@@ -110,7 +110,7 @@
<template id="details" name="Partner Detail">
<t t-call="website_crm_partner_assign.layout">
<t t-set="ref_content">
- <t t-call="website.publish"><t t-set="object" t-value="partner_id"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="partner_id"/></t>
<h1 class="col-md-12 text-center" t-field="partner_id.name"/>
<div class="col-md-4">
<div class="text-center">
diff --git a/addons/website_event/views/website_event.xml b/addons/website_event/views/website_event.xml
index d79750b1e4d..4f01417daeb 100644
--- a/addons/website_event/views/website_event.xml
+++ b/addons/website_event/views/website_event.xml
@@ -60,7 +60,7 @@
</div>
<ul class="media-list">
<li t-foreach="event_ids" t-as="event" class="media" data-publish="">
- <t t-call="website.publish"><t t-set="object" t-value="event"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="event"/></t>
<div class="media-body">
<span t-if="not event.event_ticket_ids" class="label label-default pull-right">No tickets needed.</span>
<t t-if="event.event_ticket_ids">
@@ -137,7 +137,7 @@
<div class="container">
<div class="row">
<div class="col-md-8">
- <t t-call="website.publish"><t t-set="object" t-value="event_id"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="event_id"/></t>
<t t-call="website_mail.follow"><t t-set="object" t-value="event_id"/></t>
<h1 class="text-center" t-field="event_id.name"></h1>
<h4 class="text-center">
@@ -199,7 +199,7 @@
<ul class="media-list" id="comment">
<li t-foreach="event_id.website_message_ids" t-as="comment" class="media">
<div class="media-body">
- <t t-call="website.publish"><t t-set="object" t-value="comment"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="comment"/></t>
<t t-raw="comment.body"/>
<small class="pull-right muted text-right">
<div t-field="comment.author_id"/>
diff --git a/addons/website_hr/views/website_hr.xml b/addons/website_hr/views/website_hr.xml
index 4bf30a40ed5..9175a4112b7 100644
--- a/addons/website_hr/views/website_hr.xml
+++ b/addons/website_hr/views/website_hr.xml
@@ -30,7 +30,7 @@
<div class="thumbnails">
<div t-foreach="employee_ids" t-as="employee" class="col-md-4 mt16">
<div class="media img-thumbnail" data-publish="">
- <t t-call="website.publish"><t t-set="object" t-value="employee"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="employee"/></t>
<a class="pull-left" href="#">
<img class="media-object" t-att-src="employee.img('image_small')"/>
</a>
diff --git a/addons/website_membership/views/website_membership.xml b/addons/website_membership/views/website_membership.xml
index d8be7156f90..eb56632b234 100644
--- a/addons/website_membership/views/website_membership.xml
+++ b/addons/website_membership/views/website_membership.xml
@@ -67,7 +67,7 @@
</t>
<t t-set="partner" t-value="membership_line_id.partner"/>
<div class="media thumbnail" data-publish="">
- <t t-call="website.publish"><t t-set="object" t-value="partner"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="partner"/></t>
<a class="pull-left" t-attf-href="/members/#{ partner.id }/">
<img class="media-object" t-att-src="partner.img('image_small')"/>
</a>
@@ -101,7 +101,7 @@
<template id="details" name="Member Detail">
<t t-call="website_membership.layout">
<t t-set="ref_content">
- <t t-call="website.publish"><t t-set="object" t-value="partner_id"/></t>
+ <t t-call="website.publish_management"><t t-set="object" t-value="partner_id"/></t>
<h1 class="col-md-12 text-center" t-field="partner_id.name"/>
<div class="col-md-4">
<div class="text-center">
diff --git a/addons/website_sale/__init__.py b/addons/website_sale/__init__.py
index c63bb4c1fb2..c5e6825c179 100644
--- a/addons/website_sale/__init__.py
+++ b/addons/website_sale/__init__.py
@@ -1,3 +1,4 @@
import controllers
+import website_styles
import product
import website_sale
diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py
index c61faf88811..0838da90dd6 100644
--- a/addons/website_sale/controllers/main.py
+++ b/addons/website_sale/controllers/main.py
@@ -49,6 +49,8 @@ class Website(osv.osv):
class Ecommerce(http.Controller):
+ _order = 'website_sequence desc, website_published'
+
def get_categories(self):
domain = [('parent_id', '=', False)]
@@ -68,6 +70,146 @@ class Ecommerce(http.Controller):
return (categories, full_category_ids)
+ def get_bin_packing_products(self, product_ids, fill_hole, col_number=4):
+ """
+ Packing all products of the search into a table of #col_number columns in function of the product sizes
+ The size datas of website_style_ids is use for fill table (default 1x1)
+ The other website_style_ids datas are concatenate in a html class
+
+ @values:
+
+ product_ids: list of product template
+ fill_hole: list of extra product template use to fill the holes
+ col_number: number of columns
+
+ @return:
+
+ table (list of list of #col_number items)
+ items: {
+ 'product': browse of product template,
+ 'x': size x,
+ 'y': size y,
+ 'class': html class
+ }
+ """
+ product_obj = request.registry.get('product.template')
+ data_obj = request.registry.get('ir.model.data')
+
+ # search for checking of access rules and keep order
+ 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)]
+
+ size_ids = {}
+ data_domain = [('model', '=', 'website.product.style'), ('name', 'like', 'size%')]
+ data_ids = data_obj.search(request.cr, SUPERUSER_ID, data_domain, context=request.context)
+ for data in data_obj.read(request.cr, SUPERUSER_ID, data_ids, ['name', 'res_id'], context=request.context):
+ size_ids[data['res_id']] = [int(data['name'][-3]), int(data['name'][-1])]
+
+ product_list = []
+ bin_packing = {}
+ bin_packing[0] = {}
+
+ for product in product_obj.browse(request.cr, SUPERUSER_ID, product_ids, context=request.context):
+ index = len(product_list)
+
+ # get size and all html classes
+ _class = ""
+ x = 1
+ y = 1
+ for style_id in product.website_style_ids:
+ if style_id.id in size_ids:
+ size = size_ids[style_id.id]
+ x = size[0]
+ y = size[1]
+ elif style_id.html_class:
+ _class += " " + style_id.html_class
+ product_list.append({'product': product, 'x': x, 'y': y, 'class': _class })
+
+ # bin packing products
+ insert = False
+ line = 0
+ while not insert:
+ # if not full column get next line
+ if len(bin_packing.setdefault(line, {})) >= col_number:
+ line += 1
+ continue
+
+ col = 0
+ while col < col_number:
+ if bin_packing[line].get(col, None) != None:
+ col += 1
+ continue
+
+ insert = True
+
+ # check if the box can be inserted
+ copy_line = line
+ copy_y = y
+ while copy_y > 0:
+ copy_col = col
+ copy_x = x
+ while copy_x > 0:
+ if copy_col >= col_number or bin_packing.setdefault(copy_line, {}).get(copy_col, None) != None:
+ insert = False
+ break
+ copy_col += 1
+ copy_x -= 1
+ if not insert:
+ break
+ copy_line += 1
+ copy_y -= 1
+
+ if not insert:
+ col += 1
+ continue
+
+ # insert the box
+ copy_y = y
+ while copy_y > 0:
+ copy_y -= 1
+ copy_x = x
+ while copy_x > 0:
+ copy_x -= 1
+ bin_packing[line + copy_y][col + copy_x] = False
+ bin_packing[line + copy_y][col + copy_x] = product_list[index]
+ break
+
+ if not insert:
+ line += 1
+ else:
+ break
+
+ length = len(bin_packing)
+
+ # browse product to fill the holes
+ if fill_hole:
+ fill_hole_products = []
+ # search for checking of access rules and keep order
+ fill_hole = [id for id in fill_hole if id in product_obj.search(request.cr, request.uid, [("id", 'in', fill_hole)], context=request.context)]
+ for product in product_obj.browse(request.cr, SUPERUSER_ID, fill_hole, context=request.context):
+ fill_hole_products.append(product)
+ fill_hole_products.reverse()
+
+ # packaging in list (from dict)
+ bin_packing_list = []
+ line = 0
+ while line < length:
+ bin_packing_list.append([])
+ col = 0
+ while col < col_number:
+ if fill_hole and fill_hole_products and bin_packing[line].get(col) == None:
+ bin_packing[line][col] = {'product': fill_hole_products.pop(), 'x': 1, 'y': 1, 'class': _class }
+ bin_packing_list[line].append(bin_packing[line].get(col))
+ col += 1
+ line += 1
+
+ return bin_packing_list
+
+ def get_products(self, product_ids):
+ product_obj = request.registry.get('product.template')
+ # search for checking of access rules and keep order
+ 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, SUPERUSER_ID, 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")
def category(self, cat_id=0, page=0, **post):
@@ -92,14 +234,18 @@ class Ecommerce(http.Controller):
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)
- product_ids = product_obj.search(request.cr, request.uid, domain, limit=step, offset=pager['offset'], context=request.context)
-
request.context['pricelist'] = self.get_pricelist()
+ product_ids = product_obj.search(request.cr, request.uid, domain, limit=step, offset=pager['offset'], order=self._order, context=request.context)
+ fill_hole = product_obj.search(request.cr, request.uid, domain, limit=step, offset=pager['offset']+step, order=self._order, context=request.context)
+
values = {
'get_categories': self.get_categories,
'category_id': cat_id,
- 'products': product_obj.browse(request.cr, SUPERUSER_ID, product_ids, context=request.context),
+ '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"),
'pager': pager,
}
@@ -437,4 +583,13 @@ class Ecommerce(http.Controller):
request.httprequest.session['ecommerce_pricelist'] = False
return werkzeug.utils.redirect("/shop/")
+ @website.route(['/shop/change_sequence/'], type='json', auth="public")
+ def change_sequence(self, id, top):
+ product_obj = request.registry.get('product.template')
+ if top:
+ product_obj.set_sequence_top(request.cr, request.uid, [id], request.context)
+ else:
+ product_obj.set_sequence_bottom(request.cr, request.uid, [id], request.context)
+
+
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/website_sale/product.py b/addons/website_sale/product.py
index 06c53c0af1d..0603948bb36 100644
--- a/addons/website_sale/product.py
+++ b/addons/website_sale/product.py
@@ -37,16 +37,21 @@ class product_template(osv.Model):
'website_description': fields.html('Description for the website'),
'suggested_product_id': fields.many2one('product.template', 'Suggested For Product'),
'suggested_product_ids': fields.one2many('product.template', 'suggested_product_id', 'Suggested Products'),
- 'website_sizex': fields.selection(map(lambda x: (str(x+1),str(x+1)), range(12)), 'Size X'),
- 'website_sizey': fields.selection(map(lambda x: (str(x+1),str(x+1)), range(6)), 'Size Y'),
- 'website_product_class': fields.selection([('','Default'), ('oe_image_full','Image Full')], 'Size Y'),
+ 'website_style_ids' : fields.many2many('website.product.style','product_website_style_rel', 'product_id', 'style_id', 'Styles'),
+ 'website_sequence': fields.integer('Sequence', help="Determine the display order in the Website E-commerce"),
}
_defaults = {
- 'website_sizex': '3',
- 'website_sizey': '2',
- 'website_product_class': '',
+ 'website_sequence': 0,
}
+ def set_sequence_top(self, cr, uid, ids, context=None):
+ cr.execute('SELECT MAX(website_sequence) FROM product_template')
+ max_sequence = cr.fetchone()[0] or 0
+ return self.write(cr, uid, ids, {'website_sequence': max_sequence + 1}, context=context)
+
+ def set_sequence_bottom(self, cr, uid, ids, context=None):
+ return self.write(cr, uid, ids, {'website_sequence': 0}, context=context)
+
def recommended_products(self, cr, uid, ids, context=None):
id = ids[0]
product_ids = []
diff --git a/addons/website_sale/static/src/css/website_sale.css b/addons/website_sale/static/src/css/website_sale.css
index eb8ed400341..6bfcf2ffd21 100644
--- a/addons/website_sale/static/src/css/website_sale.css
+++ b/addons/website_sale/static/src/css/website_sale.css
@@ -116,6 +116,7 @@
border: 1px solid rgba(100, 100, 100, 0.2);
max-width: 100%;
max-height: 140px;
+ position: relative;
}
.oe_list_products .oe_product_image {
position: absolute;
@@ -142,3 +143,7 @@
right: 0;
border-top: 1px solid #dddddd;
}
+
+.oe_website_sale .row .row .col-md-12 {
+ float: none;
+}
diff --git a/addons/website_sale/static/src/css/website_sale.sass b/addons/website_sale/static/src/css/website_sale.sass
index 03f1351ffeb..5d6a98bf82a 100644
--- a/addons/website_sale/static/src/css/website_sale.sass
+++ b/addons/website_sale/static/src/css/website_sale.sass
@@ -110,6 +110,7 @@
border: 1px solid rgba(100, 100, 100, 0.2)
max-width: 100%
max-height: 140px
+ position: relative
.oe_product_image
position: absolute
left: 15px
@@ -132,3 +133,6 @@
left: 180px
right: 0
border-top: 1px solid #dddddd
+
+.oe_website_sale .row .row .col-md-12
+ float: none \ No newline at end of file
diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js
index f45e1be81d6..f13b3a37d97 100644
--- a/addons/website_sale/static/src/js/website_sale.js
+++ b/addons/website_sale/static/src/js/website_sale.js
@@ -64,4 +64,9 @@ $(document).ready(function () {
return false;
});
+ $('.js_go_to_top, .js_go_to_bottom').on('click', function () {
+ var $data = $(this).parents(".js_publish_management:first");
+ openerp.jsonRpc('/shop/change_sequence/', 'call', {'id': $data.data('id'), 'top': $(this).hasClass('js_go_to_top')});
+ });
+
});
diff --git a/addons/website_sale/views/website_sale.xml b/addons/website_sale/views/website_sale.xml
index b8c513432d5..974e1e22ae9 100644
--- a/addons/website_sale/views/website_sale.xml
+++ b/addons/website_sale/views/website_sale.xml
@@ -24,6 +24,7 @@
<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>
@@ -81,6 +82,34 @@
<!-- Product list -->
+ <template id="products_cart">
+ <div class="oe_product_description">
+ <a t-attf-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&amp;category_id=%s' % category_id) or ''}">
+ <b t-field="product.name"/>
+ </a>
+ <!-- This should be an option -->
+ <div t-if="product.description_sale" class="text-muted oe_subdescription">
+ <div id="product_description" t-att-data-name="product.id"/>
+ </div>
+ <div class="product_price">
+ <b>
+ <t t-if="product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
+ <span class="text-danger" style="text-decoration: line-through;">
+ <t t-esc="product.product_variant_ids[0].lst_price" /> €
+ </span>&amp;nbsp;
+ </t>
+ <t t-esc="product.product_variant_ids[0].price" /> €
+ </b>
+ </div>
+ </div>
+
+ <div class="oe_product_image text-center">
+ <a t-attf-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&amp;category_id=%s' % category_id) or ''}">
+ <img class="img" t-att-src="product.img('image')"/>
+ </a>
+ </div>
+ </template>
+
<template id="products" page="True">
<t t-call="website.layout">
<t t-set="head">
@@ -110,40 +139,35 @@
</div>
</div>
- <div class='row style_default'>
+ <div class='style_default'>
<div class="col-md-12" id="products_grid">
- <t t-foreach="products" t-as="product">
- <div t-attf-class="col-md-#{ search and 3 or product.website_sizex } oe_product oe-height-#{ search and 2 or product.website_sizey } #{ product.website_product_class}" t-att-data-publish="product.website_published and 'on' or 'off'" data-name="products_layout">
-
- <div class="oe_product_description">
- <a t-attf-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&amp;category_id=%s' % category_id) or ''}">
- <b t-field="product.name"/>
- </a>
- <!-- This should be an option -->
- <div t-if="product.description_sale" class="text-muted oe_subdescription">
- <div id="product_description" t-att-data-name="product.id"/>
- </div>
- <div>
- <b>
- <t t-if="product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
- <span class="text-danger" style="text-decoration: line-through;">
- <t t-esc="product.product_variant_ids[0].lst_price" /> €
- </span>&amp;nbsp;
- </t>
- <t t-esc="product.product_variant_ids[0].price" /> €
- </b>
- <span id="add_to_cart" t-att-data-name="product.id"/>
- </div>
- </div>
-
- <div class="oe_product_image text-center">
- <a t-attf-href="/shop/product/#{ product.id }/?#{ search and ('search=%s' % search) or ''}#{ category_id and ('&amp;category_id=%s' % category_id) or ''}">
- <img class="img" t-att-src="product.img('image')"/>
- </a>
- </div>
-
- </div>
- </t>
+ <table width="100%">
+ <colgroup>
+ <col style="width: 1px; margin-right: -1px;" />
+ <col class="col-md-3" />
+ <col class="col-md-3" />
+ <col class="col-md-3" />
+ <col class="col-md-3" />
+ </colgroup>
+ <tbody>
+ <t t-set="table_products" t-value="get_bin_packing_products(product_ids, product_ids_for_holes, 4)"/>
+ <tr t-foreach="table_products" t-as="tr_product">
+ <td class="oe-height-2"></td>
+ <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-att-rowspan="td_product['y']"
+ t-attf-class="oe_product #{ td_product['class'] }"
+ t-att-data-publish="product.website_published and 'on' or 'off'">
+ <t t-call="website_sale.products_cart"/>
+ </td>
+ </t>
+ <td t-if="td_product == None"/>
+ </t>
+ </tr>
+ </tbody>
+ </table>
</div>
</div>
<div class="text-center">
@@ -167,8 +191,8 @@
<!-- Add to cart button-->
- <template id="add_to_basket" inherit_option_id="website_sale.products" name="Add to Cart">
- <xpath expr="//span[@id='add_to_cart']" position="replace">
+ <template id="add_to_basket" inherit_option_id="website_sale.products_cart" name="Add to Cart">
+ <xpath expr="//div[@class='product_price']" position="inside">
<a t-attf-href="./add_cart/?product_id=#{ product.id }">
<span class="icon-shopping-cart"/>
</a>
@@ -178,8 +202,15 @@
<!-- List view of products -->
<template id="list_view" inherit_option_id="website_sale.products" name="List View">
- <xpath expr="//div[@data-name='products_layout']" position="attributes">
- <attribute name="class">col-md-12 oe_list_products oe-height-1</attribute>
+ <xpath expr="//div[@id='products_grid']/table" position="replace">
+ <div class="row">
+ <t t-set="products" t-value="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>
+ </t>
+ </div>
</xpath>
</template>
@@ -203,7 +234,16 @@
<li class="active" t-field="product.name">Product Name</li>
</ol>
</div><div class="col-sm-3">
- <t t-call="website.publish"><t t-set="object" t-value="product"/></t>
+ <t t-call="website.publish_management">
+ <t t-set="object" t-value="product"/>
+ <li class='dropdown-submenu'>
+ <a tabindex="-1" href="#">Sequence</a>
+ <ul class="dropdown-menu" name="sequence">
+ <li><a href="#" class="js_go_to_top">Push on top</a></li>
+ <li><a href="#" class="js_go_to_bottom">Push on bottom</a></li>
+ </ul>
+ </li>
+ </t>
</div><div class="col-sm-3 col-sm-offset-1">
<form t-attf-action="/shop/#{ category_id and ('category/%s/' % category_id) or ''}" method="get" class="pull-right">
<div class="input-group">
diff --git a/addons/website_sale/website_sale_data.xml b/addons/website_sale/website_sale_data.xml
index 8bb2fe8f6d2..0f1bf63ebd5 100644
--- a/addons/website_sale/website_sale_data.xml
+++ b/addons/website_sale/website_sale_data.xml
@@ -12,5 +12,55 @@
<field name="state">open</field>
</record>
+ <record id="website_sale.image_full" model="website.product.style">
+ <field name="name">Image Full</field>
+ <field name="html_class">oe_image_full</field>
+ </record>
+
+ <record id="website_sale.size2x1" model="website.product.style">
+ <field name="name">Size 2x1</field>
+ <field name="html_class">Size_2x1</field>
+ </record>
+ <record id="website_sale.size3x1" model="website.product.style">
+ <field name="name">Size 3x1</field>
+ <field name="html_class">Size 3x1</field>
+ </record>
+ <record id="website_sale.size1x2" model="website.product.style">
+ <field name="name">Size 1x2</field>
+ <field name="html_class">Size_1x2</field>
+ </record>
+ <record id="website_sale.size1x3" model="website.product.style">
+ <field name="name">Size 1x3</field>
+ <field name="html_class">Size_1x3</field>
+ </record>
+ <record id="website_sale.size2x2" model="website.product.style">
+ <field name="name">Size 2x2</field>
+ <field name="html_class">Size_2x2</field>
+ </record>
+ <record id="website_sale.size2x3" model="website.product.style">
+ <field name="name">Size 2x3</field>
+ <field name="html_class">Size_2x3</field>
+ </record>
+ <record id="website_sale.size3x2" model="website.product.style">
+ <field name="name">Size 3x2</field>
+ <field name="html_class">Size_3x2</field>
+ </record>
+ <record id="website_sale.size3x3" model="website.product.style">
+ <field name="name">Size 3x3</field>
+ <field name="html_class">Size_3x3</field>
+ </record>
+ <record id="website_sale.size4x1" model="website.product.style">
+ <field name="name">Size 4x1</field>
+ <field name="html_class">Size_4x1</field>
+ </record>
+ <record id="website_sale.size4x2" model="website.product.style">
+ <field name="name">Size 4x2</field>
+ <field name="html_class">Size_4x2</field>
+ </record>
+ <record id="website_sale.size4x3" model="website.product.style">
+ <field name="name">Size 4x3</field>
+ <field name="html_class">Size_4x3</field>
+ </record>
+
</data>
</openerp>
diff --git a/addons/website_sale/website_sale_demo.xml b/addons/website_sale/website_sale_demo.xml
index c2e24359d4f..bf0edd63cd6 100644
--- a/addons/website_sale/website_sale_demo.xml
+++ b/addons/website_sale/website_sale_demo.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
- <data noupdate="0">
+ <data noupdate="1">
<record id="product.product_product_consultant" model="product.product">
<field name="image" file="website/static/description/website_edit.png"/>
@@ -8,9 +8,7 @@
<record id="product.product_product_4" model="product.product">
<field name="website_published" eval="True"/>
- <field name="website_product_class">oe_image_full</field>
- <field name="website_sizex">6</field>
- <field name="website_sizey">4</field>
+ <field name="website_style_ids" eval="[(6,0,[ref('website_sale.size2x2')])]"/>
<field name="website_description" type="html">
<section snippet-id="text-image" class="mt16 mb16 dark">
<div class="container">
@@ -59,11 +57,11 @@
</record>
<record id="product.product_product_5" model="product.product">
<field name="website_published" eval="True"/>
- <field name="website_sizex">6</field>
+ <field name="website_style_ids" eval="[(6,0,[ref('website_sale.size2x1')])]"/>
</record>
<record id="product.product_product_6" model="product.product">
<field name="website_published" eval="True"/>
- <field name="website_product_class">oe_image_full</field>
+ <field name="website_style_ids" eval="[(6,0,[ref('website_sale.image_full')])]"/>
</record>
<record id="product.product_product_7" model="product.product">
<field name="website_published" eval="True"/>
@@ -76,7 +74,7 @@
</record>
<record id="product.product_product_11" model="product.product">
<field name="website_published" eval="True"/>
+ <field name="website_style_ids" eval="[(6,0,[ref('website_sale.size1x2')])]"/>
</record>
-
</data>
</openerp>
diff --git a/addons/website_sale/website_styles.py b/addons/website_sale/website_styles.py
new file mode 100644
index 00000000000..0b5ee5aad1d
--- /dev/null
+++ b/addons/website_sale/website_styles.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import osv, fields
+
+
+class website_product_style(osv.Model):
+ _name = "website.product.style"
+ _columns = {
+ 'name' : fields.char('Style Name', required=True, translate=True),
+ 'html_class': fields.char('HTML Classes', size=64),
+ }