fix(portal): sidebar values + Purchase Order naming on /my/orders detail
1. Odoo's portal_order_page route calls _get_page_view_values which doesn't touch _prepare_portal_layout_values, so our sidebar context (fp_sidebar_items, fp_partner_display_name) was missing on every Odoo detail page (SO, invoice, delivery, quote). Override _get_page_view_values to setdefault our two keys into the values dict — non-clobbering, covers every detail route. 2. Rename "Sales Order(s)" / "Your Orders" to "Purchase Order(s)" on the customer portal so the wording matches the sidebar item and the customer's perspective (they purchase from us). Inherits in fp_sale_order_portal.xml replace the relevant text nodes in sale.portal_my_home_menu_sale / sale.portal_my_orders / sale.sale_order_portal_content. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -196,6 +196,20 @@ class FpCustomerPortal(CustomerPortal):
|
|||||||
values['fp_partner_display_name'] = commercial.name or partner.name
|
values['fp_partner_display_name'] = commercial.name or partner.name
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
def _get_page_view_values(self, document, access_token, values, session_history, no_breadcrumbs, **kwargs):
|
||||||
|
# Odoo's detail-page routes (sale order, invoice, delivery, etc.)
|
||||||
|
# funnel through this helper. It sets up chatter/pager but doesn't
|
||||||
|
# touch _prepare_portal_layout_values, so our sidebar context wouldn't
|
||||||
|
# otherwise reach those templates. Inject our keys conservatively via
|
||||||
|
# setdefault — never overwrite anything the page already set.
|
||||||
|
values = super()._get_page_view_values(
|
||||||
|
document, access_token, values, session_history, no_breadcrumbs, **kwargs,
|
||||||
|
)
|
||||||
|
layout = self._prepare_portal_layout_values()
|
||||||
|
values.setdefault('fp_sidebar_items', layout.get('fp_sidebar_items'))
|
||||||
|
values.setdefault('fp_partner_display_name', layout.get('fp_partner_display_name'))
|
||||||
|
return values
|
||||||
|
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
# Customer-visible stage timeline (detail page)
|
# Customer-visible stage timeline (detail page)
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
|
|||||||
@@ -95,4 +95,99 @@
|
|||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ================================================================== -->
|
||||||
|
<!-- Breadcrumbs: rename "Sales Orders" → "Purchase Orders" on -->
|
||||||
|
<!-- confirmed-order pages, and "Sales Order SOXXXX" → "Purchase -->
|
||||||
|
<!-- Order SOXXXX" in the detail breadcrumb active item. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- The stock template (sale.portal_my_home_menu_sale) has two -->
|
||||||
|
<!-- adjacent <li> elements inside a t-elif chain: -->
|
||||||
|
<!-- • t-if → Quotations list crumb (state=sent/cancel) -->
|
||||||
|
<!-- • t-elif → Sales Orders list crumb (confirmed orders) -->
|
||||||
|
<!-- followed by a third <li t-if="sale_order"> that shows the -->
|
||||||
|
<!-- document name with a <span t-field="sale_order.type_name"/>. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- We replace only the confirmed-order <li t-elif> (sales-orders -->
|
||||||
|
<!-- list link) and the detail <li> (document name prefix). The -->
|
||||||
|
<!-- Quotations branch is left intact — our portal doesn't expose -->
|
||||||
|
<!-- /my/quotes from the sidebar, but we don't need to break it. -->
|
||||||
|
<!-- ================================================================== -->
|
||||||
|
<template id="fp_portal_breadcrumbs_purchase_order_rename"
|
||||||
|
inherit_id="sale.portal_my_home_menu_sale"
|
||||||
|
priority="30">
|
||||||
|
|
||||||
|
<!-- Replace the "Sales Orders" list-link breadcrumb item -->
|
||||||
|
<xpath expr="//li[@t-elif and contains(., 'Sales Orders')]" position="replace">
|
||||||
|
<li t-elif="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() }}">Purchase Orders</a>
|
||||||
|
<t t-else="">Purchase Orders</t>
|
||||||
|
</li>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- Replace the detail breadcrumb item: "Sales Order SO-XXXXX" →
|
||||||
|
"Purchase Order SO-XXXXX". The original uses t-field="sale_order.type_name"
|
||||||
|
which returns "Sales Order" or "Quotation" at runtime. We hard-code
|
||||||
|
"Purchase Order" for the confirmed-order case (only this crumb fires
|
||||||
|
for state not in sent/cancel, so quotation pages are unaffected). -->
|
||||||
|
<xpath expr="//li[@t-if='sale_order' and hasclass('breadcrumb-item')]" position="replace">
|
||||||
|
<li t-if="sale_order" class="breadcrumb-item active">
|
||||||
|
<t t-if="sale_order.state in ('sent', 'cancel')">
|
||||||
|
<t t-out="sale_order.type_name"/>
|
||||||
|
</t>
|
||||||
|
<t t-else="">Purchase Order</t>
|
||||||
|
<t t-out="' ' + sale_order.name"/>
|
||||||
|
</li>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- ================================================================== -->
|
||||||
|
<!-- /my/orders list page: rename "Your Orders" title and -->
|
||||||
|
<!-- "Sales Order #" column header -->
|
||||||
|
<!-- ================================================================== -->
|
||||||
|
<template id="fp_portal_my_orders_rename"
|
||||||
|
inherit_id="sale.portal_my_orders"
|
||||||
|
priority="30">
|
||||||
|
|
||||||
|
<!-- Rename the page title from "Your Orders" to "Purchase Orders" -->
|
||||||
|
<xpath expr="//t[@t-call='portal.portal_searchbar']" position="replace">
|
||||||
|
<t t-call="portal.portal_searchbar">
|
||||||
|
<t t-set="title">Purchase Orders</t>
|
||||||
|
</t>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- Rename "Sales Order #" column header -->
|
||||||
|
<xpath expr="//span[@class='d-none d-md-inline'][contains(text(), 'Sales Order #')]" position="replace">
|
||||||
|
<span class="d-none d-md-inline">Purchase Order #</span>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- ================================================================== -->
|
||||||
|
<!-- Detail page heading: "Sales Order - SO-XXXXX" → -->
|
||||||
|
<!-- "Purchase Order - SO-XXXXX" -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- sale.sale_order_portal_content renders the <h2> with -->
|
||||||
|
<!-- <t t-out="sale_order.type_name"/> which evaluates to "Sales Order" -->
|
||||||
|
<!-- for confirmed orders and "Quotation" for draft/sent. We replace -->
|
||||||
|
<!-- the entire <h2> to hard-code "Purchase Order" for confirmed -->
|
||||||
|
<!-- orders and preserve "Quotation" for others. -->
|
||||||
|
<!-- ================================================================== -->
|
||||||
|
<template id="fp_sale_order_portal_content_rename"
|
||||||
|
inherit_id="sale.sale_order_portal_content"
|
||||||
|
priority="30">
|
||||||
|
|
||||||
|
<xpath expr="//div[@id='intro_row']/h2" position="replace">
|
||||||
|
<h2>
|
||||||
|
<t t-if="sale_order.state in ('sale', 'cancel', 'done')">Purchase Order</t>
|
||||||
|
<t t-else="" t-out="sale_order.type_name"/>
|
||||||
|
-
|
||||||
|
<em t-out="sale_order.name"/>
|
||||||
|
</h2>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
Reference in New Issue
Block a user