[MERGE] portal, *: redesign portal screens

This commit redesigns all portal screens, improve bootstrap compliance
and increases maintainability. See sub-commits for details.

Closes https://github.com/odoo/odoo/pull/26849
This commit is contained in:
qsm-odoo
2018-09-12 10:36:09 +02:00
14 changed files with 1306 additions and 1156 deletions
@@ -1,134 +1,130 @@
<odoo>
<template id="portal_my_home_menu_invoice" name="Portal layout : invoice menu entries" inherit_id="portal.portal_layout" priority="30">
<template id="portal_my_home_menu_invoice" name="Portal layout : invoice menu entries" inherit_id="portal.portal_breadcrumbs" priority="30">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'invoice'" class="breadcrumb-item active">
<li t-if="page_name == 'invoice'" t-attf-class="breadcrumb-item #{'active ' if not invoice else ''}">
<a t-if="invoice" t-attf-href="/my/invoices?{{ keep_query() }}">Invoices</a>
<t t-else="">Invoices</t>
</li>
<li t-if="invoice" class="breadcrumb-item">
<li t-if="invoice" class="breadcrumb-item active">
<t t-esc="invoice.number" t-if="invoice.number"/>
<t t-else="">Draft Invoice</t>
<t t-else=""><em>Draft Invoice</em></t>
</li>
</xpath>
</template>
<template id="portal_my_home_invoice" name="Portal My Home : invoice entries" inherit_id="portal.portal_my_home" priority="30">
<xpath expr="//ul[hasclass('o_portal_docs')]" position="inside">
<li t-if="invoice_count" class="list-group-item">
<span class="badge badge-secondary badge-pill float-right" t-esc="invoice_count"/>
<a href="/my/invoices">Invoices</a>
</li>
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="invoice_count" t-call="portal.portal_docs_entry">
<t t-set="title">Invoices</t>
<t t-set="url" t-value="'/my/invoices'"/>
<t t-set="count" t-value="invoice_count"/>
</t>
</xpath>
</template>
<template id="portal_my_invoices" name="My Invoices and Payments">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">Invoices</t>
</t>
<t t-if="not invoices">
<p>There are currently no invoices and payments for your account.</p>
</t>
<div t-if="invoices" class="card">
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
<thead>
<tr class="active">
<t t-if="invoices" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Invoice #</th>
<th>Invoice Date</th>
<th class='d-none d-md-table-cell'>Due Date</th>
<th></th>
<th>Amount Due</th>
</tr>
</thead>
<th/>
<th class="text-right">Amount Due</th>
</tr>
</thead>
<tbody>
<t t-foreach="invoices" t-as="invoice">
<tr>
<td>
<a t-att-href="invoice.get_portal_url()" t-att-title="invoice.number">
<t t-esc="invoice.number" t-if="invoice.number"/>
<t t-else="">Draft Invoice</t>
<em t-else="">Draft Invoice</em>
</a>
</td>
<td><span t-field="invoice.date_invoice"/></td>
<td class='d-none d-md-table-cell'><span t-field="invoice.date_due"/></td>
<td class="tx_status">
<t t-if="invoice.state == 'open'">
<span class="badge badge-info"><i class="fa fa-fw fa-clock-o" aria-label="Opened" title="Opened" role="img"></i><span class="d-none d-md-inline"> Waiting for Payment</span></span>
<span class="badge badge-pill badge-info"><i class="fa fa-fw fa-clock-o" aria-label="Opened" title="Opened" role="img"></i><span class="d-none d-md-inline"> Waiting for Payment</span></span>
</t>
<t t-if="invoice.state == 'paid'">
<span class="badge badge-secondary"><i class="fa fa-fw fa-check" aria-label="Paid" title="Paid" role="img"></i><span class="d-none d-md-inline"> Paid</span></span>
<span class="badge badge-pill badge-success"><i class="fa fa-fw fa-check" aria-label="Paid" title="Paid" role="img"></i><span class="d-none d-md-inline"> Paid</span></span>
</t>
<t t-if="invoice.state == 'cancel'">
<span class="badge badge-secondary"><i class="fa fa-fw fa-remove" aria-label="Cancelled" title="Cancelled" role="img"></i><span class="d-none d-md-inline"> Cancelled</span></span>
<span class="badge badge-pill badge-warning"><i class="fa fa-fw fa-remove" aria-label="Cancelled" title="Cancelled" role="img"></i><span class="d-none d-md-inline"> Cancelled</span></span>
</t>
</td>
<td><span t-esc="-invoice.residual if invoice.type == 'out_refund' else invoice.residual" t-options='{"widget": "monetary", "display_currency": invoice.currency_id}'/></td>
<td class="text-right"><span t-esc="-invoice.residual if invoice.type == 'out_refund' else invoice.residual" t-options='{"widget": "monetary", "display_currency": invoice.currency_id}'/></td>
</tr>
</t>
</table></div>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="portal.pager"/>
</div>
</div>
</tbody>
</t>
</t>
</template>
<template id="portal_invoice_page" name="Invoice Portal Template" inherit_id="portal.portal_sidebar" primary="True">
<xpath expr="//div[hasclass('o_portal_sidebar')]" position="inside">
<t t-set="wrapwrap_classes" t-value="'o_portal_bg_dark'"/>
<div class="row mt16 o_portal_invoice_sidebar">
<!-- Sidebar -->
<div class="col-lg-3 d-print-none">
<div class="bs-sidebar mb16" id="sidebar_content">
<div class="text-center pt16 o_account_portal_sidebar">
<h2 class="media-heading">
<strong>
<span t-if="invoice.residual > 0" t-field="invoice.residual"/>
<span t-else="1" t-field="invoice.amount_total"/>
</strong>
</h2>
<div class="mb4" t-if="invoice.state != 'paid' and invoice.type == 'out_invoice'"><i class="fa fa-clock-o"/><span class="o_portal_sidebar_timeago ml4" t-att-datetime="invoice.date_due"/></div>
</div>
<div class="o_payment_button">
<div class="text-center mb8 ml16 mr16 o_download_pdf">
<a class="btn btn-secondary btn-block o_download_btn" t-att-href="invoice.get_portal_url(report_type='pdf', download=True)" title="Download"><i class="fa fa-download"/> Download</a>
<a class="btn btn-secondary btn-block d-none d-lg-inline-block o_print_btn o_portal_invoice_print" t-att-href="invoice.get_portal_url(report_type='pdf')" id="print_invoice_report" title="Print"><i class="fa fa-print"/> Print</a>
</div>
</div>
<hr t-if="invoice.user_id" class="mt0 mb0"/>
<div class="pb8 ml16 mr16 container">
<t t-if="invoice.user_id">
<div><strong>Your Contact:</strong></div>
<div class="d-flex h-100">
<div class="align-self-center">
<img class="rounded-circle mr4 float-left o_portal_contact_img" t-if="invoice.user_id.image" t-attf-src="data:image/png;base64,#{invoice.user_id.image}" alt="Contact"/>
<img class="rounded-circle mr4 float-left o_portal_contact_img" t-if="not invoice.user_id.image" src="/web/static/src/img/placeholder.png" alt="Contact"/>
<t t-call="portal.portal_record_sidebar">
<t t-set="classes" t-value="'col-12 col-lg flex-lg-grow-0 d-print-none'"/>
<t t-set="title">
<h2 class="mb-0">
<b t-if="invoice.residual > 0" t-field="invoice.residual"/>
<b t-else="1" t-field="invoice.amount_total"/>
</h2>
<div class="small" t-if="invoice.state != 'paid' and invoice.type == 'out_invoice'"><i class="fa fa-clock-o"/><span class="o_portal_sidebar_timeago ml4" t-att-datetime="invoice.date_due"/></div>
</t>
<t t-set="entries">
<ul class="list-group list-group-flush flex-wrap flex-row flex-lg-column">
<li class="list-group-item o_payment_button flex-grow-1 flex-sm-grow-0">
<div class="o_download_pdf btn-toolbar flex-sm-nowrap">
<div class="btn-group flex-grow-1 mr-1 mb-1">
<a class="btn btn-secondary btn-block o_download_btn" t-att-href="invoice.get_portal_url(report_type='pdf', download=True)" title="Download"><i class="fa fa-download"/> Download</a>
</div>
<div class="align-self-center">
<span t-field="invoice.user_id" t-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
<a data-toggle="modal" href="#" data-target="#invoice_chatter"><i class="fa fa-comment"></i> Contact us</a>
<div class="btn-group flex-grow-1 mb-1">
<a class="btn btn-secondary btn-block o_print_btn o_portal_invoice_print" t-att-href="invoice.get_portal_url(report_type='pdf')" id="print_invoice_report" title="Print"><i class="fa fa-print"/> Print</a>
</div>
</div>
</li>
<li t-if="invoice.user_id" class="list-group-item flex-grow-1 o_portal_contact_block">
<div class="small mb-1"><strong class="text-muted">Your Contact:</strong></div>
<div class="row">
<div class="col flex-grow-0 pr-2">
<img t-if="invoice.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{invoice.user_id.image}" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-0">
<span t-field="invoice.user_id" t-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
<a data-toggle="modal" href="#" data-target="#invoice_chatter" class="small"><i class="fa fa-fw fa-comments"/><b>Send message</b></a>
</div>
</div>
</t>
<div t-if="not invoice.user_id" class="text-center mr16">
<a data-toggle="modal" href="#" data-target="#invoice_chatter"><i class="fa fa-comment"></i> Contact us</a>
</div>
</div>
</div>
<div class="text-center d-none d-md-block o_portal_brand">
Powered by <a target="_blank" href="https://www.odoo.com?utm_source=db&amp;utm_medium=portal">Odoo</a>
</div>
</div>
<!-- Page Content -->
<div id="invoice_content" class="col-lg-9 o_portal_page_content d-print-none">
<div t-ignore="true" class="float-md-right css_editable_mode_hidden d-print-none">
<ul class="list-inline">
<li groups="sales_team.group_sale_salesman" class="list-inline-item">
<a role="button" class="btn btn-info mt16 mr16" t-att-href="'/web#return_label=Website&amp;model=%s&amp;id=%s&amp;action=%s&amp;view_type=form' % (invoice._name, invoice.id, invoice.env.ref('account.action_invoice_tree1').id)"><t t-if="invoice.state == 'draft'">Edit Invoice</t><t t-else="">Leave Portal</t></a>
</li>
</ul>
</div>
</t>
</t>
<!-- Page Content -->
<div id="invoice_content" class="o_portal_page_content col-12 col-lg d-flex justify-content-end">
<t t-if="error or warning" t-call="account.portal_invoice_error"/>
<t t-if="success and (not error and not warning)" t-call="account.portal_invoice_success"/>
<div class="o_portal_html_view">
<div class="o_portal_html_view shadow">
<div class="o_portal_html_loader text-center">
<i class="fa fa-circle-o-notch fa-spin fa-2x fa-fw text-black-50"></i>
</div>
<iframe id="invoice_html" class="mt8 mb8" width="100%" height="100%" frameborder="0" scrolling="no" t-att-src="invoice.get_portal_url(report_type='html')"/>
</div>
</div>
@@ -1,35 +1,35 @@
<odoo>
<template id="portal_my_invoices_payment" name="Payment on My Invoices" inherit_id="account.portal_my_invoices">
<xpath expr="//table[hasclass('o_portal_my_doc_table')]/thead/tr/th[last()]" position="before">
<th>Status</th>
<xpath expr="//t[@t-call='portal.portal_table']/thead/tr/th[last()]" position="before">
<th class="text-center">Status</th>
</xpath>
<xpath expr="//t[@t-foreach='invoices']/tr/td[last()]" position="before">
<td>
<td class="text-center">
<t t-set="tx_ids" t-value="invoice.transaction_ids.filtered(lambda tx: tx.state in ('pending', 'authorized', 'done'))"/>
<t t-set="pending_manual_txs" t-value="tx_ids.filtered(lambda tx: tx.state == 'pending' and tx.acquirer_id.provider in ('transfer', 'manual'))"/>
<a t-if="invoice.state == 'open' and invoice.amount_total and invoice.type == 'out_invoice' and (pending_manual_txs or not tx_ids)"
t-att-href="invoice.get_portal_url(anchor='portal_pay')" title="Pay now" aria-label="Pay now" class="btn btn-sm btn-primary" role="button">
t-att-href="invoice.get_portal_url(anchor='portal_pay')" title="Pay now" aria-label="Pay now" class="btn btn-sm btn-success" role="button">
<i class="fa fa-arrow-circle-right"/><span class='d-none d-md-inline'> Pay Now</span>
</a>
</td>
</xpath>
<xpath expr="//t[@t-foreach='invoices']/tr/td[hasclass('tx_status')]" position="replace">
<t t-set="last_tx" t-value="invoice.get_portal_last_transaction()"/>
<td class="tx_status">
<td class="tx_status text-center">
<t t-if="invoice.state == 'open' and (last_tx.state not in ['pending', 'authorized', 'done', 'cancel'] or (last_tx.state == 'pending' and last_tx.acquirer_id.provider in ('transfer', 'manual')))">
<span class="badge badge-info"><i class="fa fa-fw fa-clock-o"></i><span class="d-none d-md-inline"> Waiting for Payment</span></span>
<span class="badge badge-pill badge-info"><i class="fa fa-fw fa-clock-o"></i><span class="d-none d-md-inline"> Waiting for Payment</span></span>
</t>
<t t-if="invoice.state == 'open' and last_tx.state == 'authorized'">
<span class="badge badge-success"><i class="fa fa-fw fa-check"/><span class="d-none d-md-inline"> Authorized</span></span>
<span class="badge badge-pill badge-primary"><i class="fa fa-fw fa-check"/><span class="d-none d-md-inline"> Authorized</span></span>
</t>
<t t-if="invoice.state == 'open' and last_tx.state == 'pending' and last_tx.acquirer_id.provider not in ('transfer', 'manual')">
<span class="badge badge-warning"><span class="d-none d-md-inline"> Pending</span></span>
<span class="badge badge-pill badge-warning"><span class="d-none d-md-inline"> Pending</span></span>
</t>
<t t-if="invoice.state == 'paid' or last_tx.state == 'done'">
<span class="badge badge-secondary"><i class="fa fa-fw fa-check"></i><span class="d-none d-md-inline"> Paid</span></span>
<span class="badge badge-pill badge-success"><i class="fa fa-fw fa-check"></i><span class="d-none d-md-inline"> Paid</span></span>
</t>
<t t-if="invoice.state == 'cancel'">
<span class="badge badge-secondary"><i class="fa fa-fw fa-remove"></i><span class="d-none d-md-inline"> Cancelled</span></span>
<span class="badge badge-pill badge-danger"><i class="fa fa-fw fa-remove"></i><span class="d-none d-md-inline"> Cancelled</span></span>
</t>
</td>
</xpath>
@@ -67,22 +67,20 @@
</template>
<template id="portal_invoice_page_inherit_payment" name="Payment on My Invoices" inherit_id="account.portal_invoice_page">
<xpath expr="//div[@id='sidebar_content']//div[hasclass('o_download_pdf')]" position="before">
<xpath expr="//t[@t-call='portal.portal_record_sidebar']//div[hasclass('o_download_pdf')]" position="before">
<t t-set="tx_ids" t-value="invoice.transaction_ids.filtered(lambda tx: tx.state in ('pending', 'authorized', 'done'))"/>
<t t-set="pending_manual_txs" t-value="tx_ids.filtered(lambda tx: tx.state == 'pending' and tx.acquirer_id.provider in ('transfer', 'manual'))"/>
<div class="mb8 ml16 mr16">
<a t-if="invoice.state == 'open' and invoice.amount_total and invoice.type == 'out_invoice' and (pending_manual_txs or not tx_ids)"
class="btn btn-primary btn-block" data-toggle="modal" data-target="#pay_with">
<i class="fa fa-arrow-circle-right"/> Pay Now
</a>
<a t-if="tx_ids and not pending_manual_txs and invoice.state != 'paid'"
class="btn btn-warning btn-block" disabled="disabled">
<i class="fa fa-check-circle"/> Pending
</a>
<a t-if="invoice.state == 'paid'"
class="btn btn-success btn-block" disabled="disabled">
<i class="fa fa-check-circle"/> Paid
<div>
<a href="#" t-if="invoice.state == 'open' and invoice.amount_total and invoice.type == 'out_invoice' and (pending_manual_txs or not tx_ids)"
class="btn btn-success btn-block mb-2" data-toggle="modal" data-target="#pay_with">
<i class="fa fa-fw fa-arrow-circle-right"/> Pay Now
</a>
<div t-if="tx_ids and not pending_manual_txs and invoice.state != 'paid'" class="alert alert-info py-1 mb-2" >
<i class="fa fa-fw fa-check-circle"/> Pending
</div>
<div t-if="invoice.state == 'paid'" class="alert alert-success py-1 mb-2" >
<i class="fa fa-fw fa-check-circle"/> Paid
</div>
</div>
</xpath>
<xpath expr="//div[@id='invoice_content']//div[hasclass('o_portal_html_view')]" position="before">
@@ -1,24 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_task" inherit_id="project.portal_my_task" name="Portal: My Task with imesheets">
<xpath expr="//div[hasclass('card-body')]" position="inside">
<template id="portal_my_task" inherit_id="project.portal_my_task" name="Portal: My Task with Timesheets">
<xpath expr="//t[@t-set='card_body']" position="inside">
<div class="container" t-if="task.timesheet_ids">
<hr/>
<table class="table table-hover">
<hr class="mt-4 mb-1"/>
<h5 class="mt-2 mb-2">Timesheets</h5>
<table class="table table-sm">
<thead>
<tr class="active">
<tr>
<th>Date</th>
<th class="col-lg-6">Description</th>
<th>Description</th>
<th>Responsible</th>
<th>Duration</th>
<th class="text-right">Duration</th>
</tr>
</thead>
<tr t-foreach="task.timesheet_ids" t-as="timesheet">
<td><t t-esc="timesheet.date"/></td>
<td><t t-esc="timesheet.name"/></td>
<td><t t-esc="timesheet.sudo().user_id.name"/></td>
<td><span t-field="timesheet.unit_amount" t-options='{"widget": "duration", "unit": "hour", "round": "minute"}'/></td>
<td class="text-right"><span t-field="timesheet.unit_amount" t-options='{"widget": "duration", "unit": "hour", "round": "minute"}'/></td>
</tr>
</table>
</div>
@@ -15,9 +15,6 @@ var PortalSidebar = Widget.extend({
start: function () {
var self = this;
this._super.apply(this, arguments);
// Window Handlers
$(window).on('resize', _.throttle(self._onUpdateSidebarPosition.bind(self), 200, {leading: false}));
this._onUpdateSidebarPosition();
this._setDelayLabel();
},
@@ -69,22 +66,6 @@ var PortalSidebar = Widget.extend({
this.printContent.get(0).contentWindow.print();
}
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Called when the window is resized or on loadoing widget
*
* @private
*/
_onUpdateSidebarPosition: function () {
var $sidebar = this.$el.find('.bs-sidebar, .o_portal_brand');
$sidebar.css({
width: config.device.size_class >= config.device.SIZES.MD ? $sidebar.outerWidth() : '',
});
},
});
return PortalSidebar;
});
+1 -1
View File
@@ -10,7 +10,7 @@ tour.register('portal_load_homepage', {
[
{
content: "Check portal is loaded",
trigger: 'a[href*="/my/account"]:contains("Change"):first',
trigger: 'a[href*="/my/account"]:contains("Edit"):first',
},
{
content: "Load my account details",
+123 -75
View File
@@ -3,8 +3,24 @@
/// rules.
///
// ====== Variables =========
$-navbar-height: $nav-link-height !default;
// Portal toolbar (filters, search bar)
$o-portal-mobile-toolbar: true; // Enable/Disable custom design
$o-portal-mobile-toolbar-border: $border-color;
$o-portal-mobile-toolbar-bg: $gray-200;
// Portal Tables
$o-portal-table-th-pt: map-get($spacers, 2) !default; // bts4 pt-2
$o-portal-table-th-pb: map-get($spacers, 2) !default; // bts4 pb-2
$o-portal-table-td-pt: map-get($spacers, 1) !default; // bts4 pt-1
$o-portal-table-td-pb: map-get($spacers, 1) !default; // bts4 pb-1
// Page custom bg (eg. 'Invoice')
$o-portal-bg: true; // Enable/Disable page custom bg.
$o-portal-bg-color: desaturate($gray-200, 100%);
// Resize and vertically align navbar’s items relative to navbar
@mixin o-w-fill-navbar($ratio: 1) {
height: round($-navbar-height * $ratio * 100) / 100;
@@ -158,6 +174,14 @@ hr {
color: color-yiq($list-group-bg);
}
%o-portal-breadcrumbs {
background-color: transparent;
.breadcrumb-item {
display: inline-flex;
}
}
// Replaces old BS3 page-header class
%o-page-header {
margin-bottom: $headings-margin-bottom * 2;
@@ -165,6 +189,7 @@ hr {
border-bottom-width: $border-width;
border-bottom-style: solid;
border-bottom-color: $border-color;
line-height: 2.1rem;
}
.o_page_header {
@extend %o-page-header;
@@ -297,14 +322,19 @@ img.o_we_custom_image {
}
// Portal specific
// === Page custom bg (eg. 'Invoice') ===
// This could have been achieved easily using a class (eg. bg-200), but we
// don't want to force the design because of themes.
@if ($o-portal-bg) {
#wrapwrap.o_portal_bg_dark {
@include o-bg-color($o-portal-bg-color);
}
}
.o_portal {
.breadcrumb {
background-color: rgba(0, 0, 0, 0);
margin-bottom: 0px;
}
.record_pager {
padding: 8px 0px;
@extend %o-portal-breadcrumbs;
}
> tbody.o_portal_report_tbody {
@@ -317,77 +347,83 @@ img.o_we_custom_image {
text-decoration: none;
}
.o_portal_my_doc_table {
td, th {
text-align: right;
}
tr > :first-child {
text-align: left;
.o_portal_navbar {
.breadcrumb {
padding-left: 0;
padding-right: 0;
@extend %o-portal-breadcrumbs;
.breadcrumb-item.active {
// In this context, active breadcrumb act as title
color: $headings-color;
line-height: $h5-font-size/$font-size-base;
font: {size: $h5-font-size; weight: $headings-font-weight};
&:before {
// Restore breadcrumb divider to default
color: $breadcrumb-divider-color;
line-height: $line-height-base;
font: {size: $font-size-base; weight: $font-weight-base};
}
}
}
}
.o_portal_navbar {
.navbar-brand {
margin: 0;
@include media-breakpoint-up(md) {
padding: $navbar-padding-y $navbar-padding-x 0 0;
}
.o_portal_my_doc_table {
th {
padding-top: $o-portal-table-th-pt;
padding-bottom: $o-portal-table-th-pb;
}
// ===== Default portal navbar design =====
&.o_portal_navbar_default {
margin-bottom: 8px;
td {
padding-top: $o-portal-table-td-pt;
padding-bottom: $o-portal-table-td-pb;
}
.navbar-brand {
padding: $navbar-padding-y $navbar-padding-x 0 0;
td, th {
vertical-align: middle;
white-space: nowrap;
}
}
address {
span[itemprop="name"] {
font-weight: bold;
margin-bottom: 0.3em;
}
div[itemprop="address"] > div {
position: relative;
span[itemprop="streetAddress"] {
line-height: 1.2;
margin-bottom: 0.3em;
}
.navbar-header .dropdown-menu {
right: 0;
left: auto;
}
.fa {
@include o-position-absolute(0, $left: 0);
line-height: $line-height-base;
.navbar-toggle {
margin-right: 0;
margin-bottom: 0;
background-color: $table-active-bg;
padding: 6px 10px $navbar-padding-y;
border-width: 1px 1px 0 1px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
z-index: 1;
&.collapsed {
padding:6px 10px;
border-width: 1px;
border-radius: $btn-border-radius;
background-color: transparent;
+ span {
display: block;
// FontAwesome '.fa-fw' fixed-with + margin
padding-left: 1.28571429em + 0.5em;
}
}
}
}
@include media-breakpoint-down(sm) {
.navbar-collapse {
z-index: 0;
background-color: $table-active-bg;
border-radius: $btn-border-radius;
border-top-right-radius: 0;
transform: translateY(-2px);
.o_my_sidebar div[itemprop="address"] > div {
margin-top: 0.5em;
}
&.in {
overflow: visible;
}
}
}
@include media-breakpoint-up(md) {
> .container-fluid {
padding: 0;
.navbar-form {
padding-right: 0;
}
}
@if ($o-portal-mobile-toolbar) {
#o_portal_navbar_content {
@include media-breakpoint-down(md) {
margin: $navbar-padding-y (-$navbar-padding-x) 0;
padding: $navbar-padding-y $navbar-padding-x ;
border-top: $border-width solid $o-portal-mobile-toolbar-border;
background-color: $o-portal-mobile-toolbar-bg;
}
}
}
@@ -444,19 +480,31 @@ img.o_we_custom_image {
font-weight: normal;
}
.o_portal_contact_img {
width: 2.3em;
height: 2.3em;
}
.o_portal_sidebar {
.bs-sidebar {
width: 100%;
border-radius: 5px;
background-color: $light;
}
.o_portal_contact_img {
width: 3.7em;
height: 3.7em;
.o_portal_contact_block {
@include media-breakpoint-down(md) {
border-left: $border-width solid $border-color;
border-bottom: 0;
}
}
.o_portal_html_view {
border: 1px solid gray('300');
border-radius: 5px;
padding-right: 1px;
overflow: hidden;
width: 100%;
max-width: 210mm; // A4 page's width
background: white;
.o_portal_html_loader {
@include o-position-absolute(45%, 0, auto, 0);
}
iframe {
position: relative;
}
}
}
+152 -81
View File
@@ -23,7 +23,7 @@
<t t-set="head" t-value="head_website + (head or '')"/>
<t t-set="direction" t-value="request.env['res.lang'].search([('code', '=', request.env.lang)]).direction"/>
<div id="wrapwrap" t-attf-class="#{pageName or ''} #{direction == 'rtl' and 'o_rtl' or ''}">
<div id="wrapwrap" t-attf-class="#{pageName or ''} #{direction == 'rtl' and 'o_rtl' or ''} #{wrapwrap_classes or ''}">
<header>
<nav class="navbar navbar-expand-md navbar-light bg-light">
<div class="container">
@@ -66,34 +66,46 @@
</t>
</template>
<template id="portal_breadcrumbs" name="Portal Breadcrumbs">
<ol t-if="page_name != 'home'" class="o_portal_submenu breadcrumb mb-0 py-2 flex-grow-1">
<li class="breadcrumb-item"><a href="/my/home" aria-label="Home" title="Home"><i class="fa fa-home"/></a></li>
<li t-if="page_name == 'my_details'" class="breadcrumb-item">Your Details</li>
</ol>
</template>
<template id="portal_layout" name="Portal Layout">
<t t-call="portal.frontend_layout">
<div class="container mt16 mb16 o_portal">
<div class="oe_structure">
<div t-if="not no_breadcrumbs" class="row">
<div t-attf-class="col-md-12">
<t t-call='portal.record_pager'/>
<ol t-if="page_name != 'home'" class="breadcrumb o_portal_submenu">
<li class="breadcrumb-item"><a href="/my/home" aria-label="Home" title="Home"><i class="fa fa-home"/></a></li>
<li t-if="page_name == 'my_details'" class="breadcrumb-item">Your Details</li>
</ol>
</div>
<div t-if="o_portal_fullwidth_alert" class="alert alert-info alert-dismissible rounded-0 fade show d-print-none css_editable_mode_hidden">
<div class="container">
<t t-raw="o_portal_fullwidth_alert"/>
</div>
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> &#215; </button>
</div>
<div t-if="not no_breadcrumbs and not my_details and not breadcrumbs_searchbar" class="o_portal container mt-3">
<div class="row align-items-center bg-white no-gutters border rounded-top">
<div class="col">
<t t-call="portal.portal_breadcrumbs"></t>
</div>
<div t-if="prev_record or next_record" class="col flex-grow-0">
<t t-call='portal.record_pager'/>
</div>
</div>
</div>
<div id="wrap" class='o_portal_wrap'>
<div class="container mb64">
<t t-if="my_details">
<div class="row">
<div t-attf-class="col-lg-9 col-xl-8">
<div class="row justify-content-between mt-4">
<div t-attf-class="col-12 col-md col-lg-6">
<t t-raw="0"/>
</div>
<div id="o_my_sidebar" class="col-lg-3 offset-xl-1 o_my_sidebar">
<div id="o_my_sidebar" class="col-12 col-md col-lg-4 col-xl-3 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="o_page_header">Your Details <a role="button" href="/my/account" class="btn btn-secondary btn-sm">Change</a></h3>
<h4>Your Details <a role="button" href="/my/account" class="btn btn-sm btn-link"><i class="fa fa-pencil"/> Edit</a></h4>
<hr class="mt-1 mb-0"/>
<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">
@@ -126,14 +138,46 @@
<t t-set="my_details" t-value="True"/>
<div class="o_portal_my_home">
<div class="oe_structure"></div>
<h3 class="o_page_header">Your Documents</h3>
<ul class="o_portal_docs list-group">
</ul>
<h3>Your Documents</h3>
<div class="o_portal_docs list-group">
</div>
</div>
<div class="col-lg-12 oe_structure"/>
</t>
</template>
<template id="portal_docs_entry" name="My Portal Docs Entry">
<a t-att-href="url" t-att-title="title" class="list-group-item list-group-item-action d-flex align-items-center justify-content-between">
<t t-esc="title"/>
<span class="badge badge-secondary badge-pill" t-esc="count"/>
</a>
</template>
<template id="portal_table" name="My Portal Table">
<div t-attf-class="table-responsive border border-top-0 #{classes if classes else ''}">
<table class="table mb-0 o_portal_my_doc_table">
<t t-raw="0"/>
</table>
</div>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="portal.pager"/>
</div>
</template>
<template id="portal_record_sidebar" name="My Portal Record Sidebar">
<div t-attf-class="col-12 col-lg flex-lg-grow-0 #{classes}">
<div class="card bg-white mb-4" id="sidebar_content">
<div t-if="title" class="card-body text-center pb-2 pt-3">
<t t-raw="title"/>
</div>
<t t-if="entries" t-raw="entries"/>
<div class="card-footer small text-center text-muted border-top-0 pt-1 pb-1 d-none d-lg-block">
Powered by <a target="_blank" href="http://www.odoo.com?utm_source=db&amp;utm_medium=portal" title="odoo"><img src="/web/static/src/img/logo.png" alt="Odoo Logo" height="15"/></a>
</div>
</div>
</div>
</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
@@ -149,28 +193,33 @@
{'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 breadcrumbs_searchbar : set to True to show breadcrumbs rather than the title
:param boolean o_portal_search_panel : set to True to active the input search
:param html $0 : content of the t-call, <li class="float-left">Link</li>
:param html $0 : content of the t-call
:param title : bavbar title
:param classes : navbar classes
-->
<template id="portal_searchbar" name="Portal Search Bar">
<nav t-attf-class="navbar o_portal_navbar {{classes if classes else 'o_portal_navbar_default'}}">
<div class="container-fluid">
<!-- Navbar title only -->
<div class="navbar-header float-left">
<t t-set="no_title">No title</t>
<h3 class="navbar-brand"><t t-esc="title or no_title"/></h3>
</div>
<nav t-attf-class="navbar navbar-light navbar-expand-lg border py-0 o_portal_navbar {{classes if classes else ''}} {{'mt-4 rounded-top border-bottom-0' if breadcrumbs_searchbar else 'border-top-0 mb-2'}}">
<!-- Navbar breadcrumb or title -->
<t t-if="breadcrumbs_searchbar">
<t t-call="portal.portal_breadcrumbs"/>
</t>
<span t-else="" class="navbar-brand mb-0 h1 mr-auto" t-esc="title or 'No title'"/>
<!-- Non-collapsing menu item(s) -->
<div class="navbar-header navbar-right float-right">
<ul class="nav float-left">
<t t-raw="0"/>
<li t-if="searchbar_sortings" class="dropdown float-left ml16">
<button id="portal_searchbar_sortby" data-toggle="dropdown" class="btn btn-secondary dropdown-toggle navbar-btn">
<span class="fa fa-sort"/>
<span class="d-none d-lg-inline"><t t-esc="searchbar_sortings[sortby].get('label', 'Newest')"/></span>
<!-- Collapse button -->
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#o_portal_navbar_content" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle filters">
<span class="navbar-toggler-icon small"/>
</button>
<!-- Collapsable content -->
<div class="collapse navbar-collapse" id="o_portal_navbar_content">
<div class="nav flex-column flex-lg-row ml-auto p-0 mb-3 mb-lg-0 mt-1 mt-lg-0">
<div t-if="searchbar_sortings" class="form-inline">
<span class="small mr-1 navbar-text">Sort By:</span>
<div class="btn-group">
<button id="portal_searchbar_sortby" data-toggle="dropdown" class="btn btn-secondary btn-sm dropdown-toggle">
<t t-esc="searchbar_sortings[sortby].get('label', 'Newest')"/>
</button>
<div class="dropdown-menu" aria-labelledby="portal_searchbar_sortby">
<t t-foreach="searchbar_sortings" t-as="option">
@@ -180,11 +229,13 @@
</a>
</t>
</div>
</li>
<li t-if="searchbar_filters" class="dropdown float-left ml4">
<button id="portal_searchbar_filters" data-toggle="dropdown" class="btn btn-secondary dropdown-toggle navbar-btn">
<span class="fa fa-filter"/>
<span class="d-none d-lg-inline"><t t-esc="searchbar_filters[filterby].get('label', 'All')"/></span>
</div>
</div>
<div t-if="searchbar_filters" class="form-inline ml-lg-2">
<span class="small mr-1 navbar-text">Filter By:</span>
<div class="btn-group">
<button id="portal_searchbar_filters" data-toggle="dropdown" class="btn btn-secondary btn-sm dropdown-toggle">
<t t-esc="searchbar_filters[filterby].get('label', 'All')"/>
</button>
<div class="dropdown-menu" aria-labelledby="portal_searchbar_filters">
<t t-foreach="searchbar_filters" t-as="option">
@@ -194,11 +245,13 @@
</a>
</t>
</div>
</li>
<li t-if="searchbar_groupby" class="dropdown float-left ml4">
<button id="portal_searchbar_groupby" data-toggle="dropdown" class="btn btn-secondary dropdown-toggle navbar-btn">
<span class="fa fa-object-group"/>
<span class="d-none d-lg-inline"><t t-esc="searchbar_groupby[groupby].get('label', 'None')"/></span>
</div>
</div>
<div t-if="searchbar_groupby" class="form-inline ml-lg-2">
<span class="small mr-1 navbar-text">Group By:</span>
<div class="btn-group">
<button id="portal_searchbar_groupby" data-toggle="dropdown" class="btn btn-secondary btn-sm dropdown-toggle">
<t t-esc="searchbar_groupby[groupby].get('label', 'None')"/>
</button>
<div class="dropdown-menu" aria-labelledby="portal_searchbar_groupby">
<t t-foreach="searchbar_groupby" t-as="option">
@@ -208,46 +261,64 @@
</a>
</t>
</div>
</li>
</ul>
<button t-if='searchbar_inputs' type="button" class="navbar-toggle collapsed btn ml16" data-toggle="collapse" data-target="#o_portal_searchbar_collapse"><span class="fa fa-search"/></button>
</div>
<div t-if='searchbar_inputs' class="d-block d-md-none clearfix"/>
<!-- Collapsing content (searchbar_inputs) -->
<div t-if='searchbar_inputs' class="collapse navbar-collapse text-right" id="o_portal_searchbar_collapse">
<div class="navbar-form o_portal_search_panel">
<div class="input-group">
<div class="input-group-prepend">
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown">
<span id="search_label" class="d-none d-md-inline mr4">Search</span>
</button>
<div class="dropdown-menu" role="menu">
<t t-foreach='searchbar_inputs' t-as='input'>
<a t-att-href="'#' + searchbar_inputs[input]['input']"
t-attf-class="dropdown-item#{search_in == searchbar_inputs[input]['input'] and ' active' or ''}">
<span t-raw="searchbar_inputs[input]['label']"/>
</a>
</t>
</div>
</div>
<input type="text" class="form-control" t-att-value='search' name="search"/>
<span class="input-group-append">
<button class="btn btn-secondary search-submit" type="button"><span class="fa fa-search d-none d-md-inline-block"/><span class="fa fa-arrow-right d-inline-block d-md-none"/></button>
</span>
</div>
</div>
<t t-raw="0"/>
</div>
</div> <!-- /.container-fluid -->
<form t-if="searchbar_inputs" class="form-inline o_portal_search_panel ml-lg-4">
<div class="input-group input-group-sm w-100">
<div class="input-group-prepend">
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown"/>
<div class="dropdown-menu" role="menu">
<t t-foreach='searchbar_inputs' t-as='input'>
<a t-att-href="'#' + searchbar_inputs[input]['input']"
t-attf-class="dropdown-item#{search_in == searchbar_inputs[input]['input'] and ' active' or ''}">
<span t-raw="searchbar_inputs[input]['label']"/>
</a>
</t>
</div>
</div>
<input type="text" class="form-control form-control-sm" placeholder="Search" t-att-value='search' name="search"/>
<span class="input-group-append">
<button class="btn btn-secondary search-submit" type="button">
<span class="fa fa-search"/>
</button>
</span>
</div>
</form>
</div>
</nav>
</template>
<template id="portal_record_layout" name="Portal single record layout">
<div t-attf-class="card mt-0 border-top-0 rounded-0 rounded-bottom #{classes if classes else ''}">
<div t-if="card_header" t-attf-class="card-header #{header_classes if header_classes else ''}">
<t t-raw="card_header"/>
</div>
<div t-if="card_body" t-attf-class="card-body #{body_classes if body_classes else ''}">
<t t-raw="card_body"/>
</div>
</div>
</template>
<template id="portal_contact" name="Contact">
<h3 class="o_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"/>
<div class="o_portal_contact_details mb-5">
<h4><t t-if="title" t-esc="title"/><t t-else="">Your contact</t></h4>
<hr class="mt-1 mb0"/>
<h6 class="mb-1"><b t-esc="sales_user.name"/></h6>
<div class="d-flex align-items-center mb-1">
<div class="fa fa-envelope fa-fw mr-1"></div>
<a t-att-href="'mailto:'+sales_user.email" t-esc="sales_user.email"/>
</div>
<div class="d-flex flex-nowrap align-items-center mb-1">
<div class="fa fa-phone fa-fw mr-1"></div>
<span t-esc="sales_user.phone"/>
</div>
<div class="d-flex flex-nowrap align-items-center mb-1">
<div class="fa fa-map-marker fa-fw mr-1"></div>
<span t-esc="sales_user.city"/>
</div>
</div>
</template>
<template id="portal_archive_groups" name="Portal Archive Groups">
@@ -357,10 +428,10 @@
<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 float-md-right" role="group">
<a role="button" t-att-class="'btn btn-secondary %s' % ('disabled' if not prev_record else '')" t-att-href="prev_record or '#'" ><i class="fa fa-arrow-left" role="img" aria-label="Previous" title="Previous"></i></a>
<a role="button" t-att-class="'btn btn-secondary %s' % ('disabled' if not next_record else '')" t-att-href="next_record or '#'" ><i class="fa fa-arrow-right" role="img" aria-label="Next" title="Previous"></i></a>
</div>
<div class="record_pager btn-group" role="group">
<a role="button" t-att-class="'btn btn-link %s' % ('disabled' if not prev_record else '')" t-att-href="prev_record or '#'" ><i class="fa fa-chevron-left" role="img" aria-label="Previous" title="Previous"></i></a>
<a role="button" t-att-class="'btn btn-link %s' % ('disabled' if not next_record else '')" t-att-href="next_record or '#'" ><i class="fa fa-chevron-right" role="img" aria-label="Next" title="Previous"></i></a>
</div>
</t>
</template>
+194 -163
View File
@@ -1,39 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_layout" name="Portal layout: project menu entry" inherit_id="portal.portal_layout" priority="40">
<template id="portal_layout" name="Portal layout: project menu entry" inherit_id="portal.portal_breadcrumbs" priority="40">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'project' or project" class="breadcrumb-item">
<li t-if="page_name == 'project' or project" t-attf-class="breadcrumb-item #{'active ' if not project else ''}">
<a t-if="project" t-attf-href="/my/projects?{{ keep_query() }}">Projects</a>
<t t-else="">Projects</t>
</li>
<li t-if="project" class="breadcrumb-item">
<li t-if="project" class="breadcrumb-item active">
<t t-esc="project.name"/>
</li>
<li t-if="page_name == 'task' or task" class="breadcrumb-item">
<li t-if="page_name == 'task' or task" t-attf-class="breadcrumb-item #{'active ' if not task else ''}">
<a t-if="task" t-attf-href="/my/tasks?{{ keep_query() }}">Tasks</a>
<t t-else="">Tasks</t>
</li>
<li t-if="task" class="breadcrumb-item">
<li t-if="task" class="breadcrumb-item active">
<span t-field="task.name"/>
</li>
</xpath>
</template>
<template id="portal_my_home" name="Portal My Home: project entries" inherit_id="portal.portal_my_home" priority="40">
<xpath expr="//ul[hasclass('o_portal_docs')]" position="inside">
<li t-if="project_count" class="list-group-item">
<span class="badge badge-secondary badge-pill float-right" t-esc="project_count"/>
<a href="/my/projects">Projects</a>
</li>
<li t-if="task_count" class="list-group-item">
<span class="badge badge-secondary badge-pill float-right" t-esc="task_count"/>
<a href="/my/tasks">Tasks</a>
</li>
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="project_count" t-call="portal.portal_docs_entry">
<t t-set="title">Projects</t>
<t t-set="url" t-value="'/my/projects'"/>
<t t-set="count" t-value="project_count"/>
</t>
<t t-if="task_count" t-call="portal.portal_docs_entry">
<t t-set="title">Tasks</t>
<t t-set="url" t-value="'/my/tasks'"/>
<t t-set="count" t-value="task_count"/>
</t>
</xpath>
</template>
<template id="portal_my_projects" name="My Projects">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">Projects</t>
</t>
@@ -42,80 +46,87 @@
There are no projects.
</div>
</t>
<div t-if="projects" class="card">
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
<thead>
<tr class="active">
<th class="col-lg-6">Name</th>
<th>Tasks</th>
</tr>
</thead>
<tbody>
<tr t-foreach="projects" t-as="project">
<td>
<a t-attf-href="/my/project/#{project.id}?{{ keep_query() }}"><span t-field="project.name"/></a>
</td>
<td>
<a t-attf-href="/my/tasks?{{keep_query('debug', filterby=project.id)}}">
<t t-esc="project.task_count" />
<t t-esc="project.label_tasks" />
</a>
</td>
</tr>
</tbody>
</table></div>
</div>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="portal.pager"/>
</div>
<t t-if="projects" t-call="portal.portal_table">
<tbody>
<tr t-foreach="projects" t-as="project">
<td>
<a t-attf-href="/my/project/#{project.id}?{{ keep_query() }}"><span t-field="project.name"/></a>
</td>
<td class="text-right">
<a t-attf-href="/my/tasks?{{keep_query('debug', filterby=project.id)}}">
<t t-esc="project.task_count" />
<t t-esc="project.label_tasks" />
</a>
</td>
</tr>
</tbody>
</t>
</t>
</template>
<template id="portal_my_project" name="My Project">
<t t-call="portal.portal_layout">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col-lg-12">
<h4>
Project - <span t-field="project.name"/>
</h4>
</div>
</div>
<t t-set="wrapwrap_classes" t-value="'o_portal_bg_dark'"/>
<t t-set="o_portal_fullwidth_alert" groups="project.group_project_user">
<div t-ignore="true" class="text-center">
This is a preview of the customer portal <i class="fa fa-chevron-right"/>
<a title="Edit in the backend" target="_blank" t-att-href="'/web#return_label=Website&amp;model=project.project&amp;id=%s&amp;view_type=form' % (project.id)">
<b>Back in edit mode</b>.
</a>
</div>
<div class="card-body">
<div class='row'>
<div class="col-lg-6">
<t t-if="project.partner_id">
<strong>Customer</strong>
<div t-if="project.partner_id">
<address t-field="project.partner_id" t-options='{"widget": "contact", "fields": ["name", "email"]}'/>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">&#215;</button>
</t>
<t t-call="portal.portal_record_layout">
<t t-set="card_header">
<h5 class="mb-0">
<small class="text-muted">Project - </small><span t-field="project.name"/>
<span class="float-right">
<a role="button" t-attf-href="/my/tasks?filterby=#{project.id}" class="btn btn-sm btn-secondary">
<span class="fa fa-tasks" role="img" aria-label="Tasks" title="Tasks"/>
<span t-esc="project.task_count" />
<span t-field="project.label_tasks" />
</a>
</span>
</h5>
</t>
<t t-set="card_body">
<div class="row">
<div t-if="project.partner_id" class="col-12 col-md-6 mb-2 mb-md-0">
<h6>Customer</h6>
<div class="row">
<div class="col flex-grow-0 pr-3">
<img t-if="project.partner_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{project.partner_id.image}" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
</t>
<t t-if="project.user_id">
<strong>Project Manager</strong>
<div>
<div class="col pl-sm-0">
<address t-field="project.partner_id" t-options='{"widget": "contact", "fields": ["name", "email", "phone"]}'/>
</div>
</div>
</div>
<div t-if="project.user_id" class="col-12 col-md-6">
<h6>Project Manager</h6>
<div class="row">
<div class="col flex-grow-0 pr-3">
<img t-if="project.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{project.user_id.image}" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-sm-0">
<address t-field="project.user_id" t-options='{"widget": "contact", "fields": ["name", "email", "phone"]}'/>
</div>
</t>
</div>
<div class="col-lg-6">
<div class="float-right">
<a role="button" t-attf-href="/my/tasks?filterby=#{project.id}" class="btn btn-secondary btn-lg">
<span class="fa fa-tasks" role="img" aria-label="Tasks" title="Tasks"/>
<span t-esc="project.task_count" />
<span t-field="project.label_tasks" />
</a>
</div>
</div>
</div>
</div>
</div>
</t>
</t>
</t>
</template>
<template id="portal_my_tasks" name="My Tasks">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">Tasks</t>
</t>
@@ -124,121 +135,141 @@
There are no tasks.
</div>
</t>
<div t-if="grouped_tasks" class="card">
<div class="table-responsive">
<t t-if="grouped_tasks">
<t t-call="portal.portal_table">
<t t-foreach="grouped_tasks" t-as="tasks">
<table class="table table-hover o_portal_my_doc_table">
<thead>
<tr class="active">
<th t-if="groupby == 'none'" class="col-lg-9">Name</th>
<th t-else="" class="col-lg-9"><span t-field="tasks[0].sudo().project_id.label_tasks"/> for project: <span t-field="tasks[0].sudo().project_id.name"/></th>
<th class="col-lg-2">Stage</th>
<th>Ref</th>
<thead>
<tr t-attf-class="{{'thead-light' if not groupby == 'none' else ''}}">
<th t-if="groupby == 'none'">Name</th>
<th t-else="">
<em class="font-weight-normal text-muted"><span t-field="tasks[0].sudo().project_id.label_tasks"/> for project:</em>
<span t-field="tasks[0].sudo().project_id.name"/></th>
<th class="text-center">Stage</th>
<th class="text-left">Ref</th>
</tr>
</thead>
<tbody>
<t t-foreach="tasks" t-as="task">
<tr>
<td>
<a t-attf-href="/my/task/#{task.id}?{{ keep_query() }}"><span t-field="task.name"/></a>
</td>
<td class="text-center">
<span class="badge badge-pill badge-info" title="Current stage of the task" t-esc="task.stage_id.name" />
</td>
<td class="text-left">
#<span t-esc="task.id"/>
</td>
</tr>
</thead>
<tbody>
<t t-foreach="tasks" t-as="task">
<tr>
<td>
<a t-attf-href="/my/task/#{task.id}?{{ keep_query() }}"><span t-field="task.name"/></a>
</td>
<td>
<span class="badge badge-info" title="Current stage of the task" t-esc="task.stage_id.name" />
</td>
<td>
<span t-esc="task.id"/>
</td>
</tr>
</t>
</tbody>
</table>
</t>
</tbody>
</t>
</div>
</div>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="portal.pager"/>
</div>
</t>
</t>
</t>
</template>
<template id="portal_my_task" name="My Task">
<t t-call="portal.portal_layout">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col-lg-12">
<h4>
Task - <span t-field="task.name"/> (#<span t-esc="task.id"/>)
<span t-field="task.stage_id.name" class="float-right badge badge-info" title="Current stage of this task"/>
<a role="button" class="btn btn-info" t-att-href="'/web#return_label=Website&amp;model=project.task&amp;id=%s&amp;view_type=form' % (task.id)" groups="project.group_project_user">Edit Task</a>
</h4>
<t t-set="wrapwrap_classes" t-value="'o_portal_bg_dark'"/>
<t t-set="o_portal_fullwidth_alert" groups="project.group_project_user">
<div t-ignore="true" class="text-center">
This is a preview of the customer portal <i class="fa fa-chevron-right"/>
<a title="Edit in the backend" target="_blank" t-att-href="'/web#return_label=Website&amp;model=project.task&amp;id=%s&amp;view_type=form' % (task.id)">
<b>Back in edit mode</b>.
</a>
</div>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">&#215;</button>
</t>
<t t-call="portal.portal_record_layout">
<t t-set="card_header">
<div class="row no-gutters">
<div class="col-md">
<h5 class="mb-1 mb-md-0">
<span t-field="task.name"/>
<small class="text-muted"> (#<span t-field="task.id"/>)</small>
</h5>
</div>
<div class="col-md text-md-right">
<small class="text-right">Status:</small>
<span t-field="task.stage_id.name" class=" badge badge-pill badge-info" title="Current stage of this task"/>
</div>
</div>
</div>
<div class="card-body">
<div class="mb8" t-if="user.partner_id.id in task.sudo().project_id.message_partner_ids.ids">
</t>
<t t-set="card_body">
<div class="mb-1" t-if="user.partner_id.id in task.sudo().project_id.message_partner_ids.ids">
<strong>Project:</strong> <a t-attf-href="/my/project/#{task.project_id.id}" t-field="task.project_id.name"/>
</div>
<div class='row'>
<div class="col-lg-6">
<div class="mb8">
<strong>Date:</strong> <span t-field="task.create_date" t-options='{"widget": "date"}'/>
</div>
<div class="row mb-4">
<div class="col-12 col-md-6 mb-1">
<strong>Date:</strong> <span t-field="task.create_date" t-options='{"widget": "date"}'/>
</div>
<div class="col-12 col-md-6" t-if="task.date_deadline">
<strong>Deadline:</strong> <span t-field="task.date_deadline" t-options='{"widget": "date"}'/>
</div>
</div>
<div t-if="task.user_id">
<strong>Assigned to</strong>
<div>
<address t-field="task.user_id" t-options='{"widget": "contact", "fields": ["name", "email", "phone"]}'/>
<div class="row mb-4" t-if="task.user_id or task.partner_id">
<div class="col-12 col-md-6 pb-2" t-if="task.user_id">
<strong>Assigned to</strong>
<div class="row">
<div class="col flex-grow-0 pr-3">
<img t-if="task.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{task.user_id.image}" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
</div>
<div t-if="task.attachment_ids" class='card-footer'>
<strong>
<t t-if='len(task.attachment_ids)&gt;1'>Attachments</t>
<t t-else="">Attachment</t>
</strong>
<div class='row'>
<div class="col-lg-2 col-md-3 text-center oe_attachments" t-foreach='task.attachment_ids' t-as='attachment'>
<a t-attf-href="/web/content/#{attachment.id}?download=true&amp;access_token=#{attachment.generate_access_token()}" target="_blank">
<div class='oe_attachment_embedded o_image o_image_small' t-att-title="attachment.name" t-att-data-mimetype="attachment.mimetype" t-attf-data-src="/web/image/#{attachment.id}/50x40"/>
<div class='oe_attachment_name'><t t-esc='attachment.name' /></div>
</a>
</div>
<div class="col pl-md-0">
<div t-field="task.user_id" t-options='{"widget": "contact", "fields": ["name", "email", "phone"]}'/>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="mb8" t-if="task.date_deadline">
<strong>Deadline:</strong> <span t-field="task.date_deadline" t-options='{"widget": "date"}'/>
</div>
<div t-if="task.partner_id">
<strong>Reported by</strong>
<div>
<address t-field="task.partner_id" t-options='{"widget": "contact", "fields": ["name", "email"]}'/>
<div class="coll-12 col-md-6 pb-2" t-if="task.partner_id">
<strong>Reported by</strong>
<div class="row">
<div class="col flex-grow-0 pr-3">
<img t-if="task.partner_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{task.partner_id.image}" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-md-0">
<div t-field="task.partner_id" t-options='{"widget": "contact", "fields": ["name", "email", "phone"]}'/>
</div>
</div>
</div>
</div>
<t t-if="task.description">
<div class="col-lg-12">
<strong>Description</strong>
<div t-field="task.description"/>
<div class="row" t-if="task.description or task.attachment_ids">
<div t-if="task.description" t-attf-class="col-12 col-lg-7 mb-4 mb-md-0 {{'col-lg-7' if task.attachment_ids else 'col-lg-12'}}">
<hr class="mb-1"/>
<strong class="d-block mb-2">Description</strong>
<div class="py-1 px-2 bg-100 small" t-field="task.description"/>
</div>
</t>
</div>
</div>
<div class="row mt32">
<div class="col-lg-12">
<h4><strong>Message and communication history</strong></h4>
</div>
<div class="col-lg-10 offset-lg-1 mt16">
<t t-call="portal.message_thread">
<t t-set="object" t-value="task"/>
<t t-set="token" t-value="task.access_token"/>
<t t-set="pid" t-value="pid"/>
<t t-set="hash" t-value="hash"/>
</t>
</div>
<div t-if="task.attachment_ids" t-attf-class="col-12 col-lg-5 o_project_portal_attachments {{'col-lg-5' if task.description else 'col-lg-12'}}">
<hr class="mb-1 d-none d-lg-block"/>
<strong class="d-block mb-2">Attachments</strong>
<div class="row">
<div t-attf-class="col {{'col-lg-6' if not task.description else 'col-lg-12'}}">
<ul class="list-group">
<a class="list-group-item list-group-item-action d-flex align-items-center oe_attachments py-1 px-2" t-foreach='task.attachment_ids' t-as='attachment' t-attf-href="/web/content/#{attachment.id}" target="_blank">
<div class='oe_attachment_embedded o_image o_image_small mr-2 mr-lg-3' t-att-title="attachment.name" t-att-data-mimetype="attachment.mimetype" t-attf-data-src="/web/image/#{attachment.id}/50x40"/>
<div class='oe_attachment_name text-truncate'><t t-esc='attachment.name'/></div>
</a>
</ul>
</div>
</div>
</div>
</div>
</t>
</t>
<div class="mt32">
<h4><strong>Message and communication history</strong></h4>
<t t-call="portal.message_thread">
<t t-set="object" t-value="task"/>
<t t-set="token" t-value="task.access_token"/>
<t t-set="pid" t-value="pid"/>
<t t-set="hash" t-value="hash"/>
</t>
</div>
</t>
</template>
+28 -33
View File
@@ -1,24 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_home_menu_purchase" name="Portal layout : purchase menu entries" inherit_id="portal.portal_layout" priority="25">
<template id="portal_my_home_menu_purchase" name="Portal layout : purchase menu entries" inherit_id="portal.portal_breadcrumbs" priority="25">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'purchase' or purchase_order" class="breadcrumb-item">
<li t-if="page_name == 'purchase' or purchase_order" t-attf-class="breadcrumb-item #{'active ' if not purchase_order else ''}">
<a t-if="purchase_order" t-attf-href="/my/purchase?{{ keep_query() }}">Purchase Orders</a>
<t t-else="">Purchase Orders</t>
</li>
<li t-if="purchase_order" class="breadcrumb-item">
<li t-if="purchase_order" class="breadcrumb-item active">
<t t-esc="purchase_order.name"/>
</li>
</xpath>
</template>
<template id="portal_my_home_purchase" name="Portal My Home : purchase entry" inherit_id="portal.portal_my_home" priority="25">
<xpath expr="//ul[hasclass('o_portal_docs')]" position="inside">
<li t-if="purchase_count" class="list-group-item">
<span class="badge badge-secondary badge-pill float-right" t-esc="purchase_count"/>
<a href="/my/purchase">Purchase Orders</a>
</li>
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="purchase_count" t-call="portal.portal_docs_entry">
<t t-set="title">Purchase Orders</t>
<t t-set="url" t-value="'/my/purchase'"/>
<t t-set="count" t-value="purchase_count"/>
</t>
</xpath>
</template>
@@ -27,8 +28,7 @@
<t t-call="portal.portal_searchbar">
<t t-set="title">Purchase Orders</t>
</t>
<div t-if="orders" class="card">
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
<t t-if="orders" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Purchase Orders #</th>
@@ -37,29 +37,24 @@
<th>Total</th>
</tr>
</thead>
<t t-foreach="orders" t-as="order">
<tr>
<td>
<a t-attf-href="/my/purchase/#{order.id}?#{keep_query()}"><t t-esc="order.name"/></a>
</td>
<td><span t-field="order.date_order"/></td>
<td>
<t t-if="order.invoice_status == 'to invoice'">
<span class="badge badge-info"><i class="fa fa-fw fa-file-text"/> Waiting for Bill</span>
</t>
<t t-if="order.state == 'cancel'">
<span class="badge badge-secondary"><i class="fa fa-fw fa-remove"/> Cancelled</span>
</t>
</td>
<td><span t-field="order.amount_total" t-options='{"widget": "monetary", "display_currency": order.currency_id}'/>
</td>
</tr>
</t>
</table></div>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="portal.pager"/>
</div>
</div>
<tbody>
<t t-foreach="orders" t-as="order">
<tr>
<td><a t-attf-href="/my/purchase/#{order.id}?#{keep_query()}"><t t-esc="order.name"/></a></td>
<td><span t-field="order.date_order"/></td>
<td>
<t t-if="order.invoice_status == 'to invoice'">
<span class="badge badge-info"><i class="fa fa-fw fa-file-text"/> Waiting for Bill</span>
</t>
<t t-if="order.state == 'cancel'">
<span class="badge badge-secondary"><i class="fa fa-fw fa-remove"/> Cancelled</span>
</t>
</td>
<td><span t-field="order.amount_total" t-options='{"widget": "monetary", "display_currency": order.currency_id}'/></td>
</tr>
</t>
</tbody>
</t>
</t>
</template>
@@ -76,11 +76,11 @@ var SalePortalSidebar = PortalSidebar.extend({
lastUL = null,
$bsSidenav = this.$el.find('.bs-sidenav');
$("[id^=quote_header_], [id^=quote_]", this.spyWatched).attr("id", "");
_.each(this.spyWatched.find("h1, h2"), function (el) {
$("#quote_content [id^=quote_header_], #quote_content [id^=quote_]", this.spyWatched).attr("id", "");
_.each(this.spyWatched.find("#quote_content h2, #quote_content h3"), function (el) {
var id, text;
switch (el.tagName.toLowerCase()) {
case "h1":
case "h2":
id = self._setElementId('quote_header_', el);
text = self._extractText($(el));
if (!text) {
@@ -89,7 +89,7 @@ var SalePortalSidebar = PortalSidebar.extend({
lastLI = $("<li class='nav-item'>").append($('<a class="nav-link" href="#' + id + '"/>').text(text)).appendTo($bsSidenav);
lastUL = false;
break;
case "h2":
case "h3":
id = self._setElementId('quote_', el);
text = self._extractText($(el));
if (!text) {
+414 -428
View File
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="portal_my_home_menu_sale" name="Portal layout : sales menu entries" inherit_id="portal.portal_layout" priority="20">
<template id="portal_my_home_menu_sale" name="Portal layout : sales menu entries" inherit_id="portal.portal_breadcrumbs" priority="20">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'quote' or sale_order and sale_order.state in ('sent', 'cancel')" class="breadcrumb-item">
<li t-if="page_name == 'quote' or sale_order and sale_order.state in ('sent', 'cancel')" t-attf-class="breadcrumb-item #{'active ' if not sale_order else ''}">
<a t-if="sale_order" t-attf-href="/my/quotes?{{ keep_query() }}">Quotations</a>
<t t-else="">Quotations</t>
</li>
<li t-if="page_name == 'order' or sale_order and sale_order.state not in ('sent', 'cancel')" class="breadcrumb-item">
<li t-if="page_name == 'order' or sale_order and sale_order.state not in ('sent', 'cancel')" t-attf-class="breadcrumb-item #{'active ' if not sale_order else ''}">
<a t-if="sale_order" t-attf-href="/my/orders?{{ keep_query() }}">Sales Orders</a>
<t t-else="">Sales Orders</t>
</li>
<li t-if="sale_order" class="breadcrumb-item">
<li t-if="sale_order" class="breadcrumb-item active">
<span t-field="sale_order.type_name"/>
<t t-esc="sale_order.name"/>
</li>
@@ -19,216 +19,212 @@
</template>
<template id="portal_my_home_sale" name="Portal My Home : sales entries" inherit_id="portal.portal_my_home" priority="20">
<xpath expr="//ul[hasclass('o_portal_docs')]" position="inside">
<li t-if="quotation_count" class="list-group-item">
<span class="badge badge-secondary badge-pill float-right" t-esc="quotation_count"/>
<a href="/my/quotes">Quotations</a>
</li>
<li t-if="order_count" class="list-group-item">
<span class="badge badge-secondary badge-pill float-right" t-esc="order_count"/>
<a href="/my/orders">Sales Orders</a>
</li>
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="quotation_count" t-call="portal.portal_docs_entry">
<t t-set="title">Quotations</t>
<t t-set="url" t-value="'/my/quotes'"/>
<t t-set="count" t-value="quotation_count"/>
</t>
<t t-if="order_count" t-call="portal.portal_docs_entry">
<t t-set="title">Sales Orders</t>
<t t-set="url" t-value="'/my/orders'"/>
<t t-set="count" t-value="order_count"/>
</t>
</xpath>
</template>
<template id="portal_my_quotations" name="My Quotations">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">Quotations</t>
</t>
<t t-if="not quotations">
<p>There are currently no quotations for your account.</p>
</t>
<div t-if="quotations" class="card">
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
<thead>
<tr class="active">
<th>Quotation #</th>
<th>Order Date</th>
<th>Valid Until</th>
<th></th>
<th>Total</th>
</tr>
</thead>
<t t-foreach="quotations" t-as="quotation">
<tr>
<td>
<a t-att-href="quotation.get_portal_url()"><t t-esc="quotation.name"/></a>
</td>
<td><span t-field="quotation.date_order"/></td>
<td><span t-field="quotation.validity_date"/></td>
<td>
<t t-if="quotation.state == 'cancel'">
<span class="badge badge-secondary"><i class="fa fa-fw fa-remove"/> Cancelled</span>
</t>
<t t-if="quotation.is_expired">
<span class="badge badge-secondary"><i class="fa fa-fw fa-clock-o"/> Expired</span>
</t>
</td>
<td>
<span t-field="quotation.amount_total"/>
</td>
</tr>
</t>
</table></div>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="portal.pager"/>
</div>
</div>
<t t-if="quotations" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Quotation #</th>
<th class="text-right">Order Date</th>
<th class="text-right">Valid Until</th>
<th class="text-center"/>
<th class="text-right">Total</th>
</tr>
</thead>
<t t-foreach="quotations" t-as="quotation">
<tr>
<td><a t-att-href="quotation.get_portal_url()"><t t-esc="quotation.name"/></a></td>
<td class="text-right"><span t-field="quotation.date_order"/></td>
<td class="text-right"><span t-field="quotation.validity_date"/></td>
<td class="text-center">
<span t-if="quotation.state == 'cancel'" class="badge badge-pill badge-secondary"><i class="fa fa-fw fa-remove"/> Cancelled</span>
<span t-if="quotation.is_expired" class="badge badge-pill badge-secondary"><i class="fa fa-fw fa-clock-o"/> Expired</span>
</td>
<td class="text-right">
<span t-field="quotation.amount_total"/>
</td>
</tr>
</t>
</t>
</t>
</template>
<template id="portal_my_orders" name="My Sales Orders">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">Sales Orders</t>
</t>
<t t-if="not orders">
<p>There are currently no orders for your account.</p>
</t>
<div t-if="orders" class="card">
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
<thead>
<tr class="active">
<th>
<span class='d-none d-md-inline'>Sales Order #</span>
<span class='d-block d-md-none'>Ref.</span>
</th>
<th>Order Date</th>
<th ></th>
<th>Total</th>
</tr>
</thead>
<t t-foreach="orders" t-as="order">
<tr>
<td>
<a t-att-href="order.get_portal_url()"><t t-esc="order.name"/></a>
</td>
<td>
<span t-field="order.date_order" t-options="{'widget': 'date'}"/>&amp;nbsp;
<span class='d-none d-md-inline' t-field="order.date_order" t-options="{'time_only': True}"/>
</td>
<td>
<t t-if="order.state == 'done'">
<span class="badge badge-success d-none d-md-inline-block"><i class="fa fa-fw fa-check" role="img" aria-label="Done" title="Done"></i><span class="d-none d-md-inline"> Done</span></span>
</t>
</td>
<td><span t-field="order.amount_total"/></td>
</tr>
</t>
</table></div>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="portal.pager"/>
</div>
</div>
<t t-if="orders" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>
<span class='d-none d-md-inline'>Sales Order #</span>
<span class='d-block d-md-none'>Ref.</span>
</th>
<th class="text-right">Order Date</th>
<th class="text-center"/>
<th class="text-right">Total</th>
</tr>
</thead>
<t t-foreach="orders" t-as="order">
<tr>
<td><a t-att-href="order.get_portal_url()"><t t-esc="order.name"/></a></td>
<td class="text-right">
<span t-field="order.date_order" t-options="{'widget': 'date'}"/>&amp;nbsp;
<span class='d-none d-md-inline' t-field="order.date_order" t-options="{'time_only': True}"/>
</td>
<td class="text-center">
<span t-if="order.state == 'done'" class="badge badge-pill badge-success">
<i class="fa fa-fw fa-check" role="img" aria-label="Done" title="Done"/>Done
</span>
</td>
<td class="text-right"><span t-field="order.amount_total"/></td>
</tr>
</t>
</t>
</t>
</template>
<!-- Complete page of the sale_order -->
<template id="sale_order_portal_template" name="Sales Order Portal Template" inherit_id="portal.portal_sidebar" primary="True">
<xpath expr="//div[hasclass('o_portal_sidebar')]" position="inside">
<t t-set="wrapwrap_classes" t-value="'o_portal_bg_dark'"/>
<t t-set="o_portal_fullwidth_alert" groups="sales_team.group_sale_salesman">
<div t-ignore="true" class="text-center">
This is a preview of the customer portal <i class="fa fa-chevron-right"/>
<a t-att-href="'/web#return_label=Website&amp;model=%s&amp;id=%s&amp;action=%s&amp;view_type=form' % (sale_order._name, sale_order.id, sale_order.env.ref('sale.action_quotations').id)">
<b>Back in edit mode</b>.
</a>
</div>
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> &#215; </button>
</t>
<div class="row mt16 o_portal_sale_sidebar">
<!-- Sidebar -->
<div class="col-lg-3 d-print-none">
<div class="bs-sidebar mb16">
<div class="text-center pt16 o_account_portal_sidebar">
<h2 class="media-heading">
<strong>
<span t-field="sale_order.amount_total"/>
</strong>
</h2>
</div>
<t t-if="sale_order.team_id.team_type != 'website'">
<div class="text-center" t-if="sale_order.state in ('draft', 'sent', 'waiting_date')" style="padding: 10px">
<t t-set="show_hr" t-value="False"/>
<a role="button" t-if="not sale_order.is_expired and not sale_order.signature and sale_order.has_to_be_signed()" class="btn btn-primary btn-block" data-toggle="modal" data-target="#modalaccept" href="#">
<i class="fa fa-check"/> Accept
<t t-set="show_hr" t-value="True"/>
</a>
<a role="button" t-elif="not sale_order.is_expired and sale_order.has_to_be_paid()" class="btn btn-primary btn-block" data-toggle="modal" data-target="#modalaccept" href="#">
<i class="fa fa-check"/> <t t-if="not sale_order.signature">Accept &amp; </t>Pay
<t t-set="show_hr" t-value="True"/>
</a>
<a role="button" t-if="sale_order.is_expired" href="#discussion" class="btn btn-info btn-block o_normalwhitespace">
<strong>This offer expired!</strong><br/>
Contact us for new quotation.
<t t-set="show_hr" t-value="True"/>
</a>
<hr class="mb0" t-if="show_hr"/>
</div>
<div class="text-center" t-if="need_payment or (sale_order.state in ('sale') and sale_order.has_to_be_paid() and tx_state != 'done')" style="padding: 10px">
<a role="button" class="btn btn-primary btn-block" data-toggle="modal" data-target="#modalaccept" href="#">
<i class="fa fa-check"></i> Pay Now
</a>
<hr class="mb0"/>
</div>
</t>
<t t-call="portal.portal_record_sidebar">
<t t-set="classes" t-value="'col-12 col-lg flex-lg-grow-0 d-print-none'"/>
<div class="navspy" t-ignore="true" role="complementary">
<ul class="nav flex-column bs-sidenav" data-id="quote_sidebar"></ul>
</div>
<t t-set="title">
<h2 class="mb-0"><b t-field="sale_order.amount_total"/> </h2>
</t>
<div t-if="not sale_order.is_expired and sale_order.state in ['draft', 'sent']" class="pl-3 pr-3">
<input type="hidden" t-att-value="sale_order.validity_date" id="validity_date"/>
<div class="mt8" t-if="sale_order.remaining_validity_days &gt; 0">
<hr class="mb0"/>
<strong>This offer expires in</strong>
<div class="day_counter mt8 mb16">
<i class="fa fa-clock-o" aria-title="Dates" title="Dates"></i>
<t t-esc="sale_order.remaining_validity_days"/>
<t t-if="sale_order.remaining_validity_days &gt; 1">
days
<t t-set="entries">
<ul class="list-group list-group-flush flex-wrap flex-row flex-lg-column">
<li class="list-group-item flex-grow-1">
<a role="button" class="btn btn-block btn-secondary" target="_blank" t-att-href="sale_order.get_portal_url(report_type='pdf')"><i class="fa fa-print mr-1"/>Print</a>
<t t-if="sale_order.state in ('draft', 'sent', 'waiting_date')">
<t t-set="to_accept" t-value="not sale_order.is_expired and not sale_order.signature and sale_order.has_to_be_signed()"/>
<t t-set="to_accept_and_pay" t-value="not sale_order.is_expired and sale_order.has_to_be_paid()"/>
<t t-if="to_accept or to_accept_and_pay or sale_order.is_expired">
<a role="button" t-if="to_accept" class="btn btn-primary btn-block" data-toggle="modal" data-target="#modalaccept" href="#">
<i class="fa fa-check"/> Accept
</a>
<a role="button" t-elif="to_accept_and_pay" class="btn btn-success btn-block" data-toggle="modal" data-target="#modalaccept" href="#">
<i class="fa fa-check"/> <t t-if="not sale_order.signature">Accept &amp; </t>Pay
</a>
<t t-if="sale_order.is_expired">
<div class="alert alert-warning small mt-3 mb-1 py-1 px-2"><b class="d-block mb-1">This offer expired!</b>
<a role="button" href="#discussion" class="btn btn-info btn-block py-1 o_normalwhitespace"> Get a new quotation.</a>
</div>
</t>
</t>
<t t-if="sale_order.remaining_validity_days &lt;= 1">
day
</t>
<t t-if="need_payment or (sale_order.state in ('sale') and sale_order.has_to_be_paid() and tx_state != 'done')">
<a role="button" class="btn btn-success btn-block" data-toggle="modal" data-target="#modalaccept" href="#">
<i class="fa fa-check"></i> Pay Now
</a>
</t>
</li>
<li class="navspy list-group-item pl-0 d-none d-lg-block" t-ignore="true" role="complementary">
<ul class="nav flex-column bs-sidenav" data-id="quote_sidebar"></ul>
</li>
<t t-if="not sale_order.is_expired and sale_order.state in ['draft', 'sent']">
<input type="hidden" t-att-value="sale_order.validity_date" id="validity_date"/>
<li t-if="sale_order.remaining_validity_days &gt; 0" class="list-group-item">
<small><b class="text-muted">This offer expires in</b></small>
<div class="day_counter">
<i class="fa fa-clock-o" aria-title="Dates" title="Dates"></i>
<t t-esc="sale_order.remaining_validity_days"/>
day<t t-if="sale_order.remaining_validity_days &gt; 1">s</t>
</div>
</li>
<li t-if="sale_order.amount_undiscounted &gt; sale_order.amount_untaxed" class="list-group-item">
<small><b class="text-muted">Your advantage</b></small>
<t t-if="sale_order.amount_untaxed == sale_order.amount_total">
<small>
<b t-field="sale_order.amount_undiscounted"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'
style="text-decoration: line-through"
class="d-block mt-1"/>
</small>
<h4 t-field="sale_order.amount_total" class="text-success"/>
</t>
</div>
</div>
<t t-if="sale_order.amount_untaxed != sale_order.amount_total">
<small>
<strong t-field="sale_order.amount_undiscounted"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'
style="text-decoration: line-through"
class="d-block mt-1"/>
</small>
<h4 t-field="sale_order.amount_untaxed" class="text-success mb-0"/>
<small>(<span t-field="sale_order.amount_total"/> Incl. tax)</small>
</t>
</li>
</t>
<div class="mb16" t-if="sale_order.amount_undiscounted &gt; sale_order.amount_untaxed">
<hr class="mb0"/>
<p class="text-muted mb8">Your advantage:</p>
<t t-if="sale_order.amount_untaxed == sale_order.amount_total">
<strong t-field="sale_order.amount_total"/>
<strong t-field="sale_order.amount_undiscounted"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'
style="text-decoration: line-through"
class="text-danger"/>
</t>
<t t-if="sale_order.amount_untaxed != sale_order.amount_total">
<strong t-field="sale_order.amount_untaxed"/>
<strong t-field="sale_order.amount_undiscounted"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'
style="text-decoration: line-through"
class="text-danger"/>
<br />
(<span t-field="sale_order.amount_total"/> Incl. tax)
</t>
</div>
</div>
<div class="pb8 ml16 mr16" t-if="sale_order.user_id">
<hr class="mb0"/>
<div><strong>Your Contact:</strong></div>
<div class="d-flex h-100">
<div class="align-self-center">
<img class="rounded-circle mr4 float-left o_portal_contact_img" t-if="sale_order.user_id.image" t-attf-src="data:image/png;base64,#{sale_order.user_id.image}" alt="Contact"/>
<img class="rounded-circle mr4 float-left o_portal_contact_img" t-if="not sale_order.user_id.image" src="/web/static/src/img/placeholder.png" alt="Contact"/>
<li t-if="sale_order.user_id" class="list-group-item flex-grow-1 o_portal_contact_block">
<div class="small mb-1"><strong class="text-muted">Your Contact:</strong></div>
<div class="row flex-nowrap">
<div class="col flex-grow-0 pr-2">
<img class="rounded-circle mr4 float-left o_portal_contact_img" t-if="sale_order.user_id.image" t-attf-src="data:image/png;base64,#{sale_order.user_id.image}" alt="Contact"/>
<img class="rounded-circle mr4 float-left o_portal_contact_img" t-if="not sale_order.user_id.image" src="/web/static/src/img/placeholder.png" alt="Contact"/>
</div>
<div class="col pl-0" style="min-width: 150px">
<span t-field="sale_order.user_id" t-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
<a href="#discussion" class="small"><i class="fa fa-comment"></i> Send message</a>
</div>
</div>
<div class="align-self-center">
<span t-field="sale_order.user_id" t-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
<a href="#discussion"><i class="fa fa-comment"></i> Contact us</a>
</div>
</div>
</div>
</div>
<div class="text-center d-none d-md-block o_portal_brand">
Powered by <a target="_blank" href="https://www.odoo.com?utm_source=db&amp;utm_medium=portal">Odoo</a>
</div>
</div>
</li>
</ul>
</t>
</t>
<!-- Page content -->
<div id="quote_content" class="col-lg-9">
<div id="quote_content" class="col-12 col-lg justify-content-end">
<div class="alert alert-success alert-dismissable" t-if="message==1" role="status">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">&amp;times;</button>
@@ -339,47 +335,43 @@
<strong>This quotation has been canceled.</strong> Contact us to get a new quotation.
</div>
<t t-call="sale.sale_order_portal_content"/>
<div t-attf-class="card #{'pb-5' if report_type == 'html' else ''}">
<div t-call="sale.sale_order_portal_content"/>
</div>
<t t-if="sale_order.team_id.team_type != 'website'">
<t t-if="sale_order.state in ('draft', 'sent', 'waiting_date')">
<t t-set="to_accept" t-value="not sale_order.is_expired and not sale_order.signature and sale_order.has_to_be_signed()"/>
<t t-set="to_accept_and_pay" t-value="not sale_order.is_expired and not sale_order.signature and sale_order.has_to_be_signed()"/>
</t>
<t t-set="to_pay" t-value="need_payment or (sale_order.state in ('sale') and sale_order.has_to_be_paid() and tx_state != 'done')"/>
<div class="row justify-content-center text-center d-print-none mt8 mb16" t-if="sale_order.state in ('draft', 'sent', 'waiting_date')">
<t t-set="show_buttons" t-value="False"/>
<div t-if="to_accept or to_accept_and_pay or to_pay" class="row justify-content-center text-center d-print-none pt-1 pb-4">
<div class="col-sm-auto mt8">
<a role="button" class="btn btn-primary" data-toggle="modal" data-target="#modalaccept" t-if="not sale_order.is_expired and not sale_order.signature and sale_order.has_to_be_signed()" href="#">
<i class="fa fa-check"></i> Accept
<t t-set="show_buttons" t-value="True"/>
</a>
<a role="button" class="btn btn-primary" data-toggle="modal" data-target="#modalaccept" t-elif="not sale_order.is_expired and sale_order.has_to_be_paid()" href="#">
<i class="fa fa-check"/> <t t-if="not sale_order.signature">Accept &amp; </t>Pay
<t t-set="show_buttons" t-value="True"/>
</a>
<a t-if="to_accept" role="button" class="btn btn-primary" data-toggle="modal" data-target="#modalaccept" href="#"><i class="fa fa-check"/> Accept</a>
<a t-elif="to_accept_and_pay" role="button" class="btn btn-primary" data-toggle="modal" data-target="#modalaccept" href="#"><i class="fa fa-check"/> <t t-if="not sale_order.signature">Accept &amp; </t>Pay</a>
</div>
<div class="col-sm-auto mt8">
<a role="button" class="btn btn-secondary" type="submit" href="#discussion" t-if="show_buttons">
<i class="fa fa-comment"></i> Feedback
</a>
<t t-if="to_accept or to_accept_and_pay">
<div class="col-sm-auto mt8">
<a role="button" class="btn btn-info" type="submit" href="#discussion"><i class="fa fa-comment"/> Feedback</a>
</div>
<div class="col-sm-auto mt8">
<a role="button" class="btn btn-warning" data-toggle="modal" data-target="#modaldecline" href="#"> <i class="fa fa-times"/> Reject</a>
</div>
</t>
<div t-if="to_pay" class="col-sm-auto mt8">
<a role="button" class="btn btn-success" data-toggle="modal" data-target="#modalaccept" href="#"><i class="fa fa-check"/> Pay Now</a>
</div>
<div class="col-sm-auto mt8">
<a role="button" class="btn btn-danger" data-toggle="modal" data-target="#modaldecline" href="#" t-if="show_buttons">
<i class="fa fa-times"></i> Reject
</a>
</div>
</div>
<div class="text-center" t-if="need_payment or (sale_order.state in ('sale') and sale_order.has_to_be_paid() and tx_state != 'done')" style="padding: 10px">
<a role="button" class="btn btn-primary" data-toggle="modal" data-target="#modalaccept" href="#">
<i class="fa fa-check"></i> Pay Now
</a>
</div>
</t>
<div id="sale_order_communication">
<h1 class="o_page_header">Communication</h1>
<div id="sale_order_communication" class="mt-4">
<h2>Communication</h2>
<t t-call="portal.message_thread">
<t t-set="object" t-value="sale_order"/>
</t>
</div>
</div><!-- //col-lg-9 -->
</div><!-- // #quote_content -->
</div>
</xpath>
</template>
@@ -391,252 +383,246 @@
-->
<template id="sale_order_portal_content" name="Sales Order Portal Content">
<!-- Intro -->
<div id="introduction" class="o_page_header mt16">
<h1>
<div id="introduction" t-attf-class="pb-2 pt-3 #{'card-header bg-white' if report_type == 'html' else ''}">
<h2 class="my-0">
<span t-field="sale_order.type_name"></span>
<em t-esc="sale_order.name"/>
<div t-ignore="true" class="float-md-right css_editable_mode_hidden d-print-none">
<ul class="list-inline">
<li groups="sales_team.group_sale_salesman" class="list-inline-item">
<a role="button" class="btn btn-info" t-att-href="'/web#return_label=Website&amp;model=%s&amp;id=%s&amp;action=%s&amp;view_type=form' % (sale_order._name, sale_order.id, sale_order.env.ref('sale.action_quotations').id)">
<t t-if="sale_order.state in ('draft', 'sent', 'cancel')">Edit Quotation</t>
<t t-else="">Edit Sales Order</t>
</a>
</li>
<li class="list-inline-item">
<a role="button" class="btn btn-info" target="_blank" t-att-href="sale_order.get_portal_url(report_type='pdf')">Print</a>
</li>
</ul>
</div>
</h1>
</h2>
</div>
<!-- Informations -->
<div id="informations">
<div t-if="sale_order.transaction_ids and not invoices and sale_order.state in ('sent', 'sale') and portal_confirmation == 'pay' and not success and not error" t-att-data-order-id="sale_order.id">
<t t-if="sale_order.transaction_ids">
<t t-call="payment.payment_confirmation_status">
<t t-set="payment_tx_id" t-value="sale_order.get_portal_last_transaction()"/>
<div t-attf-class="#{'card-body' if report_type == 'html' else ''}">
<!-- Informations -->
<div id="informations">
<div t-if="sale_order.transaction_ids and not invoices and sale_order.state in ('sent', 'sale') and portal_confirmation == 'pay' and not success and not error" t-att-data-order-id="sale_order.id">
<t t-if="sale_order.transaction_ids">
<t t-call="payment.payment_confirmation_status">
<t t-set="payment_tx_id" t-value="sale_order.get_portal_last_transaction()"/>
</t>
</t>
</t>
</div>
<div class="mb8">
<strong>Date:</strong> <span t-field="sale_order.create_date" t-options='{"widget": "date"}'/>
</div>
<div class="mb8" t-if="sale_order.validity_date">
<strong>Expiration Date:</strong> <span t-field="sale_order.validity_date" t-options='{"widget": "date"}'/>
</div>
<div class='row'>
<div class="col-lg-6">
<div>
<strong>Invoicing Address</strong>
</div>
<div>
</div>
<div class="mb-3">
<strong>Date:</strong> <span t-field="sale_order.create_date" t-options='{"widget": "date"}'/>
</div>
<div class="mb-3" t-if="sale_order.validity_date">
<strong>Expiration Date:</strong> <span t-field="sale_order.validity_date" t-options='{"widget": "date"}'/>
</div>
<div class="row">
<div class="col-lg-6">
<strong class="d-block mb-1">Invoicing Address</strong>
<address t-field="sale_order.partner_invoice_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/>
</div>
</div>
<div id="shipping_address" class="col-lg-6" groups="sale.group_delivery_invoice_address">
<div>
<strong>Shipping Address</strong>
</div>
<div>
<div id="shipping_address" class="col-lg-6" groups="sale.group_delivery_invoice_address">
<strong class="d-block mb-1">Shipping Address</strong>
<address t-field="sale_order.partner_shipping_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<t t-set="invoices" t-value="[i for i in sale_order.invoice_ids if i.state not in ['draft', 'cancel']]"/>
<t t-if="invoices">
<div>
<strong>Invoices</strong>
</div>
<div>
<t t-set="invoices" t-value="[i for i in sale_order.invoice_ids if i.state not in ['draft', 'cancel']]"/>
<div t-if="invoices" class="row">
<div class="col">
<strong class="d-block mb-1">Invoices</strong>
<ul class="list-group mb-4">
<t t-foreach="invoices" t-as="i">
<t t-set="report_url" t-value="i.get_portal_url(report_type='pdf', download=True)"/>
<div>
<a t-att-href="report_url"><span class="fa fa-download" role="img" aria-label="Download" title="Download"/></a>
<a t-att-href="report_url"><span t-esc="i.number"/></a>
<span class="text-muted" t-field="i.date_invoice"/>
<t t-if="i.state == 'paid'">
<span class="badge badge-success orders_label_text_align"><i class="fa fa-fw fa-check"/> Paid</span>
</t>
<t t-if="i.state != 'paid'">
<span class="badge badge-info orders_label_text_align"><i class="fa fa-fw fa-clock-o"/> Waiting Payment</span>
</t>
</div>
</t>
</div>
</t>
</div>
</div>
</div>
<section id="details" style="page-break-inside: auto;">
<h1 class="o_page_header" id="details">Details</h1>
<t t-set="display_discount" t-value="True in [line.discount > 0 for line in sale_order.order_line]"/>
<table class="table" id="sales_order_table">
<thead>
<tr>
<t t-set="colspan" t-value="7"/>
<th class="d-none d-xl-table-cell"></th>
<th class="text-left">Products</th>
<th class="text-left">Quantity</th>
<th t-attf-class="text-right {{ 'd-none d-sm-table-cell' if report_type == 'html' else '' }}">Unit Price</th>
<th t-if="display_discount" class="text-right">
<span>Discount</span>
<t t-set="colspan" t-value="colspan+1"/>
</th>
<th t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">Taxes</th>
<th class="text-right" >
<span groups="account.group_show_line_subtotals_tax_excluded">Amount</span>
<span groups="account.group_show_line_subtotals_tax_included">Total Price</span>
</th>
</tr>
</thead>
<tbody class="sale_tbody">
<t t-set="current_subtotal" t-value="0"/>
<t t-foreach="sale_order.order_line" t-as="line">
<t t-set="current_subtotal" t-value="current_subtotal + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
<t t-set="current_subtotal" t-value="current_subtotal + line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
<tr t-attf-class="{{ 'o_is_' + line.display_type if line.display_type else '' }}">
<t t-if="not line.display_type">
<td class="text-center d-none d-xl-table-cell">
<a class="list-group-item list-group-item-action d-flex flex-wrap align-items-center justify-content-between py-2 px-3" t-att-href="report_url">
<div>
<span t-field="line.product_image" t-options="{'widget': 'image', 'class': 'rounded', 'style':'width: 48px;height:48px'}" />
<i class="fa fa-download mr-1" role="img" aria-label="Download" title="Download"/>
<span t-esc="i.number" class="mr-lg-3"/>
<div class="small d-lg-inline-block">Date: <span class="text-muted" t-field="i.date_invoice"/></div>
</div>
</td>
<td id="product_name"><span t-field="line.name"/></td>
<td>
<div id="quote_qty">
<span t-field="line.product_uom_qty"/>
<span t-field="line.product_uom" groups="uom.group_uom"/>
<span t-if="i.state == 'paid'" class="small text-success orders_label_text_align"><i class="fa fa-fw fa-check"/> <b>Paid</b></span>
<span t-else="" class="small text-info orders_label_text_align"><i class="fa fa-fw fa-clock-o"/> <b>Waiting Payment</b></span>
</a>
</t>
</ul>
<t t-if="invoices2">
<strong class="text-muted d-block mb-1">Invoices</strong>
<div>
<t t-foreach="invoices" t-as="i">
<t t-set="report_url" t-value="i.get_portal_url(report_type='pdf', download=True)"/>
<div>
<a t-att-href="report_url"><span class="fa fa-download" role="img" aria-label="Download" title="Download"/></a>
<a t-att-href="report_url"><span t-esc="i.number"/></a>
<span class="text-muted" t-field="i.date_invoice"/>
<t t-if="i.state == 'paid'">
<span class="badge badge-success orders_label_text_align"><i class="fa fa-fw fa-check"/> Paid</span>
</t>
<t t-if="i.state != 'paid'">
<span class="badge badge-info orders_label_text_align"><i class="fa fa-fw fa-clock-o"/> Waiting Payment</span>
</t>
</div>
</td>
<td t-attf-class="text-right {{ 'd-none d-sm-table-cell' if report_type == 'html' else '' }}">
<div
t-field="line.price_unit"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'
t-att-style="line.discount and 'text-decoration: line-through' or None"
t-att-class="(line.discount and 'text-danger' or '') + ' text-right'"
/>
<div t-if="line.discount">
<t t-esc="(1-line.discount / 100.0) * line.price_unit" t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/>
</div>
</td>
<td t-if="display_discount">
<strong t-if="line.discount" class="text-info text-right">
<t t-esc="((line.discount % 1) and '%s' or '%d') % line.discount"/>% discount
</strong>
</td>
<td t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<span t-esc="', '.join(map(lambda x: (x.description or x.name), line.tax_id))"/>
</td>
</t>
</div>
</t>
</div>
</div>
</div>
<section id="details" style="page-break-inside: auto;">
<h3 id="details">Details</h3>
<t t-set="display_discount" t-value="True in [line.discount > 0 for line in sale_order.order_line]"/>
<table class="table table-sm" id="sales_order_table">
<thead class="bg-100">
<tr>
<t t-set="colspan" t-value="7"/>
<th class="d-none d-xl-table-cell"></th>
<th class="text-left">Products</th>
<th class="text-right">Quantity</th>
<th t-attf-class="text-right {{ 'd-none d-sm-table-cell' if report_type == 'html' else '' }}">Unit Price</th>
<th t-if="display_discount" class="text-left">
<span>Discount</span>
<t t-set="colspan" t-value="colspan+1"/>
</th>
<th t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">Taxes</th>
<th class="text-right" >
<span groups="account.group_show_line_subtotals_tax_excluded">Amount</span>
<span groups="account.group_show_line_subtotals_tax_included">Total Price</span>
</th>
</tr>
</thead>
<tbody class="sale_tbody">
<t t-set="current_subtotal" t-value="0"/>
<t t-foreach="sale_order.order_line" t-as="line">
<t t-set="current_subtotal" t-value="current_subtotal + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
<t t-set="current_subtotal" t-value="current_subtotal + line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
<tr t-attf-class="{{ 'o_is_' + line.display_type if line.display_type else '' }}">
<t t-if="not line.display_type">
<td class="text-center d-none d-xl-table-cell" style="height:48px; vertical-align: middle">
<span t-field="line.product_image" t-options="{'widget': 'image', 'class': 'rounded', 'style':'max-width: 48px;max-height:48px'}" />
</td>
<td id="product_name"><span t-field="line.name"/></td>
<td class="text-right">
<div id="quote_qty">
<span t-field="line.product_uom_qty"/>
<span t-field="line.product_uom" groups="uom.group_uom"/>
</div>
</td>
<td t-attf-class="text-right {{ 'd-none d-sm-table-cell' if report_type == 'html' else '' }}">
<div
t-field="line.price_unit"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'
t-att-style="line.discount and 'text-decoration: line-through' or None"
t-att-class="(line.discount and 'text-danger' or '') + ' text-right'"
/>
<div t-if="line.discount">
<t t-esc="(1-line.discount / 100.0) * line.price_unit" t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/>
</div>
</td>
<td t-if="display_discount" class="text-left">
<strong t-if="line.discount" class="text-info">
<t t-esc="((line.discount % 1) and '%s' or '%d') % line.discount"/>% discount
</strong>
</td>
<td t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<span t-esc="', '.join(map(lambda x: (x.description or x.name), line.tax_id))"/>
</td>
<td class="text-right">
<span t-field="line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
<span t-field="line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
</td>
</t>
<t t-if="line.display_type == 'line_section'">
<td t-att-colspan="colspan">
<span t-field="line.name"/>
</td>
<t t-set="current_section" t-value="line"/>
<t t-set="current_subtotal" t-value="0"/>
</t>
<t t-if="line.display_type == 'line_note'">
<td t-att-colspan="colspan">
<span t-field="line.name"/>
</td>
</t>
</tr>
<t t-if="current_section and (line_last or sale_order.order_line[line_index+1].display_type == 'line_section')">
<tr class="is-subtotal text-right">
<td t-att-colspan="colspan">
<strong class="mr16">Subtotal</strong>
<span
t-esc="current_subtotal"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'
/>
</td>
</tr>
</t>
</t>
</tbody>
</table>
<div id="total" class="row" name="total" style="page-break-inside: avoid;">
<div t-attf-class="#{'col-4' if report_type != 'html' else 'col-sm-7 col-md-5'} ml-auto">
<table class="table table-sm">
<tr class="border-black" style="border-bottom:1px solid #dddddd;">
<td><strong>Subtotal</strong></td>
<td class="text-right">
<span t-field="line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
<span t-field="line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
</td>
</t>
<t t-if="line.display_type == 'line_section'">
<td t-att-colspan="colspan">
<span t-field="line.name"/>
</td>
<t t-set="current_section" t-value="line"/>
<t t-set="current_subtotal" t-value="0"/>
</t>
<t t-if="line.display_type == 'line_note'">
<td t-att-colspan="colspan">
<span t-field="line.name"/>
</td>
</t>
</tr>
<t t-if="current_section and (line_last or sale_order.order_line[line_index+1].display_type == 'line_section')">
<tr class="is-subtotal text-right">
<td t-att-colspan="colspan">
<strong class="mr16">Subtotal</strong>
<span
t-esc="current_subtotal"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'
data-id="total_amount"
t-field="sale_order.amount_untaxed"
t-options='{"widget": "monetary","display_currency": sale_order.pricelist_id.currency_id}'
/>
</td>
</tr>
</t>
</t>
</tbody>
</table>
<div id="total" class="row" name="total" style="page-break-inside: avoid;">
<div t-attf-class="#{'col-4' if report_type != 'html' else 'col-sm-7 col-md-5'} ml-auto">
<table class="table table-sm">
<tr class="border-black" style="border-bottom:1px solid #dddddd;">
<td><strong>Subtotal</strong></td>
<td class="text-right">
<span
data-id="total_amount"
t-field="sale_order.amount_untaxed"
t-options='{"widget": "monetary","display_currency": sale_order.pricelist_id.currency_id}'
/>
</td>
</tr>
<t t-foreach="sale_order.amount_by_group" t-as="amount_by_group">
<tr style="border-bottom:1px solid #dddddd;">
<t t-if="amount_by_group[3] == 1 and sale_order.amount_untaxed == amount_by_group[2]">
<td>
<span t-esc="amount_by_group[0]"/>
<span>&amp;nbsp;<span>on</span>&amp;nbsp;<t t-esc="amount_by_group[2]" t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/></span>
</td>
<td class="text-right">
<span t-esc="amount_by_group[1]"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/>
</td>
</t>
<t t-else ="">
<td>
<span t-esc="amount_by_group[0]"/>
</td>
<td class="text-right">
<span t-esc="amount_by_group[1]"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/>
</td>
</t>
<t t-foreach="sale_order.amount_by_group" t-as="amount_by_group">
<tr style="border-bottom:1px solid #dddddd;">
<t t-if="amount_by_group[3] == 1 and sale_order.amount_untaxed == amount_by_group[2]">
<td>
<span t-esc="amount_by_group[0]"/>
<span>&amp;nbsp;<span>on</span>&amp;nbsp;<t t-esc="amount_by_group[2]" t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/></span>
</td>
<td class="text-right">
<span t-esc="amount_by_group[1]"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/>
</td>
</t>
<t t-else ="">
<td>
<span t-esc="amount_by_group[0]"/>
</td>
<td class="text-right">
<span t-esc="amount_by_group[1]"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/>
</td>
</t>
</tr>
</t>
<tr class="border-black">
<td><strong>Total</strong></td>
<td class="text-right">
<span data-id="total_amount" t-field="sale_order.amount_total" t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/>
</td>
</tr>
</t>
<tr class="border-black">
<td><strong>Total</strong></td>
<td class="text-right">
<span data-id="total_amount" t-field="sale_order.amount_total" t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/>
</td>
</tr>
</table>
</table>
</div>
</div>
</div>
</section>
</section>
<section id="terms" class="container" t-if="sale_order.note">
<h2 class="o_page_header">Terms &amp; Conditions</h2>
<p t-field="sale_order.note"/>
</section>
<section t-if="sale_order.signature" id="signature" name="Signature">
<div class="row mt64" name="signature">
<div class="offset-8 col-4">
<strong>Signature</strong>
</div>
<div class="offset-8 col-4">
<img t-att-src="'data:image/png;base64,%s' % to_text(sale_order.signature)" style="max-height: 4cm; max-width: 8cm;"/>
</div>
<div class="offset-8 col-4 text-center">
<p t-field="sale_order.signed_by"/>
</div>
</div>
</section>
<section t-if="sale_order.signature" id="signature" name="Signature">
<div class="row mt-4" name="signature">
<div class="offset-8 col-4">
<strong>Signature</strong>
</div>
<div class="offset-8 col-4">
<img t-att-src="'data:image/png;base64,%s' % to_text(sale_order.signature)" style="max-height: 4cm; max-width: 8cm;"/>
</div>
<div class="offset-8 col-4 text-center">
<p t-field="sale_order.signed_by"/>
</div>
</div>
</section>
<section id="terms" class="mt-5" t-if="sale_order.note">
<h3 class="">Terms &amp; Conditions</h3>
<hr class="mt-0 mb-1"/>
<em t-field="sale_order.note"/>
</section>
</div>
</template>
</odoo>
@@ -30,9 +30,9 @@
<xpath expr="//section[@id='signature']" position="after">
<t t-if="any([(not option.line_id) for option in sale_order.sale_order_option_ids])">
<section>
<h1 class="o_page_header">Optional Products</h1>
<h3>Optional Products</h3>
<t t-set="display_discount" t-value="True in [option.discount for option in sale_order.sale_order_option_ids]"/>
<table class="table table-hover">
<table class="table table-sm">
<thead>
<tr>
<th class="text-left">Product</th>
@@ -185,9 +185,9 @@
<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="portal.portal_layout" priority="15">
<template id="portal_my_home_menu_lead" name="Portal layout : lead menu entry" inherit_id="portal.portal_breadcrumbs" priority="15">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'lead' or lead" class="breadcrumb-item">
<li t-if="page_name == 'lead' or lead" t-attf-class="breadcrumb-item #{'active ' if not lead else ''}">
<a t-if="lead" t-attf-href="/my/leads?{{ keep_query() }}">
My Leads
</a>
@@ -195,10 +195,10 @@
My Leads
</t>
</li>
<li t-if="lead" class="breadcrumb-item">
<li t-if="lead" class="breadcrumb-item active">
<span t-field="lead.name"/>
</li>
<li t-if="page_name == 'opportunity' or opportunity" class="breadcrumb-item">
<li t-if="page_name == 'opportunity' or opportunity" t-attf-class="breadcrumb-item #{'active ' if not opportunity else ''}">
<a t-if="opportunity" t-attf-href="/my/opportunities?{{ keep_query() }}">
My Opportunities
</a>
@@ -206,22 +206,24 @@
My Opportunities
</t>
</li>
<li t-if="opportunity" class="breadcrumb-item">
<li t-if="opportunity" class="breadcrumb-item active">
<span t-field="opportunity.name"/>
</li>
</xpath>
</template>
<template id="portal_my_home_lead" name="Portal My Home : lead entries" inherit_id="portal.portal_my_home" priority="15">
<xpath expr="//ul[hasclass('o_portal_docs')]" position="inside">
<li t-if="lead_count" class="list-group-item">
<span class="badge badge-secondary badge-pill float-right" t-esc="lead_count"/>
<a href="/my/leads">My Leads</a>
</li>
<li class="list-group-item">
<span class="badge badge-secondary badge-pill float-right" t-esc="opp_count"/>
<a href="/my/opportunities">My Opportunities</a>
</li>
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="lead_count" t-call="portal.portal_docs_entry">
<t t-set="title">My Leads</t>
<t t-set="url" t-value="'/my/leads'"/>
<t t-set="count" t-value="lead_count"/>
</t>
<t t-call="portal.portal_docs_entry">
<t t-set="title">My Opportunities</t>
<t t-set="url" t-value="'/my/opportunities'"/>
<t t-set="count" t-value="opp_count"/>
</t>
</xpath>
</template>
@@ -233,38 +235,41 @@
<div t-if="not leads" class="alert alert-warning mt8" role="alert">
There are no leads.
</div>
<div t-if="leads" class="card">
<table class="table table-hover">
<thead>
<tr class="active">
<th class="col-2">Date</th>
<th class="col-5">Name</th>
<th>Contact Name</th>
</tr>
</thead>
<tbody>
<tr t-foreach="leads" t-as="lead">
<td><span t-field="lead.create_date" t-options='{"widget": "date"}' /></td>
<td>
<a t-attf-href="/my/lead/#{lead.id}"><span t-field="lead.name"/></a>
</td>
<td><span t-field="lead.contact_name" /></td>
</tr>
</tbody>
</table>
</div>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="website.pager"/>
</div>
<t t-if="leads" t-call="portal.portal_table">
<thead>
<tr>
<th>Date</th>
<th class="w-75">Name</th>
<th>Contact Name</th>
</tr>
</thead>
<tbody>
<tr t-foreach="leads" t-as="lead">
<td><span t-field="lead.create_date" t-options='{"widget": "date"}' /></td>
<td>
<a t-attf-href="/my/lead/#{lead.id}"><span t-field="lead.name"/></a>
</td>
<td><span t-field="lead.contact_name" /></td>
</tr>
</tbody>
</t>
</t>
</template>
<template id="portal_my_opportunities" name="My Opportunities">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">My Opportunities</t>
<li class="float-left"><button t-if="request.env.user.partner_id.grade_id or request.env.user.commercial_partner_id.grade_id" name='new_opp' data-toggle="modal" data-target=".modal_new_opp" class="btn btn-secondary navbar-btn ml16" title="Add an opportunity" aria-label="Add an opportunity"><i class="fa fa-plus"/></button></li>
<div class="form-inline ml-lg-4" t-if="request.env.user.partner_id.grade_id or request.env.user.commercial_partner_id.grade_id">
<button class="btn btn-success btn-sm" name='new_opp' data-toggle="modal" data-target=".modal_new_opp" title="Add an opportunity" aria-label="Add an opportunity">
<i class="fa fa-plus"/> Create New
</button>
</div>
</t>
<div class="modal fade modal_new_opp" role="form">
<div class="modal-dialog">
<form method="POST" class="modal-content js_website_submit_form new_opp_form">
@@ -299,37 +304,32 @@
There are no opportunities.
</div>
</t>
<div class="card" t-if="opportunities">
<table class="table table-hover">
<thead>
<tr class="active">
<th class="col-2">Date</th>
<th class="col-lg-4">Name</th>
<th class="col-lg-2">Expected</th>
<th>Contact Name</th>
<th>Stage</th>
</tr>
</thead>
<tbody>
<tr t-foreach="opportunities" t-as="opp">
<td><span t-field="opp.create_date" t-options='{"widget": "date"}' /></td>
<td>
<a t-attf-href="/my/opportunity/#{opp.id}"><span t-field="opp.name"/></a>
</td>
<td>
<span class="text-nowrap" t-esc="opp.planned_revenue" t-options="{'widget': 'monetary', 'display_currency': opp.company_currency}"/> at <span t-field="opp.probability" />%
</td>
<td><span t-field="opp.contact_name" /></td>
<td>
<span class="badge badge-primary" title="Current stage of the opportunity" t-esc="opp.stage_id.name" />
</td>
</tr>
</tbody>
</table>
</div>
<div t-if="pager" class="o_portal_pager text-center">
<t t-call="website.pager"/>
</div>
<t t-if="opportunities" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Date</th>
<th class="w-50">Name</th>
<th>Contact</th>
<th>Expected</th>
<th>Stage</th>
</tr>
</thead>
<tbody>
<tr t-foreach="opportunities" t-as="opp">
<td><span t-field="opp.create_date" t-options='{"widget": "date"}' /></td>
<td>
<a t-attf-href="/my/opportunity/#{opp.id}"><span t-field="opp.name"/></a>
</td>
<td><span t-field="opp.contact_name" /></td>
<td>
<span class="text-nowrap" t-esc="opp.planned_revenue" t-options="{'widget': 'monetary', 'display_currency': opp.company_currency}"/> at <span t-field="opp.probability" />%
</td>
<td>
<span class="badge badge-info badge-pill" title="Current stage of the opportunity" t-esc="opp.stage_id.name" />
</td>
</tr>
</tbody>
</t>
</t>
</template>
@@ -501,42 +501,224 @@
<template id="portal_my_opportunity" name="My Opportunity">
<t t-call="portal.portal_layout">
<div class="card">
<div class="card-header">
<div class="row">
<div class="col-lg-12">
<h4 style="display:inline-block">
Opportunity - <span t-field="opportunity.name"/>
</h4>
<span class="btn-group float-right" role="group">
<t t-foreach="stages" t-as="stage">
<button type="button" t-att-data="stage.id" t-att-opp="opportunity.id" t-attf-class="float-right btn opp-stage-button #{'btn-secondary' if opportunity.stage_id.name != stage.name else 'disabled btn-primary'}">
<t t-set="wrapwrap_classes" t-value="'o_portal_bg_dark'"/>
<t t-call="portal.portal_record_layout">
<t t-set="card_header">
<div class="row no-gutters">
<div class="col-md">
<h5 class="mb-2 mb-md-0">
<small class="text-muted">Opportunity - </small>
<span t-field="opportunity.name"/>
</h5>
</div>
<div class="col-md text-md-right">
<div class="d-inline-block">
<small class="mr-2"><b>Stage:</b></small>
<div t-foreach="stages" t-as="stage" class="float-right">
<button type="button" t-att-data="stage.id" t-att-opp="opportunity.id" t-attf-class="btn btn-sm px-2 opp-stage-button #{'btn-secondary' if opportunity.stage_id.name != stage.name else 'btn-primary disabled'}">
<span t-field="stage.name"/>
</button>
</t>
</span>
<i t-if="not stage_first" class="fa fa-chevron-right ml-1 mr-2 small" style="opacity: 0.5"/>
</div>
</div>
</div>
</div>
</t>
<t t-set="card_body">
<div class="row">
<div class="col-lg-4">
<strong><span class="text-nowrap" t-esc="opportunity.planned_revenue" t-options="{'widget': 'monetary', 'display_currency': opportunity.company_currency}"/> at <span t-field="opportunity.probability"/>%</strong>
<div class="col-lg-5 mb-4 mb-lg-0">
<div class="border-bottom d-flex justify-content-between py-2 mb-3 align-items-center">
<h5 class="mb-0">
<span class="text-nowrap" t-esc="opportunity.planned_revenue" t-options="{'widget': 'monetary', 'display_currency': opportunity.company_currency}"/> at
<span class="badge badge-info badge-pill"><span t-field="opportunity.probability"/>%</span>
</h5>
<button type="button" data-toggle="modal" data-target=".modal_edit_opp" class="btn btn-link btn-sm"><i class="fa fa-pencil mr-1"/>Edit</button>
</div>
<div class="row mb-2">
<strong class="col-12 col-sm-4">Deadline</strong>
<div class="col">
<span t-if="opportunity.date_deadline" t-field="opportunity.date_deadline"/>
<span t-else="" class="text-muted"> - </span>
</div>
</div>
<div class="row mb-2">
<strong class="col-12 col-sm-4">Priority</strong>
<div class="col">
<span class="" title="Rating" role="img" t-attf-aria-label="Rating: #{opportunity.priority} on 4">
<t t-foreach="range(1, 4)" t-as="i">
<span t-attf-class="fa text-warning fa-lg fa-star#{'' if i &lt;= int(opportunity.priority) else '-o'}" role="img" t-att-aria-label="'Star %d of 3' % i"/>
</t>
</span>
</div>
</div>
<div class="row">
<strong class="col-12 col-sm-4">Next Activity</strong>
<div class="col" t-if="user_activity">
<span t-field="user_activity.activity_type_id"/>
<span t-if="user_activity.date_deadline">&#160;on&#160;</span>
<span t-field="user_activity.date_deadline"/>
<em class="d-block" t-field="user_activity.summary"/>
</div>
<div class="col" t-else="">
<span class="text-muted"> - </span>
</div>
</div>
</div>
<div class="col-lg-4">
<strong>Expected Closing: <span t-field="opportunity.date_deadline" /></strong>
<div class="col-lg-6 offset-lg-1 col-xl-5 offset-xl-2">
<div class="d-flex justify-content-between py-2 mb-3 border-bottom align-items-center">
<h5 class="card-title mb-0">Contact</h5>
<button type="button" data-toggle="modal" data-target=".modal_edit_contact" class="btn btn-link btn-sm"><i class="fa fa-pencil mr-1"/>Edit</button>
</div>
<div class="row mb-3" t-if="opportunity.partner_name or opportunity.email_from or opportunity.contact_name">
<strong class="col-12 col-sm-3">Customer</strong>
<div class="col">
<div>
<span class="fa fa-user fa-fw" role="img" aria-label="User" title="User"/>
<strong class="font-italic" t-if="opportunity.partner_name" itemprop="name" t-field="opportunity.partner_name" />
<strong class="font-italic" t-else="" itemprop="name" t-field="opportunity.contact_name" />
</div>
<div>
<span class="fa fa-phone fa-fw" role="img" aria-label="Phone" title="Phone"/>
<span t-if="opportunity.phone" itemprop="telephone" t-field="opportunity.phone"/>
<span t-else="" class="text-muted"> - </span>
</div>
<div>
<span class="fa fa-mobile fa-fw" role="img" aria-label="Mobile" title="Mobile"/>
<span t-if="opportunity.mobile" itemprop="mobile" t-field="opportunity.mobile"/>
<span t-else="" class="text-muted"> - </span>
</div>
<div>
<span class="fa fa-envelope fa-fw" role="img" aria-label="Email" title="Email"/>
<span t-if="opportunity.email_from" itemprop="email" t-field="opportunity.email_from"/>
<span t-else="" class="text-muted"> - </span>
</div>
</div>
</div>
<div class="row">
<strong class="col-12 col-sm-3">Address</strong>
<address class="col d-flex align-items-baseline mb-0">
<span class="fa fa-map-marker fa-fw" role="img" aria-label="Address" title="Address"/>
<div>
<div t-if="opportunity.street"><span t-field="opportunity.street"/></div>
<span t-else="" class="text-muted"> - </span>
<div t-if="opportunity.street2"><span t-field="opportunity.street2"/></div>
<div t-if="opportunity.city or opportunity.zip">
<span t-field="opportunity.city"/> <span t-field="opportunity.zip"/>
</div>
<div t-if="opportunity.state_id or country_id">
<span t-field="opportunity.state_id"/> <span t-field="opportunity.country_id"/>
</div>
</div>
</address>
</div>
</div>
<div class="col-lg-4">
<span class="float-right" title="Rating" role="img" t-attf-aria-label="Rating: #{opportunity.priority} on 4">
<t t-foreach="range(1, 4)" t-as="i">
<span t-attf-class="fa fa-lg fa-star#{'' if i &lt;= int(opportunity.priority) else '-o'}" role="img" t-att-aria-label="'Star %d of 3' % i"/>
</t>
</span>
</div>
</div>
</div>
<div class="card-body">
<div class="col-lg-6">
<!-- ==== MODALS ==== -->
<div>
<button type="button" data-toggle="modal" data-target=".modal_edit_contact" class="btn btn-primary" style="margin-bottom: 10px;">Edit Contact</button>
<div role="dialog" class="modal fade modal_edit_opp">
<div class="modal-dialog">
<form method="POST" class="js_accept_json modal-content js_website_submit_form edit_opp_form">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input type="hidden" name="opportunity_id" class="opportunity_id" t-att-value="opportunity.id"/>
<header class="modal-header">
<h4 class="modal-title">Edit Opportunity</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">&amp;times;</button>
</header>
<main class="modal-body" id="sign-dialog">
<div class="form-group">
<div class="form-row align-items-center">
<div class="col-auto flex-grow-1">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text"><span class="text-nowrap" t-esc="opportunity.company_currency.symbol"/></div>
</div>
<input type="text" name="planned_revenue" class="form-control planned_revenue" t-att-value="opportunity.planned_revenue" placeholder="Planned Revenue"/>
</div>
</div>
<div class="col-auto">at</div>
<div class="col-auto">
<div class="input-group">
<input type="text" name="probability" class="form-control probability" t-att-value="opportunity.probability" placeholder="Probability"/>
<div class="input-group-append">
<div class="input-group-text">%</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<label>Priority:</label>
<div class="input-group">
<label class="radio-inline">
<input type="radio" name="PriorityRadioOptions" value="0" t-att-checked="opportunity.priority not in ['1','2','3']" aria-label="Rating: 0 on 3" title="Rating: 0 on 3"/>
<i class="ml-1 fa fa-star-o"></i>
</label>
<label class="radio-inline ml-2">
<input type="radio" name="PriorityRadioOptions" value="1" t-att-checked="opportunity.priority == '1'" aria-label="Rating: 1 on 3" title="Rating: 1 on 3"/>
<i class="ml-1 fa text-warning fa-star"></i>
</label>
<label class="radio-inline ml-2">
<input type="radio" name="PriorityRadioOptions" value="2" t-att-checked="opportunity.priority == '2'" aria-label="Rating: 2 on 3" title="Rating: 2 on 3"/>
<i class="ml-1 fa text-warning fa-star"></i>
<i class="ml-1 fa text-warning fa-star"></i>
</label>
<label class="radio-inline ml-2">
<input type="radio" name="PriorityRadioOptions" value="3" t-att-checked="opportunity.priority == '3'" aria-label="Rating: 3 on 3" title="Rating: 3 on 3"/>
<i class="ml-1 fa text-warning fa-star"></i>
<i class="ml-1 fa text-warning fa-star"></i>
<i class="ml-1 fa text-warning fa-star"></i>
</label>
</div>
</div>
<div class="col-md-6">
<label>Deadline:</label>
<div class="input-group date">
<input type="text" name="date_deadline" t-att-value="opportunity.date_deadline" class="form-control date_deadline" data-date-format="YYYY-MM-DD" t-att-name="prefix" placeholder="YYYY-MM-DD"/>
<div class="input-group-append">
<span class="input-group-text">
<span class="fa fa-calendar" role="img" aria-label="Calendar"></span>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-form-label" for="next_activity">Next Activity</label>
<select class="form-control next_activity" name="next_activity">
<t t-foreach="activity_types" t-as="activity_type">
<option t-att-data="activity_type.id" t-att-selected="activity_type.id == user_activity.activity_type_id.id" t-att-name="activity_type.name" t-att-summary="activity_type.summary"><t t-esc="activity_type.name"/></option>
</t>
</select>
</div>
<div class="form-group">
<label class="col-form-label" for="activity_summary">Details Next Activity</label>
<textarea row="3" name="activity_summary" class="form-control activity_summary"><t t-esc="user_activity.summary"/></textarea>
</div>
<div class="form-group">
<label class="col-form-label" for="activity_date_deadline">Next Activity Date</label>
<div class="input-group date">
<input type="text" name="activity_date_deadline" t-att-value="user_activity.date_deadline" class="form-control activity_date_deadline" data-date-format="YYYY-MM-DD" t-att-name="prefix" placeholder="YYYY-MM-DD"/>
<div class="input-group-append">
<span class="input-group-text">
<span class="fa fa-calendar" role="img" aria-label="Calendar" title="Calendar"></span>
</span>
</div>
</div>
</div>
</main>
<footer class="modal-footer">
<button t-attf-class="btn btn-primary edit_opp_confirm">Confirm</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</footer>
</form>
</div>
</div>
<div role="dialog" class="modal fade modal_edit_contact">
<div class="modal-dialog">
<form method="POST" class="js_accept_json modal-content js_website_submit_form edit_contact_form">
@@ -588,7 +770,7 @@
<option>States...</option>
<t t-foreach="states or []" t-as="state">
<option class="state" t-att-value="state.id" t-att-country="state.country_id.id" t-att-selected="state.id == opportunity.state_id.id">
<t t-esc="state.name" />
<t t-esc="state.name"/>
</option>
</t>
</select>
@@ -603,7 +785,7 @@
<option>Countries...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == opportunity.country_id.id">
<t t-esc="country.name" />
<t t-esc="country.name"/>
</option>
</t>
</select>
@@ -617,153 +799,14 @@
</div>
</div>
</div>
<div class="row" t-if="opportunity.partner_name or opportunity.email_from or opportunity.contact_name">
<label class="col-4">Customer</label>
<address class="col-8">
<div>
<span t-if="opportunity.partner_name" itemprop="name" t-field="opportunity.partner_name" />
<span t-if="not opportunity.partner_name" itemprop="name" t-field="opportunity.contact_name" />
</div>
<div t-if="opportunity.phone">
<span class="fa fa-phone" role="img" aria-label="Phone" title="Phone"/> <span itemprop="telephone" t-field="opportunity.phone" />
</div>
<div t-if="opportunity.mobile">
<span class="fa fa-mobile" role="img" aria-label="Mobile" title="Mobile"/> <span itemprop="mobile" t-field="opportunity.mobile" />
</div>
<div t-if="opportunity.email_from">
<span class="fa fa-envelope" role="img" aria-label="Email" title="Email"/> <span itemprop="email" t-field="opportunity.email_from" />
</div>
</address>
</div>
<div class="row" t-if="opportunity.street or opportunity.street2 or opportunity.city or opportunity.state_id or opportunity.country_id">
<label class="col-4">Address</label>
<address class="col-8">
<div t-if="opportunity.street"><span t-field="opportunity.street"/></div>
<div t-if="opportunity.street2"><span t-field="opportunity.street2"/></div>
<div t-if="opportunity.city or opportunity.zip">
<span t-field="opportunity.city"/> <span t-field="opportunity.zip"/>
</div>
<div t-if="opportunity.state_id or country_id">
<span t-field="opportunity.state_id"/> <span t-field="opportunity.country_id"/>
</div>
</address>
</div>
<!-- === / MODALS === -->
</div>
<div class="col-lg-6">
<div>
<button type="button" data-toggle="modal" data-target=".modal_edit_opp" class="btn btn-primary" style="margin-bottom: 10px;">Edit Opportunity</button>
<div role="dialog" class="modal fade modal_edit_opp">
<div class="modal-dialog">
<form method="POST" class="js_accept_json modal-content js_website_submit_form edit_opp_form">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input type="hidden" name="opportunity_id" class="opportunity_id" t-att-value="opportunity.id"/>
<header class="modal-header">
<h4 class="modal-title">Edit Opportunity</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">&amp;times;</button>
</header>
<main class="modal-body" id="sign-dialog">
<div class="form-group">
<div class="row">
<div class="col-md-6">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text"><span class="text-nowrap" t-esc="opportunity.company_currency.symbol"/></div>
</div>
<input type="text" name="planned_revenue" class="form-control planned_revenue" t-att-value="opportunity.planned_revenue" placeholder="Planned Revenue"/>
</div>
</div>
<div class="col-md-1">
<span>at </span>
</div>
<div class="col-md-5">
<div class="input-group">
<input type="text" name="probability" class="form-control probability" t-att-value="opportunity.probability" placeholder="Probability"/>
<div class="input-group-append">
<div class="input-group-text">%</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<label>Priority: </label>
<div class="input-group">
<label class="radio-inline">
<input type="radio" name="PriorityRadioOptions" value="0" t-att-checked="opportunity.priority not in ['1','2','3']" aria-label="Rating: 0 on 3" title="Rating: 0 on 3"/><i class="fa fa-star-o"></i>
</label>
<label class="radio-inline">
<input type="radio" name="PriorityRadioOptions" value="1" t-att-checked="opportunity.priority == '1'" aria-label="Rating: 1 on 3" title="Rating: 1 on 3"/><i class="fa fa-star"></i>
</label>
<label class="radio-inline">
<input type="radio" name="PriorityRadioOptions" value="2" t-att-checked="opportunity.priority == '2'" aria-label="Rating: 2 on 3" title="Rating: 2 on 3"/><i class="fa fa-star"></i><i class="fa fa-star"></i>
</label>
<label class="radio-inline">
<input type="radio" name="PriorityRadioOptions" value="3" t-att-checked="opportunity.priority == '3'" aria-label="Rating: 3 on 3" title="Rating: 3 on 3"/><i class="fa fa-star"></i><i class="fa fa-star"></i><i class="fa fa-star"></i>
</label>
</div>
</div>
<div class="col-md-6">
<label>Deadline: </label>
<div class='input-group date'>
<input type="text" name="date_deadline" t-att-value="opportunity.date_deadline" class="form-control date_deadline" data-date-format="YYYY-MM-DD" t-att-name="prefix" placeholder="YYYY-MM-DD" />
<div class="input-group-append">
<span class="input-group-text"><span class="fa fa-calendar" role="img" aria-label="Calendar"></span></span>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-form-label" for="next_activity">Next Activity</label>
<select class="form-control next_activity" name="next_activity">
<t t-foreach="activity_types" t-as="activity_type">
<option t-att-data="activity_type.id" t-att-selected="activity_type.id == user_activity.activity_type_id.id" t-att-name="activity_type.name" t-att-days="activity_type.days" t-att-summary="activity_type.summary"><t t-esc="activity_type.name"/></option>
</t>
</select>
</div>
<div class="form-group">
<label class="col-form-label" for="activity_summary">Details Next Activity</label>
<textarea row="3" name="activity_summary" class="form-control activity_summary"><t t-esc="user_activity.summary"/></textarea>
</div>
<div class="form-group">
<label class="col-form-label" for="activity_date_deadline">Next Activity Date</label>
<div class='input-group date'>
<input type="text" name="activity_date_deadline" t-att-value="user_activity.date_deadline" class="form-control activity_date_deadline" data-date-format="YYYY-MM-DD" t-att-name="prefix" placeholder="YYYY-MM-DD" />
<div class="input-group-append">
<span class="input-group-text"><span class="fa fa-calendar" role="img" aria-label="Calendar" title="Calendar"></span></span>
</div>
</div>
</div>
</main>
<footer class="modal-footer">
<button t-attf-class="btn btn-primary edit_opp_confirm">Confirm</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</footer>
</form>
</div>
</div>
</div>
<div class="row" t-if="user_activity">
<label class="col-4">Next Activity</label>
<span class="col-8">
<span t-field="user_activity.activity_type_id"/>
<span t-if="user_activity.date_deadline">&#160;on&#160;</span>
<span t-field="user_activity.date_deadline"/>
</span>
</div>
<div class="row" t-if="user_activity">
<span class="col-8 offset-4" t-field="user_activity.summary"/>
</div>
</div>
</div>
</div>
<div class="row mt32">
<div class="col-lg-12">
<h4><strong>Message and communication history</strong></h4>
</div>
<div class="col-lg-10 offset-lg-1 mt16">
</t>
</t>
<div class="mt32">
<h4><strong>Message and communication history</strong></h4>
<div class="mt16">
<t t-call="portal.message_thread">
<t t-set="object" t-value="opportunity"/>
</t>
@@ -23,7 +23,7 @@
<div itemprop="address" itemscope="itemscope" itemtype="http://schema.org/PostalAddress">
<div t-if="address and 'address' in fields">
<i t-if="not options.get('no_marker')" class='fa fa-map-marker fa-fw' role="img" aria-label="Address" title="Address"/>
<span itemprop="streetAddress" t-raw="address.replace('\n', options.get('no_tag_br') and ', ' or ('&lt;br/&gt;%s' % ('' if options.get('no_marker') else '&amp;nbsp; &amp;nbsp; ')))"/>
<span itemprop="streetAddress" t-raw="address.replace('\n', options.get('no_tag_br') and ', ' or ('&lt;br/&gt;%s' % ('' if options.get('no_marker') else '')))"/>
</div>
<div t-if="city and 'city' in fields">
<i t-if="not options.get('no_marker')" class='fa fa-map-marker fa-fw' role="img" aria-label="Address" title="Address"/>