Skip to content

Commit bbc1a31

Browse files
billing/pm-24665/license-file-generation-should-fail-for-unpaid-subscription (#7444)
* Add changes for unpaid subscriptions * Remove the unpaid status and update the test * Add changes for premium user * Fix the lint error * remove subscriptionInfo and use subscription * Fix file encoding issue * SubscriptionLicenseValidator.cs is deleted * Fix the lint error
1 parent 076804f commit bbc1a31

4 files changed

Lines changed: 334 additions & 9 deletions

File tree

src/Core/Billing/Licenses/Queries/GetUserLicenseQuery.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
using Bit.Core.Billing.Models.Business;
1+
using Bit.Core.Billing.Constants;
2+
using Bit.Core.Billing.Models.Business;
3+
using Bit.Core.Billing.Services;
24
using Bit.Core.Entities;
5+
using Bit.Core.Exceptions;
36
using Bit.Core.Services;
47

58
namespace Bit.Core.Billing.Licenses.Queries;
@@ -10,10 +13,26 @@ public interface IGetUserLicenseQuery
1013
}
1114

1215
public class GetUserLicenseQuery(
13-
IUserService userService) : IGetUserLicenseQuery
16+
IUserService userService,
17+
IStripePaymentService paymentService) : IGetUserLicenseQuery
1418
{
1519
public async Task<UserLicense> Run(User user)
1620
{
21+
var subscriptionInfo = await paymentService.GetSubscriptionAsync(user);
22+
23+
if (subscriptionInfo.Subscription is null)
24+
{
25+
throw new BadRequestException("No active subscription found.");
26+
}
27+
28+
if (subscriptionInfo.Subscription.Status is StripeConstants.SubscriptionStatus.Canceled
29+
or StripeConstants.SubscriptionStatus.Incomplete
30+
or StripeConstants.SubscriptionStatus.IncompleteExpired)
31+
{
32+
throw new BadRequestException(
33+
"Unable to generate license due to a payment issue. Please update your billing information or contact support for assistance.");
34+
}
35+
1736
return await userService.GenerateLicenseAsync(user);
1837
}
1938
}

src/Core/Billing/Organizations/Queries/GetCloudOrganizationLicenseQuery.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33

44
using Bit.Core.AdminConsole.Entities;
55
using Bit.Core.AdminConsole.Repositories;
6+
using Bit.Core.Billing.Constants;
67
using Bit.Core.Billing.Organizations.Models;
78
using Bit.Core.Billing.Services;
89
using Bit.Core.Enums;
910
using Bit.Core.Exceptions;
1011
using Bit.Core.Models.Business;
1112
using Bit.Core.Platform.Installations;
12-
using Bit.Core.Services;
1313

1414
namespace Bit.Core.Billing.Organizations.Queries;
1515

@@ -25,20 +25,17 @@ public class GetCloudOrganizationLicenseQuery : IGetCloudOrganizationLicenseQuer
2525
private readonly IStripePaymentService _paymentService;
2626
private readonly ILicensingService _licensingService;
2727
private readonly IProviderRepository _providerRepository;
28-
private readonly IFeatureService _featureService;
2928

3029
public GetCloudOrganizationLicenseQuery(
3130
IInstallationRepository installationRepository,
3231
IStripePaymentService paymentService,
3332
ILicensingService licensingService,
34-
IProviderRepository providerRepository,
35-
IFeatureService featureService)
33+
IProviderRepository providerRepository)
3634
{
3735
_installationRepository = installationRepository;
3836
_paymentService = paymentService;
3937
_licensingService = licensingService;
4038
_providerRepository = providerRepository;
41-
_featureService = featureService;
4239
}
4340

