com.shopify.buy.dataprovider.BuyClient.java Source code

Java tutorial

Introduction

Here is the source code for com.shopify.buy.dataprovider.BuyClient.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Shopify Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.shopify.buy.dataprovider;

import android.text.TextUtils;
import android.util.Base64;

import com.google.gson.Gson;
import com.shopify.buy.model.Checkout;
import com.shopify.buy.model.Collection;
import com.shopify.buy.model.Collection.SortOrder;
import com.shopify.buy.model.CreditCard;
import com.shopify.buy.model.GiftCard;
import com.shopify.buy.model.Product;
import com.shopify.buy.model.ShippingRate;
import com.shopify.buy.model.Shop;
import com.shopify.buy.model.internal.CheckoutWrapper;
import com.shopify.buy.model.internal.CollectionPublication;
import com.shopify.buy.model.internal.GiftCardWrapper;
import com.shopify.buy.model.internal.MarketingAttribution;
import com.shopify.buy.model.internal.PaymentSessionCheckout;
import com.shopify.buy.model.internal.PaymentSessionCheckoutWrapper;
import com.shopify.buy.model.internal.ProductPublication;
import com.shopify.buy.model.internal.ShippingRatesWrapper;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import retrofit.Callback;
import retrofit.ResponseCallback;
import retrofit.RetrofitError;
import retrofit.client.Header;
import retrofit.client.Response;
import retrofit.mime.TypedByteArray;

/**
 * The {@code BuyClient} provides all requests needed to perform request on the Shopify Checkout API. Use this class to perform tasks such as getting a shop, getting collections and products for a shop, creating a {@link Checkout} on Shopify and completing Checkouts.
 * All API methods presented here run asynchronously and return results via callback on the Main thread.
 */
public class BuyClient {

    public static final int MAX_PAGE_SIZE = 250;
    public static final int MIN_PAGE_SIZE = 1;
    public static final int DEFAULT_PAGE_SIZE = 25;

    private static final MediaType jsonMediateType = MediaType.parse("application/json; charset=utf-8");
    private final BuyRetrofitService retrofitService;
    private final OkHttpClient httpClient;
    private int pageSize = DEFAULT_PAGE_SIZE;

    private final String shopDomain;
    private final String apiKey;
    private final String channelId;
    private final String applicationName;
    private String webReturnToUrl;
    private String webReturnToLabel;

    public String getApiKey() {
        return apiKey;
    }

    public String getChannelId() {
        return channelId;
    }

    public String getApplicationName() {
        return applicationName;
    }

    public String getWebReturnToUrl() {
        return webReturnToUrl;
    }

    public String getWebReturnToLabel() {
        return webReturnToLabel;
    }

    public String getShopDomain() {
        return shopDomain;
    }

    BuyClient(BuyRetrofitService retrofitService, String apiKey, String channelId, String applicationName,
            String shopDomain, OkHttpClient httpClient) {
        this.retrofitService = retrofitService;
        this.apiKey = apiKey;
        this.channelId = channelId;
        this.applicationName = applicationName;
        this.shopDomain = shopDomain;
        this.httpClient = httpClient;
    }

    /**
     * For internal use only.
     */
    public void addInterceptor(Interceptor interceptor) {
        this.httpClient.interceptors().add(interceptor);
    }

    /**
     * Sets the web url to be invoked by the button on the completion page of the web checkout.
     *
     * @param webReturnToUrl a url defined as a custom scheme in the Android Manifest file.
     */
    public void setWebReturnToUrl(String webReturnToUrl) {
        this.webReturnToUrl = webReturnToUrl;
    }

    /**
     * Sets the text to be displayed on the button on the completion page of the web checkout
     *
     * @param webReturnToLabel the text to display on the button.
     */
    public void setWebReturnToLabel(String webReturnToLabel) {
        this.webReturnToLabel = webReturnToLabel;
    }

