diff --git a/modules/ppcp-subscription/services.php b/modules/ppcp-subscription/services.php index b4f25c52d..e3d290395 100644 --- a/modules/ppcp-subscription/services.php +++ b/modules/ppcp-subscription/services.php @@ -24,13 +24,17 @@ return array( $purchase_unit_factory = $container->get( 'api.factory.purchase-unit' ); $payer_factory = $container->get( 'api.factory.payer' ); $environment = $container->get( 'onboarding.environment' ); + $settings = $container->get( 'wcgateway.settings' ); + $authorized_payments_processor = $container->get( 'wcgateway.processor.authorized-payments' ); return new RenewalHandler( $logger, $repository, $endpoint, $purchase_unit_factory, $payer_factory, - $environment + $environment, + $settings, + $authorized_payments_processor ); }, 'subscription.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository { diff --git a/modules/ppcp-subscription/src/RenewalHandler.php b/modules/ppcp-subscription/src/RenewalHandler.php index 2103e443d..e0021cb1f 100644 --- a/modules/ppcp-subscription/src/RenewalHandler.php +++ b/modules/ppcp-subscription/src/RenewalHandler.php @@ -10,16 +10,19 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Subscription; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; +use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken; use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\Onboarding\Environment; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; use Psr\Log\LoggerInterface; +use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor; use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait; use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait; use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait; +use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; /** * Class RenewalHandler @@ -72,15 +75,31 @@ class RenewalHandler { */ protected $environment; + /** + * The settings + * + * @var Settings + */ + protected $settings; + + /** + * The processor for authorized payments. + * + * @var AuthorizedPaymentsProcessor + */ + protected $authorized_payments_processor; + /** * RenewalHandler constructor. * - * @param LoggerInterface $logger The logger. - * @param PaymentTokenRepository $repository The payment token repository. - * @param OrderEndpoint $order_endpoint The order endpoint. - * @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory. - * @param PayerFactory $payer_factory The payer factory. - * @param Environment $environment The environment. + * @param LoggerInterface $logger The logger. + * @param PaymentTokenRepository $repository The payment token repository. + * @param OrderEndpoint $order_endpoint The order endpoint. + * @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory. + * @param PayerFactory $payer_factory The payer factory. + * @param Environment $environment The environment. + * @param Settings $settings The Settings. + * @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor. */ public function __construct( LoggerInterface $logger, @@ -88,15 +107,19 @@ class RenewalHandler { OrderEndpoint $order_endpoint, PurchaseUnitFactory $purchase_unit_factory, PayerFactory $payer_factory, - Environment $environment + Environment $environment, + Settings $settings, + AuthorizedPaymentsProcessor $authorized_payments_processor ) { - $this->logger = $logger; - $this->repository = $repository; - $this->order_endpoint = $order_endpoint; - $this->purchase_unit_factory = $purchase_unit_factory; - $this->payer_factory = $payer_factory; - $this->environment = $environment; + $this->logger = $logger; + $this->repository = $repository; + $this->order_endpoint = $order_endpoint; + $this->purchase_unit_factory = $purchase_unit_factory; + $this->payer_factory = $payer_factory; + $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 ); + + 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 ); } + + /** + * 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; + } } diff --git a/tests/PHPUnit/Subscription/RenewalHandlerTest.php b/tests/PHPUnit/Subscription/RenewalHandlerTest.php index 036e8fd85..3dadc4889 100644 --- a/tests/PHPUnit/Subscription/RenewalHandlerTest.php +++ b/tests/PHPUnit/Subscription/RenewalHandlerTest.php @@ -22,6 +22,8 @@ use Mockery; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; +use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor; +use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; class RenewalHandlerTest extends TestCase { @@ -45,6 +47,11 @@ class RenewalHandlerTest extends TestCase $this->purchaseUnitFactory = Mockery::mock(PurchaseUnitFactory::class); $this->payerFactory = Mockery::mock(PayerFactory::class); $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) { throw new Exception($msg); @@ -57,7 +64,9 @@ class RenewalHandlerTest extends TestCase $this->orderEndpoint, $this->purchaseUnitFactory, $this->payerFactory, - $this->environment + $this->environment, + $settings, + $authorizedPaymentProcessor ); }