Fix: orders not being placed when paying with an Express payment method from the Cart block (https://github.com/woocommerce/woocommerce-blocks/pull/3403)

* Fix Express payment methods in Cart block

* Create a draft order inside get_draft_order_object() if the ID doesn't match a draft order
This commit is contained in:
Albert Juhé Lluveras 2020-11-16 14:12:56 +01:00 committed by GitHub
parent a576ba8d67
commit 624a8601bc
5 changed files with 56 additions and 37 deletions

View File

@ -1,9 +1,7 @@
/**
* Internal dependencies
*/
import { ShippingDataProvider } from '../shipping';
import { CheckoutStateProvider } from '../checkout-state';
import { PaymentMethodDataProvider } from '../payment-methods';
import { CheckoutProvider } from '../checkout';
/**
* Cart provider
@ -18,12 +16,8 @@ import { PaymentMethodDataProvider } from '../payment-methods';
*/
export const CartProvider = ( { children, redirectUrl } ) => {
return (
<CheckoutStateProvider redirectUrl={ redirectUrl } isCart={ true }>
<ShippingDataProvider>
<PaymentMethodDataProvider>
{ children }
</PaymentMethodDataProvider>
</ShippingDataProvider>
</CheckoutStateProvider>
<CheckoutProvider isCart={ true } redirectUrl={ redirectUrl }>
{ children }
</CheckoutProvider>
);
};

View File

@ -14,13 +14,19 @@ import CheckoutProcessor from './processor';
*
* @param {Object} props Incoming props for the provider.
* @param {Object} props.children The children being wrapped.
* @param {boolean} [props.isCart] Whether it's rendered in the Cart
* component.
* @param {string} [props.redirectUrl] Initialize what the checkout will
* redirect to after successful
* submit.
*/
export const CheckoutProvider = ( { children, redirectUrl } ) => {
export const CheckoutProvider = ( {
children,
isCart = false,
redirectUrl,
} ) => {
return (
<CheckoutStateProvider redirectUrl={ redirectUrl } isCart={ false }>
<CheckoutStateProvider redirectUrl={ redirectUrl } isCart={ isCart }>
<BillingDataProvider>
<ShippingDataProvider>
<PaymentMethodDataProvider>

View File

@ -6,10 +6,7 @@ import { dispatch } from '@wordpress/data';
import { useStoreCart } from '@woocommerce/base-hooks';
import { useEffect, RawHTML } from '@wordpress/element';
import LoadingMask from '@woocommerce/base-components/loading-mask';
import {
ValidationContextProvider,
CartProvider,
} from '@woocommerce/base-context';
import { ValidationContextProvider } from '@woocommerce/base-context';
import {
dispatchEvent,
translateJQueryEventToNative,
@ -82,9 +79,7 @@ const Block = ( { emptyCart, attributes, scrollToTop } ) => {
) : (
<LoadingMask showSpinner={ true } isLoading={ cartIsLoading }>
<ValidationContextProvider>
<CartProvider>
<FullCart attributes={ attributes } />
</CartProvider>
<FullCart attributes={ attributes } />
</ValidationContextProvider>
</LoadingMask>
) }

View File

@ -34,6 +34,7 @@ import Title from '@woocommerce/base-components/title';
import { getSetting } from '@woocommerce/settings';
import { useEffect } from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
import { CartProvider } from '@woocommerce/base-context';
/**
* Internal dependencies
@ -44,6 +45,14 @@ import CartLineItemsTable from './cart-line-items-table';
import './style.scss';
const Block = ( props ) => {
return (
<CartProvider>
<Cart { ...props } />
</CartProvider>
);
};
/**
* Component that renders the Cart block when user has something in cart aka "full".
*
@ -164,4 +173,4 @@ Cart.propTypes = {
attributes: PropTypes.object.isRequired,
};
export default Cart;
export default Block;

View File

@ -271,6 +271,31 @@ class Checkout extends AbstractRoute {
wc()->session->set( 'store_api_draft_order', $order_id );
}
/**
* Whether the passed argument is a draft order or an order that is
* pending/failed and the cart hasn't changed.
*
* @param \WC_Order $order_object Order object to check.
* @return boolean Whether the order is valid as a draft order.
*/
protected function is_valid_draft_order( $order_object ) {
if ( ! $order_object instanceof \WC_Order ) {
return false;
}
// Draft orders are okay.
if ( $order_object->has_status( 'checkout-draft' ) ) {
return true;
}
// Pending and failed orders can be retried if the cart hasn't changed.
if ( $order_object->needs_payment() && $order_object->has_cart_hash( wc()->cart->get_cart_hash() ) ) {
return true;
}
return false;
}
/**
* Get an order object, either using a current draft order, or returning a new one.
*
@ -278,23 +303,13 @@ class Checkout extends AbstractRoute {
* @return \WC_Order|boolean Either the draft order, or false if one has not yet been created.
*/
protected function get_draft_order_object( $order_id ) {
// If order ID doesn't exist or it doesn't match a draft order, create
// a new draft order. That might happen when trying to checkout directly
// from the Cart block with an express payment method and the draft
// order hasn't been created yet.
$draft_order_object = $order_id ? wc_get_order( $order_id ) : false;
if ( ! $draft_order_object instanceof \WC_Order ) {
return false;
}
// Draft orders are okay.
if ( $draft_order_object->has_status( 'checkout-draft' ) ) {
return $draft_order_object;
}
// Pending and failed orders can be retried if the cart hasn't changed.
if ( $draft_order_object->needs_payment() && $draft_order_object->has_cart_hash( wc()->cart->get_cart_hash() ) ) {
return $draft_order_object;
}
return false;
return $this->is_valid_draft_order( $draft_order_object ) ? $draft_order_object : $this->create_or_update_draft_order();
}
/**
@ -308,14 +323,14 @@ class Checkout extends AbstractRoute {
$cart_controller = new CartController();
$order_controller = new OrderController();
$reserve_stock = \class_exists( '\Automattic\WooCommerce\Checkout\Helpers\ReserveStock' ) ? new \Automattic\WooCommerce\Checkout\Helpers\ReserveStock() : new ReserveStock();
$order_object = $this->get_draft_order_object( $this->get_draft_order_id() );
$order_object = $this->get_draft_order_id() ? wc_get_order( $this->get_draft_order_id() ) : null;
$created = false;
// Validate items etc are allowed in the order before it gets created.
$cart_controller->validate_cart_items();
$cart_controller->validate_cart_coupons();
if ( ! $order_object instanceof \WC_Order ) {
if ( ! $this->is_valid_draft_order( $order_object ) ) {
$order_object = $order_controller->create_order_from_cart();
$created = true;
} else {