diff options
| author | Christophe Matthieu <chm@openerp.com> | 2013-09-26 13:23:07 +0200 |
|---|---|---|
| committer | Christophe Matthieu <chm@openerp.com> | 2013-09-26 13:23:07 +0200 |
| commit | f2a97662cd0a256e24c9bf48a44c2295e5d0ff4e (patch) | |
| tree | 4ee4771c57fc6befce3b62200e81648aa53a8ed4 | |
| parent | e7a469f8bc5f4fe8004ebd877da6b8a85dfd0737 (diff) | |
| parent | c66c5d5b6af1d0e7acefd675b5bd03cfce512056 (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
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&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&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 ('&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>&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 ('&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 ('&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>&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 ('&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), + } |
