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)