1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-04 01:22:50 -05:00

[AC-2959] ACH Direct Debit POC (#4703)

* Refactor: Rename some methods and models for consistency

This commit contains no logic changes at all. It's entirely comprised of renames of existing models and methods to bring our codebase more in line with our app's functionality and terminology.

* Add feature flag: AC-2476-deprecate-stripe-sources-api

* Standardize error responses from applicable billing controllers

During my work on CB, I found that just using the built-in TypedResults errors results in the client choking on the response because it's looking for the ErrroResponseModel. The new BaseBillingController provides Error utilities to return TypedResults wrapping that model so the client can process it.

* Add feature flagged payment method endoints to OrganizationBillingController

* Run dotnet format
This commit is contained in:
Alex Morask
2024-08-28 10:48:14 -04:00
committed by GitHub
parent 20478949d8
commit 3c86ec6a35
31 changed files with 391 additions and 197 deletions

View File

@ -11,7 +11,7 @@ public class OrganizationBillingService(
IOrganizationRepository organizationRepository,
ISubscriberService subscriberService) : IOrganizationBillingService
{
public async Task<OrganizationMetadataDTO> GetMetadata(Guid organizationId)
public async Task<OrganizationMetadata> GetMetadata(Guid organizationId)
{
var organization = await organizationRepository.GetByIdAsync(organizationId);
@ -29,12 +29,12 @@ public class OrganizationBillingService(
if (customer == null || subscription == null)
{
return OrganizationMetadataDTO.Default();
return OrganizationMetadata.Default();
}
var isOnSecretsManagerStandalone = IsOnSecretsManagerStandalone(organization, customer, subscription);
return new OrganizationMetadataDTO(isOnSecretsManagerStandalone);
return new OrganizationMetadata(isOnSecretsManagerStandalone);
}
private static bool IsOnSecretsManagerStandalone(

View File

@ -11,6 +11,7 @@ using Stripe;
using static Bit.Core.Billing.Utilities;
using Customer = Stripe.Customer;
using PaymentMethod = Bit.Core.Billing.Models.PaymentMethod;
using Subscription = Stripe.Subscription;
namespace Bit.Core.Billing.Services.Implementations;
@ -175,34 +176,34 @@ public class SubscriberService(
}
}
public async Task<PaymentInformationDTO> GetPaymentInformation(
public async Task<PaymentMethod> GetPaymentMethod(
ISubscriber subscriber)
{
ArgumentNullException.ThrowIfNull(subscriber);
var customer = await GetCustomer(subscriber, new CustomerGetOptions
var customer = await GetCustomerOrThrow(subscriber, new CustomerGetOptions
{
Expand = ["default_source", "invoice_settings.default_payment_method", "tax_ids"]
Expand = ["default_source", "invoice_settings.default_payment_method", "subscriptions", "tax_ids"]
});
if (customer == null)
{
return null;
}
var accountCredit = customer.Balance * -1 / 100;
var paymentMethod = await GetMaskedPaymentMethodDTOAsync(subscriber.Id, customer);
var paymentMethod = await GetPaymentSourceAsync(subscriber.Id, customer);
var taxInformation = GetTaxInformationDTOFrom(customer);
var subscriptionStatus = customer.Subscriptions
.FirstOrDefault(subscription => subscription.Id == subscriber.GatewaySubscriptionId)?
.Status;
return new PaymentInformationDTO(
var taxInformation = GetTaxInformation(customer);
return new PaymentMethod(
accountCredit,
paymentMethod,
subscriptionStatus,
taxInformation);
}
public async Task<MaskedPaymentMethodDTO> GetPaymentMethod(
public async Task<PaymentSource> GetPaymentSource(
ISubscriber subscriber)
{
ArgumentNullException.ThrowIfNull(subscriber);
@ -212,7 +213,7 @@ public class SubscriberService(
Expand = ["default_source", "invoice_settings.default_payment_method"]
});
return await GetMaskedPaymentMethodDTOAsync(subscriber.Id, customer);
return await GetPaymentSourceAsync(subscriber.Id, customer);
}
public async Task<Subscription> GetSubscription(
@ -296,10 +297,10 @@ public class SubscriberService(
var customer = await GetCustomerOrThrow(subscriber, new CustomerGetOptions { Expand = ["tax_ids"] });
return GetTaxInformationDTOFrom(customer);
return GetTaxInformation(customer);
}
public async Task RemovePaymentMethod(
public async Task RemovePaymentSource(
ISubscriber subscriber)
{
ArgumentNullException.ThrowIfNull(subscriber);
@ -391,16 +392,16 @@ public class SubscriberService(
}
}
public async Task UpdatePaymentMethod(
public async Task UpdatePaymentSource(
ISubscriber subscriber,
TokenizedPaymentMethodDTO tokenizedPaymentMethod)
TokenizedPaymentSource tokenizedPaymentSource)
{
ArgumentNullException.ThrowIfNull(subscriber);
ArgumentNullException.ThrowIfNull(tokenizedPaymentMethod);
ArgumentNullException.ThrowIfNull(tokenizedPaymentSource);
var customer = await GetCustomerOrThrow(subscriber);
var (type, token) = tokenizedPaymentMethod;
var (type, token) = tokenizedPaymentSource;
if (string.IsNullOrEmpty(token))
{
@ -678,7 +679,7 @@ public class SubscriberService(
throw new BillingException();
}
private async Task<MaskedPaymentMethodDTO> GetMaskedPaymentMethodDTOAsync(
private async Task<PaymentSource> GetPaymentSourceAsync(
Guid subscriberId,
Customer customer)
{
@ -690,11 +691,11 @@ public class SubscriberService(
{
var braintreeCustomer = await braintreeGateway.Customer.FindAsync(braintreeCustomerId);
return MaskedPaymentMethodDTO.From(braintreeCustomer);
return PaymentSource.From(braintreeCustomer);
}
}
var attachedPaymentMethodDTO = MaskedPaymentMethodDTO.From(customer);
var attachedPaymentMethodDTO = PaymentSource.From(customer);
if (attachedPaymentMethodDTO != null)
{
@ -717,10 +718,10 @@ public class SubscriberService(
Expand = ["payment_method"]
});
return MaskedPaymentMethodDTO.From(setupIntent);
return PaymentSource.From(setupIntent);
}
private static TaxInformation GetTaxInformationDTOFrom(
private static TaxInformation GetTaxInformation(
Customer customer)
{
if (customer.Address == null)