Example #1
0
        /// <summary>
        /// Gets the recurring charge asynchronous.
        /// </summary>
        /// <param name="myShopifyDomain">The myshopify URL.</param>
        /// <param name="shopifyAccessToken">The shopify access token.</param>
        /// <param name="chargeId">The charge identifier.</param>
        /// <param name="fields">The fields.</param>
        /// <returns></returns>
        public async Task <ShopifyRecurringChargeObject> GetRecurringChargeAsync(string myShopifyDomain, string shopifyAccessToken, long chargeId, string fields = null)
        {
            _CheckmyShopifyDomain(myShopifyDomain);
            _CheckShopAccessToken(shopifyAccessToken);
            RecurringChargeService service = new RecurringChargeService(myShopifyDomain, shopifyAccessToken);

            _Logger.LogInformation($"Retriving recurring charge with id ='{chargeId}'");
            var data = await service.GetAsync(chargeId, fields);

            var ret = new ShopifyRecurringChargeObject()
            {
                CancelledOn     = data.CancelledOn,
                BillingOn       = data.BillingOn,
                ActivatedOn     = data.ActivatedOn,
                CappedAmount    = data.CappedAmount,
                ConfirmationUrl = data.ConfirmationUrl,
                CreatedAt       = data.CreatedAt,
                Id          = data.Id,
                Name        = data.Name,
                Price       = data.Price,
                ReturnUrl   = data.ReturnUrl,
                Status      = data.Status,
                Terms       = data.Terms,
                Test        = data.Test,
                TrialDays   = data.TrialDays,
                TrialEndsOn = data.TrialEndsOn,
                UpdatedAt   = data.UpdatedAt
            };

            _Logger.LogInformation($"Found recurring charge '{ret.Id} - {ret.Name} - {ret.Price} - {(ret.Test.Value ? "is_test" : "not_test")} - {ret.TrialDays} days - {ret.ReturnUrl}'.");
            return(ret);
        }
        /// <summary>
        /// Generates a view with basic profile information (such as billing date, trial expiry, plan name etc tec)
        /// </summary>
        /// <returns></returns>
        public virtual async Task <ActionResult> Index()
        {
            Logger.LogInformation("Getting user to display his profile.");
            var me = await AppUserCache.GetLoggedOnUser();

            Logger.LogInformation("Found user is {@user}", me);
            Logger.LogInformation("Getting  plan data.");
            var plan = Plans[me.GetPlanId()];

            Logger.LogInformation("Found plan is {@plan}", plan);
            Logger.LogInformation("Preparing to get recurring charge info.");
            ShopifyRecurringChargeObject recChargeInfo = null;
            bool getFrmApi = (me.IsAdmin && me.BillingIsConnected) ? false : true;

            if (!getFrmApi)
            {
                Logger.LogInformation("User is admin and billing is connected so recurring charge info will NOT be loaded.");
            }
            else
            {
                Logger.LogInformation("Recurring charge info will be read from shopify API.");
            }

            if (getFrmApi)
            {
                try
                {
                    Logger.LogInformation("Requesting recurring charge infor from shopify.");
                    recChargeInfo = await ShopifyAPI.GetRecurringChargeAsync(me.MyShopifyDomain, me.ShopifyAccessToken, me.ShopifyChargeId.Value);

                    Logger.LogInformation("Recieved recurring charge info {@info}.", recChargeInfo);
                }
                catch (Exception ex)
                {
                    recChargeInfo = null;
                    Logger.LogError("Error occurred while reading recurring charge info from shopify.", ex);
                }
            }
            Logger.LogInformation($"My profile index view nmae is {this.Views.MyProfile.Index}.");
            return(View(this.Views.MyProfile.Index, new MyProfileViewModel()
            {
                Me = me,
                MyPlan = plan,
                ChargeData = recChargeInfo
            }));
        }
