mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-12 02:08:32 +01:00
Add POS Data to Invoice UI (#409)
* Add POS Data in Invoice UI * fix build * extract in helper and add UTs * add in unit test coverage through mvc view too
This commit is contained in:
parent
c25831316e
commit
e144d2479b
4 changed files with 278 additions and 137 deletions
|
@ -43,6 +43,7 @@ using System.Security.Cryptography.X509Certificates;
|
||||||
using BTCPayServer.Lightning;
|
using BTCPayServer.Lightning;
|
||||||
using BTCPayServer.Models.WalletViewModels;
|
using BTCPayServer.Models.WalletViewModels;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using BTCPayServer.Models.InvoicingModels;
|
||||||
using BTCPayServer.Models.ServerViewModels;
|
using BTCPayServer.Models.ServerViewModels;
|
||||||
using BTCPayServer.Security;
|
using BTCPayServer.Security;
|
||||||
using NBXplorer.Models;
|
using NBXplorer.Models;
|
||||||
|
@ -79,7 +80,7 @@ namespace BTCPayServer.Tests
|
||||||
Assert.False(attribute.IsValid("http://"));
|
Assert.False(attribute.IsValid("http://"));
|
||||||
Assert.False(attribute.IsValid("httpdsadsa.com"));
|
Assert.False(attribute.IsValid("httpdsadsa.com"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Fast", "Fast")]
|
[Trait("Fast", "Fast")]
|
||||||
public void CanCalculateCryptoDue2()
|
public void CanCalculateCryptoDue2()
|
||||||
|
@ -1505,6 +1506,81 @@ donation:
|
||||||
Assert.Equal("donation", donationInvoice.ItemDesc);
|
Assert.Equal("donation", donationInvoice.ItemDesc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Fast", "Fast")]
|
||||||
|
public void PosDataParser_ParsesCorrectly()
|
||||||
|
{
|
||||||
|
var testCases =
|
||||||
|
new List<(string input, Dictionary<string, string> expectedOutput)>()
|
||||||
|
{
|
||||||
|
{ (null, new Dictionary<string, string>())},
|
||||||
|
{("", new Dictionary<string, string>())},
|
||||||
|
{("{}", new Dictionary<string, string>())},
|
||||||
|
{("non-json-content", new Dictionary<string, string>(){ {string.Empty, "non-json-content"}})},
|
||||||
|
{("[1,2,3]", new Dictionary<string, string>(){ {string.Empty, "[1,2,3]"}})},
|
||||||
|
{("{ \"key\": \"value\"}", new Dictionary<string, string>(){ {"key", "value"}})},
|
||||||
|
{("{ \"key\": true}", new Dictionary<string, string>(){ {"key", "True"}})},
|
||||||
|
{("{ \"key\": \"value\", \"key2\": [\"value\", \"value2\"]}",
|
||||||
|
new Dictionary<string, string>(){ {"key", "value"}, {"key2", "value,value2"}})},
|
||||||
|
{("{ invalidjson file here}", new Dictionary<string, string>(){ {String.Empty, "{ invalidjson file here}"}})}
|
||||||
|
};
|
||||||
|
|
||||||
|
testCases.ForEach(tuple =>
|
||||||
|
{
|
||||||
|
Assert.Equal(tuple.expectedOutput, InvoiceController.PosDataParser.ParsePosData(tuple.input));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Integration", "Integration")]
|
||||||
|
public async Task PosDataParser_ParsesCorrectly_Slower()
|
||||||
|
{
|
||||||
|
using (var tester = ServerTester.Create())
|
||||||
|
{
|
||||||
|
tester.Start();
|
||||||
|
var user = tester.NewAccount();
|
||||||
|
user.GrantAccess();
|
||||||
|
user.RegisterDerivationScheme("BTC");
|
||||||
|
|
||||||
|
var controller = tester.PayTester.GetController<InvoiceController>(null);
|
||||||
|
|
||||||
|
var testCases =
|
||||||
|
new List<(string input, Dictionary<string, string> expectedOutput)>()
|
||||||
|
{
|
||||||
|
{ (null, new Dictionary<string, string>())},
|
||||||
|
{("", new Dictionary<string, string>())},
|
||||||
|
{("{}", new Dictionary<string, string>())},
|
||||||
|
{("non-json-content", new Dictionary<string, string>(){ {string.Empty, "non-json-content"}})},
|
||||||
|
{("[1,2,3]", new Dictionary<string, string>(){ {string.Empty, "[1,2,3]"}})},
|
||||||
|
{("{ \"key\": \"value\"}", new Dictionary<string, string>(){ {"key", "value"}})},
|
||||||
|
{("{ \"key\": true}", new Dictionary<string, string>(){ {"key", "True"}})},
|
||||||
|
{("{ \"key\": \"value\", \"key2\": [\"value\", \"value2\"]}",
|
||||||
|
new Dictionary<string, string>(){ {"key", "value"}, {"key2", "value,value2"}})},
|
||||||
|
{("{ invalidjson file here}", new Dictionary<string, string>(){ {String.Empty, "{ invalidjson file here}"}})}
|
||||||
|
};
|
||||||
|
|
||||||
|
var tasks = new List<Task>();
|
||||||
|
foreach (var valueTuple in testCases)
|
||||||
|
{
|
||||||
|
tasks.Add(user.BitPay.CreateInvoiceAsync(new Invoice(1, "BTC")
|
||||||
|
{
|
||||||
|
PosData = valueTuple.input
|
||||||
|
}).ContinueWith(async task =>
|
||||||
|
{
|
||||||
|
var result = await controller.Invoice(task.Result.Id);
|
||||||
|
var viewModel =
|
||||||
|
Assert.IsType<InvoiceDetailsModel>(
|
||||||
|
Assert.IsType<ViewResult>(result).Model);
|
||||||
|
Assert.Equal(valueTuple.expectedOutput, viewModel.PosData);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(tasks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Integration", "Integration")]
|
[Trait("Integration", "Integration")]
|
||||||
|
|
|
@ -14,13 +14,13 @@ using BTCPayServer.Payments.Changelly;
|
||||||
using BTCPayServer.Payments.Lightning;
|
using BTCPayServer.Payments.Lightning;
|
||||||
using BTCPayServer.Security;
|
using BTCPayServer.Security;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
using BTCPayServer.Services.Rates;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using NBitpayClient;
|
using NBitpayClient;
|
||||||
using NBXplorer;
|
using NBXplorer;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
|
@ -41,7 +41,6 @@ namespace BTCPayServer.Controllers
|
||||||
|
|
||||||
var dto = invoice.EntityToDTO(_NetworkProvider);
|
var dto = invoice.EntityToDTO(_NetworkProvider);
|
||||||
var store = await _StoreRepository.FindStore(invoice.StoreId);
|
var store = await _StoreRepository.FindStore(invoice.StoreId);
|
||||||
|
|
||||||
InvoiceDetailsModel model = new InvoiceDetailsModel()
|
InvoiceDetailsModel model = new InvoiceDetailsModel()
|
||||||
{
|
{
|
||||||
StoreName = store.StoreName,
|
StoreName = store.StoreName,
|
||||||
|
@ -64,7 +63,8 @@ namespace BTCPayServer.Controllers
|
||||||
RedirectUrl = invoice.RedirectURL,
|
RedirectUrl = invoice.RedirectURL,
|
||||||
ProductInformation = invoice.ProductInformation,
|
ProductInformation = invoice.ProductInformation,
|
||||||
StatusException = invoice.ExceptionStatus,
|
StatusException = invoice.ExceptionStatus,
|
||||||
Events = invoice.Events
|
Events = invoice.Events,
|
||||||
|
PosData = PosDataParser.ParsePosData(dto.PosData)
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var data in invoice.GetPaymentMethods(null))
|
foreach (var data in invoice.GetPaymentMethods(null))
|
||||||
|
@ -586,5 +586,43 @@ namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
return _UserManager.GetUserId(User);
|
return _UserManager.GetUserId(User);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PosDataParser
|
||||||
|
{
|
||||||
|
public static Dictionary<string, string> ParsePosData(string posData)
|
||||||
|
{
|
||||||
|
var result = new Dictionary<string,string>();
|
||||||
|
if (string.IsNullOrEmpty(posData))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
var jObject =JObject.Parse(posData);
|
||||||
|
foreach (var item in jObject)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (item.Value.Type)
|
||||||
|
{
|
||||||
|
case JTokenType.Array:
|
||||||
|
result.Add(item.Key, string.Join(',', item.Value.AsEnumerable()));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result.Add(item.Key, item.Value.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
result.Add(string.Empty, posData);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,5 +143,6 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||||
public DateTimeOffset MonitoringDate { get; internal set; }
|
public DateTimeOffset MonitoringDate { get; internal set; }
|
||||||
public List<Data.InvoiceEventData> Events { get; internal set; }
|
public List<Data.InvoiceEventData> Events { get; internal set; }
|
||||||
public string NotificationEmail { get; internal set; }
|
public string NotificationEmail { get; internal set; }
|
||||||
|
public Dictionary<string, string> PosData { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,128 +42,177 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h3>Information</h3>
|
||||||
|
<table class="table table-sm table-responsive-md">
|
||||||
|
<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.ToBrowserDate()</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Expiration date</th>
|
||||||
|
<td>@Model.ExpirationDate.ToBrowserDate()</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Monitoring date</th>
|
||||||
|
<td>@Model.MonitoringDate.ToBrowserDate()</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Transaction speed</th>
|
||||||
|
<td>@Model.TransactionSpeed</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Status</th>
|
||||||
|
<td>@Model.Status</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Status Exception</th>
|
||||||
|
<td>@Model.StatusException</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Refund email</th>
|
||||||
|
<td><a href="mailto:@Model.RefundEmail">@Model.RefundEmail</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Order Id</th>
|
||||||
|
<td>@Model.OrderId</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Total fiat due</th>
|
||||||
|
<td>@Model.Fiat</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Notification Email</th>
|
||||||
|
<td>@Model.NotificationEmail</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Notification Url</th>
|
||||||
|
<td>@Model.NotificationUrl</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Redirect Url</th>
|
||||||
|
<td><a href="@Model.RedirectUrl">@Model.RedirectUrl</a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h3>Buyer information</h3>
|
||||||
|
<table class="table table-sm table-responsive-md">
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<td>@Model.BuyerInformation.BuyerName</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Email</th>
|
||||||
|
<td><a href="mailto:@Model.BuyerInformation.BuyerEmail">@Model.BuyerInformation.BuyerEmail</a></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 table-sm table-responsive-md">
|
||||||
|
<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="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h3>Information</h3>
|
<h3>Pos Data</h3>
|
||||||
<table class="table table-sm table-responsive-md">
|
<table class="table table-sm table-responsive-md">
|
||||||
<tr>
|
@foreach (var posDataItem in Model.PosData)
|
||||||
<th>Store</th>
|
{
|
||||||
<td><a href="@Model.StoreLink">@Model.StoreName</a></td>
|
<tr>
|
||||||
</tr>
|
@if (!string.IsNullOrEmpty(posDataItem.Key))
|
||||||
<tr>
|
{
|
||||||
<th>Id</th>
|
|
||||||
<td>@Model.Id</td>
|
<th>@posDataItem.Key</th>
|
||||||
</tr>
|
<td>@posDataItem.Value</td>
|
||||||
<tr>
|
}
|
||||||
<th>Created date</th>
|
else
|
||||||
<td>@Model.CreatedDate.ToBrowserDate()</td>
|
{
|
||||||
</tr>
|
|
||||||
<tr>
|
<td colspan="2">@posDataItem.Value</td>
|
||||||
<th>Expiration date</th>
|
}
|
||||||
<td>@Model.ExpirationDate.ToBrowserDate()</td>
|
</tr>
|
||||||
</tr>
|
}
|
||||||
<tr>
|
|
||||||
<th>Monitoring date</th>
|
|
||||||
<td>@Model.MonitoringDate.ToBrowserDate()</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Transaction speed</th>
|
|
||||||
<td>@Model.TransactionSpeed</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Status</th>
|
|
||||||
<td>@Model.Status</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Status Exception</th>
|
|
||||||
<td>@Model.StatusException</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Refund email</th>
|
|
||||||
<td><a href="mailto:@Model.RefundEmail">@Model.RefundEmail</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Order Id</th>
|
|
||||||
<td>@Model.OrderId</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Total fiat due</th>
|
|
||||||
<td>@Model.Fiat</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Notification Email</th>
|
|
||||||
<td>@Model.NotificationEmail</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Notification Url</th>
|
|
||||||
<td>@Model.NotificationUrl</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Redirect Url</th>
|
|
||||||
<td><a href="@Model.RedirectUrl">@Model.RedirectUrl</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h3>Buyer information</h3>
|
<h3>Addresses</h3>
|
||||||
<table class="table table-sm table-responsive-md">
|
<table class="table table-sm table-responsive-md">
|
||||||
|
<thead class="thead-inverse">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th class="firstCol">Payment method</th>
|
||||||
<td>@Model.BuyerInformation.BuyerName</td>
|
<th>Address</th>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Email</th>
|
|
||||||
<td><a href="mailto:@Model.BuyerInformation.BuyerEmail">@Model.BuyerInformation.BuyerEmail</a></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 table-sm table-responsive-md">
|
|
||||||
<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>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var address in Model.Addresses)
|
||||||
|
{
|
||||||
|
var current = address.Current ? "font-weight-bold" : "";
|
||||||
|
<tr>
|
||||||
|
<td>@address.PaymentMethod</td>
|
||||||
|
<td class="smMaxWidth text-truncate @current">@address.Destination</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<h3>Paid summary</h3>
|
<h3>Paid summary</h3>
|
||||||
<table class="table table-sm table-responsive-md">
|
<table class="table table-sm table-responsive-md">
|
||||||
|
@ -258,29 +307,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<h3>Addresses</h3>
|
|
||||||
<table class="table table-sm table-responsive-md">
|
|
||||||
<thead class="thead-inverse">
|
|
||||||
<tr>
|
|
||||||
<th class="firstCol">Payment method</th>
|
|
||||||
<th>Address</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach (var address in Model.Addresses)
|
|
||||||
{
|
|
||||||
var current = address.Current ? "font-weight-bold" : "";
|
|
||||||
<tr>
|
|
||||||
<td>@address.PaymentMethod</td>
|
|
||||||
<td class="smMaxWidth text-truncate @current">@address.Destination</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
|
|
Loading…
Add table
Reference in a new issue