    /**
     * Sets the page size used for paged API queries
     *
     * @param pageSize the number of {@link Product} to include in a page.  The maximum page size is {@link #MAX_PAGE_SIZE} and the minimum page size is {@link #MIN_PAGE_SIZE}.
     *                 If the page size is less than {@code MIN_PAGE_SIZE}, it will be set to {@code MIN_PAGE_SIZE}.  If the page size is greater than MAX_PAGE_SIZE it will be set to {@code MAX_PAGE_SIZE}.
     *                 The default value is {@link #DEFAULT_PAGE_SIZE}
     */
    public void setPageSize(int pageSize) {
        this.pageSize = Math.max(Math.min(pageSize, MAX_PAGE_SIZE), MIN_PAGE_SIZE);
    }

    /*
     * Storefront API
     */

    /**
     * Fetch metadata about your shop
     *
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getShop(Callback<Shop> callback) {
        retrofitService.getShop(callback);
    }

    /**
     * Fetch a page of products
     *
     * @param page     the 1-based page index. The page size can be set with
     *                 {@link #setPageSize(int)}
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getProductPage(int page, final Callback<List<Product>> callback) {
        if (page < 1) {
            throw new IllegalArgumentException("page is a 1-based index, value cannot be less than 1");
        }

        // All product responses from the server are wrapped in a ProductPublication object which contains and array of products
        // For this call, we will clamp the size of the product array returned to the page size
        retrofitService.getProductPage(channelId, page, pageSize, new Callback<ProductPublication>() {
            @Override
            public void success(ProductPublication productPage, Response response) {
                List<Product> products = null;
                if (productPage != null) {
                    products = productPage.getProducts();
                }
                callback.success(products, response);
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     * Fetch a single Product
     *
     * @param productId the productId for the product to fetch
     * @param callback  the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getProduct(String productId, final Callback<Product> callback) {
        if (productId == null) {
            throw new NullPointerException("productId cannot be null");
        }

        // All product responses from the server are wrapped in a ProductPublication object
        // The same endpoint is used for single and multiple product queries.
        // For this call we will query with a single id, and the returned product array
        // If the id was found the array will contain a single object, otherwise it will be empty
        retrofitService.getProducts(channelId, productId, new Callback<ProductPublication>() {
            @Override
            public void success(ProductPublication productPublications, Response response) {
                Product product = null;

                if (productPublications != null) {
                    List<Product> products = productPublications.getProducts();

                    if (products != null && products.size() > 0) {
                        product = products.get(0);
                    }
                }
                callback.success(product, response);
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     * Fetch a list of Products
     *
     * @param productIds a List of the productIds to fetch
     * @param callback   the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getProducts(List<String> productIds, final Callback<List<Product>> callback) {
        if (productIds == null) {
            throw new NullPointerException("productIds List cannot be null");
        }
        if (productIds.size() < 1) {
            throw new IllegalArgumentException("productIds List cannot be empty");
        }
        String queryString = TextUtils.join(",", productIds.toArray());

        // All product responses from the server are wrapped in a ProductPublication object
        // The same endpoint is used for single and multiple product queries.
        // For this call we will query with multiple ids.
        // The returned product array will contain products for each id found.
        // If no ids were found, the array will be empty
        retrofitService.getProducts(channelId, queryString, new Callback<ProductPublication>() {
            @Override
            public void success(ProductPublication productPublications, Response response) {
                List<Product> products = null;

                if (productPublications != null) {
                    products = productPublications.getProducts();
                }

                callback.success(products, response);
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     * Fetch the list of Products in a Collection using the sort order defined in the shop admin
     *
     * @param page         the 1-based page index. The page size can be set with {@link #setPageSize(int)}
     * @param collectionId the collectionId that we want to fetch products for
     * @param callback     the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getProducts(int page, String collectionId, final Callback<List<Product>> callback) {
        getProducts(page, collectionId, SortOrder.COLLECTION_DEFAULT, callback);
    }

    /**
     * Fetch the list of Products in a Collection
     *
     * @param page         the 1-based page index. The page size can be set with {@link #setPageSize(int)}
     * @param collectionId the collectionId that we want to fetch products for
     * @param sortOrder    the sort order for the collection.
     * @param callback     the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getProducts(int page, String collectionId, SortOrder sortOrder,
            final Callback<List<Product>> callback) {
        if (page < 1) {
            throw new IllegalArgumentException("page is a 1-based index, value cannot be less than 1");
        }
        if (collectionId == null) {
            throw new IllegalArgumentException("collectionId cannot be null");
        }

        retrofitService.getProducts(channelId, collectionId, pageSize, page, sortOrder.toString(),
                new Callback<ProductPublication>() {
                    @Override
                    public void success(ProductPublication productPublications, Response response) {
                        List<Product> products = null;

                        if (productPublications != null) {
                            products = productPublications.getProducts();
                        }

                        callback.success(products, response);
                    }

                    @Override
                    public void failure(RetrofitError error) {
                        callback.failure(error);
                    }
                });
    }

    /**
     * Fetch a list of Collections
     *
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getCollections(final Callback<List<Collection>> callback) {
        getCollectionPage(1, callback);
    }

    /**
     * Fetch a page of collections
     *
     * @param page     the 1-based page index. The page size can be set with
     *                 {@link #setPageSize(int)}
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getCollectionPage(int page, final Callback<List<Collection>> callback) {
        if (page < 1) {
            throw new IllegalArgumentException("page is a 1-based index, value cannot be less than 1");
        }

        // All collection responses from the server are wrapped in a CollectionPublication object which contains and array of collections
        // For this call, we will clamp the size of the collection array returned to the page size
        retrofitService.getCollectionPage(channelId, page, pageSize, new Callback<CollectionPublication>() {
            @Override
            public void success(CollectionPublication collectionPage, Response response) {
                List<Collection> collections = null;
                if (collectionPage != null) {
                    collections = collectionPage.getCollections();
                }
                callback.success(collections, response);
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /*
     * Buy API
     */