Example #3
0
        public virtual async Task <IActionResult> SelectedPlan(int planId)
        {
            using (Logger.BeginScope(new { PlanId = planId }))
            {
                try
                {
                    Logger.LogInformation("Getting user");
                    var user = await UserDbServiceHelper.GetAppUserByIdAsync(UserDbService, UserInContextHelper.GetCurrentUserId(HttpContext));

                    string domain = user.MyShopifyDomain;
                    string token  = user.ShopifyAccessToken;
                    /*user plan id = 0  means that customer is new*/
                    int userPlanId = user.GetPlanId();
                    Logger.LogInformation($"Got user.User ID '{user.Id}', domain '{user.MyShopifyDomain}', token '{user.ShopifyAccessToken}' and Plan Id '{user.PlanId}'.");
                    //privileged ip holders can downgrade or upgrade plan, others are upgrade only
                    var validUpgrade    = planId >= userPlanId;
                    var priviledgedUser = IPAddressHelper.IsCurrentUserIpPrivileged(HttpContext, Settings);

                    Logger.LogInformation($"Selected is a valid upgrade : {validUpgrade}");
                    Logger.LogInformation($"Selector's IP is priviledged: {priviledgedUser}");

                    if (validUpgrade || priviledgedUser)
                    {
                        Logger.LogInformation("Plan selection is approved.");
                        var plan = PlanReader[planId];
                        if (plan != null && plan.Id > 0)
                        {
                            Logger.LogInformation($"Found plan for the selected ID. Plan Name '{plan.Name}'.");
                            var charge = new ShopifyRecurringChargeObject()
                            {
                                Name      = plan.Name,
                                Price     = plan.Price,
                                TrialDays = plan.TrialDays,
                                Test      = plan.IsTest,
                                ReturnUrl = ShopifyUrlHelper.GetChargeResultHandlerUrl(Settings),
                            };
                            try
                            {
                                Logger.LogInformation("Creating recurring charge via api for selected plan.");
                                charge = await ShopifyAPI.CreateRecurringChargeAsync(domain, token, charge);

                                Logger.LogInformation($"Successfully created recurring charge. Redirecting to confirmation URL '{charge.ConfirmationUrl}'.");
                                return(Redirect(charge.ConfirmationUrl));
                            }
                            catch (Exception ex)
                            {
                                Logger.LogError(ex, $"Failed creating recurring charge for the selected plan.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action.");
                                WebMsg.AddTempDanger(this, "Could not create a recurring charge record/confirmation url via shopify api. Please try again.", false, false);
                                return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));
                            }
                        }
                    }

                    //if we are here then it is an invalid plan
                    Logger.LogWarning($"Selection is not approved.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' adction");
                    WebMsg.AddTempDanger(this, "Invalid Plan Selected", false, false);
                    return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));
                }
                catch (Exception ex)
                {
                    Logger.LogWarning("Error occurred while executing SelectedPlan())");
                    LogGenericError(ex);
                    throw ex;
                }
            }
        }
