From ea5370017345fc2254f5011e4fdf381b3842e18a Mon Sep 17 00:00:00 2001 From: Miguel Gasca Date: Thu, 26 Oct 2023 09:45:23 +0200 Subject: [PATCH] Fix Afterpay checkout error when shipping information is missing (#7541) --- ...fails-when-shipping-information-is-missing | 4 ++ includes/class-wc-payment-gateway-wcpay.php | 32 +---------- includes/class-wc-payments-order-service.php | 56 +++++++++++++++++++ .../class-invalid-address-exception.php | 17 ++++++ .../class-upe-split-payment-gateway.php | 41 +++++++++++++- 5 files changed, 117 insertions(+), 33 deletions(-) create mode 100644 changelog/fix-7509-afterpay-checkout-fails-when-shipping-information-is-missing create mode 100644 includes/exceptions/class-invalid-address-exception.php diff --git a/changelog/fix-7509-afterpay-checkout-fails-when-shipping-information-is-missing b/changelog/fix-7509-afterpay-checkout-fails-when-shipping-information-is-missing new file mode 100644 index 00000000000..473e587b04b --- /dev/null +++ b/changelog/fix-7509-afterpay-checkout-fails-when-shipping-information-is-missing @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix Afterpay checkout error when shipping information is missing diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php index fca52f46724..6e223ee1d4e 100644 --- a/includes/class-wc-payment-gateway-wcpay.php +++ b/includes/class-wc-payment-gateway-wcpay.php @@ -2890,34 +2890,6 @@ public function cancel_authorization( $order ) { ]; } - /** - * Create the shipping data array to send to Stripe when making a purchase. - * - * @param WC_Order $order The order that is being paid for. - * @return array The shipping data to send to Stripe. - */ - public function get_shipping_data_from_order( WC_Order $order ): array { - return [ - 'name' => implode( - ' ', - array_filter( - [ - $order->get_shipping_first_name(), - $order->get_shipping_last_name(), - ] - ) - ), - 'address' => [ - 'line1' => $order->get_shipping_address_1(), - 'line2' => $order->get_shipping_address_2(), - 'postal_code' => $order->get_shipping_postcode(), - 'city' => $order->get_shipping_city(), - 'state' => $order->get_shipping_state(), - 'country' => $order->get_shipping_country(), - ], - ]; - } - /** * Create the level 3 data array to send to Stripe when making a purchase. * @@ -3736,11 +3708,11 @@ private function upe_needs_redirection( $payment_methods ) { * * @param Create_And_Confirm_Intention $request The request object for creating and confirming intention. * @param Payment_Information $payment_information The payment information object. - * @param mixed $order The order object or data. + * @param WC_Order $order The order object. * * @return void */ - protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, $order ) { + protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ) { // Do nothing. } } diff --git a/includes/class-wc-payments-order-service.php b/includes/class-wc-payments-order-service.php index 3cf3d3cbdea..f7473dd71a0 100644 --- a/includes/class-wc-payments-order-service.php +++ b/includes/class-wc-payments-order-service.php @@ -741,6 +741,62 @@ public function attach_intent_info_to_order( $order, $intent_id, $intent_status, $order->save(); } + /** + * Create the shipping data array to send to Stripe when making a purchase. + * + * @param WC_Order $order The order that is being paid for. + * @return array The shipping data to send to Stripe. + */ + public function get_shipping_data_from_order( WC_Order $order ): array { + return [ + 'name' => implode( + ' ', + array_filter( + [ + $order->get_shipping_first_name(), + $order->get_shipping_last_name(), + ] + ) + ), + 'address' => [ + 'line1' => $order->get_shipping_address_1(), + 'line2' => $order->get_shipping_address_2(), + 'postal_code' => $order->get_shipping_postcode(), + 'city' => $order->get_shipping_city(), + 'state' => $order->get_shipping_state(), + 'country' => $order->get_shipping_country(), + ], + ]; + } + + /** + * Create the billing data array to send to Stripe when making a purchase, based on order's billing data. + * + * @param WC_Order $order The order that is being paid for. + * @return array The shipping data to send to Stripe. + */ + public function get_billing_data_from_order( WC_Order $order ): array { + return [ + 'name' => implode( + ' ', + array_filter( + [ + $order->get_billing_first_name(), + $order->get_billing_last_name(), + ] + ) + ), + 'address' => [ + 'line1' => $order->get_billing_address_1(), + 'line2' => $order->get_billing_address_2(), + 'postal_code' => $order->get_billing_postcode(), + 'city' => $order->get_billing_city(), + 'state' => $order->get_billing_state(), + 'country' => $order->get_billing_country(), + ], + ]; + } + /** * Updates an order to cancelled status, while adding a note with a link to the transaction. * diff --git a/includes/exceptions/class-invalid-address-exception.php b/includes/exceptions/class-invalid-address-exception.php new file mode 100644 index 00000000000..235ff953bbd --- /dev/null +++ b/includes/exceptions/class-invalid-address-exception.php @@ -0,0 +1,17 @@ +stripe_id; } + /** + * Handles the shipping requirement for Afterpay payments. + * + * This method extracts the shipping and billing data from the order and sets the appropriate + * shipping data for the Afterpay payment request. If neither shipping nor billing data is valid + * for shipping, an exception is thrown. + * + * @param WC_Order $order The order object containing shipping and billing information. + * @param Create_And_Confirm_Intention $request The Afterpay payment request object to set shipping data on. + * + * @throws Invalid_Address_Exception If neither shipping nor billing address is valid for Afterpay payments. + * @return void + */ + private function handle_afterpay_shipping_requirement( WC_Order $order, Create_And_Confirm_Intention $request ): void { + $check_if_usable = function( array $address ): bool { + return $address['country'] && $address['state'] && $address['city'] && $address['postal_code'] && $address['line1']; + }; + + $shipping_data = $this->order_service->get_shipping_data_from_order( $order ); + if ( $check_if_usable( $shipping_data['address'] ) ) { + $request->set_shipping( $shipping_data ); + return; + } + + $billing_data = $this->order_service->get_billing_data_from_order( $order ); + if ( $check_if_usable( $billing_data['address'] ) ) { + $request->set_shipping( $billing_data ); + return; + } + + throw new Invalid_Address_Exception( __( 'A valid shipping address is required for Afterpay payments.', 'woocommerce-payments' ) ); + } + /** * Modifies the create intent parameters when processing a payment. @@ -556,13 +591,13 @@ public function get_stripe_id() { * * @param Create_And_Confirm_Intention $request The request object for creating and confirming intention. * @param Payment_Information $payment_information The payment information object. - * @param mixed $order The order object or data. + * @param WC_Order $order The order object. * * @return void */ - protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, $order ) { + protected function modify_create_intent_parameters_when_processing_payment( Create_And_Confirm_Intention $request, Payment_Information $payment_information, WC_Order $order ): void { if ( Payment_Method::AFTERPAY === $this->get_selected_stripe_payment_type_id() ) { - $request->set_shipping( $this->get_shipping_data_from_order( $order ) ); + $this->handle_afterpay_shipping_requirement( $order, $request ); } } }