mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 12:25:15 +08:00
Cleanup gateways, move process_payment
This commit is contained in:
parent
0ce3af03c3
commit
1a5eb500a5
5 changed files with 342 additions and 370 deletions
|
@ -59,7 +59,6 @@ return array(
|
|||
$order_processor = $container->get( 'wcgateway.order-processor' );
|
||||
$settings_renderer = $container->get( 'wcgateway.settings.render' );
|
||||
$funding_source_renderer = $container->get( 'wcgateway.funding-source.renderer' );
|
||||
$authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
|
||||
|
@ -68,8 +67,6 @@ return array(
|
|||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
|
||||
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$environment = $container->get( 'onboarding.environment' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$api_shop_country = $container->get( 'api.shop.country' );
|
||||
|
@ -77,7 +74,6 @@ return array(
|
|||
$settings_renderer,
|
||||
$funding_source_renderer,
|
||||
$order_processor,
|
||||
$authorized_payments,
|
||||
$settings,
|
||||
$session_handler,
|
||||
$refund_processor,
|
||||
|
@ -87,10 +83,7 @@ return array(
|
|||
$page_id,
|
||||
$environment,
|
||||
$payment_token_repository,
|
||||
$container->get( 'api.factory.shipping-preference' ),
|
||||
$logger,
|
||||
$payments_endpoint,
|
||||
$order_endpoint,
|
||||
$api_shop_country
|
||||
);
|
||||
},
|
||||
|
|
|
@ -9,20 +9,30 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
|
@ -31,7 +41,7 @@ use Psr\Container\ContainerInterface;
|
|||
*/
|
||||
class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||
|
||||
use ProcessPaymentTrait;
|
||||
use ProcessPaymentTrait, OrderMetaTrait, TransactionIdHandlingTrait, PaymentsStatusHandlingTrait, FreeTrialHandlerTrait;
|
||||
|
||||
const ID = 'ppcp-credit-card-gateway';
|
||||
|
||||
|
@ -203,15 +213,25 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
Environment $environment,
|
||||
PaymentsEndpoint $payments_endpoint
|
||||
) {
|
||||
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->config = $config;
|
||||
$this->module_url = $module_url;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->state = $state;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger;
|
||||
$this->environment = $environment;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
|
||||
if ( $state->current_state() === State::STATE_ONBOARDED ) {
|
||||
$this->supports = array( 'refunds' );
|
||||
|
@ -261,18 +281,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
|
||||
$this->module_url = $module_url;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -301,7 +309,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
* @return string
|
||||
*/
|
||||
public function generate_ppcp_html(): string {
|
||||
|
||||
ob_start();
|
||||
$this->settings_renderer->render();
|
||||
$content = ob_get_contents();
|
||||
|
@ -409,6 +416,166 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
return $this->is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process payment for a WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new GatewayGenericException( new Exception( 'WC order was not found.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen a saved credit card payment.
|
||||
*/
|
||||
$saved_credit_card = filter_input( INPUT_POST, 'saved_credit_card', FILTER_SANITIZE_STRING );
|
||||
$change_payment = filter_input( INPUT_POST, 'woocommerce_change_payment', FILTER_SANITIZE_STRING );
|
||||
if ( $saved_credit_card && ! isset( $change_payment ) ) {
|
||||
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$customer = new \WC_Customer( $user_id );
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( (int) $customer->get_id() );
|
||||
|
||||
$selected_token = null;
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->id() === $saved_credit_card ) {
|
||||
$selected_token = $token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $selected_token ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new GatewayGenericException( new Exception( 'Saved card token not found.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payer = $this->payer_factory->from_customer( $customer );
|
||||
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$purchase_unit,
|
||||
''
|
||||
);
|
||||
|
||||
try {
|
||||
$order = $this->order_endpoint->create(
|
||||
array( $purchase_unit ),
|
||||
$shipping_preference,
|
||||
$payer,
|
||||
$selected_token
|
||||
);
|
||||
|
||||
$this->add_paypal_meta( $wc_order, $order, $this->environment() );
|
||||
|
||||
if ( ! $order->status()->is( OrderStatus::COMPLETED ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new GatewayGenericException( new Exception( "Unexpected status for order {$order->id()} using a saved card: {$order->status()->name()}." ) )
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! in_array(
|
||||
$order->intent(),
|
||||
array( 'CAPTURE', 'AUTHORIZE' ),
|
||||
true
|
||||
) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new GatewayGenericException( new Exception( "Could neither capture nor authorize order {$order->id()} using a saved card. Status: {$order->status()->name()}. Intent: {$order->intent()}." ) )
|
||||
);
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'AUTHORIZE' ) {
|
||||
$order = $this->order_endpoint->authorize( $order );
|
||||
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' );
|
||||
}
|
||||
|
||||
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
||||
if ( $transaction_id ) {
|
||||
$this->update_transaction_id( $transaction_id, $wc_order );
|
||||
}
|
||||
|
||||
$this->handle_new_order_status( $order, $wc_order );
|
||||
|
||||
if ( $this->is_free_trial_order( $wc_order ) ) {
|
||||
$this->authorized_payments_processor->void_authorizations( $order );
|
||||
$wc_order->payment_complete();
|
||||
} elseif ( $this->config->has( 'intent' ) && strtoupper( (string) $this->config->get( 'intent' ) ) === 'CAPTURE' ) {
|
||||
$this->authorized_payments_processor->capture_authorized_payment( $wc_order );
|
||||
}
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen change Subscription payment.
|
||||
*/
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
||||
if ( $saved_credit_card ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_credit_card );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the WC_Order is paid through the approved webhook.
|
||||
*/
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
try {
|
||||
if ( ! $this->order_processor->process( $wc_order ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
$this->order_processor->last_error()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
as_schedule_single_action(
|
||||
time() + ( 1 * MINUTE_IN_SECONDS ),
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
array(
|
||||
'order_id' => $order_id,
|
||||
'customer_id' => $wc_order->get_customer_id(),
|
||||
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalApiException $error ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
|
|
|
@ -9,18 +9,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
|
@ -32,7 +35,7 @@ use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
|||
*/
|
||||
class PayPalGateway extends \WC_Payment_Gateway {
|
||||
|
||||
use ProcessPaymentTrait;
|
||||
use ProcessPaymentTrait, FreeTrialHandlerTrait;
|
||||
|
||||
const ID = 'ppcp-gateway';
|
||||
const INTENT_META_KEY = '_ppcp_paypal_intent';
|
||||
|
@ -63,13 +66,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
*/
|
||||
protected $order_processor;
|
||||
|
||||
/**
|
||||
* The processor for authorized payments.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor
|
||||
*/
|
||||
protected $authorized_payments_processor;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
|
@ -119,27 +115,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
*/
|
||||
protected $payment_token_repository;
|
||||
|
||||
/**
|
||||
* The shipping_preference factory.
|
||||
*
|
||||
* @var ShippingPreferenceFactory
|
||||
*/
|
||||
private $shipping_preference_factory;
|
||||
|
||||
/**
|
||||
* The payments endpoint
|
||||
*
|
||||
* @var PaymentsEndpoint
|
||||
*/
|
||||
protected $payments_endpoint;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
protected $order_endpoint;
|
||||
|
||||
/**
|
||||
* Whether the plugin is in onboarded state.
|
||||
*
|
||||
|
@ -178,30 +153,25 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
/**
|
||||
* PayPalGateway constructor.
|
||||
*
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param State $state The state.
|
||||
* @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 Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param string $api_shop_country The api shop country.
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param State $state The state.
|
||||
* @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 Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $api_shop_country The api shop country.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
FundingSourceRenderer $funding_source_renderer,
|
||||
OrderProcessor $order_processor,
|
||||
AuthorizedPaymentsProcessor $authorized_payments_processor,
|
||||
ContainerInterface $config,
|
||||
SessionHandler $session_handler,
|
||||
RefundProcessor $refund_processor,
|
||||
|
@ -211,37 +181,25 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
string $page_id,
|
||||
Environment $environment,
|
||||
PaymentTokenRepository $payment_token_repository,
|
||||
ShippingPreferenceFactory $shipping_preference_factory,
|
||||
LoggerInterface $logger,
|
||||
PaymentsEndpoint $payments_endpoint,
|
||||
OrderEndpoint $order_endpoint,
|
||||
string $api_shop_country
|
||||
) {
|
||||
|
||||
$this->id = self::ID;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->funding_source_renderer = $funding_source_renderer;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->page_id = $page_id;
|
||||
$this->environment = $environment;
|
||||
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
||||
$this->id = self::ID;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->authorized_payments = $authorized_payments_processor;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->page_id = $page_id;
|
||||
$this->environment = $environment;
|
||||
$this->logger = $logger;
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->funding_source_renderer = $funding_source_renderer;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->state = $state;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->page_id = $page_id;
|
||||
$this->environment = $environment;
|
||||
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->logger = $logger;
|
||||
$this->api_shop_country = $api_shop_country;
|
||||
|
||||
if ( $this->onboarded ) {
|
||||
$this->supports = array( 'refunds' );
|
||||
|
@ -291,13 +249,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
$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;
|
||||
$this->state = $state;
|
||||
$this->api_shop_country = $api_shop_country;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -306,7 +257,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
* @return bool
|
||||
*/
|
||||
public function needs_setup(): bool {
|
||||
|
||||
return ! $this->onboarded;
|
||||
}
|
||||
|
||||
|
@ -340,9 +290,8 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
* @return string
|
||||
*/
|
||||
public function generate_ppcp_html(): string {
|
||||
|
||||
ob_start();
|
||||
$this->settings_renderer->render( false );
|
||||
$this->settings_renderer->render();
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $content;
|
||||
|
@ -450,6 +399,126 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
/**
|
||||
* Process payment for a WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new GatewayGenericException( new Exception( 'WC order was not found.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
$funding_source = filter_input( INPUT_POST, 'ppcp-funding-source', FILTER_SANITIZE_STRING );
|
||||
|
||||
if ( 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) ) {
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
||||
if ( ! array_filter(
|
||||
$tokens,
|
||||
function ( PaymentToken $token ): bool {
|
||||
return isset( $token->source()->paypal );
|
||||
}
|
||||
) ) {
|
||||
return $this->handle_payment_failure( $wc_order, new Exception( 'No saved PayPal account.' ) );
|
||||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen change Subscription payment.
|
||||
*/
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
||||
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
||||
if ( $saved_paypal_payment ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the WC_Order is paid through the approved webhook.
|
||||
*/
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
try {
|
||||
if ( ! $this->order_processor->process( $wc_order ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
$this->order_processor->last_error()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
as_schedule_single_action(
|
||||
time() + ( 1 * MINUTE_IN_SECONDS ),
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
array(
|
||||
'order_id' => $order_id,
|
||||
'customer_id' => $wc_order->get_customer_id(),
|
||||
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalApiException $error ) {
|
||||
if ( $error->has_detail( 'INSTRUMENT_DECLINED' ) ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Instrument declined. ', 'woocommerce-paypal-payments' ) . $error->details()[0]->description ?? ''
|
||||
);
|
||||
|
||||
$this->session_handler->increment_insufficient_funding_tries();
|
||||
if ( $this->session_handler->insufficient_funding_tries() >= 3 ) {
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new Exception(
|
||||
__( 'Please use a different payment method.', 'woocommerce-paypal-payments' ),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$host = $this->config->has( 'sandbox_on' ) && $this->config->get( 'sandbox_on' ) ?
|
||||
'https://www.sandbox.paypal.com/' : 'https://www.paypal.com/';
|
||||
$url = $host . 'checkoutnow?token=' . $this->session_handler->order()->id();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $url,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
|
|
|
@ -12,243 +12,12 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
|||
use Exception;
|
||||
use Throwable;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
|
||||
/**
|
||||
* Trait ProcessPaymentTrait
|
||||
*/
|
||||
trait ProcessPaymentTrait {
|
||||
|
||||
use OrderMetaTrait, PaymentsStatusHandlingTrait, TransactionIdHandlingTrait, FreeTrialHandlerTrait;
|
||||
|
||||
/**
|
||||
* Process a payment for an WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws RuntimeException When processing payment fails.
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new GatewayGenericException( new Exception( 'WC order was not found.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
$payment_method = filter_input( INPUT_POST, 'payment_method', FILTER_SANITIZE_STRING );
|
||||
$funding_source = filter_input( INPUT_POST, 'ppcp-funding-source', FILTER_SANITIZE_STRING );
|
||||
|
||||
/**
|
||||
* If customer has chosen a saved credit card payment.
|
||||
*/
|
||||
$saved_credit_card = filter_input( INPUT_POST, 'saved_credit_card', FILTER_SANITIZE_STRING );
|
||||
$change_payment = filter_input( INPUT_POST, 'woocommerce_change_payment', FILTER_SANITIZE_STRING );
|
||||
if ( CreditCardGateway::ID === $payment_method && $saved_credit_card && ! isset( $change_payment ) ) {
|
||||
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$customer = new \WC_Customer( $user_id );
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( (int) $customer->get_id() );
|
||||
|
||||
$selected_token = null;
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->id() === $saved_credit_card ) {
|
||||
$selected_token = $token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $selected_token ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new GatewayGenericException( new Exception( 'Saved card token not found.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payer = $this->payer_factory->from_customer( $customer );
|
||||
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$purchase_unit,
|
||||
''
|
||||
);
|
||||
|
||||
try {
|
||||
$order = $this->order_endpoint->create(
|
||||
array( $purchase_unit ),
|
||||
$shipping_preference,
|
||||
$payer,
|
||||
$selected_token
|
||||
);
|
||||
|
||||
$this->add_paypal_meta( $wc_order, $order, $this->environment() );
|
||||
|
||||
if ( ! $order->status()->is( OrderStatus::COMPLETED ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new GatewayGenericException( new Exception( "Unexpected status for order {$order->id()} using a saved card: {$order->status()->name()}." ) )
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! in_array(
|
||||
$order->intent(),
|
||||
array( 'CAPTURE', 'AUTHORIZE' ),
|
||||
true
|
||||
) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new GatewayGenericException( new Exception( "Could neither capture nor authorize order {$order->id()} using a saved card. Status: {$order->status()->name()}. Intent: {$order->intent()}." ) )
|
||||
);
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'AUTHORIZE' ) {
|
||||
$order = $this->order_endpoint->authorize( $order );
|
||||
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' );
|
||||
}
|
||||
|
||||
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
||||
if ( $transaction_id ) {
|
||||
$this->update_transaction_id( $transaction_id, $wc_order );
|
||||
}
|
||||
|
||||
$this->handle_new_order_status( $order, $wc_order );
|
||||
|
||||
if ( $this->is_free_trial_order( $wc_order ) ) {
|
||||
$this->authorized_payments_processor->void_authorizations( $order );
|
||||
$wc_order->payment_complete();
|
||||
} elseif ( $this->config->has( 'intent' ) && strtoupper( (string) $this->config->get( 'intent' ) ) === 'CAPTURE' ) {
|
||||
$this->authorized_payments_processor->capture_authorized_payment( $wc_order );
|
||||
}
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
if ( PayPalGateway::ID === $payment_method && 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) ) {
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
||||
if ( ! array_filter(
|
||||
$tokens,
|
||||
function ( PaymentToken $token ): bool {
|
||||
return isset( $token->source()->paypal );
|
||||
}
|
||||
) ) {
|
||||
return $this->handle_payment_failure( $wc_order, new Exception( 'No saved PayPal account.' ) );
|
||||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen change Subscription payment.
|
||||
*/
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
||||
if ( 'ppcp-credit-card-gateway' === $this->id && $saved_credit_card ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_credit_card );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
||||
if ( 'ppcp-gateway' === $this->id && $saved_paypal_payment ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the WC_Order is paid through the approved webhook.
|
||||
*/
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
try {
|
||||
if ( $this->order_processor->process( $wc_order ) ) {
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
as_schedule_single_action(
|
||||
time() + ( 1 * MINUTE_IN_SECONDS ),
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
array(
|
||||
'order_id' => $order_id,
|
||||
'customer_id' => $wc_order->get_customer_id(),
|
||||
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart(); // Probably redundant.
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
} catch ( PayPalApiException $error ) {
|
||||
if ( $error->has_detail( 'INSTRUMENT_DECLINED' ) ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Instrument declined. ', 'woocommerce-paypal-payments' ) . $error->details()[0]->description ?? ''
|
||||
);
|
||||
|
||||
$this->session_handler->increment_insufficient_funding_tries();
|
||||
if ( $this->session_handler->insufficient_funding_tries() >= 3 ) {
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new Exception(
|
||||
__( 'Please use a different payment method.', 'woocommerce-paypal-payments' ),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$host = $this->config->has( 'sandbox_on' ) && $this->config->get( 'sandbox_on' ) ?
|
||||
'https://www.sandbox.paypal.com/' : 'https://www.paypal.com/';
|
||||
$url = $host . 'checkoutnow?token=' . $this->session_handler->order()->id();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $url,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
$this->order_processor->last_error()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if PayPal or Credit Card gateways are enabled.
|
||||
*
|
||||
|
@ -341,11 +110,4 @@ trait ProcessPaymentTrait {
|
|||
}
|
||||
return $output . ' ' . $this->format_exception( $prev );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the environment.
|
||||
*
|
||||
* @return Environment
|
||||
*/
|
||||
abstract protected function environment(): Environment;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue