mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-20 13:34:37 +01:00
Add Refunds list to Invoice details page
(this is missing the refunded badge and progress as I have another PR that makes this easier to compute to show)
This commit is contained in:
parent
04c3191795
commit
29080e9d7d
5 changed files with 413 additions and 304 deletions
|
@ -93,6 +93,7 @@ namespace BTCPayServer.Controllers
|
|||
IncludeAddresses = true,
|
||||
IncludeEvents = true,
|
||||
IncludeArchived = true,
|
||||
IncludeRefunds = true,
|
||||
})).FirstOrDefault();
|
||||
if (invoice == null)
|
||||
return NotFound();
|
||||
|
@ -116,7 +117,9 @@ namespace BTCPayServer.Controllers
|
|||
ExpirationDate = invoice.ExpirationTime,
|
||||
MonitoringDate = invoice.MonitoringExpiration,
|
||||
Fiat = _CurrencyNameTable.DisplayFormatCurrency(invoice.Price, invoice.Currency),
|
||||
TaxIncluded = _CurrencyNameTable.DisplayFormatCurrency(invoice.Metadata.TaxIncluded ?? 0.0m, invoice.Currency),
|
||||
TaxIncluded = invoice.Metadata.TaxIncluded is null
|
||||
? null
|
||||
: _CurrencyNameTable.DisplayFormatCurrency(invoice.Metadata.TaxIncluded ?? 0.0m, invoice.Currency),
|
||||
NotificationUrl = invoice.NotificationURL?.AbsoluteUri,
|
||||
RedirectUrl = invoice.RedirectURL?.AbsoluteUri,
|
||||
TypedMetadata = invoice.Metadata,
|
||||
|
@ -125,6 +128,7 @@ namespace BTCPayServer.Controllers
|
|||
PosData = PosDataParser.ParsePosData(invoice.Metadata.PosData),
|
||||
Archived = invoice.Archived,
|
||||
CanRefund = CanRefund(invoiceState),
|
||||
Refunds = invoice.Refunds,
|
||||
ShowCheckout = invoice.Status == InvoiceStatusLegacy.New,
|
||||
Deliveries = (await _InvoiceRepository.GetWebhookDeliveries(invoiceId))
|
||||
.Select(c => new Models.StoreViewModels.DeliveryViewModel(c))
|
||||
|
@ -412,8 +416,8 @@ namespace BTCPayServer.Controllers
|
|||
{
|
||||
InvoiceId = new[] { invoiceId },
|
||||
UserId = GetUserId(),
|
||||
IncludeAddresses = true,
|
||||
IncludeEvents = true,
|
||||
IncludeAddresses = false,
|
||||
IncludeEvents = false,
|
||||
IncludeArchived = true,
|
||||
})).FirstOrDefault();
|
||||
if (invoice == null)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Bitcoin;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
|
@ -131,5 +132,6 @@ namespace BTCPayServer.Models.InvoicingModels
|
|||
public bool CanMarkSettled { get; set; }
|
||||
public bool CanMarkInvalid { get; set; }
|
||||
public bool CanMarkStatus => CanMarkSettled || CanMarkInvalid;
|
||||
public List<RefundData> Refunds { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -441,6 +441,8 @@ namespace BTCPayServer.Services.Invoices
|
|||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public InvoiceType Type { get; set; }
|
||||
|
||||
public List<RefundData> Refunds { get; set; }
|
||||
|
||||
public bool IsExpired()
|
||||
{
|
||||
return DateTimeOffset.UtcNow > ExpirationTime;
|
||||
|
|
|
@ -579,6 +579,10 @@ namespace BTCPayServer.Services.Invoices
|
|||
{
|
||||
entity.Events = invoice.Events.OrderBy(c => c.Timestamp).ToList();
|
||||
}
|
||||
if (invoice.Refunds != null)
|
||||
{
|
||||
entity.Refunds = invoice.Refunds.OrderBy(c => c.PullPaymentData.StartDate).ToList();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(entity.RefundMail) && string.IsNullOrEmpty(entity.Metadata.BuyerEmail))
|
||||
{
|
||||
entity.Metadata.BuyerEmail = entity.RefundMail;
|
||||
|
@ -715,6 +719,8 @@ namespace BTCPayServer.Services.Invoices
|
|||
query = query.Include(o => o.AddressInvoices);
|
||||
if (queryObject.IncludeEvents)
|
||||
query = query.Include(o => o.Events);
|
||||
if (queryObject.IncludeRefunds)
|
||||
query = query.Include(o => o.Refunds).ThenInclude(refundData => refundData.PullPaymentData);
|
||||
var data = await query.ToArrayAsync().ConfigureAwait(false);
|
||||
return data.Select(ToEntity).ToArray();
|
||||
}
|
||||
|
@ -825,5 +831,6 @@ namespace BTCPayServer.Services.Invoices
|
|||
|
||||
public bool IncludeEvents { get; set; }
|
||||
public bool IncludeArchived { get; set; } = true;
|
||||
public bool IncludeRefunds { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="RefundTitle">Issue Refund</h4>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
|
||||
<vc:icon symbol="close" />
|
||||
<vc:icon symbol="close"/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
@ -89,359 +89,453 @@
|
|||
}
|
||||
|
||||
<div class="invoice-details">
|
||||
<div class="sticky-header-setup"></div>
|
||||
<div class="sticky-header d-md-flex align-items-center justify-content-between">
|
||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||
<div class="d-flex gap-3 mt-3 mt-md-0">
|
||||
@if (Model.ShowCheckout)
|
||||
{
|
||||
<a asp-action="Checkout" class="invoice-checkout-link btn btn-primary text-nowrap" asp-route-invoiceId="@Model.Id">Checkout</a>
|
||||
}
|
||||
@if (Model.CanRefund)
|
||||
{
|
||||
<a id="IssueRefund" class="btn btn-success text-nowrap" asp-action="Refund" asp-route-invoiceId="@Model.Id" data-bs-toggle="modal" data-bs-target="#RefundModal">Issue Refund</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button href="#" class="btn btn-secondary text-nowrap" data-bs-toggle="tooltip" title="You can only refund an invoice that has been settled. Please wait for the transaction to confirm on the blockchain before attempting to refund it." disabled>Issue refund</button>
|
||||
}
|
||||
<form asp-action="ToggleArchive" asp-route-invoiceId="@Model.Id" method="post">
|
||||
<button type="submit" class="btn @(Model.Archived ? "btn-warning" : "btn btn-danger")" id="btn-archive-toggle">
|
||||
@if (Model.Archived)
|
||||
{
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="Unarchive this invoice">Unarchive</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="Archive this invoice so that it does not appear in the invoice list by default"><i class="fa fa-archive me-1"></i> Archive</span>
|
||||
}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="sticky-header-setup"></div>
|
||||
<div class="sticky-header d-md-flex align-items-center justify-content-between">
|
||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||
<div class="d-flex gap-3 mt-3 mt-md-0">
|
||||
@if (Model.ShowCheckout)
|
||||
{
|
||||
<a asp-action="Checkout" class="invoice-checkout-link btn btn-primary text-nowrap" asp-route-invoiceId="@Model.Id">Checkout</a>
|
||||
}
|
||||
@if (Model.CanRefund)
|
||||
{
|
||||
<a id="IssueRefund" class="btn btn-success text-nowrap" asp-action="Refund" asp-route-invoiceId="@Model.Id" data-bs-toggle="modal" data-bs-target="#RefundModal">Issue Refund</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button href="#" class="btn btn-secondary text-nowrap" data-bs-toggle="tooltip" title="You can only refund an invoice that has been settled. Please wait for the transaction to confirm on the blockchain before attempting to refund it." disabled>Issue refund</button>
|
||||
}
|
||||
<form asp-action="ToggleArchive" asp-route-invoiceId="@Model.Id" method="post">
|
||||
<button type="submit" class="btn @(Model.Archived ? "btn-warning" : "btn btn-danger")" id="btn-archive-toggle">
|
||||
@if (Model.Archived)
|
||||
{
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="Unarchive this invoice">Unarchive</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="Archive this invoice so that it does not appear in the invoice list by default"><i class="fa fa-archive me-1"></i> Archive</span>
|
||||
}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<partial name="_StatusMessage" />
|
||||
<partial name="_StatusMessage"/>
|
||||
|
||||
<div class="row justify-content-between">
|
||||
<div class="col-md-6">
|
||||
<h3 class="mb-3">Invoice Information</h3>
|
||||
<table class="table mb-5">
|
||||
<tr>
|
||||
<th class="fw-semibold">Store</th>
|
||||
<td><a href="@Model.StoreLink" rel="noreferrer noopener">@Model.StoreName</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Invoice Id</th>
|
||||
<td>@Model.Id</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Order Id</th>
|
||||
<td>
|
||||
@if (string.IsNullOrEmpty(Model.TypedMetadata.OrderUrl))
|
||||
<div class="row justify-content-between">
|
||||
<div class="col-md-6">
|
||||
<h3 class="mb-3">Invoice Information</h3>
|
||||
<table class="table mb-5">
|
||||
<tr>
|
||||
<th class="fw-semibold">Store</th>
|
||||
<td>
|
||||
<a href="@Model.StoreLink" rel="noreferrer noopener">@Model.StoreName</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Invoice Id</th>
|
||||
<td>@Model.Id</td>
|
||||
</tr>
|
||||
@if (!string.IsNullOrEmpty(Model.TypedMetadata.OrderUrl))
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Order Id</th>
|
||||
<td>
|
||||
|
||||
<a href="@Model.TypedMetadata.OrderUrl" rel="noreferrer noopener" target="_blank">
|
||||
@if (string.IsNullOrEmpty(Model.TypedMetadata.OrderId))
|
||||
{
|
||||
<span>View Order</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Model.TypedMetadata.OrderId
|
||||
}
|
||||
else
|
||||
{
|
||||
<a href="@Model.TypedMetadata.OrderUrl" rel="noreferrer noopener" target="_blank">
|
||||
@if (string.IsNullOrEmpty(Model.TypedMetadata.OrderId))
|
||||
{
|
||||
<span>View Order</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Model.TypedMetadata.OrderId
|
||||
}
|
||||
</a>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Payment Request Id</th>
|
||||
<td><a href="@Model.PaymentRequestLink" rel="noreferrer noopener">@Model.TypedMetadata.PaymentRequestId</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">State</th>
|
||||
<td>
|
||||
@if (Model.CanMarkStatus)
|
||||
{
|
||||
<div class="dropdown changeInvoiceStateToggle">
|
||||
<button class="btn btn-secondary btn-sm dropdown-toggle py-1 px-2" type="button" id="markStatusDropdownMenuButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
@Model.State
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="markStatusDropdownMenuButton">
|
||||
@if (Model.CanMarkInvalid)
|
||||
{
|
||||
<a class="dropdown-item changeInvoiceState" href="#" data-id="@Model.Id" data-status="invalid" data-change-invoice-status-button>
|
||||
Mark as invalid <span class="fa fa-times"></span>
|
||||
</a>
|
||||
}
|
||||
@if (Model.CanMarkSettled)
|
||||
{
|
||||
<a class="dropdown-item changeInvoiceState" href="#" data-id="@Model.Id" data-status="settled" data-change-invoice-status-button>
|
||||
Mark as settled <span class="fa fa-check-circle"></span>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
</a>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.TypedMetadata.PaymentRequestId is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Payment Request Id</th>
|
||||
<td>
|
||||
<a href="@Model.PaymentRequestLink" rel="noreferrer noopener">@Model.TypedMetadata.PaymentRequestId</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<th class="fw-semibold">State</th>
|
||||
<td>
|
||||
@if (Model.CanMarkStatus)
|
||||
{
|
||||
<div class="dropdown changeInvoiceStateToggle">
|
||||
<button class="btn btn-secondary btn-sm dropdown-toggle py-1 px-2" type="button" id="markStatusDropdownMenuButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
@Model.State
|
||||
@if (Model.StatusException != InvoiceExceptionStatus.None)
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="markStatusDropdownMenuButton">
|
||||
@if (Model.CanMarkInvalid)
|
||||
{
|
||||
@String.Format(" ({0})", Model.StatusException.ToString());
|
||||
<a class="dropdown-item changeInvoiceState" href="#" data-id="@Model.Id" data-status="invalid" data-change-invoice-status-button>
|
||||
Mark as invalid <span class="fa fa-times"></span>
|
||||
</a>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Created Date</th>
|
||||
<td>@Model.CreatedDate.ToBrowserDate()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Expiration Date</th>
|
||||
<td>@Model.ExpirationDate.ToBrowserDate()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Monitoring Date</th>
|
||||
<td>@Model.MonitoringDate.ToBrowserDate()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Transaction Speed</th>
|
||||
<td>@Model.TransactionSpeed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Total Fiat Due</th>
|
||||
<td>@Model.Fiat</td>
|
||||
</tr>
|
||||
@if (!string.IsNullOrEmpty(Model.RefundEmail))
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Refund Email</th>
|
||||
<td><a href="mailto:@Model.RefundEmail">@Model.RefundEmail</a></td>
|
||||
</tr>
|
||||
@if (Model.CanMarkSettled)
|
||||
{
|
||||
<a class="dropdown-item changeInvoiceState" href="#" data-id="@Model.Id" data-status="settled" data-change-invoice-status-button>
|
||||
Mark as settled <span class="fa fa-check-circle"></span>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.NotificationUrl))
|
||||
else
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Notification Url</th>
|
||||
<td>@Model.NotificationUrl</td>
|
||||
</tr>
|
||||
@Model.State
|
||||
@if (Model.StatusException != InvoiceExceptionStatus.None)
|
||||
{
|
||||
@String.Format(" ({0})", Model.StatusException.ToString())
|
||||
;
|
||||
}
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.RedirectUrl))
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Redirect Url</th>
|
||||
<td><a href="@Model.RedirectUrl" rel="noreferrer noopener">@Model.RedirectUrl</a></td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
@if (Model.PosData.Count == 0)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Created Date</th>
|
||||
<td>@Model.CreatedDate.ToBrowserDate()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Expiration Date</th>
|
||||
<td>@Model.ExpirationDate.ToBrowserDate()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Monitoring Date</th>
|
||||
<td>@Model.MonitoringDate.ToBrowserDate()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Transaction Speed</th>
|
||||
<td>@Model.TransactionSpeed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Total Fiat Due</th>
|
||||
<td>@Model.Fiat</td>
|
||||
</tr>
|
||||
@if (!string.IsNullOrEmpty(Model.RefundEmail))
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Refund Email</th>
|
||||
<td>
|
||||
<a href="mailto:@Model.RefundEmail">@Model.RefundEmail</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.NotificationUrl))
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Notification Url</th>
|
||||
<td>@Model.NotificationUrl</td>
|
||||
</tr>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.RedirectUrl))
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Redirect Url</th>
|
||||
<td>
|
||||
<a href="@Model.RedirectUrl" rel="noreferrer noopener">@Model.RedirectUrl</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
@if (Model.PosData.Count == 0)
|
||||
{
|
||||
<div class="col-md-6">
|
||||
<h3 class="mb-3">Product Information</h3>
|
||||
<table class="table mb-5">
|
||||
@if (!string.IsNullOrEmpty(Model.TypedMetadata.ItemCode))
|
||||
{
|
||||
<h3 class="mb-3">Product Information</h3>
|
||||
<table class="table mb-5">
|
||||
@if (!string.IsNullOrEmpty(Model.TypedMetadata.ItemCode))
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Item code</th>
|
||||
<td>@Model.TypedMetadata.ItemCode</td>
|
||||
</tr>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.TypedMetadata.ItemDesc))
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Item Description</th>
|
||||
<td>@Model.TypedMetadata.ItemDesc</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<th class="fw-semibold">Price</th>
|
||||
<td>@Model.Fiat</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="fw-semibold">Tax Included</th>
|
||||
<td>@Model.TaxIncluded</td>
|
||||
</tr>
|
||||
</table>
|
||||
<tr>
|
||||
<th class="fw-semibold">Item code</th>
|
||||
<td>@Model.TypedMetadata.ItemCode</td>
|
||||
</tr>
|
||||
}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h3 class="mb-3">Buyer Information</h3>
|
||||
<div class="table-responsive-xl">
|
||||
<table class="table mb-5">
|
||||
@if (!string.IsNullOrEmpty(Model.TypedMetadata.ItemDesc))
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Item Description</th>
|
||||
<td>@Model.TypedMetadata.ItemDesc</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<th class="fw-semibold">Price</th>
|
||||
<td>@Model.Fiat</td>
|
||||
</tr>
|
||||
@if (Model.TaxIncluded is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Tax Included</th>
|
||||
<td>@Model.TaxIncluded</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
@if (Model.TypedMetadata.BuyerName is not null ||
|
||||
Model.TypedMetadata.BuyerEmail is not null ||
|
||||
Model.TypedMetadata.BuyerPhone is not null ||
|
||||
Model.TypedMetadata.BuyerAddress1 is not null ||
|
||||
Model.TypedMetadata.BuyerAddress2 is not null ||
|
||||
Model.TypedMetadata.BuyerCity is not null ||
|
||||
Model.TypedMetadata.BuyerState is not null ||
|
||||
Model.TypedMetadata.BuyerCountry is not null ||
|
||||
Model.TypedMetadata.BuyerZip is not null
|
||||
)
|
||||
{
|
||||
<div class="col-md-6">
|
||||
<h3 class="mb-3">Buyer Information</h3>
|
||||
<div class="table-responsive-xl">
|
||||
<table class="table mb-5">
|
||||
@if (Model.TypedMetadata.BuyerName is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Name</th>
|
||||
<td>@Model.TypedMetadata.BuyerName</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.TypedMetadata.BuyerEmail is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Email</th>
|
||||
<td><a href="mailto:@Model.TypedMetadata.BuyerEmail">@Model.TypedMetadata.BuyerEmail</a></td>
|
||||
<td>
|
||||
<a href="mailto:@Model.TypedMetadata.BuyerEmail">@Model.TypedMetadata.BuyerEmail</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.TypedMetadata.BuyerPhone is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Phone</th>
|
||||
<td>@Model.TypedMetadata.BuyerPhone</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.TypedMetadata.BuyerAddress1 is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Address 1</th>
|
||||
<td>@Model.TypedMetadata.BuyerAddress1</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.TypedMetadata.BuyerAddress2 is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Address 2</th>
|
||||
<td>@Model.TypedMetadata.BuyerAddress2</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.TypedMetadata.BuyerCity is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">City</th>
|
||||
<td>@Model.TypedMetadata.BuyerCity</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.TypedMetadata.BuyerState is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">State</th>
|
||||
<td>@Model.TypedMetadata.BuyerState</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.TypedMetadata.BuyerCountry is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Country</th>
|
||||
<td>@Model.TypedMetadata.BuyerCountry</td>
|
||||
</tr>
|
||||
}
|
||||
@if (Model.TypedMetadata.BuyerZip is not null)
|
||||
{
|
||||
<tr>
|
||||
<th class="fw-semibold">Zip</th>
|
||||
<td>@Model.TypedMetadata.BuyerZip</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (Model.PosData.Count != 0)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h3 class="mb-3">Product information</h3>
|
||||
<table class="table mb-5">
|
||||
@if (!string.IsNullOrEmpty(Model.TypedMetadata.ItemCode))
|
||||
{
|
||||
<tr>
|
||||
<th>Item code</th>
|
||||
<td>@Model.TypedMetadata.ItemCode</td>
|
||||
</tr>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.TypedMetadata.ItemDesc))
|
||||
{
|
||||
<tr>
|
||||
<th>Item Description</th>
|
||||
<td>@Model.TypedMetadata.ItemDesc</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<th>Price</th>
|
||||
<td>@Model.Fiat</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Tax included</th>
|
||||
<td>@Model.TaxIncluded</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4" id="posData">
|
||||
<h3 class="mb-3">Point of Sale Data</h3>
|
||||
|
||||
<partial name="PosData" model="(Model.PosData, 1)" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<partial name="ListInvoicesPaymentsPartial" model="(Model, true)" />
|
||||
|
||||
@if (Model.Deliveries.Count != 0)
|
||||
{
|
||||
<div class="table-responsive-xl">
|
||||
<h3 class="mb-3 mt-4">Webhooks</h3>
|
||||
<table class="table table-hover table-responsive-md mb-5">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<th>ID</th>
|
||||
<th>Type</th>
|
||||
<th>Url</th>
|
||||
<th>Date</th>
|
||||
<th class="text-end">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var delivery in Model.Deliveries)
|
||||
{
|
||||
<tr>
|
||||
<form asp-action="RedeliverWebhook"
|
||||
asp-route-storeId="@Model.StoreId"
|
||||
asp-route-invoiceId="@Model.Id"
|
||||
asp-route-deliveryId="@delivery.Id"
|
||||
method="post">
|
||||
<td>
|
||||
<span>
|
||||
@if (delivery.Success)
|
||||
{
|
||||
<span class="fa fa-check text-success" title="Success"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="fa fa-times text-danger" title="@delivery.ErrorMessage"></span>
|
||||
}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>
|
||||
<a asp-action="WebhookDelivery"
|
||||
asp-route-invoiceId="@Model.Id"
|
||||
asp-route-deliveryId="@delivery.Id"
|
||||
class="delivery-content"
|
||||
target="_blank">
|
||||
@delivery.Id
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>@delivery.Type</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="@delivery.PayloadUrl" style="cursor: pointer;">
|
||||
<span style="max-width: 250px;">@delivery.PayloadUrl</span>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>
|
||||
@delivery.Time.ToBrowserDate()
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<button id="#redeliver-@delivery.Id"
|
||||
type="submit"
|
||||
class="btn btn-link p-0 redeliver">
|
||||
Redeliver
|
||||
</button>
|
||||
</td>
|
||||
</form>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<h3 class="mb-0">Events</h3>
|
||||
<table class="table table-hover">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var evt in Model.Events)
|
||||
@if (Model.PosData.Count != 0)
|
||||
{
|
||||
<div class="col-md-6">
|
||||
<h3 class="mb-3">Product information</h3>
|
||||
<table class="table mb-5">
|
||||
@if (!string.IsNullOrEmpty(Model.TypedMetadata.ItemCode))
|
||||
{
|
||||
<tr class="text-@evt.GetCssClass()">
|
||||
<td>@evt.Timestamp.ToBrowserDate()</td>
|
||||
<td>@evt.Message</td>
|
||||
<tr>
|
||||
<th>Item code</th>
|
||||
<td>@Model.TypedMetadata.ItemCode</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@if (!string.IsNullOrEmpty(Model.TypedMetadata.ItemDesc))
|
||||
{
|
||||
<tr>
|
||||
<th>Item Description</th>
|
||||
<td>@Model.TypedMetadata.ItemDesc</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<th>Price</th>
|
||||
<td>@Model.Fiat</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Tax included</th>
|
||||
<td>@Model.TaxIncluded</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4" id="posData">
|
||||
<h3 class="mb-3">Point of Sale Data</h3>
|
||||
|
||||
<partial name="PosData" model="(Model.PosData, 1)"/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<partial name="ListInvoicesPaymentsPartial" model="(Model, true)"/>
|
||||
|
||||
@if (Model.Deliveries.Count != 0)
|
||||
{
|
||||
<div class="table-responsive-xl">
|
||||
<h3 class="mb-3 mt-4">Webhooks</h3>
|
||||
<table class="table table-hover table-responsive-md mb-5">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<th>ID</th>
|
||||
<th>Type</th>
|
||||
<th>Url</th>
|
||||
<th>Date</th>
|
||||
<th class="text-end">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var delivery in Model.Deliveries)
|
||||
{
|
||||
<tr>
|
||||
<form asp-action="RedeliverWebhook"
|
||||
asp-route-storeId="@Model.StoreId"
|
||||
asp-route-invoiceId="@Model.Id"
|
||||
asp-route-deliveryId="@delivery.Id"
|
||||
method="post">
|
||||
<td>
|
||||
<span>
|
||||
@if (delivery.Success)
|
||||
{
|
||||
<span class="fa fa-check text-success" title="Success"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="fa fa-times text-danger" title="@delivery.ErrorMessage"></span>
|
||||
}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>
|
||||
<a asp-action="WebhookDelivery"
|
||||
asp-route-invoiceId="@Model.Id"
|
||||
asp-route-deliveryId="@delivery.Id"
|
||||
class="delivery-content"
|
||||
target="_blank">
|
||||
@delivery.Id
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>@delivery.Type</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="@delivery.PayloadUrl" style="cursor: pointer;">
|
||||
<span style="max-width: 250px;">@delivery.PayloadUrl</span>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>
|
||||
@delivery.Time.ToBrowserDate()
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<button id="#redeliver-@delivery.Id"
|
||||
type="submit"
|
||||
class="btn btn-link p-0 redeliver">
|
||||
Redeliver
|
||||
</button>
|
||||
</td>
|
||||
</form>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if ((Model.Refunds?.Count ?? 0) > 0)
|
||||
{
|
||||
<div class="table-responsive-xl">
|
||||
<h3 class="mb-3 mt-4">Refunds</h3>
|
||||
<table class="table table-hover table-responsive-md mb-5">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Pull Payment</th>
|
||||
<th>Amount</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var refund in Model.Refunds)
|
||||
{
|
||||
var blob = refund.PullPaymentData.GetBlob();
|
||||
<tr>
|
||||
|
||||
<td>
|
||||
<span>
|
||||
<a asp-action="ViewPullPayment" asp-controller="UIPullPayment"
|
||||
asp-route-pullPaymentId="@refund.PullPaymentDataId"
|
||||
class="delivery-content"
|
||||
target="_blank">
|
||||
@refund.PullPaymentData.Id
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>@blob.Limit @blob.Currency</span>
|
||||
</td>
|
||||
<td>
|
||||
<span> @refund.PullPaymentData.StartDate.ToBrowserDate() </span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
<h3 class="mb-0">Events</h3>
|
||||
<table class="table table-hover">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var evt in Model.Events)
|
||||
{
|
||||
<tr class="text-@evt.GetCssClass()">
|
||||
<td>@evt.Timestamp.ToBrowserDate()</td>
|
||||
<td>@evt.Message</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Reference in a new issue