From 0262c28580e175fdcc0b052eca6183ca0b979218 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 8 Jan 2024 17:47:52 +0100 Subject: [PATCH] Add save card payment for changing subscription payment method (WIP) --- .../resources/js/add-payment-method.js | 27 +++++++ .../src/Endpoint/CreatePaymentToken.php | 9 ++- .../src/SavePaymentMethodsModule.php | 22 ++++-- .../src/WooCommercePaymentTokens.php | 16 ++-- modules/ppcp-wc-subscriptions/services.php | 8 +- .../SubscriptionChangePaymentMethod.php | 75 +++++++++++++++++++ .../src/WcSubscriptionsModule.php | 11 +++ 7 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 modules/ppcp-wc-subscriptions/src/Endpoint/SubscriptionChangePaymentMethod.php diff --git a/modules/ppcp-save-payment-methods/resources/js/add-payment-method.js b/modules/ppcp-save-payment-methods/resources/js/add-payment-method.js index 6be53940c..4a7ab80de 100644 --- a/modules/ppcp-save-payment-methods/resources/js/add-payment-method.js +++ b/modules/ppcp-save-payment-methods/resources/js/add-payment-method.js @@ -128,6 +128,33 @@ document.addEventListener( const result = await response.json(); if(result.success === true) { + if(ppcp_add_payment_method.is_subscription_change_payment_page) { + const subscriptionId = ppcp_add_payment_method.subscription_id_to_change_payment; + if(subscriptionId && result.data) { + const req = await fetch(ppcp_add_payment_method.ajax.subscription_change_payment_method.endpoint, { + method: "POST", + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + nonce: ppcp_add_payment_method.ajax.subscription_change_payment_method.nonce, + subscription_id: subscriptionId, + payment_method: getCurrentPaymentMethod(), + wc_payment_token_id: result.data + }) + }); + + const res = await req.json(); + if (res.success === true) { + window.location.href = `${ppcp_add_payment_method.view_subscriptions_page}/${subscriptionId}`; + return; + } + } + + return; + } + window.location.href = ppcp_add_payment_method.payment_methods_page; return; } diff --git a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php index 61fcae9da..3a4807ec2 100644 --- a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php +++ b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php @@ -80,7 +80,8 @@ class CreatePaymentToken implements EndpointInterface { */ public function handle_request(): bool { try { - $data = $this->request_data->read_request( $this->nonce() ); + $data = $this->request_data->read_request( $this->nonce() ); + $wc_token_id = 0; /** * Suppress ArgumentTypeCoercion @@ -107,7 +108,7 @@ class CreatePaymentToken implements EndpointInterface { $email = $result->payment_source->paypal->email_address; } - $this->wc_payment_tokens->create_payment_token_paypal( + $wc_token_id = $this->wc_payment_tokens->create_payment_token_paypal( $current_user_id, $result->id, $email @@ -115,11 +116,11 @@ class CreatePaymentToken implements EndpointInterface { } if ( isset( $result->payment_source->card ) ) { - $this->wc_payment_tokens->create_payment_token_card( $current_user_id, $result ); + $wc_token_id = $this->wc_payment_tokens->create_payment_token_card( $current_user_id, $result ); } } - wp_send_json_success( $result ); + wp_send_json_success( $wc_token_id ); return true; } catch ( Exception $exception ) { wp_send_json_error(); diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php index 9b055b415..b34092732 100644 --- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php +++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php @@ -28,6 +28,7 @@ use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; +use WooCommerce\PayPalCommerce\WcSubscriptions\Endpoint\SubscriptionChangePaymentMethod; /** * Class SavePaymentMethodsModule @@ -211,13 +212,16 @@ class SavePaymentMethodsModule implements ModuleInterface { 'ppcp-add-payment-method', 'ppcp_add_payment_method', array( - 'client_id' => $c->get( 'button.client_id' ), - 'merchant_id' => $c->get( 'api.merchant_id' ), - 'id_token' => $id_token, - 'payment_methods_page' => wc_get_account_endpoint_url( 'payment-methods' ), - 'error_message' => __( 'Could not save payment method.', 'woocommerce-paypal-payments' ), - 'verification_method' => $verification_method, - 'ajax' => array( + 'client_id' => $c->get( 'button.client_id' ), + 'merchant_id' => $c->get( 'api.merchant_id' ), + 'id_token' => $id_token, + 'payment_methods_page' => wc_get_account_endpoint_url( 'payment-methods' ), + 'view_subscriptions_page' => wc_get_account_endpoint_url( 'view-subscription' ), + 'is_subscription_change_payment_page' => $this->is_subscription_change_payment_method_page(), + 'subscription_id_to_change_payment' => $this->is_subscription_change_payment_method_page() ? (int) $_GET['change_payment_method'] : 0, + 'error_message' => __( 'Could not save payment method.', 'woocommerce-paypal-payments' ), + 'verification_method' => $verification_method, + 'ajax' => array( 'create_setup_token' => array( 'endpoint' => \WC_AJAX::get_endpoint( CreateSetupToken::ENDPOINT ), 'nonce' => wp_create_nonce( CreateSetupToken::nonce() ), @@ -226,6 +230,10 @@ class SavePaymentMethodsModule implements ModuleInterface { 'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentToken::ENDPOINT ), 'nonce' => wp_create_nonce( CreatePaymentToken::nonce() ), ), + 'subscription_change_payment_method' => array( + 'endpoint' => \WC_AJAX::get_endpoint( SubscriptionChangePaymentMethod::ENDPOINT ), + 'nonce' => wp_create_nonce( SubscriptionChangePaymentMethod::nonce() ), + ), ), ) ); diff --git a/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php b/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php index 849e1e56e..520099994 100644 --- a/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php +++ b/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php @@ -70,17 +70,17 @@ class WooCommercePaymentTokens { * @param string $token The PayPal payment token. * @param string $email The PayPal customer email. * - * @return void + * @return int */ public function create_payment_token_paypal( int $customer_id, string $token, string $email - ): void { + ): int { $wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, PayPalGateway::ID ); if ( $this->payment_token_helper->token_exist( $wc_tokens, $token ) ) { - return; + return 0; } $payment_token_paypal = $this->payment_token_factory->create( 'paypal' ); @@ -101,6 +101,8 @@ class WooCommercePaymentTokens { "Could not create WC payment token PayPal for customer {$customer_id}. " . $exception->getMessage() ); } + + return $payment_token_paypal->get_id(); } /** @@ -109,12 +111,12 @@ class WooCommercePaymentTokens { * @param int $customer_id The WC customer ID. * @param stdClass $payment_token The Credit Card payment token. * - * @return void + * @return int */ - public function create_payment_token_card( int $customer_id, stdClass $payment_token ): void { + public function create_payment_token_card( int $customer_id, stdClass $payment_token ): int { $wc_tokens = WC_Payment_Tokens::get_customer_tokens( $customer_id, CreditCardGateway::ID ); if ( $this->payment_token_helper->token_exist( $wc_tokens, $payment_token->id ) ) { - return; + return 0; } $token = new WC_Payment_Token_CC(); @@ -139,6 +141,8 @@ class WooCommercePaymentTokens { "Could not create WC payment token card for customer {$customer_id}. " . $exception->getMessage() ); } + $token->save(); + return $token->get_id(); } } diff --git a/modules/ppcp-wc-subscriptions/services.php b/modules/ppcp-wc-subscriptions/services.php index 47aaf1772..86599b3f2 100644 --- a/modules/ppcp-wc-subscriptions/services.php +++ b/modules/ppcp-wc-subscriptions/services.php @@ -9,10 +9,9 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\WcSubscriptions; -use WooCommerce\PayPalCommerce\PayPalSubscriptions\DeactivatePlanEndpoint; -use WooCommerce\PayPalCommerce\PayPalSubscriptions\SubscriptionsApiHandler; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; +use WooCommerce\PayPalCommerce\WcSubscriptions\Endpoint\SubscriptionChangePaymentMethod; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; return array( @@ -45,4 +44,9 @@ return array( $endpoint = $container->get( 'api.endpoint.payment-token' ); return new PaymentTokenRepository( $factory, $endpoint ); }, + 'wc-subscriptions.endpoint.subscription-change-payment-method' => static function( ContainerInterface $container ): SubscriptionChangePaymentMethod { + return new SubscriptionChangePaymentMethod( + $container->get( 'button.request-data' ) + ); + }, ); diff --git a/modules/ppcp-wc-subscriptions/src/Endpoint/SubscriptionChangePaymentMethod.php b/modules/ppcp-wc-subscriptions/src/Endpoint/SubscriptionChangePaymentMethod.php new file mode 100644 index 000000000..cb277e146 --- /dev/null +++ b/modules/ppcp-wc-subscriptions/src/Endpoint/SubscriptionChangePaymentMethod.php @@ -0,0 +1,75 @@ +request_data = $request_data; + } + + /** + * Returns the nonce. + * + * @return string + */ + public static function nonce(): string { + return self::ENDPOINT; + } + + /** + * Handles the request. + * + * @return bool + * @throws Exception On Error. + */ + public function handle_request(): bool { + try { + $data = $this->request_data->read_request( $this->nonce() ); + + $subscription = wcs_get_subscription( $data['subscription_id'] ); + $subscription->set_payment_method( $data['payment_method'] ); + + $wc_payment_token = WC_Payment_Tokens::get( $data['wc_payment_token_id'] ); + if ( $wc_payment_token ) { + $subscription->add_payment_token( $wc_payment_token ); + $subscription->save(); + } + + wp_send_json_success(); + return true; + } catch ( Exception $exception ) { + wp_send_json_error(); + return false; + } + } +} diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php index c8f0f99a6..1d86d8832 100644 --- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php +++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php @@ -23,6 +23,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; +use WooCommerce\PayPalCommerce\WcSubscriptions\Endpoint\SubscriptionChangePaymentMethod; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; /** @@ -169,6 +170,16 @@ class WcSubscriptionsModule implements ModuleInterface { return $methods; } ); + + add_action( + 'wc_ajax_' . SubscriptionChangePaymentMethod::ENDPOINT, + static function () use ( $c ) { + $endpoint = $c->get( 'wc-subscriptions.endpoint.subscription-change-payment-method' ); + assert( $endpoint instanceof SubscriptionChangePaymentMethod ); + + $endpoint->handle_request(); + } + ); } /**