Automattic\WooCommerce\Gateways\PayPal

Request::authorize_or_capture_paymentpublicWC 1.0

Authorize or capture a PayPal payment using the Orders v2 API.

This method authorizes or captures a PayPal payment and updates the order status.

Method of the class: Request{}

No Hooks.

Returns

null. Nothing (null).

Usage

$Request = new Request();
$Request->authorize_or_capture_payment( ?WC_Order $order, ?string $action_url, $action, $is_retry ): void;
?WC_Order $order(required)
.
?string $action_url(required)
.
$action(string)
The action to perform. Either 'authorize' or 'capture'.
Default: PayPalConstants::PAYMENT_ACTION_CAPTURE
$is_retry(true|false)
Whether the payment is being retried.
Default: false

Request::authorize_or_capture_payment() code WC 10.8.1

public function authorize_or_capture_payment( ?WC_Order $order, ?string $action_url, string $action = PayPalConstants::PAYMENT_ACTION_CAPTURE, bool $is_retry = false ): void {
	if ( ! $order ) {
		\WC_Gateway_Paypal::log( 'Order not found to authorize or capture payment.' );
		return;
	}

	$paypal_debug_id = null;
	$paypal_order_id = $order->get_meta( PayPalConstants::PAYPAL_ORDER_META_ORDER_ID );
	if ( ! $paypal_order_id ) {
		\WC_Gateway_Paypal::log( 'PayPal order ID not found. Cannot ' . $action . ' payment.' );
		return;
	}

	if ( ! $action_url || ! filter_var( $action_url, FILTER_VALIDATE_URL ) ) {
		\WC_Gateway_Paypal::log( 'Invalid or missing action URL. Cannot ' . $action . ' payment.' );
		return;
	}

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

	try {
		if ( PayPalConstants::PAYMENT_ACTION_CAPTURE === $action ) {
			$endpoint     = self::WPCOM_PROXY_PAYMENT_CAPTURE_ENDPOINT;
			$request_body = array(
				'capture_url'     => $action_url,
				'paypal_order_id' => $paypal_order_id,
				'test_mode'       => $this->gateway->testmode,
			);
		} else {
			$endpoint     = self::WPCOM_PROXY_PAYMENT_AUTHORIZE_ENDPOINT;
			$request_body = array(
				'authorize_url'   => $action_url,
				'paypal_order_id' => $paypal_order_id,
				'test_mode'       => $this->gateway->testmode,
			);
		}

		$response = $this->send_wpcom_proxy_request( 'POST', $endpoint, $request_body );

		if ( is_wp_error( $response ) ) {
			throw new Exception( 'PayPal ' . $action . ' 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'] : '';
		$duplicate_invoice_id = 422 === $http_code && PayPalConstants::PAYPAL_ISSUE_DUPLICATE_INVOICE_ID === $issue;

		// If the payment failed with a duplicate invoice ID error and it's not a retry, handle it.
		// If it's a retry, don't handle it again.
		if ( $duplicate_invoice_id && ! $is_retry ) {
			$this->handle_duplicate_invoice_id( $order, $paypal_order_id, $action_url, $action );
			return;
		}

		if ( 200 !== $http_code && 201 !== $http_code ) {
			$paypal_debug_id = isset( $response_data['debug_id'] ) ? $response_data['debug_id'] : null;
			throw new Exception( 'PayPal ' . $action . ' payment failed. Response status: ' . $http_code . '. Response body: ' . $body );
		}
	} catch ( Exception $e ) {
		\WC_Gateway_Paypal::log( $e->getMessage() );
		$note_message = sprintf(
			/* translators: %1$s: Action, %2$s: PayPal order ID */
			__( 'PayPal %1$s payment failed. PayPal Order ID: %2$s', 'woocommerce' ),
			$action,
			$paypal_order_id
		);

		// Add debug ID to the note if available.
		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->update_status( OrderStatus::FAILED );
		$order->save();
	}
}