public JsonResult ChangePlan(string organizationId, string planId) { if (String.IsNullOrEmpty(organizationId) || !User.CanAccessOrganization(organizationId)) { throw new ArgumentException("Invalid organization id.", "organizationId"); // TODO: These should probably throw http Response exceptions. } Organization organization = _repository.GetById(organizationId); if (organization == null) { return(Json(new { Success = false, Message = "Invalid OrganizationId." })); } BillingPlan plan = _billingManager.GetBillingPlan(planId); if (plan == null) { return(Json(new { Success = false, Message = "Invalid PlanId." })); } organization.BillingStatus = !String.Equals(plan.Id, BillingManager.FreePlan.Id) ? BillingStatus.Active : BillingStatus.Trialing; organization.RemoveSuspension(); _billingManager.ApplyBillingPlan(organization, plan, User.UserEntity, false); _repository.Update(organization); _notificationSender.PlanChanged(organization.Id); return(Json(new { Success = true })); }
public async Task <IActionResult> ChangePlanAsync([FromQuery] string organizationId, [FromQuery] string planId) { if (String.IsNullOrEmpty(organizationId) || !CanAccessOrganization(organizationId)) { return(Ok(new { Success = false, Message = "Invalid Organization Id." })); } var organization = await _organizationRepository.GetByIdAsync(organizationId); if (organization == null) { return(Ok(new { Success = false, Message = "Invalid Organization Id." })); } var plan = BillingManager.GetBillingPlan(planId); if (plan == null) { return(Ok(new { Success = false, Message = "Invalid PlanId." })); } organization.BillingStatus = !String.Equals(plan.Id, BillingManager.FreePlan.Id) ? BillingStatus.Active : BillingStatus.Trialing; organization.RemoveSuspension(); BillingManager.ApplyBillingPlan(organization, plan, CurrentUser, false); await _organizationRepository.SaveAsync(organization); await _messagePublisher.PublishAsync(new PlanChanged { OrganizationId = organization.Id }); return(Ok(new { Success = true })); }
public IHttpActionResult ChangePlan(string organizationId, string planId) { if (String.IsNullOrEmpty(organizationId) || !CanAccessOrganization(organizationId)) { return(Ok(new { Success = false, Message = "Invalid Organization Id." })); } var organization = _repository.GetById(organizationId); if (organization == null) { return(Ok(new { Success = false, Message = "Invalid Organization Id." })); } var plan = BillingManager.GetBillingPlan(planId); if (plan == null) { return(Ok(new { Success = false, Message = "Invalid PlanId." })); } organization.BillingStatus = !String.Equals(plan.Id, BillingManager.FreePlan.Id) ? BillingStatus.Active : BillingStatus.Trialing; organization.RemoveSuspension(); _billingManager.ApplyBillingPlan(organization, plan, ExceptionlessUser, false); _repository.Save(organization); _messagePublisher.Publish(new PlanChanged { OrganizationId = organization.Id }); return(Ok(new { Success = true })); }
private void UpgradePlan(Organization organization) { var plan = _billingManager.GetBillingPlan(organization.PlanId); if (plan == null) { Log.LogError("Unable to find a valid plan for organization: {organization}", organization.Id); return; } _billingManager.ApplyBillingPlan(organization, plan, user: null, updateBillingPrice: false); }
private void UpgradePlan(Organization organization) { var plan = BillingManager.GetBillingPlan(organization.PlanId); if (plan == null) { _logger.Error().Message("Unable to find a valid plan for organization: {0}", organization.Id).Write(); return; } BillingManager.ApplyBillingPlan(organization, plan, user: null, updateBillingPrice: false); }
public override void UpdateDocument(MongoCollection <BsonDocument> collection, BsonDocument document) { if (document.Contains("ErrorCount")) { document.ChangeName("ErrorCount", "EventCount"); } if (document.Contains("TotalErrorCount")) { document.ChangeName("TotalErrorCount", "TotalEventCount"); } if (document.Contains("LastErrorDate")) { document.ChangeName("LastErrorDate", "LastEventDate"); } if (document.Contains("MaxErrorsPerMonth")) { document.ChangeName("MaxErrorsPerMonth", "MaxEventsPerMonth"); } if (document.Contains("SuspensionCode")) { var value = document.GetValue("SuspensionCode"); document.Remove("SuspensionCode"); SuspensionCode suspensionCode; if (value.IsString && Enum.TryParse(value.AsString, true, out suspensionCode)) { document.Set("SuspensionCode", suspensionCode); } } if (document.Contains("PlanId")) { string planId = document.GetValue("PlanId").AsString; var currentPlan = BillingManager.GetBillingPlan(planId); document.Set("PlanName", currentPlan != null ? currentPlan.Name : planId); document.Set("PlanDescription", currentPlan != null ? currentPlan.Description : planId); } collection.Save(document); }
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 void GetBillingPlan() { Assert.Equal(BillingManager.FreePlan.Id, BillingManager.GetBillingPlan(BillingManager.FreePlan.Id).Id); }
public async Task <ActionResult <Invoice> > GetInvoiceAsync(string id) { if (!Settings.Current.EnableBilling) { return(NotFound()); } if (!id.StartsWith("in_")) { id = "in_" + id; } StripeInvoice stripeInvoice = null; try { var invoiceService = new StripeInvoiceService(Settings.Current.StripeApiKey); stripeInvoice = await invoiceService.GetAsync(id); } catch (Exception ex) { using (_logger.BeginScope(new ExceptionlessState().Tag("Invoice").Identity(CurrentUser.EmailAddress).Property("User", CurrentUser).SetHttpContext(HttpContext))) _logger.LogError(ex, "An error occurred while getting the invoice: {InvoiceId}", id); } if (String.IsNullOrEmpty(stripeInvoice?.CustomerId)) { return(NotFound()); } var organization = await _repository.GetByStripeCustomerIdAsync(stripeInvoice.CustomerId); if (organization == null || !CanAccessOrganization(organization.Id)) { return(NotFound()); } var invoice = new Invoice { Id = stripeInvoice.Id.Substring(3), OrganizationId = organization.Id, OrganizationName = organization.Name, Date = stripeInvoice.Date.GetValueOrDefault(), Paid = stripeInvoice.Paid, Total = stripeInvoice.Total / 100.0 }; foreach (var line in stripeInvoice.StripeInvoiceLineItems.Data) { var item = new InvoiceLineItem { Amount = line.Amount / 100.0 }; if (line.Plan != null) { string planName = line.Plan.Nickname ?? BillingManager.GetBillingPlan(line.Plan.Id)?.Name; item.Description = $"Exceptionless - {planName} Plan ({(line.Plan.Amount / 100.0):c}/{line.Plan.Interval})"; } else { item.Description = line.Description; } item.Date = $"{(line.StripePeriod.Start ?? stripeInvoice.PeriodStart).ToShortDateString()} - {(line.StripePeriod.End ?? stripeInvoice.PeriodEnd).ToShortDateString()}"; invoice.Items.Add(item); } var coupon = stripeInvoice.StripeDiscount?.StripeCoupon; if (coupon != null) { if (coupon.AmountOff.HasValue) { double discountAmount = coupon.AmountOff.GetValueOrDefault() / 100.0; string description = $"{coupon.Id} ({discountAmount.ToString("C")} off)"; invoice.Items.Add(new InvoiceLineItem { Description = description, Amount = discountAmount }); } else { double discountAmount = (stripeInvoice.Subtotal / 100.0) * (coupon.PercentOff.GetValueOrDefault() / 100.0); string description = $"{coupon.Id} ({coupon.PercentOff.GetValueOrDefault()}% off)"; invoice.Items.Add(new InvoiceLineItem { Description = description, Amount = discountAmount }); } } return(Ok(invoice)); }
public IHttpActionResult ChangePlan(string id, string planId, string stripeToken = null, string last4 = null, string couponId = null) { if (String.IsNullOrEmpty(id) || !CanAccessOrganization(id)) { return(BadRequest("Invalid organization id.")); } if (!Settings.Current.EnableBilling) { return(Ok(new { Success = false, Message = "Plans cannot be changed while billing is disabled." })); } Organization organization = _repository.GetById(id); if (organization == null) { return(Ok(new { Success = false, Message = "Invalid OrganizationId." })); } BillingPlan plan = BillingManager.GetBillingPlan(planId); if (plan == null) { return(Ok(new { Success = false, Message = "Invalid PlanId." })); } if (String.Equals(organization.PlanId, plan.Id) && String.Equals(BillingManager.FreePlan.Id, plan.Id)) { return(Ok(new { Success = true, Message = "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(new { Success = false, Message = 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(new { Success = false, Message = "Billing information was not set." })); } organization.SubscribeDate = DateTime.Now; var createCustomer = new StripeCustomerCreateOptions { 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.TokenId = stripeToken; create.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).Report(r => r.MarkAsCritical()).Write(); return(Ok(new { Success = false, Message = e.Message })); } return(Ok(new { Success = true })); }
public JsonResult ChangePlan(string organizationId, string planId, string stripeToken, string last4) { if (String.IsNullOrEmpty(organizationId) || !User.CanAccessOrganization(organizationId)) { throw new ArgumentException("Invalid organization id.", "organizationId"); // TODO: These should probably throw http Response exceptions. } if (!Settings.Current.EnableBilling) { return(Json(new { Success = false, Message = "Plans cannot be changed while billing is disabled." })); } Organization organization = _repository.GetById(organizationId); if (organization == null) { return(Json(new { Success = false, Message = "Invalid OrganizationId." })); } BillingPlan plan = _billingManager.GetBillingPlan(planId); if (plan == null) { return(Json(new { Success = false, Message = "Invalid PlanId." })); } if (String.Equals(organization.PlanId, plan.Id) && String.Equals(BillingManager.FreePlan.Id, plan.Id)) { return(Json(new { Success = true, Message = "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, User.UserEntity, out message)) { return(Json(new { Success = false, Message = message })); } var customerService = new StripeCustomerService(); 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)) { customerService.CancelSubscription(organization.StripeCustomerId); } organization.BillingStatus = BillingStatus.Trialing; organization.RemoveSuspension(); } else if (String.IsNullOrEmpty(organization.StripeCustomerId)) { if (String.IsNullOrEmpty(stripeToken)) { return(Json(new { Success = false, Message = "Billing information was not set." })); } organization.SubscribeDate = DateTime.Now; StripeCustomer customer = customerService.Create(new StripeCustomerCreateOptions { TokenId = stripeToken, PlanId = planId, Description = organization.Name }); 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 StripeCustomerUpdateSubscriptionOptions { PlanId = planId }; bool cardUpdated = false; if (!String.IsNullOrEmpty(stripeToken)) { update.TokenId = stripeToken; cardUpdated = true; } customerService.UpdateSubscription(organization.StripeCustomerId, update); if (cardUpdated) { organization.CardLast4 = last4; } organization.BillingStatus = BillingStatus.Active; organization.RemoveSuspension(); } _billingManager.ApplyBillingPlan(organization, plan, User.UserEntity); _repository.Update(organization); _notificationSender.PlanChanged(organization.Id); } catch (Exception e) { Log.Error().Exception(e).Message("An error occurred while trying to update your billing plan: " + e.Message).Report().Write(); return(Json(new { Success = false, Message = e.Message })); } return(Json(new { Success = true })); }