    /**
     * Initiate the Shopify checkout process with a new Checkout object.
     *
     * @param checkout the {@link Checkout} object to use for initiating the checkout process
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void createCheckout(Checkout checkout, final Callback<Checkout> callback) {
        if (checkout == null) {
            throw new NullPointerException("checkout cannot be null");
        }

        checkout.setChannelId(channelId);
        checkout.setMarketingAttribution(new MarketingAttribution(applicationName));
        checkout.setSourceName("mobile_app");
        checkout.setSourceIdentifier(channelId);

        if (webReturnToUrl != null) {
            checkout.setWebReturnToUrl(webReturnToUrl);
        }

        if (webReturnToLabel != null) {
            checkout.setWebReturnToLabel(webReturnToLabel);
        }

        retrofitService.createCheckout(new CheckoutWrapper(checkout), new Callback<CheckoutWrapper>() {
            @Override
            public void success(CheckoutWrapper checkoutWrapper, Response response) {
                callback.success(checkoutWrapper.getCheckout(), response);
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     * Update an existing Checkout's attributes
     *
     * @param checkout the {@link Checkout} to update
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void updateCheckout(final Checkout checkout, final Callback<Checkout> callback) {
        if (checkout == null) {
            throw new NullPointerException("checkout cannot be null");
        }

        Checkout cleanCheckout = checkout.copyForUpdate();

        retrofitService.updateCheckout(new CheckoutWrapper(cleanCheckout), cleanCheckout.getToken(),
                new Callback<CheckoutWrapper>() {
                    @Override
                    public void success(CheckoutWrapper checkoutWrapper, Response response) {
                        callback.success(checkoutWrapper.getCheckout(), response);
                    }

                    @Override
                    public void failure(RetrofitError error) {
                        callback.failure(error);
                    }
                });
    }

    /**
     * Fetch shipping rates for a given Checkout
     *
     * @param checkoutToken the {@link Checkout#token} from an existing Checkout
     * @param callback      the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getShippingRates(String checkoutToken, final Callback<List<ShippingRate>> callback) {
        if (checkoutToken == null) {
            throw new NullPointerException("checkoutToken cannot be null");
        }

        retrofitService.getShippingRates(checkoutToken, new Callback<ShippingRatesWrapper>() {
            @Override
            public void success(ShippingRatesWrapper shippingRatesWrapper, Response response) {
                if (HttpURLConnection.HTTP_OK == response.getStatus() && shippingRatesWrapper != null) {
                    callback.success(shippingRatesWrapper.getShippingRates(), response);
                } else {
                    callback.success(null, response);
                }
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     * Post a credit card to Shopify's card server and associate it with a Checkout
     *
     * @param card     the {@link CreditCard} to associate
     * @param checkout the {@link Checkout} to associate the card with
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void storeCreditCard(final CreditCard card, final Checkout checkout, final Callback<Checkout> callback) {
        if (card == null) {
            throw new NullPointerException("card cannot be null");
        }

        if (checkout == null) {
            throw new NullPointerException("checkout cannot be null");
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                PaymentSessionCheckoutWrapper dataWrapper = new PaymentSessionCheckoutWrapper();
                PaymentSessionCheckout data = new PaymentSessionCheckout();
                data.setToken(checkout.getToken());
                data.setCreditCard(card);
                data.setBillingAddress(checkout.getBillingAddress());
                dataWrapper.setCheckout(data);

                RequestBody body = RequestBody.create(jsonMediateType, new Gson().toJson(dataWrapper));

                Request request = new Request.Builder().url(checkout.getPaymentUrl()).post(body)
                        .addHeader("Authorization",
                                "Basic " + Base64.encodeToString(apiKey.getBytes(), Base64.NO_WRAP))
                        .addHeader("Content-Type", "application/json").addHeader("Accept", "application/json")
                        .build();
                try {
                    com.squareup.okhttp.Response httpResponse = httpClient.newCall(request).execute();
                    String paymentSessionId = parsePaymentSessionResponse(httpResponse);
                    checkout.setPaymentSessionId(paymentSessionId);

                    Response retrofitResponse = new Response(request.urlString(), httpResponse.code(),
                            httpResponse.message(), Collections.<Header>emptyList(), null);
                    callback.success(checkout, retrofitResponse);
                } catch (IOException e) {
                    e.printStackTrace();

                    callback.failure(RetrofitError.unexpectedError(request.urlString(), e));
                }
            }
        }).start();
    }

    /**
     * Complete the checkout and process the payment session
     *
     * @param checkout a {@link Checkout} that has had a {@link CreditCard} associated with it using {@link #storeCreditCard(CreditCard, Checkout, Callback)}
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void completeCheckout(Checkout checkout, final Callback<Checkout> callback) {
        if (checkout == null) {
            throw new NullPointerException("checkout cannot be null");
        }

        HashMap<String, String> requestBodyMap = new HashMap<>();

        String paymentSessionId = checkout.getPaymentSessionId();
        if (!TextUtils.isEmpty(paymentSessionId)) {
            requestBodyMap.put("payment_session_id", checkout.getPaymentSessionId());
        }

        retrofitService.completeCheckout(requestBodyMap, checkout.getToken(), new Callback<CheckoutWrapper>() {
            @Override
            public void success(CheckoutWrapper checkoutWrapper, Response response) {
                callback.success(checkoutWrapper.getCheckout(), response);
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     * Get the status of the payment session associated with {@code checkout}. {@code callback} will be
     * called with a boolean value indicating whether the session has completed or not. This method
     * should be polled until the {@code callback} response is {@code true}
     *
     * @param checkout a {@link Checkout} that has been passed as a parameter to {@link #completeCheckout(Checkout, Callback)}
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getCheckoutCompletionStatus(Checkout checkout, final Callback<Boolean> callback) {
        if (checkout == null) {
            throw new NullPointerException("checkout cannot be null");
        }

        retrofitService.getCheckoutCompletionStatus(checkout.getToken(), new ResponseCallback() {
            @Override
            public void success(Response response) {
                if (HttpURLConnection.HTTP_OK == response.getStatus()) {
                    callback.success(true, response);
                } else {
                    callback.success(false, response);
                }

            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     * Fetch an existing Checkout from Shopify
     *
     * @param checkoutToken the token associated with the existing {@link Checkout}
     * @param callback      the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void getCheckout(String checkoutToken, final Callback<Checkout> callback) {
        if (checkoutToken == null) {
            throw new NullPointerException("checkoutToken cannot be null");
        }

        retrofitService.getCheckout(checkoutToken, new Callback<CheckoutWrapper>() {
            @Override
            public void success(CheckoutWrapper checkoutWrapper, Response response) {
                callback.success(checkoutWrapper.getCheckout(), response);
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     * Apply a gift card to a Checkout
     *
     * @param giftCardCode the gift card code for a gift card associated with the current Shop
     * @param checkout     the {@link Checkout} object to apply the gift card to
     * @param callback     the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void applyGiftCard(String giftCardCode, final Checkout checkout, final Callback<Checkout> callback) {
        if (checkout == null) {
            throw new NullPointerException("checkout cannot be null");
        }

        final GiftCard giftCard = new GiftCard(giftCardCode);

        retrofitService.applyGiftCard(new GiftCardWrapper(giftCard), checkout.getToken(),
                new Callback<GiftCardWrapper>() {
                    @Override
                    public void success(GiftCardWrapper giftCardWrapper, Response response) {
                        GiftCard updatedGiftCard = giftCardWrapper.getGiftCard();
                        checkout.addGiftCard(updatedGiftCard);
                        checkout.setPaymentDue(updatedGiftCard.getCheckout().getPaymentDue());
                        callback.success(checkout, response);
                    }

                    @Override
                    public void failure(RetrofitError error) {
                        callback.failure(error);
                    }
                });
    }

    /**
     * Remove a gift card that was previously applied to a Checkout
     *
     * @param giftCard the {@link GiftCard} to remove from the {@link Checkout}
     * @param checkout the {@code Checkout} to remove the {@code GiftCard} from
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void removeGiftCard(final GiftCard giftCard, final Checkout checkout,
            final Callback<Checkout> callback) {
        if (checkout == null) {
            throw new NullPointerException("checkout cannot be null");
        }

        if (giftCard == null) {
            throw new NullPointerException("giftCard cannot be null");
        }

        retrofitService.removeGiftCard(giftCard.getId(), checkout.getToken(), new Callback<GiftCardWrapper>() {
            @Override
            public void success(GiftCardWrapper giftCardWrapper, Response response) {
                GiftCard updatedGiftCard = giftCardWrapper.getGiftCard();
                checkout.removeGiftCard(updatedGiftCard);
                checkout.setPaymentDue(updatedGiftCard.getCheckout().getPaymentDue());
                callback.success(checkout, response);
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     *  Convenience method to release all product inventory reservations by setting the `reservationTime` of the checkout `0` and calling {@link #updateCheckout(Checkout, Callback) updateCheckout(Checkout, Callback)}.
     *  We recommend creating a new `Checkout` object from a `Cart` for further API calls.
     *
     *  @param checkout the {@link Checkout} to expire
     *  @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void removeProductReservationsFromCheckout(final Checkout checkout, final Callback<Checkout> callback) {
        if (checkout == null || TextUtils.isEmpty(checkout.getToken())) {
            callback.failure(null);
        } else {
            checkout.setReservationTime(0);

            Checkout expiredCheckout = new Checkout();
            expiredCheckout.setToken(checkout.getToken());
            expiredCheckout.setReservationTime(0);
            updateCheckout(expiredCheckout, callback);
        }
    }

    /**
     * Test the integration with your shop.  This should not be shipped in production code
     *
     * @param callback the {@link Callback} that will be used to indicate the response from the asynchronous network operation, not null
     */
    public void testIntegration(final Callback<Void> callback) {
        retrofitService.testIntegration(apiKey, channelId, new Callback<Void>() {
            @Override
            public void success(Void aVoid, Response response) {
                callback.success(aVoid, response);
            }

            @Override
            public void failure(RetrofitError error) {
                callback.failure(error);
            }
        });
    }

    /**
     * Helper methods
     */

    /**
     * Extracts the body of the {@code Response} associated with this error
     *
     * @param error the {@link RetrofitError}
     * @return the body of the response
     */
    public static String getErrorBody(RetrofitError error) {
        String json = null;
        try {
            json = new String(((TypedByteArray) error.getResponse().getBody()).getBytes());
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return json;
    }

    private String parsePaymentSessionResponse(com.squareup.okhttp.Response response) throws IOException {
        String paymentSessionId = null;
        if (response.isSuccessful()) {
            String jsonString = response.body().string();
            try {
                JSONObject json = new JSONObject(jsonString);
                paymentSessionId = (String) json.get("id");
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return paymentSessionId;
    }
}