1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-29 13:25:17 +01:00

inject stripepaymentservice

This commit is contained in:
Kyle Spearrin 2019-02-08 23:53:09 -05:00
parent a97a6216d7
commit d568b86e1e
12 changed files with 58 additions and 464 deletions

View File

@ -28,6 +28,7 @@ namespace Bit.Api.Controllers
private readonly ICipherService _cipherService;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly ILicensingService _licenseService;
private readonly IPaymentService _paymentService;
private readonly GlobalSettings _globalSettings;
public AccountsController(
@ -38,6 +39,7 @@ namespace Bit.Api.Controllers
ICipherService cipherService,
IOrganizationUserRepository organizationUserRepository,
ILicensingService licenseService,
IPaymentService paymentService,
GlobalSettings globalSettings)
{
_userService = userService;
@ -47,6 +49,7 @@ namespace Bit.Api.Controllers
_cipherService = cipherService;
_organizationUserRepository = organizationUserRepository;
_licenseService = licenseService;
_paymentService = paymentService;
_globalSettings = globalSettings;
}
@ -476,8 +479,7 @@ namespace Bit.Api.Controllers
if(!_globalSettings.SelfHosted && user.Gateway != null)
{
var paymentService = user.GetPaymentService(_globalSettings);
var billingInfo = await paymentService.GetBillingAsync(user);
var billingInfo = await _paymentService.GetBillingAsync(user);
var license = await _userService.GenerateLicenseAsync(user, billingInfo);
return new BillingResponseModel(user, billingInfo, license);
}

View File