Example #4
0
        public virtual async Task <IActionResult> ChargeResult(string shop, long charge_id)
        {
            using (Logger.BeginScope(new { Shop = shop, ChargeId = charge_id }))
            {
                try
                {
                    Logger.LogInformation("Getting current user.");
                    var user = await UserDbServiceHelper.GetAppUserByIdAsync(UserDbService, UserInContextHelper.GetCurrentUserId(HttpContext));

                    Logger.LogInformation($"Found user. Id is '{user.Id}'");
                    //to detect if its an upgrade we need users previous plan id, 0 means no previous plan.
                    Logger.LogInformation($"Getting previous plan info, if any.");
                    var previousPlan = user.GetPlanId();
                    Logger.LogInformation($"Previous plan ID is set to '{previousPlan}'.");
                    PlanAppModel newPlan = null;
                    ShopifyRecurringChargeObject charge = null;

                    try
                    {
                        Logger.LogInformation($"Retriving recurring charge info (before activation). Access token '{user.ShopifyAccessToken}' and charge id '{charge_id}'.");
                        charge = await ShopifyAPI.GetRecurringChargeAsync(user.MyShopifyDomain, user.ShopifyAccessToken, charge_id);

                        Logger.LogInformation($"Successfully retrived recurring charge info (before activation).Id is '{charge.Id}'.Associated plan name '{charge.Name}' and price '{charge.Price}'.");
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(ex, "Error retriving recurring charge info (before activation).");
                        WebMsg.AddTempDanger(this, "Could not retrive charge status by charge id via shopify api (before activation).");
                        return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));
                    }

                    newPlan = PlanReader[charge.Name];

                    if (newPlan != null)
                    {
                        Logger.LogInformation($"New plan ID is set to '{newPlan.Id}'.");
                        Logger.LogInformation($"Recurring charge status (before activation) is '{charge.Status}'.");
                        if (charge.Status == "accepted")
                        {
                            //Lets activate the charge
                            try
                            {
                                Logger.LogInformation("Trying to activate the recurring charge.");
                                await ShopifyAPI.ActivateRecurringChargeAsync(user.MyShopifyDomain, user.ShopifyAccessToken, charge_id);

                                Logger.LogInformation("Recurring charge activationon is done.");
                            }
                            catch (Exception ex)
                            {
                                Logger.LogError(ex, $"Recurring charge activation failed.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action.");
                                WebMsg.AddTempDanger(this, "Could not activate the recurring charge via shopify api.Please try again.");
                                return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));
                            }

                            //Lets check if we were sucessful activating the charge
                            try
                            {
                                Logger.LogInformation("Checking recurring charge status after activation.");
                                charge = await ShopifyAPI.GetRecurringChargeAsync(user.MyShopifyDomain, user.ShopifyAccessToken, charge_id);
                            }
                            catch (Exception ex)
                            {
                                Logger.LogError(ex, "Error getting recurring charge status after activation.");
                                WebMsg.AddTempDanger(this, "Could not retrieve charge status by id via shopify api (after activation). Please try again or contact support");
                                return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));
                            }

                            Logger.LogInformation($"Recurring Charge Status after activation is '{charge.Status}'.");
                            //if we were succesful
                            if (charge.Status == "active")
                            {
                                Logger.LogInformation($"Saving user payment information. User id '{user.Id}', charge id '{charge_id}' , plan id '{newPlan.Id}' and billing on '{charge.BillingOn}'.");
                                var updateResult = UserDbServiceHelper.SetUsersChargeInfo(UserDbService, user.Id, charge_id, newPlan.Id, charge.BillingOn);
                                if (!updateResult)
                                {
                                    Logger.LogCritical($"Could not save user payment information.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action.");
                                    await Emailer.UserPaymentInfoCouldNotBeSavedAsync(user, charge_id, charge.Name);

                                    //this.LogCoreException(new CoreException(CoreErrorType.APP_COULD_NOT_SAVE_CHARGE_INFO, errMessage + $".Activated Charge Id {charge.Id}", user, shop));
                                    WebMsg.AddTempDanger(this, "Could not save your payment confirmation in our db.Please try again.");
                                    return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));
                                }
                                else
                                {
                                    Logger.LogInformation("Succesfully saved user payment information.");
                                    Logger.LogInformation("Refreshing user cache data now.");
                                    user = await UserCache.GetLoggedOnUser(true);

                                    Logger.LogInformation("Now detecting installation type.");
                                    if (previousPlan > 0 && previousPlan != newPlan.Id)//its an upgrade
                                    {
                                        Logger.LogInformation("Installation was an upgrade type for existing store. Redirecting to RedirectAfterSuccessfulUpgrade().");
                                        await UserChangedPlan(user, newPlan.Id);             //handle upgrade event

                                        return(RedirectAfterSuccessfulUpgrade(charge.Name)); //now redirect
                                    }
                                    else//new installation
                                    {
                                        Logger.LogInformation("Installation was for a new store.");
                                        Logger.LogInformation("Now handling post installation tasks by calling DoPostInstallationTasks().");
                                        await DoPostInstallationTasks(user);//handle new installation event

                                        Logger.LogInformation("Done handling post installation tasks. ");
                                        await SendEmailsOnSuccessfullInstallation(user);//send emails

                                        Logger.LogInformation($"Now processing all webhooks defined in the appsettings.json by calling ProcessWebHooksCreation().");
                                        await ProcessWebhooks(user);

                                        Logger.LogInformation("Done processing webhooks defined in appsettings.json.");
                                        Logger.LogInformation("Now redirecting after successfull sign in.");
                                        return(RedirectAfterSuccessfullLogin());//now redirect
                                    }
                                }
                            }
                            else /*if status is not active*/
                            {
                                Logger.LogCritical($"SHopify could not activate the recurring charge. Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action.");
                                WebMsg.AddTempDanger(this, "Shopify did not activate the recurring payment this app requested. Please try again by choosing a plan.");
                                return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));
                            }
                        }
                        else if (charge.Status == "declined")
                        {
                            Logger.LogCritical("Recurring charge was declined (before activation).Probably user declined payment.");
                            Logger.LogInformation("Calling UserCancelledPayment() event.");
                            await UserCancelledPayment(user, newPlan.Id);

                            Logger.LogInformation("Done handling UserCancelledPayment() event.");
                            if (user.GetPlanId() <= 0)
                            {
                                Logger.LogWarning("Redirecting to RedirectAfterNewUserCancelledPayment() as payment cancelled.");
                                return(RedirectAfterNewUserCancelledPayment(user));
                            }
                            else
                            {
                                Logger.LogWarning("Redirecting to RedirectAfterPlanChangePaymentDeclined() as payment declined");
                                return(RedirectAfterPlanChangePaymentDeclined());
                            }
                        }
                        else
                        {
                            Logger.LogCritical($"Recurring charge was not accepted by shopify (before activation). Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action.");
                            WebMsg.AddTempDanger(this, "Payment was not accepted by shopify. Please try again.");
                            return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));
                        }
                    }
                    else
                    {
                        Logger.LogCritical($"Recurring charge's plan is not found in the loaded db plan list.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action.");
                        WebMsg.AddTempDanger(this, "Could not retrieve plan information.Please try again.");
                        return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));//let the user try again
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogWarning("Error occurred while executing ChargeResult().");
                    LogGenericError(ex);
                    throw ex;
                }
            }
        }
