[IMP] website_sale: confirm/options dialog box have same layout of my cart
authorChristophe Matthieu <chm@odoo.com>
Fri, 13 Jun 2014 10:31:41 +0000 (12:31 +0200)
committerChristophe Matthieu <chm@odoo.com>
Fri, 13 Jun 2014 10:31:41 +0000 (12:31 +0200)
addons/website_sale/controllers/main.py
addons/website_sale/static/src/css/website_sale.css
addons/website_sale/static/src/css/website_sale.sass
addons/website_sale/static/src/js/website_sale.js
addons/website_sale/views/templates.xml

index 9f00059..a3c686a 100644 (file)
@@ -90,6 +90,7 @@ class QueryURL(object):
         for k,v in kw.items():
             if v:
                 if isinstance(v, list) or isinstance(v, set):
+                    print k, v
                     l.append(werkzeug.url_encode([(k,i) for i in v]))
                 else:
                     l.append(werkzeug.url_encode([(k,v)]))
@@ -126,6 +127,8 @@ class website_sale(http.Controller):
             domain += [('product_variant_ids.public_categ_ids', 'child_of', int(category))]
 
         attrib_values = [map(int,v.split(",")) for v in request.httprequest.args.getlist('attrib') if v]
+        attrib_set = set([v[1] for v in attrib_values])
+
         if attrib_values:
             attrib = None
             ids = []
@@ -142,8 +145,8 @@ class website_sale(http.Controller):
             if attrib:
                 domain += [('attribute_line_ids.value_ids', 'in', ids)]
 
-        attrib_set = set([v[1] for v in attrib_values])
-        keep = QueryURL('/shop', category=category and int(category), search=search, attrib=attrib_set)
+        attrib_query = set(["%s,%s" % (v[0],v[1]) for v in attrib_values])
+        keep = QueryURL('/shop', category=category and int(category), search=search, attrib=attrib_query)
 
         if not context.get('pricelist'):
             context['pricelist'] = int(self.get_pricelist())
@@ -201,7 +204,8 @@ class website_sale(http.Controller):
         attrib_values = [map(int,v.split(",")) for v in request.httprequest.args.getlist('attrib') if v]
         attrib_set = set([v[1] for v in attrib_values])
 
-        keep = QueryURL('/shop', category=category and category.id, search=search, attrib=attrib_set)
+        attrib_query = set(["%s,%s" % (v[0],v[1]) for v in attrib_values])
+        keep = QueryURL('/shop', category=category and category.id, search=search, attrib=attrib_query)
 
         category_ids = category_obj.search(cr, uid, [], context=context)
         category_list = category_obj.name_get(cr, uid, category_ids, context=context)
@@ -260,12 +264,25 @@ class website_sale(http.Controller):
         return request.website.render("website_sale.cart", values)
 
     @http.route(['/shop/cart/update'], type='http', auth="public", methods=['POST'], website=True)
-    def cart_update(self, product_id, add_qty=1, set_qty=0, **kw):
+    def cart_update(self, product_id, add_qty=1, set_qty=0, goto_shop=None, **kw):
         cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
         order = request.website.sale_get_order(force_create=1)
         if add_qty or set_qty:
             order._cart_update(product_id=int(product_id), add_qty=int(add_qty), set_qty=int(set_qty))
-        return request.redirect("/shop/cart")
+        if goto_shop:
+            path = "/shop"
+            l = list()
+            for k,v in kw.items():
+                if v and k in ["category", "search", "attrib"]:
+                    if isinstance(v, list) or isinstance(v, set):
+                        l.append(werkzeug.url_encode([(k,i) for i in v]))
+                    else:
+                        l.append(werkzeug.url_encode([(k,v)]))
+            if l:
+                path += '?' + '&'.join(l)
+            return request.redirect(path)
+        else:
+            return request.redirect("/shop/cart")
 
     @http.route(['/shop/cart/update_json'], type='json', auth="public", methods=['POST'], website=True)
     def cart_update_json(self, product_id, line_id, add_qty=None, set_qty=None, display=True):
