1
0
mirror of https://github.com/bitwarden/server.git synced 2025-05-20 11:04:31 -05:00

fix paypal edge case

This commit is contained in:
Kyle Spearrin 2019-02-23 17:40:46 -05:00
parent 2f5410de28
commit b5782f7b72

View File

@ -183,7 +183,8 @@ namespace Bit.Core.Services
var customerService = new CustomerService(); var customerService = new CustomerService();
var createdStripeCustomer = false; var createdStripeCustomer = false;
string stripeCustomerId = null; var addedCreditToStripeCustomer = false;
Customer customer = null;
Braintree.Transaction braintreeTransaction = null; Braintree.Transaction braintreeTransaction = null;
Braintree.Customer braintreeCustomer = null; Braintree.Customer braintreeCustomer = null;
var stripePaymentMethod = paymentMethodType == PaymentMethodType.Card || var stripePaymentMethod = paymentMethodType == PaymentMethodType.Card ||
@ -197,16 +198,16 @@ namespace Bit.Core.Services
{ {
await UpdatePaymentMethodAsync(user, paymentMethodType, paymentToken); await UpdatePaymentMethodAsync(user, paymentMethodType, paymentToken);
} }
catch catch { }
{
stripeCustomerId = null;
}
} }
stripeCustomerId = user.GatewayCustomerId; try
createdStripeCustomer = false; {
customer = await customerService.GetAsync(user.GatewayCustomerId);
}
catch { }
} }
if(string.IsNullOrWhiteSpace(stripeCustomerId) && !string.IsNullOrWhiteSpace(paymentToken)) if(customer == null && !string.IsNullOrWhiteSpace(paymentToken))
{ {
string stipeCustomerSourceToken = null; string stipeCustomerSourceToken = null;
var stripeCustomerMetadata = new Dictionary<string, string>(); var stripeCustomerMetadata = new Dictionary<string, string>();
@ -242,20 +243,24 @@ namespace Bit.Core.Services
throw new GatewayException("Payment method is not supported at this time."); throw new GatewayException("Payment method is not supported at this time.");
} }
var customer = await customerService.CreateAsync(new CustomerCreateOptions customer = await customerService.CreateAsync(new CustomerCreateOptions
{ {
Description = user.Name, Description = user.Name,
Email = user.Email, Email = user.Email,
SourceToken = stipeCustomerSourceToken, SourceToken = stipeCustomerSourceToken,
Metadata = stripeCustomerMetadata Metadata = stripeCustomerMetadata
}); });
stripeCustomerId = customer.Id;
createdStripeCustomer = true; createdStripeCustomer = true;
} }
if(customer == null)
{
throw new GatewayException("Could not set up customer payment profile.");
}
var subCreateOptions = new SubscriptionCreateOptions var subCreateOptions = new SubscriptionCreateOptions
{ {
CustomerId = stripeCustomerId, CustomerId = customer.Id,
Items = new List<SubscriptionItemOption>(), Items = new List<SubscriptionItemOption>(),
Metadata = new Dictionary<string, string> Metadata = new Dictionary<string, string>
{ {
@ -286,57 +291,63 @@ namespace Bit.Core.Services
{ {
var previewInvoice = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions var previewInvoice = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions
{ {
CustomerId = stripeCustomerId, CustomerId = customer.Id,
SubscriptionItems = ToInvoiceSubscriptionItemOptions(subCreateOptions.Items) SubscriptionItems = ToInvoiceSubscriptionItemOptions(subCreateOptions.Items)
}); });
await customerService.UpdateAsync(stripeCustomerId, new CustomerUpdateOptions if(previewInvoice.AmountDue > 0)
{ {
AccountBalance = -1 * previewInvoice.AmountDue var braintreeCustomerId = customer.Metadata != null &&
}); customer.Metadata.ContainsKey("btCustomerId") ? customer.Metadata["btCustomerId"] : null;
if(!string.IsNullOrWhiteSpace(braintreeCustomerId))
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."); var btInvoiceAmount = (previewInvoice.AmountDue / 100M);
} var transactionResult = await _btGateway.Transaction.SaleAsync(
new Braintree.TransactionRequest
{
Amount = btInvoiceAmount,
CustomerId = braintreeCustomerId,
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()
}
});
braintreeTransaction = transactionResult.Target; if(!transactionResult.IsSuccess())
subInvoiceMetadata.Add("btTransactionId", braintreeTransaction.Id); {
subInvoiceMetadata.Add("btPayPalTransactionId", throw new GatewayException("Failed to charge PayPal customer.");
braintreeTransaction.PayPalDetails.AuthorizationId); }
}
else braintreeTransaction = transactionResult.Target;
{ subInvoiceMetadata.Add("btTransactionId", braintreeTransaction.Id);
throw new GatewayException("No payment was able to be collected."); subInvoiceMetadata.Add("btPayPalTransactionId",
braintreeTransaction.PayPalDetails.AuthorizationId);
await customerService.UpdateAsync(customer.Id, new CustomerUpdateOptions
{
AccountBalance = -1 * previewInvoice.AmountDue
});
addedCreditToStripeCustomer = true;
}
else
{
throw new GatewayException("No payment was able to be collected.");
}
} }
} }
else if(paymentMethodType == PaymentMethodType.Credit) else if(paymentMethodType == PaymentMethodType.Credit)
{ {
var previewInvoice = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions var previewInvoice = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions
{ {
CustomerId = stripeCustomerId, CustomerId = customer.Id,
SubscriptionItems = ToInvoiceSubscriptionItemOptions(subCreateOptions.Items) SubscriptionItems = ToInvoiceSubscriptionItemOptions(subCreateOptions.Items)
}); });
if(previewInvoice.AmountDue > 0) if(previewInvoice.AmountDue > 0)
@ -369,9 +380,19 @@ namespace Bit.Core.Services
} }
catch(Exception e) catch(Exception e)
{ {
if(createdStripeCustomer && !string.IsNullOrWhiteSpace(stripeCustomerId)) if(customer != null)
{ {
await customerService.DeleteAsync(stripeCustomerId); if(createdStripeCustomer)
{
await customerService.DeleteAsync(customer.Id);
}
else if(addedCreditToStripeCustomer)
{
await customerService.UpdateAsync(customer.Id, new CustomerUpdateOptions
{
AccountBalance = customer.AccountBalance
});
}
} }
if(braintreeTransaction != null) if(braintreeTransaction != null)
{ {
@ -385,7 +406,7 @@ namespace Bit.Core.Services
} }
user.Gateway = GatewayType.Stripe; user.Gateway = GatewayType.Stripe;
user.GatewayCustomerId = stripeCustomerId; user.GatewayCustomerId = customer.Id;
user.GatewaySubscriptionId = subscription.Id; user.GatewaySubscriptionId = subscription.Id;
user.Premium = true; user.Premium = true;
user.PremiumExpirationDate = subscription.CurrentPeriodEnd; user.PremiumExpirationDate = subscription.CurrentPeriodEnd;