| Current File : /home/digitaw/www/wp-content/plugins/event-tickets/src/Tickets/Commerce/Gateways/PayPal/Client.php |
<?php
namespace TEC\Tickets\Commerce\Gateways\PayPal;
use TEC\Tickets\Commerce\Cart;
use TEC\Tickets\Commerce\Gateways\PayPal\REST\Webhook_Endpoint;
use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Events;
use Tribe__Utils__Array as Arr;
/**
* Class Client
*
* @since 5.1.6
* @package TEC\Tickets\Commerce\Gateways\PayPal
*
*/
class Client {
/**
* Debug ID from PayPal.
*
* @since 5.2.0
*
* @var string
*/
protected $debug_header;
/**
* Get environment base URL.
*
* @since 5.1.9
*
* @return string
*/
public function get_environment_url() {
$merchant = tribe( Merchant::class );
return $merchant->is_sandbox() ?
'https://api.sandbox.paypal.com' :
'https://api.paypal.com';
}
/**
* Safely checks if we have an access token to be used.
*
* @since 5.1.9
*
* @return string
*/
public function get_access_token() {
return tribe( Merchant::class )->get_access_token();
}
/**
* Get REST API endpoint URL for requests.
*
* @since 5.1.9
*
*
* @param string $endpoint The endpoint path.
* @param array $query_args Query args appended to the URL.
*
* @return string The API URL.
*
*/
public function get_api_url( $endpoint, array $query_args = [] ) {
$base_url = $this->get_environment_url();
$endpoint = ltrim( $endpoint, '/' );
return add_query_arg( $query_args, "{$base_url}/{$endpoint}" );
}
/**
* Fetches the JS SDK url.
*
* We use something like: https://www.paypal.com/sdk/js?client-id=sb&locale=en_US&components=buttons
*
* @link https://developer.paypal.com/docs/checkout/reference/customize-sdk/#query-parameters
*
* @since 5.1.9
*
* @param array $query_args Which query args will be added.
*
* @return string
*/
public function get_js_sdk_url( array $query_args = [] ) {
$url = 'https://www.paypal.com/sdk/js';
$merchant = tribe( Merchant::class );
$query_args = array_merge( [
'client-id' => $merchant->get_client_id(),
'merchant-id' => $merchant->get_merchant_id_in_paypal(),
'components' => 'hosted-fields,buttons',
'intent' => 'capture',
'disable-funding' => 'credit',
'currency' => tribe_get_option( \TEC\Tickets\Commerce\Settings::$option_currency_code, 'USD' ),
], $query_args );
$url = add_query_arg( $query_args, $url );
/**
* Filter the PayPal JS SDK url.
*
* @since 5.1.9
*
* @param string $url Which URL we are going to use to load the SDK JS.
* @param array $query_args Which URL args will be added to the JS SDK url.
*/
return apply_filters( 'tec_tickets_commerce_gateway_paypal_js_sdk_url', $url, $query_args );
}
/**
* Get PayPal homepage url.
*
* @since 5.1.6
*
* @param bool|null $sandbox Whether we are using the sandbox or not.
*
* @return string
*/
public function get_home_page_url( $sandbox = null ) {
if ( null === $sandbox ) {
$sandbox = tribe( Merchant::class )->is_sandbox();
}
$subdomain = $sandbox ? 'sandbox.' : '';
return sprintf(
'https://%1$spaypal.com/',
$subdomain
);
}
/**
* Stores the debug header from a given PayPal request, which allows for us to store it with the gateway payload.
*
* @since 5.2.0
*
* @param string $id Which ID we are storing.
*
*/
protected function set_debug_header( $id ) {
$this->debug_header = $id;
}
/**
* Fetches the last stored debug id from PayPal.
*
* @since 5.2.0
*
* @return string|null
*/
public function get_debug_header() {
return $this->debug_header;
}
/**
* Send a given method request to a given URL in the PayPal API.
*
* @since 5.1.10
* @since 5.2.0 Included $retries param.
*
* @param string $method
* @param string $url
* @param array $query_args
* @param array $request_arguments
* @param bool $raw
* @param int $retries Param used to determine the amount of time this particular request was retried.
*
* @return array|\WP_Error
*/
public function request( $method, $url, array $query_args = [], array $request_arguments = [], $raw = false, $retries = 0 ) {
// Capture original arguments before any modifications for potential recursive calls.
$original_arguments = func_get_args();
$method = strtoupper( $method );
// If the endpoint passed is a full URL don't try to append anything.
$url = 0 !== strpos( $url, 'https://' )
? $this->get_api_url( $url, $query_args )
: add_query_arg( $query_args, $url );
$default_arguments = [
'headers' => [
'Accept' => 'application/json',
'Authorization' => sprintf( 'Bearer %1$s', $this->get_access_token() ),
'Content-Type' => 'application/json',
]
];
// By default it's important that we have a body set for any method that is not the GET method.
if ( 'GET' !== $method ) {
$default_arguments['body'] = [];
}
foreach ( $default_arguments as $key => $default_argument ) {
$request_arguments[ $key ] = array_merge( $default_argument, Arr::get( $request_arguments, $key, [] ) );
}
if ( 'GET' !== $method ) {
$content_type = Arr::get( $request_arguments, [ 'headers', 'Content-Type' ] );
if ( empty( $content_type ) ) {
$content_type = Arr::get( $request_arguments, [ 'headers', 'content-type' ] );
}
// For all other methods we try to make the body into the correct type.
if (
! empty( $request_arguments['body'] )
&& 'application/json' === strtolower( $content_type )
) {
$request_arguments['body'] = wp_json_encode( $request_arguments[ $key ] );
}
}
if ( 'GET' === $method ) {
$response = wp_remote_get( $url, $request_arguments );
} elseif ( 'POST' === $method ) {
$response = wp_remote_post( $url, $request_arguments );
} else {
$request_arguments['method'] = $method;
$response = wp_remote_request( $url, $request_arguments );
}
if ( is_wp_error( $response ) ) {
tribe( 'logger' )->log_error( sprintf(
'[%s] PayPal "%s" request error: %s',
$method,
$url,
$response->get_error_message()
), 'tickets-commerce-paypal' );
return $response;
}
// When raw is true means we dont do any logic.
if ( true === $raw ) {
return $response;
}
$response_code = wp_remote_retrieve_response_code( $response );
// If the debug header was set we pass it or reset it.
$this->set_debug_header( null );
if ( ! empty( $response['headers']['Paypal-Debug-Id'] ) ) {
$this->set_debug_header( $response['headers']['Paypal-Debug-Id'] );
}
// When we get specifically a 401 and we are not trying to generate a token we try once more.
if (
401 === $response_code
&& 2 >= $retries
&& false === strpos( $url, 'v1/oauth2/token' )
) {
$merchant = tribe( Merchant::class );
$token_data = $this->get_access_token_from_client_credentials( $merchant->get_client_id(), $merchant->get_client_secret() );
$saved = $merchant->save_access_token_data( $token_data );
// If we properly saved, just re-try the request.
if ( $saved ) {
$arguments = $original_arguments;
array_pop( $arguments );
$arguments[] = $retries + 1;
return call_user_func_array( [ $this, 'request' ], $arguments );
}
}
/**
* @todo we need to log and be more verbose about the responses. Specially around failed JSON strings.
*/
$response_body = wp_remote_retrieve_body( $response );
$response_body = @json_decode( $response_body, true );
if ( empty( $response_body ) ) {
return $response;
}
if ( ! is_array( $response_body ) ) {
tribe( 'logger' )->log_error( sprintf( '[%s] Unexpected PayPal %s response', $url, $method ), 'tickets-commerce-paypal' );
return new \WP_Error( 'tec-tickets-commerce-gateway-paypal-client-unexpected', null, [
'method' => $method,
'url' => $url,
'query_args' => $query_args,
'request_arguments' => $request_arguments,
'response' => $response,
] );
}
return $response_body;
}
/**
* Send a GET request to the PayPal API.
*
* @since 5.1.9
*
* @param string $endpoint
* @param array $query_args
* @param array $request_arguments
* @param bool $raw
*
* @return array|null
*/
public function get( $endpoint, array $query_args = [], array $request_arguments = [], $raw = false ) {
return $this->request( 'GET', $endpoint, $query_args, $request_arguments, $raw );
}
/**
* Send a POST request to the PayPal API.
*
* @since 5.1.9
*
* @param string $endpoint
* @param array $query_args
* @param array $request_arguments
* @param bool $raw
*
* @return array|null
*/
public function post( $endpoint, array $query_args = [], array $request_arguments = [], $raw = false ) {
return $this->request( 'POST', $endpoint, $query_args, $request_arguments, $raw );
}
/**
* Send a PATCH request to the PayPal API.
*
* @since 5.1.10
*
* @param string $endpoint
* @param array $query_args
* @param array $request_arguments
* @param bool $raw
*
* @return array|null
*/
public function patch( $endpoint, array $query_args = [], array $request_arguments = [], $raw = false ) {
return $this->request( 'PATCH', $endpoint, $query_args, $request_arguments, $raw );
}
/**
* Send a DELETE request to the PayPal API.
*
* @since 5.1.10
*
* @param string $endpoint
* @param array $query_args
* @param array $request_arguments
* @param bool $raw
*
* @return array|null
*/
public function delete( $endpoint, array $query_args = [], array $request_arguments = [], $raw = false ) {
return $this->request( 'DELETE', $endpoint, $query_args, $request_arguments, $raw );
}
/**
* Retrieves an Access Token for the Client ID and Secret.
*
* @since 5.1.9
*
* @param string $client_id The Client ID.
* @param string $client_secret The Client Secret.
*
* @return array|null The token details response or null if there was a problem.
*/
public function get_access_token_from_client_credentials( $client_id, $client_secret ) {
$auth = base64_encode( "$client_id:$client_secret" );
$query_args = [];
$args = [
'headers' => [
'Authorization' => sprintf( 'Basic %1$s', $auth ),
'Content-Type' => 'application/x-www-form-urlencoded',
],
'body' => [
'grant_type' => 'client_credentials',
],
];
return $this->post( 'v1/oauth2/token', $query_args, $args );
}
/**
* Retrieves an Access Token from the authorization code.
*
* @since 5.1.9
*
* @param string $shared_id Shared ID for merchant.
* @param string $auth_code Authorization code from on boarding.
* @param string $nonce Seller nonce from on boarding.
*
* @return array|null The token details response or null if there was a problem.
*/
public function get_access_token_from_authorization_code( $shared_id, $auth_code, $nonce ) {
$auth = base64_encode( $shared_id );
$query_args = [];
$args = [
'headers' => [
'Authorization' => sprintf( 'Basic %1$s', $auth ),
'Content-Type' => 'application/x-www-form-urlencoded',
],
'body' => [
'grant_type' => 'authorization_code',
'code' => $auth_code,
'code_verifier' => $nonce,
],
];
return $this->post( 'v1/oauth2/token', $query_args, $args );
}
/**
* Retrieves a Client Token from the stored Access Token.
*
* @link https://developer.paypal.com/docs/business/checkout/advanced-card-payments/
*
* @since 5.1.9
*
* @return array|null The client token details response or null if there was a problem.
*/
public function get_client_token() {
$query_args = [];
$args = [
'headers' => [],
'body' => [],
];
return $this->post( 'v1/identity/generate-token', $query_args, $args );
}
/**
* Based on a Purchase Unit creates a PayPal order.
*
* @link https://developer.paypal.com/docs/api/orders/v2/#orders_create
* @link https://developer.paypal.com/docs/api/orders/v2/#definition-purchase_unit_request
*
* @since 5.1.9
*
* @param array<string,mixed>|array<array> $units {
* Purchase unit used to setup the order in PayPal.
*
* @type string $reference_id Reference ID to PayPal.
* @type string $description Description of this Purchase Unit.
* @type string $value Value to be payed.
* @type string $currency Which currency.
* @type string $merchant_id Merchant ID.
* @type string $merchant_paypal_id PayPal Merchant ID.
* @type string $first_name Payee First Name.
* @type string $last_name Payee Last Name.
* @type string $email Payee email.
* @type string $disbursement_mode (optional) By default 'INSTANT'.
* @type string $payer_id (optional) PayPal Payer ID
* @type string $tax_id (optional) Tax ID for this purchase Unit.
* @type string $tax_id_type (optional) Tax ID for this purchase Unit.
*
* }
* @return array|null
*/
public function create_order( array $units = [] ) {
$merchant = tribe( Merchant::class );
$query_args = [];
$body = [
'intent' => 'CAPTURE',
'purchase_units' => [],
'application_context' => [
'shipping_preference' => 'NO_SHIPPING',
'user_action' => 'PAY_NOW',
],
];
// Determine if this set of units was just a single unit before looping.
if ( ! empty( $units['reference_id'] ) ) {
$units = [ $units ];
}
foreach ( $units as $unit ) {
/**
* @link https://developer.paypal.com/docs/api/orders/v2/#definition-payer
*/
$purchase_unit = [
'reference_id' => Arr::get( $unit, 'reference_id' ),
'description' => Arr::get( $unit, 'description' ),
'amount' => [
'value' => Arr::get( $unit, 'value' ),
'currency_code' => Arr::get( $unit, 'currency' ),
],
'payee' => [
'merchant_id' => Arr::get( $unit, 'merchant_paypal_id', $merchant->get_merchant_id_in_paypal() ),
],
'payer' => [
'name' => [
'given_name' => Arr::get( $unit, 'first_name' ),
'surname' => Arr::get( $unit, 'last_name' ),
],
'email_address' => Arr::get( $unit, 'email' ),
],
'payment_instruction' => [
'disbursement_mode' => Arr::get( $unit, 'disbursement_mode', 'INSTANT' ),
],
];
/*
* Generate the amount breakdown using the items and any extra breakdown
* values.
*
* @see https://developer.paypal.com/docs/api/payments/v2/#definition-amount_breakdown
*
* The "item_total" section of the breakdown should be passed as the "item_value" key,
* and it will fall back to using the "value" key from the $unit array.
*
* If the "extra_breakdown" key is supplied, it will be merged into the breakdown array.
* Use this to provide additional breakdown data, such as "discount", "tax_total", etc.
*/
$items = Arr::get( $unit, 'items' );
if ( ! empty( $items ) ) {
$purchase_unit['items'] = $items;
$purchase_unit['amount']['breakdown'] = [
'item_total' => [
'value' => $unit['item_value'] ?? $unit['value'],
'currency_code' => Arr::get( $unit, 'currency' ),
],
];
// If we have extra breakdown provided, merge into the item breakdown.
if ( array_key_exists( 'extra_breakdown', $unit ) ) {
$purchase_unit['amount']['breakdown'] = array_merge(
$purchase_unit['amount']['breakdown'],
$unit['extra_breakdown']
);
}
}
if ( ! empty( $unit['tax_id'] ) ) {
$purchase_unit['payer']['tax_info']['tax_id'] = Arr::get( $unit, 'tax_id' );
}
if ( ! empty( $unit['tax_id_type'] ) ) {
$purchase_unit['payer']['tax_info']['tax_id_type'] = Arr::get( $unit, 'tax_id_type' );
}
/**
* @todo We should have some sort of Purchase Unit validation here.
*/
$body['purchase_units'][] = $purchase_unit;
}
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
'PayPal-Request-Id' => tribe( Cart::class )->generate_cart_order_hash(),
'Prefer' => 'return=representation',
],
'body' => $body,
];
$response = $this->post( '/v2/checkout/orders', $query_args, $args );
return $response;
}
/**
* Retrieves an order object for a given ID in PayPal.
*
* @since 5.4.0.2
*
* @param string $order_id Order ID to retrieve.
*
* @return array|null
*/
public function get_order( $order_id ) {
$query_args = [];
$body = [];
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
'PayPal-Request-Id' => tribe( Cart::class )->generate_cart_order_hash(),
'Prefer' => 'return=representation',
],
'body' => $body,
];
$order_id = urlencode( $order_id );
$url = '/v2/checkout/orders/{order_id}';
$url = str_replace( '{order_id}', $order_id, $url );
$response = $this->get( $url, $query_args, $args );
return $response;
}
/**
* Captures an order for a given ID in PayPal.
*
* @since 5.1.9
*
* @since 5.1.10 Added support for passing `payerID` param for PayPal API.
*
* @param string $order_id Order ID to capture.
* @param string $payer_id Payer ID for given order from PayPal.
*
* @return array|null
*/
public function capture_order( $order_id, $payer_id = '' ) {
$query_args = [];
$body = [];
if ( ! empty( $payer_id ) ) {
$body['payerID'] = $payer_id;
}
/**
* If we need to handle failures.
*
* @link https://developer.paypal.com/docs/platforms/checkout/add-capabilities/handle-funding-failures/
* 'PayPal-Mock-Response' => '{"mock_application_codes" : "INSTRUMENT_DECLINED"}',
*/
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
'PayPal-Request-Id' => tribe( Cart::class )->generate_cart_order_hash(),
'Prefer' => 'return=representation',
],
'body' => $body,
];
$capture_id = urlencode( $order_id );
$url = '/v2/checkout/orders/{order_id}/capture';
$url = str_replace( '{order_id}', $capture_id, $url );
$response = $this->post( $url, $query_args, $args );
return $response;
}
/**
* Gets the profile information from the customer in PayPal.
*
* @link https://developer.paypal.com/docs/api/identity/v1/#userinfo_get
*
* @since 5.1.9
*
* @return array|null
*/
public function get_user_info() {
$query_args = [
'schema' => 'paypalv1.1',
];
$body = [];
$args = [];
$url = '/v1/identity/oauth2/userinfo';
$response = $this->get( $url, $query_args, $args );
return $response;
}
public function refund_payment( $capture_id ) {
$query_args = [];
$body = [];
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
'Prefer' => 'return=representation',
],
'body' => $body,
];
$capture_id = urlencode( $capture_id );
$url = '/v2/payments/captures/{capture_id}/refund';
$url = str_replace( '{capture_id}', $capture_id, $url );
$response = $this->post( $url, $query_args, $args );
return $response;
}
/**
* This uses the links property of the payment to retrieve the Parent Payment ID from PayPal.
*
* @since 5.1.10
*
* @param string $payment The payment event object.
*
* @return string|false The parent payment ID or false if not found.
*/
public function get_payment_authorization( $payment ) {
$query_args = [];
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
'Prefer' => 'return=representation',
],
];
if ( ! wp_http_validate_url( $payment ) ) {
$payment = urlencode( $payment );
$url = '/v2/payments/authorizations/{payment_id}';
$url = str_replace( '{payment_id}', $payment, $url );
} else {
$url = $payment;
}
$response = $this->get( $url, $query_args, $args );
return $response;
}
/**
* Verify the identity of the Webhook request, to avoid any security problems.
*
* @link https://developer.paypal.com/docs/api/webhooks/v1/#verify-webhook-signature_post
*
* @since 5.1.10
*
* @param string $webhook_id Which webhook id we have currently stored on the database.
* @param array $event The Event received by the endpoint from PayPal.
* @param array $headers Headers from the PayPal request that we use to verify the signature.
*
* @return bool
*/
public function verify_webhook_signature( $webhook_id, $event, $headers ) {
$query_args = [];
$body = [
'transmission_id' => Arr::get( $headers, 'transmission_id' ),
'transmission_time' => Arr::get( $headers, 'transmission_time' ),
'transmission_sig' => Arr::get( $headers, 'transmission_sig' ),
'cert_url' => Arr::get( $headers, 'cert_url' ),
'auth_algo' => Arr::get( $headers, 'auth_algo' ),
'webhook_id' => $webhook_id,
'webhook_event' => $event,
];
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
],
'body' => $body,
];
$url = 'v1/notifications/verify-webhook-signature';
$response = $this->post( $url, $query_args, $args );
return 'SUCCESS' === Arr::get( $response, 'verification_status', false );
}
/**
* Get the list of webhooks.
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_list
* @since 5.1.10
*
* @return array[] The list of PayPal webhooks.
*/
public function list_webhooks() {
$query_args = [];
$body = [];
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
'Prefer' => 'return=representation',
],
'body' => $body,
];
$url = '/v1/notifications/webhooks';
$response = $this->get( $url, $query_args, $args );
if ( empty( $response['webhooks'] ) ) {
return [];
}
return $response['webhooks'];
}
/**
* Get the webhook data from a specific webhook ID.
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_get
* @since 5.1.10
*
* @param string $webhook_id The webhook ID.
*
* @return array|null The PayPal webhook data.
*/
public function get_webhook( $webhook_id ) {
$query_args = [];
$body = [];
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
],
'body' => $body,
];
$webhook_id = urlencode( $webhook_id );
$url = '/v1/notifications/webhooks/{webhook_id}';
$url = str_replace( '{webhook_id}', $webhook_id, $url );
$response = $this->get( $url, $query_args, $args );
if ( ! isset( $response['id'], $response['name'] ) ) {
$error = @json_decode( $response['body'], true );
if ( 'INVALID_RESOURCE_ID' === $error['name'] ) {
// The webhook was not found.
tribe( 'logger' )->log_warning( __( 'The PayPal webhook does not exist', 'event-tickets' ), 'tickets-commerce-gateway-paypal' );
} else {
// Other unexpected response.
tribe( 'logger' )->log_warning( __( 'Unexpected PayPal response when getting webhook', 'event-tickets' ), 'tickets-commerce-gateway-paypal' );
}
return null;
}
return $response;
}
/**
* Creates a webhook with the given event types registered.
*
* @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_post
* @since 5.1.10
*
* @return array|\WP_Error
*/
public function create_webhook() {
$events = tribe( Events::class )->get_registered_events();
$webhook_url = tribe( Webhook_Endpoint::class )->get_route_url();
$query_args = [];
$body = [
'url' => $webhook_url,
'event_types' => array_map(
static function ( $event_type ) {
return [
'name' => $event_type,
];
},
$events
),
];
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
],
'body' => $body,
];
$url = '/v1/notifications/webhooks';
$response = $this->post( $url, $query_args, $args );
if ( ! $response || empty( $response['id'] ) ) {
$error = @json_decode( $response['body'], true );
if ( empty( $error['name'] ) ) {
$message = __( 'Unexpected PayPal response when creating webhook', 'event-tickets' );
tribe( 'logger' )->log_error( $message, 'tickets-commerce-gateway-paypal' );
return new \WP_Error( 'tec-tickets-commerce-gateway-paypal-webhook-unexpected', $message, $response );
}
if ( 'WEBHOOK_URL_ALREADY_EXISTS' === $error['name'] ) {
return new \WP_Error( 'tec-tickets-commerce-gateway-paypal-webhook-url-already-exists', $error['message'], $response );
}
if ( 'WEBHOOK_NUMBER_LIMIT_EXCEEDED' === $error['name'] ) {
$message = __( 'PayPal webhook limit has been reached, you need to go into your developer.paypal.com account and remove webhooks from the associated account', 'event-tickets' );
// Limit has been reached, we cannot just delete all webhooks without permission.
tribe( 'logger' )->log_error( $message, 'tickets-commerce-gateway-paypal' );
return new \WP_Error( 'tec-tickets-commerce-gateway-paypal-webhook-limit-exceeded', $message, $response );
}
}
return $response;
}
/**
* Updates the webhook url and events
*
* @since 5.1.10
*
* @param string $webhook_id
*
* @return array|\WP_Error
*/
public function update_webhook( $webhook_id ) {
$events = tribe( Events::class )->get_registered_events();
$webhook_url = tribe( Webhook_Endpoint::class )->get_route_url();
$query_args = [];
$body = [
[
'op' => 'replace',
'path' => '/url',
'value' => $webhook_url,
],
[
'op' => 'replace',
'path' => '/event_types',
'value' => array_map(
static function ( $event_type ) {
return [
'name' => $event_type,
];
},
$events
),
],
];
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
],
'body' => $body,
];
$webhook_id = urlencode( $webhook_id );
$url = '/v1/notifications/webhooks/{webhook_id}';
$url = str_replace( '{webhook_id}', $webhook_id, $url );
$response = $this->patch( $url, $query_args, $args );
if ( ! $response || empty( $response['id'] ) ) {
$error = @json_decode( $response['body'], true );
if ( empty( $error['name'] ) ) {
$message = __( 'Unexpected PayPal response when updating webhook', 'event-tickets' );
tribe( 'logger' )->log_error( $message, 'tickets-commerce-gateway-paypal' );
return new \WP_Error( 'tec-tickets-commerce-gateway-paypal-webhook-update-unexpected', $message );
}
if ( 'INVALID_RESOURCE_ID' === $error['name'] ) {
return new \WP_Error( 'tec-tickets-commerce-gateway-paypal-webhook-update-invalid-id', $error['message'] );
}
}
return $response;
}
/**
* Deletes the webhook with the given id.
*
* @since 5.1.10
*
* @param string $webhook_id
*
* @return bool|\WP_Error Whether or not the deletion was successful
*/
public function delete_webhook( $webhook_id ) {
$query_args = [];
$args = [
'headers' => [
'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
],
];
$webhook_id = urlencode( $webhook_id );
$url = '/v1/notifications/webhooks/{webhook_id}';
$url = str_replace( '{webhook_id}', $webhook_id, $url );
$response = $this->delete( $url, $query_args, $args, true );
if ( is_wp_error( $response ) ) {
return $response;
}
return 204 === wp_remote_retrieve_response_code( $response );
}
}