public static DataAccessResponseType ProcessStripeCustomerDelinquencyChangedEvent(string accountId, string storagePartition, bool newDelinquencyStatus)
        {
            var response = new DataAccessResponseType();

            if (newDelinquencyStatus == false)
            {
                //Account is no longer delinquent according to stripe.

                //Turn off Delinquent state
                AccountManager.UpdateAccountDelinquentStatus(accountId, false);

                //Clear DunningAttempts Table:
                PlatformBillingManager.ClearAutomaticDunningAttempt(accountId, storagePartition);
            }
            else if (newDelinquencyStatus == true)
            {
                //Account is delinquent according to stripe.

                //Turn on Delinquent state:
                AccountManager.UpdateAccountDelinquentStatus(accountId, true);
            }

            response.isSuccess = true;

            return(response);
        }
        public static DataAccessResponseType ProcessStripeSubscriptionStatusChangedEvent(Account account, string newSubscriptionStatus, string previousSubscriptionStatus)
        {
            var response = new DataAccessResponseType();


            if (newSubscriptionStatus == "active" && previousSubscriptionStatus == "unpaid" ||
                newSubscriptionStatus == "active" && previousSubscriptionStatus == "past_due")
            {
                // Turn off delinquncy, clear dunning & reactive the account
                AccountManager.UpdateAccountActiveState(account.AccountID.ToString(), true);
                AccountManager.UpdateAccountDelinquentStatus(account.AccountID.ToString(), false);
                PlatformBillingManager.ClearAutomaticDunningAttempt(account.AccountID.ToString(), account.StoragePartition);
            }
            else if (newSubscriptionStatus == "past_due" && previousSubscriptionStatus == "active")
            {
                // Turn on delinquncy: The 'ProcessFailedStripeInvoicedChargeEvent' will handle the dunning emails
                AccountManager.UpdateAccountDelinquentStatus(account.AccountID.ToString(), true);
            }
            else if (newSubscriptionStatus == "unpaid" && previousSubscriptionStatus == "past_due")
            {
                // 1. Deactivate the account, assure that delinquent is still true send final email
                AccountManager.UpdateAccountActiveState(account.AccountID.ToString(), false);
                AccountManager.UpdateAccountDelinquentStatus(account.AccountID.ToString(), true);

                // 2. get the account
                //var account = AccountManager.GetAccount(accountId);

                // 3. Get all owners for the account:
                var accountOwnerEmails = AccountManager.GetAccountOwnerEmails(account.AccountID.ToString());

                //Stripe has marked the Subscritption as 'unpaid'. Messaing is an alert about account closure
                // 4. Email all account owners

                //email all account owners a copy of account closure email
                EmailManager.Send(
                    accountOwnerEmails,
                    Settings.Endpoints.Emails.FromAlerts,
                    Settings.Copy.EmailMessages.InvoicedChargeFailed_AccountDeactivated.FromName,
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_AccountDeactivated.Subject),
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_AccountDeactivated.Body, account.AccountName),
                    true);


                // 5. Email Platform Admins
                EmailManager.Send(
                    Settings.Endpoints.Emails.PlatformEmailAddresses,
                    Settings.Endpoints.Emails.FromPlatform,
                    "ACCOUNT DEACTIVATED",
                    "An account has been deactivated due to an unpaid subscription",
                    "AccountName: <b>" + account.AccountName + "</b><br/><br/>AccountID: <b>" + account.AccountID + "</b><br/>",
                    true);
            }

            response.isSuccess = true;

            return(response);
        }
예제 #3
0
        public List <Charge> GetPaymentHistory_Last(int itemLimit, string endingBeforeChargeId, string accountId, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            return(PlatformBillingManager.GetPaymentHistory_Last(itemLimit, endingBeforeChargeId, accountId));
        }
예제 #4
0
        public Charge GetPayment(string chargeId, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            return(PlatformBillingManager.GetPayment(chargeId));
        }
