1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-21 04:55:08 -05:00

upgrade stripe lib and breaking changes

This commit is contained in:
Kyle Spearrin 2019-01-29 14:41:37 -05:00
parent e54a381dba
commit a34ca4700d
6 changed files with 163 additions and 170 deletions

View File

@ -110,7 +110,7 @@ namespace Bit.Api.Controllers
try try
{ {
var invoice = await new StripeInvoiceService().GetAsync(invoiceId); var invoice = await new InvoiceService().GetAsync(invoiceId);
if(invoice != null && invoice.CustomerId == organization.GatewayCustomerId && if(invoice != null && invoice.CustomerId == organization.GatewayCustomerId &&
!string.IsNullOrWhiteSpace(invoice.HostedInvoiceUrl)) !string.IsNullOrWhiteSpace(invoice.HostedInvoiceUrl))
{ {

View File

@ -47,11 +47,11 @@ namespace Bit.Billing.Controllers
return new BadRequestResult(); return new BadRequestResult();
} }
StripeEvent parsedEvent; Stripe.Event parsedEvent;
using(var sr = new StreamReader(HttpContext.Request.Body)) using(var sr = new StreamReader(HttpContext.Request.Body))
{ {
var json = await sr.ReadToEndAsync(); var json = await sr.ReadToEndAsync();
parsedEvent = StripeEventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], parsedEvent = EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"],
_billingSettings.StripeWebhookSecret); _billingSettings.StripeWebhookSecret);
} }
@ -60,7 +60,7 @@ namespace Bit.Billing.Controllers
return new BadRequestResult(); return new BadRequestResult();
} }
if(_hostingEnvironment.IsProduction() && !parsedEvent.LiveMode) if(_hostingEnvironment.IsProduction() && !parsedEvent.Livemode)
{ {
return new BadRequestResult(); return new BadRequestResult();
} }
@ -71,8 +71,7 @@ namespace Bit.Billing.Controllers
if(subDeleted || subUpdated) if(subDeleted || subUpdated)
{ {
StripeSubscription subscription = Mapper<StripeSubscription>.MapFromJson( var subscription = parsedEvent.Data.Object as Subscription;
parsedEvent.Data.Object.ToString());
if(subscription == null) if(subscription == null)
{ {
throw new Exception("Subscription is null."); throw new Exception("Subscription is null.");
@ -115,14 +114,13 @@ namespace Bit.Billing.Controllers
} }
else if(invUpcoming) else if(invUpcoming)
{ {
StripeInvoice invoice = Mapper<StripeInvoice>.MapFromJson( var invoice = parsedEvent.Data.Object as Invoice;
parsedEvent.Data.Object.ToString());
if(invoice == null) if(invoice == null)
{ {
throw new Exception("Invoice is null."); throw new Exception("Invoice is null.");
} }
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
var subscription = await subscriptionService.GetAsync(invoice.SubscriptionId); var subscription = await subscriptionService.GetAsync(invoice.SubscriptionId);
if(subscription == null) if(subscription == null)
{ {
@ -152,7 +150,7 @@ namespace Bit.Billing.Controllers
if(!string.IsNullOrWhiteSpace(email) && invoice.NextPaymentAttempt.HasValue) if(!string.IsNullOrWhiteSpace(email) && invoice.NextPaymentAttempt.HasValue)
{ {
var items = invoice.StripeInvoiceLineItems.Select(i => i.Description).ToList(); var items = invoice.Lines.Select(i => i.Description).ToList();
await _mailService.SendInvoiceUpcomingAsync(email, invoice.AmountDue / 100M, await _mailService.SendInvoiceUpcomingAsync(email, invoice.AmountDue / 100M,
invoice.NextPaymentAttempt.Value, items, ids.Item1.HasValue); invoice.NextPaymentAttempt.Value, items, ids.Item1.HasValue);
} }

View File

@ -38,7 +38,7 @@
<PackageReference Include="AspNetCoreRateLimit" Version="2.1.0" /> <PackageReference Include="AspNetCoreRateLimit" Version="2.1.0" />
<PackageReference Include="Braintree" Version="4.6.0" /> <PackageReference Include="Braintree" Version="4.6.0" />
<PackageReference Include="Sendgrid" Version="9.10.0" /> <PackageReference Include="Sendgrid" Version="9.10.0" />
<PackageReference Include="Stripe.net" Version="19.10.0" /> <PackageReference Include="Stripe.net" Version="22.8.0" />
<PackageReference Include="U2F.Core" Version="1.0.4" /> <PackageReference Include="U2F.Core" Version="1.0.4" />
<PackageReference Include="Otp.NET" Version="1.2.0" /> <PackageReference Include="Otp.NET" Version="1.2.0" />
<PackageReference Include="YubicoDotNetClient" Version="1.2.0" /> <PackageReference Include="YubicoDotNetClient" Version="1.2.0" />

View File

@ -1,5 +1,4 @@
using Bit.Core.Enums; using Bit.Core.Enums;
using Braintree;
using Stripe; using Stripe;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -16,40 +15,37 @@ namespace Bit.Core.Models.Business
public class BillingSource public class BillingSource
{ {
public BillingSource(Source source) public BillingSource(IPaymentSource source)
{ {
switch(source.Type) if(source is BankAccount bankAccount)
{ {
case SourceType.Card:
Type = PaymentMethodType.Card;
Description = $"{source.Card.Brand}, *{source.Card.Last4}, " +
string.Format("{0}/{1}",
string.Concat(source.Card.ExpirationMonth < 10 ?
"0" : string.Empty, source.Card.ExpirationMonth),
source.Card.ExpirationYear);
CardBrand = source.Card.Brand;
break;
case SourceType.BankAccount:
Type = PaymentMethodType.BankAccount; Type = PaymentMethodType.BankAccount;
Description = $"{source.BankAccount.BankName}, *{source.BankAccount.Last4} - " + Description = $"{bankAccount.BankName}, *{bankAccount.Last4} - " +
(source.BankAccount.Status == "verified" ? "verified" : (bankAccount.Status == "verified" ? "verified" :
source.BankAccount.Status == "errored" ? "invalid" : bankAccount.Status == "errored" ? "invalid" :
source.BankAccount.Status == "verification_failed" ? "verification failed" : "unverified"); bankAccount.Status == "verification_failed" ? "verification failed" : "unverified");
NeedsVerification = source.BankAccount.Status == "new" || source.BankAccount.Status == "validated"; NeedsVerification = bankAccount.Status == "new" || bankAccount.Status == "validated";
break; }
default: else if(source is Card card)
break; {
Type = PaymentMethodType.Card;
Description = $"{card.Brand}, *{card.Last4}, " +
string.Format("{0}/{1}",
string.Concat(card.ExpMonth < 10 ?
"0" : string.Empty, card.ExpMonth),
card.ExpYear);
CardBrand = card.Brand;
} }
} }
public BillingSource(PaymentMethod method) public BillingSource(Braintree.PaymentMethod method)
{ {
if(method is PayPalAccount paypal) if(method is Braintree.PayPalAccount paypal)
{ {
Type = PaymentMethodType.PayPal; Type = PaymentMethodType.PayPal;
Description = paypal.Email; Description = paypal.Email;
} }
else if(method is CreditCard card) else if(method is Braintree.CreditCard card)
{ {
Type = PaymentMethodType.Card; Type = PaymentMethodType.Card;
Description = $"{card.CardType.ToString()}, *{card.LastFour}, " + Description = $"{card.CardType.ToString()}, *{card.LastFour}, " +
@ -59,7 +55,7 @@ namespace Bit.Core.Models.Business
card.ExpirationYear); card.ExpirationYear);
CardBrand = card.CardType.ToString(); CardBrand = card.CardType.ToString();
} }
else if(method is UsBankAccount bank) else if(method is Braintree.UsBankAccount bank)
{ {
Type = PaymentMethodType.BankAccount; Type = PaymentMethodType.BankAccount;
Description = $"{bank.BankName}, *{bank.Last4}"; Description = $"{bank.BankName}, *{bank.Last4}";
@ -70,13 +66,13 @@ namespace Bit.Core.Models.Business
} }
} }
public BillingSource(UsBankAccountDetails bank) public BillingSource(Braintree.UsBankAccountDetails bank)
{ {
Type = PaymentMethodType.BankAccount; Type = PaymentMethodType.BankAccount;
Description = $"{bank.BankName}, *{bank.Last4}"; Description = $"{bank.BankName}, *{bank.Last4}";
} }
public BillingSource(PayPalDetails paypal) public BillingSource(Braintree.PayPalDetails paypal)
{ {
Type = PaymentMethodType.PayPal; Type = PaymentMethodType.PayPal;
Description = paypal.PayerEmail; Description = paypal.PayerEmail;
@ -90,7 +86,7 @@ namespace Bit.Core.Models.Business
public class BillingSubscription public class BillingSubscription
{ {
public BillingSubscription(StripeSubscription sub) public BillingSubscription(Subscription sub)
{ {
Status = sub.Status; Status = sub.Status;
TrialStartDate = sub.TrialStart; TrialStartDate = sub.TrialStart;
@ -106,14 +102,14 @@ namespace Bit.Core.Models.Business
} }
} }
public BillingSubscription(Subscription sub, Plan plan) public BillingSubscription(Braintree.Subscription sub, Braintree.Plan plan)
{ {
Status = sub.Status.ToString(); Status = sub.Status.ToString();
if(sub.HasTrialPeriod.GetValueOrDefault() && sub.CreatedAt.HasValue && sub.TrialDuration.HasValue) if(sub.HasTrialPeriod.GetValueOrDefault() && sub.CreatedAt.HasValue && sub.TrialDuration.HasValue)
{ {
TrialStartDate = sub.CreatedAt.Value; TrialStartDate = sub.CreatedAt.Value;
if(sub.TrialDurationUnit == SubscriptionDurationUnit.DAY) if(sub.TrialDurationUnit == Braintree.SubscriptionDurationUnit.DAY)
{ {
TrialEndDate = TrialStartDate.Value.AddDays(sub.TrialDuration.Value); TrialEndDate = TrialStartDate.Value.AddDays(sub.TrialDuration.Value);
} }
@ -127,7 +123,7 @@ namespace Bit.Core.Models.Business
PeriodEndDate = sub.BillingPeriodEndDate; PeriodEndDate = sub.BillingPeriodEndDate;
CancelAtEndDate = !sub.NeverExpires.GetValueOrDefault(); CancelAtEndDate = !sub.NeverExpires.GetValueOrDefault();
Cancelled = sub.Status == SubscriptionStatus.CANCELED; Cancelled = sub.Status == Braintree.SubscriptionStatus.CANCELED;
if(Cancelled) if(Cancelled)
{ {
CancelledDate = sub.UpdatedAt.Value; CancelledDate = sub.UpdatedAt.Value;
@ -159,7 +155,7 @@ namespace Bit.Core.Models.Business
public class BillingSubscriptionItem public class BillingSubscriptionItem
{ {
public BillingSubscriptionItem(StripeSubscriptionItem item) public BillingSubscriptionItem(SubscriptionItem item)
{ {
if(item.Plan != null) if(item.Plan != null)
{ {
@ -168,10 +164,10 @@ namespace Bit.Core.Models.Business
Interval = item.Plan.Interval; Interval = item.Plan.Interval;
} }
Quantity = item.Quantity; Quantity = (int)item.Quantity;
} }
public BillingSubscriptionItem(Plan plan) public BillingSubscriptionItem(Braintree.Plan plan)
{ {
Name = plan.Name; Name = plan.Name;
Amount = plan.Price.GetValueOrDefault(); Amount = plan.Price.GetValueOrDefault();
@ -179,7 +175,7 @@ namespace Bit.Core.Models.Business
Quantity = 1; Quantity = 1;
} }
public BillingSubscriptionItem(Plan plan, AddOn addon) public BillingSubscriptionItem(Braintree.Plan plan, Braintree.AddOn addon)
{ {
Name = addon.Name; Name = addon.Name;
Amount = addon.Amount.GetValueOrDefault(); Amount = addon.Amount.GetValueOrDefault();
@ -196,13 +192,13 @@ namespace Bit.Core.Models.Business
public class BillingInvoice public class BillingInvoice
{ {
public BillingInvoice(StripeInvoice inv) public BillingInvoice(Invoice inv)
{ {
Amount = inv.AmountDue / 100M; Amount = inv.AmountDue / 100M;
Date = inv.Date.Value; Date = inv.Date.Value;
} }
public BillingInvoice(Subscription sub) public BillingInvoice(Braintree.Subscription sub)
{ {
Amount = sub.NextBillAmount.GetValueOrDefault() + sub.Balance.GetValueOrDefault(); Amount = sub.NextBillAmount.GetValueOrDefault() + sub.Balance.GetValueOrDefault();
if(Amount < 0) if(Amount < 0)
@ -218,7 +214,7 @@ namespace Bit.Core.Models.Business
public class BillingCharge public class BillingCharge
{ {
public BillingCharge(StripeCharge charge) public BillingCharge(Charge charge)
{ {
Amount = charge.Amount / 100M; Amount = charge.Amount / 100M;
RefundedAmount = charge.AmountRefunded / 100M; RefundedAmount = charge.AmountRefunded / 100M;
@ -230,7 +226,7 @@ namespace Bit.Core.Models.Business
InvoiceId = charge.InvoiceId; InvoiceId = charge.InvoiceId;
} }
public BillingCharge(Transaction transaction) public BillingCharge(Braintree.Transaction transaction)
{ {
Amount = transaction.Amount.GetValueOrDefault(); Amount = transaction.Amount.GetValueOrDefault();
RefundedAmount = 0; // TODO? RefundedAmount = 0; // TODO?
@ -239,7 +235,8 @@ namespace Bit.Core.Models.Business
{ {
PaymentSource = new BillingSource(transaction.PayPalDetails); PaymentSource = new BillingSource(transaction.PayPalDetails);
} }
else if(transaction.CreditCard != null && transaction.CreditCard.CardType != CreditCardCardType.UNRECOGNIZED) else if(transaction.CreditCard != null &&
transaction.CreditCard.CardType != Braintree.CreditCardCardType.UNRECOGNIZED)
{ {
PaymentSource = new BillingSource(transaction.CreditCard); PaymentSource = new BillingSource(transaction.CreditCard);
} }

View File

@ -186,15 +186,15 @@ namespace Bit.Core.Services
// TODO: Groups? // TODO: Groups?
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new Stripe.SubscriptionService();
if(string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId)) if(string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
{ {
// They must have been on a free plan. Create new sub. // They must have been on a free plan. Create new sub.
var subCreateOptions = new StripeSubscriptionCreateOptions var subCreateOptions = new SubscriptionCreateOptions
{ {
CustomerId = organization.GatewayCustomerId, CustomerId = organization.GatewayCustomerId,
TrialPeriodDays = newPlan.TrialPeriodDays, TrialPeriodDays = newPlan.TrialPeriodDays,
Items = new List<StripeSubscriptionItemOption>(), Items = new List<SubscriptionItemOption>(),
Metadata = new Dictionary<string, string> { Metadata = new Dictionary<string, string> {
{ "organizationId", organization.Id.ToString() } { "organizationId", organization.Id.ToString() }
} }
@ -202,7 +202,7 @@ namespace Bit.Core.Services
if(newPlan.StripePlanId != null) if(newPlan.StripePlanId != null)
{ {
subCreateOptions.Items.Add(new StripeSubscriptionItemOption subCreateOptions.Items.Add(new SubscriptionItemOption
{ {
PlanId = newPlan.StripePlanId, PlanId = newPlan.StripePlanId,
Quantity = 1 Quantity = 1
@ -211,7 +211,7 @@ namespace Bit.Core.Services
if(additionalSeats > 0 && newPlan.StripeSeatPlanId != null) if(additionalSeats > 0 && newPlan.StripeSeatPlanId != null)
{ {
subCreateOptions.Items.Add(new StripeSubscriptionItemOption subCreateOptions.Items.Add(new SubscriptionItemOption
{ {
PlanId = newPlan.StripeSeatPlanId, PlanId = newPlan.StripeSeatPlanId,
Quantity = additionalSeats Quantity = additionalSeats
@ -223,14 +223,14 @@ namespace Bit.Core.Services
else else
{ {
// Update existing sub. // Update existing sub.
var subUpdateOptions = new StripeSubscriptionUpdateOptions var subUpdateOptions = new SubscriptionUpdateOptions
{ {
Items = new List<StripeSubscriptionItemUpdateOption>() Items = new List<SubscriptionItemUpdateOption>()
}; };
if(newPlan.StripePlanId != null) if(newPlan.StripePlanId != null)
{ {
subUpdateOptions.Items.Add(new StripeSubscriptionItemUpdateOption subUpdateOptions.Items.Add(new SubscriptionItemUpdateOption
{ {
PlanId = newPlan.StripePlanId, PlanId = newPlan.StripePlanId,
Quantity = 1 Quantity = 1
@ -239,7 +239,7 @@ namespace Bit.Core.Services
if(additionalSeats > 0 && newPlan.StripeSeatPlanId != null) if(additionalSeats > 0 && newPlan.StripeSeatPlanId != null)
{ {
subUpdateOptions.Items.Add(new StripeSubscriptionItemUpdateOption subUpdateOptions.Items.Add(new SubscriptionItemUpdateOption
{ {
PlanId = newPlan.StripeSeatPlanId, PlanId = newPlan.StripeSeatPlanId,
Quantity = additionalSeats Quantity = additionalSeats
@ -333,8 +333,8 @@ namespace Bit.Core.Services
} }
} }
var subscriptionItemService = new StripeSubscriptionItemService(); var subscriptionItemService = new SubscriptionItemService();
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
var sub = await subscriptionService.GetAsync(organization.GatewaySubscriptionId); var sub = await subscriptionService.GetAsync(organization.GatewaySubscriptionId);
if(sub == null) if(sub == null)
{ {
@ -344,7 +344,7 @@ namespace Bit.Core.Services
var seatItem = sub.Items?.Data?.FirstOrDefault(i => i.Plan.Id == plan.StripeSeatPlanId); var seatItem = sub.Items?.Data?.FirstOrDefault(i => i.Plan.Id == plan.StripeSeatPlanId);
if(additionalSeats > 0 && seatItem == null) if(additionalSeats > 0 && seatItem == null)
{ {
await subscriptionItemService.CreateAsync(new StripeSubscriptionItemCreateOptions await subscriptionItemService.CreateAsync(new SubscriptionItemCreateOptions
{ {
PlanId = plan.StripeSeatPlanId, PlanId = plan.StripeSeatPlanId,
Quantity = additionalSeats, Quantity = additionalSeats,
@ -354,7 +354,7 @@ namespace Bit.Core.Services
} }
else if(additionalSeats > 0 && seatItem != null) else if(additionalSeats > 0 && seatItem != null)
{ {
await subscriptionItemService.UpdateAsync(seatItem.Id, new StripeSubscriptionItemUpdateOptions await subscriptionItemService.UpdateAsync(seatItem.Id, new SubscriptionItemUpdateOptions
{ {
PlanId = plan.StripeSeatPlanId, PlanId = plan.StripeSeatPlanId,
Quantity = additionalSeats, Quantity = additionalSeats,
@ -389,7 +389,7 @@ namespace Bit.Core.Services
} }
var bankService = new BankAccountService(); var bankService = new BankAccountService();
var customerService = new StripeCustomerService(); var customerService = new CustomerService();
var customer = await customerService.GetAsync(organization.GatewayCustomerId); var customer = await customerService.GetAsync(organization.GatewayCustomerId);
if(customer == null) if(customer == null)
{ {
@ -397,7 +397,7 @@ namespace Bit.Core.Services
} }
var bankAccount = customer.Sources var bankAccount = customer.Sources
.FirstOrDefault(s => s.BankAccount != null && s.BankAccount.Status != "verified")?.BankAccount; .FirstOrDefault(s => s is BankAccount && ((BankAccount)s).Status != "verified") as BankAccount;
if(bankAccount == null) if(bankAccount == null)
{ {
throw new GatewayException("Cannot find an unverified bank account."); throw new GatewayException("Cannot find an unverified bank account.");
@ -406,7 +406,7 @@ namespace Bit.Core.Services
try try
{ {
var result = await bankService.VerifyAsync(organization.GatewayCustomerId, bankAccount.Id, var result = await bankService.VerifyAsync(organization.GatewayCustomerId, bankAccount.Id,
new BankAccountVerifyOptions { AmountOne = amount1, AmountTwo = amount2 }); new BankAccountVerifyOptions { Amounts = new List<long> { amount1, amount2 } });
if(result.Status != "verified") if(result.Status != "verified")
{ {
throw new GatewayException("Unable to verify account."); throw new GatewayException("Unable to verify account.");
@ -453,10 +453,10 @@ namespace Bit.Core.Services
$"{plan.MaxAdditionalSeats.GetValueOrDefault(0)} additional users."); $"{plan.MaxAdditionalSeats.GetValueOrDefault(0)} additional users.");
} }
var customerService = new StripeCustomerService(); var customerService = new CustomerService();
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
StripeCustomer customer = null; Customer customer = null;
StripeSubscription subscription = null; Subscription subscription = null;
// Pre-generate the org id so that we can save it with the Stripe subscription.. // Pre-generate the org id so that we can save it with the Stripe subscription..
var newOrgId = CoreHelpers.GenerateComb(); var newOrgId = CoreHelpers.GenerateComb();
@ -472,18 +472,18 @@ namespace Bit.Core.Services
} }
else else
{ {
customer = await customerService.CreateAsync(new StripeCustomerCreateOptions customer = await customerService.CreateAsync(new CustomerCreateOptions
{ {
Description = signup.BusinessName, Description = signup.BusinessName,
Email = signup.BillingEmail, Email = signup.BillingEmail,
SourceToken = signup.PaymentToken SourceToken = signup.PaymentToken
}); });
var subCreateOptions = new StripeSubscriptionCreateOptions var subCreateOptions = new SubscriptionCreateOptions
{ {
CustomerId = customer.Id, CustomerId = customer.Id,
TrialPeriodDays = plan.TrialPeriodDays, TrialPeriodDays = plan.TrialPeriodDays,
Items = new List<StripeSubscriptionItemOption>(), Items = new List<SubscriptionItemOption>(),
Metadata = new Dictionary<string, string> { Metadata = new Dictionary<string, string> {
{ "organizationId", newOrgId.ToString() } { "organizationId", newOrgId.ToString() }
} }
@ -491,7 +491,7 @@ namespace Bit.Core.Services
if(plan.StripePlanId != null) if(plan.StripePlanId != null)
{ {
subCreateOptions.Items.Add(new StripeSubscriptionItemOption subCreateOptions.Items.Add(new SubscriptionItemOption
{ {
PlanId = plan.StripePlanId, PlanId = plan.StripePlanId,
Quantity = 1 Quantity = 1
@ -500,7 +500,7 @@ namespace Bit.Core.Services
if(signup.AdditionalSeats > 0 && plan.StripeSeatPlanId != null) if(signup.AdditionalSeats > 0 && plan.StripeSeatPlanId != null)
{ {
subCreateOptions.Items.Add(new StripeSubscriptionItemOption subCreateOptions.Items.Add(new SubscriptionItemOption
{ {
PlanId = plan.StripeSeatPlanId, PlanId = plan.StripeSeatPlanId,
Quantity = signup.AdditionalSeats Quantity = signup.AdditionalSeats
@ -509,7 +509,7 @@ namespace Bit.Core.Services
if(signup.AdditionalStorageGb > 0) if(signup.AdditionalStorageGb > 0)
{ {
subCreateOptions.Items.Add(new StripeSubscriptionItemOption subCreateOptions.Items.Add(new SubscriptionItemOption
{ {
PlanId = plan.StripeStoragePlanId, PlanId = plan.StripeStoragePlanId,
Quantity = signup.AdditionalStorageGb Quantity = signup.AdditionalStorageGb
@ -518,7 +518,7 @@ namespace Bit.Core.Services
if(signup.PremiumAccessAddon && plan.StripePremiumAccessPlanId != null) if(signup.PremiumAccessAddon && plan.StripePremiumAccessPlanId != null)
{ {
subCreateOptions.Items.Add(new StripeSubscriptionItemOption subCreateOptions.Items.Add(new SubscriptionItemOption
{ {
PlanId = plan.StripePremiumAccessPlanId, PlanId = plan.StripePremiumAccessPlanId,
Quantity = 1 Quantity = 1
@ -630,7 +630,8 @@ namespace Bit.Core.Services
var dir = $"{_globalSettings.LicenseDirectory}/organization"; var dir = $"{_globalSettings.LicenseDirectory}/organization";
Directory.CreateDirectory(dir); Directory.CreateDirectory(dir);
File.WriteAllText($"{dir}/{organization.Id}.json", JsonConvert.SerializeObject(license, Formatting.Indented)); System.IO.File.WriteAllText($"{dir}/{organization.Id}.json",
JsonConvert.SerializeObject(license, Formatting.Indented));
return result; return result;
} }
@ -756,7 +757,8 @@ namespace Bit.Core.Services
var dir = $"{_globalSettings.LicenseDirectory}/organization"; var dir = $"{_globalSettings.LicenseDirectory}/organization";
Directory.CreateDirectory(dir); Directory.CreateDirectory(dir);
File.WriteAllText($"{dir}/{organization.Id}.json", JsonConvert.SerializeObject(license, Formatting.Indented)); System.IO.File.WriteAllText($"{dir}/{organization.Id}.json",
JsonConvert.SerializeObject(license, Formatting.Indented));
organization.Name = license.Name; organization.Name = license.Name;
organization.BusinessName = license.BusinessName; organization.BusinessName = license.BusinessName;
@ -842,8 +844,8 @@ namespace Bit.Core.Services
if(updateBilling && !string.IsNullOrWhiteSpace(organization.GatewayCustomerId)) if(updateBilling && !string.IsNullOrWhiteSpace(organization.GatewayCustomerId))
{ {
var customerService = new StripeCustomerService(); var customerService = new CustomerService();
await customerService.UpdateAsync(organization.GatewayCustomerId, new StripeCustomerUpdateOptions await customerService.UpdateAsync(organization.GatewayCustomerId, new CustomerUpdateOptions
{ {
Email = organization.BillingEmail, Email = organization.BillingEmail,
Description = organization.BusinessName Description = organization.BusinessName

View File

@ -6,7 +6,6 @@ using System.Collections.Generic;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using System.Linq; using System.Linq;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Braintree;
using Bit.Core.Enums; using Bit.Core.Enums;
namespace Bit.Core.Services namespace Bit.Core.Services
@ -15,12 +14,12 @@ namespace Bit.Core.Services
{ {
private const string PremiumPlanId = "premium-annually"; private const string PremiumPlanId = "premium-annually";
private const string StoragePlanId = "storage-gb-annually"; private const string StoragePlanId = "storage-gb-annually";
private readonly BraintreeGateway _btGateway; private readonly Braintree.BraintreeGateway _btGateway;
public StripePaymentService( public StripePaymentService(
GlobalSettings globalSettings) GlobalSettings globalSettings)
{ {
_btGateway = new BraintreeGateway _btGateway = new Braintree.BraintreeGateway
{ {
Environment = globalSettings.Braintree.Production ? Environment = globalSettings.Braintree.Production ?
Braintree.Environment.PRODUCTION : Braintree.Environment.SANDBOX, Braintree.Environment.PRODUCTION : Braintree.Environment.SANDBOX,
@ -33,16 +32,16 @@ namespace Bit.Core.Services
public async Task PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken, public async Task PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken,
short additionalStorageGb) short additionalStorageGb)
{ {
Customer braintreeCustomer = null; Braintree.Customer braintreeCustomer = null;
StripeBilling? stripeSubscriptionBilling = null; Billing? stripeSubscriptionBilling = null;
string stipeCustomerSourceToken = null; string stipeCustomerSourceToken = null;
var stripeCustomerMetadata = new Dictionary<string, string>(); var stripeCustomerMetadata = new Dictionary<string, string>();
if(paymentMethodType == PaymentMethodType.PayPal) if(paymentMethodType == PaymentMethodType.PayPal)
{ {
stripeSubscriptionBilling = StripeBilling.SendInvoice; stripeSubscriptionBilling = Billing.SendInvoice;
var randomSuffix = Utilities.CoreHelpers.RandomString(3, upper: false, numeric: false); var randomSuffix = Utilities.CoreHelpers.RandomString(3, upper: false, numeric: false);
var customerResult = await _btGateway.Customer.CreateAsync(new CustomerRequest var customerResult = await _btGateway.Customer.CreateAsync(new Braintree.CustomerRequest
{ {
PaymentMethodNonce = paymentToken, PaymentMethodNonce = paymentToken,
Email = user.Email, Email = user.Email,
@ -62,8 +61,8 @@ namespace Bit.Core.Services
stipeCustomerSourceToken = paymentToken; stipeCustomerSourceToken = paymentToken;
} }
var customerService = new StripeCustomerService(); var customerService = new CustomerService();
var customer = await customerService.CreateAsync(new StripeCustomerCreateOptions var customer = await customerService.CreateAsync(new CustomerCreateOptions
{ {
Description = user.Name, Description = user.Name,
Email = user.Email, Email = user.Email,
@ -71,19 +70,19 @@ namespace Bit.Core.Services
Metadata = stripeCustomerMetadata Metadata = stripeCustomerMetadata
}); });
var subCreateOptions = new StripeSubscriptionCreateOptions var subCreateOptions = new SubscriptionCreateOptions
{ {
CustomerId = customer.Id, CustomerId = customer.Id,
Items = new List<StripeSubscriptionItemOption>(), Items = new List<SubscriptionItemOption>(),
Billing = stripeSubscriptionBilling, Billing = stripeSubscriptionBilling,
DaysUntilDue = stripeSubscriptionBilling != null ? 1 : 0, DaysUntilDue = stripeSubscriptionBilling != null ? 1 : (long?)null,
Metadata = new Dictionary<string, string> Metadata = new Dictionary<string, string>
{ {
["userId"] = user.Id.ToString() ["userId"] = user.Id.ToString()
} }
}; };
subCreateOptions.Items.Add(new StripeSubscriptionItemOption subCreateOptions.Items.Add(new SubscriptionItemOption
{ {
PlanId = PremiumPlanId, PlanId = PremiumPlanId,
Quantity = 1 Quantity = 1
@ -91,23 +90,23 @@ namespace Bit.Core.Services
if(additionalStorageGb > 0) if(additionalStorageGb > 0)
{ {
subCreateOptions.Items.Add(new StripeSubscriptionItemOption subCreateOptions.Items.Add(new SubscriptionItemOption
{ {
PlanId = StoragePlanId, PlanId = StoragePlanId,
Quantity = additionalStorageGb Quantity = additionalStorageGb
}); });
} }
StripeSubscription subscription = null; Subscription subscription = null;
try try
{ {
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
subscription = await subscriptionService.CreateAsync(subCreateOptions); subscription = await subscriptionService.CreateAsync(subCreateOptions);
if(stripeSubscriptionBilling == StripeBilling.SendInvoice) if(stripeSubscriptionBilling == Billing.SendInvoice)
{ {
var invoiceService = new StripeInvoiceService(); var invoiceService = new InvoiceService();
var invoices = await invoiceService.ListAsync(new StripeInvoiceListOptions var invoices = await invoiceService.ListAsync(new InvoiceListOptions
{ {
SubscriptionId = subscription.Id SubscriptionId = subscription.Id
}); });
@ -121,7 +120,7 @@ namespace Bit.Core.Services
if(braintreeCustomer != null) if(braintreeCustomer != null)
{ {
var btInvoiceAmount = (invoice.AmountDue / 100M); var btInvoiceAmount = (invoice.AmountDue / 100M);
var transactionResult = await _btGateway.Transaction.SaleAsync(new TransactionRequest var transactionResult = await _btGateway.Transaction.SaleAsync(new Braintree.TransactionRequest
{ {
Amount = btInvoiceAmount, Amount = btInvoiceAmount,
CustomerId = braintreeCustomer.Id CustomerId = braintreeCustomer.Id
@ -132,8 +131,8 @@ namespace Bit.Core.Services
throw new GatewayException("Failed to charge PayPal customer."); throw new GatewayException("Failed to charge PayPal customer.");
} }
var invoiceItemService = new StripeInvoiceItemService(); var invoiceItemService = new InvoiceItemService();
await invoiceItemService.CreateAsync(new StripeInvoiceItemCreateOptions await invoiceItemService.CreateAsync(new InvoiceItemCreateOptions
{ {
Currency = "USD", Currency = "USD",
CustomerId = customer.Id, CustomerId = customer.Id,
@ -153,7 +152,7 @@ namespace Bit.Core.Services
throw new GatewayException("No payment was able to be collected."); throw new GatewayException("No payment was able to be collected.");
} }
await invoiceService.PayAsync(invoice.Id, new StripeInvoicePayOptions { }); await invoiceService.PayAsync(invoice.Id, new InvoicePayOptions { });
} }
} }
catch(Exception e) catch(Exception e)
@ -176,8 +175,8 @@ namespace Bit.Core.Services
public async Task AdjustStorageAsync(IStorableSubscriber storableSubscriber, int additionalStorage, public async Task AdjustStorageAsync(IStorableSubscriber storableSubscriber, int additionalStorage,
string storagePlanId) string storagePlanId)
{ {
var subscriptionItemService = new StripeSubscriptionItemService(); var subscriptionItemService = new SubscriptionItemService();
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
var sub = await subscriptionService.GetAsync(storableSubscriber.GatewaySubscriptionId); var sub = await subscriptionService.GetAsync(storableSubscriber.GatewaySubscriptionId);
if(sub == null) if(sub == null)
{ {
@ -187,7 +186,7 @@ namespace Bit.Core.Services
var storageItem = sub.Items?.Data?.FirstOrDefault(i => i.Plan.Id == storagePlanId); var storageItem = sub.Items?.Data?.FirstOrDefault(i => i.Plan.Id == storagePlanId);
if(additionalStorage > 0 && storageItem == null) if(additionalStorage > 0 && storageItem == null)
{ {
await subscriptionItemService.CreateAsync(new StripeSubscriptionItemCreateOptions await subscriptionItemService.CreateAsync(new SubscriptionItemCreateOptions
{ {
PlanId = storagePlanId, PlanId = storagePlanId,
Quantity = additionalStorage, Quantity = additionalStorage,
@ -197,7 +196,7 @@ namespace Bit.Core.Services
} }
else if(additionalStorage > 0 && storageItem != null) else if(additionalStorage > 0 && storageItem != null)
{ {
await subscriptionItemService.UpdateAsync(storageItem.Id, new StripeSubscriptionItemUpdateOptions await subscriptionItemService.UpdateAsync(storageItem.Id, new SubscriptionItemUpdateOptions
{ {
PlanId = storagePlanId, PlanId = storagePlanId,
Quantity = additionalStorage, Quantity = additionalStorage,
@ -219,9 +218,9 @@ namespace Bit.Core.Services
{ {
if(!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId)) if(!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId))
{ {
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
await subscriptionService.CancelAsync(subscriber.GatewaySubscriptionId, await subscriptionService.CancelAsync(subscriber.GatewaySubscriptionId,
new StripeSubscriptionCancelOptions()); new SubscriptionCancelOptions());
} }
if(string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId)) if(string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId))
@ -229,36 +228,36 @@ namespace Bit.Core.Services
return; return;
} }
var chargeService = new StripeChargeService(); var chargeService = new ChargeService();
var charges = await chargeService.ListAsync(new StripeChargeListOptions var charges = await chargeService.ListAsync(new ChargeListOptions
{ {
CustomerId = subscriber.GatewayCustomerId CustomerId = subscriber.GatewayCustomerId
}); });
if(charges?.Data != null) if(charges?.Data != null)
{ {
var refundService = new StripeRefundService(); var refundService = new RefundService();
foreach(var charge in charges.Data.Where(c => !c.Refunded)) foreach(var charge in charges.Data.Where(c => !c.Refunded))
{ {
await refundService.CreateAsync(charge.Id); await refundService.CreateAsync(new RefundCreateOptions { ChargeId = charge.Id });
} }
} }
var customerService = new StripeCustomerService(); var customerService = new CustomerService();
await customerService.DeleteAsync(subscriber.GatewayCustomerId); await customerService.DeleteAsync(subscriber.GatewayCustomerId);
} }
public async Task PreviewUpcomingInvoiceAndPayAsync(ISubscriber subscriber, string planId, public async Task PreviewUpcomingInvoiceAndPayAsync(ISubscriber subscriber, string planId,
int prorateThreshold = 500) int prorateThreshold = 500)
{ {
var invoiceService = new StripeInvoiceService(); var invoiceService = new InvoiceService();
var upcomingPreview = await invoiceService.UpcomingAsync(subscriber.GatewayCustomerId, var upcomingPreview = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions
new StripeUpcomingInvoiceOptions
{ {
CustomerId = subscriber.GatewayCustomerId,
SubscriptionId = subscriber.GatewaySubscriptionId SubscriptionId = subscriber.GatewaySubscriptionId
}); });
var prorationAmount = upcomingPreview.StripeInvoiceLineItems?.Data? var prorationAmount = upcomingPreview.Lines?.Data?
.TakeWhile(i => i.Plan.Id == planId && i.Proration).Sum(i => i.Amount); .TakeWhile(i => i.Plan.Id == planId && i.Proration).Sum(i => i.Amount);
if(prorationAmount.GetValueOrDefault() >= prorateThreshold) if(prorationAmount.GetValueOrDefault() >= prorateThreshold)
{ {
@ -266,22 +265,23 @@ namespace Bit.Core.Services
{ {
// Owes more than prorateThreshold on next invoice. // Owes more than prorateThreshold on next invoice.
// Invoice them and pay now instead of waiting until next billing cycle. // Invoice them and pay now instead of waiting until next billing cycle.
var invoice = await invoiceService.CreateAsync(subscriber.GatewayCustomerId, var invoice = await invoiceService.CreateAsync(new InvoiceCreateOptions
new StripeInvoiceCreateOptions
{ {
CustomerId = subscriber.GatewayCustomerId,
SubscriptionId = subscriber.GatewaySubscriptionId SubscriptionId = subscriber.GatewaySubscriptionId
}); });
if(invoice.AmountDue > 0) if(invoice.AmountDue > 0)
{ {
var customerService = new StripeCustomerService(); var customerService = new CustomerService();
var customer = await customerService.GetAsync(subscriber.GatewayCustomerId); var customer = await customerService.GetAsync(subscriber.GatewayCustomerId);
if(customer != null) if(customer != null)
{ {
if(customer.Metadata.ContainsKey("btCustomerId")) if(customer.Metadata.ContainsKey("btCustomerId"))
{ {
var invoiceAmount = (invoice.AmountDue / 100M); var invoiceAmount = (invoice.AmountDue / 100M);
var transactionResult = await _btGateway.Transaction.SaleAsync(new TransactionRequest var transactionResult = await _btGateway.Transaction.SaleAsync(
new Braintree.TransactionRequest
{ {
Amount = invoiceAmount, Amount = invoiceAmount,
CustomerId = customer.Metadata["btCustomerId"] CustomerId = customer.Metadata["btCustomerId"]
@ -289,14 +289,14 @@ namespace Bit.Core.Services
if(!transactionResult.IsSuccess() || transactionResult.Target.Amount != invoiceAmount) if(!transactionResult.IsSuccess() || transactionResult.Target.Amount != invoiceAmount)
{ {
await invoiceService.UpdateAsync(invoice.Id, new StripeInvoiceUpdateOptions await invoiceService.UpdateAsync(invoice.Id, new InvoiceUpdateOptions
{ {
Closed = true Closed = true
}); });
throw new GatewayException("Failed to charge PayPal customer."); throw new GatewayException("Failed to charge PayPal customer.");
} }
await customerService.UpdateAsync(customer.Id, new StripeCustomerUpdateOptions await customerService.UpdateAsync(customer.Id, new CustomerUpdateOptions
{ {
AccountBalance = customer.AccountBalance - invoice.AmountDue, AccountBalance = customer.AccountBalance - invoice.AmountDue,
Metadata = customer.Metadata Metadata = customer.Metadata
@ -304,7 +304,7 @@ namespace Bit.Core.Services
} }
} }
await invoiceService.PayAsync(invoice.Id, new StripeInvoicePayOptions()); await invoiceService.PayAsync(invoice.Id, new InvoicePayOptions());
} }
} }
catch(StripeException) { } catch(StripeException) { }
@ -323,7 +323,7 @@ namespace Bit.Core.Services
throw new GatewayException("No subscription."); throw new GatewayException("No subscription.");
} }
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
var sub = await subscriptionService.GetAsync(subscriber.GatewaySubscriptionId); var sub = await subscriptionService.GetAsync(subscriber.GatewaySubscriptionId);
if(sub == null) if(sub == null)
{ {
@ -340,8 +340,8 @@ namespace Bit.Core.Services
{ {
var canceledSub = endOfPeriod ? var canceledSub = endOfPeriod ?
await subscriptionService.UpdateAsync(sub.Id, await subscriptionService.UpdateAsync(sub.Id,
new StripeSubscriptionUpdateOptions { CancelAtPeriodEnd = true }) : new SubscriptionUpdateOptions { CancelAtPeriodEnd = true }) :
await subscriptionService.CancelAsync(sub.Id, new StripeSubscriptionCancelOptions()); await subscriptionService.CancelAsync(sub.Id, new SubscriptionCancelOptions());
if(!canceledSub.CanceledAt.HasValue) if(!canceledSub.CanceledAt.HasValue)
{ {
throw new GatewayException("Unable to cancel subscription."); throw new GatewayException("Unable to cancel subscription.");
@ -368,7 +368,7 @@ namespace Bit.Core.Services
throw new GatewayException("No subscription."); throw new GatewayException("No subscription.");
} }
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
var sub = await subscriptionService.GetAsync(subscriber.GatewaySubscriptionId); var sub = await subscriptionService.GetAsync(subscriber.GatewaySubscriptionId);
if(sub == null) if(sub == null)
{ {
@ -381,7 +381,7 @@ namespace Bit.Core.Services
} }
var updatedSub = await subscriptionService.UpdateAsync(sub.Id, var updatedSub = await subscriptionService.UpdateAsync(sub.Id,
new StripeSubscriptionUpdateOptions { CancelAtPeriodEnd = false }); new SubscriptionUpdateOptions { CancelAtPeriodEnd = false });
if(updatedSub.CanceledAt.HasValue) if(updatedSub.CanceledAt.HasValue)
{ {
throw new GatewayException("Unable to reinstate subscription."); throw new GatewayException("Unable to reinstate subscription.");
@ -403,10 +403,10 @@ namespace Bit.Core.Services
var updatedSubscriber = false; var updatedSubscriber = false;
var cardService = new StripeCardService(); var cardService = new CardService();
var bankSerice = new BankAccountService(); var bankSerice = new BankAccountService();
var customerService = new StripeCustomerService(); var customerService = new CustomerService();
StripeCustomer customer = null; Customer customer = null;
if(!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId)) if(!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId))
{ {
@ -415,7 +415,7 @@ namespace Bit.Core.Services
if(customer == null) if(customer == null)
{ {
customer = await customerService.CreateAsync(new StripeCustomerCreateOptions customer = await customerService.CreateAsync(new CustomerCreateOptions
{ {
Description = subscriber.BillingName(), Description = subscriber.BillingName(),
Email = subscriber.BillingEmailAddress(), Email = subscriber.BillingEmailAddress(),
@ -437,7 +437,7 @@ namespace Bit.Core.Services
} }
else else
{ {
await cardService.CreateAsync(customer.Id, new StripeCardCreateOptions await cardService.CreateAsync(customer.Id, new CardCreateOptions
{ {
SourceToken = paymentToken SourceToken = paymentToken
}); });
@ -446,11 +446,11 @@ namespace Bit.Core.Services
if(!string.IsNullOrWhiteSpace(customer.DefaultSourceId)) if(!string.IsNullOrWhiteSpace(customer.DefaultSourceId))
{ {
var source = customer.Sources.FirstOrDefault(s => s.Id == customer.DefaultSourceId); var source = customer.Sources.FirstOrDefault(s => s.Id == customer.DefaultSourceId);
if(source.BankAccount != null) if(source is BankAccount)
{ {
await bankSerice.DeleteAsync(customer.Id, customer.DefaultSourceId); await bankSerice.DeleteAsync(customer.Id, customer.DefaultSourceId);
} }
else if(source.Card != null) else if(source is Card)
{ {
await cardService.DeleteAsync(customer.Id, customer.DefaultSourceId); await cardService.DeleteAsync(customer.Id, customer.DefaultSourceId);
} }
@ -464,8 +464,8 @@ namespace Bit.Core.Services
{ {
if(!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId)) if(!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId))
{ {
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
var invoiceService = new StripeInvoiceService(); var invoiceService = new InvoiceService();
var sub = await subscriptionService.GetAsync(subscriber.GatewaySubscriptionId); var sub = await subscriptionService.GetAsync(subscriber.GatewaySubscriptionId);
if(sub != null) if(sub != null)
{ {
@ -473,7 +473,10 @@ namespace Bit.Core.Services
{ {
try try
{ {
var upcomingInvoice = await invoiceService.UpcomingAsync(subscriber.GatewayCustomerId); var upcomingInvoice = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions
{
CustomerId = subscriber.GatewayCustomerId
});
if(upcomingInvoice != null) if(upcomingInvoice != null)
{ {
return new BillingInfo.BillingInvoice(upcomingInvoice); return new BillingInfo.BillingInvoice(upcomingInvoice);
@ -489,10 +492,10 @@ namespace Bit.Core.Services
public async Task<BillingInfo> GetBillingAsync(ISubscriber subscriber) public async Task<BillingInfo> GetBillingAsync(ISubscriber subscriber)
{ {
var billingInfo = new BillingInfo(); var billingInfo = new BillingInfo();
var customerService = new StripeCustomerService(); var customerService = new CustomerService();
var subscriptionService = new StripeSubscriptionService(); var subscriptionService = new SubscriptionService();
var chargeService = new StripeChargeService(); var chargeService = new ChargeService();
var invoiceService = new StripeInvoiceService(); var invoiceService = new InvoiceService();
if(!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId)) if(!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId))
{ {
@ -501,18 +504,10 @@ namespace Bit.Core.Services
{ {
if(!string.IsNullOrWhiteSpace(customer.DefaultSourceId) && customer.Sources?.Data != null) if(!string.IsNullOrWhiteSpace(customer.DefaultSourceId) && customer.Sources?.Data != null)
{ {
if(customer.DefaultSourceId.StartsWith("card_")) if(customer.DefaultSourceId.StartsWith("card_") || customer.DefaultSourceId.StartsWith("ba_"))
{ {
var source = customer.Sources.Data.FirstOrDefault(s => s.Card?.Id == customer.DefaultSourceId); var source = customer.Sources.Data.FirstOrDefault(s =>
if(source != null) (s is Card || s is BankAccount) && s.Id == customer.DefaultSourceId);
{
billingInfo.PaymentSource = new BillingInfo.BillingSource(source);
}
}
else if(customer.DefaultSourceId.StartsWith("ba_"))
{
var source = customer.Sources.Data
.FirstOrDefault(s => s.BankAccount?.Id == customer.DefaultSourceId);
if(source != null) if(source != null)
{ {
billingInfo.PaymentSource = new BillingInfo.BillingSource(source); billingInfo.PaymentSource = new BillingInfo.BillingSource(source);
@ -520,7 +515,7 @@ namespace Bit.Core.Services
} }
} }
var charges = await chargeService.ListAsync(new StripeChargeListOptions var charges = await chargeService.ListAsync(new ChargeListOptions
{ {
CustomerId = customer.Id, CustomerId = customer.Id,
Limit = 20 Limit = 20
@ -542,7 +537,8 @@ namespace Bit.Core.Services
{ {
try try
{ {
var upcomingInvoice = await invoiceService.UpcomingAsync(subscriber.GatewayCustomerId); var upcomingInvoice = await invoiceService.UpcomingAsync(
new UpcomingInvoiceOptions { CustomerId = subscriber.GatewayCustomerId });
if(upcomingInvoice != null) if(upcomingInvoice != null)
{ {
billingInfo.UpcomingInvoice = new BillingInfo.BillingInvoice(upcomingInvoice); billingInfo.UpcomingInvoice = new BillingInfo.BillingInvoice(upcomingInvoice);