Example #5
0
        /// <summary>
        /// Creates the recurring charge asynchronously.
        /// </summary>
        /// <param name="myShopifyDomain">My shopify URL.</param>
        /// <param name="shopifyAccessToken">The shopify access token.</param>
        /// <param name="charge">Valid charge object.</param>
        /// <returns></returns>
        public async Task <ShopifyRecurringChargeObject> CreateRecurringChargeAsync(string myShopifyDomain, string shopifyAccessToken, ShopifyRecurringChargeObject charge)
        {
            _CheckmyShopifyDomain(myShopifyDomain);
            _CheckShopAccessToken(shopifyAccessToken);
            _Logger.LogInformation($"Creating recurring charge '{charge.Name} - {charge.Price} - {(charge.Test.Value ? "is_test" : "not_test")} - {charge.TrialDays} days - {charge.ReturnUrl}'.");
            RecurringChargeService service = new RecurringChargeService(myShopifyDomain, shopifyAccessToken);
            var ret = await service.CreateAsync(new RecurringCharge()
            {
                Name      = charge.Name,
                Price     = charge.Price,
                Terms     = charge.Terms,
                ReturnUrl = charge.ReturnUrl,
                TrialDays = charge.TrialDays,
                Test      = charge.Test
            });

            _Logger.LogInformation($"Done creating '{ret.Name}' with id = {ret.Id}.");

            return(new ShopifyRecurringChargeObject()
            {
                CancelledOn = ret.CancelledOn,
                BillingOn = ret.BillingOn,
                ActivatedOn = ret.ActivatedOn,
                CappedAmount = ret.CappedAmount,
                ConfirmationUrl = ret.ConfirmationUrl,
                CreatedAt = ret.CreatedAt,
                Id = ret.Id,
                Name = ret.Name,
                Price = ret.Price,
                ReturnUrl = ret.ReturnUrl,
                Status = ret.Status,
                Terms = ret.Terms,
                Test = ret.Test,
                TrialDays = ret.TrialDays,
                TrialEndsOn = ret.TrialEndsOn,
                UpdatedAt = ret.UpdatedAt
            });
        }
