private void EnforceErrorCountLimits(Organization organization) { if (organization.RetentionDays <= 0) { return; } Log.Info().Message("Enforcing error count limits for organization '{0}' with Id: '{1}'", organization.Name, organization.Id).Write(); try { // use the next higher plans retention days to enable us to upsell them BillingPlan nextPlan = BillingManager.Plans .Where(p => p.RetentionDays > organization.RetentionDays) .OrderByDescending(p => p.RetentionDays) .FirstOrDefault(); int retentionDays = organization.RetentionDays; if (nextPlan != null) { retentionDays = nextPlan.RetentionDays; } DateTime cutoff = DateTime.UtcNow.Date.AddDays(-retentionDays); _errorRepository.RemoveAllByDate(organization.Id, cutoff); } catch (Exception ex) { ex.ToExceptionless().MarkAsCritical().AddTags("Enforce Limits").AddObject(organization).Submit(); } }
private async Task AddBillingPlans(PlanList list) { foreach (var plan in list.Plans) { //add Billing plans in the database var billingPlan = new BillingPlan(); billingPlan.PayPalPlanId = plan.Id; billingPlan.Type = plan.Type; billingPlan.Name = plan.Name; billingPlan.Description = plan.Description; billingPlan.State = plan.State; if (plan.PaymentDefinitions != null) { billingPlan.PaymentFrequency = plan.PaymentDefinitions.FirstOrDefault().Frequency; billingPlan.PaymentInterval = plan.PaymentDefinitions.FirstOrDefault().FrequencyInterval; } else { billingPlan.PaymentFrequency = "Not Provided"; billingPlan.PaymentInterval = "Not Provided"; } billingPlan.ReturnURL = "https://www.andytipsterpro.com/"; billingPlan.CancelURL = "https://www.andytipsterpro.com/"; billingPlan.CreateTime = plan.CreateTime; billingPlan.UpdateTime = plan.UpdateTime; _dbContext.BillingPlans.Add(billingPlan); } await _dbContext.SaveChangesAsync(); }
public IHttpActionResult ChangePlan(string organizationId, string planId) { if (String.IsNullOrEmpty(organizationId) || !CanAccessOrganization(organizationId)) { return(Ok(new { Success = false, Message = "Invalid Organization Id." })); } Organization organization = _repository.GetById(organizationId); if (organization == null) { return(Ok(new { Success = false, Message = "Invalid Organization Id." })); } BillingPlan 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 })); }
public bool CanDownGrade(Organization organization, BillingPlan plan, User user, out string message) { if (organization == null || String.IsNullOrWhiteSpace(organization.Id)) { message = "Invalid Organization"; return(false); } int currentNumberOfUsers = _userRepository.GetByOrganizationId(organization.Id).Count() + organization.Invites.Count; int maxUsers = plan.MaxUsers != -1 ? plan.MaxUsers : int.MaxValue; if (currentNumberOfUsers > maxUsers) { message = String.Format("Please remove {0} user{1} and try again.", currentNumberOfUsers - maxUsers, (currentNumberOfUsers - maxUsers) > 0 ? "s" : String.Empty); return(false); } int maxProjects = plan.MaxProjects != -1 ? plan.MaxProjects : int.MaxValue; if (organization.ProjectCount > maxProjects) { message = String.Format("Please remove {0} project{1} and try again.", organization.ProjectCount - maxProjects, (organization.ProjectCount - maxProjects) > 0 ? "s" : String.Empty); return(false); } // Ensure the user can't be apart of more than one free plan. if (String.Equals(plan.Id, FreePlan.Id) && user != null && _organizationRepository.GetByIds(user.OrganizationIds).Any(o => String.Equals(o.PlanId, FreePlan.Id))) { message = "You already have one free account. You are not allowed to create more than one free account."; return(false); } message = String.Empty; return(true); }
public static void ApplyBillingPlan(Organization organization, BillingPlan plan, User user = null, bool updateBillingPrice = true) { organization.PlanId = plan.Id; organization.PlanName = plan.Name; organization.PlanDescription = plan.Description; organization.BillingChangeDate = SystemClock.UtcNow; if (updateBillingPrice) { organization.BillingPrice = plan.Price; } if (user != null) { organization.BillingChangedByUserId = user.Id; } organization.MaxUsers = plan.MaxUsers; organization.MaxProjects = plan.MaxProjects; organization.RetentionDays = plan.RetentionDays; organization.MaxEventsPerMonth = plan.MaxEventsPerMonth; organization.HasPremiumFeatures = plan.HasPremiumFeatures; organization.SetMonthlyUsage(organization.GetCurrentMonthlyTotal(), organization.GetCurrentMonthlyBlocked(), organization.GetCurrentMonthlyTooBig()); }
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 ActionResult Create(BillingPlan billingPlan) { if (ModelState.IsValid) { var apiContext = Common.GetApiContext(); var plan = new Plan(); plan.description = billingPlan.Description; plan.name = billingPlan.Name; plan.type = billingPlan.PlanType; plan.merchant_preferences = new MerchantPreferences { initial_fail_amount_action = "CANCEL", max_fail_attempts = "3", cancel_url = "http://localhost:50728/plans", return_url = "http://localhost:50728/plans" }; plan.payment_definitions = new List <PaymentDefinition>(); var paymentDefinition = new PaymentDefinition(); paymentDefinition.name = "Standard Plan"; paymentDefinition.amount = new Currency { currency = "USD", value = billingPlan.Amount.ToString() }; paymentDefinition.frequency = billingPlan.Frequency.ToString(); paymentDefinition.type = "REGULAR"; paymentDefinition.frequency_interval = "1"; if (billingPlan.NumberOfCycles.HasValue) { paymentDefinition.cycles = billingPlan.NumberOfCycles.Value.ToString(); } plan.payment_definitions.Add(paymentDefinition); var created = plan.Create(apiContext); if (created.state == "CREATED") { var patchRequest = new PatchRequest(); patchRequest.Add(new Patch { path = "/", op = "replace", value = new Plan() { state = "ACTIVE" } }); created.Update(apiContext, patchRequest); } TempData["success"] = "Billing plan created."; return(RedirectToAction("Index")); } AddDropdowns(); return(View(billingPlan)); }
public void Sample() { Customer customer = (new Site()).Customer; BillingPlan plan = new BillingPlan(); customer.Plan = plan; var customerName = customer.Name; int weeksDelinquent = customer.History.GetWeeksDelinquentInLastYear(); }
public void should_return_customer_info_when_customer_not_null() { var customerName = "YanPei"; var plan = new BillingPlan(3000); var customer = new Customer(new PaymentHistory(), plan, customerName); var site = new Site(customer); var calSiteInfo = new CalSiteInfo(site); Assert.Equal(customerName, calSiteInfo.GetCustomerInfo()); Assert.Equal(2, calSiteInfo.GetWeeksDelinquent()); Assert.Equal(3000, calSiteInfo.GetBillingPlan().Rent); }
/// <summary> /// Initializes a new instance of the Micajah.Common.Bll.Instance class. /// </summary> public Instance() { m_PseudoId = string.Empty; m_Name = string.Empty; m_Description = string.Empty; m_InstanceId = Guid.Empty; m_ExternalId = string.Empty; m_WorkingDays = InstanceProvider.DefaultWorkingDays; m_Active = true; this.TimeZoneId = InstanceProvider.DefaultTimeZoneId; m_BillingPlan = BillingPlan.Free; m_CreditCardStatus = CreditCardStatus.NotRegistered; }
public void ApplyBillingPlan(Organization organization, BillingPlan plan, User user, bool updateBillingPrice = true) { organization.PlanId = plan.Id; organization.BillingChangeDate = DateTime.Now; if (updateBillingPrice) { organization.BillingPrice = plan.Price; } organization.BillingChangedByUserId = user.Id; organization.MaxUsers = plan.MaxUsers; organization.MaxProjects = plan.MaxProjects; organization.RetentionDays = plan.RetentionDays; organization.MaxEventsPerMonth = plan.MaxEventsPerMonth; organization.HasPremiumFeatures = plan.HasPremiumFeatures; }
public bool CanDownGrade(Organization organization, BillingPlan plan, User user, out string message) { if (organization == null || String.IsNullOrWhiteSpace(organization.Id)) { message = "Invalid Organization"; return(false); } int currentNumberOfUsers = _userRepository.GetByOrganizationId(organization.Id).Count() + organization.Invites.Count; int maxUsers = plan.MaxUsers != -1 ? plan.MaxUsers : int.MaxValue; if (currentNumberOfUsers > maxUsers) { message = String.Format("Please remove {0} user{1} and try again.", currentNumberOfUsers - maxUsers, (currentNumberOfUsers - maxUsers) > 0 ? "s" : String.Empty); return(false); } int maxProjects = plan.MaxProjects != -1 ? plan.MaxProjects : int.MaxValue; if (organization.ProjectCount > maxProjects) { message = String.Format("Please remove {0} project{1} and try again.", organization.ProjectCount - maxProjects, (organization.ProjectCount - maxProjects) > 0 ? "s" : String.Empty); return(false); } // TODO: We need to make this smarter. if (organization.OverageDays != null && organization.OverageDays.Count(d => d.Day > DateTime.Now.AddDays(-30)) > 0 && plan.MaxErrorsPerDay < GetBillingPlan(organization.PlanId).MaxErrorsPerDay) { message = "You would exceed the maximum errors per day plan limit."; return(false); } // Ensure the user can't be apart of more than one free plan. if (String.Equals(plan.Id, FreePlan.Id) && user != null && _organizationRepository.GetByIds(user.OrganizationIds).Any(o => String.Equals(o.PlanId, FreePlan.Id))) { message = "You already have one free account. You are not allowed to create more than one free account."; return(false); } message = String.Empty; return(true); }
public async Task <IHttpActionResult> GetPlansAsync(string id) { var organization = await GetModelAsync(id); if (organization == null) { return(NotFound()); } var plans = BillingManager.Plans.ToList(); if (!Request.IsGlobalAdmin()) { plans = plans.Where(p => !p.IsHidden || p.Id == organization.PlanId).ToList(); } var currentPlan = new BillingPlan { Id = organization.PlanId, Name = organization.PlanName, Description = organization.PlanDescription, IsHidden = false, Price = organization.BillingPrice, MaxProjects = organization.MaxProjects, MaxUsers = organization.MaxUsers, RetentionDays = organization.RetentionDays, MaxEventsPerMonth = organization.MaxEventsPerMonth, HasPremiumFeatures = organization.HasPremiumFeatures }; if (plans.All(p => p.Id != organization.PlanId)) { plans.Add(currentPlan); } else { plans[plans.FindIndex(p => p.Id == organization.PlanId)] = currentPlan; } return(Ok(plans)); }
protected void btnCreateUpdate_Click(object sender, EventArgs e) { if (!HasWriteAccess) return; if (hidCurrentPlanID.Value != (-1).ToString() && !ValidatePlanInfo()) return; BillingPlanOptions options = (BillingPlanOptions)Reflection.SaveTableSettings(phBillingPlanOptions, typeof(BillingPlanOptions)); if (hidCurrentPlanID.Value == "") { //create new plan BillingPlan plan = new BillingPlan(); plan.Title = txtTitle.Text; plan.Amount = Convert.ToSingle(txtAmount.Text); plan.Cycle = Convert.ToInt32(txtCycle.Text); plan.CycleUnit = (CycleUnits) Enum.Parse(typeof (CycleUnits), ddCycleUnit.SelectedItem.Value); plan.Options = options; BillingPlan.Create(plan); } else { //update current one if (hidCurrentPlanID.Value == (-1).ToString()) { Config.Users.SetNonPayingMembersOptions(options); } else { BillingPlan plan = BillingPlan.Fetch(Convert.ToInt32(hidCurrentPlanID.Value)); plan.Title = txtTitle.Text; plan.Amount = Convert.ToSingle(txtAmount.Text); plan.Cycle = Convert.ToInt32(txtCycle.Text); plan.CycleUnit = (CycleUnits) Enum.Parse(typeof (CycleUnits), ddCycleUnit.SelectedItem.Value); plan.Options = options; plan.Update(); } } hidCurrentPlanID.Value = ""; pnlBillingPlanInfo.Visible = false; PopulateDataGrid(); }
public static void UpdateBillingPlansFromUI(PlaceHolder phBillingPlans, BillingPlan[] billingplans) { foreach (BillingPlan plan in billingplans) { TextBox txtPlanName = FindControl(phBillingPlans, "PlanName" + plan.ID) as TextBox; TextBox txtAmount = FindControl(phBillingPlans, "Amount" + plan.ID) as TextBox; TextBox txtCycle = FindControl(phBillingPlans, "Cycle" + plan.ID) as TextBox; DropDownList ddCycleUnits = FindControl(phBillingPlans, "CycleUnits" + plan.ID) as DropDownList; //if (txtPlanName == null) // throw new Exception(String.Format("No Control with ID {0}!", "PlanName" + plan.ID)); if (txtPlanName.Text.Trim() == "") { throw new ArgumentException(Lang.TransA("The plan name field cannot be empty!")); } try { Decimal amount = Convert.ToDecimal(txtAmount.Text); if (amount < 0) { throw new ArgumentException(Lang.TransA("The amount of money can't be negative!")); } } catch (Exception) { throw new ArgumentException(Lang.TransA("Given amount of money is invalid")); } try { int cycle = Convert.ToInt32(txtCycle.Text); if (cycle < 1) { throw new ArgumentException(Lang.TransA("The billing cycle length must be positive number!")); } } catch (Exception) { throw new ArgumentException(Lang.TransA("Given billing cycle length is invalid")); } plan.Title = txtPlanName.Text; plan.Amount = Convert.ToSingle(txtAmount.Text); plan.Cycle = Convert.ToInt32(txtCycle.Text); plan.CycleUnit = (CycleUnits) Convert.ToInt32(ddCycleUnits.SelectedItem.Value); } }
/// <summary> /// Gets the list of available billing plans for the customer. /// </summary> /// <param name='cancellationToken'> /// Cancellation token. /// </param> /// <returns> /// Definition for result of ListBillingPlans operation. /// </returns> public async Task <ListBillingPlansResult> ListBillingPlansAsync(CancellationToken cancellationToken) { // Validate // Tracing bool shouldTrace = TracingAdapter.IsEnabled; string invocationId = null; if (shouldTrace) { invocationId = TracingAdapter.NextInvocationId.ToString(); Dictionary <string, object> tracingParameters = new Dictionary <string, object>(); TracingAdapter.Enter(invocationId, this, "ListBillingPlansAsync", tracingParameters); } // Construct URL string url = ""; url = url + "/"; if (this.Client.Credentials.SubscriptionId != null) { url = url + Uri.EscapeDataString(this.Client.Credentials.SubscriptionId); } url = url + "/services/"; if (this.Client.RdfeNamespace != null) { url = url + Uri.EscapeDataString(this.Client.RdfeNamespace); } url = url + "/BillingPlans"; List <string> queryParameters = new List <string>(); queryParameters.Add("api-version=2014-09-01"); if (queryParameters.Count > 0) { url = url + "?" + string.Join("&", queryParameters); } string baseUrl = this.Client.BaseUri.AbsoluteUri; // Trim '/' character from the end of baseUrl and beginning of url. if (baseUrl[baseUrl.Length - 1] == '/') { baseUrl = baseUrl.Substring(0, baseUrl.Length - 1); } if (url[0] == '/') { url = url.Substring(1); } url = baseUrl + "/" + url; url = url.Replace(" ", "%20"); // Create HTTP transport objects HttpRequestMessage httpRequest = null; try { httpRequest = new HttpRequestMessage(); httpRequest.Method = HttpMethod.Get; httpRequest.RequestUri = new Uri(url); // Set Headers httpRequest.Headers.Add("Accept", "application/json; charset=utf-8"); httpRequest.Headers.Add("x-ms-version", "2014-08-01"); // Set Credentials cancellationToken.ThrowIfCancellationRequested(); await this.Client.Credentials.ProcessHttpRequestAsync(httpRequest, cancellationToken).ConfigureAwait(false); // Send Request HttpResponseMessage httpResponse = null; try { if (shouldTrace) { TracingAdapter.SendRequest(invocationId, httpRequest); } cancellationToken.ThrowIfCancellationRequested(); httpResponse = await this.Client.HttpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false); if (shouldTrace) { TracingAdapter.ReceiveResponse(invocationId, httpResponse); } HttpStatusCode statusCode = httpResponse.StatusCode; if (statusCode != HttpStatusCode.OK) { cancellationToken.ThrowIfCancellationRequested(); CloudException ex = CloudException.Create(httpRequest, null, httpResponse, await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false)); if (shouldTrace) { TracingAdapter.Error(invocationId, ex); } throw ex; } // Create Result ListBillingPlansResult result = null; // Deserialize Response if (statusCode == HttpStatusCode.OK) { cancellationToken.ThrowIfCancellationRequested(); string responseContent = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); result = new ListBillingPlansResult(); JToken responseDoc = null; if (string.IsNullOrEmpty(responseContent) == false) { responseDoc = JToken.Parse(responseContent); } if (responseDoc != null && responseDoc.Type != JTokenType.Null) { JToken planListArray = responseDoc; if (planListArray != null && planListArray.Type != JTokenType.Null) { foreach (JToken planListValue in ((JArray)planListArray)) { BillingPlan billingPlanInstance = new BillingPlan(); result.PlanList.Add(billingPlanInstance); JToken planIdValue = planListValue["PlanId"]; if (planIdValue != null && planIdValue.Type != JTokenType.Null) { string planIdInstance = ((string)planIdValue); billingPlanInstance.Id = planIdInstance; } JToken planNameValue = planListValue["PlanName"]; if (planNameValue != null && planNameValue.Type != JTokenType.Null) { string planNameInstance = ((string)planNameValue); billingPlanInstance.Name = planNameInstance; } JToken addOnsValue = planListValue["AddOns"]; if (addOnsValue != null && addOnsValue.Type != JTokenType.Null) { string addOnsInstance = ((string)addOnsValue); billingPlanInstance.AddOns = addOnsInstance; } JToken coresPerUserValue = planListValue["CoresPerUser"]; if (coresPerUserValue != null && coresPerUserValue.Type != JTokenType.Null) { double coresPerUserInstance = ((double)coresPerUserValue); billingPlanInstance.CoresPerUser = coresPerUserInstance; } JToken minimumBilledUserCountValue = planListValue["MinimumBilledUserCount"]; if (minimumBilledUserCountValue != null && minimumBilledUserCountValue.Type != JTokenType.Null) { int minimumBilledUserCountInstance = ((int)minimumBilledUserCountValue); billingPlanInstance.MinimumBilledUserCount = minimumBilledUserCountInstance; } } } } } result.StatusCode = statusCode; if (httpResponse.Headers.Contains("x-ms-request-id")) { result.RequestId = httpResponse.Headers.GetValues("x-ms-request-id").FirstOrDefault(); } if (shouldTrace) { TracingAdapter.Exit(invocationId, result); } return(result); } finally { if (httpResponse != null) { httpResponse.Dispose(); } } } finally { if (httpRequest != null) { httpRequest.Dispose(); } } }
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 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."))); } 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. if (!String.Equals(organization.PlanId, plan.Id)) { var result = await _billingManager.CanDownGradeAsync(organization, plan, ExceptionlessUser); 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(organization.StripeCustomerId); foreach (var sub in subs.Where(s => !s.CanceledAt.HasValue)) { await subscriptionService.CancelAsync(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 = SystemClock.UtcNow; var createCustomer = new StripeCustomerCreateOptions { SourceToken = stripeToken, PlanId = planId, Description = organization.Name, Email = ExceptionlessUser.EmailAddress }; if (!String.IsNullOrWhiteSpace(couponId)) { createCustomer.CouponId = couponId; } StripeCustomer customer = await customerService.CreateAsync(createCustomer); organization.BillingStatus = BillingStatus.Active; organization.RemoveSuspension(); organization.StripeCustomerId = customer.Id; if (customer.SourceList.TotalCount > 0) { organization.CardLast4 = customer.SourceList.Data[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 subscriptionList = await subscriptionService.ListAsync(organization.StripeCustomerId); var subscription = subscriptionList.FirstOrDefault(s => !s.CanceledAt.HasValue); if (subscription != null) { await subscriptionService.UpdateAsync(organization.StripeCustomerId, subscription.Id, update); } else { await subscriptionService.CreateAsync(organization.StripeCustomerId, planId, create); } await customerService.UpdateAsync(organization.StripeCustomerId, new StripeCustomerUpdateOptions { Email = ExceptionlessUser.EmailAddress }); if (cardUpdated) { organization.CardLast4 = last4; } organization.BillingStatus = BillingStatus.Active; organization.RemoveSuspension(); } BillingManager.ApplyBillingPlan(organization, plan, ExceptionlessUser); await _repository.SaveAsync(organization, true); 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(ExceptionlessUser.EmailAddress).Property("User", ExceptionlessUser).SetActionContext(ActionContext).Write(); return(Ok(ChangePlanResult.FailWithMessage(e.Message))); } return(Ok(new ChangePlanResult { Success = true })); }
public Customer(PaymentHistory paymentHistory, BillingPlan plan, string name) { PaymentHistory = paymentHistory; Plan = plan; Name = name; }
protected void btnAddNewPlan_Click(object sender, EventArgs e) { if (!HasWriteAccess) { return; } BillingPlan plan = new BillingPlan { Title = "New BillingPlan", Amount = 1, Cycle = 1, CycleUnit = CycleUnits.Days, Options = new BillingPlanOptions() }; BillingPlan.Create(plan); RecreateTable(); }
public void Activate(DateTime subscriptionDate, BillingPlan billingPlan) { OrderDate = subscriptionDate; RenewDate = OrderDate; Confirmed = true; Renew(billingPlan); //change the user's status to ACTIVE User.SetAsPaidUser(id, true); }
public BillingPlan GetBillingPlan() { var customer = _site.GetCustomer(); return(customer == null?BillingPlan.BasicPlan() : customer.GetPlan()); }
public void Renew(BillingPlan billingPlan) { switch (billingPlan.CycleUnit) { case CycleUnits.Days: RenewDate = RenewDate.AddDays(billingPlan.Cycle); break; case CycleUnits.Weeks: RenewDate = RenewDate.AddDays(billingPlan.Cycle*7); break; case CycleUnits.Months: RenewDate = RenewDate.AddMonths(billingPlan.Cycle); break; case CycleUnits.Years: RenewDate = RenewDate.AddYears(billingPlan.Cycle); break; } Update(); }
public BillingPlans(AppOptions options) { FreePlan = new BillingPlan { Id = "EX_FREE", Name = "Free", Description = "Free", Price = 0, MaxProjects = 1, MaxUsers = 1, RetentionDays = 3, MaxEventsPerMonth = 3000, HasPremiumFeatures = false }; SmallPlan = new BillingPlan { Id = "EX_SMALL", Name = "Small", Description = "Small ($15/month)", Price = 15, MaxProjects = 5, MaxUsers = 10, RetentionDays = 30, MaxEventsPerMonth = 15000, HasPremiumFeatures = true }; SmallYearlyPlan = new BillingPlan { Id = "EX_SMALL_YEARLY", Name = "Small (Yearly)", Description = "Small Yearly ($165/year - Save $15)", Price = 165, MaxProjects = 5, MaxUsers = 10, RetentionDays = 30, MaxEventsPerMonth = 15000, HasPremiumFeatures = true }; MediumPlan = new BillingPlan { Id = "EX_MEDIUM", Name = "Medium", Description = "Medium ($49/month)", Price = 49, MaxProjects = 15, MaxUsers = 25, RetentionDays = 90, MaxEventsPerMonth = 75000, HasPremiumFeatures = true }; MediumYearlyPlan = new BillingPlan { Id = "EX_MEDIUM_YEARLY", Name = "Medium (Yearly)", Description = "Medium Yearly ($539/year - Save $49)", Price = 539, MaxProjects = 15, MaxUsers = 25, RetentionDays = 90, MaxEventsPerMonth = 75000, HasPremiumFeatures = true }; LargePlan = new BillingPlan { Id = "EX_LARGE", Name = "Large", Description = "Large ($99/month)", Price = 99, MaxProjects = -1, MaxUsers = -1, RetentionDays = 180, MaxEventsPerMonth = 250000, HasPremiumFeatures = true }; LargeYearlyPlan = new BillingPlan { Id = "EX_LARGE_YEARLY", Name = "Large (Yearly)", Description = "Large Yearly ($1,089/year - Save $99)", Price = 1089, MaxProjects = -1, MaxUsers = -1, RetentionDays = 180, MaxEventsPerMonth = 250000, HasPremiumFeatures = true }; ExtraLargePlan = new BillingPlan { Id = "EX_XL", Name = "Extra Large", Description = "Extra Large ($199/month)", Price = 199, MaxProjects = -1, MaxUsers = -1, RetentionDays = 180, MaxEventsPerMonth = 1000000, HasPremiumFeatures = true }; ExtraLargeYearlyPlan = new BillingPlan { Id = "EX_XL_YEARLY", Name = "Extra Large (Yearly)", Description = "Extra Large Yearly ($2,189/year - Save $199)", Price = 2189, MaxProjects = -1, MaxUsers = -1, RetentionDays = 180, MaxEventsPerMonth = 1000000, HasPremiumFeatures = true }; EnterprisePlan = new BillingPlan { Id = "EX_ENT", Name = "Enterprise", Description = "Enterprise ($499/month)", Price = 499, MaxProjects = -1, MaxUsers = -1, RetentionDays = 180, MaxEventsPerMonth = 3000000, HasPremiumFeatures = true }; EnterpriseYearlyPlan = new BillingPlan { Id = "EX_ENT_YEARLY", Name = "Enterprise (Yearly)", Description = "Enterprise Yearly ($5,489/year - Save $499)", Price = 5489, MaxProjects = -1, MaxUsers = -1, RetentionDays = 180, MaxEventsPerMonth = 3000000, HasPremiumFeatures = true }; UnlimitedPlan = new BillingPlan { Id = "EX_UNLIMITED", Name = "Unlimited", Description = "Unlimited", IsHidden = true, Price = 0, MaxProjects = -1, MaxUsers = -1, RetentionDays = options.MaximumRetentionDays, MaxEventsPerMonth = -1, HasPremiumFeatures = true }; Plans = new List <BillingPlan> { FreePlan, SmallYearlyPlan, MediumYearlyPlan, LargeYearlyPlan, ExtraLargeYearlyPlan, EnterpriseYearlyPlan, SmallPlan, MediumPlan, LargePlan, ExtraLargePlan, EnterprisePlan, UnlimitedPlan }; }
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 }); }
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 })); }