index 232872f..cff966f 100644 (file)
   display: none;
 }
 
-.css_not_available .row > div:nth-child(3), .css_not_available .row > div:nth-child(4) {
+.css_not_available.js_product > *:nth-child(3) > *, .css_not_available.js_product *:nth-child(4) > * {
   display: none;
 }
-.css_not_available .row > div:last-child {
-  display: block;
-}
-.css_not_available .product_price {
+.css_not_available.js_product .product_price {
   display: none;
 }
-.css_not_available .css_not_available_msg {
+.css_not_available.js_product .css_not_available_msg {
   display: block;
 }
 
index bb6a329..09bcbad 100644 (file)
 
 .css_not_available_msg
     display: none
-.css_not_available
-    .row
-        > div:nth-child(3), > div:nth-child(4)
-            display: none
-        > div:last-child
-            display: block
+.css_not_available.js_product
+    > *:nth-child(3) > *, *:nth-child(4) > *
+        display: none
     .product_price
         display: none
     .css_not_available_msg
index 149b54d..978ee10 100644 (file)
@@ -123,24 +123,39 @@ $(document).ready(function () {
         $('input.js_variant_change, select.js_variant_change', this).first().trigger('change');
     });
 
+
+    $("a.js_add, a.js_remove").click(function (event) {
+        event.preventDefault();
+        var $parent = $(this).parents('.js_product:first');
+        $parent.find("a.js_add, span.js_remove").toggleClass("hidden");
+        $parent.find("input.js_optional_same_quantity").val( $(this).hasClass("js_add") ? 1 : 0 );
+    });
+
     $('#product_detail form[action^="/shop/cart/update"] .a-submit').off("click").click(function (event) {
         event.preventDefault();
         var $link = $(this);
         var $form = $link.parents("form:first");
+        var quantity = parseInt($('input[name="add_qty"]').val() || 1, 10);
         var defs = [];
         $link.attr('disabled', 'disabled');
         $('.js_product', $form).each(function () {
             var product_id = parseInt($('input.optional_product_id', this).val(),10);
-            var quantity = parseInt($('input.js_quantity', this).val(),10);
-            if (product_id && quantity) {
+            var qty = parseInt($('input.js_quantity', this).val(),10);
+            if($('input.js_optional_same_quantity', this).val() !== '0') {
+                qty = quantity;
+            }
+            if (product_id && qty) {
                 defs.push(openerp.jsonRpc("/shop/cart/update_json", 'call', {
                     'line_id': null,
                     'product_id': product_id,
-                    'add_qty': quantity,
+                    'add_qty': qty,
                     'display': false}));
             }
         });
         $.when.apply($.when, defs).then(function () {
+            if ($link.hasClass("js_goto_shop")) {
+                $form.prepend('<input type="hidden" name="goto_shop" value="1"/>');
+            }
             $form.submit();
         });
         return false;
index 1483482..4a1a2f4 100644 (file)
             </div><div class="col-sm-5 col-md-5 col-lg-4 col-lg-offset-1">
                 <h1 itemprop="name" t-field="product.name">Product Name</h1>
                 <span itemprop="url" style="display:none;" t-esc="'/shop/product/%s' % slug(product)"/>
-                <form action="/shop/cart/update" class="js_add_cart_json" method="POST">
-                    <input type="hidden" t-if="len(product.product_variant_ids) == 1" name="product_id" t-att-value="product.product_variant_ids[0].id"/>
-                    <t t-if="len(product.product_variant_ids) &gt; 1">
-                        <label label-default="label-default" class="radio" t-foreach="product.product_variant_ids" t-as="variant_id">
-                            <input type="radio" name="product_id" t-att-value="variant_id.id"/>
-                            <span t-esc="variant_id.name_get()[0][1]"/>
-                            <span class="badge" t-if="variant_id.price_extra">
-                                <t t-esc="variant_id.price_extra > 0 and '+' or ''"/><span t-field="variant_id.price_extra" t-field-options='{ "widget": "monetary", "display_currency": "pricelist.currency_id" }'/>
-                            </span>
-                        </label>
+
+                <form t-att-action="keep('/shop/cart/update')" class="js_add_cart_variants" method="POST">
+
+                  <div class="js_product">
+                    <t t-placeholder="select">
+                      <input type="hidden" class="product_id" name="product_id" t-att-value="int(product.product_variant_ids[0]) if len(product.product_variant_ids) == 1 else '0'"/>
+                      <t t-call="website_sale.variants">
+                        <t t-set="ul_class" t-value="'nav-stacked'"/>
+                      </t>
                     </t>
 
                     <t t-call="website_sale.product_price"/>
+                    <p t-if="len(product.product_variant_ids) > 1" class="css_not_available_msg bg-danger" style="padding: 15px;">Product not available</p>
 
-                    <t t-name="button">
+                    <t t-placeholder="button">
                       <a t-if="not optional_product_ids" class="btn btn-primary btn-lg mt8 a-submit js_check_product">Add to Cart</a>
                       <a t-if="optional_product_ids" class="btn btn-primary btn-lg mt8 js_check_product" href="#" data-toggle="modal" data-target="#modal_optional_products">Add to Cart</a>
-
-                      <t t-if="optional_products">
-                        <t t-call="website_sale.product_modal_optional_products"/>
-                      </t>
                     </t>
+                  </div>
+
+                  <div t-if="optional_product_ids" id="modal_optional_products" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+                    <div class="modal-dialog modal-lg">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
+                          <h4 class="modal-title" id="myModalLabel">Product to add in your shopping cart</h4>
+                        </div>
+                        <div class="modal-body">
+
+                          <table class="table table-striped table-condensed">
+                            <thead>
+                                <tr>
+                                    <th colspan="2" width="100">Product</th>
+                                    <th width="100">Price</th>
+                                    <th width="120">Quantity</th>
+                                </tr>
+                            </thead>
+                            <tbody>
+                                <t t-set="option_inc" t-value="0"/>
+                                <tr class="js_product" t-foreach="optional_product_ids" t-as="product">
+                                  <td width="100">
+                                    <input type="hidden" class="optional_product_id" t-attf-name="optional-product-#{option_inc}" t-att-value="int(product.product_variant_ids[0]) if len(product.product_variant_ids) == 1 else '0'"/>
+                                    <span t-field="product.image_small" t-field-options='{"widget": "image"}'/>
+                                  </td>
+                                  <td>
+                                    <div class="pull-left">
+                                      <strong class="media-heading" t-field="product.name"/>
+                                      <div class="text-muted" t-field="product.description_sale"/>
+                                    </div>
+                                    <div class="pull-right">
+                                      <t t-call="website_sale.variants"/>
+                                    </div>
+                                  </td>
+                                  <td>
+                                    <t t-if="product.lst_price != product.price">
+                                    <span class="text-danger" style="text-decoration: line-through;"
+                                      t-field="product.lst_price"
+                                      t-field-options='{
+                                         "widget": "monetary",
+                                         "display_currency": "website.pricelist_id.currency_id"
+                                     }'/><br/>
+                                    </t>
+                                    <span class="oe_price"
+                                      t-field="product.price"
+                                      t-field-options='{
+                                         "widget": "monetary",
+                                         "display_currency": "website.pricelist_id.currency_id"
+                                     }'/>
+                                    <p class="css_not_available_msg bg-danger" style="position:absolute; padding: 15px;">Product not available</p>
+                                  </td>
+                                  <td>
+                                    <input type="hidden" class="js_optional_same_quantity" value="0"/>
+                                    <input type="hidden" class="js_quantity" t-attf-name="optional-quantity-#{option_inc}" value="0"/>
+                                    <a href="#" class="js_add"><strong>Add to Cart</strong></a>
+                                    <span class="js_remove hidden">
+                                      Will be add to your cart<br/>
+                                      <a href="#" class="js_remove"><small>Cancel</small></a>
+                                    </span>
+                                  </td>
+                                </tr>
+                            </tbody>
+                          </table>
+                        <!-- 
+                          <div class="js_product" t-foreach="optional_product_ids" t-as="product">
+                            <strong class="media-heading" t-field="product.name"/>
+                            <div class="row">
+                              <div class="col-xs-2">
+                                <span t-field="product.image_small" t-field-options='{"widget": "image"}'/>
+                              </div>
+                              <div class="col-xs-6">
+                                <input type="hidden" class="optional_product_id" t-attf-name="optional-product-#{option_inc}" t-att-value="int(product.product_variant_ids[0]) if len(product.product_variant_ids) == 1 else '0'"/>
+                                <t t-call="website_sale.variants"/>
+                              </div>
+                              <div class="col-xs-2">
+                                <strong>Price</strong><br/>
+                                <t t-if="product.lst_price != product.price">
+                                <span class="text-danger" style="text-decoration: line-through;"
+                                  t-field="product.lst_price"
+                                  t-field-options='{
+                                     "widget": "monetary",
+                                     "display_currency": "website.pricelist_id.currency_id"
+                                 }'/><br/>
+                                </t>
+                                <span class="oe_price"
+                                  t-field="product.price"
+                                  t-field-options='{
+                                     "widget": "monetary",
+                                     "display_currency": "website.pricelist_id.currency_id"
+                                 }'/>
+                              </div>
+                              <div class="col-xs-2">
+                                <strong>Number</strong><br/>
+                                <div class="input-group">
+                                    <span class="input-group-addon">
+                                        <a t-attf-href="#" class="mb8 js_add_cart_json">
+                                            <i class="fa fa-minus"></i>
+                                        </a>
+                                    </span>
+                                    <input type="text" class="js_quantity form-control" t-attf-name="optional-quantity-#{option_inc}" value="0"/>
+                                    <span class="input-group-addon">
+                                        <a t-attf-href="#" class="mb8 float_left js_add_cart_json">
+                                            <i class="fa fa-plus"></i>
+                                        </a>
+                                    </span>
+                                </div>
+                              </div>
+                              <div class="col-xs-4">
+                                <p class="css_not_available_msg bg-danger" style="padding: 15px;">Product not available</p>
+                              </div>
+                            </div>
+                          </div> -->
+
+                        </div>
+                        <div class="modal-footer">
+                          <a class="btn btn-default a-submit js_goto_shop"><i class="fa fa-chevron-left"></i> Continue shopping</a>
+                          <a class="btn btn-primary pull-right a-submit"><i class="fa fa-shopping-cart fa-fw"></i> Proceed to checkout</a>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+
                 </form>
 
                 <hr t-if="product.description_sale"/>
   </t>
 </template>
 
-<template id="product_preview" inherit_id="website_sale.product" optional="enabled" name="Product Preview">
-  <xpath expr="//t[@t-name='button']" position="replace">
-    <a t-if="optional_products" class="btn btn-primary btn-lg mt8 js_check_product" href="#" data-toggle="modal" data-target="#modal_optional_products">Add to Cart</a>
-    
-    <t t-call="website_sale.product_modal_optional_products"/>
+<template id="product_confirmation" inherit_id="website_sale.product" optional="enabled" name="Confirm: Add To Cart">
+  <xpath expr="//div[@id='modal_optional_products']" position="attributes">
+    <attribute name="t-if">True</attribute>
   </xpath>
-</template>
-
-<template id="product_modal_optional_products">
-  <div id="modal_optional_products" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
-    <div class="modal-dialog modal-lg">
-      <div class="modal-content">
-        <div class="modal-header">
-          <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
-          <h4 class="modal-title" id="myModalLabel">Product to add to your shopping cart</h4>
-        </div>
-        <div class="modal-body">
-          <div class="row">
-              <div class="col-xs-2">
-                <strong t-field="product.name"/>
-                <span t-field="product.image_medium" t-field-options='{"widget": "image", "class": "img-rounded shadow" }'/>
-              </div>
-              <div class="col-xs-6">
-              </div>
-              <div class="col-xs-2">
-                <strong>Price</strong><br/>
-                <t t-if="product.lst_price != product.price">
-                <span class="text-danger" style="text-decoration: line-through;"
-                  t-field="product.lst_price"
-                  t-field-options='{
-                     "widget": "monetary",
-                     "display_currency": "website.pricelist_id.currency_id"
-                 }'/><br/>
-                </t>
-                <span class="oe_price"
-                  t-field="product.price"
-                  t-field-options='{
-                     "widget": "monetary",
-                     "display_currency": "website.pricelist_id.currency_id"
-                 }'/>
-              </div>
-              <div class="col-xs-2">
-                <strong>Number</strong><br/>
-                <div class="input-group">
-                    <span class="input-group-addon">
-                        <a t-attf-href="#" class="mb8 js_add_cart_json">
-                            <i class="fa fa-minus"></i>
-                        </a>
-                    </span>
-                    <input type="text" class="js_quantity form-control" name="add_qty" value="1"/>
-                    <span class="input-group-addon">
-                        <a t-attf-href="#" class="mb8 float_left js_add_cart_json">
-                            <i class="fa fa-plus"></i>
-                        </a>
-                    </span>
-                </div>
-              </div>
-          </div>
-          <hr/>
-
-          <t t-set="option_inc" t-value="0"/>
-          <div class="js_product" t-foreach="optional_product_ids" t-as="product">
-            <strong class="media-heading" t-field="product.name"/>
-            <div class="row">
-              <div class="col-xs-2">
-                <span t-field="product.image_small" t-field-options='{"widget": "image", "class": "img-rounded shadow" }'/>
-              </div>
-              <div class="col-xs-6">
-                <input type="hidden" class="optional_product_id" t-attf-name="optional-product-#{option_inc}" t-att-value="int(product.product_variant_ids[0]) if len(product.product_variant_ids) == 1 else '0'"/>
-                <t t-call="website_sale.variants"/>
-              </div>
-              <div class="col-xs-2">
-                <strong>Price</strong><br/>
-                <t t-if="product.lst_price != product.price">
-                <span class="text-danger" style="text-decoration: line-through;"
-                  t-field="product.lst_price"
-                  t-field-options='{
-                     "widget": "monetary",
-                     "display_currency": "website.pricelist_id.currency_id"
-                 }'/><br/>
-                </t>
-                <span class="oe_price"
-                  t-field="product.price"
-                  t-field-options='{
-                     "widget": "monetary",
-                     "display_currency": "website.pricelist_id.currency_id"
-                 }'/>
-              </div>
-              <div class="col-xs-2">
-                <strong>Number</strong><br/>
-                <div class="input-group">
-                    <span class="input-group-addon">
-                        <a t-attf-href="#" class="mb8 js_add_cart_json">
-                            <i class="fa fa-minus"></i>
-                        </a>
-                    </span>
-                    <input type="text" class="js_quantity form-control" t-attf-name="optional-quantity-#{option_inc}" value="0"/>
-                    <span class="input-group-addon">
-                        <a t-attf-href="#" class="mb8 float_left js_add_cart_json">
-                            <i class="fa fa-plus"></i>
-                        </a>
-                    </span>
-                </div>
-              </div>
-              <div class="col-xs-4">
-                <p class="css_not_available_msg bg-danger" style="padding: 15px;">Product not available</p>
-              </div>
-            </div>
-          </div>
-
-        </div>
-        <div class="modal-footer">
-          <a class="btn btn-primary a-submit">Continue</a>
-          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
+  <xpath expr="//t[@t-placeholder='button']" position="replace">
+    <a class="btn btn-primary btn-lg mt8 js_check_product" href="#" data-toggle="modal" data-target="#modal_optional_products">Add to Cart</a>
+  </xpath>
+  <xpath expr="//t[@t-set='option_inc'][@t-value='0']" position="before">
+    <tr>
+      <td width="100">
+        <span t-field="product.image_medium" t-field-options='{"widget": "image" }'/>
+      </td>
+      <td>
+        <strong t-field="product.name"/>
+        <div class="text-muted" t-field="product.description_sale"/>
+      </td>
+      <td>
+        <t t-if="product.lst_price != product.price">
+        <span class="text-danger" style="text-decoration: line-through;"
+          t-field="product.lst_price"
+          t-field-options='{
+             "widget": "monetary",
+             "display_currency": "website.pricelist_id.currency_id"
+         }'/><br/>
+        </t>
+        <span class="oe_price"
+          t-field="product.price"
+          t-field-options='{
+             "widget": "monetary",
+             "display_currency": "website.pricelist_id.currency_id"
+         }'/>
+      </td>
+      <td>
+        <div class="input-group">
+            <span class="input-group-addon">
+                <a t-attf-href="#" class="mb8 js_add_cart_json">
+                    <i class="fa fa-minus"></i>
+                </a>
+            </span>
+            <input type="text" class="js_quantity form-control" name="add_qty" value="1"/>
+            <span class="input-group-addon">
+                <a t-attf-href="#" class="mb8 float_left js_add_cart_json">
+                    <i class="fa fa-plus"></i>
+                </a>
+            </span>
         </div>
