[ADD] website_sale_wishlist: add wishlist feature on eCommerce
This commit is contained in:
@@ -37,6 +37,7 @@ class WebsiteConfigSettings(models.TransientModel):
|
||||
module_website_sale_options = fields.Boolean("Optional Products", help='Installs *e-Commerce Optional Products*')
|
||||
module_website_sale_digital = fields.Boolean("Digital Content")
|
||||
|
||||
module_website_sale_wishlist = fields.Boolean("Wishlists ", help='Installs *e-Commerce Wishlist*')
|
||||
module_sale_stock = fields.Boolean("Delivery Orders")
|
||||
module_portal = fields.Boolean("Activate the customer portal", help="""Give your customers access to their documents.""")
|
||||
|
||||
|
||||
@@ -146,6 +146,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box" id="whishlist_option_setting">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_website_sale_wishlist"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="module_website_sale_wishlist"/>
|
||||
<div class="text-muted">
|
||||
Let returning shoppers save products in a whishlist
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Checkout Process</h2>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import models
|
||||
import controllers
|
||||
@@ -0,0 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
{
|
||||
'name': 'Website Wishlist',
|
||||
'description': 'Let returning shoppers save products in a wishlist',
|
||||
'author': 'Odoo SA',
|
||||
'website': 'https://www.odoo.com',
|
||||
'category': 'Website',
|
||||
'version': '1.0',
|
||||
'depends': ['website_sale'],
|
||||
'data': [
|
||||
'security/website_sale_wishlist_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'views/website_sale_wishlist_template.xml',
|
||||
],
|
||||
'installable': True,
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import main
|
||||
@@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from odoo.addons.website_sale.controllers.main import WebsiteSale
|
||||
import json
|
||||
|
||||
|
||||
class WebsiteSaleWishlist(WebsiteSale):
|
||||
|
||||
@http.route(['/shop/wishlist/add'], type='json', auth="user", website=True)
|
||||
def add_to_wishlist(self, product_id, price=False, **kw):
|
||||
if not price:
|
||||
compute_currency, pricelist_context, pl = self._get_compute_currency_and_context()
|
||||
p = request.env['product.product'].with_context(pricelist_context, display_default_code=False).browse(product_id)
|
||||
price = p.website_price
|
||||
|
||||
request.env['product.wishlist']._add_to_wishlist(
|
||||
request.env.user.partner_id.id,
|
||||
pl.id,
|
||||
pl.currency_id.id,
|
||||
request.website.id,
|
||||
price,
|
||||
product_id
|
||||
)
|
||||
return True
|
||||
|
||||
@http.route(['/shop/wishlist'], type='http', auth="user", website=True)
|
||||
def get_wishlist(self, count=False, **kw):
|
||||
values = request.env['product.wishlist'].with_context(display_default_code=False).search([('partner_id', '=', request.env.user.partner_id.id)])
|
||||
if count:
|
||||
return request.make_response(json.dumps(values.mapped('product_id').ids))
|
||||
|
||||
if not len(values):
|
||||
return request.redirect("/shop")
|
||||
|
||||
return request.render("website_sale_wishlist.product_wishlist", dict(wishes=values))
|
||||
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import product_wishlist
|
||||
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ProductWishlist(models.Model):
|
||||
_name = 'product.wishlist'
|
||||
|
||||
partner_id = fields.Many2one('res.partner', string='Owner', required=True)
|
||||
pricelist_id = fields.Many2one('product.pricelist', string='Pricelist', help='Pricelist when added')
|
||||
currency_id = fields.Many2one('res.currency', related='pricelist_id.currency_id', readonly=True)
|
||||
website_id = fields.Many2one('website', required=True)
|
||||
price = fields.Monetary(digits=0, currency_field='currency_id', string='Price', help='Price of the product when it has been added in the wishlist')
|
||||
price_new = fields.Float(compute='compute_new_price', string='Current price', help='Current price of this product, using same pricelist, ...')
|
||||
product_id = fields.Many2one('product.product', string='Product', required=True)
|
||||
active = fields.Boolean(default=True, required=True)
|
||||
create_date = fields.Datetime('Added Date', readonly=True, required=True)
|
||||
|
||||
@api.multi
|
||||
@api.depends('pricelist_id', 'currency_id', 'product_id')
|
||||
def compute_new_price(self):
|
||||
for wish in self:
|
||||
wish.price_new = wish.product_id.with_context(pricelist=wish.pricelist_id.id).website_price
|
||||
|
||||
@api.model
|
||||
def _add_to_wishlist(self, partner_id, pricelist_id, currency_id, website_id, price, product_id):
|
||||
wish = self.env['product.wishlist'].create({
|
||||
'partner_id': partner_id,
|
||||
'pricelist_id': pricelist_id,
|
||||
'currency_id': currency_id,
|
||||
'website_id': website_id,
|
||||
'price': price,
|
||||
'product_id': product_id,
|
||||
})
|
||||
return wish
|
||||
@@ -0,0 +1,5 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_product_wishlist_default,access_product_wishlist_default,model_product_wishlist,,0,0,0,0
|
||||
access_product_wishlist_public,access_product_wishlist_public,model_product_wishlist,base.group_public,1,0,0,0
|
||||
access_product_wishlist_portal,access_product_wishlist_portal,model_product_wishlist,base.group_portal,1,1,1,1
|
||||
access_product_wishlist_user,access_product_wishlist_user,model_product_wishlist,base.group_user,1,1,1,1
|
||||
|
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="product_wishlist_rule" model="ir.rule">
|
||||
<field name="name">See own Wishlist</field>
|
||||
<field name="model_id" ref="model_product_wishlist"/>
|
||||
<field name="domain_force">[('partner_id','=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal')),(4, ref('base.group_public')), (4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="all_product_wishlist_rule" model="ir.rule">
|
||||
<field name="name">See all wishlist</field>
|
||||
<field name="model_id" ref="model_product_wishlist"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('sales_team.group_sale_manager'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,131 @@
|
||||
odoo.define('website_sale_wishlist.wishlist', function (require) {
|
||||
"use strict";
|
||||
|
||||
var ajax = require('web.ajax');
|
||||
var core = require('web.core');
|
||||
var Model = require('web.Model');
|
||||
var Widget = require('web.Widget');
|
||||
var base = require('web_editor.base');
|
||||
var website_sale_utils = require('website_sale.utils');
|
||||
|
||||
|
||||
if(!$('.oe_website_sale').length) {
|
||||
return $.Deferred().reject("DOM doesn't contain '.oe_website_sale'");
|
||||
}
|
||||
|
||||
var ProductWishlist = Widget.extend({
|
||||
events: {
|
||||
'click #my_wish': 'display_wishlist',
|
||||
},
|
||||
init: function(){
|
||||
var self = this;
|
||||
this.wishlist_product_ids = [];
|
||||
|
||||
if (!odoo.session_info.is_website_user) {
|
||||
$.get('/shop/wishlist', {'count': 1}).then(function(res) {
|
||||
self.wishlist_product_ids = JSON.parse(res);
|
||||
self.update_wishlist_view();
|
||||
});
|
||||
}
|
||||
$('.oe_website_sale .o_add_wishlist, .oe_website_sale .o_add_wishlist_dyn').click(function (e){
|
||||
self.add_new_products($(this), e);
|
||||
});
|
||||
|
||||
if ($('.wishlist-section').length) {
|
||||
$('.wishlist-section a.o_wish_rm').on('click', function (e){ self.wishlist_rm(e); });
|
||||
$('.wishlist-section a.o_wish_add').on('click', function (e){ self.wishlist_add(e); });
|
||||
$('.wishlist-section a.o_wish_mv').on('click', function (e){ self.wishlist_mv(e); });
|
||||
}
|
||||
},
|
||||
add_new_products:function($el, e){
|
||||
var self = this;
|
||||
var product_id = $el.data('product-product-id');
|
||||
if (e.currentTarget.classList.contains('o_add_wishlist_dyn')) {
|
||||
product_id = parseInt($el.parent().find('.product_id').val());
|
||||
}
|
||||
if (odoo.session_info.is_website_user){
|
||||
this.warning_not_logged();
|
||||
} else {
|
||||
if (!_.contains(self.wishlist_product_ids, product_id)) {
|
||||
return ajax.jsonRpc('/shop/wishlist/add', 'call', {
|
||||
'product_id': product_id
|
||||
}).then(function () {
|
||||
self.wishlist_product_ids.push(product_id);
|
||||
self.update_wishlist_view();
|
||||
website_sale_utils.animate_clone($('#my_wish'), $el.closest('form'), 10, 10);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
display_wishlist: function() {
|
||||
if (odoo.session_info.is_website_user) {
|
||||
this.warning_not_logged();
|
||||
}
|
||||
else if (this.wishlist_product_ids.length === 0) {
|
||||
this.update_wishlist_view();
|
||||
this.redirect_no_wish();
|
||||
}
|
||||
else {
|
||||
window.location = '/shop/wishlist';
|
||||
}
|
||||
},
|
||||
update_wishlist_view: function() {
|
||||
if (this.wishlist_product_ids.length > 0) {
|
||||
$('#my_wish').show();
|
||||
$('.my_wish_quantity').text(this.wishlist_product_ids.length);
|
||||
}
|
||||
else {
|
||||
$('#my_wish').hide();
|
||||
}
|
||||
},
|
||||
wishlist_rm: function(e){
|
||||
var tr = $(e.currentTarget).parents('tr');
|
||||
var wish = tr.data('wish-id');
|
||||
var product = tr.data('product-id');
|
||||
|
||||
new Model('product.wishlist')
|
||||
.call('write', [[wish], { active: false }, base.get_context()])
|
||||
.then(function(){
|
||||
$(tr).hide();
|
||||
});
|
||||
this.wishlist_product_ids = _.without(this.wishlist_product_ids, product);
|
||||
if (this.wishlist_product_ids.length === 0) {
|
||||
this.redirect_no_wish();
|
||||
}
|
||||
this.update_wishlist_view();
|
||||
},
|
||||
wishlist_add: function(e){
|
||||
var tr = $(e.currentTarget).parents('tr');
|
||||
var product = tr.data('product-id');
|
||||
|
||||
// can be hidden if empty
|
||||
$('#my_cart').removeClass('hidden');
|
||||
website_sale_utils.animate_clone($('#my_cart'), tr, 0, 0);
|
||||
this.add_to_cart(product, tr.find('qty').val() || 1);
|
||||
},
|
||||
wishlist_mv: function(e){
|
||||
var tr = $(e.currentTarget).parents('tr');
|
||||
var product = tr.data('product-id');
|
||||
|
||||
$('#my_cart').removeClass('hidden');
|
||||
website_sale_utils.animate_clone($('#my_cart'), tr, 0, 0);
|
||||
this.add_to_cart(product, tr.find('qty').val() || 1);
|
||||
this.wishlist_rm(e);
|
||||
},
|
||||
add_to_cart: function(product_id, qty_id) {
|
||||
ajax.jsonRpc("/shop/cart/update_json", 'call', {
|
||||
'product_id': parseInt(product_id, 10),
|
||||
'add_qty': parseInt(qty_id, 10)
|
||||
});
|
||||
},
|
||||
redirect_no_wish: function() {
|
||||
window.location = '/shop/cart';
|
||||
},
|
||||
warning_not_logged: function() {
|
||||
window.location = '/shop/wishlist';
|
||||
}
|
||||
});
|
||||
|
||||
new ProductWishlist();
|
||||
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
.oe_website_sale {
|
||||
.td-wish-btn {
|
||||
width: 140px;
|
||||
}
|
||||
}
|
||||
|
||||
// XS size
|
||||
@media (max-width: @screen-xs-max) {
|
||||
.oe_website_sale {
|
||||
.td-wish-btn {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="assets_frontend" inherit_id="website.assets_frontend" name="Wishlist assets frontend">
|
||||
<xpath expr="." position="inside">
|
||||
<link type="text/less" rel='stylesheet' href='/website_sale_wishlist/static/src/less/website_sale_wishlist.less'/>
|
||||
<script type="text/javascript" src="/website_sale_wishlist/static/src/js/website_sale_wishlist.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="add_to_wishlist" inherit_id="website_sale.products_item" active="True" customize_show="True" name="Wishlist" priority="10">
|
||||
<xpath expr="//div[@class='product_price']" position="inside">
|
||||
<a class="btn btn-default btn-xs o_add_wishlist" title="Add to Wishlist" t-att-data-product-product-id="product.product_variant_ids[0].id" data-action="o_wishlist"><span class="fa fa-heart"></span></a>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="product_add_to_wishlist" name='Add to wishlist in product page' inherit_id="website_sale.product" priority="10">
|
||||
<xpath expr="//a[@id='add_to_cart']" position="after">
|
||||
<t t-if="product.env.ref('website_sale_wishlist.add_to_wishlist').active">
|
||||
<a class="btn btn-default btn-lg mt8 o_add_wishlist_dyn" title="Add to Wishlist" t-att-data-product-product-id="product.product_variant_ids[0].id" data-action="o_wishlist"><span class="fa fa-heart"></span></a>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="header" inherit_id="website.layout" name="Header Shop Wishlist Link">
|
||||
<xpath expr="//header//ul[@id='top_menu']/li[@id='my_cart']" position="after">
|
||||
<t t-if="(request.env.user.id != request.website.user_id.id) and request.env.ref('website_sale_wishlist.add_to_wishlist').active">
|
||||
<t t-set='wishcount' t-value="request.env['product.wishlist'].search_count([('partner_id', '=', request.env.user.partner_id.id)])"/>
|
||||
<li id="my_wish" t-att-style="not wishcount and 'display:none'">
|
||||
<a href="/shop/wishlist">
|
||||
<i class="fa fa-heart"></i>
|
||||
Wishlist <sup t-attf-class="my_wish_quantity o_animate_blink label label-primary"><t t-esc='wishcount'/></sup>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="product_wishlist" name="Wishlist Page">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="additional_title">Shop Wishlist</t>
|
||||
<div id="wrap" class="js_sale">
|
||||
<div class="oe_structure"/>
|
||||
<div class="container oe_website_sale">
|
||||
<section class="container wishlist-section">
|
||||
<h3>My Wishlist</h3>
|
||||
<table class="table table-bordered table-striped table-hover text-center mt16 table-comparator" id="o_comparelist_table">
|
||||
<body>
|
||||
<t t-foreach="wishes" t-as="wish">
|
||||
<tr t-att-data-wish-id='wish.id' t-att-data-product-id='wish.product_id.id'>
|
||||
<td class='td-img'>
|
||||
<a t-att-href="'/shop/product/%s' % slug(wish.product_id.product_tmpl_id)">
|
||||
<img t-attf-src="/web/image/product.product/#{wish.product_id.id}/image/100x100" class="img img-responsive" style="margin:auto;"/>
|
||||
</a>
|
||||
</td>
|
||||
<td class='text-left'>
|
||||
<strong><a t-att-href="'/shop/product/%s' % slug(wish.product_id.product_tmpl_id)"><t t-esc="wish.product_id.display_name" /></a></strong>
|
||||
<small class='hidden-xs'><p t-field="wish.product_id.description_sale" class="text-muted"/></small>
|
||||
<a class="o_wish_rm no-decoration"><small><i class='fa fa-trash-o'></i> Remove</small></a>
|
||||
</td>
|
||||
<td style='width:80px'>
|
||||
<t t-if='wish.price_new != wish.price'>
|
||||
<del class='text-danger'><t t-esc='wish.price' t-options="{'widget': 'monetary', 'display_currency': wish.currency_id}"/></del>
|
||||
<br/>
|
||||
</t>
|
||||
<t t-if="wish.product_id.availability == 'warning'">
|
||||
<div class="alert alert-warning">
|
||||
<span class="fa fa-warning"></span>
|
||||
<span t-field="wish.product_id.availability_warning"></span>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="1">
|
||||
<t t-esc='wish.price_new' t-options="{'widget': 'monetary', 'display_currency': wish.currency_id}"/>
|
||||
</t>
|
||||
</td>
|
||||
<td class='text-center td-wish-btn'>
|
||||
<input name="product_id" t-att-value="wish.product_id.id" type="hidden"/>
|
||||
<a class="btn btn-primary btn-block o_wish_mv mb4">Move <span class='hidden-xs'>to Cart</span></a>
|
||||
<a class="btn btn-default btn-block o_wish_add mb4" >Add <span class='hidden-xs'>to Cart</span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</body>
|
||||
</table>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user