diff --git a/BTCPayServer.Data/BTCPayServer.Data.csproj b/BTCPayServer.Data/BTCPayServer.Data.csproj
index 757cb9c49..7e1dbd5f8 100644
--- a/BTCPayServer.Data/BTCPayServer.Data.csproj
+++ b/BTCPayServer.Data/BTCPayServer.Data.csproj
@@ -25,5 +25,6 @@
+
diff --git a/BTCPayServer.Data/DBScripts/008.PaymentsRenaming.sql b/BTCPayServer.Data/DBScripts/008.PaymentsRenaming.sql
new file mode 100644
index 000000000..c6e443971
--- /dev/null
+++ b/BTCPayServer.Data/DBScripts/008.PaymentsRenaming.sql
@@ -0,0 +1,18 @@
+DROP FUNCTION get_monitored_invoices;
+CREATE OR REPLACE FUNCTION get_monitored_invoices(arg_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" invoice_id, p."Id" payment_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
+JOIN "Invoices" i ON cte.invoice_id=i."Id"
+LEFT JOIN "Payments" p ON cte.payment_id=p."Id" AND cte.payment_method_id=p."PaymentMethodId"
+WHERE (p."PaymentMethodId" IS NOT NULL AND p."PaymentMethodId" = arg_payment_method_id) OR
+ (p."PaymentMethodId" IS NULL AND get_prompt(i."Blob2", arg_payment_method_id) IS NOT NULL AND
+ (include_non_activated IS TRUE OR (get_prompt(i."Blob2", arg_payment_method_id)->'inactive')::BOOLEAN IS NOT TRUE));
+$$ LANGUAGE SQL STABLE;
diff --git a/BTCPayServer.Data/Migrations/20240924081444_temprefactor5.cs b/BTCPayServer.Data/Migrations/20240924081444_temprefactor5.cs
new file mode 100644
index 000000000..f6efaab87
--- /dev/null
+++ b/BTCPayServer.Data/Migrations/20240924081444_temprefactor5.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("20240924081444_temprefactor5")]
+ [DBScript("008.PaymentsRenaming.sql")]
+ public partial class temprefactor5 : DBScriptsMigration
+ {
+ }
+}
diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs
index c654c2901..b7d791b41 100644
--- a/BTCPayServer.Tests/GreenfieldAPITests.cs
+++ b/BTCPayServer.Tests/GreenfieldAPITests.cs
@@ -2717,8 +2717,8 @@ namespace BTCPayServer.Tests
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);
+ Assert.DoesNotContain(await invoiceRepo.GetMonitoredInvoices(PaymentMethodId.Parse("BTC-CHAIN"), includeNonActivated), i => i.Id == invoice.Id);
+ Assert.DoesNotContain(await invoiceRepo.GetMonitoredInvoices(PaymentMethodId.Parse("BTC-CHAIN")), i => i.Id == invoice.Id);
//
paymentMethods = await client.GetInvoicePaymentMethods(store.Id, invoice.Id);
diff --git a/BTCPayServer.Tests/TestUtils.cs b/BTCPayServer.Tests/TestUtils.cs
index 18589e1c7..1aebb0ae8 100644
--- a/BTCPayServer.Tests/TestUtils.cs
+++ b/BTCPayServer.Tests/TestUtils.cs
@@ -16,7 +16,7 @@ namespace BTCPayServer.Tests
public static class TestUtils
{
#if DEBUG && !SHORT_TIMEOUT
- public const int TestTimeout = 60_000;
+ public const int TestTimeout = 20_000;
#else
public const int TestTimeout = 90_000;
#endif
diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs
index af2142a9b..e43c63e34 100644
--- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs
+++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs
@@ -108,17 +108,27 @@ namespace BTCPayServer.Services.Invoices
var conn = ctx.Database.GetDbConnection();
var rows = await conn.QueryAsync<(string Id, uint xmin, string[] addresses, string[] payments, string invoice)>(new("""
+ WITH invoices_payments AS (
SELECT
- i."Id",
- i.xmin,
- 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
+ m.invoice_id,
+ array_agg(to_jsonb(p)) FILTER (WHERE p."Id" IS NOT NULL) as payments
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"
- GROUP BY i."Id";
+ GROUP BY 1
+ ),
+ invoices_addresses AS (
+ SELECT m.invoice_id,
+ array_agg(ai."Address") addresses
+ FROM get_monitored_invoices(@pmi, @includeNonActivated) m
+ JOIN "AddressInvoices" ai ON ai."InvoiceDataId" = m.invoice_id
+ WHERE ai."PaymentMethodId" = @pmi
+ GROUP BY 1
+ )
+ SELECT
+ ip.invoice_id, i.xmin, COALESCE(ia.addresses, '{}'), COALESCE(ip.payments, '{}'), to_jsonb(i)
+ FROM invoices_payments ip
+ JOIN "Invoices" i ON i."Id" = ip.invoice_id
+ LEFT JOIN invoices_addresses ia ON ia.invoice_id = ip.invoice_id;
"""
, new { pmi = paymentMethodId.ToString(), includeNonActivated }));
if (Enumerable.TryGetNonEnumeratedCount(rows, out var c) && c == 0)