From 819149057ea08728c598dd697af2fb3c279438d4 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 26 Aug 2024 12:34:53 +0200 Subject: [PATCH] Display PayPal fees in wc order --- .../ppcp-api-client/src/Endpoint/Orders.php | 43 ++++++++++++ .../LocalAlternativePaymentMethodsModule.php | 23 ++++++ modules/ppcp-wc-gateway/services.php | 7 ++ .../Gateway/PayUponInvoice/PayUponInvoice.php | 2 +- .../src/Helper/FeesUpdater.php | 70 +++++++++++++++++++ .../src/Handler/PaymentCaptureCompleted.php | 2 +- 6 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 modules/ppcp-wc-gateway/src/Helper/FeesUpdater.php diff --git a/modules/ppcp-api-client/src/Endpoint/Orders.php b/modules/ppcp-api-client/src/Endpoint/Orders.php index e8386ec86..4ba5b71a1 100644 --- a/modules/ppcp-api-client/src/Endpoint/Orders.php +++ b/modules/ppcp-api-client/src/Endpoint/Orders.php @@ -160,4 +160,47 @@ class Orders { return $response; } + + /** + * Get PayPal order by id. + * + * @param string $id PayPal order ID. + * @return array + * @throws RuntimeException If something went wrong with the request. + * @throws PayPalApiException If something went wrong with the PayPal API request. + */ + public function order( string $id ): array { + $bearer = $this->bearer->bearer(); + $url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $id; + + $args = array( + 'headers' => array( + 'Authorization' => 'Bearer ' . $bearer->token(), + 'Content-Type' => 'application/json', + 'PayPal-Request-Id' => uniqid( 'ppcp-', true ), + ), + ); + + $response = $this->request( $url, $args ); + if ( $response instanceof WP_Error ) { + throw new RuntimeException( $response->get_error_message() ); + } + + $status_code = (int) wp_remote_retrieve_response_code( $response ); + if ( $status_code !== 200 ) { + $body = json_decode( $response['body'] ); + + $message = $body->details[0]->description ?? ''; + if ( $message ) { + throw new RuntimeException( $message ); + } + + throw new PayPalApiException( + $body, + $status_code + ); + } + + return $response; + } } diff --git a/modules/ppcp-local-alternative-payment-methods/src/LocalAlternativePaymentMethodsModule.php b/modules/ppcp-local-alternative-payment-methods/src/LocalAlternativePaymentMethodsModule.php index 6971a24ab..9a853aadb 100644 --- a/modules/ppcp-local-alternative-payment-methods/src/LocalAlternativePaymentMethodsModule.php +++ b/modules/ppcp-local-alternative-payment-methods/src/LocalAlternativePaymentMethodsModule.php @@ -11,10 +11,14 @@ namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods; use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry; use WC_Order; +use WooCommerce\PayPalCommerce\ApiClient\Endpoint\Orders; +use WooCommerce\PayPalCommerce\ApiClient\Factory\CaptureFactory; use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider; use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface; use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; +use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; +use WooCommerce\PayPalCommerce\WcGateway\Helper\FeesUpdater; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; /** @@ -158,6 +162,25 @@ class LocalAlternativePaymentMethodsModule implements ModuleInterface { } } ); + + add_action( + 'woocommerce_paypal_payments_payment_capture_completed_webhook_handler', + function( WC_Order $wc_order, string $order_id ) use ( $c ) { + $payment_methods = $c->get( 'ppcp-local-apms.payment-methods' ); + if ( + ! $this->is_local_apm( $wc_order->get_payment_method(), $payment_methods ) + ) { + return; + } + + $fees_updater = $c->get( 'wcgateway.helper.fees-updater' ); + assert( $fees_updater instanceof FeesUpdater ); + + $fees_updater->update( $order_id, $wc_order ); + }, + 10, + 2 + ); } /** diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index bce10af51..2020b0283 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -27,6 +27,7 @@ use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Admin\RenderReauthorizeAction; use WooCommerce\PayPalCommerce\WcGateway\Endpoint\CaptureCardPayment; use WooCommerce\PayPalCommerce\WcGateway\Endpoint\RefreshFeatureStatusEndpoint; +use WooCommerce\PayPalCommerce\WcGateway\Helper\FeesUpdater; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\WcGateway\Admin\FeesRenderer; @@ -1179,6 +1180,12 @@ return array( $logger = $container->get( 'woocommerce.logger.woocommerce' ); return new RefundFeesUpdater( $order_endpoint, $logger ); }, + 'wcgateway.helper.fees-updater' => static function ( ContainerInterface $container ): FeesUpdater { + return new FeesUpdater( + $container->get( 'api.endpoint.orders' ), + $container->get( 'api.factory.capture' ) + ); + }, 'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers { return new MessagesDisclaimers( diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 9da44d069..94ed7240a 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -195,7 +195,7 @@ class PayUponInvoice { ); add_action( - 'ppcp_payment_capture_completed_webhook_handler', + 'woocommerce_paypal_payments_payment_capture_completed_webhook_handler', function ( WC_Order $wc_order, string $order_id ) { try { if ( $wc_order->get_payment_method() !== PayUponInvoiceGateway::ID ) { diff --git a/modules/ppcp-wc-gateway/src/Helper/FeesUpdater.php b/modules/ppcp-wc-gateway/src/Helper/FeesUpdater.php new file mode 100644 index 000000000..7b04ebff5 --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Helper/FeesUpdater.php @@ -0,0 +1,70 @@ +orders_endpoint = $orders_endpoint; + $this->capture_factory = $capture_factory; + } + + /** + * Updates the fees meta for a given order. + * + * @param string $order_id + * @param WC_Order $wc_order + * @return void + */ + public function update( string $order_id, WC_Order $wc_order ): void { + $order = $this->orders_endpoint->order( $order_id ); + $body = json_decode( $order['body'] ); + + $capture = $this->capture_factory->from_paypal_response( $body->purchase_units[0]->payments->captures[0] ); + $breakdown = $capture->seller_receivable_breakdown(); + if ( $breakdown ) { + $wc_order->update_meta_data( PayPalGateway::FEES_META_KEY, $breakdown->to_array() ); + $paypal_fee = $breakdown->paypal_fee(); + if ( $paypal_fee ) { + $wc_order->update_meta_data( 'PayPal Transaction Fee', (string) $paypal_fee->value() ); + } + + $wc_order->save_meta_data(); + } + } +} diff --git a/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php b/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php index d8f927b42..da291c123 100644 --- a/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php +++ b/modules/ppcp-webhooks/src/Handler/PaymentCaptureCompleted.php @@ -105,7 +105,7 @@ class PaymentCaptureCompleted implements RequestHandler { /** * Allow access to the webhook logic before updating the WC order. */ - do_action( 'ppcp_payment_capture_completed_webhook_handler', $wc_order, $order_id ); + do_action( 'woocommerce_paypal_payments_payment_capture_completed_webhook_handler', $wc_order, $order_id ); if ( $wc_order->get_status() !== 'on-hold' ) { return $this->success_response();