mirror of
https://github.com/bitwarden/server.git
synced 2025-04-05 05:00:19 -05:00
[AC-2284] Set organization billing email to MSP billing email when linked (#3897)
* Set org billing email to provider billing email when added to provider * Remove anonymous args for test assertions
This commit is contained in:
parent
84cbd9ee7d
commit
15eea77d66
@ -17,6 +17,7 @@ using Bit.Core.Services;
|
|||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
|
using Stripe;
|
||||||
|
|
||||||
namespace Bit.Commercial.Core.AdminConsole.Services;
|
namespace Bit.Commercial.Core.AdminConsole.Services;
|
||||||
|
|
||||||
@ -374,8 +375,18 @@ public class ProviderService : IProviderService
|
|||||||
Key = key,
|
Key = key,
|
||||||
};
|
};
|
||||||
|
|
||||||
await ApplyProviderPriceRateAsync(organizationId, providerId);
|
var provider = await _providerRepository.GetByIdAsync(providerId);
|
||||||
|
|
||||||
|
await ApplyProviderPriceRateAsync(organization, provider);
|
||||||
await _providerOrganizationRepository.CreateAsync(providerOrganization);
|
await _providerOrganizationRepository.CreateAsync(providerOrganization);
|
||||||
|
|
||||||
|
organization.BillingEmail = provider.BillingEmail;
|
||||||
|
await _organizationRepository.ReplaceAsync(organization);
|
||||||
|
await _stripeAdapter.CustomerUpdateAsync(organization.GatewayCustomerId, new CustomerUpdateOptions
|
||||||
|
{
|
||||||
|
Email = provider.BillingEmail
|
||||||
|
});
|
||||||
|
|
||||||
await _eventService.LogProviderOrganizationEventAsync(providerOrganization, EventType.ProviderOrganization_Added);
|
await _eventService.LogProviderOrganizationEventAsync(providerOrganization, EventType.ProviderOrganization_Added);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,16 +411,14 @@ public class ProviderService : IProviderService
|
|||||||
await _eventService.LogProviderOrganizationEventsAsync(insertedProviderOrganizations.Select(ipo => (ipo, EventType.ProviderOrganization_Added, (DateTime?)null)));
|
await _eventService.LogProviderOrganizationEventsAsync(insertedProviderOrganizations.Select(ipo => (ipo, EventType.ProviderOrganization_Added, (DateTime?)null)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ApplyProviderPriceRateAsync(Guid organizationId, Guid providerId)
|
private async Task ApplyProviderPriceRateAsync(Organization organization, Provider provider)
|
||||||
{
|
{
|
||||||
var provider = await _providerRepository.GetByIdAsync(providerId);
|
|
||||||
// if a provider was created before Nov 6, 2023.If true, the organization plan assigned to that provider is updated to a 2020 plan.
|
// if a provider was created before Nov 6, 2023.If true, the organization plan assigned to that provider is updated to a 2020 plan.
|
||||||
if (provider.CreationDate >= Constants.ProviderCreatedPriorNov62023)
|
if (provider.CreationDate >= Constants.ProviderCreatedPriorNov62023)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
|
||||||
var subscriptionItem = await GetSubscriptionItemAsync(organization.GatewaySubscriptionId, GetStripeSeatPlanId(organization.PlanType));
|
var subscriptionItem = await GetSubscriptionItemAsync(organization.GatewaySubscriptionId, GetStripeSeatPlanId(organization.PlanType));
|
||||||
var extractedPlanType = PlanTypeMappings(organization);
|
var extractedPlanType = PlanTypeMappings(organization);
|
||||||
if (subscriptionItem != null)
|
if (subscriptionItem != null)
|
||||||
|
@ -458,17 +458,112 @@ public class ProviderServiceTests
|
|||||||
{
|
{
|
||||||
organization.PlanType = PlanType.EnterpriseAnnually;
|
organization.PlanType = PlanType.EnterpriseAnnually;
|
||||||
|
|
||||||
|
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
|
||||||
|
providerRepository.GetByIdAsync(provider.Id).Returns(provider);
|
||||||
|
|
||||||
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
|
providerOrganizationRepository.GetByOrganizationId(organization.Id).ReturnsNull();
|
||||||
|
|
||||||
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||||
|
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
|
||||||
|
|
||||||
|
await sutProvider.Sut.AddOrganization(provider.Id, organization.Id, key);
|
||||||
|
|
||||||
|
await providerOrganizationRepository.Received(1)
|
||||||
|
.CreateAsync(Arg.Is<ProviderOrganization>(providerOrganization =>
|
||||||
|
providerOrganization.ProviderId == provider.Id &&
|
||||||
|
providerOrganization.OrganizationId == organization.Id &&
|
||||||
|
providerOrganization.Key == key));
|
||||||
|
|
||||||
|
await organizationRepository.Received(1)
|
||||||
|
.ReplaceAsync(Arg.Is<Organization>(org => org.BillingEmail == provider.BillingEmail));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IStripeAdapter>().Received(1).CustomerUpdateAsync(
|
||||||
|
organization.GatewayCustomerId,
|
||||||
|
Arg.Is<CustomerUpdateOptions>(options => options.Email == provider.BillingEmail));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IEventService>()
|
||||||
|
.Received().LogProviderOrganizationEventAsync(Arg.Is<ProviderOrganization>(providerOrganization =>
|
||||||
|
providerOrganization.ProviderId == provider.Id &&
|
||||||
|
providerOrganization.OrganizationId == organization.Id &&
|
||||||
|
providerOrganization.Key == key),
|
||||||
|
EventType.ProviderOrganization_Added);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task AddOrganization_CreateAfterNov62023_PlanTypeDoesNotUpdated(Provider provider, Organization organization, string key,
|
||||||
|
SutProvider<ProviderService> sutProvider)
|
||||||
|
{
|
||||||
|
provider.Type = ProviderType.Msp;
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
|
||||||
|
|
||||||
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
|
var expectedPlanType = PlanType.EnterpriseAnnually;
|
||||||
|
organization.PlanType = PlanType.EnterpriseAnnually;
|
||||||
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||||
|
|
||||||
|
await sutProvider.Sut.AddOrganization(provider.Id, organization.Id, key);
|
||||||
|
|
||||||
|
await providerOrganizationRepository.Received(1)
|
||||||
|
.CreateAsync(Arg.Is<ProviderOrganization>(providerOrganization =>
|
||||||
|
providerOrganization.ProviderId == provider.Id &&
|
||||||
|
providerOrganization.OrganizationId == organization.Id &&
|
||||||
|
providerOrganization.Key == key));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IEventService>()
|
||||||
|
.Received().LogProviderOrganizationEventAsync(Arg.Is<ProviderOrganization>(providerOrganization =>
|
||||||
|
providerOrganization.ProviderId == provider.Id &&
|
||||||
|
providerOrganization.OrganizationId == organization.Id &&
|
||||||
|
providerOrganization.Key == key),
|
||||||
|
EventType.ProviderOrganization_Added);
|
||||||
|
|
||||||
|
Assert.Equal(organization.PlanType, expectedPlanType);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task AddOrganization_CreateBeforeNov62023_PlanTypeUpdated(Provider provider, Organization organization, string key,
|
||||||
|
SutProvider<ProviderService> sutProvider)
|
||||||
|
{
|
||||||
|
var newCreationDate = new DateTime(2023, 11, 5);
|
||||||
|
BackdateProviderCreationDate(provider, newCreationDate);
|
||||||
|
provider.Type = ProviderType.Msp;
|
||||||
|
|
||||||
|
organization.PlanType = PlanType.EnterpriseAnnually;
|
||||||
|
organization.Plan = "Enterprise (Annually)";
|
||||||
|
|
||||||
|
var expectedPlanType = PlanType.EnterpriseAnnually2020;
|
||||||
|
|
||||||
|
var expectedPlanId = "2020-enterprise-org-seat-annually";
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
|
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
|
||||||
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
||||||
providerOrganizationRepository.GetByOrganizationId(organization.Id).ReturnsNull();
|
providerOrganizationRepository.GetByOrganizationId(organization.Id).ReturnsNull();
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||||
|
var subscriptionItem = GetSubscription(organization.GatewaySubscriptionId);
|
||||||
|
sutProvider.GetDependency<IStripeAdapter>().SubscriptionGetAsync(organization.GatewaySubscriptionId)
|
||||||
|
.Returns(GetSubscription(organization.GatewaySubscriptionId));
|
||||||
|
await sutProvider.GetDependency<IStripeAdapter>().SubscriptionUpdateAsync(
|
||||||
|
organization.GatewaySubscriptionId, SubscriptionUpdateRequest(expectedPlanId, subscriptionItem));
|
||||||
|
|
||||||
await sutProvider.Sut.AddOrganization(provider.Id, organization.Id, key);
|
await sutProvider.Sut.AddOrganization(provider.Id, organization.Id, key);
|
||||||
|
|
||||||
await providerOrganizationRepository.ReceivedWithAnyArgs().CreateAsync(default);
|
await providerOrganizationRepository.Received(1)
|
||||||
|
.CreateAsync(Arg.Is<ProviderOrganization>(providerOrganization =>
|
||||||
|
providerOrganization.ProviderId == provider.Id &&
|
||||||
|
providerOrganization.OrganizationId == organization.Id &&
|
||||||
|
providerOrganization.Key == key));
|
||||||
|
|
||||||
await sutProvider.GetDependency<IEventService>()
|
await sutProvider.GetDependency<IEventService>()
|
||||||
.Received().LogProviderOrganizationEventAsync(Arg.Any<ProviderOrganization>(),
|
.Received().LogProviderOrganizationEventAsync(Arg.Is<ProviderOrganization>(providerOrganization =>
|
||||||
|
providerOrganization.ProviderId == provider.Id &&
|
||||||
|
providerOrganization.OrganizationId == organization.Id &&
|
||||||
|
providerOrganization.Key == key),
|
||||||
EventType.ProviderOrganization_Added);
|
EventType.ProviderOrganization_Added);
|
||||||
|
|
||||||
|
Assert.Equal(organization.PlanType, expectedPlanType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
@ -576,65 +671,6 @@ public class ProviderServiceTests
|
|||||||
t.First().Item2 == null));
|
t.First().Item2 == null));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task AddOrganization_CreateAfterNov62023_PlanTypeDoesNotUpdated(Provider provider, Organization organization, string key,
|
|
||||||
SutProvider<ProviderService> sutProvider)
|
|
||||||
{
|
|
||||||
provider.Type = ProviderType.Msp;
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
|
|
||||||
|
|
||||||
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
|
||||||
var expectedPlanType = PlanType.EnterpriseAnnually;
|
|
||||||
organization.PlanType = PlanType.EnterpriseAnnually;
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
||||||
|
|
||||||
await sutProvider.Sut.AddOrganization(provider.Id, organization.Id, key);
|
|
||||||
|
|
||||||
await providerOrganizationRepository.ReceivedWithAnyArgs().CreateAsync(default);
|
|
||||||
await sutProvider.GetDependency<IEventService>()
|
|
||||||
.Received().LogProviderOrganizationEventAsync(Arg.Any<ProviderOrganization>(),
|
|
||||||
EventType.ProviderOrganization_Added);
|
|
||||||
Assert.Equal(organization.PlanType, expectedPlanType);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task AddOrganization_CreateBeforeNov62023_PlanTypeUpdated(Provider provider, Organization organization, string key,
|
|
||||||
SutProvider<ProviderService> sutProvider)
|
|
||||||
{
|
|
||||||
var newCreationDate = new DateTime(2023, 11, 5);
|
|
||||||
BackdateProviderCreationDate(provider, newCreationDate);
|
|
||||||
provider.Type = ProviderType.Msp;
|
|
||||||
|
|
||||||
organization.PlanType = PlanType.EnterpriseAnnually;
|
|
||||||
organization.Plan = "Enterprise (Annually)";
|
|
||||||
|
|
||||||
var expectedPlanType = PlanType.EnterpriseAnnually2020;
|
|
||||||
|
|
||||||
var expectedPlanId = "2020-enterprise-org-seat-annually";
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
|
|
||||||
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
|
|
||||||
providerOrganizationRepository.GetByOrganizationId(organization.Id).ReturnsNull();
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
||||||
var subscriptionItem = GetSubscription(organization.GatewaySubscriptionId);
|
|
||||||
sutProvider.GetDependency<IStripeAdapter>().SubscriptionGetAsync(organization.GatewaySubscriptionId)
|
|
||||||
.Returns(GetSubscription(organization.GatewaySubscriptionId));
|
|
||||||
await sutProvider.GetDependency<IStripeAdapter>().SubscriptionUpdateAsync(
|
|
||||||
organization.GatewaySubscriptionId, SubscriptionUpdateRequest(expectedPlanId, subscriptionItem));
|
|
||||||
|
|
||||||
await sutProvider.Sut.AddOrganization(provider.Id, organization.Id, key);
|
|
||||||
|
|
||||||
await providerOrganizationRepository.ReceivedWithAnyArgs().CreateAsync(default);
|
|
||||||
await sutProvider.GetDependency<IEventService>()
|
|
||||||
.Received().LogProviderOrganizationEventAsync(Arg.Any<ProviderOrganization>(),
|
|
||||||
EventType.ProviderOrganization_Added);
|
|
||||||
|
|
||||||
Assert.Equal(organization.PlanType, expectedPlanType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SubscriptionUpdateOptions SubscriptionUpdateRequest(string expectedPlanId, Subscription subscriptionItem) =>
|
private static SubscriptionUpdateOptions SubscriptionUpdateRequest(string expectedPlanId, Subscription subscriptionItem) =>
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user