@ -1,36 +1,133 @@
@@ -1,36 +1,133 @@
using Bit.Billing.Constants ;
using Bit.Billing.Services ;
using Bit.Core.AdminConsole.Entities ;
using Bit.Billing.Services ;
using Bit.Billing.Services.Implementations ;
using Bit.Core.Context ;
using Bit.Core.Enums ;
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces ;
using Bit.Core.Repositories ;
using Bit.Core.Services ;
using Bit.Core.Settings ;
using Bit.Core.Tools.Enums ;
using Bit.Core.Tools.Models.Business ;
using Bit.Core.Tools.Services ;
using Bit.Core.Utilities ;
using Braintree ;
using Braintree.Exceptions ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.Data.SqlClient ;
using Microsoft.Extensions.Options ;
using Stripe ;
using Customer = Stripe . Customer ;
using Event = Stripe . Event ;
using PaymentMethod = Stripe . PaymentMethod ;
using Subscription = Stripe . Subscription ;
using TaxRate = Bit . Core . Entities . TaxRate ;
using Transaction = Bit . Core . Entities . Transaction ;
using TransactionType = Bit . Core . Enums . TransactionType ;
namespace Bit.Billing.Controllers ;
[Route("stripe")]
public class StripeController : Controller
{
private const decimal PremiumPlanAppleIapPrice = 1 4.99 M ;
private readonly BillingSettings _ billingSettings ;
private readonly IWebHostEnvironment _ hostingEnvironment ;
private readonly IOrganizationService _ organizationService ;
private readonly IValidateSponsorshipCommand _ validateSponsorshipCommand ;
private readonly IOrganizationSponsorshipRenewCommand _ organizationSponsorshipRenewCommand ;
private readonly IOrganizationRepository _ organizationRepository ;
private readonly ITransactionRepository _ transactionRepository ;
private readonly IUserService _ userService ;
private readonly IAppleIapService _ appleIapService ;
private readonly IMailService _ mailService ;
private readonly ILogger < StripeController > _l ogger ;
private readonly BraintreeGateway _ btGateway ;
private readonly IReferenceEventService _ referenceEventService ;
private readonly ITaxRateRepository _ taxRateRepository ;
private readonly IUserRepository _ userRepository ;
private readonly ICurrentContext _ currentContext ;
private readonly GlobalSettings _ globalSettings ;
private readonly IStripeEventService _ stripeEventService ;
private readonly IStripeFacade _ stripeFacade ;
private readonly StripeWebhookHandler _ webhookHandler ;
public StripeController (
GlobalSettings globalSettings ,
IOptions < BillingSettings > billingSettings ,
IWebHostEnvironment hostingEnvironment ,
IOrganizationService organizationService ,
IValidateSponsorshipCommand validateSponsorshipCommand ,
IOrganizationSponsorshipRenewCommand organizationSponsorshipRenewCommand ,
IOrganizationRepository organizationRepository ,
ITransactionRepository transactionRepository ,
IUserService userService ,
IAppleIapService appleIapService ,
IMailService mailService ,
IReferenceEventService referenceEventService ,
ILogger < StripeController > logger ,
ITaxRateRepository taxRateRepository ,
IUserRepository userRepository ,
ICurrentContext currentContext ,
IStripeEventService stripeEventService ,
IStripeFacade stripeFacade ,
StripeWebhookHandler webhookHandler )
{
_ billingSettings = billingSettings ? . Value ;
_ hostingEnvironment = hostingEnvironment ;
_ organizationService = organizationService ;
_ validateSponsorshipCommand = validateSponsorshipCommand ;
_ organizationSponsorshipRenewCommand = organizationSponsorshipRenewCommand ;
_ organizationRepository = organizationRepository ;
_ transactionRepository = transactionRepository ;
_ userService = userService ;
_ appleIapService = appleIapService ;
_ mailService = mailService ;
_ referenceEventService = referenceEventService ;
_ taxRateRepository = taxRateRepository ;
_ userRepository = userRepository ;
_l ogger = logger ;
_ btGateway = new BraintreeGateway
{
Environment = globalSettings . Braintree . Production ?
Braintree . Environment . PRODUCTION : Braintree . Environment . SANDBOX ,
MerchantId = globalSettings . Braintree . MerchantId ,
PublicKey = globalSettings . Braintree . PublicKey ,
PrivateKey = globalSettings . Braintree . PrivateKey
} ;
_ currentContext = currentContext ;
_ globalSettings = globalSettings ;
_ stripeEventService = stripeEventService ;
_ stripeFacade = stripeFacade ;
_ webhookHandler = webhookHandler ;
// Set up the chain of responsibility
var subscriptionDeletedHandler = new SubscriptionDeletedHandler ( _ organizationService , _ userService , _ stripeEventService ) ;
var subscriptionUpdatedHandler = new SubscriptionUpdatedHandler ( _ organizationService , _ userService ,
_ stripeEventService , _ organizationSponsorshipRenewCommand ) ;
var upcomingInvoiceHandler = new UpcomingInvoiceHandler ( _ organizationRepository , _ userService ,
_ stripeEventService , _ stripeFacade , _l ogger , _ taxRateRepository , _ validateSponsorshipCommand , _ mailService ) ;
var chargeSucceededHandler = new ChargeSucceededHandler ( _ transactionRepository , _l ogger , _ stripeEventService ) ;
subscriptionDeletedHandler . SetNextHandler ( subscriptionUpdatedHandler ) ;
subscriptionUpdatedHandler . SetNextHandler ( upcomingInvoiceHandler ) ;
upcomingInvoiceHandler . SetNextHandler ( chargeSucceededHandler ) ;
_ webhookHandler = subscriptionDeletedHandler ;
}
[HttpPost("webhook")]
public async Task < IActionResult > PostWebhook ( [ FromQuery ] string key )
{
// Parse the event and pass it to the handler chain
Event parsedEvent ;
using ( var sr = new StreamReader ( HttpContext . Request . Body ) )
{
var json = await sr . ReadToEndAsync ( ) ;
parsedEvent = EventUtility . ConstructEvent ( json , Request . Headers [ "Stripe-Signature" ] ,
_ billingSettings . StripeWebhookSecret ,
throwOnApiVersionMismatch : _ billingSettings . StripeEventParseThrowMismatch ) ;
}
if ( string . IsNullOrWhiteSpace ( parsedEvent ? . Id ) )
{
_l ogger . LogWarning ( "No event id." ) ;
return new BadRequestResult ( ) ;
}
// Pass the event to the handler chain
await _ webhookHandler . HandleRequest ( parsedEvent ) ;
return new OkResult ( ) ;
}
/ * private const decimal PremiumPlanAppleIapPrice = 1 4.99 M ;
private const string PremiumPlanId = "premium-annually" ;
private const string PremiumPlanIdAppStore = "premium-annually-app" ;
@ -269,7 +366,7 @@ public class StripeController : Controller
@@ -269,7 +366,7 @@ public class StripeController : Controller
* Disabling this as part of a hot fix . It needs to check whether the organization
* belongs to a Reseller provider and only send an email to the organization owners if it does .
* It also requires a new email template as the current one contains too much billing information .
* /
# 1 #
// var ownerEmails = await _organizationRepository.GetOwnerEmailAddressesById(organization.Id);
@ -991,5 +1088,5 @@ public class StripeController : Controller
@@ -991,5 +1088,5 @@ public class StripeController : Controller
{
await invoiceService . VoidInvoiceAsync ( invoice . Id ) ;
}
}
} * /
}