public async Task <ChangePlanResult> CanDownGradeAsync(Organization organization, BillingPlan plan, User user)
        {
            if (String.IsNullOrWhiteSpace(organization?.Id))
            {
                return(ChangePlanResult.FailWithMessage("Invalid Organization"));
            }

            long currentNumberOfUsers = (await _userRepository.GetByOrganizationIdAsync(organization.Id).AnyContext()).Total + organization.Invites.Count;
            int  maxUsers             = plan.MaxUsers != -1 ? plan.MaxUsers : int.MaxValue;

            if (currentNumberOfUsers > maxUsers)
            {
                return(ChangePlanResult.FailWithMessage($"Please remove {currentNumberOfUsers - maxUsers} user{((currentNumberOfUsers - maxUsers) > 0 ? "s" : String.Empty)} and try again."));
            }

            int  maxProjects  = plan.MaxProjects != -1 ? plan.MaxProjects : int.MaxValue;
            long projectCount = await _projectRepository.GetCountByOrganizationIdAsync(organization.Id).AnyContext();

            if (projectCount > maxProjects)
            {
                return(ChangePlanResult.FailWithMessage($"Please remove {projectCount - maxProjects} project{((projectCount - maxProjects) > 0 ? "s" : String.Empty)} and try again."));
            }

            // Ensure the user can't be apart of more than one free plan.
            if (String.Equals(plan.Id, FreePlan.Id) && user != null && (await _organizationRepository.GetByIdsAsync(user.OrganizationIds.ToArray()).AnyContext()).Any(o => String.Equals(o.PlanId, FreePlan.Id)))
            {
                return(ChangePlanResult.FailWithMessage("You already have one free account. You are not allowed to create more than one free account."));
            }

            return(new ChangePlanResult {
                Success = true
            });
        }
Exemple #2
0
        public IHttpActionResult ChangePlan(string id, string planId, string stripeToken = null, string last4 = null, string couponId = null)
        {
            if (String.IsNullOrEmpty(id) || !CanAccessOrganization(id))
            {
                return(NotFound());
            }

            if (!Settings.Current.EnableBilling)
            {
                return(Ok(ChangePlanResult.FailWithMessage("Plans cannot be changed while billing is disabled.")));
            }

            Organization organization = _repository.GetById(id);

            if (organization == null)
            {
                return(Ok(ChangePlanResult.FailWithMessage("Invalid OrganizationId.")));
            }

            BillingPlan plan = BillingManager.GetBillingPlan(planId);

            if (plan == null)
            {
                return(Ok(ChangePlanResult.FailWithMessage("Invalid PlanId.")));
            }

            if (String.Equals(organization.PlanId, plan.Id) && String.Equals(BillingManager.FreePlan.Id, plan.Id))
            {
                return(Ok(ChangePlanResult.SuccessWithMessage("Your plan was not changed as you were already on the free plan.")));
            }

            // Only see if they can downgrade a plan if the plans are different.
            string message;

            if (!String.Equals(organization.PlanId, plan.Id) && !_billingManager.CanDownGrade(organization, plan, ExceptionlessUser, out message))
            {
                return(Ok(ChangePlanResult.FailWithMessage(message)));
            }

            var customerService     = new StripeCustomerService();
            var subscriptionService = new StripeSubscriptionService();

            try {
                // If they are on a paid plan and then downgrade to a free plan then cancel their stripe subscription.
                if (!String.Equals(organization.PlanId, BillingManager.FreePlan.Id) && String.Equals(plan.Id, BillingManager.FreePlan.Id))
                {
                    if (!String.IsNullOrEmpty(organization.StripeCustomerId))
                    {
                        var subs = subscriptionService.List(organization.StripeCustomerId).Where(s => !s.CanceledAt.HasValue);
                        foreach (var sub in subs)
                        {
                            subscriptionService.Cancel(organization.StripeCustomerId, sub.Id);
                        }
                    }

                    organization.BillingStatus = BillingStatus.Trialing;
                    organization.RemoveSuspension();
                }
                else if (String.IsNullOrEmpty(organization.StripeCustomerId))
                {
                    if (String.IsNullOrEmpty(stripeToken))
                    {
                        return(Ok(ChangePlanResult.FailWithMessage("Billing information was not set.")));
                    }

                    organization.SubscribeDate = DateTime.Now;

                    var createCustomer = new StripeCustomerCreateOptions {
                        Card = new StripeCreditCardOptions {
                            TokenId = stripeToken
                        },
                        PlanId      = planId,
                        Description = organization.Name,
                        Email       = ExceptionlessUser.EmailAddress
                    };

                    if (!String.IsNullOrWhiteSpace(couponId))
                    {
                        createCustomer.CouponId = couponId;
                    }

                    StripeCustomer customer = customerService.Create(createCustomer);

                    organization.BillingStatus = BillingStatus.Active;
                    organization.RemoveSuspension();
                    organization.StripeCustomerId = customer.Id;
                    if (customer.StripeCardList.StripeCards.Count > 0)
                    {
                        organization.CardLast4 = customer.StripeCardList.StripeCards[0].Last4;
                    }
                }
                else
                {
                    var update = new StripeSubscriptionUpdateOptions {
                        PlanId = planId
                    };
                    var  create      = new StripeSubscriptionCreateOptions();
                    bool cardUpdated = false;

                    if (!String.IsNullOrEmpty(stripeToken))
                    {
                        update.Card = new StripeCreditCardOptions {
                            TokenId = stripeToken
                        };
                        create.Card = new StripeCreditCardOptions {
                            TokenId = stripeToken
                        };
                        cardUpdated = true;
                    }

                    var subscription = subscriptionService.List(organization.StripeCustomerId).FirstOrDefault(s => !s.CanceledAt.HasValue);
                    if (subscription != null)
                    {
                        subscriptionService.Update(organization.StripeCustomerId, subscription.Id, update);
                    }
                    else
                    {
                        subscriptionService.Create(organization.StripeCustomerId, planId, create);
                    }

                    customerService.Update(organization.StripeCustomerId, new StripeCustomerUpdateOptions {
                        Email = ExceptionlessUser.EmailAddress
                    });

                    if (cardUpdated)
                    {
                        organization.CardLast4 = last4;
                    }

                    organization.BillingStatus = BillingStatus.Active;
                    organization.RemoveSuspension();
                }

                BillingManager.ApplyBillingPlan(organization, plan, ExceptionlessUser);
                _repository.Save(organization);
                _messagePublisher.Publish(new PlanChanged {
                    OrganizationId = organization.Id
                });
            } catch (Exception e) {
                Log.Error().Exception(e).Message("An error occurred while trying to update your billing plan: " + e.Message).Critical().Write();
                return(Ok(ChangePlanResult.FailWithMessage(e.Message)));
            }

            return(Ok(new ChangePlanResult {
                Success = true
            }));
        }
