Automattic\WooCommerce\Gateways\PayPal

Request::capture_authorized_paymentpublicWC 1.0

Capture a PayPal payment that has been authorized.

Method of the class: Request{}

No Hooks.

Returns

null. Nothing (null).

Usage

$Request = new Request();
$Request->capture_authorized_payment( ?WC_Order $order ): void;
?WC_Order $order(required)
.

Request::capture_authorized_payment() code WC 10.7.0

public function capture_authorized_payment( ?WC_Order $order ): void {
	if ( ! $order ) {
		\WC_Gateway_Paypal::log( 'Order not found to capture authorized payment.' );
		return;
	}

	$paypal_order_id = $order->get_meta( PayPalConstants::PAYPAL_ORDER_META_ORDER_ID, true );
	// Skip if the PayPal Order ID is not found. This means the order was not created via the Orders v2 API.
	if ( ! $paypal_order_id ) {
		\WC_Gateway_Paypal::log( 'PayPal Order ID not found to capture authorized payment. Order ID: ' . $order->get_id() );
		return;
	}

	$capture_id = $order->get_meta( PayPalConstants::PAYPAL_ORDER_META_CAPTURE_ID, true );
	// Skip if the payment is already captured.
	if ( $capture_id ) {
		\WC_Gateway_Paypal::log( 'PayPal payment is already captured. PayPal capture ID: ' . $capture_id . '. Order ID: ' . $order->get_id() );
		return;
	}

	$paypal_status = $order->get_meta( PayPalConstants::PAYPAL_ORDER_META_STATUS, true );

	// Skip if the payment is already captured.
	if ( PayPalConstants::STATUS_CAPTURED === $paypal_status || PayPalConstants::STATUS_COMPLETED === $paypal_status ) {
		\WC_Gateway_Paypal::log( 'PayPal payment is already captured. Skipping capture. Order ID: ' . $order->get_id() );
		return;
	}

	// Skip if the payment requires payer action.
	if ( PayPalConstants::STATUS_PAYER_ACTION_REQUIRED === $paypal_status ) {
		\WC_Gateway_Paypal::log( 'PayPal payment requires payer action. Skipping capture. Order ID: ' . $order->get_id() );
		return;
	}

	// Skip if the payment is voided.
	if ( PayPalConstants::VOIDED === $paypal_status ) {
		\WC_Gateway_Paypal::log( 'PayPal payment voided. Skipping capture. Order ID: ' . $order->get_id() );
		return;
	}

	$authorization_id = $this->get_authorization_id_for_capture( $order );
	if ( ! $authorization_id ) {
		\WC_Gateway_Paypal::log( 'Authorization ID not found to capture authorized payment. Order ID: ' . $order->get_id() );
		return;
	}

	$paypal_debug_id = null;
	$http_code       = null;

	try {
		$request_body = array(
			'test_mode'        => $this->gateway->testmode,
			'authorization_id' => $authorization_id,
			'paypal_order_id'  => $paypal_order_id,
		);
		$response     = $this->send_wpcom_proxy_request( 'POST', self::WPCOM_PROXY_PAYMENT_CAPTURE_AUTH_ENDPOINT, $request_body );

		if ( is_wp_error( $response ) ) {
			throw new Exception( 'PayPal capture payment request failed. Response error: ' . $response->get_error_message() );
		}

		$http_code             = wp_remote_retrieve_response_code( $response );
		$body                  = wp_remote_retrieve_body( $response );
		$response_data         = json_decode( $body, true );
		$issue                 = isset( $response_data['details'][0]['issue'] ) ? $response_data['details'][0]['issue'] : '';
		$auth_already_captured = 422 === $http_code && PayPalConstants::PAYPAL_ISSUE_AUTHORIZATION_ALREADY_CAPTURED === $issue;

		if ( 200 !== $http_code && 201 !== $http_code && ! $auth_already_captured ) {
			$paypal_debug_id = isset( $response_data['debug_id'] ) ? $response_data['debug_id'] : null;
			throw new Exception( 'PayPal capture payment failed. Response status: ' . $http_code . '. Response body: ' . $body );
		}

		// Set custom status for successful capture response, or if the authorization was already captured.
		$order->update_meta_data( PayPalConstants::PAYPAL_ORDER_META_STATUS, PayPalConstants::STATUS_CAPTURED );
		$order->save();
	} catch ( Exception $e ) {
		\WC_Gateway_Paypal::log( $e->getMessage() );

		$note_message = sprintf(
			__( 'PayPal capture authorized payment failed', 'woocommerce' ),
		);

		// Scenario 1: Capture auth API call returned 404 (authorization object does not exist).
		// If the authorization ID is not found (404 response), set the '_paypal_authorization_checked' flag.
		// This flag indicates that we've made an API call to capture PayPal payment and no authorization object was found with this authorization ID.
		// This prevents repeated API calls for orders that have no authorization data.
		if ( 404 === $http_code ) {
			$paypal_dashboard_url = $this->gateway->testmode
				? 'https://www.sandbox.paypal.com/unifiedtransactions'
				: 'https://www.paypal.com/unifiedtransactions';

			$note_message .= sprintf(
				/* translators: %1$s: Authorization ID, %2$s: open link tag, %3$s: close link tag */
				__( '. Authorization ID: %1$s not found. Please log into your %2$sPayPal account%3$s to capture the payment', 'woocommerce' ),
				esc_html( $authorization_id ),
				'<a href="' . esc_url( $paypal_dashboard_url ) . '" target="_blank">',
				'</a>'
			);
			$order->update_meta_data( PayPalConstants::PAYPAL_ORDER_META_AUTHORIZATION_CHECKED, 'yes' );
		}

		if ( $paypal_debug_id ) {
			$note_message .= sprintf(
				/* translators: %s: PayPal debug ID */
				__( '. PayPal debug ID: %s', 'woocommerce' ),
				$paypal_debug_id
			);
		}

		$order->add_order_note( $note_message );
		$order->save();
	}
}