From e63bb5bcc607096435270993189a70544b200354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=BCsken?= Date: Fri, 20 Dec 2024 09:49:22 +0100 Subject: [PATCH] Streamline the call off confirm_payment_source() and reference implementation for future investigating --- .../src/Endpoint/OrderEndpoint.php | 33 ++++++++++--------- .../ppcp-api-client/src/Endpoint/Orders.php | 16 ++++----- .../src/Entity/PaymentSource.php | 6 ++++ .../src/MultibancoGateway.php | 5 ++- .../src/Gateway/OXXO/OXXOGateway.php | 10 +++++- .../src/Processor/OrderProcessor.php | 21 ++++++++++-- 6 files changed, 61 insertions(+), 30 deletions(-) diff --git a/modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php b/modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php index 91b45d550f..0fcfe1d166 100644 --- a/modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php +++ b/modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php @@ -601,30 +601,23 @@ public function patch( string $order_id, PatchCollection $patches ): void { * * @param string $id The PayPal order ID. * @param array $payment_source The payment source. - * @return stdClass + * @return \stdClass * @throws PayPalApiException If the request fails. * @throws RuntimeException If something unexpected happens. */ - public function confirm_payment_source( string $id, array $payment_source ): stdClass { + public function confirm_payment_source( string $id, array $request_body ): stdClass { $bearer = $this->bearer->bearer(); $url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id . '/confirm-payment-source'; - $data = array( - 'payment_source' => $payment_source, - 'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL', - 'application_context' => array( - 'locale' => 'es-MX', - ), - ); - $args = array( 'method' => 'POST', 'headers' => array( - 'Authorization' => 'Bearer ' . $bearer->token(), - 'Content-Type' => 'application/json', - 'Prefer' => 'return=representation', + 'Authorization' => 'Bearer ' . $bearer->token(), + 'Content-Type' => 'application/json', + 'Prefer' => 'return=representation', + 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), ), - 'body' => wp_json_encode( $data ), + 'body' => wp_json_encode( $request_body ), ); $response = $this->request( $url, $args ); @@ -634,8 +627,16 @@ public function confirm_payment_source( string $id, array $payment_source ): std $json = json_decode( $response['body'] ); $status_code = (int) wp_remote_retrieve_response_code( $response ); - if ( 200 !== $status_code ) { - throw new PayPalApiException( $json, $status_code ); + if ( $status_code !== 200 ) { + $message = $json->details[0]->description ?? ''; + if ( $message ) { + throw new RuntimeException( $message ); + } + + throw new PayPalApiException( + $json, + $status_code + ); } return $json; diff --git a/modules/ppcp-api-client/src/Endpoint/Orders.php b/modules/ppcp-api-client/src/Endpoint/Orders.php index 4ba5b71a11..4a7fe030ef 100644 --- a/modules/ppcp-api-client/src/Endpoint/Orders.php +++ b/modules/ppcp-api-client/src/Endpoint/Orders.php @@ -118,13 +118,13 @@ public function create( array $request_body, array $headers = array() ): array { * * @link https://developer.paypal.com/docs/api/orders/v2/#orders_confirm * - * @param array $request_body The request body. * @param string $id PayPal order ID. - * @return array + * @param array $request_body The request body. + * @return \stdClass * @throws RuntimeException If something went wrong with the request. * @throws PayPalApiException If something went wrong with the PayPal API request. */ - public function confirm_payment_source( array $request_body, string $id ): array { + public function confirm_payment_source( string $id, array $request_body ): \stdClass { $bearer = $this->bearer->bearer(); $url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id . '/confirm-payment-source'; @@ -133,6 +133,7 @@ public function confirm_payment_source( array $request_body, string $id ): array 'headers' => array( 'Authorization' => 'Bearer ' . $bearer->token(), 'Content-Type' => 'application/json', + 'Prefer' => 'return=representation', 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), ), 'body' => wp_json_encode( $request_body ), @@ -143,22 +144,21 @@ public function confirm_payment_source( array $request_body, string $id ): array throw new RuntimeException( $response->get_error_message() ); } + $json = json_decode( $response['body'] ); $status_code = (int) wp_remote_retrieve_response_code( $response ); if ( $status_code !== 200 ) { - $body = json_decode( $response['body'] ); - - $message = $body->details[0]->description ?? ''; + $message = $json->details[0]->description ?? ''; if ( $message ) { throw new RuntimeException( $message ); } throw new PayPalApiException( - $body, + $json, $status_code ); } - return $response; + return $json; } /** diff --git a/modules/ppcp-api-client/src/Entity/PaymentSource.php b/modules/ppcp-api-client/src/Entity/PaymentSource.php index d3f1a8cc7a..da9335793d 100644 --- a/modules/ppcp-api-client/src/Entity/PaymentSource.php +++ b/modules/ppcp-api-client/src/Entity/PaymentSource.php @@ -58,4 +58,10 @@ public function name(): string { public function properties(): object { return $this->properties; } + + public function to_array(): array { + return array( + $this->name => (array) $this->properties + ); + } } diff --git a/modules/ppcp-local-alternative-payment-methods/src/MultibancoGateway.php b/modules/ppcp-local-alternative-payment-methods/src/MultibancoGateway.php index 264e208a41..856f771531 100644 --- a/modules/ppcp-local-alternative-payment-methods/src/MultibancoGateway.php +++ b/modules/ppcp-local-alternative-payment-methods/src/MultibancoGateway.php @@ -169,11 +169,10 @@ public function process_payment( $order_id ) { ), ); - $response = $this->orders_endpoint->confirm_payment_source( $request_body, $body->id ); - $body = json_decode( $response['body'] ); + $response = $this->orders_endpoint->confirm_payment_source( $body->id, $request_body ); $payer_action = ''; - foreach ( $body->links as $link ) { + foreach ( $response->links as $link ) { if ( $link->rel === 'payer-action' ) { $payer_action = $link->href; } diff --git a/modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php b/modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php index 009018558d..3babcaadb1 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php @@ -186,7 +186,15 @@ public function process_payment( $order_id ) { 'country_code' => $wc_order->get_billing_country(), ), ); - $payment_method = $this->order_endpoint->confirm_payment_source( $order->id(), $payment_source ); + $request_body = array( + 'payment_source' => $payment_source, + 'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL', + 'application_context' => array( + 'locale' => 'es-MX', + ), + ); + + $payment_method = $this->order_endpoint->confirm_payment_source( $order->id(), $request_body ); foreach ( $payment_method->links as $link ) { if ( $link->rel === 'payer-action' ) { $payer_action = $link->href; diff --git a/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php b/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php index 82183e0d41..7db16be89d 100644 --- a/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php +++ b/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php @@ -17,6 +17,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus; use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource; +use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory; @@ -196,11 +197,11 @@ public function __construct( * Processes a given WooCommerce order and captured/authorizes the connected PayPal orders. * * @param WC_Order $wc_order The WooCommerce order. - * + * @return \stdClass PayPal order details of confirmed Order * @throws PayPalOrderMissingException If no PayPal order. * @throws Exception If processing fails. */ - public function process( WC_Order $wc_order ): void { + public function process( WC_Order $wc_order ): \stdClass { $order = $this->session_handler->order(); if ( ! $order ) { // phpcs:ignore WordPress.Security.NonceVerification @@ -228,6 +229,20 @@ public function process( WC_Order $wc_order ): void { } } + $request_body = apply_filters( + 'woocommerce_paypal_payments_confirm_payment_source_request_body', + array( + 'payment_source' => $order->payment_source() !== null ? $order->payment_source()->to_array() : null, + 'application_context' => $order->application_context() !== null ? $order->application_context()->to_array() : null, + ) + ); + + if ( ! empty( $request_body[ 'payment_source' ] ) ) { + $confirm_payment_result = $this->order_endpoint->confirm_payment_source( $order->id(), $request_body ); + } else { + $confirm_payment_result = new \stdClass(); + } + $this->add_paypal_meta( $wc_order, $order, $this->environment ); if ( $this->order_helper->contains_physical_goods( $order ) && ! $this->order_is_ready_for_process( $order ) ) { @@ -268,6 +283,8 @@ public function process( WC_Order $wc_order ): void { } do_action( 'woocommerce_paypal_payments_after_order_processor', $wc_order, $order ); + + return $confirm_payment_result; } /**