public async Task <PaymentGatewayResult <IPaymentSubscription> > CreateSubscriptionAsync(string planId, string customerId, ChargeType type, string?coupon) { try { var options = new SubscriptionCreateOptions { CustomerId = customerId, Items = new List <SubscriptionItemOption> { new SubscriptionItemOption { PlanId = planId } }, CollectionMethod = _chargeTypes[(int)type], CouponId = coupon }; if ((int)type == 1) { options.DaysUntilDue = _appSettings.Stripe.InvoiceDueDays; } var subscription = await _subscriptionService.CreateAsync(options); return(PaymentGatewayResult <IPaymentSubscription> .Success(_mapper.Map <IPaymentSubscription>(subscription))); } catch (StripeException e) { return(PaymentGatewayResult <IPaymentSubscription> .Failed(e)); } }
public async Task <ActionResult <Subscription> > CreateCustomerAsync([FromBody] CustomerCreateRequest request) { var customerService = new CustomerService(this.client); var customer = await customerService.CreateAsync(new CustomerCreateOptions { Email = request.Email, PaymentMethod = request.PaymentMethod, InvoiceSettings = new CustomerInvoiceSettingsOptions { DefaultPaymentMethod = request.PaymentMethod, } }); var subscriptionService = new SubscriptionService(this.client); var subscription = await subscriptionService.CreateAsync(new SubscriptionCreateOptions { Items = new List <SubscriptionItemOptions> { new SubscriptionItemOptions { Plan = this.options.Value.SubscriptionPlanId, }, }, Customer = customer.Id, Expand = new List <string> { "latest_invoice.payment_intent", } }); return(subscription); }
public async Task <IActionResult> SubscribeAsync([FromBody] SubscribeRequest req) { try { AuthController.ValidateAndGetCurrentUserName(this.HttpContext.Request); var email = this.HttpContext.Request.Headers["From"]; var user = await context.Users.FindAsync(email); if (user == null) { return(NotFound()); } for (int i = 0; i < 3; i++) { if (string.IsNullOrEmpty(user.CustomerID)) { await Task.Delay(2000); user = await context.Users.FindAsync(email); } } if (string.IsNullOrEmpty(user.CustomerID)) { return(NotFound()); } var prevsub = context.Subscriptions.FirstOrDefault(sub => sub.CustomerEmail == email); bool newCustomer = (prevsub == null); var subscriptions = new SubscriptionService(); var customerID = user.CustomerID; SubscriptionCreateOptions mysub = new SubscriptionCreateOptions(); mysub.CustomerId = customerID; mysub.Items = new List <SubscriptionItemOption>(); mysub.TrialFromPlan = newCustomer; mysub.TaxPercent = 20m; mysub.Items.Add(new SubscriptionItemOption { PlanId = req.planId, Quantity = 1 }); var subscription = await subscriptions.CreateAsync(mysub); await context.SaveChangesAsync(); return(Ok()); } catch (Exception ex) { throw ex; } }
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 static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log, ExecutionContext context) { var config = new ConfigurationBuilder().SetBasePath(context.FunctionAppDirectory) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); var authenticationService = new AuthenticationService(config["tenantId"], config["clientId"], config["clientSecret"]); var subscriptionService = new SubscriptionService(authenticationService, config["graphEndpoint"], config["notificationEndpoint"]); var subscription = await subscriptionService.CreateAsync("created", config["resource"], DateTime.Now.AddMinutes(4230)); return(new OkObjectResult(subscription)); }
public async Task <Subscription> Subscribe(string customerId, string paymentMethod, List <SubscribeItemOption> items) { var service = new SubscriptionService(); var item = await service.CreateAsync(new SubscriptionCreateOptions { Customer = customerId, DefaultPaymentMethod = paymentMethod, Items = items.Select(x => new SubscriptionItemOptions { Price = x.PriceId, Quantity = x.Quantity }).ToList(), }); return(item); }
public async Task <Subscription> Subscribe(string customerId, string productId) { var service = new SubscriptionService(); var prices = await GetPrices(productId); var item = await service.CreateAsync(new SubscriptionCreateOptions { Customer = customerId, Items = prices.Where(x => x.Type == "recurring").Select(x => new SubscriptionItemOptions { Price = x.Id }).ToList(), }); return(item); }
/* * Here we're initializing a stripe SEPA subscription on a source with sepa/iban data. This subscription should auto-charge. */ public async Task InitializeSepaDirect(SepaDirectCheckout checkout, CancellationToken token) { logger.LogInformation("Initializing sepa direct"); IEnumerable <ValidationResult> validationResults = ValidationHelper.Validate(checkout, serviceProvider); if (validationResults.Any()) { throw new InvalidOperationException(string.Join(",", validationResults.Select(v => $"{string.Join(", ", v.MemberNames)}: {v.ErrorMessage}"))); } ApplicationUser user = await userManager.FindByEmailAsync(checkout.Email).ConfigureAwait(false); Customer customer = await GetOrCreateCustomer(checkout.Name, checkout.Email, token).ConfigureAwait(false); Source source = await sourceService.AttachAsync( customer.Id, new SourceAttachOptions() { Source = checkout.SourceId }, cancellationToken : token).ConfigureAwait(false); Plan plan = await CreateRecurringPlan(checkout.Amount, "eur", token).ConfigureAwait(false); Subscription subscription = await subscriptionService.CreateAsync( new SubscriptionCreateOptions() { DefaultSource = source.Id, Billing = Billing.ChargeAutomatically, CustomerId = customer.Id, Items = new List <SubscriptionItemOption>() { new SubscriptionItemOption() { PlanId = plan.Id, Quantity = 1 } } }, cancellationToken : token).ConfigureAwait(false); context.DonationEventLog.Add(new DonationEventLog(userId: user?.Id, type: DonationEventType.Internal, eventData: subscription.ToJson())); await context.SaveChangesAsync(token).ConfigureAwait(false); logger.LogInformation("Done initializing sepa direct"); }
// GET: Test/Subscribe public async Task <ActionResult> Subscribe(int?id) { try { // I. Checks. string currentUserId = System.Web.HttpContext.Current.User.Identity.GetUserId(); if (currentUserId == null) { return(RedirectToAction("Login", "Account")); } // Check id. if (!int.TryParse(id.ToString(), out int intId)) { return(RedirectToAction("Index")); } // II. Add a new subscription to DB. if (ModelState.IsValid) { SubscriptionDTO subscriptionDTO = new SubscriptionDTO { UserProfileId = currentUserId, CourseId = intId, SubscriptionPeriod = 1, IsApproved = false }; OperationDetails operationDetails = await SubscriptionService.CreateAsync(subscriptionDTO, currentUserId); if (operationDetails.Succedeed) { return(PartialView("Report", operationDetails)); } else { ModelState.AddModelError(operationDetails.Property, operationDetails.Message); return(PartialView("Report", operationDetails)); } } ViewBag.Message = "Non valid"; return(PartialView()); } catch (Exception ex) { throw new Exception(ex.Message); } }
public async Task <StripeIdResponse> CreateSubscription(string customerId, string planId) { var subscriptionService = new SubscriptionService(); var subscription = await subscriptionService.CreateAsync(new SubscriptionCreateOptions { CustomerId = customerId, Items = new List <SubscriptionItemOption> { new SubscriptionItemOption { PlanId = planId } } }); return(new StripeIdResponse { Id = subscription.Id }); }
/// <summary> /// Subscribes - new subscription /// </summary> /// <returns></returns> private async Task <Subscription> Subscribe(PaymentModel payment) { var subscriptions = new List <SubscriptionItemOptions>() { new SubscriptionItemOptions() { Plan = payment.PlanId, Quantity = 1, } }; var subscriptionService = new SubscriptionService(); var subscriptionOptions = new SubscriptionCreateOptions() { Customer = payment.CustomerId, CancelAtPeriodEnd = false, Items = subscriptions, }; return(await subscriptionService.CreateAsync(subscriptionOptions)); }
public async Task <Subscription> SubscribeMemberToVendorshipPlan(string VendorshipPlanId, string CustomerId) { var items = new List <SubscriptionItemOptions> { new SubscriptionItemOptions { Plan = VendorshipPlanId } }; var options = new SubscriptionCreateOptions { Items = items, Customer = CustomerId }; var service = new SubscriptionService(); Subscription subscription = await service.CreateAsync(options); return(subscription); }
public async Task Create_SupplyValidData_ReturnResponseDto() { #region Arrange var message = new CreateSubscriptionRequestDto { Email = "*****@*****.**", Details = new List <SubscriptionDetailDto> { new SubscriptionDetailDto { Catalogue = "catalogue", Key = "item", Operator = "=", Value = "BMW" } } }; _mockSubscriptionRepository.Setup(x => x.CreateAsync(It.IsAny <Subscription>())).ReturnsAsync(Guid.NewGuid().ToString()); #endregion #region Act var result = await _subscriptionService.CreateAsync(message, It.IsAny <string>()); #endregion #region Assert Assert.NotNull(result); Assert.NotNull(result.SubscriptionId); _mockCacheProvider.Verify(c => c.AddOrUpdateItem(It.IsAny <string>(), It.IsAny <object>()), Times.Once); #endregion }
public async Task <IActionResult> Post([FromRoute] Guid id, [FromQuery] string token) { if (id != Guid.Empty) { var subscriptionType = await Db.SubscriptionTypes.FirstOrDefaultAsync(x => x.SubscriptionTypeId == id); if (subscriptionType == null) { return(Error("Subscription type not found", code: 404)); } var subscription = await Db.Subscriptions.FirstOrDefaultAsync(x => x.UserId == UserId); if (subscription != null) { if (subscription.SubscriptionTypeId == subscriptionType.SubscriptionTypeId) { return(Error("You have already this subscription.")); } return(Success("We will add this feature.")); } else { subscription = new MVDSubscription { SubscriptionId = Guid.NewGuid(), SubscriptionTypeId = subscriptionType.SubscriptionTypeId, UserId = UserId, StartDate = DateTime.UtcNow, EndDate = subscriptionType.IsPaid ? DateTime.UtcNow.AddMonths(1) : DateTime.MinValue, PaymentPeriod = MVDPaymentPeriodTypes.Monthly }; await Db.AddAsync(subscription); var features = await Db.SubscriptionTypeFeatures.Where(x => x.SubscriptionTypeId == subscriptionType.SubscriptionTypeId).ToListAsync(); foreach (var feature in features) { await Db.AddAsync(new MVDSubscriptionFeature { SubscriptionFeatureId = Guid.NewGuid(), SubscriptionId = subscription.SubscriptionId, SubscriptionTypeId = subscriptionType.SubscriptionTypeId, SubscriptionTypeFeatureId = feature.SubscriptionTypeFeatureId, Description = feature.Description, Name = feature.Name, Value = feature.Value, Title = feature.Title, ValueUsed = string.Empty, ValueRemained = string.Empty }); } } if (subscriptionType.Price > 0) { try { var user = await Db.Users.FirstOrDefaultAsync(x => x.Id == UserId); var customerService = new CustomerService(); var customerResult = await customerService.CreateAsync(new CustomerCreateOptions { Email = user.Email, SourceToken = token }); var items = new List <SubscriptionItemOption> { new SubscriptionItemOption { PlanId = subscriptionType.Name } }; var subscriptionService = new SubscriptionService(); var subscriptionOptions = new SubscriptionCreateOptions { CustomerId = customerResult.Id, Items = items }; var subscriptionResult = await subscriptionService.CreateAsync(subscriptionOptions); if (subscriptionResult.Status == "active") { var payment = new MVDPayment { PaymentId = Guid.NewGuid(), Provider = "stripe", SubscriptionId = subscription.SubscriptionId, UserId = UserId, Token = subscriptionResult.LatestInvoiceId, Amount = subscriptionType.Price, Currency = "usd", Date = DateTime.UtcNow, Description = $"{subscriptionType.Title} {subscriptionType.Description}", }; await Db.AddAsync(payment); } else { return(Error("Payment not completed.", code: 400)); } } catch (Exception ex) { return(Error("Payment error. Please check your credit card and details.", internalMessage: ex.Message, code: 400)); } } if (await Db.SaveChangesAsync() > 0) { return(Success("Your subscription has been updated.")); } return(Error("There is nothing to save.")); } return(Error("You must send subscription id.")); }
public async Task <ActionResult <ChangePlanResult> > ChangePlanAsync(string id, string planId, string stripeToken = null, string last4 = null, string couponId = null) { if (String.IsNullOrEmpty(id) || !CanAccessOrganization(id)) { return(NotFound()); } if (!_options.StripeOptions.EnableBilling) { return(Ok(ChangePlanResult.FailWithMessage("Plans cannot be changed while billing is disabled."))); } var organization = await GetModelAsync(id, false); if (organization == null) { return(Ok(ChangePlanResult.FailWithMessage("Invalid OrganizationId."))); } var plan = _billingManager.GetBillingPlan(planId); if (plan == null) { return(Ok(ChangePlanResult.FailWithMessage("Invalid PlanId."))); } if (String.Equals(organization.PlanId, plan.Id) && String.Equals(_plans.FreePlan.Id, plan.Id)) { return(Ok(ChangePlanResult.SuccessWithMessage("Your plan was not changed as you were already on the free plan."))); } // Only see if they can downgrade a plan if the plans are different. if (!String.Equals(organization.PlanId, plan.Id)) { var result = await _billingManager.CanDownGradeAsync(organization, plan, CurrentUser); if (!result.Success) { return(Ok(result)); } } var client = new StripeClient(_options.StripeOptions.StripeApiKey); var customerService = new CustomerService(client); var subscriptionService = new SubscriptionService(client); 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, _plans.FreePlan.Id) && String.Equals(plan.Id, _plans.FreePlan.Id)) { if (!String.IsNullOrEmpty(organization.StripeCustomerId)) { var subs = await subscriptionService.ListAsync(new SubscriptionListOptions { Customer = organization.StripeCustomerId }); foreach (var sub in subs.Where(s => !s.CanceledAt.HasValue)) { await subscriptionService.CancelAsync(sub.Id, new SubscriptionCancelOptions()); } } 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 CustomerCreateOptions { Source = stripeToken, Plan = planId, Description = organization.Name, Email = CurrentUser.EmailAddress }; if (!String.IsNullOrWhiteSpace(couponId)) { createCustomer.Coupon = couponId; } var customer = await customerService.CreateAsync(createCustomer); organization.BillingStatus = BillingStatus.Active; organization.RemoveSuspension(); organization.StripeCustomerId = customer.Id; if (customer.Sources.Data.Count > 0) { organization.CardLast4 = (customer.Sources.Data.First() as Card)?.Last4; } } else { var update = new SubscriptionUpdateOptions { Items = new List <SubscriptionItemOptions>() }; var create = new SubscriptionCreateOptions { Customer = organization.StripeCustomerId, Items = new List <SubscriptionItemOptions>() }; bool cardUpdated = false; var customerUpdateOptions = new CustomerUpdateOptions { Description = organization.Name, Email = CurrentUser.EmailAddress }; if (!String.IsNullOrEmpty(stripeToken)) { customerUpdateOptions.Source = stripeToken; cardUpdated = true; } await customerService.UpdateAsync(organization.StripeCustomerId, customerUpdateOptions); var subscriptionList = await subscriptionService.ListAsync(new SubscriptionListOptions { Customer = organization.StripeCustomerId }); var subscription = subscriptionList.FirstOrDefault(s => !s.CanceledAt.HasValue); if (subscription != null) { update.Items.Add(new SubscriptionItemOptions { Id = subscription.Items.Data[0].Id, Plan = planId }); await subscriptionService.UpdateAsync(subscription.Id, update); } else { create.Items.Add(new SubscriptionItemOptions { Plan = planId }); await subscriptionService.CreateAsync(create); } if (cardUpdated) { organization.CardLast4 = last4; } organization.BillingStatus = BillingStatus.Active; organization.RemoveSuspension(); } _billingManager.ApplyBillingPlan(organization, plan, CurrentUser); await _repository.SaveAsync(organization, o => o.Cache()); await _messagePublisher.PublishAsync(new PlanChanged { OrganizationId = organization.Id }); } catch (Exception ex) { using (_logger.BeginScope(new ExceptionlessState().Tag("Change Plan").Identity(CurrentUser.EmailAddress).Property("User", CurrentUser).SetHttpContext(HttpContext))) _logger.LogCritical(ex, "An error occurred while trying to update your billing plan: {Message}", ex.Message); return(Ok(ChangePlanResult.FailWithMessage(ex.Message))); } return(Ok(new ChangePlanResult { Success = true })); }
public async Task <string> CreateACustomerSubcription(string customerId) { try { StripeConfiguration.ApiKey = this._configuration.GetSection("Stripe")["SecretKey"]; //================================================================== // Create Product Subcription var productoptions = new ProductCreateOptions { Name = "Quick Order Subcription", Active = true, Description = "Quick Order Admin System Subcription", Type = "service" }; var productservice = new ProductService(); var producttoken = await productservice.CreateAsync(productoptions); var priceoptions = new PriceCreateOptions { UnitAmount = 200, Currency = "usd", Recurring = new PriceRecurringOptions { Interval = "month", }, Product = producttoken.Id, }; var priceservice = new PriceService(); var priceservicetoken = await priceservice.CreateAsync(priceoptions); //======================================================================= End Create Product Subcription //=================================================================================== //Create Subcription to store var options = new SubscriptionCreateOptions { Customer = customerId, Items = new List <SubscriptionItemOptions> { new SubscriptionItemOptions { Price = priceservicetoken.Id, }, }, }; var service = new SubscriptionService(); Subscription subscription = await service.CreateAsync(options); if (!string.IsNullOrEmpty(subscription.Id)) { //var newSubcription = new Subcription() //{ // StripeCustomerId = customerId, // StripeSubCriptionID = subscription.Id //}; //_context.Subcriptions.Add(newSubcription); //try //{ //_context.SaveChanges(); //} //catch (Exception e) //{ // Console.WriteLine(e); //} return(subscription.Id); } else { return(string.Empty); } } catch (Exception e) { Console.WriteLine(e); return(string.Empty); } }
public async Task PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType, string paymentToken, Models.StaticStore.Plan plan, short additionalStorageGb, short additionalSeats, bool premiumAccessAddon) { var invoiceService = new InvoiceService(); var customerService = new CustomerService(); Braintree.Customer braintreeCustomer = null; string stipeCustomerSourceToken = null; var stripeCustomerMetadata = new Dictionary <string, string>(); var stripePaymentMethod = paymentMethodType == PaymentMethodType.Card || paymentMethodType == PaymentMethodType.BankAccount; if (stripePaymentMethod) { stipeCustomerSourceToken = paymentToken; } else if (paymentMethodType == PaymentMethodType.PayPal) { var randomSuffix = Utilities.CoreHelpers.RandomString(3, upper: false, numeric: false); var customerResult = await _btGateway.Customer.CreateAsync(new Braintree.CustomerRequest { PaymentMethodNonce = paymentToken, Email = org.BillingEmail, Id = org.BraintreeCustomerIdPrefix() + org.Id.ToString("N").ToLower() + randomSuffix, CustomFields = new Dictionary <string, string> { [org.BraintreeIdField()] = org.Id.ToString() } }); if (!customerResult.IsSuccess() || customerResult.Target.PaymentMethods.Length == 0) { throw new GatewayException("Failed to create PayPal customer record."); } braintreeCustomer = customerResult.Target; stripeCustomerMetadata.Add("btCustomerId", braintreeCustomer.Id); } else { throw new GatewayException("Payment method is not supported at this time."); } var subCreateOptions = new SubscriptionCreateOptions { TrialPeriodDays = plan.TrialPeriodDays, Items = new List <SubscriptionItemOption>(), Metadata = new Dictionary <string, string> { [org.GatewayIdField()] = org.Id.ToString() } }; if (plan.StripePlanId != null) { subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = plan.StripePlanId, Quantity = 1 }); } if (additionalSeats > 0 && plan.StripeSeatPlanId != null) { subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = plan.StripeSeatPlanId, Quantity = additionalSeats }); } if (additionalStorageGb > 0) { subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = plan.StripeStoragePlanId, Quantity = additionalStorageGb }); } if (premiumAccessAddon && plan.StripePremiumAccessPlanId != null) { subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = plan.StripePremiumAccessPlanId, Quantity = 1 }); } Customer customer = null; Subscription subscription = null; try { customer = await customerService.CreateAsync(new CustomerCreateOptions { Description = org.BusinessName, Email = org.BillingEmail, SourceToken = stipeCustomerSourceToken, Metadata = stripeCustomerMetadata }); subCreateOptions.CustomerId = customer.Id; var subscriptionService = new SubscriptionService(); subscription = await subscriptionService.CreateAsync(subCreateOptions); } catch (Exception e) { if (customer != null) { await customerService.DeleteAsync(customer.Id); } if (braintreeCustomer != null) { await _btGateway.Customer.DeleteAsync(braintreeCustomer.Id); } throw e; } org.Gateway = GatewayType.Stripe; org.GatewayCustomerId = customer.Id; org.GatewaySubscriptionId = subscription.Id; org.ExpirationDate = subscription.CurrentPeriodEnd; }
public async Task PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken, short additionalStorageGb) { var invoiceService = new InvoiceService(); var customerService = new CustomerService(); var createdStripeCustomer = false; string stripeCustomerId = null; Braintree.Transaction braintreeTransaction = null; Braintree.Customer braintreeCustomer = null; var stripePaymentMethod = paymentMethodType == PaymentMethodType.Card || paymentMethodType == PaymentMethodType.BankAccount; if (paymentMethodType == PaymentMethodType.BankAccount) { throw new GatewayException("Bank account payment method is not supported at this time."); } if (user.Gateway == GatewayType.Stripe && !string.IsNullOrWhiteSpace(user.GatewayCustomerId)) { try { await UpdatePaymentMethodAsync(user, paymentMethodType, paymentToken); stripeCustomerId = user.GatewayCustomerId; createdStripeCustomer = false; } catch (Exception) { stripeCustomerId = null; } } if (string.IsNullOrWhiteSpace(stripeCustomerId)) { string stipeCustomerSourceToken = null; var stripeCustomerMetadata = new Dictionary <string, string>(); if (stripePaymentMethod) { stipeCustomerSourceToken = paymentToken; } else if (paymentMethodType == PaymentMethodType.PayPal) { var randomSuffix = Utilities.CoreHelpers.RandomString(3, upper: false, numeric: false); var customerResult = await _btGateway.Customer.CreateAsync(new Braintree.CustomerRequest { PaymentMethodNonce = paymentToken, Email = user.Email, Id = user.BraintreeCustomerIdPrefix() + user.Id.ToString("N").ToLower() + randomSuffix, CustomFields = new Dictionary <string, string> { [user.BraintreeIdField()] = user.Id.ToString() } }); if (!customerResult.IsSuccess() || customerResult.Target.PaymentMethods.Length == 0) { throw new GatewayException("Failed to create PayPal customer record."); } braintreeCustomer = customerResult.Target; stripeCustomerMetadata.Add("btCustomerId", braintreeCustomer.Id); } else { throw new GatewayException("Payment method is not supported at this time."); } var customer = await customerService.CreateAsync(new CustomerCreateOptions { Description = user.Name, Email = user.Email, SourceToken = stipeCustomerSourceToken, Metadata = stripeCustomerMetadata }); stripeCustomerId = customer.Id; createdStripeCustomer = true; } var subCreateOptions = new SubscriptionCreateOptions { CustomerId = stripeCustomerId, Items = new List <SubscriptionItemOption>(), Metadata = new Dictionary <string, string> { [user.GatewayIdField()] = user.Id.ToString() } }; subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = PremiumPlanId, Quantity = 1, }); if (additionalStorageGb > 0) { subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = StoragePlanId, Quantity = additionalStorageGb }); } var subInvoiceMetadata = new Dictionary <string, string>(); Subscription subscription = null; try { if (!stripePaymentMethod) { var previewInvoice = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions { CustomerId = stripeCustomerId, SubscriptionItems = ToInvoiceSubscriptionItemOptions(subCreateOptions.Items) }); await customerService.UpdateAsync(stripeCustomerId, new CustomerUpdateOptions { AccountBalance = -1 * previewInvoice.AmountDue }); if (braintreeCustomer != null) { var btInvoiceAmount = (previewInvoice.AmountDue / 100M); var transactionResult = await _btGateway.Transaction.SaleAsync( new Braintree.TransactionRequest { Amount = btInvoiceAmount, CustomerId = braintreeCustomer.Id, Options = new Braintree.TransactionOptionsRequest { SubmitForSettlement = true, PayPal = new Braintree.TransactionOptionsPayPalRequest { CustomField = $"{user.BraintreeIdField()}:{user.Id}" } }, CustomFields = new Dictionary <string, string> { [user.BraintreeIdField()] = user.Id.ToString() } }); if (!transactionResult.IsSuccess()) { throw new GatewayException("Failed to charge PayPal customer."); } braintreeTransaction = transactionResult.Target; subInvoiceMetadata.Add("btTransactionId", braintreeTransaction.Id); subInvoiceMetadata.Add("btPayPalTransactionId", braintreeTransaction.PayPalDetails.AuthorizationId); } else { throw new GatewayException("No payment was able to be collected."); } } var subscriptionService = new SubscriptionService(); subscription = await subscriptionService.CreateAsync(subCreateOptions); if (!stripePaymentMethod && subInvoiceMetadata.Any()) { var invoices = await invoiceService.ListAsync(new InvoiceListOptions { SubscriptionId = subscription.Id }); var invoice = invoices?.FirstOrDefault(); if (invoice == null) { throw new GatewayException("Invoice not found."); } await invoiceService.UpdateAsync(invoice.Id, new InvoiceUpdateOptions { Metadata = subInvoiceMetadata }); } } catch (Exception e) { if (createdStripeCustomer && !string.IsNullOrWhiteSpace(stripeCustomerId)) { await customerService.DeleteAsync(stripeCustomerId); } if (braintreeTransaction != null) { await _btGateway.Transaction.RefundAsync(braintreeTransaction.Id); } if (braintreeCustomer != null) { await _btGateway.Customer.DeleteAsync(braintreeCustomer.Id); } throw e; } user.Gateway = GatewayType.Stripe; user.GatewayCustomerId = stripeCustomerId; user.GatewaySubscriptionId = subscription.Id; user.Premium = true; user.PremiumExpirationDate = subscription.CurrentPeriodEnd; }