From 4dfbcecfdb59c12eaf4b3b435a626f07574d5ce3 Mon Sep 17 00:00:00 2001
From: Vipul Bhatt <vbh@odoo.com>
Date: Tue, 12 Apr 2016 10:22:19 +0200
Subject: [PATCH] [IMP] website_{portal,portal_sale,project_issue,quote} : add
 pager for customer documents

This commit adds controller to list documents of customer, with pager and archive
widget to sort documents. Impacted documents are : quotations, sale order,
invoices, and issues.

Portal breadcrumd is improved too : add the home icon, and keep the query
params when using archive widget.

Some editable zones were added to templates, allowing people to customize
their frontend portal.
---
 .../views/website_payment_templates.xml       |   6 +-
 addons/website_portal/controllers/main.py     |  35 ++++-
 .../static/src/js/website_portal.js           |  11 +-
 .../static/src/less/website_portal.less       |   6 +-
 addons/website_portal/views/templates.xml     |  66 ++++++--
 .../website_portal_sale/controllers/main.py   | 142 ++++++++++++++++--
 .../website_portal_sale/views/templates.xml   | 111 +++++++++++---
 .../website_project_issue/controllers/main.py |  41 ++++-
 .../views/project_issue_templates.xml         |  50 ++++--
 .../website_quote/views/website_quotation.xml |   9 +-
 10 files changed, 394 insertions(+), 83 deletions(-)

diff --git a/addons/website_payment/views/website_payment_templates.xml b/addons/website_payment/views/website_payment_templates.xml
index 0395b6ccfaf7..1dc0d39a76ae 100644
--- a/addons/website_payment/views/website_payment_templates.xml
+++ b/addons/website_payment/views/website_payment_templates.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <openerp>
     <data>
-        <template id="header_footer_custom_payment" inherit_id="website_portal.account" customize_show="True" active="False" name="Payment Methods">
+        <template id="header_footer_custom_payment" inherit_id="website_portal.portal_layout" customize_show="True" active="False" name="Payment Methods">
             <xpath expr="//div[@class='o_my_details']" position="inside">
                 <h4 class="payment_method_title">Payment Method</h4>
                 <ul class="payment_method_list list-inline">
@@ -30,7 +30,7 @@
                   <div class="row">
                         <div class="col-sm-6">
                             <ol class="breadcrumb mt8">
-                                <li><a href="/my/home">My Account</a></li>
+                                <li><a href="/my/home"><i class="fa fa-home"/></a></li>
                                 <li>Payment Methods</li>
                             </ol>
                         </div>
@@ -78,7 +78,7 @@
         </t>
     </template>
 
-    <template id="pay_meth_link" inherit_id="website_portal.account">
+    <template id="pay_meth_link" inherit_id="website_portal.portal_layout">
         <xpath expr="//div[@class='o_my_details']" position="inside">
             <a href="/my/payment_method">Manage your payment methods</a>
         </xpath>
diff --git a/addons/website_portal/controllers/main.py b/addons/website_portal/controllers/main.py
index a11adac2ab49..2990ced04a28 100644
--- a/addons/website_portal/controllers/main.py
+++ b/addons/website_portal/controllers/main.py
@@ -4,12 +4,16 @@ from openerp.http import request
 from openerp import tools
 from openerp.tools.translate import _
 
+from odoo.fields import Date
+
 
 class website_account(http.Controller):
-    @http.route(['/my', '/my/home'], type='http', auth="public", website=True)
-    def account(self):
-        partner = request.env.user.partner_id
 
+    _items_per_page = 10
+
+    def _prepare_portal_layout_values(self):
+        """ prepare the values to render portal layout """
+        partner = request.env.user.partner_id
         # get customer sales rep
         if partner.user_id:
             sales_rep = partner.user_id
@@ -20,8 +24,31 @@ class website_account(http.Controller):
             '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
 
