mirror of
https://github.com/bitwarden/server
synced 2025-12-24 12:13:17 +00:00
[PM-27117] Sync Stripe Customer details for Organizations and Providers in API & Admin (#6679)
* Sync Stripe customer details for Provider / Organization in API & Admin * Remove unnecessary var * Fix logical operator * Remove customer ID check from callers * Fix failing tests * Missed conflicts
This commit is contained in:
@@ -30,7 +30,7 @@ public class OrganizationUpdateCommandTests
|
||||
var organizationBillingService = sutProvider.GetDependency<IOrganizationBillingService>();
|
||||
|
||||
organization.Id = organizationId;
|
||||
organization.GatewayCustomerId = null; // No Stripe customer, so no billing update
|
||||
organization.GatewayCustomerId = null; // No Stripe customer, but billing update is still called
|
||||
|
||||
organizationRepository
|
||||
.GetByIdAsync(organizationId)
|
||||
@@ -61,8 +61,8 @@ public class OrganizationUpdateCommandTests
|
||||
result,
|
||||
EventType.Organization_Updated);
|
||||
await organizationBillingService
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpdateOrganizationNameAndEmail(Arg.Any<Organization>());
|
||||
.Received(1)
|
||||
.UpdateOrganizationNameAndEmail(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
@@ -93,7 +93,7 @@ public class OrganizationUpdateCommandTests
|
||||
[Theory]
|
||||
[BitAutoData("")]
|
||||
[BitAutoData((string)null)]
|
||||
public async Task UpdateAsync_WhenGatewayCustomerIdIsNullOrEmpty_SkipsBillingUpdate(
|
||||
public async Task UpdateAsync_WhenGatewayCustomerIdIsNullOrEmpty_CallsBillingUpdateButHandledGracefully(
|
||||
string gatewayCustomerId,
|
||||
Guid organizationId,
|
||||
Organization organization,
|
||||
@@ -133,8 +133,8 @@ public class OrganizationUpdateCommandTests
|
||||
result,
|
||||
EventType.Organization_Updated);
|
||||
await organizationBillingService
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpdateOrganizationNameAndEmail(Arg.Any<Organization>());
|
||||
.Received(1)
|
||||
.UpdateOrganizationNameAndEmail(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Billing;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Models.Sales;
|
||||
@@ -391,12 +390,13 @@ public class OrganizationBillingServiceTests
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateOrganizationNameAndEmail_WhenNameIsLong_TruncatesTo30Characters(
|
||||
public async Task UpdateOrganizationNameAndEmail_WhenNameIsLong_UsesFullName(
|
||||
Organization organization,
|
||||
SutProvider<OrganizationBillingService> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organization.Name = "This is a very long organization name that exceeds thirty characters";
|
||||
var longName = "This is a very long organization name that exceeds thirty characters";
|
||||
organization.Name = longName;
|
||||
|
||||
CustomerUpdateOptions capturedOptions = null;
|
||||
sutProvider.GetDependency<IStripeAdapter>()
|
||||
@@ -420,14 +420,11 @@ public class OrganizationBillingServiceTests
|
||||
Assert.NotNull(capturedOptions.InvoiceSettings.CustomFields);
|
||||
|
||||
var customField = capturedOptions.InvoiceSettings.CustomFields.First();
|
||||
Assert.Equal(30, customField.Value.Length);
|
||||
|
||||
var expectedCustomFieldDisplayName = "This is a very long organizati";
|
||||
Assert.Equal(expectedCustomFieldDisplayName, customField.Value);
|
||||
Assert.Equal(longName, customField.Value);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateOrganizationNameAndEmail_WhenGatewayCustomerIdIsNull_ThrowsBillingException(
|
||||
public async Task UpdateOrganizationNameAndEmail_WhenGatewayCustomerIdIsNull_LogsWarningAndReturns(
|
||||
Organization organization,
|
||||
SutProvider<OrganizationBillingService> sutProvider)
|
||||
{
|
||||
@@ -435,15 +432,93 @@ public class OrganizationBillingServiceTests
|
||||
organization.GatewayCustomerId = null;
|
||||
organization.Name = "Test Organization";
|
||||
organization.BillingEmail = "billing@example.com";
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<BillingException>(
|
||||
() => sutProvider.Sut.UpdateOrganizationNameAndEmail(organization));
|
||||
// Act
|
||||
await sutProvider.Sut.UpdateOrganizationNameAndEmail(organization);
|
||||
|
||||
Assert.Contains("Cannot update an organization in Stripe without a GatewayCustomerId.", exception.Response);
|
||||
// Assert
|
||||
await stripeAdapter.DidNotReceive().UpdateCustomerAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<CustomerUpdateOptions>());
|
||||
}
|
||||
|
||||
await sutProvider.GetDependency<IStripeAdapter>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpdateCustomerAsync(Arg.Any<string>(), Arg.Any<CustomerUpdateOptions>());
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateOrganizationNameAndEmail_WhenGatewayCustomerIdIsEmpty_LogsWarningAndReturns(
|
||||
Organization organization,
|
||||
SutProvider<OrganizationBillingService> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organization.GatewayCustomerId = "";
|
||||
organization.Name = "Test Organization";
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.UpdateOrganizationNameAndEmail(organization);
|
||||
|
||||
// Assert
|
||||
await stripeAdapter.DidNotReceive().UpdateCustomerAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<CustomerUpdateOptions>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateOrganizationNameAndEmail_WhenNameIsNull_LogsWarningAndReturns(
|
||||
Organization organization,
|
||||
SutProvider<OrganizationBillingService> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organization.Name = null;
|
||||
organization.GatewayCustomerId = "cus_test123";
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.UpdateOrganizationNameAndEmail(organization);
|
||||
|
||||
// Assert
|
||||
await stripeAdapter.DidNotReceive().UpdateCustomerAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<CustomerUpdateOptions>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateOrganizationNameAndEmail_WhenNameIsEmpty_LogsWarningAndReturns(
|
||||
Organization organization,
|
||||
SutProvider<OrganizationBillingService> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organization.Name = "";
|
||||
organization.GatewayCustomerId = "cus_test123";
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.UpdateOrganizationNameAndEmail(organization);
|
||||
|
||||
// Assert
|
||||
await stripeAdapter.DidNotReceive().UpdateCustomerAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<CustomerUpdateOptions>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateOrganizationNameAndEmail_WhenBillingEmailIsNull_UpdatesWithNull(
|
||||
Organization organization,
|
||||
SutProvider<OrganizationBillingService> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organization.Name = "Test Organization";
|
||||
organization.BillingEmail = null;
|
||||
organization.GatewayCustomerId = "cus_test123";
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.UpdateOrganizationNameAndEmail(organization);
|
||||
|
||||
// Assert
|
||||
await stripeAdapter.Received(1).UpdateCustomerAsync(
|
||||
organization.GatewayCustomerId,
|
||||
Arg.Is<CustomerUpdateOptions>(options =>
|
||||
options.Email == null &&
|
||||
options.Description == organization.Name));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user