예제 #1
0
        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();
        }
예제 #3
0
        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 }));
        }
예제 #4
0
        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);
        }
예제 #5
0
        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());
        }
예제 #6
0
        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 }));
        }
예제 #7
0
        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();
        }
예제 #9
0
        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);
        }
예제 #10
0
        /// <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;
        }
예제 #11
0
        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;
        }
예제 #12
0
        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);
        }
예제 #13
0
        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));
        }
예제 #14
0
        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();
        }
예제 #15
0
        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 }));
        }
예제 #18
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.")));
            }

            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
            }));
        }
예제 #19
0
 public Customer(PaymentHistory paymentHistory, BillingPlan plan, string name)
 {
     PaymentHistory = paymentHistory;
     Plan           = plan;
     Name           = name;
 }
예제 #20
0
        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();
        }
예제 #21
0
        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);
        }
예제 #22
0
        public BillingPlan GetBillingPlan()
        {
            var customer = _site.GetCustomer();

            return(customer == null?BillingPlan.BasicPlan() : customer.GetPlan());
        }
예제 #23
0
        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();
        }
예제 #24
0
    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
        };
    }
예제 #25
0
        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
            });
        }
예제 #26
0
        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 }));
        }