diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index 5c09bd919..14d79959c 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -393,6 +393,7 @@ namespace BTCPayServer.Tests var storeUrl = s.Driver.Url; s.ClickOnAllSectionLinks(); s.GoToInvoices(); + Assert.Contains("There are no invoices matching your criteria.", s.Driver.PageSource); var invoiceId = s.CreateInvoice(); s.FindAlertMessage(); s.Driver.FindElement(By.ClassName("invoice-details-link")).Click(); @@ -414,6 +415,23 @@ namespace BTCPayServer.Tests Assert.DoesNotContain("Unarchive", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text); s.GoToInvoices(); Assert.Contains(invoiceId, s.Driver.PageSource); + + // archive via list + s.Driver.FindElement(By.CssSelector($".selector[value=\"{invoiceId}\"]")).Click(); + s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click(); + s.Driver.FindElement(By.Id("ActionsDropdownArchive")).Click(); + Assert.Contains("1 invoice archived", s.FindAlertMessage().Text); + Assert.DoesNotContain(invoiceId, s.Driver.PageSource); + + // unarchive via list + s.Driver.FindElement(By.Id("SearchOptionsToggle")).Click(); + s.Driver.FindElement(By.Id("SearchOptionsIncludeArchived")).Click(); + Assert.Contains(invoiceId, s.Driver.PageSource); + s.Driver.FindElement(By.CssSelector($".selector[value=\"{invoiceId}\"]")).Click(); + s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click(); + s.Driver.FindElement(By.Id("ActionsDropdownUnarchive")).Click(); + Assert.Contains("1 invoice unarchived", s.FindAlertMessage().Text); + Assert.Contains(invoiceId, s.Driver.PageSource); // When logout out we should not be able to access store and invoice details s.Logout(); diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 4c82aeb18..32560e72d 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -437,8 +437,12 @@ namespace BTCPayServer.Controllers { case "archive": await _InvoiceRepository.MassArchive(selectedItems); - TempData[WellKnownTempData.SuccessMessage] = $"{selectedItems.Length} invoice(s) archived."; - + TempData[WellKnownTempData.SuccessMessage] = $"{selectedItems.Length} invoice{(selectedItems.Length == 1 ? "" : "s")} archived."; + break; + + case "unarchive": + await _InvoiceRepository.MassArchive(selectedItems, false); + TempData[WellKnownTempData.SuccessMessage] = $"{selectedItems.Length} invoice{(selectedItems.Length == 1 ? "" : "s")} unarchived."; break; } } @@ -763,6 +767,8 @@ namespace BTCPayServer.Controllers invoiceQuery.Skip = model.Skip; var list = await _InvoiceRepository.GetInvoices(invoiceQuery); + model.IncludeArchived = invoiceQuery.IncludeArchived; + foreach (var invoice in list) { var state = invoice.GetInvoiceState(); diff --git a/BTCPayServer/Models/InvoicingModels/InvoicesModel.cs b/BTCPayServer/Models/InvoicingModels/InvoicesModel.cs index 97e7854eb..32704e411 100644 --- a/BTCPayServer/Models/InvoicingModels/InvoicesModel.cs +++ b/BTCPayServer/Models/InvoicingModels/InvoicesModel.cs @@ -10,6 +10,7 @@ namespace BTCPayServer.Models.InvoicingModels public List Invoices { get; set; } = new List(); public string[] StoreIds { get; set; } public string StoreId { get; set; } + public bool IncludeArchived { get; set; } } public class InvoiceModel diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs index f546277fa..327d2d45a 100644 --- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs +++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs @@ -446,7 +446,7 @@ namespace BTCPayServer.Services.Invoices } } - public async Task MassArchive(string[] invoiceIds) + public async Task MassArchive(string[] invoiceIds, bool archive = true) { using (var context = _applicationDbContextFactory.CreateContext()) { @@ -458,7 +458,7 @@ namespace BTCPayServer.Services.Invoices foreach (InvoiceData invoice in items) { - invoice.Archived = true; + invoice.Archived = archive; } await context.SaveChangesAsync(); diff --git a/BTCPayServer/Views/Invoice/CreateInvoice.cshtml b/BTCPayServer/Views/Invoice/CreateInvoice.cshtml index 2137d43ee..62c34875c 100644 --- a/BTCPayServer/Views/Invoice/CreateInvoice.cshtml +++ b/BTCPayServer/Views/Invoice/CreateInvoice.cshtml @@ -44,111 +44,112 @@ - +

Invoice Details

} -
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - @foreach (var item in Model.AvailablePaymentMethods) - { -
- -
- } - -
-
- - - -
-

Customer Information

-
- - - -
-
- - - -
- -

Additional Options

-
-
-
-

- -

-
-

