From 664b920a397d51a83df41e863a196bc27bc23b4f Mon Sep 17 00:00:00 2001 From: Andrew Camilleri Date: Sat, 24 Aug 2019 16:10:13 +0200 Subject: [PATCH] Make invoice payments view modular per payment handler (#991) --- .../Controllers/InvoiceController.UI.cs | 47 +------ .../InvoicingModels/InvoiceDetailsModel.cs | 66 ++++------ BTCPayServer/Payments/PaymentTypes.Bitcoin.cs | 1 + .../Payments/PaymentTypes.Lightning.cs | 1 + BTCPayServer/Payments/PaymentTypes.cs | 1 + .../Invoice/InvoicePaymentsPartial.cshtml | 117 +++++------------- .../Shared/ViewBitcoinLikePaymentData.cshtml | 66 ++++++++++ .../ViewLightningLikePaymentData.cshtml | 42 +++++++ 8 files changed, 175 insertions(+), 166 deletions(-) create mode 100644 BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml create mode 100644 BTCPayServer/Views/Shared/ViewLightningLikePaymentData.cshtml diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index e84b66aa9..0cf675209 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -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; } diff --git a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs index 1c1af53ec..36e5e044d 100644 --- a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs +++ b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs @@ -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,39 +49,7 @@ 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 { get; set; @@ -73,14 +64,6 @@ namespace BTCPayServer.Models.InvoicingModels get; set; } = new List(); - public List OnChainPayments { get; set; } = new List(); - public List OffChainPayments { get; set; } = new List(); - 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 Events { get; internal set; } public string NotificationEmail { get; internal set; } public Dictionary PosData { get; set; } + public List Payments { get; set; } } } diff --git a/BTCPayServer/Payments/PaymentTypes.Bitcoin.cs b/BTCPayServer/Payments/PaymentTypes.Bitcoin.cs index a2d631874..7e4729c85 100644 --- a/BTCPayServer/Payments/PaymentTypes.Bitcoin.cs +++ b/BTCPayServer/Payments/PaymentTypes.Bitcoin.cs @@ -56,5 +56,6 @@ namespace BTCPayServer.Payments return null; return string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, txId); } + public override string InvoiceViewPaymentPartialName { get; } = "ViewBitcoinLikePaymentData"; } } diff --git a/BTCPayServer/Payments/PaymentTypes.Lightning.cs b/BTCPayServer/Payments/PaymentTypes.Lightning.cs index 2f42c6157..71805c03d 100644 --- a/BTCPayServer/Payments/PaymentTypes.Lightning.cs +++ b/BTCPayServer/Payments/PaymentTypes.Lightning.cs @@ -39,5 +39,6 @@ namespace BTCPayServer.Payments { return null; } + public override string InvoiceViewPaymentPartialName { get; } = "ViewLightningLikePaymentData"; } } diff --git a/BTCPayServer/Payments/PaymentTypes.cs b/BTCPayServer/Payments/PaymentTypes.cs index 1203401c1..375d17e9c 100644 --- a/BTCPayServer/Payments/PaymentTypes.cs +++ b/BTCPayServer/Payments/PaymentTypes.cs @@ -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; } } } diff --git a/BTCPayServer/Views/Invoice/InvoicePaymentsPartial.cshtml b/BTCPayServer/Views/Invoice/InvoicePaymentsPartial.cshtml index 20ffba212..0c4c7455d 100644 --- a/BTCPayServer/Views/Invoice/InvoicePaymentsPartial.cshtml +++ b/BTCPayServer/Views/Invoice/InvoicePaymentsPartial.cshtml @@ -1,100 +1,49 @@ @model InvoiceDetailsModel +@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary

Paid summary

- - - - - - - @if (Model.StatusException == InvoiceExceptionStatus.PaidOver) - { - - } - + + + + + + + @if (Model.StatusException == InvoiceExceptionStatus.PaidOver) + { + + } + - @foreach (var payment in Model.CryptoPayments) - { - - - - - - - @if (Model.StatusException == InvoiceExceptionStatus.PaidOver) - { - - } - - } + @foreach (var payment in Model.CryptoPayments) + { + + + + + + + @if (Model.StatusException == InvoiceExceptionStatus.PaidOver) + { + + } + + }
Payment methodAddressRatePaidDueOverpaid
Payment methodAddressRatePaidDueOverpaid
@payment.PaymentMethod - @payment.Address - @payment.Rate@payment.Paid@payment.Due@payment.Overpaid
@payment.PaymentMethod + @payment.Address + @payment.Rate@payment.Paid@payment.Due@payment.Overpaid
-@if (Model.OnChainPayments.Count > 0) -{ -
-
-

On-Chain payments

- - - - - - - - - - - @foreach (var payment in Model.OnChainPayments) - { - - - - - - - } - -
CryptoDeposit addressTransaction IdConfirmations
@payment.Crypto@payment.DepositAddress - - @payment.Confirmations
-
-
+@{ + var grouped = Model.Payments.GroupBy(payment => payment.GetPaymentMethodId().PaymentType); + } -@if (Model.OffChainPayments.Count > 0) +@foreach (var paymentGroup in grouped) { -
-
-

Off-Chain payments

- - - - - - - - - @foreach (var payment in Model.OffChainPayments) - { - - - - - } - -
CryptoBOLT11
@payment.Crypto
@payment.BOLT11
-
-
+ } diff --git a/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml b/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml new file mode 100644 index 000000000..79ecfb538 --- /dev/null +++ b/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml @@ -0,0 +1,66 @@ +@using System.Globalization +@using BTCPayServer.Payments +@using BTCPayServer.Payments.Bitcoin +@model IEnumerable + +@{ + 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()) +{ +
+
+

On-Chain payments

+ + + + + + + + + + + @foreach (var payment in onchainPayments) + { + + + + + + + } + +
CryptoDeposit addressTransaction IdConfirmations
@payment.Crypto@payment.DepositAddress + + @payment.Confirmations
+
+
+} diff --git a/BTCPayServer/Views/Shared/ViewLightningLikePaymentData.cshtml b/BTCPayServer/Views/Shared/ViewLightningLikePaymentData.cshtml new file mode 100644 index 000000000..d59a1d277 --- /dev/null +++ b/BTCPayServer/Views/Shared/ViewLightningLikePaymentData.cshtml @@ -0,0 +1,42 @@ +@using BTCPayServer.Payments +@using BTCPayServer.Payments.Lightning +@model IEnumerable + +@{ + 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()) +{ +
+
+

Off-Chain payments

+ + + + + + + + + @foreach (var payment in offchainPayments) + { + + + + + } + +
CryptoBOLT11
@payment.Crypto
@payment.BOLT11
+
+
+}