Example #6
0
        public void index_should_return_valid_view_for_connected_billing(bool isAdmin)
        {
            //arrange
            InitAllMocks();
            userCaching.Setup(x => x.GetLoggedOnUser(false)).ReturnsAsync(new AppUser(new AspNetUser()
            {
                Id              = "1",
                PlanId          = 1,
                ShopifyChargeId = 1 /*always connected billing*/
            }, isAdmin));

            planReader.Setup(x => x[1]).Returns(new PlanAppModel()
            {
                Id = 1
            });

            var obj = new ShopifyRecurringChargeObject()
            {
                Id = 12345,
            };

            shopifyApi.Setup(x => x.GetRecurringChargeAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <long>(), It.IsAny <string>())).ReturnsAsync(obj);

            //act
            var c      = InitController();
            var result = c.Index().Result;

            //assert

            if (isAdmin == false)/*because admin==true && billing is always connected, in that situation we will not be computed*/
            {
                shopifyApi.Verify(x => x.GetRecurringChargeAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <long>(), It.IsAny <string>()));
            }

            //shopifyApi.VerifyAll();
            planReader.VerifyAll();
            userCaching.VerifyAll();

            Assert.NotNull(result);
            Assert.IsType <ViewResult>(result);

            var vResult = (ViewResult)result;

            Assert.NotNull(vResult.Model);
            Assert.IsType <MyProfileViewModel>(vResult.Model);

            var model = (MyProfileViewModel)vResult.Model;

            Assert.NotNull(model.Me);
            Assert.NotNull(model.MyPlan);
            if (isAdmin == false)
            {
                Assert.NotNull(model.ChargeData);
            }
            if (isAdmin == true)
            {
                Assert.Null(model.ChargeData);
            }

            Assert.Equal("1", model.Me.Id);
            Assert.Equal(1, model.MyPlan.Id);
            if (isAdmin == false)
            {
                Assert.Equal(12345, model.ChargeData.Id);
            }
        }
