Skip to content

Commit

Permalink
Change subscription payment method (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
Emili Castells Guasch authored and Emili Castells Guasch committed Jan 3, 2024
1 parent 9ad2272 commit f758469
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 36 deletions.
13 changes: 0 additions & 13 deletions modules/ppcp-vaulting/src/VaultedCreditCardHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,6 @@ public function handle_payment(
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 ) {
Expand Down
32 changes: 30 additions & 2 deletions modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
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;
Expand Down Expand Up @@ -377,11 +378,11 @@ public function process_payment( $order_id ) {
}

/**
* 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,
Expand All @@ -395,6 +396,33 @@ public function process_payment( $order_id ) {
}
}

/**
* 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.
*/
Expand Down
49 changes: 45 additions & 4 deletions modules/ppcp-wc-subscriptions/src/RenewalHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

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;
Expand Down Expand Up @@ -194,8 +197,8 @@ private function process_order( \WC_Order $wc_order ): void {
'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',
Expand All @@ -215,7 +218,7 @@ private function process_order( \WC_Order $wc_order ): void {
$payment_source = new PaymentSource(
'card',
(object) array(
'vault_id' => $token->id(),
'vault_id' => $token_id,
'stored_credential' => $stored_credentials,
)
);
Expand Down Expand Up @@ -244,11 +247,23 @@ private function process_order( \WC_Order $wc_order ): void {
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 );
Expand Down Expand Up @@ -399,4 +414,30 @@ private function handle_paypal_order( \WC_Order $wc_order, Order $order ): void
$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;
}
}
52 changes: 35 additions & 17 deletions modules/ppcp-wc-subscriptions/src/WcSubscriptionsModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

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;
Expand Down Expand Up @@ -115,6 +115,10 @@ function ( $subscription ) use ( $c ) {
* @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' );
Expand All @@ -133,6 +137,10 @@ function ( $description, $id ) use ( $c ) {
* @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' );
Expand All @@ -142,6 +150,27 @@ function ( $default_fields, $id ) use ( $c ) {
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;
}
);
}

/**
Expand Down Expand Up @@ -269,35 +298,24 @@ protected function display_saved_credit_cards(
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>';

Expand Down

0 comments on commit f758469

Please sign in to comment.