diff --git a/addons/auth_oauth/static/src/js/auth_oauth.js b/addons/auth_oauth/static/src/js/auth_oauth.js index 5046469a5dc..a4295877e76 100644 --- a/addons/auth_oauth/static/src/js/auth_oauth.js +++ b/addons/auth_oauth/static/src/js/auth_oauth.js @@ -3,6 +3,7 @@ openerp.auth_oauth = function(instance) { _lt = instance.web._lt; var QWeb = instance.web.qweb; + /* TODO: make this a server side controller instance.web.Login.include({ start: function(parent, params) { var self = this; @@ -76,5 +77,5 @@ openerp.auth_oauth = function(instance) { }; }, }); - + */ }; diff --git a/addons/auth_oauth_signup/static/src/js/auth_oauth_signup.js b/addons/auth_oauth_signup/static/src/js/auth_oauth_signup.js index 6715943af9b..926fb607358 100644 --- a/addons/auth_oauth_signup/static/src/js/auth_oauth_signup.js +++ b/addons/auth_oauth_signup/static/src/js/auth_oauth_signup.js @@ -1,5 +1,6 @@ openerp.auth_oauth_signup = function(instance) { + /* TODO: make this a server side controller // override Login._oauth_state to add the signup token in the state instance.web.Login.include({ _oauth_state: function(provider) { @@ -10,5 +11,6 @@ openerp.auth_oauth_signup = function(instance) { return state; }, }); + */ }; diff --git a/addons/auth_openid/static/src/js/auth_openid.js b/addons/auth_openid/static/src/js/auth_openid.js index ac2804cb130..a96346f4699 100644 --- a/addons/auth_openid/static/src/js/auth_openid.js +++ b/addons/auth_openid/static/src/js/auth_openid.js @@ -3,6 +3,7 @@ openerp.auth_openid = function(instance) { var QWeb = instance.web.qweb; +/* TODO: make this a server side controller instance.web.Login = instance.web.Login.extend({ start: function() { var self = this; @@ -149,6 +150,7 @@ instance.web.Login = instance.web.Login.extend({ } }); +*/ }; diff --git a/addons/auth_signup/__openerp__.py b/addons/auth_signup/__openerp__.py index 08740962c59..50402207018 100644 --- a/addons/auth_signup/__openerp__.py +++ b/addons/auth_signup/__openerp__.py @@ -34,13 +34,14 @@ Allow users to sign up and reset their password 'depends': [ 'base_setup', 'email_template', + 'web', ], 'data': [ 'auth_signup_data.xml', 'res_config.xml', 'res_users_view.xml', + 'views/auth_signup_login.xml', ], 'js': ['static/src/js/auth_signup.js'], - 'qweb': ['static/src/xml/auth_signup.xml'], 'bootstrap': True, } diff --git a/addons/auth_signup/controllers/main.py b/addons/auth_signup/controllers/main.py index a778cbcf061..650268755e5 100644 --- a/addons/auth_signup/controllers/main.py +++ b/addons/auth_signup/controllers/main.py @@ -21,64 +21,71 @@ import logging import openerp +import openerp.addons.web.controllers.main as webmain from openerp import http -from openerp.http import request -from openerp.modules.registry import RegistryManager -from ..res_users import SignupError +from openerp.http import request, LazyResponse +from openerp.tools.translate import _ _logger = logging.getLogger(__name__) -class Controller(http.Controller): +class Home(openerp.addons.web.controllers.main.Home): - @http.route('/auth_signup/get_config', type='json', auth="none") - def get_config(self, dbname): - """ retrieve the module config (which features are enabled) for the login page """ - registry = RegistryManager.get(dbname) - with registry.cursor() as cr: - icp = registry.get('ir.config_parameter') - config = { - 'signup': icp.get_param(cr, openerp.SUPERUSER_ID, 'auth_signup.allow_uninvited') == 'True', - 'reset_password': icp.get_param(cr, openerp.SUPERUSER_ID, 'auth_signup.reset_password') == 'True', - } - return config + @http.route() + def web_login(self, *args, **kw): + # TODO: ensure_db() + request.disable_db = False - @http.route('/auth_signup/retrieve', type='json', auth="none") - def retrieve(self, dbname, token): - """ retrieve the user info (name, login or email) corresponding to a signup token """ - registry = RegistryManager.get(dbname) - with registry.cursor() as cr: - res_partner = registry.get('res.partner') - user_info = res_partner.signup_retrieve_info(cr, openerp.SUPERUSER_ID, token) - return user_info - - @http.route('/auth_signup/signup', type='json', auth="none") - def signup(self, dbname, token, **values): - """ sign up a user (new or existing)""" - try: - self._signup_with_values(dbname, token, values) - except SignupError, e: - return {'error': openerp.tools.exception_to_unicode(e)} - return {} - - def _signup_with_values(self, dbname, token, values): - registry = RegistryManager.get(dbname) - with registry.cursor() as cr: - res_users = registry.get('res.users') - res_users.signup(cr, openerp.SUPERUSER_ID, values, token) - - @http.route('/auth_signup/reset_password', type='json', auth="none") - def reset_password(self, dbname, login): - """ retrieve user, and perform reset password """ - registry = RegistryManager.get(dbname) - with registry.cursor() as cr: + mode = request.params.get('mode') + qcontext = request.params.copy() + response = webmain.render_bootstrap_template(request.session.db, 'auth_signup.signup', qcontext, lazy=True) + token = qcontext.get('token', None) + token_infos = None + if token: try: - res_users = registry.get('res.users') - res_users.reset_password(cr, openerp.SUPERUSER_ID, login) - cr.commit() - except Exception as e: - # signup error - _logger.exception('error when resetting password') - raise(e) - return True + # retrieve the user info (name, login or email) corresponding to a signup token + res_partner = request.registry.get('res.partner') + token_infos = res_partner.signup_retrieve_info(request.cr, openerp.SUPERUSER_ID, token) + for k, v in token_infos.items(): + qcontext.setdefault(k, v) + except: + qcontext['error'] = _("Invalid signup token") + response.params['template'] = 'web.login' + return response + + # retrieve the module config (which features are enabled) for the login page + icp = request.registry.get('ir.config_parameter') + config = { + 'signup': icp.get_param(request.cr, openerp.SUPERUSER_ID, 'auth_signup.allow_uninvited') == 'True', + 'reset': icp.get_param(request.cr, openerp.SUPERUSER_ID, 'auth_signup.reset_password') == 'True', + } + qcontext.update(config) + + if 'error' in qcontext or mode not in ('reset', 'signup') or (not token and not config[mode]): + response = super(Home, self).web_login(*args, **kw) + if isinstance(response, LazyResponse): + response.params['values'].update(config) + return response + + if request.httprequest.method == 'GET': + if token_infos: + qcontext.update(token_infos) + else: + res_users = request.registry.get('res.users') + login = request.params.get('login') + if mode == 'reset' and not token: + try: + res_users.reset_password(request.cr, openerp.SUPERUSER_ID, login) + qcontext['message'] = _("An email has been sent with credentials to reset your password") + response.params['template'] = 'web.login' + except: + qcontext['error'] = _("Could not reset your password") + _logger.exception('error when resetting password') + else: + values = dict((key, qcontext.get(key)) for key in ('login', 'name', 'password')) + res_users.signup(request.cr, openerp.SUPERUSER_ID, values, token) + request.cr.commit() + return super(Home, self).web_login(*args, **kw) + + return response # vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py index 669ea3a56a1..37ad9f68fe4 100644 --- a/addons/auth_signup/res_users.py +++ b/addons/auth_signup/res_users.py @@ -66,19 +66,20 @@ class res_partner(osv.Model): self.signup_prepare(cr, uid, [partner.id], context=context) partner.refresh() - # the parameters to encode for the query and fragment part of url - query = {'db': cr.dbname} + # the parameters to encode for the query + query = dict(db=cr.dbname) signup_type = context.get('signup_force_type_in_url', partner.signup_type or '') - fragment = {'action': action, 'type': signup_type} + if signup_type: + query['mode'] = signup_type if partner.signup_token and signup_type: - fragment['token'] = partner.signup_token + query['token'] = partner.signup_token elif partner.user_ids: - fragment['db'] = cr.dbname - fragment['login'] = partner.user_ids[0].login + query['login'] = partner.user_ids[0].login else: continue # no signup token, no user, thus no signup url! + fragment = dict() if view_type: fragment['view_type'] = view_type if menu_id: @@ -88,7 +89,7 @@ class res_partner(osv.Model): if res_id: fragment['id'] = res_id - res[partner.id] = urljoin(base_url, "?%s#%s" % (urlencode(query), urlencode(fragment))) + res[partner.id] = urljoin(base_url, "/web/login?%s#%s" % (urlencode(query), urlencode(fragment))) return res diff --git a/addons/auth_signup/static/src/js/auth_signup.js b/addons/auth_signup/static/src/js/auth_signup.js index d9edb44d65f..a317440fd6b 100644 --- a/addons/auth_signup/static/src/js/auth_signup.js +++ b/addons/auth_signup/static/src/js/auth_signup.js @@ -1,186 +1,19 @@ openerp.auth_signup = function(instance) { - instance.auth_signup = instance.auth_signup || {}; - var _t = instance.web._t; - - instance.web.Login.include({ - start: function() { + openerp.web.LoginForm.include({ + start: function () { var self = this; - this.signup_enabled = false; - this.reset_password_enabled = false; - return this._super().always(function() { - - // Switches the login box to the select mode whith mode == [default|signup|reset] - self.on('change:login_mode', self, function() { - var mode = self.get('login_mode') || 'default'; - self.$('*[data-modes]').each(function() { - var modes = $(this).data('modes').split(/\s+/); - $(this).toggle(modes.indexOf(mode) > -1); - }); - self.$('a.oe_signup_signup:visible').toggle(self.signup_enabled); - self.$('a.oe_signup_reset_password:visible').toggle(self.reset_password_enabled); - }); - - // to switch between the signup and regular login form - self.$('a.oe_signup_signup').click(function(ev) { - self.set('login_mode', 'signup'); + this.$el.on('submit', function () { + var password = self.get_password_field('password'); + var confirm_password = self.get_password_field('confirm_password'); + if (password && confirm_password && (password.value != confirm_password.value)) { + alert("Passwords do not match; please retype them."); return false; - }); - self.$('a.oe_signup_back').click(function(ev) { - self.set('login_mode', 'default'); - delete self.params.token; - return false; - }); - - var dbname = self.selected_db; - - // if there is an error message in params, show it then forget it - if (self.params.error_message) { - self.show_error(self.params.error_message); - delete self.params.error_message; - } - - if (dbname && self.params.login) { - self.$("form input[name=login]").val(self.params.login); - } - - // bind reset password link - self.$('a.oe_signup_reset_password').click(self.do_reset_password); - - if (dbname) { - self.rpc("/auth_signup/get_config", {dbname: dbname}).then(function(result) { - self.signup_enabled = result.signup; - self.reset_password_enabled = result.reset_password; - if (!self.signup_enabled || self.$("form input[name=login]").val()){ - self.set('login_mode', self.params.type || 'default'); - } else { - self.set('login_mode', 'signup'); - } - - // in case of a signup, retrieve the user information from the token - if (self.params.token) { - self.rpc("/auth_signup/retrieve", {dbname: dbname, token: self.params.token}) - .then(self.on_token_loaded, self.on_token_failed); - } - - }); - } else { - // TODO: support multiple database mode - self.set('login_mode', self.params.type || 'default'); } }); }, - - on_token_loaded: function(result) { - // select the right the database - this.selected_db = result.db; - this.on_db_loaded([result.db]); - if (result.token) { - // switch to signup mode, set user name and login - this.set('login_mode', (this.params.type === 'reset' ? 'reset' : 'signup')); - this.$("form input[name=name]").val(result.name).attr("readonly", "readonly"); - if (result.login) { - this.$("form input[name=login]").val(result.login).attr("readonly", "readonly"); - } else { - this.$("form input[name=login]").val(result.email); - } - } else { - // remain in login mode, set login if present - delete this.params.token; - this.set('login_mode', 'default'); - this.$("form input[name=login]").val(result.login || ""); - } - }, - - on_token_failed: function(result, ev) { - if (ev) { - ev.preventDefault(); - } - this.show_error(_t("Invalid signup token")); - delete this.params.db; - delete this.params.token; - this.set('login_mode', 'default'); - }, - - get_params: function(){ - // signup user (or reset password) - var db = this.$("form [name=db]").val(); - var name = this.$("form input[name=name]").val(); - var login = this.$("form input[name=login]").val(); - var password = this.$("form input[name=password]").val(); - var confirm_password = this.$("form input[name=confirm_password]").val(); - if (!db) { - this.do_warn(_t("Login"), _t("No database selected !")); - return false; - } else if (!name) { - this.do_warn(_t("Login"), _t("Please enter a name.")); - return false; - } else if (!login) { - this.do_warn(_t("Login"), _t("Please enter a username.")); - return false; - } else if (!password || !confirm_password) { - this.do_warn(_t("Login"), _t("Please enter a password and confirm it.")); - return false; - } else if (password !== confirm_password) { - this.do_warn(_t("Login"), _t("Passwords do not match; please retype them.")); - return false; - } - var params = { - dbname : db, - token: this.params.token || "", - name: name, - login: login, - password: password, - }; - return params; - }, - - on_submit: function(ev) { - if (ev) { - ev.preventDefault(); - } - var login_mode = this.get('login_mode'); - if (login_mode === 'signup' || login_mode === 'reset') { - var params = this.get_params(); - if (_.isEmpty(params)){ - return false; - } - var self = this, - super_ = this._super; - this.rpc('/auth_signup/signup', params) - .done(function(result) { - if (result.error) { - self.show_error(result.error); - } else { - super_.apply(self, [ev]); - } - }); - } else { - // regular login - this._super(ev); - } - }, - - do_reset_password: function(ev) { - if (ev) { - ev.preventDefault(); - } - var self = this; - var db = this.$("form [name=db]").val(); - var login = this.$("form input[name=login]").val(); - if (!db) { - this.do_warn(_t("Login"), _t("No database selected !")); - return $.Deferred().reject(); - } else if (!login) { - this.do_warn(_t("Login"), _t("Please enter a username or email address.")); - return $.Deferred().reject(); - } - return self.rpc("/auth_signup/reset_password", { dbname: db, login: login }).done(function(result) { - self.show_error(_t("An email has been sent with credentials to reset your password")); - self.set('login_mode', 'default'); - }).fail(function(result, ev) { - ev.preventDefault(); - self.show_error(result.message); - }); + get_password_field: function (field) { + var selector = 'input[name="' + field + '"][type="password"]:visible'; + return this.$(selector)[0]; }, }); }; diff --git a/addons/auth_signup/static/src/xml/auth_signup.xml b/addons/auth_signup/static/src/xml/auth_signup.xml deleted file mode 100644 index 1c41dbed181..00000000000 --- a/addons/auth_signup/static/src/xml/auth_signup.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - Name - - - - Username - Username (Email) - - - this.attr('data-modes', 'default signup reset'); - - - Confirm Password - - - - - - Log in - Sign Up - Reset password - - Sign Up - Back to Login - Reset password - - - - this.attr('data-modes', 'default'); - - - - diff --git a/addons/auth_signup/views/auth_signup_login.xml b/addons/auth_signup/views/auth_signup_login.xml new file mode 100644 index 00000000000..9f5d88eb33a --- /dev/null +++ b/addons/auth_signup/views/auth_signup_login.xml @@ -0,0 +1,90 @@ + + + + + + + Sign up + Reset Password + + + + + + + + + + + + + + + + + + + + Name + + + + + Username (email) + + + + + + Password + + + + + Confirm Password + + + + + + + + + + + + + + + + Back to Login + + Signup + Reset password + + + + + + + + + + + diff --git a/addons/edi/static/src/js/edi.js b/addons/edi/static/src/js/edi.js index 80002bd8743..91d2b842f8a 100644 --- a/addons/edi/static/src/js/edi.js +++ b/addons/edi/static/src/js/edi.js @@ -1,6 +1,7 @@ openerp.edi = function(instance) { var _t = instance.web._t; -instance.edi = {} +instance.edi = {}; + instance.edi.EdiImport = instance.web.Widget.extend({ @@ -10,11 +11,7 @@ instance.edi.EdiImport = instance.web.Widget.extend({ }, start: function() { if (!this.session.session_is_valid()) { - this.show_login(); - this.session.on_session_valid.add({ - callback: this.proxy('show_import'), - unique: true, - }); + instance.redirect('/web/login?redir=' + encodeURIComponent(window.location)); } else { this.show_import(); } @@ -25,12 +22,6 @@ instance.edi.EdiImport = instance.web.Widget.extend({ this.do_import(); }, - show_login: function() { - this.destroy_content(); - this.login = new instance.web.Login(this); - this.login.appendTo(this.$el); - }, - destroy_content: function() { _.each(_.clone(this.getChildren()), function(el) { el.destroy(); diff --git a/addons/product/product.py b/addons/product/product.py index 9cba104831f..0bd3d43ecea 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -568,10 +568,15 @@ class product_product(osv.osv): _product_incoming_qty = _get_product_available_func(('confirmed','waiting','assigned'), ('in',)) def _product_lst_price(self, cr, uid, ids, name, arg, context=None): - res = {} + res = dict.fromkeys(ids, 0.0) product_uom_obj = self.pool.get('product.uom') - for id in ids: - res.setdefault(id, 0.0) + + # retrieve pricelist + pricelist = None + if context.get('pricelist'): + pricelist = self.pool['product.pricelist'].browse(cr, uid, context.get('pricelist'), context=context) + base_currency = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id + for product in self.browse(cr, uid, ids, context=context): if 'uom' in context: uom = product.uos_id or product.uom_id @@ -579,7 +584,11 @@ class product_product(osv.osv): uom.id, product.list_price, context['uom']) else: res[product.id] = product.list_price - res[product.id] = (res[product.id] or 0.0) * (product.price_margin or 1.0) + product.price_extra + res[product.id] = (res[product.id] or 0.0) * (product.price_margin or 1.0) + product.price_extra + # update the result, according to the eventual pricelist currency + if pricelist and pricelist.currency_id: + res[product.id] = self.pool['res.currency'].compute( + cr, uid, base_currency.id, pricelist.currency_id.id, res[product.id], round=False, context=context) return res def _save_product_lst_price(self, cr, uid, product_id, field_name, field_value, arg, context=None): diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index 56132472a17..da4dd88e162 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -20,7 +20,7 @@ import openerp from openerp.osv import fields from openerp.addons.website.models import website from openerp.addons.web import http -from openerp.addons.web.http import request +from openerp.addons.web.http import request, LazyResponse from ..utils import slugify @@ -42,6 +42,14 @@ class Website(openerp.addons.web.controllers.main.Home): pass return self.page("website.homepage") + @http.route(website=True, auth="public", multilang=True) + def web_login(self, *args, **kw): + response = super(Website, self).web_login(*args, **kw) + if isinstance(response, LazyResponse): + values = dict(response.params['values'], disable_footer=True) + response = request.website.render(response.params['template'], values) + return response + @http.route('/pagenew/', type='http', auth="user") def pagenew(self, path, noredirect=NOPE): web = request.registry['website'] diff --git a/addons/website/static/src/css/website.css b/addons/website/static/src/css/website.css index 72053e130f2..170b6b5ff87 100644 --- a/addons/website/static/src/css/website.css +++ b/addons/website/static/src/css/website.css @@ -491,3 +491,8 @@ span[data-oe-type="monetary"] { -o-column-count: 3; column-count: 3; } + +.oe_website_login_container { + width: 400px; + margin: 40px auto; +} diff --git a/addons/website/static/src/css/website.sass b/addons/website/static/src/css/website.sass index 7c1825d6670..0709047bb02 100644 --- a/addons/website/static/src/css/website.sass +++ b/addons/website/static/src/css/website.sass @@ -392,3 +392,6 @@ span[data-oe-type="monetary"] .oe_template_fallback @include column-count(3) +.oe_website_login_container + width: 400px + margin: 40px auto diff --git a/addons/website/static/src/js/website.ace.js b/addons/website/static/src/js/website.ace.js index 4ff5aa44146..6433330e50e 100644 --- a/addons/website/static/src/js/website.ace.js +++ b/addons/website/static/src/js/website.ace.js @@ -94,11 +94,18 @@ }).then(function (views) { self.loadViews.call(self, views); self.open.call(self); - // cf. fp's direct request - if (views.length >= 2) { - var mainTemplate = views[1]; - self.$('#ace-view-list').val(mainTemplate.id).trigger('change'); - } + var curentHash = window.location.hash; + var indexOfView = curentHash.indexOf("?view="); + if (indexOfView >= 0) { + var viewId = parseInt(curentHash.substring(indexOfView + 6, curentHash.length), 10); + self.$('#ace-view-list').val(viewId).change(); + } else { + if (views.length >= 2) { + var mainTemplate = views[1]; + self.$('#ace-view-list').val(mainTemplate.id).trigger('change'); + } + window.location.hash = hash; + } }); var $editor = self.$('.ace_editor'); @@ -253,7 +260,9 @@ $.when.apply($, requests).then(function () { self.reloadPage.call(self); }).fail(function (source, error) { - var message = (error.data.arguments[0] === "Access Denied") ? "Access denied: please sign in" : error.message; + var message = _.isString(error) ? error + : (error.data.arguments[0] === "Access Denied") ? "Access denied: please sign in" + : error.message; self.displayError.call(self, message); }); }, @@ -266,7 +275,7 @@ args: [[session.id], { 'arch': xml.xml }, website.get_context()], }); } else { - return $.Deferred().fail("Malformed XML document"); + return $.Deferred().reject(null, "Malformed XML document"); } }, updateHash: function () { @@ -282,14 +291,6 @@ }, open: function () { this.$el.removeClass('oe_ace_closed').addClass('oe_ace_open'); - var curentHash = window.location.hash; - var indexOfView = curentHash.indexOf("?view="); - if (indexOfView >= 0) { - var viewId = parseInt(curentHash.substring(indexOfView + 6, curentHash.length), 10); - this.$('#ace-view-list').val(viewId).change(); - } else { - window.location.hash = hash; - } }, close: function () { window.location.hash = ""; diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index f5a1c845f28..7cd3a4be67b 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -836,7 +836,7 @@ .on('snippet-dropped', function (e, el) { // CKEDITOR data processor extended by widgets plugin // to add wrappers around upcasting elements - el.outerHTML = editor.dataProcessor.toHtml(el.outerHTML, { + el.innerHTML = editor.dataProcessor.toHtml(el.innerHTML, { fixForBody: false, dontFilter: true, }); diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js index e232a050b27..c6c2b21f9d4 100644 --- a/addons/website/static/src/js/website.js +++ b/addons/website/static/src/js/website.js @@ -263,7 +263,7 @@ dom_ready.then(function () { /* ----- BOOTSTRAP STUFF ---- */ - $('.js_tooltip').bstooltip(); + // $('.js_tooltip').bstooltip(); /* ----- PUBLISHING STUFF ---- */ $(document).on('click', '.js_publish_management .js_publish_btn', function () { diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index 7e8d2aea7a0..f58bd048e80 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -295,6 +295,7 @@ }, }); + website.EditorBar.include({ tours: [], init: function () { @@ -340,13 +341,23 @@ window.onbeforeunload = function () { clearTimeout(overlapsCrash); }; + function throwError (message) { + console.log(JSON.parse(window.localStorage.getItem("test-report"))); + test.reset(); + throw message; + } function executeStep (step) { + // check if they are a cycle var lastStep = window.localStorage.getItem(testId); - var tryStep = lastStep != step.stepId ? 0 : parseInt(window.localStorage.getItem("last-"+testId) || 0, 10)+1; - window.localStorage.setItem("last-"+testId, tryStep); + var tryStep = lastStep != step.stepId ? 0 : (+(window.localStorage.getItem("test-last-"+testId) || 0) + 1); + window.localStorage.setItem("test-last-"+testId, tryStep); if (tryStep > 2) { - window.localStorage.removeItem(testId); - throw "Test: '" + testId + "' cycling step: '" + step.stepId + "'"; + throwError("Test: '" + testId + "' cycling step: '" + step.stepId + "'"); + } + + // set last time for report + if (tryStep == 0 || !window.localStorage.getItem("test-last-time")) { + window.localStorage.setItem("test-last-time", new Date().getTime()); } var _next = false; @@ -354,6 +365,12 @@ function next () { clearTimeout(overlapsCrash); _next = true; + + // set report + var report = JSON.parse(window.localStorage.getItem("test-report")) || {}; + report[step.stepId] = (new Date().getTime() - window.localStorage.getItem("test-last-time")) + " ms"; + window.localStorage.setItem("test-report", JSON.stringify(report)); + var nextStep = actionSteps.shift(); if (nextStep) { setTimeout(function () { @@ -363,34 +380,42 @@ window.localStorage.removeItem(testId); } } - overlapsCrash = setTimeout(function () { - window.localStorage.removeItem(testId); - throw "Test: '" + testId + "' can't resolve step: '" + step.stepId + "'"; - }, (step.delay || defaultDelay) + 500); - var $element = $(step.element); - if (step.triggers) step.triggers(next); - if ((step.trigger === 'reload' || (step.trigger && step.trigger.url)) && _next) return; - - if (step.snippet && step.trigger === 'drag') { - website.TestConsole.dragAndDropSnippet(step.snippet); - } else if (step.trigger && step.trigger.id === 'change') { - $element.trigger($.Event("change", { srcElement: $element })); - } else if (step.sampleText) { - $element.val(step.sampleText); - $element.trigger($.Event("change", { srcElement: $element })); - } else if ($element.is(":visible")) { // Click by default - if (step.trigger.id === 'mousedown') { - $element.trigger($.Event("mousedown", { srcElement: $element })); + overlapsCrash = setTimeout(function () { + throwError("Test: '" + testId + "' can't resolve step: '" + step.stepId + "'"); + }, (step.delay || defaultDelay) + 1000); + + setTimeout(function () { + var $element = $(step.element); + if (step.triggers) { + try { + step.triggers(next); + } catch (e) { + throwError(e); + } } - var evt = document.createEvent("MouseEvents"); - evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); - $element[0].dispatchEvent(evt); - if (step.trigger.id === 'mouseup') { - $element.trigger($.Event("mouseup", { srcElement: $element })); + if ((step.trigger === 'reload' || (step.trigger && step.trigger.url)) && _next) return; + + if (step.snippet && step.trigger === 'drag') { + website.TestConsole.dragAndDropSnippet(step.snippet); + } else if (step.trigger && step.trigger.id === 'change') { + $element.trigger($.Event("change", { srcElement: $element })); + } else if (step.sampleText) { + $element.val(step.sampleText); + $element.trigger($.Event("change", { srcElement: $element })); + } else if ($element.is(":visible")) { // Click by default + if (step.trigger.id === 'mousedown') { + $element.trigger($.Event("mousedown", { srcElement: $element })); + } + var evt = document.createEvent("MouseEvents"); + evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + $element[0].dispatchEvent(evt); + if (step.trigger.id === 'mouseup') { + $element.trigger($.Event("mouseup", { srcElement: $element })); + } } - } - if (!step.triggers) next(); + if (!step.triggers) next(); + },0); } var url = new website.UrlParser(window.location.href); if (tour.path && url.pathname !== tour.path && !window.localStorage.getItem(testId)) { @@ -415,6 +440,12 @@ }, reset: function () { window.localStorage.removeItem(testId); + window.localStorage.removeItem("test-report"); + for (var k in window.localStorage) { + if (window.localStorage[k].indexOf("test-last")) { + window.localStorage.removeItem(k); + } + } }, }; website.TestConsole.tests.push(test); diff --git a/addons/website/tests/test_requests.py b/addons/website/tests/test_requests.py index fc56a93158c..e78c59a69cf 100644 --- a/addons/website/tests/test_requests.py +++ b/addons/website/tests/test_requests.py @@ -48,8 +48,8 @@ class CrawlSuite(unittest2.TestSuite): self.opener.add_handler(urllib2.UnknownHandler()) self.opener.add_handler(urllib2.HTTPHandler()) self.opener.add_handler(urllib2.HTTPSHandler()) - self.opener.add_handler(RedirectHandler()) self.opener.add_handler(urllib2.HTTPCookieProcessor()) + self.opener.add_handler(RedirectHandler()) self._authenticate(user, password) self.user = user diff --git a/addons/website/tests/test_ui.py b/addons/website/tests/test_ui.py index cc5dbc9db4f..a4dcf8cf434 100644 --- a/addons/website/tests/test_ui.py +++ b/addons/website/tests/test_ui.py @@ -146,6 +146,6 @@ def full_path(pyfile, filename): def load_tests(loader, base, _): base.addTest(WebsiteUiSuite(full_path(__file__, 'dummy_test.js'), {}, 5.0)) - base.addTest(WebsiteUiSuite(full_path(__file__, 'simple_dom_test.js'), { 'action': 'website.action_website_homepage' }, 60.0)) - base.addTest(WebsiteUiSuite(full_path(__file__, 'homepage_test.js'), { 'action': 'website.action_website_homepage' }, 60.0)) + base.addTest(WebsiteUiSuite(full_path(__file__, 'simple_dom_test.js'), {'redirect': '/page/website.homepage'}, 60.0)) + base.addTest(WebsiteUiSuite(full_path(__file__, 'homepage_test.js'), {'redirect': '/page/website.homepage'}, 60.0)) return base diff --git a/addons/website/tests/ui_suite/ui_test_runner.js b/addons/website/tests/ui_suite/ui_test_runner.js index e8f38ebb9d9..d3e3132f603 100644 --- a/addons/website/tests/ui_suite/ui_test_runner.js +++ b/addons/website/tests/ui_suite/ui_test_runner.js @@ -9,8 +9,10 @@ function waitFor (ready, callback, timeout, timeoutMessageCallback) { if(!condition) { var message = timeoutMessageCallback ? timeoutMessageCallback() : "Timeout after "+timeout+" ms"; console.log('{ "event": "error", "message": "'+message+'" }'); - var json = { "event": "error", "message": "Waiting for...\n"+ready }; - console.log(JSON.stringify(json)); + console.log("Waiting for...\n"+ready); + if (window.localStorage.getItem("test-report")) { + console.log(JSON.parse(website.localStorage.getItem("test-report"))); + } phantom.exit(1); } else { clearInterval(interval); @@ -28,15 +30,16 @@ function run (test) { var scheme = options.scheme ? options.scheme+'://' : 'http://'; var host = options.host ? options.host : 'localhost'; var port = options.port ? ':'+options.port : ''; - var path = options.path ? options.path : '/web'; + var path = options.path ? options.path : '/login'; var queryParams = []; if (options.db) queryParams.push('db='+options.db); + if (options.user) queryParams.push('login='+options.user); + if (options.password) queryParams.push('key='+options.password); + if (options.redirect) queryParams.push('redirect='+options.redirect); var query = queryParams.length > 0 ? '?'+queryParams.join('&') : ''; var hashParams = []; - if (options.user) hashParams.push('login='+options.user); - if (options.password) hashParams.push('password='+options.password); if (options.action) hashParams.push('action='+options.action); var hash = hashParams.length > 0 ? '#'+hashParams.join('&') : ''; diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index 066e067ec8b..f40474ac75a 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -255,11 +255,19 @@ + + + + + + + + - + Sign in diff --git a/addons/website_blog/tests/test_ui.py b/addons/website_blog/tests/test_ui.py index dad6a4752e7..36f464e4998 100644 --- a/addons/website_blog/tests/test_ui.py +++ b/addons/website_blog/tests/test_ui.py @@ -1,5 +1,5 @@ import openerp.addons.website.tests.test_ui as test_ui def load_tests(loader, base, _): - base.addTest(test_ui.WebsiteUiSuite(test_ui.full_path(__file__,'post_test.js'), { 'action': 'website.action_website_homepage' }, 60.0)) - return base \ No newline at end of file + base.addTest(test_ui.WebsiteUiSuite(test_ui.full_path(__file__,'post_test.js'), {'redirect': '/page/website.homepage'}, 60.0)) + return base diff --git a/addons/website_event/tests/test_ui.py b/addons/website_event/tests/test_ui.py index 52cce70defd..176bc77ecc5 100644 --- a/addons/website_event/tests/test_ui.py +++ b/addons/website_event/tests/test_ui.py @@ -1,5 +1,5 @@ import openerp.addons.website.tests.test_ui as test_ui def load_tests(loader, base, _): - base.addTest(test_ui.WebsiteUiSuite(test_ui.full_path(__file__,'event_test.js'), { 'action': 'website.action_website_homepage' }, 60.0)) - return base \ No newline at end of file + base.addTest(test_ui.WebsiteUiSuite(test_ui.full_path(__file__,'event_test.js'), {'redirect': '/page/website.homepage'}, 60.0)) + return base diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index caa9aad7846..b2a4d1eb57e 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -191,10 +191,9 @@ class Ecommerce(http.Controller): return [r["product_tmpl_id"][0] for r in att] @http.route(['/shop/pricelist'], type='http', auth="public", website=True, multilang=True) - def shop_promo(self, code, **post): - assert code, 'No pricelist code provided' - request.registry['website']._ecommerce_change_pricelist(request.cr, request.uid, code=code, context=request.context) - return request.redirect("/shop") + def shop_promo(self, promo=None, **post): + request.registry['website']._ecommerce_change_pricelist(request.cr, request.uid, code=promo, context=request.context) + return request.redirect("/shop/mycart/") @http.route([ '/shop/', @@ -708,6 +707,8 @@ class Ecommerce(http.Controller): order = request.registry['sale.order'].browse(cr, SUPERUSER_ID, sale_order_id, context=context) assert order.website_session_id == request.httprequest.session['website_session_id'] + request.registry['website']._ecommerce_change_pricelist(cr, uid, None, context=context or {}) + return request.website.render("website_sale.confirmation", {'order': order}) @http.route(['/shop/change_sequence/'], type='json', auth="public", website=True) diff --git a/addons/website_sale/models/website.py b/addons/website_sale/models/website.py index 192b33b5296..11ff6cf2efc 100644 --- a/addons/website_sale/models/website.py +++ b/addons/website_sale/models/website.py @@ -51,7 +51,7 @@ class Website(orm.Model): values.update(order.onchange_pricelist_id(pricelist_id, None)['value']) order.write(values) for line in order.order_line: - self.add_product_to_cart(order_line_id=line.id, number=0) + self._ecommerce_add_product_to_cart(cr, uid, order_line_id=line.id, number=0) # ************************************************************ # Ecommerce quotation management @@ -65,7 +65,7 @@ class Website(orm.Model): order_line_obj = self.pool.get('sale.order.line') order_obj = self.pool.get('sale.order') - context = dict(context, pricelist=self.ecommerce_get_pricelist_id(cr, uid, None, context=context)) + context = dict(context or {}, pricelist=self.ecommerce_get_pricelist_id(cr, uid, None, context=context)) # set order_line_id and product_id if order_line_id: @@ -122,6 +122,11 @@ class Website(orm.Model): else: order_line_id = order_line_obj.create(cr, SUPERUSER_ID, values, context=context) order_obj.write(cr, SUPERUSER_ID, [order.id], {'order_line': [(4, order_line_id)]}, context=context) + + order = self.ecommerce_get_current_order(cr, uid, context=context) + if not order or not order.order_line: + self._ecommerce_change_pricelist(cr, uid, None, context=context) + return quantity def _ecommerce_get_quotation_values(self, cr, uid, context=None): diff --git a/addons/website_sale/static/src/js/website.tour.shop.js b/addons/website_sale/static/src/js/website.tour.shop.js index 78643d1b110..f6b64342c58 100644 --- a/addons/website_sale/static/src/js/website.tour.shop.js +++ b/addons/website_sale/static/src/js/website.tour.shop.js @@ -292,8 +292,7 @@ url: /shop\/confirmation\//, }, afterTrigger: function (tour) { - window.localStorage.setItem("test-success", "{}"); - throw "afterTrigger test finish, remove this throw"; + console.log('{ "event": "success" }'); }, } ]; diff --git a/addons/website_sale/tests/test_ui.py b/addons/website_sale/tests/test_ui.py index 68ba5dc0a05..bda42eb1bd7 100644 --- a/addons/website_sale/tests/test_ui.py +++ b/addons/website_sale/tests/test_ui.py @@ -2,5 +2,5 @@ import openerp.addons.website.tests.test_ui as test_ui def load_tests(loader, base, _): base.addTest(test_ui.WebsiteUiSuite(test_ui.full_path(__file__,'website_sale-sale_process-test.js'), - { 'action': 'website.action_website_homepage' }, 60.0)) + { 'action': 'website.action_website_homepage' }, 120.0)) return base \ No newline at end of file diff --git a/addons/website_sale/tests/ui_suite/website_sale-sale_process-test.js b/addons/website_sale/tests/ui_suite/website_sale-sale_process-test.js index c1027107e44..5554ea75271 100644 --- a/addons/website_sale/tests/ui_suite/website_sale-sale_process-test.js +++ b/addons/website_sale/tests/ui_suite/website_sale-sale_process-test.js @@ -14,15 +14,5 @@ testRunner.run(function websiteSaleTest (page, timeout) { page.evaluate(function () { window.openerp.website.TestConsole.test('shoptest').run(true); }); - waitFor(function testExecuted () { - return page.evaluate(function () { - var res = window.localStorage && window.localStorage.getItem - && window.localStorage.getItem("test-success"); - return res; - }); - }, function finish () { - console.log('{ "event": "success" }'); - phantom.exit(); - }, 4*timeout/5); }, timeout/5); }); \ No newline at end of file diff --git a/addons/website_sale/views/website_sale.xml b/addons/website_sale/views/website_sale.xml index 32d7f3989b8..105eceac596 100644 --- a/addons/website_sale/views/website_sale.xml +++ b/addons/website_sale/views/website_sale.xml @@ -62,7 +62,7 @@ - + + - - + + @@ -669,10 +670,17 @@ - + + + + @@ -692,7 +700,7 @@ Have a coupon code? Fill in this field and apply. - +
+ +
Have a coupon code? Fill in this field and apply.