[FIX] website_sale: forbid payment if an error is displayed
steps to reproduce: - as admin, go to /shop and add a storable product to cart - disable all delivery methods - use a coupon to set the price to 0 before this commit: - the payment button is clickable even if there is a big red warning saying "Sorry, we are unable to ship your order" after this commit: - the payment button is hidden if an error is displayed and the route /shop/payment/validate is blocked if there is an error displayed opw-3582207-nda closes odoo/odoo#146251 X-original-commit: 6db61c5cc0ca49a31252985fa2d690cb6514e7f7 Related: odoo/enterprise#52753 Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com> Signed-off-by: Nicolas Danhier (nda) <nda@odoo.com>
This commit is contained in:
@@ -1679,7 +1679,7 @@ class WebsiteSale(payment_portal.PaymentPortal):
|
||||
def _get_shop_payment_values(self, order, **kwargs):
|
||||
checkout_page_values = {
|
||||
'website_sale_order': order,
|
||||
'errors': [],
|
||||
'errors': self._get_shop_payment_errors(order),
|
||||
'partner': order.partner_invoice_id,
|
||||
'order': order,
|
||||
'submit_button_label': _("Pay now"),
|
||||
@@ -1702,13 +1702,6 @@ class WebsiteSale(payment_portal.PaymentPortal):
|
||||
has_storable_products = any(
|
||||
line.product_id.type in ['consu', 'product'] for line in order.order_line
|
||||
)
|
||||
if not order._get_delivery_methods() and has_storable_products:
|
||||
values['errors'].append((
|
||||
_('Sorry, we are unable to ship your order'),
|
||||
_('No shipping method is available for your current order and shipping address.'
|
||||
' Please contact us for more information.')
|
||||
))
|
||||
|
||||
if has_storable_products:
|
||||
if order.carrier_id and not order.delivery_rating_success:
|
||||
order._remove_delivery_line()
|
||||
@@ -1722,6 +1715,24 @@ class WebsiteSale(payment_portal.PaymentPortal):
|
||||
|
||||
return values
|
||||
|
||||
def _get_shop_payment_errors(self, order):
|
||||
""" Check that there is no error that should block the payment.
|
||||
|
||||
:param sale.order order: The sales order to pay
|
||||
:return: A list of errors (error_title, error_message)
|
||||
:rtype: list[tuple]
|
||||
"""
|
||||
has_storable_products = any(line.product_id.type in ['consu', 'product'] for line in order.order_line)
|
||||
errors = []
|
||||
|
||||
if not order._get_delivery_methods() and has_storable_products:
|
||||
errors.append((
|
||||
_('Sorry, we are unable to ship your order'),
|
||||
_('No shipping method is available for your current order and shipping address. '
|
||||
'Please contact us for more information.'),
|
||||
))
|
||||
return errors
|
||||
|
||||
@http.route('/shop/payment', type='http', auth='public', website=True, sitemap=False)
|
||||
def shop_payment(self, **post):
|
||||
""" Payment step. This page proposes several payment means based on available
|
||||
@@ -1780,6 +1791,12 @@ class WebsiteSale(payment_portal.PaymentPortal):
|
||||
order = request.env['sale.order'].sudo().browse(sale_order_id)
|
||||
assert order.id == request.session.get('sale_last_order_id')
|
||||
|
||||
errors = self._get_shop_payment_errors(order)
|
||||
if errors:
|
||||
first_error = errors[0] # only display first error
|
||||
error_msg = f"{first_error[0]}\n{first_error[1]}"
|
||||
raise ValidationError(error_msg)
|
||||
|
||||
tx_sudo = order.get_portal_last_transaction() if order else order.env['payment.transaction']
|
||||
|
||||
if not order or (order.amount_total and not tx_sudo):
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.fields import Command
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tests import tagged
|
||||
|
||||
from odoo.addons.payment.tests.common import PaymentCommon
|
||||
@@ -110,3 +110,23 @@ class TestWebsiteSaleDeliveryController(PaymentCommon, SaleCommon):
|
||||
self.assertEqual(
|
||||
self.empty_order._get_delivery_methods().mapped('name'), ['Under 300', 'Fixed']
|
||||
)
|
||||
|
||||
def test_validate_payment_with_no_available_delivery_method(self):
|
||||
"""
|
||||
An error should be raised if you try to validate an order with a storable
|
||||
product without any delivery method available
|
||||
"""
|
||||
storable_product = self.env['product.product'].create({
|
||||
'name': 'Storable Product',
|
||||
'sale_ok': True,
|
||||
'type': 'product',
|
||||
'website_published': True,
|
||||
})
|
||||
carriers = self.env['delivery.carrier'].search([])
|
||||
carriers.write({'website_published': False})
|
||||
|
||||
with MockRequest(self.env, website=self.website):
|
||||
self.website.sale_get_order(force_create=True)
|
||||
self.Controller.cart_update_json(product_id=storable_product.id, add_qty=1)
|
||||
with self.assertRaises(ValidationError):
|
||||
self.Controller.shop_payment_validate()
|
||||
|
||||
@@ -1759,7 +1759,7 @@
|
||||
<div t-attf-class="#{_container_classes} d-flex #{_form_send_navigation and 'flex-column flex-lg-row align-items-lg-center' or 'flex-column'} pt-4">
|
||||
<t t-if="website_sale_order and website_sale_order.website_order_line">
|
||||
<t t-if="xmlid == 'website_sale.payment'">
|
||||
<div t-if="not website_sale_order.amount_total"
|
||||
<div t-if="not errors and not website_sale_order.amount_total"
|
||||
name="o_website_sale_free_cart">
|
||||
<form name="o_wsale_confirm_order"
|
||||
class="d-flex flex-column"
|
||||
@@ -2127,7 +2127,7 @@
|
||||
</div>
|
||||
<div class="oe_structure clearfix mt-3" id="oe_structure_website_sale_payment_1"/>
|
||||
|
||||
<t t-if="website_sale_order.amount_total">
|
||||
<t t-if="not errors and website_sale_order.amount_total" name="website_sale_non_free_cart">
|
||||
<div class="mt-4">
|
||||
<h3>Pay with</h3>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
</template>
|
||||
|
||||
<template id="payment_delivery" name="Delivery Costs" inherit_id="website_sale.payment">
|
||||
<xpath expr="//t[@t-if='website_sale_order.amount_total']" position="before">
|
||||
<!-- //t[@t-if='website_sale_order.amount_total'] should be removed in master -->
|
||||
<xpath expr="//t[@name='website_sale_non_free_cart'] | //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)"/>
|
||||
<h4>Choose a delivery method</h4>
|
||||
@@ -58,10 +59,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
<!-- we shouldn't be able to pay if there is no way to deliver -->
|
||||
<xpath expr="//div[@id='payment_method']" position="attributes">
|
||||
<attribute name="t-att-style">'display: none!important' if not deliveries and delivery_has_storable else ''</attribute>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user