@ -24,6 +24,7 @@ namespace Bit.Api.Controllers
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IOrganizationService _organizationService;
private readonly IUserService _userService;
private readonly IPaymentService _paymentService;
private readonly CurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
@ -32,6 +33,7 @@ namespace Bit.Api.Controllers
IOrganizationUserRepository organizationUserRepository,
IOrganizationService organizationService,
IUserService userService,
IPaymentService paymentService,
CurrentContext currentContext,
GlobalSettings globalSettings)
{
@ -39,6 +41,7 @@ namespace Bit.Api.Controllers
_organizationUserRepository = organizationUserRepository;
_organizationService = organizationService;
_userService = userService;
_paymentService = paymentService;
_currentContext = currentContext;
_globalSettings = globalSettings;
}
@ -78,8 +81,7 @@ namespace Bit.Api.Controllers
if(!_globalSettings.SelfHosted && organization.Gateway != null)
{
var paymentService = new StripePaymentService(_globalSettings);
var billingInfo = await paymentService.GetBillingAsync(organization);
var billingInfo = await _paymentService.GetBillingAsync(organization);
if(billingInfo == null)
{
throw new NotFoundException();

View File

@ -17,12 +17,14 @@ namespace Bit.Billing.Jobs
private readonly GlobalSettings _globalSettings;
private readonly IUserRepository _userRepository;
private readonly IMailService _mailService;
private readonly IPaymentService _paymentService;
public PremiumRenewalRemindersJob(
IOptions<BillingSettings> billingSettings,
GlobalSettings globalSettings,
IUserRepository userRepository,
IMailService mailService,
IPaymentService paymentService,
ILogger<PremiumRenewalRemindersJob> logger)
: base(logger)
{
@ -30,6 +32,7 @@ namespace Bit.Billing.Jobs
_globalSettings = globalSettings;
_userRepository = userRepository;
_mailService = mailService;
_paymentService = paymentService;
}
protected async override Task ExecuteJobAsync(IJobExecutionContext context)
@ -37,8 +40,7 @@ namespace Bit.Billing.Jobs
var users = await _userRepository.GetManyByPremiumRenewalAsync();
foreach(var user in users)
{
var paymentService = user.GetPaymentService(_globalSettings);
var upcomingInvoice = await paymentService.GetUpcomingInvoiceAsync(user);
var upcomingInvoice = await _paymentService.GetUpcomingInvoiceAsync(user);
if(upcomingInvoice?.Date != null)
{
var items = new List<string> { "1 × Premium Membership (Annually)" };

View File

@ -15,6 +15,5 @@ namespace Bit.Core.Models.Table
string BraintreeCustomerIdPrefix();
string BraintreeIdField();
string GatewayIdField();
IPaymentService GetPaymentService(GlobalSettings globalSettings);
}
}

View File

@ -99,29 +99,6 @@ namespace Bit.Core.Models.Table
return maxStorageBytes - Storage.Value;
}
public IPaymentService GetPaymentService(GlobalSettings globalSettings)
{
if(Gateway == null)
{
throw new BadRequestException("No gateway.");
}
IPaymentService paymentService = null;
switch(Gateway)
{
case GatewayType.Stripe:
paymentService = new StripePaymentService(globalSettings);
break;
case GatewayType.Braintree:
paymentService = new BraintreePaymentService(globalSettings);
break;
default:
throw new NotSupportedException("Unsupported gateway.");
}
return paymentService;
}
public Dictionary<TwoFactorProviderType, TwoFactorProvider> GetTwoFactorProviders()
{
if(string.IsNullOrWhiteSpace(TwoFactorProviders))

View File

@ -148,29 +148,6 @@ namespace Bit.Core.Models.Table
return maxStorageBytes - Storage.Value;
}
public IPaymentService GetPaymentService(GlobalSettings globalSettings)
{
if(Gateway == null)
{
throw new BadRequestException("No gateway.");
}
IPaymentService paymentService = null;
switch(Gateway)
{
case GatewayType.Stripe:
paymentService = new StripePaymentService(globalSettings);
break;
case GatewayType.Braintree:
paymentService = new BraintreePaymentService(globalSettings);
break;
default:
throw new NotSupportedException("Unsupported gateway.");
}
return paymentService;
}
public IdentityUser ToIdentityUser(bool twoFactorEnabled)
{
return new IdentityUser

View File

@ -8,6 +8,8 @@ namespace Bit.Core.Services
public interface IPaymentService
{
Task CancelAndRecoverChargesAsync(ISubscriber subscriber);
Task PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType, string paymentToken,
Models.StaticStore.Plan plan, short additionalStorageGb, short additionalSeats, bool premiumAccessAddon);
Task PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken,
short additionalStorageGb);
Task AdjustStorageAsync(IStorableSubscriber storableSubscriber, int additionalStorage, string storagePlanId);

View File

@ -1,386 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Bit.Core.Models.Table;
using Braintree;
using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.Enums;
using System.Collections.Generic;
namespace Bit.Core.Services
{
public class BraintreePaymentService : IPaymentService
{
private const string PremiumPlanId = "premium-annually";
private const string StoragePlanId = "storage-gb-annually";
private readonly BraintreeGateway _gateway;
public BraintreePaymentService(
GlobalSettings globalSettings)
{
_gateway = new BraintreeGateway
{
Environment = globalSettings.Braintree.Production ?
Braintree.Environment.PRODUCTION : Braintree.Environment.SANDBOX,
MerchantId = globalSettings.Braintree.MerchantId,
PublicKey = globalSettings.Braintree.PublicKey,
PrivateKey = globalSettings.Braintree.PrivateKey
};
}
public async Task AdjustStorageAsync(IStorableSubscriber storableSubscriber, int additionalStorage, string storagePlanId)
{
var sub = await _gateway.Subscription.FindAsync(storableSubscriber.GatewaySubscriptionId);
if(sub == null)
{
throw new GatewayException("Subscription was not found.");
}
var req = new SubscriptionRequest
{
AddOns = new AddOnsRequest(),
Options = new SubscriptionOptionsRequest
{
ProrateCharges = true,
RevertSubscriptionOnProrationFailure = true
}
};
var storageItem = sub.AddOns?.FirstOrDefault(a => a.Id == storagePlanId);
if(additionalStorage > 0 && storageItem == null)
{
req.AddOns.Add = new AddAddOnRequest[]
{
new AddAddOnRequest
{
InheritedFromId = storagePlanId,
Quantity = additionalStorage,
NeverExpires = true
}
};
}
else if(additionalStorage > 0 && storageItem != null)
{
req.AddOns.Update = new UpdateAddOnRequest[]
{
new UpdateAddOnRequest
{
ExistingId = storageItem.Id,
Quantity = additionalStorage,
NeverExpires = true
}
};
}
else if(additionalStorage == 0 && storageItem != null)
{
req.AddOns.Remove = new string[] { storageItem.Id };
}
var result = await _gateway.Subscription.UpdateAsync(sub.Id, req);
if(!result.IsSuccess())
{
throw new GatewayException("Failed to adjust storage.");
}
}
public async Task CancelAndRecoverChargesAsync(ISubscriber subscriber)
{
if(!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId))
{
await _gateway.Subscription.CancelAsync(subscriber.GatewaySubscriptionId);
}
if(string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId))
{
return;
}
var transactionRequest = new TransactionSearchRequest().CustomerId.Is(subscriber.GatewayCustomerId);
var transactions = _gateway.Transaction.Search(transactionRequest);
if((transactions?.MaximumCount ?? 0) > 0)
{
var txs = transactions.Cast<Braintree.Transaction>().Where(c => c.RefundedTransactionId == null);
foreach(var transaction in txs)
{
await _gateway.Transaction.RefundAsync(transaction.Id);
}
}
await _gateway.Customer.DeleteAsync(subscriber.GatewayCustomerId);
}
public async Task CancelSubscriptionAsync(ISubscriber subscriber, bool endOfPeriod = false)
{
if(subscriber == null)
{
throw new ArgumentNullException(nameof(subscriber));
}
if(string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId))
{
throw new GatewayException("No subscription.");
}
var sub = await _gateway.Subscription.FindAsync(subscriber.GatewaySubscriptionId);
if(sub == null)
{
throw new GatewayException("Subscription was not found.");
}
if(sub.Status == SubscriptionStatus.CANCELED || sub.Status == SubscriptionStatus.EXPIRED ||
!sub.NeverExpires.GetValueOrDefault())
{
throw new GatewayException("Subscription is already canceled.");
}
if(endOfPeriod)
{
var req = new SubscriptionRequest
{
NeverExpires = false,
NumberOfBillingCycles = sub.CurrentBillingCycle
};
var result = await _gateway.Subscription.UpdateAsync(subscriber.GatewaySubscriptionId, req);
if(!result.IsSuccess())
{
throw new GatewayException("Unable to cancel subscription.");
}
}
else
{
var result = await _gateway.Subscription.CancelAsync(subscriber.GatewaySubscriptionId);
if(!result.IsSuccess())
{
throw new GatewayException("Unable to cancel subscription.");
}
}
}
public async Task<BillingInfo.BillingInvoice> GetUpcomingInvoiceAsync(ISubscriber subscriber)
{
if(!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId))
{
var sub = await _gateway.Subscription.FindAsync(subscriber.GatewaySubscriptionId);
if(sub != null)
{
var cancelAtEndDate = !sub.NeverExpires.GetValueOrDefault();
var canceled = sub.Status == SubscriptionStatus.CANCELED;
if(!canceled && !cancelAtEndDate && sub.NextBillingDate.HasValue)
{
return new BillingInfo.BillingInvoice(sub);
}
}
}
return null;
}
public async Task<BillingInfo> GetBillingAsync(ISubscriber subscriber)
{
var billingInfo = new BillingInfo();
if(!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId))
{
var customer = await _gateway.Customer.FindAsync(subscriber.GatewayCustomerId);
if(customer != null)
{
if(customer.DefaultPaymentMethod != null)
{
billingInfo.PaymentSource = new BillingInfo.BillingSource(customer.DefaultPaymentMethod);
}
var transactionRequest = new TransactionSearchRequest().CustomerId.Is(customer.Id);
var transactions = _gateway.Transaction.Search(transactionRequest);
billingInfo.Charges = transactions?.Cast<Braintree.Transaction>()
.OrderByDescending(t => t.CreatedAt).Select(t => new BillingInfo.BillingCharge(t));
}
}
if(!string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId))
{
var sub = await _gateway.Subscription.FindAsync(subscriber.GatewaySubscriptionId);
if(sub != null)
{
var plans = await _gateway.Plan.AllAsync();
var plan = plans?.FirstOrDefault(p => p.Id == sub.PlanId);
billingInfo.Subscription = new BillingInfo.BillingSubscription(sub, plan);
}
if(!billingInfo.Subscription.Cancelled && !billingInfo.Subscription.CancelAtEndDate &&
sub.NextBillingDate.HasValue)
{
billingInfo.UpcomingInvoice = new BillingInfo.BillingInvoice(sub);
}
}
return billingInfo;
}
public async Task PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken,
short additionalStorageGb)
{
var customerResult = await _gateway.Customer.CreateAsync(new CustomerRequest
{
PaymentMethodNonce = paymentToken,
Email = user.Email,
CustomFields = new Dictionary<string, string>
{
[user.BraintreeIdField()] = user.Id.ToString()
}
});
if(!customerResult.IsSuccess() || customerResult.Target.PaymentMethods.Length == 0)
{
throw new GatewayException("Failed to create customer.");
}
var subId = user.BraintreeCustomerIdPrefix() + user.Id.ToString("N").ToLower() +
Utilities.CoreHelpers.RandomString(3, upper: false, numeric: false);
var subRequest = new SubscriptionRequest
{
Id = subId,
PaymentMethodToken = customerResult.Target.PaymentMethods[0].Token,
PlanId = PremiumPlanId
};
if(additionalStorageGb > 0)
{
subRequest.AddOns = new AddOnsRequest();
subRequest.AddOns.Add = new AddAddOnRequest[]
{
new AddAddOnRequest
{
InheritedFromId = StoragePlanId,
Quantity = additionalStorageGb
}
};
}
var subResult = await _gateway.Subscription.CreateAsync(subRequest);
if(!subResult.IsSuccess())
{
await _gateway.Customer.DeleteAsync(customerResult.Target.Id);
throw new GatewayException("Failed to create subscription.");
}
user.Gateway = Enums.GatewayType.Braintree;
user.GatewayCustomerId = customerResult.Target.Id;
user.GatewaySubscriptionId = subResult.Target.Id;
user.Premium = true;
user.PremiumExpirationDate = subResult.Target.BillingPeriodEndDate;
}
public async Task ReinstateSubscriptionAsync(ISubscriber subscriber)
{
if(subscriber == null)
{
throw new ArgumentNullException(nameof(subscriber));
}
if(string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId))
{
throw new GatewayException("No subscription.");
}
var sub = await _gateway.Subscription.FindAsync(subscriber.GatewaySubscriptionId);
if(sub == null)
{
throw new GatewayException("Subscription was not found.");
}
if(sub.Status != SubscriptionStatus.ACTIVE || sub.NeverExpires.GetValueOrDefault())
{
throw new GatewayException("Subscription is not marked for cancellation.");
}
var req = new SubscriptionRequest
{
NeverExpires = true,
NumberOfBillingCycles = null
};
var result = await _gateway.Subscription.UpdateAsync(subscriber.GatewaySubscriptionId, req);
if(!result.IsSuccess())
{
throw new GatewayException("Unable to reinstate subscription.");
}
}
public async Task<bool> UpdatePaymentMethodAsync(ISubscriber subscriber, PaymentMethodType paymentMethodType,
string paymentToken)
{
if(subscriber == null)
{
throw new ArgumentNullException(nameof(subscriber));
}
if(paymentMethodType != PaymentMethodType.PayPal)
{
throw new GatewayException("Payment method not allowed");
}
if(subscriber.Gateway.HasValue && subscriber.Gateway.Value != GatewayType.Braintree)
{
throw new GatewayException("Switching from one payment type to another is not supported. " +
"Contact us for assistance.");
}
var updatedSubscriber = false;
Customer customer = null;
if(!string.IsNullOrWhiteSpace(subscriber.GatewayCustomerId))
{
customer = await _gateway.Customer.FindAsync(subscriber.GatewayCustomerId);
}
if(customer == null)
{
var result = await _gateway.Customer.CreateAsync(new CustomerRequest
{
Email = subscriber.BillingEmailAddress(),
PaymentMethodNonce = paymentToken,
CustomFields = new Dictionary<string, string>
{
[subscriber.BraintreeIdField()] = subscriber.Id.ToString()
}
});
if(!result.IsSuccess())
{
throw new GatewayException("Cannot create customer.");
}
customer = result.Target;
subscriber.Gateway = Enums.GatewayType.Braintree;
subscriber.GatewayCustomerId = customer.Id;
updatedSubscriber = true;
}
else
{
if(customer.DefaultPaymentMethod != null)
{
var deleteResult = await _gateway.PaymentMethod.DeleteAsync(customer.DefaultPaymentMethod.Token);
if(!deleteResult.IsSuccess())
{
throw new GatewayException("Cannot delete old payment method.");
}
}
var result = await _gateway.PaymentMethod.CreateAsync(new PaymentMethodRequest
{
PaymentMethodNonce = paymentToken,
CustomerId = customer.Id
});
if(!result.IsSuccess())
{
throw new GatewayException("Cannot add new payment method.");
}
}
return updatedSubscriber;
}
}
}

