mirror of
https://github.com/bitwarden/server.git
synced 2025-12-10 00:42:07 -06:00
* Upgrade Stripe.net to v48.4.0 * Update PreviewTaxAmountCommand * Remove unused UpcomingInvoiceOptionExtensions * Added SubscriptionExtensions with GetCurrentPeriodEnd * Update PremiumUserBillingService * Update OrganizationBillingService * Update GetOrganizationWarningsQuery * Update BillingHistoryInfo * Update SubscriptionInfo * Remove unused Sql Billing folder * Update StripeAdapter * Update StripePaymentService * Update InvoiceCreatedHandler * Update PaymentFailedHandler * Update PaymentSucceededHandler * Update ProviderEventService * Update StripeEventUtilityService * Update SubscriptionDeletedHandler * Update SubscriptionUpdatedHandler * Update UpcomingInvoiceHandler * Update ProviderSubscriptionResponse * Remove unused Stripe Subscriptions Admin Tool * Update RemoveOrganizationFromProviderCommand * Update ProviderBillingService * Update RemoveOrganizatinoFromProviderCommandTests * Update PreviewTaxAmountCommandTests * Update GetCloudOrganizationLicenseQueryTests * Update GetOrganizationWarningsQueryTests * Update StripePaymentServiceTests * Update ProviderBillingControllerTests * Update ProviderEventServiceTests * Update SubscriptionDeletedHandlerTests * Update SubscriptionUpdatedHandlerTests * Resolve Billing test failures I completely removed tests for the StripeEventService as they were using a system I setup a while back that read JSON files of the Stripe event structure. I did not anticipate how frequently these structures would change with each API version and the cost of trying to update these specific JSON files to test a very static data retrieval service far outweigh the benefit. * Resolve Core test failures * Run dotnet format * Remove unused provider migration * Fixed failing tests * Run dotnet format * Replace the old webhook secret key with new one (#6223) * Fix compilation failures in additions * Run dotnet format * Bump Stripe API version * Fix recent addition: CreatePremiumCloudHostedSubscriptionCommand * Fix new code in main according to Stripe update * Fix InvoiceExtensions * Bump SDK version to match API Version * Fix provider invoice generation validation * More QA fixes * Fix tests * QA defect resolutions * QA defect resolutions * Run dotnet format * Fix tests --------- Co-authored-by: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com>
519 lines
19 KiB
C#
519 lines
19 KiB
C#
using Bit.Core.Billing.Constants;
|
|
using Bit.Core.Billing.Enums;
|
|
using Bit.Core.Billing.Models.StaticStore.Plans;
|
|
using Bit.Core.Billing.Pricing;
|
|
using Bit.Core.Billing.Tax.Requests;
|
|
using Bit.Core.Enums;
|
|
using Bit.Core.Services;
|
|
using Bit.Test.Common.AutoFixture;
|
|
using Bit.Test.Common.AutoFixture.Attributes;
|
|
using NSubstitute;
|
|
using Stripe;
|
|
using Xunit;
|
|
|
|
namespace Bit.Core.Test.Services;
|
|
|
|
[SutProviderCustomize]
|
|
public class StripePaymentServiceTests
|
|
{
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task
|
|
PreviewInvoiceAsync_ForOrganization_CalculatesSalesTaxCorrectlyForFamiliesWithoutAdditionalStorage(
|
|
SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
var familiesPlan = new FamiliesPlan();
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.FamiliesAnnually))
|
|
.Returns(familiesPlan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager =
|
|
new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.FamiliesAnnually,
|
|
AdditionalStorage = 0
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel { Country = "FR", PostalCode = "12345" }
|
|
};
|
|
|
|
sutProvider.GetDependency<IStripeAdapter>()
|
|
.InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(p =>
|
|
p.Currency == "usd" &&
|
|
p.SubscriptionDetails.Items.Any(x =>
|
|
x.Plan == familiesPlan.PasswordManager.StripePlanId &&
|
|
x.Quantity == 1) &&
|
|
p.SubscriptionDetails.Items.Any(x =>
|
|
x.Plan == familiesPlan.PasswordManager.StripeStoragePlanId &&
|
|
x.Quantity == 0)))
|
|
.Returns(new Invoice
|
|
{
|
|
TotalExcludingTax = 4000,
|
|
TotalTaxes = [new InvoiceTotalTax { Amount = 800 }],
|
|
Total = 4800
|
|
});
|
|
|
|
var actual = await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
Assert.Equal(8M, actual.TaxAmount);
|
|
Assert.Equal(48M, actual.TotalAmount);
|
|
Assert.Equal(40M, actual.TaxableBaseAmount);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PreviewInvoiceAsync_ForOrganization_CalculatesSalesTaxCorrectlyForFamiliesWithAdditionalStorage(
|
|
SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
var familiesPlan = new FamiliesPlan();
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.FamiliesAnnually))
|
|
.Returns(familiesPlan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager =
|
|
new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.FamiliesAnnually,
|
|
AdditionalStorage = 1
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel { Country = "FR", PostalCode = "12345" }
|
|
};
|
|
|
|
sutProvider.GetDependency<IStripeAdapter>()
|
|
.InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(p =>
|
|
p.Currency == "usd" &&
|
|
p.SubscriptionDetails.Items.Any(x =>
|
|
x.Plan == familiesPlan.PasswordManager.StripePlanId &&
|
|
x.Quantity == 1) &&
|
|
p.SubscriptionDetails.Items.Any(x =>
|
|
x.Plan == familiesPlan.PasswordManager.StripeStoragePlanId &&
|
|
x.Quantity == 1)))
|
|
.Returns(new Invoice { TotalExcludingTax = 4000, TotalTaxes = [new InvoiceTotalTax { Amount = 800 }], Total = 4800 });
|
|
|
|
var actual = await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
Assert.Equal(8M, actual.TaxAmount);
|
|
Assert.Equal(48M, actual.TotalAmount);
|
|
Assert.Equal(40M, actual.TaxableBaseAmount);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task
|
|
PreviewInvoiceAsync_ForOrganization_CalculatesSalesTaxCorrectlyForFamiliesForEnterpriseWithoutAdditionalStorage(
|
|
SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
var familiesPlan = new FamiliesPlan();
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.FamiliesAnnually))
|
|
.Returns(familiesPlan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.FamiliesAnnually,
|
|
SponsoredPlan = PlanSponsorshipType.FamiliesForEnterprise,
|
|
AdditionalStorage = 0
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel { Country = "FR", PostalCode = "12345" }
|
|
};
|
|
|
|
sutProvider.GetDependency<IStripeAdapter>()
|
|
.InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(p =>
|
|
p.Currency == "usd" &&
|
|
p.SubscriptionDetails.Items.Any(x =>
|
|
x.Plan == "2021-family-for-enterprise-annually" &&
|
|
x.Quantity == 1) &&
|
|
p.SubscriptionDetails.Items.Any(x =>
|
|
x.Plan == familiesPlan.PasswordManager.StripeStoragePlanId &&
|
|
x.Quantity == 0)))
|
|
.Returns(new Invoice { TotalExcludingTax = 0, TotalTaxes = [new InvoiceTotalTax { Amount = 0 }], Total = 0 });
|
|
|
|
var actual = await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
Assert.Equal(0M, actual.TaxAmount);
|
|
Assert.Equal(0M, actual.TotalAmount);
|
|
Assert.Equal(0M, actual.TaxableBaseAmount);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task
|
|
PreviewInvoiceAsync_ForOrganization_CalculatesSalesTaxCorrectlyForFamiliesForEnterpriseWithAdditionalStorage(
|
|
SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
var familiesPlan = new FamiliesPlan();
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.FamiliesAnnually))
|
|
.Returns(familiesPlan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.FamiliesAnnually,
|
|
SponsoredPlan = PlanSponsorshipType.FamiliesForEnterprise,
|
|
AdditionalStorage = 1
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel { Country = "FR", PostalCode = "12345" }
|
|
};
|
|
|
|
sutProvider.GetDependency<IStripeAdapter>()
|
|
.InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(p =>
|
|
p.Currency == "usd" &&
|
|
p.SubscriptionDetails.Items.Any(x =>
|
|
x.Plan == "2021-family-for-enterprise-annually" &&
|
|
x.Quantity == 1) &&
|
|
p.SubscriptionDetails.Items.Any(x =>
|
|
x.Plan == familiesPlan.PasswordManager.StripeStoragePlanId &&
|
|
x.Quantity == 1)))
|
|
.Returns(new Invoice { TotalExcludingTax = 400, TotalTaxes = [new InvoiceTotalTax { Amount = 8 }], Total = 408 });
|
|
|
|
var actual = await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
Assert.Equal(0.08M, actual.TaxAmount);
|
|
Assert.Equal(4.08M, actual.TotalAmount);
|
|
Assert.Equal(4M, actual.TaxableBaseAmount);
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PreviewInvoiceAsync_USBased_PersonalUse_SetsAutomaticTaxEnabled(SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
// Arrange
|
|
var familiesPlan = new FamiliesPlan();
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.FamiliesAnnually))
|
|
.Returns(familiesPlan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.FamiliesAnnually
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel
|
|
{
|
|
Country = "US",
|
|
PostalCode = "12345"
|
|
}
|
|
};
|
|
|
|
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
|
stripeAdapter
|
|
.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>())
|
|
.Returns(new Invoice
|
|
{
|
|
TotalExcludingTax = 400,
|
|
TotalTaxes = [new InvoiceTotalTax { Amount = 8 }],
|
|
Total = 408
|
|
});
|
|
|
|
// Act
|
|
await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
// Assert
|
|
await stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
|
|
options.AutomaticTax.Enabled == true
|
|
));
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PreviewInvoiceAsync_USBased_BusinessUse_SetsAutomaticTaxEnabled(SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
// Arrange
|
|
var plan = new EnterprisePlan(true);
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.EnterpriseAnnually))
|
|
.Returns(plan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.EnterpriseAnnually
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel
|
|
{
|
|
Country = "US",
|
|
PostalCode = "12345"
|
|
}
|
|
};
|
|
|
|
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
|
stripeAdapter
|
|
.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>())
|
|
.Returns(new Invoice
|
|
{
|
|
TotalExcludingTax = 400,
|
|
TotalTaxes = [new InvoiceTotalTax { Amount = 8 }],
|
|
Total = 408
|
|
});
|
|
|
|
// Act
|
|
await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
// Assert
|
|
await stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
|
|
options.AutomaticTax.Enabled == true
|
|
));
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PreviewInvoiceAsync_NonUSBased_PersonalUse_SetsAutomaticTaxEnabled(SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
// Arrange
|
|
var familiesPlan = new FamiliesPlan();
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.FamiliesAnnually))
|
|
.Returns(familiesPlan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.FamiliesAnnually
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel
|
|
{
|
|
Country = "FR",
|
|
PostalCode = "12345"
|
|
}
|
|
};
|
|
|
|
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
|
stripeAdapter
|
|
.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>())
|
|
.Returns(new Invoice
|
|
{
|
|
TotalExcludingTax = 400,
|
|
TotalTaxes = [new InvoiceTotalTax { Amount = 8 }],
|
|
Total = 408
|
|
});
|
|
|
|
// Act
|
|
await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
// Assert
|
|
await stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
|
|
options.AutomaticTax.Enabled == true
|
|
));
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PreviewInvoiceAsync_NonUSBased_BusinessUse_SetsAutomaticTaxEnabled(SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
// Arrange
|
|
var plan = new EnterprisePlan(true);
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.EnterpriseAnnually))
|
|
.Returns(plan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.EnterpriseAnnually
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel
|
|
{
|
|
Country = "FR",
|
|
PostalCode = "12345"
|
|
}
|
|
};
|
|
|
|
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
|
stripeAdapter
|
|
.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>())
|
|
.Returns(new Invoice
|
|
{
|
|
TotalExcludingTax = 400,
|
|
TotalTaxes = [new InvoiceTotalTax { Amount = 8 }],
|
|
Total = 408
|
|
});
|
|
|
|
// Act
|
|
await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
// Assert
|
|
await stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
|
|
options.AutomaticTax.Enabled == true
|
|
));
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PreviewInvoiceAsync_USBased_PersonalUse_DoesNotSetTaxExempt(SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
// Arrange
|
|
var familiesPlan = new FamiliesPlan();
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.FamiliesAnnually))
|
|
.Returns(familiesPlan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.FamiliesAnnually
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel
|
|
{
|
|
Country = "US",
|
|
PostalCode = "12345"
|
|
}
|
|
};
|
|
|
|
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
|
stripeAdapter
|
|
.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>())
|
|
.Returns(new Invoice
|
|
{
|
|
TotalExcludingTax = 400,
|
|
TotalTaxes = [new InvoiceTotalTax { Amount = 8 }],
|
|
Total = 408
|
|
});
|
|
|
|
// Act
|
|
await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
// Assert
|
|
await stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
|
|
options.CustomerDetails.TaxExempt == null
|
|
));
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PreviewInvoiceAsync_USBased_BusinessUse_DoesNotSetTaxExempt(SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
// Arrange
|
|
var plan = new EnterprisePlan(true);
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.EnterpriseAnnually))
|
|
.Returns(plan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.EnterpriseAnnually
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel
|
|
{
|
|
Country = "US",
|
|
PostalCode = "12345"
|
|
}
|
|
};
|
|
|
|
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
|
stripeAdapter
|
|
.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>())
|
|
.Returns(new Invoice
|
|
{
|
|
TotalExcludingTax = 400,
|
|
TotalTaxes = [new InvoiceTotalTax { Amount = 8 }],
|
|
Total = 408
|
|
});
|
|
|
|
// Act
|
|
await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
// Assert
|
|
await stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
|
|
options.CustomerDetails.TaxExempt == null
|
|
));
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PreviewInvoiceAsync_NonUSBased_PersonalUse_DoesNotSetTaxExempt(SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
// Arrange
|
|
var familiesPlan = new FamiliesPlan();
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.FamiliesAnnually))
|
|
.Returns(familiesPlan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.FamiliesAnnually
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel
|
|
{
|
|
Country = "FR",
|
|
PostalCode = "12345"
|
|
}
|
|
};
|
|
|
|
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
|
stripeAdapter
|
|
.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>())
|
|
.Returns(new Invoice
|
|
{
|
|
TotalExcludingTax = 400,
|
|
TotalTaxes = [new InvoiceTotalTax { Amount = 8 }],
|
|
Total = 408
|
|
});
|
|
|
|
// Act
|
|
await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
// Assert
|
|
await stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
|
|
options.CustomerDetails.TaxExempt == null
|
|
));
|
|
}
|
|
|
|
[Theory]
|
|
[BitAutoData]
|
|
public async Task PreviewInvoiceAsync_NonUSBased_BusinessUse_SetsTaxExemptReverse(SutProvider<StripePaymentService> sutProvider)
|
|
{
|
|
// Arrange
|
|
var plan = new EnterprisePlan(true);
|
|
sutProvider.GetDependency<IPricingClient>()
|
|
.GetPlanOrThrow(Arg.Is<PlanType>(p => p == PlanType.EnterpriseAnnually))
|
|
.Returns(plan);
|
|
|
|
var parameters = new PreviewOrganizationInvoiceRequestBody
|
|
{
|
|
PasswordManager = new OrganizationPasswordManagerRequestModel
|
|
{
|
|
Plan = PlanType.EnterpriseAnnually
|
|
},
|
|
TaxInformation = new TaxInformationRequestModel
|
|
{
|
|
Country = "FR",
|
|
PostalCode = "12345"
|
|
}
|
|
};
|
|
|
|
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
|
stripeAdapter
|
|
.InvoiceCreatePreviewAsync(Arg.Any<InvoiceCreatePreviewOptions>())
|
|
.Returns(new Invoice
|
|
{
|
|
TotalExcludingTax = 400,
|
|
TotalTaxes = [new InvoiceTotalTax { Amount = 8 }],
|
|
Total = 408
|
|
});
|
|
|
|
// Act
|
|
await sutProvider.Sut.PreviewInvoiceAsync(parameters, null, null);
|
|
|
|
// Assert
|
|
await stripeAdapter.Received(1).InvoiceCreatePreviewAsync(Arg.Is<InvoiceCreatePreviewOptions>(options =>
|
|
options.CustomerDetails.TaxExempt == StripeConstants.TaxExempt.Reverse
|
|
));
|
|
}
|
|
}
|