From d63f89a4a2f294a8dff7b6ae31141a6b032f650b Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 4 May 2022 16:23:54 +0300 Subject: [PATCH] Retry without shipping field when got invalid address error --- .../src/Entity/PurchaseUnit.php | 9 ++++ .../src/Exception/PayPalApiException.php | 9 ++++ .../src/Endpoint/CreateOrderEndpoint.php | 49 ++++++++++++++++--- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/modules/ppcp-api-client/src/Entity/PurchaseUnit.php b/modules/ppcp-api-client/src/Entity/PurchaseUnit.php index 0eaa1076d..f9fa0228e 100644 --- a/modules/ppcp-api-client/src/Entity/PurchaseUnit.php +++ b/modules/ppcp-api-client/src/Entity/PurchaseUnit.php @@ -175,6 +175,15 @@ class PurchaseUnit { return $this->shipping; } + /** + * Sets shipping info. + * + * @param Shipping|null $shipping The value to set. + */ + public function set_shipping( ?Shipping $shipping ): void { + $this->shipping = $shipping; + } + /** * Returns the reference id. * diff --git a/modules/ppcp-api-client/src/Exception/PayPalApiException.php b/modules/ppcp-api-client/src/Exception/PayPalApiException.php index 699bb2423..d5720532b 100644 --- a/modules/ppcp-api-client/src/Exception/PayPalApiException.php +++ b/modules/ppcp-api-client/src/Exception/PayPalApiException.php @@ -119,4 +119,13 @@ class PayPalApiException extends RuntimeException { public function issues(): array { return $this->response->issues ?? array(); } + + /** + * The HTTP status code. + * + * @return int + */ + public function status_code(): int { + return $this->status_code; + } } diff --git a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php index 89c5faa54..f2e7b7be1 100644 --- a/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php +++ b/modules/ppcp-button/src/Endpoint/CreateOrderEndpoint.php @@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\Button\Endpoint; use Exception; use Psr\Log\LoggerInterface; +use stdClass; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\Amount; use WooCommerce\PayPalCommerce\ApiClient\Entity\Money; @@ -317,19 +318,51 @@ class CreateOrderEndpoint implements EndpointInterface { * @return Order Created PayPal order. * * @throws RuntimeException If create order request fails. + * @throws PayPalApiException If create order request fails. + * phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ private function create_paypal_order( \WC_Order $wc_order = null ): Order { $needs_shipping = WC()->cart instanceof \WC_Cart && WC()->cart->needs_shipping(); $shipping_address_is_fix = $needs_shipping && 'checkout' === $this->parsed_request_data['context']; - return $this->api_endpoint->create( - $this->purchase_units, - $this->payer( $this->parsed_request_data, $wc_order ), - null, - $this->payment_method(), - '', - $shipping_address_is_fix - ); + try { + return $this->api_endpoint->create( + $this->purchase_units, + $this->payer( $this->parsed_request_data, $wc_order ), + null, + $this->payment_method(), + '', + $shipping_address_is_fix + ); + } catch ( PayPalApiException $exception ) { + // Looks like currently there is no proper way to validate the shipping address for PayPal, + // so we cannot make some invalid addresses null in PurchaseUnitFactory, + // which causes failure e.g. for guests using the button on products pages when the country does not have postal codes. + if ( 422 === $exception->status_code() + && array_filter( + $exception->details(), + function ( stdClass $detail ): bool { + return isset( $detail->field ) && str_contains( (string) $detail->field, 'shipping/address' ); + } + ) ) { + $this->logger->info( 'Invalid shipping address for order creation, retrying without it.' ); + + foreach ( $this->purchase_units as $purchase_unit ) { + $purchase_unit->set_shipping( null ); + } + + return $this->api_endpoint->create( + $this->purchase_units, + $this->payer( $this->parsed_request_data, $wc_order ), + null, + $this->payment_method(), + '', + $shipping_address_is_fix + ); + } + + throw $exception; + } } /**