1
0
mirror of https://github.com/bitwarden/server synced 2025-12-24 04:03:25 +00:00
Files
server/src/Billing/Services/Implementations/ChargeSucceededHandler.cs
Alex Morask 04efe402be [PM-28128] Create transaction for bank transfer charges (#6691)
* Create transaction for charges that were the result of a bank transfer

* Claude feedback

* Run dotnet format
2025-12-16 10:12:56 -06:00

68 lines
2.5 KiB
C#

using Bit.Billing.Constants;
using Bit.Core.Enums;
using Bit.Core.Repositories;
using Microsoft.Data.SqlClient;
using Event = Stripe.Event;
namespace Bit.Billing.Services.Implementations;
public class ChargeSucceededHandler : IChargeSucceededHandler
{
private readonly ILogger<ChargeSucceededHandler> _logger;
private readonly IStripeEventService _stripeEventService;
private readonly ITransactionRepository _transactionRepository;
private readonly IStripeEventUtilityService _stripeEventUtilityService;
public ChargeSucceededHandler(
ILogger<ChargeSucceededHandler> logger,
IStripeEventService stripeEventService,
ITransactionRepository transactionRepository,
IStripeEventUtilityService stripeEventUtilityService)
{
_logger = logger;
_stripeEventService = stripeEventService;
_transactionRepository = transactionRepository;
_stripeEventUtilityService = stripeEventUtilityService;
}
/// <summary>
/// Handles the <see cref="HandledStripeWebhook.ChargeSucceeded"/> event type from Stripe.
/// </summary>
/// <param name="parsedEvent"></param>
public async Task HandleAsync(Event parsedEvent)
{
var charge = await _stripeEventService.GetCharge(parsedEvent);
var existingTransaction = await _transactionRepository.GetByGatewayIdAsync(GatewayType.Stripe, charge.Id);
if (existingTransaction is not null)
{
_logger.LogInformation("Charge success already processed. {ChargeId}", charge.Id);
return;
}
var (organizationId, userId, providerId) = await _stripeEventUtilityService.GetEntityIdsFromChargeAsync(charge);
if (!organizationId.HasValue && !userId.HasValue && !providerId.HasValue)
{
_logger.LogWarning("Charge success has no subscriber ids. {ChargeId}", charge.Id);
return;
}
var transaction = await _stripeEventUtilityService.FromChargeToTransactionAsync(charge, organizationId, userId, providerId);
if (!transaction.PaymentMethodType.HasValue)
{
_logger.LogWarning("Charge success from unsupported source/method. {ChargeId}", charge.Id);
return;
}
try
{
await _transactionRepository.CreateAsync(transaction);
}
catch (SqlException e) when (e.Number == 547)
{
_logger.LogWarning(
"Charge success could not create transaction as entity may have been deleted. {ChargeId}",
charge.Id);
}
}
}