mirror of
https://github.com/bitwarden/server.git
synced 2024-11-30 13:33:24 +01:00
[AC-2795] Add account credit & tax information to provider subscription (#4276)
* Add account credit, suspension and tax information to subscription response * Run dotnet format'
This commit is contained in:
parent
6646d11074
commit
e8e725c389
@ -1,6 +1,5 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Bit.Commercial.Core.Billing.Models;
|
using Bit.Commercial.Core.Billing.Models;
|
||||||
using Bit.Core;
|
|
||||||
using Bit.Core.AdminConsole.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Entities.Provider;
|
using Bit.Core.AdminConsole.Entities.Provider;
|
||||||
using Bit.Core.AdminConsole.Enums.Provider;
|
using Bit.Core.AdminConsole.Enums.Provider;
|
||||||
@ -29,7 +28,6 @@ namespace Bit.Commercial.Core.Billing;
|
|||||||
|
|
||||||
public class ProviderBillingService(
|
public class ProviderBillingService(
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
IFeatureService featureService,
|
|
||||||
IGlobalSettings globalSettings,
|
IGlobalSettings globalSettings,
|
||||||
ILogger<ProviderBillingService> logger,
|
ILogger<ProviderBillingService> logger,
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
@ -272,13 +270,6 @@ public class ProviderBillingService(
|
|||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(provider);
|
ArgumentNullException.ThrowIfNull(provider);
|
||||||
|
|
||||||
if (provider.Type == ProviderType.Reseller)
|
|
||||||
{
|
|
||||||
logger.LogError("Consolidated billing subscription cannot be retrieved for reseller-type provider ({ID})", provider.Id);
|
|
||||||
|
|
||||||
throw ContactSupport("Consolidated billing does not support reseller-type providers");
|
|
||||||
}
|
|
||||||
|
|
||||||
var subscription = await subscriberService.GetSubscription(provider, new SubscriptionGetOptions
|
var subscription = await subscriberService.GetSubscription(provider, new SubscriptionGetOptions
|
||||||
{
|
{
|
||||||
Expand = ["customer", "test_clock"]
|
Expand = ["customer", "test_clock"]
|
||||||
@ -289,18 +280,6 @@ public class ProviderBillingService(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime? subscriptionSuspensionDate = null;
|
|
||||||
DateTime? subscriptionUnpaidPeriodEndDate = null;
|
|
||||||
if (featureService.IsEnabled(FeatureFlagKeys.AC1795_UpdatedSubscriptionStatusSection))
|
|
||||||
{
|
|
||||||
var (suspensionDate, unpaidPeriodEndDate) = await paymentService.GetSuspensionDateAsync(subscription);
|
|
||||||
if (suspensionDate.HasValue && unpaidPeriodEndDate.HasValue)
|
|
||||||
{
|
|
||||||
subscriptionSuspensionDate = suspensionDate;
|
|
||||||
subscriptionUnpaidPeriodEndDate = unpaidPeriodEndDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var providerPlans = await providerPlanRepository.GetByProviderId(provider.Id);
|
var providerPlans = await providerPlanRepository.GetByProviderId(provider.Id);
|
||||||
|
|
||||||
var configuredProviderPlans = providerPlans
|
var configuredProviderPlans = providerPlans
|
||||||
@ -308,11 +287,15 @@ public class ProviderBillingService(
|
|||||||
.Select(ConfiguredProviderPlanDTO.From)
|
.Select(ConfiguredProviderPlanDTO.From)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
var taxInformation = await subscriberService.GetTaxInformation(provider);
|
||||||
|
|
||||||
|
var suspension = await GetSuspensionAsync(stripeAdapter, subscription);
|
||||||
|
|
||||||
return new ConsolidatedBillingSubscriptionDTO(
|
return new ConsolidatedBillingSubscriptionDTO(
|
||||||
configuredProviderPlans,
|
configuredProviderPlans,
|
||||||
subscription,
|
subscription,
|
||||||
subscriptionSuspensionDate,
|
taxInformation,
|
||||||
subscriptionUnpaidPeriodEndDate);
|
suspension);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ScaleSeats(
|
public async Task ScaleSeats(
|
||||||
|
@ -857,13 +857,16 @@ public class ProviderBillingServiceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetConsolidatedBillingSubscription_Success(
|
public async Task GetConsolidatedBillingSubscription_Active_NoSuspension_Success(
|
||||||
SutProvider<ProviderBillingService> sutProvider,
|
SutProvider<ProviderBillingService> sutProvider,
|
||||||
Provider provider)
|
Provider provider)
|
||||||
{
|
{
|
||||||
var subscriberService = sutProvider.GetDependency<ISubscriberService>();
|
var subscriberService = sutProvider.GetDependency<ISubscriberService>();
|
||||||
|
|
||||||
var subscription = new Subscription();
|
var subscription = new Subscription
|
||||||
|
{
|
||||||
|
Status = "active"
|
||||||
|
};
|
||||||
|
|
||||||
subscriberService.GetSubscription(provider, Arg.Is<SubscriptionGetOptions>(
|
subscriberService.GetSubscription(provider, Arg.Is<SubscriptionGetOptions>(
|
||||||
options => options.Expand.Count == 2 && options.Expand.First() == "customer" && options.Expand.Last() == "test_clock")).Returns(subscription);
|
options => options.Expand.Count == 2 && options.Expand.First() == "customer" && options.Expand.Last() == "test_clock")).Returns(subscription);
|
||||||
@ -894,26 +897,33 @@ public class ProviderBillingServiceTests
|
|||||||
|
|
||||||
providerPlanRepository.GetByProviderId(provider.Id).Returns(providerPlans);
|
providerPlanRepository.GetByProviderId(provider.Id).Returns(providerPlans);
|
||||||
|
|
||||||
var consolidatedBillingSubscription = await sutProvider.Sut.GetConsolidatedBillingSubscription(provider);
|
var taxInformation =
|
||||||
|
new TaxInformationDTO("US", "12345", "123456789", "123 Example St.", null, "Example Town", "NY");
|
||||||
|
|
||||||
Assert.NotNull(consolidatedBillingSubscription);
|
subscriberService.GetTaxInformation(provider).Returns(taxInformation);
|
||||||
|
|
||||||
Assert.Equivalent(consolidatedBillingSubscription.Subscription, subscription);
|
var (gotProviderPlans, gotSubscription, gotTaxInformation, gotSuspension) = await sutProvider.Sut.GetConsolidatedBillingSubscription(provider);
|
||||||
|
|
||||||
Assert.Equal(2, consolidatedBillingSubscription.ProviderPlans.Count);
|
Assert.Equal(2, gotProviderPlans.Count);
|
||||||
|
|
||||||
var configuredEnterprisePlan =
|
var configuredEnterprisePlan =
|
||||||
consolidatedBillingSubscription.ProviderPlans.FirstOrDefault(configuredPlan =>
|
gotProviderPlans.FirstOrDefault(configuredPlan =>
|
||||||
configuredPlan.PlanType == PlanType.EnterpriseMonthly);
|
configuredPlan.PlanType == PlanType.EnterpriseMonthly);
|
||||||
|
|
||||||
var configuredTeamsPlan =
|
var configuredTeamsPlan =
|
||||||
consolidatedBillingSubscription.ProviderPlans.FirstOrDefault(configuredPlan =>
|
gotProviderPlans.FirstOrDefault(configuredPlan =>
|
||||||
configuredPlan.PlanType == PlanType.TeamsMonthly);
|
configuredPlan.PlanType == PlanType.TeamsMonthly);
|
||||||
|
|
||||||
Compare(enterprisePlan, configuredEnterprisePlan);
|
Compare(enterprisePlan, configuredEnterprisePlan);
|
||||||
|
|
||||||
Compare(teamsPlan, configuredTeamsPlan);
|
Compare(teamsPlan, configuredTeamsPlan);
|
||||||
|
|
||||||
|
Assert.Equivalent(subscription, gotSubscription);
|
||||||
|
|
||||||
|
Assert.Equivalent(taxInformation, gotTaxInformation);
|
||||||
|
|
||||||
|
Assert.Null(gotSuspension);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
void Compare(ProviderPlan providerPlan, ConfiguredProviderPlanDTO configuredProviderPlan)
|
void Compare(ProviderPlan providerPlan, ConfiguredProviderPlanDTO configuredProviderPlan)
|
||||||
@ -927,6 +937,83 @@ public class ProviderBillingServiceTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task GetConsolidatedBillingSubscription_PastDue_HasSuspension_Success(
|
||||||
|
SutProvider<ProviderBillingService> sutProvider,
|
||||||
|
Provider provider)
|
||||||
|
{
|
||||||
|
var subscriberService = sutProvider.GetDependency<ISubscriberService>();
|
||||||
|
|
||||||
|
var subscription = new Subscription
|
||||||
|
{
|
||||||
|
Id = "subscription_id",
|
||||||
|
Status = "past_due",
|
||||||
|
CollectionMethod = "send_invoice"
|
||||||
|
};
|
||||||
|
|
||||||
|
subscriberService.GetSubscription(provider, Arg.Is<SubscriptionGetOptions>(
|
||||||
|
options => options.Expand.Count == 2 && options.Expand.First() == "customer" && options.Expand.Last() == "test_clock")).Returns(subscription);
|
||||||
|
|
||||||
|
var providerPlanRepository = sutProvider.GetDependency<IProviderPlanRepository>();
|
||||||
|
|
||||||
|
var enterprisePlan = new ProviderPlan
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
PlanType = PlanType.EnterpriseMonthly,
|
||||||
|
SeatMinimum = 100,
|
||||||
|
PurchasedSeats = 0,
|
||||||
|
AllocatedSeats = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
var teamsPlan = new ProviderPlan
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
PlanType = PlanType.TeamsMonthly,
|
||||||
|
SeatMinimum = 50,
|
||||||
|
PurchasedSeats = 10,
|
||||||
|
AllocatedSeats = 60
|
||||||
|
};
|
||||||
|
|
||||||
|
var providerPlans = new List<ProviderPlan> { enterprisePlan, teamsPlan, };
|
||||||
|
|
||||||
|
providerPlanRepository.GetByProviderId(provider.Id).Returns(providerPlans);
|
||||||
|
|
||||||
|
var taxInformation =
|
||||||
|
new TaxInformationDTO("US", "12345", "123456789", "123 Example St.", null, "Example Town", "NY");
|
||||||
|
|
||||||
|
subscriberService.GetTaxInformation(provider).Returns(taxInformation);
|
||||||
|
|
||||||
|
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||||
|
|
||||||
|
var openInvoice = new Invoice
|
||||||
|
{
|
||||||
|
Id = "invoice_id",
|
||||||
|
Status = "open",
|
||||||
|
DueDate = new DateTime(2024, 6, 1),
|
||||||
|
Created = new DateTime(2024, 5, 1),
|
||||||
|
PeriodEnd = new DateTime(2024, 6, 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
stripeAdapter.InvoiceSearchAsync(Arg.Is<InvoiceSearchOptions>(options =>
|
||||||
|
options.Query == $"subscription:'{subscription.Id}' status:'open'"))
|
||||||
|
.Returns([openInvoice]);
|
||||||
|
|
||||||
|
var (gotProviderPlans, gotSubscription, gotTaxInformation, gotSuspension) = await sutProvider.Sut.GetConsolidatedBillingSubscription(provider);
|
||||||
|
|
||||||
|
Assert.Equal(2, gotProviderPlans.Count);
|
||||||
|
|
||||||
|
Assert.Equivalent(subscription, gotSubscription);
|
||||||
|
|
||||||
|
Assert.Equivalent(taxInformation, gotTaxInformation);
|
||||||
|
|
||||||
|
Assert.NotNull(gotSuspension);
|
||||||
|
Assert.Equal(openInvoice.DueDate.Value.AddDays(30), gotSuspension.SuspensionDate);
|
||||||
|
Assert.Equal(openInvoice.PeriodEnd, gotSuspension.UnpaidPeriodEndDate);
|
||||||
|
Assert.Equal(30, gotSuspension.GracePeriod);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region StartSubscription
|
#region StartSubscription
|
||||||
|
@ -8,11 +8,11 @@ public record ConsolidatedBillingSubscriptionResponse(
|
|||||||
DateTime CurrentPeriodEndDate,
|
DateTime CurrentPeriodEndDate,
|
||||||
decimal? DiscountPercentage,
|
decimal? DiscountPercentage,
|
||||||
string CollectionMethod,
|
string CollectionMethod,
|
||||||
DateTime? UnpaidPeriodEndDate,
|
IEnumerable<ProviderPlanResponse> Plans,
|
||||||
int? GracePeriod,
|
long AccountCredit,
|
||||||
DateTime? SuspensionDate,
|
TaxInformationDTO TaxInformation,
|
||||||
DateTime? CancelAt,
|
DateTime? CancelAt,
|
||||||
IEnumerable<ProviderPlanResponse> Plans)
|
SubscriptionSuspensionDTO Suspension)
|
||||||
{
|
{
|
||||||
private const string _annualCadence = "Annual";
|
private const string _annualCadence = "Annual";
|
||||||
private const string _monthlyCadence = "Monthly";
|
private const string _monthlyCadence = "Monthly";
|
||||||
@ -20,9 +20,9 @@ public record ConsolidatedBillingSubscriptionResponse(
|
|||||||
public static ConsolidatedBillingSubscriptionResponse From(
|
public static ConsolidatedBillingSubscriptionResponse From(
|
||||||
ConsolidatedBillingSubscriptionDTO consolidatedBillingSubscription)
|
ConsolidatedBillingSubscriptionDTO consolidatedBillingSubscription)
|
||||||
{
|
{
|
||||||
var (providerPlans, subscription, suspensionDate, unpaidPeriodEndDate) = consolidatedBillingSubscription;
|
var (providerPlans, subscription, taxInformation, suspension) = consolidatedBillingSubscription;
|
||||||
|
|
||||||
var providerPlansDTO = providerPlans
|
var providerPlanResponses = providerPlans
|
||||||
.Select(providerPlan =>
|
.Select(providerPlan =>
|
||||||
{
|
{
|
||||||
var plan = StaticStore.GetPlan(providerPlan.PlanType);
|
var plan = StaticStore.GetPlan(providerPlan.PlanType);
|
||||||
@ -37,18 +37,16 @@ public record ConsolidatedBillingSubscriptionResponse(
|
|||||||
cadence);
|
cadence);
|
||||||
});
|
});
|
||||||
|
|
||||||
var gracePeriod = subscription.CollectionMethod == "charge_automatically" ? 14 : 30;
|
|
||||||
|
|
||||||
return new ConsolidatedBillingSubscriptionResponse(
|
return new ConsolidatedBillingSubscriptionResponse(
|
||||||
subscription.Status,
|
subscription.Status,
|
||||||
subscription.CurrentPeriodEnd,
|
subscription.CurrentPeriodEnd,
|
||||||
subscription.Customer?.Discount?.Coupon?.PercentOff,
|
subscription.Customer?.Discount?.Coupon?.PercentOff,
|
||||||
subscription.CollectionMethod,
|
subscription.CollectionMethod,
|
||||||
unpaidPeriodEndDate,
|
providerPlanResponses,
|
||||||
gracePeriod,
|
subscription.Customer?.Balance ?? 0,
|
||||||
suspensionDate,
|
taxInformation,
|
||||||
subscription.CancelAt,
|
subscription.CancelAt,
|
||||||
providerPlansDTO);
|
suspension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,5 +5,5 @@ namespace Bit.Core.Billing.Models;
|
|||||||
public record ConsolidatedBillingSubscriptionDTO(
|
public record ConsolidatedBillingSubscriptionDTO(
|
||||||
List<ConfiguredProviderPlanDTO> ProviderPlans,
|
List<ConfiguredProviderPlanDTO> ProviderPlans,
|
||||||
Subscription Subscription,
|
Subscription Subscription,
|
||||||
DateTime? SuspensionDate,
|
TaxInformationDTO TaxInformation,
|
||||||
DateTime? UnpaidPeriodEndDate);
|
SubscriptionSuspensionDTO Suspension);
|
||||||
|
6
src/Core/Billing/Models/SubscriptionSuspensionDTO.cs
Normal file
6
src/Core/Billing/Models/SubscriptionSuspensionDTO.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace Bit.Core.Billing.Models;
|
||||||
|
|
||||||
|
public record SubscriptionSuspensionDTO(
|
||||||
|
DateTime SuspensionDate,
|
||||||
|
DateTime UnpaidPeriodEndDate,
|
||||||
|
int GracePeriod);
|
@ -1,4 +1,8 @@
|
|||||||
namespace Bit.Core.Billing;
|
using Bit.Core.Billing.Models;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Stripe;
|
||||||
|
|
||||||
|
namespace Bit.Core.Billing;
|
||||||
|
|
||||||
public static class Utilities
|
public static class Utilities
|
||||||
{
|
{
|
||||||
@ -8,4 +12,67 @@ public static class Utilities
|
|||||||
string internalMessage = null,
|
string internalMessage = null,
|
||||||
Exception innerException = null) => new("Something went wrong with your request. Please contact support.",
|
Exception innerException = null) => new("Something went wrong with your request. Please contact support.",
|
||||||
internalMessage, innerException);
|
internalMessage, innerException);
|
||||||
|
|
||||||
|
public static async Task<SubscriptionSuspensionDTO> GetSuspensionAsync(
|
||||||
|
IStripeAdapter stripeAdapter,
|
||||||
|
Subscription subscription)
|
||||||
|
{
|
||||||
|
if (subscription.Status is not "past_due" && subscription.Status is not "unpaid")
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var openInvoices = await stripeAdapter.InvoiceSearchAsync(new InvoiceSearchOptions
|
||||||
|
{
|
||||||
|
Query = $"subscription:'{subscription.Id}' status:'open'"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (openInvoices.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentDate = subscription.TestClock?.FrozenTime ?? DateTime.UtcNow;
|
||||||
|
|
||||||
|
switch (subscription.CollectionMethod)
|
||||||
|
{
|
||||||
|
case "charge_automatically":
|
||||||
|
{
|
||||||
|
var firstOverdueInvoice = openInvoices
|
||||||
|
.Where(invoice => invoice.PeriodEnd < currentDate && invoice.Attempted)
|
||||||
|
.MinBy(invoice => invoice.Created);
|
||||||
|
|
||||||
|
if (firstOverdueInvoice == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int gracePeriod = 14;
|
||||||
|
|
||||||
|
return new SubscriptionSuspensionDTO(
|
||||||
|
firstOverdueInvoice.Created.AddDays(gracePeriod),
|
||||||
|
firstOverdueInvoice.PeriodEnd,
|
||||||
|
gracePeriod);
|
||||||
|
}
|
||||||
|
case "send_invoice":
|
||||||
|
{
|
||||||
|
var firstOverdueInvoice = openInvoices
|
||||||
|
.Where(invoice => invoice.DueDate < currentDate)
|
||||||
|
.MinBy(invoice => invoice.Created);
|
||||||
|
|
||||||
|
if (firstOverdueInvoice?.DueDate == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int gracePeriod = 30;
|
||||||
|
|
||||||
|
return new SubscriptionSuspensionDTO(
|
||||||
|
firstOverdueInvoice.DueDate.Value.AddDays(gracePeriod),
|
||||||
|
firstOverdueInvoice.PeriodEnd,
|
||||||
|
gracePeriod);
|
||||||
|
}
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,19 +385,34 @@ public class ProviderBillingControllerTests
|
|||||||
|
|
||||||
var subscription = new Subscription
|
var subscription = new Subscription
|
||||||
{
|
{
|
||||||
Status = "active",
|
Status = "unpaid",
|
||||||
CurrentPeriodEnd = new DateTime(2025, 1, 1),
|
CurrentPeriodEnd = new DateTime(2024, 6, 30),
|
||||||
Customer = new Customer { Discount = new Discount { Coupon = new Coupon { PercentOff = 10 } } }
|
Customer = new Customer
|
||||||
|
{
|
||||||
|
Balance = 100000,
|
||||||
|
Discount = new Discount
|
||||||
|
{
|
||||||
|
Coupon = new Coupon
|
||||||
|
{
|
||||||
|
PercentOff = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DateTime? SuspensionDate = new DateTime();
|
var taxInformation =
|
||||||
DateTime? UnpaidPeriodEndDate = new DateTime();
|
new TaxInformationDTO("US", "12345", "123456789", "123 Example St.", null, "Example Town", "NY");
|
||||||
var gracePeriod = 30;
|
|
||||||
|
var suspension = new SubscriptionSuspensionDTO(
|
||||||
|
new DateTime(2024, 7, 30),
|
||||||
|
new DateTime(2024, 5, 30),
|
||||||
|
30);
|
||||||
|
|
||||||
var consolidatedBillingSubscription = new ConsolidatedBillingSubscriptionDTO(
|
var consolidatedBillingSubscription = new ConsolidatedBillingSubscriptionDTO(
|
||||||
configuredProviderPlans,
|
configuredProviderPlans,
|
||||||
subscription,
|
subscription,
|
||||||
SuspensionDate,
|
taxInformation,
|
||||||
UnpaidPeriodEndDate);
|
suspension);
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderBillingService>().GetConsolidatedBillingSubscription(provider)
|
sutProvider.GetDependency<IProviderBillingService>().GetConsolidatedBillingSubscription(provider)
|
||||||
.Returns(consolidatedBillingSubscription);
|
.Returns(consolidatedBillingSubscription);
|
||||||
@ -408,13 +423,10 @@ public class ProviderBillingControllerTests
|
|||||||
|
|
||||||
var response = ((Ok<ConsolidatedBillingSubscriptionResponse>)result).Value;
|
var response = ((Ok<ConsolidatedBillingSubscriptionResponse>)result).Value;
|
||||||
|
|
||||||
Assert.Equal(response.Status, subscription.Status);
|
Assert.Equal(subscription.Status, response.Status);
|
||||||
Assert.Equal(response.CurrentPeriodEndDate, subscription.CurrentPeriodEnd);
|
Assert.Equal(subscription.CurrentPeriodEnd, response.CurrentPeriodEndDate);
|
||||||
Assert.Equal(response.DiscountPercentage, subscription.Customer!.Discount!.Coupon!.PercentOff);
|
Assert.Equal(subscription.Customer!.Discount!.Coupon!.PercentOff, response.DiscountPercentage);
|
||||||
Assert.Equal(response.CollectionMethod, subscription.CollectionMethod);
|
Assert.Equal(subscription.CollectionMethod, response.CollectionMethod);
|
||||||
Assert.Equal(response.UnpaidPeriodEndDate, UnpaidPeriodEndDate);
|
|
||||||
Assert.Equal(response.GracePeriod, gracePeriod);
|
|
||||||
Assert.Equal(response.SuspensionDate, SuspensionDate);
|
|
||||||
|
|
||||||
var teamsPlan = StaticStore.GetPlan(PlanType.TeamsMonthly);
|
var teamsPlan = StaticStore.GetPlan(PlanType.TeamsMonthly);
|
||||||
var providerTeamsPlan = response.Plans.FirstOrDefault(plan => plan.PlanName == teamsPlan.Name);
|
var providerTeamsPlan = response.Plans.FirstOrDefault(plan => plan.PlanName == teamsPlan.Name);
|
||||||
@ -433,7 +445,13 @@ public class ProviderBillingControllerTests
|
|||||||
Assert.Equal(90, providerEnterprisePlan.AssignedSeats);
|
Assert.Equal(90, providerEnterprisePlan.AssignedSeats);
|
||||||
Assert.Equal(100 * enterprisePlan.PasswordManager.ProviderPortalSeatPrice, providerEnterprisePlan.Cost);
|
Assert.Equal(100 * enterprisePlan.PasswordManager.ProviderPortalSeatPrice, providerEnterprisePlan.Cost);
|
||||||
Assert.Equal("Monthly", providerEnterprisePlan.Cadence);
|
Assert.Equal("Monthly", providerEnterprisePlan.Cadence);
|
||||||
|
|
||||||
|
Assert.Equal(100000, response.AccountCredit);
|
||||||
|
Assert.Equal(taxInformation, response.TaxInformation);
|
||||||
|
Assert.Null(response.CancelAt);
|
||||||
|
Assert.Equal(suspension, response.Suspension);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region GetTaxInformationAsync
|
#region GetTaxInformationAsync
|
||||||
|
Loading…
Reference in New Issue
Block a user