1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 13:08:17 -05:00

[PM-15808]Show suspended org modals for orgs in 'unpaid' & 'canceled' status (#5228)

* Recreate changes on the closed pr

Signed-off-by: Cy Okeke <cokeke@bitwarden.com>

* Remove unused references

Signed-off-by: Cy Okeke <cokeke@bitwarden.com>

---------

Signed-off-by: Cy Okeke <cokeke@bitwarden.com>
This commit is contained in:
cyprain-okeke 2025-01-07 20:01:40 +01:00 committed by GitHub
parent 61a8726492
commit eeb1be1dba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 54 additions and 4 deletions

View File

@ -1,7 +1,9 @@
#nullable enable #nullable enable
using Bit.Api.AdminConsole.Models.Request.Organizations;
using Bit.Api.Billing.Models.Requests; using Bit.Api.Billing.Models.Requests;
using Bit.Api.Billing.Models.Responses; using Bit.Api.Billing.Models.Responses;
using Bit.Core; using Bit.Core;
using Bit.Core.Billing.Models.Sales;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Repositories; using Bit.Core.Repositories;
@ -21,7 +23,8 @@ public class OrganizationBillingController(
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IPaymentService paymentService, IPaymentService paymentService,
ISubscriberService subscriberService, ISubscriberService subscriberService,
IPaymentHistoryService paymentHistoryService) : BaseBillingController IPaymentHistoryService paymentHistoryService,
IUserService userService) : BaseBillingController
{ {
[HttpGet("metadata")] [HttpGet("metadata")]
public async Task<IResult> GetMetadataAsync([FromRoute] Guid organizationId) public async Task<IResult> GetMetadataAsync([FromRoute] Guid organizationId)
@ -278,4 +281,37 @@ public class OrganizationBillingController(
return TypedResults.Ok(); return TypedResults.Ok();
} }
[HttpPost("restart-subscription")]
public async Task<IResult> RestartSubscriptionAsync([FromRoute] Guid organizationId,
[FromBody] OrganizationCreateRequestModel model)
{
var user = await userService.GetUserByPrincipalAsync(User);
if (user == null)
{
throw new UnauthorizedAccessException();
}
if (!featureService.IsEnabled(FeatureFlagKeys.AC2476_DeprecateStripeSourcesAPI))
{
return Error.NotFound();
}
if (!await currentContext.EditPaymentMethods(organizationId))
{
return Error.Unauthorized();
}
var organization = await organizationRepository.GetByIdAsync(organizationId);
if (organization == null)
{
return Error.NotFound();
}
var organizationSignup = model.ToOrganizationSignup(user);
var sale = OrganizationSale.From(organization, organizationSignup);
await organizationBillingService.Finalize(sale);
return TypedResults.Ok();
}
} }

View File

@ -9,6 +9,7 @@ public record OrganizationMetadataResponse(
bool IsSubscriptionUnpaid, bool IsSubscriptionUnpaid,
bool HasSubscription, bool HasSubscription,
bool HasOpenInvoice, bool HasOpenInvoice,
bool IsSubscriptionCanceled,
DateTime? InvoiceDueDate, DateTime? InvoiceDueDate,
DateTime? InvoiceCreatedDate, DateTime? InvoiceCreatedDate,
DateTime? SubPeriodEndDate) DateTime? SubPeriodEndDate)
@ -21,6 +22,7 @@ public record OrganizationMetadataResponse(
metadata.IsSubscriptionUnpaid, metadata.IsSubscriptionUnpaid,
metadata.HasSubscription, metadata.HasSubscription,
metadata.HasOpenInvoice, metadata.HasOpenInvoice,
metadata.IsSubscriptionCanceled,
metadata.InvoiceDueDate, metadata.InvoiceDueDate,
metadata.InvoiceCreatedDate, metadata.InvoiceCreatedDate,
metadata.SubPeriodEndDate); metadata.SubPeriodEndDate);

