Automattic\WooCommerce\Gateways\PayPal

Request::handle_duplicate_invoice_idprivateWC 1.0

Handle duplicate invoice ID. This is a workaround to handle the duplicate invoice ID error that occurs when the invoice ID is not unique. We generate a new invoice ID and patch the invoice ID in the PayPal order. Then we retry capturing the payment.

Method of the class: Request{}

No Hooks.

Returns

null. Nothing (null).

Usage

// private - for code of main (parent) class only
$result = $this->handle_duplicate_invoice_id( $order, $paypal_order_id, $action_url, $action ): void;
$order(WC_Order) (required)
Order object.
$paypal_order_id(string) (required)
The PayPal order ID.
$action_url(string) (required)
The action URL.
$action(string) (required)
The action.

Request::handle_duplicate_invoice_id() code WC 10.7.0

private function handle_duplicate_invoice_id( WC_Order $order, string $paypal_order_id, string $action_url, string $action ): void {
	$new_invoice_id = $this->generate_paypal_invoice_id_with_unique_suffix( $order );

	\WC_Gateway_Paypal::log( 'Attempting to patch PayPal order invoice_id. PayPal Order ID: ' . $paypal_order_id . '. New invoice_id: ' . $new_invoice_id . '. Order ID: ' . $order->get_id() );

	try {
		$request_body = array(
			'test_mode' => $this->gateway->testmode,
			'order'     => array(
				array(
					'op'    => 'replace',
					'path'  => "/purchase_units/@reference_id=='default'/invoice_id",
					'value' => $new_invoice_id,
				),
			),
		);

		$response = $this->send_wpcom_proxy_request( 'PATCH', self::WPCOM_PROXY_ORDER_ENDPOINT . '/' . $paypal_order_id, $request_body );

		if ( is_wp_error( $response ) ) {
			throw new Exception( 'PayPal patch invoice_id 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 );

		if ( 200 !== $http_code && 204 !== $http_code ) {
			\WC_Gateway_Paypal::log( 'PayPal patch invoice_id failed. Response status: ' . $http_code . '. Response body: ' . $body );
			throw new Exception( 'Failed to patch PayPal order invoice_id. Response status: ' . $http_code );
		}

		\WC_Gateway_Paypal::log( 'Successfully patched PayPal order invoice_id. PayPal Order ID: ' . $paypal_order_id . '. New invoice_id: ' . $new_invoice_id . '. Order ID: ' . $order->get_id() );

		$order->add_order_note(
			sprintf(
				/* translators: %1$s: New invoice ID */
				__( 'PayPal order Invoice ID updated to %1$s to ensure uniqueness.', 'woocommerce' ),
				esc_html( $new_invoice_id )
			)
		);
		$order->save();

		// Retry authorizing or capturing the payment after patching the invoice_id.
		$this->authorize_or_capture_payment( $order, $action_url, $action, true );
	} catch ( Exception $e ) {
		\WC_Gateway_Paypal::log( $e->getMessage() );
		// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
		throw new Exception( $e->getMessage() );
	}
}