2022-03-01 15:12:54 +01:00
< ? php
/**
* Check if payment token is saved and updates order accordingly .
*
* @ package WooCommerce\PayPalCommerce\Vaulting
*/
declare ( strict_types = 1 );
namespace WooCommerce\PayPalCommerce\Vaulting ;
use Exception ;
use Psr\Log\LoggerInterface ;
use RuntimeException ;
2022-03-01 16:10:46 +01:00
use WC_Order ;
2022-03-01 15:12:54 +01:00
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint ;
2022-04-05 09:31:57 +03:00
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository ;
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait ;
2022-07-19 09:20:26 +03:00
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway ;
2022-04-05 09:31:57 +03:00
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway ;
2022-04-25 15:24:37 +03:00
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway ;
2022-03-01 15:12:54 +01:00
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor ;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings ;
2022-03-01 16:10:46 +01:00
/**
* Class PaymentTokenChecker
*/
2022-03-01 15:12:54 +01:00
class PaymentTokenChecker {
2022-04-05 09:31:57 +03:00
use FreeTrialHandlerTrait ;
2022-07-11 15:56:48 +04:00
const VAULTING_FAILED_META_KEY = '_ppcp_vaulting_failed' ;
2022-03-01 15:12:54 +01:00
/**
2022-03-01 16:10:46 +01:00
* The payment token repository .
*
2022-03-01 15:12:54 +01:00
* @ var PaymentTokenRepository
*/
protected $payment_token_repository ;
2022-04-05 09:31:57 +03:00
/**
* The order repository .
*
* @ var OrderRepository
*/
protected $order_repository ;
2022-03-01 15:12:54 +01:00
/**
2022-03-01 16:10:46 +01:00
* The settings .
*
2022-03-01 15:12:54 +01:00
* @ var Settings
*/
protected $settings ;
/**
2022-03-01 16:10:46 +01:00
* The authorized payments processor .
*
2022-03-01 15:12:54 +01:00
* @ var AuthorizedPaymentsProcessor
*/
protected $authorized_payments_processor ;
/**
2022-03-01 16:10:46 +01:00
* The payments endpoint .
*
2022-03-01 15:12:54 +01:00
* @ var PaymentsEndpoint
*/
protected $payments_endpoint ;
/**
2022-03-01 16:10:46 +01:00
* The logger .
*
2022-03-01 15:12:54 +01:00
* @ var LoggerInterface
*/
protected $logger ;
2022-03-01 16:10:46 +01:00
/**
* PaymentTokenChecker constructor .
*
* @ param PaymentTokenRepository $payment_token_repository The payment token repository .
2022-04-05 09:31:57 +03:00
* @ param OrderRepository $order_repository The order repository .
2022-03-01 16:10:46 +01:00
* @ param Settings $settings The settings .
* @ param AuthorizedPaymentsProcessor $authorized_payments_processor The authorized payments processor .
* @ param PaymentsEndpoint $payments_endpoint The payments endpoint .
* @ param LoggerInterface $logger The logger .
*/
2022-03-01 15:12:54 +01:00
public function __construct (
PaymentTokenRepository $payment_token_repository ,
2022-04-05 09:31:57 +03:00
OrderRepository $order_repository ,
2022-03-01 15:12:54 +01:00
Settings $settings ,
AuthorizedPaymentsProcessor $authorized_payments_processor ,
PaymentsEndpoint $payments_endpoint ,
LoggerInterface $logger
2022-03-01 16:10:46 +01:00
) {
$this -> payment_token_repository = $payment_token_repository ;
2022-04-05 09:31:57 +03:00
$this -> order_repository = $order_repository ;
2022-03-01 16:10:46 +01:00
$this -> settings = $settings ;
2022-03-01 15:12:54 +01:00
$this -> authorized_payments_processor = $authorized_payments_processor ;
2022-03-01 16:10:46 +01:00
$this -> payments_endpoint = $payments_endpoint ;
$this -> logger = $logger ;
2022-03-01 15:12:54 +01:00
}
2022-03-01 16:10:46 +01:00
/**
* Check if payment token exist and updates order accordingly .
*
2022-03-16 11:50:01 +01:00
* @ param int $order_id The order ID .
* @ param int $customer_id The customer ID .
* @ param string $intent The intent from settings when order was created .
2022-03-01 16:10:46 +01:00
* @ return void
*/
2022-03-16 11:50:01 +01:00
public function check_and_update ( int $order_id , int $customer_id , string $intent ) : void {
2022-03-02 16:51:22 +01:00
$wc_order = wc_get_order ( $order_id );
2022-03-04 12:02:43 +01:00
if ( ! is_a ( $wc_order , WC_Order :: class ) ) {
return ;
}
2022-03-16 11:50:01 +01:00
if ( $wc_order -> get_status () === 'processing' || 'capture' !== $intent ) {
2022-03-02 16:51:22 +01:00
return ;
}
2022-03-01 15:12:54 +01:00
$tokens = $this -> payment_token_repository -> all_for_user_id ( $customer_id );
2022-07-11 15:56:48 +04:00
$subscription_behavior_when_vault_fails_setting_name = 'subscription_behavior_when_vault_fails' ;
$subscription_behavior_when_vault_fails = $this -> settings -> get ( $subscription_behavior_when_vault_fails_setting_name );
if ( $tokens || $subscription_behavior_when_vault_fails === 'capture_auth' ) {
2022-03-01 16:10:46 +01:00
try {
2022-04-05 09:31:57 +03:00
if ( $this -> is_free_trial_order ( $wc_order ) ) {
2022-07-19 09:20:26 +03:00
if ( in_array ( $wc_order -> get_payment_method (), array ( CreditCardGateway :: ID , CardButtonGateway :: ID ), true )
2022-04-27 23:50:23 +03:00
|| ( PayPalGateway :: ID === $wc_order -> get_payment_method () && 'card' === $wc_order -> get_meta ( PayPalGateway :: ORDER_PAYMENT_SOURCE_META_KEY ) )
2022-04-25 15:24:37 +03:00
) {
2022-04-05 09:31:57 +03:00
$order = $this -> order_repository -> for_wc_order ( $wc_order );
$this -> authorized_payments_processor -> void_authorizations ( $order );
$wc_order -> payment_complete ();
}
return ;
}
2022-07-11 15:56:48 +04:00
if ( ! $tokens ) {
update_post_meta ( $wc_order -> get_id (), self :: VAULTING_FAILED_META_KEY , $subscription_behavior_when_vault_fails );
}
2022-03-04 12:02:43 +01:00
$this -> capture_authorized_payment ( $wc_order );
2022-07-11 15:56:48 +04:00
if ( ! $tokens && $subscription_behavior_when_vault_fails === 'capture_auth' ) {
$subscriptions = function_exists ( 'wcs_get_subscriptions_for_order' ) ? wcs_get_subscriptions_for_order ( $wc_order ) : array ();
foreach ( $subscriptions as $subscription ) {
try {
$subscription -> set_requires_manual_renewal ( true );
$subscription -> save ();
$message = __ ( 'Subscription set to Manual Renewal because the payment method could not be saved at PayPal' , 'woocommerce-paypal-payments' );
$wc_order -> add_order_note ( $message );
} catch ( Exception $exception ) {
$this -> logger -> error ( " Could not update payment method on subscription # { $subscription -> get_id () } " . $exception -> getMessage () );
}
}
}
2022-03-08 12:00:09 +01:00
} catch ( Exception $exception ) {
$this -> logger -> error ( $exception -> getMessage () );
2022-03-01 16:10:46 +01:00
}
return ;
2022-03-01 15:12:54 +01:00
}
$this -> logger -> error ( " Payment for subscription parent order # { $order_id } was not saved on PayPal. " );
try {
2022-04-05 09:31:57 +03:00
$order = $this -> order_repository -> for_wc_order ( $wc_order );
2022-07-11 15:56:48 +04:00
update_post_meta ( $wc_order -> get_id (), self :: VAULTING_FAILED_META_KEY , $subscription_behavior_when_vault_fails );
2022-04-05 09:31:57 +03:00
$this -> authorized_payments_processor -> void_authorizations ( $order );
2022-03-01 15:12:54 +01:00
} catch ( RuntimeException $exception ) {
2022-03-01 16:10:46 +01:00
$this -> logger -> warning ( $exception -> getMessage () );
2022-03-01 15:12:54 +01:00
}
2022-03-01 16:10:46 +01:00
$this -> update_failed_status ( $wc_order );
2022-07-11 15:56:48 +04:00
2022-03-01 15:12:54 +01:00
}
/**
2022-03-04 12:02:43 +01:00
* Captures authorized payments for the given WC order .
2022-03-01 16:10:46 +01:00
*
2022-03-04 12:02:43 +01:00
* @ param WC_Order $wc_order The WC order .
2022-03-08 12:00:09 +01:00
* @ throws Exception When there is a problem capturing the payment .
2022-03-01 15:12:54 +01:00
*/
2022-03-04 12:02:43 +01:00
private function capture_authorized_payment ( WC_Order $wc_order ) : void {
2022-03-01 15:12:54 +01:00
if ( $this -> settings -> has ( 'intent' ) && strtoupper ( ( string ) $this -> settings -> get ( 'intent' ) ) === 'CAPTURE' ) {
2022-03-08 12:00:09 +01:00
if ( ! $this -> authorized_payments_processor -> capture_authorized_payment ( $wc_order ) ) {
throw new Exception ( " Could not capture payment for order: # { $wc_order -> get_id () } " );
}
2022-03-01 15:12:54 +01:00
}
}
/**
2022-03-01 16:10:46 +01:00
* Updates WC order and subscription status to failed and canceled respectively .
*
* @ param WC_Order $wc_order The WC order .
2022-03-01 15:12:54 +01:00
*/
2022-03-01 16:10:46 +01:00
private function update_failed_status ( WC_Order $wc_order ) : void {
2022-07-11 15:56:48 +04:00
$error_message = __ ( 'Subscription payment failed because the payment method could not be saved at PayPal. Contact PayPal MTS for guidance.' , 'woocommerce-paypal-payments' );
2022-03-01 15:12:54 +01:00
$wc_order -> update_status ( 'failed' , $error_message );
2022-03-04 12:02:43 +01:00
/**
* Function already exist in Subscription plugin
*
* @ psalm - suppress UndefinedFunction
*/
2022-03-01 16:10:46 +01:00
$subscriptions = wcs_get_subscriptions_for_order ( $wc_order -> get_id () );
2022-03-01 15:12:54 +01:00
foreach ( $subscriptions as $key => $subscription ) {
2022-03-01 16:10:46 +01:00
if ( $subscription -> get_parent_id () === $wc_order -> get_id () ) {
2022-03-01 15:12:54 +01:00
try {
$subscription -> update_status ( 'cancelled' );
break ;
} catch ( Exception $exception ) {
$this -> logger -> error ( " Could not update cancelled status on subscription # { $subscription -> get_id () } " . $exception -> getMessage () );
}
}
}
}
}