mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Make invoice payments view modular per payment handler (#991)
This commit is contained in:
committed by
Nicolas Dorier
parent
7ea3312534
commit
664b920a39
@@ -72,7 +72,8 @@ namespace BTCPayServer.Controllers
|
||||
StatusException = invoice.ExceptionStatus,
|
||||
Events = invoice.Events,
|
||||
PosData = PosDataParser.ParsePosData(invoice.PosData),
|
||||
StatusMessage = StatusMessage
|
||||
StatusMessage = StatusMessage,
|
||||
|
||||
};
|
||||
|
||||
model.Addresses = invoice.HistoricalAddresses.Select(h =>
|
||||
@@ -85,20 +86,21 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
var details = InvoicePopulatePayments(invoice);
|
||||
model.CryptoPayments = details.CryptoPayments;
|
||||
model.OnChainPayments = details.OnChainPayments;
|
||||
model.OffChainPayments = details.OffChainPayments;
|
||||
model.Payments = details.Payments;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
private InvoiceDetailsModel InvoicePopulatePayments(InvoiceEntity invoice)
|
||||
{
|
||||
var model = new InvoiceDetailsModel();
|
||||
|
||||
model.Payments = invoice.GetPayments();
|
||||
foreach (var data in invoice.GetPaymentMethods())
|
||||
{
|
||||
var accounting = data.Calculate();
|
||||
var paymentMethodId = data.GetId();
|
||||
var cryptoPayment = new InvoiceDetailsModel.CryptoPayment();
|
||||
|
||||
cryptoPayment.PaymentMethodId = paymentMethodId;
|
||||
cryptoPayment.PaymentMethod = paymentMethodId.ToPrettyString();
|
||||
cryptoPayment.Due = _CurrencyNameTable.DisplayFormatCurrency(accounting.Due.ToDecimal(MoneyUnit.BTC), paymentMethodId.CryptoCode);
|
||||
cryptoPayment.Paid = _CurrencyNameTable.DisplayFormatCurrency(accounting.CryptoPaid.ToDecimal(MoneyUnit.BTC), paymentMethodId.CryptoCode);
|
||||
@@ -108,43 +110,6 @@ namespace BTCPayServer.Controllers
|
||||
cryptoPayment.Rate = ExchangeRate(data);
|
||||
model.CryptoPayments.Add(cryptoPayment);
|
||||
}
|
||||
|
||||
foreach (var payment in invoice.GetPayments())
|
||||
{
|
||||
var paymentData = payment.GetCryptoPaymentData();
|
||||
//TODO: abstract
|
||||
if (paymentData is Payments.Bitcoin.BitcoinLikePaymentData onChainPaymentData)
|
||||
{
|
||||
var m = new InvoiceDetailsModel.Payment();
|
||||
m.Crypto = payment.GetPaymentMethodId().CryptoCode;
|
||||
m.DepositAddress = onChainPaymentData.GetDestination();
|
||||
|
||||
int confirmationCount = onChainPaymentData.ConfirmationCount;
|
||||
if (confirmationCount >= payment.Network.MaxTrackedConfirmation)
|
||||
{
|
||||
m.Confirmations = "At least " + (payment.Network.MaxTrackedConfirmation);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.Confirmations = confirmationCount.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
m.TransactionId = onChainPaymentData.Outpoint.Hash.ToString();
|
||||
m.ReceivedTime = payment.ReceivedTime;
|
||||
m.TransactionLink = string.Format(CultureInfo.InvariantCulture, payment.Network.BlockExplorerLink, m.TransactionId);
|
||||
m.Replaced = !payment.Accounted;
|
||||
model.OnChainPayments.Add(m);
|
||||
}
|
||||
else
|
||||
{
|
||||
var lightningPaymentData = (LightningLikePaymentData)paymentData;
|
||||
model.OffChainPayments.Add(new InvoiceDetailsModel.OffChainPayment()
|
||||
{
|
||||
Crypto = payment.Network.CryptoCode,
|
||||
BOLT11 = lightningPaymentData.BOLT11
|
||||
});
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,32 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using NBitcoin;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Models.InvoicingModels
|
||||
{
|
||||
public class OnchainPaymentViewModel
|
||||
{
|
||||
public string Crypto { get; set; }
|
||||
public string Confirmations { get; set; }
|
||||
public BitcoinAddress DepositAddress { get; set; }
|
||||
public string Amount { get; set; }
|
||||
public string TransactionId { get; set; }
|
||||
public DateTimeOffset ReceivedTime { get; set; }
|
||||
public string TransactionLink { get; set; }
|
||||
|
||||
public bool Replaced { get; set; }
|
||||
}
|
||||
|
||||
public class OffChainPaymentViewModel
|
||||
{
|
||||
public string Crypto { get; set; }
|
||||
public string BOLT11 { get; set; }
|
||||
}
|
||||
|
||||
public class InvoiceDetailsModel
|
||||
{
|
||||
public class CryptoPayment
|
||||
@@ -19,6 +40,8 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||
public string Rate { get; internal set; }
|
||||
public string PaymentUrl { get; internal set; }
|
||||
public string Overpaid { get; set; }
|
||||
[JsonIgnore]
|
||||
public PaymentMethodId PaymentMethodId { get; set; }
|
||||
}
|
||||
public class AddressModel
|
||||
{
|
||||
@@ -26,38 +49,6 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||
public string Destination { get; set; }
|
||||
public bool Current { get; set; }
|
||||
}
|
||||
public class Payment
|
||||
{
|
||||
public string Crypto { get; set; }
|
||||
public string Confirmations
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public BitcoinAddress DepositAddress
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string Amount
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string TransactionId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public DateTimeOffset ReceivedTime
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
public string TransactionLink
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool Replaced { get; set; }
|
||||
}
|
||||
|
||||
public string StatusMessage
|
||||
{
|
||||
@@ -73,14 +64,6 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||
get; set;
|
||||
} = new List<CryptoPayment>();
|
||||
|
||||
public List<Payment> OnChainPayments { get; set; } = new List<Payment>();
|
||||
public List<OffChainPayment> OffChainPayments { get; set; } = new List<OffChainPayment>();
|
||||
public class OffChainPayment
|
||||
{
|
||||
public string Crypto { get; set; }
|
||||
public string BOLT11 { get; set; }
|
||||
}
|
||||
|
||||
public string State
|
||||
{
|
||||
get; set;
|
||||
@@ -145,5 +128,6 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||
public List<Data.InvoiceEventData> Events { get; internal set; }
|
||||
public string NotificationEmail { get; internal set; }
|
||||
public Dictionary<string, object> PosData { get; set; }
|
||||
public List<PaymentEntity> Payments { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,5 +56,6 @@ namespace BTCPayServer.Payments
|
||||
return null;
|
||||
return string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, txId);
|
||||
}
|
||||
public override string InvoiceViewPaymentPartialName { get; } = "ViewBitcoinLikePaymentData";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,5 +39,6 @@ namespace BTCPayServer.Payments
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override string InvoiceViewPaymentPartialName { get; } = "ViewLightningLikePaymentData";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,5 +61,6 @@ namespace BTCPayServer.Payments
|
||||
public abstract ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value);
|
||||
|
||||
public abstract string GetTransactionLink(BTCPayNetworkBase network, string txId);
|
||||
public abstract string InvoiceViewPaymentPartialName { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@model InvoiceDetailsModel
|
||||
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12 invoice-payments">
|
||||
@@ -38,63 +39,11 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@if (Model.OnChainPayments.Count > 0)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-md-12 invoice-payments">
|
||||
<h3>On-Chain payments</h3>
|
||||
<table class="table table-sm table-responsive-lg">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Crypto</th>
|
||||
<th>Deposit address</th>
|
||||
<th>Transaction Id</th>
|
||||
<th class="text-right">Confirmations</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var payment in Model.OnChainPayments)
|
||||
{
|
||||
<tr class="@(payment.Replaced ? "linethrough" : "")" >
|
||||
<td>@payment.Crypto</td>
|
||||
<td>@payment.DepositAddress</td>
|
||||
<td>
|
||||
<div class="wraptextAuto">
|
||||
<a href="@payment.TransactionLink" target="_blank">
|
||||
@payment.TransactionId
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-right">@payment.Confirmations</td>
|
||||
</tr>
|
||||
@{
|
||||
var grouped = Model.Payments.GroupBy(payment => payment.GetPaymentMethodId().PaymentType);
|
||||
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (Model.OffChainPayments.Count > 0)
|
||||
@foreach (var paymentGroup in grouped)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-md-12 invoice-payments">
|
||||
<h3>Off-Chain payments</h3>
|
||||
<table class="table table-sm table-responsive-md">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th class="firstCol">Crypto</th>
|
||||
<th>BOLT11</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var payment in Model.OffChainPayments)
|
||||
{
|
||||
<tr>
|
||||
<td>@payment.Crypto</td>
|
||||
<td><div class="wraptextAuto">@payment.BOLT11</div></td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<partial name="@paymentGroup.Key.InvoiceViewPaymentPartialName" model="@paymentGroup.ToList()" />
|
||||
}
|
||||
|
||||
66
BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml
Normal file
66
BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml
Normal file
@@ -0,0 +1,66 @@
|
||||
@using System.Globalization
|
||||
@using BTCPayServer.Payments
|
||||
@using BTCPayServer.Payments.Bitcoin
|
||||
@model IEnumerable<BTCPayServer.Services.Invoices.PaymentEntity>
|
||||
|
||||
@{
|
||||
var onchainPayments = Model.Where(entity => entity.GetPaymentMethodId().PaymentType == BitcoinPaymentType.Instance).Select(payment =>
|
||||
{
|
||||
var m = new OnchainPaymentViewModel();
|
||||
var onChainPaymentData = payment.GetCryptoPaymentData() as BitcoinLikePaymentData;
|
||||
m.Crypto = payment.GetPaymentMethodId().CryptoCode;
|
||||
m.DepositAddress = onChainPaymentData.GetDestination();
|
||||
|
||||
int confirmationCount = onChainPaymentData.ConfirmationCount;
|
||||
if (confirmationCount >= payment.Network.MaxTrackedConfirmation)
|
||||
{
|
||||
m.Confirmations = "At least " + (payment.Network.MaxTrackedConfirmation);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.Confirmations = confirmationCount.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
m.TransactionId = onChainPaymentData.Outpoint.Hash.ToString();
|
||||
m.ReceivedTime = payment.ReceivedTime;
|
||||
m.TransactionLink = string.Format(CultureInfo.InvariantCulture, payment.Network.BlockExplorerLink, m.TransactionId);
|
||||
m.Replaced = !payment.Accounted;
|
||||
return m;
|
||||
});
|
||||
}
|
||||
|
||||
@if (onchainPayments.Any())
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-md-12 invoice-payments">
|
||||
<h3>On-Chain payments</h3>
|
||||
<table class="table table-sm table-responsive-lg">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Crypto</th>
|
||||
<th>Deposit address</th>
|
||||
<th>Transaction Id</th>
|
||||
<th class="text-right">Confirmations</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var payment in onchainPayments)
|
||||
{
|
||||
<tr class="@(payment.Replaced ? "linethrough" : "")" >
|
||||
<td>@payment.Crypto</td>
|
||||
<td>@payment.DepositAddress</td>
|
||||
<td>
|
||||
<div class="wraptextAuto">
|
||||
<a href="@payment.TransactionLink" target="_blank">
|
||||
@payment.TransactionId
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-right">@payment.Confirmations</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
@using BTCPayServer.Payments
|
||||
@using BTCPayServer.Payments.Lightning
|
||||
@model IEnumerable<BTCPayServer.Services.Invoices.PaymentEntity>
|
||||
|
||||
@{
|
||||
var offchainPayments = Model.Where(entity => entity.GetPaymentMethodId().PaymentType == LightningPaymentType.Instance).Select(payment =>
|
||||
{
|
||||
var offChainPaymentData = payment.GetCryptoPaymentData() as LightningLikePaymentData;
|
||||
return new OffChainPaymentViewModel()
|
||||
{
|
||||
Crypto = payment.Network.CryptoCode,
|
||||
BOLT11 = offChainPaymentData.BOLT11
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@if (offchainPayments.Any())
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-md-12 invoice-payments">
|
||||
<h3>Off-Chain payments</h3>
|
||||
<table class="table table-sm table-responsive-md">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th class="firstCol">Crypto</th>
|
||||
<th>BOLT11</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var payment in offchainPayments)
|
||||
{
|
||||
<tr>
|
||||
<td>@payment.Crypto</td>
|
||||
<td><div class="wraptextAuto">@payment.BOLT11</div></td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
Reference in New Issue
Block a user