예제 #5
0
        public List <Invoice> GetInvoiceHistory_ByDateRange_Last(int itemLimit, string endingBeforeInvoiceId, DateTime startDate, DateTime endDate, string accountId, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            return(PlatformBillingManager.GetInvoiceHistory_ByDateRange_Last(itemLimit, endingBeforeInvoiceId, startDate, endDate, accountId));
        }
예제 #6
0
        public Invoice GetUpcomingInvoice(string accountId, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            return(PlatformBillingManager.GetUpcomingInvoice(accountId));
        }
예제 #7
0
        public List <Invoice> GetInvoiceHistory_Next(int itemLimit, string startingAfterInvoiceId, string accountId, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            return(PlatformBillingManager.GetInvoiceHistory_Next(itemLimit, startingAfterInvoiceId, accountId));
        }
        public List <Transfer> GetTransferHistory_ByDateRange_Next(int itemLimit, string startingAfterTransferId, DateTime startDate, DateTime endDate, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            return(PlatformBillingManager.GetTransferHistory_ByDateRange_Next(itemLimit, startingAfterTransferId, startDate, endDate));
        }
        public List <Transfer> GetTransferHistory_Last(int itemLimit, string endingBeforeTransferId, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            return(PlatformBillingManager.GetTransferHistory_Last(itemLimit, endingBeforeTransferId));
        }
        public Transfer GetTransfer(string transferId, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            return(PlatformBillingManager.GetTransfer(transferId));
        }
        public SourceBalanceTransactions GetBalanceTransactionsForSource(string sourceId, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            return(PlatformBillingManager.GetBalanceTransactionsForSource(sourceId));
        }
예제 #12
0
        public List <DunningAttempt> GetDunningAttempts(string accountId, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            var account = AccountManager.GetAccount(accountId);

            return(PlatformBillingManager.GetAutomaticDunningAttempts(accountId, account.StoragePartition));
        }
예제 #13
0
        public DataAccessResponseType RefundPayment(string accountId, string chargeId, decimal refundAmount, string requesterID, RequesterType requesterType, string sharedClientKey)
        {
            // Ensure the clients are certified.
            if (sharedClientKey != Sahara.Core.Platform.Requests.RequestManager.SharedClientKey)
            {
                return(null);
            }

            if (String.IsNullOrEmpty(accountId))
            {
                return(new DataAccessResponseType {
                    isSuccess = false, ErrorMessage = "Must include an accountId"
                });
            }

            #region Validate Request

            var requesterName  = string.Empty;
            var requesterEmail = string.Empty;

            var requestResponseType = RequestManager.ValidateRequest(requesterID,
                                                                     requesterType, out requesterName, out requesterEmail,
                                                                     Sahara.Core.Settings.Platform.Users.Authorization.Roles.SuperAdmin, //<-- Only Platform SuperAdmins can refund payments
                                                                     null);

            if (!requestResponseType.isApproved)
            {
                //Request is not approved, send results:
                return(new DataAccessResponseType {
                    isSuccess = false, ErrorMessage = requestResponseType.requestMessage
                });
            }

            #endregion

            return(PlatformBillingManager.RefundPayment(accountId, chargeId, refundAmount));
        }
