[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:
committed by
Valentin Chevalier
co-authored by
Valentin Chevalier
parent
41bd821f82
commit
0750eb6315
@@ -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 < 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>
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 & 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>
|
||||
|
||||
+6
-6
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user