123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- <?xml version="1.0" encoding="utf-8"?>
- <odoo>
- <template id="frontend_layout" name="Main Frontend Layout" inherit_id="web.frontend_layout">
- <xpath expr="//div[@id='wrapwrap']" position="attributes">
- <attribute name="t-attf-class" add="#{request.env['res.lang']._lang_get_direction(request.env.lang) == 'rtl' and 'o_rtl' or ''}" separator=" "/>
- <attribute name="t-attf-class" add="#{'o_portal' if is_portal else ''}" separator=" "/>
- </xpath>
- <xpath expr="//div[@id='wrapwrap']/header/img" position="replace">
- <t t-cache="res_company">
- <nav class="navbar navbar-expand navbar-light bg-light">
- <div class="container">
- <a href="/" class="navbar-brand logo">
- <img t-att-src="'/logo.png?company=%s' % res_company.id" t-att-alt="'Logo of %s' % res_company.name" t-att-title="res_company.name"/>
- </a>
- <ul id="top_menu" class="nav navbar-nav ms-auto">
- <t t-call="portal.placeholder_user_sign_in">
- <t t-set="_item_class" t-value="'nav-item'"/>
- <t t-set="_link_class" t-value="'nav-link'"/>
- </t>
- <t t-call="portal.user_dropdown">
- <t t-set="_user_name" t-value="true"/>
- <t t-set="_item_class" t-value="'nav-item dropdown'"/>
- <t t-set="_link_class" t-value="'nav-link'"/>
- <t t-set="_dropdown_menu_class" t-value="'dropdown-menu-end'"/>
- </t>
- </ul>
- </div>
- </nav>
- </t>
- </xpath>
- <xpath expr="//div[@id='wrapwrap']/main/t[@t-out='0']" position="before">
- <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-out="o_portal_fullwidth_alert"/>
- </div>
- </div>
- </xpath>
- </template>
- <!-- Added by another template so that it can be disabled if needed -->
- <template id="footer_language_selector" inherit_id="portal.frontend_layout" name="Footer Language Selector">
- <xpath expr="//*[hasclass('o_footer_copyright_name')]" position="after">
- <t id="language_selector_call" t-call="portal.language_selector">
- <t t-set="_div_classes" t-value="(_div_classes or '') + ' dropup'"/>
- </t>
- </xpath>
- </template>
- <template id="language_selector" name="Language Selector">
- <t t-nocache="The query strings can change for the same page and the same rendering."
- t-nocache-no_text="no_text"
- t-nocache-_div_classes="_div_classes"
- t-nocache-_btn_class="_btn_class"
- t-nocache-_dropdown_menu_class="_dropdown_menu_class">
- <t t-set="active_lang" t-value="list(filter(lambda lg : lg[0] == lang, languages))[0]"/>
- <t t-set="language_selector_visible" t-value="len(languages) > 1"/>
- <div t-attf-class="js_language_selector #{_div_classes} d-print-none" t-if="language_selector_visible">
- <button t-attf-class="btn btn-sm btn-outline-secondary border-0 dropdown-toggle #{_btn_class}" type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
- <span t-if="not no_text"
- class="align-middle"
- t-esc="active_lang[2].split('/').pop()"/>
- </button>
- <div t-attf-class="dropdown-menu #{_dropdown_menu_class}" role="menu">
- <t t-foreach="languages" t-as="lg">
- <a t-att-href="url_for(request.httprequest.path + '?' + keep_query(), lang_code=lg[0])"
- t-attf-class="dropdown-item js_change_lang #{active_lang == lg and 'active'}"
- t-att-data-url_code="lg[1]">
- <span t-if="not no_text" t-esc="lg[2].split('/').pop()"/>
- </a>
- </t>
- </div>
- </div>
- </t>
- </template>
- <template id="user_dropdown" name="Portal User Dropdown">
- <t t-nocache="Each user is different regardless of the page visited."
- t-nocache-_avatar="_avatar"
- t-nocache-_icon="_icon"
- t-nocache-_icon_class="_icon_class"
- t-nocache-_user_name="_user_name"
- t-nocache-_user_name_class="_user_name_class"
- t-nocache-_item_class="_item_class"
- t-nocache-_link_class="_link_class"
- t-nocache-_dropdown_menu_class="_dropdown_menu_class">
- <t t-set="is_connected" t-value="not user_id._is_public()"/>
- <li t-if="is_connected" t-attf-class="#{_item_class} o_no_autohide_item">
- <a href="#" role="button" data-bs-toggle="dropdown" t-attf-class="dropdown-toggle #{_link_class}">
- <t t-if="_avatar">
- <t t-set="avatar_source" t-value="image_data_uri(user_id.avatar_256)"/>
- <img t-att-src="avatar_source" t-attf-class="rounded-circle o_object_fit_cover #{_avatar_class}" width="24" height="24" alt="" loading="eager"/>
- </t>
- <i t-if="_icon" t-attf-class="fa fa-1x fa-fw fa-user-circle-o #{_icon_class}"/>
- <span t-if="_user_name" t-attf-class="#{_user_name_class}" t-esc="user_id.name[:23] + '...' if user_id.name and len(user_id.name) > 25 else user_id.name"/>
- </a>
- <div t-attf-class="dropdown-menu js_usermenu #{_dropdown_menu_class}" role="menu">
- <a groups="base.group_user" href="/web" role="menuitem" class="dropdown-item ps-3" id="o_backend_user_dropdown_link">
- <i class="fa fa-fw fa-th me-1 small text-muted"/> Apps
- </a>
- <div id="o_logout_divider" class="dropdown-divider"/>
- <a t-attf-href="/web/session/logout?redirect=/" role="menuitem" id="o_logout" class="dropdown-item ps-3">
- <i class="fa fa-fw fa-sign-out me-1 small text-muted"/> Logout
- </a>
- </div>
- </li>
- </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 ms-1"><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">Details</li>
- </ol>
- </template>
- <template id="portal_back_in_edit_mode" name="Back to edit mode">
- <div t-ignore="true" class="text-center">
- <t t-if="custom_html" t-out="custom_html"/>
- <t t-else="">This is a preview of the customer portal.</t>
- <a t-att-href="backend_url"><i class="fa fa-arrow-right me-1"/>Back to edit mode</a>
- </div>
- <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
- </template>
- <template id="portal_layout" name="Portal Layout">
- <t t-call="portal.frontend_layout">
- <t t-set="is_portal" t-value="True"/>
- <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 g-0 border rounded">
- <div class="col-10">
- <t t-call="portal.portal_breadcrumbs"></t>
- </div>
- <div t-if="prev_record or next_record" class="col-2 flex-grow-0 text-center">
- <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 justify-content-between mt-4">
- <div t-attf-class="col-12 col-md col-lg-6">
- <t t-out="0"/>
- </div>
- <div id="o_my_sidebar" class="pt-3 pt-lg-0 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">
- <h4>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_portal_my_security mt-3">
- <h4>Account Security </h4>
- <hr class="mt-1 mb-1"/>
- <a href="/my/security"><i class="fa fa-pencil mx-1"/>Edit Security Settings</a>
- </div>
- </div>
- </div>
- </t>
- <t t-else="">
- <t t-out="0"/>
- </t>
- </div>
- </div>
- </t>
- </template>
- <template id="placeholder_user_sign_in" name="User Sign In Placeholder"/>
- <template id="user_sign_in" name="User Sign In" inherit_id="portal.placeholder_user_sign_in">
- <xpath expr="." position="inside">
- <li t-nocache="Profile session and user group can change unrelated to parent caches."
- t-nocache-_item_class="_item_class"
- t-nocache-_link_class="_link_class"
- groups="base.group_public" t-attf-class="#{_item_class} o_no_autohide_item">
- <a t-attf-href="/web/login" t-attf-class="#{_link_class}">Sign in<span t-if="request.session.profile_session" class="text-danger fa fa-circle"/></a>
- </li>
- </xpath>
- </template>
- <template id="portal_my_home" name="My Portal">
- <t t-call="portal.portal_layout">
- <t t-set="my_details" t-value="True"/>
- <div class="o_portal_my_home">
- <div class="oe_structure" id="oe_structure_portal_my_home_1"/>
- <h3>Documents</h3>
- <div class="o_portal_docs list-group">
- <div class="o_portal_doc_spinner spinner-border text-o-color-2 align-self-center mt-5"/>
- <p class="o_portal_no_doc_message d-none">No Documents to display</p>
- </div>
- </div>
- <div class="oe_structure" id="oe_structure_portal_my_home_2"/>
- </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 d-none">
- <t t-esc="title"/>
- <t t-if='count'>
- <span class="badge text-bg-secondary rounded-pill" t-esc="count"/>
- </t>
- <t t-elif="placeholder_count">
- <span class="badge text-bg-secondary rounded-pill" t-att-data-placeholder_count="placeholder_count">
- <i class="fa fa-spin fa-circle-o-notch"></i>
- </span>
- </t>
- </a>
- </template>
- <template id="portal_table" name="My Portal Table">
- <div t-attf-class="table-responsive border rounded border-top-0 #{classes if classes else ''}">
- <table class="table rounded mb-0 bg-white o_portal_my_doc_table">
- <t t-out="0"/>
- </table>
- </div>
- <div t-if="pager" class="o_portal_pager d-flex justify-content-center">
- <t t-call="portal.pager"/>
- </div>
- </template>
- <template id="portal_record_sidebar" name="My Portal Record Sidebar">
- <div t-attf-class="#{classes}">
- <div class="card bg-white mb-4 sticky-top" id="sidebar_content">
- <div t-if="title" class="card-body text-center pb-2 pt-3">
- <t t-out="title"/>
- </div>
- <t t-if="entries" t-out="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&utm_medium=portal" title="odoo"><img src="/web/static/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
- redirect the user to the beginning of document list, keeping query parameters.
- These 2 buttons can be prepended by a advanced search input, to activate it, search_input need
- to be initialized at 'True' and the content of the t-call is the list of li elements searchable.
- :param dict searchbar_sortings : containing the sort criteria like
- {'date': {'label': _('Newest'), 'order': 'create_date desc'}}
- :param string sortby : name of the sort criteria
- :param dict searchbar_filters : containing the filter criteria like
- {'open': {'label': _('In Progress'), 'domain': [('state', '=', 'open')]}}
- :param string filterby : name of the filter criteria
- :param default_url : the base url of the pages (like '/my/orders')
- :param boolean 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
- :param title : bavbar title
- :param classes : navbar classes
- -->
- <template id="portal_searchbar" name="Portal Search Bar">
- <nav t-attf-class="navbar navbar-light navbar-expand-lg border py-0 mb-2 o_portal_navbar {{classes if classes else ''}} {{'mt-3 rounded' if breadcrumbs_searchbar else 'border-top-0' }}">
- <!-- 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 me-auto" t-esc="title or 'No title'"/>
- <!-- Collapse button -->
- <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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 ms-auto p-0 mb-3 mb-lg-0 mt-1 mt-lg-0">
- <div t-if="searchbar_sortings">
- <span class="small me-1 navbar-text">Sort By:</span>
- <div class="btn-group">
- <button id="portal_searchbar_sortby" data-bs-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">
- <a t-att-href="request.httprequest.path + '?' + keep_query('*', sortby=option)"
- t-attf-class="dropdown-item#{sortby == option and ' active' or ''}">
- <span t-esc="searchbar_sortings[option].get('label')"/>
- </a>
- </t>
- </div>
- </div>
- </div>
- <div t-if="searchbar_filters" class="ms-lg-2">
- <span class="small me-1 navbar-text">Filter By:</span>
- <div class="btn-group">
- <button id="portal_searchbar_filters" data-bs-toggle="dropdown" class="btn btn-secondary btn-sm dropdown-toggle">
- <t t-esc="searchbar_filters.get(filterby,searchbar_filters.get('all')).get('label', 'All')"/>
- </button>
- <div class="dropdown-menu" aria-labelledby="portal_searchbar_filters">
- <t t-foreach="searchbar_filters" t-as="option">
- <a t-att-href="default_url + '?' + keep_query('*', filterby=option)"
- t-attf-class="dropdown-item#{filterby == option and ' active' or ''}">
- <span t-esc="searchbar_filters[option].get('label')"/>
- </a>
- </t>
- </div>
- </div>
- </div>
- <div t-if="searchbar_groupby" class="ms-lg-2">
- <span class="small me-1 navbar-text">Group By:</span>
- <div class="btn-group">
- <button id="portal_searchbar_groupby" data-bs-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">
- <a t-att-href="default_url + '?' + keep_query('*', groupby=option)"
- t-attf-class="dropdown-item#{groupby == option and ' active' or ''}">
- <span t-esc="searchbar_groupby[option].get('label')"/>
- </a>
- </t>
- </div>
- </div>
- </div>
- <t t-out="0"/>
- </div>
- <form t-if="searchbar_inputs" class="o_portal_search_panel ms-lg-4 col-xl-4 col-md-5">
- <div class="input-group input-group-sm w-100">
- <button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown"/>
- <div class="dropdown-menu" role="menu">
- <t t-foreach='searchbar_inputs' t-as='input'>
- <a t-att-href="'#' + input_value['input']"
- t-attf-class="dropdown-item#{search_in == input_value['input'] and ' active' or ''}">
- <span t-out="input_value['label']"/>
- </a>
- </t>
- </div>
- <input type="text" class="form-control form-control-sm" placeholder="Search" t-att-value='search' name="search"/>
- <button class="btn btn-secondary o_wait_lazy_js" type="submit">
- <span class="fa fa-search"/>
- </button>
- </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-out="card_header"/>
- </div>
- <div t-if="card_body" t-attf-class="card-body #{body_classes if body_classes else ''}">
- <t t-out="card_body"/>
- </div>
- </div>
- </template>
- <!--
- TODO adapt in master: remove the use of the "title" variable in this
- template (or rename the variable). Using it at controller level actually
- also controls the browser tab title, which makes no sense.
- -->
- <template id="portal_contact" name="Contact">
- <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 me-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 me-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 me-1"></div>
- <span t-esc="sales_user.city"/>
- </div>
- </div>
- </template>
- <template id="portal_my_details_fields">
- <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <div t-if="error_message" class="alert alert-danger" role="alert">
- <div class="col-lg-12">
- <t t-foreach="error_message" t-as="err"><t t-esc="err"/><br /></t>
- </div>
- </div>
- <div t-attf-class="mb-3 #{error.get('name') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label" for="name">Name</label>
- <input type="text" name="name" t-attf-class="form-control #{error.get('name') and 'is-invalid' or ''}" t-att-value="name or partner.name" />
- </div>
- <div t-attf-class="mb-3 #{error.get('email') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label" for="email">Email</label>
- <input type="email" name="email" t-attf-class="form-control #{error.get('email') and 'is-invalid' or ''}" t-att-value="email or partner.email" />
- </div>
- <div class="clearfix" />
- <div t-attf-class="mb-1 #{error.get('company_name') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label label-optional" for="company_name">Company Name</label>
- <!-- The <input> use "disabled" attribute to avoid sending an unauthorized value on form submit.
- The user might not have rights to change company_name but should still be able to see it.
- -->
- <input type="text" name="company_name" t-attf-class="form-control #{error.get('company_name') and 'is-invalid' or ''}" t-att-value="company_name or partner.commercial_company_name" t-att-disabled="None if partner_can_edit_vat else '1'" />
- <small t-if="not partner_can_edit_vat" class="form-text text-muted d-block d-xl-none">
- Changing company name is not allowed once document(s) have been issued for your account. Please contact us directly for this operation.
- </small>
- </div>
- <div t-attf-class="mb-1 #{error.get('vat') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label label-optional" for="vat">VAT Number</label>
- <!-- The <input> use "disabled" attribute to avoid sending an unauthorized value on form submit.
- The user might not have rights to change company_name but should still be able to see it.
- -->
- <input type="text" name="vat" t-attf-class="form-control #{error.get('vat') and 'is-invalid' or ''}" t-att-value="vat or partner.vat" t-att-disabled="None if partner_can_edit_vat else '1'" />
- <small t-if="not partner_can_edit_vat" class="form-text text-muted d-block d-xl-none">Changing VAT number is not allowed once document(s) have been issued for your account. Please contact us directly for this operation.</small>
- </div>
- <div t-if="not partner_can_edit_vat" class="col-12 d-none d-xl-block">
- <small class="form-text text-muted">Changing company name or VAT number is not allowed once document(s) have been issued for your account. <br/>Please contact us directly for this operation.</small>
- </div>
- <div t-attf-class="mb-3 #{error.get('phone') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label" for="phone">Phone</label>
- <input type="tel" name="phone" t-attf-class="form-control #{error.get('phone') and 'is-invalid' or ''}" t-att-value="phone or partner.phone" />
- </div>
- <div class="clearfix" />
- <div t-attf-class="mb-3 #{error.get('street') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label" for="street">Street</label>
- <input type="text" name="street" t-attf-class="form-control #{error.get('street') and 'is-invalid' or ''}" t-att-value="street or partner.street"/>
- </div>
- <div t-attf-class="mb-3 #{error.get('city') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label" for="city">City</label>
- <input type="text" name="city" t-attf-class="form-control #{error.get('city') and 'is-invalid' or ''}" t-att-value="city or partner.city" />
- </div>
- <div t-attf-class="mb-3 #{error.get('zip') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label label-optional" for="zipcode">Zip / Postal Code</label>
- <input type="text" name="zipcode" t-attf-class="form-control #{error.get('zip') and 'is-invalid' or ''}" t-att-value="zipcode or partner.zip" />
- </div>
- <div t-attf-class="mb-3 #{error.get('country_id') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label" for="country_id">Country</label>
- <select name="country_id" t-attf-class="form-select #{error.get('country_id') and 'is-invalid' or ''}">
- <option value="">Country...</option>
- <t t-foreach="countries or []" t-as="country">
- <option t-att-value="country.id" t-att-selected="country.id == int(country_id) if country_id else country.id == partner.country_id.id">
- <t t-esc="country.name" />
- </option>
- </t>
- </select>
- </div>
- <div t-attf-class="mb-3 #{error.get('state_id') and 'o_has_error' or ''} col-xl-6">
- <label class="col-form-label label-optional" for="state_id">State / Province</label>
- <select name="state_id" t-attf-class="form-select #{error.get('state_id') and 'is-invalid' or ''}">
- <option value="">select...</option>
- <t t-foreach="states or []" t-as="state">
- <option t-att-value="state.id" style="display:none;" t-att-data-country_id="state.country_id.id" t-att-selected="state.id == int(state_id) if state_id else state.id == partner.state_id.id">
- <t t-esc="state.name" />
- </option>
- </t>
- </select>
- </div>
- </template>
- <template id="portal_my_details">
- <t t-call="portal.portal_layout">
- <t t-set="additional_title">Contact Details</t>
- <form action="/my/account" method="post">
- <div class="row o_portal_details">
- <div class="col-lg-8">
- <div class="row">
- <t t-call="portal.portal_my_details_fields"/>
- <input type="hidden" name="redirect" t-att-value="redirect"/>
- </div>
- <div class="clearfix">
- <button type="submit" class="btn btn-primary float-end mb32 ">
- Confirm
- <span class="fa fa-long-arrow-right" />
- </button>
- </div>
- </div>
- </div>
- </form>
- </t>
- </template>
- <template id="portal_my_security">
- <t t-call="portal.portal_layout"><div class="o_portal_security_body">
- <t t-set="additional_title">Security</t>
- <t t-set="no_breadcrumbs" t-value="1"/>
- <div class="alert alert-danger" role="alert" t-if="get_error(errors)">
- <t t-esc="errors"/>
- </div>
- <section name="portal_change_password">
- <h3>Change Password</h3>
- <t t-set="path">password</t>
- <div class="alert alert-success" role="alert" t-if="success and success.get('password')">
- Password Updated!
- </div>
- <div class="alert alert-danger" role="alert" t-if="get_error(errors, 'password')">
- <t t-esc="errors['password']"/>
- </div>
- <form action="/my/security" method="post" class="oe_reset_password_form">
- <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- <input type="hidden" name="op" value="password"/>
- <div class="mb-3">
- <label for="current">Password:</label>
- <input type="password" t-attf-class="form-control form-control-sm {{ 'is-invalid' if get_error(errors, 'password.old') else '' }}"
- id="current" name="old"
- autocomplete="current-password" required="required"/>
- <div class="invalid-feedback">
- <t t-esc="get_error(errors, 'password.old')"/>
- </div>
- </div>
- <div class="mb-3">
- <label for="new">New Password:</label>
- <input type="password" t-attf-class="form-control form-control-sm {{ 'is-invalid' if get_error(errors, 'password.new1') else '' }}"
- id="new" name="new1"
- autocomplete="new-password" required="required"/>
- <div class="invalid-feedback">
- <t t-esc="get_error(errors, 'password.new1')"/>
- </div>
- </div>
- <div class="mb-3">
- <label for="new2">Verify New Password:</label>
- <input type="password" t-attf-class="form-control form-control-sm {{ 'is-invalid' if get_error(errors, 'password.new2') else '' }}"
- id="new2" name="new2"
- autocomplete="new-password" required="required"/>
- <div class="invalid-feedback">
- <t t-esc="get_error(errors, 'password.new2')"/>
- </div>
- </div>
- <button type="submit" class="btn btn-secondary">Change Password</button>
- </form>
- </section>
- <section t-if="debug and allow_api_keys">
- <h3>
- Developer API Keys
- <a href="https://www.odoo.com/documentation/16.0/developer/misc/api/external_api.html#api-keys" target="_blank">
- <i title="Documentation" class="fa fa-fw o_button_icon fa-info-circle"></i>
- </a>
- </h3>
- <div>
- <table class="table o_main_table">
- <thead>
- <tr>
- <th>Description</th>
- <th>Scope</th>
- <th>Added On</th>
- <th/>
- </tr>
- </thead>
- <tbody>
- <t t-foreach="request.env.user.api_key_ids" t-as="key">
- <tr>
- <td><span t-field="key.name"/></td>
- <td><span t-field="key.scope"/></td>
- <td><span t-field="key.create_date"/></td>
- <td>
- <i class="fa fa-trash text-danger o_portal_remove_api_key" type="button" t-att-id="key.id"/>
- </td>
- </tr>
- </t>
- </tbody>
- </table>
- </div>
- <div>
- <button type="submit" class="btn btn-secondary o_portal_new_api_key">New API Key</button>
- </div>
- </section>
- <section name="portal_deactivate_account" groups="base.group_portal">
- <h3>Delete Account</h3>
- <t t-set="deactivate_error" t-value="get_error(errors, 'deactivate')"/>
- <button class="btn btn-secondary" data-bs-toggle="modal"
- data-bs-target="#portal_deactivate_account_modal">
- Delete Account
- </button>
- <div t-attf-class="modal #{'show d-block' if open_deactivate_modal else ''}"
- id="portal_deactivate_account_modal" tabindex="-1" role="dialog">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header bg-danger">
- <h5 class="modal-title">Are you sure you want to do this?</h5>
- <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
- </div>
- <form action="/my/deactivate_account" method="post" class="modal-body"
- id="portal_deactivate_account_form">
- <div>
- <div class="alert alert-danger"
- t-esc="get_error(errors, 'deactivate.other')"/>
- <p class="text-muted">
- Disable your account, preventing any further login.<br/>
- <b>
- <i class="fa fa-exclamation-triangle text-danger"></i>
- This action cannot be undone.
- </b>
- </p>
- <hr/>
- <p>1. Enter your password to confirm you own this account</p>
- <input name="password" type="password" required="1"
- t-attf-class="form-control #{'is-invalid' if deactivate_error == 'password' else ''}"
- placeholder="Password"/>
- <div t-if="deactivate_error == 'password'" class="invalid-feedback">
- Wrong password.
- </div>
- <hr/>
- <p>
- 2. Confirm you want to delete your account by
- copying down your login (<t t-esc="env.user.login"/>).
- </p>
- <input name="validation" type="text" required="1"
- t-attf-class="form-control #{'is-invalid' if deactivate_error == 'validation' else ''}"/>
- <div t-if="deactivate_error == 'validation'" class="invalid-feedback">
- You should enter "<t t-esc="env.user.login"/>" to validate your action.
- </div>
- <div class="d-flex flex-row align-items-center">
- <input type="checkbox" name="request_blacklist" id="request_blacklist" checked="1"/>
- <label for="request_blacklist" class="ms-2 mw-100 fw-normal mt-3">
- Put my email and phone in a block list to make sure I'm never contacted again
- </label>
- </div>
- </div>
- <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
- </form>
- <div class="modal-footer justify-content-start">
- <input type="submit" class="btn btn-danger" form="portal_deactivate_account_form"
- value="Delete Account"/>
- <button type="button" class="btn" data-bs-dismiss="modal">
- Cancel
- </button>
- </div>
- </div>
- </div>
- </div>
- </section>
- </div></t>
- </template>
- <template id="record_pager" name="Portal Record Pager">
- <t t-if='prev_record or next_record'>
- <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="Next"></i></a>
- </div>
- </t>
- </template>
- <template id="pager" name="Pager">
- <ul t-if="pager['page_count'] > 1" t-attf-class="#{ classname or '' } pagination m-0 #{_classes}" t-att-style="style or None">
- <li t-attf-class="page-item #{'disabled' if pager['page']['num'] == 1 else ''}">
- <a t-att-href=" pager['page_previous']['url'] if pager['page']['num'] != 1 else None" t-attf-class="page-link #{extraLinkClass}">Prev</a>
- </li>
- <t t-foreach="pager['pages']" t-as="page">
- <li t-attf-class="page-item #{'active' if page['num'] == pager['page']['num'] else ''}"> <a t-att-href="page['url']" t-attf-class="page-link #{extraLinkClass}" t-out="page['num']"/></li>
- </t>
- <li t-attf-class="page-item #{'disabled' if pager['page']['num'] == pager['page_count'] else ''}">
- <a t-att-href="pager['page_next']['url'] if pager['page']['num'] != pager['page_count'] else None" t-attf-class="page-link #{extraLinkClass}">Next</a>
- </li>
- </ul>
- </template>
- <template id="my_account_link" name="Link to frontend portal" inherit_id="portal.user_dropdown">
- <xpath expr="//*[@id='o_logout_divider']" position="before">
- <a href="/my/home" role="menuitem" class="dropdown-item ps-3">
- <i class="fa fa-fw fa-id-card-o me-1 small text-muted"/> My Account
- </a>
- </xpath>
- </template>
- <!--
- Generic chatter template for the frontend
- This template provide the container of the chatter. The rest is done in js.
- To use this template, you need to call it after setting the following variable in your template or in your controller:
- :object browserecord : the mail_thread object
- :message_per_page int (optional): number of message per chatter page
- :token string (optional): if you want your chatter to be available for non-logged user,
- you can use a token to verify the identity of the user;
- the message will be posted with the identity of the partner_id of the object
- :hash : signed token with the partner_id using `_sign_token` method (on mail.thread)
- :pid : identifier of the partner signing the token
- NOTE: for standard portal flows, _get_page_view_values should be used to properly setup the template parameters
- -->
- <template id="message_thread">
- <div id="discussion" data-anchor="true"
- class="d-print-none o_portal_chatter o_not_editable p-0"
- t-att-data-token="token"
- t-att-data-res_model="object._name"
- t-att-data-pid="pid"
- t-att-data-hash="hash"
- t-att-data-res_id="object.id"
- t-att-data-pager_step="message_per_page or 10"
- t-att-data-allow_composer="'0' if disable_composer else '1'"
- t-att-data-two_columns="'true' if two_columns else 'false'">
- </div>
- </template>
- <!--
- Snippet to request user signature in the portal. The feature comes with
- the JS file `portal_signature.js`.
- The following variable has to be set:
- - {string} call_url: url where to send the name and signature by RPC
- The url should contain a query string if additional parameters
- have to be sent, such as an access token.
- The following variables are optional:
- - {string} default_name: the default name to display
- - {string} mode: 'draw', 'auto', or 'load'
- - {string} send_label: label of the send button
- - {number} signature_ratio: ratio of the signature area
- - {string} signature_type: 'signature' or 'initial'
- For the default values and more information, see init() of the widgets
- SignatureForm and NameAndSignature.
- -->
- <template id="portal.signature_form" name="Ask Signature">
- <div class="o_portal_signature_form"
- t-att-data-call-url="call_url"
- t-att-data-default-name="default_name"
- t-att-data-mode="mode"
- t-att-data-send-label="send_label"
- t-att-data-signature-ratio="signature_ratio"
- t-att-data-signature-type="signature_type"
- t-att-data-font-color="font_color"
- />
- </template>
- <template id="portal_sidebar" name="Sidebar">
- <t t-call="portal.portal_layout">
- <body data-bs-spy="scroll" data-target=".navspy" data-offset="50">
- <div class="container o_portal_sidebar"></div>
- <div class="oe_structure mb32" id="oe_structure_portal_sidebar_1"/>
- </body>
- </t>
- </template>
- </odoo>
|