2024-06-03 11:00:52 -04:00
|
|
|
|
using Bit.Api.Billing.Models.Requests;
|
|
|
|
|
|
using Bit.Api.Billing.Models.Responses;
|
2024-03-28 08:46:12 -04:00
|
|
|
|
using Bit.Core;
|
2024-06-03 11:00:52 -04:00
|
|
|
|
using Bit.Core.AdminConsole.Entities.Provider;
|
|
|
|
|
|
using Bit.Core.AdminConsole.Repositories;
|
|
|
|
|
|
using Bit.Core.Billing.Constants;
|
|
|
|
|
|
using Bit.Core.Billing.Extensions;
|
|
|
|
|
|
using Bit.Core.Billing.Models;
|
2024-05-23 10:17:00 -04:00
|
|
|
|
using Bit.Core.Billing.Services;
|
2024-03-28 08:46:12 -04:00
|
|
|
|
using Bit.Core.Context;
|
|
|
|
|
|
using Bit.Core.Services;
|
|
|
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
2024-06-03 11:00:52 -04:00
|
|
|
|
using Stripe;
|
2024-03-28 08:46:12 -04:00
|
|
|
|
|
|
|
|
|
|
namespace Bit.Api.Billing.Controllers;
|
|
|
|
|
|
|
|
|
|
|
|
[Route("providers/{providerId:guid}/billing")]
|
|
|
|
|
|
[Authorize("Application")]
|
|
|
|
|
|
public class ProviderBillingController(
|
|
|
|
|
|
ICurrentContext currentContext,
|
|
|
|
|
|
IFeatureService featureService,
|
2024-06-03 11:00:52 -04:00
|
|
|
|
IProviderBillingService providerBillingService,
|
|
|
|
|
|
IProviderRepository providerRepository,
|
|
|
|
|
|
IStripeAdapter stripeAdapter,
|
|
|
|
|
|
ISubscriberService subscriberService) : Controller
|
2024-03-28 08:46:12 -04:00
|
|
|
|
{
|
2024-06-03 11:00:52 -04:00
|
|
|
|
[HttpGet("payment-information")]
|
|
|
|
|
|
public async Task<IResult> GetPaymentInformationAsync([FromRoute] Guid providerId)
|
2024-03-28 08:46:12 -04:00
|
|
|
|
{
|
2024-06-03 11:00:52 -04:00
|
|
|
|
var (provider, result) = await GetAuthorizedBillableProviderOrResultAsync(providerId);
|
|
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var paymentInformation = await subscriberService.GetPaymentInformation(provider);
|
|
|
|
|
|
|
|
|
|
|
|
if (paymentInformation == null)
|
2024-03-28 08:46:12 -04:00
|
|
|
|
{
|
|
|
|
|
|
return TypedResults.NotFound();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
var response = PaymentInformationResponse.From(paymentInformation);
|
|
|
|
|
|
|
|
|
|
|
|
return TypedResults.Ok(response);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpGet("payment-method")]
|
|
|
|
|
|
public async Task<IResult> GetPaymentMethodAsync([FromRoute] Guid providerId)
|
|
|
|
|
|
{
|
|
|
|
|
|
var (provider, result) = await GetAuthorizedBillableProviderOrResultAsync(providerId);
|
|
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
2024-03-28 08:46:12 -04:00
|
|
|
|
{
|
2024-06-03 11:00:52 -04:00
|
|
|
|
return result;
|
2024-03-28 08:46:12 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
var maskedPaymentMethod = await subscriberService.GetPaymentMethod(provider);
|
2024-03-28 08:46:12 -04:00
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
if (maskedPaymentMethod == null)
|
2024-03-28 08:46:12 -04:00
|
|
|
|
{
|
|
|
|
|
|
return TypedResults.NotFound();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
var response = MaskedPaymentMethodResponse.From(maskedPaymentMethod);
|
|
|
|
|
|
|
|
|
|
|
|
return TypedResults.Ok(response);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpPut("payment-method")]
|
|
|
|
|
|
public async Task<IResult> UpdatePaymentMethodAsync(
|
|
|
|
|
|
[FromRoute] Guid providerId,
|
|
|
|
|
|
[FromBody] TokenizedPaymentMethodRequestBody requestBody)
|
|
|
|
|
|
{
|
|
|
|
|
|
var (provider, result) = await GetAuthorizedBillableProviderOrResultAsync(providerId);
|
|
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var tokenizedPaymentMethod = new TokenizedPaymentMethodDTO(
|
|
|
|
|
|
requestBody.Type,
|
|
|
|
|
|
requestBody.Token);
|
2024-03-28 08:46:12 -04:00
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
await subscriberService.UpdatePaymentMethod(provider, tokenizedPaymentMethod);
|
2024-03-28 08:46:12 -04:00
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
await stripeAdapter.SubscriptionUpdateAsync(provider.GatewaySubscriptionId,
|
|
|
|
|
|
new SubscriptionUpdateOptions
|
|
|
|
|
|
{
|
|
|
|
|
|
CollectionMethod = StripeConstants.CollectionMethod.ChargeAutomatically
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return TypedResults.Ok();
|
2024-03-28 08:46:12 -04:00
|
|
|
|
}
|
2024-05-23 10:17:00 -04:00
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
[HttpPost]
|
|
|
|
|
|
[Route("payment-method/verify-bank-account")]
|
|
|
|
|
|
public async Task<IResult> VerifyBankAccountAsync(
|
|
|
|
|
|
[FromRoute] Guid providerId,
|
|
|
|
|
|
[FromBody] VerifyBankAccountRequestBody requestBody)
|
2024-05-23 10:17:00 -04:00
|
|
|
|
{
|
2024-06-03 11:00:52 -04:00
|
|
|
|
var (provider, result) = await GetAuthorizedBillableProviderOrResultAsync(providerId);
|
|
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await subscriberService.VerifyBankAccount(provider, (requestBody.Amount1, requestBody.Amount2));
|
|
|
|
|
|
|
|
|
|
|
|
return TypedResults.Ok();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpGet("subscription")]
|
|
|
|
|
|
public async Task<IResult> GetSubscriptionAsync([FromRoute] Guid providerId)
|
|
|
|
|
|
{
|
|
|
|
|
|
var (provider, result) = await GetAuthorizedBillableProviderOrResultAsync(providerId);
|
|
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var consolidatedBillingSubscription = await providerBillingService.GetConsolidatedBillingSubscription(provider);
|
|
|
|
|
|
|
|
|
|
|
|
if (consolidatedBillingSubscription == null)
|
2024-05-23 10:17:00 -04:00
|
|
|
|
{
|
|
|
|
|
|
return TypedResults.NotFound();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
var response = ConsolidatedBillingSubscriptionResponse.From(consolidatedBillingSubscription);
|
|
|
|
|
|
|
|
|
|
|
|
return TypedResults.Ok(response);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpGet("tax-information")]
|
|
|
|
|
|
public async Task<IResult> GetTaxInformationAsync([FromRoute] Guid providerId)
|
|
|
|
|
|
{
|
|
|
|
|
|
var (provider, result) = await GetAuthorizedBillableProviderOrResultAsync(providerId);
|
|
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
2024-05-23 10:17:00 -04:00
|
|
|
|
{
|
2024-06-03 11:00:52 -04:00
|
|
|
|
return result;
|
2024-05-23 10:17:00 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
var taxInformation = await subscriberService.GetTaxInformation(provider);
|
2024-05-23 10:17:00 -04:00
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
if (taxInformation == null)
|
2024-05-23 10:17:00 -04:00
|
|
|
|
{
|
|
|
|
|
|
return TypedResults.NotFound();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
var response = TaxInformationResponse.From(taxInformation);
|
|
|
|
|
|
|
|
|
|
|
|
return TypedResults.Ok(response);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpPut("tax-information")]
|
|
|
|
|
|
public async Task<IResult> UpdateTaxInformationAsync(
|
|
|
|
|
|
[FromRoute] Guid providerId,
|
|
|
|
|
|
[FromBody] TaxInformationRequestBody requestBody)
|
|
|
|
|
|
{
|
|
|
|
|
|
var (provider, result) = await GetAuthorizedBillableProviderOrResultAsync(providerId);
|
|
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var taxInformation = new TaxInformationDTO(
|
|
|
|
|
|
requestBody.Country,
|
|
|
|
|
|
requestBody.PostalCode,
|
|
|
|
|
|
requestBody.TaxId,
|
|
|
|
|
|
requestBody.Line1,
|
|
|
|
|
|
requestBody.Line2,
|
|
|
|
|
|
requestBody.City,
|
|
|
|
|
|
requestBody.State);
|
2024-05-23 10:17:00 -04:00
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
await subscriberService.UpdateTaxInformation(provider, taxInformation);
|
|
|
|
|
|
|
|
|
|
|
|
return TypedResults.Ok();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task<(Provider, IResult)> GetAuthorizedBillableProviderOrResultAsync(Guid providerId)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!featureService.IsEnabled(FeatureFlagKeys.EnableConsolidatedBilling))
|
|
|
|
|
|
{
|
|
|
|
|
|
return (null, TypedResults.NotFound());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var provider = await providerRepository.GetByIdAsync(providerId);
|
|
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (null, TypedResults.NotFound());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!currentContext.ProviderProviderAdmin(providerId))
|
|
|
|
|
|
{
|
|
|
|
|
|
return (null, TypedResults.Unauthorized());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!provider.IsBillable())
|
|
|
|
|
|
{
|
|
|
|
|
|
return (null, TypedResults.Unauthorized());
|
|
|
|
|
|
}
|
2024-05-23 10:17:00 -04:00
|
|
|
|
|
2024-06-03 11:00:52 -04:00
|
|
|
|
return (provider, null);
|
2024-05-23 10:17:00 -04:00
|
|
|
|
}
|
2024-03-28 08:46:12 -04:00
|
|
|
|
}
|