From f75846952ddb0ac1857a7d37073a1d59be7807cf Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Wed, 3 Jan 2024 15:44:24 +0100
Subject: [PATCH 01/14] Change subscription payment method (WIP)
---
.../src/VaultedCreditCardHandler.php | 13 -----
.../src/Gateway/CreditCardGateway.php | 32 +++++++++++-
.../src/RenewalHandler.php | 49 +++++++++++++++--
.../src/WcSubscriptionsModule.php | 52 +++++++++++++------
4 files changed, 110 insertions(+), 36 deletions(-)
diff --git a/modules/ppcp-vaulting/src/VaultedCreditCardHandler.php b/modules/ppcp-vaulting/src/VaultedCreditCardHandler.php
index 59e60b912..3261e4b8e 100644
--- a/modules/ppcp-vaulting/src/VaultedCreditCardHandler.php
+++ b/modules/ppcp-vaulting/src/VaultedCreditCardHandler.php
@@ -143,19 +143,6 @@ class VaultedCreditCardHandler {
string $saved_credit_card,
WC_Order $wc_order
): WC_Order {
- if (
- // phpcs:ignore WordPress.Security.NonceVerification.Missing
- isset( $_POST['woocommerce_change_payment'] )
- && $this->subscription_helper->has_subscription( $wc_order->get_id() )
- && $this->subscription_helper->is_subscription_change_payment()
- && $saved_credit_card
- ) {
- $wc_order->update_meta_data( 'payment_token_id', $saved_credit_card );
- $wc_order->save();
-
- return $wc_order;
- }
-
$tokens = $this->payment_token_repository->all_for_user_id( $wc_order->get_customer_id() );
$selected_token = null;
foreach ( $tokens as $token ) {
diff --git a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php
index 5b35aef1a..aaa92abdb 100644
--- a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php
+++ b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php
@@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
use Exception;
use Psr\Log\LoggerInterface;
use WC_Order;
+use WC_Payment_Tokens;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
@@ -377,11 +378,11 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
}
/**
- * If customer has chosen a saved credit card payment.
+ * If customer has chosen a saved credit card payment from checkout page.
*/
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$saved_credit_card = wc_clean( wp_unslash( $_POST['saved_credit_card'] ?? '' ) );
- if ( $saved_credit_card ) {
+ if ( $saved_credit_card && is_checkout() ) {
try {
$wc_order = $this->vaulted_credit_card_handler->handle_payment(
$saved_credit_card,
@@ -395,6 +396,33 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
}
}
+ /**
+ * If customer is changing subscription payment.
+ */
+ if (
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ isset( $_POST['woocommerce_change_payment'] )
+ && $this->subscription_helper->has_subscription( $wc_order->get_id() )
+ && $this->subscription_helper->is_subscription_change_payment()
+ && $saved_credit_card
+ ) {
+ $payment_token = WC_Payment_Tokens::get($saved_credit_card);
+ if($payment_token) {
+ $wc_order->add_payment_token($payment_token);
+ $wc_order->save();
+
+ return $this->handle_payment_success( $wc_order );
+ }
+
+ wc_add_notice( __( 'Could not change payment.', 'woocommerce-paypal-payments' ), 'error' );
+
+ return array(
+ 'result' => 'failure',
+ 'redirect' => wc_get_checkout_url(),
+ 'errorMessage' => __( 'Could not change payment.', 'woocommerce-paypal-payments' ),
+ );
+ }
+
/**
* If the WC_Order is paid through the approved webhook.
*/
diff --git a/modules/ppcp-wc-subscriptions/src/RenewalHandler.php b/modules/ppcp-wc-subscriptions/src/RenewalHandler.php
index 7440074f9..adee662f2 100644
--- a/modules/ppcp-wc-subscriptions/src/RenewalHandler.php
+++ b/modules/ppcp-wc-subscriptions/src/RenewalHandler.php
@@ -9,6 +9,9 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcSubscriptions;
+use WC_Customer;
+use WC_Order;
+use WC_Payment_Tokens;
use WC_Subscription;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
@@ -194,8 +197,8 @@ class RenewalHandler {
'renewal'
);
- $token = $this->get_token_for_customer( $customer, $wc_order );
- if ( $token ) {
+ $token_id = $this->token_id( $wc_order, $customer );
+ if ( $token_id ) {
if ( $wc_order->get_payment_method() === CreditCardGateway::ID ) {
$stored_credentials = array(
'payment_initiator' => 'MERCHANT',
@@ -215,7 +218,7 @@ class RenewalHandler {
$payment_source = new PaymentSource(
'card',
(object) array(
- 'vault_id' => $token->id(),
+ 'vault_id' => $token_id,
'stored_credential' => $stored_credentials,
)
);
@@ -244,11 +247,23 @@ class RenewalHandler {
return;
}
+ $payment_source = new PaymentSource(
+ 'paypal',
+ (object) array(
+ 'vault_id' => $token_id,
+ )
+ );
+
$order = $this->order_endpoint->create(
array( $purchase_unit ),
$shipping_preference,
$payer,
- $token
+ null,
+ '',
+ ApplicationContext::USER_ACTION_CONTINUE,
+ '',
+ array(),
+ $payment_source
);
$this->handle_paypal_order( $wc_order, $order );
@@ -399,4 +414,30 @@ class RenewalHandler {
$this->authorized_payments_processor->capture_authorized_payment( $wc_order );
}
}
+
+ /**
+ * Returns a payment token id for the given order or customer.
+ *
+ * @param WC_Order $wc_order WC order.
+ * @param WC_Customer $customer WC customer.
+ * @return string
+ */
+ private function token_id( WC_Order $wc_order, WC_Customer $customer ): string {
+ $token_id = '';
+
+ $tokens = $wc_order->get_payment_tokens();
+ if ( $tokens ) {
+ $token = WC_Payment_Tokens::get( $tokens[0] );
+ if ( $token ) {
+ $token_id = $token->get_token();
+ }
+ }
+
+ if ( ! $token_id ) {
+ $token = $this->get_token_for_customer( $customer, $wc_order );
+ $token_id = $token->id();
+ }
+
+ return $token_id;
+ }
}
diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
index c5fb04541..393a7ef8f 100644
--- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
+++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
@@ -11,7 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcSubscriptions;
use Psr\Log\LoggerInterface;
use WC_Order;
-use WC_Subscription;
+use WC_Payment_Tokens;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
@@ -115,6 +115,10 @@ class WcSubscriptionsModule implements ModuleInterface {
* @psalm-suppress MissingClosureParamType
*/
function ( $description, $id ) use ( $c ) {
+ if ( $c->has( 'save-payment-methods.eligible' ) && $c->get( 'save-payment-methods.eligible' ) ) {
+ return $description;
+ }
+
$payment_token_repository = $c->get( 'vaulting.repository.payment-token' );
$settings = $c->get( 'wcgateway.settings' );
$subscription_helper = $c->get( 'wc-subscriptions.helper' );
@@ -133,6 +137,10 @@ class WcSubscriptionsModule implements ModuleInterface {
* @psalm-suppress MissingClosureParamType
*/
function ( $default_fields, $id ) use ( $c ) {
+ if ( $c->has( 'save-payment-methods.eligible' ) && $c->get( 'save-payment-methods.eligible' ) ) {
+ return $default_fields;
+ }
+
$payment_token_repository = $c->get( 'vaulting.repository.payment-token' );
$settings = $c->get( 'wcgateway.settings' );
$subscription_helper = $c->get( 'wc-subscriptions.helper' );
@@ -142,6 +150,27 @@ class WcSubscriptionsModule implements ModuleInterface {
20,
2
);
+
+ add_filter(
+ 'woocommerce_available_payment_gateways',
+ function( array $methods ): array {
+ if ( ! is_wc_endpoint_url( 'order-pay' ) ) {
+ return $methods;
+ }
+
+ $paypal_tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), PayPalGateway::ID );
+ if ( ! $paypal_tokens ) {
+ unset( $methods[ PayPalGateway::ID ] );
+ }
+
+ $card_tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), CreditCardGateway::ID );
+ if ( ! $card_tokens ) {
+ unset( $methods[ CreditCardGateway::ID ] );
+ }
+
+ return $methods;
+ }
+ );
}
/**
@@ -269,35 +298,24 @@ class WcSubscriptionsModule implements ModuleInterface {
array $default_fields,
SubscriptionHelper $subscription_helper
) {
-
if ( $settings->has( 'vault_enabled_dcc' )
&& $settings->get( 'vault_enabled_dcc' )
&& $subscription_helper->is_subscription_change_payment()
&& CreditCardGateway::ID === $id
) {
- $tokens = $payment_token_repository->all_for_user_id( get_current_user_id() );
- if ( ! $tokens || ! $payment_token_repository->tokens_contains_card( $tokens ) ) {
- $default_fields = array();
- $default_fields['saved-credit-card'] = esc_html__(
- 'No Credit Card saved, in order to use a saved Credit Card you first need to create it through a purchase.',
- 'woocommerce-paypal-payments'
- );
- return $default_fields;
- }
-
+ $tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), CreditCardGateway::ID );
$output = sprintf(
'';
From e23f50a5f3085bc87c09e4b9eb1abc433da7f0e2 Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Wed, 3 Jan 2024 16:57:23 +0100
Subject: [PATCH 02/14] Add change subscription payment for PayPal payment
---
.../src/Gateway/PayPalGateway.php | 19 ++++++++++---
.../src/RenewalHandler.php | 8 +++---
.../src/WcSubscriptionsModule.php | 27 +++++++------------
3 files changed, 29 insertions(+), 25 deletions(-)
diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php
index 741436c22..4c4bc4671 100644
--- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php
+++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php
@@ -12,11 +12,11 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
use Exception;
use Psr\Log\LoggerInterface;
use WC_Order;
+use WC_Payment_Tokens;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
-use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
@@ -522,10 +522,21 @@ class PayPalGateway extends \WC_Payment_Gateway {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$saved_paypal_payment = wc_clean( wp_unslash( $_POST['saved_paypal_payment'] ?? '' ) );
if ( $saved_paypal_payment ) {
- $wc_order->update_meta_data( 'payment_token_id', $saved_paypal_payment );
- $wc_order->save();
+ $payment_token = WC_Payment_Tokens::get( $saved_paypal_payment );
+ if ( $payment_token ) {
+ $wc_order->add_payment_token( $payment_token );
+ $wc_order->save();
- return $this->handle_payment_success( $wc_order );
+ return $this->handle_payment_success( $wc_order );
+ }
+
+ wc_add_notice( __( 'Could not change payment.', 'woocommerce-paypal-payments' ), 'error' );
+
+ return array(
+ 'result' => 'failure',
+ 'redirect' => wc_get_checkout_url(),
+ 'errorMessage' => __( 'Could not change payment.', 'woocommerce-paypal-payments' ),
+ );
}
}
diff --git a/modules/ppcp-wc-subscriptions/src/RenewalHandler.php b/modules/ppcp-wc-subscriptions/src/RenewalHandler.php
index adee662f2..650329714 100644
--- a/modules/ppcp-wc-subscriptions/src/RenewalHandler.php
+++ b/modules/ppcp-wc-subscriptions/src/RenewalHandler.php
@@ -427,9 +427,11 @@ class RenewalHandler {
$tokens = $wc_order->get_payment_tokens();
if ( $tokens ) {
- $token = WC_Payment_Tokens::get( $tokens[0] );
- if ( $token ) {
- $token_id = $token->get_token();
+ foreach ( $tokens as $token_id ) {
+ $token = WC_Payment_Tokens::get( $token_id );
+ if ( $token && $token->get_gateway_id() === $wc_order->get_payment_method() ) {
+ return $token->get_token();
+ }
}
}
diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
index 393a7ef8f..d15906d46 100644
--- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
+++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
@@ -251,30 +251,21 @@ class WcSubscriptionsModule implements ModuleInterface {
&& PayPalGateway::ID === $id
&& $subscription_helper->is_subscription_change_payment()
) {
- $tokens = $payment_token_repository->all_for_user_id( get_current_user_id() );
- if ( ! $tokens || ! $payment_token_repository->tokens_contains_paypal( $tokens ) ) {
- return esc_html__(
- 'No PayPal payments saved, in order to use a saved payment you first need to create it through a purchase.',
- 'woocommerce-paypal-payments'
- );
- }
-
+ $tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), PayPalGateway::ID );
$output = sprintf(
'';
+ $output .= '
';
- return $output;
+ return $output;
}
return $description;
From 16eebecc5a836b72a6df8353fd93d3e8a54f1a43 Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Mon, 8 Jan 2024 11:38:00 +0100
Subject: [PATCH 03/14] Add change subscription payment for vault v3
---
.../src/Gateway/CreditCardGateway.php | 21 ++++++++++++-------
.../src/WcSubscriptionsModule.php | 4 ----
2 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php
index aaa92abdb..66f370124 100644
--- a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php
+++ b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php
@@ -400,18 +400,25 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
* If customer is changing subscription payment.
*/
if (
- // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ // phpcs:disable WordPress.Security.NonceVerification.Missing
isset( $_POST['woocommerce_change_payment'] )
&& $this->subscription_helper->has_subscription( $wc_order->get_id() )
&& $this->subscription_helper->is_subscription_change_payment()
- && $saved_credit_card
) {
- $payment_token = WC_Payment_Tokens::get($saved_credit_card);
- if($payment_token) {
- $wc_order->add_payment_token($payment_token);
- $wc_order->save();
+ $saved_credit_card = wc_clean( wp_unslash( $_POST['wc-ppcp-credit-card-gateway-payment-token'] ?? '' ) );
+ if ( ! $saved_credit_card ) {
+ $saved_credit_card = wc_clean( wp_unslash( $_POST['saved_credit_card'] ?? '' ) );
+ // phpcs:enable WordPress.Security.NonceVerification.Missing
+ }
- return $this->handle_payment_success( $wc_order );
+ if ( $saved_credit_card ) {
+ $payment_token = WC_Payment_Tokens::get( $saved_credit_card );
+ if ( $payment_token ) {
+ $wc_order->add_payment_token( $payment_token );
+ $wc_order->save();
+
+ return $this->handle_payment_success( $wc_order );
+ }
}
wc_add_notice( __( 'Could not change payment.', 'woocommerce-paypal-payments' ), 'error' );
diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
index 6049e3823..c8f0f99a6 100644
--- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
+++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
@@ -117,10 +117,6 @@ class WcSubscriptionsModule implements ModuleInterface {
* @psalm-suppress MissingClosureParamType
*/
function ( $description, $id ) use ( $c ) {
- if ( $c->has( 'save-payment-methods.eligible' ) && $c->get( 'save-payment-methods.eligible' ) ) {
- return $description;
- }
-
$payment_token_repository = $c->get( 'vaulting.repository.payment-token' );
$settings = $c->get( 'wcgateway.settings' );
$subscription_helper = $c->get( 'wc-subscriptions.helper' );
From dc9ad87b3e6796e85d1883dd6abb03cb42894a20 Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Mon, 8 Jan 2024 12:40:56 +0100
Subject: [PATCH 04/14] Allow create payment when changing subscription payment
method (WIP)
---
.../ppcp-button/src/Helper/ContextTrait.php | 13 +++
.../resources/js/add-payment-method.js | 87 ++++++++++---------
.../src/SavePaymentMethodsModule.php | 2 +-
3 files changed, 59 insertions(+), 43 deletions(-)
diff --git a/modules/ppcp-button/src/Helper/ContextTrait.php b/modules/ppcp-button/src/Helper/ContextTrait.php
index a02a79709..9b5874bfa 100644
--- a/modules/ppcp-button/src/Helper/ContextTrait.php
+++ b/modules/ppcp-button/src/Helper/ContextTrait.php
@@ -212,6 +212,19 @@ trait ContextTrait {
return $page_id && is_page( $page_id ) && isset( $wp->query_vars['add-payment-method'] );
}
+ /**
+ * Checks whether this user is changing the payment method for a subscription.
+ *
+ * @return bool
+ */
+ private function is_subscription_change_payment_method_page(): bool {
+ if ( isset( $_GET['change_payment_method'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
+ return wcs_is_subscription( wc_clean( wp_unslash( $_GET['change_payment_method'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification
+ }
+
+ return false;
+ }
+
/**
* Checks if it is the block editor page.
*/
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 d861421e4..6be53940c 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
@@ -38,54 +38,57 @@ document.addEventListener(
.then((paypal) => {
errorHandler.clear();
- paypal.Buttons(
- {
- createVaultSetupToken: async () => {
- const response = await fetch(ppcp_add_payment_method.ajax.create_setup_token.endpoint, {
- method: "POST",
- credentials: 'same-origin',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- nonce: ppcp_add_payment_method.ajax.create_setup_token.nonce,
+ const paypalButtonContainer = document.querySelector(`#ppc-button-${PaymentMethods.PAYPAL}-save-payment-method`);
+ if(paypalButtonContainer) {
+ paypal.Buttons(
+ {
+ createVaultSetupToken: async () => {
+ const response = await fetch(ppcp_add_payment_method.ajax.create_setup_token.endpoint, {
+ method: "POST",
+ credentials: 'same-origin',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ nonce: ppcp_add_payment_method.ajax.create_setup_token.nonce,
+ })
})
- })
- const result = await response.json()
- if (result.data.id) {
- return result.data.id
- }
+ const result = await response.json()
+ if (result.data.id) {
+ return result.data.id
+ }
- errorHandler.message(ppcp_add_payment_method.error_message);
- },
- onApprove: async ({vaultSetupToken}) => {
- const response = await fetch(ppcp_add_payment_method.ajax.create_payment_token.endpoint, {
- method: "POST",
- credentials: 'same-origin',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- nonce: ppcp_add_payment_method.ajax.create_payment_token.nonce,
- vault_setup_token: vaultSetupToken,
+ errorHandler.message(ppcp_add_payment_method.error_message);
+ },
+ onApprove: async ({vaultSetupToken}) => {
+ const response = await fetch(ppcp_add_payment_method.ajax.create_payment_token.endpoint, {
+ method: "POST",
+ credentials: 'same-origin',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ nonce: ppcp_add_payment_method.ajax.create_payment_token.nonce,
+ vault_setup_token: vaultSetupToken,
+ })
})
- })
- const result = await response.json();
- if(result.success === true) {
- window.location.href = ppcp_add_payment_method.payment_methods_page;
- return;
+ const result = await response.json();
+ if(result.success === true) {
+ window.location.href = ppcp_add_payment_method.payment_methods_page;
+ return;
+ }
+
+ errorHandler.message(ppcp_add_payment_method.error_message);
+ },
+ onError: (error) => {
+ console.error(error)
+ errorHandler.message(ppcp_add_payment_method.error_message);
}
-
- errorHandler.message(ppcp_add_payment_method.error_message);
},
- onError: (error) => {
- console.error(error)
- errorHandler.message(ppcp_add_payment_method.error_message);
- }
- },
- ).render(`#ppc-button-${PaymentMethods.PAYPAL}-save-payment-method`);
+ ).render(`#ppc-button-${PaymentMethods.PAYPAL}-save-payment-method`);
+ }
const cardField = paypal.CardFields({
createVaultSetupToken: async () => {
@@ -167,7 +170,7 @@ document.addEventListener(
}
}
- document.querySelector('#place_order').addEventListener("click", (event) => {
+ document.querySelector('#place_order')?.addEventListener("click", (event) => {
event.preventDefault();
cardField.submit()
diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php
index 3501d71aa..9b055b415 100644
--- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php
+++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php
@@ -176,7 +176,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
add_action(
'wp_enqueue_scripts',
function() use ( $c ) {
- if ( ! is_user_logged_in() || ! $this->is_add_payment_method_page() ) {
+ if ( ! is_user_logged_in() || ! ( $this->is_add_payment_method_page() || $this->is_subscription_change_payment_method_page() ) ) {
return;
}
From 018b497611f1e8bb28d30702ebac186a5a1179cb Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Mon, 8 Jan 2024 14:37:51 +0100
Subject: [PATCH 05/14] Move create wc card payment method to helper class
---
.../src/Endpoint/CreatePaymentToken.php | 22 +++---------
.../src/WooCommercePaymentTokens.php | 35 +++++++++++++++++++
2 files changed, 39 insertions(+), 18 deletions(-)
diff --git a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php
index 6698c4340..61fcae9da 100644
--- a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php
+++ b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php
@@ -98,7 +98,8 @@ class CreatePaymentToken implements EndpointInterface {
$result = $this->payment_method_tokens_endpoint->payment_tokens( $payment_source );
if ( is_user_logged_in() && isset( $result->customer->id ) ) {
- update_user_meta( get_current_user_id(), '_ppcp_target_customer_id', $result->customer->id );
+ $current_user_id = get_current_user_id();
+ update_user_meta( $current_user_id, '_ppcp_target_customer_id', $result->customer->id );
if ( isset( $result->payment_source->paypal ) ) {
$email = '';
@@ -107,29 +108,14 @@ class CreatePaymentToken implements EndpointInterface {
}
$this->wc_payment_tokens->create_payment_token_paypal(
- get_current_user_id(),
+ $current_user_id,
$result->id,
$email
);
}
if ( isset( $result->payment_source->card ) ) {
- $token = new \WC_Payment_Token_CC();
- $token->set_token( $result->id );
- $token->set_user_id( get_current_user_id() );
- $token->set_gateway_id( CreditCardGateway::ID );
-
- $token->set_last4( $result->payment_source->card->last_digits ?? '' );
- $expiry = explode( '-', $result->payment_source->card->expiry ?? '' );
- $token->set_expiry_year( $expiry[0] ?? '' );
- $token->set_expiry_month( $expiry[1] ?? '' );
-
- $brand = $result->payment_source->card->brand ?? __( 'N/A', 'woocommerce-paypal-payments' );
- if ( $brand ) {
- $token->set_card_type( $brand );
- }
-
- $token->save();
+ $this->wc_payment_tokens->create_payment_token_card( $current_user_id, $result );
}
}
diff --git a/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php b/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php
index 4fb066b6e..d9e13ce33 100644
--- a/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php
+++ b/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php
@@ -11,10 +11,13 @@ namespace WooCommerce\PayPalCommerce\SavePaymentMethods;
use Exception;
use Psr\Log\LoggerInterface;
+use stdClass;
+use WC_Payment_Token_CC;
use WC_Payment_Tokens;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenFactory;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenHelper;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenPayPal;
+use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
/**
@@ -99,4 +102,36 @@ class WooCommercePaymentTokens {
);
}
}
+
+ /**
+ * Creates a WC Payment Token for Credit Card payment.
+ *
+ * @param int $customer_id The WC customer ID.
+ * @param stdClass $payment_token The Credit Card payment token.
+ *
+ * @return void
+ */
+ public function create_payment_token_card( int $customer_id, stdClass $payment_token ): void {
+ $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;
+ }
+
+ $token = new WC_Payment_Token_CC();
+ $token->set_token( $payment_token->id );
+ $token->set_user_id( get_current_user_id() );
+ $token->set_gateway_id( CreditCardGateway::ID );
+
+ $token->set_last4( $payment_token->payment_source->card->last_digits ?? '' );
+ $expiry = explode( '-', $payment_token->payment_source->card->expiry ?? '' );
+ $token->set_expiry_year( $expiry[0] ?? '' );
+ $token->set_expiry_month( $expiry[1] ?? '' );
+
+ $brand = $payment_token->payment_source->card->brand ?? __( 'N/A', 'woocommerce-paypal-payments' );
+ if ( $brand ) {
+ $token->set_card_type( $brand );
+ }
+
+ $token->save();
+ }
}
From f081fc2392e01e1a6b93a3e729c936f0b1fb3808 Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Mon, 8 Jan 2024 14:39:44 +0100
Subject: [PATCH 06/14] Move create wc card payment method to helper class
---
.../src/WooCommercePaymentTokens.php | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php b/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php
index d9e13ce33..849e1e56e 100644
--- a/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php
+++ b/modules/ppcp-save-payment-methods/src/WooCommercePaymentTokens.php
@@ -132,6 +132,13 @@ class WooCommercePaymentTokens {
$token->set_card_type( $brand );
}
+ try {
+ $token->save();
+ } catch ( Exception $exception ) {
+ $this->logger->error(
+ "Could not create WC payment token card for customer {$customer_id}. " . $exception->getMessage()
+ );
+ }
$token->save();
}
}
From 0262c28580e175fdcc0b052eca6183ca0b979218 Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Mon, 8 Jan 2024 17:47:52 +0100
Subject: [PATCH 07/14] 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();
+ }
+ );
}
/**
From dfd3f0cbe9fd30b4107b09a4b0e1f3b77ea7e376 Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Tue, 9 Jan 2024 12:15:48 +0100
Subject: [PATCH 08/14] Ensure change payment method only submit card fields
for new payment
---
.../resources/js/add-payment-method.js | 7 +++++++
1 file changed, 7 insertions(+)
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 4a7ab80de..4e67aaf1b 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
@@ -198,6 +198,13 @@ document.addEventListener(
}
document.querySelector('#place_order')?.addEventListener("click", (event) => {
+ if (
+ getCurrentPaymentMethod() !== 'ppcp-credit-card-gateway'
+ || document.querySelector('input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked')?.value !== 'new'
+ ) {
+ return;
+ }
+
event.preventDefault();
cardField.submit()
From cd8cfaf0b845c2c48fe7f555b0ed3e3eff9e0ed5 Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Tue, 9 Jan 2024 16:18:16 +0100
Subject: [PATCH 09/14] Fix add payment method conflict with button event
---
.../resources/js/add-payment-method.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
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 4e67aaf1b..6c2c51783 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
@@ -198,9 +198,10 @@ document.addEventListener(
}
document.querySelector('#place_order')?.addEventListener("click", (event) => {
+ const cardPaymentToken = document.querySelector('input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked')?.value;
if (
getCurrentPaymentMethod() !== 'ppcp-credit-card-gateway'
- || document.querySelector('input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked')?.value !== 'new'
+ || cardPaymentToken && cardPaymentToken !== 'new'
) {
return;
}
From 51aa79af11fde7bf448cc79d11ce6db4a561919e Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Thu, 11 Jan 2024 12:29:36 +0100
Subject: [PATCH 10/14] Disable save to account checkout if subscription in the
cart
---
.../js/modules/Renderer/CardFieldsRenderer.js | 8 +++++++
.../ppcp-button/src/Assets/SmartButton.php | 1 +
.../resources/js/add-payment-method.js | 8 +++++++
.../src/WcSubscriptionsModule.php | 24 +++++++++----------
4 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js
index 4cf07a0bf..3287c7492 100644
--- a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js
+++ b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsRenderer.js
@@ -112,6 +112,14 @@ class CardFieldsRenderer {
show(buttonSelector);
+ if(this.defaultConfig.cart_contains_subscription) {
+ const saveToAccount = document.querySelector('#wc-ppcp-credit-card-gateway-new-payment-method');
+ if(saveToAccount) {
+ saveToAccount.checked = true;
+ saveToAccount.disabled = true;
+ }
+ }
+
document.querySelector(buttonSelector).addEventListener("click", (event) => {
event.preventDefault();
this.spinner.block();
diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php
index 24393d6b4..2f6a24781 100644
--- a/modules/ppcp-button/src/Assets/SmartButton.php
+++ b/modules/ppcp-button/src/Assets/SmartButton.php
@@ -1056,6 +1056,7 @@ document.querySelector("#payment").before(document.querySelector("#ppcp-messages
'endpoint' => \WC_AJAX::get_endpoint( CartScriptParamsEndpoint::ENDPOINT ),
),
),
+ 'cart_contains_subscription' => $this->subscription_helper->cart_contains_subscription(),
'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(),
'variable_paypal_subscription_variations' => $this->subscription_helper->variable_paypal_subscription_variations(),
'subscription_product_allowed' => $this->subscription_helper->checkout_subscription_product_allowed(),
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 6c2c51783..8aca64f7c 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
@@ -28,6 +28,14 @@ document.addEventListener(
init()
});
+ if(ppcp_add_payment_method.is_subscription_change_payment_page) {
+ const saveToAccount = document.querySelector('#wc-ppcp-credit-card-gateway-new-payment-method');
+ if(saveToAccount) {
+ saveToAccount.checked = true;
+ saveToAccount.disabled = true;
+ }
+ }
+
setTimeout(() => {
loadScript({
clientId: ppcp_add_payment_method.client_id,
diff --git a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
index 1d86d8832..6e3e25937 100644
--- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
+++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
@@ -152,8 +152,11 @@ class WcSubscriptionsModule implements ModuleInterface {
add_filter(
'woocommerce_available_payment_gateways',
- function( array $methods ): array {
- if ( ! is_wc_endpoint_url( 'order-pay' ) ) {
+ function( array $methods ) use ( $c ) : array {
+ if (
+ ! is_wc_endpoint_url( 'order-pay' )
+ || $c->has( 'save-payment-methods.eligible' ) && $c->get( 'save-payment-methods.eligible' )
+ ) {
return $methods;
}
@@ -261,18 +264,15 @@ class WcSubscriptionsModule implements ModuleInterface {
&& $subscription_helper->is_subscription_change_payment()
) {
$tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), PayPalGateway::ID );
- $output = sprintf(
- '';
+ $output .= '';
return $output;
}
From 8a5e823801406dd0e5adeae133fd2c60e8c53107 Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Fri, 12 Jan 2024 09:58:35 +0100
Subject: [PATCH 11/14] Fix phpunit
---
.../Vaulting/VaultedCreditCardHandlerTest.php | 18 ------------------
.../Gateway/CreditCardGatewayTest.php | 2 ++
2 files changed, 2 insertions(+), 18 deletions(-)
diff --git a/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php b/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php
index fa92f6f89..fb728709a 100644
--- a/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php
+++ b/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php
@@ -68,24 +68,6 @@ class VaultedCreditCardHandlerTest extends TestCase
);
}
- public function testHandlePaymentChangingPayment()
- {
- $_POST['woocommerce_change_payment'] = 1;
- $wcOrder = Mockery::mock(\WC_Order::class);
- $wcOrder->shouldReceive('get_id')->andReturn(1);
- $wcOrder->shouldReceive('update_meta_data')
- ->with('payment_token_id', 'abc123')
- ->andReturn(1);
- $wcOrder->shouldReceive('save')->andReturn(1);
- $this->subscriptionHelper->shouldReceive('has_subscription')->andReturn(true);
- $this->subscriptionHelper->shouldReceive('is_subscription_change_payment')->andReturn(true);
-
- $customer = Mockery::mock(WC_Customer::class);
-
- $result = $this->testee->handle_payment('abc123', $wcOrder, $customer);
- $this->assertInstanceOf(\WC_Order::class, $result);
- }
-
public function testHandlePayment()
{
$_POST['woocommerce_change_payment'] = null;
diff --git a/tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php b/tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php
index f76438f98..15689d08e 100644
--- a/tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php
+++ b/tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php
@@ -109,6 +109,8 @@ class CreditCardGatewayTest extends TestCase
$session->shouldReceive('set')->andReturn([]);
$session->shouldReceive('get')->andReturn('');
+ when('is_checkout')->justReturn(true);
+
$savedCreditCard = 'abc123';
$_POST['saved_credit_card'] = $savedCreditCard;
From eb7e921d44ece11da6de3e72e0afaf90d2c8fdea Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Fri, 12 Jan 2024 10:48:50 +0100
Subject: [PATCH 12/14] Fix psalm
---
.../SubscriptionChangePaymentMethod.php | 20 ++++++++++++-------
.../src/WcSubscriptionsModule.php | 4 +++-
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/modules/ppcp-wc-subscriptions/src/Endpoint/SubscriptionChangePaymentMethod.php b/modules/ppcp-wc-subscriptions/src/Endpoint/SubscriptionChangePaymentMethod.php
index cb277e146..7f3df3601 100644
--- a/modules/ppcp-wc-subscriptions/src/Endpoint/SubscriptionChangePaymentMethod.php
+++ b/modules/ppcp-wc-subscriptions/src/Endpoint/SubscriptionChangePaymentMethod.php
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcSubscriptions\Endpoint;
use Exception;
+use WC_Order;
use WC_Payment_Tokens;
use WooCommerce\PayPalCommerce\Button\Endpoint\EndpointInterface;
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
@@ -57,16 +58,21 @@ class SubscriptionChangePaymentMethod implements EndpointInterface {
$data = $this->request_data->read_request( $this->nonce() );
$subscription = wcs_get_subscription( $data['subscription_id'] );
- $subscription->set_payment_method( $data['payment_method'] );
+ if ( $subscription instanceof WC_Order ) {
+ $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();
+ $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;
}
- wp_send_json_success();
- return true;
+ wp_send_json_error();
+ return false;
} 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 6e3e25937..0f2fa2e21 100644
--- a/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
+++ b/modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
@@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcSubscriptions;
use Psr\Log\LoggerInterface;
use WC_Order;
+use WC_Payment_Token_CC;
use WC_Payment_Tokens;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
@@ -309,13 +310,14 @@ class WcSubscriptionsModule implements ModuleInterface {
esc_html__( 'Select a saved Credit Card payment', 'woocommerce-paypal-payments' )
);
foreach ( $tokens as $token ) {
+ if ( $token instanceof WC_Payment_Token_CC ) {
$output .= sprintf(
'',
$token->get_id(),
$token->get_card_type(),
$token->get_last4()
);
-
+ }
}
$output .= '';
From f35373f73dfae625a19cbab9d1cc4b4131b8a3a5 Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Fri, 12 Jan 2024 11:02:13 +0100
Subject: [PATCH 13/14] Fix phpcs
---
.../ppcp-save-payment-methods/src/SavePaymentMethodsModule.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php
index b34092732..be10dccb2 100644
--- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php
+++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php
@@ -208,6 +208,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
assert( $settings instanceof Settings );
$verification_method = $settings->has( '3d_secure_contingency' ) ? $settings->get( '3d_secure_contingency' ) : '';
+ $change_payment_method = wc_clean( wp_unslash( $_GET['change_payment_method'] ?? 0 ) ); // phpcs:ignore WordPress.Security.NonceVerification
wp_localize_script(
'ppcp-add-payment-method',
'ppcp_add_payment_method',
@@ -218,7 +219,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
'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,
+ 'subscription_id_to_change_payment' => $this->is_subscription_change_payment_method_page() ? (int) $change_payment_method : 0,
'error_message' => __( 'Could not save payment method.', 'woocommerce-paypal-payments' ),
'verification_method' => $verification_method,
'ajax' => array(
From 65ba26e7cc297b42a6615ee20bc6382c6b9cb4bc Mon Sep 17 00:00:00 2001
From: Emili Castells Guasch
Date: Fri, 12 Jan 2024 11:05:52 +0100
Subject: [PATCH 14/14] Fix psalm
---
.../ppcp-save-payment-methods/src/SavePaymentMethodsModule.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php
index be10dccb2..4f3fc1fb1 100644
--- a/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php
+++ b/modules/ppcp-save-payment-methods/src/SavePaymentMethodsModule.php
@@ -208,7 +208,8 @@ class SavePaymentMethodsModule implements ModuleInterface {
assert( $settings instanceof Settings );
$verification_method = $settings->has( '3d_secure_contingency' ) ? $settings->get( '3d_secure_contingency' ) : '';
- $change_payment_method = wc_clean( wp_unslash( $_GET['change_payment_method'] ?? 0 ) ); // phpcs:ignore WordPress.Security.NonceVerification
+ $change_payment_method = wc_clean( wp_unslash( $_GET['change_payment_method'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification
+
wp_localize_script(
'ppcp-add-payment-method',
'ppcp_add_payment_method',