Change subscription payment method (WIP)

This commit is contained in:
Emili Castells Guasch 2024-01-03 15:44:24 +01:00
parent 9ad2272907
commit f75846952d
4 changed files with 110 additions and 36 deletions

View file

@ -143,19 +143,6 @@ class VaultedCreditCardHandler {
string $saved_credit_card, string $saved_credit_card,
WC_Order $wc_order WC_Order $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() ); $tokens = $this->payment_token_repository->all_for_user_id( $wc_order->get_customer_id() );
$selected_token = null; $selected_token = null;
foreach ( $tokens as $token ) { foreach ( $tokens as $token ) {

View file

@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
use Exception; use Exception;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use WC_Order; use WC_Order;
use WC_Payment_Tokens;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; 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 // phpcs:ignore WordPress.Security.NonceVerification.Missing
$saved_credit_card = wc_clean( wp_unslash( $_POST['saved_credit_card'] ?? '' ) ); $saved_credit_card = wc_clean( wp_unslash( $_POST['saved_credit_card'] ?? '' ) );
if ( $saved_credit_card ) { if ( $saved_credit_card && is_checkout() ) {
try { try {
$wc_order = $this->vaulted_credit_card_handler->handle_payment( $wc_order = $this->vaulted_credit_card_handler->handle_payment(
$saved_credit_card, $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. * If the WC_Order is paid through the approved webhook.
*/ */

View file

@ -9,6 +9,9 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\WcSubscriptions; namespace WooCommerce\PayPalCommerce\WcSubscriptions;
use WC_Customer;
use WC_Order;
use WC_Payment_Tokens;
use WC_Subscription; use WC_Subscription;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext; use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
@ -194,8 +197,8 @@ class RenewalHandler {
'renewal' 'renewal'
); );
$token = $this->get_token_for_customer( $customer, $wc_order ); $token_id = $this->token_id( $wc_order, $customer );
if ( $token ) { if ( $token_id ) {
if ( $wc_order->get_payment_method() === CreditCardGateway::ID ) { if ( $wc_order->get_payment_method() === CreditCardGateway::ID ) {
$stored_credentials = array( $stored_credentials = array(
'payment_initiator' => 'MERCHANT', 'payment_initiator' => 'MERCHANT',
@ -215,7 +218,7 @@ class RenewalHandler {
$payment_source = new PaymentSource( $payment_source = new PaymentSource(
'card', 'card',
(object) array( (object) array(
'vault_id' => $token->id(), 'vault_id' => $token_id,
'stored_credential' => $stored_credentials, 'stored_credential' => $stored_credentials,
) )
); );
@ -244,11 +247,23 @@ class RenewalHandler {
return; return;
} }
$payment_source = new PaymentSource(
'paypal',
(object) array(
'vault_id' => $token_id,
)
);
$order = $this->order_endpoint->create( $order = $this->order_endpoint->create(
array( $purchase_unit ), array( $purchase_unit ),
$shipping_preference, $shipping_preference,
$payer, $payer,
$token null,
'',
ApplicationContext::USER_ACTION_CONTINUE,
'',
array(),
$payment_source
); );
$this->handle_paypal_order( $wc_order, $order ); $this->handle_paypal_order( $wc_order, $order );
@ -399,4 +414,30 @@ class RenewalHandler {
$this->authorized_payments_processor->capture_authorized_payment( $wc_order ); $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;
}
} }

View file

@ -11,7 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcSubscriptions;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use WC_Order; use WC_Order;
use WC_Subscription; use WC_Payment_Tokens;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider; use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
@ -115,6 +115,10 @@ class WcSubscriptionsModule implements ModuleInterface {
* @psalm-suppress MissingClosureParamType * @psalm-suppress MissingClosureParamType
*/ */
function ( $description, $id ) use ( $c ) { 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' ); $payment_token_repository = $c->get( 'vaulting.repository.payment-token' );
$settings = $c->get( 'wcgateway.settings' ); $settings = $c->get( 'wcgateway.settings' );
$subscription_helper = $c->get( 'wc-subscriptions.helper' ); $subscription_helper = $c->get( 'wc-subscriptions.helper' );
@ -133,6 +137,10 @@ class WcSubscriptionsModule implements ModuleInterface {
* @psalm-suppress MissingClosureParamType * @psalm-suppress MissingClosureParamType
*/ */
function ( $default_fields, $id ) use ( $c ) { 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' ); $payment_token_repository = $c->get( 'vaulting.repository.payment-token' );
$settings = $c->get( 'wcgateway.settings' ); $settings = $c->get( 'wcgateway.settings' );
$subscription_helper = $c->get( 'wc-subscriptions.helper' ); $subscription_helper = $c->get( 'wc-subscriptions.helper' );
@ -142,6 +150,27 @@ class WcSubscriptionsModule implements ModuleInterface {
20, 20,
2 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, array $default_fields,
SubscriptionHelper $subscription_helper SubscriptionHelper $subscription_helper
) { ) {
if ( $settings->has( 'vault_enabled_dcc' ) if ( $settings->has( 'vault_enabled_dcc' )
&& $settings->get( 'vault_enabled_dcc' ) && $settings->get( 'vault_enabled_dcc' )
&& $subscription_helper->is_subscription_change_payment() && $subscription_helper->is_subscription_change_payment()
&& CreditCardGateway::ID === $id && CreditCardGateway::ID === $id
) { ) {
$tokens = $payment_token_repository->all_for_user_id( get_current_user_id() ); $tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), CreditCardGateway::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;
}
$output = sprintf( $output = sprintf(
'<p class="form-row form-row-wide"><label>%1$s</label><select id="saved-credit-card" name="saved_credit_card">', '<p class="form-row form-row-wide"><label>%1$s</label><select id="saved-credit-card" name="saved_credit_card">',
esc_html__( 'Select a saved Credit Card payment', 'woocommerce-paypal-payments' ) esc_html__( 'Select a saved Credit Card payment', 'woocommerce-paypal-payments' )
); );
foreach ( $tokens as $token ) { foreach ( $tokens as $token ) {
if ( isset( $token->source()->card ) ) {
$output .= sprintf( $output .= sprintf(
'<option value="%1$s">%2$s ...%3$s</option>', '<option value="%1$s">%2$s ...%3$s</option>',
$token->id(), $token->get_id(),
$token->source()->card->brand, $token->get_card_type(),
$token->source()->card->last_digits $token->get_last4()
); );
}
} }
$output .= '</select></p>'; $output .= '</select></p>';