Add payouts report (#5320)

This commit is contained in:
Andrew Camilleri 2023-09-19 02:55:15 +02:00 committed by GitHub
parent 77d8e202d3
commit 00acbccd7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 138 additions and 9 deletions

View file

@ -538,7 +538,8 @@ namespace BTCPayServer.Controllers
{
var ppBlob = item.PullPayment?.GetBlob();
var payoutBlob = item.Payout.GetBlob(_jsonSerializerSettings);
string payoutSource;
item.Payout.PullPaymentData = item.PullPayment;
string payoutSource = item.Payout.GetPayoutSource(_jsonSerializerSettings);
if (payoutBlob.Metadata?.TryGetValue("source", StringComparison.InvariantCultureIgnoreCase,
out var source) is true)
{

View file

@ -33,6 +33,22 @@ namespace BTCPayServer.Data
return PaymentMethodId.TryParse(data.PaymentMethodId, out var paymentMethodId) ? paymentMethodId : null;
}
public static string GetPayoutSource(this PayoutData data, BTCPayNetworkJsonSerializerSettings jsonSerializerSettings)
{
var ppBlob = data.PullPaymentData?.GetBlob();
var payoutBlob = data.GetBlob(jsonSerializerSettings);
string payoutSource;
if (payoutBlob.Metadata?.TryGetValue("source", StringComparison.InvariantCultureIgnoreCase,
out var source) is true)
{
return source.Value<string>();
}
else
{
return ppBlob?.Name ?? data.PullPaymentDataId;
}
}
public static PayoutBlob GetBlob(this PayoutData data, BTCPayNetworkJsonSerializerSettings serializers)
{
var result = JsonConvert.DeserializeObject<PayoutBlob>(Encoding.UTF8.GetString(data.Blob), serializers.GetSerializer(data.GetPaymentMethodId().CryptoCode));

View file

@ -157,6 +157,8 @@ namespace BTCPayServer.HostedServices
public bool IncludeArchived { get; set; }
public bool IncludeStoreData { get; set; }
public bool IncludePullPaymentData { get; set; }
public DateTimeOffset? From { get; set; }
public DateTimeOffset? To { get; set; }
}
public async Task<List<PayoutData>> GetPayouts(PayoutQuery payoutQuery)
@ -217,6 +219,14 @@ namespace BTCPayServer.HostedServices
data.PullPaymentData == null || !data.PullPaymentData.Archived);
}
if (payoutQuery.From is not null)
{
query = query.Where(data => data.Date >= payoutQuery.From);
}
if (payoutQuery.To is not null)
{
query = query.Where(data => data.Date <= payoutQuery.To);
}
return await query.ToListAsync(cancellationToken);
}

View file

@ -359,6 +359,7 @@ namespace BTCPayServer.Hosting
services.AddReportProvider<PaymentsReportProvider>();
services.AddReportProvider<OnChainWalletReportProvider>();
services.AddReportProvider<ProductsReportProvider>();
services.AddReportProvider<PayoutsReportProvider>();
services.AddHttpClient(WebhookSender.OnionNamedClient)
.ConfigurePrimaryHttpMessageHandler<Socks5HttpClientHandler>();

View file

@ -0,0 +1,109 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Payments;
namespace BTCPayServer.Services.Reporting;
public class PayoutsReportProvider:ReportProvider
{
private readonly PullPaymentHostedService _pullPaymentHostedService;
private readonly BTCPayNetworkJsonSerializerSettings _btcPayNetworkJsonSerializerSettings;
public PayoutsReportProvider(PullPaymentHostedService pullPaymentHostedService, BTCPayNetworkJsonSerializerSettings btcPayNetworkJsonSerializerSettings)
{
_pullPaymentHostedService = pullPaymentHostedService;
_btcPayNetworkJsonSerializerSettings = btcPayNetworkJsonSerializerSettings;
}
public override string Name => "Payouts";
public override async Task Query(QueryContext queryContext, CancellationToken cancellation)
{
queryContext.ViewDefinition = CreateDefinition();
foreach (var payout in (await _pullPaymentHostedService.GetPayouts(new PullPaymentHostedService.PayoutQuery()
{
Stores = new[] {queryContext.StoreId},
From = queryContext.From,
To = queryContext.To,
IncludeArchived = true,
IncludePullPaymentData = true,
})).OrderBy(data => data.Date))
{
var blob = payout.GetBlob(_btcPayNetworkJsonSerializerSettings);
var data = queryContext.CreateData();
data.Add(payout.Date);
data.Add(payout.GetPayoutSource(_btcPayNetworkJsonSerializerSettings));
data.Add(payout.State.ToString());
if (PaymentMethodId.TryParse(payout.PaymentMethodId, out var paymentType))
{
if (paymentType.PaymentType == PaymentTypes.LightningLike || paymentType.PaymentType == PaymentTypes.LNURLPay)
data.Add("Lightning");
else if (paymentType.PaymentType == PaymentTypes.BTCLike)
data.Add("On-Chain");
else
data.Add(paymentType.PaymentType.ToStringNormalized());
}
else
continue;
data.Add(paymentType.CryptoCode);
data.Add(blob.CryptoAmount);
var ppBlob = payout.PullPaymentData?.GetBlob();
data.Add(ppBlob?.Currency??paymentType.CryptoCode);
data.Add(blob.Amount);
data.Add(blob.Destination);
queryContext.Data.Add(data);
}
}
private ViewDefinition CreateDefinition()
{
return new ViewDefinition()
{
Fields = new List<StoreReportResponse.Field>()
{
new("Date", "datetime"),
new("Source", "string"),
new("State", "string"),
new("PaymentType", "string"),
new("Crypto", "string"),
new("CryptoAmount", "decimal"),
new("Currency", "string"),
new("CurrencyAmount", "decimal"),
new("Destination", "string")
},
Charts =
{
new ()
{
Name = "Aggregated crypto amount",
Groups = { "Crypto", "PaymentType", "State" },
Totals = { "Crypto" },
HasGrandTotal = false,
Aggregates = { "CryptoAmount" }
},new ()
{
Name = "Aggregated amount",
Groups = { "Currency", "State" },
Totals = { "CurrencyAmount" },
HasGrandTotal = false,
Aggregates = { "CurrencyAmount" }
},new ()
{
Name = "Aggregated amount by Source",
Groups = { "Currency", "State", "Source" },
Totals = { "CurrencyAmount" },
HasGrandTotal = false,
Aggregates = { "CurrencyAmount" }
}
}
};
}
}

View file

@ -1,18 +1,10 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Data;
using BTCPayServer.Rating;
using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Rates;
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Newtonsoft.Json;
namespace BTCPayServer.Services.Reporting;
public class ProductsReportProvider : ReportProvider