5 changed files with 155 additions and 8 deletions
@ -0,0 +1,33 @@ |
|||||||
|
using Bit.Billing.Constants; |
||||||
|
using Microsoft.AspNetCore.Mvc; |
||||||
|
using Stripe; |
||||||
|
|
||||||
|
namespace Bit.Billing.Services.Implementations; |
||||||
|
|
||||||
|
public class InvoiceCreatedHandler : StripeWebhookHandler |
||||||
|
{ |
||||||
|
private readonly IStripeEventService _stripeEventService; |
||||||
|
private readonly IWebhookUtility _webhookUtility; |
||||||
|
|
||||||
|
public InvoiceCreatedHandler(IStripeEventService stripeEventService, |
||||||
|
IWebhookUtility webhookUtility) |
||||||
|
{ |
||||||
|
_stripeEventService = stripeEventService; |
||||||
|
_webhookUtility = webhookUtility; |
||||||
|
} |
||||||
|
protected override bool CanHandle(Event parsedEvent) |
||||||
|
{ |
||||||
|
return parsedEvent.Type.Equals(HandledStripeWebhook.InvoiceCreated); |
||||||
|
} |
||||||
|
|
||||||
|
protected override async Task<IActionResult> ProcessEvent(Event parsedEvent) |
||||||
|
{ |
||||||
|
var invoice = await _stripeEventService.GetInvoice(parsedEvent, true); |
||||||
|
if (!invoice.Paid && _webhookUtility.UnpaidAutoChargeInvoiceForSubscriptionCycle(invoice)) |
||||||
|
{ |
||||||
|
await _webhookUtility.AttemptToPayInvoice(invoice); |
||||||
|
} |
||||||
|
|
||||||
|
return new OkResult(); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,105 @@ |
|||||||
|
using Bit.Billing.Constants; |
||||||
|
using Microsoft.AspNetCore.Mvc; |
||||||
|
using Stripe; |
||||||
|
|
||||||
|
namespace Bit.Billing.Services.Implementations; |
||||||
|
|
||||||
|
public class PaymentMethodAttachedHandler : StripeWebhookHandler |
||||||
|
{ |
||||||
|
private readonly IStripeEventService _stripeEventService; |
||||||
|
private readonly IWebhookUtility _webhookUtility; |
||||||
|
private readonly ILogger<PaymentMethodAttachedHandler> _logger; |
||||||
|
|
||||||
|
public PaymentMethodAttachedHandler(IStripeEventService stripeEventService, |
||||||
|
IWebhookUtility webhookUtility, |
||||||
|
ILogger<PaymentMethodAttachedHandler> logger) |
||||||
|
{ |
||||||
|
_stripeEventService = stripeEventService; |
||||||
|
_webhookUtility = webhookUtility; |
||||||
|
_logger = logger; |
||||||
|
} |
||||||
|
|
||||||
|
protected override bool CanHandle(Event parsedEvent) |
||||||
|
{ |
||||||
|
return parsedEvent.Type.Equals(HandledStripeWebhook.InvoiceCreated); |
||||||
|
} |
||||||
|
|
||||||
|
protected override async Task<IActionResult> ProcessEvent(Event parsedEvent) |
||||||
|
{ |
||||||
|
var paymentMethod = await _stripeEventService.GetPaymentMethod(parsedEvent); |
||||||
|
await HandlePaymentMethodAttachedAsync(paymentMethod); |
||||||
|
return new OkResult(); |
||||||
|
} |
||||||
|
|
||||||
|
private async Task HandlePaymentMethodAttachedAsync(PaymentMethod paymentMethod) |
||||||
|
{ |
||||||
|
if (paymentMethod is null) |
||||||
|
{ |
||||||
|
_logger.LogWarning("Attempted to handle the event payment_method.attached but paymentMethod was null"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var subscriptionService = new SubscriptionService(); |
||||||
|
var subscriptionListOptions = new SubscriptionListOptions |
||||||
|
{ |
||||||
|
Customer = paymentMethod.CustomerId, |
||||||
|
Status = StripeSubscriptionStatus.Unpaid, |
||||||
|
Expand = new List<string> { "data.latest_invoice" } |
||||||
|
}; |
||||||
|
|
||||||
|
StripeList<Subscription> unpaidSubscriptions; |
||||||
|
try |
||||||
|
{ |
||||||
|
unpaidSubscriptions = await subscriptionService.ListAsync(subscriptionListOptions); |
||||||
|
} |
||||||
|
catch (Exception e) |
||||||
|
{ |
||||||
|
_logger.LogError(e, |
||||||
|
"Attempted to get unpaid invoices for customer {CustomerId} but encountered an error while calling Stripe", |
||||||
|
paymentMethod.CustomerId); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
foreach (var unpaidSubscription in unpaidSubscriptions) |
||||||
|
{ |
||||||
|
await AttemptToPayOpenSubscriptionAsync(unpaidSubscription); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private async Task AttemptToPayOpenSubscriptionAsync(Subscription unpaidSubscription) |
||||||
|
{ |
||||||
|
var latestInvoice = unpaidSubscription.LatestInvoice; |
||||||
|
|
||||||
|
if (unpaidSubscription.LatestInvoice is null) |
||||||
|
{ |
||||||
|
_logger.LogWarning( |
||||||
|
"Attempted to pay unpaid subscription {SubscriptionId} but latest invoice didn't exist", |
||||||
|
unpaidSubscription.Id); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (latestInvoice.Status != StripeInvoiceStatus.Open) |
||||||
|
{ |
||||||
|
_logger.LogWarning( |
||||||
|
"Attempted to pay unpaid subscription {SubscriptionId} but latest invoice wasn't \"open\"", |
||||||
|
unpaidSubscription.Id); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
await _webhookUtility.AttemptToPayInvoice(latestInvoice, true); |
||||||
|
} |
||||||
|
catch (Exception e) |
||||||
|
{ |
||||||
|
_logger.LogError(e, |
||||||
|
"Attempted to pay open invoice {InvoiceId} on unpaid subscription {SubscriptionId} but encountered an error", |
||||||
|
latestInvoice.Id, unpaidSubscription.Id); |
||||||
|
throw; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue