oca-ocb-sale/odoo-bringout-oca-ocb-website_sale/website_sale/views/templates.xml
Ernad Husremovic 73afc09215 19.0 vanilla
2026-03-09 09:32:12 +01:00

4462 lines
234 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="header_cart_link" name="Header Cart Link">
<t t-set="website_sale_cart_quantity" t-value="request.session.get('website_sale_cart_quantity', request.cart.cart_quantity) or 0"/>
<t t-set="show_cart" t-value="website.has_ecommerce_access()"/>
<li t-attf-class="#{_item_class} divider d-none"/> <!-- Make sure the cart and related menus are not folded (see autohideMenu) -->
<li t-attf-class="o_wsale_my_cart #{not show_cart and 'd-none'} #{_item_class}">
<a href="/shop/cart" t-attf-class="#{_link_class}" aria-label="eCommerce cart">
<div t-attf-class="#{_icon_wrap_class}">
<i t-if="_icon" class="fa fa-shopping-cart fa-stack"/>
<sup t-attf-class="my_cart_quantity badge bg-primary #{_badge_class} #{'d-none' if (website_sale_cart_quantity == 0) else ''}" t-out="website_sale_cart_quantity" t-att-data-order-id="request.session.get('sale_order_id', None) if website_sale_cart_quantity else None"/>
</div>
<span t-if="_text" t-attf-class="#{_text_class}">My Cart</span>
</a>
</li>
</template>
<template id="header_hide_empty_cart_link" inherit_id="website_sale.header_cart_link" name="Header Hide Empty Cart link" active="False">
<xpath expr="//t[@t-set='show_cart']" position="after">
<t t-set="show_cart" t-value="website_sale_cart_quantity" />
</xpath>
</template>
<!-- Insert JSON-LD markup data for SEO. -->
<template id="website_sale_layout" inherit_id="website.layout" priority="1">
<body position="before">
<t
t-if="website._get_product_image_ratio() != '1_1'"
t-set="body_classname"
t-value="'o_wsale_products_opt_thumb_' + website._get_product_image_ratio() + (' ' + body_classname if body_classname else '')"
/>
</body>
<head position="inside">
<!-- Company markup data, in all pages. -->
<t t-set="base_url" t-value="website.get_base_url()"/>
<script t-if="res_company and website" type="application/ld+json" >
{
"@context": "http://schema.org",
"@type": "Organization",
"name": "<t t-out="res_company.name"/>",
"logo": "<t t-out="'%s/logo.png?company=%s' % (base_url, res_company.id)"/>",
"url": "<t t-out="base_url"/>"
}
</script>
<!-- Product markup data, on product pages. -->
<script
t-if="product_markup_data" type="application/ld+json" t-out="product_markup_data"
/>
</head>
</template>
<template
id="template_footer_website_sale"
name="eCommerce Footer"
inherit_id="website.layout"
active="False"
>
<div id="footer" position="replace">
<div
t-if="not no_footer"
id="footer"
class="oe_structure oe_structure_solo"
t-ignore="true"
>
<section class="s_text_block pt48" data-snippet="s_text_block" data-name="Container">
<div class="container s_allow_columns">
<div class="row">
<!-- Column 1: Products -->
<div class="col-lg-3 pb32">
<h5>Products</h5>
<div class="s_hr pb8" data-snippet="s_hr" data-name="Separator">
<hr class="w-100 mx-auto"/>
</div>
<ul class="list-unstyled">
<t t-set="ecommerce_categories" t-value="[]"/>
<li t-foreach="ecommerce_categories" t-as="category">
<a
t-att-href="'/shop/category/' + str(category['id'])"
t-out="category['name']"
/>
</li>
<t t-if="not ecommerce_categories">
<li><a href="#">Accessories</a></li>
<li><a href="#">Apparel</a></li>
<li><a href="#">Beauty</a></li>
<li><a href="#">Essentials</a></li>
<li><a href="#">Fitness</a></li>
<li><a href="#">Gadgets</a></li>
</t>
</ul>
<div class="s_hr pb8" data-snippet="s_hr" data-name="Separator">
<hr class="w-100 mx-auto"/>
</div>
<a href="/shop"><i class="fa fa-long-arrow-right"/> All Products</a>
<div class="s_hr pt8 pb8" data-snippet="s_hr" data-name="Separator">
<hr class="w-100 mx-auto"/>
</div>
</div>
<!-- Column 2: Customer Care -->
<div class="col-lg-3 pb32">
<h5>Customer Care</h5>
<div class="s_hr pb8" data-snippet="s_hr" data-name="Separator">
<hr class="w-100 mx-auto"/>
</div>
<ul class="list-unstyled">
<li><a href="#">Help Center</a></li>
<li><a href="#">Returns</a></li>
<li><a href="#">Delivery</a></li>
<li><a href="#">Shipping</a></li>
<li><a href="/contactus">Contact us</a></li>
</ul>
</div>
<!-- Column 3: Badges, Social, Payments -->
<div class="col-lg-5 offset-lg-1 pb48">
<!-- Payment Icons -->
<h5>Our payment methods</h5>
<div class="s_hr pb8" data-snippet="s_hr" data-name="Separator">
<hr class="w-100 mx-auto"/>
</div>
<div
class="s_supported_payment_methods o_not_editable"
data-snippet="s_supported_payment_methods"
data-name="Supported Payment Methods"
data-limit="8"
data-height="32px"
data-oe-protected="true"
/>
<div class="s_hr pt8 pb24" data-snippet="s_hr" data-name="Separator">
<hr class="w-100 mx-auto"/>
</div>
<!-- Service Badges -->
<span
class="s_badge badge text-bg-primary o_animable"
data-name="Badge"
>
<i class="fa fa-dollar fa-fw o_not-animable"/> Low Prices
</span>
<span
class="s_badge badge text-bg-primary o_animable"
data-name="Badge"
>
<i class="fa fa-shopping-basket fa-fw o_not-animable"/>
Easy Returns
</span>
<span
class="s_badge badge text-bg-primary o_animable"
data-name="Badge"
>
<i class="fa fa-truck fa-fw o_not-animable"/> Fast Shipping
</span>
<div class="s_hr pt8 pb8" data-snippet="s_hr" data-name="Separator">
<hr class="w-100 mx-auto" style="border-top-color: rgba(255, 255, 255, 0);"/>
</div>
<!-- Social Media -->
<div
class="s_social_media text-start o_not_editable"
data-snippet="s_social_media"
data-name="Social Media"
contenteditable="false"
>
<h5 class="s_social_media_title d-none">
Follow us
</h5>
<a
href="/website/social/instagram"
class="s_social_media_instagram"
target="_blank"
aria-label="Instagram"
>
<i class="fa fa-instagram o_editable_media rounded shadow-sm"/>
</a>
<a
href="/website/social/youtube"
class="s_social_media_youtube"
target="_blank"
aria-label="YouTube"
>
<i class="fa fa-youtube-play o_editable_media rounded shadow-sm"/>
</a>
<a
href="/website/social/tiktok"
class="s_social_media_tiktok"
target="_blank"
aria-label="TikTok"
>
<i class="fa fa-tiktok o_editable_media rounded shadow-sm"/>
</a>
<a
href="/website/social/twitter"
class="s_social_media_twitter"
aria-label="Twitter"
>
<i class="fa fa-twitter o_editable_media rounded shadow-sm"/>
</a>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
<xpath expr="//span[hasclass('o_footer_copyright_name')]" position="replace">
<span class="small">
&amp;copy;
<span class="o_footer_copyright_name align-baseline">Company name</span>
- <a href="#">Terms &amp; Conditions</a>
- <a href="#">Privacy Policy</a>
</span>
</xpath>
</template>
<template id="product_category_extra_link" name="Product Category Extra Link">
<button class="btn btn-link btn-sm pe-0" disabled="disabled">
<t t-if="len(categories) == 1">Category:</t>
<t t-else="">Categories:</t>
</button>
<t t-foreach="categories" t-as="category">
<button
class="btn btn-link btn-sm p-0 text-wrap"
t-out="category.name"
t-attf-onclick="location.href='#{shop_path}/category/#{slug(category)}';return false;"
/>
</t>
</template>
<template id="template_header_mobile" inherit_id="website.template_header_mobile">
<xpath expr="//ul[hasclass('o_header_mobile_buttons_wrap')]" position="inside">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_link_class" t-value="'o_navlink_background_hover btn position-relative rounded-circle border-0 p-1 text-reset'"/>
<t t-set="_badge_class" t-value="'position-absolute top-0 end-0 mt-n1 me-n1 rounded-pill'"/>
</t>
</xpath>
</template>
<template id="template_header_default" inherit_id="website.template_header_default">
<xpath expr="//t[@t-call='website.placeholder_header_search_box']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_link_class" t-value="'o_navlink_background btn position-relative rounded-circle p-1 text-center text-reset'"/>
<t t-set="_badge_class" t-value="'position-absolute top-0 end-0 mt-n1 me-n1 rounded-pill'"/>
</t>
</xpath>
</template>
<template id="template_header_hamburger" inherit_id="website.template_header_hamburger">
<xpath expr="//t[@t-call='portal.placeholder_user_sign_in']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_link_class" t-value="'o_navlink_background btn position-relative rounded-pill p-1 text-reset'"/>
<t t-set="_badge_class" t-value="'position-absolute top-0 end-0 mt-n1 me-n1 rounded'"/>
</t>
</xpath>
</template>
<template id="template_header_stretch" inherit_id="website.template_header_stretch">
<xpath expr="//t[@t-call='website.placeholder_header_social_links']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_item_class" t-value="'border-start o_border_contrast'"/>
<t t-set="_link_class" t-value="'o_navlink_background_hover btn position-relative d-flex align-items-center h-100 rounded-0 p-2 text-reset'"/>
<t t-set="_badge_class" t-value="'rounded'"/>
</t>
</xpath>
</template>
<template id="template_header_vertical" inherit_id="website.template_header_vertical">
<xpath expr="//t[@t-call='portal.placeholder_user_sign_in']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_link_class" t-value="'o_navlink_background btn position-relative rounded-circle p-1 text-reset'"/>
<t t-set="_badge_class" t-value="'position-absolute top-0 end-0 mt-n1 me-n1 rounded-pill'"/>
</t>
</xpath>
</template>
<template id="template_header_search" inherit_id="website.template_header_search">
<xpath expr="//t[@t-call='portal.placeholder_user_sign_in']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_text" t-value="True"/>
<t t-set="_item_class" t-value="'border-start o_border_contrast'"/>
<t t-set="_link_class" t-value="'o_navlink_background_hover btn btn-sm d-flex align-items-center gap-1 h-100 rounded-0 p-2 text-reset'"/>
<t t-set="_badge_class" t-value="'rounded'"/>
</t>
</xpath>
</template>
<template id="template_header_sales_one" inherit_id="website.template_header_sales_one">
<xpath expr="//t[@t-call='portal.user_dropdown']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_link_class" t-value="'btn position-relative rounded-circle p-1 text-reset o_navlink_background'"/>
<t t-set="_badge_class" t-value="'position-absolute top-0 end-0 mt-n1 me-n1 rounded-pill'"/>
</t>
</xpath>
</template>
<template id="template_header_sales_two" inherit_id="website.template_header_sales_two">
<xpath expr="//t[@t-call='portal.placeholder_user_sign_in']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_text" t-value="True"/>
<t t-set="_icon_wrap_class" t-value="'o_navlink_background position-relative me-2 rounded-circle p-2 transition-base'"/>
<t t-set="_link_class" t-value="'o_navlink_trigger_hover btn d-flex align-items-center fw-bold text-reset'"/>
<t t-set="_badge_class" t-value="'position-absolute top-0 end-0 mt-n1 me-n1 rounded-pill'"/>
<t t-set="_text_class" t-value="'small'"/>
</t>
</xpath>
</template>
<template id="template_header_sales_three" inherit_id="website.template_header_sales_three">
<xpath expr="//t[@t-call='website.placeholder_header_language_selector']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_text" t-value="True"/>
<t t-set="_item_class" t-value="'position-relative'"/>
<t t-set="_link_class" t-value="'nav-link d-flex flex-row-reverse align-items-center text-uppercase fw-bold'"/>
<t t-set="_icon_wrap_class" t-value="'d-contains'"/>
<t t-set="_badge_class" t-value="'top-0 d-block ms-2'"/>
</t>
</xpath>
</template>
<template id="template_header_sales_four" inherit_id="website.template_header_sales_four">
<xpath expr="//t[@t-call='website.placeholder_header_call_to_action']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_link_class" t-value="'o_navlink_background btn position-relative rounded-pill p-1 text-reset'"/>
<t t-set="_badge_class" t-value="'position-absolute top-0 end-0 mt-n1 me-n1 rounded-pill'"/>
</t>
</xpath>
</template>
<template id="template_header_sidebar" inherit_id="website.template_header_sidebar">
<xpath expr="//t[@t-call='website.placeholder_header_brand']" position="after">
<ul class="list-unstyled d-flex gap-1 ms-auto mb-0">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_link_class" t-value="'o_navlink_background btn position-relative p-1 rounded-circle text-reset'"/>
<t t-set="_badge_class" t-value="'position-absolute top-0 end-0 rounded-pill mt-n1 me-n1'"/>
</t>
</ul>
</xpath>
</template>
<template id="template_header_boxed" inherit_id="website.template_header_boxed">
<xpath expr="//t[@t-call='website.placeholder_header_search_box']" position="before">
<t t-call="website_sale.header_cart_link">
<t t-set="_icon" t-value="True"/>
<t t-set="_link_class" t-value="'o_navlink_background btn position-relative rounded-circle p-1 text-center text-reset'"/>
<t t-set="_badge_class" t-value="'position-absolute top-0 end-0 mt-n1 me-n1 rounded-pill'"/>
</t>
</xpath>
</template>
<!-- Search Bar input-group template -->
<template id="search" name="Search Box" active="True">
<t t-call="website.website_search_box_input">
<t t-set="_form_classes" t-valuef="o_wsale_products_searchbar_form me-auto flex-grow-1 {{_form_classes}}"/>
<t t-set="_submit_classes" t-valuef="btn btn-{{navClass}}"/>
<t t-set="_input_classes" t-valuef="border-0 text-bg-{{navClass}}"/>
<t t-set="search_type" t-valuef="products"/>
<t t-set="action" t-value="keep(search=0)"/>
<t t-set="display_image" t-valuef="true"/>
<t t-set="display_description" t-valuef="true"/>
<t t-set="display_extra_link" t-valuef="true"/>
<t t-set="display_detail" t-valuef="true"/>
</t>
</template>
<template id="product_variant_preview">
<!-- If gap-1 is changed make sure to update the margin in product_variant_preview.js -->
<div
t-attf-class="o_wsale_attribute_previewer d-flex align-items-center gap-1 flex-nowrap overflow-hidden {{
'show_on_hover' if product_ptavs[0]['ptav'].attribute_id.preview_variants == 'hover' and layout_mode != 'list' else ''
}}"
t-att-data-hidden-ptav-count="product_ptavs_data.get('hidden_ptavs_count')"
>
<t t-foreach="product_ptavs" t-as="previewed_ptav">
<t t-set="ptav" t-value="previewed_ptav['ptav']"/>
<t t-set="selected_attribute_value" t-value="ptav.product_attribute_value_id.id"/>
<a
class="o_product_variant_preview d-none z-2"
t-att-data-variant-image="previewed_ptav['variant_image_url']"
t-att-href="previewed_ptav['variant_url']"
>
<div
t-if="ptav.attribute_id.is_thumbnail_visible"
class="d-flex"
>
<label
class="css_attribute_preview_thumbnail cursor-pointer d-block"
t-att-style="'background:url(%s); background-size:cover; background-position: center center;' % previewed_ptav['variant_image_url']"
t-att-title="ptav.name"
/>
</div>
<div
t-elif="ptav.display_type == 'color'"
class="d-flex"
>
<t
t-if="ptav.product_attribute_value_id.image"
t-set="background_style"
t-value="'background:url(/web/image/product.attribute.value/%s/image); background-size:cover;' % ptav.product_attribute_value_id.id"
/>
<t
t-elif="not ptav.is_custom"
t-set="background_style"
t-value="'background: ' + str(ptav.html_color or ptav.name)"
/>
<label
t-att-style="background_style"
class="css_attribute_color cursor-pointer d-block"
t-att-title="ptav.name"
/>
</div>
<div
t-elif="ptav.display_type == 'image'"
class="d-flex"
>
<div
t-attf-class="css_attribute_image size_small cursor-pointer d-block rounded bg-body #{'custom_value' if ptav.is_custom else ''} #{'transparent' if (not ptav.is_custom and not ptav.html_color) else ''}"
t-att-title="ptav.name"
>
<div
class="o_bg_img_center w-100 h-100 rounded-1"
t-att-style="'background-image:url(/web/image/product.attribute.value/%s/image);' % ptav.product_attribute_value_id.id"
/>
</div>
</div>
<span
t-else=""
t-attf-class="{{'' if ppr == 2 and layout_mode != 'list' else 'btn-sm'}} o_wsale_product_ptav_pill btn w-100 bg-body text-body"
>
<span class="o_wsale_product_ptav_pill_label d-block text-truncate" t-out="ptav.name"/>
</span>
</a>
</t>
<span name="hidden_ptavs_count" class="d-none ms-1 small z-2">
<a t-att-href="product_href"/>
</span>
</div>
</template>
<template id="pricelist_list" name="Pricelists Dropdown">
<t t-set="website_sale_pricelists" t-value="website_sale_pricelists or website.get_pricelist_available(show_visible=True)" />
<t t-set="hasPricelistDropdown" t-value="hasPricelistDropdown or (website_sale_pricelists and len(website_sale_pricelists)&gt;1)"/>
<t t-set="pricelist" t-value="request.pricelist"/>
<t t-set="pricelist_label">Pricelist</t>
<div t-attf-class="o_pricelist_dropdown dropdown #{_classes if hasPricelistDropdown else 'd-none'}">
<a
role="button"
href="#"
t-attf-class="dropdown-toggle btn px-2"
data-bs-toggle="dropdown"
>
<small class="d-none d-md-inline opacity-75"><t t-out="pricelist_label"/>:</small>
<span class="d-none d-md-inline" t-out="pricelist and pricelist.name or ' - '" />
<span class="d-md-none"><t t-out="pricelist_label"/></span>
</a>
<div class="dropdown-menu" role="menu">
<t t-foreach="website_sale_pricelists" t-as="pl">
<t t-set="_is_active" t-value="pricelist.id == pl.id"/>
<a
role="menuitem"
t-att-href="'/shop/change_pricelist/%s' % pl.id"
t-attf-class="dropdown-item {{_is_active and 'active'}}"
t-att-aria-current="_is_active and 'true' or 'false'"
>
<span
class="switcher_pricelist"
t-att-data-pl_id="pl.id"
t-out="pl.name"
/>
</a>
</t>
</div>
</div>
</template>
<template id="products_breadcrumb" name="Products Breadcrumb">
<ol t-if="category" t-attf-class="breadcrumb #{_classes}">
<li class="breadcrumb-item">
<a
t-att-class="'d-none d-lg-inline' if len(category.parents_and_self) &gt; 1 else ''"
t-att-href="keep(shop_path)"
>
Products
</a>
<span t-if="len(category.parents_and_self) &gt; 1" class="d-lg-none">...</span>
</li>
<t t-foreach="category.parents_and_self" t-as="cat">
<li t-if="cat == category" class="breadcrumb-item">
<span class="d-inline-block" t-field="cat.name"/>
</li>
<li
t-else=""
t-attf-class="breadcrumb-item {{cat_index &lt; cat_size - 2 and 'd-none d-lg-inline'}}"
>
<a
t-att-href="keep('%s/category/%s' % (shop_path, slug(cat)))"
t-field="cat.name"
/>
</li>
</t>
</ol>
</template>
<!-- /shop product listing -->
<template id="products" name="Products">
<t t-call="website.layout">
<t t-set="additional_title" t-value="category.name"/>
<t t-set="grid_block_name">Grid</t>
<t t-set="product_block_name">Product</t>
<!-- Qweb variable defining the class suffix for navbar items.
Change accordingly to the derired visual result (eg. `primary`, `dark`...)-->
<t t-set="navClass" t-valuef="light"/>
<!-- Check for active options: the stored value may be used in sub-templates too -->
<t t-set="opt_wsale_fullwidth" t-value="website.shop_page_container == 'fluid'"/>
<t t-set="opt_wsale_categories" t-value="is_view_active('website_sale.products_categories')"/>
<t t-set="opt_wsale_attributes" t-value="is_view_active('website_sale.products_attributes')"/>
<t t-set="opt_wsale_filter_price" t-value="is_view_active('website_sale.filter_products_price')"/>
<t t-set="opt_wsale_filter_tags" t-value="is_view_active('website_sale.filter_products_tags')"/>
<t t-set="opt_wsale_design_grid" t-value="'o_wsale_products_opt_design_grid' in website.shop_opt_products_design_classes"/>
<t t-set="opt_wsale_categories_top" t-value="is_view_active('website_sale.products_categories_top')"/>
<t t-set="opt_wsale_attributes_top" t-value="is_view_active('website_sale.products_attributes_top')"/>
<t t-set="opt_wsale_floating_bar" t-value="is_view_active('website_sale.floating_bar')"/>
<t t-set="opt_wsale_show_shop_title" t-value="is_view_active('website_sale.products_shop_title')"/>
<t t-set="opt_wsale_shop_title_align" t-value="is_view_active('website_sale.products_shop_title_align')"/>
<t t-set="opt_wsale_show_category_title" t-value="bool(category) and category.show_category_title"/>
<t t-set="opt_wsale_show_category_description" t-value="bool(category) and category.show_category_description"/>
<t t-set="opt_wsale_category_align" t-value="bool(category) and category.align_category_content"/>
<t t-set="website_sale_pricelists" t-value="website.get_pricelist_available(show_visible=True)" />
<t t-set="website_sale_sortable" t-value="website._get_product_sort_mapping()"/>
<t t-set="hasLeftColumn" t-value="opt_wsale_categories or opt_wsale_attributes"/>
<t t-set="isFilteringByPrice" t-if="opt_wsale_filter_price" t-value="float_round(available_min_price, 2) != float_round(min_price, 2) or float_round(available_max_price, 2) != float_round(max_price, 2)"/>
<t t-set="hasPricelistDropdown" t-value="website_sale_pricelists and len(website_sale_pricelists)&gt;1"/>
<t t-set="isSortingBy" t-value="[sort for sort in website_sale_sortable if sort[0]==request.params.get('order', '')]"/>
<t
t-set="wsale_has_filters_btn"
t-value="opt_wsale_categories or opt_wsale_attributes or opt_wsale_attributes_top"
/>
<t
t-set="wsale_has_filters_btn_lg"
t-value="opt_wsale_attributes_top"
/>
<div id="wrap" class="js_sale o_wsale_products_page">
<div class="oe_structure oe_empty oe_structure_not_nearest" id="oe_structure_website_sale_products_1"/>
<div
id="o_wsale_container"
t-attf-class="oe_website_sale
{{opt_wsale_fullwidth and 'container-fluid o_wsale_page_fluid' or 'o_wsale_page_contained container'}}
{{opt_wsale_categories_top and 'o_wsale_has_filmstrip'}}
{{opt_wsale_floating_bar and 'o_wsale_has_floating_bar'}}
{{hasLeftColumn and 'o_wsale_has_sidebar'}}
{{editionPreviews and 'o_wsale_edit_preview_enabled'}}
{{opt_wsale_design_grid and 'o_wsale_uses_grid_design'}}"
t-att-data-ppg="ppg"
t-att-data-ppr="ppr"
t-att-data-default-sort="website.shop_default_sort"
>
<div class="row o_wsale_products_main_row flex-nowrap">
<aside
t-if="hasLeftColumn"
id="products_grid_before"
class="d-none d-lg-block position-sticky align-self-start col clearfix pt-2"
>
<t t-call="website_sale.sidebar_dropzone_at_top"/>
<div class="o_wsale_products_grid_before_rail vh-100 ms-n2 px-lg-2 ps-2 overflow-y-scroll">
<t
t-set="is_sidebar_collapsible"
t-value="is_view_active('website_sale.products_categories_list_collapsible')"
/>
<div
t-if="opt_wsale_categories"
t-att-class="'products_categories'
+ (' accordion accordion-flush' if is_sidebar_collapsible else ' mb-3')"
>
<t t-call="website_sale.products_categories_list"/>
</div>
<t
t-set="show_price_filter"
t-value="opt_wsale_filter_price and opt_wsale_attributes"
/>
<div
t-if="attrib_values or tags or (
show_price_filter and isFilteringByPrice
)"
class="py-3 border-bottom"
>
<a
t-att-href="keep(attribute_values=0, tags=0, min_price=0, max_price=0)"
t-attf-class="btn btn-{{navClass}} d-flex align-items-center py-1"
title="Clear Filters"
>
<small class="mx-auto"><b>Clear Filters</b></small>
<i class="oi oi-close" role="presentation"/>
</a>
</div>
<div
t-attf-class="products_attributes_filters d-empty-none {{opt_wsale_categories and 'border-top'}} {{'pt-3' if not is_sidebar_collapsible else ''}}"
/>
<t
t-if="show_price_filter"
t-call="website_sale.filter_products_price"
>
<t
t-set="_classes"
t-valuef="{{is_sidebar_collapsible and 'accordion accordion-flush'}} {{is_sidebar_collapsible and (opt_wsale_categories or len(attributes) > 0) and 'border-top'}}"
/>
</t>
<t t-call="website_sale.sidebar_dropzone_at_bottom"/>
</div>
</aside>
<div id="products_grid" class="col">
<t
t-set="_header_has_content"
t-value="category or opt_wsale_categories_top or (not opt_wsale_floating_bar and (opt_wsale_attributes_top or is_view_active('website_sale.search') or is_view_active('website_sale.sort') or hasPricelistDropdown))"
/>
<header
id="o_wsale_products_header"
t-att-data-category-id="category.id"
t-att-data-category-name="category.name"
t-attf-class="d-flex flex-column gap-2
{{_header_has_content and 'pt-4 pb-3' or opt_wsale_design_grid and 'py-3'}}
{{category and 'o_wsale_products_header_is_category' or 'o_wsale_products_header_is_shop'}}
{{opt_wsale_show_category_title and 'o_wsale_products_header_show_category_title'}}
{{opt_wsale_show_category_description and 'o_wsale_products_header_show_category_description'}}
{{opt_wsale_category_align and 'o_wsale_products_header_category_center_content'}}
{{opt_wsale_show_shop_title and 'o_wsale_products_header_show_shop_title'}}
{{opt_wsale_shop_title_align and 'o_wsale_products_header_shop_center_content'}}"
>
<t t-if="category and not search" t-call="website_sale.products_breadcrumb">
<t
t-set="_classes"
t-valuef="w-100 p-0 mb-0 small {{not opt_wsale_show_category_title and 'mb-2 mb-lg-0'}}"
/>
</t>
<h1
t-if="category or search"
t-attf-class="o_wsale_category_title d-flex gap-1 align-items-center mb-0 lh-lg {{search and bool(category) and 'mb-2'}} {{search and 'o_wsale_category_title_is_search base-fs font-sans-serif' or 'fs-3'}}"
>
<t t-if="search and category">
<span class="text-muted">Searching</span>
<span class="badge text-bg-info fw-normal base-fs">
<t t-out="search"/>
<a
title="Clear search for this category"
t-att-href="keep(search=0)"
class="link-info"
>
<i class="oi oi-close" role="img"/>
</a>
</span>
<span class="text-muted">in</span>
<span class="badge text-bg-primary fw-normal base-fs">
<t t-out="category.name"/>
<a
title="Search globally"
t-att-href="keep(shop_path, search=search)"
>
<i class="oi oi-close" role="img"/>
</a>
</span>
</t>
<span t-elif="search">
<span class="text-muted">Search results for </span>'<strong t-out="search"/>' <small t-if="search_count" class="text-muted"> (<t t-out="search_count"/>)</small>
</span>
<t t-elif="category">
<span t-field="category.name"/>
</t>
</h1>
<h1
class="o_wsale_shop_title h4-fs"
t-if="not category and not search"
>
All products
</h1>
<t t-if="category">
<t t-set='editor_msg'>
Drag building blocks here to customize the header for
"<t t-out='category.name'/>" category.
</t>
<div
id="category_header"
class="o_wsale_category_description"
t-att-data-editor-message="editor_msg"
t-field="category.website_description"
/>
</t>
<t t-else="">
<t t-set="editor_msg">
Drag building blocks here to customize the header for the shop page.
</t>
<div
id="oe_structure_products_header_shop"
class="oe_structure oe_empty"
t-att-data-editor-message="editor_msg"
/>
</t>
<t t-if="opt_wsale_categories_top and category_entries"
t-call="website_sale.filmstrip_categories"
entries="category_entries"
/>
<div
t-if="not opt_wsale_floating_bar"
class="products_header btn-toolbar flex-nowrap align-items-center justify-content-between gap-1 gap-lg-2 gap-xl-3"
>
<t t-if="is_view_active('website_sale.search')">
<t t-set="_has_all_sibligns" t-value="hasPricelistDropdown and is_view_active('website_sale.sort') and wsale_has_filters_btn"></t>
<!-- Desktop Search button -->
<div t-attf-class="o_wsale_products_header_search_form_container {{ _has_all_sibligns and 'd-none d-sm-inline-block'}} col-xl-5 me-auto {{not hasLeftColumn and 'col-xl-6'}}">
<t t-set="search_term">Search in</t>
<t t-if="category" t-set="placeholder" t-valuef="{{ search_term }} {{ category.name }}"/>
<t t-call="website_sale.search" placeholder="placeholder" search="original_search or search"/>
</div>
<!-- Mobile Search button -->
<a
t-attf-class="btn o_not_editable {{_has_all_sibligns and 'd-inline-block d-sm-none' or 'd-none'}} me-auto btn-{{navClass}}"
data-bs-target="#o_wsale_search_modal"
data-bs-toggle="modal"
role="button"
title="Search Products"
href="#"
>
<i class="oi oi-search" role="img"/>
</a>
</t>
<t
t-if="hasPricelistDropdown"
t-call="website_sale.pricelist_list"
/>
<t
t-if="is_view_active('website_sale.sort')"
t-call="website_sale.sort"
/>
<button
t-if="wsale_has_filters_btn"
t-attf-class="btn btn-{{navClass}} position-relative {{not wsale_has_filters_btn_lg and 'd-lg-none'}} {{not is_view_active('website_sale.search') and 'ms-auto'}} text-nowrap"
title="Filters"
data-bs-toggle="offcanvas"
data-bs-target="#o_wsale_offcanvas"
>
<i class="oi oi-settings-adjust" role="img"/>
<small t-attf-class="ms-1 {{(hasPricelistDropdown and is_view_active('website_sale.search') and is_view_active('website_sale.sort')) and 'd-none d-md-inline-block'}}">Filters</small>
<span
t-if="isFilteringByPrice or attrib_set or tags"
t-attf-class="position-absolute top-0 start-100 translate-middle border border-{{navClass}} rounded-circle bg-danger p-1"
>
<span class="visually-hidden">filters active</span>
</span>
</button>
</div>
<div t-if="original_search and products" class="alert alert-warning mt8">
No results found for '<span t-out="original_search"/>'. Showing results for '<span t-out="search"/>'.
</div>
</header>
<div t-if="products" class="o_wsale_products_grid_table_wrapper">
<t t-set="grid_md_allow_custom_cols" t-value="hasLeftColumn"/>
<t
t-set="grid_md_use_3col"
t-value="(not hasLeftColumn and ppr == 4) or (opt_wsale_fullwidth and ppr > 3)"
/>
<section
id="o_wsale_products_grid"
t-attf-class="o_wsale_products_grid_table grid
{{grid_md_allow_custom_cols and 'o_wsale_products_grid_table_md'}}
{{website.shop_opt_products_design_classes}}"
t-attf-style="--o-wsale-ppr: {{ppr}}; --o-wsale-ppg: {{ppg}}; --o-wsale-products-grid-gap: {{gap}};"
t-att-data-name="grid_block_name"
>
<t t-foreach="bins" t-as="tr_product">
<t t-foreach="tr_product" t-as="td_product">
<t t-if="td_product">
<t t-set="col_height" t-value="td_product['y']"/>
<t t-set="col_width"
t-value="12 // ppr * td_product['x']"/>
<t t-set="col_class" t-valuef="g-col-6"/>
<t t-set="col_class_lg"
t-value="'g-col-lg-' + str(col_width)"/>
<t t-set="col_class_md"
t-value="grid_md_allow_custom_cols and ('g-col-md-' + str(col_width)) or grid_md_use_3col and 'g-col-md-4' or 'g-col-md-6'"/>
<t t-set="col_is_stretched"
t-value="(td_product['x'] &gt;= td_product['y'] * 2)"/>
<t t-set="col_is_custom_portrait"
t-value="not col_is_stretched and (col_height &gt; td_product['x'])"/>
<t t-set="product" t-value="td_product['product']"/>
<t t-set="template_price_vals" t-value="get_product_prices(product)"/>
<t
t-set="ribbon"
t-value="product._get_ribbon(
price_vals=template_price_vals,
auto_assign_ribbons=auto_assign_ribbons,
variant=product_variants[product],
)"
/>
<div
t-attf-class="oe_product {{col_is_custom_portrait and 'oe_product_custom_portrait'}} {{col_class}} {{col_class_md}} {{col_class_lg}} {{col_is_stretched and 'oe_product_size_stretch'}}"
t-attf-style="--o-wsale-products-grid-product-col-height: {{col_height}};"
t-att-data-colspan="td_product['x'] != 1 and td_product['x']"
t-att-data-rowspan="td_product['y'] != 1 and td_product['y']"
t-att-data-name="product_block_name"
>
<div t-attf-class="o_wsale_product_grid_wrapper position-relative h-100 o_wsale_product_grid_wrapper_#{td_product['x']}_#{td_product['y']}">
<t t-call="website_sale.products_item">
<t
t-set="design_field"
t-value="website.shop_opt_products_design_classes"
/>
<t
t-set="product_href"
t-value="product._get_product_url(category, product_query_params, grouped_attributes_values)"
/>
</t>
</div>
</div>
</t>
</t>
</t>
</section>
</div>
<div t-else="" class="text-center text-muted mt128 mb256">
<t t-if="not search">
<div class="mt-5 mb-3"><t t-call="website.empty_search_svg"/></div>
<h3
class="mt8"
style="text-align: center;"
>
No product defined
</h3>
<p
t-if="category"
style="text-align: center;"
>
No product defined in this category.
</p>
</t>
<t t-else="">
<div class="mt-5 mb-3"><t t-call="website.empty_search_svg"/></div>
<h3 class="mt8" style="text-align: center;">No results</h3>
<p style="text-align: center;">
No results for "<strong t-out='search'/>"<t t-if="category"> in category "<strong t-out="category.display_name"/>"</t>.
</p>
<p style="text-align: center;">
<a
t-if="category"
t-att-href="keep(shop_path, search=search)"
t-attf-title="Search {{search}} globally"
class="d-block pb-5"
>
Search globally
</a>
</p>
</t>
<div
t-ignore="true"
groups="sales_team.group_sale_manager"
class="alert alert-info d-inline-block mx-auto text-center"
>
Click <i>'New'</i> in the top-right corner to create your first product.
</div>
</div>
<div id="o_wsale_pager" t-attf-class="products_pager d-flex justify-content-center {{opt_wsale_design_grid and 'py-4' or 'py-5 pb-4'}}">
<t t-call="website.pager"/>
</div>
<t t-if="category">
<t t-set='footer_editor_message'>
Drag building blocks here to customize the footer for
"<t t-out='category.name'/>" category.
</t>
<div
class="mb16"
id="category_footer"
t-att-data-editor-message="footer_editor_message"
t-field="category.website_footer"
/>
</t>
</div>
</div>
<t t-call="website_sale.o_wsale_offcanvas"/>
</div>
<div class="oe_structure oe_empty oe_structure_not_nearest" id="oe_structure_website_sale_products_2"/>
</div>
<div
t-if="is_view_active('website_sale.search')"
id="o_wsale_search_modal"
class="modal fade css_editable_mode_hidden"
aria-hidden="true"
tabindex="-1"
>
<div class="modal-dialog modal-lg pt-5">
<div class="modal-content mt-5 bg-transparent border-0">
<div class="o_container_small">
<t t-call="website.website_search_box_input">
<t t-set="default_style" t-valuef="true"/>
<t t-set="search_type" t-valuef="products"/>
<t t-set="_classes" t-valuef="input-group rounded o_cc o_cc1 mb-1"/>
<t t-set="_input_classes" t-valuef="border-0 p-3"/>
<t t-set="_submit_classes" t-valuef="px-4"/>
<t t-set="search_term">Search in</t>
<t t-if="category" t-set="placeholder" t-valuef="{{ search_term }} {{ category.name }}"/>
</t>
</div>
</div>
</div>
</div>
</t>
</template>
<template id="website_sale.sidebar_dropzone_at_top">
<div id="oe_structure_website_sale_sidebar_top" class="oe_structure">
<section
class="s_text_block oe_unmovable oe_unremovable"
data-snippet="s_text_block"
data-name="Text"
>
<p/>
</section>
</div>
</template>
<template id="website_sale.sidebar_dropzone_at_bottom">
<div id="oe_structure_website_sale_sidebar_bottom" class="oe_structure">
<section
class="s_text_block oe_unmovable oe_unremovable"
data-snippet="s_text_block"
data-name="Text"
>
<p/>
</section>
</div>
</template>
<!-- (Option) Mobile: Show 1 product for row -->
<template
id="website_sale.products_mobile_cols_single"
active="False"
name="Mobile: Show 1 product for row"
inherit_id="website_sale.products"
>
<xpath expr="//t[@t-set='col_class']" position="attributes">
<attribute name="t-valuef">g-col-12</attribute>
</xpath>
</template>
<template id="website_sale.sort" name="Sort-by Template">
<div t-attf-class="o_sortby_dropdown dropdown dropdown_sorty_by {{_classes}}">
<t
t-set="_current_sort"
t-value="isSortingBy and isSortingBy[0][0] or website.shop_default_sort"
/>
<t t-set="_sort_label">Sort By</t>
<a
role="button"
href="#"
t-attf-class="dropdown-toggle btn px-2"
data-bs-toggle="dropdown"
>
<span class="d-md-none"><t t-out="_sort_label"/></span>
<small class="d-none d-md-inline opacity-75"><t t-out="_sort_label"/>:</small>
<span class="d-none d-md-inline">
<t t-if="isSortingBy" t-out="isSortingBy[0][1]"/>
<!-- Prevent editing the content in website builder -->
<span t-else="" t-out="dict(website_sale_sortable)[website.shop_default_sort]"/>
</span>
<i t-if="_icon_classes" t-attf-class="fa fa-sort {{_icon_classes}}" role="img"/>
</a>
<div class="dropdown-menu dropdown-menu-end" role="menu">
<t t-foreach="website_sale_sortable" t-as="sortby">
<t t-set="_is_active" t-value="_current_sort == sortby[0]"/>
<a
role="menuitem"
rel="noindex,nofollow"
t-att-href="keep(order=sortby[0])"
t-attf-class="dropdown-item {{_is_active and 'active'}}"
>
<span t-out="sortby[1]"/>
</a>
</t>
</div>
</div>
</template>
<template id="website_sale.products_categories" active="False" name="Categories in Left Side "/>
<template id="website_sale.products_categories_top" active="True" name="Categories in top-nav"/>
<template id="website_sale.products_attributes_top" active="False" name="Attributes in top-nav"/>
<template id="website_sale.products_shop_title" active="True" name="Show Shop Title"/>
<template id="website_sale.products_shop_title_align" active="False" name="Align Shop Title"/>
<template id="website_sale.filter_color_attributes" name="Color attributes in Filter">
<t t-foreach="a.value_ids" t-as="v">
<t t-set="img_style"
t-value="'background:url(/web/image/product.attribute.value/%s/image); background-size:cover;' % v.id if v.image else ''"
/>
<t t-set="color_style"
t-value="'background: ' + str(v.html_color or v.name if not v.is_custom else '')"
/>
<label t-attf-style="#{img_style or color_style}"
t-attf-class="css_attribute_color cursor-pointer #{'active' if v.id in attrib_set else ''}"
>
<input type="checkbox"
name="attribute_value"
class="cursor-pointer"
t-att-value="'%s-%s' % (a.id, v.id)"
t-att-checked="'checked' if v.id in attrib_set else None"
t-att-title="v.name"
/>
</label>
</t>
</template>
<template id="website_sale.filter_image_attributes" name="Image attributes in Filter">
<t t-foreach="a.value_ids" t-as="v">
<label
t-attf-class="css_attribute_image size_small position-relative rounded-3 bg-body text-center cursor-pointer #{'active' if v.id in attrib_set else ''} #{'custom_value' if v.is_custom else ''} #{'transparent' if (not v.is_custom and not v.html_color) else ''}"
>
<input
type="checkbox"
name="attribute_value"
t-att-value="'%s-%s' % (a.id, v.id)"
t-att-checked="'checked' if v.id in attrib_set else None"
t-att-title="v.name"
class="w-100 h-100 opacity-0 cursor-pointer"
/>
<div
class="oe_img_bg o_bg_img_center position-absolute top-0 w-100 h-100 rounded-1"
t-att-style="'background-image:url(/web/image/product.attribute.value/%s/image); background-size:cover;' % v.id if v.image else ''"
/>
</label>
</t>
</template>
<template id="website_sale.filter_select_attributes" name="Select attributes in Filter">
<select class="form-select css_attribute_select" name="attribute_value">
<option value="" selected="true">All <t t-out="a.name"/></option>
<t t-foreach="a.value_ids" t-as="v">
<option
t-att-value="'%s-%s' % (a.id,v.id)"
t-out="v.name"
t-att-selected="v.id in attrib_set"
/>
</t>
</select>
</template>
<template
id="website_sale.filter_radio_and_multi_attributes"
name="Radio and Multi attributes in Filter"
>
<t
t-set="sorted_values"
t-value="sorted(a.value_ids, key=lambda v: v.id not in attrib_set)"
/>
<t t-if="len(sorted_values) &lt;= 20">
<div
t-foreach="sorted_values[:8]"
t-as="v"
t-attf-class="{{'list-group-item border-0 ps-0 pb-0' if isMobile else ''}}"
>
<div class="form-check mb-1">
<input
type="checkbox"
name="attribute_value"
class="form-check-input"
t-att-id="'%s-%s' % (a.id,v.id)"
t-att-value="'%s-%s' % (a.id,v.id)"
t-att-checked="v.id in attrib_set"
/>
<label
class="form-check-label fw-normal"
t-att-for="'%s-%s' % (a.id,v.id)"
t-field="v.name"
/>
</div>
</div>
<t t-if="len(sorted_values) &gt; 8">
<div
t-attf-id="o_wsale_remaining_values_{{a.id}}"
class="accordion-collapse collapse"
t-attf-aria-labelledby="o_wsale_view_more_{{a.id}}_header"
>
<div
t-foreach="sorted_values[8:]"
t-as="v"
t-attf-class="{{'list-group-item border-0 ps-0 pb-0' if isMobile else ''}}"
>
<div class="form-check mb-1">
<input
type="checkbox"
name="attribute_value"
class="form-check-input"
t-att-id="'%s-%s' % (a.id,v.id)"
t-att-value="'%s-%s' % (a.id,v.id)"
t-att-checked="v.id in attrib_set"
/>
<label
class="form-check-label fw-normal"
t-att-for="'%s-%s' % (a.id,v.id)"
t-field="v.name"
/>
</div>
</div>
</div>
<div
t-attf-id="o_wsale_view_more_{{a.id}}_header"
t-attf-class="accordion-header {{'mb-0' if isMobile else ''}}"
>
<button
type="button"
class="o_wsale_view_more_btn btn btn-link px-0 collapsed"
data-bs-toggle="collapse"
t-attf-data-bs-target="#o_wsale_remaining_values_{{a.id}}"
t-attf-aria-controls="o_wsale_remaining_values_{{a.id}}"
aria-expanded="false"
>
View More
</button>
</div>
</t>
</t>
<t t-elif="len(sorted_values) &gt; 20">
<div t-attf-class="{{'my-3' if isMobile else 'mb-3'}}">
<input
type="text"
class="o_wsale_attribute_search_bar form-control"
t-attf-placeholder="Search {{a.name}} ({{len(a.value_ids)}})"
t-att-data-container-id="'searchable-values-%s' % a.id"
/>
</div>
<div
t-attf-id="searchable-values-{{ a.id }}"
class="overflow-auto"
t-attf-style="max-height:{{'290px' if isMobile else '220px'}};"
>
<t t-foreach="sorted_values" t-as="v">
<div
t-attf-class="form-check mb-1 {{'list-group-item border-0 ms-3 pb-0' if isMobile else 'ms-1'}}"
>
<input
type="checkbox"
name="attribute_value"
class="form-check-input"
t-att-id="'%s-%s' % (a.id,v.id)"
t-att-value="'%s-%s' % (a.id,v.id)"
t-att-checked="v.id in attrib_set"
/>
<label
class="form-check-label fw-normal"
t-att-for="'%s-%s' % (a.id,v.id)"
t-field="v.name"
/>
</div>
</t>
</div>
</t>
</template>
<template id="website_sale.filter_pills_attributes" name="Pills attributes in Filter">
<t t-foreach="a.value_ids" t-as="v">
<input
type="checkbox"
name="attribute_value"
class="btn-check"
t-att-id="'%s-%s' % (a.id,v.id)"
t-att-value="'%s-%s' % (a.id,v.id)"
t-att-checked="v.id in attrib_set"
autocomplete="off"
/>
<label
t-attf-class="btn border {{'active bg-primary-subtle border-primary text-primary-emphasis' if v.id in attrib_set else ''}}"
t-att-for="'%s-%s' % (a.id,v.id)"
t-field="v.name"
/>
</t>
</template>
<template
id="website_sale.product_attribute_filters_form"
name="Product Attribute Filters Form"
>
<form
t-attf-class="js_attributes {{('accordion accordion-flush d-flex flex-column ' + ('border-bottom' if attributes else '')) if isMobile else 'position-relative mb-2'}}"
method="get"
t-att-action="keep(attribute_values=0, tags=0)"
>
<t
t-set="visible_attributes"
t-value="len([a for a in attributes if a.value_ids and len(a.value_ids) &gt; 1])"
/>
<t t-foreach="attributes" t-as="a">
<t t-set="_status" t-value="'inactive'"/>
<t t-foreach="a.value_ids" t-as="v" t-if="v.id in attrib_set" t-set="_status" t-value="'active'"/>
<t t-set="_expand_attributes" t-value="_status == 'active' or visible_attributes &lt; 4"/>
<div
t-if="a.value_ids and len(a.value_ids) &gt; 1"
t-attf-class="accordion-item {{('border-top-0 ' + ('order-1' if _status == 'active' else 'order-2')) if isMobile else 'nav-item mb-1 rounded-0'}}"
>
<h2
t-if="isMobile"
class="accordion-header mb-0"
t-attf-id="o_wsale_offcanvas_attribute_{{a.id}}_header"
>
<button
t-attf-class="o_wsale_offcanvas_title accordion-button rounded-0 {{'' if _expand_attributes else 'collapsed'}}"
type="button"
t-att-data-status="_status"
data-bs-toggle="collapse"
t-attf-data-bs-target="#o_wsale_offcanvas_attribute_{{a.id}}"
t-att-aria-expanded="_expand_attributes"
t-attf-aria-controls="o_wsale_offcanvas_attribute_{{a.id}}"
>
<b t-out="a.name"/>
</button>
</h2>
<h6 t-else="" class="mb-3">
<b class="d-none d-lg-block" t-field="a.name"/>
</h6>
<div
t-attf-id="{{'o_wsale_offcanvas_attribute_' + str(a.id) if isMobile else 'o_products_attributes_' + str(a.id)}}"
t-attf-class="{{'accordion-collapse collapse ' + ('show' if _expand_attributes else '') if isMobile else ''}}"
>
<div t-attf-class="{{'accordion-body pt-0' if isMobile else ''}}">
<div
t-if="a.display_type == 'select'"
t-attf-class="{{'my-2' if isMobile else 'mb-3'}}"
>
<t t-call="website_sale.filter_select_attributes"/>
</div>
<div
t-elif="a.display_type == 'color'"
t-attf-class="d-flex flex-wrap gap-2 {{'pt-1 pb-3' if isMobile else 'mb-3'}}"
>
<t t-call="website_sale.filter_color_attributes"/>
</div>
<div
t-elif="a.display_type == 'image'"
t-attf-class="d-flex flex-wrap gap-2 #{'pt-1 pb-3' if isMobile else 'mb-3'}"
>
<t t-call="website_sale.filter_image_attributes"/>
</div>
<div
t-elif="a.display_type in ('radio', 'multi')"
t-attf-class="{{'list-group list-group-flush' if isMobile else 'flex-column mb-3'}}"
>
<t t-call="website_sale.filter_radio_and_multi_attributes">
<t t-set="isMobile" t-value="isMobile"/>
</t>
</div>
<div
t-elif="a.display_type == 'pills'"
t-attf-class="d-flex flex-wrap gap-2 {{'my-2' if isMobile else 'mb-3'}}"
data-bs-toggle="buttons"
>
<t t-call="website_sale.filter_pills_attributes"/>
</div>
</div>
</div>
</div>
</t>
<t t-if="isMobile">
<t t-if="opt_wsale_filter_tags and (opt_wsale_attributes or opt_wsale_attributes_top)">
<t t-set="_status" t-value="'inactive'"/>
<t t-foreach="all_tags" t-as="v" t-if="v.id in tags" t-set="_status" t-value="'active'"/>
<div t-if="all_tags">
<h2 class="accordion-header mb-0" t-attf-id="o_wsale_offcanvas_tags_header">
<button
t-attf-class="o_wsale_offcanvas_title accordion-button border-top rounded-0 {{not tags and 'collapsed'}}"
type="button"
t-att-data-status="_status"
data-bs-toggle="collapse"
t-attf-data-bs-target="#o_wsale_offcanvas_tags"
t-att-aria-expanded="_status == 'active' and 'True' or 'False'"
t-attf-aria-controls="o_wsale_offcanvas_tags"
>
<b>Tags</b>
</button>
</h2>
<div
t-attf-id="o_wsale_offcanvas_tags"
t-attf-class="accordion-collapse collapse {{(_status == 'active') and 'show'}}"
t-att-aria-expanded="(_status == 'active') and 'True' or 'False'"
t-attf-aria-labelledby="o_wsale_offcanvas_tags_header"
>
<div class="accordion-body pt-0">
<div class="list-group list-group-flush">
<t t-call="website_sale.filter_products_tags_list">
<t t-set="all_tags" t-value="all_tags"/>
</t>
</div>
</div>
</div>
</div>
</t>
</t>
<t t-else="">
<t
t-if="opt_wsale_filter_tags and opt_wsale_attributes"
t-call="website_sale.filter_products_tags"
>
<t t-set="all_tags" t-value="all_tags"/>
</t>
</t>
</form>
</template>
<!-- OffCanvas Nav -->
<template id="website_sale.o_wsale_offcanvas" name="Offcanvas">
<aside id="o_wsale_offcanvas"
class="o_website_offcanvas offcanvas offcanvas-end p-0">
<div class="offcanvas-header justify-content-end">
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"/>
</div>
<div
t-if="is_view_active('website_sale.search') and (opt_wsale_attributes or opt_wsale_attributes_top)"
class="offcanvas-body flex-grow-0 overflow-visible"
>
<t t-call="website_sale.search">
<t t-set="search_term">Search in</t>
<t t-if="category" t-set="placeholder" t-valuef="{{ search_term }} {{ category.name }}"/>
<t t-set="search" t-value="original_search or search"/>
<t t-set="_s_searchbar_autocomplete_classes" t-valuef="bg-primary"> </t>
</t>
</div>
<div id="o_wsale_offcanvas_content" class="accordion accordion-flush flex-grow-1 overflow-auto">
<!-- Show sorting only if it's not avavailbe in the topbar already -->
<div t-if="not is_view_active('website_sale.sort')" class="accordion-item">
<t t-if="isSortingBy" t-set="isSortingBy" t-value="isSortingBy[0][1]"/>
<t t-else="" t-set="isSortingBy" t-value="website.shop_default_sort"/>
<h2 id="o_wsale_offcanvas_orderby_header" class="accordion-header mb-0">
<button class="o_wsale_offcanvas_title accordion-button rounded-0 collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#o_wsale_offcanvas_orderby"
aria-expanded="false"
aria-controls="o_wsale_offcanvas_orderby">
<b>Sort By</b>
</button>
</h2>
<div id="o_wsale_offcanvas_orderby"
class="accordion-collapse collapse"
aria-labelledby="o_wsale_offcanvas_orderby_header">
<div class="accordion-body pt-0">
<div class="list-group list-group-flush">
<a t-foreach="website_sale_sortable" t-as="sortby"
role="menuitem"
rel="noindex,nofollow"
t-att-href="keep(order=sortby[0])"
class="list-group-item border-0 ps-0 pb-0">
<div class="form-check d-inline-block">
<input type="radio"
t-attf-onclick="location.href='#{keep(order=sortby[0])}';"
class="form-check-input o_not_editable"
name="wsale_sortby_radios_offcanvas"
t-att-checked="isSortingBy and isSortingBy == sortby[1]">
<label class="form-check-label fw-normal" t-out="sortby[1]"/>
</input>
</div>
</a>
</div>
</div>
</div>
</div>
<div t-if="opt_wsale_categories" class="accordion-item d-lg-none">
<h2 id="o_wsale_offcanvas_categories_header" class="accordion-header mb-0">
<button class="o_wsale_offcanvas_title accordion-button rounded-0 collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#o_wsale_offcanvas_categories"
aria-expanded="false"
aria-controls="o_wsale_offcanvas_categories">
<b>Categories</b>
</button>
</h2>
<div id="o_wsale_offcanvas_categories"
class="accordion-collapse collapse"
aria-labelledby="o_wsale_offcanvas_categories_header">
<div class="accordion-body pt-0">
<t t-call="website_sale.products_categories_list">
<t t-set="isOffcanvas" t-value="true"/>
<t t-set="_titleClasses" t-valuef="d-none"/>
<t t-set="_radioGroup" t-valuef="_offcanvas"/>
</t>
</div>
</div>
</div>
<t t-call="website_sale.product_attribute_filters_form">
<t t-set="isMobile" t-value="True"/>
</t>
<t t-if="opt_wsale_filter_price and (opt_wsale_attributes or opt_wsale_attributes_top)"
t-call="website_sale.filter_products_price">
<t
t-set="_classes"
t-valuef="o_wsale_offcanvas_title accordion accordion-flush px-4"
/>
<t t-set="_classes_title" t-valuef="ms-n1 pt-3 pb-2"/>
<t t-set="isOffcanvas" t-value="True"/>
</t>
</div>
<div class="offcanvas-body d-flex justify-content-between flex-grow-0 border-top overflow-hidden">
<a t-attf-class="btn btn-{{navClass}} d-flex py-1 mb-2 {{(not attrib_values and not isFilteringByPrice and not tags) and 'disabled' }}"
t-att-aria-disabled="(not attrib_values and not isFilteringByPrice and not tags) and 'true' or 'false'"
t-att-href="keep(attribute_values=0, tags=0, min_price=0, max_price=0)"
title="Clear Filters">
Clear Filters
</a>
</div>
</aside>
</template>
<!-- Top-Nav Categories -->
<template id="website_sale.filmstrip_categories" name="Categories Filmstrip">
<div
id="o_wsale_categories_filmstrip"
class="o_wsale_filmstrip_container o_wsale_filmstrip_default d-flex align-items-stretch overflow-hidden"
role="navigation"
>
<div class="o_wsale_filmstrip_wrapper position-relative overflow-auto z-1">
<ul
class="o_wsale_filmstrip d-flex align-items-stretch mb-0 list-unstyled overflow-visible"
role="menu"
aria-label="Categories"
>
<li
t-foreach="entries"
t-as="c"
t-att-data-publish="c.has_published_products and 'on' or 'off'"
role="presentation"
>
<a
t-att-href="keep('%s/category/%s' % (shop_path, slug(c)))"
class="o_wsale_filmstrip_link d-block w-100 h-100 text-decoration-none"
draggable="false"
role="menuitem"
t-att-aria-label="c.name"
>
<input
type="radio"
t-attf-name="wsale_categories_top_radios_{{parentCategoryId}}"
class="btn-check pe-none"
t-att-id="c.id"
t-att-value="c.id"
t-att-checked="'true' if c.id == category.id else None"
tabindex="-1"
/>
<div
t-att-class="'o_wsale_filmstrip_item position-relative d-flex w-100 h-100'
+ (c.id == category.id and ' active' or '')"
>
<div
t-if="c.image_128"
name="o_wsale_filmstrip_image"
class="o_wsale_filmstrip_image oe_img_bg o_bg_img_center rounded"
t-attf-style="background-image:url('data:image/png;base64, #{c.image_128}')"
t-att-alt="c.name"
role="img"
aria-label="Category image"
/>
<div
t-else=""
name="o_wsale_filmstrip_placeholder"
class="o_wsale_filmstrip_image o_wsale_filmstrip_placeholder oe_img_bg o_bg_img_center rounded"
role="img"
aria-label="Category image"
/>
<span t-field="c.name"/>
</div>
</a>
</li>
</ul>
</div>
</div>
</template>
<!-- Categories Variations -->
<template
id="website_sale.filmstrip_categories_bordered"
inherit_id="website_sale.filmstrip_categories"
name="Categories Filmstrip Bordered"
active="False"
>
<div id="o_wsale_categories_filmstrip" position="attributes">
<attribute name="class" add="o_wsale_filmstrip_bordered" remove="o_wsale_filmstrip_default" separator=" "/>
</div>
</template>
<template
id="website_sale.filmstrip_categories_tabs"
inherit_id="website_sale.filmstrip_categories"
name="Categories Filmstrip Tabs"
active="False"
>
<div id="o_wsale_categories_filmstrip" position="attributes">
<attribute name="class" add="o_wsale_filmstrip_tabs" remove="o_wsale_filmstrip_default" separator=" "/>
</div>
</template>
<template
id="website_sale.filmstrip_categories_pills"
inherit_id="website_sale.filmstrip_categories"
name="Categories Filmstrip Tabs"
active="False"
>
<div id="o_wsale_categories_filmstrip" position="attributes">
<attribute name="class" add="o_wsale_filmstrip_pills" remove="o_wsale_filmstrip_default" separator=" "/>
</div>
</template>
<template
id="website_sale.filmstrip_categories_images"
inherit_id="website_sale.filmstrip_categories"
name="Categories Filmstrip Basic"
active="False"
>
<div id="o_wsale_categories_filmstrip" position="attributes">
<attribute name="class" add="o_wsale_filmstrip_images" remove="o_wsale_filmstrip_default" separator=" "/>
</div>
<div name="o_wsale_filmstrip_placeholder" position="attributes">
<attribute name="t-if">not c.has_published_products</attribute>
</div>
</template>
<template
id="website_sale.filmstrip_categories_grid"
inherit_id="website_sale.filmstrip_categories"
name="Categories Filmstrip Grid"
active="False"
>
<div id="o_wsale_categories_filmstrip" position="attributes">
<attribute name="class" add="o_wsale_filmstrip_grid" remove="o_wsale_filmstrip_default" separator=" "/>
</div>
</template>
<template
id="website_sale.filmstrip_categories_large_images"
inherit_id="website_sale.filmstrip_categories"
name="Categories Filmstrip Cover"
active="False"
>
<div id="o_wsale_categories_filmstrip" position="attributes">
<attribute name="class" add="o_wsale_filmstrip_large_images" remove="o_wsale_filmstrip_default" separator=" "/>
</div>
<div name="o_wsale_filmstrip_placeholder" position="attributes">
<attribute name="class" remove="o_wsale_filmstrip_placeholder" add="o_wsale_filmstrip_no_image" separator=" "/>
</div>
<div name="o_wsale_filmstrip_image" position="attributes">
<attribute name="t-attf-style">background-image:url('data:image/png;base64, #{c.image_512 if c.image_512 else c.image_128}')</attribute>
</div>
</template>
<!-- Floating Toolbar -->
<template
id="website_sale.floating_bar"
name="Shop Floating Bar"
inherit_id="website_sale.products"
active="False"
>
<xpath expr="//div[hasclass('o_wsale_products_main_row')]" position="attributes">
<attribute name="class" add="position-relative" separator=" "/>
</xpath>
<xpath expr="//div[@id='o_wsale_pager']" position="attributes">
<attribute name="t-attf-class" add="o_wsale_pager_accommodate_floating" separator=" "/>
</xpath>
<xpath expr="//div[@id='products_grid']" position="after">
<t
t-set="floatBar_hasSort"
t-value="is_view_active('website_sale.sort')"
/>
<t
t-set="floatBar_hasSearch"
t-value="is_view_active('website_sale.search')"
/>
<t
t-set="website_sale_pricelists"
t-value="website_sale_pricelists or website.get_pricelist_available(show_visible=True)"
/>
<t
t-set="floatBar_hasPricelist"
t-value="website_sale_pricelists and len(website_sale_pricelists)&gt;1"
/>
<div
id="o_wsale_floating_bar_rail"
class="o_not_editable position-absolute top-0 bottom-0 d-flex justify-content-end align-items-end p-0"
>
<nav
id="o_wsale_floating_bar"
t-attf-class="navbar position-sticky d-flex gap-1 gap-lg-2 flex-shrink-0 bg-body rounded mb-2 px-2 px-lg-3 shadow {{floatBar_hasSearch and 'ps-1 ps-lg-1'}}"
>
<div t-if="floatBar_hasSearch">
<a
t-attf-class="btn o_not_editable {{(wsale_has_filters_btn or floatBar_hasSort or floatBar_hasPricelist) and 'me-n2'}}"
data-bs-target="#o_wsale_search_modal"
data-bs-toggle="modal"
role="button"
title="Search Products"
href="#"
>
<i class="oi oi-search" role="img"/>
</a>
</div>
<span
t-if="floatBar_hasSearch and (wsale_has_filters_btn or floatBar_hasSort or floatBar_hasPricelist)"
t-attf-class="align-self-stretch border-start opacity-50 {{(not floatBar_hasSort and not floatBar_hasPricelist and not wsale_has_filters_btn_lg) and 'd-lg-none'}}"
/>
<t t-if="floatBar_hasPricelist" t-call="website_sale.pricelist_list"/>
<t
t-if="floatBar_hasSort"
t-call="website_sale.sort"
/>
<button
t-if="wsale_has_filters_btn"
t-attf-class="btn btn-{{navClass}} position-relative {{not wsale_has_filters_btn_lg and 'd-lg-none'}}"
data-bs-toggle="offcanvas"
data-bs-target="#o_wsale_offcanvas"
>
<i class="oi oi-settings-adjust" role="img"/>
<span
t-if="isFilteringByPrice or attrib_set or tags"
t-attf-class="position-absolute top-0 start-100 translate-middle rounded-circle bg-danger p-1"
>
<span class="visually-hidden">filters active</span>
</span>
</button>
</nav>
</div>
</xpath>
</template>
<!-- Add to cart button-->
<template id="categories_recursive" name="Category list">
<li class="nav-item mb-1" t-att-data-publish="c.has_published_products and 'on' or 'off'">
<t t-call="website_sale.categorie_link"/>
<!-- Dynamic category display based on search -->
<t t-set="children" t-value="not search and c.child_id or c.child_id.filtered(lambda c: c.id in search_categories_ids)"/>
<!-- Only show categories with published products to portal users preventing from access errors -->
<t t-set="children" t-value="request.env.user._is_internal() and children or children.filtered('has_published_products')"/>
<ul t-if="children" class="nav flex-column nav-hierarchy mt-1 ps-3">
<t t-foreach="children" t-as="c">
<t t-if="not search or c.id in search_categories_ids">
<t t-call="website_sale.categories_recursive" />
</t>
</t>
</ul>
</li>
</template>
<template id="categorie_link" name="Category Link">
<a
t-att-href="keep('%s/category/%s' % (shop_path, slug(c)))"
t-attf-class="{{c.id == category.id and 'text-decoration-underline'}} p-0"
t-field="c.name"
/>
</template>
<template id="website_sale.products_categories_list" active="True" name="eCommerce Categories">
<!--
We must keep `t-attf-class` attr. for both following divs to work correctly with
products_categories_list_collapsible and option_collapse_products_categories
-->
<div t-attf-class="d-contents">
<h6 t-attf-class="o_categories_collapse_title {{_titleClasses}}"><b>Categories</b></h6>
<div name="wsale_products_categories_list" t-attf-class="wsale_products_categories_list">
<ul class="nav d-flex flex-column mb-3">
<li class="nav-item mb-1">
<a
t-att-href="keep(shop_path)"
t-attf-class="{{not category and 'text-decoration-underline'}} p-0"
>
All Products
</a>
</li>
<t t-foreach="categories" t-as="c">
<t t-call="website_sale.categories_recursive"/>
</t>
</ul>
</div>
</div>
</template>
<template
id="website_sale.products_categories_list_collapsible"
inherit_id="website_sale.products_categories_list"
name="Collapsed eCommerce Categories"
>
<xpath expr="//div" position="attributes">
<attribute
name="t-attf-class"
add="{{not isOffcanvas and 'accordion-item'}}"
remove="d-contents"
separator=" "
/>
</xpath>
<xpath expr="//h6" position="attributes">
<attribute name="t-attf-class" add="accordion-header" separator=" "/>
</xpath>
<xpath expr="//h6//b" position="replace">
<button
class="accordion-button px-0 bg-transparent shadow-none"
type="button"
data-bs-toggle="collapse"
t-attf-data-bs-target="#o_wsale_categories"
t-attf-aria-controls="o_wsale_categories"
aria-expanded="true"
>
<b>Categories</b>
</button>
</xpath>
<xpath expr="//div//div" position="attributes">
<attribute
name="t-attf-id"
add="{{not isOffcanvas and 'o_wsale_categories'}}"
separator=" "
/>
<attribute
name="t-attf-class"
add="{{not isOffcanvas and 'accordion-collapse collapse show'}}"
separator=" "
/>
</xpath>
</template>
<template id="option_collapse_categories_recursive" name="Collapse Category Recursive">
<!-- Dynamic category display based on search -->
<t t-set="children" t-value="not search and c.child_id or c.child_id.filtered(lambda c: c.id in search_categories_ids)"/>
<!-- Only show categories with published products to portal users preventing from access errors -->
<t t-set="children" t-value="request.env.user._is_internal() and children or children.filtered('has_published_products')"/>
<t t-if="children">
<t t-set="isOpen" t-value="c.id in category.parents_and_self.ids"/>
<li class="nav-item" t-att-data-publish="c.has_published_products and 'on' or 'off'">
<div class="accordion-header d-flex mb-1">
<t t-call="website_sale.categorie_link"/>
<button t-attf-id="o_wsale_cat_accordion_title_{{c.id}}"
t-attf-class="o_categories_recursive_button accordion-button p-0 ms-3 {{not isOpen and 'collapsed'}} w-auto flex-grow-1 bg-transparent shadow-none"
t-attf-data-bs-target="#o_wsale_cat_accordion_{{c.id}}"
t-att-aria-expanded="isOpen and 'true' or 'false'"
t-attf-aria-controls="o_wsale_cat_accordion_{{c.id}}"
data-bs-toggle="collapse"
type="button"/>
</div>
<ul t-attf-id="o_wsale_cat_accordion_{{c.id}}"
t-attf-class="accordion-collapse list-unstyled ps-2 collapse {{isOpen and 'show'}}"
t-attf-aria-labelledby="o_wsale_cat_accordion_title_{{c.id}}">
<t t-set="parentCategoryId" t-value="c.id"/>
<t t-if="isOffcanvas" t-set="parentCategoryId" t-valuef="offcanvas_{{c.id}}"/>
<t t-foreach="children" t-as="c">
<t t-call="website_sale.option_collapse_categories_recursive"/>
</t>
</ul>
</li>
</t>
<li t-else="" class="nav-item mb-1"
t-att-data-publish="c.has_published_products and 'on' or 'off'">
<t t-if="isOffcanvas" t-set="parentCategoryId" t-valuef="offcanvas"/>
<div class="d-flex flex-wrap justify-content-between align-items-center">
<t t-call="website_sale.categorie_link"/>
</div>
</li>
</template>
<template id="option_collapse_products_categories" name="Collapsible Category List" inherit_id="website_sale.products_categories_list" active="False">
<xpath expr="//t[@t-call='website_sale.categories_recursive']" position="attributes">
<attribute name="t-call">website_sale.option_collapse_categories_recursive</attribute>
</xpath>
</template>
<template id="products_attributes" inherit_id="website_sale.products" active="True" name="Attributes &amp; Variants filters">
<xpath expr="//div[contains(@t-attf-class, 'products_attributes_filters')]" position="inside">
<div t-if="attributes or all_tags" id="wsale_products_attributes_collapse"
class=" position-relative">
<t t-call="website_sale.product_attribute_filters_form">
<t t-set="isMobile" t-value="False"/>
</t>
</div>
</xpath>
</template>
<template
id="products_attributes_collapsible"
name="Collapsed Attributes &amp; Variants filters"
inherit_id="website_sale.product_attribute_filters_form"
>
<xpath expr="//form" position="attributes">
<t t-if="not isMobile">
<attribute
name="t-attf-class"
add="wsale_accordion_collapsible accordion accordion-flush"
remove="mb-2"
separator=" "
/>
</t>
</xpath>
<xpath expr="//div[contains(@t-attf-class, 'accordion-item')]//h6" position="replace">
<div t-if="not isMobile" class="accordion-header h6 mb-0">
<button
t-attf-class="accordion-button px-0 bg-transparent shadow-none {{'' if _expand_attributes else 'collapsed'}}"
type="button"
data-bs-toggle="collapse"
t-attf-data-bs-target="#o_products_attributes_{{a.id}}"
t-attf-aria-controls="o_products_attributes_{{a.id}}"
t-att-aria-expanded="_expand_attributes"
>
<b t-field="a.name"/>
</button>
</div>
</xpath>
<xpath expr="//div[contains(@t-attf-id, 'o_products_attributes_')]" position="attributes">
<attribute
name="t-attf-class"
add="accordion-collapse collapse {{'show' if _expand_attributes else ''}}"
separator=" "
/>
<attribute name="data-bs-parent" add="wsale_products_attributes_collapse"/>
</xpath>
</template>
<template id="filter_products_price" name="Filter by Prices">
<t t-set="is_disabled" t-value="available_min_price == available_max_price"/>
<div
id="o_wsale_price_range_option"
t-attf-class="position-relative {{_classes}} {{is_disabled and 'opacity-75 pe-none user-select-none'}}"
>
<t t-if="is_sidebar_collapsible">
<div class="accordion-item">
<div class="accordion-header h6 mb-0">
<button
class="accordion-button px-0 bg-transparent shadow-none"
type="button"
data-bs-toggle="collapse"
t-attf-data-bs-target="#o_wsale_price_range_option_inner"
t-attf-aria-controls="o_wsale_price_range_option_inner"
aria-expanded="true"
>
<b>Price Range</b>
</button>
</div>
<div
id="o_wsale_price_range_option_inner"
class="accordion-collapse collapse show"
>
<input
type="range"
multiple="multiple"
t-attf-class="form-range range-with-input {{_classes_input}}"
t-att-data-currency="website.currency_id.symbol"
t-att-data-currency-position="website.currency_id.position"
t-att-data-url="keep(min_price=0, max_price=0)"
t-att-step="website.currency_id.rounding"
t-att-min="'%f' % (available_min_price)"
t-att-max="'%f' % (available_max_price)"
t-att-value="'%f,%f' % (min_price, max_price)"
/>
</div>
</div>
</t>
<t t-else="">
<label t-attf-class="h6 m-0 {{_classes_title}}">
<b>Price Range</b>
</label>
<input
type="range"
multiple="multiple"
t-attf-class="form-range range-with-input {{_classes_input}}"
t-att-data-currency="website.currency_id.symbol"
t-att-data-currency-position="website.currency_id.position"
t-att-data-url="keep(min_price=0, max_price=0)"
t-att-step="website.currency_id.rounding"
t-att-min="'%f' % (available_min_price)"
t-att-max="'%f' % (available_max_price)"
t-att-value="'%f,%f' % (min_price, max_price)"
/>
</t>
</div>
</template>
<template id="filter_products_tags" name="Filter by Tags" active="True">
<div t-if="all_tags" class="accordion-item">
<div class="accordion-header h6 mb-0">
<button class="accordion-button px-0 bg-transparent shadow-none"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
t-attf-data-bs-target="#o_wsale_tags_option_inner"
t-attf-aria-controls="o_wsale_tags_option_inner">
<b>Tags</b>
</button>
</div>
<div id="o_wsale_tags_option_inner" class="accordion-collapse collapse show">
<div class="flex-column mb-3">
<t t-call="website_sale.filter_products_tags_list">
<t t-set="all_tags" t-value="all_tags"/>
</t>
</div>
</div>
</div>
</template>
<template id="filter_products_tags_list">
<t t-foreach="all_tags" t-as="tag" class="list-group-item border-0 ps-0 pb-0">
<div class="form-check mb-1">
<input type="checkbox"
name="tags"
class="form-check-input"
t-attf-id="tag_#{tag.id}"
t-att-value="tag.id"
t-att-checked="'checked' if tag.id in tags else None"
/>
<label class="form-check-label fw-normal" t-attf-for="tag_#{tag.id}" t-field="tag.name"/>
</div>
</t>
</template>
<template id="products_list_view" inherit_id="website_sale.products" active="False" name="List View (by default)">
<xpath expr="//div[@id='products_grid']" position="after">
<!-- Nothing to do, this view is only meant to allow the server -->
<!-- to know if the list view layout should be used -->
</xpath>
</template>
<!-- Enable HTML previews in edition mode. The template is active by default, but can be
manually disabled for advanced debug if necessary -->
<template id="website_sale.editor_previews" name="Enable edit previews" inherit_id="website_sale.products">
<xpath expr="//div[@id='wrap']" position="before">
<t t-set="editionPreviews" t-value="true" groups="website.group_website_designer"/>
</xpath>
</template>
<!-- /shop/product page -->
<template id="base_unit_price" name="Product Base unit price">
<span
class="o_base_unit_price"
t-out="base_unit_price"
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"
/>
/ <span class="oe_custom_base_unit" t-field="product.base_unit_name"/>
</template>
<template id="website_sale.product" name="Product" track="1">
<!-- Qweb variable defining the class suffix for navbar items.
Change accordingly to the derired visual result (eg. `primary`, `dark`...)-->
<t t-set="navClass" t-valuef="light"/>
<t
t-set="is_fullwidth_content"
t-value="website.product_page_image_width in ['none', '100_pc']"
/>
<t t-set="is_50_pc" t-value="website.product_page_image_width == '50_pc'"/>
<t t-call="website.layout">
<t t-set="additional_title" t-value="product.name" />
<div id="wrap" class="js_sale o_wsale_product_page">
<div class="oe_structure oe_empty oe_structure_not_nearest" id="oe_structure_website_sale_product_1" data-editor-message.translate="DROP BUILDING BLOCKS HERE TO MAKE THEM AVAILABLE ACROSS ALL PRODUCTS"/>
<section id="product_detail"
t-attf-class="oe_website_sale mt-1 mt-lg-2 mb-5 #{'discount'
if combination_info['has_discounted_price'] else ''}
{{website._get_product_page_container() == 'regular' and 'o_wsale_container_lg container-lg' or (website._get_product_page_container() == 'fluid' and 'o_wsale_container_fluid container-fluid' or false)}}
o_wsale_product_page_opt_image_width_{{website.product_page_image_width}}
o_wsale_product_page_opt_image_ratio_{{website.product_page_image_ratio}}
o_wsale_product_page_opt_image_ratio_mobile_{{website.product_page_image_ratio_mobile}}
o_wsale_product_page_opt_image_radius_{{website.product_page_image_roundness}}
"
t-att-data-image-ratio="website.product_page_image_ratio"
t-att-data-view-track="view_track and '1' or '0'"
>
<div class="o_wsale_content_contained container d-flex flex-wrap align-items-center py-3">
<div class="d-flex align-items-center flex-grow-1">
<ol class="o_wsale_breadcrumb breadcrumb m-0 p-0">
<li class="breadcrumb-item d-none d-lg-inline-block">
<a t-att-href="keep(shop_path)">
<t t-call="website_sale.all_products_link_name"/>
</a>
</li>
<t t-foreach="category.parents_and_self" t-as="cat">
<li
class="breadcrumb-item d-none d-lg-inline-block"
>
<a
class="py-2 py-lg-0"
t-att-href="keep('%s/category/%s' % (shop_path, slug(cat)))"
>
<i
class="oi oi-chevron-left d-lg-none me-1"
role="img"
/>
<t t-out="cat.name"/>
</a>
</li>
</t>
<li class="breadcrumb-item d-none d-lg-inline-block active">
<span t-field="product.name" />
</li>
<li class="breadcrumb-item d-lg-none">
<a t-att-href="category and keep('%s/category/%s' % (shop_path, slug(cat))) or keep(shop_path)">
<i class="oi oi-chevron-left me-2" role="img"/>
<t t-if="category.name" t-out="category.name"/>
<t t-else="" t-call="website_sale.all_products_link_name"/>
</a>
</li>
</ol>
<div class="d-flex d-md-none gap-2 ms-auto">
<t t-call="website_sale.pricelist_list"/>
<a
t-attf-class="o_wsale_product_search_mobile_btn o_not_editable btn btn-{{navClass}} d-none"
data-bs-target="#o_wsale_product_search_modal"
data-bs-toggle="modal"
role="button"
title="Search Products"
href="#"
>
<i class="oi oi-search" role="presentation"/>
</a>
</div>
</div>
<div
class="o_wsale_product_top_bar_desktop d-none d-md-inline-flex flex-wrap gap-2 w-auto mb-lg-auto"
>
<t t-call="website_sale.pricelist_list"/>
</div>
</div>
<div
t-attf-class="row align-items-lg-start {{website.product_page_cols_order == 'inverse' and 'flex-lg-row-reverse' or ''}}"
id="product_detail_main"
data-name="Product Page"
t-att-data-image_layout="website.product_page_image_layout"
>
<div
t-attf-class="o_wsale_product_images col o_wsale_sticky_object"
t-att-data-image-amount="len(product_variant._get_images() if product_variant else product._get_images())"
>
<t t-call="website_sale.shop_product_images"/>
</div>
<div
id="product_details"
t-attf-class="position-relative position-lg-sticky o_wsale_sticky_object col"
>
<div id="o_wsale_product_details_content" t-attf-class="js_product js_main_product o_wsale_content_contained container">
<!-- Product title (purchase not available)-->
<t t-set="is_add_to_cart_possible" t-value="product._is_add_to_cart_possible()"/>
<t
t-if="not is_add_to_cart_possible"
t-call="website_sale.product_title"
/>
<form t-if="is_add_to_cart_possible">
<!-- Product title (purchase available)-->
<t t-call="website_sale.product_title"/>
<div
t-if="not is_view_active('website_sale.cta_wrapper_boxed')"
class="o_wsale_product_details_content_section o_wsale_product_details_content_section_price mb-4"
>
<t t-call="website_sale.product_price"/>
<small t-if="combination_info.get('base_unit_price')"
class="ms-1 text-muted o_base_unit_price_wrapper d-none">
<t t-call="website_sale.base_unit_price">
<t
t-set="base_unit_price"
t-value="combination_info['base_unit_price']"
/>
</t>
</small>
</div>
<input
type="hidden"
name="csrf_token"
t-att-value="request.csrf_token()"
/>
<t name="variant_info">
<input
type="hidden"
class="o_not_editable product_id"
name="product_id"
t-att-value="product_variant.id"
/>
<input
type="hidden"
class="o_not_editable product_template_id"
name="product_template_id"
t-att-value="product.id"
/>
<input
t-if="product.public_categ_ids.ids"
type="hidden"
class="product_category_id"
name="product_category_id"
t-att-value="product.public_categ_ids.ids[0]"
/>
<input
type="hidden"
name="product_type"
t-att-value="product.type"
/>
<div
t-attf-class="o_wsale_product_details_content_section o_wsale_product_details_content_section_attributes mb-4 {{not (product.valid_product_template_attribute_line_ids or product._has_multiple_uoms()) and 'd-none' or ''}}"
>
<t t-call="website_sale.variants">
<t t-set="ul_class" t-valuef="flex-column" />
<t t-set="parent_combination" t-value="None" />
<t
t-set="combination"
t-value="combination_info['combination']"
/>
</t>
</div>
</t>
<div class="o_wsale_product_details_content_section o_wsale_product_details_content_section_cta mb-4">
<t
t-call="website_sale.cta_wrapper"
/>
<t
t-if="is_view_active('website_sale.product_terms_and_conditions')"
t-call="website_sale.product_terms_and_conditions"
/>
</div>
<div
class="o_wsale_product_details_content_section o_wsale_product_details_content_section_accordion mb-4"
t-if="is_view_active('website_sale_comparison.accordion_specs_item') or is_view_active('website_sale.accordion_more_information')"
>
<t t-call="website_sale.product_accordion"/>
</div>
<div
class="o_wsale_product_details_content_section o_wsale_product_details_content_section_contact mb-4"
>
<div
id="contact_us_wrapper"
t-attf-class="d-flex oe_structure oe_structure_solo #{_div_classes} {{'d-flex' if combination_info['prevent_zero_price_sale'] else 'd-none'}}"
>
<section
class="s_text_block"
data-snippet="s_text_block"
data-name="Text">
<div class="container">
<a
t-att-href="website.contact_us_button_url"
t-att-data-url="website.contact_us_button_url"
class="btn btn-primary btn_cta"
>
Contact Us
</a>
</div>
</section>
</div>
</div>
<t
t-set="single_value_attributes"
t-value="product.valid_product_template_attribute_line_ids._prepare_single_value_for_display()"
/>
<div
id="product_attributes_simple"
t-if="single_value_attributes"
class="o_wsale_product_details_content_section o_wsale_product_details_content_section_specs mb-4"
>
<table t-attf-class="table table-sm text-muted {{'' if single_value_attributes else 'd-none'}}">
<t t-foreach="single_value_attributes" t-as="attribute">
<tr>
<td>
<span t-field="attribute.name"/>:
<t
t-foreach="single_value_attributes[attribute]"
t-as="ptal"
>
<span t-field="ptal.product_template_value_ids._only_active().name"/>
<t t-if="not ptal_last">, </t>
</t>
</td>
</tr>
</t>
</table>
</div>
<t t-set="product_documents" t-value="product.sudo().product_document_ids.filtered(lambda doc: doc.shown_on_product_page)"/>
<div
id="product_documents"
class="o_wsale_product_details_content_section o_wsale_product_details_content_section_documents mb-4"
t-if="product_documents"
>
<strong>Documents</strong>
<div class="list-group">
<t t-foreach="product_documents" t-as="document_sudo">
<t
t-set="attachment_sudo"
t-value="document_sudo.ir_attachment_id"
/>
<t
t-set="target"
t-value="attachment_sudo.type == 'url' and '_blank' or '_self'"
/>
<t
t-set="icon"
t-value="attachment_sudo.type == 'url' and 'fa-link' or 'fa-download'"
/>
<a
class="list-group-item list-group-item-action"
t-att-href="'/shop/' + slug(product) + '/document/' + str(document_sudo.id)"
t-att-target="target">
<i t-att-class="'fa ' + icon + ' me-2'"/>
<t t-out="attachment_sudo.name"/>
</a>
</t>
</div>
</div>
</form>
</div>
</div>
</div>
</section>
<div
id="product_full_description"
t-field="product.website_description"
class="oe_structure oe_empty mt16"
/>
<div class="oe_structure oe_empty oe_structure_not_nearest mt16" id="oe_structure_website_sale_product_2" data-editor-message.translate="DROP BUILDING BLOCKS HERE TO MAKE THEM AVAILABLE ACROSS ALL PRODUCTS"/>
</div>
<div
id="o_wsale_product_search_modal"
class="modal fade css_editable_mode_hidden"
aria-hidden="true"
tabindex="-1"
>
<div class="modal-dialog modal-lg pt-5">
<div class="modal-content mt-5 bg-transparent border-0">
<div class="o_container_small">
<t t-call="website.website_search_box_input">
<t t-set="default_style" t-valuef="true"/>
<t t-set="search_type" t-valuef="products"/>
<t t-set="_classes" t-valuef="input-group rounded o_cc o_cc1 mb-1"/>
<t t-set="_input_classes" t-valuef="border-0 p-3"/>
<t t-set="_submit_classes" t-valuef="px-4"/>
<t t-if="category" t-set="placeholder">Search in <t t-out="category.name"/></t>
</t>
</div>
</div>
</div>
</div>
</t>
</template>
<template id="website_sale.product_title">
<div
t-attf-class="o_wsale_product_details_content_section o_wsale_product_details_content_section_title {{'mb-3' if not product.description_ecommerce else ''}}"
>
<!-- FIXME VCR variable seems unused -->
<t t-set="base_url" t-value="website.get_base_url()"/>
<h1
t-attf-class="h3 {{'mb-3' if not product.description_ecommerce and not is_view_active('website_sale.product_comment') else ''}}"
t-field="product.name"
>
Product Name
</h1>
<t t-if="is_view_active('website_sale.product_comment')">
<a
href="#o_product_page_reviews"
class="o_product_page_reviews_link d-block mb-2 text-decoration-none"
>
<t t-call="portal_rating.rating_widget_stars_static">
<!-- sudo: product.product - visitor can access product average rating -->
<t t-set="rating_avg" t-value="product.sudo().rating_avg"/>
<t t-set="trans_text_plural">%s reviews</t>
<t t-set="trans_text_singular">%s review</t>
<t
t-set="rating_count"
t-value="(trans_text_plural if product.rating_count > 1 else trans_text_singular) % product.rating_count"
/>
</t>
</a>
</t>
<div
t-field="product.description_ecommerce"
t-attf-class="oe_structure mb-3 text-muted"
placeholder="A detailed, formatted description to promote your product on this page. Use '/' to discover more features."
/>
<t
t-if="is_view_active('website_sale.product_tags')"
t-call="website_sale.product_tags"
>
<t
t-set="all_product_tags"
t-value="product_variant.all_product_tag_ids"
/>
</t>
<p t-if="(not is_add_to_cart_possible) and (not product.active)" class="alert alert-warning">
This product is no longer available.
</p>
<p t-elif="not is_add_to_cart_possible" class="alert alert-warning">
This product has no valid combination.
</p>
</div>
</template>
<template id="website_sale.cta_wrapper" name="CTA Wrapper">
<div
id="o_wsale_cta_wrapper"
t-att-class="'d-flex flex-wrap align-items-center gap-2 mb-4' +
(' w-100 w-lg-auto' if is_50_pc else ' w-100') +
(' ' if not is_fullwidth_content and not is_view_active('website_sale.cta_wrapper_boxed') else ' ')"
>
<div
id="add_to_cart_wrap"
t-attf-class="{{'d-none' if combination_info['prevent_zero_price_sale'] else 'd-flex'}} flex-grow-1 flex-lg-grow-0 flex-wrap align-items-center gap-2 {{'' if is_50_pc else ' w-100'}}"
>
<a
id="add_to_cart"
role="button"
href="#"
t-attf-class="btn btn-primary js_check_product a-submit flex-grow-1"
t-att-data-show-quantity="is_view_active('website_sale.product_quantity')"
data-animation-selector=".o_wsale_product_images"
>
<i class="fa fa-shopping-cart me-2"/>
Add to cart
</a>
</div>
<div
id="product_option_block"
t-attf-class="d-flex d-empty-none flex-wrap gap-2 w-100 {{'w-sm-auto' if is_50_pc and not (is_view_active('website_sale.cta_wrapper_boxed') or is_view_active('website_sale.cta_wrapper_large')) else ''}}"
/>
</div>
</template>
<template
id="website_sale.cta_wrapper_boxed"
inherit_id="website_sale.cta_wrapper"
active="False"
name="Bordered CTA Wrapper"
>
<xpath expr="//div[@id='o_wsale_cta_wrapper']" position="attributes">
<attribute
name="t-att-class"
remove="pt-3"
add="' o_wsale_cta_wrapper_boxed border rounded p-3'"
separator=" + "
/>
</xpath>
<xpath expr="//div[@id='add_to_cart_wrap']" position="attributes">
<attribute name="t-attf-class" remove="flex-lg-grow-0" separator=" "/>
</xpath>
<xpath expr="//div[@id='product_option_block']" position="attributes">
<attribute name="t-att-class" remove="flex-lg-grow-0" separator=" "/>
</xpath>
<xpath expr="//div[@id='o_wsale_cta_wrapper']" position="inside">
<div class="d-flex gap-5 flex-grow-1 justify-content-between align-items-center order-first w-100 mb-3 pb-3 border-bottom">
<span name="o_wsale_cta_wrapper_boxed_price_label" class="text-muted">Price</span>
<t t-call="website_sale.product_price"/>
</div>
</xpath>
</template>
<template
id="website_sale.cta_wrapper_large"
inherit_id="website_sale.cta_wrapper"
active="False"
name="Large CTA Wrapper">
<xpath expr="//div[@id='o_wsale_cta_wrapper']" position="attributes">
<attribute name="t-att-class" add="' o_wsale_cta_wrapper_large'" separator=" + "/>
</xpath>
<xpath expr="//div[@id='add_to_cart_wrap']" position="attributes">
<attribute name="t-attf-class" remove="flex-lg-grow-0" separator=" "/>
</xpath>
<xpath expr="//div[@id='product_option_block']" position="attributes">
<attribute name="t-att-class" remove="flex-lg-grow-0" separator=" "/>
</xpath>
<xpath expr="//a[@id='add_to_cart']" position="attributes">
<attribute
name="t-attf-class"
add="btn-lg {{('' if is_50_pc else ' px-xl-0')}}"
separator=" "
/>
</xpath>
</template>
<template
id="website_sale.cta_separator"
inherit_id="website_sale.product"
name="Product Info - Dividers">
<xpath expr="//section[@id='product_detail']" position="attributes">
<attribute
name="t-attf-class"
add="o_wsale_product_page_opt_separators"
separator=" "
/>
</xpath>
</template>
<template
id="website_sale.product_search"
inherit_id="website_sale.product"
active="False"
name="Searchbar On Product Page"
>
<xpath expr="//div[hasclass('o_wsale_product_top_bar_desktop')]" position="inside">
<t t-call="website_sale.search">
<t t-set="search" t-value="False"/>
<t t-set="_classes" t-value="'me-sm-2'"/>
</t>
</xpath>
<xpath expr="//a[contains(@t-attf-class, 'o_wsale_product_search_mobile_btn')]" position="attributes">
<attribute name="t-attf-class" add="d-md-none" remove="d-none" separator=" "/>
</xpath>
</template>
<template id="all_products_link_name" name="All Products name">
<span placeholder="All products">All products</span>
</template>
<template id="product_accordion" name="Accordion On Product Page">
<div
t-if="is_view_active('website_sale_comparison.accordion_specs_item')
or is_view_active('website_sale.accordion_more_information')"
id="product_accordion"
class="o_accordion_not_initialized accordion accordion-flush my-4"
>
<div
t-if="is_view_active('website_sale.accordion_more_information')"
id="more_information_accordion_item"
class="accordion-item"
/>
</div>
</template>
<template
id="accordion_more_information"
name="More Information Accordion Item"
inherit_id="website_sale.product_accordion"
active="False"
>
<xpath expr="//div[@id='more_information_accordion_item']" position="inside">
<div class="accordion-header my-0 h6">
<button
class="accordion-button collapsed fw-medium"
type="button"
data-bs-toggle="collapse"
data-bs-target="#customizable_item"
aria-expanded="false"
aria-controls="customizable_item"
>
More Information
</button>
</div>
<div
id="customizable_item"
class="accordion-collapse collapse"
data-bs-parent="#product_accordion"
>
<div class="accordion-body py-0">
<p>This content will be shared across all product pages.</p>
</div>
</div>
</xpath>
</template>
<template id="website_sale.product_tags" name="Product Tags" active="True">
<t t-set="visible_tags" t-value="all_product_tags.filtered('visible_to_customers')"/>
<div
t-attf-class="o_product_tags o_field_tags {{ 'd-flex flex-wrap align-items-center gap-2 mb-2 mt-1' if visible_tags else '' }}"
>
<t t-foreach="visible_tags" t-as="tag">
<span t-if="tag.image"
class="order-0"
t-field="tag.image"
t-options="{'widget': 'image', 'class': 'o_product_tag_img rounded'}"
/>
<span t-else="" class="position-relative order-1 py-1 px-2">
<span class="position-absolute top-0 start-0 w-100 h-100 rounded"
t-attf-style="background-color: #{tag.color}; opacity: .2;"
/>
<span class="text-nowrap small"
t-attf-style="color: #{tag.color}"
t-field="tag.name"
/>
</span>
</t>
</div>
</template>
<template id="alternative_products" name="Alternative Products" inherit_id="website_sale.product" active="True">
<div t-field="product.website_description" position="after">
<div class="oe_structure oe_structure_solo oe_unremovable oe_unmovable" id="oe_structure_website_sale_recommended_products" t-ignore="true" t-if="product.alternative_product_ids">
<section data-snippet="s_dynamic_snippet_products"
class="oe_unmovable oe_unremovable s_dynamic_snippet_products o_wsale_alternative_products s_dynamic pt32 pb32 o_colored_level s_product_product_borderless_1"
data-name="Alternative Products" style="background-image: none;" t-att-data-filter-id="product._get_alternative_product_filter()"
data-template-key="website_sale.dynamic_filter_template_product_product_products_item" data-product-category-id="all" data-number-of-elements="4"
data-number-of-elements-small-devices="1" data-number-of-records="16" data-carousel-interval="5000" data-bs-original-title="" title="">
<div class="container">
<div class="row s_nb_column_fixed">
<section class="s_dynamic_snippet_title oe_unremovable oe_unmovable d-flex flex-column flex-md-row justify-content-between mb-lg-0 pb-3 pb-md-0">
<div>
<h4>Alternative Products</h4>
<p class="lead">These other products might interest you</p>
</div>
</section>
</div>
<div class="o_not_editable">
<div class="dynamic_snippet_template"/>
</div>
</div>
</section>
</div>
</div>
</template>
<template
name="Terms and Conditions"
id="website_sale.product_terms_and_conditions"
active="True"
priority="21">
<small class="text-muted mb-0">
<a href="/terms" class="o_translate_inline text-muted"><u>Terms and Conditions</u></a><br/>
30-day money-back guarantee<br/>
Shipping: 2-3 Business Days
</small>
</template>
<!-- Product options: Zoom -->
<template inherit_id='website_sale.product' id="product_picture_magnify_click" name="Image Zoom On Click">
<xpath expr='//div[hasclass("o_wsale_product_page")]' position='attributes'>
<attribute name="data-ecom-zoom-click">1</attribute>
<attribute name="class" separator=" " add="ecom-zoomable" />
</xpath>
</template>
<!-- Product options: OpenChatter -->
<template id="product_comment" inherit_id="website_sale.product" active="False" name="Discussion and Rating" priority="15">
<xpath expr="//div[@t-field='product.website_description']" position="after">
<div class="o_shop_discussion_rating border-top" data-anchor='true'>
<section id="o_product_page_reviews" class="container pt48 pb48" data-anchor='true'>
<a class="o_product_page_reviews_title d-flex justify-content-between text-reset text-decoration-none collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#o_product_page_reviews_content" aria-expanded="false" aria-controls="o_product_page_reviews_content">
<h2 class="fs-4 mb-0">Customer Reviews</h2>
<i class="oi align-self-center"/>
</a>
<div id="o_product_page_reviews_content" class="collapse mt-3">
<t t-call="portal.message_thread">
<t t-set="object" t-value="product"/>
<t t-set="display_rating" t-value="True"/>
<t t-set="message_per_page" t-value="5"/>
<t t-set="two_columns" t-value="true"/>
</t>
</div>
</section>
</div>
</xpath>
</template>
<template
id="website_sale.product_quantity"
inherit_id="website_sale.cta_wrapper"
name="Select Quantity"
>
<div id="add_to_cart_wrap" position="inside">
<div
t-attf-class="css_quantity input-group {{'d-none' if combination_info['prevent_zero_price_sale'] else 'd-inline-flex order-first'}} align-middle border"
contenteditable="false"
>
<a
t-attf-href="#"
class="css_quantity_minus btn btn-link pe-2 js_add_cart_json border-0"
aria-label="Remove one"
title="Remove one"
name="remove_one"
>
<i class="oi oi-minus text-600"/>
</a>
<input
type="text"
t-attf-class="form-control quantity text-center border-0"
data-min="1"
name="add_qty"
t-att-value="1"
/>
<a
t-attf-href="#"
class="css_quantity_plus btn btn-link ps-2 js_add_cart_json border-0"
aria-label="Add one"
title="Add one"
>
<i class="oi oi-plus text-600"/>
</a>
</div>
</div>
</template>
<template
id="website_sale.product_quantity_large"
inherit_id="website_sale.product_quantity"
active="False"
name="Select Quantity Large"
>
<xpath expr="//div[contains(@t-attf-class, 'css_quantity')]" position="attributes">
<attribute
name="t-attf-class"
add="input-group-lg {{(' css_quantity_50' if is_50_pc else '')}}"
separator=" "
/>
</xpath>
</template>
<template
id="website_sale.product_buy_now"
inherit_id="website_sale.cta_wrapper"
active="False"
name="Buy Now Button"
>
<xpath expr="//div[@id='add_to_cart_wrap']" position="inside">
<a
role="button"
t-attf-class="btn btn-outline-primary o_we_buy_now w-100 {{'' if is_view_active('website_sale.cta_wrapper_boxed') or is_view_active('website_sale.cta_wrapper_large') or not is_50_pc else 'w-sm-auto'}} {{'flex-grow-1' if not is_50_pc else ''}}"
href="#"
>
<i class="fa fa-bolt me-2"/>
Buy now
</a>
</xpath>
</template>
<template
id="website_sale.product_buy_now_large"
inherit_id="website_sale.product_buy_now"
active="False"
name="Large Buy Now Button"
>
<xpath expr="//a[contains(@t-attf-class, 'o_we_buy_now')]" position="attributes">
<attribute name="t-attf-class" add="btn-lg" separator=" "/>
</xpath>
</template>
<template id="website_sale.tax_indication" active="False">
<span
t-if="website.show_line_subtotals_tax_selection == 'tax_excluded'"
class="fs-6 fw-normal text-muted text-nowrap"
>
(Tax excluded)
</span>
<span t-else="" class="fs-6 fw-normal text-muted text-nowrap">
(Tax included)
</span>
</template>
<template id="product_price">
<div
name="product_price"
t-attf-class="product_price {{'d-none' if combination_info['prevent_zero_price_sale'] else 'd-inline-block'}}"
>
<div
name="product_price_container"
class="css_editable_mode_hidden d-flex align-items-baseline justify-content-end gap-2 flex-wrap h5 mb-0 text-wrap"
>
<span class="oe_price"
style="white-space: nowrap;"
t-out="combination_info['price']"
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
<span t-attf-class="text-muted oe_default_price mb-0 h6 {{'' if combination_info['has_discounted_price'] else 'd-none'}}"
style="text-decoration: line-through; white-space: nowrap;"
t-out="combination_info['list_price']"
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"
name="product_list_price"
/>
<t t-if="is_view_active('website_sale.tax_indication')" t-call="website_sale.tax_indication"/>
<del
name="product_price_strikethrough"
t-if="combination_info.get('compare_list_price') and (combination_info['compare_list_price'] &gt; combination_info['price'])"
class="text-muted ms-1 h6 oe_compare_list_price"
>
<bdi dir="inherit">
<span t-out="combination_info['compare_list_price']"
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
</bdi>
</del>
</div>
<div
t-if="editable"
name="product_list_price_container"
class="css_non_editable_mode_hidden decimal_precision h5"
t-att-data-precision="str(website.currency_id.decimal_places)"
>
<span t-field="product.list_price"
t-options="{'widget': 'monetary', 'display_currency': product.currency_id}"/>
<t t-if="is_view_active('website_sale.tax_indication')" t-call="website_sale.tax_indication"/>
<del t-if="combination_info.get('compare_list_price') and (combination_info['compare_list_price'] &gt; combination_info['price'])">
<bdi dir="inherit">
<span t-field="product.compare_list_price"
t-options="{'widget': 'monetary', 'display_currency': product.currency_id}"/>
</bdi>
</del>
</div>
<small t-if="combination_info.get('tax_disclaimer')" class="text-muted">
<t t-out="combination_info['tax_disclaimer']"/>
</small>
</div>
<div id="product_unavailable" t-attf-class="{{'d-flex' if combination_info['prevent_zero_price_sale'] else 'd-none'}}">
<br/>
</div>
</template>
<template id="wizard_checkout" name="Wizard Checkout">
<t t-call="website.step_wizard">
<t t-set="wizard_step" t-value="website._get_checkout_steps()"/>
</t>
</template>
<!-- /shop/extra_info route -->
<template id="extra_info" name="Checkout Extra Info" active="False">
<t t-call="website_sale.checkout_layout">
<t t-set="redirect" t-valuef="/shop/extra_info"/>
<t t-set="oe_structure">
<!-- This is the drag-and-drop area for website building blocs at the end of each
checkout page. This is append at the of the page in `checkout_layout`. The
templates created in the database to store blocs are hooked using XPath on the
`oe_struture` element ID. Therefore, we can't use dynamic IDs (like with
t-att-id) and each template needs to define a div element. -->
<div class="oe_structure" id="oe_structure_website_sale_extra_info_1"/>
</t>
<h4 class="mb-3">Extra info</h4>
<section class="s_website_form" data-vcss="001" data-snippet="s_website_form">
<div class="container">
<form
action="/website/form/"
method="post"
enctype="multipart/form-data"
class="o_mark_required s_website_form_no_recaptcha"
data-mark="*"
data-force_action="shop.sale.order"
data-model_name="sale.order"
data-success-mode="redirect"
data-success-page="/shop/payment"
hide-change-model="true"
>
<div class="s_website_form_rows s_col_no_bgcolor row">
<span id="s_website_form_result"/>
<div class="s_website_form_field col-12 pb-2 mb-0" data-type="char" data-name="Field">
<div class="s_col_no_resize s_col_no_bgcolor">
<label class="s_website_form_label col-form-label col-sm-auto" style="width: 200px" for="sale1">
<span class="s_website_form_label_content">Your Reference</span>
</label>
<div class="col-sm">
<input id="sale1" type="text" class="s_website_form_input form-control" name="client_order_ref"/>
</div>
</div>
</div>
<div class="s_website_form_field s_website_form_custom col-12 pb-2 mb-0" data-type="text" data-name="Field">
<div class="s_col_no_resize s_col_no_bgcolor">
<label class="s_website_form_label col-form-label col-sm-auto" style="width: 200px" for="sale2">
<span class="s_website_form_label_content">Give us your feedback</span>
</label>
<div class="col-sm">
<textarea id="sale2" class="s_website_form_input form-control" name="Give us your feedback" />
</div>
</div>
</div>
<div class="s_website_form_field s_website_form_custom col-12 pb-2 mb-0" data-type="binary" data-name="Field">
<div class="s_col_no_resize s_col_no_bgcolor">
<label class="s_website_form_label col-form-label col-sm-auto" style="width: 200px" for="sale3">
<span class="s_website_form_label_content">Upload a document</span>
</label>
<div class="col-sm">
<input id="sale3" type="file" class="s_website_form_input form-control" name="a_document" />
</div>
</div>
</div>
</div>
</form>
</div>
</section>
</t>
</template>
<!-- Encapsulate the content in a `a` tag with a link to the product page. Override this
template to change or remove the product link. Called in `website_sale.cart_lines`. -->
<template id="cart_line_product_link" name="Shopping Cart Line Product Link">
<a
t-if="line._is_sellable()"
class="text-reset"
t-att-href="line.product_id.website_url"
name="o_cart_line_product_link"
>
<t t-out="0"/>
</a>
<t t-else="" t-out="0"/>
</template>
<!-- This template displays all the lines following the first one on the description of the sale
order line, with a muted style. For typical products this content will be the product
description_sale. Called in `website_sale.cart_lines`. -->
<template id="cart_line_description_following_lines" name="Shopping Cart Line Description Following Lines">
<t t-set="description_lines" t-value="line.get_description_following_lines()"/>
<div t-if="description_lines" class="text-muted small">
<t t-foreach="description_lines" t-as="name_line">
<span
t-if="name_line"
t-attf-class="d-block #{not name_line_last and 'mb-1'}"
t-out="name_line"
/>
</t>
</div>
</template>
<!-- Lines that show items in the cart. Called in `website_sale.cart`. -->
<template id="cart_lines" name="Shopping Cart Lines">
<div
t-if="not website_sale_order or not website_sale_order.website_order_line"
class="js_cart_lines w-100"
>
<div class="mt-5 mb-3"><t t-call="website_sale.empty_cart_svg"/></div>
<h5 class="mb-3" style="text-align: center;">
Your cart is empty!
</h5>
<p style="text-align: center;">
<a href="/shop" class="btn btn-primary">
Shop
</a>
</p>
</div>
<t t-if='website_sale_order'>
<div t-if='website_sale_order._get_shop_warning(clear=False)' class="alert alert-warning js_cart_lines" role="alert">
<strong>Warning!</strong>
<div t-out="website_sale_order._get_shop_warning()" class="text-prewrap"/>
</div>
</t>
<div id="cart_products"
t-if="website_sale_order and website_sale_order.website_order_line"
class="js_cart_lines d-flex flex-column mb32">
<t t-foreach="website_sale_order.website_order_line" t-as="line">
<t t-set="is_combo" t-value="line.product_type == 'combo'"/>
<div
class="o_cart_product d-flex gap-3 pb-4"
t-attf-data-product-id="#{line.product_id and line.product_id.id}"
>
<div
class="o_cart_product_image"
>
<!--
Unsellable lines can have unpublished products, but portal users have no
access to unpublished product images. To ensure product images are
always shown for unsellable lines, we use the raw image data as src
(which doesn't require access, unlike the image URL).
-->
<t t-call="website_sale.cart_line_product_link">
<img
t-if="not line._is_sellable() and line.product_id.image_128"
t-att-src="image_data_uri(line.product_id.image_128)"
class="img border rounded"
t-att-alt="line.name_short"
/>
<div
t-else=""
t-field="line.product_id.image_128"
t-options="{
'widget': 'image',
'qweb_img_responsive': False,
'class': 'border rounded',
}"
/>
</t>
</div>
<div class="d-flex flex-column flex-grow-1 gap-3 min-w-0">
<div class="d-flex gap-3">
<div class="flex-grow-1 text-wrap w-100">
<div class="d-flex justify-content-between">
<div class="d-md-flex flex-md-wrap column-gap-md-1 align-items-md-center">
<t t-call="website_sale.cart_line_product_link">
<h6
t-out="line._get_line_header()"
class="text-wrap mb-1"
/>
</t>
<t t-set="combination_name" t-value="line._get_combination_name()"/>
<span t-if="combination_name" class="d-none d-md-inline h6 text-muted mb-1">-</span>
<div
t-if="combination_name or line.product_template_id._has_multiple_uoms()"
class="d-inline-flex flex-wrap column-gap-2 row-gap-1 align-items-center my-1 my-md-0 w-100 w-md-auto"
>
<span
t-if="combination_name"
class="h6 text-muted mb-1"
t-out="combination_name"
/>
<span
t-if="line.product_template_id._has_multiple_uoms()"
class="badge bg-light mb-1"
t-out="line.product_uom_id.name"
/>
</div>
</div>
<div t-attf-class="{{'d-block d-md-none' if not is_combo else ''}}"><t t-call="website_sale.cart_lines_price"/></div>
</div>
<t t-call="website_sale.cart_line_description_following_lines"/>
<ul t-if="is_combo" class="list-group">
<t
t-foreach="line.linked_line_ids.filtered('combo_item_id')"
t-as="combo_item_line"
>
<t t-call="website_sale.cart_combo_item_line"/>
</t>
</ul>
<div
name="o_wsale_cart_line_button_container"
t-attf-class="d-none d-md-flex align-items-center gap-2 mt-2 {{'justify-content-between' if is_combo else ''}}"
>
<a
href='#'
class="js_delete_product small"
aria-label="Remove from cart"
title="Remove from cart"
>
Remove
</a>
<div t-if="is_combo" class="d-none d-md-block ms-auto"><t t-call="website_sale.cart_lines_quantity"/></div>
</div>
</div>
<div t-if="not is_combo" class="d-none d-md-block">
<t t-call="website_sale.cart_lines_price"/>
<div class="d-none d-md-block mt-2"><t t-call="website_sale.cart_lines_quantity"/></div>
</div>
</div>
<div
name="o_wsale_cart_line_button_container_mobile"
class="d-flex d-md-none"
>
<div class="d-flex d-md-none align-items-center me-auto">
<t t-call="website_sale.cart_lines_quantity" is_mobile="True"/>
</div>
<button
class="js_delete_product btn btn-link d-inline-block d-md-none px-2"
title="Remove"
>
<i class="fa fa-fw fa-trash-o"/>
</button>
</div>
</div>
</div>
</t>
</div>
</template>
<template id="cart_lines_quantity" name="Shopping Cart Line quantity">
<t
t-set="should_show_quantity_selector"
t-value="is_view_active('website_sale.product_quantity')"
/>
<div
t-attf-class="css_quantity input-group justify-content-end h-100 {{should_show_quantity_selector and line._is_sellable() and 'border' or ''}}"
t-attf-name="{{'website_sale_cart_line_quantity' if not is_mobile else 'website_sale_cart_line_quantity_mobile'}}"
>
<t t-if="should_show_quantity_selector and line._is_sellable()">
<a
href="#"
class="btn btn-link d-inline-block border-end-0"
aria-label="Remove one"
title="Remove one"
>
<i class="oi oi-minus position-relative z-1"/>
</a>
<input
type="text"
class="js_quantity quantity form-control border-0"
t-att-data-line-id="line.id"
t-att-data-product-id="line.product_id.id"
t-att-value="line._get_displayed_quantity()"
/>
<t t-if="line._get_shop_warning(clear=False)">
<a href="#" class="btn btn-link">
<i
class="fa fa-warning text-warning"
t-att-title="line._get_shop_warning()"
role="img"
aria-label="Warning"
/>
</a>
</t>
<a
t-else=""
href="#"
class="btn btn-link d-inline-block border-start-0"
aria-label="Add one"
title="Add one"
>
<i class="oi oi-plus position-relative z-1"/>
</a>
</t>
<t t-else="">
<input
type="text"
class="js_quantity form-control quantity text-start text-md-end text-md-end border-0 p-0 shadow-none mw-100"
t-att-data-line-id="line.id"
t-att-data-product-id="line.product_id.id"
t-att-value="line._get_displayed_quantity()"
readonly="True"
/>
</t>
</div>
</template>
<template id="cart_lines_price" name="Shopping Cart Line Price">
<h6
class="d-flex flex-column flex-md-row align-items-end align-items-md-start justify-content-md-end mb-1"
name="website_sale_cart_line_price"
>
<del
t-if="line._should_show_strikethrough_price()"
class="me-md-2 text-muted text-nowrap opacity-50"
t-out="line._get_displayed_unit_price() * line.product_uom_qty"
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"
/>
<t t-set="product_price" t-value="line._get_cart_display_price()"/>
<t t-call="website_sale.cart_product_price"/>
</h6>
<small
t-if="line._is_sellable() and line.env['res.groups']._is_feature_enabled('website_sale.group_show_uom_price') and line.product_id.base_unit_price"
class="cart_product_base_unit_price d-block text-muted text-end"
groups="website_sale.group_show_uom_price"
>
<t t-call="website_sale.base_unit_price">
<t t-set="product" t-value="line.product_id"/>
<t
t-set="base_unit_price"
t-value="product._get_base_unit_price(product_price/line.product_qty)"
/>
</t>
</small>
</template>
<template id="cart_combo_item_line">
<a
t-att-href="combo_item_line.product_id.website_url if combo_item_line._is_sellable() and combo_item_line.product_id.website_published else '#'"
t-attf-class="list-group-item #{'list-group-item-action' if combo_item_line._is_sellable() and combo_item_line.product_id.website_published else 'cursor-default text-decoration-none'}"
>
<h6 class="d-inline small">
<span t-out="combo_item_line._get_displayed_quantity()"/>
x
<span t-out="combo_item_line.name_short"/>
</h6>
<t
t-set="description_lines"
t-value="combo_item_line.get_description_following_lines()"
/>
<div t-if="description_lines" class="small text-muted">
<t t-foreach="description_lines" t-as="description_line">
<span
t-if="description_line"
class="d-block"
t-out="description_line"
/>
</t>
</div>
</a>
</template>
<template id="cart_product_price">
<span
t-out="product_price"
style="white-space: nowrap;"
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"
/>
</template>
<!-- /shop/cart route -->
<template id="cart" name="Shopping Cart">
<t t-call="website_sale.checkout_layout">
<t t-set="show_shorter_cart_summary" t-value="True"/>
<t t-set="show_footer" t-value="True"/>
<t t-set="oe_structure">
<!-- This is the drag-and-drop area for website building blocs at the end of each
checkout page. This is append at the of the page in `checkout_layout`. The
templates created in the database to store blocs are hooked using XPath on the
`oe_struture` element ID. Therefore, we can't use dynamic IDs (like with
t-att-id) and each template needs to define a div element. -->
<div class="oe_structure" id="oe_structure_website_sale_cart_2"/>
</t>
<div id="shop_cart" class="col">
<div class="d-flex align-items-center mb-3">
<h4 class="mb-0">Order summary</h4>
<div class="ms-3 border-start ps-2"><t t-call="website_sale.quick_reorder_button"/></div>
</div>
<div t-if="abandoned_proceed or access_token" class="alert alert-info mt8 mb8" role="alert"> <!-- abandoned cart choices -->
<t t-if="abandoned_proceed">
<p>Your previous cart has already been completed.</p>
<p t-if="website_sale_order">Please proceed your current cart.</p>
</t>
<t t-if="access_token">
<p>This is your current cart.</p>
<p>
<strong>
<a class="o_translate_inline" t-attf-href="/shop/cart/?id={{id}}&amp;access_token={{access_token}}&amp;revive_method=squash">Click here</a>
</strong> if you want to restore your previous cart. Your current cart will be replaced with your previous cart.
</p>
<p>
<strong>
<a class="o_translate_inline" t-attf-href="/shop/cart/?id={{id}}&amp;access_token={{access_token}}&amp;revive_method=merge">Click here</a>
</strong> if you want to merge your previous cart into current cart.
</p>
</t>
</div>
<t t-call="website_sale.cart_lines"/>
<div class="clearfix" />
<div class="oe_structure" id="oe_structure_website_sale_cart_1"/>
</div>
</t>
</template>
<template id="quick_reorder_button">
<t t-set="quick_reorder_button_title">
<t t-if="request.website.is_public_user()">Login to reorder</t>
<t t-elif="not order_history">No previous products available for reorder.</t>
</t>
<span t-att-title="quick_reorder_button_title">
<button
id="quick_reorder_button"
type="button"
class="btn btn-sm btn-link"
data-bs-toggle="offcanvas"
data-bs-target="#quick_reorder_sidebar"
aria-controls="quick_reorder_sidebar"
t-att-disabled="not order_history"
>
<i class="fa fa-rotate-left me-2"/>Quick reorder
</button>
</span>
<t t-call="website_sale.quick_reorder_sidebar"/>
</template>
<template id="quick_reorder_sidebar">
<div
id="quick_reorder_sidebar"
class="offcanvas offcanvas-end"
aria-labelledby="quick_reorder_sidebar"
>
<div class="offcanvas-header">
<h5 class="offcanvas-title">Quick reorder</h5>
<button
type="button"
class="btn-close text-reset"
data-bs-dismiss="offcanvas"
aria-label="Close"
/>
</div>
<div class="offcanvas-body">
<!-- Parent element needed for proper JS side rendering -->
<t t-if="order_history" t-call="website_sale.quick_reorder_history"/>
</div>
</div>
</template>
<template id="quick_reorder_history">
<div
class="o_wsale_quick_reorder_line_group ps-sm-3"
t-foreach="order_history"
t-as="order_line_group"
>
<div class="o_wsale_quick_reorder_group_content d-flex gap-3 w-100 position-relative">
<div
class="o_dot_line d-none d-sm-block position-absolute top-0 bottom-0 mb-1 border-start"
/>
<span
class="o_dot d-none d-sm-block position-absolute translate-middle-x text-o-color-1"
/>
<div class="w-100 ps-sm-4">
<h6 t-out="order_line_group['label']" class="mt-1 mb-3 text-muted"/>
<div
t-foreach="order_line_group['lines']"
t-as="order_line"
t-att-class="'o_wsale_quick_reorder_line d-flex flex-column flex-sm-row justify-content-between gap-3 '
+ ('align-items-start' if order_line.product_type == 'combo' else '')"
>
<div
t-att-class="'d-flex gap-2 ' + ('align-items-start' if order_line.product_type == 'combo' else 'align-items-center')"
>
<div class="o_cart_product_image">
<div
t-field="order_line.product_id.image_128"
t-options="{
'widget': 'image',
'qweb_img_responsive': False,
'class': 'border rounded',
}"
/>
</div>
<div
class="d-flex flex-column align-items-start justify-content-center flex-grow-1 h-100"
>
<div>
<h6
t-out="order_line.name_short"
t-att-class="'small ' + ('mb-2' if order_line.product_type == 'combo' else 'mb-0')"
/>
<ul
t-if="order_line.product_type == 'combo'" class="list-group"
>
<t
t-foreach="order_line.linked_line_ids"
t-as="combo_item_line"
t-call="website_sale.cart_combo_item_line"
/>
</ul>
</div>
<small
t-if="order_line.product_template_id._has_multiple_uoms()"
t-out="order_line.product_uom_id.name"
class="badge mt-1 bg-light"
/>
</div>
</div>
<div class="d-flex align-items-center ms-auto gap-2">
<t
t-set="combination_info"
t-value="order_line.product_id._get_combination_info_variant()"
/>
<small
t-out="combination_info['price'] * order_line.product_uom_qty"
t-options="{
'widget': 'monetary',
'display_currency': website.currency_id,
}"
class="o_wsale_quick_reorder_product_price"
style="white-space: nowrap;"
/>
<input
type="text"
t-att-value="int(order_line.product_uom_qty)"
class="o_wsale_quick_reorder_qty_input form-control text-center"
t-att-data-price-unit="combination_info['price']"
t-att-data-currency-digits="combination_info['currency'].decimal_places"
/>
<button
type="button"
title="Press 'Enter' to add to cart"
class="o_wsale_quick_reorder_product_button btn btn-outline-primary"
t-att-data-quantity="order_line.product_uom_qty"
t-att-data-product-id="order_line.product_id.id"
t-att-data-product-template-id="order_line.product_id.product_tmpl_id.id"
t-att-data-product-type="order_line.product_id.type"
t-att-data-selected-combo-items="json.dumps(order_line._get_selected_combo_items())"
>
<i class="fa fa-cart-plus"/>
</button>
</div>
</div>
</div>
</div>
</div>
</template>
<!-- Deactivatable through the website editor. -->
<template id="suggested_products_list" inherit_id="website_sale.cart_lines" name="Accessory Products in my cart">
<xpath expr="//div[@id='cart_products']" position="inside">
<h5 t-attf-class="mt-3 mb-0" t-if="suggested_products">Suggested accessories</h5>
<div t-if="suggested_products"
id="suggested_products"
class="d-flex flex-column align-items-stretch">
<div
t-foreach="suggested_products"
t-as="product"
t-attf-class="d-flex gap-3 py-4 #{not product_last and 'border-bottom'}"
t-att-data-publish="product.website_published and 'on' or 'off'"
name="suggested_product"
>
<div class="o_cart_product_image">
<a t-att-href="product.website_url">
<div t-field="product.image_128" t-options="{'widget': 'image', 'qweb_img_responsive': False, 'class': 'border rounded'}"/>
</a>
</div>
<div class="flex-grow-1">
<div class="d-flex justify-content-between">
<div>
<a class="text-reset" t-att-href="product.website_url">
<h6
class="align-top text-wrap"
t-out="product.with_context(display_default_code=False).display_name"
/>
</a>
<div
class="mb-2 small text-muted"
t-field="product.description_sale"
/>
</div>
<div class="d-flex flex-column gap-2 align-items-end">
<h6
class="d-flex mb-0 text-end"
name="suggested_product_price_container"
>
<t
t-set="combination_info"
t-value="product._get_combination_info_variant()"
/>
<del
name="suggested_product_list_price"
t-attf-class="me-2 text-nowrap text-muted {{'' if combination_info['has_discounted_price'] else 'd-none'}}"
t-out="combination_info['list_price']"
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"
/>
<span
name="suggested_product_price"
class="text-nowrap"
t-out="combination_info['price']"
t-options="{'widget': 'monetary','display_currency': website.currency_id}"
/>
</h6>
<button
class="js_add_suggested_products btn btn-primary text-nowrap"
t-att-data-product-id="product.id"
t-att-data-product-template-id="product.product_tmpl_id.id"
t-att-data-product-type="product.type"
t-att-data-show-quantity="is_view_active('website_sale.product_quantity')"
>
<i class="d-md-none fa fa-shopping-cart" role="presentation"/>
<span class="d-none d-md-inline">Add to cart</span>
</button>
</div>
</div>
</div>
</div>
</div>
</xpath>
</template>
<!-- Called in `website_sale.reduction_code`. -->
<template id='coupon_form' name='Coupon form'>
<!-- Checkout context:
- redirect: The route to redirect to when a customer enters a coupon; default: `None`.
- website_sale_order: The current order.
-->
<form
class="mb-3"
t-attf-action="/shop/pricelist#{redirect and '?r=' + redirect or ''}"
method="post"
name="coupon_code"
>
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="input-group w-100">
<input name="promo" class="form-control" type="text" placeholder="Discount code..." t-att-value="website_sale_order.pricelist_id.code or None"/>
<button type="submit" class="btn btn-light border">Apply</button>
</div>
</form>
<t t-if="request.params.get('code_not_available')" name="code_not_available">
<div class="alert alert-danger text-start" role="alert">This promo code is not available.</div>
</t>
</template>
<!-- Called in `website_sale.checkout_layout`. -->
<template id="navigation_buttons" name="Navigation buttons">
<!-- Layout customization parameters:
- hide_payment_button: Whether the payment button should be hidden; default: False.
-->
<!-- Checkout context:
- website_sale_order: The current order.
-->
<div t-attf-class="#{_container_classes} d-flex flex-column gap-2">
<t t-if="website_sale_order and website_sale_order.website_order_line">
<t
t-if="(website.account_on_checkout != 'mandatory' or
not website.is_public_user()) and show_shorter_cart_summary"
t-call="payment.express_checkout"
/>
<t t-if="current_website_checkout_step_href == '/shop/payment'">
<div t-if="not errors and not website_sale_order.amount_total"
name="o_website_sale_free_cart">
<form name="o_wsale_confirm_order"
class="d-flex flex-column"
target="_self"
action="/shop/payment/validate"
method="post">
<input type="hidden"
name="csrf_token"
t-att-value="request.csrf_token()"/>
<t t-if="not hide_payment_button" t-call="payment.submit_button">
<t t-set="submit_button_label">Confirm Order</t>
</t>
</form>
</div>
<t t-elif="not hide_payment_button" t-call="payment.submit_button"/>
</t>
<t t-else="">
<a role="button" name="website_sale_main_button"
t-attf-class="btn btn-primary #{not website_sale_order._is_cart_ready() and 'disabled'} w-100"
t-att-href="next_website_checkout_step_href">
<span t-field="next_website_checkout_step.main_button_label"/>
<i class="fa fa-angle-right ms-2 fw-light"/>
</a>
</t>
</t>
<div t-if="not hide_payment_button" class="position-relative d-none d-lg-flex w-100 justify-content-center align-items-center my-2 opacity-75">
<hr class="w-100"/>
<span class="px-3">or</span>
<hr class="w-100"/>
</div>
<t t-if="previous_website_checkout_step">
<a
t-att-href="previous_website_checkout_step.step_href"
class="mt-2 mt-lg-0 text-center"
>
<i class="fa fa-angle-left me-2 fw-light"/>
<span t-field="previous_website_checkout_step.back_button_label"/>
</a>
</t>
<t t-else="">
<a t-att-href="'/shop'" class="mt-2 mt-lg-0 text-center">
<i class="fa fa-angle-left me-2 fw-light"/>
Continue shopping
</a>
</t>
</div>
</template>
<!-- /shop/checkout route -->
<template id="checkout">
<t t-call="website_sale.checkout_layout">
<t t-set="additional_title">Shop - Checkout</t>
<t t-set="redirect" t-valuef="/shop/checkout"/>
<t t-set="same_shipping" t-value="bool(order.partner_shipping_id==order.partner_invoice_id or only_services)" />
<div id="shop_checkout">
<t t-if="order._has_deliverable_products()">
<div class="mb-4">
<t t-call="website_sale.delivery_form">
<t t-set="selected_dm_id" t-value="order.carrier_id.id"/>
</t>
</div>
<div class="mb-4">
<t t-call="website_sale.delivery_address_list">
<t t-set="addresses" t-value="delivery_addresses"/>
</t>
</div>
</t>
<t t-call="website_sale.billing_address_list">
<t t-set="addresses" t-value="billing_addresses"/>
</t>
</div>
</t>
</template>
<template id="delivery_address_list">
<t t-set="address_type" t-value="'delivery'"/>
<t
t-set="new_address_url"
t-valuef="{{address_url}}?address_type={{address_type}}&amp;use_delivery_as_billing={{use_delivery_as_billing}}"
/>
<div id="delivery_address_list">
<div class="d-flex justify-content-between align-items-start gap-3 mb-3">
<h5 name="delivery_address_title" class="mb-0">Delivery address</h5>
<!-- We don't allow public users to have multiple delivery addresses. -->
<a
t-if="not order.website_id.is_public_user()"
role="button"
t-att-href="new_address_url"
t-att-data-address-type="address_type"
class="o_address_card_add_new btn btn-outline-primary btn-sm"
title="Add an address"
aria-label="Add an address"
>
<i class="oi oi-plus me-2"/>Add Address
</a>
</div>
<t t-call="website_sale.address_list">
<t t-set="addresses" t-value="delivery_addresses"/>
<t t-set="selected_address" t-value="order.partner_shipping_id"/>
</t>
</div>
</template>
<template id="billing_address_list">
<t t-set="address_type" t-value="'billing'"/>
<t t-set="new_address_url" t-valuef="{{address_url}}?address_type={{address_type}}"/>
<t t-set="has_delivery" t-value="order._has_deliverable_products()"/>
<div id="billing_address_list" class="mb-3 pt-2">
<div class="d-flex justify-content-between align-items-start gap-3">
<p t-attf-class="mb-0 {{only_services and 'h4' or 'h5'}}">
Billing address
</p>
<a
role="button"
t-att-href="new_address_url"
t-att-data-address-type="address_type"
t-attf-class="o_address_card_add_new o_add_billing_address_btn btn btn-outline-primary btn-sm {{'d-none' if use_delivery_as_billing and has_delivery else ''}}"
title="Add an address"
aria-label="Add an address"
>
<i class="oi oi-plus me-2"/>Add Address
</a>
</div>
<div t-if="has_delivery" class="form-check form-switch mt-2">
<label id="use_delivery_as_billing_label">
<input
type="checkbox"
id="use_delivery_as_billing"
class="form-check-input"
t-att-checked="use_delivery_as_billing"
/>
<span name="use_delivery_as_billing_text">
Same as delivery address
</span>
</label>
</div>
<div
id="billing_container"
t-attf-class="mt-3 {{'d-none' if use_delivery_as_billing and has_delivery else ''}}"
>
<t t-call="website_sale.address_list">
<t t-set="addresses" t-value="billing_addresses"/>
<t t-set="selected_address" t-value="order.partner_invoice_id"/>
</t>
</div>
</div>
</template>
<template id="website_sale.address_list" inherit_id="portal.address_list" primary="True">
<t t-call="portal.address_card" position="replace">
<t t-call="website_sale.address_card">
<!-- Drop show_removal and address_update_url which were in the base call to portal.address_card -->
<t t-set="is_user_address" t-value="address == request.env.user.partner_id"/>
<t t-set="contact" t-value="address"/>
<t
t-set="can_be_edited"
t-value="contact._can_be_edited_by_current_customer(order_sudo=order)"
/>
<t t-set="selected" t-value="address == selected_address"/>
</t>
</t>
</template>
<!-- To ensure modification dones in the checkout are not applied on the portal -->
<template id="website_sale.address_card" inherit_id="portal.address_card" primary="True"/>
<!-- /shop/address route -->
<template id="website_sale.address_form_fields" inherit_id="portal.address_form_fields" primary="True">
<t name="b2b_fields" position="attributes">
<attribute name="t-if">display_b2b_fields</attribute>
</t>
</template>
<!-- /shop/address route -->
<template id="website_sale.address" name="Address Management">
<t t-call="website_sale.checkout_layout">
<div class="o_customer_address_fill">
<div>
<t t-if="not is_anonymous_cart">
<h4 class="mb-3">
<t t-if="partner_sudo">Edit address</t>
<t t-else="">New address</t>
</h4>
</t>
<div
t-if="use_delivery_as_billing and not only_services and partner_sudo"
class="alert alert-warning"
role="alert"
>
<p class="mb-0">
You are editing your <b>delivery and billing</b> addresses
at the same time!<br/>
If you want to modify your billing address, create a
<a class="o_translate_inline" href="/shop/address?address_type=billing">new address</a>.
</p>
</div>
<div id="errors"/> <!-- for js -->
<form
action="/shop/address/submit"
method="post"
name="address_form"
class="address_autoformat"
t-att-data-company-country-code="res_company.country_id.code"
t-att-data-submit-url="'/shop/address/submit'"
>
<t t-if="is_anonymous_cart">
<div class="d-flex flex-column flex-md-row align-items-center justify-content-between mb-1">
<h4 class="w-100 w-md-auto">Details</h4>
<div
t-if="website.account_on_checkout != 'disabled'"
class="o_address_signin d-flex d-md-block justify-content-between align-items-center p-3 p-md-0 w-100 text-md-end"
>
<span class="align-middle">Already have an account?</span>
<a
role="button"
href='/web/login?redirect=/shop/checkout'
class="btn btn-primary ms-2"
>
Sign in
</a>
</div>
</div>
</t>
<div class="row">
<t t-call="website_sale.address_form_fields"/>
</div>
</form>
</div>
</div>
</t>
</template>
<!-- Deactivatable through the website editor. -->
<template id="address_b2b" inherit_id="website_sale.address" name="Show b2b fields" />
<template id="address_edit_button" name="Address edit button">
<t t-if="xmlid != 'website_sale.confirmation'">
<a t-if="order.partner_invoice_id.country_id" class="float-end no-decoration" href="/shop/checkout">
<i class="fa fa-pencil me-1"/>Edit
</a>
<a
t-else=""
class="float-end no-decoration"
t-attf-href="/shop/address?partner_id={{order.partner_invoice_id.id}}&amp;address_type=billing"
>
<i class="fa fa-pencil me-1"/>Want an invoice?
</a>
</t>
</template>
<!-- Called in `website_sale.payment` and `website_sale.confirmation`. -->
<template id="address_on_checkout" name="Address on payment">
<div class="card">
<div class="card-body" id="delivery_and_billing">
<t t-call="website_sale.address_edit_button"/>
<t t-set="delivery_title_classes" t-value="'badge text-bg-info mb-2'"/>
<t
t-set="use_delivery_as_billing"
t-value="order.partner_invoice_id == order.partner_shipping_id and not order.pickup_location_data"
/>
<div class="d-flex flex-column flex-md-row gap-4">
<div
t-if="not use_delivery_as_billing and order._has_deliverable_products()"
t-attf-class="{{not use_delivery_as_billing and not only_services and 'col'}}"
>
<t t-if="order.pickup_location_data">
<p t-att-class="delivery_title_classes">Deliver to pickup point</p>
<div
class="fw-bold" t-out="order.pickup_location_data.get('name', '')"
/>
<div t-out="order.pickup_location_data.get('street', '')"/>
<div t-out="order.pickup_location_data.get('city', '')
+ ' ' + order.pickup_location_data.get('zip_code','')"
/>
</t>
<t t-else="">
<p t-att-class="delivery_title_classes">Delivery</p>
<t
t-out="order.partner_shipping_id"
t-options="dict(
widget='contact',
fields=['name', 'address'],
no_marker=True,
)"
/>
</t>
</div>
<div t-attf-class="{{not use_delivery_as_billing and not only_services and 'col'}}">
<p t-if="use_delivery_as_billing and not only_services" t-att-class="delivery_title_classes">Delivery &amp; Billing</p>
<p t-else="" t-att-class="delivery_title_classes">Billing</p>
<t
t-out="order.partner_invoice_id"
t-options="dict(
widget='contact',
fields=['name', 'address'],
no_marker=True,
)"
/>
</div>
</div>
</div>
</div>
</template>
<!-- /shop/payment route -->
<template id="payment" name="Payment">
<t t-call="website_sale.checkout_layout">
<t t-set="additional_title">Shop - Select Payment Method</t>
<t t-set='redirect' t-valuef="/shop/payment"/>
<t t-set="oe_structure">
<!-- This is the drag-and-drop area for website building blocs at the end of each
checkout page. This is append at the of the page in `checkout_layout`. The
templates created in the database to store blocs are hooked using XPath on the
`oe_struture` element ID. Therefore, we can't use dynamic IDs (like with
t-att-id) and each template needs to define a div element. -->
<div class="oe_structure" id="oe_structure_website_sale_payment_2"/>
</t>
<div class="col-12" t-if="errors">
<t t-set="hide_payment_button" t-value="True"/>
<t t-foreach="errors" t-as="error">
<div class="alert alert-danger" t-if="error" role="alert">
<h4>
<t t-out="error[0]" />
</h4>
<t t-out="error[1]" />
</div>
</t>
</div>
<div class="oe_structure clearfix" id="oe_structure_website_sale_payment_1"/>
<div t-if="not errors and website_sale_order.amount_total" name="website_sale_non_free_cart">
<div id="payment_method" class="o_not_editable mb-3">
<t t-call="payment.form"/>
</div>
<t t-if="not (payment_methods_sudo or tokens_sudo)" t-set="hide_payment_button" t-value="True"/>
</div>
<h4 t-else="" class="mb-3">
Confirm order
</h4>
<div id="address_on_payment">
<t t-call="website_sale.address_on_checkout"/>
</div>
</t>
</template>
<!-- Activatable through the website editor. -->
<template id="accept_terms_and_conditions"
inherit_id="navigation_buttons"
name="Accept Terms &amp; Conditions"
active="False">
<xpath expr="//div[@name='o_website_sale_free_cart']" position="before">
<div name="website_sale_terms_and_conditions_checkbox" class="form-check mb-2">
<input type="checkbox" id="website_sale_tc_checkbox" class="form-check-input"/>
<label for="website_sale_tc_checkbox" class="form-check-label">
I agree to the <a target="_BLANK" href="/terms">terms &amp; conditions</a>
</label>
</div>
</xpath>
</template>
<!-- Template of the checkout pages. Should be called in every page of the checkout flow. -->
<template id="checkout_layout" name="Checkout layout page">
<!-- Layout customization parameters:
- show_footer: Whether to show the website footer; default: `False`.
- show_navigation_button: Whether to show the navigation buttons; default: `True`.
- show_wizard_checkout: Whether to show the wizard checkout; default: `True`.
- show_shorter_cart_summary: Whether to show the shorter cart_summary (without items
summary and with express checkout buttons) or the full;
default: `None`.
- show_mobile_cart_summary: Whether to show the mobile offcanvas cart_summary;
default: `True`.
- oe_structure: The structure element to append at the bottom of the page;
default: `None`.
-->
<!-- Checkout context (non exhaustive):
- redirect: The route to redirect to when a customer enters a coupon; default: `None`.
- website_sale_order: The current order.
-->
<t t-call="website.layout">
<t t-set="no_footer" t-value="True if show_footer is None else not show_footer"/>
<t t-set="show_navigation_button" t-value="True if show_navigation_button is None else show_navigation_button"/>
<t t-set="expand_order_summary" t-value="not show_navigation_button"/>
<t t-set="show_wizard_checkout" t-value="True if show_wizard_checkout is None else show_wizard_checkout"/>
<t
t-set="show_mobile_cart_summary"
t-value="True if show_mobile_cart_summary is None else show_mobile_cart_summary"
/>
<t t-set="body_classname" t-value="'o_website_sale_checkout'"/>
<div id="wrap" class="d-flex flex-column flex-grow-1">
<div class="oe_website_sale o_website_sale_checkout_container container d-flex flex-column flex-grow-1 py-lg-2">
<div t-attf-class="row #{not show_wizard_checkout and 'mt32'} mb32">
<div t-if="show_wizard_checkout" class="col-12">
<t t-call="website_sale.wizard_checkout"/>
</div>
<!-- Checkout Page Content | Left Column -->
<div
t-attf-class="oe_clear_stucture oe_cart col-12 #{'col-lg-7' if website_sale_order and website_sale_order.website_order_line else ''}"
>
<t t-out="0"/>
</div>
<!-- Short Checkout Summary displayed on /cart | Right Column -->
<div
t-if="show_shorter_cart_summary"
class="o_wsale_shorter_cart_summary offset-xxl-1 col-lg-5 col-xxl-4"
>
<!-- Parent element needed for proper JS side rendering -->
<t t-call="website_sale.shorter_cart_summary"/>
</div>
<!-- Full Checkout Summary displayed on all checkout pages | Right Column -->
<div
t-else=""
class="d-none d-lg-block offset-xxl-1 col-12 col-lg-5 col-xxl-4 rounded"
>
<div class="o_total_card card sticky-lg-top o_wsale_sticky_object mb-3 mb-lg-0">
<div class="card-body p-lg-4 pt-lg-3">
<div class="d-none d-lg-block">
<t t-call="website_sale.cart_summary_content"/>
<t t-call="website_sale.total">
<t
t-set="_cart_total_classes"
t-valuef="border-top pt-2"
/>
</t>
</div>
<div
t-if="show_navigation_button"
class="o_cta_navigation_container px-0"
>
<t t-call="website_sale.navigation_buttons"/>
</div>
</div>
</div>
</div>
</div>
<!-- Mobile Order Summary | Bottom of page and Offcanvas -->
<t t-if="not show_shorter_cart_summary and show_mobile_cart_summary">
<div class="o_mobile_summary d-lg-none sticky-bottom mt-auto bg-body">
<button
class="btn btn-light d-flex justify-content-between align-items-center gap-2 w-100 mb-2"
data-bs-toggle="offcanvas"
href="#o_cart_summary_offcanvas"
aria-controls="o_cart_summary_offcanvas"
>
Order
<span
id="amount_total_summary"
class="monetary_field ms-auto"
t-field="website_sale_order.amount_total"
t-options='{"widget": "monetary", "display_currency": website_sale_order.currency_id}'
/>
<span
class="o_cart_item_count badge ms-1 top-0 bg-primary"
t-out="str(website_sale_order.cart_quantity)"
/>
<i class="fa fa-angle-right ms-2" role="img"/>
</button>
<t
t-if="show_navigation_button"
t-call="website_sale.navigation_buttons"
/>
</div>
<div
id="o_cart_summary_offcanvas"
class="offcanvas offcanvas-end"
tabindex="-1"
aria-labelledby="o_cart_summary_offcanvas"
>
<div class="offcanvas-body">
<t t-call="website_sale.cart_summary_content"/>
</div>
<div class="offcanvas-footer p-3">
<a href="/shop/cart" class="btn btn-link w-100">
Coupon, Gift card, Promo-code?
</a>
<t t-call="website_sale.total">
<t t-set="hide_promotions" t-value="True"/>
<t
t-set="_cart_total_classes"
t-valuef="border-top px-3 pt-2 mx-n3"
/>
</t>
<button
class="btn btn-light w-100"
type="button"
data-bs-dismiss="offcanvas"
aria-label="Close"
>
Close
</button>
</div>
</div>
</t>
</div>
<!-- This is the drag-and-drop area for website building blocs at the end of each
checkout page. The templates created in the database to store blocs are hooked
using XPath on the `oe_struture` element ID. Therefore, we can't use dynamic
IDs (like with t-att-id) and each template needs to define a div element. -->
<t t-out="oe_structure"/>
</div>
</t>
</template>
<template id="website_sale.shorter_cart_summary">
<div
t-if="website_sale_order and website_sale_order.website_order_line"
class="o_total_card card o_wsale_sticky_object sticky-lg-top"
>
<div class="card-body p-0 p-lg-4" name="o_cart_total_card_body">
<t t-call="website_sale.total">
<t
t-set="_cart_total_classes"
t-valuef="o_checkout_cart_total pt-2 pt-lg-0"
/>
</t>
<t t-call="website_sale.navigation_buttons"/>
</div>
</div>
</template>
<!-- Called in `website_sale.checkout_layout` and `website_sale.confirmation`. -->
<template id="website_sale.cart_summary_content">
<div
t-if="not website_sale_order or not website_sale_order.website_order_line"
name="cart_summary_info"
class="alert alert-info"
>
Your cart is empty!
</div>
<div>
<div t-att-class="len(website_sale_order.website_order_line) &gt; 3 and 'o_wsale_scrollable_table'">
<table
t-if="website_sale_order and website_sale_order.website_order_line"
class="o_cart_products_table table mb-0"
>
<tbody>
<tr
t-foreach="website_sale_order.website_order_line"
t-as="line"
t-att-class="line_last and 'border-transparent'"
>
<td class="td-img ps-0 pt-3">
<div class="o_cart_product_image position-relative">
<span
t-if="not line._is_sellable() and line.product_id.image_128"
>
<img
t-att-src="image_data_uri(line.product_id.image_128)"
class="img rounded"
t-att-alt="line.name_short"
/>
</span>
<span
t-else=""
t-field="line.product_id.image_128"
t-options="{'widget': 'image', 'qweb_img_responsive': False, 'class': 'rounded'}"
/>
<span class="o_cart_item_count badge bg-secondary position-absolute top-0 start-100 translate-middle">
<t t-out="int(line.product_uom_qty)" />
<i
t-if="line._get_shop_warning(clear=False)"
class="fa fa-warning"
role="img"
t-att-title="line._get_shop_warning()"
aria-label="Warning"
/>
</span>
</div>
</td>
<td
class="td-product_name td-qty w-100 pt-3"
name="website_sale_cart_summary_product_name"
>
<span class="text-wrap" t-out="line._get_line_header()"/>
<p class="text-muted small mb-0" t-out="line._get_combination_name()"/>
<span
t-if="line.product_template_id._has_multiple_uoms()"
class="badge mt-1 bg-light"
t-out="line.product_uom_id.name"
/>
</td>
<td class="td-price pe-0 pt-3 text-end"
name="website_sale_cart_summary_line_price">
<t t-call="website_sale.cart_product_price">
<t
t-set="product_price"
t-value="line._get_cart_display_price()"
/>
</t>
</td>
</tr>
</tbody>
</table>
</div>
<t t-if='website_sale_order'>
<t t-set='warning' t-value='website_sale_order._get_shop_warning(clear=False)' />
<div t-if='warning' class="alert alert-warning" role="alert">
<strong>Warning!</strong> <t t-out='website_sale_order._get_shop_warning()'/>
</div>
</t>
</div>
</template>
<!-- /shop/confirmation route -->
<template id="confirmation">
<t t-call="website_sale.checkout_layout">
<t t-set="show_wizard_checkout" t-value="False"/>
<t t-set="show_mobile_cart_summary" t-value="False"/>
<t t-set="show_navigation_button" t-value="False"/>
<t t-set="show_footer" t-value="True"/>
<t t-set="additional_title">Shop - Confirmed</t>
<t t-set="hide_promotions" t-value="True"/>
<t t-set="oe_structure">
<!-- This is the drag-and-drop area for website building blocs at the end of each
checkout page. This is append at the of the page in `checkout_layout`. The
templates created in the database to store blocs are hooked using XPath on the
`oe_struture` element ID. Therefore, we can't use dynamic IDs (like with
t-att-id) and each template needs to define a div element. -->
<div class="oe_structure" id="oe_structure_website_sale_confirmation_3"/>
</t>
<t t-set="tx_sudo" t-value="order.get_portal_last_transaction()"/>
<div
t-if="tx_sudo.state in ['pending', 'done'] or not order.amount_total"
class="d-flex justify-content-between align-items-center"
>
<h3>Thank you for your order.</h3>
<a
title="Print"
role="button"
class="d-none d-md-inline-block btn btn-light ms-auto"
href="/shop/print"
target="_blank"
aria-label="Print"
>
<i class="fa fa-print me-2"/>Print
</a>
</div>
<div id="order_name" class="mb-4">
<h5>
<span>Order</span>
<span t-field="order.name"/>
</h5>
</div>
<t t-if="request.env['res.users']._get_signup_invitation_scope() == 'b2c' and request.website.is_public_user()">
<p class="alert alert-info mt-3" role="status">
<a role="button" t-att-href="order.partner_id.signup_prepare() and order.partner_id.with_context(relative_url=True)._get_signup_url()" class="btn btn-primary o_translate_inline">Sign Up</a>
<span class="align-middle">to follow your order.</span>
</p>
</t>
<div class="oe_structure clearfix mt-3" id="oe_structure_website_sale_confirmation_1"/>
<t t-call="website_sale.payment_confirmation_status"/>
<div class="mt-3">
<t t-call="website_sale.address_on_checkout"/>
</div>
<div class="oe_structure mt-3" id="oe_structure_website_sale_confirmation_2"/>
<input t-if='website.plausible_shared_key' type='hidden' class='js_plausible_push' data-event-name='Shop' t-attf-data-event-params='{"CTA": "Order Confirmed", "amount": "#{"%3s-%3s" % (max(0, round(website_sale_order.amount_total/100)*100 - 50), round(website_sale_order.amount_total/100)*100 + 50)}"}' />
<div class="d-lg-none">
<t t-call="website_sale.cart_summary_content"/>
<t t-call="website_sale.total">
<t
t-set="_cart_total_classes"
t-valuef="border-top pt-2"
/>
</t>
</div>
</t>
</template>
<!-- Called in `website_sale.checkout_layout`. -->
<template id="total">
<!-- Layout customization parameters:
- _cart_total_classes: CSS classes to append on the root div of the total template;
default `None`.
-->
<div
t-if="website_sale_order and website_sale_order.website_order_line"
t-attf-class="o_cart_total #{_cart_total_classes}"
>
<table class="table mb-0">
<tr
t-if="website_sale_order._has_deliverable_products()"
name="o_order_delivery"
>
<td class="ps-0 pt-0 pb-2 border-0 text-muted" colspan="2">
Delivery
</td>
<td class="text-end pe-0 pt-0 pb-2 border-0">
<span
name="o_message_no_dm_set"
t-att-class="'d-none' if website_sale_order.carrier_id else ''"
title="Price will be updated after choosing a delivery method"
>
-
</span>
<span
t-out="website_sale_order.amount_delivery"
t-att-class="'monetary_field' + ('' if website_sale_order.carrier_id else ' d-none')"
style="white-space: nowrap;"
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"
/>
</td>
</tr>
<tr name="o_order_total_untaxed">
<td
class="border-0 pb-2 ps-0 pt-0 text-start text-muted"
colspan="2">
Subtotal
</td>
<td class="text-end border-0 pb-2 pe-0 pt-0">
<span t-field="website_sale_order.amount_untaxed"
class="monetary_field"
style="white-space: nowrap;"
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"/>
</td>
</tr>
<tr name="o_order_total_taxes">
<td colspan="2" class="text-muted border-0 p-0 pe-3 pb-2">Taxes</td>
<td class="text-end border-0 p-0 ps-3 pb-2">
<span t-field="website_sale_order.amount_tax"
class="monetary_field"
style="white-space: nowrap;"
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"/>
</td>
</tr>
<tr name="o_order_total" class="border-top">
<td colspan="2" class="border-0 ps-0 pt-2"><strong>Total</strong></td>
<td class="text-end border-0 px-0 pt-2">
<strong t-field="website_sale_order.amount_total"
class="monetary_field text-end p-0"
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"/>
</td>
</tr>
</table>
</div>
</template>
<!-- Deactivatable through the website editor. -->
<template id="reduction_code" inherit_id="website_sale.total" name="Promo Code">
<!-- Checkout context:
- hide_promotions: Whether to hide promotion input; default: `None`.
- redirect: The route to redirect to when a customer enters a coupon; default: `None`.
- website_sale_order: The current order.
-->
<xpath expr="//div[contains(@t-attf-class, 'o_cart_total')]//table/tr[last()]" position="after">
<tr t-if="not hide_promotions">
<td colspan="3" class="text-end text-xl-end border-0 p-0">
<span>
<t t-set="force_coupon" t-value="website_sale_order.pricelist_id.code"/>
<div t-if="not force_coupon" class="coupon_form">
<t t-call="website_sale.coupon_form"/>
</div>
</span>
</td>
</tr>
</xpath>
</template>
<!-- Called in `website_sale.confirmation`. -->
<template id="payment_confirmation_status">
<div
name="order_confirmation"
class="mt-3"
t-att-data-order-id="order.id"
t-att-data-order-tracking-info="json.dumps(order_tracking_info)"
>
<t t-set="tx_sudo" t-value="order.get_portal_last_transaction()"/>
<div
t-if="tx_sudo"
t-attf-class="alert px-3 pb-0 pt-3 #{
(tx_sudo.state == 'pending' and 'alert-info') or
(tx_sudo.state == 'done' and order.amount_total == tx_sudo.amount and 'alert-success') or
(tx_sudo.state == 'done' and order.amount_total != tx_sudo.amount and 'alert-warning') or
(tx_sudo.state == 'authorized' and 'alert-success') or
'alert-danger'}"
role="alert"
>
<a
title="Edit"
class="btn btn-sm btn-link text-dark float-end"
role="button"
groups="base.group_system"
target="_blank"
aria-label="Edit"
t-attf-href="/odoo/action-payment.action_payment_provider/{{tx_sudo.provider_id.id}}"
>
<i class="fa fa-pencil"/>
</a>
<div>
<t t-if="tx_sudo.state == 'pending'">
<t t-out="tx_sudo.provider_id.sudo().pending_msg"/>
</t>
<t t-if="tx_sudo.state == 'done'">
<span t-if='tx_sudo.provider_id.sudo().done_msg' t-out="tx_sudo.provider_id.sudo().done_msg"/>
</t>
<t t-if="tx_sudo.state == 'done' and order.amount_total != tx_sudo.amount">
<span>Unfortunately your order can not be confirmed as the amount of your payment does not match the amount of your cart.
Please contact the responsible of the shop for more information.</span>
</t>
<t t-if="tx_sudo.state == 'cancel'">
<t t-out="tx_sudo.provider_id.sudo().cancel_msg"/>
</t>
<t t-if="tx_sudo.state == 'authorized'">
<t t-if="tx_sudo.provider_id.sudo().auth_msg" t-out="tx_sudo.provider_id.sudo().auth_msg"/>
<span t-else="">Your payment has been authorized.</span>
</t>
<t t-if="tx_sudo.state == 'error'">
<span t-out="tx_sudo.state_message"/>
</t>
</div>
<t t-if="tx_sudo.provider_code == 'custom'">
<div id="order_reference" t-if="order.reference" class="mt-2">
<b>Communication: </b><span t-out='order.reference'/>
</div>
<div t-if="tx_sudo.provider_id.sudo().qr_code">
<t t-set="qr_code" t-value="tx_sudo.company_id.partner_id.bank_ids[:1].build_qr_code_base64(order.amount_total,tx_sudo.reference, None, tx_sudo.currency_id, tx_sudo.partner_id)"/>
<div class="mt-2" t-if="qr_code">
<h3>Or scan me with your banking app.</h3>
<img class="border border-dark rounded" t-att-src="qr_code"/>
</div>
</div>
</t>
</div>
</div>
</template>
<template id="website_sale.brand_promotion" inherit_id="website.brand_promotion">
<xpath expr="//t[@t-call='web.brand_promotion_message']" position="replace">
<t t-call="web.brand_promotion_message">
<t t-set="_message">
The #1 <a target="_blank" href="http://www.odoo.com/app/ecommerce?utm_source=db&amp;utm_medium=website">Open Source eCommerce</a>
</t>
<t t-set="_utm_medium" t-valuef="website"/>
</t>
</xpath>
</template>
<!-- Product page images -->
<template id="website_sale.shop_product_images" name="Shop Product Images">
<t t-set="product_images" t-value="product_variant._get_images() if product_variant else product._get_images()"/>
<t
t-set="ribbon"
t-value="product.sudo()._get_ribbon(price_vals=combination_info, variant=product_variant)"
/>
<t t-set="bg_color" t-value="ribbon.bg_color"/>
<t t-set="text_color" t-value="ribbon.text_color"/>
<t t-call="website_sale.shop_product_#{website.product_page_image_layout}"/>
</template>
<template id="website_sale.shop_product_image">
<span
t-attf-class="o_ribbons o_not_editable #{ribbon._get_css_classes()} z-1"
t-attf-style="#{text_color and ('color: %s; ' % text_color)}#{bg_color and 'background-color:' + bg_color}"
t-att-data-ribbon-id="ribbon.id"
t-out="ribbon.name or ''"
/>
<div
t-if="product_image._name == 'product.image' and product_image.embed_code"
t-att-class="image_classes + ' ratio ratio-16x9'"
>
<t t-out="product_image.embed_code"/>
</div>
<div
t-elif="len(product_images) == 1 and website.product_page_image_layout != 'grid'"
class="position-relative d-inline-flex overflow-hidden m-auto h-100 w-100"
>
<span
t-field="product_image.image_1920"
name="o_img_with_max_suggested_width"
class="o_product_detail_img_wrapper d-flex align-items-start justify-content-center h-100 w-100 oe_unmovable"
t-options="{
'widget': 'image',
'preview_image': 'image_1024',
'class': 'oe_unmovable product_detail_img h-100 w-100',
'alt-field': 'name',
'zoom': product_image.can_image_1024_be_zoomed and 'image_1920',
}"
/>
</div>
<div
t-else=""
t-field="product_image.image_1920"
t-att-class="image_classes + ' o_product_detail_img_wrapper oe_unmovable'"
t-attf-style="{{
image_natural_index and ('--o-wsale-grid-product-img-natural-order: ' + str(image_natural_index)) or false
}}"
t-options="{
'widget': 'image',
'preview_image': 'image_1024',
'class': 'oe_unmovable product_detail_img w-100 h-100',
'alt-field': 'name',
'zoom': product_image.can_image_1024_be_zoomed and 'image_1920',
}"
/>
</template>
<!-- Product page images: Carousel -->
<template id="website_sale.shop_product_carousel" name="Shop Product Carousel">
<t t-set="product_carousel_block_name">Product Carousel</t>
<div
id="o-carousel-product"
t-attf-class="#{len(product_images) > 1 and 'o_carousel_not_single'} carousel slide mb-3 overflow-hidden"
t-att-data-name="product_carousel_block_name"
>
<div
class="o_carousel_product_outer carousel-outer position-relative d-flex align-items-center w-100 overflow-hidden"
>
<span
t-if="len(product_images) > 1"
t-attf-class="o_ribbons #{ribbon._get_css_classes()} z-1"
t-attf-style="#{text_color and ('color: %s; ' % text_color)}#{bg_color and 'background-color:' + bg_color}"
t-out="ribbon.name or ''"
t-att-data-ribbon-id="ribbon.id"
/>
<div class="carousel-inner h-100">
<t t-set="image_classes" t-value="'d-flex align-items-center justify-content-center h-100'"/>
<t t-foreach="product_images" t-as="product_image">
<div t-attf-class="carousel-item h-100 w-100 text-center#{' active' if product_image_first else ''}">
<t t-call="website_sale.shop_product_image"/>
</div>
</t>
</div>
<t t-if="len(product_images) > 1">
<a class="carousel-control-prev" href="#o-carousel-product" role="button" data-bs-slide="prev">
<i
class="oi oi-chevron-left oe_unmovable border bg-white text-900"
role="img"
aria-label="Previous"
title="Previous"
/>
</a>
<a class="carousel-control-next" href="#o-carousel-product" role="button" data-bs-slide="next">
<i
class="oi oi-chevron-right oe_unmovable border bg-white text-900"
role="img"
aria-label="Next"
title="Next"
/>
</a>
</t>
</div>
</div>
</template>
<template id="carousel_product_indicators_bottom" inherit_id="website_sale.shop_product_carousel" name="Carousel Product Indicators Bottom" active="False">
<xpath expr="//div[hasclass('o_carousel_product_outer')]" position="after">
<t t-call="website_sale.carousel_product_indicators">
<t t-set="indicators_div_class" t-value="'pt-2 overflow-hidden'"/>
</t>
</xpath>
</template>
<template id="carousel_product_indicators_left" inherit_id="website_sale.shop_product_carousel" name="Carousel Product Indicators Left">
<xpath expr="//div[hasclass('o_carousel_product_outer')]" position="before">
<t t-call="website_sale.carousel_product_indicators">
<t t-set="indicators_list_class" t-value="'d-flex d-lg-block pe-lg-2'"/>
</t>
</xpath>
<xpath expr="//div[@id='o-carousel-product']" position="attributes">
<attribute name="t-attf-class" add="o_carousel_product_left_indicators d-flex" separator=" "/>
</xpath>
</template>
<template id="carousel_product_indicators" name="Carousel Product">
<div
t-if="len(product_images) > 1"
t-ignore="True"
t-attf-class="o_carousel_product_indicators {{indicators_div_class}}"
>
<ol
t-attf-class="carousel-indicators position-static pt-2 pt-lg-0 mx-auto my-0 {{indicators_list_class}} {{website.product_page_image_width == '100_pc' and 'justify-content-center'}}"
>
<li
t-foreach="product_images" t-as="product_image"
t-attf-class="align-top position-relative {{'active' if product_image_first else ''}}"
data-bs-target="#o-carousel-product"
t-att-data-bs-slide-to="str(product_image_index)"
>
<div
t-field="product_image.image_128"
t-options="{'widget': 'image', 'qweb_img_responsive': False, 'class': 'object-fit-cover w-100 h-100', 'alt-field': 'name'}"
/>
<i
t-if="product_image._name == 'product.image' and product_image.embed_code"
class="fa fa-2x fa-play-circle o_product_video_thumb bg-black-50 text-center"
/>
</li>
</ol>
</div>
</template>
<!-- Product page images: Grid -->
<template id="website_sale.shop_product_grid" name="Shop Product Grid">
<t t-set="imagesCount" t-value="len(product_images)"/>
<div
id="o-grid-product"
t-attf-class="
o_grid_uses_ratio_{{website.product_page_image_ratio}}
o_grid_uses_ratio_mobile_{{website.product_page_image_ratio_mobile}}
{{
imagesCount &gt; 11 and 'o_grid_has_more_than_11' or
imagesCount &gt; 9 and 'o_grid_has_more_than_9' or
imagesCount &gt; 5 and 'o_grid_has_more_than_5' or
imagesCount &gt; 3 and 'o_grid_has_more_than_3' or
imagesCount == 1 and 'o_grid_solo' or ''
}}
"
data-name="Product Grid"
t-att-data-image_spacing="website.product_page_image_spacing"
t-att-data-image_count="len(product_images)"
t-att-data-grid_columns="website.product_page_grid_columns"
>
<div class="position-relative overflow-hidden">
<span
t-attf-class="o_ribbons #{ribbon._get_css_classes()}"
t-attf-style="#{text_color and ('color: %s; ' % text_color)}#{bg_color and 'background-color:' + bg_color}"
t-out="ribbon.name or ''"
t-att-data-ribbon-id="ribbon.id"
/>
<!-- One row for every two images -->
<t t-set="image_classes" t-value="'w-100'"/>
<div
t-attf-class="o_wsale_product_page_grid_row {{website._get_product_page_grid_image_spacing_classes()}}"
>
<t t-foreach="website.product_page_grid_columns" t-as="col_idx">
<t t-set="col_feed_counter" t-value="0"/>
<div
t-if="col_idx_index &lt; len(product_images)"
t-attf-class="o_wsale_product_page_grid_column flex-column px-0"
>
<t t-foreach="len(product_images)" t-as="image_idx">
<t
t-set="product_image"
t-value="image_idx &lt; len(product_images) and product_images[image_idx] or False"
/>
<t
t-if="product_image and col_idx == col_feed_counter"
t-call="website_sale.shop_product_image"
>
<t t-set="image_natural_index" t-value="image_idx"/>
<t
t-set="image_classes"
t-value="image_idx_last and 'o_product_detail_img_wrapper_last' or ''"
/>
</t>
<t t-if="col_feed_counter == (website.product_page_grid_columns - 1)">
<t t-set="col_feed_counter" t-value="0"/>
</t>
<t t-else="">
<t t-set="col_feed_counter" t-value="col_feed_counter + 1"/>
</t>
</t>
</div>
</t>
</div>
</div>
</div>
</template>
<template id="ecom_show_extra_fields" inherit_id="website_sale.product" active="True" name="Show Extra Fields">
<xpath expr="//div[@id='product_details']" position="inside">
<t t-if="any([product.sudo()[field.name] for field in website.shop_extra_field_ids])">
<hr/>
<p class="text-muted">
<t t-foreach="website.shop_extra_field_ids" t-as='field' t-if="product.sudo()[field.name]">
<b><t t-out='field.label'/>: </b>
<t t-if='field.field_id.ttype != "binary"'>
<span t-out="product.sudo()[field.name]" t-options="{'widget': field.field_id.ttype}"/>
</t>
<t t-else=''>
<a target='_blank' t-attf-href='/web/content/product.template/#{product.id}/#{field.name}?download=1'>
<i class='fa fa-file'></i>
</a>
</t>
<br/>
</t>
</p>
</t>
</xpath>
</template>
</odoo>