-        return request.website.render("website_portal.account", values)
+    @http.route(['/my', '/my/home'], type='http', auth="public", website=True)
+    def account(self):
+        values = self._prepare_portal_layout_values()
+        return request.website.render("website_portal.portal_my_home", values)
 
     @http.route(['/my/account'], type='http', auth='user', website=True)
     def details(self, redirect=None, **post):
diff --git a/addons/website_portal/static/src/js/website_portal.js b/addons/website_portal/static/src/js/website_portal.js
index 6f9e364998dd..d63ef0672948 100644
--- a/addons/website_portal/static/src/js/website_portal.js
+++ b/addons/website_portal/static/src/js/website_portal.js
@@ -1,9 +1,10 @@
+
 odoo.define('website_portal', function(require) {
     'use strict';
     require('website.website');
 
-    if(!$('.o_website_portal_details, .o_my_show_more').length) {
-        return $.Deferred().reject("DOM doesn't contain '.o_website_portal_details' or '.o_my_show_more'");
+    if(!$('.o_website_portal_details').length) {
+        return $.Deferred().reject("DOM doesn't contain '.o_website_portal_details'");
     }
 
     var state_options = $("select[name='state_id']:enabled option:not(:first)");
@@ -15,10 +16,4 @@ odoo.define('website_portal', function(require) {
         select.parent().toggle(nb>=1);
     });
     $('.o_website_portal_details').find("select[name='country_id']").change();
-
-    $('.o_my_show_more').on('click', function(ev) {
-        ev.preventDefault();
-        $(this).parents('table').find(".to_hide").toggleClass('hidden');
-        $(this).find('span').toggleClass('hidden');
-    });
 });
diff --git a/addons/website_portal/static/src/less/website_portal.less b/addons/website_portal/static/src/less/website_portal.less
index d1f04277023b..1de553fa7cb0 100644
--- a/addons/website_portal/static/src/less/website_portal.less
+++ b/addons/website_portal/static/src/less/website_portal.less
@@ -15,4 +15,8 @@
         text-align: left;
     }
     table-layout: fixed;
-}
\ No newline at end of file
+}
+
+.o_my_home_content > .page-header > a:hover {
+    text-decoration: none;
+}
diff --git a/addons/website_portal/views/templates.xml b/addons/website_portal/views/templates.xml
index 6f52b9a8aacd..3c6e70b78aab 100644
--- a/addons/website_portal/views/templates.xml
+++ b/addons/website_portal/views/templates.xml
@@ -8,30 +8,76 @@
       </xpath>
     </template>
 
-    <template id="account" name="Account">
+    <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']}&amp;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_layout" name="Portal Layout">
         <t t-call="website.layout">
+            <div class="container mt16">
+                <div class="navbar navbar-default">
+                    <div class="navbar-header">
+                        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#oe-help-navbar-collapse">
+                            <span class="sr-only">Toggle navigation</span>
+                            <span class="icon-bar"></span>
+                            <span class="icon-bar"></span>
+                        </button>
+                        <a class="navbar-brand" href="/my/home">
+                            My Account
+                        </a>
+                    </div>
+                    <div class="collapse navbar-collapse" id="oe-help-navbar-collapse">
+                        <ul class="nav navbar-nav o_portal_submenu">
+                        </ul>
+                    </div>
+                </div>
+            </div>
             <div id="wrap">
                 <div class="container mb64">
-                    <div class="col-md-8 o_my_documents">
-                        <div class="oe_structure"/>
-                    </div>
-                    <div t-if="sales_rep" class="col-md-3">
-                      <t t-call="website_portal.contact" />
-                      <div class="oe_structure"/>
+                    <div class="col-md-8">
+                        <t t-raw="0"/>
                     </div>
                     <div id="o_my_sidebar" class="col-md-3 col-md-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-field-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 class="col-md-12 oe_structure"/>
                 </div>
             </div>
         </t>
     </template>
 