View File

@ -32,7 +32,7 @@ namespace Bit.Core.Services
private readonly IEventService _eventService;
private readonly IInstallationRepository _installationRepository;
private readonly IApplicationCacheService _applicationCacheService;
private readonly StripePaymentService _stripePaymentService;
private readonly IPaymentService _paymentService;
private readonly GlobalSettings _globalSettings;
public OrganizationService(
@ -50,6 +50,7 @@ namespace Bit.Core.Services
IEventService eventService,
IInstallationRepository installationRepository,
IApplicationCacheService applicationCacheService,
IPaymentService paymentService,
GlobalSettings globalSettings)
{
_organizationRepository = organizationRepository;
@ -66,7 +67,7 @@ namespace Bit.Core.Services
_eventService = eventService;
_installationRepository = installationRepository;
_applicationCacheService = applicationCacheService;
_stripePaymentService = new StripePaymentService(globalSettings);
_paymentService = paymentService;
_globalSettings = globalSettings;
}
@ -92,7 +93,7 @@ namespace Bit.Core.Services
paymentMethodType = PaymentMethodType.PayPal;
}
var updated = await _stripePaymentService.UpdatePaymentMethodAsync(organization,
var updated = await _paymentService.UpdatePaymentMethodAsync(organization,
paymentMethodType, paymentToken);
if(updated)
{
@ -115,7 +116,7 @@ namespace Bit.Core.Services
eop = false;
}
await _stripePaymentService.CancelSubscriptionAsync(organization, eop);
await _paymentService.CancelSubscriptionAsync(organization, eop);
}
public async Task ReinstateSubscriptionAsync(Guid organizationId)
@ -126,7 +127,7 @@ namespace Bit.Core.Services
throw new NotFoundException();
}
await _stripePaymentService.ReinstateSubscriptionAsync(organization);
await _paymentService.ReinstateSubscriptionAsync(organization);
}
public async Task UpgradePlanAsync(Guid organizationId, PlanType plan, int additionalSeats)
@ -286,7 +287,7 @@ namespace Bit.Core.Services
throw new BadRequestException("Plan does not allow additional storage.");
}
await BillingHelpers.AdjustStorageAsync(_stripePaymentService, organization, storageAdjustmentGb,
await BillingHelpers.AdjustStorageAsync(_paymentService, organization, storageAdjustmentGb,
plan.StripeStoragePlanId);
await ReplaceAndUpdateCache(organization);
}
@ -411,7 +412,7 @@ namespace Bit.Core.Services
var invoicedNow = false;
if(additionalSeats > 0)
{
invoicedNow = await _stripePaymentService.PreviewUpcomingInvoiceAndPayAsync(
invoicedNow = await (_paymentService as StripePaymentService).PreviewUpcomingInvoiceAndPayAsync(
organization, plan.StripeSeatPlanId, subItemOptions, 500);
}
@ -561,7 +562,7 @@ namespace Bit.Core.Services
paymentMethodType = PaymentMethodType.PayPal;
}
await _stripePaymentService.PurchaseOrganizationAsync(organization, paymentMethodType,
await _paymentService.PurchaseOrganizationAsync(organization, paymentMethodType,
signup.PaymentToken, plan, signup.AdditionalStorageGb, signup.AdditionalSeats,
signup.PremiumAccessAddon);
}
@ -676,7 +677,7 @@ namespace Bit.Core.Services
{
if(withPayment)
{
await _stripePaymentService.CancelAndRecoverChargesAsync(organization);
await _paymentService.CancelAndRecoverChargesAsync(organization);
}
if(organization.Id != default(Guid))
@ -785,7 +786,7 @@ namespace Bit.Core.Services
{
var eop = !organization.ExpirationDate.HasValue ||
organization.ExpirationDate.Value >= DateTime.UtcNow;
await _stripePaymentService.CancelSubscriptionAsync(organization, eop);
await _paymentService.CancelSubscriptionAsync(organization, eop);
}
catch(GatewayException) { }
}
@ -1206,8 +1207,7 @@ namespace Bit.Core.Services
throw new BadRequestException("Invalid installation id");
}
var paymentService = new StripePaymentService(_globalSettings);
var billingInfo = await paymentService.GetBillingAsync(organization);
var billingInfo = await _paymentService.GetBillingAsync(organization);
return new OrganizationLicense(organization, billingInfo, installationId, _licensingService);
}

