2020-06-28 21:44:35 -05:00
|
|
|
using System;
|
2019-01-14 22:43:29 +01:00
|
|
|
using System.Linq;
|
|
|
|
using System.Threading.Tasks;
|
2020-07-24 09:40:37 +02:00
|
|
|
using BTCPayServer.Client.Models;
|
2019-08-30 00:24:42 +09:00
|
|
|
using BTCPayServer.Data;
|
2019-01-14 22:43:29 +01:00
|
|
|
using BTCPayServer.Models.PaymentRequestViewModels;
|
2019-05-29 14:33:31 +00:00
|
|
|
using BTCPayServer.Payments;
|
2023-03-13 02:12:58 +01:00
|
|
|
using BTCPayServer.Services;
|
2019-01-14 22:43:29 +01:00
|
|
|
using BTCPayServer.Services.Apps;
|
|
|
|
using BTCPayServer.Services.Invoices;
|
|
|
|
using BTCPayServer.Services.PaymentRequests;
|
|
|
|
using BTCPayServer.Services.Rates;
|
2020-07-24 09:40:37 +02:00
|
|
|
using PaymentRequestData = BTCPayServer.Data.PaymentRequestData;
|
2019-01-14 22:43:29 +01:00
|
|
|
|
|
|
|
namespace BTCPayServer.PaymentRequest
|
|
|
|
{
|
|
|
|
public class PaymentRequestService
|
|
|
|
{
|
2023-12-01 10:50:05 +01:00
|
|
|
private readonly PaymentRequestRepository _paymentRequestRepository;
|
|
|
|
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
2023-03-17 03:56:32 +01:00
|
|
|
private readonly InvoiceRepository _invoiceRepository;
|
2019-01-14 22:43:29 +01:00
|
|
|
private readonly CurrencyNameTable _currencies;
|
2024-04-04 16:31:04 +09:00
|
|
|
private readonly PaymentMethodHandlerDictionary _handlers;
|
2023-11-29 18:51:40 +09:00
|
|
|
private readonly TransactionLinkProviders _transactionLinkProviders;
|
2023-03-13 02:12:58 +01:00
|
|
|
private readonly DisplayFormatter _displayFormatter;
|
2019-01-14 22:43:29 +01:00
|
|
|
|
2019-02-22 11:37:45 +01:00
|
|
|
public PaymentRequestService(
|
2019-01-14 22:43:29 +01:00
|
|
|
PaymentRequestRepository paymentRequestRepository,
|
|
|
|
BTCPayNetworkProvider btcPayNetworkProvider,
|
2023-03-17 03:56:32 +01:00
|
|
|
InvoiceRepository invoiceRepository,
|
2023-03-13 02:12:58 +01:00
|
|
|
DisplayFormatter displayFormatter,
|
2023-11-29 18:51:40 +09:00
|
|
|
CurrencyNameTable currencies,
|
2024-04-04 16:31:04 +09:00
|
|
|
PaymentMethodHandlerDictionary handlers,
|
2023-11-29 18:51:40 +09:00
|
|
|
TransactionLinkProviders transactionLinkProviders)
|
2019-01-14 22:43:29 +01:00
|
|
|
{
|
2023-12-01 10:50:05 +01:00
|
|
|
_paymentRequestRepository = paymentRequestRepository;
|
|
|
|
_btcPayNetworkProvider = btcPayNetworkProvider;
|
2023-03-17 03:56:32 +01:00
|
|
|
_invoiceRepository = invoiceRepository;
|
2019-01-14 22:43:29 +01:00
|
|
|
_currencies = currencies;
|
2024-04-04 16:31:04 +09:00
|
|
|
_handlers = handlers;
|
2023-11-29 18:51:40 +09:00
|
|
|
_transactionLinkProviders = transactionLinkProviders;
|
2023-03-13 02:12:58 +01:00
|
|
|
_displayFormatter = displayFormatter;
|
2019-01-14 22:43:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public async Task UpdatePaymentRequestStateIfNeeded(string id)
|
|
|
|
{
|
2023-12-01 10:50:05 +01:00
|
|
|
var pr = await _paymentRequestRepository.FindPaymentRequest(id, null);
|
2019-01-14 22:43:29 +01:00
|
|
|
await UpdatePaymentRequestStateIfNeeded(pr);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async Task UpdatePaymentRequestStateIfNeeded(PaymentRequestData pr)
|
|
|
|
{
|
|
|
|
var blob = pr.GetBlob();
|
|
|
|
var currentStatus = pr.Status;
|
|
|
|
if (blob.ExpiryDate.HasValue)
|
|
|
|
{
|
|
|
|
if (blob.ExpiryDate.Value <= DateTimeOffset.UtcNow)
|
2020-05-19 19:59:23 +02:00
|
|
|
currentStatus = Client.Models.PaymentRequestData.PaymentRequestStatus.Expired;
|
2019-01-14 22:43:29 +01:00
|
|
|
}
|
2021-08-31 08:07:54 +02:00
|
|
|
else if (currentStatus != Client.Models.PaymentRequestData.PaymentRequestStatus.Completed)
|
|
|
|
{
|
|
|
|
currentStatus = Client.Models.PaymentRequestData.PaymentRequestStatus.Pending;
|
|
|
|
}
|
2020-06-28 17:55:27 +09:00
|
|
|
|
2021-07-28 15:38:26 +02:00
|
|
|
if (currentStatus != Client.Models.PaymentRequestData.PaymentRequestStatus.Expired)
|
2019-01-14 22:43:29 +01:00
|
|
|
{
|
2023-12-01 10:50:05 +01:00
|
|
|
var invoices = await _paymentRequestRepository.GetInvoicesForPaymentRequest(pr.Id);
|
2023-03-17 03:56:32 +01:00
|
|
|
var contributions = _invoiceRepository.GetContributionsByPaymentMethodId(blob.Currency, invoices, true);
|
2024-04-04 16:31:04 +09:00
|
|
|
var allSettled = contributions.All(i => i.Value.Settled);
|
2023-09-19 03:10:13 +02:00
|
|
|
var isPaid = contributions.TotalCurrency >= blob.Amount;
|
2021-07-28 15:38:26 +02:00
|
|
|
|
2023-09-19 03:10:13 +02:00
|
|
|
if (isPaid)
|
|
|
|
{
|
|
|
|
currentStatus = allSettled
|
|
|
|
? Client.Models.PaymentRequestData.PaymentRequestStatus.Completed
|
|
|
|
: Client.Models.PaymentRequestData.PaymentRequestStatus.Processing;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
currentStatus = Client.Models.PaymentRequestData.PaymentRequestStatus.Pending;
|
|
|
|
}
|
2019-01-14 22:43:29 +01:00
|
|
|
}
|
2019-02-22 11:37:45 +01:00
|
|
|
|
2019-02-24 09:26:37 +01:00
|
|
|
if (currentStatus != pr.Status)
|
2019-01-14 22:43:29 +01:00
|
|
|
{
|
|
|
|
pr.Status = currentStatus;
|
2023-12-01 10:50:05 +01:00
|
|
|
await _paymentRequestRepository.UpdatePaymentRequestStatus(pr.Id, currentStatus);
|
2019-01-14 22:43:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public async Task<ViewPaymentRequestViewModel> GetPaymentRequest(string id, string userId = null)
|
|
|
|
{
|
2023-12-01 10:50:05 +01:00
|
|
|
var pr = await _paymentRequestRepository.FindPaymentRequest(id, userId);
|
2019-01-14 22:43:29 +01:00
|
|
|
if (pr == null)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
var blob = pr.GetBlob();
|
2023-12-01 10:50:05 +01:00
|
|
|
var invoices = await _paymentRequestRepository.GetInvoicesForPaymentRequest(id);
|
2023-03-17 03:56:32 +01:00
|
|
|
var paymentStats = _invoiceRepository.GetContributionsByPaymentMethodId(blob.Currency, invoices, true);
|
2019-03-05 13:54:34 +09:00
|
|
|
var amountDue = blob.Amount - paymentStats.TotalCurrency;
|
2020-08-04 07:55:13 +02:00
|
|
|
var pendingInvoice = invoices.OrderByDescending(entity => entity.InvoiceTime)
|
2024-05-15 07:49:53 +09:00
|
|
|
.FirstOrDefault(entity => entity.Status == InvoiceStatus.New);
|
2023-09-19 03:10:13 +02:00
|
|
|
|
2019-01-14 22:43:29 +01:00
|
|
|
return new ViewPaymentRequestViewModel(pr)
|
|
|
|
{
|
2020-05-08 12:33:47 +02:00
|
|
|
Archived = pr.Archived,
|
2023-03-13 02:12:58 +01:00
|
|
|
AmountFormatted = _displayFormatter.Currency(blob.Amount, blob.Currency, DisplayFormatter.CurrencyFormat.Symbol),
|
2019-03-05 13:54:34 +09:00
|
|
|
AmountCollected = paymentStats.TotalCurrency,
|
2023-03-13 02:12:58 +01:00
|
|
|
AmountCollectedFormatted = _displayFormatter.Currency(paymentStats.TotalCurrency, blob.Currency, DisplayFormatter.CurrencyFormat.Symbol),
|
2019-01-14 22:43:29 +01:00
|
|
|
AmountDue = amountDue,
|
2023-03-13 02:12:58 +01:00
|
|
|
AmountDueFormatted = _displayFormatter.Currency(amountDue, blob.Currency, DisplayFormatter.CurrencyFormat.Symbol),
|
2019-01-14 22:43:29 +01:00
|
|
|
CurrencyData = _currencies.GetCurrencyData(blob.Currency, true),
|
2021-12-17 15:31:06 +09:00
|
|
|
LastUpdated = DateTime.UtcNow,
|
2022-11-25 02:42:55 +01:00
|
|
|
FormId = blob.FormId,
|
|
|
|
FormSubmitted = blob.FormResponse is not null,
|
2019-05-07 08:26:40 +00:00
|
|
|
AnyPendingInvoice = pendingInvoice != null,
|
2020-06-28 17:55:27 +09:00
|
|
|
PendingInvoiceHasPayments = pendingInvoice != null &&
|
2019-05-07 08:26:40 +00:00
|
|
|
pendingInvoice.ExceptionStatus != InvoiceExceptionStatus.None,
|
2022-11-02 18:41:19 +09:00
|
|
|
Invoices = new ViewPaymentRequestViewModel.InvoiceList(invoices.Select(entity =>
|
2019-01-14 22:43:29 +01:00
|
|
|
{
|
2020-10-23 10:37:28 +02:00
|
|
|
var state = entity.GetInvoiceState();
|
2024-04-04 16:31:04 +09:00
|
|
|
var payments = ViewPaymentRequestViewModel.PaymentRequestInvoicePayment.GetViewModels(entity, _displayFormatter, _transactionLinkProviders, _handlers);
|
2021-08-04 09:13:33 +02:00
|
|
|
|
2024-05-15 07:49:53 +09:00
|
|
|
if (state.Status == InvoiceStatus.Invalid ||
|
|
|
|
state.Status == InvoiceStatus.Expired && !payments.Any())
|
2021-08-04 09:13:33 +02:00
|
|
|
return null;
|
2021-12-31 16:59:02 +09:00
|
|
|
|
2020-10-23 10:37:28 +02:00
|
|
|
return new ViewPaymentRequestViewModel.PaymentRequestInvoice
|
2019-01-14 22:43:29 +01:00
|
|
|
{
|
2020-10-23 10:37:28 +02:00
|
|
|
Id = entity.Id,
|
|
|
|
Amount = entity.Price,
|
2023-03-13 02:12:58 +01:00
|
|
|
AmountFormatted = _displayFormatter.Currency(entity.Price, blob.Currency, DisplayFormatter.CurrencyFormat.Symbol),
|
2020-10-23 10:37:28 +02:00
|
|
|
Currency = entity.Currency,
|
|
|
|
ExpiryDate = entity.ExpirationTime.DateTime,
|
|
|
|
State = state,
|
2020-10-23 21:00:23 +09:00
|
|
|
StateFormatted = state.ToString(),
|
2021-08-04 09:13:33 +02:00
|
|
|
Payments = payments
|
2020-10-23 10:37:28 +02:00
|
|
|
};
|
2021-08-04 09:13:33 +02:00
|
|
|
})
|
2022-11-02 18:41:19 +09:00
|
|
|
.Where(invoice => invoice != null))
|
2019-01-14 22:43:29 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|