From bc5322f4cfbc38d2ce124b2761080f4b2aaa4be0 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Sat, 10 Aug 2019 11:58:44 -0400 Subject: [PATCH] support for payment intent/method on org signup --- src/Core/Services/IPaymentService.cs | 5 ++- .../Implementations/StripePaymentService.cs | 38 +++++++++++++++++-- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/Core/Services/IPaymentService.cs b/src/Core/Services/IPaymentService.cs index 11e7af3d3a..952c2fd34e 100644 --- a/src/Core/Services/IPaymentService.cs +++ b/src/Core/Services/IPaymentService.cs @@ -8,8 +8,9 @@ namespace Bit.Core.Services public interface IPaymentService { Task CancelAndRecoverChargesAsync(ISubscriber subscriber); - Task PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType, string paymentToken, - Models.StaticStore.Plan plan, short additionalStorageGb, short additionalSeats, bool premiumAccessAddon); + Task PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType, + string paymentToken, Models.StaticStore.Plan plan, short additionalStorageGb, short additionalSeats, + bool premiumAccessAddon); Task UpgradeFreeOrganizationAsync(Organization org, Models.StaticStore.Plan plan, short additionalStorageGb, short additionalSeats, bool premiumAccessAddon); Task PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken, diff --git a/src/Core/Services/Implementations/StripePaymentService.cs b/src/Core/Services/Implementations/StripePaymentService.cs index fed1dbc622..98db411927 100644 --- a/src/Core/Services/Implementations/StripePaymentService.cs +++ b/src/Core/Services/Implementations/StripePaymentService.cs @@ -38,7 +38,7 @@ namespace Bit.Core.Services _logger = logger; } - public async Task PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType, + public async Task PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType, string paymentToken, Models.StaticStore.Plan plan, short additionalStorageGb, short additionalSeats, bool premiumAccessAddon) { @@ -46,13 +46,21 @@ namespace Bit.Core.Services Braintree.Customer braintreeCustomer = null; string stipeCustomerSourceToken = null; + string stipeCustomerPaymentMethodId = null; var stripeCustomerMetadata = new Dictionary(); var stripePaymentMethod = paymentMethodType == PaymentMethodType.Card || paymentMethodType == PaymentMethodType.BankAccount; if(stripePaymentMethod) { - stipeCustomerSourceToken = paymentToken; + if(paymentToken.StartsWith("pm_")) + { + stipeCustomerPaymentMethodId = paymentToken; + } + else + { + stipeCustomerSourceToken = paymentToken; + } } else if(paymentMethodType == PaymentMethodType.PayPal) { @@ -84,6 +92,7 @@ namespace Bit.Core.Services var subCreateOptions = new SubscriptionCreateOptions { TrialPeriodDays = plan.TrialPeriodDays, + DefaultPaymentMethodId = stipeCustomerPaymentMethodId, Items = new List(), Metadata = new Dictionary { @@ -136,11 +145,20 @@ namespace Bit.Core.Services Description = org.BusinessName, Email = org.BillingEmail, Source = stipeCustomerSourceToken, + PaymentMethodId = stipeCustomerPaymentMethodId, Metadata = stripeCustomerMetadata }); subCreateOptions.CustomerId = customer.Id; var subscriptionService = new SubscriptionService(); subscription = await subscriptionService.CreateAsync(subCreateOptions); + if(subscription.Status == "incomplete" && subscription.LatestInvoice?.PaymentIntent != null) + { + if(subscription.LatestInvoice.PaymentIntent.Status == "requires_payment_method") + { + await subscriptionService.CancelAsync(subscription.Id, new SubscriptionCancelOptions()); + throw new GatewayException("Payment method was declined."); + } + } } catch(Exception e) { @@ -158,7 +176,19 @@ namespace Bit.Core.Services org.Gateway = GatewayType.Stripe; org.GatewayCustomerId = customer.Id; org.GatewaySubscriptionId = subscription.Id; - org.ExpirationDate = subscription.CurrentPeriodEnd; + + if(subscription.Status == "incomplete" && + subscription.LatestInvoice?.PaymentIntent?.Status == "requires_action") + { + org.Enabled = false; + return subscription.LatestInvoice.PaymentIntent.ClientSecret; + } + else + { + org.Enabled = true; + org.ExpirationDate = subscription.CurrentPeriodEnd; + return null; + } } public async Task UpgradeFreeOrganizationAsync(Organization org, Models.StaticStore.Plan plan, @@ -514,7 +544,7 @@ namespace Bit.Core.Services if(subscription.LatestInvoice.PaymentIntent.Status == "requires_payment_method") { await subscriptionService.CancelAsync(subscription.Id, new SubscriptionCancelOptions()); - throw new GatewayException("Payment method failed."); + throw new GatewayException("Payment method was declined."); } }