Exemple #3
0
        public async Task <IHttpActionResult> ChangePlanAsync(string id, string planId, string stripeToken = null, string last4 = null, string couponId = null)
        {
            if (String.IsNullOrEmpty(id) || !CanAccessOrganization(id))
            {
                return(NotFound());
            }

            if (!Settings.Current.EnableBilling)
            {
                return(Ok(ChangePlanResult.FailWithMessage("Plans cannot be changed while billing is disabled.")));
            }

            var organization = await GetModelAsync(id, false);

            if (organization == null)
            {
                return(Ok(ChangePlanResult.FailWithMessage("Invalid OrganizationId.")));
            }

            var plan = BillingManager.GetBillingPlan(planId);

            if (plan == null)
            {
                return(Ok(ChangePlanResult.FailWithMessage("Invalid PlanId.")));
            }

            if (String.Equals(organization.PlanId, plan.Id) && String.Equals(BillingManager.FreePlan.Id, plan.Id))
            {
                return(Ok(ChangePlanResult.SuccessWithMessage("Your plan was not changed as you were already on the free plan.")));
            }

            // Only see if they can downgrade a plan if the plans are different.
            if (!String.Equals(organization.PlanId, plan.Id))
            {
                var result = await _billingManager.CanDownGradeAsync(organization, plan, CurrentUser);

                if (!result.Success)
                {
                    return(Ok(result));
                }
            }

            var customerService     = new StripeCustomerService(Settings.Current.StripeApiKey);
            var subscriptionService = new StripeSubscriptionService(Settings.Current.StripeApiKey);

            try {
                // If they are on a paid plan and then downgrade to a free plan then cancel their stripe subscription.
                if (!String.Equals(organization.PlanId, BillingManager.FreePlan.Id) && String.Equals(plan.Id, BillingManager.FreePlan.Id))
                {
                    if (!String.IsNullOrEmpty(organization.StripeCustomerId))
                    {
                        var subs = await subscriptionService.ListAsync(new StripeSubscriptionListOptions { CustomerId = organization.StripeCustomerId });

                        foreach (var sub in subs.Where(s => !s.CanceledAt.HasValue))
                        {
                            await subscriptionService.CancelAsync(sub.Id);
                        }
                    }

                    organization.BillingStatus = BillingStatus.Trialing;
                    organization.RemoveSuspension();
                }
                else if (String.IsNullOrEmpty(organization.StripeCustomerId))
                {
                    if (String.IsNullOrEmpty(stripeToken))
                    {
                        return(Ok(ChangePlanResult.FailWithMessage("Billing information was not set.")));
                    }

                    organization.SubscribeDate = SystemClock.UtcNow;

                    var createCustomer = new StripeCustomerCreateOptions {
                        SourceToken = stripeToken,
                        PlanId      = planId,
                        Description = organization.Name,
                        Email       = CurrentUser.EmailAddress
                    };

                    if (!String.IsNullOrWhiteSpace(couponId))
                    {
                        createCustomer.CouponId = couponId;
                    }

                    var customer = await customerService.CreateAsync(createCustomer);

                    organization.BillingStatus = BillingStatus.Active;
                    organization.RemoveSuspension();
                    organization.StripeCustomerId = customer.Id;
                    if (customer.Sources.TotalCount > 0)
                    {
                        organization.CardLast4 = customer.Sources.Data.First().Card.Last4;
                    }
                }
                else
                {
                    var update = new StripeSubscriptionUpdateOptions {
                        PlanId = planId
                    };
                    var  create      = new StripeSubscriptionCreateOptions();
                    bool cardUpdated = false;

                    if (!String.IsNullOrEmpty(stripeToken))
                    {
                        update.Source = stripeToken;
                        create.Source = stripeToken;
                        cardUpdated   = true;
                    }

                    var subscriptionList = await subscriptionService.ListAsync(new StripeSubscriptionListOptions { CustomerId = organization.StripeCustomerId });

                    var subscription = subscriptionList.FirstOrDefault(s => !s.CanceledAt.HasValue);
                    if (subscription != null)
                    {
                        await subscriptionService.UpdateAsync(subscription.Id, update);
                    }
                    else
                    {
                        await subscriptionService.CreateAsync(organization.StripeCustomerId, planId, create);
                    }

                    await customerService.UpdateAsync(organization.StripeCustomerId, new StripeCustomerUpdateOptions {
                        Email = CurrentUser.EmailAddress
                    });

                    if (cardUpdated)
                    {
                        organization.CardLast4 = last4;
                    }

                    organization.BillingStatus = BillingStatus.Active;
                    organization.RemoveSuspension();
                }

                BillingManager.ApplyBillingPlan(organization, plan, CurrentUser);
                await _repository.SaveAsync(organization, o => o.Cache());

                await _messagePublisher.PublishAsync(new PlanChanged { OrganizationId = organization.Id });
            } catch (Exception e) {
                _logger.Error().Exception(e).Message("An error occurred while trying to update your billing plan: " + e.Message).Critical().Identity(CurrentUser.EmailAddress).Property("User", CurrentUser).SetActionContext(ActionContext).Write();
                return(Ok(ChangePlanResult.FailWithMessage(e.Message)));
            }

            return(Ok(new ChangePlanResult {
                Success = true
            }));
        }
        public async Task <ActionResult <ChangePlanResult> > ChangePlanAsync(string id, string planId, string stripeToken = null, string last4 = null, string couponId = null)
        {
            if (String.IsNullOrEmpty(id) || !CanAccessOrganization(id))
            {
                return(NotFound());
            }

            if (!_options.StripeOptions.EnableBilling)
            {
                return(Ok(ChangePlanResult.FailWithMessage("Plans cannot be changed while billing is disabled.")));
            }

            var organization = await GetModelAsync(id, false);

            if (organization == null)
            {
                return(Ok(ChangePlanResult.FailWithMessage("Invalid OrganizationId.")));
            }

            var plan = _billingManager.GetBillingPlan(planId);

            if (plan == null)
            {
                return(Ok(ChangePlanResult.FailWithMessage("Invalid PlanId.")));
            }

            if (String.Equals(organization.PlanId, plan.Id) && String.Equals(_plans.FreePlan.Id, plan.Id))
            {
                return(Ok(ChangePlanResult.SuccessWithMessage("Your plan was not changed as you were already on the free plan.")));
            }

            // Only see if they can downgrade a plan if the plans are different.
            if (!String.Equals(organization.PlanId, plan.Id))
            {
                var result = await _billingManager.CanDownGradeAsync(organization, plan, CurrentUser);

                if (!result.Success)
                {
                    return(Ok(result));
                }
            }

            var client              = new StripeClient(_options.StripeOptions.StripeApiKey);
            var customerService     = new CustomerService(client);
            var subscriptionService = new SubscriptionService(client);

            try {
                // If they are on a paid plan and then downgrade to a free plan then cancel their stripe subscription.
                if (!String.Equals(organization.PlanId, _plans.FreePlan.Id) && String.Equals(plan.Id, _plans.FreePlan.Id))
                {
                    if (!String.IsNullOrEmpty(organization.StripeCustomerId))
                    {
                        var subs = await subscriptionService.ListAsync(new SubscriptionListOptions { Customer = organization.StripeCustomerId });

                        foreach (var sub in subs.Where(s => !s.CanceledAt.HasValue))
                        {
                            await subscriptionService.CancelAsync(sub.Id, new SubscriptionCancelOptions());
                        }
                    }

                    organization.BillingStatus = BillingStatus.Trialing;
                    organization.RemoveSuspension();
                }
                else if (String.IsNullOrEmpty(organization.StripeCustomerId))
                {
                    if (String.IsNullOrEmpty(stripeToken))
                    {
                        return(Ok(ChangePlanResult.FailWithMessage("Billing information was not set.")));
                    }

                    organization.SubscribeDate = SystemClock.UtcNow;

                    var createCustomer = new CustomerCreateOptions {
                        Source      = stripeToken,
                        Plan        = planId,
                        Description = organization.Name,
                        Email       = CurrentUser.EmailAddress
                    };

                    if (!String.IsNullOrWhiteSpace(couponId))
                    {
                        createCustomer.Coupon = couponId;
                    }

                    var customer = await customerService.CreateAsync(createCustomer);

                    organization.BillingStatus = BillingStatus.Active;
                    organization.RemoveSuspension();
                    organization.StripeCustomerId = customer.Id;
                    organization.CardLast4        = last4;
                }
                else
                {
                    var update = new SubscriptionUpdateOptions {
                        Items = new List <SubscriptionItemOptions>()
                    };
                    var create = new SubscriptionCreateOptions {
                        Customer = organization.StripeCustomerId, Items = new List <SubscriptionItemOptions>()
                    };
                    bool cardUpdated = false;

                    var customerUpdateOptions = new CustomerUpdateOptions {
                        Description = organization.Name
                    };
                    if (!Request.IsGlobalAdmin())
                    {
                        customerUpdateOptions.Email = CurrentUser.EmailAddress;
                    }

                    if (!String.IsNullOrEmpty(stripeToken))
                    {
                        customerUpdateOptions.Source = stripeToken;
                        cardUpdated = true;
                    }

                    await customerService.UpdateAsync(organization.StripeCustomerId, customerUpdateOptions);

                    var subscriptionList = await subscriptionService.ListAsync(new SubscriptionListOptions { Customer = organization.StripeCustomerId });

                    var subscription = subscriptionList.FirstOrDefault(s => !s.CanceledAt.HasValue);
                    if (subscription != null)
                    {
                        update.Items.Add(new SubscriptionItemOptions {
                            Id = subscription.Items.Data[0].Id, Plan = planId
                        });
                        await subscriptionService.UpdateAsync(subscription.Id, update);
                    }
                    else
                    {
                        create.Items.Add(new SubscriptionItemOptions {
                            Plan = planId
                        });
                        await subscriptionService.CreateAsync(create);
                    }

                    if (cardUpdated)
                    {
                        organization.CardLast4 = last4;
                    }

                    organization.BillingStatus = BillingStatus.Active;
                    organization.RemoveSuspension();
                }

                _billingManager.ApplyBillingPlan(organization, plan, CurrentUser);
                await _repository.SaveAsync(organization, o => o.Cache());

                await _messagePublisher.PublishAsync(new PlanChanged { OrganizationId = organization.Id });
            } catch (Exception ex) {
                using (_logger.BeginScope(new ExceptionlessState().Tag("Change Plan").Identity(CurrentUser.EmailAddress).Property("User", CurrentUser).SetHttpContext(HttpContext)))
                    _logger.LogCritical(ex, "An error occurred while trying to update your billing plan: {Message}", ex.Message);

                return(Ok(ChangePlanResult.FailWithMessage(ex.Message)));
            }

            return(Ok(new ChangePlanResult {
                Success = true
            }));
        }