1
0
mirror of https://github.com/bitwarden/server.git synced 2025-05-20 11:04:31 -05:00

[AC-2386][AC-2750] Updated BitPay controller to add transactions and account credit for providers (#4153)

This commit is contained in:
Conner Turnbull 2024-06-04 14:58:21 -04:00 committed by GitHub
parent cae417e2a2
commit 4a6113dc86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,5 +1,6 @@
using System.Globalization; using System.Globalization;
using Bit.Billing.Models; using Bit.Billing.Models;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Repositories; using Bit.Core.Repositories;
@ -19,6 +20,7 @@ public class BitPayController : Controller
private readonly ITransactionRepository _transactionRepository; private readonly ITransactionRepository _transactionRepository;
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly IProviderRepository _providerRepository;
private readonly IMailService _mailService; private readonly IMailService _mailService;
private readonly IPaymentService _paymentService; private readonly IPaymentService _paymentService;
private readonly ILogger<BitPayController> _logger; private readonly ILogger<BitPayController> _logger;
@ -29,6 +31,7 @@ public class BitPayController : Controller
ITransactionRepository transactionRepository, ITransactionRepository transactionRepository,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IUserRepository userRepository, IUserRepository userRepository,
IProviderRepository providerRepository,
IMailService mailService, IMailService mailService,
IPaymentService paymentService, IPaymentService paymentService,
ILogger<BitPayController> logger) ILogger<BitPayController> logger)
@ -38,6 +41,7 @@ public class BitPayController : Controller
_transactionRepository = transactionRepository; _transactionRepository = transactionRepository;
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
_userRepository = userRepository; _userRepository = userRepository;
_providerRepository = providerRepository;
_mailService = mailService; _mailService = mailService;
_paymentService = paymentService; _paymentService = paymentService;
_logger = logger; _logger = logger;
@ -83,8 +87,8 @@ public class BitPayController : Controller
return new OkResult(); return new OkResult();
} }
var ids = GetIdsFromPosData(invoice); var (organizationId, userId, providerId) = GetIdsFromPosData(invoice);
if (!ids.Item1.HasValue && !ids.Item2.HasValue) if (!organizationId.HasValue && !userId.HasValue && !providerId.HasValue)
{ {
return new OkResult(); return new OkResult();
} }
@ -93,14 +97,14 @@ public class BitPayController : Controller
if (!isAccountCredit) if (!isAccountCredit)
{ {
// Only processing credits // Only processing credits
_logger.LogWarning("Non-credit payment received. #" + invoice.Id); _logger.LogWarning("Non-credit payment received. #{InvoiceId}", invoice.Id);
return new OkResult(); return new OkResult();
} }
var transaction = await _transactionRepository.GetByGatewayIdAsync(GatewayType.BitPay, invoice.Id); var transaction = await _transactionRepository.GetByGatewayIdAsync(GatewayType.BitPay, invoice.Id);
if (transaction != null) if (transaction != null)
{ {
_logger.LogWarning("Already processed this invoice. #" + invoice.Id); _logger.LogWarning("Already processed this invoice. #{InvoiceId}", invoice.Id);
return new OkResult(); return new OkResult();
} }
@ -110,8 +114,9 @@ public class BitPayController : Controller
{ {
Amount = Convert.ToDecimal(invoice.Price), Amount = Convert.ToDecimal(invoice.Price),
CreationDate = GetTransactionDate(invoice), CreationDate = GetTransactionDate(invoice),
OrganizationId = ids.Item1, OrganizationId = organizationId,
UserId = ids.Item2, UserId = userId,
ProviderId = providerId,
Type = TransactionType.Credit, Type = TransactionType.Credit,
Gateway = GatewayType.BitPay, Gateway = GatewayType.BitPay,
GatewayId = invoice.Id, GatewayId = invoice.Id,
@ -120,42 +125,57 @@ public class BitPayController : Controller
}; };
await _transactionRepository.CreateAsync(tx); await _transactionRepository.CreateAsync(tx);
if (isAccountCredit) string billingEmail = null;
if (tx.OrganizationId.HasValue)
{ {
string billingEmail = null; var org = await _organizationRepository.GetByIdAsync(tx.OrganizationId.Value);
if (tx.OrganizationId.HasValue) if (org != null)
{ {
var org = await _organizationRepository.GetByIdAsync(tx.OrganizationId.Value); billingEmail = org.BillingEmailAddress();
if (org != null) if (await _paymentService.CreditAccountAsync(org, tx.Amount))
{ {
billingEmail = org.BillingEmailAddress(); await _organizationRepository.ReplaceAsync(org);
if (await _paymentService.CreditAccountAsync(org, tx.Amount))
{
await _organizationRepository.ReplaceAsync(org);
}
} }
} }
else }
else if (tx.UserId.HasValue)
{
var user = await _userRepository.GetByIdAsync(tx.UserId.Value);
if (user != null)
{ {
var user = await _userRepository.GetByIdAsync(tx.UserId.Value); billingEmail = user.BillingEmailAddress();
if (user != null) if (await _paymentService.CreditAccountAsync(user, tx.Amount))
{ {
billingEmail = user.BillingEmailAddress(); await _userRepository.ReplaceAsync(user);
if (await _paymentService.CreditAccountAsync(user, tx.Amount))
{
await _userRepository.ReplaceAsync(user);
}
} }
} }
}
else if (tx.ProviderId.HasValue)
{
var provider = await _providerRepository.GetByIdAsync(tx.ProviderId.Value);
if (provider != null)
{
billingEmail = provider.BillingEmailAddress();
if (await _paymentService.CreditAccountAsync(provider, tx.Amount))
{
await _providerRepository.ReplaceAsync(provider);
}
}
}
else
{
_logger.LogError("Received BitPay account credit transaction that didn't have a user, org, or provider. Invoice#{InvoiceId}", invoice.Id);
}
if (!string.IsNullOrWhiteSpace(billingEmail)) if (!string.IsNullOrWhiteSpace(billingEmail))
{ {
await _mailService.SendAddedCreditAsync(billingEmail, tx.Amount); await _mailService.SendAddedCreditAsync(billingEmail, tx.Amount);
}
} }
} }
// Catch foreign key violations because user/org could have been deleted. // Catch foreign key violations because user/org could have been deleted.
catch (SqlException e) when (e.Number == 547) { } catch (SqlException e) when (e.Number == 547)
{
}
return new OkResult(); return new OkResult();
} }
@ -177,31 +197,41 @@ public class BitPayController : Controller
return CoreHelpers.FromEpocMilliseconds(invoice.CurrentTime); return CoreHelpers.FromEpocMilliseconds(invoice.CurrentTime);
} }
public Tuple<Guid?, Guid?> GetIdsFromPosData(BitPayLight.Models.Invoice.Invoice invoice) public Tuple<Guid?, Guid?, Guid?> GetIdsFromPosData(BitPayLight.Models.Invoice.Invoice invoice)
{ {
Guid? orgId = null; Guid? orgId = null;
Guid? userId = null; Guid? userId = null;
Guid? providerId = null;
if (invoice != null && !string.IsNullOrWhiteSpace(invoice.PosData) && invoice.PosData.Contains(":")) if (invoice == null || string.IsNullOrWhiteSpace(invoice.PosData) || !invoice.PosData.Contains(':'))
{ {
var mainParts = invoice.PosData.Split(','); return new Tuple<Guid?, Guid?, Guid?>(null, null, null);
foreach (var mainPart in mainParts) }
var mainParts = invoice.PosData.Split(',');
foreach (var mainPart in mainParts)
{
var parts = mainPart.Split(':');
if (parts.Length <= 1 || !Guid.TryParse(parts[1], out var id))
{ {
var parts = mainPart.Split(':'); continue;
if (parts.Length > 1 && Guid.TryParse(parts[1], out var id)) }
{
if (parts[0] == "userId") switch (parts[0])
{ {
userId = id; case "userId":
} userId = id;
else if (parts[0] == "organizationId") break;
{ case "organizationId":
orgId = id; orgId = id;
} break;
} case "providerId":
providerId = id;
break;
} }
} }
return new Tuple<Guid?, Guid?>(orgId, userId); return new Tuple<Guid?, Guid?, Guid?>(orgId, userId, providerId);
} }
} }