[IMP] website, website_sale, crm, web_planner : add planner for website modules

This commit impact crm, website, website_sale and web_planner modules because it
- add planner for website and website_sale
- improve planner notebook by setting texterea and input size to 100% and using col-md-* class
- split js code into common part (used in backend and frontend) and backend part (only for backend)
- adapt some tour, since every page will have the planner modal in its DOM, the tour selectors msut be more accurate
- introduce some style fixes and adaptations
- ...
This commit is contained in:
Darshan Kalola
2015-05-15 10:59:42 +02:00
committed by Jérome Maes
parent 49fe33a3ba
commit 50a043d979
21 changed files with 1896 additions and 144 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
odoo.define('planner_crm.planner', function (require) {
"use strict";
var planner = require('web.planner');
var planner = require('web.planner.common');
planner.PlannerDialog.include({
prepare_planner_event: function() {
@@ -1,17 +1,5 @@
#PlannerModal {
#planner_page2, #planner_page3 {
textarea{
width: 100%;
max-width: 100%;
}
}
#planner_page4 {
textarea {
width: 58%;
max-width: 58%;
}
}
#planner_page5, #planner_page7, #planner_page8, #planner_page10, #planner_page11 {
.container-fluid {
.col-xs-12 {
+42 -14
View File
@@ -307,38 +307,66 @@
<h5 class="col-xs-12 col-md-8 col-md-pull-4"><strong>Stages</strong> from the initial contact to won deals:</h5>
</li>
<li class="row"><span>#1</span>
<input class="col-xs-12 col-sm-4" id="input_element_stage_0" type="text" value="New"/>
<textarea class="col-xs-12 col-sm-7 col-sm-offset-1" id="input_element_stage_7" type="text"/>
<div class="col-md-6">
<input id="input_element_stage_0" type="text" value="New"/>
</div>
<div class="col-md-6">
<textarea id="input_element_stage_7" type="text"/>
</div>
</li>
<li class="row">
<span>#2</span>
<input class="col-xs-12 col-sm-4" id="input_element_stage_1" type="text" value="Qualified"/>
<textarea class="col-xs-12 col-sm-7 col-sm-offset-1" id="input_element_stage_8" type="text"/>
<div class="col-md-6">
<input id="input_element_stage_1" type="text" value="Qualified"/>
</div>
<div class="col-md-6">
<textarea id="input_element_stage_8" type="text"/>
</div>
</li>
<li class="row">
<span>#3</span>
<input class="col-xs-12 col-sm-4" id="input_element_stage_2" type="text" value="Proposition"/>
<textarea class="col-xs-12 col-sm-7 col-sm-offset-1" id="input_element_stage_9" type="text"/>
<div class="col-md-6">
<input id="input_element_stage_2" type="text" value="Proposition"/>
</div>
<div class="col-md-6">
<textarea id="input_element_stage_9" type="text"/>
</div>
</li>
<li class="row">
<span>#4</span>
<input class="col-xs-12 col-sm-4" id="input_element_stage_3" type="text" value="Negotiation"/>
<textarea class="col-xs-12 col-sm-7 col-sm-offset-1" id="input_element_stage_10" type="text"/>
<div class="col-md-6">
<input id="input_element_stage_3" type="text" value="Negotiation"/>
</div>
<div class="col-md-6">
<textarea id="input_element_stage_10" type="text"/>
</div>
</li>
<li class="row">
<span>#5</span>
<input class="col-xs-12 col-sm-4" id="input_element_stage_4" type="text" value="Won"/>
<textarea class="col-xs-12 col-sm-7 col-sm-offset-1" id="input_element_stage_11" type="text"/>
<div class="col-md-6">
<input id="input_element_stage_4" type="text" value="Won"/>
</div>
<div class="col-md-6">
<textarea id="input_element_stage_11" type="text"/>
</div>
</li>
<li class="row">
<span>#6</span>
<input class="col-xs-12 col-sm-4" id="input_element_stage_5" type="text" value="Lost"/>
<textarea class="col-xs-12 col-sm-7 col-sm-offset-1" id="input_element_stage_12" type="text"/>
<div class="col-md-6">
<input id="input_element_stage_5" type="text" value="Lost"/>
</div>
<div class="col-md-6">
<textarea id="input_element_stage_12" type="text"/>
</div>
</li>
<li class="row">
<span>#7</span>
<input class="col-xs-12 col-sm-4" id="input_element_stage_6" type="text"/>
<textarea class="col-xs-12 col-sm-7 col-sm-offset-1" id="input_element_stage_13" type="text"/>
<div class="col-md-6">
<input id="input_element_stage_6" type="text"/>
</div>
<div class="col-md-6">
<textarea id="input_element_stage_13" type="text"/>
</div>
</li>
<div class="o_planner_notebook_line_separator"></div>
</ul>
@@ -0,0 +1,97 @@
odoo.define('web.planner', function (require) {
"use strict";
var Model = require('web.Model');
var SystrayMenu = require('web.SystrayMenu');
var Widget = require('web.Widget');
var planner = require('web.planner.common');
var PlannerDialog = planner.PlannerDialog;
var PlannerLauncher = Widget.extend({
template: "PlannerLauncher",
events: {
'click .o_planner_progress': 'toggle_dialog'
},
init: function(parent) {
this._super(parent);
this.planner_by_menu = {};
this.webclient = parent.getParent();
this.need_reflow = false;
},
start: function() {
var self = this;
self._super();
self.webclient.menu.on("open_menu", self, self.on_menu_clicked);
self.$el.hide(); // hidden by default
return self.fetch_application_planner().done(function(apps) {
self.planner_apps = apps;
return apps;
});
},
fetch_application_planner: function() {
var self = this;
var def = $.Deferred();
if (!_.isEmpty(this.planner_by_menu)) {
def.resolve(self.planner_by_menu);
}else{
(new Model('web.planner')).query().all().then(function(res) {
_.each(res, function(planner){
self.planner_by_menu[planner.menu_id[0]] = planner;
self.planner_by_menu[planner.menu_id[0]].data = $.parseJSON(self.planner_by_menu[planner.menu_id[0]].data) || {};
});
def.resolve(self.planner_by_menu);
}).fail(function() {def.reject();});
}
return def;
},
on_menu_clicked: function(id, $clicked_menu) {
var menu_id = $clicked_menu.parents('.oe_secondary_menu').data('menu-parent') || 0; // find top menu id
if (_.contains(_.keys(this.planner_apps), menu_id.toString())) {
this.$el.show();
this.setup(this.planner_apps[menu_id]);
this.need_reflow = true;
} else {
if (this.$el.is(":visible")) {
this.$el.hide();
this.need_reflow = true;
}
}
if (this.need_reflow) {
this.webclient.menu.reflow();
this.need_reflow = false;
}
},
setup: function(planner){
var self = this;
this.planner = planner;
this.dialog && this.dialog.destroy();
this.dialog = new PlannerDialog(this, planner);
this.$(".o_planner_progress").tooltip({html: true, title: this.planner.tooltip_planner, placement: 'bottom', delay: {'show': 500}});
this.dialog.on("planner_progress_changed", this, function(percent){
self.update_parent_progress_bar(percent);
});
this.dialog.appendTo(document.body);
},
// event
update_parent_progress_bar: function(percent) {
this.$(".progress-bar").css('width', percent+"%");
},
toggle_dialog: function() {
this.dialog.$('#PlannerModal').modal('toggle');
}
});
// add planner launcher to the systray
// if it is empty, it won't be display. Then, each time a top menu is clicked
// a planner will be given to the launcher. The launcher will appears if the
// given planner is not null.
SystrayMenu.Items.push(PlannerLauncher);
return {
PlannerLauncher: PlannerLauncher,
};
});
@@ -1,92 +1,14 @@
odoo.define('web.planner', function (require) {
odoo.define('web.planner.common', function (require) {
"use strict";
var core = require('web.core');
var Model = require('web.Model');
var session = require('web.session');
var SystrayMenu = require('web.SystrayMenu');
var Widget = require('web.Widget');
var utils = require('web.utils');
var QWeb = core.qweb;
var bus = core.bus;
var PlannerLauncher = Widget.extend({
template: "PlannerLauncher",
events: {
'click .o_planner_progress': 'toggle_dialog'
},
init: function(parent) {
this._super(parent);
this.planner_by_menu = {};
this.webclient = parent.getParent();
this.need_reflow = false;
},
start: function() {
var self = this;
self._super();
self.webclient.menu.on("open_menu", self, self.on_menu_clicked);
self.$el.hide(); // hidden by default
return self.fetch_application_planner().done(function(apps) {
self.planner_apps = apps;
return apps;
});
},
fetch_application_planner: function() {
var self = this;
var def = $.Deferred();
if (!_.isEmpty(this.planner_by_menu)) {
def.resolve(self.planner_by_menu);
}else{
(new Model('web.planner')).query().all().then(function(res) {
_.each(res, function(planner){
self.planner_by_menu[planner.menu_id[0]] = planner;
self.planner_by_menu[planner.menu_id[0]].data = $.parseJSON(self.planner_by_menu[planner.menu_id[0]].data) || {};
});
def.resolve(self.planner_by_menu);
}).fail(function() {def.reject();});
}
return def;
},
on_menu_clicked: function(id, $clicked_menu) {
var menu_id = $clicked_menu.parents('.oe_secondary_menu').data('menu-parent') || 0; // find top menu id
if (_.contains(_.keys(this.planner_apps), menu_id.toString())) {
this.$el.show();
this.setup(this.planner_apps[menu_id]);
this.need_reflow = true;
} else {
if (this.$el.is(":visible")) {
this.$el.hide();
this.need_reflow = true;
}
}
if (this.need_reflow) {
this.webclient.menu.reflow();
this.need_reflow = false;
}
},
setup: function(planner){
var self = this;
this.planner = planner;
this.dialog && this.dialog.destroy();
this.dialog = new PlannerDialog(this, planner);
this.$(".o_planner_progress").tooltip({html: true, title: this.planner.tooltip_planner, placement: 'bottom', delay: {'show': 500}});
this.dialog.on("planner_progress_changed", this, function(percent){
self.update_parent_progress_bar(percent);
});
this.dialog.appendTo(document.body);
},
// event
update_parent_progress_bar: function(percent) {
this.$(".progress-bar").css('width', percent+"%");
},
toggle_dialog: function() {
this.dialog.$('#PlannerModal').modal('toggle');
}
});
/*
Widget implementing the Modal of the planner (with all form, menu items, mark buttons, pages, ...). The content (the view_id) is fetched by
calling the 'render' method (server side), then footer are appended to every pages (client side). Data are saved when a 'mark button' is clicked.
@@ -145,7 +67,7 @@ var PlannerDialog = Widget.extend({
// set the default value
self._set_values(self.planner.data);
// show last opened page
var last_open_page = (session.get_cookie(self.cookie_name)) ? session.get_cookie(self.cookie_name) : self.planner.data['last_open_page'] || false;
var last_open_page = (utils.get_cookie(self.cookie_name)) ? utils.get_cookie(self.cookie_name) : self.planner.data['last_open_page'] || false;
if (last_open_page) {
self._switch_page(last_open_page);
}
@@ -198,7 +120,7 @@ var PlannerDialog = Widget.extend({
this.$(".o_planner div[id="+page_id+"]").addClass('show');
this.$(".o_planner .o_planner_pages").scrollTop("0");
this.planner.data['last_open_page'] = page_id;
session.set_cookie(this.cookie_name, page_id, 8*60*60); // create cookie for 8h
utils.set_cookie(this.cookie_name, page_id, 8*60*60); // create cookie for 8h
},
// planner data functions
_get_values: function(page_id){
@@ -209,24 +131,24 @@ var PlannerDialog = Widget.extend({
// only INPUT (select, textearea, input, checkbox and radio), and BUTTON (.mark_button#) are observed
var inputs = base_elem.find("textarea[id^='input_element'], input[id^='input_element'], select[id^='input_element'], button[id^='mark_button']");
_.each(inputs, function(elem){
elem = $(elem);
var tid = elem.attr('id');
if (elem.prop("tagName") == 'BUTTON'){
if(elem.hasClass('fa-check-square-o')){
var $elem = $(elem);
var tid = $elem.attr('id');
if ($elem.prop("tagName") == 'BUTTON'){
if($elem.hasClass('fa-check-square-o')){
values[tid] = 'marked';
}else{
values[tid] = '';
}
}
if (elem.prop("tagName") == 'INPUT' || elem.prop("tagName") == 'TEXTAREA'){
var ttype = elem.attr('type');
if ($elem.prop("tagName") == 'INPUT' || $elem.prop("tagName") == 'TEXTAREA'){
var ttype = $elem.attr('type');
if (ttype == 'checkbox' || ttype == 'radio'){
values[tid] = '';
if (elem.is(':checked')){
if ($elem.is(':checked')){
values[tid] = 'checked';
}
}else{
values[tid] = elem.val();
values[tid] = $elem.val();
}
}
});
@@ -235,21 +157,21 @@ var PlannerDialog = Widget.extend({
_set_values: function(values){
var self = this;
_.each(values, function(val, id){
var elem = self.$('#'+id);
if (elem.prop("tagName") == 'BUTTON'){
var $elem = self.$('#'+id);
if ($elem.prop("tagName") == 'BUTTON'){
if(val == 'marked'){
elem.addClass('fa-check-square-o btn-default').removeClass('fa-square-o btn-primary');
self.$(".o_planner li a[href=#"+elem.data('pageid')+"] span").addClass('fa-check');
$elem.addClass('fa-check-square-o btn-default').removeClass('fa-square-o btn-primary');
self.$(".o_planner li a[href=#"+$elem.data('pageid')+"] span").addClass('fa-check');
}
}
if (elem.prop("tagName") == 'INPUT' || elem.prop("tagName") == 'TEXTAREA'){
var ttype = elem.attr("type");
if ($elem.prop("tagName") == 'INPUT' || $elem.prop("tagName") == 'TEXTAREA'){
var ttype = $elem.attr("type");
if (ttype == 'checkbox' || ttype == 'radio'){
if (val == 'checked') {
elem.attr('checked', 'checked');
$elem.attr('checked', 'checked');
}
}else{
elem.val(val);
$elem.val(val);
}
}
});
@@ -306,15 +228,7 @@ var PlannerDialog = Widget.extend({
this.$('#PlannerModal').modal('hide');
},
});
// add planner launcher to the systray
// if it is empty, it won't be display. Then, each time a top menu is clicked
// a planner will be given to the launcher. The launcher will appears if the
// given planner is not null.
SystrayMenu.Items.push(PlannerLauncher);
return {
PlannerLauncher: PlannerLauncher,
PlannerDialog: PlannerDialog,
};
@@ -254,6 +254,7 @@
.modal-body {
overflow-x: hidden;
max-height: inherit;
padding: 0;
}
.row.o_planner {
padding: 0 15px;
@@ -282,6 +283,9 @@
background: #f7f7f7;
min-height: 60px;
}
.mark_as_done span{
font-family: Lato,serif;
}
// mark/uncheck button animation
button.fa-check-square-o {
left: 5em;
@@ -483,6 +487,8 @@
textarea,input {
background: #fcf8e3;
border: none;
width: 100%;
max-width: 100%;
}
> li {
list-style: none;
@@ -1,10 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" name="planner assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/web_planner/static/src/less/web_planner.less"/>
<script type="text/javascript" src="/web_planner/static/src/js/web_planner.js"></script>
<script type="text/javascript" src="/web_planner/static/src/js/web_planner_backend.js"></script>
</xpath>
</template>
<template id="assets_common" name="planner common assets" inherit_id="web.assets_common">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/web_planner/static/src/less/web_planner_common.less"/>
<script type="text/javascript" src="/web_planner/static/src/js/web_planner_common.js"></script>
</xpath>
</template>
</odoo>
+2 -1
View File
@@ -11,10 +11,11 @@ OpenERP Website CMS
""",
'author': 'OpenERP SA',
'depends': ['web', 'share', 'mail'],
'depends': ['web', 'share', 'mail', 'web_planner'],
'installable': True,
'data': [
'data/data.xml',
'data/web_planner_data.xml',
'security/ir.model.access.csv',
'security/ir_ui_view.xml',
'views/website_templates.xml',
File diff suppressed because it is too large Load Diff
+1
View File
@@ -8,5 +8,6 @@ import ir_qweb
import ir_http
import res_config
import update
import web_planner
import test_models
+14
View File
@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
import json
from openerp import api, models
class WebsitePlanner(models.Model):
_inherit = 'web.planner'
@api.model
def _get_planner_application(self):
planner = super(WebsitePlanner, self)._get_planner_application()
planner.append(['planner_website', 'Website Planner'])
return planner
Binary file not shown.

After

Width:  |  Height:  |  Size: 578 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

@@ -0,0 +1,65 @@
odoo.define('web.planner.website', function (require) {
'use strict';
var Model = require('web.Model');
var Widget = require('web.Widget');
var planner = require('web.planner.common');
var website = require('website.website');
var PlannerDialog = planner.PlannerDialog;
planner.WebistePlannerLauncher = Widget.extend({
template: "PlannerLauncher",
events: {
'click .o_planner_progress': 'toggle_dialog'
},
start: function() {
var self = this;
this._super.apply(this, arguments);
return this.get_website_planner().then(function(planner) {
if (planner.length) {
self.planner = planner[0];
self.planner.data = $.parseJSON(planner[0].data) || {};
self.setup();
}
});
},
get_website_planner: function() {
return (new Model('web.planner')).call('search_read', [[['planner_application', '=', 'planner_website']]]);
},
setup: function() {
var self = this;
this.dialog = new PlannerDialog(this, this.planner);
this.$(".o_planner_progress").tooltip({html: true, title: this.planner.tooltip_planner, placement: 'bottom', container: 'body', delay: {'show': 700}});
this.dialog.on("planner_progress_changed", this, function(percent) {
self.update_parent_progress_bar(percent);
});
this.dialog.appendTo(document.body);
},
update_parent_progress_bar: function(percent) {
this.$(".progress-bar").css('width', percent+"%");
},
toggle_dialog: function() {
this.dialog.$('#PlannerModal').modal('toggle');
},
});
PlannerDialog.include({
prepare_planner_event: function() {
var self = this;
this._super.apply(this, arguments);
self.$el.on("click", ".o_planner a.o_planner_hide", function(ev) {
self.$('#PlannerModal').modal('hide');
});
}
});
website.ready().done(function() {
if($('#oe_systray').length) {
website.add_template_file('/web_planner/static/src/xml/web_planner.xml').then(function() {
new planner.WebistePlannerLauncher().prependTo($('#oe_systray'));
});
}
});
});
+2 -1
View File
@@ -16,7 +16,6 @@
<link rel="stylesheet" href="/web/static/lib/select2/select2.css"/>
<link rel="stylesheet" href="/website/static/lib/select2-bootstrap-css/select2-bootstrap.css"/>
<script type="text/javascript" src="/web/static/lib/select2/select2.js"></script>
</template>
<template id="assets_backend" name="website assets for backend" inherit_id="web.assets_backend">
@@ -287,6 +286,8 @@
<script type="text/javascript" src="/website/static/src/js/website.ace.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.translator.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.theme.js"></script>
<script type="text/javascript" src="/website/static/src/js/web_planner_website.js"></script>
</template>
@@ -41,7 +41,7 @@ website.ready().done(function () {
},
{
waitNot: '.modal-dialog #editor_new_event input[type=text]:not([value!=""])',
element: '.modal-dialog button.btn-primary',
element: '.modal-dialog button.btn-primary.btn-continue',
placement: 'right',
title: _t("Create Event"),
content: _t("Click <em>Continue</em> to create the event."),
+1
View File
@@ -13,6 +13,7 @@ OpenERP E-Commerce
'depends': ['website', 'sale', 'payment'],
'data': [
'data/data.xml',
'data/web_planner_data.xml',
'views/views.xml',
'views/templates.xml',
'views/payment.xml',
@@ -0,0 +1,441 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="website_planner" name="website sale planner" inherit_id="website.website_planner">
<!--Mobile Planner Menu-->
<xpath expr="//span[@class='o_mbl_website_sale_planner']" position="after">
<li>
<a href="#planner_page9">
<span class="fa fa-fw"/>Product Pages
</a>
</li>
<li>
<a href="#planner_page10">
<span class="fa fa-fw"/>Import Your Products
</a>
</li>
<li>
<a href="#planner_page11">
<span class="fa fa-fw"/>Payment Methods
</a>
</li>
<li>
<a href="#planner_page12">
<span class="fa fa-fw"/>Delivery Strategy
</a>
</li>
</xpath>
<xpath expr="//span[@class='o_mobile_sell_more']" position="after">
<li>
<a href="#planner_page18">
<span class="fa fa-fw"/>Sell More
</a>
</li>
</xpath>
<xpath expr="//span[@class='o_website_sale_planner']" position="after">
<h4><i class="fa fa-shopping-cart"/>Sell</h4>
<li>
<a href="#planner_page9">
<span class="fa fa-fw"/>Product Pages
</a>
</li>
<li>
<a href="#planner_page10">
<span class="fa fa-fw"/>Import Your Products
</a>
</li>
<li>
<a href="#planner_page11">
<span class="fa fa-fw"/>Payment Methods
</a>
</li>
<li>
<a href="#planner_page12">
<span class="fa fa-fw"/>Delivery Strategy
</a>
</li>
</xpath>
<xpath expr="//span[@class='o_sell_more']" position="after">
<li>
<a href="#planner_page18">
<span class="fa fa-fw"/>Sell More
</a>
</li>
</xpath>
<xpath expr="//div[@id='planner_page8']" position="after">
<div id="planner_page9" class="o_planner_page">
<h1>Product Pages</h1>
<p class="text-muted">
The best way to start your online shop is by creating 3 products pages directly in the website.<br/>
To help you, here are some guidelines that will convert customers:
</p>
<div class="container-fluid">
<div class="row">
<h4>Example of Good Product Page <a data-toggle="collapse" data-parent="#accordion" href="#productpage"><i class="fa fa-question-circle"></i></a></h4>
<div id="productpage" class="col-md-12 panel-collapse collapse">
<div style="height:300px;width:100%; overflow:auto">
<img src="/website/static/src/img/website_planner_clean.png"></img>
</div>
</div>
</div>
</div>
<div class="container-fluid o_planner_paragraphs">
<div class="row">
<div class="col-sm-1 col-md-2 icon"><span class="fa fa-check-circle-o"/></div>
<div class="col-sm-11 col-md-10">
<p><strong>Mandatory content</strong><br/>
<li><strong>Name</strong> of your product</li>
<li><strong>Price</strong> with currency</li>
<li><strong>Variants</strong> of the product like size or color (see below)</li>
<li><strong>Call to action</strong> short and clear: (Add to Cart, Ask for quote,...)</li>
<li><strong>High-quality picture</strong></li>
<li><strong>Short description</strong> of the product or service</li>
</p>
</div>
</div>
<div class="row">
<div class="col-sm-1 col-md-2 icon"><span class="fa fa-heart"/></div>
<div class="col-sm-11 col-md-10">
<p><strong>Key features, emotional and commercial content</strong><br/>
Recommended for at least for your top products, because it can have a big impact on your sales and conversion rates.
</p>
<p>
<li><strong>Pictures gallery of the product:</strong> all angles, detailed view, package,etc.</li>
<li><strong>Value proposition:</strong> what’s the end-benefit of this product and who is it for?</li>
<li><strong>Features and benefits:</strong> what the product does and why that is good</li>
<li><strong>Technical information:</strong> what do you get and how does it work?</li>
<li><strong>Customers review:</strong> what do the customers think of the product</li>
<li><strong>Bonuses:</strong> what you get on top of the offer</li>
</p>
</div>
</div>
<div class="row">
<div class="col-sm-1 col-md-2 icon"><span class="fa fa-question-circle "/></div>
<div class="col-sm-11 col-md-10">
<p><strong>Reassurance arguments</strong><br/>
Anticipate your customers questions &amp; worries on practical details like Shipping rates &amp; policies, Return &amp; replacement policies, Payment methods &amp; security, General Conditions, etc.
</p>
</div>
</div>
<div class="row">
<div class="col-sm-1 col-md-2 icon"><span class="fa fa-sitemap"/></div>
<div class="col-sm-11 col-md-10">
<p><strong>Product variants</strong><br/>
Product variants are used to offer variations of the same product to your customers on the products page.<br/>
For example, the customer choose a T-shirt and then select its size or color.
</p>
<p>To use them:
<li>Activate the 'Support multiple variants per products' option in
<a t-att-href="prepare_backend_url('base_setup.action_sale_config')">Sales / Settings</a>
</li>
<li>Select a product from the <a t-att-href="prepare_backend_url('product.product_template_action')">Products list</a>, go to the 'Variants' tab</li>
<li>Add as many variants as you need from 3 different types: radio buttons, drop-down menu or color buttons.</li>
<li>You can also define different prices for the variants you created by activating the 'Use pricelists to adapt your price per customers' option in <a t-att-href="prepare_backend_url('base_setup.action_sale_config')">Sales / Settings</a></li>
</p>
</div>
</div>
<div class="alert alert-info info_icon" role="alert">
<span class="fa fa-lightbulb-o fa-2x"></span>
<p>
<li>Put the practical details (shipping, payment options,...) as links in the footer; that way, they will be accessible from all your product pages.</li>
<li> Focus on adding content and improving the pages for your best-selling products: don't try to create complete pages for all your products at first!</li>
</p>
</div>
<div class="row">
<div class="col-md-7 col-xs-12">
<div class="well well-lg">
<strong>Recommended actions:</strong>
<p>Try to apply what you've learned above by manually creating three Product pages from the Content menu.</p>
</div>
</div>
<div class="col-md-5 col-xs-12">
<div class="well well-lg">
<strong>Contact us now:</strong><br/>
<a href="#" target="_blank" ><i class="fa fa-comment-o"/> Live Chat on</a><br/>
<a href="mailto:info@odoo.com?subject=Website%20Planner" target="_blank"><i class="fa fa-envelope-o"/> Email Our Website Expert</a>
</div>
</div>
</div>
</div>
</div>
<div id="planner_page10" class="o_planner_page">
<h1>Import Your Products</h1>
<p class="text-muted">Now you can also <strong>import your existing products:</strong></p>
<div class="row">
<div class="col-md-6 col-xs-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title"><span class="fa fa-sitemap"/><strong> Importation</strong><br/>by using a CSV file</span>
</div>
<div class="panel-body">
<li>Go to the <a t-att-href="prepare_backend_url('product.product_template_action')">Products list view</a> of the Sales module</li>
<li>Export the 3 products you have already created by checking them and choosing 'Export' from the 'More' menu</li>
<li>Enter your existing products into this CSV file, respecting its structure.</li>
<li>Save and import the modified CSV file from the 'More' menu of the <a t-att-href="prepare_backend_url('product.product_template_action')">Products list view</a></li>
</div>
</div>
</div>
<div class="col-md-6 col-xs-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title"><span class="fa fa-pencil-square-o"/><strong> Web-Services</strong><br/>scripts development</span>
</div>
<div class="panel-body">
<p>
Odoo's web-services allows developers to create scripts that will load data automatically into the system.
</p>
<p>
Read the <a href="https://www.odoo.com/documentation/8.0/api_integration.html" target="_blank">Web Service technical documentation.</a>
</p>
</div>
</div>
</div>
</div>
<div>
<div class="row">
<div class="col-md-7 col-xs-12">
<div class="well well-lg">
<strong>Need help to import your products?</strong>
<p>Odoo offers an importation service to handle the whole process for you!</p>
</div>
</div>
<div class="col-md-5 col-xs-12">
<div class="well well-lg">
<strong>Contact us now:</strong><br/>
<a href="#" target="_blank" style="margin-right:10px"><span class="fa fa-comment-o"/> Live Chat on</a><br/>
<a href="mailto:info@odoo.com?subject=Website%20Planner" target="_blank"><span class="fa fa-envelope-o"/> Email Our Website Expert</a>
</div>
</div>
</div>
</div>
</div>
<div id="planner_page11" class="o_planner_page">
<h1>Payment Methods</h1>
<p class="text-muted">
In order to take money from customers, you need a way of accepting payments.<br/>
That's what a payment gateway is for: it helps you make money, but that does cost money.<br/>
That why it's important to choose the right provider for your online payments.
</p>
<h4>You can setup 3 types of <strong>payment methods in Odoo:</strong></h4>
<div class="row">
<div class="col-md-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title"><span class="fa fa-lock"/><strong>Wire transfer</strong> (Slow and inefficient)</span>
</div>
<div class="panel-body">
<div class="col-md-6 col-xs-12">
<p><strong>Pros:</strong>
<li>Free and easy to setup</li>
<li>Some customers prefer to pay this way</li>
</p>
</div>
<div class="col-md-6 col-xs-12">
<p><strong>Cons:</strong>
<li>Can take up to several days for you to receive the money</li>
<li>You have to reconcile the payment manually</li>
</p>
</div>
<p>
> <a t-att-href="prepare_backend_url('base.action_res_company_form', 'form')">Configure your bank account(s)</a><br/>
> <a t-att-href="prepare_backend_url('payment.action_payment_acquirer')">Customize your Payment message</a>
</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-xs-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title"><span class="fa fa-cc-paypal"/><strong> Paypal</strong> (Recommended for starters)</span>
</div>
<div class="panel-body">
<p><strong>Pros:</strong>
<li>Quick and easy to set up</li>
<li>No monthly fees for standard offer</li>
</p>
</div>
</div>
</div>
<div class="col-md-6 col-xs-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title"><span class="fa fa-credit-card"/><strong> Ogone, Adyen, Authorize.net, Buckaroo...</strong></span>
</div>
<div class="panel-body">
<p>It's difficult to recommend one over the others. So, simply pick the one that is more popular in your country!
</p>
</div>
</div>
</div>
<div class="col-md-12">
<div class="well well-lg">
<p>
<strong>Recommended actions:</strong>
<li><a t-att-href="prepare_backend_url('account.action_account_config')">Activate the payment options you want to use</a><br/>
<small>(don't forget to apply the changes)</small></li>
<li><a t-att-href="prepare_backend_url('payment.action_payment_acquirer')">Enter their identification credentials</a><br/>
<small>(you'll have to subscribe directly on each of the payment companies' websites)</small></li>
</p>
</div>
</div>
</div>
<p class="text-muted">
Electronic payments have the advantage of being integrated into the buying process. This means your customers will be less likely to drop out before the payment, resulting in a higher conversion rate at the end.
</p>
</div>
<div id="planner_page12" class="o_planner_page">
<h1>Delivery Strategy</h1>
<p class="text-muted">
Imagine a new customer who comes to your website, finds the product they want and add it to their cart.<br/>
Then they get to the checkout page and are hit with the delivery and handling charges.<br/>
Suddenly, a product that looked like it was a fair price seems little expensive, and the customer leaves your website disappointed.
</p>
<p>Defining a good delivery strategy is difficult: you don't want to cut into your margins, but you want to be attractive to customers.</p>
<h4>Here are <strong>some pros and cons</strong> to help you decide:</h4>
<div class="row">
<div class="col-md-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title"><span class="fa fa-smile-o"/><strong> Free delivery</strong> (risky, but has best potential)</span>
</div>
<div class="panel-body">
<p><strong>Pros:</strong> gives you a significant advantage over any competitors that don't offer the same perk.</p>
<p><strong>Cons:</strong> will require you to either absorb the cost or slightly increase your prices to cover it.</p>
<p>Example: you sell T-shirts in the US only. You can offer free delivery because your items are medium priced and the delivery costs are limited and well defined.</p>
</div>
</div>
</div>
<div class="col-md-12">
<div class="alert alert-info info_icon" role="alert">
<span class="fa fa-lightbulb-o fa-2x"></span>
Offering free delivery with a minimum amount or minimum number of items should drive up your average order value and help to compensate for the delivery costs.
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title"><span class="fa fa-table"/><strong> Flat rates</strong> (everybody pays the same)</span>
</div>
<div class="panel-body">
<p><strong>Pros:</strong> simple for your customers to understand.</p>
<p><strong>Cons:</strong> The delivery cost may be discouraging for your cheapest items.</p>
<p>Example: you sell cheap specialized electronic components. You choose flat rates because the price of an item is sometimes lower than the delivery costs.</p>
</div>
</div>
</div>
<div class="col-md-12">
<div class="alert alert-info info_icon" role="alert">
<span class="fa fa-lightbulb-o fa-2x"></span>
You can also create different rates based on order amount ranges, for example 10€ up to a 50€ order, then 5€ after.
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title"><span class="fa fa-shopping-cart"/><strong> At cost price</strong> (customer pay what you pay)</span>
</div>
<div class="panel-body">
<p><strong>Pros:</strong> being transparent about your charges can win you the trust of your customers.</p>
<p><strong>Cons:</strong> customers have to wait until checkout to find out the delivery price.</p>
<p>Example: you sell custom-made wood sculptures, and because your customers are all over the world, each delivery is different and at cost price.</p>
</div>
</div>
</div>
<div class="col-md-12">
<div class="alert alert-info info_icon" role="alert">
<span class="fa fa-lightbulb-o fa-2x"></span>
At cost price is a good option for heavy or oversized packages.
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="well well-lg">
<strong>Recommended action:</strong>
<li><a t-att-href="prepare_backend_url('delivery.action_delivery_carrier_form')"> Configure your delivery prices</a> using one or several of the strategies above</li>
</div>
</div>
</div>
</div>
</xpath>
<xpath expr="//div[@id='planner_page8']" position="after">
<div id="planner_page18" class="o_planner_page">
<h1>Sell More</h1>
<p class="text-muted">
If you have an eCommerce, one of your objectives is of course to grow your revenues by
selling more and pricier products. Luckily for you, Odoo integrates three powerful
customizations for that.
</p>
<div class="row">
<div class="col-md-12 text-center mb16">
<strong>See it in action</strong><br/>
<iframe width="100%" height="300" src="//www.youtube.com/embed/204DbheXfWw" frameborder="0" allowfullscreen="True"></iframe>
</div>
<div class="col-md-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title">
<span class="fa fa-tag"/>
<strong> 1. On Product pages:</strong> Show alternative products
</span>
</div>
<div class="panel-body">
<p>
Increase your chances to make a sale by displaying alternative products.
</p>
<li>On your website, go to the product page where you want to add alternative products.</li>
<li>Activate 'Alternative products' from the 'Customize' menu.</li>
<li>Go to the <a t-att-href="prepare_backend_url('product.product_template_action', 'kanban')">Product detail form</a> and fill in one or more <strong>'Alternative Products'</strong>.</li>
</div>
</div>
</div>
<div class="col-md-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title">
<span class="fa fa-shopping-cart"/>
<strong>2. On Add to Cart window:</strong> Show accessories, services
</span>
</div>
<div class="panel-body">
<p>
Users will buy more accessories and services if they can add them to their cart in one click.
</p>
<li>From a <a t-att-href="prepare_backend_url('product.product_template_action', 'kanban')">Product detail form</a>, go in the 'Sales' tab</li>
<li>Simply add one or more products as an <strong>'Accessory Product'</strong>.</li>
</div>
</div>
</div>
<div class="col-md-12">
<div class="panel panel-success">
<div class="panel-heading">
<span class="panel-title">
<span class="fa fa-shopping-cart"/>
<strong>3. On Check-out page:</strong> Show optional products
</span>
</div>
<div class="panel-body">
<p>
Increase your average cart amount by proposing complementary products to your visitors.
</p>
<li> From a <a t-att-href="prepare_backend_url('product.product_template_action')">Product detail form</a>, go the 'Sales' tab</li>
<li>Simply add the product you want as an <strong>'Optional Product'</strong></li>
</div>
</div>
</div>
</div>
</div>
</xpath>
</template>
</odoo>
@@ -40,7 +40,7 @@ website.ready().done(function () {
},
{
waitNot: '.modal-dialog #editor_new_product input[type=text]:not([value!=""])',
element: '.modal-dialog button.btn-primary',
element: '.modal-dialog button.btn-primary.btn-continue',
placement: 'right',
title: _t("Create Product"),
content: _t("Click on <em>Continue</em> to create the product."),
@@ -35,21 +35,21 @@ Tour.register({
title: _t("Give a version name"),
content: _t("Give a clever name to retrieve it easily."),
popover: { fixed: true },
waitFor: '.modal button.btn-primary',
element: '.modal input[type="text"]',
waitFor: '.modal button.btn-primary.o_create',
element: '.modal input.o_version_name[type="text"]',
sampleText: 'Test',
},
{
title: _t("Validate the version name"),
placement: 'right',
popover: { fixed: true },
element: '.modal button.btn-primary',
element: '.modal button.btn-primary.o_create',
},
{
title: _t("Confirm"),
placement: 'right',
popover: { fixed: true },
waitNot: '.modal input',
waitNot: '.modal input.form-control[type=text]',
element: '.modal button.o_confirm',
},
{