Capture virtual renewal orders functionality for subscriptions

This commit is contained in:
Narek Zakarian 2022-06-29 16:52:19 +04:00
parent 998a327ebc
commit 90c2a01350
3 changed files with 94 additions and 15 deletions

View file

@ -24,13 +24,17 @@ return array(
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' ); $purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
$payer_factory = $container->get( 'api.factory.payer' ); $payer_factory = $container->get( 'api.factory.payer' );
$environment = $container->get( 'onboarding.environment' ); $environment = $container->get( 'onboarding.environment' );
$settings = $container->get( 'wcgateway.settings' );
$authorized_payments_processor = $container->get( 'wcgateway.processor.authorized-payments' );
return new RenewalHandler( return new RenewalHandler(
$logger, $logger,
$repository, $repository,
$endpoint, $endpoint,
$purchase_unit_factory, $purchase_unit_factory,
$payer_factory, $payer_factory,
$environment $environment,
$settings,
$authorized_payments_processor
); );
}, },
'subscription.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository { 'subscription.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository {

View file

@ -10,16 +10,19 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Subscription; namespace WooCommerce\PayPalCommerce\Subscription;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken; use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
use WooCommerce\PayPalCommerce\Onboarding\Environment; use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor; use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait; use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait; use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait; use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/** /**
* Class RenewalHandler * Class RenewalHandler
@ -72,6 +75,20 @@ class RenewalHandler {
*/ */
protected $environment; protected $environment;
/**
* The settings
*
* @var Settings
*/
protected $settings;
/**
* The processor for authorized payments.
*
* @var AuthorizedPaymentsProcessor
*/
protected $authorized_payments_processor;
/** /**
* RenewalHandler constructor. * RenewalHandler constructor.
* *
@ -81,6 +98,8 @@ class RenewalHandler {
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory. * @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
* @param PayerFactory $payer_factory The payer factory. * @param PayerFactory $payer_factory The payer factory.
* @param Environment $environment The environment. * @param Environment $environment The environment.
* @param Settings $settings The Settings.
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor.
*/ */
public function __construct( public function __construct(
LoggerInterface $logger, LoggerInterface $logger,
@ -88,7 +107,9 @@ class RenewalHandler {
OrderEndpoint $order_endpoint, OrderEndpoint $order_endpoint,
PurchaseUnitFactory $purchase_unit_factory, PurchaseUnitFactory $purchase_unit_factory,
PayerFactory $payer_factory, PayerFactory $payer_factory,
Environment $environment Environment $environment,
Settings $settings,
AuthorizedPaymentsProcessor $authorized_payments_processor
) { ) {
$this->logger = $logger; $this->logger = $logger;
@ -97,6 +118,8 @@ class RenewalHandler {
$this->purchase_unit_factory = $purchase_unit_factory; $this->purchase_unit_factory = $purchase_unit_factory;
$this->payer_factory = $payer_factory; $this->payer_factory = $payer_factory;
$this->environment = $environment; $this->environment = $environment;
$this->settings = $settings;
$this->authorized_payments_processor = $authorized_payments_processor;
} }
/** /**
@ -163,6 +186,14 @@ class RenewalHandler {
} }
$this->handle_new_order_status( $order, $wc_order ); $this->handle_new_order_status( $order, $wc_order );
if ( $this->capture_authorized_downloads( $order ) && AuthorizedPaymentsProcessor::SUCCESSFUL === $this->authorized_payments_processor->process( $wc_order ) ) {
$wc_order->add_order_note(
__( 'Payment successfully captured.', 'woocommerce-paypal-payments' )
);
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'true' );
$wc_order->update_status( 'completed' );
}
} }
/** /**
@ -213,4 +244,39 @@ class RenewalHandler {
return current( $tokens ); return current( $tokens );
} }
/**
* Returns if an order should be captured immediately.
*
* @param Order $order The PayPal order.
*
* @return bool
* @throws NotFoundException When a setting was not found.
*/
protected function capture_authorized_downloads( Order $order ): bool {
if (
! $this->settings->has( 'capture_for_virtual_only' )
|| ! $this->settings->get( 'capture_for_virtual_only' )
) {
return false;
}
if ( $order->intent() === 'CAPTURE' ) {
return false;
}
/**
* We fetch the order again as the authorize endpoint (from which the Order derives)
* drops the item's category, making it impossible to check, if purchase units contain
* physical goods.
*/
$order = $this->order_endpoint->order( $order->id() );
foreach ( $order->purchase_units() as $unit ) {
if ( $unit->contains_physical_goods() ) {
return false;
}
}
return true;
}
} }

View file

@ -22,6 +22,8 @@ use Mockery;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
class RenewalHandlerTest extends TestCase class RenewalHandlerTest extends TestCase
{ {
@ -45,6 +47,11 @@ class RenewalHandlerTest extends TestCase
$this->purchaseUnitFactory = Mockery::mock(PurchaseUnitFactory::class); $this->purchaseUnitFactory = Mockery::mock(PurchaseUnitFactory::class);
$this->payerFactory = Mockery::mock(PayerFactory::class); $this->payerFactory = Mockery::mock(PayerFactory::class);
$this->environment = new Environment(new Dictionary([])); $this->environment = new Environment(new Dictionary([]));
$authorizedPaymentProcessor = Mockery::mock(AuthorizedPaymentsProcessor::class);
$settings = Mockery::mock(Settings::class);
$settings
->shouldReceive('has')
->andReturnFalse();
$this->logger->shouldReceive('error')->andReturnUsing(function ($msg) { $this->logger->shouldReceive('error')->andReturnUsing(function ($msg) {
throw new Exception($msg); throw new Exception($msg);
@ -57,7 +64,9 @@ class RenewalHandlerTest extends TestCase
$this->orderEndpoint, $this->orderEndpoint,
$this->purchaseUnitFactory, $this->purchaseUnitFactory,
$this->payerFactory, $this->payerFactory,
$this->environment $this->environment,
$settings,
$authorizedPaymentProcessor
); );
} }