Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing subscription payment method to ACDC results in an error (3949) #2891

Open
wants to merge 11 commits into
base: trunk
Choose a base branch
from
112 changes: 63 additions & 49 deletions modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -444,28 +444,27 @@ public function process_payment( $order_id ) {
}
}

if ( $card_payment_token_id ) {
$customer_tokens = $this->wc_payment_tokens->customer_tokens( get_current_user_id() );

$wc_tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id(), self::ID );

if ( $customer_tokens && empty( $wc_tokens ) ) {
$this->wc_payment_tokens->create_wc_tokens( $customer_tokens, get_current_user_id() );
if ( $this->is_customer_changing_subscription_payment( $this->subscription_helper, $wc_order ) ) {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$wc_payment_token_id = wc_clean( wp_unslash( $_POST['wc-ppcp-credit-card-gateway-payment-token'] ?? '' ) );
if ( ! $wc_payment_token_id ) {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$wc_payment_token_id = wc_clean( wp_unslash( $_POST['saved_credit_card'] ?? '' ) );
}

$customer_token_ids = array();
foreach ( $customer_tokens as $customer_token ) {
$customer_token_ids[] = $customer_token['id'];
if ( $wc_payment_token_id ) {
return $this->add_payment_token_to_order( $wc_order, (int) $wc_payment_token_id, $this->get_return_url( $wc_order ), $this->session_handler );
}
}

/**
* Vault v3 (save payment methods).
* If customer has chosen a saved credit card payment from checkout page.
*/
if ( $card_payment_token_id ) {
$tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id() );
foreach ( $tokens as $token ) {
if ( $token->get_id() === (int) $card_payment_token_id ) {
if ( ! in_array( $token->get_token(), $customer_token_ids, true ) ) {
$token->delete();
continue;
}

$custom_id = (string) $wc_order->get_id();
$invoice_id = $this->prefix . $wc_order->get_order_number();
$create_order = $this->capture_card_payment->create_order( $token->get_token(), $custom_id, $invoice_id, $wc_order );
Expand Down Expand Up @@ -514,40 +513,6 @@ public function process_payment( $order_id ) {
}
}

/**
* If customer is changing subscription payment.
*/
if (
// 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 = 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
}

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

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 Expand Up @@ -676,4 +641,53 @@ private function is_enabled(): bool {
protected function settings_renderer(): SettingsRenderer {
return $this->settings_renderer;
}

/**
* Check whether customer is changing subscription payment.
*
* @param SubscriptionHelper $subscription_helper Subscription helper.
* @param WC_Order $wc_order WC order.
* @return bool
*/
private function is_customer_changing_subscription_payment( SubscriptionHelper $subscription_helper, WC_Order $wc_order ): bool {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
return isset( $_POST['woocommerce_change_payment'] ) && $subscription_helper->has_subscription( $wc_order->get_id() ) && $subscription_helper->is_subscription_change_payment();
}

/**
* Adds the given WC payment token into the given WC Order.
*
* @param WC_Order $wc_order WC order.
* @param int $wc_payment_token_id WC payment token ID.
* @param string $return_url Return url.
* @param SessionHandler $session_handler Session handler.
* @return array{result: string, redirect: string, errorMessage?: string}
*/
private function add_payment_token_to_order(
WC_Order $wc_order,
int $wc_payment_token_id,
string $return_url,
SessionHandler $session_handler
): array {
$payment_token = WC_Payment_Tokens::get( $wc_payment_token_id );
if ( $payment_token ) {
$wc_order->add_payment_token( $payment_token );
$wc_order->save();

$session_handler->destroy_session_data();

return array(
'result' => 'success',
'redirect' => $return_url,
);
}

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' ),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
use WC_Subscriptions_Product;
use WCS_Manual_Renewal_Manager;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;

/**
* Class SubscriptionHelper
Expand Down Expand Up @@ -301,7 +303,11 @@ public function previous_transaction( WC_Subscription $subscription ): string {

foreach ( $orders as $order_id ) {
$order = wc_get_order( $order_id );
if ( is_a( $order, WC_Order::class ) && in_array( $order->get_status(), array( 'processing', 'completed' ), true ) ) {
if (
is_a( $order, WC_Order::class )
&& in_array( $order->get_status(), array( 'processing', 'completed' ), true )
&& in_array( $order->get_payment_method(), array( PayPalGateway::ID, CreditCardGateway::ID ), true )
) {
$transaction_id = $order->get_transaction_id();
if ( $transaction_id ) {
return $transaction_id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use WC_Payment_Token_CC;
use WC_Payment_Tokens;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule;
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use WC_Order;
use WC_Subscription;
use WooCommerce\PayPalCommerce\TestCase;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use function Brain\Monkey\Functions\when;

class SubscriptionHelperTest extends TestCase
Expand All @@ -26,6 +27,7 @@ public function testPreviousTransaction()
$wc_order = Mockery::mock(WC_Order::class);
$wc_order->shouldReceive('get_status')->andReturn('processing');
$wc_order->shouldReceive('get_transaction_id')->andReturn('ABC123');
$wc_order->shouldReceive('get_payment_method')->andReturn(CreditCardGateway::ID);

when('wc_get_order')->justReturn($wc_order);

Expand Down
Loading