mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Add page for viewing the Invoice details
This commit is contained in:
@@ -108,7 +108,7 @@ namespace BTCPayServer.Tests
|
||||
_Host.Start();
|
||||
Runtime = (BTCPayServerRuntime)_Host.Services.GetService(typeof(BTCPayServerRuntime));
|
||||
var watcher = (InvoiceWatcher)_Host.Services.GetService(typeof(InvoiceWatcher));
|
||||
watcher.PollInterval = TimeSpan.FromMilliseconds(50);
|
||||
watcher.PollInterval = TimeSpan.FromMilliseconds(500);
|
||||
}
|
||||
|
||||
public BTCPayServerRuntime Runtime
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<Version>1.0.0.8</Version>
|
||||
<Version>1.0.0.9</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Build\dockerfiles\**" />
|
||||
|
||||
@@ -20,6 +20,77 @@ namespace BTCPayServer.Controllers
|
||||
public partial class InvoiceController
|
||||
{
|
||||
|
||||
[HttpPost]
|
||||
[Route("invoices/{invoiceId}")]
|
||||
public async Task<IActionResult> Invoice(string invoiceId, string command)
|
||||
{
|
||||
if(command == "refresh")
|
||||
{
|
||||
await _Watcher.WatchAsync(invoiceId, true);
|
||||
}
|
||||
StatusMessage = "Invoice is state is being refreshed, please refresh the page soon...";
|
||||
return RedirectToAction(nameof(Invoice), new
|
||||
{
|
||||
invoiceId = invoiceId
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("invoices/{invoiceId}")]
|
||||
public async Task<IActionResult> Invoice(string invoiceId)
|
||||
{
|
||||
var invoice = (await _InvoiceRepository.GetInvoices(new InvoiceQuery()
|
||||
{
|
||||
UserId = GetUserId(),
|
||||
InvoiceId = invoiceId
|
||||
})).FirstOrDefault();
|
||||
if(invoice == null)
|
||||
return NotFound();
|
||||
|
||||
var dto = invoice.EntityToDTO();
|
||||
var store = await _StoreRepository.FindStore(invoice.StoreId);
|
||||
InvoiceDetailsModel model = new InvoiceDetailsModel()
|
||||
{
|
||||
StoreName = store.StoreName,
|
||||
StoreLink = Url.Action(nameof(StoresController.UpdateStore), "Stores", new { storeId = store.Id }),
|
||||
Id = invoice.Id,
|
||||
Status = invoice.Status,
|
||||
RefundEmail = invoice.RefundMail,
|
||||
CreatedDate = invoice.InvoiceTime,
|
||||
ExpirationDate = invoice.ExpirationTime,
|
||||
OrderId = invoice.OrderId,
|
||||
BuyerInformation = invoice.BuyerInformation,
|
||||
Rate = invoice.Rate,
|
||||
Fiat = dto.Price + " " + dto.Currency,
|
||||
BTC = invoice.GetTotalCryptoDue().ToString() + " BTC",
|
||||
BTCDue = invoice.GetCryptoDue().ToString() + " BTC",
|
||||
BTCPaid = invoice.GetTotalPaid().ToString() + " BTC",
|
||||
NetworkFee = invoice.GetNetworkFee().ToString() + " BTC",
|
||||
NotificationUrl = invoice.NotificationURL,
|
||||
ProductInformation = invoice.ProductInformation,
|
||||
BitcoinAddress = invoice.DepositAddress,
|
||||
PaymentUrl = dto.PaymentUrls.BIP72
|
||||
};
|
||||
|
||||
var payments = invoice
|
||||
.Payments
|
||||
.Select(async payment =>
|
||||
{
|
||||
var m = new InvoiceDetailsModel.Payment();
|
||||
m.DepositAddress = payment.Output.ScriptPubKey.GetDestinationAddress(_Network);
|
||||
m.Confirmations = (await _Explorer.GetTransactionAsync(payment.Outpoint.Hash))?.Confirmations ?? 0;
|
||||
m.TransactionId = payment.Outpoint.Hash.ToString();
|
||||
m.ReceivedTime = payment.ReceivedTime;
|
||||
m.TransactionLink = _Network == Network.Main ? $"https://www.smartbit.com.au/tx/{m.TransactionId}" : $"https://testnet.smartbit.com.au/{m.TransactionId}";
|
||||
return m;
|
||||
})
|
||||
.ToArray();
|
||||
await Task.WhenAll(payments);
|
||||
model.Payments = payments.Select(p => p.GetAwaiter().GetResult()).ToList();
|
||||
model.StatusMessage = StatusMessage;
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("i/{invoiceId}")]
|
||||
[AcceptMediaTypeConstraint("application/bitcoin-paymentrequest", false)]
|
||||
|
||||
@@ -37,6 +37,7 @@ using BTCPayServer.Validations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer.Controllers
|
||||
{
|
||||
@@ -51,6 +52,7 @@ namespace BTCPayServer.Controllers
|
||||
Network _Network;
|
||||
UserManager<ApplicationUser> _UserManager;
|
||||
IFeeProvider _FeeProvider;
|
||||
ExplorerClient _Explorer;
|
||||
|
||||
public InvoiceController(
|
||||
Network network,
|
||||
@@ -61,8 +63,10 @@ namespace BTCPayServer.Controllers
|
||||
IRateProvider rateProvider,
|
||||
StoreRepository storeRepository,
|
||||
InvoiceWatcher watcher,
|
||||
ExplorerClient explorerClient,
|
||||
IFeeProvider feeProvider)
|
||||
{
|
||||
_Explorer = explorerClient ?? throw new ArgumentNullException(nameof(explorerClient));
|
||||
_StoreRepository = storeRepository ?? throw new ArgumentNullException(nameof(storeRepository));
|
||||
_Network = network ?? throw new ArgumentNullException(nameof(network));
|
||||
_TokenRepository = tokenRepository ?? throw new ArgumentNullException(nameof(tokenRepository));
|
||||
|
||||
146
BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs
Normal file
146
BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Models.InvoicingModels
|
||||
{
|
||||
public class InvoiceDetailsModel
|
||||
{
|
||||
public class Payment
|
||||
{
|
||||
public int 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 string StatusMessage
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public String Id
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<Payment> Payments
|
||||
{
|
||||
get; set;
|
||||
} = new List<Payment>();
|
||||
|
||||
public string Status
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public DateTimeOffset CreatedDate
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public DateTimeOffset ExpirationDate
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string OrderId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string RefundEmail
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public BuyerInformation BuyerInformation
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public object StoreName
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
public string StoreLink
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public double Rate
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
public string NotificationUrl
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
public string Fiat
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string BTC
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string BTCDue
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string BTCPaid
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
public String NetworkFee
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
public ProductInformation ProductInformation
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
public BitcoinAddress BitcoinAddress
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
public string PaymentUrl
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,6 +302,12 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
var str = JsonConvert.SerializeObject(from);
|
||||
JsonConvert.PopulateObject(str, dest);
|
||||
}
|
||||
|
||||
public Money GetNetworkFee()
|
||||
{
|
||||
var item = Calculate();
|
||||
return TxFee * item.TxCount;
|
||||
}
|
||||
}
|
||||
|
||||
public class PaymentEntity
|
||||
|
||||
@@ -65,12 +65,17 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RemovePendingInvoice(string invoiceId)
|
||||
public async Task<bool> RemovePendingInvoice(string invoiceId)
|
||||
{
|
||||
using(var ctx = _ContextFactory.CreateContext())
|
||||
{
|
||||
ctx.PendingInvoices.Remove(new PendingInvoiceData() { Id = invoiceId });
|
||||
try
|
||||
{
|
||||
await ctx.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
catch(DbUpdateException) { return false; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,12 +212,16 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
{
|
||||
using(var context = _ContextFactory.CreateContext())
|
||||
{
|
||||
|
||||
IQueryable<InvoiceData> query = context
|
||||
.Invoices
|
||||
.Include(o => o.Payments)
|
||||
.Include(o => o.RefundAddresses);
|
||||
|
||||
if(!string.IsNullOrEmpty(queryObject.InvoiceId))
|
||||
{
|
||||
query = query.Where(i => i.Id == queryObject.InvoiceId);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(queryObject.StoreId))
|
||||
{
|
||||
query = query.Where(i => i.StoreDataId == queryObject.StoreId);
|
||||
@@ -380,5 +389,10 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string InvoiceId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
BTCPayWallet wallet,
|
||||
InvoiceNotificationManager notificationManager)
|
||||
{
|
||||
LongPollingMode = explorerClient.Network == Network.RegTest;
|
||||
PollInterval = explorerClient.Network == Network.RegTest ? TimeSpan.FromSeconds(10.0) : TimeSpan.FromMinutes(1.0);
|
||||
_Wallet = wallet ?? throw new ArgumentNullException(nameof(wallet));
|
||||
_ExplorerClient = explorerClient ?? throw new ArgumentNullException(nameof(explorerClient));
|
||||
_DerivationFactory = new DerivationStrategyFactory(_ExplorerClient.Network);
|
||||
@@ -36,6 +38,11 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
_NotificationManager = notificationManager ?? throw new ArgumentNullException(nameof(notificationManager));
|
||||
}
|
||||
|
||||
public bool LongPollingMode
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public async Task NotifyReceived(Script scriptPubKey)
|
||||
{
|
||||
var invoice = await _Wallet.GetInvoiceId(scriptPubKey);
|
||||
@@ -52,7 +59,6 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
|
||||
private async Task UpdateInvoice(string invoiceId)
|
||||
{
|
||||
Logs.PayServer.LogInformation("Updating invoice " + invoiceId);
|
||||
UTXOChanges changes = null;
|
||||
while(true)
|
||||
{
|
||||
@@ -75,7 +81,7 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
|
||||
if(invoice.Status == "complete" || invoice.Status == "invalid")
|
||||
{
|
||||
await _InvoiceRepository.RemovePendingInvoice(invoice.Id).ConfigureAwait(false);
|
||||
if(await _InvoiceRepository.RemovePendingInvoice(invoice.Id).ConfigureAwait(false))
|
||||
Logs.PayServer.LogInformation("Stopped watching invoice " + invoiceId);
|
||||
break;
|
||||
}
|
||||
@@ -98,23 +104,18 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
|
||||
private async Task<(bool NeedSave, UTXOChanges Changes)> UpdateInvoice(UTXOChanges changes, InvoiceEntity invoice)
|
||||
{
|
||||
if(invoice.Status == "invalid")
|
||||
{
|
||||
return (false, changes);
|
||||
}
|
||||
bool needSave = false;
|
||||
bool shouldWait = true;
|
||||
|
||||
if(invoice.ExpirationTime < DateTimeOffset.UtcNow && (invoice.Status == "new" || invoice.Status == "paidPartial"))
|
||||
if(invoice.Status != "invalid" && invoice.ExpirationTime < DateTimeOffset.UtcNow && (invoice.Status == "new" || invoice.Status == "paidPartial"))
|
||||
{
|
||||
needSave = true;
|
||||
invoice.Status = "invalid";
|
||||
}
|
||||
|
||||
if(invoice.Status == "new" || invoice.Status == "paidPartial")
|
||||
if(invoice.Status == "invalid" || invoice.Status == "new" || invoice.Status == "paidPartial")
|
||||
{
|
||||
var strategy = _DerivationFactory.Parse(invoice.DerivationStrategy);
|
||||
changes = await _ExplorerClient.SyncAsync(strategy, changes, true, _Cts.Token).ConfigureAwait(false);
|
||||
changes = await _ExplorerClient.SyncAsync(strategy, changes, !LongPollingMode, _Cts.Token).ConfigureAwait(false);
|
||||
|
||||
var utxos = changes.Confirmed.UTXOs.Concat(changes.Unconfirmed.UTXOs).ToArray();
|
||||
var invoiceIds = utxos.Select(u => _Wallet.GetInvoiceId(u.Output.ScriptPubKey)).ToArray();
|
||||
@@ -123,8 +124,6 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
.Where((u, i) => invoiceIds[i].GetAwaiter().GetResult() == invoice.Id)
|
||||
.ToArray();
|
||||
|
||||
shouldWait = false; //should not wait, Sync is blocking call
|
||||
|
||||
List<Coin> receivedCoins = new List<Coin>();
|
||||
foreach(var received in utxos)
|
||||
if(received.Output.ScriptPubKey == invoice.DepositAddress.ScriptPubKey)
|
||||
@@ -218,23 +217,30 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
}
|
||||
}
|
||||
|
||||
shouldWait = shouldWait && !needSave;
|
||||
|
||||
if(shouldWait)
|
||||
{
|
||||
await Task.Delay(PollInterval, _Cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return (needSave, changes);
|
||||
}
|
||||
|
||||
|
||||
TimeSpan _PollInterval;
|
||||
public TimeSpan PollInterval
|
||||
{
|
||||
get; set;
|
||||
} = TimeSpan.FromSeconds(10);
|
||||
|
||||
public async Task WatchAsync(string invoiceId)
|
||||
get
|
||||
{
|
||||
return _PollInterval;
|
||||
}
|
||||
set
|
||||
{
|
||||
_PollInterval = value;
|
||||
if(_UpdatePendingInvoices != null)
|
||||
{
|
||||
_UpdatePendingInvoices.Change(0, (int)value.TotalMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task WatchAsync(string invoiceId, bool singleShot = false)
|
||||
{
|
||||
if(!singleShot)
|
||||
await _InvoiceRepository.AddPendingInvoice(invoiceId).ConfigureAwait(false);
|
||||
_WatchRequests.Add(invoiceId);
|
||||
}
|
||||
@@ -264,7 +270,7 @@ namespace BTCPayServer.Servcices.Invoices
|
||||
{
|
||||
_WatchRequests.Add(pending);
|
||||
}
|
||||
}, null, 0, (int)TimeSpan.FromMinutes(1.0).TotalMilliseconds);
|
||||
}, null, 0, (int)PollInterval.TotalMilliseconds);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
187
BTCPayServer/Views/Invoice/Invoice.cshtml
Normal file
187
BTCPayServer/Views/Invoice/Invoice.cshtml
Normal file
@@ -0,0 +1,187 @@
|
||||
@model InvoiceDetailsModel
|
||||
@{
|
||||
ViewData["Title"] = "Invoice " + Model.Id;
|
||||
}
|
||||
|
||||
<section>
|
||||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-center">
|
||||
@Html.Partial("_StatusMessage", Model.StatusMessage)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-center">
|
||||
<h2 class="section-heading">@ViewData["Title"]</h2>
|
||||
<hr class="primary">
|
||||
<p>Invoice details</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h3>Information</h3>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Store</th>
|
||||
<td><a href="@Model.StoreLink">@Model.StoreName</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<td>@Model.Id</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Created date</th>
|
||||
<td>@Model.CreatedDate</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Expiration date</th>
|
||||
<td>@Model.CreatedDate</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<td>@Model.Status</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Refund email</th>
|
||||
<td>@Model.RefundEmail</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Order Id</th>
|
||||
<td>@Model.OrderId</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Rate</th>
|
||||
<td>@Model.Rate</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total fiat due</th>
|
||||
<td>@Model.Fiat</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Network Fee</th>
|
||||
<td>@Model.NetworkFee</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total crypto due</th>
|
||||
<td>@Model.BTC</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Crypto due</th>
|
||||
<td>@Model.BTCDue</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Crypto paid</th>
|
||||
<td>@Model.BTCPaid</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Notification Url</th>
|
||||
<td>@Model.NotificationUrl</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Payment address</th>
|
||||
<td>@Model.BitcoinAddress</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Payment Url</th>
|
||||
<td><a href="@Model.PaymentUrl">@Model.PaymentUrl</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<h3>Buyer information</h3>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Name
|
||||
<th>
|
||||
<td>@Model.BuyerInformation.BuyerName</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<td>@Model.BuyerInformation.BuyerEmail</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Phone</th>
|
||||
<td>@Model.BuyerInformation.BuyerPhone</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Address 1</th>
|
||||
<td>@Model.BuyerInformation.BuyerAddress1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Address 2</th>
|
||||
<td>@Model.BuyerInformation.BuyerAddress2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>City</th>
|
||||
<td>@Model.BuyerInformation.BuyerCity</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>State</th>
|
||||
<td>@Model.BuyerInformation.BuyerState</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Country</th>
|
||||
<td>@Model.BuyerInformation.BuyerCountry</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Zip</th>
|
||||
<td>@Model.BuyerInformation.BuyerZip</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>Product information</h3>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Item code</th>
|
||||
<td>@Model.ProductInformation.ItemCode</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Item Description</th>
|
||||
<td>@Model.ProductInformation.ItemDesc</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Price</th>
|
||||
<td>@Model.ProductInformation.Price @Model.ProductInformation.Currency</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Payments</h3>
|
||||
<div class="form-group">
|
||||
<form asp-action="Invoice" method="post">
|
||||
<button type="submit" name="command" class="btn btn-success" value="refresh" title="Refresh State">
|
||||
Refresh state
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<table class="table">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Deposit address</th>
|
||||
<th>Transaction Id</th>
|
||||
<th>Confirmations</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach(var payment in Model.Payments)
|
||||
{
|
||||
<tr>
|
||||
<td>@payment.ReceivedTime</td>
|
||||
<td>@payment.DepositAddress</td>
|
||||
<td><a href="@payment.TransactionLink" target="_blank">@payment.TransactionId</a></td>
|
||||
<td>@payment.Confirmations</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -50,7 +50,7 @@
|
||||
<td>@invoice.InvoiceId</td>
|
||||
<td>@invoice.Status</td>
|
||||
<td>@invoice.AmountCurrency</td>
|
||||
<td><a asp-action="Checkout" asp-route-invoiceId="@invoice.InvoiceId">Checkout</a></td>
|
||||
<td><a asp-action="Checkout" asp-route-invoiceId="@invoice.InvoiceId">Checkout</a> - <a asp-action="Invoice" asp-route-invoiceId="@invoice.InvoiceId">Details</a></td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
|
||||
Reference in New Issue
Block a user