From 2bf3c14feb33b1d6fabebb0d61d75f27b62fec15 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 3 Apr 2024 09:59:40 +0200 Subject: [PATCH 1/9] Do not execute current free trial flow if vault v3 enabled --- modules/ppcp-button/resources/js/button.js | 7 +++++- modules/ppcp-button/services.php | 1 + .../ppcp-button/src/Assets/SmartButton.php | 25 +++++++++++++------ .../resources/js/add-payment-method.js | 2 +- .../src/SavePaymentMethodsModule.php | 8 ++++++ modules/ppcp-vaulting/services.php | 3 +++ 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/modules/ppcp-button/resources/js/button.js b/modules/ppcp-button/resources/js/button.js index 0f5d573ce..d0e1a8543 100644 --- a/modules/ppcp-button/resources/js/button.js +++ b/modules/ppcp-button/resources/js/button.js @@ -137,7 +137,12 @@ const bootstrap = () => { } const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart; - if (isFreeTrial && data.fundingSource !== 'card' && ! PayPalCommerceGateway.subscription_plan_id) { + if ( + isFreeTrial + && data.fundingSource !== 'card' + && ! PayPalCommerceGateway.subscription_plan_id + && ! PayPalCommerceGateway.vault_v3_enabled + ) { freeTrialHandler.handle(); return actions.reject(); } diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index a812dc53e..13c130c2a 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -145,6 +145,7 @@ return array( $container->get( 'button.early-wc-checkout-validation-enabled' ), $container->get( 'button.pay-now-contexts' ), $container->get( 'wcgateway.funding-sources-without-redirect' ), + $container->get('vaulting.vault-v3-enabled'), $container->get( 'woocommerce.logger.woocommerce' ) ); }, diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index c33bdcf47..e2c64ac0c 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -184,13 +184,6 @@ class SmartButton implements SmartButtonInterface { */ private $funding_sources_without_redirect; - /** - * The logger. - * - * @var LoggerInterface - */ - private $logger; - /** * Session handler. * @@ -198,6 +191,20 @@ class SmartButton implements SmartButtonInterface { */ private $session_handler; + /** + * Whether Vault v3 module is enabled. + * + * @var bool + */ + private $vault_v3_enabled; + + /** + * The logger. + * + * @var LoggerInterface + */ + private $logger; + /** * SmartButton constructor. * @@ -220,6 +227,7 @@ class SmartButton implements SmartButtonInterface { * @param bool $early_validation_enabled Whether to execute WC validation of the checkout form. * @param array $pay_now_contexts The contexts that should have the Pay Now button. * @param string[] $funding_sources_without_redirect The sources that do not cause issues about redirecting (on mobile, ...) and sometimes not returning back. + * @param bool $vault_v3_enabled Whether Vault v3 module is enabled. * @param LoggerInterface $logger The logger. */ public function __construct( @@ -242,6 +250,7 @@ class SmartButton implements SmartButtonInterface { bool $early_validation_enabled, array $pay_now_contexts, array $funding_sources_without_redirect, + bool $vault_v3_enabled, LoggerInterface $logger ) { @@ -264,6 +273,7 @@ class SmartButton implements SmartButtonInterface { $this->early_validation_enabled = $early_validation_enabled; $this->pay_now_contexts = $pay_now_contexts; $this->funding_sources_without_redirect = $funding_sources_without_redirect; + $this->vault_v3_enabled = $vault_v3_enabled; $this->logger = $logger; } @@ -1063,6 +1073,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages ), 'cart_contains_subscription' => $this->subscription_helper->cart_contains_subscription(), 'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(), + 'vault_v3_enabled' => $this->vault_v3_enabled, 'variable_paypal_subscription_variations' => $this->subscription_helper->variable_paypal_subscription_variations(), 'subscription_product_allowed' => $this->subscription_helper->checkout_subscription_product_allowed(), 'locations_with_subscription_product' => $this->subscription_helper->locations_with_subscription_product(), 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 8aca64f7c..6178bd92c 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 @@ -12,7 +12,7 @@ import ErrorHandler from "../../../ppcp-button/resources/js/modules/ErrorHandler import {cardFieldStyles} from "../../../ppcp-button/resources/js/modules/Helper/CardFieldsHelper"; const errorHandler = new ErrorHandler( - PayPalCommerceGateway.labels.error.generic, + ppcp_add_payment_method.labels.error.generic, document.querySelector('.woocommerce-notices-wrapper') ); diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php index 59010f6ca..f93a75a66 100644 --- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php +++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php @@ -312,6 +312,14 @@ class SavePaymentMethodsModule implements ModuleInterface { 'nonce' => wp_create_nonce( SubscriptionChangePaymentMethod::nonce() ), ), ), + 'labels' => array( + 'error' => array( + 'generic' => __( + 'Something went wrong. Please try again or choose another payment source.', + 'woocommerce-paypal-payments' + ), + ) + ), ) ); } catch ( RuntimeException $exception ) { diff --git a/modules/ppcp-vaulting/services.php b/modules/ppcp-vaulting/services.php index 7d3c5e485..45355225d 100644 --- a/modules/ppcp-vaulting/services.php +++ b/modules/ppcp-vaulting/services.php @@ -64,4 +64,7 @@ return array( $container->get( 'woocommerce.logger.woocommerce' ) ); }, + 'vaulting.vault-v3-enabled' => static function( ContainerInterface $container ): bool { + return $container->has( 'save-payment-methods.eligible' ) && $container->get( 'save-payment-methods.eligible' ); + }, ); From bc0eb5746079ec31ca459196f025c79307694c08 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 4 Apr 2024 16:52:08 +0200 Subject: [PATCH 2/9] Do not create PayPal order for free trial subscription if user has payment token --- modules/ppcp-button/services.php | 3 +- .../ppcp-button/src/Assets/SmartButton.php | 24 +++++++++++++++- modules/ppcp-wc-gateway/services.php | 3 +- .../src/Gateway/PayPalGateway.php | 28 +++++++++++++++++-- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index 13c130c2a..6f781911b 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -145,7 +145,8 @@ return array( $container->get( 'button.early-wc-checkout-validation-enabled' ), $container->get( 'button.pay-now-contexts' ), $container->get( 'wcgateway.funding-sources-without-redirect' ), - $container->get('vaulting.vault-v3-enabled'), + $container->get( 'vaulting.vault-v3-enabled' ), + $container->get( 'api.endpoint.payment-tokens' ), $container->get( 'woocommerce.logger.woocommerce' ) ); }, diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 22ff4e208..605006d12 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use WC_Order; use WC_Product; use WC_Product_Variation; +use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\Money; use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken; use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory; @@ -198,6 +199,13 @@ class SmartButton implements SmartButtonInterface { */ private $vault_v3_enabled; + /** + * Payment tokens endpoint. + * + * @var PaymentTokensEndpoint + */ + private $payment_tokens_endpoint; + /** * The logger. * @@ -228,6 +236,7 @@ class SmartButton implements SmartButtonInterface { * @param array $pay_now_contexts The contexts that should have the Pay Now button. * @param string[] $funding_sources_without_redirect The sources that do not cause issues about redirecting (on mobile, ...) and sometimes not returning back. * @param bool $vault_v3_enabled Whether Vault v3 module is enabled. + * @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint. * @param LoggerInterface $logger The logger. */ public function __construct( @@ -251,6 +260,7 @@ class SmartButton implements SmartButtonInterface { array $pay_now_contexts, array $funding_sources_without_redirect, bool $vault_v3_enabled, + PaymentTokensEndpoint $payment_tokens_endpoint, LoggerInterface $logger ) { @@ -275,6 +285,7 @@ class SmartButton implements SmartButtonInterface { $this->funding_sources_without_redirect = $funding_sources_without_redirect; $this->vault_v3_enabled = $vault_v3_enabled; $this->logger = $logger; + $this->payment_tokens_endpoint = $payment_tokens_endpoint; } /** @@ -1915,8 +1926,18 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages */ private function get_vaulted_paypal_email(): string { try { - $tokens = $this->get_payment_tokens(); + $customer_id = get_user_meta( get_current_user_id(), '_ppcp_target_customer_id', true ); + if ( $customer_id ) { + $customer_tokens = $this->payment_tokens_endpoint->payment_tokens_for_customer( $customer_id ); + foreach ( $customer_tokens as $token ) { + $email_address = $token['payment_source']->properties()->email_address ?? ''; + if ( $email_address ) { + return $email_address; + } + } + } + $tokens = $this->get_payment_tokens(); foreach ( $tokens as $token ) { if ( isset( $token->source()->paypal ) ) { return $token->source()->paypal->payer->email_address; @@ -1925,6 +1946,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages } catch ( Exception $exception ) { $this->logger->error( 'Failed to get PayPal vaulted email. ' . $exception->getMessage() ); } + return ''; } diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 9802e1951..a78a6527e 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -103,7 +103,8 @@ return array( $api_shop_country, $container->get( 'api.endpoint.order' ), $container->get( 'api.factory.paypal-checkout-url' ), - $container->get( 'wcgateway.place-order-button-text' ) + $container->get( 'wcgateway.place-order-button-text' ), + $container->get( 'api.endpoint.payment-tokens' ) ); }, 'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway { diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index 19ebe9d08..14beda474 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use WC_Order; use WC_Payment_Tokens; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; +use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus; use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; @@ -179,6 +180,13 @@ class PayPalGateway extends \WC_Payment_Gateway { */ private $paypal_checkout_url_factory; + /** + * Payment tokens endpoint. + * + * @var PaymentTokensEndpoint + */ + private $payment_tokens_endpoint; + /** * PayPalGateway constructor. * @@ -199,6 +207,7 @@ class PayPalGateway extends \WC_Payment_Gateway { * @param OrderEndpoint $order_endpoint The order endpoint. * @param callable(string):string $paypal_checkout_url_factory The function return the PayPal checkout URL for the given order ID. * @param string $place_order_button_text The text for the standard "Place order" button. + * @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint. */ public function __construct( SettingsRenderer $settings_renderer, @@ -217,7 +226,8 @@ class PayPalGateway extends \WC_Payment_Gateway { string $api_shop_country, OrderEndpoint $order_endpoint, callable $paypal_checkout_url_factory, - string $place_order_button_text + string $place_order_button_text, + PaymentTokensEndpoint $payment_tokens_endpoint ) { $this->id = self::ID; $this->settings_renderer = $settings_renderer; @@ -300,7 +310,8 @@ class PayPalGateway extends \WC_Payment_Gateway { ) ); - $this->order_endpoint = $order_endpoint; + $this->order_endpoint = $order_endpoint; + $this->payment_tokens_endpoint = $payment_tokens_endpoint; } /** @@ -501,6 +512,18 @@ class PayPalGateway extends \WC_Payment_Gateway { } if ( 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) && ! $this->subscription_helper->paypal_subscription_id() ) { + $customer_id = get_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', true ); + if ( $customer_id ) { + $customer_tokens = $this->payment_tokens_endpoint->payment_tokens_for_customer( $customer_id ); + foreach ( $customer_tokens as $token ) { + $payment_source_name = $token['payment_source']->name() ?? ''; + if ( $payment_source_name === 'paypal' || $payment_source_name === 'venmo' ) { + $wc_order->payment_complete(); + return $this->handle_payment_success( $wc_order ); + } + } + } + $user_id = (int) $wc_order->get_customer_id(); $tokens = $this->payment_token_repository->all_for_user_id( $user_id ); if ( ! array_filter( @@ -513,7 +536,6 @@ class PayPalGateway extends \WC_Payment_Gateway { } $wc_order->payment_complete(); - return $this->handle_payment_success( $wc_order ); } From 457e9f0182d07a45e73f49040ac576694aa5d3e4 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Sat, 6 Apr 2024 17:31:57 +0200 Subject: [PATCH 3/9] Allow free trial subscription without payment token for logged-in users --- .../ActionHandler/CheckoutActionHandler.js | 49 +++++++++++++++++++ .../ContextBootstrap/CheckoutBootstap.js | 8 +++ .../ppcp-button/src/Assets/SmartButton.php | 10 ++++ .../tests/save-payment-methods.spec.js | 47 ++++++++++++++++++ 4 files changed, 114 insertions(+) diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js index 93ecf7c8f..f3afd4f30 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js @@ -144,6 +144,55 @@ class CheckoutActionHandler { } } } + + addPaymentMethodConfiguration() { + return { + createVaultSetupToken: async () => { + const response = await fetch(this.config.ajax.create_setup_token.endpoint, { + method: "POST", + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + nonce: this.config.ajax.create_setup_token.nonce, + }) + }); + + const result = await response.json() + if (result.data.id) { + return result.data.id + } + + console.error(result) + }, + onApprove: async ({vaultSetupToken}) => { + const response = await fetch(this.config.ajax.create_payment_token.endpoint, { + method: "POST", + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + nonce: this.config.ajax.create_payment_token.nonce, + vault_setup_token: vaultSetupToken, + return_url: location.href, + }) + }) + + const result = await response.json(); + if (result.success === true) { + window.location.href = location.href; + return; + } + + console.error(result) + }, + onError: (error) => { + console.error(error) + } + } + } } export default CheckoutActionHandler; diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js index e7fae33b0..26a278736 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js @@ -116,6 +116,14 @@ class CheckoutBootstap { return; } + if( + PayPalCommerceGateway.is_free_trial_cart + && PayPalCommerceGateway.vault_v3_enabled + ) { + this.renderer.render(actionHandler.addPaymentMethodConfiguration(), {}, actionHandler.configuration()); + return; + } + this.renderer.render(actionHandler.configuration(), {}, actionHandler.configuration()); } diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 605006d12..db703c7f1 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -34,6 +34,8 @@ use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait; use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply; use WooCommerce\PayPalCommerce\Onboarding\Environment; use WooCommerce\PayPalCommerce\PayLaterBlock\PayLaterBlockModule; +use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken; +use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; @@ -1091,6 +1093,14 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages 'cart_script_params' => array( 'endpoint' => \WC_AJAX::get_endpoint( CartScriptParamsEndpoint::ENDPOINT ), ), + 'create_setup_token' => array( + 'endpoint' => \WC_AJAX::get_endpoint( CreateSetupToken::ENDPOINT ), + 'nonce' => wp_create_nonce( CreateSetupToken::nonce() ), + ), + 'create_payment_token' => array( + 'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentToken::ENDPOINT ), + 'nonce' => wp_create_nonce( CreatePaymentToken::nonce() ), + ), ), 'cart_contains_subscription' => $this->subscription_helper->cart_contains_subscription(), 'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(), diff --git a/tests/Playwright/tests/save-payment-methods.spec.js b/tests/Playwright/tests/save-payment-methods.spec.js index 4648eebca..f6fb46315 100644 --- a/tests/Playwright/tests/save-payment-methods.spec.js +++ b/tests/Playwright/tests/save-payment-methods.spec.js @@ -37,6 +37,53 @@ test('Save during purchase', async ({page}) => { await expectOrderReceivedPage(page); }); +test('PayPal add payment method', async ({page}) => { + await loginAsCustomer(page); + await page.goto('/my-account/add-payment-method'); + + const popup = await openPaypalPopup(page); + await loginIntoPaypal(popup); + popup.locator('#consentButton').click(); + + await page.waitForURL('/my-account/payment-methods'); +}); + +test('ACDC add payment method', async ({page}) => { + await loginAsCustomer(page); + await page.goto('/my-account/add-payment-method'); + + await page.click("text=Debit & Credit Cards"); + + const creditCardNumber = await page.frameLocator('[title="paypal_card_number_field"]').locator('.card-field-number'); + await creditCardNumber.fill('4005519200000004'); + + const expirationDate = await page.frameLocator('[title="paypal_card_expiry_field"]').locator('.card-field-expiry'); + await expirationDate.fill('01/25'); + + const cvv = await page.frameLocator('[title="paypal_card_cvv_field"]').locator('.card-field-cvv'); + await cvv.fill('123'); + + await page.waitForURL('/my-account/payment-methods'); +}); + +test('PayPal logged-in user free trial subscription without payment token', async ({page}) => { + await loginAsCustomer(page); + + await page.goto('/shop'); + await page.click("text=Sign up now"); + await page.goto('/classic-checkout'); + + const popup = await openPaypalPopup(page); + await loginIntoPaypal(popup); + popup.locator('#consentButton').click(); + + await page.click("text=Proceed to PayPal"); + + const title = await page.locator('.entry-title'); + await expect(title).toHaveText('Order received'); +}) + + From efc20c390d51eac93dd49d5061b3065963cd24dd Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 8 Apr 2024 13:38:18 +0200 Subject: [PATCH 4/9] Rename method --- .../src/Endpoint/PaymentMethodTokensEndpoint.php | 2 +- .../src/Endpoint/CreatePaymentToken.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php b/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php index ab8d5473b..1b547a11e 100644 --- a/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php +++ b/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php @@ -115,7 +115,7 @@ class PaymentMethodTokensEndpoint { * @throws RuntimeException When something when wrong with the request. * @throws PayPalApiException When something when wrong setting up the token. */ - public function payment_tokens( PaymentSource $payment_source ): stdClass { + public function create_payment_token(PaymentSource $payment_source ): stdClass { $data = array( 'payment_source' => array( $payment_source->name() => $payment_source->properties(), diff --git a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php index ca4839372..4fea1f188 100644 --- a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php +++ b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php @@ -94,7 +94,7 @@ class CreatePaymentToken implements EndpointInterface { ) ); - $result = $this->payment_method_tokens_endpoint->payment_tokens( $payment_source ); + $result = $this->payment_method_tokens_endpoint->create_payment_token( $payment_source ); if ( is_user_logged_in() && isset( $result->customer->id ) ) { $current_user_id = get_current_user_id(); From 636541c6c1e2ac292d32deeb094b0f8dbd463b4f Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 9 Apr 2024 11:10:40 +0200 Subject: [PATCH 5/9] Inject vault v3 enabled service into PayPal gateway --- modules/ppcp-wc-gateway/services.php | 3 ++- .../src/Gateway/PayPalGateway.php | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index a78a6527e..83c55ae1a 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -104,7 +104,8 @@ return array( $container->get( 'api.endpoint.order' ), $container->get( 'api.factory.paypal-checkout-url' ), $container->get( 'wcgateway.place-order-button-text' ), - $container->get( 'api.endpoint.payment-tokens' ) + $container->get( 'api.endpoint.payment-tokens' ), + $container->get( 'vaulting.vault-v3-enabled' ) ); }, 'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway { diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index 14beda474..d341000dd 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -187,6 +187,13 @@ class PayPalGateway extends \WC_Payment_Gateway { */ private $payment_tokens_endpoint; + /** + * Whether Vault v3 module is enabled. + * + * @var bool + */ + private $vault_v3_enabled; + /** * PayPalGateway constructor. * @@ -208,6 +215,7 @@ class PayPalGateway extends \WC_Payment_Gateway { * @param callable(string):string $paypal_checkout_url_factory The function return the PayPal checkout URL for the given order ID. * @param string $place_order_button_text The text for the standard "Place order" button. * @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint. + * @param bool $vault_v3_enabled Whether Vault v3 module is enabled. */ public function __construct( SettingsRenderer $settings_renderer, @@ -227,7 +235,8 @@ class PayPalGateway extends \WC_Payment_Gateway { OrderEndpoint $order_endpoint, callable $paypal_checkout_url_factory, string $place_order_button_text, - PaymentTokensEndpoint $payment_tokens_endpoint + PaymentTokensEndpoint $payment_tokens_endpoint, + bool $vault_v3_enabled ) { $this->id = self::ID; $this->settings_renderer = $settings_renderer; @@ -247,6 +256,9 @@ class PayPalGateway extends \WC_Payment_Gateway { $this->api_shop_country = $api_shop_country; $this->paypal_checkout_url_factory = $paypal_checkout_url_factory; $this->order_button_text = $place_order_button_text; + $this->order_endpoint = $order_endpoint; + $this->payment_tokens_endpoint = $payment_tokens_endpoint; + $this->vault_v3_enabled = $vault_v3_enabled; if ( $this->onboarded ) { $this->supports = array( 'refunds', 'tokenization' ); @@ -309,9 +321,6 @@ class PayPalGateway extends \WC_Payment_Gateway { 'process_admin_options', ) ); - - $this->order_endpoint = $order_endpoint; - $this->payment_tokens_endpoint = $payment_tokens_endpoint; } /** From 197e70607a6ffcb620b9688ed74d377bd80425c6 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 9 Apr 2024 17:34:51 +0200 Subject: [PATCH 6/9] Add payment token for guest free trial subscription (WIP) --- .../ActionHandler/CheckoutActionHandler.js | 7 +- .../ppcp-button/src/Assets/SmartButton.php | 5 ++ .../ppcp-save-payment-methods/services.php | 7 ++ .../Endpoint/CreatePaymentTokenForGuest.php | 90 +++++++++++++++++++ .../src/SavePaymentMethodsModule.php | 11 +++ modules/ppcp-wc-gateway/services.php | 3 +- .../src/Gateway/PayPalGateway.php | 45 +++++++++- 7 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentTokenForGuest.php diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js index f3afd4f30..ed5926816 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler.js @@ -167,22 +167,21 @@ class CheckoutActionHandler { console.error(result) }, onApprove: async ({vaultSetupToken}) => { - const response = await fetch(this.config.ajax.create_payment_token.endpoint, { + const response = await fetch(this.config.ajax.create_payment_token_for_guest.endpoint, { method: "POST", credentials: 'same-origin', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ - nonce: this.config.ajax.create_payment_token.nonce, + nonce: this.config.ajax.create_payment_token_for_guest.nonce, vault_setup_token: vaultSetupToken, - return_url: location.href, }) }) const result = await response.json(); if (result.success === true) { - window.location.href = location.href; + document.querySelector('#place_order').click() return; } diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index db703c7f1..6f73e6d88 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -36,6 +36,7 @@ use WooCommerce\PayPalCommerce\Onboarding\Environment; use WooCommerce\PayPalCommerce\PayLaterBlock\PayLaterBlockModule; use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken; use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken; +use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; @@ -1101,6 +1102,10 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages 'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentToken::ENDPOINT ), 'nonce' => wp_create_nonce( CreatePaymentToken::nonce() ), ), + 'create_payment_token_for_guest' => array( + 'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentTokenForGuest::ENDPOINT ), + 'nonce' => wp_create_nonce( CreatePaymentTokenForGuest::nonce() ), + ), ), 'cart_contains_subscription' => $this->subscription_helper->cart_contains_subscription(), 'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(), diff --git a/modules/ppcp-save-payment-methods/services.php b/modules/ppcp-save-payment-methods/services.php index 2453235c8..a0b43f021 100644 --- a/modules/ppcp-save-payment-methods/services.php +++ b/modules/ppcp-save-payment-methods/services.php @@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\SavePaymentMethods; use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken; use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken; +use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest; use WooCommerce\PayPalCommerce\SavePaymentMethods\Helper\SavePaymentMethodsApplies; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; @@ -811,4 +812,10 @@ return array( $container->get( 'vaulting.wc-payment-tokens' ) ); }, + 'save-payment-methods.endpoint.create-payment-token-for-guest' => static function ( ContainerInterface $container ): CreatePaymentTokenForGuest { + return new CreatePaymentTokenForGuest( + $container->get( 'button.request-data' ), + $container->get( 'api.endpoint.payment-method-tokens' ) + ); + }, ); diff --git a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentTokenForGuest.php b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentTokenForGuest.php new file mode 100644 index 000000000..e458c96be --- /dev/null +++ b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentTokenForGuest.php @@ -0,0 +1,90 @@ +request_data = $request_data; + $this->payment_method_tokens_endpoint = $payment_method_tokens_endpoint; + } + + /** + * 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 { + $data = $this->request_data->read_request( $this->nonce() ); + + /** + * Suppress ArgumentTypeCoercion + * + * @psalm-suppress ArgumentTypeCoercion + */ + $payment_source = new PaymentSource( + 'token', + (object) array( + 'id' => $data['vault_setup_token'], + 'type' => 'SETUP_TOKEN', + ) + ); + + $result = $this->payment_method_tokens_endpoint->create_payment_token( $payment_source ); + WC()->session->set( 'ppcp_guest_payment_for_free_trial', $result ); + + wp_send_json_success(); + return true; + } +} diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php index 61244b2e2..8daafae4a 100644 --- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php +++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php @@ -20,6 +20,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait; use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken; +use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest; use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken; use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens; use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider; @@ -371,6 +372,16 @@ class SavePaymentMethodsModule implements ModuleInterface { } ); + add_action( + 'wc_ajax_' . CreatePaymentTokenForGuest::ENDPOINT, + static function () use ( $c ) { + $endpoint = $c->get( 'save-payment-methods.endpoint.create-payment-token-for-guest' ); + assert( $endpoint instanceof CreatePaymentTokenForGuest ); + + $endpoint->handle_request(); + } + ); + add_action( 'woocommerce_paypal_payments_before_delete_payment_token', function( string $token_id ) use ( $c ) { diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 83c55ae1a..6bf3d5ecf 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -105,7 +105,8 @@ return array( $container->get( 'api.factory.paypal-checkout-url' ), $container->get( 'wcgateway.place-order-button-text' ), $container->get( 'api.endpoint.payment-tokens' ), - $container->get( 'vaulting.vault-v3-enabled' ) + $container->get( 'vaulting.vault-v3-enabled' ), + $container->get( 'vaulting.wc-payment-tokens' ) ); }, 'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway { diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index d341000dd..20b7a840d 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -21,6 +21,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\Onboarding\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Session\SessionHandler; +use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens; use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; @@ -194,6 +195,13 @@ class PayPalGateway extends \WC_Payment_Gateway { */ private $vault_v3_enabled; + /** + * WooCommerce payment tokens. + * + * @var WooCommercePaymentTokens + */ + private $wc_payment_tokens; + /** * PayPalGateway constructor. * @@ -216,6 +224,7 @@ class PayPalGateway extends \WC_Payment_Gateway { * @param string $place_order_button_text The text for the standard "Place order" button. * @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint. * @param bool $vault_v3_enabled Whether Vault v3 module is enabled. + * @param WooCommercePaymentTokens $wc_payment_tokens WooCommerce payment tokens. */ public function __construct( SettingsRenderer $settings_renderer, @@ -236,7 +245,8 @@ class PayPalGateway extends \WC_Payment_Gateway { callable $paypal_checkout_url_factory, string $place_order_button_text, PaymentTokensEndpoint $payment_tokens_endpoint, - bool $vault_v3_enabled + bool $vault_v3_enabled, + WooCommercePaymentTokens $wc_payment_tokens ) { $this->id = self::ID; $this->settings_renderer = $settings_renderer; @@ -259,6 +269,7 @@ class PayPalGateway extends \WC_Payment_Gateway { $this->order_endpoint = $order_endpoint; $this->payment_tokens_endpoint = $payment_tokens_endpoint; $this->vault_v3_enabled = $vault_v3_enabled; + $this->wc_payment_tokens = $wc_payment_tokens; if ( $this->onboarded ) { $this->supports = array( 'refunds', 'tokenization' ); @@ -520,7 +531,37 @@ class PayPalGateway extends \WC_Payment_Gateway { $wc_order->save(); } - if ( 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) && ! $this->subscription_helper->paypal_subscription_id() ) { + if ( + 'card' !== $funding_source + && $this->is_free_trial_order( $wc_order ) + && ! $this->subscription_helper->paypal_subscription_id() + ) { + $ppcp_guest_payment_for_free_trial = WC()->session->get( 'ppcp_guest_payment_for_free_trial') ?? null; + if($this->vault_v3_enabled && $ppcp_guest_payment_for_free_trial) { + $customer_id = $ppcp_guest_payment_for_free_trial->customer->id ?? ''; + if($customer_id) { + update_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', $customer_id ); + } + + if ( isset( $ppcp_guest_payment_for_free_trial->payment_source->paypal ) ) { + $email = ''; + if ( isset( $ppcp_guest_payment_for_free_trial->payment_source->paypal->email_address ) ) { + $email = $ppcp_guest_payment_for_free_trial->payment_source->paypal->email_address; + } + + $this->wc_payment_tokens->create_payment_token_paypal( + $wc_order->get_customer_id(), + $ppcp_guest_payment_for_free_trial->id, + $email + ); + } + + WC()->session->set( 'ppcp_guest_payment_for_free_trial', null); + + $wc_order->payment_complete(); + return $this->handle_payment_success( $wc_order ); + } + $customer_id = get_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', true ); if ( $customer_id ) { $customer_tokens = $this->payment_tokens_endpoint->payment_tokens_for_customer( $customer_id ); From 93f74aac92aa3373a7280c07994ac167ab5531e5 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 10 Apr 2024 16:13:44 +0200 Subject: [PATCH 7/9] Ensure free trial with saved card payment does not create PayPal order --- .../src/Gateway/CreditCardGateway.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php index 4032869d1..6e21e70df 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php @@ -33,6 +33,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait; use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor; use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait; use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer; +use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; /** @@ -40,7 +41,7 @@ use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; */ class CreditCardGateway extends \WC_Payment_Gateway_CC { - use ProcessPaymentTrait, GatewaySettingsRendererTrait, TransactionIdHandlingTrait, PaymentsStatusHandlingTrait; + use ProcessPaymentTrait, GatewaySettingsRendererTrait, TransactionIdHandlingTrait, PaymentsStatusHandlingTrait, FreeTrialHandlerTrait; const ID = 'ppcp-credit-card-gateway'; @@ -454,6 +455,17 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC { // phpcs:ignore WordPress.Security.NonceVerification.Missing $card_payment_token_id = wc_clean( wp_unslash( $_POST['wc-ppcp-credit-card-gateway-payment-token'] ?? '' ) ); + + if ( $this->is_free_trial_order( $wc_order ) && $card_payment_token_id ) { + $customer_tokens = $this->wc_payment_tokens->customer_tokens( get_current_user_id() ); + foreach ( $customer_tokens as $token ) { + if ( $token['payment_source']->name() === 'card' ) { + $wc_order->payment_complete(); + return $this->handle_payment_success( $wc_order ); + } + } + } + if ( $card_payment_token_id ) { $customer_tokens = $this->wc_payment_tokens->customer_tokens( get_current_user_id() ); From dd53229e8d545141dbfde5f18892355f89c9474b Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 10 Apr 2024 16:36:41 +0200 Subject: [PATCH 8/9] Fix phpunit --- tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php b/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php index 5239af7dc..041141492 100644 --- a/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php +++ b/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php @@ -6,11 +6,13 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway; use Exception; use Psr\Log\LoggerInterface; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; +use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus; use WooCommerce\PayPalCommerce\Onboarding\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Session\SessionHandler; +use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\TestCase; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; @@ -44,6 +46,9 @@ class WcGatewayTest extends TestCase private $logger; private $apiShopCountry; private $orderEndpoint; + private $paymentTokensEndpoint; + private $vaultV3Enabled; + private $wcPaymentTokens; public function setUp(): void { parent::setUp(); @@ -88,6 +93,10 @@ class WcGatewayTest extends TestCase $this->logger->shouldReceive('info'); $this->logger->shouldReceive('error'); + + $this->paymentTokensEndpoint = Mockery::mock(PaymentTokensEndpoint::class); + $this->vaultV3Enabled = true; + $this->wcPaymentTokens = Mockery::mock(WooCommercePaymentTokens::class); } private function createGateway() @@ -111,7 +120,10 @@ class WcGatewayTest extends TestCase function ($id) { return 'checkoutnow=' . $id; }, - 'Pay via PayPal' + 'Pay via PayPal', + $this->paymentTokensEndpoint, + $this->vaultV3Enabled, + $this->wcPaymentTokens ); } From bd9f80f82f4316fe0bf5a413fa0396a9870717f0 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 10 Apr 2024 17:05:33 +0200 Subject: [PATCH 9/9] Fix phpcs --- .../Endpoint/PaymentMethodTokensEndpoint.php | 2 +- .../ppcp-button/src/Assets/SmartButton.php | 22 ++++---- .../src/SavePaymentMethodsModule.php | 4 +- .../src/Gateway/PayPalGateway.php | 54 +++++++++---------- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php b/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php index 1b547a11e..538ca224d 100644 --- a/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php +++ b/modules/ppcp-api-client/src/Endpoint/PaymentMethodTokensEndpoint.php @@ -115,7 +115,7 @@ class PaymentMethodTokensEndpoint { * @throws RuntimeException When something when wrong with the request. * @throws PayPalApiException When something when wrong setting up the token. */ - public function create_payment_token(PaymentSource $payment_source ): stdClass { + public function create_payment_token( PaymentSource $payment_source ): stdClass { $data = array( 'payment_source' => array( $payment_source->name() => $payment_source->properties(), diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 6f73e6d88..d795d4950 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -1059,46 +1059,46 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages 'redirect' => wc_get_checkout_url(), 'context' => $this->context(), 'ajax' => array( - 'simulate_cart' => array( + 'simulate_cart' => array( 'endpoint' => \WC_AJAX::get_endpoint( SimulateCartEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( SimulateCartEndpoint::nonce() ), ), - 'change_cart' => array( + 'change_cart' => array( 'endpoint' => \WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( ChangeCartEndpoint::nonce() ), ), - 'create_order' => array( + 'create_order' => array( 'endpoint' => \WC_AJAX::get_endpoint( CreateOrderEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( CreateOrderEndpoint::nonce() ), ), - 'approve_order' => array( + 'approve_order' => array( 'endpoint' => \WC_AJAX::get_endpoint( ApproveOrderEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( ApproveOrderEndpoint::nonce() ), ), - 'approve_subscription' => array( + 'approve_subscription' => array( 'endpoint' => \WC_AJAX::get_endpoint( ApproveSubscriptionEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( ApproveSubscriptionEndpoint::nonce() ), ), - 'vault_paypal' => array( + 'vault_paypal' => array( 'endpoint' => \WC_AJAX::get_endpoint( StartPayPalVaultingEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( StartPayPalVaultingEndpoint::nonce() ), ), - 'save_checkout_form' => array( + 'save_checkout_form' => array( 'endpoint' => \WC_AJAX::get_endpoint( SaveCheckoutFormEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( SaveCheckoutFormEndpoint::nonce() ), ), - 'validate_checkout' => array( + 'validate_checkout' => array( 'endpoint' => \WC_AJAX::get_endpoint( ValidateCheckoutEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( ValidateCheckoutEndpoint::nonce() ), ), - 'cart_script_params' => array( + 'cart_script_params' => array( 'endpoint' => \WC_AJAX::get_endpoint( CartScriptParamsEndpoint::ENDPOINT ), ), - 'create_setup_token' => array( + 'create_setup_token' => array( 'endpoint' => \WC_AJAX::get_endpoint( CreateSetupToken::ENDPOINT ), 'nonce' => wp_create_nonce( CreateSetupToken::nonce() ), ), - 'create_payment_token' => array( + 'create_payment_token' => array( 'endpoint' => \WC_AJAX::get_endpoint( CreatePaymentToken::ENDPOINT ), 'nonce' => wp_create_nonce( CreatePaymentToken::nonce() ), ), diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php index 8daafae4a..b667fb10b 100644 --- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php +++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php @@ -317,13 +317,13 @@ class SavePaymentMethodsModule implements ModuleInterface { 'nonce' => wp_create_nonce( SubscriptionChangePaymentMethod::nonce() ), ), ), - 'labels' => array( + 'labels' => array( 'error' => array( 'generic' => __( 'Something went wrong. Please try again or choose another payment source.', 'woocommerce-paypal-payments' ), - ) + ), ), ) ); diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index 20b7a840d..8ac87156f 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -205,25 +205,25 @@ class PayPalGateway extends \WC_Payment_Gateway { /** * PayPalGateway constructor. * - * @param SettingsRenderer $settings_renderer The Settings Renderer. - * @param FundingSourceRenderer $funding_source_renderer The funding source renderer. - * @param OrderProcessor $order_processor The Order Processor. - * @param ContainerInterface $config The settings. - * @param SessionHandler $session_handler The Session Handler. - * @param RefundProcessor $refund_processor The Refund Processor. - * @param State $state The state. - * @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order. - * @param SubscriptionHelper $subscription_helper The subscription helper. - * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page. - * @param Environment $environment The environment. - * @param PaymentTokenRepository $payment_token_repository The payment token repository. - * @param LoggerInterface $logger The logger. - * @param string $api_shop_country The api shop country. - * @param OrderEndpoint $order_endpoint The order endpoint. - * @param callable(string):string $paypal_checkout_url_factory The function return the PayPal checkout URL for the given order ID. - * @param string $place_order_button_text The text for the standard "Place order" button. - * @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint. - * @param bool $vault_v3_enabled Whether Vault v3 module is enabled. + * @param SettingsRenderer $settings_renderer The Settings Renderer. + * @param FundingSourceRenderer $funding_source_renderer The funding source renderer. + * @param OrderProcessor $order_processor The Order Processor. + * @param ContainerInterface $config The settings. + * @param SessionHandler $session_handler The Session Handler. + * @param RefundProcessor $refund_processor The Refund Processor. + * @param State $state The state. + * @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order. + * @param SubscriptionHelper $subscription_helper The subscription helper. + * @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page. + * @param Environment $environment The environment. + * @param PaymentTokenRepository $payment_token_repository The payment token repository. + * @param LoggerInterface $logger The logger. + * @param string $api_shop_country The api shop country. + * @param OrderEndpoint $order_endpoint The order endpoint. + * @param callable(string):string $paypal_checkout_url_factory The function return the PayPal checkout URL for the given order ID. + * @param string $place_order_button_text The text for the standard "Place order" button. + * @param PaymentTokensEndpoint $payment_tokens_endpoint Payment tokens endpoint. + * @param bool $vault_v3_enabled Whether Vault v3 module is enabled. * @param WooCommercePaymentTokens $wc_payment_tokens WooCommerce payment tokens. */ public function __construct( @@ -266,10 +266,10 @@ class PayPalGateway extends \WC_Payment_Gateway { $this->api_shop_country = $api_shop_country; $this->paypal_checkout_url_factory = $paypal_checkout_url_factory; $this->order_button_text = $place_order_button_text; - $this->order_endpoint = $order_endpoint; - $this->payment_tokens_endpoint = $payment_tokens_endpoint; - $this->vault_v3_enabled = $vault_v3_enabled; - $this->wc_payment_tokens = $wc_payment_tokens; + $this->order_endpoint = $order_endpoint; + $this->payment_tokens_endpoint = $payment_tokens_endpoint; + $this->vault_v3_enabled = $vault_v3_enabled; + $this->wc_payment_tokens = $wc_payment_tokens; if ( $this->onboarded ) { $this->supports = array( 'refunds', 'tokenization' ); @@ -536,10 +536,10 @@ class PayPalGateway extends \WC_Payment_Gateway { && $this->is_free_trial_order( $wc_order ) && ! $this->subscription_helper->paypal_subscription_id() ) { - $ppcp_guest_payment_for_free_trial = WC()->session->get( 'ppcp_guest_payment_for_free_trial') ?? null; - if($this->vault_v3_enabled && $ppcp_guest_payment_for_free_trial) { + $ppcp_guest_payment_for_free_trial = WC()->session->get( 'ppcp_guest_payment_for_free_trial' ) ?? null; + if ( $this->vault_v3_enabled && $ppcp_guest_payment_for_free_trial ) { $customer_id = $ppcp_guest_payment_for_free_trial->customer->id ?? ''; - if($customer_id) { + if ( $customer_id ) { update_user_meta( $wc_order->get_customer_id(), '_ppcp_target_customer_id', $customer_id ); } @@ -556,7 +556,7 @@ class PayPalGateway extends \WC_Payment_Gateway { ); } - WC()->session->set( 'ppcp_guest_payment_for_free_trial', null); + WC()->session->set( 'ppcp_guest_payment_for_free_trial', null ); $wc_order->payment_complete(); return $this->handle_payment_success( $wc_order );