mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 14:57:26 +08:00
Void authorized transaction when payment is not saved
This commit is contained in:
parent
a21aa9111a
commit
1cee5d51f1
6 changed files with 195 additions and 49 deletions
|
@ -55,6 +55,8 @@ return array(
|
|||
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
|
||||
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
return new PayPalGateway(
|
||||
$settings_renderer,
|
||||
$order_processor,
|
||||
|
@ -68,7 +70,9 @@ return array(
|
|||
$subscription_helper,
|
||||
$page_id,
|
||||
$payment_token_repository,
|
||||
$logger
|
||||
$logger,
|
||||
$payments_endpoint,
|
||||
$order_endpoint
|
||||
);
|
||||
},
|
||||
'wcgateway.credit-card-gateway' => static function ( $container ): CreditCardGateway {
|
||||
|
@ -88,6 +92,7 @@ return array(
|
|||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
return new CreditCardGateway(
|
||||
$settings_renderer,
|
||||
$order_processor,
|
||||
|
@ -104,7 +109,8 @@ return array(
|
|||
$payer_factory,
|
||||
$order_endpoint,
|
||||
$subscription_helper,
|
||||
$logger
|
||||
$logger,
|
||||
$payments_endpoint
|
||||
);
|
||||
},
|
||||
'wcgateway.disabler' => static function ( $container ): DisableGateways {
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
|||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
|
@ -54,6 +55,13 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* The payments endpoint
|
||||
*
|
||||
* @var PaymentsEndpoint
|
||||
*/
|
||||
protected $payments_endpoint;
|
||||
|
||||
/**
|
||||
* The URL to the module.
|
||||
*
|
||||
|
@ -115,6 +123,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
|
@ -132,7 +141,8 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
PayerFactory $payer_factory,
|
||||
OrderEndpoint $order_endpoint,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
LoggerInterface $logger
|
||||
LoggerInterface $logger,
|
||||
PaymentsEndpoint $payments_endpoint
|
||||
) {
|
||||
|
||||
$this->id = self::ID;
|
||||
|
@ -201,6 +211,7 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,8 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
|
@ -100,6 +102,8 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
protected $payment_token_repository;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
@ -125,6 +129,20 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
*/
|
||||
protected $page_id;
|
||||
|
||||
/**
|
||||
* The payments endpoint
|
||||
*
|
||||
* @var PaymentsEndpoint
|
||||
*/
|
||||
protected $payments_endpoint;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
protected $order_endpoint;
|
||||
|
||||
/**
|
||||
* PayPalGateway constructor.
|
||||
*
|
||||
|
@ -139,6 +157,10 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
|
@ -153,7 +175,9 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
SubscriptionHelper $subscription_helper,
|
||||
string $page_id,
|
||||
PaymentTokenRepository $payment_token_repository,
|
||||
LoggerInterface $logger
|
||||
LoggerInterface $logger,
|
||||
PaymentsEndpoint $payments_endpoint,
|
||||
OrderEndpoint $order_endpoint
|
||||
) {
|
||||
|
||||
$this->id = self::ID;
|
||||
|
@ -213,6 +237,8 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
$this->subscription_helper = $subscription_helper;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->logger = $logger;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,8 @@ declare( strict_types=1 );
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
@ -24,6 +26,8 @@ trait ProcessPaymentTrait {
|
|||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws RuntimeException When processing payment fails.
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
|
||||
|
@ -173,8 +177,41 @@ trait ProcessPaymentTrait {
|
|||
|
||||
$this->logger->error( "Payment for subscription parent order #{$order_id} was not saved." );
|
||||
|
||||
// TODO void authorized payment
|
||||
// wait until https://github.com/woocommerce/woocommerce-paypal-payments/pull/299 is merged.
|
||||
$paypal_order_id = $wc_order->get_meta( PayPalGateway::ORDER_ID_META_KEY );
|
||||
if ( ! $paypal_order_id ) {
|
||||
throw new RuntimeException( 'PayPal order ID not found in meta.' );
|
||||
}
|
||||
$order = $this->order_endpoint->order( $paypal_order_id );
|
||||
|
||||
$purchase_units = $order->purchase_units();
|
||||
if ( ! $purchase_units ) {
|
||||
throw new RuntimeException( 'No purchase units.' );
|
||||
}
|
||||
|
||||
$payments = $purchase_units[0]->payments();
|
||||
if ( ! $payments ) {
|
||||
throw new RuntimeException( 'No payments.' );
|
||||
}
|
||||
|
||||
$this->logger->debug(
|
||||
sprintf(
|
||||
'Trying to void order %1$s, payments: %2$s.',
|
||||
$order->id(),
|
||||
wp_json_encode( $payments->to_array() )
|
||||
)
|
||||
);
|
||||
|
||||
$voidable_authorizations = array_filter(
|
||||
$payments->authorizations(),
|
||||
array( $this, 'is_voidable_authorization' )
|
||||
);
|
||||
if ( ! $voidable_authorizations ) {
|
||||
throw new RuntimeException( 'No voidable authorizations.' );
|
||||
}
|
||||
|
||||
foreach ( $voidable_authorizations as $authorization ) {
|
||||
$this->payments_endpoint->void( $authorization );
|
||||
}
|
||||
|
||||
$error_message = __( 'Could not process order because it was not possible to save the payment.', 'woocommerce-paypal-payments' );
|
||||
$wc_order->update_status( 'failed', $error_message );
|
||||
|
@ -186,7 +223,7 @@ trait ProcessPaymentTrait {
|
|||
$subscription->update_status( 'cancelled' );
|
||||
break;
|
||||
} catch ( Exception $exception ) {
|
||||
$this->logger->error("Could not update cancelled status on subscription #{$subscriptions[0]->get_id()} " . $exception->getMessage());
|
||||
$this->logger->error( "Could not update cancelled status on subscription #{$subscription->get_id()} " . $exception->getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -278,4 +315,14 @@ trait ProcessPaymentTrait {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the authorization can be voided.
|
||||
*
|
||||
* @param Authorization $authorization The authorization to check.
|
||||
* @return bool
|
||||
*/
|
||||
private function is_voidable_authorization( Authorization $authorization ): bool {
|
||||
return $authorization->status()->is( AuthorizationStatus::CREATED );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,14 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
|||
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
|
@ -27,6 +31,8 @@ class WcGatewayTest extends TestCase
|
|||
|
||||
$orderId = 1;
|
||||
$wcOrder = Mockery::mock(\WC_Order::class);
|
||||
$wcOrder->shouldReceive('get_customer_id')->andReturn(1);
|
||||
|
||||
$settingsRenderer = Mockery::mock(SettingsRenderer::class);
|
||||
$orderProcessor = Mockery::mock(OrderProcessor::class);
|
||||
$orderProcessor
|
||||
|
@ -53,11 +59,18 @@ class WcGatewayTest extends TestCase
|
|||
$subscriptionHelper
|
||||
->shouldReceive('has_subscription')
|
||||
->with($orderId)
|
||||
->andReturn(true);
|
||||
->andReturn(true)
|
||||
->andReturn(false);
|
||||
$subscriptionHelper
|
||||
->shouldReceive('is_subscription_change_payment')
|
||||
->andReturn(true);
|
||||
|
||||
$paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
$logger->shouldReceive('info');
|
||||
$paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
|
||||
$testee = new PayPalGateway(
|
||||
$settingsRenderer,
|
||||
$orderProcessor,
|
||||
|
@ -69,7 +82,11 @@ class WcGatewayTest extends TestCase
|
|||
$state,
|
||||
$transactionUrlProvider,
|
||||
$subscriptionHelper,
|
||||
PayPalGateway::ID
|
||||
PayPalGateway::ID,
|
||||
$paymentTokenRepository,
|
||||
$logger,
|
||||
$paymentsEndpoint,
|
||||
$orderEndpoint
|
||||
);
|
||||
|
||||
expect('wc_get_order')
|
||||
|
@ -107,6 +124,11 @@ class WcGatewayTest extends TestCase
|
|||
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
|
||||
$subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||
|
||||
$paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
$paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
|
||||
$testee = new PayPalGateway(
|
||||
$settingsRenderer,
|
||||
$orderProcessor,
|
||||
|
@ -118,7 +140,11 @@ class WcGatewayTest extends TestCase
|
|||
$state,
|
||||
$transactionUrlProvider,
|
||||
$subscriptionHelper,
|
||||
PayPalGateway::ID
|
||||
PayPalGateway::ID,
|
||||
$paymentTokenRepository,
|
||||
$logger,
|
||||
$paymentsEndpoint,
|
||||
$orderEndpoint
|
||||
);
|
||||
|
||||
expect('wc_get_order')
|
||||
|
@ -173,6 +199,11 @@ class WcGatewayTest extends TestCase
|
|||
$subscriptionHelper->shouldReceive('is_subscription_change_payment')->andReturn(true);
|
||||
$wcOrder->shouldReceive('update_status')->andReturn(true);
|
||||
|
||||
$paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
$paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
|
||||
$testee = new PayPalGateway(
|
||||
$settingsRenderer,
|
||||
$orderProcessor,
|
||||
|
@ -184,7 +215,11 @@ class WcGatewayTest extends TestCase
|
|||
$state,
|
||||
$transactionUrlProvider,
|
||||
$subscriptionHelper,
|
||||
PayPalGateway::ID
|
||||
PayPalGateway::ID,
|
||||
$paymentTokenRepository,
|
||||
$logger,
|
||||
$paymentsEndpoint,
|
||||
$orderEndpoint
|
||||
);
|
||||
|
||||
expect('wc_get_order')
|
||||
|
@ -244,6 +279,11 @@ class WcGatewayTest extends TestCase
|
|||
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
|
||||
$subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||
|
||||
$paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
$paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
|
||||
$testee = new PayPalGateway(
|
||||
$settingsRenderer,
|
||||
$orderProcessor,
|
||||
|
@ -255,7 +295,11 @@ class WcGatewayTest extends TestCase
|
|||
$state,
|
||||
$transactionUrlProvider,
|
||||
$subscriptionHelper,
|
||||
PayPalGateway::ID
|
||||
PayPalGateway::ID,
|
||||
$paymentTokenRepository,
|
||||
$logger,
|
||||
$paymentsEndpoint,
|
||||
$orderEndpoint
|
||||
);
|
||||
|
||||
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
|
||||
|
@ -299,6 +343,11 @@ class WcGatewayTest extends TestCase
|
|||
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
|
||||
$subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||
|
||||
$paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
$paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
|
||||
$testee = new PayPalGateway(
|
||||
$settingsRenderer,
|
||||
$orderProcessor,
|
||||
|
@ -310,7 +359,11 @@ class WcGatewayTest extends TestCase
|
|||
$state,
|
||||
$transactionUrlProvider,
|
||||
$subscriptionHelper,
|
||||
PayPalGateway::ID
|
||||
PayPalGateway::ID,
|
||||
$paymentTokenRepository,
|
||||
$logger,
|
||||
$paymentsEndpoint,
|
||||
$orderEndpoint
|
||||
);
|
||||
|
||||
$this->assertTrue($testee->capture_authorized_payment($wcOrder));
|
||||
|
@ -348,6 +401,11 @@ class WcGatewayTest extends TestCase
|
|||
->shouldReceive('current_state')->andReturn(State::STATE_ONBOARDED);
|
||||
$subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||
|
||||
$paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
$paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
|
||||
$testee = new PayPalGateway(
|
||||
$settingsRenderer,
|
||||
$orderProcessor,
|
||||
|
@ -359,7 +417,11 @@ class WcGatewayTest extends TestCase
|
|||
$state,
|
||||
$transactionUrlProvider,
|
||||
$subscriptionHelper,
|
||||
PayPalGateway::ID
|
||||
PayPalGateway::ID,
|
||||
$paymentTokenRepository,
|
||||
$logger,
|
||||
$paymentsEndpoint,
|
||||
$orderEndpoint
|
||||
);
|
||||
|
||||
$this->assertFalse($testee->capture_authorized_payment($wcOrder));
|
||||
|
@ -388,6 +450,11 @@ class WcGatewayTest extends TestCase
|
|||
$transactionUrlProvider = Mockery::mock(TransactionUrlProvider::class);
|
||||
$subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||
|
||||
$paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$logger = Mockery::mock(LoggerInterface::class);
|
||||
$paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
|
||||
$testee = new PayPalGateway(
|
||||
$settingsRenderer,
|
||||
$orderProcessor,
|
||||
|
@ -399,7 +466,11 @@ class WcGatewayTest extends TestCase
|
|||
$onboardingState,
|
||||
$transactionUrlProvider,
|
||||
$subscriptionHelper,
|
||||
PayPalGateway::ID
|
||||
PayPalGateway::ID,
|
||||
$paymentTokenRepository,
|
||||
$logger,
|
||||
$paymentsEndpoint,
|
||||
$orderEndpoint
|
||||
);
|
||||
|
||||
$this->assertSame($needSetup, $testee->needs_setup());
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Repository;
|
||||
|
||||
use Mockery\Adapter\Phpunit\MockeryTestCase;
|
||||
|
||||
class CartRepositoryTest extends MockeryTestCase
|
||||
{
|
||||
public function testAll()
|
||||
{
|
||||
self::markTestSkipped("Todo");
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue