diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index c30516ac1..8a7cee98b 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -390,6 +390,7 @@ namespace BTCPayServer.Hosting services.AddReportProvider(); services.AddReportProvider(); services.AddReportProvider(); + services.AddReportProvider(); services.AddWebhooks(); services.AddSingleton(); services.AddSingleton(provider => provider.GetRequiredService()); diff --git a/BTCPayServer/Services/Reporting/LegacyInvoiceExportReportProvider.cs b/BTCPayServer/Services/Reporting/LegacyInvoiceExportReportProvider.cs new file mode 100644 index 000000000..69a767e69 --- /dev/null +++ b/BTCPayServer/Services/Reporting/LegacyInvoiceExportReportProvider.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; +using BTCPayServer.Client.Models; +using BTCPayServer.Services.Invoices; +using BTCPayServer.Services.Rates; + +namespace BTCPayServer.Services.Reporting; + +public class LegacyInvoiceExportReportProvider : ReportProvider +{ + private readonly CurrencyNameTable _currencyNameTable; + private readonly InvoiceRepository _invoiceRepository; + + + public override string Name { get; } = "Invoice Export (legacy)"; + + public override async Task Query(QueryContext queryContext, CancellationToken cancellation) + { + var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery() + { + EndDate = queryContext.To, + StartDate = queryContext.From, + StoreId = new[] {queryContext.StoreId}, + }, cancellation); + + queryContext.ViewDefinition = new ViewDefinition() + { + Fields = new List() + { + new("ReceivedDate", "datetime"), + new("StoreId", "text"), + new("OrderId", "text"), + new("InvoiceId", "text"), + new("InvoiceCreatedDate", "datetime"), + new("InvoiceExpirationDate", "datetime"), + new("InvoiceMonitoringDate", "datetime"), + new("PaymentId", "text"), + new("Destination", "text"), + new("PaymentType", "text"), + new("CryptoCode", "text"), + new("Paid", "text"), + new("NetworkFee", "text"), + new("ConversionRate", "number"), + new("PaidCurrency", "text"), + new("InvoiceCurrency", "text"), + new("InvoiceDue", "number"), + new("InvoicePrice", "number"), + new("InvoiceItemCode", "text"), + new("InvoiceItemDesc", "text"), + new("InvoiceFullStatus", "text"), + new("InvoiceStatus", "text"), + new("InvoiceExceptionStatus", "text"), + new("BuyerEmail", "text"), + new("Accounted", "boolean") + } + }; + + foreach (var invoiceEntity in invoices) + { + var currency = _currencyNameTable.GetNumberFormatInfo(invoiceEntity.Currency, true); + var invoiceDue = invoiceEntity.Price; + var payments = invoiceEntity.GetPayments(false); + + if (payments.Count > 0) + { + foreach (var payment in payments) + { + var pdata = payment.GetCryptoPaymentData(); + invoiceDue -= payment.InvoicePaidAmount.Net; + var data = queryContext.AddData(); + + // Add each field in the order defined in ViewDefinition + data.Add(payment.ReceivedTime); + data.Add(invoiceEntity.StoreId); + data.Add(invoiceEntity.Metadata.OrderId ?? string.Empty); + data.Add(invoiceEntity.Id); + data.Add(invoiceEntity.InvoiceTime); + data.Add(invoiceEntity.ExpirationTime); + data.Add(invoiceEntity.MonitoringExpiration); + data.Add(pdata.GetPaymentId()); + data.Add(pdata.GetDestination()); + data.Add(payment.GetPaymentMethodId().PaymentType.ToPrettyString()); + data.Add(payment.Currency); + data.Add(payment.PaidAmount.Gross.ToString(CultureInfo.InvariantCulture)); + data.Add(payment.NetworkFee.ToString(CultureInfo.InvariantCulture)); + data.Add(payment.Rate); + data.Add(Math.Round(payment.InvoicePaidAmount.Gross, currency.NumberDecimalDigits) + .ToString(CultureInfo.InvariantCulture)); + data.Add(invoiceEntity.Currency); + data.Add(Math.Round(invoiceDue, currency.NumberDecimalDigits)); + data.Add(invoiceEntity.Price); + data.Add(invoiceEntity.Metadata.ItemCode); + data.Add(invoiceEntity.Metadata.ItemDesc); + data.Add(invoiceEntity.GetInvoiceState().ToString()); + data.Add(invoiceEntity.StatusString); + data.Add(invoiceEntity.ExceptionStatusString); + data.Add(invoiceEntity.Metadata.BuyerEmail); + data.Add(payment.Accounted); + } + } + else + { + var data = queryContext.AddData(); + + // Add fields for invoices without payments + data.Add(null); // ReceivedDate + data.Add(invoiceEntity.StoreId); + data.Add(invoiceEntity.Metadata.OrderId ?? string.Empty); + data.Add(invoiceEntity.Id); + data.Add(invoiceEntity.InvoiceTime); + data.Add(invoiceEntity.ExpirationTime); + data.Add(invoiceEntity.MonitoringExpiration); + data.Add(null); // PaymentId + data.Add(null); // Destination + data.Add(null); // PaymentType + data.Add(null); // CryptoCode + data.Add(null); // Paid + data.Add(null); // NetworkFee + data.Add(null); // ConversionRate + data.Add(null); // PaidCurrency + data.Add(invoiceEntity.Currency); + data.Add(Math.Round(invoiceDue, currency.NumberDecimalDigits)); // InvoiceDue + data.Add(invoiceEntity.Price); + data.Add(invoiceEntity.Metadata.ItemCode); + data.Add(invoiceEntity.Metadata.ItemDesc); + data.Add(invoiceEntity.GetInvoiceState().ToString()); + data.Add(invoiceEntity.StatusString); + data.Add(invoiceEntity.ExceptionStatusString); + data.Add(invoiceEntity.Metadata.BuyerEmail); + data.Add(null); // Accounted + } + } + } + + public LegacyInvoiceExportReportProvider(CurrencyNameTable currencyNameTable, InvoiceRepository invoiceRepository) + { + _currencyNameTable = currencyNameTable; + _invoiceRepository = invoiceRepository; + } +} diff --git a/BTCPayServer/Services/Reporting/PaymentsReportProvider.cs b/BTCPayServer/Services/Reporting/PaymentsReportProvider.cs index 134b88f7d..6d79e0b0c 100644 --- a/BTCPayServer/Services/Reporting/PaymentsReportProvider.cs +++ b/BTCPayServer/Services/Reporting/PaymentsReportProvider.cs @@ -91,14 +91,14 @@ public class PaymentsReportProvider : ReportProvider var conn = ctx.Database.GetDbConnection(); string[] fields = { - "i.\"Created\" created", - "i.\"Id\" invoice_id", - "i.\"OrderId\" order_id", - "p.\"Id\" payment_id", - "p.\"Type\" payment_type", - "i.\"Blob2\" invoice_blob", - "p.\"Blob2\" payment_blob", - }; + "i.\"Created\" created", + "i.\"Id\" invoice_id", + "i.\"OrderId\" order_id", + "p.\"Id\" payment_id", + "p.\"Type\" payment_type", + "i.\"Blob2\" invoice_blob", + "p.\"Blob2\" payment_blob", + }; string select = "SELECT " + String.Join(", ", fields) + " "; string body = "FROM \"Payments\" p " +