Ejemplo n.º 1
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 override async Task HandleItemAsync(WorkItemContext context)
        {
            var wi = context.GetData <RemoveOrganizationWorkItem>();

            using (Log.BeginScope(new ExceptionlessState().Organization(wi.OrganizationId))) {
                Log.LogInformation("Received remove organization work item for: {organization}", wi.OrganizationId);

                await context.ReportProgressAsync(0, "Starting deletion...").AnyContext();

                var organization = await _organizationRepository.GetByIdAsync(wi.OrganizationId).AnyContext();

                if (organization == null)
                {
                    await context.ReportProgressAsync(100, "Organization deleted").AnyContext();

                    return;
                }

                await context.ReportProgressAsync(10, "Removing subscriptions").AnyContext();

                if (!String.IsNullOrEmpty(organization.StripeCustomerId))
                {
                    Log.LogInformation("Canceling stripe subscription for the organization {OrganizationName} with Id: {organization}.", organization.Name, organization.Id);

                    var subscriptionService = new StripeSubscriptionService(Settings.Current.StripeApiKey);
                    var subscriptions       = (await subscriptionService.ListAsync(new StripeSubscriptionListOptions {
                        CustomerId = organization.StripeCustomerId
                    }).AnyContext()).Where(s => !s.CanceledAt.HasValue);
                    foreach (var subscription in subscriptions)
                    {
                        await subscriptionService.CancelAsync(subscription.Id, new StripeSubscriptionCancelOptions()).AnyContext();
                    }
                }

                await context.ReportProgressAsync(20, "Removing users").AnyContext();

                var users = await _userRepository.GetByOrganizationIdAsync(organization.Id).AnyContext();

                foreach (var user in users.Documents)
                {
                    // delete the user if they are not associated to any other organizations and they are not the current user
                    if (user.OrganizationIds.All(oid => String.Equals(oid, organization.Id)) && !String.Equals(user.Id, wi.CurrentUserId))
                    {
                        Log.LogInformation("Removing user {user} as they do not belong to any other organizations.", user.Id);
                        await _userRepository.RemoveAsync(user.Id).AnyContext();
                    }
                    else
                    {
                        Log.LogInformation("Removing user {user} from organization {OrganizationName} with Id: {organization}", user.Id, organization.Name, organization.Id);
                        user.OrganizationIds.Remove(organization.Id);
                        await _userRepository.SaveAsync(user, o => o.Cache()).AnyContext();
                    }
                }

                await context.ReportProgressAsync(30, "Removing tokens").AnyContext();

                await _tokenRepository.RemoveAllByOrganizationIdAsync(organization.Id).AnyContext();

                await context.ReportProgressAsync(40, "Removing web hooks").AnyContext();

                await _webHookRepository.RemoveAllByOrganizationIdAsync(organization.Id).AnyContext();

                await context.ReportProgressAsync(50, "Removing projects").AnyContext();

                var projects = await _projectRepository.GetByOrganizationIdAsync(organization.Id).AnyContext();

                if (wi.IsGlobalAdmin && projects.Total > 0)
                {
                    int completed = 1;
                    foreach (var project in projects.Documents)
                    {
                        using (Log.BeginScope(new ExceptionlessState().Organization(wi.OrganizationId).Project(project.Id))) {
                            Log.LogInformation("Resetting all project data for project {ProjectName} with Id: {project}.", project.Name, project.Id);
                            await _eventRepository.RemoveAllByProjectIdAsync(organization.Id, project.Id).AnyContext();

                            await _stackRepository.RemoveAllByProjectIdAsync(organization.Id, project.Id).AnyContext();

                            await context.ReportProgressAsync(CalculateProgress(projects.Total, completed++, 51, 89), "Removing projects...").AnyContext();
                        }
                    }

                    Log.LogInformation("Deleting all projects for organization {OrganizationName} with Id: {organization}.", organization.Name, organization.Id);
                    await _projectRepository.RemoveAsync(projects.Documents).AnyContext();
                }

                Log.LogInformation("Deleting organization {OrganizationName} with Id: {organization}.", organization.Name, organization.Id);
                await context.ReportProgressAsync(90, "Removing organization").AnyContext();

                await _organizationRepository.RemoveAsync(organization.Id).AnyContext();

                await context.ReportProgressAsync(100, "Organization deleted").AnyContext();
            }
        }