From b8f1ffaafc55defa079275f691e48ed0288c4546 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Wed, 25 Sep 2013 20:05:38 +0200 Subject: [PATCH 1/6] [IMP] website_sale: bin packing product for sweet layout bzr revid: chm@openerp.com-20130925180538-qnq699csoof8jrt5 --- addons/website_sale/__init__.py | 1 + addons/website_sale/controllers/main.py | 123 +++++++++++++++++- addons/website_sale/product.py | 9 +- .../static/src/css/website_sale.css | 5 + .../static/src/css/website_sale.sass | 4 + addons/website_sale/views/website_sale.xml | 92 ++++++++----- addons/website_sale/website_sale_data.xml | 42 ++++++ addons/website_sale/website_sale_demo.xml | 8 +- addons/website_sale/website_styles.py | 30 +++++ 9 files changed, 262 insertions(+), 52 deletions(-) create mode 100644 addons/website_sale/website_styles.py 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..dea83f8b015 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -68,6 +68,125 @@ class Ecommerce(http.Controller): return (categories, full_category_ids) + def bin_packing_product_ids(self, domain, limit, offset): + product_obj = request.registry.get('product.template') + data_obj = request.registry.get('ir.model.data') + + product_ids = product_obj.search(request.cr, request.uid, domain, limit=limit, offset=offset, 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, {})) >= 4: + line += 1 + continue + + col = 0 + while col < 4: + if bin_packing[line].get(col, None) != None: + col += 1 + continue + + insert = True + + copy_line = line + copy_y = y + while copy_y > 0: + # check if the box can be inserted + copy_col = col + copy_x = x + while copy_x > 0: + if copy_col >= 4 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 + + 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 + + + # complete empty cell and packaging in list (from dict) + nb_empty = 0 + line = 0 + length = len(bin_packing) + while line < length: + col = 0 + while col < 4: + if bin_packing[line].get(col) == None: + nb_empty += 1 + col += 1 + line += 1 + + products = [] + if nb_empty: + product_ids = product_obj.search(request.cr, request.uid, domain, limit=nb_empty, offset=offset+limit, context=request.context) + if product_ids: + for product in product_obj.browse(request.cr, SUPERUSER_ID, product_ids, context=request.context): + products.append(product) + products.reverse() + + bin_packing_list = [] + line = 0 + while line < length: + bin_packing_list.append([]) + col = 0 + while col < 4: + if products and bin_packing[line].get(col) == None: + bin_packing[line][col] = {'product': products.pop(), 'x': 1, 'y': 1, 'class': _class } + bin_packing_list[line].append(bin_packing[line].get(col, False)) + col += 1 + line += 1 + return bin_packing_list + @website.route(['/shop/', '/shop/category//', '/shop/category//page//', '/shop/page//'], type='http', auth="public") def category(self, cat_id=0, page=0, **post): @@ -92,14 +211,12 @@ 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() values = { 'get_categories': self.get_categories, 'category_id': cat_id, - 'products': product_obj.browse(request.cr, SUPERUSER_ID, product_ids, context=request.context), + 'table_products': self.bin_packing_product_ids(domain, limit=step, offset=pager['offset']), 'search': post.get("search"), 'pager': pager, } diff --git a/addons/website_sale/product.py b/addons/website_sale/product.py index 06c53c0af1d..ebd5057117f 100644 --- a/addons/website_sale/product.py +++ b/addons/website_sale/product.py @@ -37,14 +37,7 @@ 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'), - } - _defaults = { - 'website_sizex': '3', - 'website_sizey': '2', - 'website_product_class': '', + 'website_style_ids' : fields.many2many('website.product.style','product_website_style_rel', 'product_id', 'style_id', 'Styles'), } def recommended_products(self, cr, uid, ids, context=None): 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/views/website_sale.xml b/addons/website_sale/views/website_sale.xml index b8c513432d5..a9cf7029516 100644 --- a/addons/website_sale/views/website_sale.xml +++ b/addons/website_sale/views/website_sale.xml @@ -81,6 +81,35 @@ + +