namespace WPForms\Integrations\Square\Api;
use WPForms\Integrations\Square\Helpers;
use WPForms\Vendor\Square\Models\Invoice;
use WPForms\Vendor\Square\Exceptions\ApiException;
use WPForms\Vendor\Square\Http\ApiResponse;
use WPForms\Vendor\Square\Models\Address;
use WPForms\Vendor\Square\Models\Card;
use WPForms\Vendor\Square\Models\CatalogObject;
use WPForms\Vendor\Square\Models\CatalogObjectType;
use WPForms\Vendor\Square\Models\CatalogQuery;
use WPForms\Vendor\Square\Models\CatalogQueryExact;
use WPForms\Vendor\Square\Models\CatalogSubscriptionPlan;
use WPForms\Vendor\Square\Models\UpdateSubscriptionResponse;
use WPForms\Vendor\Square\Models\CatalogSubscriptionPlanVariation;
use WPForms\Vendor\Square\Models\CreateCardRequest;
use WPForms\Vendor\Square\Models\CreateCustomerRequest;
use WPForms\Vendor\Square\Models\CreateOrderRequest;
use WPForms\Vendor\Square\Models\CreatePaymentRequest;
use WPForms\Vendor\Square\Models\CreatePaymentResponse;
use WPForms\Vendor\Square\Models\CreateSubscriptionRequest;
use WPForms\Vendor\Square\Models\CreateSubscriptionResponse;
use WPForms\Vendor\Square\Models\Money;
use WPForms\Vendor\Square\Models\Order;
use WPForms\Vendor\Square\Models\OrderLineItem;
use WPForms\Vendor\Square\Models\OrderLineItemDiscount;
use WPForms\Vendor\Square\Models\OrderSource;
use WPForms\Vendor\Square\Models\OrderState;
use WPForms\Vendor\Square\Models\Payment;
use WPForms\Vendor\Square\Models\RefundPaymentRequest;
use WPForms\Vendor\Square\Models\SearchCatalogObjectsRequest;
use WPForms\Vendor\Square\Models\Subscription;
use WPForms\Vendor\Square\Models\SubscriptionPhase;
use WPForms\Vendor\Square\Models\SubscriptionPricing;
use WPForms\Vendor\Square\Models\SubscriptionSource;
use WPForms\Vendor\Square\Models\UpdateOrderRequest;
use WPForms\Vendor\Square\Models\UpdateSubscriptionRequest;
use WPForms\Vendor\Square\Models\UpsertCatalogObjectRequest;
use WPForms\Vendor\Square\Models\Customer;
use WPForms\Vendor\Square\SquareClient;
use WPForms\Integrations\Square\Connection;
use WPForms\Integrations\Square\Square;
* WPForms Square API class.
* Square API client instance.
* Payment token (card nonce) generated by the Web Payments SDK.
* Last API call response.
* Last API call exception.
* Constructs the main Square API wrapper class.
* @param Connection $connection Connection object.
public function __construct( $connection ) {
$this->client = new SquareClient(
'accessToken' => $connection->get_access_token(),
'environment' => $connection->get_mode(),
* Set tokens from a submitted form data.
* @param array $entry Copy of original $_POST.
public function set_payment_tokens( array $entry ) {
if ( ! empty( $entry['square']['source_id'] ) ) {
$this->source_id = $entry['square']['source_id'];
* Check if OAuth connection is present and ready to use.
private function check_connection() {
$connection = Connection::get();
if ( ! $connection || ! $connection->is_configured() ) {
$this->errors[] = esc_html__( 'Square account connection is missing.', 'wpforms-lite' );
if ( ! $connection->is_valid() ) {
$this->errors[] = esc_html__( 'Square account connection is invalid.', 'wpforms-lite' );
if ( ! $connection->is_currency_matched() ) {
$this->errors[] = esc_html__( 'The currency associated with the payment is not valid for the provided business location.', 'wpforms-lite' );
* Check if single payment tokens are present.
private function check_payment_tokens() {
if ( empty( $this->source_id ) ) {
$this->errors[] = esc_html__( 'Square payment stopped, missing card tokens.', 'wpforms-lite' );
* Check if all required general arguments are present.
* @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.', 'wpforms-lite' );
if ( empty( $args['currency'] ) ) {
$this->errors[] = esc_html__( 'Missing currency.', 'wpforms-lite' );
if ( empty( $args['amount'] ) && ! is_numeric( $args['amount'] ) ) {
$this->errors[] = esc_html__( 'Missing amount.', 'wpforms-lite' );
* Check if all required single payment arguments are present.
* @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.', 'wpforms-lite' );
* Process single transaction.
* @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 );
$result = $this->perform_single_transaction( $args );
* Fire when a single transaction is performed.
* @param array $result Single transaction result.
* @param array $args Payment arguments.
* @param Api $api Api class instance.
do_action( 'wpforms_square_api_process_single_transaction_after', $result, $args, $this ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
* Process subscription transaction.
* @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 );
$this->perform_subscription_transaction( $args );
* @param string $payment_id Payment ID.
* @param array $args Payment data.
public function refund_payment( string $payment_id, array $args ): bool {
$request = new RefundPaymentRequest( $this->get_idempotency_key(), new Money() );
$request->setPaymentId( $payment_id );
$request->setReason( $args['reason'] );
$request->getAmountMoney()->setAmount( $args['amount'] );
$request->getAmountMoney()->setCurrency( $args['currency'] );
$this->response = $this->client->getRefundsApi()->refundPayment( $request );
if ( ! $this->response->isSuccess() ) {
} catch ( ApiException $e ) {
* @param array $args Subscription arguments.
public function update_subscription( array $args ) {
$subscription = $this->retrieve_subscription( $args['id'] );
if ( ! $subscription instanceof Subscription ) {
$request = $this->get_update_subscription_request_object( $subscription, $args );
$this->send_update_subscription_request( $args['id'], $request );
* @param string $subscription_id Subscription id.
public function cancel_subscription( string $subscription_id ): bool {
$this->response = $this->client->getSubscriptionsApi()->cancelSubscription( $subscription_id );
if ( ! $this->response->isSuccess() ) {
} catch ( ApiException $e ) {
* Retrieve a Card object.
* @param Subscription $subscription Subscription object.
public function get_subscription_card( $subscription ) {
if ( ! $subscription instanceof Subscription ) {
$card_id = $subscription->getCardId();
if ( empty( $card_id ) ) {
$card = $this->send_retrieve_card_request( $card_id );
if ( ! $card instanceof Card ) {
* Send a retrieve subscription request to API.
* @param string $id The ID of the subscription to retrieve.
* @return Subscription|null
public function retrieve_subscription( string $id ) {
$response = $this->client->getSubscriptionsApi()->retrieveSubscription( $id );
if ( ! $response->isSuccess() ) {
return $response->getResult()->getSubscription();
} catch ( ApiException $e ) {
* Retrieve a Card object.
* @param Subscription $subscription Subscription object.
public function get_latest_subscription_invoice( $subscription ) {
if ( ! $subscription instanceof Subscription ) {
$invoices = $subscription->getInvoiceIds();
if ( empty( $invoices ) ) {
$response = $this->client->getInvoicesApi()->getInvoice( reset( $invoices ) ); // Get the latest invoice by using the first ID in the array as the subscription's invoice IDs are sorted by date in ascending order.
if ( ! $response->isSuccess() ) {
return $response->getResult()->getInvoice();
} catch ( ApiException $e ) {
* Perform a single transaction.
* @param array $args Payment arguments.
private function perform_single_transaction( array $args ): array {
$order_request = $this->prepare_create_order_request( $args );
$order = $this->send_create_order_request( $order_request );
if ( ! $order instanceof Order ) {
$result['order'] = $order;
$payment_request = $this->prepare_create_payment_request( $order, $args );
$payment = $this->send_create_payment_request( $payment_request );
// 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 ? [ 'order' => $updated_order ] : $result;
$result['payment'] = $payment;
* Prepare a create order request object for sending to API.
* @param array $args Single payment arguments.
* @return CreateOrderRequest
private function prepare_create_order_request( array $args ): CreateOrderRequest {
$request = $this->get_create_order_request_object( $args );
$request = $this->create_order_request_set_line_items( $request, $args );
$request = $this->create_order_request_set_discounts( $request, $args );
* Filter a create order request object.
* @param CreateOrderRequest $request Create order request object.
* @param array $args Payment arguments.
* @param Api $api Api class instance.
return apply_filters( 'wpforms_square_api_prepare_create_order_request', $request, $args, $this ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
* Prepare an update order request object for sending to API.
* @param Order $order Order object.
* @return UpdateOrderRequest