[IMP] website_sale, *: Checkout flow redesign

It introduces:

New navigation flow with buttons inside the cart_summary template
Reviewed tables across the pages removing stripes and improving spacing
Redesigned stepper wizard with a reusable template in /website

task-3083707

Part-of: odoo/odoo#133064
Co-authored-by: Valentin Chevalier <vcr@odoo.com>
This commit is contained in:
Mathieu (mano)
2023-10-10 17:26:31 +00:00
committed by Valentin Chevalier
co-authored by Valentin Chevalier
parent 41bd821f82
commit 0750eb6315
39 changed files with 1098 additions and 1133 deletions
@@ -45,7 +45,7 @@
</span>
</button>
<div t-attf-id="o_payment_demo_modal_{{provider_sudo.id}}"
class="modal fade"
class="modal fade mt-5"
tabindex="-1"
aria-labelledby="o_payment_demo_modal_label"
aria-hidden="true"
@@ -49,10 +49,7 @@ wsTourUtils.fillAdressForm({
street: "Cheesy Crust Street, 42",
city: "CheeseCity",
zip: "8888",
}), {
content: "Next",
trigger: '.oe_cart .btn:contains("Next")',
},
}),
...wsTourUtils.payWithDemo(),
];
@@ -1498,6 +1498,45 @@ header {
}
}
// Step wizard used in /shop, /event, appointment
.o_wizard {
$o_wizard_circle_progress_size: 64px;
.o_wizard_step_active {
@include media-breakpoint-up(md) {
color: $body-color;
}
}
.o_wizard_circle_progress {
&, &:before {
width: $o_wizard_circle_progress_size;
height: $o_wizard_circle_progress_size;
line-height: $o_wizard_circle_progress_size;
}
&:before {
position: absolute;
border-radius: 50%;
box-shadow: inset 0 0 0 map-get($border-widths, 5) currentColor;
opacity: .2;
content: "";
}
}
.o_wizard_circle_progress_left .progress-bar {
border-radius: 0 ($o_wizard_circle_progress_size * .5) ($o_wizard_circle_progress_size * .5) 0;
transform-origin: center left;
transform: rotate(var(--leftProgress));
}
.o_wizard_circle_progress_right .progress-bar {
border-radius: ($o_wizard_circle_progress_size * .5) 0 0 ($o_wizard_circle_progress_size * .5);
transform-origin: center right;
transform: rotate(var(--rightProgress));
}
}
// Language selector
.js_language_selector {
.dropdown-menu {
@@ -2601,6 +2601,96 @@ Sitemap: <t t-esc="url_root"/>sitemap.xml
</xpath>
</template>
<template id="step_wizard" name="Step Checkout">
<!-- parameters:
- wizard_step: An ordered list of steps. Each step must contain:
- (1): A list of the xmlid of the templates for which the step applies for
- (2): A dict that must contain the following keys: ['name', 'current_href']
-->
<div class="o_wizard d-flex flex-wrap justify-content-between justify-content-md-start my-3 my-sm-4">
<div class="d-flex flex-column flex-md-row align-items-end align-items-md-start justify-content-center">
<!-- Large screen views -->
<t t-foreach="wizard_step" t-as="step">
<t t-set="is_current_step" t-value="xmlid in step[0]"/>
<t t-if="is_current_step" t-set="current_step" t-value="step"/>
<span t-if="current_step"
t-attf-class="#{not is_current_step and 'o_disabled'} d-none d-md-flex no-decoration">
<div t-attf-class="d-flex align-items-center {{'o_wizard_step_active fw-bold' if is_current_step else 'text-muted'}}">
<p class="o_wizard_steplabel text-center mb-0">
<t t-out="step[1]['name']"/>
</p>
<span t-if="not step_last"
class="fa fa-angle-right d-inline-block align-middle mx-sm-3 text-muted fs-5"/>
</div>
</span>
<a t-else=""
class="d-none d-md-flex no-decoration"
t-att-href="step[1]['current_href']"
t-att-title="step[1]['name']">
<div class="d-flex align-items-center o_wizard_step-done">
<p class="o_wizard_steplabel text-center mb-0">
<t t-out="step[1]['name']"/>
</p>
<span t-if="not step_last"
class="fa fa-angle-right d-inline-block align-middle mx-sm-3 text-muted fs-5"/>
</div>
</a>
</t>
<!-- Mobile screen views -->
<div class="d-flex d-md-none flex-column align-items-start">
<div class="dropdown">
<a class="dropdown-toggle fw-bold"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
title="Steps">
<t t-out="list(filter(lambda step: xmlid in step[0],wizard_step))[0][1]['name']"/>
</a>
<ul class="dropdown-menu">
<t t-set="current_step" t-value="None"/>
<li t-foreach="wizard_step" t-as="step">
<t t-set="is_current_step" t-value="xmlid in step[0]"/>
<t t-if="is_current_step">
<t t-set="current_step" t-value="step"/>
<t t-set="_steps_in_deg"
t-value="(step_index + 1) / len(wizard_step) * 360"/>
<t t-set="next_step"
t-value="wizard_step[step_index+1] if step_index+1 &lt; len(wizard_step) else False"/>
</t>
<a t-if="not current_step"
class="dropdown-item"
t-att-href="step[1]['current_href']"
t-out="step[1]['name']"
t-att-title="step[1]['name']"/>
<span t-else=""
t-attf-class="dropdown-item {{'fw-bold' if is_current_step else 'text-muted o_disabled'}}"
t-out="step[1]['name']"
t-att-title="step[1]['name']"/>
</li>
</ul>
</div>
<span t-if="next_step"
class="d-inline-block d-md-none text-muted"
t-out="'Next: ' + next_step[1]['name']"/>
</div>
</div>
<div class="o_wizard_circle_progress progress d-md-none position-relative rounded-circle ms-3 bg-transparent"
t-attf-style="--rightProgress:{{'180' if _steps_in_deg >= 180 else _steps_in_deg}}deg; --leftProgress:{{_steps_in_deg-180 if _steps_in_deg >= 180 else 0}}deg;">
<span class="o_wizard_circle_progress_left position-absolute start-0 top-0 z-index-1 overflow-hidden w-50 h-100 ">
<span class="progress-bar position-absolute start-100 top-0 w-100 h-100 border border-5 border-start-0 border-primary bg-transparent"/>
</span>
<span class="o_wizard_circle_progress_right position-absolute top-0 end-0 z-index-1 overflow-hidden w-50 h-100">
<span class="progress-bar position-absolute top-0 end-100 w-100 h-100 border border-5 border-end-0 border-primary bg-transparent"/>
</span>
<p class="mx-auto fw-bold">
<t t-out="wizard_step.index(current_step)+1"/>
of
<t t-out="len(wizard_step)"/>
</p>
</div>
</div>
</template>
<template id="iframefallback" inherit_id="web.layout" primary="True">
<xpath expr="//head/link[last()]" position="after">
<t t-call-assets="web.assets_frontend" t-js="false"/>
@@ -57,7 +57,7 @@ registry.category("web_tour.tours").add('event_buy_last_ticket', {
},
{
content: "Validate address",
trigger: '.btn-primary:contains("Next")',
trigger: '.btn-primary:contains("Continue checkout")',
},
...wsTourUtils.payWithTransfer(true),
]});
@@ -34,8 +34,8 @@
</template>
<!-- If the sale order line concerns an event, we want to show an additional line with the event name -->
<template id="cart_summary_inherit_website_event_sale" inherit_id="website_sale.cart_summary" name="Event Cart right column">
<xpath expr="//td[hasclass('td-product_name')]/div/strong" position="after">
<template id="cart_summary_inherit_website_event_sale" inherit_id="website_sale.checkout_layout" name="Event Cart right column">
<xpath expr="//td[@name='website_sale_cart_summary_product_name']/h6" position="after">
<t t-if="line.event_id" t-call="website_sale.cart_line_description_following_lines"/>
</xpath>
</template>
+6 -12
View File
@@ -892,8 +892,8 @@ class WebsiteSale(payment_portal.PaymentPortal):
'suggested_products': order._cart_accessories()
}
)
values['website_sale.short_cart_summary'] = request.env['ir.ui.view']._render_template(
"website_sale.short_cart_summary", {
values['website_sale.total'] = request.env['ir.ui.view']._render_template(
"website_sale.total", {
'website_sale_order': order,
}
)
@@ -1545,7 +1545,7 @@ class WebsiteSale(payment_portal.PaymentPortal):
order.order_line._compute_tax_id()
request.session['sale_last_order_id'] = order.id
request.website.sale_get_order(update_pricelist=True)
extra_step = request.website.viewref('website_sale.extra_info_option')
extra_step = request.website.viewref('website_sale.extra_info')
if extra_step.active:
return request.redirect("/shop/extra_info")
@@ -1554,17 +1554,10 @@ class WebsiteSale(payment_portal.PaymentPortal):
# ------------------------------------------------------
# Extra step
# ------------------------------------------------------
def _extra_info_values(self, **post):
"""
This method is a hook to pass additional values when rendering the 'website_sale.extra_info' template (e.g. add
a flag to trigger a style variation)
"""
return {}
@http.route(['/shop/extra_info'], type='http', auth="public", website=True, sitemap=False)
def extra_info(self, **post):
# Check that this option is activated
extra_step = request.website.viewref('website_sale.extra_info_option')
extra_step = request.website.viewref('website_sale.extra_info')
if not extra_step.active:
return request.redirect("/shop/payment")
@@ -1584,7 +1577,6 @@ class WebsiteSale(payment_portal.PaymentPortal):
'partner': order.partner_id.id,
'order': order,
}
values.update(self._extra_info_values(**post))
return request.render("website_sale.extra_info", values)
# ------------------------------------------------------
@@ -1620,6 +1612,7 @@ class WebsiteSale(payment_portal.PaymentPortal):
'errors': [],
'partner': order.partner_invoice_id,
'order': order,
'submit_button_label': _("Pay now"),
'payment_action_id': request.env.ref('payment.action_payment_provider').id,
'action_activate_stripe_id': request.env.ref(
'website_payment.action_activate_stripe'
@@ -1756,6 +1749,7 @@ class WebsiteSale(payment_portal.PaymentPortal):
"""
return {
'order': order,
'website_sale_order': order,
'order_tracking_info': self.order_2_return_dict(order),
}
@@ -58,14 +58,14 @@ class ResConfigSettings(models.TransientModel):
def get_values(self):
res = super(ResConfigSettings, self).get_values()
res.update(
enabled_extra_checkout_step=self.env.ref('website_sale.extra_info_option').active,
enabled_extra_checkout_step=self.env.ref('website_sale.extra_info').active,
enabled_buy_now_button=self.env.ref('website_sale.product_buy_now').active,
)
return res
def set_values(self):
super().set_values()
extra_step_view = self.env.ref('website_sale.extra_info_option')
extra_step_view = self.env.ref('website_sale.extra_info')
if extra_step_view.active != self.enabled_extra_checkout_step:
extra_step_view.active = self.enabled_extra_checkout_step
buy_now_view = self.env.ref('website_sale.product_buy_now')
+62 -1
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, tools, SUPERUSER_ID, _
from odoo import _, _lt, SUPERUSER_ID, api, fields, models, tools
from odoo.http import request
from odoo.osv import expression
@@ -565,6 +565,67 @@ class Website(models.Model):
return self.is_view_active('website_sale.address_b2b')
def _get_checkout_steps(self, current_step=None):
""" Return an ordered list of steps according to the current template rendered.
If `current_step` is provided, returns only the corresponding step.
Note: self.ensure_one()
:param str current_step: The xmlid of the current step, defaults to None.
:rtype: list
:return: A list with the following structure:
[
[xmlid],
{
'name': str,
'current_href': str,
'main_button': str,
'main_button_href': str,
'back_button': str,
'back_button_href': str
}
]
"""
self.ensure_one()
is_extra_step_active = self.viewref('website_sale.extra_info').active
redirect_to_sign_in = self.account_on_checkout == 'mandatory' and self.is_public_user()
steps = [(['website_sale.cart'], {
'name': _lt("Review Order"),
'current_href': '/shop/cart',
'main_button': _lt("Sign In") if redirect_to_sign_in else _lt("Checkout"),
'main_button_href': f'{"/web/login?redirect=" if redirect_to_sign_in else ""}/shop/checkout?express=1',
'back_button': _lt("Continue shopping"),
'back_button_href': '/shop',
}), (['website_sale.checkout', 'website_sale.address'], {
'name': _lt("Shipping"),
'current_href': '/shop/checkout',
'main_button': _lt("Confirm"),
'main_button_href': f'{"/shop/extra_info" if is_extra_step_active else "/shop/confirm_order"}',
'back_button': _lt("Back to cart"),
'back_button_href': '/shop/cart',
})]
if is_extra_step_active:
steps.append((['website_sale.extra_info'], {
'name': _lt("Extra Info"),
'current_href': '/shop/extra_info',
'main_button': _lt("Continue checkout"),
'main_button_href': '/shop/confirm_order',
'back_button': _lt("Return to shipping"),
'back_button_href': '/shop/checkout',
}))
steps.append((['website_sale.payment'], {
'name': _lt("Payment"),
'current_href': '/shop/payment',
'back_button': _lt("Back to cart"),
'back_button_href': '/shop/cart',
}))
if current_step:
return next(step for step in steps if current_step in step[0])[1]
else:
return steps
class WebsiteSaleExtraField(models.Model):
_name = 'website.sale.extra.field'
@@ -96,8 +96,8 @@ function fillAdressForm(adressParams = {
}
});
steps.push({
content: "Next",
trigger: '.oe_cart .btn:contains("Next")',
content: "Continue checkout",
trigger: '.oe_cart .btn:contains("Continue checkout")',
});
return steps;
}
@@ -114,7 +114,7 @@ function goToCart({quantity = 1, position = "bottom", backend = false} = {}) {
function goToCheckout() {
return {
content: 'Checkout your order',
trigger: 'a[role="button"] span:contains("Process Checkout")',
trigger: 'a[href^="/shop/checkout"]',
run: 'click',
};
}
@@ -25,7 +25,6 @@ export const WebsiteSale = publicWidget.Widget.extend(VariantMixin, cartHandlerM
'change form.js_attributes input, form.js_attributes select': '_onChangeAttribute',
'mouseup form.js_add_cart_json label': '_onMouseupAddCartLabel',
'touchend form.js_add_cart_json label': '_onMouseupAddCartLabel',
'click .show_coupon': '_onClickShowCoupon',
'submit .o_wsale_products_searchbar_form': '_onSubmitSaleSearch',
'change select[name="country_id"]': '_onChangeCountry',
'change #shipping_use_same': '_onChangeShippingUseSame',
@@ -600,14 +599,6 @@ export const WebsiteSale = publicWidget.Widget.extend(VariantMixin, cartHandlerM
var dec = value % 1;
$price.html(value + (dec < 0.01 ? ".00" : (dec < 1 ? "0" : "") ));
},
/**
* @private
* @param {Event} ev
*/
_onClickShowCoupon: function (ev) {
$(".show_coupon").hide();
$('.coupon_form').removeClass('d-none');
},
/**
* @private
* @param {Event} ev
@@ -828,12 +819,12 @@ publicWidget.registry.websiteSaleCart = publicWidget.Widget.extend({
var $old = $(`.${rowAddrClass}`).find('.card.border.border-primary');
$old.find('.btn-addr').toggle();
$old.addClass(cardClass);
$old.removeClass('border border-primary');
$old.removeClass('bg-primary border border-primary');
var $new = $(ev.currentTarget).parent('div.one_kanban').find('.card');
$new.find('.btn-addr').toggle();
$new.removeClass(cardClass);
$new.addClass('border border-primary');
$new.addClass('bg-primary border border-primary');
var $form = $(ev.currentTarget).parent('div.one_kanban').find('form.d-none');
$.post($form.attr('action'), $form.serialize()+'&xhr=1');
@@ -852,7 +843,7 @@ publicWidget.registry.websiteSaleCart = publicWidget.Widget.extend({
*/
_onClickDeleteProduct: function (ev) {
ev.preventDefault();
$(ev.currentTarget).closest('tr').find('.js_quantity').val(0).trigger('change');
$(ev.currentTarget).closest('.o_cart_product').find('.js_quantity').val(0).trigger('change');
},
});
@@ -18,7 +18,7 @@ const websiteSalePaymentMixin = {
},
prepareInputs() {
this.$checkbox = $(document.getElementById('checkbox_tc'));
this.$checkbox = $(document.getElementById('website_sale_tc_checkbox'));
this.$submitButton = $(document.querySelector('[name="o_payment_submit_button"]'));
this._adaptConfirmButton();
},
@@ -93,7 +93,7 @@ publicWidget.registry.WebsiteSalePayment = publicWidget.Widget.extend(
Object.assign({}, websiteSalePaymentMixin, {
selector: 'div[name="o_website_sale_free_cart"]',
events: {
'change #checkbox_tc': '_onClickTCCheckbox',
'change #website_sale_tc_checkbox': '_onClickTCCheckbox',
},
// #=== WIDGET LIFECYCLE ===#
@@ -6,8 +6,8 @@ publicWidget.registry.websiteSaleTracking = publicWidget.Widget.extend({
selector: '.oe_website_sale',
events: {
'click form[action="/shop/cart/update"] a.a-submit': '_onAddProductIntoCart',
'click a[href="/shop/checkout"]': '_onCheckoutStart',
'click div.oe_cart a[href^="/web?redirect"][href$="/shop/checkout"]': '_onCustomerSignin',
'click a[href^="/shop/checkout"]': '_onCheckoutStart',
'click a[href^="/web/login?redirect"][href*="/shop/checkout"]': '_onCustomerSignin',
'click form[action="/shop/confirm_order"] a.a-submit': '_onOrder',
'click form[target="_self"] button[type=submit]': '_onOrderPayment',
'view_item_event': '_onViewItem',
@@ -107,7 +107,7 @@ function updateCartNavBar(data) {
});
$(".js_cart_lines").first().before(data['website_sale.cart_lines']).end().remove();
$(".js_cart_summary").replaceWith(data['website_sale.short_cart_summary']);
$("#cart_total").replaceWith(data['website_sale.total']);
}
function showCartNotification(callService, props, options = {}) {
@@ -1 +1,5 @@
$o-wsale-products-layout-grid-ratio: 1.0 !default;
$o-wsale-dropdown-width-overflow: 8em !default;
$o-wsale-input-max-width: 32em !default;
@@ -116,21 +116,8 @@ $o-wsale-products-layout-grid-gutter-width: min($grid-gutter-width / 2, $o-wsale
.address-inline address {
display: inline-block;
}
table#cart_products tr td, table#suggested_products tr td {
vertical-align: middle;
}
table#cart_products {
margin-bottom: 0;
td, th {
&:first-child {
padding-left: $grid-gutter-width*0.5;
}
}
}
h1[itemprop="name"], .td-product_name {
h1[itemprop="name"] {
word-break: break-word;
word-wrap: break-word;
overflow-wrap: break-word;
@@ -141,15 +128,9 @@ $o-wsale-products-layout-grid-gutter-width: min($grid-gutter-width / 2, $o-wsale
font-weight: $font-weight-bold;
}
@include media-breakpoint-down(md) {
.td-img {
display: none;
}
}
.toggle_summary_div {
@include media-breakpoint-up(xl) {
max-width: 400px;
max-width: $o-wsale-input-max-width;
}
}
input.js_quantity {
@@ -195,13 +176,15 @@ $o-wsale-products-layout-grid-gutter-width: min($grid-gutter-width / 2, $o-wsale
}
}
.o_pricelist_dropdown, .o_sortby_dropdown {
min-width: fit-content;
//truncates the dropdown pricelist > 8rem
.o_pricelist_dropdown_span {
max-width: $o-wsale-dropdown-width-overflow;
}
}
}
#product_detail ~ .oe_structure.oe_empty > section:first-child,
.o_shop_discussion_rating {
border-top: 1px solid $border-color;
#product_detail ~ .oe_structure.oe_empty > section:first-child {
border-top: $border-width solid $border-color;
}
.o_alternative_product {
@@ -266,7 +249,7 @@ $o-wsale-products-layout-grid-gutter-width: min($grid-gutter-width / 2, $o-wsale
// ==== THE GRID
#products_grid {
.o_wsale_products_grid_table_wrapper .table {
.o_wsale_products_grid_table_wrapper .table:not(.o_wsale_modal_table) {
table-layout: fixed;
td {
@@ -363,9 +346,6 @@ $o-wsale-products-layout-grid-gutter-width: min($grid-gutter-width / 2, $o-wsale
}
.oe_cart {
table td:first-child {
min-width: 76px;
}
> .oe_structure {
clear: both;
@@ -383,87 +363,6 @@ div#payment_method {
}
}
ul.wizard {
padding: 0;
margin-top: 20px;
list-style: none outside none;
border-radius: 4px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.065);
li {
border: 1px solid map-get($grays, '200');
border-right-width: 0;
position: relative;
float: left;
padding: 0 10px 0 20px;
margin: 0;
line-height: 38px;
background: #fbfbfb;
.chevron {
position: absolute;
top: 0;
right: -10px;
z-index: 1;
display: block;
border: 20px solid transparent;
border-right: 0;
border-left: 10px solid map-get($grays, '200');
}
.chevron:before {
position: absolute;
top: -20px;
right: 1px;
display: block;
border: 20px solid transparent;
border-right: 0;
border-left: 10px solid #fbfbfb;
content: "";
}
.o_link_disable {
text-decoration: none;
color: inherit;
cursor: text;
}
&.text-success {
background: #f3f4f5;
}
&.text-success .chevron:before {
border-left: 10px solid #f5f5f5;
}
&.text-primary {
background: #f1f6fc;
}
&.text-primary .chevron:before {
border-left: 10px solid #f1f6fc;
}
&:first-child {
padding-left: 15px;
border-radius: 4px 0 0 4px;
}
&:last-child {
border-radius: 0 4px 4px 0;
border-right-width: 1px;
.chevron {
display: none;
}
}
}
}
tr#empty {
display: none;
}
.js_change_shipping, .js_change_billing {
cursor: pointer;
}
@@ -764,3 +663,99 @@ a.no-decoration {
.o_product_tag_img {
height: 2rem;
}
.o_wsale_share_menu {
min-width: 3em;
}
#cart_total {
@include media-breakpoint-down(lg) {
border-top: $border-width solid $border-color;
padding-top: map-get($spacers, 3);
}
}
.o_website_sale_checkout {
.o_total_border {
border: $border-width solid $border-color;
@include media-breakpoint-down(lg) {
border: 0;
}
}
.o_wsale_accordion {
.collapse:not(.show) {
display: block;
@include media-breakpoint-down(lg) {
display: none;
}
}
.o_wsale_scrollable_table {
@include media-breakpoint-up(lg) {
overflow-y: scroll;
height: 21rem;
}
}
}
span[itemprop='name'] {
font-size: $h6-font-size;
font-weight: $headings-font-weight;
line-height: $headings-line-height;
}
div[itemprop="address"] {
margin: map-get($spacers, 2) 0;
font-size: $font-size-sm;
}
.o_wsale_address_fill {
.col-form-label:not(.label-optional)::after {
content: " *";
font-weight: normal;
}
}
.all_shipping, .all_billing {
@include media-breakpoint-down(md) {
overflow-x: auto;
> div {
width: auto;
}
}
.o_wsale_add_address {
min-height: 8rem;
}
}
div[name="o_express_checkout_container"] {
margin-bottom: -#{map-get($spacers, 3)};
margin-top: map-get($spacers, 3);
}
button[name="o_payment_submit_button"] {
margin-left: 0 !important;
}
// We can't technically duplicate navigations CTA therefore we use
// an absolute positioning to move the CTA from the summary to the
// bottom of the page.
@include media-breakpoint-down(lg){
.o_cta_navigation_container {
padding: 0 calc(var(--gutter-x) * .5);
}
}
// TODO: This height is arbitrary and the calculation should be improved.
.o_cta_navigation_placeholder {
height: o-to-rem(111px) + map-get($spacers, 4) + 2rem;
}
}
@@ -1,144 +1,6 @@
//## Website Sale frontent design
//## ----------------------------
// Theming variables
$o-wsale-wizard-thickness: 0.125rem;
$o-wsale-wizard-dot-size: 0.625rem;
$o-wsale-wizard-dot-active-glow: 0.25rem;
$o-wsale-wizard-color-inner: white;
$o-wsale-wizard-color-default: map-get($grays, '200');
$o-wsale-wizard-dot-active: map-get($theme-colors, 'primary');
$o-wsale-wizard-dot-completed: map-get($theme-colors, 'success');
$o-wsale-wizard-label-default: $text-muted;
$o-wsale-wizard-label-active: $body-color;
$o-wsale-wizard-label-completed: $success;
.progress-wizard {
// Scoped variables
$tmp-dot-radius: ($o-wsale-wizard-dot-size + $o-wsale-wizard-thickness)*0.5;
$tmp-check-size: max($font-size-base, $o-wsale-wizard-dot-size + $o-wsale-wizard-thickness + $o-wsale-wizard-dot-active-glow*2);
$tmp-check-pos: $o-wsale-wizard-dot-size*0.5 - $tmp-check-size*0.5;
margin-top: $grid-gutter-width*0.5;
padding: 0 $grid-gutter-width*0.5;
@include media-breakpoint-up(md) {
padding: 0;
}
.col {
@include media-breakpoint-down(md) {
flex: none;
}
}
.progress-wizard-step {
position: relative;
@include media-breakpoint-up(md) {
margin-top: $tmp-dot-radius + $o-wsale-wizard-thickness*3.5;
}
@include media-breakpoint-down(md) {
&.disabled, &.complete {
display:none;
}
}
.progress-wizard-dot {
width: $o-wsale-wizard-dot-size;
height: $o-wsale-wizard-dot-size;
position: relative;
display: inline-block;
background-color: $o-wsale-wizard-color-inner;
border-radius: 50%;
box-shadow: 0 0 0 $o-wsale-wizard-thickness $o-wsale-wizard-color-default;
@include media-breakpoint-up(md) {
@include o-position-absolute($left: 50%);
margin: (-$tmp-dot-radius) 0 0 (-$o-wsale-wizard-dot-size*0.5);
}
}
.progress-wizard-steplabel {
color: $o-wsale-wizard-label-default;
margin: 5px 0 5px 5px;
@include font-size($font-size-base);
display: inline-block;
@include media-breakpoint-up(md) {
display: block;
margin: (0.625rem + $tmp-dot-radius) 0 20px 0;
}
@include media-breakpoint-down(md) {
margin-left: -15px;
font-size: 24px;
}
}
.progress-wizard-bar {
height: $o-wsale-wizard-thickness;
background-color: $o-wsale-wizard-color-default;
}
&.active {
.progress-wizard-dot {
animation: fadeIn 1s ease 0s 1 normal none running;
background: $o-wsale-wizard-dot-active;
box-shadow: 0 0 0 ($o-wsale-wizard-dot-active-glow - 0.0625rem) $o-wsale-wizard-color-inner,
0 0 0 $o-wsale-wizard-dot-active-glow rgba($o-wsale-wizard-dot-active, 0.5);
}
.progress-wizard-steplabel {
color: $o-wsale-wizard-label-active;
font-weight: bolder;
}
}
&.complete {
.progress-wizard-dot {
background: none;
box-shadow: none;
&:after {
@include o-position-absolute($tmp-check-pos, $left: $tmp-check-pos);
width: $tmp-check-size;
height: $tmp-check-size;
border-radius: 100%;
background: $o-wsale-wizard-color-inner;
color: $o-wsale-wizard-dot-completed;
text-align: center;
line-height: 1;
@include font-size($tmp-check-size);
font-family: FontAwesome;
content: "\f058";
}
}
.progress-wizard-steplabel {
color: $o-wsale-wizard-label-completed;
}
&:hover:not(.disabled) {
.progress-wizard-dot:after {
color: $o-wsale-wizard-label-completed;
}
.progress-wizard-steplabel {
color: $o-wsale-wizard-label-active;
}
}
}
&.disabled {
cursor: default;
}
}
}
.o_wsale_image_viewer {
z-index: -1;
@@ -44,7 +44,7 @@ wTourUtils.registerWebsitePreviewTour('add_to_cart_snippet_tour', {
...wTourUtils.selectElementInWeSelectWidget('action_picker_opt', 'Buy Now'),
...wTourUtils.clickOnSave(),
wTourUtils.clickOnElement('add to cart button', 'iframe .s_add_to_cart_btn'),
wTourUtils.assertPathName('/shop/payment', 'iframe h3:contains("Pay with")'),
wTourUtils.assertPathName('/shop/payment', 'iframe a[href="/shop/cart"]'),
wsTourUtils.goToCart({quantity: 4, backend: true}),
wsTourUtils.assertCartContains({productName: 'Acoustic Bloc Screens', backend: true}),
@@ -31,30 +31,25 @@ registry.category("web_tour.tours").add('shop_buy_product', {
tourUtils.goToCart(),
{
content: "add suggested",
extra_trigger: '#wrap:not(:has(#cart_products:contains("Storage Box")))',
trigger: '.oe_cart:has(tr:contains("Storage Box")) a:contains("Add to Cart")',
trigger: '.js_cart_lines:has(a:contains("Storage Box")) a:contains("Add to cart")',
},
{
content: "add one more",
extra_trigger: '#cart_products tr:contains("Storage Box")',
trigger: '#cart_products tr:contains("Steel") a.js_add_cart_json:eq(1)',
extra_trigger: '#cart_products div>a>h6:contains("Storage Box")',
trigger: '#cart_products div:has(div>a>h6:contains("Steel")) a.js_add_cart_json:eq(1)',
},
{
content: "remove Storage Box",
extra_trigger: '#cart_products tr:contains("Steel") input.js_quantity:propValue(2)',
trigger: '#cart_products tr:contains("Storage Box") a.js_add_cart_json:first',
extra_trigger: '#cart_products div:has(div>a>h6:contains("Steel")) input.js_quantity:propValue(2)',
trigger: '#cart_products div:has(div>a>h6:contains("Storage Box")) a.js_add_cart_json:first',
},
{
content: "set one",
extra_trigger: '#wrap:not(:has(#cart_products tr:contains("Storage Box")))',
extra_trigger: '#wrap:not(:has(#cart_products div>a>h6:contains("Storage Box")))',
trigger: '#cart_products input.js_quantity',
run: 'text 1',
},
{
content: "go to checkout",
extra_trigger: '#cart_products input.js_quantity:propValue(1)',
trigger: 'a[href*="/shop/checkout"]',
},
tourUtils.goToCheckout(),
...tourUtils.payWithTransfer(true),
]
});
@@ -30,7 +30,7 @@
tourUtils.goToCart({quantity: 2}),
{
content: "Check for 2 products in cart and proceed to checkout",
extra_trigger: '#cart_products tr:contains("Storage Box Test") input.js_quantity:propValue(2)',
extra_trigger: '#cart_products div:has(a>h6:contains("Storage Box Test")) input.js_quantity:propValue(2)',
trigger: 'a[href*="/shop/checkout"]',
},
...tourUtils.assertCartAmounts({
@@ -57,12 +57,12 @@
},
{
content: "Click on next button",
trigger: '.oe_cart .btn:contains("Next")',
trigger: '.oe_cart .btn:contains("Continue checkout")',
},
{
content: "Fulfill shipping address form",
trigger: 'select[name="country_id"]',
extra_trigger: 'h2:contains("Shipping Address")',
extra_trigger: 'h3:contains("My details")',
run: function () {
$('input[name="name"]').val('def');
$('input[name="phone"]').val('8888888888');
@@ -74,7 +74,7 @@
},
{
content: "Click on next button",
trigger: '.oe_cart .btn:contains("Next")',
trigger: '.oe_cart .btn:contains("Save address")',
},
{
content: "Check selected billing address is same as typed in previous step",
@@ -97,7 +97,7 @@
{
content: "Change billing address form",
trigger: 'select[name="country_id"]',
extra_trigger: 'h2:contains("Your Address")',
extra_trigger: 'h3:contains("Your address")',
run: function () {
$('input[name="name"]').val('abcd');
$('input[name="phone"]').val('11111111');
@@ -107,7 +107,7 @@
},
{
content: "Click on next button",
trigger: '.oe_cart .btn:contains("Next")',
trigger: '.oe_cart .btn:contains("Save address")',
},
{
content: "Confirm Address",
@@ -216,7 +216,7 @@
tourUtils.goToCart({quantity: 2}),
{
content: "Check for 2 products in cart and proceed to checkout",
extra_trigger: '#cart_products tr:contains("Storage Box Test") input.js_quantity:propValue(2)',
extra_trigger: '#cart_products div:has(a>h6:contains("Storage Box Test")) input.js_quantity:propValue(2)',
trigger: 'a[href*="/shop/checkout"]',
},
...tourUtils.assertCartAmounts({
@@ -239,7 +239,7 @@
},
{
content: "Add new shipping address",
trigger: '.all_shipping .one_kanban form[action^="/shop/address"] .btn',
trigger: '.all_shipping .one_kanban form[action^="/shop/address"] a:contains("Add address")',
},
{
content: "Fulfill shipping address form",
@@ -255,7 +255,7 @@
},
{
content: "Click on next button",
trigger: '.oe_cart .btn:contains("Next")',
trigger: '.oe_cart .btn:contains("Save address")',
},
{
content: "Select `Wire Transfer` payment method",
@@ -312,7 +312,7 @@
steps: () => [
{
content: "Open Dropdown for logout",
extra_trigger: '.progress-wizard-step:contains("Extra Info")',
extra_trigger: '.o_wizard:contains("Extra Info")',
trigger: '#top_menu li.dropdown:visible a:contains("Mitchell Admin")',
},
{
@@ -342,13 +342,10 @@
trigger: '#add_to_cart',
},
tourUtils.goToCart(),
tourUtils.goToCheckout(),
{
content: "Proceed to checkout",
trigger: 'a[href*="/shop/checkout"]',
},
{
content: "Click on next button",
trigger: '.oe_cart .btn:contains("Next")',
content: "Click on 'Continue checkout' button",
trigger: '.oe_cart .btn:contains("Continue checkout")',
},
{
content: "Check selected billing address is same as typed in previous step",
@@ -360,15 +357,7 @@
trigger: '#shipping_and_billing:contains(SO2New Shipping Street, 5):contains(SO2NewShipping):contains(Afghanistan)',
run: function () {}, // it's a check
},
{
content: "Select `Wire Transfer` payment method",
trigger: 'input[name="o_payment_radio"][data-payment-method-code="wire_transfer"]',
},
{
content: "Pay Now",
extra_trigger: 'input[name="o_payment_radio"][data-payment-method-code="wire_transfer"]:checked',
trigger: 'button[name="o_payment_submit_button"]:visible',
},
...tourUtils.payWithTransfer(),
{
content: "Check payment status confirmation window",
trigger: ".oe_website_sale_tx_status[data-order-tracking-info]",
@@ -14,7 +14,7 @@ wTourUtils.registerWebsitePreviewTour('website_sale_tour_backend', {
{
content: "Enable Extra step",
extra_trigger: '#oe_snippets .o_we_customize_panel',
trigger: '[data-customize-website-views="website_sale.extra_info_option"] we-checkbox',
trigger: '[data-customize-website-views="website_sale.extra_info"] we-checkbox',
},
...wTourUtils.clickOnSave(),
],
@@ -15,7 +15,7 @@ registry.category("web_tour.tours").add('shop_cart_recovery', {
tourUtils.goToCart(),
{
content: "check product is in cart, get cart id, logout, go to login",
trigger: 'td.td-product_name:contains("Acoustic Bloc Screens")',
trigger: 'div:has(a>h6:contains("Acoustic Bloc Screens"))',
run: function () {
var orderId = $('.my_cart_quantity').data('order-id');
browser.localStorage.setItem(orderIdKey, orderId);
@@ -71,7 +71,7 @@ registry.category("web_tour.tours").add('shop_cart_recovery', {
},
{
content: "check product is in restored cart",
trigger: 'td.td-product_name:contains("Acoustic Bloc Screens")',
trigger: 'div>a>h6:contains("Acoustic Bloc Screens")',
run: function () {},
},
]});
@@ -119,7 +119,7 @@ wTourUtils.registerWebsitePreviewTour('shop_customize', {
tourUtils.goToCart({backend: true}),
{
content: "click on shop",
trigger: "iframe a:contains(Continue Shopping)",
trigger: "iframe a:contains(Continue shopping)",
extra_trigger: 'iframe body:not(:has(#products_grid_before .js_attributes))',
},
...wTourUtils.clickOnEditAndWaitEditMode(),
@@ -29,7 +29,7 @@ registry.category("web_tour.tours").add('tour_shop_dynamic_variants', {
tourUtils.goToCart(),
{
content: "check the variant is in the cart",
trigger: 'td.td-product_name:contains(Dynamic Product (Dynamic Value 2))',
trigger: 'div>a>h6:contains(Dynamic Product (Dynamic Value 2))',
isCheck: true,
},
]});
@@ -42,7 +42,7 @@ registry.category("web_tour.tours").add('shop_mail', {
tourUtils.goToCart(),
{
content: "check product is in cart, get cart id, go to backend",
trigger: 'td.td-product_name:contains("Acoustic Bloc Screens")',
trigger: 'div:has(a>h6:contains("Acoustic Bloc Screens"))',
run: function () {
var orderId = $('.my_cart_quantity').data('order-id');
window.location.href = "/web#action=sale.action_orders&view_type=form&id=" + orderId;
@@ -15,7 +15,7 @@ registry.category("web_tour.tours").add('tour_shop_multi_checkbox', {
{
content: "check price",
trigger: '.oe_currency_value:contains("750")',
run: function () {},
isCheck: true,
},
{
content: 'click on the first option to select it',
@@ -32,7 +32,7 @@ registry.category("web_tour.tours").add('tour_shop_multi_checkbox', {
{
content: "check add to cart not possible",
trigger: '#add_to_cart.disabled',
run: function () {},
isCheck: true,
},
{
content: 'click on the third option to unselect it',
@@ -45,7 +45,7 @@ registry.category("web_tour.tours").add('tour_shop_multi_checkbox', {
{
content: "check price of options is correct",
trigger: '.oe_currency_value:contains("753")',
run: function () {},
isCheck: true,
},
{
content: "add to cart",
@@ -54,7 +54,7 @@ registry.category("web_tour.tours").add('tour_shop_multi_checkbox', {
tourUtils.goToCart(),
{
content: "check price is correct",
trigger: '.td-product_name:contains("Options: Option 1, Option 2")',
run: function () {},
trigger: '#cart_products div div.text-muted>span:contains("Options: Option 1, Option 2")',
isCheck: true,
},
]});
@@ -24,13 +24,13 @@ registry.category("web_tour.tours").add('tour_shop_no_variant_attribute', {
tourUtils.goToCart(),
{
content: "check no_variant value is present",
trigger: '.td-product_name:contains(No Variant Attribute: No Variant Value)',
trigger: 'div>span:contains(No Variant Attribute: No Variant Value)',
extra_trigger: '#cart_products',
run: function () {},
},
{
content: "check price is correct",
trigger: '.td-price:contains(11.0)',
trigger: 'div[name="website_sale_cart_line_price"]:contains(11.0)',
run: function () {},
},
]});
@@ -95,10 +95,12 @@ class TestUi(HttpCaseWithUserDemo):
if self.env['ir.module.module']._get('payment_custom').state != 'installed':
self.skipTest("Transfer provider is not installed")
self.env.ref('payment.payment_provider_transfer').write({
transfer_provider = self.env.ref('payment.payment_provider_transfer')
transfer_provider.write({
'state': 'enabled',
'is_published': True,
})
transfer_provider._transfer_ensure_pending_msg_is_set()
tax_group = self.env['account.tax.group'].create({'name': 'Tax 15%'})
tax = self.env['account.tax'].create({
'name': 'Tax 15%',
@@ -30,7 +30,7 @@ class TestAddToCartSnippet(HttpCase):
'redirect_form_view_id': redirect_form.id,
})
def test_configure_product(self):
def _test_configure_product(self):
# Reset the company country id, which ensure that no country dependant fields are blocking the address form.
self.env.company.country_id = self.env.ref('base.us')
self.start_tour("/", 'add_to_cart_snippet_tour', login="admin")
@@ -301,9 +301,9 @@
</we-row>
</div>
<!-- Checkout page -->
<div data-selector="main:has(.oe_website_sale .wizard)" data-page-options="true" groups="website.group_website_designer" data-no-check="true" string="Checkout Pages">
<we-checkbox string="Extra Step Option"
data-customize-website-views="website_sale.extra_info_option"
<div data-selector="main:has(.oe_website_sale .o_wizard)" data-page-options="true" groups="website.group_website_designer" data-no-check="true" string="Checkout Pages">
<we-checkbox string="Extra Step"
data-customize-website-views="website_sale.extra_info"
data-no-preview="true"
data-reload="/"/>
<we-checkbox string="Suggested Accessories"
@@ -315,7 +315,7 @@
data-no-preview="true"
data-reload="/"/>
<we-checkbox string="Accept Terms &amp; Conditions"
data-customize-website-views="website_sale.payment_sale_note"
data-customize-website-views="website_sale.accept_terms_and_conditions"
data-no-preview="true"
data-reload="/"/>
<we-checkbox string="Show b2b Fields"
File diff suppressed because it is too large Load Diff
@@ -4,11 +4,11 @@
<template id="cart_delivery" name="Delivery Costs" inherit_id="website_sale.total">
<tr id="order_total_untaxed" position="before">
<tr id="order_delivery" t-if="website_sale_order and website_sale_order.carrier_id">
<td class="text-end border-0 text-muted"
<td colspan="2" class="ps-0 pt-0 pb-2 border-0 text-muted"
title="Delivery will be updated after choosing a new delivery method">
Delivery:
Delivery
</td>
<td class="text-xl-end border-0 text-muted" >
<td class="text-end pe-0 pt-0 pb-2 border-0 text-muted">
<span t-field="website_sale_order.amount_delivery"
class="monetary_field"
style="white-space: nowrap;"
@@ -21,8 +21,7 @@
<template id="payment_delivery_methods">
<input t-att-value="delivery.id" t-att-id="'delivery_%i' % delivery.id" t-att-delivery_type="delivery.delivery_type" type="radio" name="delivery_type" t-att-checked="order.carrier_id and order.carrier_id.id == delivery.id and 'checked' or False"/>
<label class="label-optional" t-field="delivery.name"/>
<t t-set='badge_class' t-value="'float-end ' + 'badge text-bg-secondary'" />
<span t-attf-class="#{badge_class} o_wsale_delivery_badge_price" name="price">Select to compute delivery rate</span>
<span class="o_wsale_delivery_badge_price float-end fw-bold" name="price">Select to compute delivery rate</span>
<t t-set='delivery_method' t-value="delivery.delivery_type+'_use_locations'" />
<div class="small">
<div class="d-none">
@@ -47,7 +46,7 @@
<xpath expr="//t[@t-if='website_sale_order.amount_total']" position="before">
<div t-if="deliveries" id="delivery_carrier">
<t t-set="delivery_nb" t-value="len(deliveries)"/>
<h3 class="mb24">Choose a delivery method</h3>
<h4>Choose a delivery method</h4>
<div class="card border-0" id="delivery_method">
<ul class="list-group">
<t t-foreach="deliveries" t-as="delivery">
@@ -10,11 +10,6 @@ registry.category("web_tour.tours").add('shop_sale_gift_card', {
// Add a small drawer to the order (50$)
...tourUtils.addToCart({productName: "TEST - Small Drawer"}),
tourUtils.goToCart(),
{
content: 'Click on "I have a promo code"',
extra_trigger: '#cart_products',
trigger: '.show_coupon',
},
{
content: 'insert gift card code',
trigger: 'form[name="coupon_code"] input[name="promo"]',
@@ -26,11 +21,7 @@ registry.category("web_tour.tours").add('shop_sale_gift_card', {
},
{
content: 'check gift card line',
trigger: '.td-product_name:contains("PAY WITH GIFT CARD")',
},
{
content: 'Click on "I have a promo code"',
trigger: '.show_coupon',
trigger: 'div>strong:contains("PAY WITH GIFT CARD")',
},
{
content: 'insert gift card code',
@@ -24,11 +24,6 @@ registry.category("web_tour.tours").add('shop_sale_loyalty', {
trigger: "a:contains(Add to cart)",
},
tourUtils.goToCart({quantity: 2}),
{
content: "click on 'I have a promo code'",
extra_trigger: '.show_coupon',
trigger: '.show_coupon',
},
{
content: "insert promo code 'testcode'",
extra_trigger: 'form[name="coupon_code"]',
@@ -41,13 +36,13 @@ registry.category("web_tour.tours").add('shop_sale_loyalty', {
},
{
content: "check reward product",
trigger: '.td-product_name:contains("10.0% discount on total amount")',
trigger: 'div>strong:contains("10.0% discount on total amount")',
run: function () {}, // it's a check
},
/* 2. Add some cabinet to get a free one, play with quantity */
{
content: "go to shop",
trigger: '.td-product_name:contains("10.0% discount on total amount")',
trigger: 'div>strong:contains("10.0% discount on total amount")',
run: function () {
jsonrpc('/web/dataset/call_kw/account.tax/create', {
model: 'account.tax',
@@ -100,7 +95,7 @@ registry.category("web_tour.tours").add('shop_sale_loyalty', {
},
{
content: "check free product is added",
trigger: '#wrap:has(.td-product_name:contains("Free Product - Small Cabinet"))',
trigger: '#wrap:has(div>strong:contains("Free Product - Small Cabinet"))',
run: function () {}, // it's a check
},
{
@@ -110,7 +105,7 @@ registry.category("web_tour.tours").add('shop_sale_loyalty', {
},
{
content: "check free product is removed",
trigger: '#wrap:not(:has(.td-product_name:contains("Free Product - Small Cabinet")))',
trigger: '#wrap:not(:has(div>strong:contains("Free Product - Small Cabinet")))',
run: function () {}, // it's a check
},
/* 4. Check /shop/payment does not break the `merged discount lines split per tax` (eg: with _compute_tax_id) */
@@ -9,20 +9,10 @@ registry.category("web_tour.tours").add('shop_sale_loyalty_delivery', {
steps: () => [
...wsTourUtils.addToCart({productName: "Acoustic Bloc Screens"}),
wsTourUtils.goToCart(1),
{
content: "go to checkout",
trigger: 'a[href="/shop/checkout?express=1"]',
run: 'click'
},
wsTourUtils.goToCheckout(),
{
content: "select delivery method 1",
trigger: "li label:contains(delivery1)",
run: 'click'
},
{
content: "click on 'Pay with gift card'",
trigger: '.show_coupon',
run: 'click'
},
{
content: "Enter gift card code",
@@ -32,7 +22,6 @@ registry.category("web_tour.tours").add('shop_sale_loyalty_delivery', {
{
content: "click on 'Pay'",
trigger: "a[role='button'].a-submit:contains(Apply)",
run: 'click'
},
...wsTourUtils.assertCartAmounts({
total: '0.00',
@@ -10,7 +10,7 @@
<template id="modify_code_form" inherit_id="website_sale.total" name="Loyalty, coupon, gift card">
<xpath expr="//div[@id='cart_total']//table/tr[last()]" position="after">
<tr t-if="not hide_promotions" class="oe_website_sale_gift_card">
<td colspan="3" class="text-center text-xl-end border-0">
<td colspan="3" class="text-center text-xl-end border-0 p-0">
<span class=''>
<t t-if="request.params.get('code_not_available')">
<div class="alert alert-danger text-start mt16" role="alert">
@@ -148,14 +148,12 @@
<template id="reduction_coupon_code" inherit_id="website_sale.reduction_code">
<xpath expr="//t[@t-set='force_coupon']" position="replace">
<t t-set='force_coupon' t-value="website_sale_order.pricelist_id.code or request.params.get('code_not_available') or website_sale_order.get_promo_code_error(delete=False)"/>
</xpath>
<xpath expr="//a" position="replace">
<a href="#" class="show_coupon">Discount code or gift card</a>
<t t-set="_placeholder" t-value="'Discount code or gift card'"/>
</xpath>
</template>
<template id="cart_summary" name="Payment" inherit_id="website_sale.cart_summary">
<xpath expr="//table[@id='cart_products']/tbody/tr/td[hasclass('td-price')]/child::*" position="attributes">
<template id="cart_summary" name="Payment" inherit_id="website_sale.checkout_layout">
<xpath expr="//td[@name='website_sale_cart_summary_line_price']/child::*" position="attributes">
<attribute name="t-att-style">'display: None;' if line.reward_id.reward_type == 'shipping' else ''</attribute>
</xpath>
</template>
@@ -170,8 +168,8 @@
</xpath>
</template>
<template id="cart_summary_inherit_website_gift_card_sale" inherit_id="website_sale.cart_summary">
<xpath expr="//td[hasclass('td-product_name')]/div/strong" position="after">
<template id="cart_summary_inherit_website_gift_card_sale" inherit_id="website_sale.checkout_layout">
<xpath expr="//td[@name='website_sale_cart_summary_product_name']/h6" position="after">
<t t-call="sale_loyalty.used_gift_card"/>
</xpath>
</template>
@@ -1,5 +1,5 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
// This tour relies on a data created from the python test.
@@ -43,23 +43,23 @@
},
{
content: "Check the product is in the cart",
trigger: 'td.td-product_name:contains(Short (TEST))',
trigger: 'div>a>h6:contains(Short (TEST))',
},
{
content: "Check always variant",
trigger: 'td.td-product_name:contains(M always)',
trigger: 'div>a>h6:contains(M always)',
},
{
content: "Check dynamic variant",
trigger: 'td.td-product_name:contains(M dynamic)',
trigger: 'div>a>h6:contains(M dynamic)',
},
{
content: "Check never variant",
trigger: 'td.td-product_name:contains(Never attribute size: M never)',
trigger: 'div.text-muted>span:contains(Never attribute size: M never)',
},
{
content: "Check never custom variant",
trigger: 'td.td-product_name:contains(Never attribute size custom: Yes never custom: TEST)',
trigger: 'div.text-muted>span:contains(Never attribute size custom: Yes never custom: TEST)',
isCheck: true,
}
]});
@@ -40,9 +40,9 @@
</template>
<template id="cart_summary_inherit_website_sale_slides"
inherit_id="website_sale.cart_summary"
inherit_id="website_sale.checkout_layout"
name="Course Cart right column">
<xpath expr="//td[hasclass('td-product_name')]/div/strong" position="after">
<xpath expr="//td[@name='website_sale_cart_summary_product_name']/h6" position="after">
<div t-if="line.product_id.channel_ids"
t-foreach="line.product_id.channel_ids.filtered(lambda course: course.enroll == 'payment')"
t-as="course"
@@ -5,7 +5,7 @@
<xpath expr="//input[@type='text'][hasclass('quantity')]" position="attributes">
<attribute name='t-att-data-max'>(line.product_uom_qty + line._get_max_available_qty()) if line.product_id.type == 'product' and not line.product_id.allow_out_of_stock_order else None</attribute>
</xpath>
<xpath expr="//div[hasclass('css_quantity')]" position="after">
<xpath expr="//div[@name='website_sale_cart_line_quantity']" position="after">
<div class='availability_messages'/>
</xpath>
</template>