2024-06-03 11:00:52 -04:00
|
|
|
|
using Bit.Api.Billing.Models.Requests;
|
|
|
|
|
|
using Bit.Api.Billing.Models.Responses;
|
|
|
|
|
|
using Bit.Core.AdminConsole.Repositories;
|
|
|
|
|
|
using Bit.Core.Billing.Constants;
|
|
|
|
|
|
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,
|
2024-06-24 11:15:47 -04:00
|
|
|
|
ISubscriberService subscriberService) : BaseProviderController(currentContext, featureService, providerRepository)
|
2024-03-28 08:46:12 -04:00
|
|
|
|
{
|
2024-06-05 13:33:28 -04:00
|
|
|
|
[HttpGet("invoices")]
|
|
|
|
|
|
public async Task<IResult> GetInvoicesAsync([FromRoute] Guid providerId)
|
|
|
|
|
|
{
|
2024-06-24 11:15:47 -04:00
|
|
|
|
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
2024-06-05 13:33:28 -04:00
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var invoices = await subscriberService.GetInvoices(provider);
|
|
|
|
|
|
|
|
|
|
|
|
var response = InvoicesResponse.From(invoices);
|
|
|
|
|
|
|
|
|
|
|
|
return TypedResults.Ok(response);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-14 12:26:49 -04:00
|
|
|
|
[HttpGet("invoices/{invoiceId}")]
|
|
|
|
|
|
public async Task<IResult> GenerateClientInvoiceReportAsync([FromRoute] Guid providerId, string invoiceId)
|
|
|
|
|
|
{
|
2024-06-24 11:15:47 -04:00
|
|
|
|
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
2024-06-14 12:26:49 -04:00
|
|
|
|
|
|
|
|
|
|
if (provider == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var reportContent = await providerBillingService.GenerateClientInvoiceReport(invoiceId);
|
|
|
|
|
|
|
|
|
|
|
|
if (reportContent == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return TypedResults.NotFound();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return TypedResults.File(
|
|
|
|
|
|
reportContent,
|
|
|
|
|
|
"text/csv");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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-24 11:15:47 -04:00
|
|
|
|
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
2024-06-03 11:00:52 -04:00
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
2024-06-24 11:15:47 -04:00
|
|
|
|
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
2024-06-03 11:00:52 -04:00
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
2024-06-24 11:15:47 -04:00
|
|
|
|
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
2024-06-03 11:00:52 -04:00
|
|
|
|
|
|
|
|
|
|
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-24 11:15:47 -04:00
|
|
|
|
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
2024-06-03 11:00:52 -04:00
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
2024-06-24 11:15:47 -04:00
|
|
|
|
var (provider, result) = await TryGetBillableProviderForServiceUserOperation(providerId);
|
2024-06-03 11:00:52 -04:00
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
2024-06-24 11:15:47 -04:00
|
|
|
|
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
2024-06-03 11:00:52 -04:00
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
2024-06-24 11:15:47 -04:00
|
|
|
|
var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
|
2024-06-03 11:00:52 -04:00
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
}
|
2024-03-28 08:46:12 -04:00
|
|
|
|
}
|