From a34ca4700d34805e47475e060e274bf0371844cf Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Tue, 29 Jan 2019 14:41:37 -0500 Subject: [PATCH] upgrade stripe lib and breaking changes --- .../Controllers/OrganizationsController.cs | 2 +- src/Billing/Controllers/StripeController.cs | 16 +- src/Core/Core.csproj | 2 +- src/Core/Models/Business/BillingInfo.cs | 79 ++++---- .../Implementations/OrganizationService.cs | 64 +++---- .../Implementations/StripePaymentService.cs | 170 +++++++++--------- 6 files changed, 163 insertions(+), 170 deletions(-) diff --git a/src/Api/Controllers/OrganizationsController.cs b/src/Api/Controllers/OrganizationsController.cs index 5ab83bc30b..cea2162d9c 100644 --- a/src/Api/Controllers/OrganizationsController.cs +++ b/src/Api/Controllers/OrganizationsController.cs @@ -110,7 +110,7 @@ namespace Bit.Api.Controllers try { - var invoice = await new StripeInvoiceService().GetAsync(invoiceId); + var invoice = await new InvoiceService().GetAsync(invoiceId); if(invoice != null && invoice.CustomerId == organization.GatewayCustomerId && !string.IsNullOrWhiteSpace(invoice.HostedInvoiceUrl)) { diff --git a/src/Billing/Controllers/StripeController.cs b/src/Billing/Controllers/StripeController.cs index b30357cb12..df39e02532 100644 --- a/src/Billing/Controllers/StripeController.cs +++ b/src/Billing/Controllers/StripeController.cs @@ -47,11 +47,11 @@ namespace Bit.Billing.Controllers return new BadRequestResult(); } - StripeEvent parsedEvent; + Stripe.Event parsedEvent; using(var sr = new StreamReader(HttpContext.Request.Body)) { var json = await sr.ReadToEndAsync(); - parsedEvent = StripeEventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], + parsedEvent = EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], _billingSettings.StripeWebhookSecret); } @@ -60,7 +60,7 @@ namespace Bit.Billing.Controllers return new BadRequestResult(); } - if(_hostingEnvironment.IsProduction() && !parsedEvent.LiveMode) + if(_hostingEnvironment.IsProduction() && !parsedEvent.Livemode) { return new BadRequestResult(); } @@ -71,8 +71,7 @@ namespace Bit.Billing.Controllers if(subDeleted || subUpdated) { - StripeSubscription subscription = Mapper.MapFromJson( - parsedEvent.Data.Object.ToString()); + var subscription = parsedEvent.Data.Object as Subscription; if(subscription == null) { throw new Exception("Subscription is null."); @@ -115,14 +114,13 @@ namespace Bit.Billing.Controllers } else if(invUpcoming) { - StripeInvoice invoice = Mapper.MapFromJson( - parsedEvent.Data.Object.ToString()); + var invoice = parsedEvent.Data.Object as Invoice; if(invoice == null) { throw new Exception("Invoice is null."); } - var subscriptionService = new StripeSubscriptionService(); + var subscriptionService = new SubscriptionService(); var subscription = await subscriptionService.GetAsync(invoice.SubscriptionId); if(subscription == null) { @@ -152,7 +150,7 @@ namespace Bit.Billing.Controllers 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, invoice.NextPaymentAttempt.Value, items, ids.Item1.HasValue); } diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index b86969acbb..823206c8d9 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -38,7 +38,7 @@ - + diff --git a/src/Core/Models/Business/BillingInfo.cs b/src/Core/Models/Business/BillingInfo.cs index 1e1d5d9bf8..8cbd164114 100644 --- a/src/Core/Models/Business/BillingInfo.cs +++ b/src/Core/Models/Business/BillingInfo.cs @@ -1,5 +1,4 @@ using Bit.Core.Enums; -using Braintree; using Stripe; using System; using System.Collections.Generic; @@ -16,40 +15,37 @@ namespace Bit.Core.Models.Business 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; - Description = $"{source.BankAccount.BankName}, *{source.BankAccount.Last4} - " + - (source.BankAccount.Status == "verified" ? "verified" : - source.BankAccount.Status == "errored" ? "invalid" : - source.BankAccount.Status == "verification_failed" ? "verification failed" : "unverified"); - NeedsVerification = source.BankAccount.Status == "new" || source.BankAccount.Status == "validated"; - break; - default: - break; + Type = PaymentMethodType.BankAccount; + Description = $"{bankAccount.BankName}, *{bankAccount.Last4} - " + + (bankAccount.Status == "verified" ? "verified" : + bankAccount.Status == "errored" ? "invalid" : + bankAccount.Status == "verification_failed" ? "verification failed" : "unverified"); + NeedsVerification = bankAccount.Status == "new" || bankAccount.Status == "validated"; + } + else if(source is Card card) + { + 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; Description = paypal.Email; } - else if(method is CreditCard card) + else if(method is Braintree.CreditCard card) { Type = PaymentMethodType.Card; Description = $"{card.CardType.ToString()}, *{card.LastFour}, " + @@ -59,7 +55,7 @@ namespace Bit.Core.Models.Business card.ExpirationYear); CardBrand = card.CardType.ToString(); } - else if(method is UsBankAccount bank) + else if(method is Braintree.UsBankAccount bank) { Type = PaymentMethodType.BankAccount; 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; Description = $"{bank.BankName}, *{bank.Last4}"; } - public BillingSource(PayPalDetails paypal) + public BillingSource(Braintree.PayPalDetails paypal) { Type = PaymentMethodType.PayPal; Description = paypal.PayerEmail; @@ -90,7 +86,7 @@ namespace Bit.Core.Models.Business public class BillingSubscription { - public BillingSubscription(StripeSubscription sub) + public BillingSubscription(Subscription sub) { Status = sub.Status; 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(); if(sub.HasTrialPeriod.GetValueOrDefault() && sub.CreatedAt.HasValue && sub.TrialDuration.HasValue) { TrialStartDate = sub.CreatedAt.Value; - if(sub.TrialDurationUnit == SubscriptionDurationUnit.DAY) + if(sub.TrialDurationUnit == Braintree.SubscriptionDurationUnit.DAY) { TrialEndDate = TrialStartDate.Value.AddDays(sub.TrialDuration.Value); } @@ -127,7 +123,7 @@ namespace Bit.Core.Models.Business PeriodEndDate = sub.BillingPeriodEndDate; CancelAtEndDate = !sub.NeverExpires.GetValueOrDefault(); - Cancelled = sub.Status == SubscriptionStatus.CANCELED; + Cancelled = sub.Status == Braintree.SubscriptionStatus.CANCELED; if(Cancelled) { CancelledDate = sub.UpdatedAt.Value; @@ -159,7 +155,7 @@ namespace Bit.Core.Models.Business public class BillingSubscriptionItem { - public BillingSubscriptionItem(StripeSubscriptionItem item) + public BillingSubscriptionItem(SubscriptionItem item) { if(item.Plan != null) { @@ -168,10 +164,10 @@ namespace Bit.Core.Models.Business Interval = item.Plan.Interval; } - Quantity = item.Quantity; + Quantity = (int)item.Quantity; } - public BillingSubscriptionItem(Plan plan) + public BillingSubscriptionItem(Braintree.Plan plan) { Name = plan.Name; Amount = plan.Price.GetValueOrDefault(); @@ -179,7 +175,7 @@ namespace Bit.Core.Models.Business Quantity = 1; } - public BillingSubscriptionItem(Plan plan, AddOn addon) + public BillingSubscriptionItem(Braintree.Plan plan, Braintree.AddOn addon) { Name = addon.Name; Amount = addon.Amount.GetValueOrDefault(); @@ -196,13 +192,13 @@ namespace Bit.Core.Models.Business public class BillingInvoice { - public BillingInvoice(StripeInvoice inv) + public BillingInvoice(Invoice inv) { Amount = inv.AmountDue / 100M; Date = inv.Date.Value; } - public BillingInvoice(Subscription sub) + public BillingInvoice(Braintree.Subscription sub) { Amount = sub.NextBillAmount.GetValueOrDefault() + sub.Balance.GetValueOrDefault(); if(Amount < 0) @@ -218,7 +214,7 @@ namespace Bit.Core.Models.Business public class BillingCharge { - public BillingCharge(StripeCharge charge) + public BillingCharge(Charge charge) { Amount = charge.Amount / 100M; RefundedAmount = charge.AmountRefunded / 100M; @@ -230,7 +226,7 @@ namespace Bit.Core.Models.Business InvoiceId = charge.InvoiceId; } - public BillingCharge(Transaction transaction) + public BillingCharge(Braintree.Transaction transaction) { Amount = transaction.Amount.GetValueOrDefault(); RefundedAmount = 0; // TODO? @@ -239,7 +235,8 @@ namespace Bit.Core.Models.Business { 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); } diff --git a/src/Core/Services/Implementations/OrganizationService.cs b/src/Core/Services/Implementations/OrganizationService.cs index 1388ae2b28..8c2159f6af 100644 --- a/src/Core/Services/Implementations/OrganizationService.cs +++ b/src/Core/Services/Implementations/OrganizationService.cs @@ -186,15 +186,15 @@ namespace Bit.Core.Services // TODO: Groups? - var subscriptionService = new StripeSubscriptionService(); + var subscriptionService = new Stripe.SubscriptionService(); if(string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId)) { // They must have been on a free plan. Create new sub. - var subCreateOptions = new StripeSubscriptionCreateOptions + var subCreateOptions = new SubscriptionCreateOptions { CustomerId = organization.GatewayCustomerId, TrialPeriodDays = newPlan.TrialPeriodDays, - Items = new List(), + Items = new List(), Metadata = new Dictionary { { "organizationId", organization.Id.ToString() } } @@ -202,7 +202,7 @@ namespace Bit.Core.Services if(newPlan.StripePlanId != null) { - subCreateOptions.Items.Add(new StripeSubscriptionItemOption + subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = newPlan.StripePlanId, Quantity = 1 @@ -211,7 +211,7 @@ namespace Bit.Core.Services if(additionalSeats > 0 && newPlan.StripeSeatPlanId != null) { - subCreateOptions.Items.Add(new StripeSubscriptionItemOption + subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = newPlan.StripeSeatPlanId, Quantity = additionalSeats @@ -223,14 +223,14 @@ namespace Bit.Core.Services else { // Update existing sub. - var subUpdateOptions = new StripeSubscriptionUpdateOptions + var subUpdateOptions = new SubscriptionUpdateOptions { - Items = new List() + Items = new List() }; if(newPlan.StripePlanId != null) { - subUpdateOptions.Items.Add(new StripeSubscriptionItemUpdateOption + subUpdateOptions.Items.Add(new SubscriptionItemUpdateOption { PlanId = newPlan.StripePlanId, Quantity = 1 @@ -239,7 +239,7 @@ namespace Bit.Core.Services if(additionalSeats > 0 && newPlan.StripeSeatPlanId != null) { - subUpdateOptions.Items.Add(new StripeSubscriptionItemUpdateOption + subUpdateOptions.Items.Add(new SubscriptionItemUpdateOption { PlanId = newPlan.StripeSeatPlanId, Quantity = additionalSeats @@ -333,8 +333,8 @@ namespace Bit.Core.Services } } - var subscriptionItemService = new StripeSubscriptionItemService(); - var subscriptionService = new StripeSubscriptionService(); + var subscriptionItemService = new SubscriptionItemService(); + var subscriptionService = new SubscriptionService(); var sub = await subscriptionService.GetAsync(organization.GatewaySubscriptionId); if(sub == null) { @@ -344,7 +344,7 @@ namespace Bit.Core.Services var seatItem = sub.Items?.Data?.FirstOrDefault(i => i.Plan.Id == plan.StripeSeatPlanId); if(additionalSeats > 0 && seatItem == null) { - await subscriptionItemService.CreateAsync(new StripeSubscriptionItemCreateOptions + await subscriptionItemService.CreateAsync(new SubscriptionItemCreateOptions { PlanId = plan.StripeSeatPlanId, Quantity = additionalSeats, @@ -354,7 +354,7 @@ namespace Bit.Core.Services } else if(additionalSeats > 0 && seatItem != null) { - await subscriptionItemService.UpdateAsync(seatItem.Id, new StripeSubscriptionItemUpdateOptions + await subscriptionItemService.UpdateAsync(seatItem.Id, new SubscriptionItemUpdateOptions { PlanId = plan.StripeSeatPlanId, Quantity = additionalSeats, @@ -389,7 +389,7 @@ namespace Bit.Core.Services } var bankService = new BankAccountService(); - var customerService = new StripeCustomerService(); + var customerService = new CustomerService(); var customer = await customerService.GetAsync(organization.GatewayCustomerId); if(customer == null) { @@ -397,7 +397,7 @@ namespace Bit.Core.Services } 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) { throw new GatewayException("Cannot find an unverified bank account."); @@ -406,7 +406,7 @@ namespace Bit.Core.Services try { var result = await bankService.VerifyAsync(organization.GatewayCustomerId, bankAccount.Id, - new BankAccountVerifyOptions { AmountOne = amount1, AmountTwo = amount2 }); + new BankAccountVerifyOptions { Amounts = new List { amount1, amount2 } }); if(result.Status != "verified") { throw new GatewayException("Unable to verify account."); @@ -453,10 +453,10 @@ namespace Bit.Core.Services $"{plan.MaxAdditionalSeats.GetValueOrDefault(0)} additional users."); } - var customerService = new StripeCustomerService(); - var subscriptionService = new StripeSubscriptionService(); - StripeCustomer customer = null; - StripeSubscription subscription = null; + var customerService = new CustomerService(); + var subscriptionService = new SubscriptionService(); + Customer customer = null; + Subscription subscription = null; // Pre-generate the org id so that we can save it with the Stripe subscription.. var newOrgId = CoreHelpers.GenerateComb(); @@ -472,18 +472,18 @@ namespace Bit.Core.Services } else { - customer = await customerService.CreateAsync(new StripeCustomerCreateOptions + customer = await customerService.CreateAsync(new CustomerCreateOptions { Description = signup.BusinessName, Email = signup.BillingEmail, SourceToken = signup.PaymentToken }); - var subCreateOptions = new StripeSubscriptionCreateOptions + var subCreateOptions = new SubscriptionCreateOptions { CustomerId = customer.Id, TrialPeriodDays = plan.TrialPeriodDays, - Items = new List(), + Items = new List(), Metadata = new Dictionary { { "organizationId", newOrgId.ToString() } } @@ -491,7 +491,7 @@ namespace Bit.Core.Services if(plan.StripePlanId != null) { - subCreateOptions.Items.Add(new StripeSubscriptionItemOption + subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = plan.StripePlanId, Quantity = 1 @@ -500,7 +500,7 @@ namespace Bit.Core.Services if(signup.AdditionalSeats > 0 && plan.StripeSeatPlanId != null) { - subCreateOptions.Items.Add(new StripeSubscriptionItemOption + subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = plan.StripeSeatPlanId, Quantity = signup.AdditionalSeats @@ -509,7 +509,7 @@ namespace Bit.Core.Services if(signup.AdditionalStorageGb > 0) { - subCreateOptions.Items.Add(new StripeSubscriptionItemOption + subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = plan.StripeStoragePlanId, Quantity = signup.AdditionalStorageGb @@ -518,7 +518,7 @@ namespace Bit.Core.Services if(signup.PremiumAccessAddon && plan.StripePremiumAccessPlanId != null) { - subCreateOptions.Items.Add(new StripeSubscriptionItemOption + subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = plan.StripePremiumAccessPlanId, Quantity = 1 @@ -630,7 +630,8 @@ namespace Bit.Core.Services var dir = $"{_globalSettings.LicenseDirectory}/organization"; 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; } @@ -756,7 +757,8 @@ namespace Bit.Core.Services var dir = $"{_globalSettings.LicenseDirectory}/organization"; 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.BusinessName = license.BusinessName; @@ -842,8 +844,8 @@ namespace Bit.Core.Services if(updateBilling && !string.IsNullOrWhiteSpace(organization.GatewayCustomerId)) { - var customerService = new StripeCustomerService(); - await customerService.UpdateAsync(organization.GatewayCustomerId, new StripeCustomerUpdateOptions + var customerService = new CustomerService(); + await customerService.UpdateAsync(organization.GatewayCustomerId, new CustomerUpdateOptions { Email = organization.BillingEmail, Description = organization.BusinessName diff --git a/src/Core/Services/Implementations/StripePaymentService.cs b/src/Core/Services/Implementations/StripePaymentService.cs index 1f34da4239..225d404f5a 100644 --- a/src/Core/Services/Implementations/StripePaymentService.cs +++ b/src/Core/Services/Implementations/StripePaymentService.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using Bit.Core.Exceptions; using System.Linq; using Bit.Core.Models.Business; -using Braintree; using Bit.Core.Enums; namespace Bit.Core.Services @@ -15,12 +14,12 @@ namespace Bit.Core.Services { private const string PremiumPlanId = "premium-annually"; private const string StoragePlanId = "storage-gb-annually"; - private readonly BraintreeGateway _btGateway; + private readonly Braintree.BraintreeGateway _btGateway; public StripePaymentService( GlobalSettings globalSettings) { - _btGateway = new BraintreeGateway + _btGateway = new Braintree.BraintreeGateway { Environment = globalSettings.Braintree.Production ? Braintree.Environment.PRODUCTION : Braintree.Environment.SANDBOX, @@ -33,16 +32,16 @@ namespace Bit.Core.Services public async Task PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken, short additionalStorageGb) { - Customer braintreeCustomer = null; - StripeBilling? stripeSubscriptionBilling = null; + Braintree.Customer braintreeCustomer = null; + Billing? stripeSubscriptionBilling = null; string stipeCustomerSourceToken = null; var stripeCustomerMetadata = new Dictionary(); if(paymentMethodType == PaymentMethodType.PayPal) { - stripeSubscriptionBilling = StripeBilling.SendInvoice; + stripeSubscriptionBilling = Billing.SendInvoice; 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, Email = user.Email, @@ -62,8 +61,8 @@ namespace Bit.Core.Services stipeCustomerSourceToken = paymentToken; } - var customerService = new StripeCustomerService(); - var customer = await customerService.CreateAsync(new StripeCustomerCreateOptions + var customerService = new CustomerService(); + var customer = await customerService.CreateAsync(new CustomerCreateOptions { Description = user.Name, Email = user.Email, @@ -71,19 +70,19 @@ namespace Bit.Core.Services Metadata = stripeCustomerMetadata }); - var subCreateOptions = new StripeSubscriptionCreateOptions + var subCreateOptions = new SubscriptionCreateOptions { CustomerId = customer.Id, - Items = new List(), + Items = new List(), Billing = stripeSubscriptionBilling, - DaysUntilDue = stripeSubscriptionBilling != null ? 1 : 0, + DaysUntilDue = stripeSubscriptionBilling != null ? 1 : (long?)null, Metadata = new Dictionary { ["userId"] = user.Id.ToString() } }; - subCreateOptions.Items.Add(new StripeSubscriptionItemOption + subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = PremiumPlanId, Quantity = 1 @@ -91,23 +90,23 @@ namespace Bit.Core.Services if(additionalStorageGb > 0) { - subCreateOptions.Items.Add(new StripeSubscriptionItemOption + subCreateOptions.Items.Add(new SubscriptionItemOption { PlanId = StoragePlanId, Quantity = additionalStorageGb }); } - StripeSubscription subscription = null; + Subscription subscription = null; try { - var subscriptionService = new StripeSubscriptionService(); + var subscriptionService = new SubscriptionService(); subscription = await subscriptionService.CreateAsync(subCreateOptions); - if(stripeSubscriptionBilling == StripeBilling.SendInvoice) + if(stripeSubscriptionBilling == Billing.SendInvoice) { - var invoiceService = new StripeInvoiceService(); - var invoices = await invoiceService.ListAsync(new StripeInvoiceListOptions + var invoiceService = new InvoiceService(); + var invoices = await invoiceService.ListAsync(new InvoiceListOptions { SubscriptionId = subscription.Id }); @@ -121,7 +120,7 @@ namespace Bit.Core.Services if(braintreeCustomer != null) { var btInvoiceAmount = (invoice.AmountDue / 100M); - var transactionResult = await _btGateway.Transaction.SaleAsync(new TransactionRequest + var transactionResult = await _btGateway.Transaction.SaleAsync(new Braintree.TransactionRequest { Amount = btInvoiceAmount, CustomerId = braintreeCustomer.Id @@ -132,8 +131,8 @@ namespace Bit.Core.Services throw new GatewayException("Failed to charge PayPal customer."); } - var invoiceItemService = new StripeInvoiceItemService(); - await invoiceItemService.CreateAsync(new StripeInvoiceItemCreateOptions + var invoiceItemService = new InvoiceItemService(); + await invoiceItemService.CreateAsync(new InvoiceItemCreateOptions { Currency = "USD", CustomerId = customer.Id, @@ -153,7 +152,7 @@ namespace Bit.Core.Services 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) @@ -176,8 +175,8 @@ namespace Bit.Core.Services public async Task AdjustStorageAsync(IStorableSubscriber storableSubscriber, int additionalStorage, string storagePlanId) { - var subscriptionItemService = new StripeSubscriptionItemService(); - var subscriptionService = new StripeSubscriptionService(); + var subscriptionItemService = new SubscriptionItemService(); + var subscriptionService = new SubscriptionService(); var sub = await subscriptionService.GetAsync(storableSubscriber.GatewaySubscriptionId); if(sub == null) { @@ -187,7 +186,7 @@ namespace Bit.Core.Services var storageItem = sub.Items?.Data?.FirstOrDefault(i => i.Plan.Id == storagePlanId); if(additionalStorage > 0 && storageItem == null) { - await subscriptionItemService.CreateAsync(new StripeSubscriptionItemCreateOptions + await subscriptionItemService.CreateAsync(new SubscriptionItemCreateOptions { PlanId = storagePlanId, Quantity = additionalStorage, @@ -197,7 +196,7 @@ namespace Bit.Core.Services } else if(additionalStorage > 0 && storageItem != null) { - await subscriptionItemService.UpdateAsync(storageItem.Id, new StripeSubscriptionItemUpdateOptions + await subscriptionItemService.UpdateAsync(storageItem.Id, new SubscriptionItemUpdateOptions { PlanId = storagePlanId, Quantity = additionalStorage, @@ -219,9 +218,9 @@ namespace Bit.Core.Services { if(!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId)) { - var subscriptionService = new StripeSubscriptionService(); + var subscriptionService = new SubscriptionService(); await subscriptionService.CancelAsync(subscriber.GatewaySubscriptionId, - new StripeSubscriptionCancelOptions()); + new SubscriptionCancelOptions()); } if(string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId)) @@ -229,36 +228,36 @@ namespace Bit.Core.Services return; } - var chargeService = new StripeChargeService(); - var charges = await chargeService.ListAsync(new StripeChargeListOptions + var chargeService = new ChargeService(); + var charges = await chargeService.ListAsync(new ChargeListOptions { CustomerId = subscriber.GatewayCustomerId }); if(charges?.Data != null) { - var refundService = new StripeRefundService(); + var refundService = new RefundService(); 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); } public async Task PreviewUpcomingInvoiceAndPayAsync(ISubscriber subscriber, string planId, int prorateThreshold = 500) { - var invoiceService = new StripeInvoiceService(); - var upcomingPreview = await invoiceService.UpcomingAsync(subscriber.GatewayCustomerId, - new StripeUpcomingInvoiceOptions - { - SubscriptionId = subscriber.GatewaySubscriptionId - }); + var invoiceService = new InvoiceService(); + var upcomingPreview = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions + { + CustomerId = subscriber.GatewayCustomerId, + 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); if(prorationAmount.GetValueOrDefault() >= prorateThreshold) { @@ -266,37 +265,38 @@ namespace Bit.Core.Services { // Owes more than prorateThreshold on next invoice. // Invoice them and pay now instead of waiting until next billing cycle. - var invoice = await invoiceService.CreateAsync(subscriber.GatewayCustomerId, - new StripeInvoiceCreateOptions - { - SubscriptionId = subscriber.GatewaySubscriptionId - }); + var invoice = await invoiceService.CreateAsync(new InvoiceCreateOptions + { + CustomerId = subscriber.GatewayCustomerId, + SubscriptionId = subscriber.GatewaySubscriptionId + }); if(invoice.AmountDue > 0) { - var customerService = new StripeCustomerService(); + var customerService = new CustomerService(); var customer = await customerService.GetAsync(subscriber.GatewayCustomerId); if(customer != null) { if(customer.Metadata.ContainsKey("btCustomerId")) { var invoiceAmount = (invoice.AmountDue / 100M); - var transactionResult = await _btGateway.Transaction.SaleAsync(new TransactionRequest - { - Amount = invoiceAmount, - CustomerId = customer.Metadata["btCustomerId"] - }); + var transactionResult = await _btGateway.Transaction.SaleAsync( + new Braintree.TransactionRequest + { + Amount = invoiceAmount, + CustomerId = customer.Metadata["btCustomerId"] + }); if(!transactionResult.IsSuccess() || transactionResult.Target.Amount != invoiceAmount) { - await invoiceService.UpdateAsync(invoice.Id, new StripeInvoiceUpdateOptions + await invoiceService.UpdateAsync(invoice.Id, new InvoiceUpdateOptions { Closed = true }); 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, 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) { } @@ -323,7 +323,7 @@ namespace Bit.Core.Services throw new GatewayException("No subscription."); } - var subscriptionService = new StripeSubscriptionService(); + var subscriptionService = new SubscriptionService(); var sub = await subscriptionService.GetAsync(subscriber.GatewaySubscriptionId); if(sub == null) { @@ -340,8 +340,8 @@ namespace Bit.Core.Services { var canceledSub = endOfPeriod ? await subscriptionService.UpdateAsync(sub.Id, - new StripeSubscriptionUpdateOptions { CancelAtPeriodEnd = true }) : - await subscriptionService.CancelAsync(sub.Id, new StripeSubscriptionCancelOptions()); + new SubscriptionUpdateOptions { CancelAtPeriodEnd = true }) : + await subscriptionService.CancelAsync(sub.Id, new SubscriptionCancelOptions()); if(!canceledSub.CanceledAt.HasValue) { throw new GatewayException("Unable to cancel subscription."); @@ -368,7 +368,7 @@ namespace Bit.Core.Services throw new GatewayException("No subscription."); } - var subscriptionService = new StripeSubscriptionService(); + var subscriptionService = new SubscriptionService(); var sub = await subscriptionService.GetAsync(subscriber.GatewaySubscriptionId); if(sub == null) { @@ -381,7 +381,7 @@ namespace Bit.Core.Services } var updatedSub = await subscriptionService.UpdateAsync(sub.Id, - new StripeSubscriptionUpdateOptions { CancelAtPeriodEnd = false }); + new SubscriptionUpdateOptions { CancelAtPeriodEnd = false }); if(updatedSub.CanceledAt.HasValue) { throw new GatewayException("Unable to reinstate subscription."); @@ -403,10 +403,10 @@ namespace Bit.Core.Services var updatedSubscriber = false; - var cardService = new StripeCardService(); + var cardService = new CardService(); var bankSerice = new BankAccountService(); - var customerService = new StripeCustomerService(); - StripeCustomer customer = null; + var customerService = new CustomerService(); + Customer customer = null; if(!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId)) { @@ -415,7 +415,7 @@ namespace Bit.Core.Services if(customer == null) { - customer = await customerService.CreateAsync(new StripeCustomerCreateOptions + customer = await customerService.CreateAsync(new CustomerCreateOptions { Description = subscriber.BillingName(), Email = subscriber.BillingEmailAddress(), @@ -437,7 +437,7 @@ namespace Bit.Core.Services } else { - await cardService.CreateAsync(customer.Id, new StripeCardCreateOptions + await cardService.CreateAsync(customer.Id, new CardCreateOptions { SourceToken = paymentToken }); @@ -446,11 +446,11 @@ namespace Bit.Core.Services if(!string.IsNullOrWhiteSpace(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); } - else if(source.Card != null) + else if(source is Card) { await cardService.DeleteAsync(customer.Id, customer.DefaultSourceId); } @@ -464,8 +464,8 @@ namespace Bit.Core.Services { if(!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId)) { - var subscriptionService = new StripeSubscriptionService(); - var invoiceService = new StripeInvoiceService(); + var subscriptionService = new SubscriptionService(); + var invoiceService = new InvoiceService(); var sub = await subscriptionService.GetAsync(subscriber.GatewaySubscriptionId); if(sub != null) { @@ -473,7 +473,10 @@ namespace Bit.Core.Services { try { - var upcomingInvoice = await invoiceService.UpcomingAsync(subscriber.GatewayCustomerId); + var upcomingInvoice = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions + { + CustomerId = subscriber.GatewayCustomerId + }); if(upcomingInvoice != null) { return new BillingInfo.BillingInvoice(upcomingInvoice); @@ -489,10 +492,10 @@ namespace Bit.Core.Services public async Task GetBillingAsync(ISubscriber subscriber) { var billingInfo = new BillingInfo(); - var customerService = new StripeCustomerService(); - var subscriptionService = new StripeSubscriptionService(); - var chargeService = new StripeChargeService(); - var invoiceService = new StripeInvoiceService(); + var customerService = new CustomerService(); + var subscriptionService = new SubscriptionService(); + var chargeService = new ChargeService(); + var invoiceService = new InvoiceService(); if(!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId)) { @@ -501,18 +504,10 @@ namespace Bit.Core.Services { 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); - if(source != null) - { - billingInfo.PaymentSource = new BillingInfo.BillingSource(source); - } - } - else if(customer.DefaultSourceId.StartsWith("ba_")) - { - var source = customer.Sources.Data - .FirstOrDefault(s => s.BankAccount?.Id == customer.DefaultSourceId); + var source = customer.Sources.Data.FirstOrDefault(s => + (s is Card || s is BankAccount) && s.Id == customer.DefaultSourceId); if(source != null) { 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, Limit = 20 @@ -542,7 +537,8 @@ namespace Bit.Core.Services { try { - var upcomingInvoice = await invoiceService.UpcomingAsync(subscriber.GatewayCustomerId); + var upcomingInvoice = await invoiceService.UpcomingAsync( + new UpcomingInvoiceOptions { CustomerId = subscriber.GatewayCustomerId }); if(upcomingInvoice != null) { billingInfo.UpcomingInvoice = new BillingInfo.BillingInvoice(upcomingInvoice);