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'); +}) + +