diff --git a/BTCPayServer.Data/BTCPayServer.Data.csproj b/BTCPayServer.Data/BTCPayServer.Data.csproj
index fdece06d5..f2042776f 100644
--- a/BTCPayServer.Data/BTCPayServer.Data.csproj
+++ b/BTCPayServer.Data/BTCPayServer.Data.csproj
@@ -23,5 +23,6 @@
+
diff --git a/BTCPayServer.Data/DBScripts/006.PaymentsRenaming.sql b/BTCPayServer.Data/DBScripts/006.PaymentsRenaming.sql
new file mode 100644
index 000000000..393b41180
--- /dev/null
+++ b/BTCPayServer.Data/DBScripts/006.PaymentsRenaming.sql
@@ -0,0 +1,18 @@
+DROP FUNCTION get_monitored_invoices;
+CREATE OR REPLACE FUNCTION get_monitored_invoices(payment_method_id TEXT, include_non_activated BOOLEAN)
+RETURNS TABLE (invoice_id TEXT, payment_id TEXT, payment_method_id TEXT) AS $$
+WITH cte AS (
+-- Get all the invoices which are pending. Even if no payments.
+SELECT i."Id" invoice_id, p."Id" payment_id, p."PaymentMethodId" payment_method_id FROM "Invoices" i LEFT JOIN "Payments" p ON i."Id" = p."InvoiceDataId"
+ WHERE is_pending(i."Status")
+UNION ALL
+-- For invoices not pending, take all of those which have pending payments
+SELECT i."Id", p."Id", p."PaymentMethodId" payment_method_id FROM "Invoices" i INNER JOIN "Payments" p ON i."Id" = p."InvoiceDataId"
+ WHERE is_pending(p."Status") AND NOT is_pending(i."Status"))
+SELECT cte.* FROM cte
+LEFT JOIN "Payments" p ON cte.payment_id=p."Id" AND cte.payment_id=p."PaymentMethodId"
+LEFT JOIN "Invoices" i ON cte.invoice_id=i."Id"
+WHERE (p."PaymentMethodId" IS NOT NULL AND p."PaymentMethodId" = payment_method_id) OR
+ (p."PaymentMethodId" IS NULL AND get_prompt(i."Blob2", payment_method_id) IS NOT NULL AND
+ (include_non_activated IS TRUE OR (get_prompt(i."Blob2", payment_method_id)->'activated')::BOOLEAN IS NOT FALSE));
+$$ LANGUAGE SQL STABLE;
diff --git a/BTCPayServer.Data/Migrations/20240924071444_temprefactor3.cs b/BTCPayServer.Data/Migrations/20240924071444_temprefactor3.cs
new file mode 100644
index 000000000..6884ded7d
--- /dev/null
+++ b/BTCPayServer.Data/Migrations/20240924071444_temprefactor3.cs
@@ -0,0 +1,15 @@
+using BTCPayServer.Data;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace BTCPayServer.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ [Migration("20240924071444_temprefactor3")]
+ [DBScript("006.PaymentsRenaming.sql")]
+ public partial class temprefactor3 : DBScriptsMigration
+ {
+ }
+}
diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs
index d7ae0e270..c654c2901 100644
--- a/BTCPayServer.Tests/GreenfieldAPITests.cs
+++ b/BTCPayServer.Tests/GreenfieldAPITests.cs
@@ -14,6 +14,7 @@ using BTCPayServer.Events;
using BTCPayServer.Lightning;
using BTCPayServer.Models.InvoicingModels;
using BTCPayServer.NTag424;
+using BTCPayServer.Payments;
using BTCPayServer.Payments.Lightning;
using BTCPayServer.PayoutProcessors;
using BTCPayServer.Plugins.PointOfSale.Controllers;
@@ -2711,6 +2712,14 @@ namespace BTCPayServer.Tests
invoiceObject = await client.GetOnChainWalletObject(user.StoreId, "BTC", new OnChainWalletObjectId("invoice", invoice.Id), false);
Assert.DoesNotContain(invoiceObject.Links.Select(l => l.Type), t => t == "address");
+ // Check if we can get the monitored invoice
+ var invoiceRepo = tester.PayTester.GetService();
+ var includeNonActivated = true;
+ Assert.Single(await invoiceRepo.GetMonitoredInvoices(PaymentMethodId.Parse("BTC-CHAIN"), includeNonActivated), i => i.Id == invoice.Id);
+ includeNonActivated = false;
+ Assert.Single(await invoiceRepo.GetMonitoredInvoices(PaymentMethodId.Parse("BTC-CHAIN"), includeNonActivated), i => i.Id == invoice.Id);
+ Assert.Single(await invoiceRepo.GetMonitoredInvoices(PaymentMethodId.Parse("BTC-CHAIN")), i => i.Id == invoice.Id);
+ //
paymentMethods = await client.GetInvoicePaymentMethods(store.Id, invoice.Id);
Assert.Single(paymentMethods);
diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs
index 88271c53d..814d971d1 100644
--- a/BTCPayServer.Tests/UnitTest1.cs
+++ b/BTCPayServer.Tests/UnitTest1.cs
@@ -3161,9 +3161,11 @@ namespace BTCPayServer.Tests
var invoiceRepo = tester.PayTester.GetService();
var monitored = Assert.Single(await invoiceRepo.GetMonitoredInvoices(PaymentMethodId.Parse("BTC-CHAIN")), i => i.Id == invoiceId);
Assert.Single(monitored.Payments);
- //
+ monitored = Assert.Single(await invoiceRepo.GetMonitoredInvoices(PaymentMethodId.Parse("BTC-CHAIN"), true), i => i.Id == invoiceId);
+ Assert.Single(monitored.Payments);
+ //
- app = await client.CreatePointOfSaleApp(acc.StoreId, new PointOfSaleAppRequest
+ app = await client.CreatePointOfSaleApp(acc.StoreId, new PointOfSaleAppRequest
{
AppName = "Cart",
DefaultView = PosViewType.Cart,
diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs
index 2088bd977..7c06a1070 100644
--- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs
+++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs
@@ -88,11 +88,30 @@ namespace BTCPayServer.Services.Invoices
/// The payment method id
/// Cancellation token
///
- public async Task GetMonitoredInvoices(PaymentMethodId paymentMethodId, CancellationToken cancellationToken = default)
+ public Task GetMonitoredInvoices(PaymentMethodId paymentMethodId, CancellationToken cancellationToken = default)
+ => GetMonitoredInvoices(paymentMethodId, false, cancellationToken: cancellationToken);
+
+ ///
+ /// Returns all invoices which either:
+ /// * Have the activated and are pending
+ /// * Aren't pending but have a payment from the that is pending
+ /// is filled with the monitored addresses of the for this invoice.
+ /// include the payments for this invoice.
+ ///
+ /// The payment method id
+ /// If true, include pending invoice with non activated payment methods
+ /// Cancellation token
+ ///
+ public async Task GetMonitoredInvoices(PaymentMethodId paymentMethodId, bool includeNonActivated, CancellationToken cancellationToken = default)
{
var pmi = paymentMethodId.ToString();
using var ctx = _applicationDbContextFactory.CreateContext();
var conn = ctx.Database.GetDbConnection();
+
+ string includeNonActivateQuery = String.Empty;
+ if (includeNonActivated)
+ includeNonActivateQuery = " AND (get_prompt(i.\"Blob2\", @pmi)->'activated')::BOOLEAN IS NOT FALSE)";
+
var rows = await conn.QueryAsync<(string Id, uint xmin, string[] addresses, string[] payments, string invoice)>(new("""
SELECT
i."Id",
@@ -100,14 +119,14 @@ namespace BTCPayServer.Services.Invoices
array_agg(ai."Address") addresses,
COALESCE(array_agg(to_jsonb(p)) FILTER (WHERE p."Id" IS NOT NULL), '{}') as payments,
(array_agg(to_jsonb(i)))[1] as invoice
- FROM get_monitored_invoices(@pmi) m
+ FROM get_monitored_invoices(@pmi, @includeNonActivated) m
LEFT JOIN "Payments" p ON p."Id" = m.payment_id AND p."PaymentMethodId" = m.payment_method_id
LEFT JOIN "Invoices" i ON i."Id" = m.invoice_id
LEFT JOIN "AddressInvoices" ai ON i."Id" = ai."InvoiceDataId"
WHERE ai."PaymentMethodId" = @pmi
GROUP BY i."Id";
"""
- , new { pmi = paymentMethodId.ToString() }));
+ , new { pmi = paymentMethodId.ToString(), includeNonActivated }));
if (Enumerable.TryGetNonEnumeratedCount(rows, out var c) && c == 0)
return Array.Empty();
List invoices = new List();