[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:
Christophe Matthieu 2014-06-11 12:50:41 +02:00
parent 286ced7183
commit 8319356630
7 changed files with 135 additions and 24 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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):

View File

@ -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'

View File

@ -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');
});

View File

@ -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">

View File

@ -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>