View File

@ -7,6 +7,7 @@ using Bit.Core.Exceptions;
using System.Linq;
using Bit.Core.Models.Business;
using Bit.Core.Enums;
using Bit.Core.Repositories;
namespace Bit.Core.Services
{
@ -15,9 +16,11 @@ namespace Bit.Core.Services
private const string PremiumPlanId = "premium-annually";
private const string StoragePlanId = "storage-gb-annually";
private readonly ITransactionRepository _transactionRepository;
private readonly Braintree.BraintreeGateway _btGateway;
public StripePaymentService(
ITransactionRepository transactionRepository,
GlobalSettings globalSettings)
{
_btGateway = new Braintree.BraintreeGateway
@ -28,6 +31,7 @@ namespace Bit.Core.Services
PublicKey = globalSettings.Braintree.PublicKey,
PrivateKey = globalSettings.Braintree.PrivateKey
};
_transactionRepository = transactionRepository;
}
public async Task PurchaseOrganizationAsync(Organization org, PaymentMethodType paymentMethodType,
@ -912,6 +916,22 @@ namespace Bit.Core.Services
public async Task<BillingInfo> GetBillingAsync(ISubscriber subscriber)
{
var billingInfo = new BillingInfo();
ICollection<Transaction> transactions = null;
if(subscriber is User)
{
transactions = await _transactionRepository.GetManyByUserIdAsync(subscriber.Id);
}
else if(subscriber is Organization)
{
transactions = await _transactionRepository.GetManyByOrganizationIdAsync(subscriber.Id);
}
if(transactions != null)
{
billingInfo.Transactions = transactions?.OrderByDescending(i => i.CreationDate)
.Select(t => new BillingInfo.BillingTransaction(t));
}
var customerService = new CustomerService();
var subscriptionService = new SubscriptionService();
var chargeService = new ChargeService();

View File

@ -42,6 +42,7 @@ namespace Bit.Core.Services
private readonly ILicensingService _licenseService;
private readonly IEventService _eventService;
private readonly IApplicationCacheService _applicationCacheService;
private readonly IPaymentService _paymentService;
private readonly IDataProtector _organizationServiceDataProtector;
private readonly CurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
@ -67,6 +68,7 @@ namespace Bit.Core.Services
IEventService eventService,
IApplicationCacheService applicationCacheService,
IDataProtectionProvider dataProtectionProvider,
IPaymentService paymentService,
CurrentContext currentContext,
GlobalSettings globalSettings)
: base(
@ -94,6 +96,7 @@ namespace Bit.Core.Services
_licenseService = licenseService;
_eventService = eventService;
_applicationCacheService = applicationCacheService;
_paymentService = paymentService;
_organizationServiceDataProtector = dataProtectionProvider.CreateProtector(
"OrganizationServiceDataProtector");
_currentContext = currentContext;
@ -717,7 +720,7 @@ namespace Bit.Core.Services
paymentMethodType = PaymentMethodType.PayPal;
}
await new StripePaymentService(_globalSettings).PurchasePremiumAsync(user, paymentMethodType,
await _paymentService.PurchasePremiumAsync(user, paymentMethodType,
paymentToken, additionalStorageGb);
}
else
@ -793,8 +796,7 @@ namespace Bit.Core.Services
throw new BadRequestException("Not a premium user.");
}
var paymentService = user.GetPaymentService(_globalSettings);
await BillingHelpers.AdjustStorageAsync(paymentService, user, storageAdjustmentGb, StoragePlanId);
await BillingHelpers.AdjustStorageAsync(_paymentService, user, storageAdjustmentGb, StoragePlanId);
await SaveUserAsync(user);
}
@ -806,7 +808,6 @@ namespace Bit.Core.Services
}
PaymentMethodType paymentMethodType;
var paymentService = new StripePaymentService(_globalSettings);
if(paymentToken.StartsWith("tok_"))
{
paymentMethodType = PaymentMethodType.Card;
@ -816,7 +817,7 @@ namespace Bit.Core.Services
paymentMethodType = PaymentMethodType.PayPal;
}
var updated = await paymentService.UpdatePaymentMethodAsync(user, paymentMethodType, paymentToken);
var updated = await _paymentService.UpdatePaymentMethodAsync(user, paymentMethodType, paymentToken);
if(updated)
{
await SaveUserAsync(user);
@ -825,20 +826,18 @@ namespace Bit.Core.Services
public async Task CancelPremiumAsync(User user, bool? endOfPeriod = null)
{
var paymentService = user.GetPaymentService(_globalSettings);
var eop = endOfPeriod.GetValueOrDefault(true);
if(!endOfPeriod.HasValue && user.PremiumExpirationDate.HasValue &&
user.PremiumExpirationDate.Value < DateTime.UtcNow)
{
eop = false;
}
await paymentService.CancelSubscriptionAsync(user, eop);
await _paymentService.CancelSubscriptionAsync(user, eop);
}
public async Task ReinstatePremiumAsync(User user)
{
var paymentService = user.GetPaymentService(_globalSettings);
await paymentService.ReinstateSubscriptionAsync(user);
await _paymentService.ReinstateSubscriptionAsync(user);
}
public async Task DisablePremiumAsync(Guid userId, DateTime? expirationDate)
@ -878,8 +877,7 @@ namespace Bit.Core.Services
if(billingInfo == null && user.Gateway != null)
{
var paymentService = user.GetPaymentService(_globalSettings);
billingInfo = await paymentService.GetBillingAsync(user);
billingInfo = await _paymentService.GetBillingAsync(user);
}
return billingInfo == null ? new UserLicense(user, _licenseService) :

View File

@ -78,6 +78,7 @@ namespace Bit.Core.Utilities
public static void AddDefaultServices(this IServiceCollection services, GlobalSettings globalSettings)
{
services.AddSingleton<IPaymentService, StripePaymentService>();
services.AddSingleton<IMailService, HandlebarsMailService>();
services.AddSingleton<ILicensingService, LicensingService>();
services.AddSingleton<IApplicationCacheService, InMemoryApplicationCacheService>();