-    <template id="website_portal.custom_panel" inherit_id='website_portal.account' customize_show="True" name="Editable Panel" active="False">
+    <template id="portal_my_home" name="My Portal">
+        <t t-call="website_portal.portal_layout">
+            <div class="o_my_home_content">
+                <div class="oe_structure"></div>
+            </div>
+            <div class="col-md-12 oe_structure"/>
+        </t>
+    </template>
+
+    <template id="website_portal.custom_panel" inherit_id='website_portal.portal_layout' customize_show="True" name="Editable Panel" active="False">
         <xpath expr="//div[@id='o_my_sidebar']" position="inside">
             <div class="oe_structure">
               <h3 class="page-header">Custom Panel</h3>
@@ -56,7 +102,7 @@
                   <div class="row">
                         <div class="col-sm-6">
                             <ol class="breadcrumb mt8">
-                                <li><a href="/my/home">My Account</a></li>
+                                <li><a href="/my/home"><i class="fa fa-home"/></a></li>
                                 <li>Details</li>
                             </ol>
                         </div>
diff --git a/addons/website_portal_sale/controllers/main.py b/addons/website_portal_sale/controllers/main.py
index fc88ce8125c0..11da77648ea4 100644
--- a/addons/website_portal_sale/controllers/main.py
+++ b/addons/website_portal_sale/controllers/main.py
@@ -9,45 +9,163 @@ from openerp.addons.website_portal.controllers.main import website_account
 
 
 class website_account(website_account):
-    @http.route(['/my/home'], type='http', auth="user", website=True)
-    def account(self, **kw):
+
+    @http.route()
+    def account(self):
         """ Add sales documents to main account page """
         response = super(website_account, self).account()
         partner = request.env.user.partner_id
 
