From 6ada37db06b0fccd33e7aae1f5a135a981e9af16 Mon Sep 17 00:00:00 2001 From: Cy Okeke Date: Fri, 20 Dec 2024 16:44:50 +0100 Subject: [PATCH] changes for restarting subscription Signed-off-by: Cy Okeke --- .../OrganizationBillingController.cs | 37 ++++++++++++++++++- .../Responses/OrganizationMetadataResponse.cs | 6 ++- .../Billing/Models/OrganizationMetadata.cs | 3 +- .../OrganizationBillingService.cs | 19 ++++++++-- 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/Api/Billing/Controllers/OrganizationBillingController.cs b/src/Api/Billing/Controllers/OrganizationBillingController.cs index 7da0a0f6020b..27a686b2af1f 100644 --- a/src/Api/Billing/Controllers/OrganizationBillingController.cs +++ b/src/Api/Billing/Controllers/OrganizationBillingController.cs @@ -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 GetMetadataAsync([FromRoute] Guid organizationId) @@ -278,4 +281,36 @@ public async Task UpdateTaxInformationAsync( return TypedResults.Ok(); } + + [HttpPost("restart-subscription")] + public async Task 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(); + } } diff --git a/src/Api/Billing/Models/Responses/OrganizationMetadataResponse.cs b/src/Api/Billing/Models/Responses/OrganizationMetadataResponse.cs index 86cbdb92c3d9..19b506fbd2db 100644 --- a/src/Api/Billing/Models/Responses/OrganizationMetadataResponse.cs +++ b/src/Api/Billing/Models/Responses/OrganizationMetadataResponse.cs @@ -7,7 +7,8 @@ public record OrganizationMetadataResponse( bool IsManaged, bool IsOnSecretsManagerStandalone, bool IsSubscriptionUnpaid, - bool HasSubscription) + bool HasSubscription, + bool IsSubscriptionCanceled) { public static OrganizationMetadataResponse From(OrganizationMetadata metadata) => new( @@ -15,5 +16,6 @@ public static OrganizationMetadataResponse From(OrganizationMetadata metadata) metadata.IsManaged, metadata.IsOnSecretsManagerStandalone, metadata.IsSubscriptionUnpaid, - metadata.HasSubscription); + metadata.HasSubscription, + metadata.IsSubscriptionCanceled); } diff --git a/src/Core/Billing/Models/OrganizationMetadata.cs b/src/Core/Billing/Models/OrganizationMetadata.cs index 5bdb450dc653..fd2c3c66e942 100644 --- a/src/Core/Billing/Models/OrganizationMetadata.cs +++ b/src/Core/Billing/Models/OrganizationMetadata.cs @@ -5,4 +5,5 @@ public record OrganizationMetadata( bool IsManaged, bool IsOnSecretsManagerStandalone, bool IsSubscriptionUnpaid, - bool HasSubscription); + bool HasSubscription, + bool IsSubscriptionCanceled); diff --git a/src/Core/Billing/Services/Implementations/OrganizationBillingService.cs b/src/Core/Billing/Services/Implementations/OrganizationBillingService.cs index eadc5896258f..abd85b9882a9 100644 --- a/src/Core/Billing/Services/Implementations/OrganizationBillingService.cs +++ b/src/Core/Billing/Services/Implementations/OrganizationBillingService.cs @@ -28,7 +28,9 @@ public class OrganizationBillingService( IOrganizationRepository organizationRepository, ISetupIntentCache setupIntentCache, IStripeAdapter stripeAdapter, - ISubscriberService subscriberService) : IOrganizationBillingService + ISubscriberService subscriberService, + IPaymentService paymentService, + IFeatureService featureService) : IOrganizationBillingService { public async Task Finalize(OrganizationSale sale) { @@ -68,7 +70,7 @@ public async Task Finalize(OrganizationSale sale) if (string.IsNullOrWhiteSpace(organization.GatewaySubscriptionId)) { return new OrganizationMetadata(isEligibleForSelfHost, isManaged, false, - false, false); + false, false, false); } var customer = await subscriberService.GetCustomer(organization, @@ -77,10 +79,11 @@ public async Task Finalize(OrganizationSale sale) var subscription = await subscriberService.GetSubscription(organization); var isOnSecretsManagerStandalone = IsOnSecretsManagerStandalone(organization, customer, subscription); var isSubscriptionUnpaid = IsSubscriptionUnpaid(subscription); + var isSubscriptionCanceled = IsSubscriptionCanceled(subscription); var hasSubscription = true; return new OrganizationMetadata(isEligibleForSelfHost, isManaged, isOnSecretsManagerStandalone, - isSubscriptionUnpaid, hasSubscription); + isSubscriptionUnpaid, hasSubscription, isSubscriptionCanceled); } public async Task UpdatePaymentMethod( @@ -393,6 +396,16 @@ private static bool IsSubscriptionUnpaid(Subscription subscription) return subscription.Status == "unpaid"; } + private static bool IsSubscriptionCanceled(Subscription subscription) + { + if (subscription == null) + { + return false; + } + + return subscription.Status == "canceled"; + } + #endregion }