uawdijnntqw1x1x1
IP : 216.73.216.109
Hostname : premium160.web-hosting.com
Kernel : Linux premium160.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
Disable Function : None :)
OS : Linux
PATH:
/
home
/
batcwwjx
/
www
/
wp-content
/
plugins
/
charitable
/
.
/
includes
/
square
/
class-charitable-square-api.php
/
/
<?php /** * Super-simple, minimum abstraction Square API wrapper. * * @package Charitable Square/Classes * @author WP Charitable * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License * @since 1.8.7 * @version 1.8.7 */ use Square\Legacy\Exceptions\ApiException; use Square\Types\CreateOrderRequest; use Square\Types\Order; use Square\Types\OrderSource; use Square\Types\OrderLineItem; use Square\Types\Money; use Square\Exceptions\SquareApiException; use Square\Payments\Requests\CreatePaymentRequest; use Square\ApiResponse; use Square\Types\Address; use Square\Types\Payment; use Square\Types\OrderLineItemDiscount; use Square\Types\OrderState; use Square\Refunds\Requests\RefundPaymentRequest; use Square\Customers\Requests\CreateCustomerRequest; use Square\Cards\Requests\CreateCardRequest; use Square\Types\Card; use Square\Types\CatalogQuery; use Square\Types\CatalogQueryExact; use Square\Types\CatalogObject; use Square\Types\CatalogObjectType; use Square\Types\Customer; use Square\Types\SubscriptionSource; use Square\Types\SubscriptionPricing; use Square\Types\SubscriptionPhase; use Square\Types\CatalogSubscriptionPlan; use Square\Types\CatalogSubscriptionPlanVariation; use Square\Types\CatalogObjectSubscriptionPlan; use Square\Types\CatalogObjectSubscriptionPlanVariation; use Square\Orders\Requests\UpdateOrderRequest; use Square\Catalog\Requests\SearchCatalogObjectsRequest; use Square\Catalog\Object\Requests\UpsertCatalogObjectRequest; use Square\Subscriptions\Requests\CreateSubscriptionRequest; use Square\Legacy\Models\Builders\CatalogObjectBuilder; use Square\Subscriptions\Requests\CancelSubscriptionsRequest; use Square\Customers\CustomersClient; use Square\Core\Client\RawClient; use Square\Cards\CardsClient; use Square\Catalog\CatalogClient; if ( ! defined( 'ABSPATH' ) ) { exit; } /** * API class. * * @since 1.8.7 */ class Charitable_Square_API { /** * The Square API version to target * * @since 1.8.7 * * @var string */ const SQUARE_VERSION = '2025-03-19'; /** * Square application name. * * @since 1.8.7 */ public const APP_NAME = 'WPCharitable'; /** * Square API client instance. * * @since 1.8.7 * * @var SquareClient */ private $client; /** * Payment token (card nonce) generated by the Web Payments SDK. * * @since 1.8.7 * * @var string */ private $source_id; /** * Last API call response. * * @since 1.8.7 * * @var ApiResponse */ private $response; /** * Last API call exception. * * @since 1.8.7 * * @var ApiException */ private $exception; /** * The base URL that we will call with our API requests. * * @since 1.8.7 * * @var string */ private $api_base_url; /** * The Live Access Token supplied by the user. * * @since 1.8.7 * * @var string */ private $live_access_token; /** * The Test Access Token supplied by the user. * * @since 1.8.7 * * @var string */ private $test_access_token; /** * The Access Token supplied by the user. * * @since 1.8.7 * * @var string */ private $access_token; /** * The Refresh Token supplied by the user. * * @since 1.8.7 * * @var string */ private $refresh_token; /** * The Client ID supplied by the user. * * @since 1.8.7 * * @var string */ private $merchant_id; /** * * The ID of the business location to associate the payment with * * @since 1.8.7 * * @var string */ private $location_id; /** * Whether the Access Token was validated. * * @since 1.8.7 * * @var boolean */ private $access_token_validated; /** * The response to the most recent request. * * @since 1.8.7 * * @var WP_Error|? */ private $last_response; /** * Whether the test mode is enabled. * * @since 1.8.7 * * @var boolean */ private $test_mode; /** * The Client ID supplied by the user. * * @since 1.8.7 * * @var string */ private $client_id; /** * API errors. * * @since 1.8.7 * * @var array */ private $errors; /** * Maximum number of retries for rate-limited requests. * * @since 1.8.7 * * @var int */ const MAX_RETRIES = 5; /** * Base delay in seconds for exponential backoff. * * @since 1.8.7 * * @var int */ const BASE_DELAY = 1; /** * Create a new instance. * * @since 1.8.7 * * @param Charitable_Square_Connection $connection The connection object. * * Connection object structure: * - live_mode (private): null * - access_token (private): string - OAuth access token * - refresh_token (private): string - OAuth refresh token * - client_id (private): string - Square application client ID * - merchant_id (private): string - Square merchant ID * - currency (private): null * - status (private): string - Connection status ("valid") * - renew_at (private): int - Unix timestamp for token renewal * - encrypted (private): bool - Whether tokens are encrypted * - scopes_updated (private): int - Unix timestamp of last scope update */ /** * Constructor. * * @since 1.8.7 * * @param Charitable_Square_Connection $connection The connection object. */ public function __construct( $connection ) { if ( empty( $connection ) ) { return; } $this->client = new \Square\SquareClient( token: $connection->get_access_token(), options: array( 'baseUrl' => $connection->get_mode() !== 'live' ? \Square\Environments::Sandbox->value : \Square\Environments::Production->value, ), ); // Set the location ID. $this->location_id = charitable_square_get_location_id(); if ( empty( $this->location_id ) ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Square API: No location ID found. Please configure your Square location ID in the plugin settings.' ); // phpcs:enable } return; } $this->test_mode = $connection->get_mode(); $this->api_base_url = $this->test_mode ? 'https://connect.squareupsandbox.com/v2' : 'https://connect.squareup.com/v2'; $this->access_token = $connection->get_access_token(); $this->refresh_token = $connection->get_refresh_token(); $this->client_id = $connection->get_client_id(); $this->merchant_id = $connection->get_merchant_id(); } /** * Set tokens from a submitted form data. * * @since 1.8.7 * * @param string $square_token The Square token. */ public function set_payment_tokens( string $square_token ) { if ( ! empty( $square_token ) ) { $this->source_id = $square_token; } } /** * Set up hooks. * * @since 1.8.7 * * @return void */ public function init() { // Nothing much here yet. Add any filters pertaining to API here etc.. } /** * Check if OAuth connection is present and ready to use. * * @since 1.8.7 */ private function check_connection() { $connection = Charitable_Square_Connection::get(); if ( ! $connection || ! $connection->is_configured() ) { $this->errors[] = esc_html__( 'Square account connection is missing.', 'charitable' ); return; } if ( ! $connection->is_valid() ) { $this->errors[] = esc_html__( 'Square account connection is invalid.', 'charitable' ); return; } if ( ! $connection->is_currency_matched() ) { $this->errors[] = esc_html__( 'The currency associated with the payment is not valid for the provided business location.', 'charitable' ); } } /** * Check if single payment tokens are present. * * @since 1.8.7 */ private function check_payment_tokens() { if ( empty( $this->source_id ) ) { $this->errors[] = esc_html__( 'Square payment stopped, missing card tokens.', 'charitable' ); } } /** * Check if all required general arguments are present. * * @since 1.8.7 * * @param array $args Arguments to check. */ private function check_required_args_general( array $args ) { if ( empty( $args['location_id'] ) ) { $this->errors[] = esc_html__( 'Missing location ID.', 'charitable' ); } if ( empty( $args['currency'] ) ) { $this->errors[] = esc_html__( 'Missing currency.', 'charitable' ); } if ( empty( $args['amount'] ) && ! is_numeric( $args['amount'] ) ) { $this->errors[] = esc_html__( 'Missing amount.', 'charitable' ); } } /** * Check if all required single payment arguments are present. * * @since 1.8.7 * * @param array $args Arguments to check. */ private function check_required_args_single( array $args ) { if ( empty( $args['order_items'] ) ) { $this->errors[] = esc_html__( 'Missing order/payment items.', 'charitable' ); } } /** * Process single transaction. * * @since 1.8.7 * * @param array $args Payment arguments. */ public function process_single_transaction( array $args ) { $this->check_connection(); $this->check_payment_tokens(); $this->check_required_args_general( $args ); $this->check_required_args_single( $args ); if ( $this->errors ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Charitable_Square_API. process_single_transaction - before perform_single_transaction errors' ); error_log( print_r( $this->errors, true ) ); // phpcs:enable } return $this->errors; } $result = $this->perform_single_transaction( $args ); if ( $this->errors ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Charitable_Square_API. process_single_transaction - after perform_single_transaction errors' ); error_log( print_r( $this->errors, true ) ); // phpcs:enable } return $this->errors; } if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'process_single_transaction - result' ); error_log( print_r( $result, true ) ); // phpcs:enable } /** * Fire when a single transaction is performed. * * @since 1.8.7 * * @param array $result Single transaction result. * @param array $args Payment arguments. * @param Api $api Api class instance. */ do_action( 'charitable_square_api_process_single_transaction_after', $result, $args, $this ); return $result; } /** * Process subscription transaction. * * @since 1.8.7 * * @param array $args Payment arguments. */ public function process_subscription_transaction( array $args ) { $this->check_connection(); $this->check_payment_tokens(); $this->check_required_args_general( $args ); $this->check_required_args_subscription( $args ); if ( $this->errors ) { return; } $result = $this->perform_subscription_transaction( $args ); return $result; } /** * Perform a single transaction. * * @since 1.8.7 * * @param array $args Payment arguments. * * @return array */ private function perform_single_transaction( array $args ): array { $result = array(); // Create an order. $order_request = $this->prepare_create_order_request( $args ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Charitable_Square_API. perform_single_transaction - order_request' ); error_log( print_r( $order_request, true ) ); // phpcs:enable } $order = $this->send_create_order_request( $order_request ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Charitable_Square_API. perform_single_transaction - order' ); error_log( print_r( $order, true ) ); // phpcs:enable } if ( ! $order instanceof Order ) { error_log( 'Charitable_Square_API. perform_single_transaction - order not created' ); // phpcs:ignore return $result; } $result['order'] = $order; // Create a payment. $payment_request = $this->prepare_create_payment_request( $order, $args ); $payment = $this->send_create_payment_request( $payment_request ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Charitable_Square_API. perform_single_transaction - payment' ); error_log( print_r( $payment, true ) ); // phpcs:enable } // In this case we should cancel an order. if ( ! $payment instanceof Payment ) { $update_order_request = $this->prepare_update_order_request( $order ); $updated_order = $this->send_update_order_request( $order->getId(), $update_order_request ); return $updated_order instanceof Order ? array( 'order' => $updated_order ) : $result; } $result['payment'] = $payment; return $result; } /** * Prepare a create order request object for sending to API. * * @since 1.8.7 * * @param array $args Single payment arguments. * * @return CreateOrderRequest */ private function prepare_create_order_request( array $args ) { $request = $this->get_create_order_request_object( $args ); $request = $this->create_order_request_set_line_items( $request, $args ); /** * Filter a create order request object. * * @since 1.8.7 * * @param CreateOrderRequest $request Create order request object. * @param array $args Payment arguments. * @param Api $api Api class instance. */ return apply_filters( 'charitable_square_api_prepare_create_order_request', $request, $args, $this ); } /** * Retrieve a create order request object. * * @since 1.8.7 * * @param array $args Payment arguments. * * @return CreateOrderRequest */ private function get_create_order_request_object( array $args ) { $request = new CreateOrderRequest(); $request->setIdempotencyKey( $this->get_idempotency_key() ); $request->setOrder( new Order( array( 'locationId' => $args['location_id'] ) ) ); $request->getOrder()->setSource( new OrderSource( array( 'name' => self::APP_NAME ) ) ); return $request; } /** * Retrieve an update order request object. * * @since 1.8.7 * * @param Order $order Order object. * * @return UpdateOrderRequest */ private function get_update_order_request_object( $order ): UpdateOrderRequest { $request = new UpdateOrderRequest( array( 'orderId' => $order->getId(), 'order' => $order, 'idempotencyKey' => $this->get_idempotency_key(), ) ); $request->getOrder()->setState( \Square\Types\OrderState::Canceled->value ); return $request; } /** * Set line items to a create order request object. * * @since 1.8.7 * * @param CreateOrderRequest $request Request to create an order. * @param array $args Payment arguments. * * @return CreateOrderRequest */ private function create_order_request_set_line_items( $request, array $args ): CreateOrderRequest { $line_items = array(); foreach ( (array) $args['order_items'] as $item ) { // Order item without variations. if ( empty( $item['variations'] ) ) { $line_items[] = $this->get_order_line_item_object( $item, $args ); continue; } // Order item with variations (e.g. Small, Medium and Large). foreach ( (array) $item['variations'] as $variation ) { $order_line_item = $this->get_order_line_item_object( $variation, $args ); $order_line_item->setVariationName( $variation['variation_name'] ); $line_items[] = $order_line_item; } } $request->getOrder()->setLineItems( $line_items ); return $request; } /** * Retrieve a single order line item object. * * @since 1.8.7 * * @param array $item Order item data. * @param array $args Payment arguments. * * @return OrderLineItem */ private function get_order_line_item_object( array $item, array $args ) { $base_price_money = new Money(); $base_price_money->setAmount( round( $item['amount'] ) ); $base_price_money->setCurrency( $args['currency'] ); $order_line_items = new OrderLineItem( array( 'quantity' => $item['quantity'], 'name' => $item['name'], 'basePriceMoney' => $base_price_money, ) ); return $order_line_items; } /** * Retrieve a single order discount object. * * @since 1.8.7 * * @param array $discount Discount data. * @param array $args Payment arguments. * * @return OrderLineItemDiscount */ private function get_order_discount_object( array $discount, array $args ): OrderLineItemDiscount { $order_discounts = new OrderLineItemDiscount(); $order_discounts->setName( $discount['name'] ); $order_discounts->setAmountMoney( new Money() ); $order_discounts->getAmountMoney()->setAmount( $discount['amount'] ); $order_discounts->getAmountMoney()->setCurrency( $args['currency'] ); return $order_discounts; } /** * Set discounts to a create order request object. * * @since 1.8.7 * * @param CreateOrderRequest $request Request to create an order. * @param array $args Payment arguments. * * @return CreateOrderRequest */ private function create_order_request_set_discounts( $request, array $args ): CreateOrderRequest { $discounts = array(); if ( empty( $args['discounts'] ) ) { return $request; } foreach ( (array) $args['discounts'] as $discount ) { $discounts[] = $this->get_order_discount_object( $discount, $args ); } if ( ! empty( $discounts ) ) { $request->getOrder()->setDiscounts( $discounts ); } return $request; } /** * Set order to a create payment request object. * * @since 1.8.7 * * @param CreatePaymentRequest $request Create payment request object. * @param Order $order Order object. * * @return CreatePaymentRequest */ private function create_payment_request_set_order( $request, $order ): CreatePaymentRequest { $request->setOrderId( $order->getId() ); $request->setLocationId( $order->getLocationId() ); $amount = $order->getTotalMoney()->getAmount(); $currency = $order->getTotalMoney()->getCurrency(); $request->getAmountMoney()->setAmount( $amount ); $request->getAmountMoney()->setCurrency( $currency ); if ( ! Charitable_Square_Helpers::is_license_ok() && Charitable_Square_Helpers::is_application_fee_supported( $currency ) ) { $request->setAppFeeMoney( new Money() ); $request->getAppFeeMoney()->setAmount( (int) ( round( $amount * 0.03 ) ) ); $request->getAppFeeMoney()->setCurrency( $currency ); } return $request; } /** * Retrieve a create payment request object. * * @since 1.8.7 * * @return CreatePaymentRequest */ private function get_create_payment_request_object(): CreatePaymentRequest { $request = new CreatePaymentRequest( array( 'sourceId' => $this->source_id, 'idempotencyKey' => $this->get_idempotency_key(), ) ); $request->setAmountMoney( new Money() ); return $request; } /** * Send a create order request object to API. * * @since 1.8.7 * * @param CreateOrderRequest $request Create order request object. * * @return Order|null */ private function send_create_order_request( $request ) { try { $this->response = $this->handle_rate_limiting( function () use ( $request ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Charitable_Square_API. send_create_order_request - inside rate limiting function' ); // phpcs:enable } return $this->client->orders->create( $request ); } ); if ( $this->response->getErrors() ) { $this->errors[] = esc_html__( 'Square fail: order was not created.', 'charitable' ); return null; } return $this->response->getOrder(); } catch ( \Square\Exceptions\SquareApiException $e ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Charitable_Square_API. send_create_order_request - caught exception: ' . $e->getMessage() ); // phpcs:enable } $this->exception = $e; // Get the error category and code from the exception message using regex. $error_category = ''; $error_code = ''; // Look for "category": "SOME_CATEGORY" pattern. if ( preg_match( '/"category":\s*"([^"]+)"/', $e->getMessage(), $category_matches ) ) { $error_category = $category_matches[1]; if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Charitable_Square_API. send_create_order_request - error category: ' . $error_category ); // phpcs:enable } } // Look for "code": "SOME_CODE" pattern. if ( preg_match( '/"code":\s*"([^"]+)"/', $e->getMessage(), $code_matches ) ) { $error_code = $code_matches[1]; if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Charitable_Square_API. send_create_order_request - error code: ' . $error_code ); // phpcs:enable } } $this->errors[] = array( 'message' => esc_html__( 'Square fail: order was not created.', 'charitable' ), 'category' => $error_category, 'code' => $error_code, ); return null; } } /** * Send an update order request object to API. * * @since 1.8.7 * * @param string $order_id The ID of the order to update. * @param UpdateOrderRequest $request Update order request object. * * @return Order|null */ private function send_update_order_request( string $order_id, $request ) { try { $response = $this->handle_rate_limiting( function () use ( $order_id, $request ) { return $this->client->getOrdersApi()->updateOrder( $order_id, $request ); } ); if ( ! $response->isSuccess() ) { return null; } return $response->getResult()->getOrder(); } catch ( ApiException $e ) { return null; } } /** * Handle rate limiting with exponential backoff. * * @since 1.8.7 * * @param callable $api_call The API call to make. * @param int $retry_count Current retry attempt. * @return mixed The API response. * @throws ApiException If the API call fails after all retries. */ private function handle_rate_limiting( $api_call, $retry_count = 0 ) { try { return $api_call(); } catch ( ApiException $e ) { // Check if this is a rate limit error (429). if ( $e->getCode() === 429 && $retry_count < self::MAX_RETRIES ) { // Calculate delay using exponential backoff: base_delay * (2^retry_count). $delay = self::BASE_DELAY * pow( 2, $retry_count ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( sprintf( 'Square API rate limited. Retry %d of %d. Waiting %d seconds.', $retry_count + 1, self::MAX_RETRIES, $delay ) ); // phpcs:enable } // Sleep for the calculated delay. sleep( $delay ); // Retry the API call. return $this->handle_rate_limiting( $api_call, $retry_count + 1 ); } // If not a rate limit error or max retries reached, rethrow the exception. throw $e; } } /** * Send a create payment request to API. * * @since 1.8.7 * * @param CreatePaymentRequest $request Create payment request object. * * @return Payment|null */ private function send_create_payment_request( $request ) { try { $this->response = $this->handle_rate_limiting( function () use ( $request ) { return $this->client->payments->create( $request ); } ); if ( $this->response->getErrors() ) { $this->errors[] = esc_html__( 'Square fail: payment was not processed.', 'charitable' ); $this->add_response_errors_message(); return null; } return $this->response->getPayment(); } catch ( ApiException $e ) { $this->exception = $e; $this->errors[] = esc_html__( 'Square fail: payment was not processed.', 'charitable' ); $this->add_response_errors_message( 'Exception' ); return null; } } /** * Perform a subscription transaction. * * @since 1.8.7 * * @param array $args Payment arguments. */ private function perform_subscription_transaction( array $args ) { // Create a customer. $customer_request = $this->prepare_create_customer_request( $args ); $customer = $this->send_create_customer_request( $customer_request ); if ( ! $customer instanceof Customer ) { return; } // Create a customer card. $card_request = $this->prepare_create_customer_card_request( $customer->getId(), $args ); $card = $this->send_create_customer_card_request( $card_request ); if ( ! $card instanceof Card ) { return; } // Get a subscription plan. $plan = $this->get_plan( $args ); if ( ! $plan instanceof CatalogObject ) { return; } // Get a subscription plan variation. $plan_variation = $this->get_plan_variation( $args, $plan ); if ( ! $plan_variation instanceof CatalogObject ) { return; } // Create a subscription. $subscription_request = $this->prepare_create_subscription_request( $plan_variation->getValue()->getId(), $customer->getId(), $card->getId(), $args ); $result = $this->send_create_subscription_request( $subscription_request ); return $result; } /** * Check if all required subscription arguments are present. * * @since 1.8.7 * * @param array $args Arguments to check. */ private function check_required_args_subscription( array $args ) { if ( empty( $args['subscription']['plan_name'] ) ) { $this->errors[] = esc_html__( 'Missing subscription plan name.', 'charitable' ); } if ( empty( $args['subscription']['plan_variation_name'] ) ) { $this->errors[] = esc_html__( 'Missing subscription plan variation name.', 'charitable' ); } if ( empty( $args['subscription']['phase_cadence'] ) ) { $this->errors[] = esc_html__( 'Missing subscription cadence.', 'charitable' ); } if ( empty( $args['subscription']['customer']['first_name'] ) && empty( $args['subscription']['customer']['last_name'] ) ) { $this->errors[] = esc_html__( 'Missing customer name.', 'charitable' ); } if ( empty( $args['subscription']['customer']['email'] ) ) { $this->errors[] = esc_html__( 'Missing customer email.', 'charitable' ); } } /** * Prepare a create customer request object for sending to API. * * @since 1.8.7 * * @param array $args Payment arguments. * * @return CreateCustomerRequest */ private function prepare_create_customer_request( array $args ): CreateCustomerRequest { $request = $this->get_create_customer_request_object(); $request->setEmailAddress( $args['subscription']['customer']['email'] ); if ( ! empty( $args['subscription']['customer']['first_name'] ) ) { $request->setGivenName( $args['subscription']['customer']['first_name'] ); } if ( ! empty( $args['subscription']['customer']['last_name'] ) ) { $request->setFamilyName( $args['subscription']['customer']['last_name'] ); } if ( ! empty( $args['subscription']['customer']['address'] ) ) { $address = $this->get_address_object( $args['subscription']['customer'] ); $request->setAddress( $address ); } return $request; } /** * Prepare a create customer card request object for sending to API. * * @since 1.8.7 * * @param string $customer_id Customer ID. * @param array $args Payment arguments. * * @return CreateCardRequest */ private function prepare_create_customer_card_request( string $customer_id, array $args ): CreateCardRequest { $request = new CreateCardRequest( array( 'idempotencyKey' => $this->get_idempotency_key(), 'sourceId' => $this->source_id, 'card' => new Card(), ) ); $request->getCard()->setCustomerId( $customer_id ); if ( ! empty( $args['subscription']['customer']['address'] ) ) { $address = $this->get_address_object( $args['subscription']['customer'] ); // For subscriptions: make sure that a postal code is not empty. // Otherwise, API error "The postal code doesn't match the one used for card nonce creation" is occur here. if ( ! empty( $address->getPostalCode() ) ) { $request->getCard()->setBillingAddress( $address ); } } if ( ! empty( $args['subscription']['card_name'] ) ) { $request->getCard()->setCardholderName( $args['subscription']['card_name'] ); } return $request; } /** * Prepare a create subscription request object for sending to API. * * @since 1.8.7 * * @param string $plan_id Plan ID. * @param string $customer_id Customer ID. * @param string $card_id Customer ID. * @param array $args Payment arguments. * * @return CreateSubscriptionRequest */ private function prepare_create_subscription_request( string $plan_id, string $customer_id, string $card_id, array $args ) { $request = $this->get_create_subscription_request_object( $plan_id, $customer_id, $args ); $request->setCardId( $card_id ); $request->setSource( new SubscriptionSource() ); $request->getSource()->setName( self::APP_NAME ); return $request; } /** * Retrieve a create customer request object. * * @since 1.8.7 * * @return CreateCustomerRequest */ private function get_create_customer_request_object(): CreateCustomerRequest { $request = new CreateCustomerRequest(); $request->setIdempotencyKey( $this->get_idempotency_key() ); return $request; } /** * Prepare an update order request object for sending to API. * * @since 1.8.7 * * @param Order $order Order object. * * @return UpdateOrderRequest */ private function prepare_update_order_request( $order ): UpdateOrderRequest { $request = $this->get_update_order_request_object( $order ); /** * Filter an update order request object. * * @since 1.8.7 * * @param UpdateOrderRequest $request Update order request object. * @param Order $order Order object. * @param Api $api Api class instance. */ return apply_filters( 'charitable_square_api_prepare_update_order_request', $request, $order, $this ); } /** * Send a create customer card request to API. * * @since 1.8.7 * * @param CreateCardRequest $request Create card request object. * * @return Card|null */ private function send_create_customer_card_request( $request ) { try { $raw_client = new RawClient( array( 'baseUrl' => $this->test_mode ? \Square\Environments::Sandbox->value : \Square\Environments::Production->value, 'headers' => array( 'Authorization' => 'Bearer ' . $this->access_token, 'Square-Version' => self::SQUARE_VERSION, 'Content-Type' => 'application/json', ), ) ); $cards_client = new CardsClient( $raw_client ); $this->response = $this->handle_rate_limiting( function () use ( $cards_client, $request ) { return $cards_client->create( $request ); } ); // Get the card from the response. $card = $this->response->getCard(); if ( ! $card ) { $this->errors[] = esc_html__( 'Square fail: customer card was not created.', 'charitable' ); return null; } return $card; } catch ( ApiException $e ) { $this->exception = $e; $this->errors[] = esc_html__( 'Square fail: customer card was not created.', 'charitable' ); return null; } } /** * Prepare a create payment request object for sending to API. * * @since 1.8.7 * * @param Order $order Order object. * @param array $args Payment arguments. * * @return CreatePaymentRequest */ private function prepare_create_payment_request( $order, array $args ): CreatePaymentRequest { $request = $this->get_create_payment_request_object(); $request = $this->create_payment_request_set_order( $request, $order ); if ( ! empty( $args['billing'] ) ) { $address = $this->get_address_object( $args['billing'] ); $request->setBillingAddress( $address ); } if ( ! empty( $args['buyer_email'] ) ) { $request->setBuyerEmailAddress( $args['buyer_email'] ); } if ( ! empty( $args['note'] ) ) { $request->setNote( $args['note'] ); } /** * Filter a create payment request object. * * @since 1.8.7 * * @param CreateOrderRequest $request Create payment request object. * @param array $args Payment arguments. * @param Api $api Api class instance. */ return apply_filters( 'charitable_square_api_prepare_create_payment_request', $request, $args, $this ); } /** * Send a create customer request to API. * * @since 1.8.7 * * @param CreateCustomerRequest $request Create customer request object. * * @return Customer|null */ private function send_create_customer_request( $request ) { try { $raw_client = new RawClient( array( 'baseUrl' => $this->test_mode ? \Square\Environments::Sandbox->value : \Square\Environments::Production->value, 'headers' => array( 'Authorization' => 'Bearer ' . $this->access_token, 'Square-Version' => self::SQUARE_VERSION, 'Content-Type' => 'application/json', ), ) ); $customers_client = new CustomersClient( $raw_client ); $this->response = $this->handle_rate_limiting( function () use ( $customers_client, $request ) { return $customers_client->create( $request ); } ); // Get the customer from the response. $customer = $this->response->getCustomer(); if ( ! $customer ) { $this->errors[] = esc_html__( 'Square fail: customer was not created.', 'charitable' ); return null; } return $customer; } catch ( ApiException $e ) { $this->exception = $e; $this->errors[] = esc_html__( 'Square fail: customer was not created.', 'charitable' ); return null; } } /** * Get subscription plan. * * @since 1.8.7 * * @param array $args Payment arguments. * * @return CatalogObject|null */ private function get_plan( array $args ) { // Search a subscription plan. $search_plan_request = $this->get_search_catalog_request_object( 'SUBSCRIPTION_PLAN', $args['subscription']['plan_variation_name'] ); $plan = $this->send_search_catalog_request( $search_plan_request ); // Create a subscription plan if it's not exists. if ( ! $plan ) { $create_plan_request = $this->get_create_plan_request_object( $args ); $plan = $this->send_create_plan_request( $create_plan_request ); } return $plan; } /** * Send a create subscription plan request to API. * * @since 1.8.7 * * @param UpsertCatalogObjectRequest $request Create subscription plan request object. * * @return CatalogObject|null */ private function send_create_plan_request( $request ) { try { $this->response = $this->handle_rate_limiting( function () use ( $request ) { return $this->client->catalog->object->upsert( $request ); } ); if ( ! $this->response->getCatalogObject() ) { $this->errors[] = esc_html__( 'Square fail: subscription plan was not created.', 'charitable' ); return null; } return $this->response->getCatalogObject(); } catch ( ApiException $e ) { $this->exception = $e; $this->errors[] = esc_html__( 'Square fail: subscription plan was not created.', 'charitable' ); return null; } } /** * Send a create subscription plan variations request to API. * * @since 1.8.7 * * @param UpsertCatalogObjectRequest $request Create subscription plan request object. * * @return CatalogObject|null */ private function send_create_plan_variations_request( $request ) { try { $this->response = $this->handle_rate_limiting( function () use ( $request ) { return $this->client->catalog->object->upsert( $request ); } ); if ( ! $this->response->getCatalogObject() ) { $this->errors[] = esc_html__( 'Square fail: subscription plan variation was not created.', 'charitable' ); return null; } return $this->response->getCatalogObject(); } catch ( ApiException $e ) { $this->exception = $e; $this->errors[] = esc_html__( 'Square fail: subscription plan variation was not created.', 'charitable' ); return null; } } /** * Send a create subscription request to API. * * @since 1.8.7 * * @param CreateSubscriptionRequest $request Create subscription request object. * * @return Subscription|null */ private function send_create_subscription_request( $request ) { try { $this->response = $this->handle_rate_limiting( function () use ( $request ) { return $this->client->subscriptions->create( $request ); } ); if ( ! $this->response->getSubscription() ) { $this->errors[] = esc_html__( 'Square fail: something went wrong during subscription process.', 'charitable' ); return null; } return $this->response->getSubscription(); } catch ( ApiException $e ) { $this->exception = $e; $this->errors[] = esc_html__( 'Square fail: something went wrong during subscription process.', 'charitable' ); return null; } } /** * Retrieve a create plan request object. * * @since 1.8.7 * * @param array $args Payment arguments. * * @return UpsertCatalogObjectRequest */ private function get_create_plan_request_object( array $args ) { $request = new UpsertCatalogObjectRequest( array( 'idempotencyKey' => $this->get_idempotency_key(), 'object' => CatalogObject::subscriptionPlan( new CatalogObjectSubscriptionPlan( array( 'id' => '#plan_' . uniqid(), // Square requires IDs to start with # for new objects. 'subscriptionPlanData' => new CatalogSubscriptionPlan( array( 'name' => $args['subscription']['plan_name'], ) ), ) ) ), ) ); $request->getObject()->asSubscriptionPlan()->getSubscriptionPlanData()->setAllItems( true ); return $request; } /** * Get subscription plan variation. * * @since 1.8.7 * * @param array $args Payment arguments. * @param CatalogObject $plan Plan object. * * @return CatalogObject|null */ private function get_plan_variation( array $args, $plan ) { // Search a subscription plan. $search_plan_request = $this->get_search_catalog_request_object( 'SUBSCRIPTION_PLAN_VARIATION', $args['subscription']['plan_name'] ); $plan_variation = $this->send_search_catalog_request( $search_plan_request ); // Create a subscription plan if it's not exists. if ( ! $plan_variation ) { $create_plan_variations_request = $this->get_create_plan_variations_request_object( $args, $plan ); $plan_variation = $this->send_create_plan_variations_request( $create_plan_variations_request ); } return $plan_variation; } /** * Retrieve a create plan variation request object. * * @since 1.8.7 * * @param array $args Payment arguments. * @param CatalogObject $plan Plan object. * * @return UpsertCatalogObjectRequest */ private function get_create_plan_variations_request_object( array $args, $plan ): UpsertCatalogObjectRequest { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_create_plan_variations_request_object - args' ); error_log( print_r( $args, true ) ); error_log( 'get_create_plan_variations_request_object - plan' ); error_log( print_r( $plan, true ) ); // phpcs:enable } $request = new UpsertCatalogObjectRequest( array( 'idempotencyKey' => $this->get_idempotency_key(), 'object' => CatalogObject::subscriptionPlanVariation( new CatalogObjectSubscriptionPlanVariation( array( 'id' => '#variation_' . uniqid(), 'subscriptionPlanVariationData' => new CatalogSubscriptionPlanVariation( array( 'name' => $args['subscription']['plan_variation_name'], 'phases' => array( new SubscriptionPhase( array( 'cadence' => $args['subscription']['phase_cadence']['value'], 'pricing' => new SubscriptionPricing( array( 'type' => 'STATIC', 'priceMoney' => new Money( array( 'amount' => $args['amount'], 'currency' => $args['currency'], ) ), ) ), ) ), ), 'subscriptionPlanId' => $plan->asSubscriptionPlan()->getId(), ) ), ) ) ), ) ); return $request; } /** * Retrieve a create subscription request object. * * @since 1.8.7 * * @param string $plan_id Plan ID. * @param string $customer_id Customer ID. * @param array $args Payment arguments. * * @return CreateSubscriptionRequest */ private function get_create_subscription_request_object( string $plan_id, string $customer_id, array $args ): CreateSubscriptionRequest { $request = new CreateSubscriptionRequest( array( 'locationId' => $this->location_id, 'customerId' => $customer_id, 'planVariationId' => $plan_id, 'idempotencyKey' => $this->get_idempotency_key(), 'cardId' => $args['card_id'] ?? null, 'startDate' => $args['start_date'] ?? null, 'canceledDate' => $args['canceled_date'] ?? null, 'taxPercentage' => $args['tax_percentage'] ?? null, 'timezone' => $args['timezone'] ?? null, ) ); return $request; } /** * Retrieve a search catalog request object. * * @since 1.8.7 * * @param string $type Object type. * @param string $name Object name. * * @return SearchCatalogObjectsRequest */ private function get_search_catalog_request_object( string $type, string $name ): SearchCatalogObjectsRequest { $request = new SearchCatalogObjectsRequest(); $request->setObjectTypes( array( $type ) ); $request->setLimit( 1 ); $request->setQuery( new CatalogQuery() ); $request->getQuery()->setExactQuery( new CatalogQueryExact( array( 'attributeName' => 'name', 'attributeValue' => $name, ) ) ); return $request; } /** * Send a search catalog request to API. * * @since 1.8.7 * * @param SearchCatalogObjectsRequest $request Search subscription plan request object. * * @return CatalogObject|null */ private function send_search_catalog_request( $request ) { try { $this->response = $this->handle_rate_limiting( function () use ( $request ) { return $this->client->catalog->search( $request ); } ); $objects = $this->response->getObjects(); if ( empty( $objects ) ) { $this->errors[] = esc_html__( 'Square fail: no catalog objects found.', 'charitable' ); return null; } return $objects; } catch ( ApiException $e ) { $this->exception = $e; $this->errors[] = esc_html__( 'Square fail: something went wrong during catalog search.', 'charitable' ); return null; } } /** * Process a subscription cancellation. * * @since 1.8.7 * * @param string $subscription_id The ID of the subscription to cancel. * @return bool True if the subscription was cancelled successfully, false otherwise. */ public function process_subscription_cancellation( string $subscription_id ) { $this->check_connection(); if ( $this->errors ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'process_subscription_cancellation - errors' ); error_log( print_r( $this->errors, true ) ); // phpcs:enable } return false; } try { // Create cancel request. $request = new CancelSubscriptionsRequest( array( 'subscriptionId' => $subscription_id, ) ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'process_subscription_cancellation - request' ); error_log( print_r( $request, true ) ); // phpcs:enable } // Send the request to Square API. $response = $this->client->subscriptions->cancel( $request ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'process_subscription_cancellation - response' ); error_log( print_r( $response, true ) ); // phpcs:enable } // Check if cancellation was successful by looking for errors. if ( $response->getErrors() === null || empty( $response->getErrors() ) ) { // No errors means success. return $response; } else { // Log errors. $this->add_response_errors_message( 'SUBSCRIPTION_CANCELLATION' ); return false; } } catch ( \Exception $e ) { $this->exception = $e; $this->errors[] = esc_html__( 'Square fail: subscription was not cancelled.', 'charitable' ); return false; } } /** * Refund payment. * * @since 1.8.7 * * @param string $payment_id Payment ID. * @param array $args Payment data. */ public function refund_payment( string $payment_id, array $args ) { try { $request = new RefundPaymentRequest( array( 'idempotencyKey' => $this->get_idempotency_key(), 'paymentId' => $payment_id, 'amountMoney' => ( new Money() )->setAmount( $args['amount'] )->setCurrency( $args['currency'] ), 'reason' => $args['reason'], ) ); $this->response = $this->client->refunds->refundPayment( $request ); if ( $this->response->getErrors() ) { $this->errors[] = esc_html__( 'Square fail: refund was not processed.', 'charitable' ); return false; } return $this->response->getRefund(); } catch ( ApiException $e ) { $this->exception = $e; $this->errors[] = esc_html__( 'Square fail: refund was not processed.', 'charitable' ); return false; } } /** * Prepare and retrieve an address object. * * @since 1.8.7 * * @param array $data Address data. * * @return Address */ private function get_address_object( array $data ): Address { $address = new Address(); // The empty country value may occur API errors. if ( ! empty( $data['address']['country'] ) ) { $address->setAddressLine1( $data['address']['address1'] ); $address->setAddressLine2( $data['address']['address2'] ); $address->setLocality( $data['address']['city'] ); $address->setAdministrativeDistrictLevel1( $data['address']['state'] ); $address->setPostalCode( $data['address']['postal'] ); $address->setCountry( $data['address']['country'] ); } if ( ! empty( $data['first_name'] ) ) { $address->setFirstName( $data['first_name'] ); } if ( ! empty( $data['last_name'] ) ) { $address->setLastName( $data['last_name'] ); } return $address; } /** * Retrieve information of all locations of a business. * * @since 1.8.7 * * @return array|Location|null */ public function get_locations() { try { $this->response = $this->client->locations->list(); if ( $this->response->getErrors() ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_locations - errors' ); error_log( $this->response->getErrors() ); // phpcs:enable } return null; } return $this->response->getLocations(); } catch ( \Square\Exceptions\SquareApiException $e ) { $this->exception = $e; return null; } } /** * Return the Square business location ID * * @since 1.8.7 * * @param string $mode The test mode... either 'test' or 'live'. * @return string|false */ public function get_location_id( $mode = 'test' ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_location_id - the mode is: ' . $mode ); // phpcs:enable } if ( 'test' !== $mode && 'live' !== $mode ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_location_id - bad mode' . $mode ); // phpcs:enable } return false; } if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_location_id - checking if square_legacy_settings is set' ); // phpcs:enable } // Are we overridng with legacy settings? if ( charitable_square_legacy_mode() ) { $location_id = charitable_get_option( 'gateways_square', $mode . '_location_id' ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_location_id - square_legacy_settings is set to true, so the location id is' ); error_log( print_r( $location_id, true ) ); // phpcs:enable } return $location_id; } $location_id = get_option( 'charitable_square_location_id_' . $mode ); if ( empty( $location_id ) ) { return false; } return $location_id; } /** * Set the location ID for a specific mode. * * @since 1.8.7 * * @param string $location_id The location ID to set. * @param string $mode The mode to set the location ID for (test or live). * @return bool True on success. */ public function set_location_id( $location_id = '', $mode = 'test' ) { update_option( 'charitable_square_location_id_' . $mode, $location_id ); return true; } /** * Set the location currency for a specific mode. * * @since 1.8.7 * * @param string $currency The currency code to set. * @param string $mode The mode to set the currency for (test or live). * @return bool True on success. */ public function set_location_currency( $currency = '', $mode = 'test' ) { update_option( 'charitable_square_location_currency_' . $mode, $currency ); return true; } /** * Retrieve last API call response and display error messages. * * @since 1.14.0 * * @param string $type Type of error message. */ private function add_response_errors_message( string $type = 'API' ) { $errors = $this->get_response_errors(); if ( empty( $errors ) ) { return; } $key = ( $type === 'Exception' ) ? 'message' : 'detail'; foreach ( $errors as $error ) { $message = $error[ $key ] ?? ''; if ( empty( $error['code'] ) || empty( $message ) ) { return; } $this->errors[] = esc_html( $type ) . ': (' . esc_html( $error['code'] ) . ') ' . esc_html( $message ); } } /** * Retrieve API errors. * * @since 1.8.7 * * @return array|null */ public function get_errors() { return $this->errors; } /** * Retrieve last API call errors if are exist. * * @since 1.8.7 * * @return array */ public function get_response_errors(): array { if ( $this->response instanceof \Square\Legacy\Http\ApiResponse && ! $this->response->isSuccess() ) { $errors = array(); foreach ( (array) $this->response->getErrors() as $error ) { $errors[] = $error->jsonSerialize(); } return $errors; } if ( $this->exception instanceof ApiException ) { return array( 'code' => $this->exception->getCode(), 'message' => $this->exception->getMessage(), ); } return array(); } /** * Retrieve an idempotency key. * * @since 1.8.7 * * @link https://developer.squareup.com/docs/working-with-apis/idempotency * * @return string */ private function get_idempotency_key(): string { return uniqid( '', false ); } /** * Delete transients by mode. * * @since 1.8.7 * * @param string $mode Square mode. */ public static function detete_transients( string $mode ) { delete_transient( 'charitable_square_account_' . $mode ); delete_transient( 'charitable_square_active_locations_' . $mode ); } /** * Return the API key to use for the current mode. * This function might be deprecated in the future. * * @since 1.8.7 * @param string $type live|test. * * @return string|false */ public function get_access_token( $type = 'test' ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'starting to get the access token' ); // phpcs:enable } if ( 'test' !== $type && 'live' !== $type ) { return false; } $settings = charitable_get_option( 'gateways_square' ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'got charitablesquare settings, now get the access token' ); // phpcs:enable } if ( empty( $settings ) ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_access_token - settings are empty' ); // phpcs:enable } return false; } if ( empty( $settings[ $type ]['access_token'] ) ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_access_token - access token is empty' ); // phpcs:enable } return false; } $access_token = trim( $settings[ $type ]['access_token'] ); if ( empty( $access_token ) ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_access_token - access token is empty' ); // phpcs:enable } return false; } if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'get_access_token - got the access token and it is ' . $access_token ); // phpcs:enable } return $access_token; } /** * Checks whether an Access Token is set. * * @since 1.8.7 * * @return boolean */ public function has_valid_access_token() { $token_type = $this->test_mode ? 'test' : 'live'; /* We're missing an Access Token. */ if ( false === $this->{$token_type . '_access_token'} ) { return false; } /** * If we have made an API call, we record whether there * was an issue with using the Access Token. This will catch * incorrect or invalid Access Tokens. */ if ( isset( $this->access_token_validated ) ) { return $this->access_token_validated; } return true; } /** * Return the response to the most recent request. * * @since 1.8.7 * * @return WP_Error|? */ public function get_last_response() { return $this->last_response; } /** * Checks whether the API key is valid, based on API call response. * * @since 1.8.7 * * @return boolean */ private function access_token_validated() { return '401' !== wp_remote_retrieve_response_code( $this->last_response ); } /** * Returns whether the most recent request failed. * * @since 1.8.7 * * @return boolean */ private function is_failed_request() { return is_wp_error( $this->last_response ) || '2' !== substr( wp_remote_retrieve_response_code( $this->last_response ), 0, 1 ); } /** * Renew the access token using the refresh token. * * @since 1.8.7 * * @param string $refresh_token The refresh token to use for renewal. * @return array|false The response from Square API or false on failure. */ public function renew_token( $refresh_token ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'check for removal - starting renew_token' ); // phpcs:enable } if ( empty( $refresh_token ) ) { return false; } $oauth_url = $this->test_mode ? 'https://connect.squareupsandbox.com/oauth2/token' : 'https://connect.squareup.com/oauth2/token'; $args = array( 'grant_type' => 'refresh_token', 'refresh_token' => $refresh_token, ); $request_args = array( 'method' => 'POST', 'timeout' => 30, 'redirection' => 5, 'httpversion' => '1.0', 'blocking' => true, 'headers' => array( 'Content-Type' => 'application/json', ), 'body' => wp_json_encode( $args ), ); $response = wp_remote_post( $oauth_url, $request_args ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'renew_token - response' ); error_log( print_r( $response, true ) ); // phpcs:enable } if ( is_wp_error( $response ) ) { return false; } $body = wp_remote_retrieve_body( $response ); $data = json_decode( $body, true ); if ( empty( $data ) || ! isset( $data['access_token'] ) ) { return false; } return $data; } /** * Check the status of the access token. * * @since 1.8.7 * * @return array { * Token status information. * * @type bool $is_valid Whether the token is valid. * @type string $message Error message if token is invalid. * } */ public function check_token_status() { try { $response = $this->client->oAuth->retrieveTokenStatus(); if ( empty( $response->getErrors() ) ) { return array( 'is_valid' => true, 'message' => '', ); } $errors = $response->getErrors(); $error = reset( $errors ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Square token status check error: ' . print_r( $error, true ) ); // phpcs:enable } return array( 'is_valid' => false, 'message' => $error->getDetail() ?? __( 'Your Square connection has expired.', 'charitable' ), ); } catch ( \Exception $e ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Square token status check exception: ' . $e->getMessage() ); // phpcs:enable } return array( 'is_valid' => false, 'message' => $e->getMessage(), ); } } /** * Revoke an access token. * * @param string $client_id The client ID. * @param string $access_token The access token to revoke. * @param string $merchant_id The merchant ID. * @return array{success: bool, error?: string} */ public function revoke_token( string $client_id, string $access_token, string $merchant_id ): array { try { $request = new \Square\Models\RevokeTokenRequest( array( 'clientId' => $client_id, 'accessToken' => $access_token, 'merchantId' => $merchant_id, ) ); // Get the application secret from settings. $settings = charitable_get_option( 'square_settings', array() ); $application_secret = isset( $settings['application_secret'] ) ? $settings['application_secret'] : ''; if ( empty( $application_secret ) ) { return array( 'success' => false, 'error' => __( 'Square application secret is not configured.', 'charitable' ), ); } // Set the authorization header with the application secret. $options = array( 'headers' => array( 'Authorization' => 'Client ' . $application_secret, ), ); $response = $this->client->getOAuthApi()->revokeToken( $request, $options ); if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Square token revocation response: ' . print_r( $response, true ) ); // phpcs:enable } return array( 'success' => true ); } catch ( \Exception $e ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Square token revocation error: ' . $e->getMessage() ); // phpcs:enable } return array( 'success' => false, 'error' => $e->getMessage(), ); } } /** * Get merchant details from Square API. * * @since 1.8.7 * * @return string|null The merchant name or null if not found. */ public function get_merchant_name() { // Get merchant ID from instance property or settings. $merchant_id = $this->merchant_id; if ( empty( $merchant_id ) ) { $square_settings = charitable_get_option( 'gateways_square', array() ); $mode = $this->test_mode ? 'test' : 'live'; $merchant_id = ! empty( $square_settings[ $mode ]['merchant_id'] ) ? $square_settings[ $mode ]['merchant_id'] : ''; } if ( empty( $merchant_id ) ) { return null; } $merchant_name = get_transient( 'charitable_square_merchant_name_' . $merchant_id ); if ( false !== $merchant_name ) { return $merchant_name; } try { $request = new \Square\Merchants\Requests\GetMerchantsRequest( array( 'merchantId' => $merchant_id, ) ); $response = $this->client->merchants->get( $request ); if ( $response && $response->getMerchant() ) { $merchant = $response->getMerchant(); $merchant_name = $merchant->getBusinessName() ? $merchant->getBusinessName() : $merchant->getMainLocationName(); if ( $merchant_name ) { set_transient( 'charitable_square_merchant_name_' . $merchant_id, $merchant_name, DAY_IN_SECONDS ); return $merchant_name; } } } catch ( \Exception $e ) { if ( charitable_is_debug( 'square' ) ) { // phpcs:disable error_log( 'Square API Error: ' . $e->getMessage() ); // phpcs:enable } } return null; } }
/home/batcwwjx/www/wp-content/plugins/charitable/./includes/square/class-charitable-square-api.php