-      </div>
-    </div>
-  </div>
+      </td>
+    </tr>
+  </xpath>
 </template>
 
 <template id="product_price">
   </div>
 </template>
 
-<template id="product_variants" inherit_id="website_sale.product" optional="enabled" name="Product Variants">
-  <xpath expr="//form[@action='/shop/cart/update']" position="replace">
-    <form action="/shop/cart/update" class="js_add_cart_variants" method="POST">
-
-        <t t-call="website_sale.product_modal_optional_products"/>
-
-        <div class="js_product">
-          <input type="hidden" class="product_id" name="product_id" t-att-value="int(product.product_variant_ids[0]) if len(product.product_variant_ids) == 1 else '0'"/>
-          <t t-call="website_sale.variants">
-            <t t-set="ul_class" t-value="'nav-stacked'"/>
-          </t>
-
-          <t t-call="website_sale.product_price"/>
-
-          <p class="css_not_available_msg bg-danger" style="padding: 15px;">Product not available</p>
-
-          <a t-if="not optional_product_ids" class="btn btn-primary btn-lg mt8 a-submit js_check_product">Add to Cart</a>
-          <a t-if="optional_product_ids" class="btn btn-primary btn-lg mt8 js_check_product" href="#" data-toggle="modal" data-target="#modal_optional_products">Add to Cart</a>
-        </div>
-    </form>
+<template id="product_variants" inherit_id="website_sale.product" optional="disabled" name="List View of Variants">
+  <xpath expr="//t[@t-placeholder='select']" position="replace">
+    <input type="hidden" t-if="len(product.product_variant_ids) == 1" name="product_id" t-att-value="product.product_variant_ids[0].id"/>
+    <t t-if="len(product.product_variant_ids) &gt; 1">
+      <label label-default="label-default" class="radio" t-foreach="product.product_variant_ids" t-as="variant_id">
+        <input type="radio" name="product_id" t-att-value="variant_id.id"/>
+        <span t-esc="variant_id.name_get()[0][1]"/>
+        <span class="badge" t-if="variant_id.price_extra">
+          <t t-esc="variant_id.price_extra > 0 and '+' or ''"/><span t-field="variant_id.price_extra" t-field-options='{ "widget": "monetary", "display_currency": "pricelist.currency_id" }'/>
+        </span>
+      </label>
+    </t>
   </xpath>
 </template>
 
 <template id="variants">
-  <ul t-attf-class="nav nav-pills js_add_cart_variants #{ul_class}" t-att-data-attribute_value_ids="[[p.id, map(int, p.attribute_value_ids), p.price] for p in product.product_variant_ids]">
+  <ul t-attf-class="list-unstyled js_add_cart_variants #{ul_class}" t-att-data-attribute_value_ids="[[p.id, map(int, p.attribute_value_ids), p.price] for p in product.product_variant_ids]">
     <t t-foreach="product.attribute_line_ids" t-as="variant_id">
       <li t-if="len(variant_id.value_ids) > 1">
 
           </colgroup>
           <thead>
               <tr>
-                  <th colspan="2">Suggested products</th>
+                  <th colspan="4">Suggested products</th>
               </tr>
           </thead>
           <tbody>