4441
public async Task<OrganizationLicense> GetLicenseAsync(Organization organization, Guid installationId,
@@ -51,6 +48,20 @@ public async Task<OrganizationLicense> GetLicenseAsync(Organization organization
5148
}
5249

5350
var subscriptionInfo = await GetSubscriptionAsync(organization);
51+
52+
if (subscriptionInfo.Subscription is null)
53+
{
54+
throw new BadRequestException("No active subscription found.");
55+
}
56+
57+
if (subscriptionInfo.Subscription.Status is StripeConstants.SubscriptionStatus.Canceled
58+
or StripeConstants.SubscriptionStatus.Incomplete
59+
or StripeConstants.SubscriptionStatus.IncompleteExpired)
60+
{
61+
throw new BadRequestException(
62+
"Unable to generate license due to a payment issue. Please update your billing information or contact support for assistance.");
63+
}
64+
5465
var license = new OrganizationLicense(organization, subscriptionInfo, installationId, _licensingService, version);
5566
license.Token = await _licensingService.CreateOrganizationTokenAsync(organization, installationId, subscriptionInfo);
5667

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
using Bit.Core.Billing.Licenses.Queries;
2+
using Bit.Core.Billing.Models.Business;
3+
using Bit.Core.Billing.Services;
4+
using Bit.Core.Entities;
5+
using Bit.Core.Exceptions;
6+
using Bit.Core.Models.Business;
7+
using Bit.Core.Services;
8+
using Bit.Test.Common.AutoFixture;
9+
using Bit.Test.Common.AutoFixture.Attributes;
10+
using NSubstitute;
11+
using Stripe;
12+
using Xunit;
13+
14+
namespace Bit.Core.Test.Billing.Licenses.Queries;
15+
16+
[SutProviderCustomize]
17+
public class GetUserLicenseQueryTests
18+
{
19+
[Theory]
20+
[BitAutoData]
21+
public async Task RunAsync_CanceledSubscription_Throws(
22+
SutProvider<GetUserLicenseQuery> sutProvider,
23+
User user)
24+
{
25+
var subInfo = new SubscriptionInfo
26+
{
27+
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "canceled" })
28+
};
29+
sutProvider.GetDependency<IStripePaymentService>()
30+
.GetSubscriptionAsync(user)
31+
.Returns(subInfo);
32+
33+
var exception = await Assert.ThrowsAsync<BadRequestException>(async () =>
34+
await sutProvider.Sut.Run(user));
35+
Assert.Contains("Unable to generate license due to a payment issue", exception.Message);
36+
}
37+
38+
[Theory]
39+
[BitAutoData]
40+
public async Task RunAsync_IncompleteSubscription_Throws(
41+
SutProvider<GetUserLicenseQuery> sutProvider,
42+
User user)
43+
{
44+
var subInfo = new SubscriptionInfo
45+
{
46+
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "incomplete" })
47+
};
48+
sutProvider.GetDependency<IStripePaymentService>()
49+
.GetSubscriptionAsync(user)
50+
.Returns(subInfo);
51+
52+
var exception = await Assert.ThrowsAsync<BadRequestException>(async () =>
53+
await sutProvider.Sut.Run(user));
54+
Assert.Contains("Unable to generate license due to a payment issue", exception.Message);
55+
}
56+
57+
[Theory]
58+
[BitAutoData]
59+
public async Task RunAsync_IncompleteExpiredSubscription_Throws(
60+
SutProvider<GetUserLicenseQuery> sutProvider,
61+
User user)
62+
{
63+
var subInfo = new SubscriptionInfo
64+
{
65+
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "incomplete_expired" })
66+
};
67+
sutProvider.GetDependency<IStripePaymentService>()
68+
.GetSubscriptionAsync(user)
69+
.Returns(subInfo);
70+
71+
var exception = await Assert.ThrowsAsync<BadRequestException>(async () =>
72+
await sutProvider.Sut.Run(user));
73+
Assert.Contains("Unable to generate license due to a payment issue", exception.Message);
74+
}
75+
76+
[Theory]
77+
[BitAutoData]
78+
public async Task RunAsync_NullSubscription_Throws(
79+
SutProvider<GetUserLicenseQuery> sutProvider,
80+
User user)
81+
{
82+
var subInfo = new SubscriptionInfo { Subscription = null };
83+
sutProvider.GetDependency<IStripePaymentService>()
84+
.GetSubscriptionAsync(user)
85+
.Returns(subInfo);
86+
87+
var exception = await Assert.ThrowsAsync<BadRequestException>(async () =>
88+
await sutProvider.Sut.Run(user));
89+
Assert.Contains("No active subscription found", exception.Message);
90+
}
91+
92+
[Theory]
93+
[BitAutoData]
94+
public async Task RunAsync_ActiveSubscription_Succeeds(
95+
SutProvider<GetUserLicenseQuery> sutProvider,
96+
User user, UserLicense userLicense)
97+
{
98+
var subInfo = new SubscriptionInfo
99+
{
100+
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "active" })
101+
};
102+
sutProvider.GetDependency<IStripePaymentService>()
103+
.GetSubscriptionAsync(user)
104+
.Returns(subInfo);
105+
sutProvider.GetDependency<IUserService>().GenerateLicenseAsync(user).Returns(userLicense);
106+
107+
var result = await sutProvider.Sut.Run(user);
108+
109+
Assert.NotNull(result);
110+
Assert.Equal(userLicense, result);
111+
}
112+
113+
[Theory]
114+
[BitAutoData]
115+
public async Task RunAsync_TrialingSubscription_Succeeds(
116+
SutProvider<GetUserLicenseQuery> sutProvider,
117+
User user, UserLicense userLicense)
118+
{
119+
var subInfo = new SubscriptionInfo
120+
{
121+
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "trialing" })
122+
};
123+
sutProvider.GetDependency<IStripePaymentService>()
124+
.GetSubscriptionAsync(user)
125+
.Returns(subInfo);
126+
sutProvider.GetDependency<IUserService>().GenerateLicenseAsync(user).Returns(userLicense);
127+
128+
var result = await sutProvider.Sut.Run(user);
129+
130+
Assert.NotNull(result);
131+
Assert.Equal(userLicense, result);
132+
}
133+
134+
[Theory]
135+
[BitAutoData]
136+
public async Task RunAsync_PastDueSubscription_Succeeds(
137+
SutProvider<GetUserLicenseQuery> sutProvider,
138+
User user, UserLicense userLicense)
139+
{
140+
var subInfo = new SubscriptionInfo
141+
{
142+
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "past_due" })
143+
};
144+
sutProvider.GetDependency<IStripePaymentService>()
145+
.GetSubscriptionAsync(user)
146+
.Returns(subInfo);
147+
sutProvider.GetDependency<IUserService>().GenerateLicenseAsync(user).Returns(userLicense);
148+
149+
var result = await sutProvider.Sut.Run(user);
150+
151+
Assert.NotNull(result);
152+
Assert.Equal(userLicense, result);
153+
}
154+
}

0 commit comments

Comments
 (0)