From ea27c1b7a341b6f913197a2e8843562c5e71ea52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 7 Jun 2017 18:13:11 +0200 Subject: [PATCH] [MOV] website_portal, portal: move customer portal to portal module This commit moves the whole customer portal to the portal module. It now completely uses portal and http_routing features and is not dependent on website anymore. An override of web controller is added in portal in order to redirect portal users to /my instead of /web. That way once having the customer portal installed all share users are correctly redirected to their account. All modules defining customer portal templates and controllers are updated accordingly. --- addons/portal/__init__.py | 1 + addons/portal/__manifest__.py | 2 + addons/portal/controllers/__init__.py | 1 + addons/portal/controllers/portal.py | 122 +++++++- addons/portal/controllers/web.py | 20 ++ .../data/portal_data.xml} | 2 +- .../static/src/js/portal.js} | 8 +- .../static/src/js/portal_tour.js} | 4 +- .../tests/__init__.py | 0 .../tests/test_load_process.py | 0 addons/portal/views/assets.xml | 7 +- addons/portal/views/portal_templates.xml | 253 +++++++++++++++++ .../wizard/__init__.py | 0 .../wizard/portal_wizard.py | 2 +- .../wizard/portal_wizard_views.xml | 0 addons/web/controllers/main.py | 7 +- .../static/src/less/portal.less} | 0 addons/web/views/webclient_templates.xml | 2 + addons/website/views/website_templates.xml | 11 - .../views/account_templates.xml | 8 +- .../__manifest__.py | 2 +- .../controllers/main.py | 5 +- .../website_crm_partner_assign_templates.xml | 18 +- addons/website_payment/__manifest__.py | 2 +- .../views/website_payment_templates.xml | 4 +- addons/website_portal/__init__.py | 3 - addons/website_portal/__manifest__.py | 3 - addons/website_portal/controllers/__init__.py | 4 - addons/website_portal/controllers/main.py | 145 ---------- .../views/website_portal_templates.xml | 264 ------------------ .../website_portal_purchase/__manifest__.py | 3 +- .../controllers/website_portal.py | 5 +- .../website_portal_purchase_templates.xml | 12 +- .../website_portal_sale/controllers/main.py | 3 +- .../views/website_portal_sale_templates.xml | 16 +- addons/website_project/__manifest__.py | 2 +- addons/website_project/controllers/main.py | 5 +- .../views/project_templates.xml | 20 +- addons/website_quote/controllers/main.py | 2 +- .../views/website_quote_templates.xml | 4 +- 40 files changed, 472 insertions(+), 500 deletions(-) create mode 100644 addons/portal/controllers/web.py rename addons/{website_portal/data/website_portal_data.xml => portal/data/portal_data.xml} (94%) rename addons/{website_portal/static/src/js/website_portal.js => portal/static/src/js/portal.js} (95%) rename addons/{website_portal/static/src/js/website_portal_tour.js => portal/static/src/js/portal_tour.js} (77%) rename addons/{website_portal => portal}/tests/__init__.py (100%) rename addons/{website_portal => portal}/tests/test_load_process.py (100%) rename addons/{website_portal => portal}/wizard/__init__.py (100%) rename addons/{website_portal => portal}/wizard/portal_wizard.py (99%) rename addons/{website_portal => portal}/wizard/portal_wizard_views.xml (100%) rename addons/{website_portal/static/src/less/website_portal.less => web/static/src/less/portal.less} (100%) delete mode 100644 addons/website_portal/controllers/__init__.py delete mode 100644 addons/website_portal/controllers/main.py delete mode 100644 addons/website_portal/views/website_portal_templates.xml diff --git a/addons/portal/__init__.py b/addons/portal/__init__.py index dd15b5c32e5..c92af4efd3d 100644 --- a/addons/portal/__init__.py +++ b/addons/portal/__init__.py @@ -2,3 +2,4 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import controllers +from . import wizard diff --git a/addons/portal/__manifest__.py b/addons/portal/__manifest__.py index 61e0818a929..c57c80433a0 100644 --- a/addons/portal/__manifest__.py +++ b/addons/portal/__manifest__.py @@ -16,8 +16,10 @@ This module contains most code coming from odoo v10 website_portal. Purpose of this module is to allow the display of a customer portal without having a dependency towards website edition and customization capabilities.""", 'data': [ + 'data/portal_data.xml', 'views/assets.xml', 'views/portal_templates.xml', + 'wizard/portal_wizard_views.xml', ], 'depends': ['http_routing', 'mail'], } diff --git a/addons/portal/controllers/__init__.py b/addons/portal/controllers/__init__.py index 903b755e71e..ac871b40c75 100644 --- a/addons/portal/controllers/__init__.py +++ b/addons/portal/controllers/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import web from . import portal diff --git a/addons/portal/controllers/portal.py b/addons/portal/controllers/portal.py index 1fd7c9ee759..8c5d632fdc2 100644 --- a/addons/portal/controllers/portal.py +++ b/addons/portal/controllers/portal.py @@ -5,9 +5,10 @@ import math from werkzeug import urls +from odoo import fields as odoo_fields, tools, _ +from odoo.exceptions import ValidationError from odoo.http import Controller, request, route - # -------------------------------------------------- # Misc tools # -------------------------------------------------- @@ -71,14 +72,131 @@ def pager(url, total, page=1, step=30, scope=5, url_args=None): } +def get_records_pager(ids, current): + if current.id in ids: + idx = ids.index(current.id) + return { + 'prev_record': idx != 0 and current.browse(ids[idx - 1]).website_url, + 'next_record': idx < len(ids) - 1 and current.browse(ids[idx + 1]).website_url + } + return {} + + class CustomerPortal(Controller): + MANDATORY_BILLING_FIELDS = ["name", "phone", "email", "street", "city", "country_id"] + OPTIONAL_BILLING_FIELDS = ["zipcode", "state_id", "vat", "company_name"] + + _items_per_page = 20 + + def _get_archive_groups(self, model, domain=None, fields=None, groupby="create_date", order="create_date desc"): + if not model: + return [] + if domain is None: + domain = [] + if fields is None: + fields = ['name', 'create_date'] + groups = [] + for group in request.env[model]._read_group_raw(domain, fields=fields, groupby=groupby, orderby=order): + dates, label = group[groupby] + date_begin, date_end = dates.split('/') + groups.append({ + 'date_begin': odoo_fields.Date.to_string(odoo_fields.Date.from_string(date_begin)), + 'date_end': odoo_fields.Date.to_string(odoo_fields.Date.from_string(date_end)), + 'name': label, + 'item_count': group[groupby + '_count'] + }) + return groups + def _prepare_portal_layout_values(self): + # get customer sales rep + sales_user = False + partner = request.env.user.partner_id + if partner.user_id and not partner.user_id._is_public(): + sales_user = partner.user_id + return { + 'sales_user': sales_user, 'page_name': 'home', + 'archive_groups': [], } @route(['/my', '/my/home'], type='http', auth="user", website=True) def home(self, **kw): values = self._prepare_portal_layout_values() - return request.render("portal.portal_layout", values) + return request.render("portal.portal_my_home", values) + + @route(['/my/account'], type='http', auth='user', website=True) + def account(self, redirect=None, **post): + partner = request.env.user.partner_id + values = { + 'error': {}, + 'error_message': [] + } + + if post: + error, error_message = self.details_form_validate(post) + values.update({'error': error, 'error_message': error_message}) + values.update(post) + if not error: + values = {key: post[key] for key in self.MANDATORY_BILLING_FIELDS} + values.update({key: post[key] for key in self.OPTIONAL_BILLING_FIELDS if key in post}) + values.update({'zip': values.pop('zipcode', '')}) + partner.sudo().write(values) + if redirect: + return request.redirect(redirect) + return request.redirect('/my/home') + + countries = request.env['res.country'].sudo().search([]) + states = request.env['res.country.state'].sudo().search([]) + + values.update({ + 'partner': partner, + 'countries': countries, + 'states': states, + 'has_check_vat': hasattr(request.env['res.partner'], 'check_vat'), + 'redirect': redirect, + 'page_name': 'my_details', + }) + + response = request.render("portal.portal_my_details", values) + response.headers['X-Frame-Options'] = 'DENY' + return response + + def details_form_validate(self, data): + error = dict() + error_message = [] + + # Validation + for field_name in self.MANDATORY_BILLING_FIELDS: + if not data.get(field_name): + error[field_name] = 'missing' + + # email validation + if data.get('email') and not tools.single_email_re.match(data.get('email')): + error["email"] = 'error' + error_message.append(_('Invalid Email! Please enter a valid email address.')) + + # vat validation + partner = request.env["res.partner"] + if data.get("vat") and hasattr(partner, "check_vat"): + partner_dummy = partner.new({ + 'vat': data['vat'], + 'country_id': (int(data['country_id']) + if data.get('country_id') else False), + }) + try: + partner_dummy.check_vat() + except ValidationError: + error["vat"] = 'error' + + # error message for empty required fields + if [err for err in tools.pycompat.values(error) if err == 'missing']: + error_message.append(_('Some required fields are empty.')) + + unknown = [k for k in data if k not in self.MANDATORY_BILLING_FIELDS + self.OPTIONAL_BILLING_FIELDS] + if unknown: + error['common'] = 'Unknown field' + error_message.append("Unknown field '%s'" % ','.join(unknown)) + + return error, error_message diff --git a/addons/portal/controllers/web.py b/addons/portal/controllers/web.py new file mode 100644 index 00000000000..d5db3a30b7b --- /dev/null +++ b/addons/portal/controllers/web.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import http +from odoo.addons.web.controllers.main import Home +from odoo.http import request + + +class Home(Home): + + @http.route() + def index(self, *args, **kw): + if request.session.uid and not request.env['res.users'].sudo().browse(request.session.uid).has_group('base.group_user'): + return http.local_redirect('/my', query=request.params, keep_hash=True) + return super(Home, self).index(*args, **kw) + + def _login_redirect(self, uid, redirect=None): + if not redirect and not request.env['res.users'].sudo().browse(uid).has_group('base.group_user'): + return '/my' + return super(Home, self)._login_redirect(uid, redirect=redirect) diff --git a/addons/website_portal/data/website_portal_data.xml b/addons/portal/data/portal_data.xml similarity index 94% rename from addons/website_portal/data/website_portal_data.xml rename to addons/portal/data/portal_data.xml index 3ffcb7693ff..ffe12934227 100644 --- a/addons/website_portal/data/website_portal_data.xml +++ b/addons/portal/data/portal_data.xml @@ -4,7 +4,7 @@ Portal: new user - + ${object.partner_id.email} Your Odoo account at ${user.company_id.name} ${object.partner_id.lang} diff --git a/addons/website_portal/static/src/js/website_portal.js b/addons/portal/static/src/js/portal.js similarity index 95% rename from addons/website_portal/static/src/js/website_portal.js rename to addons/portal/static/src/js/portal.js index c969b06f0b7..edc5ae4c2dd 100644 --- a/addons/website_portal/static/src/js/website_portal.js +++ b/addons/portal/static/src/js/portal.js @@ -1,7 +1,8 @@ -odoo.define('website_portal', function(require) { - 'use strict'; - require('website.website'); +odoo.define('portal.portal', function(require) { +'use strict'; + +$(document).ready(function () { if(!$('.o_portal').length) { return $.Deferred().reject("DOM doesn't contain '.o_portal'"); @@ -45,3 +46,4 @@ odoo.define('website_portal', function(require) { }); } }); +}); diff --git a/addons/website_portal/static/src/js/website_portal_tour.js b/addons/portal/static/src/js/portal_tour.js similarity index 77% rename from addons/website_portal/static/src/js/website_portal_tour.js rename to addons/portal/static/src/js/portal_tour.js index a3a8beb66be..aa566f8d0d4 100644 --- a/addons/website_portal/static/src/js/website_portal_tour.js +++ b/addons/portal/static/src/js/portal_tour.js @@ -1,13 +1,11 @@ -odoo.define('website_portal.tour', function (require) { +odoo.define('portal.tour', function (require) { 'use strict'; var tour = require("web_tour.tour"); -var base = require("web_editor.base"); tour.register('portal_load_homepage', { test: true, url: '/my', - wait_for: base.ready() }, [ { diff --git a/addons/website_portal/tests/__init__.py b/addons/portal/tests/__init__.py similarity index 100% rename from addons/website_portal/tests/__init__.py rename to addons/portal/tests/__init__.py diff --git a/addons/website_portal/tests/test_load_process.py b/addons/portal/tests/test_load_process.py similarity index 100% rename from addons/website_portal/tests/test_load_process.py rename to addons/portal/tests/test_load_process.py diff --git a/addons/portal/views/assets.xml b/addons/portal/views/assets.xml index c90c7f3aacc..a40533c7876 100644 --- a/addons/portal/views/assets.xml +++ b/addons/portal/views/assets.xml @@ -1,10 +1,15 @@ \ No newline at end of file diff --git a/addons/portal/views/portal_templates.xml b/addons/portal/views/portal_templates.xml index bd89945c81f..67e027aea48 100644 --- a/addons/portal/views/portal_templates.xml +++ b/addons/portal/views/portal_templates.xml @@ -62,11 +62,258 @@ + + + + + + + + + + + + + @@ -83,4 +330,10 @@ + + diff --git a/addons/website_portal/wizard/__init__.py b/addons/portal/wizard/__init__.py similarity index 100% rename from addons/website_portal/wizard/__init__.py rename to addons/portal/wizard/__init__.py diff --git a/addons/website_portal/wizard/portal_wizard.py b/addons/portal/wizard/portal_wizard.py similarity index 99% rename from addons/website_portal/wizard/portal_wizard.py rename to addons/portal/wizard/portal_wizard.py index 4bc731c3ff8..0c8206c86f6 100644 --- a/addons/website_portal/wizard/portal_wizard.py +++ b/addons/portal/wizard/portal_wizard.py @@ -182,7 +182,7 @@ class PortalWizardUser(models.TransientModel): raise UserError(_('You must have an email address in your User Preferences to send emails.')) # determine subject and body in the portal user's language - template = self.env.ref('website_portal.mail_template_data_portal_welcome') + template = self.env.ref('portal.mail_template_data_portal_welcome') for wizard_line in self: lang = wizard_line.user_id.lang partner = wizard_line.user_id.partner_id diff --git a/addons/website_portal/wizard/portal_wizard_views.xml b/addons/portal/wizard/portal_wizard_views.xml similarity index 100% rename from addons/website_portal/wizard/portal_wizard_views.xml rename to addons/portal/wizard/portal_wizard_views.xml diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index fd2d596a4b2..e2f2d7814a4 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -458,6 +458,9 @@ class Home(http.Controller): ensure_db() return werkzeug.utils.redirect(redirect, 303) + def _login_redirect(self, uid, redirect=None): + return redirect if redirect else '/web' + @http.route('/web/login', type='http', auth="none") def web_login(self, redirect=None, **kw): ensure_db() @@ -479,9 +482,7 @@ class Home(http.Controller): uid = request.session.authenticate(request.session.db, request.params['login'], request.params['password']) if uid is not False: request.params['login_success'] = True - if not redirect: - redirect = '/web' - return http.redirect_with_hash(redirect) + return http.redirect_with_hash(self._login_redirect(uid, redirect=redirect)) request.uid = old_uid values['error'] = _("Wrong login/password") else: diff --git a/addons/website_portal/static/src/less/website_portal.less b/addons/web/static/src/less/portal.less similarity index 100% rename from addons/website_portal/static/src/less/website_portal.less rename to addons/web/static/src/less/portal.less diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index 730b4d883e1..c2c3d5a2a4c 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -241,6 +241,8 @@ + + diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index 1cc552a3208..b46402aba28 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -216,17 +216,6 @@ - -