[IMP] website_sale: allow optional products in shop; In shop, it opens the modal jus after having clicked on the 'Add to cart'. The modal contains the optional products.
This commit is contained in:
parent
286ced7183
commit
8319356630
|
@ -802,10 +802,8 @@ class product_product(osv.osv):
|
|||
uom.id, product.list_price, context['uom'])
|
||||
else:
|
||||
res[product.id] = product.list_price
|
||||
price_extra = 0.0
|
||||
for variant_id in product.attribute_value_ids:
|
||||
price_extra += variant_id.price_extra
|
||||
res[product.id] = (res[product.id] or 0.0) + price_extra
|
||||
res[product.id] = res[product.id] + product.price_extra
|
||||
|
||||
return res
|
||||
|
||||
def _get_partner_code_name(self, cr, uid, ids, product, partner_id, context=None):
|
||||
|
@ -864,6 +862,8 @@ class product_product(osv.osv):
|
|||
def _get_price_extra(self, cr, uid, ids, name, args, context=None):
|
||||
result = dict.fromkeys(ids, False)
|
||||
for product in self.browse(cr, uid, ids, context=context):
|
||||
ctx = context.copy()
|
||||
ctx.update(active_id=product.product_tmpl_id.id)
|
||||
price_extra = 0.0
|
||||
for variant_id in product.attribute_value_ids:
|
||||
for price_id in variant_id.price_ids:
|
||||
|
|
|
@ -212,6 +212,17 @@ class website_sale(http.Controller):
|
|||
|
||||
variants = [[p.id, map(int, p.attribute_value_ids), p.price] for p in product.product_variant_ids]
|
||||
|
||||
|
||||
optional_products = {}
|
||||
for o in product.optional_product_ids:
|
||||
if not optional_products.get(o.product_tmpl_id.id):
|
||||
optional_products[o.product_tmpl_id.id] = {
|
||||
'product_tmpl_id': o.product_tmpl_id,
|
||||
'product_ids': []
|
||||
}
|
||||
if o not in optional_products[o.product_tmpl_id.id]:
|
||||
optional_products[o.product_tmpl_id.id]['product_ids'].append(o)
|
||||
|
||||
values = {
|
||||
'search': search,
|
||||
'category': category,
|
||||
|
@ -223,6 +234,7 @@ class website_sale(http.Controller):
|
|||
'main_object': product,
|
||||
'product': product,
|
||||
'variants': variants,
|
||||
'optional_products': optional_products
|
||||
}
|
||||
return request.website.render("website_sale.product", values)
|
||||
|
||||
|
@ -240,21 +252,31 @@ class website_sale(http.Controller):
|
|||
|
||||
@http.route(['/shop/cart'], type='http', auth="public", website=True)
|
||||
def cart(self, **post):
|
||||
cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
|
||||
order = request.website.sale_get_order()
|
||||
|
||||
values = {
|
||||
'order': order,
|
||||
'suggested_products': [],
|
||||
'suggested_products': []
|
||||
}
|
||||
if order:
|
||||
if not request.context.get('pricelist'):
|
||||
request.context['pricelist'] = order.pricelist_id.id
|
||||
values['suggested_products'] = order._cart_accessories(context=request.context)
|
||||
if not context.get('pricelist'):
|
||||
context['pricelist'] = order.pricelist_id.id
|
||||
values['suggested_products'] = order._cart_accessories(context=context)
|
||||
|
||||
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):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
request.website.sale_get_order(force_create=1)._cart_update(product_id=int(product_id), add_qty=add_qty, set_qty=set_qty)
|
||||
cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
|
||||
order = request.website.sale_get_order(force_create=1)
|
||||
|
||||
print kw
|
||||
for key,val in kw.items():
|
||||
if 'option-' in key:
|
||||
order._cart_update(product_id=int(key.split("-")[1]), add_qty=1)
|
||||
|
||||
order._cart_update(product_id=int(product_id), add_qty=add_qty, set_qty=set_qty)
|
||||
return request.redirect("/shop/cart")
|
||||
|
||||
@http.route(['/shop/cart/update_json'], type='json', auth="public", methods=['POST'], website=True)
|
||||
|
@ -445,7 +467,7 @@ class website_sale(http.Controller):
|
|||
|
||||
@http.route(['/shop/checkout'], type='http', auth="public", website=True)
|
||||
def checkout(self, **post):
|
||||
cr, uid, context, registry = 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, context=context)
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ class product_template(osv.Model):
|
|||
'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"),
|
||||
'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.product', string='Optional Products'),
|
||||
}
|
||||
|
||||
def _defaults_website_sequence(self, cr, uid, *l, **kwargs):
|
||||
|
|
|
@ -116,6 +116,28 @@ class sale_order(osv.Model):
|
|||
product_ids = random.sample(s, min(len(s),3))
|
||||
return self.pool['product.product'].browse(cr, uid, product_ids, context=context)
|
||||
|
||||
def _cart_optional_products(self, cr, uid, ids, context=None):
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
products = {}
|
||||
for l in order.website_order_line:
|
||||
opt = {}
|
||||
for o in l.product_id.optional_product_ids:
|
||||
if not opt.get(o.product_tmpl_id.id):
|
||||
opt[o.product_tmpl_id.id] = {
|
||||
'product_tmpl_id': o.product_tmpl_id,
|
||||
'product_ids': []
|
||||
}
|
||||
if o not in opt[o.product_tmpl_id.id]:
|
||||
opt[o.product_tmpl_id.id]['product_ids'].append(o)
|
||||
|
||||
if opt:
|
||||
products[l.id] = {
|
||||
'order_line_id': l,
|
||||
'optional_product_tmpl': opt
|
||||
}
|
||||
|
||||
return products
|
||||
|
||||
class website(orm.Model):
|
||||
_inherit = 'website'
|
||||
|
||||
|
|
|
@ -50,6 +50,13 @@ $(document).ready(function () {
|
|||
$(this).closest("form").submit();
|
||||
});
|
||||
|
||||
// modal to select optional product in my cart
|
||||
$("#modal_optional_products label").mousedown(function(event) {
|
||||
$(event.currentTarget).parents('li.optional_product_tmpl:first').find("input[type=checkbox]").each(function () {
|
||||
if($(this).parent()[0] != event.currentTarget) $(this).removeAttr('checked');
|
||||
});
|
||||
});
|
||||
|
||||
// change price when they are variants
|
||||
var $price = $(".oe_price .oe_currency_value");
|
||||
$('form.js_add_cart_json label').on('mouseup', function (ev) {
|
||||
|
@ -70,12 +77,12 @@ $(document).ready(function () {
|
|||
|
||||
var $form_var = $('form.js_add_cart_variants');
|
||||
var variant_ids = $form_var.data("attribute_value_ids");
|
||||
$form_var.on('change', 'input, select', function (ev) {
|
||||
$form_var.on('change', 'input.js_variant_change, select.js_variant_change', function (ev) {
|
||||
var values = [];
|
||||
$form_var.find("label").removeClass("text-muted css_not_available");
|
||||
$form_var.find(".a-submit").removeProp("disabled");
|
||||
|
||||
$form_var.find('input:checked, select').each(function () {
|
||||
$form_var.find('input.js_variant_change:checked, select').each(function () {
|
||||
values.push(+$(this).val());
|
||||
});
|
||||
var available = false;
|
||||
|
@ -89,10 +96,10 @@ $(document).ready(function () {
|
|||
}
|
||||
}
|
||||
|
||||
$form_var.find("input:radio, select").each(function () {
|
||||
$form_var.find("input.js_variant_change:radio, select.js_variant_change").each(function () {
|
||||
var id = +$(this).val();
|
||||
var values = [id];
|
||||
$form_var.find(">ul>li:not(:has(input[value='" + id + "'])) input:checked, select").each(function () {
|
||||
$form_var.find(">ul>li:not(:has(input.js_variant_change[value='" + id + "'])) input.js_variant_change:checked, select").each(function () {
|
||||
values.push(+$(this).val());
|
||||
});
|
||||
for (var k in variant_ids) {
|
||||
|
@ -112,10 +119,9 @@ $(document).ready(function () {
|
|||
$(".oe_price_h4").addClass("hidden");
|
||||
$(".oe_not_available").removeClass("hidden");
|
||||
$form_var.find('input[name="product_id"]').val(0);
|
||||
$form_var.find(".a-submit").prop("disabled", "disabled");
|
||||
$form_var.find(".js_check_product").prop("disabled", "disabled");
|
||||
}
|
||||
});
|
||||
$form_var.find("input:first").trigger('change');
|
||||
|
||||
$form_var.find("input.js_variant_change:first").trigger('change');
|
||||
|
||||
});
|
||||
|
|
|
@ -387,7 +387,11 @@
|
|||
|
||||
<t t-call="website_sale.product_price"/>
|
||||
|
||||
<a class="btn btn-primary btn-lg mt8 a-submit">Add to Cart</a>
|
||||
<a t-if="not optional_products" class="btn btn-primary btn-lg mt8 a-submit js_check_product">Add to Cart</a>
|
||||
<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"/>
|
||||
|
||||
</form>
|
||||
|
||||
<hr t-if="product.description_sale"/>
|
||||
|
@ -402,10 +406,60 @@
|
|||
</div>
|
||||
</section>
|
||||
<div itemprop="description" t-field="product.website_description" class="oe_structure mt16" id="product_full_description"/>
|
||||
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="product_modal_optional_products">
|
||||
<div t-if="optional_products" id="modal_optional_products" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<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">Choose your optional products</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul>
|
||||
<li class="optional_product_tmpl" t-foreach="optional_products" t-as="t">
|
||||
<t t-set="o_tmpl" t-value="optional_products[t]"/>
|
||||
|
||||
<t t-if="len(o_tmpl['product_ids']) == 1">
|
||||
<label><input t-att-name="'option-%s' % o_tmpl['product_ids'][0].id" type="checkbox"/> <span t-field="o_tmpl['product_tmpl_id'].name"/></label>
|
||||
|
||||
<span class="badge" t-if="o_tmpl['product_ids'][0].price">
|
||||
+ <span t-field="o_tmpl['product_ids'][0].price" t-field-options='{
|
||||
"widget": "monetary",
|
||||
"display_currency": "website.pricelist_id.currency_id"
|
||||
}'/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="len(o_tmpl['product_ids']) > 1">
|
||||
<span t-field="o_tmpl['product_tmpl_id'].name"/>
|
||||
<ul>
|
||||
<li t-foreach="o_tmpl['product_ids']" t-as="product_id">
|
||||
<label><input t-att-name="'option-%s' % product_id.id" type="checkbox"/> <span t-esc="', '.join([value_id.name for value_id in product_id.attribute_value_ids])"/></label>
|
||||
<span class="badge" t-if="product_id.price">
|
||||
+ <span t-field="product_id.price" t-field-options='{
|
||||
"widget": "monetary",
|
||||
"display_currency": "website.pricelist_id.currency_id"
|
||||
}'/>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</t>
|
||||
</li>
|
||||
</ul>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="product_price">
|
||||
<div itemprop="offers" itemscope="itemscope" itemtype="http://schema.org/Offer" class="product_price mt16">
|
||||
<h4 class="oe_price_h4">
|
||||
|
@ -441,7 +495,7 @@
|
|||
<strong t-field="variant_id.attribute_id.name"/>
|
||||
|
||||
<t t-if="variant_id.attribute_id.type == 'select'">
|
||||
<select class="form-control" t-att-name="'attribute-%s' % variant_id.attribute_id.id">
|
||||
<select class="form-control js_variant_change" t-att-name="'attribute-%s' % variant_id.attribute_id.id">
|
||||
<t t-foreach="variant_id.value_ids" t-as="value_id">
|
||||
<option t-att-value="value_id.id">
|
||||
<span t-field="value_id.name"/>
|
||||
|
@ -462,7 +516,7 @@
|
|||
<t t-foreach="variant_id.value_ids" t-as="value_id">
|
||||
<li t-if="value_id.product_ids" class="form-group js_attribute_value" style="margin: 0;">
|
||||
<label class="control-label" style="margin: 0 20px;">
|
||||
<input type="radio" t-att-checked="'checked' if not inc else ''" t-att-name="'attribute-%s' % variant_id.attribute_id.id" t-att-value="value_id.id" style="vertical-align: top; margin-right: 10px;"/>
|
||||
<input type="radio" class="js_variant_change" t-att-checked="'checked' if not inc else ''" t-att-name="'attribute-%s' % variant_id.attribute_id.id" t-att-value="value_id.id" style="vertical-align: top; margin-right: 10px;"/>
|
||||
<span t-field="value_id.name"/>
|
||||
<span class="badge" t-if="value_id.price_extra">
|
||||
<t t-esc="value_id.price_extra > 0 and '+' or ''"/><span t-field="value_id.price_extra" t-field-options='{
|
||||
|
@ -483,7 +537,7 @@
|
|||
<t t-foreach="variant_id.value_ids" t-as="value_id">
|
||||
<label t-attf-style="background-color:#{value_id.color or value_id.name}"
|
||||
t-attf-class="css_attribute_color #{'active' if not inc else ''}">
|
||||
<input type="radio"
|
||||
<input type="radio" class="js_variant_change"
|
||||
t-att-checked="'checked' if not inc else ''"
|
||||
t-att-name="'attribute-%s' % variant_id.attribute_id.id"
|
||||
t-att-value="value_id.id"
|
||||
|
@ -500,7 +554,10 @@
|
|||
|
||||
<t t-call="website_sale.product_price"/>
|
||||
|
||||
<a class="btn btn-primary btn-lg mt8 a-submit">Add to Cart</a>
|
||||
<a t-if="not optional_products" class="btn btn-primary btn-lg mt8 a-submit">Add to Cart</a>
|
||||
<a t-if="optional_products" class="btn btn-primary btn-lg mt8 " href="#" data-toggle="modal" data-target="#modal_optional_products">Add to Cart</a>
|
||||
|
||||
<t t-call="website_sale.product_modal_optional_products"/>
|
||||
</form>
|
||||
</xpath>
|
||||
</template>
|
||||
|
@ -685,7 +742,9 @@
|
|||
</table>
|
||||
<t t-call="website_sale.total"/>
|
||||
<div class="clearfix"/>
|
||||
<a t-if="website_sale_order and website_sale_order.website_order_line" href="/shop/checkout" class="btn btn-primary pull-right mb32">Process Checkout <span class="fa fa-long-arrow-right"/></a>
|
||||
|
||||
<a t-if="not optional_products and website_sale_order and website_sale_order.website_order_line" class="btn btn-primary pull-right mb32" href="/shop/checkout">Process Checkout <span class="fa fa-long-arrow-right"/></a>
|
||||
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
<div class="col-lg-3 col-lg-offset-1 col-sm-3 col-md-3 text-muted" id="right_column">
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<field name="website_published" class="pull-right" widget="website_button"/>
|
||||
<field name="alternative_product_ids" widget="many2many_tags"/>
|
||||
<field name="accessory_product_ids" widget="many2many_tags"/>
|
||||
<field name="optional_product_ids" widget="many2many_tags"/>
|
||||
<field name="website_style_ids" widget="many2many_tags"/>
|
||||
<field name="website_sequence"/>
|
||||
</group>
|
||||
|
|
Loading…
Reference in New Issue