diff options
| author | Thibault Delavallée <tde@odoo.com> | 2017-06-07 18:13:11 +0200 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2017-08-08 14:58:49 +0200 |
| commit | ea27c1b7a341b6f913197a2e8843562c5e71ea52 (patch) | |
| tree | edff4bb4b14ba7afea08ce0c92ba609aa5d314fa | |
| parent | 86aa1b81bcc7452e42c84a995479a59440dab956 (diff) | |
[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.
40 files changed, 472 insertions, 500 deletions
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 index 3ffcb7693ff..ffe12934227 100644 --- a/addons/website_portal/data/website_portal_data.xml +++ b/addons/portal/data/portal_data.xml @@ -4,7 +4,7 @@ <record id="mail_template_data_portal_welcome" model="mail.template"> <field name="name">Portal: new user</field> - <field name="model_id" ref="website_portal.model_portal_wizard_user"/> + <field name="model_id" ref="portal.model_portal_wizard_user"/> <field name="email_to">${object.partner_id.email}</field> <field name="subject">Your Odoo account at ${user.company_id.name}</field> <field name="lang">${object.partner_id.lang}</field> diff --git a/addons/website_portal/static/src/js/website_portal.js b/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 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 index 279e43d2034..279e43d2034 100644 --- a/addons/website_portal/tests/__init__.py +++ b/addons/portal/tests/__init__.py diff --git a/addons/website_portal/tests/test_load_process.py b/addons/portal/tests/test_load_process.py index 344d8bec7a9..344d8bec7a9 100644 --- a/addons/website_portal/tests/test_load_process.py +++ b/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 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> <template id="assets_frontend" inherit_id="web.assets_frontend" name="Portal Assets"> - <xpath expr="//script[last()]" position="after"> + <xpath expr="//link[last()]" position="after"> <link rel="stylesheet" type="text/less" href="/portal/static/src/less/website.ui.less"/> <link rel="stylesheet" type="text/less" href="/portal/static/src/less/website.wrapwrap.less"/> <link rel="stylesheet" type="text/less" href="/portal/static/src/less/bootstrap.extend.less"/> </xpath> + + <xpath expr="//link[last()]" position="after"> + <script type="text/javascript" src="/portal/static/src/js/portal.js"></script> + <script type="text/javascript" src="/portal/static/src/js/portal_tour.js"></script> + </xpath> </template> </odoo>
\ 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 @@ <template id="portal_layout" name="Portal Layout"> <t t-call="portal.frontend_layout"> + <div class="container mt16 o_portal"> + <div class="oe_structure"> + <div t-if="not no_breadcrumbs" class="row"> + <div class="col-sm-12"> + <ol class="breadcrumb o_portal_submenu"> + <li><a href="/my/home"><i class="fa fa-home"/></a></li> + <li t-if="page_name == 'my_details'">Your Details</li> + </ol> + </div> + </div> + </div> + </div> + <div id="wrap" class='portal-wrap'> + <div class="container mb64"> + <t t-if="my_details"> + <div class="row"> + <div t-attf-class="col-md-9 col-lg-8"> + <t t-raw="0"/> + </div> + <div id="o_my_sidebar" class="col-md-3 col-lg-offset-1 o_my_sidebar"> + <div class="o_my_contact" t-if="sales_user"> + <t t-call="portal.portal_contact"/> + </div> + <div class="o_portal_my_details"> + <h3 class="page-header">Your Details <a href="/my/account" class="btn btn-default btn-xs">Change</a></h3> + <div t-field="user_id.partner_id" t-options='{"widget": "contact", "fields": ["email", "phone", "address", "name"]}'/> + </div> + <div class="o_my_archives" t-if="archive_groups"> + <t t-call="portal.portal_archive_groups"/> + </div> + </div> + </div> + </t> + <t t-else=""> + <t t-raw="0"/> + </t> + </div> + </div> </t> </template> + <template id="portal_show_sign_in" inherit_id="portal.frontend_layout" name="Show Sign In"> + <xpath expr="//ul[@id='top_menu']" position="inside"> + <li class="divider" groups="base.group_public"/> + <li groups="base.group_public"> + <a t-attf-href="/web/login"> + <b>Sign in</b> + </a> + </li> + </xpath> + </template> + <template id="portal_my_home" name="My Portal"> <t t-call="portal.portal_layout"> + <t t-set="my_details" t-value="True"/> + <div class="o_my_home_content"> + <div class="oe_structure"></div> + <h3 class="page-header">Your Documents</h3> + <ul class="o_portal_docs list-group"> + </ul> + </div> + <div class="col-md-12 oe_structure"/> + </t> + </template> + + <!-- + The search bar is composed of 2 buttons : a "filter by" and a "sort by". Changing the 'sortby' + criteria will keep the number of page, query params, ... Changing the 'filterby' param will + redirect the user to the beginning of document list, keeping query parameters. + + These 2 buttons can be prepended by a advanced search input, to activate it, search_input need + to be initialized at 'True' and the content of the t-call is the list of li elements searchable. + + :param dict searchbar_sortings : containing the sort criteria like + {'date': {'label': _('Newest'), 'order': 'create_date desc'}} + :param string sortby : name of the sort criteria + :param dict searchbar_filters : containing the filter criteria like + {'open': {'label': _('In Progress'), 'domain': [('state', '=', 'open')]}} + :param string filterby : name of the filter criteria + :param default_url : the base url of the pages (like '/my/orders') + :param boolean o_portal_search_panel : set to True to active the input search + :param html $0 : content of the t-call, <li>a</li><li>b</li> + --> + <template id="portal_searchbar" name="Portal Search Bar"> + <t t-if='searchbar_inputs'> + <div class='hidden-xs pull-right o_portal_search_panel'> + <div class="input-group"> + <div class="input-group-btn"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> + <span id="search_label">Search</span> <span class="caret"></span> + </button> + <ul class="dropdown-menu" role="menu"> + <li t-foreach='searchbar_inputs' t-as='input' t-att-class="search_in == searchbar_inputs[input]['input'] and 'active'"> + <a t-att-href="'#' + searchbar_inputs[input]['input']"><span t-raw="searchbar_inputs[input]['label']"/></a> + </li> + </ul> + </div> + <input type="text" class="form-control search_panel_fixed_width" t-att-value='search' name="search"/> + <span class="input-group-btn"> + <button class="btn btn-default search-submit" type="button"><span class="fa fa-search"></span></button> + </span> + </div> + </div> + </t> + <div t-if="searchbar_sortings" class="dropdown pull-right mr4"> + <button id="portal_searchbar_sortby" class="search_panel_fixed_width btn btn-default" type="button" data-toggle="dropdown"> + <span class="fa fa-sort fa-lg" /> + <span class='hidden-xs hidden-sm hidden-md' t-esc="searchbar_sortings[sortby].get('label', 'Newest')"/> + <span class="caret"></span> + </button> + <ul class="dropdown-menu" aria-labelledby="portal_searchbar_sortby"> + <li t-foreach="searchbar_sortings" t-as="option" t-attf-class="#{sortby == option and 'active'}"> + <a t-att-href="request.httprequest.path + '?' + keep_query('*', sortby=option)"> + <span t-esc="searchbar_sortings[option].get('label')"/> + </a> + </li> + </ul> + </div> + <div t-if="searchbar_filters" class="dropdown pull-right mr4"> + <button id="portal_searchbar_filters" class="search_panel_fixed_width btn btn-default" type="button" data-toggle="dropdown"> + <span class="fa fa-filter fa-lg" /> + <span class='hidden-xs hidden-sm hidden-md' t-esc="searchbar_filters[filterby].get('label', 'All')"/> + <span class="caret"></span> + </button> + <ul class="dropdown-menu" aria-labelledby="portal_searchbar_filters"> + <li t-foreach="searchbar_filters" t-as="option" t-att-class="filterby == option and 'active'"> + <a t-att-href="default_url + '?' + keep_query('*', filterby=option)"> + <span t-esc="searchbar_filters[option].get('label')"/> + </a> + </li> + </ul> + </div> + </template> + + <template id="portal_contact" name="Contact"> + <h3 class="page-header"><t t-esc="title"/></h3> + <h5 t-esc="sales_user.name"/> + <p><a t-att-href="'mailto:'+sales_user.email" t-esc="sales_user.email"/></p> + <p t-esc="sales_user.phone"/> + <p t-esc="sales_user.city"/> + </template> + + <template id="portal_archive_groups" name="Portal Archive Groups"> + <h3 class="page-header">Archives</h3> + <ul class="nav nav-pills nav-stacked"> + <t t-foreach="archive_groups" t-as="group"> + <t t-if="group['date_begin'] == date"> + <li class="active"> + <a t-att-href="default_url" t-ignore="True"><t t-esc="group['name']"/><span class="pull-right badge" t-esc="group['item_count']"/></a> + </li> + </t> + <t t-if="group['date_begin'] != date"> + <li> + <a t-ignore="True" t-attf-href="#{default_url}?date_begin=#{group['date_begin']}&date_end=#{group['date_end']}"><t t-esc="group['name']"/><span class="pull-right badge" t-esc="group['item_count']"/></a> + </li> + </t> + </t> + </ul> + </template> + + <template id="portal_my_details"> + <t t-call="portal.portal_layout"> + <t t-set="additional_title">Your Contact Details</t> + <h3>Your Details</h3> + <form action="/my/account" method="post"> + <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/> + <div class="row o_portal_details"> + <div class="col-md-8"> + <div class="row"> + <div class="col-md-12"> + <div t-if="error_message" class="alert alert-danger"> + <t t-foreach="error_message" t-as="err"><t t-esc="err"/><br /></t> + </div> + </div> + <div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6"> + <label class="control-label" for="name">Your Name</label> + <input type="text" name="name" class="form-control" t-att-value="name or partner.name" /> + </div> + <div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6"> + <label class="control-label" for="email">Email</label> + <input type="email" name="email" class="form-control" t-att-value="email or partner.email" /> + </div> + <div t-attf-class="form-group #{error.get('phone') and 'has-error' or ''} col-lg-6"> + <label class="control-label" for="phone">Phone</label> + <input type="tel" name="phone" class="form-control" t-att-value="phone or partner.phone" /> + </div> + + <div class="clearfix" /> + <div t-attf-class="form-group #{error.get('company_name') and 'has-error' or ''} col-lg-6"> + <label class="control-label label-optional" for="company_name">Company Name</label> + <input type="text" name="company_name" class="form-control" t-att-value="company_name or partner.company_name"/> + </div> + <div t-if="has_check_vat" t-attf-class="form-group #{error.get('vat') and 'has-error' or ''} col-lg-6"> + <label class="control-label label-optional" for="vat">VAT Number</label> + <input type="text" name="vat" class="form-control" t-att-value="vat or partner.vat" /> + </div> + + <div class="clearfix" /> + <div t-attf-class="form-group #{error.get('street') and 'has-error' or ''} col-lg-6"> + <label class="control-label label-optional" for="street">Street</label> + <input type="text" name="street" class="form-control" t-att-value="street or partner.street"/> + </div> + <div t-attf-class="form-group #{error.get('city') and 'has-error' or ''} col-lg-6"> + <label class="control-label" for="city">City</label> + <input type="text" name="city" class="form-control" t-att-value="city or partner.city" /> + </div> + <div t-attf-class="form-group #{error.get('zip') and 'has-error' or ''} col-lg-6"> + <label class="control-label" for="zipcode">Zip / Postal Code</label> + <input type="text" name="zipcode" class="form-control" t-att-value="zipcode or partner.zip" /> + </div> + <div t-attf-class="form-group #{error.get('country_id') and 'has-error' or ''} col-lg-6"> + <label class="control-label" for="country_id">Country</label> + <select name="country_id" class="form-control"> + <option value="">Country...</option> + <t t-foreach="countries or []" t-as="country"> + <option t-att-value="country.id" t-att-selected="country.id == partner.country_id.id"> + <t t-esc="country.name" /> + </option> + </t> + </select> + </div> + <div t-attf-class="form-group #{error.get('state_id') and 'has-error' or ''} col-lg-6"> + <label class="control-label label-optional" for="state_id">State / Province</label> + <select name="state_id" class="form-control"> + <option value="">select...</option> + <t t-foreach="states or []" t-as="state"> + <option t-att-value="state.id" style="display:none;" t-att-data-country_id="state.country_id.id" t-att-selected="state.id == partner.state_id.id"> + <t t-esc="state.name" /> + </option> + </t> + </select> + </div> + <input type="hidden" name="redirect" t-att-value="redirect"/> + </div> + <div class="clearfix"> + <button type="submit" class="btn btn-primary pull-right mb32 "> + Confirm + <span class="fa fa-long-arrow-right" /> + </button> + </div> + </div> + </div> + </form> + </t> + </template> + + <template id="record_pager" name="Portal Record Pager"> + <t t-if='prev_record or next_record'> + <div class="ml8 record_pager btn-group btn-group-xs pull-right" role="group"> + <a t-att-class="'btn btn-default %s' % ('disabled' if not prev_record else '')" t-att-href="prev_record or '#'" ><i class="fa fa-arrow-left" aria-hidden="true"></i></a> + <a t-att-class="'btn btn-default %s' % ('disabled' if not next_record else '')" t-att-href="next_record or '#'" ><i class="fa fa-arrow-right" aria-hidden="true"></i></a> + </div> </t> </template> @@ -83,4 +330,10 @@ </li> </ul> </template> + + <template id="my_account_link" name="Link to frontend portal" inherit_id="portal.frontend_layout"> + <xpath expr="//li[@id='o_logout']" position="before"> + <li><a href="/my/home" role="menuitem">My Account</a></li> + </xpath> + </template> </odoo> diff --git a/addons/website_portal/wizard/__init__.py b/addons/portal/wizard/__init__.py index d92478011a5..d92478011a5 100644 --- a/addons/website_portal/wizard/__init__.py +++ b/addons/portal/wizard/__init__.py diff --git a/addons/website_portal/wizard/portal_wizard.py b/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 index b1cb31e63ba..b1cb31e63ba 100644 --- a/addons/website_portal/wizard/portal_wizard_views.xml +++ b/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 index afc5b17dd08..afc5b17dd08 100644 --- a/addons/website_portal/static/src/less/website_portal.less +++ b/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 @@ <t t-call="web.less_helpers"/> <link rel="stylesheet" type="text/less" href="/web/static/src/less/import_bootstrap.less"/> + <link rel='stylesheet' type="text/less" href='/web/static/src/less/portal.less'/> + <script type="text/javascript" src="/web/static/src/js/services/session.js"></script> </template> 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 @@ </xpath> </template> -<template id="show_sign_in" customize_show="True" inherit_id="website.layout" name="Show Sign In"> - <xpath expr="//ul[@id='top_menu']" position="inside"> - <li class="divider" groups="base.group_public"/> - <li groups="base.group_public"> - <a t-attf-href="/web/login"> - <b>Sign in</b> - </a> - </li> - </xpath> -</template> - <template id="footer_custom" inherit_id="website.layout" name="Footer"> <xpath expr="//div[@id='footer']" position="replace"> <div class="oe_structure" id="footer" t-if='not no_footer'> diff --git a/addons/website_account/views/account_templates.xml b/addons/website_account/views/account_templates.xml index dbce386184b..6fe2c7fd6ac 100644 --- a/addons/website_account/views/account_templates.xml +++ b/addons/website_account/views/account_templates.xml @@ -1,5 +1,5 @@ <odoo> - <template id="portal_my_home_menu_invoice" name="Portal layout : invoice menu entries" inherit_id="website_portal.portal_layout" priority="30"> + <template id="portal_my_home_menu_invoice" name="Portal layout : invoice menu entries" inherit_id="portal.portal_layout" priority="30"> <xpath expr="//ol[contains(@class,'o_portal_submenu')]" position="inside"> <li t-if="page_name == 'invoice'" class="active"> Invoices @@ -7,7 +7,7 @@ </xpath> </template> - <template id="portal_my_home_invoice" name="Portal My Home : invoice entries" inherit_id="website_portal.portal_my_home" priority="30"> + <template id="portal_my_home_invoice" name="Portal My Home : invoice entries" inherit_id="portal.portal_my_home" priority="30"> <xpath expr="//ul[contains(@class,'o_portal_docs')]" position="inside"> <li t-if="invoice_count" class="list-group-item"> <span class="badge" t-esc="invoice_count"/> @@ -17,9 +17,9 @@ </template> <template id="portal_my_invoices" name="My Invoices and Payments"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <h3>Invoices - <t t-call="website_portal.portal_searchbar"/> + <t t-call="portal.portal_searchbar"/> </h3> <t t-if="not invoices"> <p>There are currently no invoices and payments for your account.</p> diff --git a/addons/website_crm_partner_assign/__manifest__.py b/addons/website_crm_partner_assign/__manifest__.py index 3bf2b7d2a2b..2065bb14845 100644 --- a/addons/website_crm_partner_assign/__manifest__.py +++ b/addons/website_crm_partner_assign/__manifest__.py @@ -12,7 +12,7 @@ Publish and Assign Partner ========================== """, 'depends': ['base_geolocalize', 'crm', 'account', - 'website_partner', 'website_google_map', 'website_portal'], + 'website_partner', 'website_google_map', 'portal'], 'data': [ 'data/crm_partner_assign_data.xml', 'security/ir.model.access.csv', diff --git a/addons/website_crm_partner_assign/controllers/main.py b/addons/website_crm_partner_assign/controllers/main.py index 9eb27180be9..bb973843018 100644 --- a/addons/website_crm_partner_assign/controllers/main.py +++ b/addons/website_crm_partner_assign/controllers/main.py @@ -11,15 +11,14 @@ from odoo import fields from odoo import http from odoo.http import request from odoo.addons.http_routing.models.ir_http import slug, unslug +from odoo.addons.portal.controllers.portal import CustomerPortal from odoo.addons.website_partner.controllers.main import WebsitePartnerPage from odoo.tools import pycompat from odoo.tools.translate import _ -from odoo.addons.website_portal.controllers.main import website_account - -class WebsiteAccount(website_account): +class WebsiteAccount(CustomerPortal): def get_domain_my_lead(self, user): return [ diff --git a/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml b/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml index 8b92d401113..202f090f331 100644 --- a/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml +++ b/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml @@ -192,7 +192,7 @@ <script type="text/javascript" src="/website_crm_partner_assign/static/src/js/crm_partner_assign.js" /> </xpath> </template> - <template id="portal_my_home_menu_lead" name="Portal layout : lead menu entry" inherit_id="website_portal.portal_layout" priority="15"> + <template id="portal_my_home_menu_lead" name="Portal layout : lead menu entry" inherit_id="portal.portal_layout" priority="15"> <xpath expr="//ol[contains(@class,'o_portal_submenu')]" position="inside"> <li t-if="page_name == 'lead' or lead"> <a t-if="lead" t-attf-href="/my/leads?{{ keep_query() }}"> @@ -219,9 +219,9 @@ </xpath> </template> - <template id="portal_my_home_lead" name="Portal My Home : lead entries" inherit_id="website_portal.portal_my_home" priority="15"> + <template id="portal_my_home_lead" name="Portal My Home : lead entries" inherit_id="portal.portal_my_home" priority="15"> <xpath expr="//div[contains(@class,'o_my_home_content')]" position="inside"> - <t t-if="user.commercial_partner_id.grade_id"> + <t t-if="user_id.commercial_partner_id.grade_id"> <h3 t-if="lead_count" class="page-header"> <a href="/my/leads">My Leads <span class="badge ml8" t-esc="lead_count"/> @@ -240,10 +240,10 @@ </template> <template id="portal_my_leads" name="My Leads"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <h3 class="page-header"> My Leads - <t t-call="website_portal.portal_searchbar"/> + <t t-call="portal.portal_searchbar"/> </h3> <div t-if="not leads" class="alert alert-warning mt8" role="alert"> There are no leads. @@ -275,10 +275,10 @@ </template> <template id="portal_my_opportunities" name="My Opportunities"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <h3 class="page-header"> My Opportunities - <t t-call="website_portal.portal_searchbar"/> + <t t-call="portal.portal_searchbar"/> <button name='new_opp' data-toggle="modal" data-target=".modal_new_opp" class="btn btn-default pull-right mr8"><i class="fa fa-plus fa-lg" /></button> </h3> <div class="modal fade modal_new_opp" role="form" aria-hidden="true"> @@ -350,7 +350,7 @@ </template> <template id="portal_my_lead" name="My Lead"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <div class="panel panel-default"> <div class="panel-heading"> <div class="row"> @@ -516,7 +516,7 @@ </template> <template id="portal_my_opportunity" name="My Opportunity"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <div class="panel panel-default"> <div class="panel-heading"> <div class="row"> diff --git a/addons/website_payment/__manifest__.py b/addons/website_payment/__manifest__.py index 481c0110906..fce4212ca02 100644 --- a/addons/website_payment/__manifest__.py +++ b/addons/website_payment/__manifest__.py @@ -9,7 +9,7 @@ 'depends': [ 'website', 'payment', - 'website_portal', + 'portal', ], 'data': [ 'views/website_payment_view.xml', diff --git a/addons/website_payment/views/website_payment_templates.xml b/addons/website_payment/views/website_payment_templates.xml index bdaff74d0c4..ba012478c79 100644 --- a/addons/website_payment/views/website_payment_templates.xml +++ b/addons/website_payment/views/website_payment_templates.xml @@ -70,8 +70,8 @@ </t> </template> - <template id="pay_meth_link" inherit_id="website_portal.portal_layout" customize_show="True"> - <xpath expr="//div[@class='o_my_details']" position="inside"> + <template id="pay_meth_link" inherit_id="portal.portal_layout" customize_show="True"> + <xpath expr="//div[@class='o_portal_my_details']" position="inside"> <t t-if="request.env['payment.acquirer'].search([('website_published', '=', True), ('registration_view_template_id', '!=', False)])"> <div class='manage_payment_method mt16'><a href="/my/payment_method">Manage your payment acquirers</a></div> </t> diff --git a/addons/website_portal/__init__.py b/addons/website_portal/__init__.py index c92af4efd3d..67dee8c60db 100644 --- a/addons/website_portal/__init__.py +++ b/addons/website_portal/__init__.py @@ -1,5 +1,2 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import controllers -from . import wizard diff --git a/addons/website_portal/__manifest__.py b/addons/website_portal/__manifest__.py index c9e243a5efd..6b9012d3474 100644 --- a/addons/website_portal/__manifest__.py +++ b/addons/website_portal/__manifest__.py @@ -13,8 +13,5 @@ Allows your customers to manage their account from a beautiful web interface. 'website', 'auth_signup' ], 'data': [ - 'views/website_portal_templates.xml', - 'wizard/portal_wizard_views.xml', - 'data/website_portal_data.xml', ], } diff --git a/addons/website_portal/controllers/__init__.py b/addons/website_portal/controllers/__init__.py deleted file mode 100644 index 5d4b25db9c0..00000000000 --- a/addons/website_portal/controllers/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import main diff --git a/addons/website_portal/controllers/main.py b/addons/website_portal/controllers/main.py deleted file mode 100644 index 3b2fbfc2a2d..00000000000 --- a/addons/website_portal/controllers/main.py +++ /dev/null @@ -1,145 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import http -from odoo.http import request -from odoo import tools -from odoo.tools import pycompat -from odoo.tools.translate import _ -from odoo.exceptions import ValidationError - -from odoo.fields import Date - - -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 website_account(http.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 _prepare_portal_layout_values(self): - """ prepare the values to render portal layout template. This returns the - data displayed on every portal pages. - """ - partner = request.env.user.partner_id - # get customer sales rep - if partner.user_id: - sales_rep = partner.user_id - else: - sales_rep = False - values = { - 'sales_rep': sales_rep, - 'company': request.website.company_id, - 'user': request.env.user - } - return values - - 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': Date.to_string(Date.from_string(date_begin)), - 'date_end': Date.to_string(Date.from_string(date_end)), - 'name': label, - 'item_count': group[groupby + '_count'] - }) - return groups - - @http.route(['/my', '/my/home'], type='http', auth="user", website=True) - def account(self, **kw): - values = self._prepare_portal_layout_values() - return request.render("website_portal.portal_my_home", values) - - @http.route(['/my/account'], type='http', auth='user', website=True) - def details(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("website_portal.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 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/website_portal/views/website_portal_templates.xml b/addons/website_portal/views/website_portal_templates.xml deleted file mode 100644 index d320689553e..00000000000 --- a/addons/website_portal/views/website_portal_templates.xml +++ /dev/null @@ -1,264 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<odoo> - - <template id="assets_frontend" inherit_id="website.assets_frontend" name="Account Manager"> - <xpath expr="." position="inside"> - <link rel='stylesheet' href='/website_portal/static/src/less/website_portal.less'/> - <script type="text/javascript" src="/website_portal/static/src/js/website_portal.js"></script> - <script type="text/javascript" src="/website_portal/static/src/js/website_portal_tour.js"></script> - </xpath> - </template> - - <template id="portal_archive_groups" name="Portal Archive Groups"> - <h3 class="page-header">Archives</h3> - <ul class="nav nav-pills nav-stacked"> - <t t-foreach="archive_groups" t-as="group"> - <t t-if="group['date_begin'] == date"> - <li class="active"> - <a t-att-href="default_url" t-ignore="True"><t t-esc="group['name']"/><span class="pull-right badge" t-esc="group['item_count']"/></a> - </li> - </t> - <t t-if="group['date_begin'] != date"> - <li> - <a t-ignore="True" t-attf-href="#{default_url}?date_begin=#{group['date_begin']}&date_end=#{group['date_end']}"><t t-esc="group['name']"/><span class="pull-right badge" t-esc="group['item_count']"/></a> - </li> - </t> - </t> - </ul> - </template> - - <!-- - The search bar is composed of 2 buttons : a "filter by" and a "sort by". Changing the 'sortby' - criteria will keep the number of page, query params, ... Changing the 'filterby' param will - redirect the user to the beginning of document list, keeping query parameters. - - These 2 buttons can be prepended by a advanced search input, to activate it, search_input need - to be initialized at 'True' and the content of the t-call is the list of li elements searchable. - - :param dict searchbar_sortings : containing the sort criteria like - {'date': {'label': _('Newest'), 'order': 'create_date desc'}} - :param string sortby : name of the sort criteria - :param dict searchbar_filters : containing the filter criteria like - {'open': {'label': _('In Progress'), 'domain': [('state', '=', 'open')]}} - :param string filterby : name of the filter criteria - :param default_url : the base url of the pages (like '/my/orders') - :param boolean o_portal_search_panel : set to True to active the input search - :param html $0 : content of the t-call, <li>a</li><li>b</li> - --> - <template id="portal_searchbar" name="Portal Search Bar"> - <t t-if='searchbar_inputs'> - <div class='hidden-xs pull-right o_portal_search_panel'> - <div class="input-group"> - <div class="input-group-btn"> - <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> - <span id="search_label">Search</span> <span class="caret"></span> - </button> - <ul class="dropdown-menu" role="menu"> - <li t-foreach='searchbar_inputs' t-as='input' t-att-class="search_in == searchbar_inputs[input]['input'] and 'active'"> - <a t-att-href="'#' + searchbar_inputs[input]['input']"><span t-raw="searchbar_inputs[input]['label']"/></a> - </li> - </ul> - </div> - <input type="text" class="form-control search_panel_fixed_width" t-att-value='search' name="search"/> - <span class="input-group-btn"> - <button class="btn btn-default search-submit" type="button"><span class="fa fa-search"></span></button> - </span> - </div> - </div> - </t> - <div t-if="searchbar_sortings" class="dropdown pull-right mr4"> - <button id="portal_searchbar_sortby" class="search_panel_fixed_width btn btn-default" type="button" data-toggle="dropdown"> - <span class="fa fa-sort fa-lg" /> - <span class='hidden-xs hidden-sm hidden-md' t-esc="searchbar_sortings[sortby].get('label', 'Newest')"/> - <span class="caret"></span> - </button> - <ul class="dropdown-menu" aria-labelledby="portal_searchbar_sortby"> - <li t-foreach="searchbar_sortings" t-as="option" t-attf-class="#{sortby == option and 'active'}"> - <a t-att-href="request.httprequest.path + '?' + keep_query('*', sortby=option)"> - <span t-esc="searchbar_sortings[option].get('label')"/> - </a> - </li> - </ul> - </div> - <div t-if="searchbar_filters" class="dropdown pull-right mr4"> - <button id="portal_searchbar_filters" class="search_panel_fixed_width btn btn-default" type="button" data-toggle="dropdown"> - <span class="fa fa-filter fa-lg" /> - <span class='hidden-xs hidden-sm hidden-md' t-esc="searchbar_filters[filterby].get('label', 'All')"/> - <span class="caret"></span> - </button> - <ul class="dropdown-menu" aria-labelledby="portal_searchbar_filters"> - <li t-foreach="searchbar_filters" t-as="option" t-att-class="filterby == option and 'active'"> - <a t-att-href="default_url + '?' + keep_query('*', filterby=option)"> - <span t-esc="searchbar_filters[option].get('label')"/> - </a> - </li> - </ul> - </div> - </template> - - <template id="portal_layout" name="Portal Layout"> - <t t-call="website.layout"> - <div class="container mt16 o_portal"> - <div class="oe_structure"> - <div t-if="not no_breadcrumbs" class="row"> - <div class="col-sm-12"> - <ol class="breadcrumb o_portal_submenu"> - <li><a href="/my/home"><i class="fa fa-home"/></a></li> - <li t-if="page_name == 'my_details'">Your Details</li> - </ol> - </div> - </div> - </div> - </div> - <div id="wrap" class='portal-wrap'> - <div class="container mb64"> - <t t-if="my_details"> - <div class="row"> - <div t-attf-class="col-md-9 col-lg-8"> - <t t-raw="0"/> - </div> - <div id="o_my_sidebar" class="col-md-3 col-lg-offset-1 o_my_sidebar"> - <div class="o_my_contact" t-if="sales_rep"> - <t t-call="website_portal.contact"/> - </div> - <div class="o_my_details"> - <h3 class="page-header">Your Details <a href="/my/account" class="btn btn-default btn-xs">Change</a></h3> - <div t-field="user.partner_id" t-options='{"widget": "contact", "fields": ["email", "phone", "address", "name"]}'/> - </div> - <div class="o_my_archives" t-if="archive_groups"> - <t t-call="website_portal.portal_archive_groups"/> - </div> - </div> - </div> - </t> - <t t-else=""> - <t t-raw="0"/> - </t> - </div> - </div> - </t> - </template> - - <template id="portal_my_home" name="My Portal"> - <t t-call="website_portal.portal_layout"> - <t t-set="my_details" t-value="True"/> - <div class="o_my_home_content"> - <div class="oe_structure"></div> - <h3 class="page-header">Your Documents</h3> - <ul class="o_portal_docs list-group"> - </ul> - </div> - <div class="col-md-12 oe_structure"/> - </t> - </template> - - <template id="contact" name="Contact"> - <h3 class="page-header">Salesperson</h3> - <h5 t-esc="sales_rep.name"/> - <p><a t-att-href="'mailto:'+sales_rep.email" t-esc="sales_rep.email"/></p> - <p t-esc="sales_rep.phone"/> - <p t-esc="sales_rep.city"/> - </template> - - <template id="details"> - <t t-call="website_portal.portal_layout"> - <t t-set="additional_title">Your Contact Details</t> - <h3>Your Details</h3> - <form action="/my/account" method="post"> - <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/> - <div class="row o_portal_details"> - <div class="col-md-8"> - <div class="row"> - <div class="col-md-12"> - <div t-if="error_message" class="alert alert-danger"> - <t t-foreach="error_message" t-as="err"><t t-esc="err"/><br /></t> - </div> - </div> - <div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6"> - <label class="control-label" for="name">Your Name</label> - <input type="text" name="name" class="form-control" t-att-value="name or partner.name" /> - </div> - <div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6"> - <label class="control-label" for="email">Email</label> - <input type="email" name="email" class="form-control" t-att-value="email or partner.email" /> - </div> - <div t-attf-class="form-group #{error.get('phone') and 'has-error' or ''} col-lg-6"> - <label class="control-label" for="phone">Phone</label> - <input type="tel" name="phone" class="form-control" t-att-value="phone or partner.phone" /> - </div> - - <div class="clearfix" /> - <div t-attf-class="form-group #{error.get('company_name') and 'has-error' or ''} col-lg-6"> - <label class="control-label label-optional" for="company_name">Company Name</label> - <input type="text" name="company_name" class="form-control" t-att-value="company_name or partner.company_name"/> - </div> - <div t-if="has_check_vat" t-attf-class="form-group #{error.get('vat') and 'has-error' or ''} col-lg-6"> - <label class="control-label label-optional" for="vat">VAT Number</label> - <input type="text" name="vat" class="form-control" t-att-value="vat or partner.vat" /> - </div> - - <div class="clearfix" /> - <div t-attf-class="form-group #{error.get('street') and 'has-error' or ''} col-lg-6"> - <label class="control-label label-optional" for="street">Street</label> - <input type="text" name="street" class="form-control" t-att-value="street or partner.street"/> - </div> - <div t-attf-class="form-group #{error.get('city') and 'has-error' or ''} col-lg-6"> - <label class="control-label" for="city">City</label> - <input type="text" name="city" class="form-control" t-att-value="city or partner.city" /> - </div> - <div t-attf-class="form-group #{error.get('zip') and 'has-error' or ''} col-lg-6"> - <label class="control-label" for="zipcode">Zip / Postal Code</label> - <input type="text" name="zipcode" class="form-control" t-att-value="zipcode or partner.zip" /> - </div> - <div t-attf-class="form-group #{error.get('country_id') and 'has-error' or ''} col-lg-6"> - <label class="control-label" for="country_id">Country</label> - <select name="country_id" class="form-control"> - <option value="">Country...</option> - <t t-foreach="countries or []" t-as="country"> - <option t-att-value="country.id" t-att-selected="country.id == partner.country_id.id"> - <t t-esc="country.name" /> - </option> - </t> - </select> - </div> - <div t-attf-class="form-group #{error.get('state_id') and 'has-error' or ''} col-lg-6"> - <label class="control-label label-optional" for="state_id">State / Province</label> - <select name="state_id" class="form-control"> - <option value="">select...</option> - <t t-foreach="states or []" t-as="state"> - <option t-att-value="state.id" style="display:none;" t-att-data-country_id="state.country_id.id" t-att-selected="state.id == partner.state_id.id"> - <t t-esc="state.name" /> - </option> - </t> - </select> - </div> - <input type="hidden" name="redirect" t-att-value="redirect"/> - </div> - <div class="clearfix"> - <button type="submit" class="btn btn-primary pull-right mb32 "> - Confirm - <span class="fa fa-long-arrow-right" /> - </button> - </div> - </div> - </div> - </form> - </t> - </template> - - <template id="my_account_link" name="Link to frontend portal" inherit_id="website.layout"> - <xpath expr="//li[@id='o_logout']" position="before"> - <li><a href="/my/home" role="menuitem">My Account</a></li> - </xpath> - </template> - - <template id="record_pager" name="Portal Record Pager"> - <t t-if='prev_record or next_record'> - <div class="ml8 record_pager btn-group btn-group-xs pull-right" role="group"> - <a t-att-class="'btn btn-default %s' % ('disabled' if not prev_record else '')" t-att-href="prev_record or '#'" ><i class="fa fa-arrow-left" aria-hidden="true"></i></a> - <a t-att-class="'btn btn-default %s' % ('disabled' if not next_record else '')" t-att-href="next_record or '#'" ><i class="fa fa-arrow-right" aria-hidden="true"></i></a> - </div> - </t> - </template> - -</odoo> diff --git a/addons/website_portal_purchase/__manifest__.py b/addons/website_portal_purchase/__manifest__.py index 473ee58521f..5e99ea91d51 100644 --- a/addons/website_portal_purchase/__manifest__.py +++ b/addons/website_portal_purchase/__manifest__.py @@ -11,7 +11,8 @@ Display purchase orders on your website. Customers will be able to access their """, 'depends': [ 'purchase', - 'website_portal', + 'website', + 'portal', ], 'data': [ 'views/website_portal_purchase_templates.xml', diff --git a/addons/website_portal_purchase/controllers/website_portal.py b/addons/website_portal_purchase/controllers/website_portal.py index 874c311f92a..4694cc541c3 100644 --- a/addons/website_portal_purchase/controllers/website_portal.py +++ b/addons/website_portal_purchase/controllers/website_portal.py @@ -8,11 +8,10 @@ from odoo.exceptions import AccessError from odoo.http import request from odoo.tools import pycompat from odoo.tools.translate import _ +from odoo.addons.portal.controllers.portal import get_records_pager, CustomerPortal -from odoo.addons.website_portal.controllers.main import website_account, get_records_pager - -class WebsitePortal(website_account): +class WebsitePortal(CustomerPortal): def _prepare_portal_layout_values(self): values = super(WebsitePortal, self)._prepare_portal_layout_values() diff --git a/addons/website_portal_purchase/views/website_portal_purchase_templates.xml b/addons/website_portal_purchase/views/website_portal_purchase_templates.xml index 17fe2e81d31..118b317b802 100644 --- a/addons/website_portal_purchase/views/website_portal_purchase_templates.xml +++ b/addons/website_portal_purchase/views/website_portal_purchase_templates.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> - <template id="portal_my_home_menu_purchase" name="Portal layout : purchase menu entries" inherit_id="website_portal.portal_layout" priority="25"> + <template id="portal_my_home_menu_purchase" name="Portal layout : purchase menu entries" inherit_id="portal.portal_layout" priority="25"> <xpath expr="//ol[contains(@class,'o_portal_submenu')]" position="inside"> <li t-if="page_name == 'purchase' or purchase_order"> <a t-if="purchase_order" t-attf-href="/my/purchase?{{ keep_query() }}">Purchase Orders</a> @@ -13,7 +13,7 @@ </xpath> </template> - <template id="portal_my_home_purchase" name="Portal My Home : purchase entry" inherit_id="website_portal.portal_my_home" priority="25"> + <template id="portal_my_home_purchase" name="Portal My Home : purchase entry" inherit_id="portal.portal_my_home" priority="25"> <xpath expr="//ul[contains(@class,'o_portal_docs')]" position="inside"> <li t-if="purchase_count" class="list-group-item"> <span class="badge" t-esc="purchase_count"/> @@ -23,9 +23,9 @@ </template> <template id="portal_my_purchase_orders" name="Portal: My Purchase Orders"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <h3>Purchase Orders - <t t-call="website_portal.portal_searchbar"/> + <t t-call="portal.portal_searchbar"/> </h3> <div t-if="orders" class="panel panel-default"> <div class="table-responsive"><table class="table table-hover o_my_status_table"> @@ -61,7 +61,7 @@ </template> <template id="portal_my_purchase_order" name="Portal: My Purchase Order"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <t t-set="purchase_order" t-value="order"/> <div id="optional_placeholder"></div> <div class="container"> @@ -70,7 +70,7 @@ <div class="row"> <div class="col-md-12"> <h4> - <t t-call='website_portal.record_pager'/> + <t t-call='portal.record_pager'/> Purchase Order <span t-esc="order.name"/> </h4> diff --git a/addons/website_portal_sale/controllers/main.py b/addons/website_portal_sale/controllers/main.py index 3103b3037e3..2da2aa1ba06 100644 --- a/addons/website_portal_sale/controllers/main.py +++ b/addons/website_portal_sale/controllers/main.py @@ -6,7 +6,8 @@ from odoo.exceptions import AccessError from odoo.http import request from odoo.tools import consteq -from odoo.addons.website_portal.controllers.main import website_account, get_records_pager +from odoo.addons.portal.controllers.portal import get_records_pager +from odoo.addons.website_portal.controllers.main import website_account class website_account(website_account): diff --git a/addons/website_portal_sale/views/website_portal_sale_templates.xml b/addons/website_portal_sale/views/website_portal_sale_templates.xml index 01884a10859..1374d1a506d 100644 --- a/addons/website_portal_sale/views/website_portal_sale_templates.xml +++ b/addons/website_portal_sale/views/website_portal_sale_templates.xml @@ -6,7 +6,7 @@ </xpath> </template> - <template id="portal_my_home_menu_sale" name="Portal layout : sales menu entries" inherit_id="website_portal.portal_layout" priority="20"> + <template id="portal_my_home_menu_sale" name="Portal layout : sales menu entries" inherit_id="portal.portal_layout" priority="20"> <xpath expr="//ol[contains(@class,'o_portal_submenu')]" position="inside"> <li t-if="page_name == 'quote' or sales_order and sales_order.state == 'sent'"> <a t-if="sales_order" t-attf-href="/my/quotes?{{ keep_query() }}">Quotations</a> @@ -24,7 +24,7 @@ </xpath> </template> - <template id="portal_my_home_sale" name="Portal My Home : sales entries" inherit_id="website_portal.portal_my_home" priority="20"> + <template id="portal_my_home_sale" name="Portal My Home : sales entries" inherit_id="portal.portal_my_home" priority="20"> <xpath expr="//ul[contains(@class,'o_portal_docs')]" position="inside"> <li t-if="quotation_count" class="list-group-item"> <span class="badge" t-esc="quotation_count"/> @@ -38,9 +38,9 @@ </template> <template id="portal_my_quotations" name="My Quotations"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <h3>Quotations - <t t-call="website_portal.portal_searchbar"/> + <t t-call="portal.portal_searchbar"/> </h3> <t t-if="not quotations"> <p>There are currently no quotations for your account.</p> @@ -84,9 +84,9 @@ </template> <template id="portal_my_orders" name="My Sales Orders"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <h3>Sales Orders - <t t-call="website_portal.portal_searchbar"/> + <t t-call="portal.portal_searchbar"/> </h3> <t t-if="not orders"> <p>There are currently no orders for your account.</p> @@ -136,7 +136,7 @@ </template> <template id="orders_followup" name="Sales Order"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <t t-set="sales_order" t-value="order"/> <!-- rename to ensure breadcrumb compatibility (differentiate with purchase orders) --> <div id="optional_placeholder"></div> <div class="container"> @@ -146,7 +146,7 @@ <div class="row"> <div class="col-md-12"> <h4> - <t t-call='website_portal.record_pager'/> + <t t-call='portal.record_pager'/> <t t-if="order.state == 'sent'"> Quotation </t> diff --git a/addons/website_project/__manifest__.py b/addons/website_project/__manifest__.py index e105d8177a7..50212999215 100644 --- a/addons/website_project/__manifest__.py +++ b/addons/website_project/__manifest__.py @@ -7,7 +7,7 @@ Website portal for Project and Tasks ==================================== """, 'category': 'Website', - 'depends': ['project', 'website_portal'], + 'depends': ['project', 'website', 'portal'], 'data': [ 'security/project_security.xml', 'security/ir.model.access.csv', diff --git a/addons/website_project/controllers/main.py b/addons/website_project/controllers/main.py index d8716efd9ac..4e29fb1ccf4 100644 --- a/addons/website_project/controllers/main.py +++ b/addons/website_project/controllers/main.py @@ -5,13 +5,12 @@ from collections import OrderedDict from odoo import http, _ from odoo.http import request - -from odoo.addons.website_portal.controllers.main import website_account, get_records_pager +from odoo.addons.portal.controllers.portal import get_records_pager, CustomerPortal from odoo.osv.expression import OR from odoo.tools import pycompat -class WebsiteAccount(website_account): +class WebsiteAccount(CustomerPortal): def _prepare_portal_layout_values(self): values = super(WebsiteAccount, self)._prepare_portal_layout_values() diff --git a/addons/website_project/views/project_templates.xml b/addons/website_project/views/project_templates.xml index cd4a6e9dac5..1b0b0599c1a 100644 --- a/addons/website_project/views/project_templates.xml +++ b/addons/website_project/views/project_templates.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> - <template id="portal_layout" name="Portal layout: project menu entry" inherit_id="website_portal.portal_layout" priority="40"> + <template id="portal_layout" name="Portal layout: project menu entry" inherit_id="portal.portal_layout" priority="40"> <xpath expr="//ol[contains(@class,'o_portal_submenu')]" position="inside"> <li t-if="page_name == 'project' or project"> <a t-if="project" t-attf-href="/my/projects?{{ keep_query() }}">Projects</a> @@ -19,7 +19,7 @@ </xpath> </template> - <template id="portal_my_home" name="Portal My Home: project entries" inherit_id="website_portal.portal_my_home" priority="40"> + <template id="portal_my_home" name="Portal My Home: project entries" inherit_id="portal.portal_my_home" priority="40"> <xpath expr="//ul[contains(@class,'o_portal_docs')]" position="inside"> <li t-if="project_count" class="list-group-item"> <span class="badge" t-esc="project_count"/> @@ -33,9 +33,9 @@ </template> <template id="my_projects" name="My Projects"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <h3>Projects - <t t-call="website_portal.portal_searchbar"/> + <t t-call="portal.portal_searchbar"/> </h3> <t t-if="not projects"> <div class="alert alert-warning mt8" role="alert"> @@ -72,13 +72,13 @@ </template> <template id="my_project" name="My Project"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <div class="panel panel-default"> <div class="panel-heading"> <div class="row"> <div class="col-md-12"> <h4> - <t t-call='website_portal.record_pager'/> + <t t-call='portal.record_pager'/> Project - <span t-field="project.name"/> </h4> </div> @@ -126,9 +126,9 @@ </template> <template id="my_tasks" name="My Tasks"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <h3>Tasks - <t t-call="website_portal.portal_searchbar"/> + <t t-call="portal.portal_searchbar"/> </h3> <t t-if="not tasks"> <div class="alert alert-warning mt8" role="alert"> @@ -164,13 +164,13 @@ </template> <template id="my_task" name="My Task"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <div class="panel panel-default"> <div class="panel-heading"> <div class="row"> <div class="col-md-12"> <h4> - <t t-call='website_portal.record_pager'/> + <t t-call='portal.record_pager'/> Task - <span t-field="task.name"/> <span t-field="task.stage_id.name" class="pull-right label label-info" title="Current stage of this task"/> <a class="btn btn-info" t-att-href="'/web#return_label=Website&model=project.task&id=%s&view_type=form' % (task.id)" groups="project.group_project_user">Edit Task</a> diff --git a/addons/website_quote/controllers/main.py b/addons/website_quote/controllers/main.py index 8e4359ecbec..522d3561b7f 100644 --- a/addons/website_quote/controllers/main.py +++ b/addons/website_quote/controllers/main.py @@ -5,8 +5,8 @@ import werkzeug from odoo import fields, http, _ from odoo.http import request +from odoo.addons.portal.controllers.portal import get_records_pager from odoo.addons.website_mail.controllers.main import _message_post_helper -from odoo.addons.website_portal.controllers.main import get_records_pager class sale_quote(http.Controller): diff --git a/addons/website_quote/views/website_quote_templates.xml b/addons/website_quote/views/website_quote_templates.xml index 80f54b02f2f..e7e9c574ec0 100644 --- a/addons/website_quote/views/website_quote_templates.xml +++ b/addons/website_quote/views/website_quote_templates.xml @@ -166,7 +166,7 @@ <!-- Complete page of the quotation --> <template id="so_quotation" name="Product Quotation"> - <t t-call="website_portal.portal_layout"> + <t t-call="portal.portal_layout"> <t t-set="sales_order" t-value="quotation"/> <!-- rename to ensure breadcrumb compatibility with website_portal_sale's portal_layout inheritance --> <body data-spy="scroll" data-target=".navspy" data-offset="50"> <div class="container o_website_quote"> @@ -470,7 +470,7 @@ <a class="btn btn-info" target="_blank" t-att-href="'/quote/%s/%s' % (quotation.id,quotation.access_token)+'?pdf=True'">Print</a> </li> <li> - <t t-call='website_portal.record_pager'/> + <t t-call='portal.record_pager'/> </li> </ul> </div> |
