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,
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 ) {

View file

@ -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.
*/

View file

@ -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;
}
}

View file

@ -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(
'<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' )
);
foreach ( $tokens as $token ) {
if ( isset( $token->source()->card ) ) {
$output .= sprintf(
'<option value="%1$s">%2$s ...%3$s</option>',
$token->id(),
$token->source()->card->brand,
$token->source()->card->last_digits
$token->get_id(),
$token->get_card_type(),
$token->get_last4()
);
}
}
$output .= '</select></p>';