diff --git a/addons/payment_acquirer_adyen/controllers/main.py b/addons/payment_acquirer_adyen/controllers/main.py
index 2ea9fb00c51..706b26e163d 100644
--- a/addons/payment_acquirer_adyen/controllers/main.py
+++ b/addons/payment_acquirer_adyen/controllers/main.py
@@ -19,7 +19,7 @@ class AdyenController(http.Controller):
@website.route([
'/payment/adyen/return/',
- ], type='http', auth='public')
+ ], type='http', auth='public', methods=['POST'])
def adyen_return(self, **post):
""" Paypal IPN. """
_logger.info('Beginning Adyen form_feedback with post data %s', pprint.pformat(post)) # debug
diff --git a/addons/product/product.py b/addons/product/product.py
index 3e8aecc8e08..e6ea84b9c85 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -529,12 +529,15 @@ class product_product(osv.osv):
pricelist_ids = self.pool.get('product.pricelist').name_search(
cr, uid, pricelist, operator='=', context=context, limit=1)
pricelist = pricelist_ids[0][0] if pricelist_ids else pricelist
+
+ qtys = map(lambda x: (x, quantity, partner), ids)
+ price = self.pool.get('product.pricelist').price_get_multi(cr,uid, [pricelist],
+ qtys, context=context)
for id in ids:
try:
- price = self.pool.get('product.pricelist').price_get(cr,uid,[pricelist], id, quantity, partner=partner, context=context)[pricelist]
+ res[id] = price[id][pricelist]
except:
price = 0.0
- res[id] = price
for id in ids:
res.setdefault(id, 0.0)
return res
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index c430e9168f9..7d14c4deacf 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -2,6 +2,7 @@
import logging
import traceback
+import werkzeug
import werkzeug.routing
import openerp
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index 738c8d460ae..962a4bf5479 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -77,6 +77,9 @@ def urlplus(url, params):
for k, v in params.iteritems()
))
+def quote_plus(value):
+ return urllib.quote_plus(value.encode('utf-8') if isinstance(value, unicode) else str(value))
+
class website(osv.osv):
def _get_menu_website(self, cr, uid, ids, context=None):
# IF a menu is changed, update all websites
@@ -181,10 +184,12 @@ class website(osv.osv):
return self.pool['website'].browse(cr, uid, 1, context=context)
def preprocess_request(self, cr, uid, ids, request, context=None):
+ # TODO FP: is_website_publisher and editable in context should be removed
+ # for performance reasons (1 query per image to load) but also to be cleaner
+ # I propose to replace this by a group 'base.group_website_publisher' on the
+ # view that requires it.
Access = request.registry['ir.model.access']
- is_website_publisher = (
- Access.check_groups(cr, uid, 'base.group_website_publisher')
- and Access.check(cr, uid, 'ir.ui.view', 'write', False, context))
+ is_website_publisher = Access.check(cr, uid, 'ir.ui.view', 'write', False, context)
lang = request.context['lang']
is_master_lang = lang == request.website.default_lang_code
@@ -224,6 +229,7 @@ class website(osv.osv):
slug=slug,
res_company=request.website.company_id,
user_id=user.browse(cr, uid, uid),
+ quote_plus=quote_plus,
)
context.update(
diff --git a/addons/website/security/ir.model.access.csv b/addons/website/security/ir.model.access.csv
index c5ccffd697e..86d258edc5c 100644
--- a/addons/website/security/ir.model.access.csv
+++ b/addons/website/security/ir.model.access.csv
@@ -17,3 +17,5 @@ access_website_qweb_field_html,access_website_qweb_field_html,model_website_qweb
access_website_qweb_field_image,access_website_qweb_field_image,model_website_qweb_field_image,,0,0,0,0
access_website_qweb_field_monetary,access_website_qweb_field_monetary,model_website_qweb_field_monetary,,0,0,0,0
access_website_ir_ui_view,access_website_ir_ui_view,model_ir_ui_view,base.group_website_designer,1,1,1,1
+access_seo_public,access_seo_public,model_website_seo_metadata,base.group_public,1,0,0,0
+access_seo_designer,access_seo_designer,model_website_seo_metadata,base.group_website_designer,1,1,1,1
diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css
index f8034b52c49..487306be5dc 100644
--- a/addons/website/static/src/css/editor.css
+++ b/addons/website/static/src/css/editor.css
@@ -150,10 +150,10 @@ div.oe_menu_buttons {
right: -8px;
}
-ul.oe_menu_editor .icon-home {
+ul.oe_menu_editor .fa-home {
display: none;
}
-ul.oe_menu_editor > li:first-child > div > span > .icon-home {
+ul.oe_menu_editor > li:first-child > div > span > .fa-home {
display: block;
}
ul.oe_menu_editor .oe_menu_placeholder {
@@ -220,6 +220,13 @@ ul.oe_menu_editor .disclose {
background-color: #ffd9dd !important;
}
+.hover-edition-button {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 42;
+}
+
/* ---- SNIPPET EDITOR ---- */
#oe_snippets {
position: fixed;
diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass
index cb0876d4212..7de48fdc611 100644
--- a/addons/website/static/src/css/editor.sass
+++ b/addons/website/static/src/css/editor.sass
@@ -120,9 +120,9 @@ div.oe_menu_buttons
right: -8px
ul.oe_menu_editor
- .icon-home
+ .fa-home
display: none
- > li:first-child > div > span > .icon-home
+ > li:first-child > div > span > .fa-home
display: block
.oe_menu_placeholder
outline: 1px dashed #4183C4
@@ -181,6 +181,12 @@ ul.oe_menu_editor
outline: 1px solid red !important
background-color: #ffd9dd !important
+.hover-edition-button
+ position: absolute
+ top: 0
+ left: 0
+ z-index: 42
+
/* ---- SNIPPET EDITOR ---- */
#oe_snippets
diff --git a/addons/website/static/src/css/website.css b/addons/website/static/src/css/website.css
index 78de8be5803..d62a3b9b371 100644
--- a/addons/website/static/src/css/website.css
+++ b/addons/website/static/src/css/website.css
@@ -406,29 +406,33 @@ ul.nav-stacked > li > a {
}
/* Parallax Theme */
-.parallax_quote, [data-snippet-id="slider"] {
- background: center center no-repeat fixed;
- background-size: contain;
-}
-.parallax_quote .carousel-indicators li, [data-snippet-id="slider"] .carousel-indicators li {
+div.carousel[data-snippet-id="slider"] .carousel-indicators li {
border: 1px solid grey;
}
-.parallax_quote .carousel-indicators .active, [data-snippet-id="slider"] .carousel-indicators .active {
+div.carousel[data-snippet-id="slider"] .carousel-indicators .active {
background-color: grey;
}
.parallax {
position: relative;
background-size: 100%;
+ display: table;
+ width: 100%;
+ min-height: 100px;
}
.parallax.oe_small {
- height: 200px;
+ min-height: 200px;
}
.parallax.oe_medium {
- height: 300px;
+ min-height: 300px;
}
.parallax.oe_big {
- height: 450px;
+ min-height: 450px;
+}
+.parallax > div {
+ display: table-cell;
+ vertical-align: middle;
+ padding: 32px 0;
}
/* Background */
diff --git a/addons/website/static/src/css/website.sass b/addons/website/static/src/css/website.sass
index a559efdca75..8329ef09070 100644
--- a/addons/website/static/src/css/website.sass
+++ b/addons/website/static/src/css/website.sass
@@ -304,9 +304,7 @@ ul.nav-stacked > li > a
/* Parallax Theme */
-.parallax_quote, [data-snippet-id="slider"]
- background: center center no-repeat fixed
- background-size: contain
+div.carousel[data-snippet-id="slider"]
.carousel-indicators
li
border: 1px solid grey
@@ -316,12 +314,19 @@ ul.nav-stacked > li > a
.parallax
position: relative
background-size: 100%
+ display: table
+ width: 100%
+ min-height: 100px
&.oe_small
- height: 200px
+ min-height: 200px
&.oe_medium
- height: 300px
+ min-height: 300px
&.oe_big
- height: 450px
+ min-height: 450px
+ > div
+ display: table-cell
+ vertical-align: middle
+ padding: 32px 0
/* Background */
diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js
index b5caac71d74..a834f5f8162 100644
--- a/addons/website/static/src/js/website.editor.js
+++ b/addons/website/static/src/js/website.editor.js
@@ -17,6 +17,11 @@
website.form(this.pathname, 'POST');
});
+ $(document).on('submit', '.cke_editable form', function (ev) {
+ // Disable form submition in editable mode
+ ev.preventDefault();
+ });
+
$(document).on('hide.bs.dropdown', '.dropdown', function (ev) {
// Prevent dropdown closing when a contenteditable children is focused
if (ev.originalEvent
@@ -68,57 +73,6 @@
link_dialog(editor);
}, null, null, 500);
- var previousSelection;
- $(editor.element.$).on('mouseenter', 'img', function () {
- if (previousSelection) { return; }
- var selected = new CKEDITOR.dom.element(this);
- if (!selected.is('img')
- || selected.data('cke-realelement')
- || selected.isReadOnly()
- || selected.data('oe-model') === 'ir.ui.view') {
- return;
- }
-
- // display button
- var $el = $((previousSelection = selected).$);
- var $btn = $('')
- .insertAfter($el)
- .click(function (e) {
- e.preventDefault();
- e.stopPropagation();
- image_dialog(editor, selected);
- });
-
- var position = $el.position();
- // http://bugs.jquery.com/ticket/5445#comment:6
- // if the image has margin: x auto for centering, FF & IE
- // will report top/left as the "correct" value and
- // marginTop/marginLeft at "0px", webkit browsers will
- // report top/left as 0-ish and set marginTop and
- // marginLeft
- var image_top = position.top + parseInt($el.css('marginTop'), 10);
- var image_left = position.left + parseInt($el.css('marginLeft'), 10);
- $btn.css({
- position: 'absolute',
- top: $el.height() / 2 + image_top - $btn.outerHeight() / 2,
- left: $el.width() / 2 + image_left - $btn.outerWidth() / 2,
- });
- }).on('mouseleave', 'img', function (e) {
- if (!previousSelection) { return; }
- var $previous = $(previousSelection.$);
- var $button = $previous.next('button');
- $button.css('visibility', 'hidden');
- var el = document.elementFromPoint(e.clientX, e.clientY);
- $button.css('visibility', '');
- if (el === this) { return; }
- $button.remove();
- previousSelection = null;
- });
- editor.on('destroy', function () {
- if (!previousSelection) { return; }
- $('.image-edit-button').remove();
- });
-
//noinspection JSValidateTypes
editor.addCommand('link', {
exec: function (editor) {
@@ -416,8 +370,8 @@
if (item.header) {
menu.append('
');
} else {
- menu.append(_.str.sprintf(' %s',
- item.id, item.active ? '' : '-empty', item.name));
+ menu.append(_.str.sprintf(' %s',
+ item.id, item.active ? '' : '-check', item.name));
}
});
// Adding Static Menus
@@ -458,6 +412,7 @@
this.rte = new website.RTE(this);
this.rte.on('change', this, this.proxy('rte_changed'));
this.rte.on('rte:ready', this, function () {
+ self.setup_hover_buttons();
self.trigger('rte:ready');
});
@@ -555,7 +510,20 @@
});
},
cancel: function () {
- website.reload();
+ new $.Deferred(function (d) {
+ var $dialog = $(openerp.qweb.render('website.editor.discard')).appendTo(document.body);
+ $dialog.on('click', '.btn-danger', function () {
+ d.resolve();
+ }).on('hidden.bs.modal', function () {
+ d.reject();
+ });
+ d.always(function () {
+ $dialog.remove();
+ });
+ $dialog.modal('show');
+ }).then(function () {
+ website.reload();
+ })
},
new_page: function (ev) {
ev.preventDefault();
@@ -568,6 +536,97 @@
}
});
},
+
+ /**
+ * Creates a "hover" button for image and link edition
+ *
+ * @param {String} label the button's label
+ * @param {Function} editfn edition function, called when clicking the button
+ * @param {String} [classes] additional classes to set on the button
+ * @returns {jQuery}
+ */
+ make_hover_button: function (label, editfn, classes) {
+ return $(openerp.qweb.render('website.editor.hoverbutton', {
+ label: label,
+ classes: classes,
+ })).hide().appendTo(document.body).click(function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ editfn.call(this, e);
+ });
+ },
+ /**
+ * For UI clarity, during RTE edition when the user hovers links and
+ * images a small button should appear to make the capability clear,
+ * as not all users think of double-clicking the image or link.
+ */
+ setup_hover_buttons: function () {
+ var editor = this.rte.editor;
+ var $link_button = this.make_hover_button(_t("Edit Link"), function () {
+ var sel = new CKEDITOR.dom.element(previous);
+ editor.getSelection().selectElement(sel);
+ link_dialog(editor);
+ $link_button.hide();
+ previous = null;
+ }, 'btn-xs');
+ var $image_button = this.make_hover_button(_t("Edit Image"), function () {
+ image_dialog(editor, new CKEDITOR.dom.element(previous));
+ $image_button.hide();
+ previous = null;
+ });
+
+ // previous is the state of the button-trigger: it's the
+ // currently-ish hovered element which can trigger a button showing.
+ // -ish, because when moving to the button itself ``previous`` is
+ // still set to the element having triggered showing the button.
+ var previous;
+ $(editor.element.$).on('mouseover', 'a, img', function (e) {
+ // Back from edit button -> ignore
+ if (previous && previous === this) { return; }
+
+ var selected = new CKEDITOR.dom.element(this);
+ if (selected.data('oe-model') === 'ir.ui.view'
+ || selected.data('cke-realelement')
+ || selected.isReadOnly()) {
+ return;
+ }
+
+ previous = this;
+ var $selected = $(this);
+ var position = $selected.offset();
+ if ($selected.is('img')) {
+ var image_top = position.top + parseInt($selected.css('marginTop'), 10);
+ var image_left = position.left + parseInt($selected.css('marginLeft'), 10);
+ $link_button.hide();
+ // center button on image
+ $image_button.show().offset({
+ top: $selected.outerHeight() / 2
+ + image_top
+ - $image_button.outerHeight() / 2,
+ left: $selected.outerWidth() / 2
+ + image_left
+ - $image_button.outerWidth() / 2,
+ });
+ } else {
+ $image_button.hide();
+ // put button below link, horizontally centered
+ $link_button.show().offset({
+ top: $selected.outerHeight()
+ + position.top,
+ left: $selected.outerWidth() / 2
+ + position.left
+ - $link_button.outerWidth() / 2
+ })
+ }
+ }).on('mouseleave', 'a, img', function (e) {
+ var current = document.elementFromPoint(e.clientX, e.clientY);
+ if (current === $link_button[0] || current === $image_button[0]) {
+ return;
+ }
+ $image_button.add($link_button).hide();
+ previous = null;
+ });
+ }
});
var blocks_selector = _.keys(CKEDITOR.dtd.$block).join(',');
@@ -1415,14 +1474,11 @@
var output = [];
for(var i=0; i appears when focusing RTE in FF, ignore
- continue;
- }
- if (node.className.indexOf('image-edit-button') !== -1) {
- // [Edit] button added and removed on image hover, don't count
- // as making parent node dirty
- continue;
+ if (node.nodeType === document.ELEMENT_NODE) {
+ if (node.nodeName === 'BR' && node.getAttribute('type') === '_moz') {
+ //
appears when focusing RTE in FF, ignore
+ continue;
+ }
}
output.push(node);
diff --git a/addons/website/static/src/js/website.snippets.animation.js b/addons/website/static/src/js/website.snippets.animation.js
index 1dbb2d7426e..7d3b84f2254 100644
--- a/addons/website/static/src/js/website.snippets.animation.js
+++ b/addons/website/static/src/js/website.snippets.animation.js
@@ -106,6 +106,7 @@
$(window).scroll();
};
img.src = this.$target.css("background-image").replace(/url\(['"]*|['"]*\)/g, "");
+ $(window).scroll();
}
});
diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js
index c083aeea70f..ef1afe88d47 100644
--- a/addons/website/static/src/js/website.snippets.editor.js
+++ b/addons/website/static/src/js/website.snippets.editor.js
@@ -301,7 +301,11 @@
$toInsert = $snippet.find('.oe_snippet_body').clone();
$toInsert.removeClass('oe_snippet_body');
- $toInsert.attr('data-snippet-id', snipped_id);
+ if (!$toInsert.data('snippet-id')) {
+ $toInsert.attr('data-snippet-id', snipped_id);
+ } else {
+ snipped_id = $toInsert.data('snippet-id');
+ }
} else if( action === 'mutate' ){
if (!$snippet.data('selector')) {
@@ -936,7 +940,8 @@
* function called just before save vue
*/
clean_for_save: function () {
- this.$target.find(".row:empty").remove();
+ this.$target.removeAttr('contentEditable')
+ .find('*').removeAttr('contentEditable');
},
});
@@ -1104,7 +1109,7 @@
},
on_clone: function () {
var $clone = this.$target.clone(false);
- var _class = $clone.attr("class").replace(/\s*(col-md-|col-lg-offset-|col-md-offset-)([0-9-]+)/g, '');
+ var _class = $clone.attr("class").replace(/\s*(col-lg-offset-|col-md-offset-)([0-9-]+)/g, '');
_class += ' col-md-1';
$clone.attr("class", _class);
this.$target.after($clone);
@@ -1143,13 +1148,7 @@
website.snippet.editorRegistry.slider = website.snippet.editorRegistry.resize.extend({
drop_and_build_snippet: function() {
- var id = 0;
- $(".carousel").each(function () {
- var _id = +$(this).attr("id").replace(/^[^a-z]+/i, '');
- if (id <= _id) {
- id = _id + 1;
- }
- });
+ var id = $(".carousel").length;
this.id = "myCarousel" + id;
this.$target.attr("id", this.id);
this.$target.find(".carousel-control").attr("href", "#myCarousel" + id);
@@ -1174,8 +1173,6 @@
if(!this.$target.find(".item.active").length) {
this.$target.find(".item:first").addClass("active");
}
- this.$target.removeAttr('contentEditable')
- .find('*').removeAttr('contentEditable');
},
onFocus: function () {
this._super();
@@ -1186,13 +1183,14 @@
this.$target.carousel('cycle');
},
start : function () {
+ var self = this;
this._super();
this.id = this.$target.attr("id");
this.$inner = this.$target.find('.carousel-inner');
this.$indicators = this.$target.find('.carousel-indicators');
- this.$editor.find(".js_add").on('click', _.bind(this.on_add_slide, this));
- this.$editor.find(".js_remove").on('click', _.bind(this.on_remove_slide, this));
+ this.$editor.find(".js_add").on('click', function () {self.on_add_slide(); return false;});
+ this.$editor.find(".js_remove").on('click', function () {self.on_remove_slide(); return false;});
this.rebind_event();
},
@@ -1318,6 +1316,8 @@
this.$target.on('snippet-style-change snippet-style-preview', function () {
self.$target.data("snippet-view").set_values();
});
+ this.$target.attr('contentEditable', 'false');
+ this.$target.find('> div > .oe_structure').attr('contentEditable', 'true');
},
scroll: function () {
var self = this;
diff --git a/addons/website/static/src/js/website.tour.banner.js b/addons/website/static/src/js/website.tour.banner.js
index 41c12f7a592..75838ada953 100644
--- a/addons/website/static/src/js/website.tour.banner.js
+++ b/addons/website/static/src/js/website.tour.banner.js
@@ -103,7 +103,7 @@
},
{
stepId: 'activate-text-block-title',
- element: '#wrap [data-snippet-id=three-columns] .text-center[data-snippet-id=colmd]',
+ element: '#wrap [data-snippet-id=three-columns]:first .text-center[data-snippet-id=colmd]',
placement: 'top',
title: "Edit an Area",
content: "Select any area of the page to modify it. Click on this subtitle.",
@@ -115,11 +115,11 @@
},
{
stepId: 'remove-text-block-title',
- element: '.oe_snippet_remove:last',
+ element: '.ui-draggable.oe_active .oe_snippet_remove',
placement: 'top',
reflex: true,
title: "Delete the Title",
- content: "From this toolbar you can move, duplicate or delete the selected zone. Click on the cross to delete the title.",
+ content: "From this toolbar you can move, duplicate or delete the selected zone. Click on the trash can to delete the title.",
},
{
stepId: 'save-changes',
diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js
index 3d46e51c28d..a14a55bded5 100644
--- a/addons/website/static/src/js/website.tour.js
+++ b/addons/website/static/src/js/website.tour.js
@@ -38,8 +38,23 @@
self.moveToNextStep();
});
};
- } else {
- step.onShow = step.triggers;
+ } else if (step.triggers) {
+ step.onShow = (function () {
+ var executed = false;
+ return function () {
+ if (!executed) {
+ step.triggers();
+ executed = true;
+ }
+ };
+ }());
+ } else if (step.reflex) {
+ step.onShow = function () {
+ $(step.element).one('click', function () {
+ self.moveToNextStep();
+ });
+ };
+ delete step.reflex;
}
return step;
}));
@@ -84,17 +99,18 @@
}
},
moveToNextStep: function () {
- this.moveToStep(this.currentStepIndex() + 1);
+ var nextStepIndex = this.currentStepIndex() + 1;
+ this.moveToStep(nextStepIndex);
},
stop: function () {
this.tour.end();
},
redirect: function (url) {
url = url || new website.UrlParser(window.location.href);
- if (this.startPath && url.pathname !== this.startPath) {
- var newUrl = this.startPath + (url.search ? (url.search + "&") : "?") + this.id + "=true";
- window.location.replace(newUrl);
- }
+ var path = (this.startPath && url.pathname !== this.startPath) ? this.startPath : url.pathname;
+ var search = url.addToSearch(this.id + "=true");
+ var newUrl = path + search;
+ window.location.replace(newUrl);
},
ended: function () {
return this.tourStorage.getItem(this.id+'_end') === "yes";
@@ -146,6 +162,18 @@
this.origin = a.origin;
this.search = a.search;
this.hash = a.hash;
+ this.addToSearch= function (query) {
+ var querystring = _.filter(this.search.split('?'), function (str) {
+ return str;
+ });
+ if (querystring.length > 0) {
+ var queries = querystring[0].split("&");
+ queries.push(query);
+ return "?" + _.uniq(queries).join("&");
+ } else {
+ return "?"+query;
+ }
+ };
},
});
diff --git a/addons/website/static/src/xml/website.editor.xml b/addons/website/static/src/xml/website.editor.xml
index 8f749374485..be80e71afc0 100644
--- a/addons/website/static/src/xml/website.editor.xml
+++ b/addons/website/static/src/xml/website.editor.xml
@@ -6,7 +6,7 @@
+ class="btn">Discard
@@ -170,4 +170,35 @@
+
+
+
+
+
+
+
+ If you discard the current edition, all
+ unsaved changes will be lost.
+
+
You can cancel to return to the edition mode.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/website/static/src/xml/website.menu.xml b/addons/website/static/src/xml/website.menu.xml
index 2276076550a..9277b0d4bc2 100644
--- a/addons/website/static/src/xml/website.menu.xml
+++ b/addons/website/static/src/xml/website.menu.xml
@@ -2,16 +2,16 @@
-
+
-
+
-
-
+
+
@@ -32,11 +32,11 @@
- right indent for multi-level menus
+ right indent for multi-level menus
diff --git a/addons/website/views/snippets.xml b/addons/website/views/snippets.xml
index 085d26803bc..031fedcee4d 100644
--- a/addons/website/views/snippets.xml
+++ b/addons/website/views/snippets.xml
@@ -711,10 +711,11 @@
Very Fast
-
-
+
+
@@ -722,51 +723,57 @@
Parallax Slider
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
- Write here a quote from one of your customer. Quotes are are
- great way to give confidence in your products or services.
-
- Author of this quote
-
+
+
+
+ Write here a quote from one of your customer. Quotes are are
+ great way to give confidence in your products or services.
+
+ Author of this quote
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OpenERP provides essential platform for our project management.
+ Things are better organized and more visible with it.
+
+ John Doe, CEO
+
+
+
+
-
-
-
-
-
-
-
-
- OpenERP provides essential platform for our project management.
- Things are better organized and more visible with it.
-
- John Doe, CEO
-
-
-
-
-
-
-
@@ -794,18 +801,19 @@
-
+
-
+
@@ -162,16 +162,16 @@
Contact us
-
-
-
-
-
-
+
+
+
+
+
+
@@ -193,15 +193,15 @@
-
-
-
-
+
-
+
Add a language...
@@ -227,7 +227,7 @@
-
-
+
Sign in
@@ -528,7 +528,7 @@ Sitemap: sitemap.xml
Name
✆
-
+
diff --git a/addons/website_blog/controllers/main.py b/addons/website_blog/controllers/main.py
index 401fd3ce4b2..29f680f8183 100644
--- a/addons/website_blog/controllers/main.py
+++ b/addons/website_blog/controllers/main.py
@@ -110,7 +110,7 @@ class WebsiteBlog(http.Controller):
domain = []
if category:
- path_filter += "cat/%s/" % category.id
+ path_filter += "%s/" % category.id
domain += [("id", "in", [blog.id for blog in category.blog_post_ids])]
if tag:
path_filter += 'tag/%s/' % tag.id
@@ -178,7 +178,7 @@ class WebsiteBlog(http.Controller):
- 'nav_list': a dict [year][month] for archives navigation
"""
- pager_url = "/blog/%s" % blog_post.id
+ pager_url = "/blogpost/%s" % blog_post.id
pager = request.website.pager(
url=pager_url,
@@ -233,7 +233,7 @@ class WebsiteBlog(http.Controller):
new_blog_post_id = request.registry['blog.post'].create(
request.cr, request.uid, {
'category_id': category_id,
- 'name': _("Blog title"),
+ 'name': _("Blog Post Title"),
'content': '',
'website_published': False,
}, context=create_context)
diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py
index ed64ea26b1c..92de50ee772 100644
--- a/addons/website_blog/models/website_blog.py
+++ b/addons/website_blog/models/website_blog.py
@@ -79,7 +79,7 @@ class BlogPost(osv.Model):
'oe_expand_container_tag': 'div',
'oe_expand_container_class': 'oe_mail_expand text-center',
'oe_expand_container_content': '',
- 'oe_expand_a_href': '/blog/%d/' % page.id,
+ 'oe_expand_a_href': '/blogpost/%d' % page.id,
'oe_expand_a_class': 'oe_mail_expand btn btn-info',
'oe_expand_separator_node': 'br',
},
diff --git a/addons/website_blog/static/src/js/website.tour.blog.js b/addons/website_blog/static/src/js/website.tour.blog.js
index 3768d7d013a..2a7d3e69a47 100644
--- a/addons/website_blog/static/src/js/website.tour.blog.js
+++ b/addons/website_blog/static/src/js/website.tour.blog.js
@@ -87,7 +87,7 @@
element: 'button[data-action=snippet]',
placement: 'bottom',
title: "Layout Your Blog Post",
- content: "Use well designed building blocks to structure the content of your blog.",
+ content: "Use well designed building blocks to structure the content of your blog. Click 'Insert Blocks' to add new content.",
triggers: function () {
$('button[data-action=snippet]').one('click', function () {
self.moveToNextStep();
diff --git a/addons/website_blog/views/website_blog_templates.xml b/addons/website_blog/views/website_blog_templates.xml
index 958f29c770a..10b9cf4973b 100644
--- a/addons/website_blog/views/website_blog_templates.xml
+++ b/addons/website_blog/views/website_blog_templates.xml
@@ -55,25 +55,25 @@
-
+
-
-
In
+
+ In
-
+
No keywords defined!
-
@@ -83,18 +83,6 @@
-
-
@@ -125,10 +113,10 @@
- ,
+ ,
-
+
@@ -257,7 +245,7 @@
- ,
+ ,
diff --git a/addons/website_project/views/website_project.xml b/addons/website_project/views/website_project.xml
index b968b415e22..88e048c8979 100644
--- a/addons/website_project/views/website_project.xml
+++ b/addons/website_project/views/website_project.xml
@@ -36,7 +36,7 @@
-
+
Ending Date:
diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py
index 8de4712c579..7cfde4c9948 100644
--- a/addons/website_sale/controllers/main.py
+++ b/addons/website_sale/controllers/main.py
@@ -288,26 +288,33 @@ class Ecommerce(http.Controller):
request.context = dict(request.context, pricelist=self.get_pricelist())
- quantity = 0
+ # set order_line_id and product_id
+ if order_line_id:
+ order_line = order_line_obj.browse(request.cr, SUPERUSER_ID, order_line_id, context=request.context)
+ if order_line.order_id.id == order.id:
+ product_id = order_line.product_id.id
+ else:
+ order_line_id = None
+ else:
+ order_line_ids = order_line_obj.search(request.cr, SUPERUSER_ID,
+ [('order_id', '=', order.id),('product_id', '=', product_id)], context=request.context)
+ if order_line_ids:
+ order_line_id = order_line_ids[0]
+
+ if not order_line_id and not product_id:
+ return 0
# values initialisation
+ quantity = 0
values = {}
-
- domain = [('order_id', '=', order.id)]
if order_line_id:
- domain += [('id', '=', order_line_id)]
- else:
- domain += [('product_id', '=', product_id)]
-
- order_line_ids = order_line_obj.search(request.cr, SUPERUSER_ID, domain, context=request.context)
- if order_line_ids:
- order_line = order_line_obj.read(request.cr, SUPERUSER_ID, order_line_ids, [], context=request.context)[0]
+ order_line_val = order_line_obj.read(request.cr, SUPERUSER_ID, [order_line_id], [], context=request.context)[0]
if not product_id:
- product_id = order_line['product_id'][0]
+ product_id = order_line_val['product_id'][0]
if set_number >= 0:
quantity = set_number
else:
- quantity = order_line['product_uom_qty'] + number
+ quantity = order_line_val['product_uom_qty'] + number
if quantity < 0:
quantity = 0
else:
@@ -316,17 +323,17 @@ class Ecommerce(http.Controller):
quantity = 1
# change and record value
- vals = order_line_obj._recalculate_product_values(request.cr, request.uid, order_line_ids, product_id, context=request.context)
+ vals = order_line_obj._recalculate_product_values(request.cr, request.uid, [order_line_id], product_id, context=request.context)
values.update(vals)
values['product_uom_qty'] = quantity
values['product_id'] = product_id
values['order_id'] = order.id
- if order_line_ids:
- order_line_obj.write(request.cr, SUPERUSER_ID, order_line_ids, values, context=request.context)
+ if order_line_id:
+ order_line_obj.write(request.cr, SUPERUSER_ID, [order_line_id], values, context=request.context)
if not quantity:
- order_line_obj.unlink(request.cr, SUPERUSER_ID, order_line_ids, context=request.context)
+ order_line_obj.unlink(request.cr, SUPERUSER_ID, [order_line_id], context=request.context)
else:
order_line_id = order_line_obj.create(request.cr, SUPERUSER_ID, values, context=request.context)
order_obj.write(request.cr, SUPERUSER_ID, [order.id], {'order_line': [(4, order_line_id)]}, context=request.context)
@@ -338,7 +345,7 @@ class Ecommerce(http.Controller):
prod_obj = request.registry.get('product.product')
# must have a draft sale order with lines at this point, otherwise reset
- order = context.get('website_sale_order')
+ order = request.registry['website'].get_current_order(request.cr, request.uid, context=request.context)
if order and order.state != 'draft':
request.registry['website'].sale_reset_order(cr, uid, context=context)
return request.redirect('/shop/')
@@ -367,9 +374,14 @@ class Ecommerce(http.Controller):
}
return request.website.render("website_sale.mycart", values)
- @website.route(['/shop/add_cart/'], type='http', auth="public", multilang=True)
- def add_cart(self, product_id=None, order_line_id=None, remove=None, **kw):
- self.add_product_to_cart(product_id=product_id and int(product_id), order_line_id=order_line_id and int(order_line_id), number=(remove and -1 or 1))
+ @website.route(['/shop/add_cart/', '/shop/add_cart/
/'], type='http', auth="public", multilang=True, methods=['POST'])
+ def add_cart(self, product=None, product_id=None, remove=None, **kw):
+ self.add_product_to_cart(product_id=int(product_id or product.id))
+ return request.redirect("/shop/mycart/")
+
+ @website.route(['/shop/change_cart//'], type='http', auth="public", multilang=True)
+ def add_cart_order_line(self, order_line=None, remove=None, **kw):
+ self.add_product_to_cart(order_line_id=int(order_line.id), number=(remove and -1 or 1))
return request.redirect("/shop/mycart/")
@website.route(['/shop/add_cart_json/'], type='json', auth="public")
@@ -390,7 +402,7 @@ class Ecommerce(http.Controller):
cr, uid, context, registry = request.cr, request.uid, request.context, request.registry
# must have a draft sale order with lines at this point, otherwise reset
- order = context.get('website_sale_order')
+ order = request.registry['website'].get_current_order(request.cr, request.uid, context=request.context)
if not order or order.state != 'draft' or not order.order_line:
request.registry['website'].sale_reset_order(cr, uid, context=context)
return request.redirect('/shop/')
@@ -421,14 +433,20 @@ class Ecommerce(http.Controller):
checkout = values['checkout']
error = values['error']
- if not request.uid == request.registry['website'].get_public_user(cr, uid, context):
+ partner = None
+ public_id = request.registry['website'].get_public_user(cr, uid, context)
+ if not request.uid == public_id:
partner = orm_user.browse(cr, uid, uid, context).partner_id
+ elif order.partner_id and order.partner_id.id != public_id:
+ partner = orm_partner.browse(cr, SUPERUSER_ID, order.partner_id.id, context)
+
+ if partner:
partner_info = info.from_partner(partner)
checkout.update(partner_info)
- shipping_ids = orm_partner.search(cr, uid, [("parent_id", "=", partner.id), ('type', "=", 'delivery')], context=context)
+ shipping_ids = orm_partner.search(cr, SUPERUSER_ID, [("parent_id", "=", partner.id), ('type', "=", 'delivery')], context=context)
if shipping_ids:
values['shipping'] = "true"
- shipping_partner = orm_partner.browse(cr, uid, shipping_ids[0], context)
+ shipping_partner = orm_partner.browse(cr, SUPERUSER_ID, shipping_ids[0], context)
checkout['shipping_name'] = getattr(shipping_partner, 'name')
checkout['shipping_phone'] = getattr(shipping_partner, 'phone')
checkout['shipping_street'] = getattr(shipping_partner, 'street')
@@ -446,6 +464,7 @@ class Ecommerce(http.Controller):
@website.route(['/shop/confirm_order/'], type='http', auth="public", multilang=True)
def confirm_order(self, **post):
cr, uid, context, registry = request.cr, request.uid, request.context, request.registry
+ order_line_obj = request.registry.get('sale.order')
# must have a draft sale order with lines at this point, otherwise redirect to shop
order = request.registry['website'].get_current_order(request.cr, request.uid, context=request.context)
@@ -534,7 +553,8 @@ class Ecommerce(http.Controller):
'partner_shipping_id': shipping_id or partner_id
}
order_info.update(registry.get('sale.order').onchange_partner_id(cr, SUPERUSER_ID, [], order.partner_id.id, context=context)['value'])
- order.write(order_info)
+
+ order_line_obj.write(cr, SUPERUSER_ID, [order.id], order_info, context=context)
return request.redirect("/shop/payment/")
@@ -553,7 +573,7 @@ class Ecommerce(http.Controller):
payment_obj = request.registry.get('payment.acquirer')
# if no sale order at this stage: back to checkout beginning
- order = context.get('website_sale_order')
+ order = request.registry['website'].get_current_order(request.cr, request.uid, context=request.context)
if not order or not order.state == 'draft' or not order.order_line:
request.registry['website'].sale_reset_order(cr, uid, context=context)
return request.redirect("/shop/")
@@ -677,11 +697,13 @@ class Ecommerce(http.Controller):
if transaction_id is None:
tx = context.get('website_sale_transaction')
+ if not tx:
+ return request.redirect('/shop/')
else:
tx = request.registry['payment.transaction'].browse(cr, uid, transaction_id, context=context)
if sale_order_id is None:
- order = context.get('website_sale_order')
+ order = request.registry['website'].get_current_order(request.cr, request.uid, context=request.context)
else:
order = request.registry['sale.order'].browse(cr, uid, sale_order_id, context=context)
diff --git a/addons/website_sale/models/website_sale.py b/addons/website_sale/models/website_sale.py
index 8d5404810aa..a2b087b4d7a 100644
--- a/addons/website_sale/models/website_sale.py
+++ b/addons/website_sale/models/website_sale.py
@@ -41,8 +41,7 @@ class sale_order_line(osv.Model):
if context is None:
context = {}
user_obj = self.pool.get('res.users')
- product_id = product_id and int(product_id) or \
- ids and self.browse(cr, uid, ids[0], context=context).product_id.id
+ product_id = product_id or ids and self.browse(cr, uid, ids[0], context=context).product_id.id
return self.product_id_change(
cr, SUPERUSER_ID, ids,
diff --git a/addons/website_sale/static/src/js/website_sale.js b/addons/website_sale/static/src/js/website_sale.js
index 46a360c5761..d5fcd913684 100644
--- a/addons/website_sale/static/src/js/website_sale.js
+++ b/addons/website_sale/static/src/js/website_sale.js
@@ -38,12 +38,13 @@ $(document).ready(function () {
$('.oe_website_sale a.js_add_cart_json').on('click', function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
- var product = $link.attr("href").match(/product_id=([0-9]+)/);
- var product_id = product ? +product[1] : 0;
- if (!product) {
- var line = $link.attr("href").match(/order_line_id=([0-9]+)/);
- order_line_id = line ? +line[1] : 0;
- }
+ var href = $link.attr("href");
+
+ var add_cart = href.match(/add_cart\/([0-9]+)/);
+ var product_id = add_cart && +add_cart[1] || false;
+
+ var change_cart = href.match(/change_cart\/([0-9]+)/);
+ var order_line_id = change_cart && +change_cart[1] || false;
openerp.jsonRpc("/shop/add_cart_json/", 'call', {
'product_id': product_id,
'order_line_id': order_line_id,
diff --git a/addons/website_sale/views/website_sale.xml b/addons/website_sale/views/website_sale.xml
index 8b6e91c9720..22f8dae0663 100644
--- a/addons/website_sale/views/website_sale.xml
+++ b/addons/website_sale/views/website_sale.xml
@@ -8,7 +8,7 @@
-
+
My cart
@@ -42,8 +42,8 @@
-
-
+