Custom data to correlate the invoice with an order. This data can be a simple text, number or JSON object, e.g. { "orderId": 615, "product": "Pizza" }

-
- - - +
+
+ + + +
+
+ + + +
+
+
+ + + +
+
+ + + +
+
+ + @foreach (var item in Model.AvailablePaymentMethods) + { +
+ +
+ } + +
+
+ + + +
+

Customer Information

+
+ + + +
+
+ + + +
+ +

Additional Options

+
+
+
+

+ +

+
+

Custom data to correlate the invoice with an order. This data can be a simple text, number or JSON object, e.g. { "orderId": 615, "product": "Pizza" }

+
+ + + +
-
-
-

- -

-
-
-
- - - -
-
- - - -

- Receive updates for this invoice. -

+
+

+ +

+
+
+
+ + + +
+
+ + + +

+ Receive updates for this invoice. +

+
-
- -
- -
+
+ +
diff --git a/BTCPayServer/Views/Invoice/Invoice.cshtml b/BTCPayServer/Views/Invoice/Invoice.cshtml index f1d3fd73f..5bd214a9d 100644 --- a/BTCPayServer/Views/Invoice/Invoice.cshtml +++ b/BTCPayServer/Views/Invoice/Invoice.cshtml @@ -314,7 +314,7 @@ @if (Model.Deliveries.Count != 0) { -

Webhook deliveries

+

Webhook deliveries

    @foreach (var delivery in Model.Deliveries) { @@ -369,7 +369,7 @@ }
} -
+

Events

diff --git a/BTCPayServer/Views/Invoice/InvoiceStatusChangePartial.cshtml b/BTCPayServer/Views/Invoice/InvoiceStatusChangePartial.cshtml index 22366cb21..072c82dc3 100644 --- a/BTCPayServer/Views/Invoice/InvoiceStatusChangePartial.cshtml +++ b/BTCPayServer/Views/Invoice/InvoiceStatusChangePartial.cshtml @@ -11,8 +11,8 @@
Updated in v1.4.0

Invoice states have been updated to match the Greenfield API:

-
-
    +
    +
    • Paid is now shown as @@ -30,7 +30,7 @@
    -
    +
    diff --git a/BTCPayServer/Views/Invoice/ListInvoices.cshtml b/BTCPayServer/Views/Invoice/ListInvoices.cshtml index 98ef75ced..dc7adc283 100644 --- a/BTCPayServer/Views/Invoice/ListInvoices.cshtml +++ b/BTCPayServer/Views/Invoice/ListInvoices.cshtml @@ -6,7 +6,7 @@ } @section PageHeadContent { - } @@ -102,7 +101,7 @@ alert("Invoice state update failed"); }); }) - + delegate('click', '.showInvoice', e => { e.preventDefault(); const { invoiceId } = e.target.dataset; @@ -135,7 +134,7 @@ $("#dtpStartDate").next().trigger("focus"); } }) - + function getDateStringWithOffset(hoursDiff) { var datenow = new Date(); var newDate = new Date(datenow.getTime() - (hoursDiff * 60 * 60 * 1000)); @@ -150,7 +149,7 @@ }); $("#invoices") - .on("click", ".invoice-row .invoice-details-toggle", function(e) { + .on("click", ".invoice-row .invoice-details-toggle", function (e) { e.preventDefault(); e.stopPropagation(true); @@ -167,7 +166,7 @@ } }); }) - .on("click", ".invoice-row", function(e) { + .on("click", ".invoice-row", function (e) { const $invoiceRow = $(e.currentTarget); if (!$(e.target).is("a,.badge,.selector")) { $invoiceRow.find(".selector").trigger("click"); @@ -196,94 +195,55 @@
- + -
-
-
- - -
- - - - - - - - + - - - - @* Custom Range Modal *@ -
-
-
+
+

You can search for invoice Id, deposit address, price, order id, store id, any buyer information and any product information. Be sure to split your search parameters with comma, for example:
@@ -304,17 +264,57 @@

+
+ + +
+ + + + + + -@if (Model.Total > 0) -{ - + +
+ + + +
+
+ + + @@ -326,139 +326,140 @@ JSON
+
- - - - -
- - - - - - - - - - - - - @foreach (var invoice in Model.Invoices) - { - - - - - - + + } + +
- - - Date - - - - OrderIdInvoiceIdStatusAmountActions
- - - - @invoice.Date.ToBrowserDate() - - - @if (invoice.RedirectUrl != string.Empty) - { - @invoice.OrderId - } - else - { - @invoice.OrderId - } - @invoice.InvoiceId - @if (invoice.Details.Archived) - { - archived - } - @if (invoice.CanMarkStatus) - { -
-
+
- - -} -else -{ -

- There are no invoices matching your criteria. -

-} + + } + else + { +

+ There are no invoices matching your criteria. +

+ } +