mirror of
https://github.com/bitwarden/server.git
synced 2025-05-20 19:14:32 -05:00
Handle case where Stripe IDs do not relate to Stripe entities (#4021)
This commit is contained in:
parent
78b57ba99f
commit
f7aa56b324
@ -24,16 +24,27 @@ public class SubscriberQueries(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions);
|
try
|
||||||
|
|
||||||
if (customer != null)
|
|
||||||
{
|
{
|
||||||
return customer;
|
var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions);
|
||||||
|
|
||||||
|
if (customer != null)
|
||||||
|
{
|
||||||
|
return customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.LogError("Could not find Stripe customer ({CustomerID}) for subscriber ({SubscriberID})",
|
||||||
|
subscriber.GatewayCustomerId, subscriber.Id);
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
catch (StripeException exception)
|
||||||
|
{
|
||||||
|
logger.LogError("An error occurred while trying to retrieve Stripe customer ({CustomerID}) for subscriber ({SubscriberID}): {Error}",
|
||||||
|
subscriber.GatewayCustomerId, subscriber.Id, exception.Message);
|
||||||
|
|
||||||
logger.LogError("Could not find Stripe customer ({CustomerID}) for subscriber ({SubscriberID})", subscriber.GatewayCustomerId, subscriber.Id);
|
return null;
|
||||||
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Subscription> GetSubscription(
|
public async Task<Subscription> GetSubscription(
|
||||||
@ -49,41 +60,28 @@ public class SubscriberQueries(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var subscription = await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions);
|
try
|
||||||
|
|
||||||
if (subscription != null)
|
|
||||||
{
|
{
|
||||||
return subscription;
|
var subscription =
|
||||||
|
await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions);
|
||||||
|
|
||||||
|
if (subscription != null)
|
||||||
|
{
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.LogError("Could not find Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID})",
|
||||||
|
subscriber.GatewaySubscriptionId, subscriber.Id);
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
catch (StripeException exception)
|
||||||
logger.LogError("Could not find Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID})", subscriber.GatewaySubscriptionId, subscriber.Id);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Subscription> GetSubscriptionOrThrow(
|
|
||||||
ISubscriber subscriber,
|
|
||||||
SubscriptionGetOptions subscriptionGetOptions = null)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(subscriber);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(subscriber.GatewaySubscriptionId))
|
|
||||||
{
|
{
|
||||||
logger.LogError("Cannot retrieve subscription for subscriber ({SubscriberID}) with no {FieldName}", subscriber.Id, nameof(subscriber.GatewaySubscriptionId));
|
logger.LogError("An error occurred while trying to retrieve Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID}): {Error}",
|
||||||
|
subscriber.GatewaySubscriptionId, subscriber.Id, exception.Message);
|
||||||
|
|
||||||
throw ContactSupport();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var subscription = await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions);
|
|
||||||
|
|
||||||
if (subscription != null)
|
|
||||||
{
|
|
||||||
return subscription;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.LogError("Could not find Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID})", subscriber.GatewaySubscriptionId, subscriber.Id);
|
|
||||||
|
|
||||||
throw ContactSupport();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Customer> GetCustomerOrThrow(
|
public async Task<Customer> GetCustomerOrThrow(
|
||||||
@ -99,15 +97,63 @@ public class SubscriberQueries(
|
|||||||
throw ContactSupport();
|
throw ContactSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions);
|
try
|
||||||
|
|
||||||
if (customer != null)
|
|
||||||
{
|
{
|
||||||
return customer;
|
var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions);
|
||||||
|
|
||||||
|
if (customer != null)
|
||||||
|
{
|
||||||
|
return customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.LogError("Could not find Stripe customer ({CustomerID}) for subscriber ({SubscriberID})",
|
||||||
|
subscriber.GatewayCustomerId, subscriber.Id);
|
||||||
|
|
||||||
|
throw ContactSupport();
|
||||||
|
}
|
||||||
|
catch (StripeException exception)
|
||||||
|
{
|
||||||
|
logger.LogError("An error occurred while trying to retrieve Stripe customer ({CustomerID}) for subscriber ({SubscriberID}): {Error}",
|
||||||
|
subscriber.GatewayCustomerId, subscriber.Id, exception.Message);
|
||||||
|
|
||||||
|
throw ContactSupport("An error occurred while trying to retrieve a Stripe Customer", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Subscription> GetSubscriptionOrThrow(
|
||||||
|
ISubscriber subscriber,
|
||||||
|
SubscriptionGetOptions subscriptionGetOptions = null)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(subscriber);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(subscriber.GatewaySubscriptionId))
|
||||||
|
{
|
||||||
|
logger.LogError("Cannot retrieve subscription for subscriber ({SubscriberID}) with no {FieldName}", subscriber.Id, nameof(subscriber.GatewaySubscriptionId));
|
||||||
|
|
||||||
|
throw ContactSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LogError("Could not find Stripe customer ({CustomerID}) for subscriber ({SubscriberID})", subscriber.GatewayCustomerId, subscriber.Id);
|
try
|
||||||
|
{
|
||||||
|
var subscription =
|
||||||
|
await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions);
|
||||||
|
|
||||||
throw ContactSupport();
|
if (subscription != null)
|
||||||
|
{
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.LogError("Could not find Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID})",
|
||||||
|
subscriber.GatewaySubscriptionId, subscriber.Id);
|
||||||
|
|
||||||
|
throw ContactSupport();
|
||||||
|
}
|
||||||
|
catch (StripeException exception)
|
||||||
|
{
|
||||||
|
logger.LogError("An error occurred while trying to retrieve Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID}): {Error}",
|
||||||
|
subscriber.GatewaySubscriptionId, subscriber.Id, exception.Message);
|
||||||
|
|
||||||
|
throw ContactSupport("An error occurred while trying to retrieve a Stripe Subscription", exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using Bit.Core.Services;
|
|||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
|
using NSubstitute.ExceptionExtensions;
|
||||||
using NSubstitute.ReturnsExtensions;
|
using NSubstitute.ReturnsExtensions;
|
||||||
using Stripe;
|
using Stripe;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -48,6 +49,20 @@ public class SubscriberQueriesTests
|
|||||||
Assert.Null(customer);
|
Assert.Null(customer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task GetCustomer_StripeException_ReturnsNull(
|
||||||
|
Organization organization,
|
||||||
|
SutProvider<SubscriberQueries> sutProvider)
|
||||||
|
{
|
||||||
|
sutProvider.GetDependency<IStripeAdapter>()
|
||||||
|
.CustomerGetAsync(organization.GatewayCustomerId)
|
||||||
|
.ThrowsAsync<StripeException>();
|
||||||
|
|
||||||
|
var customer = await sutProvider.Sut.GetCustomer(organization);
|
||||||
|
|
||||||
|
Assert.Null(customer);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetCustomer_Succeeds(
|
public async Task GetCustomer_Succeeds(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
@ -98,6 +113,20 @@ public class SubscriberQueriesTests
|
|||||||
Assert.Null(subscription);
|
Assert.Null(subscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task GetSubscription_StripeException_ReturnsNull(
|
||||||
|
Organization organization,
|
||||||
|
SutProvider<SubscriberQueries> sutProvider)
|
||||||
|
{
|
||||||
|
sutProvider.GetDependency<IStripeAdapter>()
|
||||||
|
.SubscriptionGetAsync(organization.GatewaySubscriptionId)
|
||||||
|
.ThrowsAsync<StripeException>();
|
||||||
|
|
||||||
|
var subscription = await sutProvider.Sut.GetSubscription(organization);
|
||||||
|
|
||||||
|
Assert.Null(subscription);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetSubscription_Succeeds(
|
public async Task GetSubscription_Succeeds(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
@ -123,7 +152,7 @@ public class SubscriberQueriesTests
|
|||||||
async () => await sutProvider.Sut.GetCustomerOrThrow(null));
|
async () => await sutProvider.Sut.GetCustomerOrThrow(null));
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetCustomerOrThrow_NoGatewaySubscriptionId_ThrowsGatewayException(
|
public async Task GetCustomerOrThrow_NoGatewayCustomerId_ContactSupport(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
SutProvider<SubscriberQueries> sutProvider)
|
SutProvider<SubscriberQueries> sutProvider)
|
||||||
{
|
{
|
||||||
@ -133,7 +162,7 @@ public class SubscriberQueriesTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetSubscriptionOrThrow_NoCustomer_ThrowsGatewayException(
|
public async Task GetCustomerOrThrow_NoCustomer_ContactSupport(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
SutProvider<SubscriberQueries> sutProvider)
|
SutProvider<SubscriberQueries> sutProvider)
|
||||||
{
|
{
|
||||||
@ -144,6 +173,23 @@ public class SubscriberQueriesTests
|
|||||||
await ThrowsContactSupportAsync(async () => await sutProvider.Sut.GetCustomerOrThrow(organization));
|
await ThrowsContactSupportAsync(async () => await sutProvider.Sut.GetCustomerOrThrow(organization));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task GetCustomerOrThrow_StripeException_ContactSupport(
|
||||||
|
Organization organization,
|
||||||
|
SutProvider<SubscriberQueries> sutProvider)
|
||||||
|
{
|
||||||
|
var stripeException = new StripeException();
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IStripeAdapter>()
|
||||||
|
.CustomerGetAsync(organization.GatewayCustomerId)
|
||||||
|
.ThrowsAsync(stripeException);
|
||||||
|
|
||||||
|
await ThrowsContactSupportAsync(
|
||||||
|
async () => await sutProvider.Sut.GetCustomerOrThrow(organization),
|
||||||
|
"An error occurred while trying to retrieve a Stripe Customer",
|
||||||
|
stripeException);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetCustomerOrThrow_Succeeds(
|
public async Task GetCustomerOrThrow_Succeeds(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
@ -169,7 +215,7 @@ public class SubscriberQueriesTests
|
|||||||
async () => await sutProvider.Sut.GetSubscriptionOrThrow(null));
|
async () => await sutProvider.Sut.GetSubscriptionOrThrow(null));
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetSubscriptionOrThrow_NoGatewaySubscriptionId_ThrowsGatewayException(
|
public async Task GetSubscriptionOrThrow_NoGatewaySubscriptionId_ContactSupport(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
SutProvider<SubscriberQueries> sutProvider)
|
SutProvider<SubscriberQueries> sutProvider)
|
||||||
{
|
{
|
||||||
@ -179,7 +225,7 @@ public class SubscriberQueriesTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetSubscriptionOrThrow_NoSubscription_ThrowsGatewayException(
|
public async Task GetSubscriptionOrThrow_NoSubscription_ContactSupport(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
SutProvider<SubscriberQueries> sutProvider)
|
SutProvider<SubscriberQueries> sutProvider)
|
||||||
{
|
{
|
||||||
@ -190,6 +236,23 @@ public class SubscriberQueriesTests
|
|||||||
await ThrowsContactSupportAsync(async () => await sutProvider.Sut.GetSubscriptionOrThrow(organization));
|
await ThrowsContactSupportAsync(async () => await sutProvider.Sut.GetSubscriptionOrThrow(organization));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task GetSubscriptionOrThrow_StripeException_ContactSupport(
|
||||||
|
Organization organization,
|
||||||
|
SutProvider<SubscriberQueries> sutProvider)
|
||||||
|
{
|
||||||
|
var stripeException = new StripeException();
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IStripeAdapter>()
|
||||||
|
.SubscriptionGetAsync(organization.GatewaySubscriptionId)
|
||||||
|
.ThrowsAsync(stripeException);
|
||||||
|
|
||||||
|
await ThrowsContactSupportAsync(
|
||||||
|
async () => await sutProvider.Sut.GetSubscriptionOrThrow(organization),
|
||||||
|
"An error occurred while trying to retrieve a Stripe Subscription",
|
||||||
|
stripeException);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetSubscriptionOrThrow_Succeeds(
|
public async Task GetSubscriptionOrThrow_Succeeds(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
|
@ -7,12 +7,17 @@ namespace Bit.Core.Test.Billing;
|
|||||||
|
|
||||||
public static class Utilities
|
public static class Utilities
|
||||||
{
|
{
|
||||||
public static async Task ThrowsContactSupportAsync(Func<Task> function)
|
public static async Task ThrowsContactSupportAsync(
|
||||||
|
Func<Task> function,
|
||||||
|
string internalMessage = null,
|
||||||
|
Exception innerException = null)
|
||||||
{
|
{
|
||||||
var contactSupport = ContactSupport();
|
var contactSupport = ContactSupport(internalMessage, innerException);
|
||||||
|
|
||||||
var exception = await Assert.ThrowsAsync<BillingException>(function);
|
var exception = await Assert.ThrowsAsync<BillingException>(function);
|
||||||
|
|
||||||
|
Assert.Equal(contactSupport.ClientFriendlyMessage, exception.ClientFriendlyMessage);
|
||||||
Assert.Equal(contactSupport.Message, exception.Message);
|
Assert.Equal(contactSupport.Message, exception.Message);
|
||||||
|
Assert.Equal(contactSupport.InnerException, exception.InnerException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user