-        res_sale_order = request.env['sale.order']
-        res_invoices = request.env['account.invoice']
-        quotations = res_sale_order.search([
+        SaleOrder = request.env['sale.order']
+        Invoice = request.env['account.invoice']
+        quotation_count = SaleOrder.search_count([
             ('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
             ('state', 'in', ['sent', 'cancel'])
         ])
-        orders = res_sale_order.search([
+        order_count = SaleOrder.search_count([
             ('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
             ('state', 'in', ['sale', 'done'])
         ])
-        invoices = res_invoices.search([
+        invoice_count = Invoice.search_count([
             ('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
             ('state', 'in', ['open', 'paid', 'cancelled'])
         ])
 
         response.qcontext.update({
-            'date': datetime.date.today().strftime('%Y-%m-%d'),
+            'quotation_count': quotation_count,
+            'order_count': order_count,
+            'invoice_count': invoice_count,
+        })
+        return response
+
+    #
+    # Quotations and Sale Orders
+    #
+
+    @http.route(['/my/quotes', '/my/quotes/page/<int:page>'], type='http', auth="user", website=True)
+    def portal_my_quotes(self, page=1, date_begin=None, date_end=None, **kw):
+        values = self._prepare_portal_layout_values()
+        partner = request.env.user.partner_id
+        SaleOrder = request.env['sale.order']
+
+        domain = [
+            ('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
+            ('state', 'in', ['sent', 'cancel'])
+        ]
+
+        archive_groups = self._get_archive_groups('sale.order', domain)
+        if date_begin and date_end:
+            domain += [('create_date', '>=', date_begin), ('create_date', '<', date_end)]
+
+        # count for pager
+        quotation_count = SaleOrder.search_count(domain)
+        # make pager
+        pager = request.website.pager(
+            url="/my/quotes",
+            url_args={'date_begin': date_begin, 'date_end': date_end},
+            total=quotation_count,
+            page=page,
+            step=self._items_per_page
+        )
+        # search the count to display, according to the pager data
+        quotations = SaleOrder.search(domain, limit=self._items_per_page, offset=pager['offset'])
+
+        values.update({
+            'date': date_begin,
             'quotations': quotations,
+            'pager': pager,
+            'archive_groups': archive_groups,
+            'default_url': '/my/quotes',
+        })
+        return request.website.render("website_portal_sale.portal_my_quotations", values)
+
+    @http.route(['/my/orders', '/my/orders/page/<int:page>'], type='http', auth="user", website=True)
+    def portal_my_orders(self, page=1, date_begin=None, date_end=None, **kw):
+        values = self._prepare_portal_layout_values()
+        partner = request.env.user.partner_id
+        SaleOrder = request.env['sale.order']
+
+        domain = [
+            ('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
+            ('state', 'in', ['sale', 'done'])
+        ]
+        archive_groups = self._get_archive_groups('sale.order', domain)
+        if date_begin and date_end:
+            domain += [('create_date', '>=', date_begin), ('create_date', '<', date_end)]
+
+        # count for pager
+        order_count = SaleOrder.search_count(domain)
+        # pager
+        pager = request.website.pager(
+            url="/my/orders",
+            url_args={'date_begin': date_begin, 'date_end': date_end},
+            total=order_count,
+            page=page,
+            step=self._items_per_page
+        )
+        # content according to pager and archive selected
+        orders = SaleOrder.search(domain, limit=self._items_per_page, offset=pager['offset'])
+
+        values.update({
+            'date': date_begin,
             'orders': orders,
-            'invoices': invoices,
+            'page_name': 'order',
+            'pager': pager,
+            'archive_groups': archive_groups,
+            'default_url': '/my/orders',
         })
-        return response
+        return request.website.render("website_portal_sale.portal_my_orders", values)
 
     @http.route(['/my/orders/<int:order>'], type='http', auth="user", website=True)
-    def orders_followup(self, order=None):
+    def orders_followup(self, order=None, **kw):
         order = request.env['sale.order'].browse([order])
         try:
             order.check_access_rights('read')
             order.check_access_rule('read')
         except AccessError:
-                return request.website.render("website.403")
+            return request.website.render("website.403")
         order_invoice_lines = {il.product_id.id: il.invoice_id for il in order.invoice_ids.mapped('invoice_line_ids')}
         return request.website.render("website_portal_sale.orders_followup", {
             'order': order.sudo(),
             'order_invoice_lines': order_invoice_lines,
         })
+
+    #
+    # Invoices
+    #
+
+    @http.route(['/my/invoices', '/my/invoices/page/<int:page>'], type='http', auth="user", website=True)
+    def portal_my_invoices(self, page=1, date_begin=None, date_end=None, **kw):
+        values = self._prepare_portal_layout_values()
+        partner = request.env.user.partner_id
+        AccountInvoice = request.env['account.invoice']
+
+        domain = [
+            ('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
+            ('state', 'in', ['open', 'paid', 'cancelled'])
+        ]
+        archive_groups = self._get_archive_groups('account.invoice', domain)
+        if date_begin and date_end:
+            domain += [('create_date', '>=', date_begin), ('create_date', '<', date_end)]
+
+        # count for pager
+        invoice_count = AccountInvoice.search_count(domain)
+        # pager
+        pager = request.website.pager(
+            url="/my/invoices",
+            url_args={'date_begin': date_begin, 'date_end': date_end},
+            total=invoice_count,
+            page=page,
+            step=self._items_per_page
+        )
+        # content according to pager and archive selected
+        invoices = AccountInvoice.search(domain, limit=self._items_per_page, offset=pager['offset'])
+        values.update({
+            'date': date_begin,
+            'invoices': invoices,
+            'page_name': 'invoice',
+            'pager': pager,
+            'archive_groups': archive_groups,
+            'default_url': '/my/invoices',
+        })
+        return request.website.render("website_portal_sale.portal_my_invoices", values)
diff --git a/addons/website_portal_sale/views/templates.xml b/addons/website_portal_sale/views/templates.xml
index 25c88200800b..80103dca6714 100644
--- a/addons/website_portal_sale/views/templates.xml
+++ b/addons/website_portal_sale/views/templates.xml
@@ -6,15 +6,63 @@
       </xpath>
     </template>
 
-    <template id="account" name="Account" inherit_id="website_portal.account">
-        <xpath expr="//div[contains(@class,'o_my_documents')]" position="inside">
-            <t t-call="website_portal_sale.quotations" />
-            <t t-call="website_portal_sale.sale_orders" />
-            <t t-call="website_portal_sale.invoices" />
+    <template id="portal_my_home_menu_sale" name="Portal layout : sales menu entries" inherit_id="website_portal.portal_layout" priority="25">
+        <xpath expr="//ul[contains(@class,'o_portal_submenu')]" position="inside">
+            <li>
+                <a href="/my/quotes">Quotes</a>
+            </li>
+            <li>
+                <a href="/my/orders">Orders</a>
+            </li>
+            <li>
+                <a href="/my/invoices">Invoices</a>
+            </li>
         </xpath>
     </template>
 
-    <template id="quotations" name="Quotations">
+    <template id="portal_my_home_sale" name="Portal My Home : sales entries" inherit_id="website_portal.portal_my_home" priority="25">
+        <xpath expr="//div[contains(@class,'o_my_home_content')]" position="inside">
+            <h3 class="page-header">
+                <a href="/my/quotes">Your Quotes
+                    <small class="ml8">
+                        <t t-if="quotation_count">
+                            <span class='badge'><t t-esc="quotation_count"/></span>
+                        </t>
+                        <t t-if="not quotation_count">
+                            There are currently no quotes for your account.
+                        </t>
+                    </small>
+                </a>
+            </h3>
+            <h3 class="page-header">
+                <a href="/my/orders">Your Orders
+                    <small class="ml8">
+                        <t t-if="order_count">
+                            <span class='badge'><t t-esc="order_count"/></span>
+                        </t>
+                        <t t-if="not order_count">
+                            There are currently no orders for your account.
+                        </t>
+                    </small>
+                </a>
+            </h3>
+            <h3 class="page-header">
+                <a href="/my/invoices">Your Invoices and Payments
+                    <small class="ml8">
+                        <t t-if="invoice_count">
+                            <span class='badge'><t t-esc="invoice_count"/></span>
+                        </t>
+                        <t t-if="not invoice_count">
+                            There are currently no invoices for your account.
+                        </t>
+                    </small>
+                </a>
+            </h3>
+        </xpath>
+    </template>
+
+    <template id="portal_my_quotations" name="My Quotations">
+      <t t-call="website_portal.portal_layout">
         <h3 class="page-header">Your Quotes</h3>
         <t t-if="not quotations">
             <p>There are currently no quotes for your account.</p>
@@ -30,9 +78,9 @@
                     </tr>
                 </thead>
                 <t t-foreach="quotations" t-as="quotation">
-                    <tr t-att-class="'hidden to_hide' if quotation.state!='sent' and quotation_index &gt; 4 else ''">
+                    <tr>
                         <td>
-                            <a t-att-href="'/my/orders/'+str(quotation.id)"><t t-esc="quotation.name"/></a>
+                            <a t-attf-href="/my/orders/#{quotation.id}?#{keep_query()}"><t t-esc="quotation.name"/></a>
                         </td>
                         <td><span t-field="quotation.validity_date"/></td>
                         <td>
@@ -47,14 +95,16 @@
                         </td>
                     </tr>
                 </t>
-                <tr t-att-class="'hidden' if len(quotations) &lt; 5 else ''">
-                  <td colspan="5"><a href="" class="o_my_show_more btn btn-xs btn-default"><span>Show more</span><span class="hidden">Show less</span></a></td>
-                </tr>
             </table>
+            <div t-if="pager" class="o_portal_pager text-center">
+              <t t-call="website.pager"/>
+            </div>
         </t>
+      </t>
     </template>
 
-    <template id="sale_orders" name="Sales Orders">
+    <template id="portal_my_orders" name="My Sales Orders">
+      <t t-call="website_portal.portal_layout">
         <h3 class="page-header">Your Orders</h3>
         <t t-if="not orders">
             <p>There are currently no orders for your account.</p>
@@ -70,9 +120,9 @@
                   </tr>
                 </thead>
                 <t t-foreach="orders" t-as="order">
-                    <tr t-att-class="'hidden to_hide' if order.state not in ['manual', 'progress'] and order_index &gt; 4 else ''">
+                    <tr>
                         <td>
-                            <a t-att-href="'/my/orders/'+str(order.id)"><t t-esc="order.name"/></a>
+                            <a t-attf-href="/my/orders/{{order.id}}?{{keep_query()}}"><t t-esc="order.name"/></a>
                         </td>
                         <td><span t-field="order.date_order"/></td>
                         <td>
@@ -89,14 +139,16 @@
                         <td><span t-field="order.amount_total" t-field-options='{"widget": "monetary", "display_currency": "order.pricelist_id.currency_id"}'/></td>
                     </tr>
                 </t>
-                <tr t-att-class="'hidden' if len(orders) &lt; 5 else ''">
-                  <td colspan="4"><a href="" class="o_my_show_more btn btn-xs btn-default"><span>Show more</span><span class="hidden">Show less</span></a></td>
-                </tr>
             </table>
+            <div t-if="pager" class="o_portal_pager text-center">
+              <t t-call="website.pager"/>
+            </div>
         </t>
+      </t>
     </template>
 
-    <template id="invoices" name="Invoices and Payments">
+    <template id="portal_my_invoices" name="My Invoices and Payments">
+      <t t-call="website_portal.portal_layout">
         <h3 class="page-header">Your Invoices and Payments</h3>
         <t t-if="not invoices">
             <p>There are currently no invoices for your account.</p>
@@ -114,7 +166,7 @@
                   </tr>
                 </thead>
                 <t t-foreach="invoices" t-as="invoice">
-                    <tr t-att-class="'hidden to_hide' if invoice.state!='open' and invoice_index &gt; 4 else ''">
+                    <tr>
                         <td>
                             <a t-att-href="'/report/pdf/account.report_invoice/'+str(invoice.id)"><t t-esc="invoice.number"/></a>
                         </td>
@@ -137,11 +189,12 @@
                         <td><span t-field="invoice.residual" t-field-options='{"widget": "monetary", "display_currency": "invoice.currency_id"}'/></td>
                     </tr>
                 </t>
-                <tr t-att-class="'hidden' if len(invoices) &lt; 5 else ''">
-                  <td colspan="5"><a href="" class="o_my_show_more btn btn-xs btn-default"><span>Show more</span><span class="hidden">Show less</span></a></td>
-                </tr>
             </table>
+            <div t-if="pager" class="o_portal_pager text-center">
+                <t t-call="website.pager"/>
+            </div>
         </t>
+      </t>
     </template>
 
     <template id="orders_followup" name="Sales Order">
@@ -152,7 +205,17 @@
                 <div class="row">
                     <div class="col-sm-4">
                         <ol class="breadcrumb mt8">
-                            <li><a href="/my/home">My Account</a></li>
+                            <li><a href="/my/home"><i class="fa fa-home"/></a></li>
+                            <li>
+                              <a t-attf-href="/my/#{'quotes' if order.state == 'sent' else 'orders'}?{{ keep_query()}}">
+                                <t t-if="order.state == 'sent'">
+                                    My Quotes
+                                </t>
+                                <t t-if="order.state != 'sent'">
+                                    My Orders
+                                </t>
+                              </a>
+                            </li>
                             <li>
                               <t t-if="order.state == 'sent'">
                                   Quotation
@@ -318,7 +381,7 @@
       </t>
     </template>
 
-    <template id="sale_backend_link" inherit_id='website_portal_sale.sale_orders' customize_show="True" name="Link to Sales Backend" active="False">
+    <template id="sale_backend_link" inherit_id='website_portal_sale.portal_my_orders' customize_show="True" name="Link to Sales Backend" active="False">
         <xpath expr="//h3[@class='page-header']" position="inside">
             <a href="/web#action=portal_sale.action_orders_portal" target="_blank" class="btn btn-default btn-xs pull-right"> Access the complete Sale application</a>
         </xpath>
diff --git a/addons/website_project_issue/controllers/main.py b/addons/website_project_issue/controllers/main.py
index 98f06c0c281f..64b006e2f42c 100644
--- a/addons/website_project_issue/controllers/main.py
+++ b/addons/website_project_issue/controllers/main.py
@@ -6,17 +6,46 @@ from openerp.http import request
 
 
 class WebsiteAccount(website_account):
-    @http.route(['/my', '/my/home'], type='http', auth="user", website=True)
+
+    @http.route()
     def account(self):
         response = super(WebsiteAccount, self).account()
-        user = request.env.user
-        project_issues = request.env['project.issue'].search([])
-        response.qcontext.update({'issues': project_issues})
+        issue_count = request.env['project.issue'].search_count([])
+        response.qcontext.update({'issue_count': issue_count})
         return response
 
+    @http.route(['/my/issues', '/my/issues/page/<int:page>'], type='http', auth="user", website=True)
+    def portal_my_issues(self, page=1, date_begin=None, date_end=None, **kw):
+        values = self._prepare_portal_layout_values()
+        ProjectIssue = request.env['project.issue']
+        domain = []
+        # archive groups - Default Group By 'create_date'
+        archive_groups = self._get_archive_groups('project.issue', domain)
+        if date_begin and date_end:
+            domain += [('create_date', '>=', date_begin), ('create_date', '<', date_end)]
+        # pager
+        issue_count = ProjectIssue.search_count(domain)
+        pager = request.website.pager(
+            url="/my/issues",
+            url_args={'date_begin': date_begin, 'date_end': date_end},
+            total=issue_count,
+            page=page,
+            step=self._items_per_page
+        )
+        # content according to pager and archive selected
+        project_issues = ProjectIssue.search(domain, order="stage_id", limit=self._items_per_page, offset=pager['offset'])
+
+        values.update({
+            'date': date_begin,
+            'issues': project_issues,
+            'page_name': 'issue',
+            'archive_groups': archive_groups,
+            'default_url': '/my/issues',
+            'pager': pager
+        })
+        return request.website.render("website_project_issue.portal_my_issues", values)
 
-class WebsiteProjectIssue(http.Controller):
     @http.route(['/my/issues/<int:issue_id>'], type='http', auth="user", website=True)
-    def issues_followup(self, issue_id=None):
+    def issues_followup(self, issue_id=None, **kw):
         issue = request.env['project.issue'].browse(issue_id)
         return request.website.render("website_project_issue.issues_followup", {'issue': issue})
diff --git a/addons/website_project_issue/views/project_issue_templates.xml b/addons/website_project_issue/views/project_issue_templates.xml
index a19fa256366c..27a120cd84cb 100644
--- a/addons/website_project_issue/views/project_issue_templates.xml
+++ b/addons/website_project_issue/views/project_issue_templates.xml
@@ -1,7 +1,33 @@
 <?xml version="1.0" encoding="utf-8"?>
 <odoo>
-    <template id="portal_project_issue" name="Portal Project Issues" inherit_id="website_portal.account">
-        <xpath expr="//div[contains(@class,'o_my_documents')]/*[last()]" position="after">
+
+    <template id="portal_my_home_menu_issue" name="Portal layout : issues menu entry" inherit_id="website_portal.portal_layout" priority="30">
+        <xpath expr="//ul[contains(@class,'o_portal_submenu')]" position="inside">
+            <li t-att-class="page_name == 'issue' and 'active' or ''">
+                 <a href="/my/issues">Issues</a>
+            </li>
+        </xpath>
+    </template>
+
+    <template id="portal_my_home_issue" name="Portal My Home : issue entries" inherit_id="website_portal.portal_my_home" priority="30">
+        <xpath expr="//div[contains(@class,'o_my_home_content')]" position="inside">
+            <h3 class="page-header">
+                <a href="/my/issues">Your Issues
+                    <small class="ml8">
+                        <t t-if="issue_count">
+                            <span class='badge'><t t-esc="issue_count"/></span>
+                        </t>
+                        <t t-if="not issue_count">
+                            There are currently no issues for your account.
+                        </t>
+                    </small>
+                </a>
+            </h3>
+        </xpath>
+    </template>
+
+    <template id="portal_my_issues" name="My Issues" priority="30">
+        <t t-call="website_portal.portal_layout">
             <h3 class="page-header">Your Issues</h3>
             <t t-if="not issues">
                 <p>There are currently no issues for your account.</p>
@@ -16,20 +42,21 @@
                         </tr>
                     </thead>
                     <t t-foreach="issues" t-as="issue">
-                        <tr t-att-class="'hidden to_hide' if issue_index &gt; 4 else ''">
-                            <td><a t-attf-href="/my/issues/#{issue.id}">Issue <t t-esc="issue.id"/></a></td>
+                        <tr>
+
+                            <td>
+                                <a t-attf-href="/my/issues/#{issue.id}?{{ keep_query() }}">Issue <t t-esc="issue.id"/></a>
+                            </td>
                             <td><span t-field="issue.name"/></td><td/>
                             <td><span t-field="issue.stage_id.name"/></td>
                         </tr>
                     </t>
-                    <tr t-att-class="'hidden' if len(issues) &lt; 6 else ''">
-                        <td colspan="4">
-                            <a href="" class="o_my_show_more btn btn-xs btn-default"><span>Show more</span><span class="hidden">Show less</span></a>
-                        </td>
-                    </tr>
                 </table>
+                <div t-if="pager" class="o_portal_pager text-center">
+                    <t t-call="website.pager"/>
+                </div>
             </t>
-        </xpath>
+        </t>
     </template>
 
     <template id="issues_followup" name="Project Issues">
@@ -40,7 +67,8 @@
                         <div class="row">
                             <div class="col-sm-4">
                                 <ol class="breadcrumb mt8">
-                                    <li><a href="/my/home">My Account</a></li>
+                                    <li><a href="/my/home"><i class="fa fa-home"/></a></li>
+                                    <li><a t-attf-href="/my/issues?#{keep_query()}">My Issues</a></li>
                                     <li>Issue <span t-field="issue.id"/></li>
                                 </ol>
                             </div>
diff --git a/addons/website_quote/views/website_quotation.xml b/addons/website_quote/views/website_quotation.xml
index 75b1086e6e9d..0e5795aadba4 100644
--- a/addons/website_quote/views/website_quotation.xml
+++ b/addons/website_quote/views/website_quotation.xml
@@ -162,7 +162,8 @@
               <div t-if="breadcrumb" class="row">
                   <div class="col-sm-4">
                       <ol class="breadcrumb mt8">
-                          <li><a href="/my/home">My Account</a></li>
+                          <li><a href="/my/home"><i class="fa fa-home"/></a></li>
+                          <li><a t-attf-href="/my/quotes?#{keep_query()}">My Quotations</a></li>
                           <li>
                               Quotation <t t-esc="quotation.name"/>
                           </li>
@@ -682,12 +683,12 @@
       </xpath>
   </template>
 
-  <template id="quotations" inherit_id="website_portal_sale.quotations">
+  <template id="quotations" inherit_id="website_portal_sale.portal_my_quotations">
       <xpath expr="//t[@t-foreach='quotations']" position="replace">
           <t t-foreach="quotations" t-as="quotation">
-              <tr t-att-class="'hidden to_hide' if quotation_index &gt; 4 else ''">
+              <tr>
                   <td>
-                      <a t-att-href="'/quote/'+str(quotation.id)"><t t-esc="quotation.name"/></a>
+                      <a t-attf-href="/quote/#{quotation.id}?#{keep_query()}"><t t-esc="quotation.name"/></a>
                   </td>
                   <td><span t-field="quotation.validity_date"/></td>
                       <td>
-- 
GitLab