예제 #14
0
        public static BillingReport GetBillingReport(int sinceHoursAgo)
        {
            var billingReport = new BillingReport();

            #region get from Redis

            //IDatabase cache = Sahara.Core.Settings.Azure.Redis.RedisMultiplexers.PlatformManager_Multiplexer.GetDatabase();
            IDatabase cache = Sahara.Core.Settings.Azure.Redis.RedisMultiplexers.RedisMultiplexer.GetDatabase();

            Object cachedBillingReport = null;

            try
            {
                cachedBillingReport = cache.HashGet(
                    Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.ReportsHash.Key,
                    Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.ReportsHash.Fields.Billing(sinceHoursAgo)
                    );

                if (((RedisValue)cachedBillingReport).HasValue)
                {
                    billingReport = JsonConvert.DeserializeObject <BillingReport>((RedisValue)cachedBillingReport);
                }
            }
            catch
            {
            }

            #endregion

            #region Generate report

            if (((RedisValue)cachedBillingReport).IsNullOrEmpty)
            {
                var stripeManager = new StripeManager();


                //Counts & Totals:
                var chargeCount = 0;
                //var failedChargeCount = 0;
                var refundCount            = 0;
                var transferCount          = 0;
                var transferCount_Pending  = 0;
                var transferCount_Complete = 0;

                decimal totalGross              = 0;
                decimal totalFees               = 0;
                decimal totalRefunds            = 0;
                decimal totalNet                = 0;
                decimal totalTransfers          = 0;
                decimal totalTransfers_Pending  = 0;
                decimal totalTransfers_Complete = 0;


                //Get charges from time period:

                /*var stripeCharges = new List<StripeCharge>();
                 *
                 *
                 * //Since Stripe limit is 100 we break up the call into 100 item increments until we reach the last item:
                 * var stripeChargesPending = stripeManager.GetCharges_SinceHoursAgo(sinceHoursAgo, null, null, true).ToList();
                 *
                 * stripeCharges.AddRange(stripeChargesPending);
                 * while (stripeChargesPending.Count == 100)
                 * {
                 *  stripeChargesPending = stripeManager.GetCharges_SinceHoursAgo(sinceHoursAgo, stripeChargesPending[99].Id, null, true).ToList();
                 *  stripeCharges.AddRange(stripeChargesPending);
                 * }
                 */



                //Loop through all charges from time period and generate report data

                /*
                 * foreach(StripeCharge stripeCharge in stripeCharges)
                 * {
                 *  if (stripeCharge.Paid.HasValue)
                 *  {
                 *      if (stripeCharge.Paid.Value)
                 *      {
                 *          chargeCount++;
                 *          /*totalGross = totalGross + Sahara.Core.Common.Methods.Billing.ConvertStripeAmountToDecimals(stripeCharge.Amount.ToString());
                 *          totalFees = totalFees + Sahara.Core.Common.Methods.Billing.ConvertStripeAmountToDecimals(stripeCharge.BalanceTransaction.Fee.ToString());
                 *          totalNet = totalNet + Sahara.Core.Common.Methods.Billing.ConvertStripeAmountToDecimals(stripeCharge.BalanceTransaction.Net.ToString());
                 *          if (stripeCharge.AmountRefunded.HasValue)
                 *          {
                 *              totalRefunds = totalRefunds + Sahara.Core.Common.Methods.Billing.ConvertStripeAmountToDecimals(stripeCharge.AmountRefunded.Value.ToString());
                 *          }
                 *          if (stripeCharge.Refunded.HasValue)
                 *          {
                 *              if (stripeCharge.Refunded.Value)
                 *              {
                 *                  refundCount++;
                 *              }
                 *          }* /
                 *      }
                 *      else if (!stripeCharge.Paid.Value)
                 *      {
                 *          failedChargeCount++;
                 *      }
                 *  }
                 *
                 * }*/

                billingReport.BalanceTransactions           = new List <Billing.Models.BalanceTransaction>();
                billingReport.BalanceTransactions_Created   = new List <Billing.Models.BalanceTransaction>();
                billingReport.BalanceTransactions_Available = new List <Billing.Models.BalanceTransaction>();

                //Since Stripe limit is 100 we break up the call into 100 item increments until we reach the last item:
                var balanceTransactions = PlatformBillingManager.GetBalanceTransaction_AvailableSinceHourssAgo(sinceHoursAgo);

                billingReport.BalanceTransactions.AddRange(balanceTransactions);
                while (balanceTransactions.Count == 100)
                {
                    balanceTransactions = PlatformBillingManager.GetBalanceTransaction_AvailableSinceHourssAgo(sinceHoursAgo, balanceTransactions[99].BalanceTransactionID);
                    billingReport.BalanceTransactions.AddRange(balanceTransactions);
                }



                //Split all results into 2 camps ===============================================

                foreach (var balanceTransaction in billingReport.BalanceTransactions)
                {
                    if (balanceTransaction.Created >= DateTime.UtcNow.AddHours(sinceHoursAgo * -1))
                    {
                        billingReport.BalanceTransactions_Created.Add(balanceTransaction);
                    }
                    else
                    {
                        billingReport.BalanceTransactions_Available.Add(balanceTransaction);
                    }
                }

                //=================================================================================================
                //Loop through all balance transactions from ENTIRE time period to generate daily activity data for transactions


                foreach (var btr in billingReport.BalanceTransactions)
                {
                    if (btr.Type == "transfer")
                    {
                        transferCount++;
                        totalTransfers = totalTransfers + btr.Amount;

                        if (btr.Status == "pending")
                        {
                            transferCount_Pending++;
                            totalTransfers_Pending = totalTransfers_Pending + btr.Amount;
                        }
                        else
                        {
                            transferCount_Complete++;
                            totalTransfers_Complete = totalTransfers_Complete + btr.Amount;
                        }
                    }
                }


                //=================================================================================================
                //Loop through all balance transactions from the CREATED time period to generate daily activity data for charges & refunds

                foreach (var btr in billingReport.BalanceTransactions_Created)
                {
                    if (btr.Type == "charge")
                    {
                        chargeCount++;

                        totalGross = totalGross + btr.Amount;
                        totalFees  = totalFees + btr.Fee;
                        totalNet   = totalNet + btr.Net;
                    }
                    else if (btr.Type == "refund")
                    {
                        refundCount++;

                        totalRefunds = totalRefunds + btr.Amount;

                        //totalGross = totalGross + btr.Amount;
                        totalFees = totalFees + btr.Fee;
                        totalNet  = totalNet + btr.Net;
                    }
                    else if (btr.Type == "adjustment")
                    {
                        totalGross = totalGross + btr.Amount;
                        totalFees  = totalFees + btr.Fee;
                        totalNet   = totalNet + btr.Net;
                    }
                    else if (btr.Type == "application_fee" || btr.Type == "application_fee_refund")
                    {
                        totalGross = totalGross + btr.Amount;
                        totalFees  = totalFees + btr.Fee;
                        totalNet   = totalNet + btr.Net;
                    }

                    /*
                     * else if (btr.Type == "transfer")
                     * {
                     *
                     * transferCount++;
                     * totalTransfers = totalTransfers + btr.Amount;
                     * if (btr.Status == "pending")
                     * {
                     *  transferCount_Pending++;
                     *  totalTransfers_Pending = totalTransfers_Pending + btr.Amount;
                     * }
                     * else
                     * {
                     *  transferCount_Complete++;
                     *  totalTransfers_Complete = totalTransfers_Complete + btr.Amount;
                     * }
                     * }*/
                }

                billingReport.ChargeCount = chargeCount;
                billingReport.RefundCount = refundCount;
                //billingReport.FailedChargeCount = failedChargeCount;
                billingReport.TransferCount          = transferCount;
                billingReport.TransferCount_Pending  = transferCount_Pending;
                billingReport.TransferCount_Complete = transferCount_Complete;

                billingReport.TotalGross              = totalGross;
                billingReport.TotalFees               = Math.Abs(totalFees);
                billingReport.TotalRefunds            = Math.Abs(totalRefunds);
                billingReport.TotalNet                = totalNet;
                billingReport.TotalTransfers          = Math.Abs(totalTransfers);
                billingReport.TotalTransfers_Pending  = Math.Abs(totalTransfers_Pending);
                billingReport.TotalTransfers_Complete = Math.Abs(totalTransfers_Complete);

                //============================================


                billingReport.BillingIssues = false;

                //Check for any billing issues during this time period
                var latestBillingIssue = PlatformLogManager.GetPlatformLogByActivity(Logging.PlatformLogs.Types.ActivityType.Billing_Issue, 1);
                if (latestBillingIssue.Count > 0)
                {
                    if (latestBillingIssue[0].Timestamp >= DateTime.UtcNow.AddHours(sinceHoursAgo * -1))
                    {
                        billingReport.BillingIssues = true;
                    }
                }


                #region Store into Redis

                try
                {
                    //Store a copy in the Redis cache
                    cache.HashSet(
                        Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.ReportsHash.Key,
                        Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.ReportsHash.Fields.Billing(sinceHoursAgo),
                        JsonConvert.SerializeObject(billingReport),
                        When.Always,
                        CommandFlags.FireAndForget
                        );

                    //Expire cache after set time
                    cache.KeyExpire(
                        Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.ReportsHash.Key,
                        Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.ReportsHash.Expiration,
                        CommandFlags.FireAndForget
                        );
                }
                catch
                {
                }


                #endregion
            }



            /*/TESTS!
             * billingReport.BalanceTransactions.Add(new BalanceTransaction { Type = "adjustment", Amount = Convert.ToDecimal(20.77), Fee = Convert.ToDecimal(20.77), Net = Convert.ToDecimal(20.77) });
             * billingReport.BalanceTransactions.Add(new BalanceTransaction { Type = "application_fee", Amount = Convert.ToDecimal(20.77), Fee = Convert.ToDecimal(20.77), Net = Convert.ToDecimal(20.77) });
             * billingReport.BalanceTransactions.Add(new BalanceTransaction { Type = "application_fee_refund", Amount = Convert.ToDecimal(20.77), Fee = Convert.ToDecimal(20.77), Net = Convert.ToDecimal(20.77) });
             * billingReport.BalanceTransactions.Add(new BalanceTransaction { Type = "transfer_cancel", Amount = Convert.ToDecimal(20.77), Fee = Convert.ToDecimal(20.77), Net = Convert.ToDecimal(20.77) });
             * billingReport.BalanceTransactions.Add(new BalanceTransaction { Type = "transfer_failure", Amount = Convert.ToDecimal(20.77), Fee = Convert.ToDecimal(20.77), Net = Convert.ToDecimal(20.77) });
             */


            #endregion

            return(billingReport);
        }
        public static BillingSnapshot GetBillingSnapshot()
        {
            var billingSnapshot = new BillingSnapshot();

            #region Generate Billing Snapshot

            #region Get from Redis Cache

            //IDatabase cache = Sahara.Core.Settings.Azure.Redis.RedisMultiplexers.PlatformManager_Multiplexer.GetDatabase();
            IDatabase cache = Sahara.Core.Settings.Azure.Redis.RedisMultiplexers.RedisMultiplexer.GetDatabase();

            Object cachedBillingSnapshot = null;

            try
            {
                cachedBillingSnapshot = cache.HashGet(
                    Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.SnapshotsHash.Key,
                    Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.SnapshotsHash.Fields.Billing
                    );

                if (((RedisValue)cachedBillingSnapshot).HasValue)
                {
                    billingSnapshot = JsonConvert.DeserializeObject <BillingSnapshot>((RedisValue)cachedBillingSnapshot);
                }
            }
            catch
            {
            }


            #endregion

            #region Generate Snapshot

            if (((RedisValue)cachedBillingSnapshot).IsNullOrEmpty)
            {
                billingSnapshot = new BillingSnapshot();

                billingSnapshot.CreditsInCirculation             = AccountCreditsManager.GetCreditsInCirculation();
                billingSnapshot.CreditsInCirculationDollarAmount = Sahara.Core.Common.Methods.Commerce.ConvertCreditsAmountToDollars(billingSnapshot.CreditsInCirculation);

                billingSnapshot.Balance = PlatformBillingManager.GetBalance();

                billingSnapshot.UpcomingTransfers = new List <Billing.Models.Transfer>();
                billingSnapshot.LatestTransfers   = new List <Billing.Models.Transfer>();

                try
                {
                    var topTransfers = PlatformBillingManager.GetTransferHistory(10);

                    foreach (var transfer in topTransfers)
                    {
                        if (transfer.Status == "pending")
                        {
                            billingSnapshot.UpcomingTransfers.Add(transfer);
                        }
                        else if (transfer.Status == "paid" && billingSnapshot.LatestTransfers.Count < 2) //<-- We only show the latest 2 available transfers
                        {
                            billingSnapshot.LatestTransfers.Add(transfer);
                        }
                    }

                    //We reverse the upcoming list so the latest transfers show up first
                    billingSnapshot.UpcomingTransfers.Reverse();
                }
                catch
                {
                    billingSnapshot.LatestTransfers   = null;
                    billingSnapshot.UpcomingTransfers = null;
                }

                #region Store in Redis

                try
                {
                    //Store a copy in the Redis cache
                    cache.HashSet(
                        Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.SnapshotsHash.Key,
                        Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.SnapshotsHash.Fields.Billing,
                        JsonConvert.SerializeObject(billingSnapshot),
                        When.Always,
                        CommandFlags.FireAndForget
                        );

                    //Expire cache after set time
                    cache.KeyExpire(
                        Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.SnapshotsHash.Key,
                        Sahara.Core.Common.Redis.PlatformManagerServer.Hashes.SnapshotsHash.Expiration,
                        CommandFlags.FireAndForget
                        );
                }
                catch
                {
                }

                #endregion
            }


            #endregion

            #endregion

            return(billingSnapshot);
        }
        public static DataAccessResponseType ProcessFailedStripeRecurringChargeEvent(string stripeCustomerID, string stripeChargeId, string amount, string failureMessage, string stripeEventId)
        {
            /* FROM STRIPE DOCS (why we only focus on the charge failure since we ensure a card is always on file:
             *
             * We'll let you know about this case with an 'invoice.payment_failed' event.
             * The payment could have failed either because your customer did not have a card on file or because the charge was declined;
             * if it was due to a decline, we'll also emit a 'charge.failed event'.
             *
             * You'll also see a 'customer.updated' event to set the 'delinquent' flag,
             * an 'invoice.updated' event to track the payment attempts, and 'customer.subscription.updated'
             * or 'customer.subscription.deleted' depending on your retry settings.
             *
             * */

            var response = new DataAccessResponseType();

            // 1. Get the account
            var account = AccountManager.GetAccount(stripeCustomerID);

            // 2. Update account Delinquent state
            AccountManager.UpdateAccountDelinquentStatus(account.AccountID.ToString(), true);

            // 3. Determine number of previous autmatic failures, and adjust messaging severity accordingly
            int previousFailureCount = PlatformBillingManager.GetAutomaticDunningAttemptCount(account.AccountID.ToString(), account.StoragePartition);

            //Pull count of past failures from table storage rows
            // Details shoul include:
            // TieStamp
            // Charge amount
            // Stripe ID's (charge, event, etc)


            // 4. Get all owners for the account:
            var accountOwnerEmails = AccountManager.GetAccountOwnerEmails(stripeCustomerID);

            if (previousFailureCount == 0)
            {
                //First attempt, light messagng
                //Email all account owners
                //email all account owners a copy of the associated invoice
                EmailManager.Send(
                    accountOwnerEmails,
                    Settings.Endpoints.Emails.FromBilling,
                    Settings.Copy.EmailMessages.InvoicedChargeFailed_FirstDunningAttempt.FromName,
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_FirstDunningAttempt.Subject),
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_FirstDunningAttempt.Body, account.AccountName, account.AccountNameKey, failureMessage),
                    true);
            }
            else if (previousFailureCount == 1)
            {
                //This was the second attempt, email is more sever and includes platform admins
                //Email all account owners

                //email all account owners a copy of alert email
                EmailManager.Send(
                    accountOwnerEmails,
                    Settings.Endpoints.Emails.FromBilling,
                    Settings.Copy.EmailMessages.InvoicedChargeFailed_SecondDunningAttempt.FromName,
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_SecondDunningAttempt.Subject),
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_SecondDunningAttempt.Body, account.AccountName, account.AccountNameKey, failureMessage),
                    true);


                //Email Platform Admins
                EmailManager.Send(
                    Settings.Endpoints.Emails.PlatformEmailAddresses,
                    Settings.Endpoints.Emails.FromPlatform,
                    "Second Failed Charge Warning",
                    "An account has been sent a second warning about failed charge",
                    "AccountName: <b>" + account.AccountName + "</b><br/><br/>AccountID: <b>" + account.AccountID + "</b><br/><br/>Failure Message: <b>" + failureMessage + "</b><br/>",
                    true);
            }
            else if (previousFailureCount == 2)
            {
                //This was the third attempt, email is more sever and includes platform admins
                //Email all account owners

                //email all account owners a copy of alert email
                EmailManager.Send(
                    accountOwnerEmails,
                    Settings.Endpoints.Emails.FromBilling,
                    Settings.Copy.EmailMessages.InvoicedChargeFailed_ThirdDunningAttempt.FromName,
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_ThirdDunningAttempt.Subject),
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_ThirdDunningAttempt.Body, account.AccountName, account.AccountNameKey, failureMessage),
                    true);


                //Email Platform Admins
                EmailManager.Send(
                    Settings.Endpoints.Emails.PlatformEmailAddresses,
                    Settings.Endpoints.Emails.FromPlatform,
                    "Third Failed Charge Warning",
                    "An account has been sent a third warning about failed charge",
                    "AccountName: <b>" + account.AccountName + "</b><br/><br/>AccountID: <b>" + account.AccountID + "</b><br/><br/>Failure Message: <b>" + failureMessage + "</b><br/>",
                    true);

                //Send alert notification with a 7 day expiration to the account owners (or do this on the second attempt?)

                /* NOTIFICATIONS TURNED OFF
                 * NotificationsManager.SendNotificationToAccount(
                 *  NotificationType.Alert,
                 *  account.AccountID.ToString(),
                 *  Settings.Copy.NotificationMessages.ChargeFailure_Automatic.NotificationMessage,
                 *  10080, //<-- 7 Days (Length of time until Stripe makes final attempt)
                 *  true
                 *  );
                 */

                // Send email to Platform Admins
            }
            else if (previousFailureCount == 3)
            {
                //This was the fourth and final attempt, after this Stripe has marked the Subscritption as 'unpaid'. Messaing is a dire warning about account closure
                //Email all account owners

                //email all account owners a copy of alert email
                EmailManager.Send(
                    accountOwnerEmails,
                    Settings.Endpoints.Emails.FromBilling,
                    Settings.Copy.EmailMessages.InvoicedChargeFailed_FinalDunningAttempt.FromName,
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_FinalDunningAttempt.Subject),
                    String.Format(Settings.Copy.EmailMessages.InvoicedChargeFailed_FinalDunningAttempt.Body, account.AccountName),
                    true);



                //Email Platform Admins
                EmailManager.Send(
                    Settings.Endpoints.Emails.PlatformEmailAddresses,
                    Settings.Endpoints.Emails.FromPlatform,
                    "FINAL Failed Charge Warning",
                    "An account has been sent a final warning about failed charge",
                    "AccountName: <b>" + account.AccountName + "</b><br/><br/>AccountID: <b>" + account.AccountID + "</b><br/><br/>Failure Message: <b>" + failureMessage + "</b><br/>",
                    true);
            }


            //Store failure (increase failure count by 1)
            PlatformBillingManager.StoreAutomaticDunningAttempt(account.AccountID.ToString(), account.StoragePartition, stripeChargeId, amount, account.StripeSubscriptionID, stripeEventId, failureMessage);


            response.isSuccess = true;

            return(response);
        }