public async Task ChangeCommunityCard(Community community, BillingRecord billing, object card)
        {
            if (card is string stripeToken)
            {
                try
                {
                    var update = new CustomerUpdateOptions()
                    {
                        Source = stripeToken
                    };
                    update.AddExpand("default_source");
                    var stripeCustomer = await Customers.UpdateAsync(billing.Stripe !.CustomerId, update, RequestOptions);

                    if (stripeCustomer.DefaultSource is Stripe.Card stripeCard)
                    {
                        billing.Card = new Card()
                        {
                            Last4 = stripeCard.Last4,
                            Brand = stripeCard.Brand
                        };
                    }
                }
                catch (StripeException e)
                {
                    logger.LogError(e, "Failed to update stripe customer");
                    throw new PaymentProcessorCardException();
                }
            }
            else
            {
                throw new ArgumentException("StripePaymentProcessor requires a string card token");
            }
        }
        public async Task CancelCommunitySubscription(Community community, BillingRecord billing)
        {
            var plan = plans.GetPlan(billing.PlanId) !;

            if (plan.Stripe is StripePlan stripePlan)
            {
                try
                {
                    var update = new SubscriptionUpdateOptions()
                    {
                        CancelAtPeriodEnd = true
                    };
                    await Subscriptions.UpdateAsync(billing.Stripe !.SubscriptionId, update, RequestOptions);
                }
                catch (StripeException e)
                {
                    logger.LogError(e, "Failed to update stripe subscription");
                    throw;
                }
            }
            else
            {
                throw new ArgumentException("StripePaymentProcessor requires a StripePlan");
            }
        }
        public async Task StartCommunitySubscription(Community community, BillingRecord billing, User contact)
        {
            var plan = plans.GetPlan(billing.PlanId) !;

            if (plan.Stripe is StripePlan stripePlan)
            {
                try
                {
                    var customer = new CustomerCreateOptions()
                    {
                        Name  = community.Name,
                        Email = contact.Email.PlainText
                    };
                    var stripeCustomer = await Customers.CreateAsync(customer, RequestOptions);

                    var subscription = new SubscriptionCreateOptions()
                    {
                        Customer = stripeCustomer.Id,
                        Items    = new List <SubscriptionItemOptions>()
                        {
                            new SubscriptionItemOptions()
                            {
                                Price = stripePlan.PriceId
                            }
                        }
                    };

                    if (billing.TrialEnd > DateTime.Now)
                    {
                        subscription.TrialEnd = billing.TrialEnd;
                    }
                    var stripeSubscription = await Subscriptions.CreateAsync(subscription, RequestOptions);

                    if (billing.Stripe == null)
                    {
                        billing.Stripe = new StripeBillingRecord();
                    }
                    billing.Stripe.CustomerId         = stripeCustomer.Id;
                    billing.Stripe.SubscriptionId     = stripeSubscription.Id;
                    billing.Stripe.SubscriptionItemId = stripeSubscription.Items.Data[0].Id;
                }
                catch (StripeException e)
                {
                    logger.LogError(e, "Failed to create stripe subscription");
                    throw;
                }
            }
            else
            {
                throw new ArgumentException("StripePaymentProcessor requires a StripePlan");
            }
        }
 public async Task ChangeCommunityContact(Community community, BillingRecord billing, User contact)
 {
     try
     {
         var update = new CustomerUpdateOptions()
         {
             Email = contact.Email.PlainText
         };
         await Customers.UpdateAsync(billing.Stripe !.CustomerId, update, RequestOptions);
     }
     catch (StripeException e)
     {
         logger.LogError(e, "Failed to update stripe customer");
         throw;
     }
 }
        /// <summary>
        /// Updates the coupon used by the community billing.
        /// </summary>
        /// <param name="community"></param>
        /// <param name="billing"></param>
        /// <param name="couponCode">The coupon code. null to remove it.</param>
        /// <returns>The coupon, or null if it's unknown.</returns>
        /// <exception cref="PaymentProcessorCardException"></exception>
        public async Task <Coupon?> ChangeCommunityCoupon(Community community, BillingRecord billing, string?couponCode)
        {
            PromotionCode?promo = string.IsNullOrEmpty(couponCode) ? null : await this.FindCode(couponCode);

            try
            {
                CustomerUpdateOptions options = new CustomerUpdateOptions()
                {
                    PromotionCode = promo?.Id,
                };

                options.AddExpand("default_source");
                await this.Customers.UpdateAsync(billing.Stripe !.CustomerId, options, this.RequestOptions);
            }
            catch (StripeException e)
            {
                this.logger.LogError(e, "Failed to update stripe customer");
                throw new PaymentProcessorCardException();
            }

            return(promo == null ? null : await this.GetCoupon(promo));
        }