[WIP]
This commit is contained in:
parent
204a62499a
commit
7505cce2e9
|
@ -216,7 +216,7 @@ class website_sale(http.Controller):
|
||||||
product = template_obj.browse(cr, uid, int(product), context=context)
|
product = template_obj.browse(cr, uid, int(product), context=context)
|
||||||
|
|
||||||
attribute_value_ids = []
|
attribute_value_ids = []
|
||||||
if request.website.company_pricelist_id.id != context['pricelist']:
|
if request.website.pricelist_id.id != context['pricelist']:
|
||||||
company_currency_id = request.website.company_currency_id.id
|
company_currency_id = request.website.company_currency_id.id
|
||||||
currency_id = self.get_pricelist().currency_id.id
|
currency_id = self.get_pricelist().currency_id.id
|
||||||
for p in product.product_variant_ids:
|
for p in product.product_variant_ids:
|
||||||
|
@ -289,12 +289,11 @@ class website_sale(http.Controller):
|
||||||
@http.route(['/shop/cart/update_json'], type='json', auth="public", methods=['POST'], website=True)
|
@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):
|
def cart_update_json(self, product_id, line_id, add_qty=None, set_qty=None, display=True):
|
||||||
order = request.website.sale_get_order(force_create=1)
|
order = request.website.sale_get_order(force_create=1)
|
||||||
line_id, quantity, option_ids = order._cart_update(product_id=product_id, line_id=line_id, add_qty=add_qty, set_qty=set_qty)
|
line_id, quantity = order._cart_update(product_id=product_id, line_id=line_id, add_qty=add_qty, set_qty=set_qty)
|
||||||
if not display:
|
if not display:
|
||||||
return None
|
return None
|
||||||
return {
|
return {
|
||||||
'quantity': quantity,
|
'quantity': quantity,
|
||||||
'option_ids': option_ids,
|
|
||||||
'cart_quantity': order.cart_quantity,
|
'cart_quantity': order.cart_quantity,
|
||||||
'website_sale.total': request.website._render("website_sale.total", {
|
'website_sale.total': request.website._render("website_sale.total", {
|
||||||
'website_sale_order': request.website.sale_get_order()
|
'website_sale_order': request.website.sale_get_order()
|
||||||
|
|
|
@ -132,7 +132,6 @@ class product_template(osv.Model):
|
||||||
'website_sequence': fields.integer('Sequence', help="Determine the display order in the Website E-commerce"),
|
'website_sequence': fields.integer('Sequence', help="Determine the display order in the Website E-commerce"),
|
||||||
'website_url': fields.function(_website_url, string="Website url", type="char"),
|
'website_url': fields.function(_website_url, string="Website url", type="char"),
|
||||||
'public_categ_ids': fields.many2many('product.public.category', string='Public Category', help="Those categories are used to group similar products for e-commerce."),
|
'public_categ_ids': fields.many2many('product.public.category', string='Public Category', help="Those categories are used to group similar products for e-commerce."),
|
||||||
'optional_product_ids': fields.many2many('product.template','product_optional_rel','src_id','dest_id',string='Optional Products', help="Products to propose when add to cart."),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def _defaults_website_sequence(self, cr, uid, *l, **kwargs):
|
def _defaults_website_sequence(self, cr, uid, *l, **kwargs):
|
||||||
|
|
|
@ -51,18 +51,12 @@ class sale_order(osv.Model):
|
||||||
'order': order
|
'order': order
|
||||||
}
|
}
|
||||||
|
|
||||||
def _cart_find_product_line(self, cr, uid, ids, product_id=None, line_id=None, context=None):
|
def _cart_find_product_line(self, cr, uid, ids, product_id=None, line_id=None, context=None, *args):
|
||||||
for so in self.browse(cr, uid, ids, context=context):
|
for so in self.browse(cr, uid, ids, context=context):
|
||||||
order_line_id = None
|
|
||||||
|
|
||||||
domain = [('order_id', '=', so.id), ('product_id', '=', product_id)]
|
domain = [('order_id', '=', so.id), ('product_id', '=', product_id)]
|
||||||
if line_id:
|
if line_id:
|
||||||
domain += [('id', '=', line_id)]
|
domain += [('id', '=', line_id)]
|
||||||
|
return self.pool.get('sale.order.line').search(cr, SUPERUSER_ID, domain, context=context)
|
||||||
order_line_ids = self.pool.get('sale.order.line').search(cr, SUPERUSER_ID, domain, context=context)
|
|
||||||
if order_line_ids:
|
|
||||||
order_line_id = order_line_ids[0]
|
|
||||||
return order_line_id
|
|
||||||
|
|
||||||
def _website_product_id_change(self, cr, uid, ids, order_id, product_id, line_id=None, context=None):
|
def _website_product_id_change(self, cr, uid, ids, order_id, product_id, line_id=None, context=None):
|
||||||
so = self.pool.get('sale.order').browse(cr, uid, order_id, context=context)
|
so = self.pool.get('sale.order').browse(cr, uid, order_id, context=context)
|
||||||
|
@ -87,13 +81,16 @@ class sale_order(osv.Model):
|
||||||
values['tax_id'] = [(6, 0, values['tax_id'])]
|
values['tax_id'] = [(6, 0, values['tax_id'])]
|
||||||
return values
|
return values
|
||||||
|
|
||||||
def _cart_update(self, cr, uid, ids, product_id=None, line_id=None, add_qty=0, set_qty=0, linked_line_id=None, optional_product_ids=None, context=None):
|
def _cart_update(self, cr, uid, ids, product_id=None, line_id=None, add_qty=0, set_qty=0, context=None, *args):
|
||||||
""" Add or set product quantity, add_qty can be negative """
|
""" Add or set product quantity, add_qty can be negative """
|
||||||
sol = self.pool.get('sale.order.line')
|
sol = self.pool.get('sale.order.line')
|
||||||
|
|
||||||
quantity = 0
|
quantity = 0
|
||||||
for so in self.browse(cr, uid, ids, context=context):
|
for so in self.browse(cr, uid, ids, context=context):
|
||||||
line_id = so._cart_find_product_line(product_id, line_id, context=context)
|
if line_id != False:
|
||||||
|
line_ids = so._cart_find_product_line(product_id, line_id, context=context, *args)
|
||||||
|
if line_ids:
|
||||||
|
line_id = line_ids[0]
|
||||||
|
|
||||||
# Create line if no line with product_id can be located
|
# Create line if no line with product_id can be located
|
||||||
if not line_id:
|
if not line_id:
|
||||||
|
@ -132,9 +129,7 @@ class website(orm.Model):
|
||||||
_columns = {
|
_columns = {
|
||||||
'pricelist_id': fields.related('user_id','partner_id','property_product_pricelist',
|
'pricelist_id': fields.related('user_id','partner_id','property_product_pricelist',
|
||||||
type='many2one', relation='product.pricelist', string='Default pricelist'),
|
type='many2one', relation='product.pricelist', string='Default pricelist'),
|
||||||
'company_pricelist_id': fields.related('company_id','partner_id','property_product_pricelist',
|
'currency_id': fields.related('pricelist_id','currency_id',
|
||||||
type='many2one', relation='product.pricelist', string='Default pricelist'),
|
|
||||||
'company_currency_id': fields.related('company_pricelist_id','currency_id',
|
|
||||||
type='many2one', relation='res.currency', string='Default pricelist'),
|
type='many2one', relation='res.currency', string='Default pricelist'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +225,7 @@ class website(orm.Model):
|
||||||
})
|
})
|
||||||
|
|
||||||
def compute_curency(self, cr, uid, ids, from_amount, from_currency_id=None, context=None):
|
def compute_curency(self, cr, uid, ids, from_amount, from_currency_id=None, context=None):
|
||||||
from_currency_id = from_currency_id or self.browse(cr, SUPERUSER_ID, ids[0]).company_currency_id.id
|
from_currency_id = from_currency_id or self.browse(cr, SUPERUSER_ID, ids[0]).currency_id.id
|
||||||
to_currency_id = self.pool.get("res.users").browse(cr, uid, uid).partner_id.property_product_pricelist.currency_id.id
|
to_currency_id = self.pool.get("res.users").browse(cr, uid, uid).partner_id.property_product_pricelist.currency_id.id
|
||||||
return self.pool['res.currency'].compute(cr, uid, from_currency_id, to_currency_id, from_amount, context=context)
|
return self.pool['res.currency'].compute(cr, uid, from_currency_id, to_currency_id, from_amount, context=context)
|
||||||
|
|
||||||
|
|
|
@ -1,80 +1,5 @@
|
||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
openerp.Tour.register({
|
|
||||||
id: 'shop_customize',
|
|
||||||
name: "Customize the page and search a product",
|
|
||||||
path: '/shop',
|
|
||||||
mode: 'test',
|
|
||||||
steps: [
|
|
||||||
{
|
|
||||||
title: "open customize menu",
|
|
||||||
element: '#customize-menu-button',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "click on 'Product Attribute's Filters'",
|
|
||||||
element: "#customize-menu a:contains(Product Attribute's Filters)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "select product attribute memory 16 Go",
|
|
||||||
waitNot: '#customize-menu:visible',
|
|
||||||
element: 'form.js_attributes label:contains(16 Go) input:not(:checked)',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "check the selection",
|
|
||||||
waitFor: 'form.js_attributes label:contains(16 Go) input:checked',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "select iPod",
|
|
||||||
waitNot: '.oe_website_sale .oe_product_cart:eq(2)',
|
|
||||||
element: '.oe_product_cart a:contains("iPod")',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "open customize menu 2",
|
|
||||||
waitFor: 'form[action^="/shop/cart/update"] label:contains(32 Go) input',
|
|
||||||
element: '#customize-menu-button',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "click on 'Confirm: Add To Cart'",
|
|
||||||
element: "#customize-menu a:contains(Confirm: Add To Cart)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "click on 'Add to Cart' button",
|
|
||||||
waitNot: '#customize-menu:visible',
|
|
||||||
element: "a[data-toggle='modal']:contains(Add to Cart)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "click in modal on 'Proceed to checkout' button",
|
|
||||||
element: '.modal a:contains("Proceed to checkout")',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "return to the iPod product",
|
|
||||||
waitFor: '#cart_products',
|
|
||||||
element: "a:contains(iPod)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "open customize menu 3",
|
|
||||||
waitFor: 'form[action^="/shop/cart/update"] label:contains(32 Go) input',
|
|
||||||
element: '#customize-menu-button',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "click on 'Confirm: Add To Cart'",
|
|
||||||
element: "#customize-menu a:contains(Confirm: Add To Cart)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "click on 'My Cart'",
|
|
||||||
waitFor: "a.a-submit:contains(Add to Cart)",
|
|
||||||
element: "a[href='/shop/cart']",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "remove iPod from cart",
|
|
||||||
element: '#cart_products a.js_add_cart_json:first',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "finish",
|
|
||||||
waitFor: '.my_cart_quantity:contains(1)',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
openerp.Tour.register({
|
openerp.Tour.register({
|
||||||
id: 'shop_buy_product',
|
id: 'shop_buy_product',
|
||||||
|
|
|
@ -85,7 +85,7 @@ $(document).ready(function () {
|
||||||
$('input.js_variant_change, select.js_variant_change').change(function (ev) {
|
$('input.js_variant_change, select.js_variant_change').change(function (ev) {
|
||||||
var $ul = $(this).parents('ul.js_add_cart_variants:first');
|
var $ul = $(this).parents('ul.js_add_cart_variants:first');
|
||||||
var $parent = $ul.parents('.js_product:first');
|
var $parent = $ul.parents('.js_product:first');
|
||||||
var $porduct_id = $parent.find('input.product_id, input.optional_product_id').first();
|
var $product_id = $parent.find('input.product_id').first();
|
||||||
var $price = $parent.find(".oe_price:first .oe_currency_value");
|
var $price = $parent.find(".oe_price:first .oe_currency_value");
|
||||||
var $default_price = $parent.find(".oe_default_price:first .oe_currency_value");
|
var $default_price = $parent.find(".oe_default_price:first .oe_currency_value");
|
||||||
var variant_ids = $ul.data("attribute_value_ids");
|
var variant_ids = $ul.data("attribute_value_ids");
|
||||||
|
@ -127,11 +127,11 @@ $(document).ready(function () {
|
||||||
|
|
||||||
if (product_id) {
|
if (product_id) {
|
||||||
$parent.removeClass("css_not_available");
|
$parent.removeClass("css_not_available");
|
||||||
$porduct_id.val(product_id);
|
$product_id.val(product_id);
|
||||||
$parent.find(".js_check_product").removeAttr("disabled");
|
$parent.find(".js_check_product").removeAttr("disabled");
|
||||||
} else {
|
} else {
|
||||||
$parent.addClass("css_not_available");
|
$parent.addClass("css_not_available");
|
||||||
$porduct_id.val(0);
|
$product_id.val(0);
|
||||||
$parent.find(".js_check_product").attr("disabled", "disabled");
|
$parent.find(".js_check_product").attr("disabled", "disabled");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -139,32 +139,6 @@ $(document).ready(function () {
|
||||||
$('input.js_variant_change, select.js_variant_change', this).first().trigger('change');
|
$('input.js_variant_change, select.js_variant_change', this).first().trigger('change');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#modal_optional_products').on('show.bs.modal', function () {
|
|
||||||
var $confirm = $('#product_confirmation .js_attributes');
|
|
||||||
if (!$confirm.size()) return;
|
|
||||||
$confirm.empty();
|
|
||||||
$('.js_add_cart_variants:first ul:first > li').each(function () {
|
|
||||||
var $li = $(this);
|
|
||||||
var $span = $("<div><span></span>: <span></span></div>");
|
|
||||||
var attr = $li.children().first().text();
|
|
||||||
var value = $li.find("label:has(input:checked) span:first").text();
|
|
||||||
if (!/\S/.test(value)) {
|
|
||||||
value = $li.find("label:has(input:checked) input").attr("title");
|
|
||||||
}
|
|
||||||
$span.children().first().text( attr );
|
|
||||||
$span.children().last().text( value );
|
|
||||||
$confirm.append($span);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("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 );
|
|
||||||
var $remove = $parent.find(".js_remove");
|
|
||||||
});
|
|
||||||
|
|
||||||
$("input.js_quantity").change(function (event) {
|
$("input.js_quantity").change(function (event) {
|
||||||
var qty = parseFloat($(this).val());
|
var qty = parseFloat($(this).val());
|
||||||
if (qty === 1) {
|
if (qty === 1) {
|
||||||
|
|
|
@ -12,7 +12,6 @@ inject = [
|
||||||
class TestUi(openerp.tests.HttpCase):
|
class TestUi(openerp.tests.HttpCase):
|
||||||
def test_01_admin_shop_tour(self):
|
def test_01_admin_shop_tour(self):
|
||||||
self.phantom_js("/", "openerp.Tour.run('shop', 'test')", "openerp.Tour.tours.shop", login="admin")
|
self.phantom_js("/", "openerp.Tour.run('shop', 'test')", "openerp.Tour.tours.shop", login="admin")
|
||||||
self.phantom_js("/", "openerp.Tour.run('shop_customize', 'test')", "openerp.Tour.tours.shop_customize", login="admin", inject=inject)
|
|
||||||
|
|
||||||
def test_02_admin_checkout(self):
|
def test_02_admin_checkout(self):
|
||||||
self.phantom_js("/", "openerp.Tour.run('shop_buy_product', 'test')", "openerp.Tour.tours.shop_buy_product", login="admin", inject=inject)
|
self.phantom_js("/", "openerp.Tour.run('shop_buy_product', 'test')", "openerp.Tour.tours.shop_buy_product", login="admin", inject=inject)
|
||||||
|
|
|
@ -393,79 +393,7 @@
|
||||||
<t t-call="website_sale.product_price"/>
|
<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>
|
<p t-if="len(product.product_variant_ids) > 1" class="css_not_available_msg bg-danger" style="padding: 15px;">Product not available</p>
|
||||||
|
|
||||||
<a class="btn btn-primary btn-lg mt8 js_check_product" href="#" data-toggle="modal" data-target="#modal_optional_products">Add to Cart</a>
|
<a id="add_to_cart" class="btn btn-primary btn-lg mt8 js_check_product a-submit" href="#">Add to Cart</a>
|
||||||
</div>
|
|
||||||
|
|
||||||
<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 in your shopping cart</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<table class="table table-striped table-condensed">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th colspan="2">Product</th>
|
|
||||||
<th style="min-width: 140px;"> </th>
|
|
||||||
<th width="100">Price</th>
|
|
||||||
<th width="120">Quantity</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr id="product_confirmation">
|
|
||||||
<td width="100">
|
|
||||||
<span t-field="product.image_medium" t-field-options='{"widget": "image" }'/>
|
|
||||||
</td>
|
|
||||||
<td colspan="2">
|
|
||||||
<strong t-field="product.name"/>
|
|
||||||
<div class="text-muted">
|
|
||||||
<div t-field="product.description_sale"/>
|
|
||||||
<div class="js_attributes"/>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span t-attf-class="text-danger oe_default_price" t-att-style="'' if (website.compute_curency(product.lst_price) - product.price) > 0.1 else 'display: none;'" style="text-decoration: line-through; white-space: nowrap;"
|
|
||||||
t-field="product.lst_price"
|
|
||||||
t-field-options='{
|
|
||||||
"widget": "monetary",
|
|
||||||
"from_currency": "website.company_currency_id",
|
|
||||||
"display_currency": "user_id.partner_id.property_product_pricelist.currency_id"
|
|
||||||
}'/><br/>
|
|
||||||
<span class="oe_price" style="white-space: nowrap;"
|
|
||||||
t-field="product.price"
|
|
||||||
t-field-options='{
|
|
||||||
"widget": "monetary",
|
|
||||||
"from_currency": "website.company_currency_id",
|
|
||||||
"display_currency": "user_id.partner_id.property_product_pricelist.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" data-min="1" 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>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</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>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
@ -488,7 +416,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template id="product_quantity" inherit_id="website_sale.product" optional="enabled" name="Select Quantity">
|
<template id="product_quantity" inherit_id="website_sale.product" optional="enabled" name="Select Quantity">
|
||||||
<xpath expr="//a[@data-target='#modal_optional_products']" position="before">
|
<xpath expr="//form" position="inside">
|
||||||
<div class="css_quantity input-group" style="width: 108px;">
|
<div class="css_quantity input-group" style="width: 108px;">
|
||||||
<span class="input-group-addon">
|
<span class="input-group-addon">
|
||||||
<a t-attf-href="#" class="mb8 js_add_cart_json">
|
<a t-attf-href="#" class="mb8 js_add_cart_json">
|
||||||
|
|
|
@ -4,7 +4,6 @@ from openerp import SUPERUSER_ID
|
||||||
from openerp.addons.web import http
|
from openerp.addons.web import http
|
||||||
from openerp.addons.web.http import request
|
from openerp.addons.web.http import request
|
||||||
from openerp.addons.website.models.website import slug
|
from openerp.addons.website.models.website import slug
|
||||||
from openerp.addons.website_sale.controllers.main import QueryURL
|
|
||||||
from openerp.addons.website_sale.controllers.main import website_sale
|
from openerp.addons.website_sale.controllers.main import website_sale
|
||||||
|
|
||||||
class website_sale_options(website_sale):
|
class website_sale_options(website_sale):
|
||||||
|
@ -23,11 +22,12 @@ class website_sale_options(website_sale):
|
||||||
r.qcontext['optional_product_ids'] = optional_product_ids
|
r.qcontext['optional_product_ids'] = optional_product_ids
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def cart_update(self, product_id, add_qty=1, set_qty=0, goto_shop=None, **kw):
|
@http.route(['/shop/cart/update_option_json'], type='json', auth="public", methods=['POST'], website=True)
|
||||||
|
def cart_options_update_json(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
|
cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
|
||||||
order = request.website.sale_get_order(force_create=1)
|
order = request.website.sale_get_order(force_create=1)
|
||||||
prod_obj = pool['product.product']
|
|
||||||
|
|
||||||
|
line_id = None
|
||||||
optional_product_ids = []
|
optional_product_ids = []
|
||||||
for k, v in kw.items():
|
for k, v in kw.items():
|
||||||
if "optional-product-" in k and int(kw.get(k.replace("product", "quantity"))):
|
if "optional-product-" in k and int(kw.get(k.replace("product", "quantity"))):
|
||||||
|
@ -36,11 +36,16 @@ class website_sale_options(website_sale):
|
||||||
line_id, quantity = order._cart_update(product_id=int(product_id),
|
line_id, quantity = order._cart_update(product_id=int(product_id),
|
||||||
add_qty=int(add_qty), set_qty=int(set_qty),
|
add_qty=int(add_qty), set_qty=int(set_qty),
|
||||||
optional_product_ids=optional_product_ids)
|
optional_product_ids=optional_product_ids)
|
||||||
|
|
||||||
# options have all time the same quantity
|
# options have all time the same quantity
|
||||||
for option_id in optional_product_ids:
|
for option_id in optional_product_ids:
|
||||||
order._cart_update(product_id=option_id, set_qty=value.get('quantity'), linked_line_id=value.get('line_id'))
|
order._cart_update(product_id=option_id, set_qty=quantity, linked_line_id=line_id)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'quantity': quantity,
|
||||||
|
'cart_quantity': order.cart_quantity,
|
||||||
|
'website_sale.total': request.website._render("website_sale.total", {
|
||||||
|
'website_sale_order': request.website.sale_get_order()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if goto_shop:
|
|
||||||
return request.redirect("/shop/product/%s" % slug(prod_obj.browse(cr, uid, product_id).product_tmpl_id))
|
|
||||||
else:
|
|
||||||
return request.redirect("/shop/cart")
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
import product
|
||||||
import sale_order
|
import sale_order
|
|
@ -0,0 +1,10 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from openerp import tools
|
||||||
|
from openerp.osv import osv, fields
|
||||||
|
|
||||||
|
class product_template(osv.Model):
|
||||||
|
_inherit = "product.template"
|
||||||
|
|
||||||
|
_columns = {
|
||||||
|
'optional_product_ids': fields.many2many('product.template','product_optional_rel','src_id','dest_id',string='Optional Products', help="Products to propose when add to cart."),
|
||||||
|
}
|
|
@ -2,17 +2,19 @@
|
||||||
|
|
||||||
from openerp import SUPERUSER_ID
|
from openerp import SUPERUSER_ID
|
||||||
from openerp.osv import osv, orm, fields
|
from openerp.osv import osv, orm, fields
|
||||||
from openerp.addons.web.http import request
|
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
|
|
||||||
class sale_order(osv.Model):
|
class sale_order(osv.Model):
|
||||||
_inherit = "sale.order"
|
_inherit = "sale.order"
|
||||||
|
|
||||||
def _cart_find_product_line(self, cr, uid, ids, product_id=None, line_id=None, linked_line_id=None, optional_product_ids=None, context=None):
|
def _cart_find_product_line(self, cr, uid, ids, product_id=None, line_id=None, context=None, *args):
|
||||||
for so in self.browse(cr, uid, ids, context=context):
|
line_ids = super(sale_order, self)._cart_find_product_line(cr, uid, ids, product_id, line_id, context=context)
|
||||||
|
linked_line_id = args.get('linked_line_id')
|
||||||
|
optional_product_ids = args.get('optional_product_ids')
|
||||||
|
|
||||||
domain = [('order_id', '=', so.id), ('product_id', '=', product_id)]
|
for so in self.browse(cr, uid, ids, context=context):
|
||||||
|
domain = [('order_id', '=', so.id), ('product_id', '=', product_id), ('id', 'in', line_ids)]
|
||||||
if line_id:
|
if line_id:
|
||||||
domain += [('id', '=', line_id)]
|
domain += [('id', '=', line_id)]
|
||||||
domain += linked_line_id and [('linked_line_id', '=', linked_line_id)] or [('linked_line_id', '=', False)]
|
domain += linked_line_id and [('linked_line_id', '=', linked_line_id)] or [('linked_line_id', '=', False)]
|
||||||
|
@ -22,51 +24,35 @@ class sale_order(osv.Model):
|
||||||
else:
|
else:
|
||||||
domain += [('option_line_ids', '=', False)]
|
domain += [('option_line_ids', '=', False)]
|
||||||
|
|
||||||
order_line_id = None
|
return self.pool.get('sale.order.line').search(cr, SUPERUSER_ID, domain, context=context)
|
||||||
order_line_ids = self.pool.get('sale.order.line').search(cr, SUPERUSER_ID, domain, context=context)
|
|
||||||
if order_line_ids:
|
|
||||||
order_line_id = order_line_ids[0]
|
|
||||||
return order_line_id
|
|
||||||
|
|
||||||
def _cart_update(self, cr, uid, ids, product_id=None, line_id=None, add_qty=0, set_qty=0, linked_line_id=None, optional_product_ids=None, context=None):
|
def _cart_update(self, cr, uid, ids, product_id=None, line_id=None, add_qty=0, set_qty=0, context=None, *args):
|
||||||
""" Add or set product quantity, add_qty can be negative """
|
""" Add or set product quantity, add_qty can be negative """
|
||||||
|
line_id, quantity = super(sale_order, self)._cart_update(cr, uid, ids, product_id, line_id, add_qty, set_qty, context=context, *args)
|
||||||
|
linked_line_id = args.get('linked_line_id')
|
||||||
sol = self.pool.get('sale.order.line')
|
sol = self.pool.get('sale.order.line')
|
||||||
|
|
||||||
quantity = 0
|
|
||||||
for so in self.browse(cr, uid, ids, context=context):
|
for so in self.browse(cr, uid, ids, context=context):
|
||||||
line_id = so._cart_find_product_line(product_id, line_id, linked_line_id, optional_product_ids, context=context)
|
values = {}
|
||||||
|
|
||||||
# Create line if no line with product_id can be located
|
if linked_line_id and linked_line_id in map(int,so.order_line):
|
||||||
if not line_id:
|
linked = sol.browse(cr, SUPERUSER_ID, linked_line_id, context=context)
|
||||||
values = self._website_product_id_change(cr, uid, ids, so.id, product_id, context=context)
|
sol.write(cr, SUPERUSER_ID, [line_id], {
|
||||||
if linked_line_id and linked_line_id in map(int,so.order_line):
|
"name": _("%s\nOption for: %s") % (values["name"], linked.product_id.name_get()[0][1]),
|
||||||
values["linked_line_id"] = linked_line_id
|
"linked_line_id": linked_line_id
|
||||||
linked = sol.browse(cr, SUPERUSER_ID, linked_line_id, context=context)
|
}, context=context)
|
||||||
values["name"] = _("%s\nLinked to: %s") % (values["name"], linked.product_id.name_get()[0][1])
|
|
||||||
line_id = sol.create(cr, SUPERUSER_ID, values, context=context)
|
|
||||||
if add_qty:
|
|
||||||
add_qty -= 1
|
|
||||||
|
|
||||||
# compute new quantity
|
|
||||||
if set_qty:
|
|
||||||
quantity = set_qty
|
|
||||||
elif add_qty != None:
|
|
||||||
quantity = sol.browse(cr, SUPERUSER_ID, line_id, context=context).product_uom_qty + (add_qty or 0)
|
|
||||||
|
|
||||||
# select linked product
|
# select linked product
|
||||||
option_ids = [line.id for line in so.order_line if line.linked_line_id.id == line_id]
|
option_ids = [line.id for line in so.order_line if line.linked_line_id.id == line_id]
|
||||||
|
|
||||||
# Remove zero of negative lines
|
if option_ids:
|
||||||
if quantity <= 0:
|
# Remove zero of negative lines
|
||||||
sol.unlink(cr, SUPERUSER_ID, [line_id] + option_ids, context=context)
|
if quantity <= 0:
|
||||||
else:
|
sol.unlink(cr, SUPERUSER_ID, option_ids, context=context)
|
||||||
# update line
|
else:
|
||||||
values = self._website_product_id_change(cr, uid, ids, so.id, product_id, line_id, context=context)
|
# update line
|
||||||
values['product_uom_qty'] = quantity
|
sol.write(cr, SUPERUSER_ID, option_ids, {
|
||||||
sol.write(cr, SUPERUSER_ID, [line_id], values, context=context)
|
'product_uom_qty': quantity
|
||||||
|
}, context=context)
|
||||||
# change quantity of linked product
|
|
||||||
if option_ids:
|
|
||||||
sol.write(cr, SUPERUSER_ID, option_ids, {'product_uom_qty': quantity}, context=context)
|
|
||||||
|
|
||||||
return (line_id, quantity)
|
return (line_id, quantity)
|
||||||
|
|
|
@ -1 +1,38 @@
|
||||||
|
$(document).ready(function () {
|
||||||
|
|
||||||
|
$('#add_to_cart').click(function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
openerp.jsonRpc("/shop/cart/update_json", 'call', {
|
||||||
|
'line_id': parseInt($input.data('line-id'),10),
|
||||||
|
'product_id': parseInt($input.data('product-id'),10),
|
||||||
|
'set_qty': value})
|
||||||
|
.then(function (data) {
|
||||||
|
if (!data.quantity) {
|
||||||
|
location.reload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data.option_ids.length) {
|
||||||
|
_.each(data.option_ids, function (line_id) {
|
||||||
|
$(".js_quantity[data-line-id="+line_id+"]").text(data.quantity);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var $q = $(".my_cart_quantity");
|
||||||
|
$q.parent().parent().removeClass("hidden", !data.quantity);
|
||||||
|
$q.html(data.cart_quantity).hide().fadeIn(600);
|
||||||
|
$input.val(data.quantity);
|
||||||
|
$("#cart_total").replaceWith(data['website_sale.total']);
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$('form:has(#add_to_cart)').submit(function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
$(this).ajaxSubmit({
|
||||||
|
beforeSubmit: function () { console.log("beforeSubmit"); },
|
||||||
|
success: function () { console.log("success"); },
|
||||||
|
url: '/stqdfdsfdf'
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
openerp.Tour.register({
|
||||||
|
id: 'shop_customize',
|
||||||
|
name: "Customize the page and search a product",
|
||||||
|
path: '/shop',
|
||||||
|
mode: 'test',
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
title: "open customize menu",
|
||||||
|
element: '#customize-menu-button',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "click on 'Product Attribute's Filters'",
|
||||||
|
element: "#customize-menu a:contains(Product Attribute's Filters)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "select product attribute memory 16 Go",
|
||||||
|
waitNot: '#customize-menu:visible',
|
||||||
|
element: 'form.js_attributes label:contains(16 Go) input:not(:checked)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "check the selection",
|
||||||
|
waitFor: 'form.js_attributes label:contains(16 Go) input:checked',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "select iPod",
|
||||||
|
waitNot: '.oe_website_sale .oe_product_cart:eq(2)',
|
||||||
|
element: '.oe_product_cart a:contains("iPod")',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "open customize menu 2",
|
||||||
|
waitFor: 'form[action^="/shop/cart/update"] label:contains(32 Go) input',
|
||||||
|
element: '#customize-menu-button',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "click on 'Confirm: Add To Cart'",
|
||||||
|
element: "#customize-menu a:contains(Confirm: Add To Cart)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "click on 'Add to Cart' button",
|
||||||
|
waitNot: '#customize-menu:visible',
|
||||||
|
element: "a[data-toggle='modal']:contains(Add to Cart)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "click in modal on 'Proceed to checkout' button",
|
||||||
|
element: '.modal a:contains("Proceed to checkout")',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "return to the iPod product",
|
||||||
|
waitFor: '#cart_products',
|
||||||
|
element: "a:contains(iPod)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "open customize menu 3",
|
||||||
|
waitFor: 'form[action^="/shop/cart/update"] label:contains(32 Go) input',
|
||||||
|
element: '#customize-menu-button',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "click on 'Confirm: Add To Cart'",
|
||||||
|
element: "#customize-menu a:contains(Confirm: Add To Cart)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "click on 'My Cart'",
|
||||||
|
waitFor: "a.a-submit:contains(Add to Cart)",
|
||||||
|
element: "a[href='/shop/cart']",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "remove iPod from cart",
|
||||||
|
element: '#cart_products a.js_add_cart_json:first',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "finish",
|
||||||
|
waitFor: '.my_cart_quantity:contains(1)',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
}());
|
|
@ -0,0 +1 @@
|
||||||
|
import customize_test
|
|
@ -0,0 +1,14 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
import openerp.tests
|
||||||
|
|
||||||
|
inject = [
|
||||||
|
("openerp.Tour", os.path.join(os.path.dirname(__file__), '../../web/static/src/js/tour.js')),
|
||||||
|
("openerp.Tour.ShopTest", os.path.join(os.path.dirname(__file__), "../static/src/js/website.tour.sale.js")),
|
||||||
|
]
|
||||||
|
|
||||||
|
@openerp.tests.common.at_install(False)
|
||||||
|
@openerp.tests.common.post_install(True)
|
||||||
|
class TestUi(openerp.tests.HttpCase):
|
||||||
|
def test_01_admin_shop_tour(self):
|
||||||
|
self.phantom_js("/", "openerp.Tour.run('shop_customize', 'test')", "openerp.Tour.tours.shop_customize", login="admin", inject=inject)
|
|
@ -2,55 +2,138 @@
|
||||||
<openerp>
|
<openerp>
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
<template id="optional_products" inherit_id="website_sale.product" name="Optional Products">
|
<template id="debugger" inherit_id="website.debugger" name="Event Debugger">
|
||||||
<xpath expr="//tr[@id='product_confirmation']" position="after">
|
<xpath expr='//t[@t-set="debugger_hook"]' position="after">
|
||||||
<tr t-if="optional_product_ids"><td colspan="4"><h4>Select Your Options:</h4></td></tr>
|
<script type="text/javascript" src="/website_sale_options/static/src/js/website_sale.test.js"></script>
|
||||||
<t t-set="option_inc" t-value="0"/>
|
</xpath>
|
||||||
<tr class="js_product" t-foreach="optional_product_ids" t-as="product">
|
</template>
|
||||||
<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'"/>
|
<template id="product_options_script" inherit_id="website_sale.product" name="Script for Options">
|
||||||
<span t-field="product.image_small" t-field-options='{"widget": "image"}'/>
|
<xpath expr="//t[@t-set='head']" position="inside">
|
||||||
</td>
|
<script type="text/javascript" src="/website_sale_options/static/src/js/website_sale.js"></script>
|
||||||
<td>
|
|
||||||
<div class="pull-left">
|
|
||||||
<strong class="media-heading" t-field="product.name"/>
|
|
||||||
<div class="text-muted" t-field="product.description_sale"/>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="pull-right">
|
|
||||||
<t t-call="website_sale.variants"/>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<t t-if="(website.compute_curency(product.lst_price) - product.price) > 0.1">
|
|
||||||
<span class="text-danger" style="text-decoration: line-through; white-space: nowrap;"
|
|
||||||
t-field="product.lst_price"
|
|
||||||
t-field-options='{
|
|
||||||
"widget": "monetary",
|
|
||||||
"from_currency": "website.company_currency_id",
|
|
||||||
"display_currency": "user_id.partner_id.property_product_pricelist.currency_id"
|
|
||||||
}'/><br/>
|
|
||||||
</t>
|
|
||||||
<span class="oe_price" style="white-space: nowrap;"
|
|
||||||
t-field="product.price"
|
|
||||||
t-field-options='{
|
|
||||||
"widget": "monetary",
|
|
||||||
"display_currency": "user_id.partner_id.property_product_pricelist.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" 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">
|
|
||||||
<span class="js_item">1 Item</span><span class="js_items hidden">5 Items</span><br/>
|
|
||||||
<a href="#" class="js_remove"><small>Remove from cart</small></a>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template id="optional_products" name="Optional Products">
|
||||||
|
<div id="modal_optional_products" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false">
|
||||||
|
<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">Product</th>
|
||||||
|
<th style="min-width: 140px;"> </th>
|
||||||
|
<th width="100">Price</th>
|
||||||
|
<th width="120">Quantity</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr id="product_confirmation">
|
||||||
|
<td width="100">
|
||||||
|
<span t-field="product.image_medium" t-field-options='{"widget": "image" }'/>
|
||||||
|
</td>
|
||||||
|
<td colspan="2">
|
||||||
|
<strong t-field="product.name"/>
|
||||||
|
<div class="text-muted">
|
||||||
|
<div t-field="product.description_sale"/>
|
||||||
|
<div class="js_attributes"/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span t-attf-class="text-danger oe_default_price" t-att-style="'' if (website.compute_curency(product.lst_price) - product.price) > 0.1 else 'display: none;'" style="text-decoration: line-through; white-space: nowrap;"
|
||||||
|
t-field="product.lst_price"
|
||||||
|
t-field-options='{
|
||||||
|
"widget": "monetary",
|
||||||
|
"from_currency": "website.currency_id",
|
||||||
|
"display_currency": "user_id.partner_id.property_product_pricelist.currency_id"
|
||||||
|
}'/><br/>
|
||||||
|
<span class="oe_price" style="white-space: nowrap;"
|
||||||
|
t-field="product.price"
|
||||||
|
t-field-options='{
|
||||||
|
"widget": "monetary",
|
||||||
|
"from_currency": "website.currency_id",
|
||||||
|
"display_currency": "user_id.partner_id.property_product_pricelist.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" data-min="1" 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>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr t-if="optional_product_ids"><td colspan="4"><h4>Select Your Options:</h4></td></tr>
|
||||||
|
<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>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="pull-right">
|
||||||
|
<t t-call="website_sale.variants"/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<t t-if="(website.compute_curency(product.lst_price) - product.price) > 0.1">
|
||||||
|
<span class="text-danger" style="text-decoration: line-through; white-space: nowrap;"
|
||||||
|
t-field="product.lst_price"
|
||||||
|
t-field-options='{
|
||||||
|
"widget": "monetary",
|
||||||
|
"from_currency": "website.currency_id",
|
||||||
|
"display_currency": "user_id.partner_id.property_product_pricelist.currency_id"
|
||||||
|
}'/><br/>
|
||||||
|
</t>
|
||||||
|
<span class="oe_price" style="white-space: nowrap;"
|
||||||
|
t-field="product.price"
|
||||||
|
t-field-options='{
|
||||||
|
"widget": "monetary",
|
||||||
|
"display_currency": "user_id.partner_id.property_product_pricelist.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" 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">
|
||||||
|
<span class="js_item">1 Item</span><span class="js_items hidden">5 Items</span><br/>
|
||||||
|
<a href="#" class="js_remove"><small>Remove from cart</small></a>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</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>
|
||||||
|
</template>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
Loading…
Reference in New Issue