mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 06:21:44 +01:00
145 lines
6.6 KiB
C#
145 lines
6.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using BTCPayServer.Payments.Bitcoin;
|
|
using BTCPayServer.Services.Invoices;
|
|
using BTCPayServer.Services.Rates;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace BTCPayServer.Services.Invoices.Export
|
|
{
|
|
public class InvoiceExport
|
|
{
|
|
public BTCPayNetworkProvider Networks { get; }
|
|
public CurrencyNameTable Currencies { get; }
|
|
|
|
public InvoiceExport(BTCPayNetworkProvider networks, CurrencyNameTable currencies)
|
|
{
|
|
Networks = networks;
|
|
Currencies = currencies;
|
|
}
|
|
public string Process(InvoiceEntity[] invoices, string fileFormat)
|
|
{
|
|
var csvInvoices = new List<ExportInvoiceHolder>();
|
|
foreach (var i in invoices)
|
|
{
|
|
csvInvoices.AddRange(convertFromDb(i));
|
|
}
|
|
|
|
if (String.Equals(fileFormat, "json", StringComparison.OrdinalIgnoreCase))
|
|
return processJson(csvInvoices);
|
|
else if (String.Equals(fileFormat, "csv", StringComparison.OrdinalIgnoreCase))
|
|
return processCsv(csvInvoices);
|
|
else
|
|
throw new Exception("Export format not supported");
|
|
}
|
|
|
|
private string processJson(List<ExportInvoiceHolder> invoices)
|
|
{
|
|
var serializerSett = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
|
|
var json = JsonConvert.SerializeObject(invoices, Formatting.Indented, serializerSett);
|
|
|
|
return json;
|
|
}
|
|
|
|
private string processCsv(List<ExportInvoiceHolder> invoices)
|
|
{
|
|
var serializer = new CsvSerializer<ExportInvoiceHolder>();
|
|
var csv = serializer.Serialize(invoices);
|
|
|
|
return csv;
|
|
}
|
|
|
|
private IEnumerable<ExportInvoiceHolder> convertFromDb(InvoiceEntity invoice)
|
|
{
|
|
var exportList = new List<ExportInvoiceHolder>();
|
|
var currency = Currencies.GetNumberFormatInfo(invoice.ProductInformation.Currency, true);
|
|
|
|
var invoiceDue = invoice.ProductInformation.Price;
|
|
// in this first version we are only exporting invoices that were paid
|
|
foreach (var payment in invoice.GetPayments())
|
|
{
|
|
// not accounted payments are payments which got double spent like RBfed
|
|
if (!payment.Accounted)
|
|
continue;
|
|
var cryptoCode = payment.GetPaymentMethodId().CryptoCode;
|
|
var pdata = payment.GetCryptoPaymentData();
|
|
|
|
var pmethod = invoice.GetPaymentMethod(payment.GetPaymentMethodId(), Networks);
|
|
var paidAfterNetworkFees = pdata.GetValue() - payment.NetworkFee;
|
|
invoiceDue -= paidAfterNetworkFees * pmethod.Rate;
|
|
|
|
var target = new ExportInvoiceHolder
|
|
{
|
|
ReceivedDate = payment.ReceivedTime.UtcDateTime,
|
|
PaymentId = pdata.GetPaymentId(),
|
|
CryptoCode = cryptoCode,
|
|
ConversionRate = pmethod.Rate,
|
|
PaymentType = payment.GetPaymentMethodId().PaymentType == Payments.PaymentTypes.BTCLike ? "OnChain" : "OffChain",
|
|
Destination = payment.GetCryptoPaymentData().GetDestination(Networks.GetNetwork(cryptoCode)),
|
|
Paid = pdata.GetValue().ToString(CultureInfo.InvariantCulture),
|
|
PaidCurrency = Math.Round(pdata.GetValue() * pmethod.Rate, currency.NumberDecimalDigits).ToString(CultureInfo.InvariantCulture),
|
|
// Adding NetworkFee because Paid doesn't take into account network fees
|
|
// so if fee is 10000 satoshis, customer can essentially send infinite number of tx
|
|
// and merchant effectivelly would receive 0 BTC, invoice won't be paid
|
|
// while looking just at export you could sum Paid and assume merchant "received payments"
|
|
NetworkFee = payment.NetworkFee.ToString(CultureInfo.InvariantCulture),
|
|
InvoiceDue = Math.Round(invoiceDue, currency.NumberDecimalDigits),
|
|
OrderId = invoice.OrderId,
|
|
StoreId = invoice.StoreId,
|
|
InvoiceId = invoice.Id,
|
|
InvoiceCreatedDate = invoice.InvoiceTime.UtcDateTime,
|
|
InvoiceExpirationDate = invoice.ExpirationTime.UtcDateTime,
|
|
InvoiceMonitoringDate = invoice.MonitoringExpiration.UtcDateTime,
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
InvoiceFullStatus = invoice.GetInvoiceState().ToString(),
|
|
InvoiceStatus = invoice.StatusString,
|
|
InvoiceExceptionStatus = invoice.ExceptionStatusString,
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
InvoiceItemCode = invoice.ProductInformation.ItemCode,
|
|
InvoiceItemDesc = invoice.ProductInformation.ItemDesc,
|
|
InvoicePrice = invoice.ProductInformation.Price,
|
|
InvoiceCurrency = invoice.ProductInformation.Currency,
|
|
BuyerEmail = invoice.BuyerInformation?.BuyerEmail
|
|
};
|
|
|
|
exportList.Add(target);
|
|
}
|
|
|
|
exportList = exportList.OrderBy(a => a.ReceivedDate).ToList();
|
|
|
|
return exportList;
|
|
}
|
|
}
|
|
|
|
public class ExportInvoiceHolder
|
|
{
|
|
public DateTime ReceivedDate { get; set; }
|
|
public string StoreId { get; set; }
|
|
public string OrderId { get; set; }
|
|
public string InvoiceId { get; set; }
|
|
public DateTime InvoiceCreatedDate { get; set; }
|
|
public DateTime InvoiceExpirationDate { get; set; }
|
|
public DateTime InvoiceMonitoringDate { get; set; }
|
|
|
|
public string PaymentId { get; set; }
|
|
public string Destination { get; set; }
|
|
public string PaymentType { get; set; }
|
|
public string CryptoCode { get; set; }
|
|
public string Paid { get; set; }
|
|
public string NetworkFee { get; set; }
|
|
public decimal ConversionRate { get; set; }
|
|
public string PaidCurrency { get; set; }
|
|
public string InvoiceCurrency { get; set; }
|
|
public decimal InvoiceDue { get; set; }
|
|
public decimal InvoicePrice { get; set; }
|
|
public string InvoiceItemCode { get; set; }
|
|
public string InvoiceItemDesc { get; set; }
|
|
public string InvoiceFullStatus { get; set; }
|
|
public string InvoiceStatus { get; set; }
|
|
public string InvoiceExceptionStatus { get; set; }
|
|
public string BuyerEmail { get; set; }
|
|
}
|
|
}
|