Example #7
0
        public void OnAuthorization(AuthorizationFilterContext filterContext)
        {
            //already logged in by Identity now check subscription
            if (filterContext.Result == null)
            {
                _Logger.LogInformation("Starting subscription check.");
                var context = filterContext.HttpContext;

                _Logger.LogInformation("Getting current user.");
                AppUser currentUser = _UserCache.GetLoggedOnUser().Result;
                if (currentUser == null)
                {
                    _Logger.LogError("User must be logged on before checking subscription.Redirecting to login page.");
                    //throw new Exception("Subscription check must be done on logged on user. But current user is found null.");
                    filterContext.Result = new RedirectToActionResult(ACCOUNT_ACTIONS.Login.ToString(), _Settings.GetAccountControllerName(), new { });
                }
                else
                {
                    _Logger.LogInformation($"Current user is '{currentUser.MyShopifyDomain}'");

                    //admin must have access token atleast
                    if (currentUser.ShopIsConnected == false /*&& !currentUser.IsAdmin*/)
                    {
                        _Logger.LogWarning($"User '{currentUser.MyShopifyDomain}' has no shopify access token. Charge status check cannot be done on diconnected shop.Redirecting to '{_Settings.GetShopifyControllerName()}/{SHOPIFY_ACTIONS.HandShake.ToString()}'.");
                        filterContext.Result = _CreateRedirectResult(_Settings.GetShopifyControllerName(), SHOPIFY_ACTIONS.HandShake.ToString());
                    }
                    //billing connected or disconnected, for admin it is never checked
                    else if (currentUser.BillingIsConnected == false && !currentUser.IsAdmin)
                    {
                        _Logger.LogWarning($"User '{currentUser.MyShopifyDomain}' billing charge id is null.Charge status check cannot be done on null charge id.Redirecting to '{_Settings.GetShopifyControllerName()}/{SHOPIFY_ACTIONS.ChoosePlan.ToString()}'.");
                        filterContext.Result = _CreateRedirectResult(_Settings.GetShopifyControllerName(), SHOPIFY_ACTIONS.ChoosePlan.ToString());
                    }
                    else
                    {
                        ShopifyRecurringChargeObject chargeStatus = null;
                        //for admin user if no billing charge id all good, but if theres one then we will look into it
                        if (currentUser.IsAdmin)
                        {
                            _Logger.LogInformation($"Skipping charge status check because user '{currentUser.MyShopifyDomain}' is admin.");
                            chargeStatus = new ShopifyRecurringChargeObject()
                            {
                                Status = SHOPIFY_CHARGE_STATUS.active.ToString()
                            };
                        }
                        else
                        {
                            _Logger.LogInformation($"Checking charge status for user '{currentUser.MyShopifyDomain}'.");
                            try
                            {
                                chargeStatus = Task.Run(() => _ShopifyApi.GetRecurringChargeAsync(currentUser.MyShopifyDomain, currentUser.ShopifyAccessToken, currentUser.ShopifyChargeId.Value)).Result;
                            }
                            catch (Exception ex)
                            {
                                _Logger.LogError($"Error occurred duing GetRecurringChargeAsync() call.{ex.Message}.{ex.StackTrace}");
                                throw ex;
                            }
                        }

                        if (chargeStatus.Status == SHOPIFY_CHARGE_STATUS.accepted.ToString() || chargeStatus.Status == SHOPIFY_CHARGE_STATUS.active.ToString())
                        {
                            _Logger.LogInformation($"Require subscription passed for user '{currentUser.MyShopifyDomain}'");
                        }
                        else
                        {
                            _Emailer.InActiveChargeIdDetectedAsync(currentUser, chargeStatus.Status);

                            if (chargeStatus.Status == SHOPIFY_CHARGE_STATUS.declined.ToString() ||
                                chargeStatus.Status == SHOPIFY_CHARGE_STATUS.expired.ToString() ||
                                chargeStatus.Status == SHOPIFY_CHARGE_STATUS.pending.ToString())
                            {
                                _Logger.LogWarning($"Require subscription did not pass for user '{currentUser.MyShopifyDomain}'");
                                _Logger.LogWarning($"User '{currentUser.MyShopifyDomain}' has declined/expired/pending charge status.");
                                _Logger.LogWarning($"Unsetting charge info for user '{currentUser.MyShopifyDomain}'.");
                                UserDbServiceHelper.UnSetUserChargeInfo(_UserDbService, currentUser.Id);
                                _Logger.LogWarning($"Removing user '{currentUser.MyShopifyDomain}' from cache.");
                                _UserCache.ClearLoggedOnUser();//resset cache so that next try makes BillingIsConnected = false
                                var handShakeAction = SHOPIFY_ACTIONS.HandShake.ToString();
                                _Logger.LogWarning($"Redirecting user '{currentUser.MyShopifyDomain}' to '{_Settings.GetShopifyControllerName()}/{handShakeAction}'.");
                                filterContext.Result = _CreateRedirectResult(_Settings.GetShopifyControllerName(), handShakeAction);
                            }
                            else if (chargeStatus.Status == SHOPIFY_CHARGE_STATUS.frozen.ToString())
                            {
                                _Logger.LogError($"User '{currentUser.MyShopifyDomain}' has frozen shopify store account. Throwing error.");
                                throw new UnauthorizedAccessException("Your shopify account is frozen.Once shopify unfreezes your store account you will be able to use this app again.");
                            }
                        }
                    }
                }
            }
        }