Make invoice payments view modular per payment handler (#991)

This commit is contained in:
Andrew Camilleri
2019-08-24 16:10:13 +02:00
committed by Nicolas Dorier
parent 7ea3312534
commit 664b920a39
8 changed files with 175 additions and 166 deletions

View File

@@ -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;
}

View File

@@ -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; }
}
}

View File

@@ -56,5 +56,6 @@ namespace BTCPayServer.Payments
return null;
return string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, txId);
}
public override string InvoiceViewPaymentPartialName { get; } = "ViewBitcoinLikePaymentData";
}
}

View File

@@ -39,5 +39,6 @@ namespace BTCPayServer.Payments
{
return null;
}
public override string InvoiceViewPaymentPartialName { get; } = "ViewLightningLikePaymentData";
}
}

View File

@@ -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; }
}
}

View File

@@ -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()" />
}

View 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>
}

View File

@@ -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>
}