View File

@ -7,6 +7,7 @@ public record OrganizationMetadata(
bool IsSubscriptionUnpaid, bool IsSubscriptionUnpaid,
bool HasSubscription, bool HasSubscription,
bool HasOpenInvoice, bool HasOpenInvoice,
bool IsSubscriptionCanceled,
DateTime? InvoiceDueDate, DateTime? InvoiceDueDate,
DateTime? InvoiceCreatedDate, DateTime? InvoiceCreatedDate,
DateTime? SubPeriodEndDate); DateTime? SubPeriodEndDate);

View File

@ -69,7 +69,7 @@ public class OrganizationBillingService(
if (string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId)) if (string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId))
{ {
return new OrganizationMetadata(isEligibleForSelfHost, isManaged, false, return new OrganizationMetadata(isEligibleForSelfHost, isManaged, false,
false, false, false, null, null, null); false, false, false, false, null, null, null);
} }
var customer = await subscriberService.GetCustomer(organization, var customer = await subscriberService.GetCustomer(organization,
@ -79,6 +79,7 @@ public class OrganizationBillingService(
var isOnSecretsManagerStandalone = IsOnSecretsManagerStandalone(organization, customer, subscription); var isOnSecretsManagerStandalone = IsOnSecretsManagerStandalone(organization, customer, subscription);
var isSubscriptionUnpaid = IsSubscriptionUnpaid(subscription); var isSubscriptionUnpaid = IsSubscriptionUnpaid(subscription);
var isSubscriptionCanceled = IsSubscriptionCanceled(subscription);
var hasSubscription = true; var hasSubscription = true;
var openInvoice = await HasOpenInvoiceAsync(subscription); var openInvoice = await HasOpenInvoiceAsync(subscription);
var hasOpenInvoice = openInvoice.HasOpenInvoice; var hasOpenInvoice = openInvoice.HasOpenInvoice;
@ -87,7 +88,7 @@ public class OrganizationBillingService(
var subPeriodEndDate = subscription?.CurrentPeriodEnd; var subPeriodEndDate = subscription?.CurrentPeriodEnd;
return new OrganizationMetadata(isEligibleForSelfHost, isManaged, isOnSecretsManagerStandalone, return new OrganizationMetadata(isEligibleForSelfHost, isManaged, isOnSecretsManagerStandalone,
isSubscriptionUnpaid, hasSubscription, hasOpenInvoice, invoiceDueDate, invoiceCreatedDate, subPeriodEndDate); isSubscriptionUnpaid, hasSubscription, hasOpenInvoice, isSubscriptionCanceled, invoiceDueDate, invoiceCreatedDate, subPeriodEndDate);
} }
public async Task UpdatePaymentMethod( public async Task UpdatePaymentMethod(
@ -437,5 +438,15 @@ public class OrganizationBillingService(
? (true, invoice.Created, invoice.DueDate) ? (true, invoice.Created, invoice.DueDate)
: (false, null, null); : (false, null, null);
} }
private static bool IsSubscriptionCanceled(Subscription subscription)
{
if (subscription == null)
{
return false;
}
return subscription.Status == "canceled";
}
#endregion #endregion
} }

View File

@ -52,7 +52,7 @@ public class OrganizationBillingControllerTests
{ {
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(organizationId).Returns(true); sutProvider.GetDependency<ICurrentContext>().OrganizationUser(organizationId).Returns(true);
sutProvider.GetDependency<IOrganizationBillingService>().GetMetadata(organizationId) sutProvider.GetDependency<IOrganizationBillingService>().GetMetadata(organizationId)
.Returns(new OrganizationMetadata(true, true, true, true, true, true, null, null, null)); .Returns(new OrganizationMetadata(true, true, true, true, true, true, true, null, null, null));
var result = await sutProvider.Sut.GetMetadataAsync(organizationId); var result = await sutProvider.Sut.GetMetadataAsync(organizationId);