1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-09 15:18:13 -05:00

support for payment intent/method on org signup

This commit is contained in:
Kyle Spearrin 2019-08-10 11:58:44 -04:00
parent 00e808d731
commit bc5322f4cf
2 changed files with 37 additions and 6 deletions

View File

@ -8,8 +8,9 @@ namespace Bit.Core.Services
public interface IPaymentService public interface IPaymentService
{ {
Task CancelAndRecoverChargesAsync(ISubscriber subscriber); Task CancelAndRecoverChargesAsync(ISubscriber subscriber);
Task PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType, string paymentToken, Task<string> PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType,
Models.StaticStore.Plan plan, short additionalStorageGb, short additionalSeats, bool premiumAccessAddon); string paymentToken, Models.StaticStore.Plan plan, short additionalStorageGb, short additionalSeats,
bool premiumAccessAddon);
Task<string> UpgradeFreeOrganizationAsync(Organization org, Models.StaticStore.Plan plan, Task<string> UpgradeFreeOrganizationAsync(Organization org, Models.StaticStore.Plan plan,
short additionalStorageGb, short additionalSeats, bool premiumAccessAddon); short additionalStorageGb, short additionalSeats, bool premiumAccessAddon);
Task<string> PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken, Task<string> PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken,

View File

@ -38,7 +38,7 @@ namespace Bit.Core.Services
_logger = logger; _logger = logger;
} }
public async Task PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType, public async Task<string> PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType,
string paymentToken, Models.StaticStore.Plan plan, short additionalStorageGb, string paymentToken, Models.StaticStore.Plan plan, short additionalStorageGb,
short additionalSeats, bool premiumAccessAddon) short additionalSeats, bool premiumAccessAddon)
{ {
@ -46,13 +46,21 @@ namespace Bit.Core.Services
Braintree.Customer braintreeCustomer = null; Braintree.Customer braintreeCustomer = null;
string stipeCustomerSourceToken = null; string stipeCustomerSourceToken = null;
string stipeCustomerPaymentMethodId = null;
var stripeCustomerMetadata = new Dictionary<string, string>(); var stripeCustomerMetadata = new Dictionary<string, string>();
var stripePaymentMethod = paymentMethodType == PaymentMethodType.Card || var stripePaymentMethod = paymentMethodType == PaymentMethodType.Card ||
paymentMethodType == PaymentMethodType.BankAccount; paymentMethodType == PaymentMethodType.BankAccount;
if(stripePaymentMethod) if(stripePaymentMethod)
{ {
stipeCustomerSourceToken = paymentToken; if(paymentToken.StartsWith("pm_"))
{
stipeCustomerPaymentMethodId = paymentToken;
}
else
{
stipeCustomerSourceToken = paymentToken;
}
} }
else if(paymentMethodType == PaymentMethodType.PayPal) else if(paymentMethodType == PaymentMethodType.PayPal)
{ {
@ -84,6 +92,7 @@ namespace Bit.Core.Services
var subCreateOptions = new SubscriptionCreateOptions var subCreateOptions = new SubscriptionCreateOptions
{ {
TrialPeriodDays = plan.TrialPeriodDays, TrialPeriodDays = plan.TrialPeriodDays,
DefaultPaymentMethodId = stipeCustomerPaymentMethodId,
Items = new List<SubscriptionItemOption>(), Items = new List<SubscriptionItemOption>(),
Metadata = new Dictionary<string, string> Metadata = new Dictionary<string, string>
{ {
@ -136,11 +145,20 @@ namespace Bit.Core.Services
Description = org.BusinessName, Description = org.BusinessName,
Email = org.BillingEmail, Email = org.BillingEmail,
Source = stipeCustomerSourceToken, Source = stipeCustomerSourceToken,
PaymentMethodId = stipeCustomerPaymentMethodId,
Metadata = stripeCustomerMetadata Metadata = stripeCustomerMetadata
}); });
subCreateOptions.CustomerId = customer.Id; subCreateOptions.CustomerId = customer.Id;
var subscriptionService = new SubscriptionService(); var subscriptionService = new SubscriptionService();
subscription = await subscriptionService.CreateAsync(subCreateOptions); 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) catch(Exception e)
{ {
@ -158,7 +176,19 @@ namespace Bit.Core.Services
org.Gateway = GatewayType.Stripe; org.Gateway = GatewayType.Stripe;
org.GatewayCustomerId = customer.Id; org.GatewayCustomerId = customer.Id;
org.GatewaySubscriptionId = subscription.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<string> UpgradeFreeOrganizationAsync(Organization org, Models.StaticStore.Plan plan, public async Task<string> UpgradeFreeOrganizationAsync(Organization org, Models.StaticStore.Plan plan,
@ -514,7 +544,7 @@ namespace Bit.Core.Services
if(subscription.LatestInvoice.PaymentIntent.Status == "requires_payment_method") if(subscription.LatestInvoice.PaymentIntent.Status == "requires_payment_method")
{ {
await subscriptionService.CancelAsync(subscription.Id, new SubscriptionCancelOptions()); await subscriptionService.CancelAsync(subscription.Id, new SubscriptionCancelOptions());
throw new GatewayException("Payment method failed."); throw new GatewayException("Payment method was declined.");
} }
} }