diff --git a/modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php b/modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php index 26489d7a9..25e1837f8 100644 --- a/modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php +++ b/modules/ppcp-api-client/src/Endpoint/OrderEndpoint.php @@ -178,7 +178,7 @@ class OrderEndpoint { * @param string $shipping_preference One of ApplicationContext::SHIPPING_PREFERENCE_ values. * @param Payer|null $payer The payer off the order. * @param PaymentToken|null $payment_token The payment token. - * @param string $paypal_request_id The paypal request id. + * @param string $paypal_request_id The PayPal request id. * @param string $user_action The user action. * * @return Order diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php index e7defbe7f..b898b73c3 100644 --- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php +++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php @@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\SavePaymentMethods; use Psr\Log\LoggerInterface; use WC_Order; +use WC_Payment_Tokens; use WooCommerce\PayPalCommerce\ApiClient\Authentication\UserIdToken; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource; @@ -89,6 +90,27 @@ class SavePaymentMethodsModule implements ModuleInterface { add_filter( 'ppcp_create_order_request_body_data', function( array $data ): array { + // phpcs:ignore WordPress.Security.NonceVerification.Missing + $wc_order_action = wc_clean( wp_unslash( $_POST['wc_order_action'] ?? '' ) ); + if ( $wc_order_action === 'wcs_process_renewal' ) { + // phpcs:ignore WordPress.Security.NonceVerification.Missing + $subscription_id = wc_clean( wp_unslash( $_POST['post_ID'] ?? '' ) ); + $subscription = wcs_get_subscription( (int) $subscription_id ); + if ( $subscription ) { + $customer_id = $subscription->get_customer_id(); + $wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID ); + foreach ( $wc_tokens as $token ) { + $data['payment_source'] = array( + 'paypal' => array( + 'vault_id' => $token->get_token(), + ), + ); + + return $data; + } + } + } + $data['payment_source'] = array( 'paypal' => array( 'attributes' => array( @@ -139,6 +161,8 @@ class SavePaymentMethodsModule implements ModuleInterface { add_filter( 'woocommerce_paypal_payments_disable_add_payment_method', '__return_false' ); + add_filter('woocommerce_paypal_payments_subscription_renewal_return_before_create_order_without_token', '__return_false'); + add_action( 'wp_enqueue_scripts', function() use ( $c ) { diff --git a/modules/ppcp-wc-subscriptions/src/RenewalHandler.php b/modules/ppcp-wc-subscriptions/src/RenewalHandler.php index 78b87cbde..5541335da 100644 --- a/modules/ppcp-wc-subscriptions/src/RenewalHandler.php +++ b/modules/ppcp-wc-subscriptions/src/RenewalHandler.php @@ -181,13 +181,8 @@ class RenewalHandler { * @throws \Exception If customer cannot be read/found. */ private function process_order( \WC_Order $wc_order ): void { - $user_id = (int) $wc_order->get_customer_id(); $customer = new \WC_Customer( $user_id ); - $token = $this->get_token_for_customer( $customer, $wc_order ); - if ( ! $token ) { - return; - } $purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order ); $payer = $this->payer_factory->from_customer( $customer ); @@ -196,36 +191,38 @@ class RenewalHandler { 'renewal' ); + $token = $this->get_token_for_customer( $customer, $wc_order ); + if ( $token ) { + $order = $this->order_endpoint->create( + array( $purchase_unit ), + $shipping_preference, + $payer, + $token + ); + + $this->handle_paypal_order( $wc_order, $order ); + + $this->logger->info( + sprintf( + 'Renewal for order %d is completed.', + $wc_order->get_id() + ) + ); + + return; + } + + if ( apply_filters( 'woocommerce_paypal_payments_subscription_renewal_return_before_create_order_without_token', true ) ) { + return; + } + $order = $this->order_endpoint->create( array( $purchase_unit ), $shipping_preference, - $payer, - $token + $payer ); - $this->add_paypal_meta( $wc_order, $order, $this->environment ); - - if ( $order->intent() === 'AUTHORIZE' ) { - $order = $this->order_endpoint->authorize( $order ); - $wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' ); - } - - $transaction_id = $this->get_paypal_order_transaction_id( $order ); - if ( $transaction_id ) { - $this->update_transaction_id( $transaction_id, $wc_order ); - - $subscriptions = wcs_get_subscriptions_for_order( $wc_order->get_id(), array( 'order_type' => 'any' ) ); - foreach ( $subscriptions as $id => $subscription ) { - $subscription->update_meta_data( 'ppcp_previous_transaction_reference', $transaction_id ); - $subscription->save(); - } - } - - $this->handle_new_order_status( $order, $wc_order ); - - if ( $this->capture_authorized_downloads( $order ) ) { - $this->authorized_payments_processor->capture_authorized_payment( $wc_order ); - } + $this->handle_paypal_order( $wc_order, $order ); $this->logger->info( sprintf( @@ -317,4 +314,38 @@ class RenewalHandler { } return true; } + + /** + * Handles PayPal order creation and updates WC order accordingly. + * + * @param \WC_Order $wc_order WC order. + * @param Order $order PayPal order. + * @return void + * @throws NotFoundException When something goes wrong while handling the order. + */ + private function handle_paypal_order( \WC_Order $wc_order, Order $order ): void { + $this->add_paypal_meta( $wc_order, $order, $this->environment ); + + if ( $order->intent() === 'AUTHORIZE' ) { + $order = $this->order_endpoint->authorize( $order ); + $wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' ); + } + + $transaction_id = $this->get_paypal_order_transaction_id( $order ); + if ( $transaction_id ) { + $this->update_transaction_id( $transaction_id, $wc_order ); + + $subscriptions = wcs_get_subscriptions_for_order( $wc_order->get_id(), array( 'order_type' => 'any' ) ); + foreach ( $subscriptions as $id => $subscription ) { + $subscription->update_meta_data( 'ppcp_previous_transaction_reference', $transaction_id ); + $subscription->save(); + } + } + + $this->handle_new_order_status( $order, $wc_order ); + + if ( $this->capture_authorized_downloads( $order ) ) { + $this->authorized_payments_processor->capture_authorized_payment( $wc_order ); + } + } }