3364 lines
198 KiB
XML
3364 lines
198 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
<template id="header_cart_link" name="Header Cart Link">
|
|
<t t-nocache="The number of products is dynamic, this rendering cannot be cached."
|
|
t-nocache-_icon="_icon"
|
|
t-nocache-_text="_text"
|
|
t-nocache-_badge="_badge"
|
|
t-nocache-_badge_class="_badge_class"
|
|
t-nocache-_icon_wrap_class="_icon_wrap_class"
|
|
t-nocache-_text_class="_text_class"
|
|
t-nocache-_item_class="_item_class"
|
|
t-nocache-_link_class="_link_class">
|
|
<t t-set="website_sale_cart_quantity" t-value="request.session['website_sale_cart_quantity'] if 'website_sale_cart_quantity' in request.session else website.sale_get_order().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-esc="website_sale_cart_quantity" t-att-data-order-id="request.session.get('sale_order_id', '')"/>
|
|
</div>
|
|
<span t-if="_text" t-attf-class="#{_text_class}">My Cart</span>
|
|
</a>
|
|
</li>
|
|
</t>
|
|
</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>
|
|
|
|
<template id="template_header_mobile" inherit_id="website.template_header_mobile">
|
|
<xpath expr="//ul[hasclass('o_header_mobile_buttons_wrap')]//li" 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_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_hover 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="'position-relative me-2 rounded-circle border p-2 bg-o-color-3 o_border_contrast'"/>
|
|
<t t-set="_link_class" t-value="'btn d-flex align-items-center fw-bold text-reset o_navlink_background_hover'"/>
|
|
<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_hover 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">
|
|
<div class="d-flex 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_hover 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>
|
|
</div>
|
|
</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('/shop'+ ('/category/'+slug(category)) if category else None, search=0) or '/shop'"/>
|
|
<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 t-if="attrib_values">
|
|
<t t-foreach="attrib_values" t-as="a">
|
|
<input type="hidden" name="attribute_value" t-att-value="'%s-%s' % (a[0], a[1])" />
|
|
</t>
|
|
</t>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="products_item" name="Products item">
|
|
<form action="/shop/cart/update" method="post" class="oe_product_cart h-100 d-flex"
|
|
t-att-data-publish="product.website_published and 'on' or 'off'"
|
|
itemscope="itemscope" itemtype="http://schema.org/Product">
|
|
<t t-set="product_href" t-value="keep(product.website_url, page=(pager['page']['num'] if pager['page']['num']>1 else None)) + selected_attributes_hash" />
|
|
<t t-set="image_type" t-value="product._get_suitable_image_size(ppr, td_product['x'], td_product['y'])"/>
|
|
|
|
<div class="oe_product_image position-relative flex-grow-0 overflow-hidden">
|
|
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" t-nocache="The csrf token must always be up to date."/>
|
|
<a
|
|
t-att-href="product_href"
|
|
class="oe_product_image_link d-block position-relative"
|
|
itemprop="url"
|
|
contenteditable="false"
|
|
>
|
|
<t t-set="image_holder" t-value="product._get_image_holder()"/>
|
|
<span t-field="image_holder.image_1920"
|
|
t-options="{'widget': 'image', 'preview_image': image_type, 'itemprop': 'image', 'class': 'h-100 w-100 position-absolute'}"
|
|
class="oe_product_image_img_wrapper d-flex h-100 justify-content-center align-items-center position-absolute"/>
|
|
|
|
<t t-set="bg_color" t-value="td_product['ribbon'].bg_color"/>
|
|
<t t-set="text_color" t-value="td_product['ribbon'].text_color"/>
|
|
<t t-set="bg_class" t-value="td_product['ribbon']._get_position_class()"/>
|
|
<span
|
|
t-attf-class="o_ribbon o_not_editable #{bg_class}"
|
|
t-attf-style="#{text_color and ('color: %s;' % text_color)} #{bg_color and 'background-color:' + bg_color}"
|
|
t-out="td_product['ribbon'].name or ''"
|
|
/>
|
|
</a>
|
|
</div>
|
|
<div class="o_wsale_product_information position-relative d-flex flex-column flex-grow-1 flex-shrink-1">
|
|
<div class="o_wsale_product_information_text">
|
|
<h6 class="o_wsale_products_item_title mb-2 text-break">
|
|
<a class="text-primary text-decoration-none text-primary-emphasis" itemprop="name" t-att-href="product_href" t-att-content="product.name" t-field="product.name" />
|
|
<a t-if="not product.website_published" role="button" t-att-href="product_href" class="btn btn-sm btn-danger" title="This product is unpublished.">
|
|
Unpublished
|
|
</a>
|
|
</h6>
|
|
</div>
|
|
<div class="o_wsale_product_sub d-flex justify-content-between align-items-end gap-2 flex-wrap">
|
|
<t t-set="template_price_vals" t-value="get_product_prices(product)"/>
|
|
<div class="o_wsale_product_btn d-flex gap-2"/>
|
|
<div class="product_price" itemprop="offers" itemscope="itemscope" itemtype="http://schema.org/Offer">
|
|
<span class="h6 mb-0"
|
|
t-if="template_price_vals['price_reduce'] or not website.prevent_zero_price_sale"
|
|
t-out="template_price_vals['price_reduce']"
|
|
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
|
|
<span class="h6 mb-0" t-elif="any(ptav.price_extra for ptav in product.attribute_line_ids.product_template_value_ids)">&nbsp;</span>
|
|
<span class="h6 mb-0" t-else="" t-field="website.prevent_zero_price_sale_text"/>
|
|
<t t-if="'base_price' in template_price_vals and (template_price_vals['base_price'] > template_price_vals['price_reduce']) and (template_price_vals['price_reduce'] or not website.prevent_zero_price_sale)">
|
|
<del t-attf-class="text-muted me-1 h6 mb-0" style="white-space: nowrap;">
|
|
<em class="small" t-esc="template_price_vals['base_price']" t-options="{'widget': 'monetary', 'display_currency': website.currency_id}" />
|
|
</del>
|
|
</t>
|
|
<span itemprop="price" style="display:none;" t-esc="template_price_vals['price_reduce']" />
|
|
<span itemprop="priceCurrency" style="display:none;" t-esc="website.currency_id.name" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</template>
|
|
|
|
<template id="products_description" inherit_id="website_sale.products_item" active="False" name="Product Description">
|
|
<xpath expr="//form" position="attributes">
|
|
<attribute name="class" add="oe_product_cart_has_description" separator=" "/>
|
|
</xpath>
|
|
<xpath expr="//*[hasclass('o_wsale_products_item_title')]" position="after">
|
|
<div class="oe_subdescription mb-2 text-muted small" contenteditable="false">
|
|
<div itemprop="description" t-field="product.description_sale"/>
|
|
</div>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="products_add_to_cart" inherit_id="website_sale.products_item" active="False" name="Add to Cart">
|
|
<xpath expr="//div[hasclass('o_wsale_product_btn')]" position="inside">
|
|
<t t-set="product_variant_id" t-value="product._get_first_possible_variant_id()"/>
|
|
<input name="product_id" t-att-value="product_variant_id" type="hidden"/>
|
|
<input name="product_template_id" t-att-value="product.id" type="hidden"/>
|
|
<t t-if="product_variant_id and template_price_vals['price_reduce'] or not website.prevent_zero_price_sale">
|
|
<a
|
|
t-if="product._website_show_quick_add()"
|
|
href="#"
|
|
role="button"
|
|
class="btn btn-light a-submit"
|
|
aria-label="Shopping cart"
|
|
title="Shopping cart"
|
|
>
|
|
<span class="fa fa-shopping-cart"/>
|
|
</a>
|
|
</t>
|
|
</xpath>
|
|
</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)>1)"/>
|
|
<t t-set="pricelist" t-value="website.pricelist_id"/>
|
|
<div t-attf-class="o_pricelist_dropdown dropdown #{_classes if hasPricelistDropdown else 'd-none'}">
|
|
<t t-cache="pricelist,website_sale_pricelists,navClass">
|
|
<a role="button" href="#" t-attf-class="dropdown-toggle btn btn-{{navClass}}" data-bs-toggle="dropdown">
|
|
<t t-esc="pricelist and pricelist.name or ' - '" />
|
|
</a>
|
|
<div class="dropdown-menu" role="menu">
|
|
<t t-foreach="website_sale_pricelists" t-as="pl">
|
|
<a role="menuitem" t-att-href="'/shop/change_pricelist/%s' % pl.id" class="dropdown-item">
|
|
<span class="switcher_pricelist small" t-att-data-pl_id="pl.id" t-esc="pl.name"/>
|
|
</a>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="products_breadcrumb" name="Products Breadcrumb">
|
|
<ol t-if="category" t-attf-class="breadcrumb #{_classes}">
|
|
<li class="breadcrumb-item">
|
|
<a href="/shop">Products</a>
|
|
</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="" class="breadcrumb-item">
|
|
<a t-att-href="keep('/shop/category/%s' % slug(cat), category=0)" 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_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_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="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)>1"/>
|
|
<t t-set="isSortingBy" t-value="[sort for sort in website_sale_sortable if sort[0]==request.params.get('order', '')]"/>
|
|
|
|
<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 class="container oe_website_sale pt-2">
|
|
<div class="row o_wsale_products_main_row align-items-start flex-nowrap">
|
|
<aside t-if="hasLeftColumn" id="products_grid_before" class="d-none d-lg-block position-sticky col-3 px-3 clearfix">
|
|
<div class="o_wsale_products_grid_before_rail vh-100 ms-n2 mt-n2 pt-2 p-lg-2 pb-lg-5 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>
|
|
<div
|
|
t-attf-class="products_attributes_filters d-empty-none {{opt_wsale_categories and 'border-top'}}"
|
|
/>
|
|
<t
|
|
t-if="opt_wsale_filter_price and opt_wsale_attributes"
|
|
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>
|
|
</div>
|
|
</aside>
|
|
<div id="products_grid"
|
|
t-attf-class="#{'o_wsale_layout_list' if layout_mode == 'list' else ''} {{'col-lg-9' if hasLeftColumn else 'col-12'}}">
|
|
<t t-call="website_sale.products_breadcrumb">
|
|
<t t-set="_classes" t-valuef="d-none d-lg-flex w-100 p-0 small"/>
|
|
</t>
|
|
|
|
<h1 t-if="category">
|
|
<t t-esc="category.name"/>
|
|
</h1>
|
|
|
|
<t t-if="category">
|
|
<t t-set='editor_msg'>
|
|
Drag building blocks here to customize the header for
|
|
"<t t-esc='category.name'/>" category.
|
|
</t>
|
|
<div class="mb16"
|
|
id="category_header"
|
|
t-att-data-editor-message="editor_msg"
|
|
t-field="category.website_description"/>
|
|
</t>
|
|
|
|
<t t-if="opt_wsale_categories_top"
|
|
t-call="website_sale.filmstrip_categories"/>
|
|
|
|
<div class="products_header btn-toolbar flex-nowrap align-items-center justify-content-between gap-3 mb-3">
|
|
<t t-if="is_view_active('website_sale.search')" t-call="website_sale.search">
|
|
<t t-set="search" t-value="original_search or search"/>
|
|
<t t-set="_form_classes" t-valuef="d-lg-inline {{'d-inline' if not category else 'd-none'}}"/>
|
|
</t>
|
|
|
|
<t t-call="website_sale.pricelist_list">
|
|
<t t-set="_classes" t-valuef="d-none d-lg-inline"/>
|
|
</t>
|
|
|
|
<t t-if="is_view_active('website_sale.sort')" t-call="website_sale.sort">
|
|
<t t-set="_classes" t-valuef="d-none me-auto d-lg-inline-block"/>
|
|
</t>
|
|
|
|
<div t-if="category" class="d-flex align-items-center d-lg-none me-auto">
|
|
<t t-if="not category.parent_id" t-set="backUrl" t-valuef="/shop"/>
|
|
<t t-else="" t-set="backUrl" t-value="keep('/shop/category/' + slug(category.parent_id), category=0)"/>
|
|
|
|
<a t-attf-class="btn btn-{{navClass}} me-2" t-att-href="category.parent_id and keep('/shop/category/' + slug(category.parent_id), category=0) or '/shop'">
|
|
<i class="fa fa-angle-left"/>
|
|
</a>
|
|
<h4 t-out="category.name" class="mb-0 me-auto"/>
|
|
</div>
|
|
|
|
<t t-if="is_view_active('website_sale.add_grid_or_list_option')" t-call="website_sale.add_grid_or_list_option">
|
|
<t t-set="_classes" t-valuef="d-flex"/>
|
|
</t>
|
|
|
|
<button t-if="is_view_active('website_sale.sort') or opt_wsale_categories or opt_wsale_attributes or opt_wsale_attributes_top"
|
|
t-attf-class="btn btn-{{navClass}} position-relative {{not opt_wsale_attributes_top and 'd-lg-none'}}"
|
|
data-bs-toggle="offcanvas"
|
|
data-bs-target="#o_wsale_offcanvas">
|
|
<i class="fa fa-sliders"/>
|
|
<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-esc="original_search"/>'. Showing results for '<span t-esc="search"/>'.
|
|
</div>
|
|
|
|
<div t-if="products" class="o_wsale_products_grid_table_wrapper pt-3 pt-lg-0">
|
|
<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"/>
|
|
|
|
<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'}}"
|
|
t-attf-style="--o-wsale-products-grid-gap: {{gap}}; --o-wsale-ppr: {{ppr}}; --o-wsale-ppg: {{ppg}}"
|
|
t-att-data-ppg="ppg"
|
|
t-att-data-ppr="ppr"
|
|
t-att-data-default-sort="website.shop_default_sort"
|
|
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_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'] >= td_product['y'] * 2)"/>
|
|
<t t-set="col_is_custom_portrait"
|
|
t-value="not col_is_stretched and (col_height > td_product['x'])"/>
|
|
<div
|
|
t-attf-class="oe_product {{col_is_custom_portrait and 'oe_product_custom_portrait'}} g-col-6 {{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-ribbon-id="td_product['ribbon'].id"
|
|
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="product"
|
|
t-value="td_product['product']"/>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
</t>
|
|
</section>
|
|
</div>
|
|
<div t-else="" class="text-center text-muted mt128 mb256">
|
|
<t t-if="not search">
|
|
<h3 class="mt8">No product defined</h3>
|
|
<p t-if="category">No product defined in this category.</p>
|
|
</t>
|
|
<t t-else="">
|
|
<h3 class="mt8">No results</h3>
|
|
<p>No results for "<strong t-esc='search'/>"<t t-if="category"> in category "<strong t-esc="category.display_name"/>"</t>.</p>
|
|
</t>
|
|
<p t-ignore="true" groups="sales_team.group_sale_manager">Click <i>'New'</i> in the top-right corner to create your first product.</p>
|
|
</div>
|
|
<div class="products_pager d-flex justify-content-center pt-5 pb-3">
|
|
<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-esc='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>
|
|
</t>
|
|
</template>
|
|
|
|
<!-- (Option) Products: Enable "Card" or "Thumbnails" designs -->
|
|
<template id="products_design_card" name="Card Design" inherit_id="website_sale.products" active="False">
|
|
<xpath expr="//section[@id='o_wsale_products_grid']" position="attributes">
|
|
<attribute name="t-attf-class" add="o_wsale_design_cards" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
<template id="products_design_thumbs" name="Thumbnails Design" inherit_id="website_sale.products" active="False">
|
|
<xpath expr="//section[@id='o_wsale_products_grid']" position="attributes">
|
|
<attribute name="t-attf-class" add="o_wsale_design_thumbs" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
<template id="products_design_grid" name="Grid Design" inherit_id="website_sale.products" active="False">
|
|
<xpath expr="//section[@id='o_wsale_products_grid']" position="attributes">
|
|
<attribute name="t-attf-class" add="o_wsale_design_grid" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
|
|
<!-- (Options) Products: Define products' default image ratio -->
|
|
<template id="products_thumb_4_3" name="thumb_4_3" inherit_id="website_sale.products" active="False">
|
|
<xpath expr="//section[@id='o_wsale_products_grid']" position="attributes">
|
|
<attribute name="t-attf-class" add="o_wsale_context_thumb_4_3" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
<template id="products_thumb_4_5" name="thumb_4_5" inherit_id="website_sale.products" active="False">
|
|
<xpath expr="//section[@id='o_wsale_products_grid']" position="attributes">
|
|
<attribute name="t-attf-class" add="o_wsale_context_thumb_4_5" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
<template id="products_thumb_2_3" name="thumb_2_3" inherit_id="website_sale.products" active="False">
|
|
<xpath expr="//section[@id='o_wsale_products_grid']" position="attributes">
|
|
<attribute name="t-attf-class" add="o_wsale_context_thumb_2_3" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
|
|
<!-- (Option) Products: Define products' images filling mode -->
|
|
<template id="products_thumb_cover" name="thumb_cover" inherit_id="website_sale.products" active="True">
|
|
<xpath expr="//section[@id='o_wsale_products_grid']" position="attributes">
|
|
<attribute name="t-attf-class" add="o_wsale_context_thumb_cover" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="website_sale.sort" name="Sort-by Template">
|
|
<div t-attf-class="o_sortby_dropdown dropdown dropdown_sorty_by {{_classes}}">
|
|
<a role="button" href="#" t-attf-class="dropdown-toggle btn btn-{{navClass}}" data-bs-toggle="dropdown">
|
|
<small class="d-none d-lg-inline text-muted">Sort By:</small>
|
|
<span class="d-none d-lg-inline">
|
|
<t t-if="isSortingBy" t-out="isSortingBy[0][1]"/>
|
|
<span t-else="1" t-field="website.shop_default_sort"/>
|
|
</span>
|
|
<i class="fa fa-sort-amount-asc d-lg-none"/>
|
|
</a>
|
|
<div class="dropdown-menu dropdown-menu-end" role="menu">
|
|
<t t-foreach="website_sale_sortable" t-as="sortby">
|
|
<a role="menuitem" rel="noindex,nofollow" t-att-href="keep('/shop', order=sortby[0])" class="dropdown-item">
|
|
<span t-out="sortby[1]"/>
|
|
</a>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="website_sale.add_grid_or_list_option" active="True" name="Grid or List button">
|
|
<t t-set="_activeClasses" t-translation="off">active</t>
|
|
<div t-attf-class="o_wsale_apply_layout btn-group {{_classes}}" t-att-data-active-classes="_activeClasses">
|
|
<input type="radio" class="btn-check" name="wsale_products_layout" id="o_wsale_apply_grid" t-att-checked="'checked' if layout_mode != 'list' else None" value="grid"/>
|
|
<label t-attf-class="btn btn-{{navClass}} #{_activeClasses if layout_mode != 'list' else None} o_wsale_apply_grid" title="Grid" for="o_wsale_apply_grid">
|
|
<i class="fa fa-th-large"/>
|
|
</label>
|
|
<input type="radio" class="btn-check" name="wsale_products_layout" id="o_wsale_apply_list" t-att-checked="'checked' if layout_mode == 'list' else None" value="list"/>
|
|
<label t-attf-class="btn btn-{{navClass}} #{_activeClasses if layout_mode == 'list' else None} o_wsale_apply_list" title="List" for="o_wsale_apply_list">
|
|
<i class="oi oi-view-list"/>
|
|
</label>
|
|
</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="o_wsale_offcanvas_color_attribute" name="Color type attribute 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 mb-1 #{'active' if v.id in attrib_set 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"
|
|
/>
|
|
</label>
|
|
</t>
|
|
</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="category" class="offcanvas-body d-lg-none flex-grow-0 overflow-visible">
|
|
<t t-call="website_sale.search">
|
|
<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">
|
|
<div class="d-block d-lg-none accordion-item" t-if="hasPricelistDropdown">
|
|
<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_pricelist"
|
|
aria-expanded="false"
|
|
aria-controls="o_wsale_offcanvas_pricelist">
|
|
<b>Pricelist</b>
|
|
</button>
|
|
</h2>
|
|
<t t-set="curr_pl" t-value="website.pricelist_id"/>
|
|
<div id="o_wsale_offcanvas_pricelist"
|
|
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_pricelists" t-as="pl"
|
|
role="menuitem"
|
|
rel="noindex,nofollow"
|
|
t-att-href="'/shop/change_pricelist/%s' % pl.id"
|
|
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='/shop/change_pricelist/#{pl.id}';"
|
|
class="form-check-input o_not_editable"
|
|
name="wsale_pricelist_radios_offcanvas"
|
|
t-att-checked="curr_pl == pl">
|
|
<label class="form-check-label fw-normal" t-out="pl.name"/>
|
|
</input>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div t-if="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('/shop', 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('/shop', 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">
|
|
<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>
|
|
|
|
<form t-if="opt_wsale_attributes or opt_wsale_attributes_top"
|
|
t-attf-class="js_attributes accordion accordion-flush d-flex flex-column {{len(attributes) > 0 and 'border-bottom'}}"
|
|
method="get">
|
|
<input t-if="category" type="hidden" name="category" t-att-value="category.id"/>
|
|
<input type="hidden" name="search" t-att-value="search"/>
|
|
|
|
<t t-foreach="attributes" t-as="a">
|
|
<t t-cache="a,attrib_set">
|
|
<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'"/>
|
|
|
|
<div t-if="a.value_ids and len(a.value_ids) > 1"
|
|
t-attf-class="accordion-item border-top-0 {{(_status == 'active') and 'order-1' or 'order-2'}}">
|
|
<h2 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 {{ not attrib_values and '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="_status == 'active' and 'True' or 'False'"
|
|
t-attf-aria-controls="o_wsale_offcanvas_attribute_{{a.id}}">
|
|
<b t-out="a.name"/>
|
|
</button>
|
|
</h2>
|
|
<div t-attf-id="o_wsale_offcanvas_attribute_{{a.id}}"
|
|
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_attribute_{{a.id}}_header">
|
|
|
|
<div class="accordion-body pt-0">
|
|
<div t-if="a.display_type == 'color'" class="pt-1 pb-3">
|
|
<t t-call="website_sale.o_wsale_offcanvas_color_attribute"/>
|
|
</div>
|
|
<div t-elif="a.display_type in ('radio', 'pills', 'select')"
|
|
class="list-group list-group-flush">
|
|
<div t-foreach="a.value_ids" t-as="v" class="list-group-item border-0 ps-0 pb-0">
|
|
<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="'checked' if v.id in attrib_set else None"/>
|
|
<label class="form-check-label fw-normal" t-att-for="'%s-%s' % (a.id,v.id)" t-field="v.name"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
<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>
|
|
</form>
|
|
|
|
<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'"
|
|
href="/shop"
|
|
title="Clear Filters">
|
|
Clear Filters
|
|
</a>
|
|
</div>
|
|
</aside>
|
|
</template>
|
|
|
|
|
|
<!-- Top-Nav Categories -->
|
|
<template id="website_sale.filmstrip_categories" name="Categories Filmstrip">
|
|
<t t-if="category.id">
|
|
<t t-set="entries" t-value="not search and category.child_id or category.child_id.filtered(lambda c: category.id in search_categories_ids)"/>
|
|
|
|
<t t-if="not entries">
|
|
<t t-set="parent" t-value="category.parent_id"/>
|
|
<t t-set="entries" t-value="not search and parent.child_id or parent.child_id.filtered(lambda c: parent.id in search_categories_ids)"/>
|
|
</t>
|
|
</t>
|
|
<t t-else="">
|
|
<t t-set="entries" t-value="categories"/>
|
|
</t>
|
|
|
|
<div t-if="entries" class="o_wsale_filmstip_container d-flex align-items-stretch mb-2 overflow-hidden">
|
|
<div class="o_wsale_filmstip_wrapper pb-1 overflow-auto">
|
|
<ul class="o_wsale_filmstip d-flex align-items-stretch mb-0 list-unstyled overflow-visible">
|
|
<t t-if="category.parent_id" t-set="backUrl" t-value="keep('/shop/category/' + slug(category.parent_id), category=0)"/>
|
|
<t t-else="" t-set="backUrl" t-value="'/shop'"/>
|
|
|
|
<li
|
|
t-foreach="entries"
|
|
t-as="c"
|
|
t-attf-class="d-flex {{'pe-3' if not c_last else ''}}"
|
|
>
|
|
<a
|
|
t-att-href="keep('/shop/category/' + slug(c), category=0)"
|
|
class="text-decoration-none"
|
|
draggable="false"
|
|
>
|
|
<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"/>
|
|
<div
|
|
t-att-class="'d-flex align-items-center h-100 btn btn-'
|
|
+ navClass
|
|
+ (c.image_128 and ' ps-2 pe-3' or ' px-4')
|
|
+ (c.id == category.id and ' border-primary' or '')"
|
|
>
|
|
<div
|
|
t-if="c.image_128"
|
|
t-attf-style="background-image:url('data:image/png;base64,
|
|
#{c.image_128}')"
|
|
class="o_image_40_cover oe_img_bg o_bg_img_center
|
|
flex-shrink-0 rounded-3 me-3"
|
|
t-att-alt="c.name "/>
|
|
<span class="text-nowrap" t-field="c.name"/>
|
|
</div>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- Add to cart button-->
|
|
<template id="categories_recursive" name="Category list">
|
|
<li class="nav-item mb-1">
|
|
<t t-call="website_sale.categorie_link"/>
|
|
<ul t-if="c.child_id" class="nav flex-column nav-hierarchy mt-1 ps-3">
|
|
<t t-foreach="c.child_id" 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('/shop/category/' + slug(c), category=0)"
|
|
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', category=0)"
|
|
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">
|
|
<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)"/>
|
|
|
|
<t t-if="children">
|
|
<t t-set="isOpen" t-value="c.id in category.parents_and_self.ids"/>
|
|
|
|
<li class="nav-item">
|
|
<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 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 & 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">
|
|
<form class="js_attributes position-relative mb-2" method="get">
|
|
<input t-if="category" type="hidden" name="category" t-att-value="category.id" />
|
|
<input type="hidden" name="search" t-att-value="search" />
|
|
<input type="hidden" name="order" t-att-value="order"/>
|
|
<div
|
|
t-if="attrib_values or tags"
|
|
class="accordion-item rounded-0 border-top-0 py-3"
|
|
>
|
|
<a
|
|
t-att-href="keep('/shop' + ('/category/' + slug(category)) if category else None, attribute_value=0, tags=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>
|
|
<t t-foreach="attributes" t-as="a">
|
|
<t t-cache="a,attrib_set">
|
|
<div class="accordion-item nav-item mb-1 rounded-0" t-if="a.value_ids and len(a.value_ids) > 1">
|
|
<h6 class="mb-3">
|
|
<b class="d-none d-lg-block" t-field="a.name"/>
|
|
</h6>
|
|
<div t-attf-id="o_products_attributes_{{a.id}}" class="">
|
|
<t t-if="a.display_type == 'select'">
|
|
<select class="form-select css_attribute_select mb-2" 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-esc="v.name" t-att-selected="v.id in attrib_set" />
|
|
</t>
|
|
</select>
|
|
</t>
|
|
<div t-elif="a.display_type == 'color'" class="mb-3">
|
|
<t t-call="website_sale.o_wsale_offcanvas_color_attribute"/>
|
|
</div>
|
|
<div t-elif="a.display_type in ('radio', 'pills', 'multi')" class="flex-column mb-3">
|
|
<t t-foreach="a.value_ids" t-as="v">
|
|
<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="'checked' if v.id in attrib_set else None"/>
|
|
<label class="form-check-label fw-normal" t-att-for="'%s-%s' % (a.id,v.id)" t-field="v.name"/>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
<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>
|
|
</form>
|
|
</div>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template
|
|
id="products_attributes_collapsible"
|
|
name="Collapsed Attributes & Variants filters"
|
|
inherit_id="website_sale.products_attributes"
|
|
>
|
|
<xpath expr="//form" position="attributes">
|
|
<attribute
|
|
name="class"
|
|
add="wsale_accordion_collapsible accordion accordion-flush"
|
|
remove="mb-2"
|
|
separator=" "
|
|
/>
|
|
</xpath>
|
|
<xpath expr="//div[hasclass('accordion-item')]//h6" position="replace">
|
|
<h6 class="accordion-header">
|
|
<button
|
|
class="accordion-button px-0 bg-transparent shadow-none"
|
|
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}}"
|
|
aria-expanded="true"
|
|
>
|
|
<b t-field="a.name"/>
|
|
</button>
|
|
</h6>
|
|
</xpath>
|
|
<xpath expr="//div[@t-attf-id='o_products_attributes_{{a.id}}']" position="attributes">
|
|
<attribute name="class" add="accordion-collapse collapse show" separator=" "/>
|
|
<attribute name="data-bs-parent" add="wsale_products_attributes_collapse"/>
|
|
</xpath>
|
|
<xpath expr="//select" position="attributes">
|
|
<attribute name="class" add="mb-3" remove="mb-2" separator=" "/>
|
|
</xpath>
|
|
<xpath expr="//div[hasclass('flex-column')]" position="attributes">
|
|
<attribute name="class" add="mb-3" separator=" "/>
|
|
</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">
|
|
<h6 class="accordion-header">
|
|
<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>
|
|
</h6>
|
|
<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-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-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">
|
|
<h6 class="mb-3">
|
|
<b>Tags</b>
|
|
</h6>
|
|
<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>
|
|
</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>
|
|
|
|
<!-- /shop/product page -->
|
|
<template id="base_unit_price" name="Product Base unit price">
|
|
(<span class="o_base_unit_price" t-esc="combination_info['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="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="combination_info" t-value="product._get_combination_info()"/>
|
|
<t t-set="product_variant" t-value="product.env['product.product'].browse(combination_info['product_id'])"/>
|
|
|
|
<t t-call="website.layout">
|
|
<t t-set="additional_title" t-value="product.name" />
|
|
<div itemscope="itemscope" itemtype="http://schema.org/Product" id="wrap" class="js_sale o_wsale_product_page">
|
|
<t t-set="editor_message">DROP BUILDING BLOCKS HERE TO MAKE THEM AVAILABLE ACROSS ALL PRODUCTS</t>
|
|
<div class="oe_structure oe_empty oe_structure_not_nearest" id="oe_structure_website_sale_product_1" t-att-data-editor-message="editor_message"/>
|
|
<section id="product_detail"
|
|
t-attf-class="oe_website_sale container my-3 my-lg-4 #{'discount'
|
|
if combination_info['has_discounted_price'] else ''}"
|
|
t-att-data-view-track="view_track and '1' or '0'"
|
|
t-att-data-product-tracking-info="'product_tracking_info' in combination_info and json.dumps(combination_info['product_tracking_info'])"
|
|
>
|
|
<div class="row align-items-center">
|
|
<div class="col d-flex align-items-center order-1 order-lg-0">
|
|
<ol class="o_wsale_breadcrumb breadcrumb p-0 mb-4 m-lg-0">
|
|
<li class="o_not_editable breadcrumb-item d-none d-lg-inline-block">
|
|
<a t-att-href="keep(category=0, attribute_value=0, tags=0)">
|
|
<i class="oi oi-chevron-left d-lg-none me-1" role="presentation"/>All Products
|
|
</a>
|
|
</li>
|
|
<li
|
|
t-nocache="The category does not have to be cached, as the product can be accessed via different paths."
|
|
t-if="category"
|
|
class="breadcrumb-item"
|
|
>
|
|
<a
|
|
class="py-2 py-lg-0"
|
|
t-att-href="keep('/shop/category/%s' % slug(category), category=0, attribute_value=0, tags=0)"
|
|
>
|
|
<i class="oi oi-chevron-left d-lg-none me-1" role="presentation"/><t t-out="category.name"/>
|
|
</a>
|
|
</li>
|
|
<li t-else="" class="o_not_editable breadcrumb-item d-lg-none">
|
|
<a
|
|
class="py-2 py-lg-0"
|
|
t-att-href="keep(category=0, attribute_value=0, tags=0)"
|
|
>
|
|
<i class="oi oi-chevron-left me-1" role="presentation"/>All Products
|
|
</a>
|
|
</li>
|
|
<li class="breadcrumb-item d-none d-lg-inline-block active">
|
|
<span t-field="product.name" />
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
<div class="col-lg-4 d-flex align-items-center">
|
|
<div class="d-flex justify-content-between w-100">
|
|
<t t-if="is_view_active('website_sale.search')" t-call="website_sale.search">
|
|
<t t-set="search" t-value="False"/>
|
|
<t t-set="_form_classes" t-valuef="mb-4 mb-lg-0"/>
|
|
<t t-set="_classes" t-value="'me-sm-2'"/>
|
|
</t>
|
|
<t t-call="website_sale.pricelist_list">
|
|
<t t-set="_classes" t-valuef="d-lg-inline ms-2"/>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row" id="product_detail_main" data-name="Product Page"
|
|
t-att-data-image_width="website.product_page_image_width"
|
|
t-att-data-image_layout="website.product_page_image_layout">
|
|
<t t-set="image_cols" t-value="website._get_product_page_proportions()"/>
|
|
<div
|
|
t-attf-class="col-lg-#{image_cols[0]} mt-lg-4 o_wsale_product_images position-relative"
|
|
t-if="website.product_page_image_width != 'none'"
|
|
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 t-attf-class="col-lg-#{image_cols[1]} mt-md-4" id="product_details">
|
|
<t t-set="base_url" t-value="website.get_base_url()"/>
|
|
<h1 itemprop="name" t-field="product.name">Product Name</h1>
|
|
<span itemprop="url" style="display:none;" t-esc="base_url + product.website_url"/>
|
|
<span itemprop="image" style="display:none;" t-esc="base_url + website.image_url(product, 'image_1920')" />
|
|
<t t-if="is_view_active('website_sale.product_comment')">
|
|
<a href="#o_product_page_reviews" class="o_product_page_reviews_link text-decoration-none">
|
|
<t t-call="portal_rating.rating_widget_stars_static">
|
|
<t t-set="rating_avg" t-value="product.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" class="oe_structure"
|
|
placeholder="A detailed, formatted description to promote your product on this page. Use '/' to discover more features."/>
|
|
<form t-if="product._is_add_to_cart_possible()" action="/shop/cart/update" method="POST">
|
|
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" t-nocache="The csrf token must always be up to date."/>
|
|
<div class="js_product js_main_product mb-3">
|
|
<div>
|
|
<t t-call="website_sale.product_price"/>
|
|
<small t-if="'base_unit_price' in combination_info"
|
|
class="ms-1 text-muted o_base_unit_price_wrapper d-none" groups="website_sale.group_show_uom_price">
|
|
<t t-call='website_sale.base_unit_price'/>
|
|
</small>
|
|
</div>
|
|
<t t-placeholder="select">
|
|
<input type="hidden" class="product_id" name="product_id" t-att-value="product_variant.id" />
|
|
<input type="hidden" class="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]" />
|
|
<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>
|
|
</t>
|
|
<p t-if="True" class="css_not_available_msg alert alert-warning">This combination does not exist.</p>
|
|
<div id="o_wsale_cta_wrapper" class="d-flex flex-wrap align-items-center">
|
|
<t t-set="hasQuantities" t-value="false"/>
|
|
<t t-set="hasBuyNow" t-value="false"/>
|
|
<!-- TODO: remove line below in master -->
|
|
<t t-set="ctaSizeBig" t-value="not hasQuantities or not hasBuyNow"/>
|
|
|
|
<div id="add_to_cart_wrap" t-attf-class="{{'d-none' if combination_info['prevent_zero_price_sale'] else 'd-inline-flex'}} align-items-center mb-2 me-auto">
|
|
<a data-animation-selector=".o_wsale_product_images" role="button" id="add_to_cart" t-attf-class="btn btn-primary js_check_product a-submit flex-grow-1" href="#">
|
|
<i class="fa fa-shopping-cart me-2"/>
|
|
Add to cart
|
|
</a>
|
|
</div>
|
|
<div id="product_option_block" class="d-flex flex-wrap w-100"/>
|
|
</div>
|
|
<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>
|
|
</div>
|
|
</form>
|
|
<p t-elif="not product.active" class="alert alert-warning">
|
|
This product is no longer available.
|
|
</p>
|
|
<p t-else="" class="alert alert-warning">
|
|
This product has no valid combination.
|
|
</p>
|
|
<t t-call="website_sale.product_accordion"/>
|
|
<div
|
|
id="contact_us_wrapper"
|
|
t-attf-class="{{'d-flex' if combination_info['prevent_zero_price_sale'] else 'd-none'}} oe_structure oe_structure_solo #{_div_classes}"
|
|
>
|
|
<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"
|
|
class="btn btn-primary btn_cta"
|
|
>
|
|
Contact Us
|
|
</a>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
<div
|
|
t-if="not is_view_active('website_sale_comparison.accordion_specs_item')"
|
|
id="product_attributes_simple"
|
|
>
|
|
<t t-set="single_value_attributes" t-value="product.valid_product_template_attribute_line_ids._prepare_single_value_for_display()"/>
|
|
<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="my-2" t-if="product_documents">
|
|
<h5>Documents</h5>
|
|
<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'"/>
|
|
<div>
|
|
<a t-att-href="'/shop/' + slug(product) + '/document/' + str(document_sudo.id)" t-att-target="target">
|
|
<i t-att-class="'fa ' + icon"/>
|
|
<t t-out="attachment_sudo.name"/>
|
|
</a>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
<div
|
|
id="o_product_terms_and_share"
|
|
class="d-flex justify-content-between flex-column flex-md-row align-items-md-end gap-3 mb-3"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<div itemprop="description" t-field="product.website_description" class="oe_structure oe_empty mt16" id="product_full_description"/>
|
|
<div class="oe_structure oe_empty oe_structure_not_nearest mt16" id="oe_structure_website_sale_product_2" t-att-data-editor-message="editor_message"/>
|
|
</div>
|
|
</t>
|
|
</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 pt-0">
|
|
<p>This content will be shared across all product pages.</p>
|
|
</div>
|
|
</div>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="product_tags" name="Product Tags" active="True">
|
|
<div class="o_product_tags o_field_tags d-flex flex-wrap align-items-center gap-2 mb-2 mt-1">
|
|
<t t-foreach="all_product_tags" t-as="tag">
|
|
<t t-if="tag.visible_on_ecommerce">
|
|
<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>
|
|
</t>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="alternative_products" name="Alternative Products" inherit_id="website_sale.product" active="True">
|
|
<div itemprop="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_borderless_1" 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 o_not_editable">
|
|
<div class="css_non_editable_mode_hidden">
|
|
<div class="missing_option_warning alert alert-info rounded-0 fade show d-none d-print-none o_default_snippet_text">
|
|
Your Dynamic Snippet will be displayed here...
|
|
This message is displayed because youy did not provide both a filter and a template to use.
|
|
</div>
|
|
</div>
|
|
<div class="dynamic_snippet_template"></div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="product_custom_text" inherit_id="website_sale.product" customize_show="True" active="True" name="Terms and Conditions" priority="21">
|
|
<xpath expr="//div[@id='o_product_terms_and_share']" position="inside">
|
|
<p class="text-muted mb-0">
|
|
<a href="/terms" class="text-muted"><u>Terms and Conditions</u></a><br/>
|
|
30-day money-back guarantee<br/>
|
|
Shipping: 2-3 Business Days
|
|
</p>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="product_share_buttons" inherit_id="website_sale.product" active="True" name="Share Buttons" priority="22">
|
|
<xpath expr="//div[@id='o_product_terms_and_share']" position="inside">
|
|
<div
|
|
data-snippet="s_share"
|
|
data-name="Share"
|
|
class="s_share text-start o_no_link_popover"
|
|
>
|
|
<h4 class="s_share_title d-none o_default_snippet_text">Share</h4>
|
|
<a
|
|
href="https://www.facebook.com/sharer/sharer.php?u={url}"
|
|
target="_blank"
|
|
aria-label="Facebook"
|
|
class="s_share_facebook"
|
|
>
|
|
<i class="fa fa-facebook rounded shadow-sm"/>
|
|
</a>
|
|
<a
|
|
href="https://twitter.com/intent/tweet?text={title}&url={url}"
|
|
target="_blank"
|
|
aria-label="X"
|
|
class="s_share_twitter"
|
|
>
|
|
<i class="fa fa-twitter rounded shadow-sm"/>
|
|
</a>
|
|
<a
|
|
href="https://www.linkedin.com/sharing/share-offsite/?url={url}"
|
|
target="_blank"
|
|
aria-label="LinkedIn"
|
|
class="s_share_linkedin"
|
|
>
|
|
<i class="fa fa-linkedin rounded shadow-sm"/>
|
|
</a>
|
|
<a
|
|
href="https://wa.me/?text={title}"
|
|
target="_blank"
|
|
aria-label="WhatsApp"
|
|
class="s_share_whatsapp"
|
|
>
|
|
<i class="fa fa-whatsapp rounded shadow-sm"/>
|
|
</a>
|
|
<a
|
|
href="https://pinterest.com/pin/create/button/?url={url}&media={media}&description={title}"
|
|
target="_blank"
|
|
aria-label="Pinterest"
|
|
class="s_share_pinterest"
|
|
>
|
|
<i class="fa fa-pinterest rounded shadow-sm"/>
|
|
</a>
|
|
<a
|
|
href="mailto:?body={url}&subject={title}"
|
|
aria-label="Email"
|
|
class="s_share_email"
|
|
>
|
|
<i class="fa fa-envelope rounded shadow-sm"/>
|
|
</a>
|
|
</div>
|
|
</xpath>
|
|
</template>
|
|
|
|
<!-- Product options: Zoom -->
|
|
<template inherit_id='website_sale.product' id="product_picture_magnify_hover" name="Automatic Image Zoom">
|
|
<xpath expr='//div[hasclass("o_wsale_product_page")]' position='attributes'>
|
|
<attribute name="data-ecom-zoom-auto">1</attribute>
|
|
<attribute name="class" separator=" " add="ecom-zoomable zoomodoo-next" />
|
|
</xpath>
|
|
</template>
|
|
|
|
<template inherit_id='website_sale.product' id="product_picture_magnify_click" active="False" 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 zoomodoo-next" />
|
|
</xpath>
|
|
</template>
|
|
|
|
<template inherit_id='website_sale.product' id="product_picture_magnify_both" active="False" name="Automatic Image Zoom And On Click">
|
|
<xpath expr='//div[hasclass("o_wsale_product_page")]' position='attributes'>
|
|
<attribute name="data-ecom-zoom-auto">1</attribute>
|
|
<attribute name="data-ecom-zoom-click">1</attribute>
|
|
<attribute name="class" separator=" " add="ecom-zoomable zoomodoo-next" />
|
|
</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" data-anchor='true'>
|
|
<section id="o_product_page_reviews" class="container pt32 pb32" data-anchor='true'>
|
|
<a class="o_product_page_reviews_title d-flex justify-content-between 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">
|
|
<h3 class="mb32">Customer Reviews</h3>
|
|
<i class="fa align-self-start"/>
|
|
</a>
|
|
<div id="o_product_page_reviews_content" class="collapse">
|
|
<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="product_quantity" inherit_id="website_sale.product" name="Select Quantity">
|
|
<xpath expr="//t[@t-set='hasQuantities']" position="attributes">
|
|
<attribute name="t-value" remove="false" add="true" separator=" "/>
|
|
</xpath>
|
|
<div id="add_to_cart_wrap" position="before">
|
|
<div t-attf-class="css_quantity input-group {{'d-none' if combination_info['prevent_zero_price_sale'] else 'd-inline-flex'}} me-2 mb-2 align-middle" contenteditable="false">
|
|
<a t-attf-href="#" class="btn btn-link js_add_cart_json" aria-label="Remove one" title="Remove one">
|
|
<i class="fa fa-minus"/>
|
|
</a>
|
|
<input type="text" class="form-control quantity text-center" data-min="1" name="add_qty" t-att-value="1"/>
|
|
<a t-attf-href="#" class="btn btn-link float_left js_add_cart_json" aria-label="Add one" title="Add one">
|
|
<i class="fa fa-plus"/>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="product_buy_now" inherit_id="website_sale.product" active="False" name="Buy Now Button">
|
|
<xpath expr="//t[@t-set='hasBuyNow']" position="attributes">
|
|
<attribute name="t-value" remove="false" add="true" separator=" "/>
|
|
</xpath>
|
|
<xpath expr="//a[@id='add_to_cart']" position="after">
|
|
<a role="button" class="btn btn-outline-primary o_we_buy_now ms-1" href="#">
|
|
<i class="fa fa-bolt me-2"/>
|
|
Buy now
|
|
</a>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="website_sale.tax_indication" active="False">
|
|
<span t-if="website.show_line_subtotals_tax_selection == 'tax_excluded'" class="h6 text-muted">
|
|
Tax Excluded
|
|
</span>
|
|
<span t-else="" class="h6 text-muted">
|
|
Tax Included
|
|
</span>
|
|
</template>
|
|
|
|
<template id="product_price">
|
|
<div itemprop="offers" itemscope="itemscope" itemtype="http://schema.org/Offer" t-attf-class="product_price mt-2 mb-3 {{'d-none' if combination_info['prevent_zero_price_sale'] else 'd-inline-block'}}">
|
|
<h3 class="css_editable_mode_hidden">
|
|
<span class="oe_price"
|
|
style="white-space: nowrap;"
|
|
t-out="combination_info['price']"
|
|
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
|
|
<span itemprop="price" style="display:none;" t-out="combination_info['price']"/>
|
|
<span itemprop="priceCurrency" style="display:none;" t-esc="website.currency_id.name"/>
|
|
<span t-attf-class="text-muted oe_default_price ms-1 h5 {{'' if combination_info['has_discounted_price'] and not combination_info['compare_list_price'] else 'd-none'}}"
|
|
style="text-decoration: line-through; white-space: nowrap;"
|
|
t-esc="combination_info['list_price']"
|
|
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"
|
|
itemprop="listPrice"
|
|
/>
|
|
<t t-if="is_view_active('website_sale.tax_indication')" t-call="website_sale.tax_indication"/>
|
|
<del t-if="combination_info['compare_list_price'] and (combination_info['compare_list_price'] > combination_info['price'])"
|
|
class="text-muted ms-1 h5 oe_compare_list_price">
|
|
<bdi dir="inherit">
|
|
<span t-esc="combination_info['compare_list_price']"
|
|
groups="website_sale.group_product_price_comparison"
|
|
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
|
|
</bdi>
|
|
</del>
|
|
</h3>
|
|
<h3 class="css_non_editable_mode_hidden decimal_precision" 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['compare_list_price'] and (combination_info['compare_list_price'] > combination_info['price'])">
|
|
<bdi dir="inherit">
|
|
<span t-field="product.compare_list_price"
|
|
groups="website_sale.group_product_price_comparison"
|
|
t-options="{'widget': 'monetary', 'display_currency': product.currency_id}"/>
|
|
</bdi>
|
|
</del>
|
|
</h3>
|
|
</div>
|
|
<div id="product_unavailable" t-attf-class="{{'d-flex' if combination_info['prevent_zero_price_sale'] else 'd-none'}}">
|
|
<h3 class="fst-italic" t-field="website.prevent_zero_price_sale_text"/>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="product_variants" inherit_id="website_sale.product" active="False" name="List View of Variants">
|
|
<xpath expr="//t[@t-placeholder='select']" position="replace">
|
|
<!--
|
|
Using this setting with dynamic variants is not supported.
|
|
Indeed the variants that have yet to exist will not show on the
|
|
list and will never be selectable to be created...
|
|
|
|
We also don't use the feature with no_variant because these
|
|
attributes have to be selected manually.
|
|
|
|
Finally we don't use the feature with is_custom values because
|
|
they need to be set by the user.
|
|
-->
|
|
<t t-if="not product.has_dynamic_attributes() and not product._has_no_variant_attributes() and not product._has_is_custom_values()">
|
|
<t t-set="attribute_exclusions" t-value="product._get_attribute_exclusions()"/>
|
|
<t t-set="filtered_sorted_variants" t-value="product._get_possible_variants_sorted()"/>
|
|
<ul class="d-none js_add_cart_variants mb-0" t-att-data-attribute_exclusions="json.dumps(attribute_exclusions)"/>
|
|
<input type="hidden" class="product_template_id" name="product_template_id" t-att-value="product.id"/>
|
|
<input type="hidden" t-if="len(filtered_sorted_variants) == 1" class="product_id" name="product_id" t-att-value="filtered_sorted_variants[0].id"/>
|
|
<t t-if="len(filtered_sorted_variants) > 1">
|
|
<t t-set="template_combination_info" t-value="product._get_combination_info(only_template=True)"/>
|
|
<div class="mb-4">
|
|
<div t-foreach="filtered_sorted_variants" t-as="variant_id" class="form-check mb-1">
|
|
<t t-set="combination_info" t-value="variant_id._get_combination_info_variant()"/>
|
|
<input type="radio"
|
|
name="product_id"
|
|
class="form-check-input product_id js_product_change"
|
|
t-att-checked="'checked' if variant_id_index == 0 else None"
|
|
t-attf-id="radio_variant_#{variant_id.id}"
|
|
t-att-value="variant_id.id"
|
|
t-att-data-price="combination_info['price']"
|
|
t-att-data-combination="variant_id.product_template_attribute_value_ids.ids"/>
|
|
<label t-attf-for="radio_variant_#{variant_id.id}" label-default="label-default" class="form-check-label fw-normal">
|
|
<span t-out="combination_info['display_name']"/>
|
|
<t t-set="diff_price" t-value="website.currency_id.compare_amounts(combination_info['price'], template_combination_info['price'])"/>
|
|
<span t-attf-class="badge text-bg-{{navClass}} border" t-if="diff_price != 0">
|
|
<span class="sign_badge_price_extra" t-out="diff_price > 0 and '+' or '-'"/>
|
|
<span t-out="abs(combination_info['price'] - template_combination_info['price'])"
|
|
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"
|
|
class="text-muted fst-italic"/>
|
|
</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
<t t-else="">$0</t>
|
|
</xpath>
|
|
</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="show_navigation_button" t-value="False"/>
|
|
<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>
|
|
|
|
<h3 class="mb-4">Extra info</h3>
|
|
<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">
|
|
<div class="s_website_form_field col-12 py-2 mb-0" data-type="char" data-name="Field">
|
|
<div class="s_col_no_resize s_col_no_bgcolor row">
|
|
<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 py-2 mb-0" data-type="text" data-name="Field">
|
|
<div class="s_col_no_resize s_col_no_bgcolor row">
|
|
<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 py-2 mb-0" data-type="binary" data-name="Field">
|
|
<div class="s_col_no_resize s_col_no_bgcolor row">
|
|
<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 class="s_website_form_submit s_website_form_no_submit_option d-flex flex-column flex-lg-row align-items-lg-center pt-4">
|
|
<a role="button"
|
|
name="website_sale_main_button"
|
|
class="s_website_form_send btn btn-primary order-lg-3 w-100 w-lg-auto ms-lg-auto"
|
|
href="/shop/confirm_order">
|
|
Continue checkout
|
|
<i class="fa fa-angle-right ms-2 fw-light"/>
|
|
</a>
|
|
|
|
<div class="position-relative d-flex d-lg-none 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>
|
|
|
|
<a href="/shop/checkout" class="text-center">
|
|
<i class="fa fa-angle-left me-2 fw-light"/>
|
|
Return to shipping
|
|
</a>
|
|
<span id="s_website_form_result"/>
|
|
</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-att-href="line.product_id.website_url">
|
|
<t t-out="0"/>
|
|
</a>
|
|
</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" t-attf-class="text-muted {{div_class}} small">
|
|
<t t-foreach="description_lines" t-as="name_line">
|
|
<span t-if="name_line" class="d-block" 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 alert alert-info">
|
|
Your cart is empty!
|
|
</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> <t t-esc='website_sale_order._get_shop_warning()'/>
|
|
</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-set="show_qty" t-value="is_view_active('website_sale.product_quantity')"/>
|
|
<div t-foreach="website_sale_order.website_order_line"
|
|
t-as="line"
|
|
t-attf-class="o_cart_product d-flex align-items-stretch gap-3 #{line.linked_line_id and 'optional_product info'} #{not line_last and 'border-bottom pb-4'} #{line_index > 0 and 'pt-4'}"
|
|
t-attf-data-product-id="#{line.product_id and line.product_id.id}">
|
|
<t t-if="line.product_id">
|
|
<div style="width: 64px">
|
|
<!--
|
|
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).
|
|
-->
|
|
<img
|
|
t-if="line._is_not_sellable_line() and line.product_id.image_128"
|
|
t-att-src="image_data_uri(line.product_id.image_128)"
|
|
class="o_image_64_max img rounded"
|
|
t-att-alt="line.name_short"
|
|
/>
|
|
<div
|
|
t-elif="line.product_id.image_128"
|
|
t-field="line.product_id.image_128"
|
|
t-options="{
|
|
'widget': 'image',
|
|
'qweb_img_responsive': False,
|
|
'class': 'o_image_64_max rounded',
|
|
}"
|
|
/>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<t t-call="website_sale.cart_line_product_link">
|
|
<h6 t-field="line.name_short" class="d-inline align-top h6 fw-bold"/>
|
|
</t>
|
|
<t t-call="website_sale.cart_line_description_following_lines">
|
|
<t t-set="div_class" t-value="''"/>
|
|
</t>
|
|
<div name="o_wsale_cart_line_button_container">
|
|
<a href='#'
|
|
class="js_delete_product d-none d-md-inline-block small"
|
|
aria-label="Remove from cart"
|
|
title="Remove from cart">Remove</a>
|
|
<button class="js_delete_product btn btn-light d-inline-block d-md-none"
|
|
title="remove">
|
|
<i class="fa fa-trash-o"/>
|
|
</button>
|
|
</div>
|
|
<t t-if="line.product_type == 'combo'">
|
|
<div
|
|
t-foreach="line.linked_line_ids"
|
|
t-as="combo_item_line"
|
|
t-attf-class="{{'' if combo_item_line_last else 'pb-2'}}"
|
|
>
|
|
<t t-call="website_sale.cart_combo_item_line"/>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
<div class="d-flex flex-column align-items-end">
|
|
<div t-attf-class="css_quantity input-group mb-2"
|
|
name="website_sale_cart_line_quantity">
|
|
<t t-if="not line._is_not_sellable_line()">
|
|
<t t-if="show_qty">
|
|
<a href="#"
|
|
class="js_add_cart_json btn btn-link d-inline-block border-end-0"
|
|
aria-label="Remove one"
|
|
title="Remove one">
|
|
<i class="position-relative z-1 fa fa-minus"/>
|
|
</a>
|
|
<input type="text"
|
|
class="js_quantity quantity form-control border-start-0 border-end-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="js_add_cart_json d-inline-block float_left btn btn-link border-start-0"
|
|
aria-label="Add one"
|
|
title="Add one">
|
|
<i class="fa fa-plus position-relative z-1"/>
|
|
</a>
|
|
</t>
|
|
<t t-else="">
|
|
<input type="hidden"
|
|
class="js_quantity form-control quantity"
|
|
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>
|
|
<t t-else="">
|
|
<span class="w-100 text-muted" t-esc="int(line.product_uom_qty)"/>
|
|
<input type="hidden"
|
|
class="js_quantity quantity form-control"
|
|
t-att-data-line-id="line.id"
|
|
t-att-data-product-id="line.product_id.id"
|
|
t-att-value="line._get_displayed_quantity()"/>
|
|
</t>
|
|
</div>
|
|
<div class="mb-0 h6 fw-bold text-end" name="website_sale_cart_line_price">
|
|
<t t-if="line.discount">
|
|
<del t-attf-class="#{'text-muted mr8'}"
|
|
style="white-space: nowrap;"
|
|
t-out="line._get_displayed_unit_price() * line.product_uom_qty"
|
|
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
|
|
</t>
|
|
<t t-set="product_price" t-value="line._get_cart_display_price()"/>
|
|
<t t-call="website_sale.cart_product_price"/>
|
|
<small t-if="not line._is_not_sellable_line() and line.product_id.base_unit_price"
|
|
class="cart_product_base_unit_price d-block text-muted"
|
|
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='combination_info'
|
|
t-value="{'base_unit_price': product._get_base_unit_price(product_price/line.product_uom_qty)}"/>
|
|
</t>
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="cart_combo_item_line">
|
|
<div class="d-flex align-items-center">
|
|
<div t-field="combo_item_line.product_id.image_128"
|
|
t-options="{
|
|
'widget': 'image',
|
|
'qweb_img_responsive': False,
|
|
'class': 'o_image_64_max rounded',
|
|
}"
|
|
/>
|
|
<div class="ms-3">
|
|
<a t-att-href="combo_item_line.product_id.website_url">
|
|
<h6 class="d-inline align-top h6 fw-bold">
|
|
<span t-out="combo_item_line._get_displayed_quantity()"/>
|
|
x
|
|
<span t-out="combo_item_line.name_short"/>
|
|
</h6>
|
|
</a>
|
|
<t
|
|
t-set="description_lines"
|
|
t-value="combo_item_line.get_description_following_lines()"
|
|
/>
|
|
<div t-if="description_lines" t-attf-class="text-muted d-none d-md-block small">
|
|
<t t-foreach="description_lines" t-as="description_line">
|
|
<span class="d-block" t-if="description_line" t-out="description_line"/>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</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 class="col">
|
|
<h3 class="mb-4">Order overview</h3>
|
|
<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 t-attf-href="/shop/cart/?access_token=#{access_token}&revive=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 t-attf-href="/shop/cart/?access_token=#{access_token}&revive=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>
|
|
|
|
<!-- 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="mt32 mb-3" t-if="suggested_products">Suggested accessories</h5>
|
|
<div t-if="suggested_products"
|
|
id="suggested_products"
|
|
class="d-flex flex-column align-items-stretch mb32">
|
|
<div t-foreach="suggested_products"
|
|
t-as="product"
|
|
t-attf-class="d-flex gap-3 #{not product_last and 'border-bottom pb-4'} #{product_index > 0 and 'pt-4'}"
|
|
t-att-data-publish="product.website_published and 'on' or 'off'">
|
|
<div style="width: 64px">
|
|
<a t-att-href="product.website_url">
|
|
<span t-field="product.image_128" t-options="{'widget': 'image', 'qweb_img_responsive': False, 'class': 'o_image_64_max rounded'}"/>
|
|
</a>
|
|
</div>
|
|
<div class="o_cart_suggested_product_name flex-grow-1">
|
|
<div>
|
|
<a t-att-href="product.website_url">
|
|
<strong t-out="product.with_context(display_default_code=False).display_name"/>
|
|
</a>
|
|
</div>
|
|
<div class="d-none d-md-block text-muted" t-field="product.description_sale"/>
|
|
</div>
|
|
<div class="d-flex flex-column align-items-end">
|
|
<input class="js_quantity" name="product_id" t-att-data-product-id="product.id" type="hidden"/>
|
|
<a role="button"
|
|
class="js_add_suggested_products btn btn-md btn-outline-primary text-nowrap">
|
|
<span class="d-md-none fa fa-shopping-cart"/>
|
|
<span class="d-none d-md-inline">Add to cart</span>
|
|
</a>
|
|
<div class="mb-0 h-6 fw-bold text-end d-flex"
|
|
name="website_sale_suggested_product_price">
|
|
<t t-set="combination_info"
|
|
t-value="product._get_combination_info_variant()"/>
|
|
<del t-attf-class="text-muted mr8 {{'' if combination_info['has_discounted_price'] else 'd-none'}}"
|
|
t-esc="combination_info['list_price']"
|
|
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"
|
|
style="white-space: nowrap;"/>
|
|
<span t-esc="combination_info['price']"
|
|
t-options="{'widget': 'monetary','display_currency': website.currency_id}"
|
|
style="white-space: nowrap;"/>
|
|
</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 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()" t-nocache="The csrf token must always be up to date."/>
|
|
<div class="input-group w-100 my-2">
|
|
<input name="promo" class="form-control" type="text" placeholder="Discount code..." t-att-value="website_sale_order.pricelist_id.code or None"/>
|
|
<a href="#" role="button" class="btn btn-secondary a-submit ps-2">Apply</a>
|
|
</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:
|
|
- _cta_classes: CSS classes to append on the primary navigation button; default `None`.
|
|
- _form_send_navigation: Whether the primary button serves as a submit button for a
|
|
form; default `None`.
|
|
- hide_payment_button: Whether the payment button should be hidden; default: False.
|
|
-->
|
|
<!-- Checkout context:
|
|
- website_sale_order: The current order.
|
|
- xmlid: The id of the xml templated rendered by the controller.
|
|
-->
|
|
<t t-set="step_specific_values" t-value="website._get_checkout_steps(xmlid)"/>
|
|
<div t-attf-class="#{_container_classes} d-flex #{_form_send_navigation and 'flex-column flex-lg-row align-items-lg-center' or 'flex-column'} mb-5 mb-lg-0 pt-4">
|
|
<t t-if="website_sale_order and website_sale_order.website_order_line">
|
|
<t t-if="xmlid == 'website_sale.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-nocache="The csrf token must always be up to date."/>
|
|
<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="#{_cta_classes} btn btn-primary #{not website_sale_order._is_cart_ready() and 'disabled'} #{_form_send_navigation and 'order-lg-3 w-100 w-lg-auto ms-lg-auto' or 'w-100'}"
|
|
t-att-href="step_specific_values['main_button_href']">
|
|
<t t-out="step_specific_values['main_button']"/>
|
|
<i class="fa fa-angle-right ms-2 fw-light"/>
|
|
</a>
|
|
</t>
|
|
</t>
|
|
<div t-if="not hide_payment_button" t-attf-class="position-relative #{_form_send_navigation and 'd-flex d-lg-none' or 'd-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>
|
|
<a t-att-href="step_specific_values['back_button_href']" class="text-center">
|
|
<i class="fa fa-angle-left me-2 fw-light"/>
|
|
<t t-out="step_specific_values['back_button']"/>
|
|
</a>
|
|
</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()">
|
|
<t t-call="website_sale.delivery_address_row">
|
|
<t t-set="addresses" t-value="delivery_addresses"/>
|
|
</t>
|
|
<t t-call="website_sale.delivery_form">
|
|
<t t-set="selected_dm_id" t-value="order.carrier_id.id"/>
|
|
</t>
|
|
</t>
|
|
<t t-call="website_sale.billing_address_row">
|
|
<t t-set="addresses" t-value="billing_addresses"/>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="delivery_address_row">
|
|
<div id="delivery_address_row" class="mb-4">
|
|
<h4 class="text-uppercase small fs-6 fw-bold">Delivery address</h4>
|
|
<t groups="account.group_delivery_invoice_address">
|
|
<t t-call="website_sale.address_row">
|
|
<t t-set="is_invoice" t-value="False"/>
|
|
<t t-set="addresses" t-value="delivery_addresses"/>
|
|
<t t-set="selected_address" t-value="order.partner_shipping_id"/>
|
|
</t>
|
|
</t>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="billing_address_row">
|
|
<div id="billing_address_row">
|
|
<h4 class="text-uppercase small fs-6 fw-bold mt-3">Billing address</h4>
|
|
<t t-set="has_delivery" t-value="order._has_deliverable_products()"/>
|
|
<div t-if="has_delivery" class="form-check form-switch mt-2 mb-3">
|
|
<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"
|
|
/> Same as delivery address
|
|
</label>
|
|
</div>
|
|
<div
|
|
id="billing_container"
|
|
t-attf-class="{{'d-none' if use_delivery_as_billing and has_delivery else ''}}"
|
|
>
|
|
<t t-call="website_sale.address_row">
|
|
<t t-set="is_invoice" t-value="True"/>
|
|
<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="address_row">
|
|
<div t-att-class="('all_billing' if is_invoice else 'all_delivery')
|
|
+ ' row row-cols-md-2 row-cols-lg-3 g-3 flex-nowrap flex-md-wrap'"
|
|
>
|
|
<div t-foreach="addresses" t-as="addr" class="one_kanban col-md">
|
|
<t t-call="website_sale.address_kanban">
|
|
<t t-set="contact" t-value="addr"/>
|
|
<t t-set="selected" t-value="addr == selected_address"/>
|
|
</t>
|
|
</div>
|
|
<div
|
|
t-if="is_invoice or not order.website_id.is_public_user()" class="one_kanban col-md"
|
|
>
|
|
<!-- We don't allow public users to have multiple delivery addresses. -->
|
|
<t t-if="is_invoice">
|
|
<t t-set="new_address_href" t-valuef="/shop/address?address_type=billing"/>
|
|
</t>
|
|
<t t-else="">
|
|
<t
|
|
t-set="new_address_href"
|
|
t-valuef="/shop/address?address_type=delivery&use_delivery_as_billing={{use_delivery_as_billing}}"
|
|
/>
|
|
</t>
|
|
<a
|
|
role="button"
|
|
t-att-href="new_address_href"
|
|
t-att-data-address-type="is_invoice and 'billing' or 'delivery'"
|
|
class="o_wsale_add_address d-flex align-items-center justify-content-center h-100 px-4 border rounded mx-auto no-decoration"
|
|
>
|
|
<i class="fa fa-plus me-md-2"/>
|
|
<span class="d-none d-md-inline">Add address</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- Card view of addresses. Called in `website_sale.checkout`. -->
|
|
<template id="address_kanban" name="Kanban address">
|
|
<t t-set="address_type" t-value="is_invoice and 'billing' or 'delivery'"/>
|
|
<div
|
|
name="address_card"
|
|
t-attf-class="card position-relative h-100 #{selected and 'bg-primary border border-primary' or 'js_change_address'}"
|
|
t-att-data-address-type="address_type"
|
|
t-att-data-partner-id="contact.id"
|
|
>
|
|
<div class="card-body d-flex flex-column align-items-start">
|
|
<t t-esc="contact" t-options="dict(widget='contact', fields=['name', 'address'], no_marker=True)"/>
|
|
<t t-if="contact._can_be_edited_by_current_customer(website_sale_order, address_type)">
|
|
<t t-set="new_address_href" t-value="'/shop/address?address_type=' + address_type"/>
|
|
<a
|
|
t-att-href="new_address_href + '&partner_id=' + str(contact.id)"
|
|
class="js_edit_address btn btn-link p-0 mt-auto"
|
|
role="button"
|
|
title="Edit this address"
|
|
aria-label="Edit this address">
|
|
<i class="fa fa-pencil me-1"/>Edit
|
|
</a>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- /shop/address route -->
|
|
<template id="website_sale.address" name="Address Management">
|
|
<t t-set="no_footer" t-value="1"/>
|
|
<t t-call="website.layout">
|
|
<div id="wrap">
|
|
<div class="oe_website_sale o_wsale_address_fill container py-2">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<t t-call="website_sale.wizard_checkout"/>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="oe_cart col-12 col-lg-8">
|
|
<div>
|
|
<t t-if="not is_anonymous_cart">
|
|
<t t-if="use_delivery_as_billing">
|
|
<h3 class="mb-3">Your address</h3>
|
|
</t>
|
|
<t t-elif="address_type == 'delivery'">
|
|
<h3 class="mb-3">Delivery address</h3>
|
|
</t>
|
|
<t t-else="">
|
|
<h3 class="mb-3">Billing address</h3>
|
|
</t>
|
|
</t>
|
|
<div
|
|
t-if="use_delivery_as_billing and not only_services"
|
|
class="alert alert-warning"
|
|
role="alert"
|
|
groups="account.group_delivery_invoice_address"
|
|
>
|
|
<h4 class="alert-heading">Be aware!</h4>
|
|
<p>
|
|
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 href="/shop/address?address_type=billing">new address</a>.
|
|
</p>
|
|
</div>
|
|
<div id="errors"/> <!-- for js -->
|
|
<form
|
|
action="/shop/address/submit"
|
|
method="post"
|
|
class="checkout_autoformat"
|
|
t-att-data-company-country-code="res_company.country_id.code"
|
|
>
|
|
<t t-if="is_anonymous_cart">
|
|
<div id="div_email_public" t-attf-class="col-lg-12">
|
|
<label class="col-form-label" for="o_email">Email</label>
|
|
<div
|
|
t-if="website.account_on_checkout != 'disabled'"
|
|
class="align-items-center float-end"
|
|
style="margin-top: -11px"
|
|
>
|
|
<span>Already have an account?</span>
|
|
<a
|
|
role="button"
|
|
href='/web/login?redirect=/shop/checkout'
|
|
class="btn btn-primary"
|
|
>
|
|
Sign in
|
|
</a>
|
|
</div>
|
|
<input
|
|
id="o_email"
|
|
type="email"
|
|
name="email"
|
|
class="form-control"
|
|
t-att-value="partner_sudo.email"
|
|
/>
|
|
</div>
|
|
<h4 class="mb-1 mt-5">Fill in your address</h4>
|
|
</t>
|
|
<div class="row">
|
|
<div id="div_name" class="col-lg-12 mb-2">
|
|
<label class="col-form-label" for="o_name">Full name</label>
|
|
<input
|
|
id="o_name"
|
|
type="text"
|
|
name="name"
|
|
t-att-value="partner_sudo.name"
|
|
class="form-control"
|
|
/>
|
|
</div>
|
|
<div class="w-100"/>
|
|
<div
|
|
t-if="not is_anonymous_cart"
|
|
id="div_email"
|
|
class="col-lg-6 mb-2"
|
|
>
|
|
<label class="col-form-label" for="o_email">Email</label>
|
|
<input
|
|
id="o_email"
|
|
type="email"
|
|
name="email"
|
|
t-att-value="partner_sudo.email"
|
|
class="form-control"
|
|
/>
|
|
</div>
|
|
<div id="div_phone" class="col-lg-6 mb-2">
|
|
<label class="col-form-label" for="o_phone">Phone</label>
|
|
<input
|
|
id="o_phone"
|
|
type="tel"
|
|
name="phone"
|
|
t-att-value="partner_sudo.phone"
|
|
class="form-control"
|
|
/>
|
|
</div>
|
|
<t t-if="website._display_partner_b2b_fields()">
|
|
<div class="w-100"/>
|
|
<t t-if="show_vat">
|
|
<t t-set="vat_warning" t-value="partner_sudo.vat and not can_edit_vat"/>
|
|
<div id="company_name_div" class="col-lg-6 mb-2">
|
|
<label
|
|
class="col-form-label fw-normal label-optional"
|
|
for="o_company_name"
|
|
>
|
|
Company Name
|
|
</label>
|
|
<input
|
|
id="o_company_name"
|
|
type="text"
|
|
name="company_name"
|
|
t-att-value="partner_sudo.commercial_company_name"
|
|
t-att-readonly="'1' if vat_warning else None"
|
|
class="form-control"
|
|
/>
|
|
<small t-if="vat_warning" class="form-text text-muted d-block d-lg-none">
|
|
Changing company name is not allowed once document(s) have been issued for your account. Please contact us directly for this operation.
|
|
</small>
|
|
</div>
|
|
<div id="div_vat" class="col-lg-6 mb-2">
|
|
<label class="col-form-label fw-normal label-optional" for="o_vat">
|
|
<t t-out="vat_label"/>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="o_vat"
|
|
name="vat"
|
|
t-att-value="partner_sudo.vat"
|
|
t-att-readonly="'1' if vat_warning else None"
|
|
class="form-control"
|
|
/>
|
|
<small t-if="vat_warning" class="form-text text-muted d-block d-lg-none">
|
|
Changing VAT number is not allowed once document(s) have been issued for your account. Please contact us directly for this operation.
|
|
</small>
|
|
</div>
|
|
<div t-if="vat_warning" class="col-12 d-none d-lg-block mb-1">
|
|
<small class="form-text text-muted">
|
|
Changing company name or VAT number is not allowed once document(s) have been issued for your account. Please contact us directly for this operation.
|
|
</small>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
<div id="div_street" class="col-lg-12 mb-2">
|
|
<label class="col-form-label" for="o_street">Street and Number</label>
|
|
<input id="o_street" type="text" name="street" class="form-control" t-att-value="partner_sudo.street"/>
|
|
</div>
|
|
<div id="div_street2" class="col-lg-12 mb-2">
|
|
<label class="col-form-label label-optional" for="o_street2">Apartment, suite, etc.</label>
|
|
<input id="o_street2" type="text" name="street2" class="form-control" t-att-value="partner_sudo.street2" />
|
|
</div>
|
|
<div class="w-100"/>
|
|
<t t-if="zip_before_city">
|
|
<div id="div_zip" class="col-md-4 mb-2">
|
|
<label class="col-form-label label-optional" for="o_zip">Zip Code</label>
|
|
<input id="o_zip" type="text" name="zip" class="form-control" t-att-value="partner_sudo.zip"/>
|
|
</div>
|
|
</t>
|
|
<div id="div_city" class="col-md-8 mb-2">
|
|
<label class="col-form-label" for="o_city">City</label>
|
|
<input id="o_city" type="text" name="city" class="form-control" t-att-value="partner_sudo.city"/>
|
|
</div>
|
|
<t t-if="not zip_before_city">
|
|
<div id="div_zip" class="col-md-4 mb-2">
|
|
<label class="col-form-label label-optional" for="o_zip">Zip Code</label>
|
|
<input id="o_zip" type="text" name="zip" class="form-control" t-att-value="partner_sudo.zip"/>
|
|
</div>
|
|
</t>
|
|
<div class="w-100"/>
|
|
<div id="div_country" class="col-lg-6 mb-2">
|
|
<label class="col-form-label" for="o_country_id">Country</label>
|
|
<select id="o_country_id" name="country_id" class="form-select">
|
|
<option value="">Country...</option>
|
|
<t t-foreach="countries" t-as="c">
|
|
<option t-att-value="c.id" t-att-selected="c.id == country.id" t-att-code="c.code">
|
|
<t t-esc="c.name" />
|
|
</option>
|
|
</t>
|
|
</select>
|
|
</div>
|
|
<div id="div_state" class="col-lg-6 mb-2"
|
|
t-att-style="not country_states and 'display: none'">
|
|
<label class="col-form-label" for="o_state_id">State / Province</label>
|
|
<select id="o_state_id" name="state_id" class="form-select">
|
|
<option value="">State / Province...</option>
|
|
<t t-foreach="country_states" t-as="s">
|
|
<option t-att-value="s.id" t-att-selected="s.id == state_id">
|
|
<t t-esc="s.name" />
|
|
</option>
|
|
</t>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" t-nocache="The csrf token must always be up to date."/>
|
|
<input type="hidden" name="address_type" t-att-value="address_type"/>
|
|
<input
|
|
type="hidden"
|
|
name="use_delivery_as_billing"
|
|
t-att-value="use_delivery_as_billing"
|
|
/>
|
|
<t t-if="partner_id">
|
|
<input type="hidden" name="partner_id" t-att-value="partner_id"/>
|
|
</t>
|
|
<t t-if="callback">
|
|
<input type="hidden" name="callback" t-att-value="callback"/>
|
|
</t>
|
|
|
|
<!-- Example -->
|
|
<input type="hidden" name="required_fields" t-att-value="'name,country_id'"/>
|
|
|
|
<div class="d-flex flex-column flex-md-row align-items-center justify-content-between mt32 mb32">
|
|
<a role="button" t-att-href="discard_url" class="btn btn-outline-secondary w-100 w-md-auto order-md-1 order-3">
|
|
<i class="fw-light fa fa-angle-left me-2"/>Discard
|
|
</a>
|
|
<div class="position-relative w-100 d-flex d-md-none justify-content-center align-items-center order-2 my-2 opacity-75">
|
|
<hr class="w-100"/>
|
|
<span class="px-3">or</span>
|
|
<hr class="w-100"/>
|
|
</div>
|
|
<button id="save_address" class="btn btn-primary w-100 w-md-auto order-1 order-md-3">
|
|
<t t-if="is_anonymous_cart">
|
|
Continue checkout
|
|
</t>
|
|
<t t-else="">
|
|
Save address
|
|
</t>
|
|
<i class="fw-light fa fa-angle-right ms-2"/>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
<!-- Deactivatable through the website editor. -->
|
|
<template id="address_b2b" inherit_id="website_sale.address" name="Show b2b fields" />
|
|
|
|
<!-- Called in `website_sale.payment`. -->
|
|
<template id="address_on_payment" name="Address on payment">
|
|
<div class="card">
|
|
<div class="card-body" id="delivery_and_billing">
|
|
<a class="float-end no-decoration" href="/shop/checkout"><i class="fa fa-pencil me-1"/>Edit</a>
|
|
<t
|
|
t-set="use_delivery_as_billing"
|
|
t-value="order.partner_invoice_id == order.partner_shipping_id and not order.pickup_location_data"
|
|
/>
|
|
<div t-if="not use_delivery_as_billing and order._has_deliverable_products()" groups="account.group_delivery_invoice_address">
|
|
<t t-if="order.pickup_location_data">
|
|
<b>Deliver to pickup point: </b>
|
|
<t t-out="order.pickup_location_data.get('name', '') + ', ' + order.pickup_location_data.get('street', '') + ' ' + order.pickup_location_data.get('zip_code', '') + ' ' + order.pickup_location_data.get('city','')"/>
|
|
</t>
|
|
<t t-else="">
|
|
<b>Delivery: </b>
|
|
<span
|
|
t-out="order.partner_shipping_id"
|
|
t-options="dict(widget='contact', fields=['address'], no_marker=True, separator=', ')"
|
|
class="address-inline"
|
|
/>
|
|
</t>
|
|
</div>
|
|
<div>
|
|
<b><t t-if="use_delivery_as_billing and not only_services">Delivery & </t>Billing: </b>
|
|
<span t-esc="order.partner_invoice_id" t-options="dict(widget='contact', fields=['address'], no_marker=True, separator=', ')" class="address-inline"/>
|
|
</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-esc="error[0]" />
|
|
</h4>
|
|
<t t-esc="error[1]" />
|
|
</div>
|
|
</t>
|
|
</div>
|
|
<h3 class="mb-4">Confirm order</h3>
|
|
<div id="address_on_payment" class="mb-4">
|
|
<t t-call="website_sale.address_on_payment"/>
|
|
</div>
|
|
<div class="oe_structure clearfix mt-3" 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 mt-4">
|
|
<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>
|
|
</t>
|
|
</template>
|
|
|
|
<!-- Activatable through the website editor. -->
|
|
<template id="accept_terms_and_conditions"
|
|
inherit_id="navigation_buttons"
|
|
name="Accept Terms & 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 & 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`.
|
|
- 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="show_wizard_checkout" t-value="True if show_wizard_checkout is None else show_wizard_checkout"/>
|
|
<div id="wrap">
|
|
<div class="oe_website_sale o_website_sale_checkout container py-2">
|
|
<div t-attf-class="row #{show_navigation_button and 'position-relative'} #{not show_wizard_checkout and 'mt32'} mb32">
|
|
<div t-if="show_wizard_checkout" class="col-12">
|
|
<t t-call="website_sale.wizard_checkout"/>
|
|
</div>
|
|
<div t-if="show_shorter_cart_summary"
|
|
class="offset-xl-1 col-lg-5 col-xl-4 order-2"
|
|
id="o_cart_summary">
|
|
<div class="o_total_card card sticky-lg-top"
|
|
t-if="website_sale_order and website_sale_order.website_order_line">
|
|
<div class="card-body p-0 p-lg-4">
|
|
<t t-call="website_sale.total"/>
|
|
<t
|
|
t-if="website.account_on_checkout != 'mandatory' or
|
|
not website.is_public_user()"
|
|
t-call="payment.express_checkout"
|
|
/>
|
|
<t t-call="website_sale.navigation_buttons"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div t-else=""
|
|
class="o_wsale_accordion accordion sticky-lg-top offset-xl-1 col-12 col-lg-5 col-xl-4 order-lg-2 rounded"
|
|
id="o_wsale_total_accordion">
|
|
<div class="o_total_card sticky-lg-top">
|
|
<div id="o_wsale_total_accordion_item" class="accordion-item p-lg-4 border-0">
|
|
<div class="accordion-header d-block align-items-center mb-4">
|
|
<button class="accordion-button px-0 collapsed"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#o_wsale_accordion_item"
|
|
aria-expanded="false"
|
|
aria-controls="o_wsale_accordion_item">
|
|
<div class="d-flex flex-wrap">
|
|
<b class="w-100">Order summary</b>
|
|
<span t-out="str(website_sale_order.cart_quantity)"/>
|
|
&nbsp;item(s)&nbsp;-&nbsp;
|
|
<span id="amount_total_summary"
|
|
class="monetary_field ms-1"
|
|
t-field="website_sale_order.amount_total"
|
|
t-options='{"widget": "monetary", "display_currency": website_sale_order.currency_id}'/>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
<div name="cart_summary_info" t-if="not website_sale_order or not website_sale_order.website_order_line" class="alert alert-info">
|
|
Your cart is empty!
|
|
</div>
|
|
<div id="o_wsale_accordion_item"
|
|
class="accordion-collapse collapse mb-4 mb-lg-0"
|
|
data-bs-parent="#o_wsale_total_accordion">
|
|
<div t-att-class="len(website_sale_order.website_order_line) > 3 and 'o_wsale_scrollable_table mt-n4 me-n4 pt-4 pe-4'">
|
|
<table t-if="website_sale_order and website_sale_order.website_order_line"
|
|
class="table accordion-body mb-0"
|
|
id="cart_products">
|
|
<tbody>
|
|
<tr t-foreach="website_sale_order.website_order_line" t-as="line" t-att-class="line_last and 'border-transparent'">
|
|
<t t-set="o_cart_sum_padding_top"
|
|
t-value="'pt-3' if line_size > 1 and not line_first else 'pt-0'"/>
|
|
<td t-if="not line.product_id" colspan="2"/>
|
|
<t t-else="">
|
|
<td t-attf-class="td-img ps-0 #{o_cart_sum_padding_top}">
|
|
<span t-if="line._is_not_sellable_line() and line.product_id.image_128">
|
|
<img t-att-src="image_data_uri(line.product_id.image_128)" class="o_image_64_max 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': 'o_image_64_max rounded'}"
|
|
/>
|
|
</td>
|
|
<td t-attf-class="#{o_cart_sum_padding_top} td-product_name td-qty w-100"
|
|
name='website_sale_cart_summary_product_name'>
|
|
<h6>
|
|
<t t-out="int(line.product_uom_qty)" />
|
|
<t t-if="line._get_shop_warning(clear=False)">
|
|
<i class="fa fa-warning text-warning"
|
|
role="img"
|
|
t-att-title="line._get_shop_warning()"
|
|
aria-label="Warning"/>
|
|
</t>
|
|
x
|
|
<t t-out="line.name_short"/>
|
|
</h6>
|
|
</td>
|
|
</t>
|
|
<td t-attf-class="#{o_cart_sum_padding_top} td-price pe-0 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-esc='website_sale_order._get_shop_warning()'/>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
<t t-call="website_sale.total">
|
|
<t t-set="_cart_total_classes" t-valuef="border-top pt-3"/>
|
|
</t>
|
|
<div t-if="show_navigation_button" class="o_cta_navigation_container position-absolute position-lg-static start-0 bottom-0 col-12">
|
|
<t t-call="website_sale.navigation_buttons"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div t-attf-class="oe_cart col-12 col-lg-7">
|
|
<t t-out="0"/>
|
|
</div>
|
|
<!-- This div serves as an anchor for the navigation buttons on the mobile
|
|
view. -->
|
|
<div t-if="not show_shorter_cart_summary and show_navigation_button"
|
|
class="o_cta_navigation_placeholder d-block d-none d-lg-none order-lg-4"/>
|
|
</div>
|
|
</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>
|
|
|
|
<!-- /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_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']" class="d-flex justify-content-between align-items-center">
|
|
<h3>Thank you for your order.</h3>
|
|
<a role="button" class="d-none d-md-inline-block btn btn-primary ms-auto" href="/shop/print" target="_blank" aria-label="Print" title="Print"><i class="fa fa-print me-2"></i>Print</a>
|
|
</div>
|
|
<t t-if="tx_sudo.state == 'done'">
|
|
<div class="mb-4">
|
|
<h5>
|
|
<em>
|
|
<span>Order</span>
|
|
<span t-field="order.name" />
|
|
<t t-if="order.state == 'sale'">
|
|
<i class="fa fa-check-circle ms-1"/>
|
|
</t>
|
|
</em>
|
|
</h5>
|
|
</div>
|
|
</t>
|
|
<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">Sign Up</a>
|
|
to follow your order.
|
|
</p>
|
|
</t>
|
|
<div class="oe_structure clearfix mt-3" id="oe_structure_website_sale_confirmation_1"/>
|
|
<h4 class="text-start mt-3">Payment Information</h4>
|
|
<table class="table">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" class="ps-0">
|
|
<t t-esc="tx_sudo.provider_id.name" />
|
|
</td>
|
|
<td class="text-end pe-0" width="100">
|
|
<strong>Total:</strong>
|
|
</td>
|
|
<td class="text-end pe-0" width="100">
|
|
<strong t-field="tx_sudo.amount" t-options="{'widget': 'monetary', 'display_currency': order.currency_id}" />
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<t t-call="website_sale.payment_confirmation_status"/>
|
|
<div class="card mt-3">
|
|
<div class="card-body">
|
|
<t t-set="same_shipping" t-value="bool(order.partner_shipping_id == order.partner_invoice_id or only_services)" />
|
|
<div><b>Billing <t t-if="same_shipping and not only_services"> & Delivery</t>: </b><span t-esc='order.partner_invoice_id' t-options="dict(widget='contact', fields=['address'], no_marker=True, separator=', ')" class="address-inline"/></div>
|
|
<div t-if="not same_shipping and not only_services" groups="account.group_delivery_invoice_address"><b>Delivery: </b><span t-esc='order.partner_shipping_id' t-options="dict(widget='contact', fields=['address'], no_marker=True, separator=', ')" class="address-inline"/></div>
|
|
</div>
|
|
</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)}"}' />
|
|
</t>
|
|
</template>
|
|
|
|
<!-- Called in `website_sale.checkout_layout`. -->
|
|
<template id="total">
|
|
<div id="cart_total" t-if="website_sale_order and website_sale_order.website_order_line" t-att-class="_cart_total_classes">
|
|
<table class="table mb-0">
|
|
<tr
|
|
t-if="website_sale_order._has_deliverable_products() and website_sale_order.carrier_id"
|
|
id="order_delivery"
|
|
>
|
|
<td
|
|
class="ps-0 pt-0 pb-2 border-0 text-muted"
|
|
colspan="2"
|
|
title="Delivery will be updated after choosing a new delivery method"
|
|
>
|
|
Delivery
|
|
</td>
|
|
<td class="text-end pe-0 pt-0 pb-2 border-0">
|
|
<span
|
|
t-out="website_sale_order.amount_delivery"
|
|
class="monetary_field"
|
|
style="white-space: nowrap;"
|
|
t-options="{'widget': 'monetary', 'display_currency': website_sale_order.currency_id}"
|
|
/>
|
|
</td>
|
|
</tr>
|
|
<tr id="order_total_untaxed">
|
|
<td id="cart_total_subtotal"
|
|
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 id="order_total_taxes">
|
|
<td colspan="2" class="text-muted border-0 ps-0 pt-0 pb-3">Taxes</td>
|
|
<td class="text-end border-0 pe-0 pt-0 pb-3">
|
|
<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 id="order_total" class="border-top">
|
|
<td colspan="2" class="border-0 ps-0 pt-3"><strong>Total</strong></td>
|
|
<td class="text-end border-0 px-0 pt-3">
|
|
<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[@id='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 class="oe_website_sale_tx_status 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-attf-class="card #{
|
|
(tx_sudo.state == 'pending' and 'bg-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 'bg-warning') or
|
|
(tx_sudo.state == 'authorized' and 'alert-success') or
|
|
'bg-danger'}">
|
|
<div class="card-header">
|
|
<a role="button" groups="base.group_system" class="btn btn-sm btn-link text-white float-end" target="_blank" aria-label="Edit" title="Edit"
|
|
t-attf-href="/odoo/action-payment.action_payment_provider/{{tx_sudo.provider_id.id}}">
|
|
<i class="fa fa-pencil"></i>
|
|
</a>
|
|
<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-esc="tx_sudo.state_message"/>
|
|
</t>
|
|
</div>
|
|
<t t-if="tx_sudo.provider_code == 'custom'">
|
|
<div t-if="order.reference" class="card-body">
|
|
<b>Communication: </b><span t-esc='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="card-body" 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&utm_medium=website">Open Source eCommerce</a>
|
|
</t>
|
|
<t t-set="_utm_medium" t-valuef="website"/>
|
|
</t>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="sale_order_portal_content_inherit_website_sale" name="Orders Followup Products Links" inherit_id="sale.sale_order_portal_content">
|
|
<xpath expr="//section[@id='details']//div[hasclass('table-responsive')]" position="attributes">
|
|
<attribute name="class" remove="table-responsive" separator=" "/>
|
|
</xpath>
|
|
<xpath expr="//section[@id='details']//td[@id='product_name']/*" position="replace">
|
|
<a t-if="line.product_id.website_published" t-att-href="line.product_id.website_url" class="d-block text-wrap" style="max-width: 35vw">
|
|
<span t-field="line.name" />
|
|
</a>
|
|
<t t-if="not line.product_id.website_published">
|
|
<span t-field="line.name" class="d-block text-wrap" style="max-width: 35vw"/>
|
|
</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_variant.sudo().variant_ribbon_id or product.sudo().website_ribbon_id"/>
|
|
<t t-set="bg_color" t-value="ribbon['bg_color'] or ''"/>
|
|
<t t-set="text_color" t-value="ribbon['text_color']"/>
|
|
<t t-set="bg_class" t-value="ribbon._get_position_class()"/>
|
|
<t t-call="website_sale.shop_product_#{website.product_page_image_layout}"/>
|
|
</template>
|
|
|
|
<template id="website_sale.shop_product_image">
|
|
<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 w-100"
|
|
>
|
|
<span t-attf-class="o_ribbon #{ribbon._get_position_class()} z-1"
|
|
t-attf-style="#{text_color and ('color: %s; ' % text_color)}#{bg_color and 'background-color:' + bg_color}"
|
|
t-out="ribbon['name'] or ''"
|
|
/>
|
|
<div
|
|
t-field="product_image.image_1920"
|
|
name="o_img_with_max_suggested_width"
|
|
class="d-flex align-items-start justify-content-center w-100 oe_unmovable"
|
|
t-options="{
|
|
'widget': 'image',
|
|
'preview_image': 'image_1024',
|
|
'class': 'oe_unmovable product_detail_img 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 + ' oe_unmovable'"
|
|
t-options="{
|
|
'widget': 'image',
|
|
'preview_image': 'image_1024',
|
|
'class': 'oe_unmovable product_detail_img w-100 mh-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 position-sticky mb-3 overflow-hidden"
|
|
data-bs-ride="true"
|
|
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_ribbon #{ribbon._get_position_class()} z-1"
|
|
t-attf-style="#{text_color and ('color: %s; ' % text_color)}#{bg_color and 'background-color:' + bg_color}"
|
|
t-out="ribbon['name'] or ''"
|
|
/>
|
|
<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 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="products_carousel_4x3"
|
|
name="carousel_img_ratio_4x3"
|
|
inherit_id="website_sale.shop_product_carousel"
|
|
active="False"
|
|
>
|
|
<xpath expr="//div[hasclass('o_carousel_product_outer')]" position="attributes">
|
|
<attribute name="class" add="o_wsale_carousel_ratio_4x3" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template
|
|
id="products_carousel_4x5"
|
|
name="carousel_img_ratio_4x5"
|
|
inherit_id="website_sale.shop_product_carousel"
|
|
active="False"
|
|
>
|
|
<xpath expr="//div[hasclass('o_carousel_product_outer')]" position="attributes">
|
|
<attribute name="class" add="o_wsale_carousel_ratio_4x5" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template
|
|
id="products_carousel_16x9"
|
|
name="carousel_img_ratio_16x9"
|
|
inherit_id="website_sale.shop_product_carousel"
|
|
active="False"
|
|
>
|
|
<xpath expr="//div[hasclass('o_carousel_product_outer')]" position="attributes">
|
|
<attribute name="class" add="o_wsale_carousel_ratio_16x9" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template
|
|
id="products_carousel_21x9"
|
|
name="carousel_img_ratio_21x9"
|
|
inherit_id="website_sale.shop_product_carousel"
|
|
active="False"
|
|
>
|
|
<xpath expr="//div[hasclass('o_carousel_product_outer')]" position="attributes">
|
|
<attribute name="class" add="o_wsale_carousel_ratio_21x9" separator=" "/>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="carousel_product_indicators_bottom" inherit_id="website_sale.shop_product_carousel" name="Carousel Product Indicators Bottom">
|
|
<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" active="False">
|
|
<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-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-att-class="'carousel-indicators '
|
|
+ (indicators_list_class or '')
|
|
+ ('justify-content-center ' if website.product_page_image_width == '100_pc' else '')
|
|
+ ' position-static pt-2 pt-lg-0 mx-auto my-0'"
|
|
>
|
|
<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': 'o_image_64_cover', '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">
|
|
<div
|
|
id="o-grid-product"
|
|
class="mb-3"
|
|
data-name="Product Grid"
|
|
t-att-data-image_spacing="website.product_page_image_spacing"
|
|
t-att-data-grid_columns="website.product_page_grid_columns"
|
|
>
|
|
<div class="container position-relative overflow-hidden">
|
|
<span t-attf-class="o_ribbon #{ribbon._get_position_class()}"
|
|
t-attf-style="#{text_color and ('color: %s; ' % text_color)}#{bg_color and 'background-color:' + bg_color}"
|
|
t-out="ribbon['name'] or ''"
|
|
/>
|
|
<!-- One row for every two images -->
|
|
<t t-set="image_classes" t-value="'w-100'"/>
|
|
<div class="row">
|
|
<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 < len(product_images)"
|
|
class="col o_wsale_product_page_grid_column d-flex flex-column px-0"
|
|
>
|
|
<t t-foreach="len(product_images)" t-as="image_idx">
|
|
<t
|
|
t-set="product_image"
|
|
t-value="image_idx < len(product_images) and product_images[image_idx] or False"
|
|
/>
|
|
<t
|
|
t-set="image_classes"
|
|
t-value="website._get_product_page_grid_image_spacing_classes()"
|
|
/>
|
|
<t
|
|
t-if="product_image and col_idx == col_feed_counter"
|
|
t-call="website_sale.shop_product_image"
|
|
/>
|
|
<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[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[field.name]'>
|
|
<b><t t-esc='field.label'/>: </b>
|
|
<t t-if='field.field_id.ttype != "binary"'>
|
|
<span t-esc='product[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>
|
|
|
|
<template id="add_to_cart_redirect" inherit_id="website.layout" name="Cart Redirection" priority="1">
|
|
<xpath expr="//html" position="before">
|
|
<t t-set="html_data" t-value="dict(html_data, **{'data-add2cart-redirect': '1' if website.add_to_cart_action == 'stay' else '0' if website.add_to_cart_action == 'go_to_cart' else '2'})"/>
|
|
</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/category/#{slug(category)}';return false;"/>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="sale_order_re_order_btn" inherit_id="sale.sale_order_portal_template" name="Sale Order Order Again">
|
|
<xpath expr="//t[@t-set='entries']/div/div/div[hasclass('o_download_pdf')]" position="before">
|
|
<t t-if="request.website.enabled_portal_reorder_button and sale_order.with_user(request.env.user).sudo()._is_reorder_allowed()">
|
|
<button class="btn btn-primary o_wsale_reorder_button" t-att-data-sale-order-id="sale_order.id">
|
|
<i class="fa fa-rotate-right me-1"/>
|
|
Order Again
|
|
</button>
|
|
</t>
|
|
</xpath>
|
|
</template>
|
|
</odoo>
|