diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 7c14ebdd7..7601fb0f6 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -371,13 +371,15 @@ namespace BTCPayServer.Controllers Skip = skip, UserId = GetUserId(), Status = filterString.Filters.ContainsKey("status") ? filterString.Filters["status"].ToArray() : null, + ExceptionStatus = filterString.Filters.ContainsKey("exceptionstatus") ? filterString.Filters["exceptionstatus"].ToArray() : null, StoreId = filterString.Filters.ContainsKey("storeid") ? filterString.Filters["storeid"].ToArray() : null })) { model.SearchTerm = searchTerm; model.Invoices.Add(new InvoiceModel() { - Status = invoice.Status, + Status = invoice.Status + (invoice.ExceptionStatus == null ? string.Empty : $" ({invoice.ExceptionStatus})"), + ShowCheckout = invoice.Status == "new", Date = (DateTimeOffset.UtcNow - invoice.InvoiceTime).Prettify() + " ago", InvoiceId = invoice.Id, OrderId = invoice.OrderId ?? string.Empty, diff --git a/BTCPayServer/Models/InvoicingModels/InvoicesModel.cs b/BTCPayServer/Models/InvoicingModels/InvoicesModel.cs index 594e28c40..63385532d 100644 --- a/BTCPayServer/Models/InvoicingModels/InvoicesModel.cs +++ b/BTCPayServer/Models/InvoicingModels/InvoicesModel.cs @@ -49,6 +49,8 @@ namespace BTCPayServer.Models.InvoicingModels { get; set; } + public bool ShowCheckout { get; set; } + public string ExceptionStatus { get; set; } public string AmountCurrency { get; set; diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs index d4c90b718..d3460f311 100644 --- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs +++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs @@ -436,6 +436,12 @@ namespace BTCPayServer.Services.Invoices query = query.Where(i => statusSet.Contains(i.Status)); } + if (queryObject.ExceptionStatus != null && queryObject.ExceptionStatus.Length > 0) + { + var exceptionStatusSet = queryObject.ExceptionStatus.Select(s => NormalizeExceptionStatus(s)).ToHashSet(); + query = query.Where(i => exceptionStatusSet.Contains(i.ExceptionStatus)); + } + query = query.OrderByDescending(q => q.Created); if (queryObject.Skip != null) @@ -451,6 +457,29 @@ namespace BTCPayServer.Services.Invoices } + private string NormalizeExceptionStatus(string status) + { + status = status.ToLowerInvariant(); + switch (status) + { + case "paidover": + case "over": + case "overpaid": + status = "paidOver"; + break; + case "paidlate": + case "late": + status = "paidLate"; + break; + case "paidpartial": + case "underpaid": + case "partial": + status = "paidPartial"; + break; + } + return status; + } + public async Task AddRefundsAsync(string invoiceId, TxOut[] outputs, Network network) { if (outputs.Length == 0) @@ -618,6 +647,12 @@ namespace BTCPayServer.Services.Invoices { get; set; } + + public string[] ExceptionStatus + { + get; set; + } + public string InvoiceId { get; diff --git a/BTCPayServer/Views/Invoice/ListInvoices.cshtml b/BTCPayServer/Views/Invoice/ListInvoices.cshtml index e6699eda6..3f88526b0 100644 --- a/BTCPayServer/Views/Invoice/ListInvoices.cshtml +++ b/BTCPayServer/Views/Invoice/ListInvoices.cshtml @@ -20,14 +20,15 @@
You can search for invoice Id, deposit address, price, order id, store id, any buyer information and any product information.
- You can also apply filters to your search by searching for `filtername:value`, here is a list of supported filters
+ You can also apply filters to your search by searching for filtername:value, here is a list of supported filters
storeid:id for filtering a specific storestatus:(expired|invalid|complete|confirmed|paid|new) for filtering a specific statusexceptionstatus:(paidover|paidlate|paidpartial) for filtering a specific exception state
- If you want two confirmed and complete invoices, duplicate the filter: `status:confirmed status:complete`.
+ If you want two confirmed and complete invoices, duplicate the filter: status:confirmed status:complete.