Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AC-2471] Prevent calls to Stripe when unlinking client org has no Stripe objects #3999

Merged
merged 10 commits into from
May 9, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -67,27 +67,31 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv

await _organizationRepository.ReplaceAsync(organization);

var customerUpdateOptions = new CustomerUpdateOptions
if (!string.IsNullOrEmpty(organization.GatewayCustomerId) &&
!string.IsNullOrEmpty(organization.GatewaySubscriptionId))
eliykat marked this conversation as resolved.
Show resolved Hide resolved
{
Coupon = string.Empty,
Email = organization.BillingEmail
};
var customerUpdateOptions = new CustomerUpdateOptions
{
eliykat marked this conversation as resolved.
Show resolved Hide resolved
Coupon = string.Empty,
Email = organization.BillingEmail
};

await _stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, customerUpdateOptions);
await _stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, customerUpdateOptions);

var subscriptionUpdateOptions = new SubscriptionUpdateOptions
{
CollectionMethod = "send_invoice",
DaysUntilDue = 30
};
var subscriptionUpdateOptions = new SubscriptionUpdateOptions
{
CollectionMethod = "send_invoice",
DaysUntilDue = 30
};

await _stripeAdapter.SubscriptionUpdateAsync(organization.GatewaySubscriptionId, subscriptionUpdateOptions);
await _stripeAdapter.SubscriptionUpdateAsync(organization.GatewaySubscriptionId, subscriptionUpdateOptions);

await _mailService.SendProviderUpdatePaymentMethod(
organization.Id,
organization.Name,
provider.Name,
organizationOwnerEmails);
await _mailService.SendProviderUpdatePaymentMethod(
organization.Id,
organization.Name,
provider.Name,
organizationOwnerEmails);
}

await _providerOrganizationRepository.DeleteAsync(providerOrganization);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using NSubstitute;
using Stripe;
using Xunit;
using IMailService = Bit.Core.Services.IMailService;

namespace Bit.Commercial.Core.Test.AdminConsole.ProviderFeatures;

Expand Down Expand Up @@ -80,6 +81,55 @@ public class RemoveOrganizationFromProviderCommandTests
Assert.Equal("Organization must have at least one confirmed owner.", exception.Message);
}

[Theory, BitAutoData]
public async Task RemoveOrganizationFromProvider_NoStripeObjects_MakesCorrectInvocations(
Provider provider,
ProviderOrganization providerOrganization,
Organization organization,
SutProvider<RemoveOrganizationFromProviderCommand> sutProvider)
{
organization.GatewayCustomerId = null;
organization.GatewaySubscriptionId = null;

providerOrganization.ProviderId = provider.Id;

var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();

sutProvider.GetDependency<IOrganizationService>().HasConfirmedOwnersExceptAsync(
providerOrganization.OrganizationId,
Array.Empty<Guid>(),
includeProvider: false)
.Returns(true);

var organizationOwnerEmails = new List<string> { "[email protected]", "[email protected]" };

organizationRepository.GetOwnerEmailAddressesById(organization.Id).Returns(organizationOwnerEmails);

await sutProvider.Sut.RemoveOrganizationFromProvider(provider, providerOrganization, organization);

await organizationRepository.Received(1).ReplaceAsync(Arg.Is<Organization>(
org => org.Id == organization.Id && org.BillingEmail == "[email protected]"));

var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();

await stripeAdapter.DidNotReceiveWithAnyArgs().CustomerUpdateAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>());

await stripeAdapter.DidNotReceiveWithAnyArgs().SubscriptionUpdateAsync(Arg.Any<string>(), Arg.Any<SubscriptionUpdateOptions>());

await sutProvider.GetDependency<IMailService>().DidNotReceiveWithAnyArgs().SendProviderUpdatePaymentMethod(
Arg.Any<Guid>(),
Arg.Any<string>(),
Arg.Any<string>(),
Arg.Any<IEnumerable<string>>());

await sutProvider.GetDependency<IProviderOrganizationRepository>().Received(1)
.DeleteAsync(providerOrganization);

await sutProvider.GetDependency<IEventService>().Received(1).LogProviderOrganizationEventAsync(
providerOrganization,
EventType.ProviderOrganization_Removed);
}

[Theory, BitAutoData]
public async Task RemoveOrganizationFromProvider_MakesCorrectInvocations(
Provider provider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ public async Task<IActionResult> DeleteAsync(Guid providerId, Guid id)
providerOrganization,
organization);

await _removePaymentMethodCommand.RemovePaymentMethod(organization);
if (!string.IsNullOrEmpty(organization.GatewayCustomerId) &&
!string.IsNullOrEmpty(organization.GatewaySubscriptionId))
{
await _removePaymentMethodCommand.RemovePaymentMethod(organization);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be part of the command? Or are you trying to avoid calling a command from within a command?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, originally I had RemoveOrganizationFromProviderCommand invoke RemovePaymentMethodCommand, but I was told not to do so when this was originally implemented.


return Json(null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ public async Task Delete(Guid providerId, Guid id)
providerOrganization,
organization);

await _removePaymentMethodCommand.RemovePaymentMethod(organization);
if (!string.IsNullOrEmpty(organization.GatewayCustomerId) &&
!string.IsNullOrEmpty(organization.GatewaySubscriptionId))
{
await _removePaymentMethodCommand.RemovePaymentMethod(organization);
}
}
}