1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 05:00:19 -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
using Bit.Api.AdminConsole.Models.Request.Organizations;
using Bit.Api.Billing.Models.Requests;
using Bit.Api.Billing.Models.Responses;
using Bit.Core;
using Bit.Core.Billing.Models.Sales;
using Bit.Core.Billing.Services;
using Bit.Core.Context;
using Bit.Core.Repositories;
@ -21,7 +23,8 @@ public class OrganizationBillingController(
IOrganizationRepository organizationRepository,
IPaymentService paymentService,
ISubscriberService subscriberService,
IPaymentHistoryService paymentHistoryService) : BaseBillingController
IPaymentHistoryService paymentHistoryService,
IUserService userService) : BaseBillingController
{
[HttpGet("metadata")]
public async Task<IResult> GetMetadataAsync([FromRoute] Guid organizationId)
@ -278,4 +281,37 @@ public class OrganizationBillingController(
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 HasSubscription,
bool HasOpenInvoice,
bool IsSubscriptionCanceled,
DateTime? InvoiceDueDate,
DateTime? InvoiceCreatedDate,
DateTime? SubPeriodEndDate)
@ -21,6 +22,7 @@ public record OrganizationMetadataResponse(
metadata.IsSubscriptionUnpaid,
metadata.HasSubscription,
metadata.HasOpenInvoice,
metadata.IsSubscriptionCanceled,
metadata.InvoiceDueDate,
metadata.InvoiceCreatedDate,
metadata.SubPeriodEndDate);

View File

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

View File

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

View File

@ -52,7 +52,7 @@ public class OrganizationBillingControllerTests
{
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(organizationId).Returns(true);
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);