Various bugfixes (#308)

* NotifyEmail field on Invoice, sending email when triggered

* Styling invoices page

* Exporting Invoices in JSON

* Recoding based on feedback

* Fixing image breaking responsive layout on mobile

* Reducing amount of data sent in email notification

* Turning bundling on by default
This commit is contained in:
Rockstar Developer
2018-10-11 20:09:13 -05:00
committed by Nicolas Dorier
parent db40c7bc32
commit c2bbc04c4c
14 changed files with 180 additions and 51 deletions

View File

@@ -58,6 +58,7 @@ namespace BTCPayServer.Controllers
OrderId = invoice.OrderId, OrderId = invoice.OrderId,
BuyerInformation = invoice.BuyerInformation, BuyerInformation = invoice.BuyerInformation,
Fiat = _CurrencyNameTable.DisplayFormatCurrency((decimal)dto.Price, dto.Currency), Fiat = _CurrencyNameTable.DisplayFormatCurrency((decimal)dto.Price, dto.Currency),
NotificationEmail = invoice.NotificationEmail,
NotificationUrl = invoice.NotificationURL, NotificationUrl = invoice.NotificationURL,
RedirectUrl = invoice.RedirectURL, RedirectUrl = invoice.RedirectURL,
ProductInformation = invoice.ProductInformation, ProductInformation = invoice.ProductInformation,
@@ -228,7 +229,7 @@ namespace BTCPayServer.Controllers
if (!isDefaultCrypto) if (!isDefaultCrypto)
return null; return null;
var paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider) var paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider)
.Where(c=> paymentMethodId.CryptoCode == c.GetId().CryptoCode) .Where(c => paymentMethodId.CryptoCode == c.GetId().CryptoCode)
.FirstOrDefault(); .FirstOrDefault();
if (paymentMethodTemp == null) if (paymentMethodTemp == null)
paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider).First(); paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider).First();
@@ -405,23 +406,17 @@ namespace BTCPayServer.Controllers
[BitpayAPIConstraint(false)] [BitpayAPIConstraint(false)]
public async Task<IActionResult> ListInvoices(string searchTerm = null, int skip = 0, int count = 50) public async Task<IActionResult> ListInvoices(string searchTerm = null, int skip = 0, int count = 50)
{ {
var model = new InvoicesModel(); var model = new InvoicesModel
var filterString = new SearchString(searchTerm);
foreach (var invoice in await _InvoiceRepository.GetInvoices(new InvoiceQuery()
{ {
TextSearch = filterString.TextSearch, SearchTerm = searchTerm,
Count = count,
Skip = skip, Skip = skip,
UserId = GetUserId(), Count = count,
Unusual = !filterString.Filters.ContainsKey("unusual") ? null StatusMessage = StatusMessage
: !bool.TryParse(filterString.Filters["unusual"].First(), out var r) ? (bool?)null };
: r,
Status = filterString.Filters.ContainsKey("status") ? filterString.Filters["status"].ToArray() : null, var list = await ListInvoicesProcess(searchTerm, skip, count);
ExceptionStatus = filterString.Filters.ContainsKey("exceptionstatus") ? filterString.Filters["exceptionstatus"].ToArray() : null, foreach (var invoice in list)
StoreId = filterString.Filters.ContainsKey("storeid") ? filterString.Filters["storeid"].ToArray() : null
}))
{ {
model.SearchTerm = searchTerm;
model.Invoices.Add(new InvoiceModel() model.Invoices.Add(new InvoiceModel()
{ {
Status = invoice.Status + (invoice.ExceptionStatus == null ? string.Empty : $" ({invoice.ExceptionStatus})"), Status = invoice.Status + (invoice.ExceptionStatus == null ? string.Empty : $" ({invoice.ExceptionStatus})"),
@@ -433,12 +428,29 @@ namespace BTCPayServer.Controllers
AmountCurrency = $"{invoice.ProductInformation.Price.ToString(CultureInfo.InvariantCulture)} {invoice.ProductInformation.Currency}" AmountCurrency = $"{invoice.ProductInformation.Price.ToString(CultureInfo.InvariantCulture)} {invoice.ProductInformation.Currency}"
}); });
} }
model.Skip = skip;
model.Count = count;
model.StatusMessage = StatusMessage;
return View(model); return View(model);
} }
private async Task<InvoiceEntity[]> ListInvoicesProcess(string searchTerm = null, int skip = 0, int count = 50)
{
var filterString = new SearchString(searchTerm);
var list = await _InvoiceRepository.GetInvoices(new InvoiceQuery()
{
TextSearch = filterString.TextSearch,
Count = count,
Skip = skip,
UserId = GetUserId(),
Unusual = !filterString.Filters.ContainsKey("unusual") ? null
: !bool.TryParse(filterString.Filters["unusual"].First(), out var r) ? (bool?)null
: r,
Status = filterString.Filters.ContainsKey("status") ? filterString.Filters["status"].ToArray() : null,
ExceptionStatus = filterString.Filters.ContainsKey("exceptionstatus") ? filterString.Filters["exceptionstatus"].ToArray() : null,
StoreId = filterString.Filters.ContainsKey("storeid") ? filterString.Filters["storeid"].ToArray() : null
});
return list;
}
[HttpGet] [HttpGet]
[Route("invoices/create")] [Route("invoices/create")]
[Authorize(AuthenticationSchemes = Policies.CookieAuthentication)] [Authorize(AuthenticationSchemes = Policies.CookieAuthentication)]
@@ -501,6 +513,7 @@ namespace BTCPayServer.Controllers
PosData = model.PosData, PosData = model.PosData,
OrderId = model.OrderId, OrderId = model.OrderId,
//RedirectURL = redirect + "redirect", //RedirectURL = redirect + "redirect",
NotificationEmail = model.NotificationEmail,
NotificationURL = model.NotificationUrl, NotificationURL = model.NotificationUrl,
ItemDesc = model.ItemDesc, ItemDesc = model.ItemDesc,
FullNotifications = true, FullNotifications = true,
@@ -517,6 +530,21 @@ namespace BTCPayServer.Controllers
} }
} }
[HttpGet]
[Authorize(AuthenticationSchemes = Policies.CookieAuthentication)]
[BitpayAPIConstraint(false)]
public async Task<IActionResult> Export(string format, string searchTerm = null)
{
var model = new ExportInvoicesModel
{
Format = format,
Invoices = await ListInvoicesProcess(searchTerm, 0, int.MaxValue)
};
return Content(model.Process(), "application/" + format);
}
[HttpPost] [HttpPost]
[Authorize(AuthenticationSchemes = Policies.CookieAuthentication)] [Authorize(AuthenticationSchemes = Policies.CookieAuthentication)]
[BitpayAPIConstraint(false)] [BitpayAPIConstraint(false)]

View File

@@ -83,6 +83,7 @@ namespace BTCPayServer.Controllers
entity.FullNotifications = invoice.FullNotifications || invoice.ExtendedNotifications; entity.FullNotifications = invoice.FullNotifications || invoice.ExtendedNotifications;
entity.ExtendedNotifications = invoice.ExtendedNotifications; entity.ExtendedNotifications = invoice.ExtendedNotifications;
entity.NotificationURL = notificationUri?.AbsoluteUri; entity.NotificationURL = notificationUri?.AbsoluteUri;
entity.NotificationEmail = invoice.NotificationEmail;
entity.BuyerInformation = Map<Invoice, BuyerInformation>(invoice); entity.BuyerInformation = Map<Invoice, BuyerInformation>(invoice);
entity.PaymentTolerance = storeBlob.PaymentTolerance; entity.PaymentTolerance = storeBlob.PaymentTolerance;
//Another way of passing buyer info to support //Another way of passing buyer info to support

View File

@@ -51,7 +51,7 @@ namespace BTCPayServer.Controllers
Currency = model.Currency, Currency = model.Currency,
ItemDesc = model.CheckoutDesc, ItemDesc = model.CheckoutDesc,
OrderId = model.OrderId, OrderId = model.OrderId,
BuyerEmail = model.NotifyEmail, NotificationEmail = model.NotifyEmail,
NotificationURL = model.ServerIpn, NotificationURL = model.ServerIpn,
RedirectURL = model.BrowserRedirect, RedirectURL = model.BrowserRedirect,
FullNotifications = true FullNotifications = true

View File

@@ -20,6 +20,7 @@ using BTCPayServer.Events;
using NBXplorer; using NBXplorer;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Services.Mails;
namespace BTCPayServer.HostedServices namespace BTCPayServer.HostedServices
{ {
@@ -52,24 +53,44 @@ namespace BTCPayServer.HostedServices
EventAggregator _EventAggregator; EventAggregator _EventAggregator;
InvoiceRepository _InvoiceRepository; InvoiceRepository _InvoiceRepository;
BTCPayNetworkProvider _NetworkProvider; BTCPayNetworkProvider _NetworkProvider;
IEmailSender _EmailSender;
public InvoiceNotificationManager( public InvoiceNotificationManager(
IBackgroundJobClient jobClient, IBackgroundJobClient jobClient,
EventAggregator eventAggregator, EventAggregator eventAggregator,
InvoiceRepository invoiceRepository, InvoiceRepository invoiceRepository,
BTCPayNetworkProvider networkProvider, BTCPayNetworkProvider networkProvider,
ILogger<InvoiceNotificationManager> logger) ILogger<InvoiceNotificationManager> logger,
IEmailSender emailSender)
{ {
Logger = logger as ILogger ?? NullLogger.Instance; Logger = logger as ILogger ?? NullLogger.Instance;
_JobClient = jobClient; _JobClient = jobClient;
_EventAggregator = eventAggregator; _EventAggregator = eventAggregator;
_InvoiceRepository = invoiceRepository; _InvoiceRepository = invoiceRepository;
_NetworkProvider = networkProvider; _NetworkProvider = networkProvider;
_EmailSender = emailSender;
} }
async Task Notify(InvoiceEntity invoice, int? eventCode = null, string name = null) async Task Notify(InvoiceEntity invoice, int? eventCode = null, string name = null)
{ {
CancellationTokenSource cts = new CancellationTokenSource(10000); CancellationTokenSource cts = new CancellationTokenSource(10000);
if (!String.IsNullOrEmpty(invoice.NotificationEmail))
{
// just extracting most important data for email body, merchant should query API back for full invoice based on Invoice.Id
var ipn = new
{
invoice.Id,
invoice.Status,
invoice.StoreId
};
// TODO: Consider adding info on ItemDesc and payment info (amount)
var emailBody = NBitcoin.JsonConverters.Serializer.ToString(ipn);
await _EmailSender.SendEmailAsync(
invoice.NotificationEmail, $"BtcPayServer Invoice Notification - ${invoice.StoreId}", emailBody);
}
try try
{ {
if (string.IsNullOrEmpty(invoice.NotificationURL)) if (string.IsNullOrEmpty(invoice.NotificationURL))
@@ -264,15 +285,15 @@ namespace BTCPayServer.HostedServices
sendRequest() sendRequest()
.ContinueWith(t => .ContinueWith(t =>
{ {
if(t.Status == TaskStatus.RanToCompletion) if (t.Status == TaskStatus.RanToCompletion)
{ {
completion.TrySetResult(t.Result); completion.TrySetResult(t.Result);
} }
if(t.Status == TaskStatus.Faulted) if (t.Status == TaskStatus.Faulted)
{ {
completion.TrySetException(t.Exception); completion.TrySetException(t.Exception);
} }
if(t.Status == TaskStatus.Canceled) if (t.Status == TaskStatus.Canceled)
{ {
completion.TrySetCanceled(); completion.TrySetCanceled();
} }
@@ -289,7 +310,7 @@ namespace BTCPayServer.HostedServices
lock (_SendingRequestsByInvoiceId) lock (_SendingRequestsByInvoiceId)
{ {
_SendingRequestsByInvoiceId.TryGetValue(id, out var executing2); _SendingRequestsByInvoiceId.TryGetValue(id, out var executing2);
if(executing2 == sending) if (executing2 == sending)
_SendingRequestsByInvoiceId.Remove(id); _SendingRequestsByInvoiceId.Remove(id);
} }
}, TaskScheduler.Default); }, TaskScheduler.Default);

View File

@@ -53,6 +53,12 @@ namespace BTCPayServer.Models.InvoicingModels
get; set; get; set;
} }
[EmailAddress]
public string NotificationEmail
{
get; set;
}
[Uri] [Uri]
public string NotificationUrl public string NotificationUrl
{ {

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Services.Invoices;
using Newtonsoft.Json;
namespace BTCPayServer.Models.InvoicingModels
{
public class ExportInvoicesModel
{
public InvoiceEntity[] Invoices { get; set; }
public string Format { get; set; }
public string Process()
{
if (String.Equals(Format, "json", StringComparison.OrdinalIgnoreCase))
return processJson();
else
throw new Exception("Export format not supported");
}
private string processJson()
{
foreach (var i in Invoices)
{
// removing error causing complex circular dependencies
i.Payments?.ForEach(a =>
{
a.Output = null;
a.Outpoint = null;
});
}
var serializerSett = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
var json = JsonConvert.SerializeObject(new { Invoices }, Formatting.Indented, serializerSett);
return json;
}
}
}

View File

@@ -142,5 +142,6 @@ namespace BTCPayServer.Models.InvoicingModels
public AddressModel[] Addresses { get; set; } public AddressModel[] Addresses { get; set; }
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; }
} }
} }

View File

@@ -5,7 +5,7 @@
"launchBrowser": true, "launchBrowser": true,
"environmentVariables": { "environmentVariables": {
"BTCPAY_NETWORK": "regtest", "BTCPAY_NETWORK": "regtest",
"BTCPAY_BUNDLEJSCSS": "false", "BTCPAY_BUNDLEJSCSS": "true",
"BTCPAY_LTCEXPLORERURL": "http://127.0.0.1:32838/", "BTCPAY_LTCEXPLORERURL": "http://127.0.0.1:32838/",
"BTCPAY_BTCLIGHTNING": "type=charge;server=http://127.0.0.1:54938/;api-token=foiewnccewuify", "BTCPAY_BTCLIGHTNING": "type=charge;server=http://127.0.0.1:54938/;api-token=foiewnccewuify",
"BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true", "BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true",

View File

@@ -283,6 +283,11 @@ namespace BTCPayServer.Services.Invoices
get; get;
set; set;
} }
public string NotificationEmail
{
get;
set;
}
public string NotificationURL public string NotificationURL
{ {
get; get;

View File

@@ -57,14 +57,14 @@
<div class="container text-center"> <div class="container text-center">
<h2>Video tutorials</h2> <h2>Video tutorials</h2>
<div class="row"> <div class="row">
<div class="col-md-4 text-center"> <div class="col-md-2 text-center">
</div> </div>
<div class="col-md-4 text-center"> <div class="col-md-8 text-center">
<a href="https://www.youtube.com/channel/UCpG9WL6TJuoNfFVkaDMp9ug" target="_blank"> <a href="https://www.youtube.com/channel/UCpG9WL6TJuoNfFVkaDMp9ug" target="_blank">
<img src="~/img/youtube.png" height="225" width="400" /> <img src="~/img/youtube.png" class="img-fluid" />
</a> </a>
</div> </div>
<div class="col-md-6 text-center"> <div class="col-md-2 text-center">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -44,6 +44,11 @@
<input asp-for="BuyerEmail" class="form-control" /> <input asp-for="BuyerEmail" class="form-control" />
<span asp-validation-for="BuyerEmail" class="text-danger"></span> <span asp-validation-for="BuyerEmail" class="text-danger"></span>
</div> </div>
<div class="form-group">
<label asp-for="NotificationEmail" class="control-label"></label>
<input asp-for="NotificationEmail" class="form-control" />
<span asp-validation-for="NotificationEmail" class="text-danger"></span>
</div>
<div class="form-group"> <div class="form-group">
<label asp-for="NotificationUrl" class="control-label"></label> <label asp-for="NotificationUrl" class="control-label"></label>
<input asp-for="NotificationUrl" class="form-control" /> <input asp-for="NotificationUrl" class="form-control" />

View File

@@ -87,6 +87,10 @@
<th>Total fiat due</th> <th>Total fiat due</th>
<td>@Model.Fiat</td> <td>@Model.Fiat</td>
</tr> </tr>
<tr>
<th>Notification Email</th>
<td>@Model.NotificationEmail</td>
</tr>
<tr> <tr>
<th>Notification Url</th> <th>Notification Url</th>
<td>@Model.NotificationUrl</td> <td>@Model.NotificationUrl</td>
@@ -167,14 +171,14 @@
<th class="text-right">Rate</th> <th class="text-right">Rate</th>
<th class="text-right">Paid</th> <th class="text-right">Paid</th>
<th class="text-right">Due</th> <th class="text-right">Due</th>
@if(Model.StatusException == "paidOver") @if (Model.StatusException == "paidOver")
{ {
<th class="text-right">Overpaid</th> <th class="text-right">Overpaid</th>
} }
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach(var payment in Model.CryptoPayments) @foreach (var payment in Model.CryptoPayments)
{ {
<tr> <tr>
<td>@payment.PaymentMethod</td> <td>@payment.PaymentMethod</td>
@@ -182,7 +186,7 @@
<td class="text-right">@payment.Rate</td> <td class="text-right">@payment.Rate</td>
<td class="text-right">@payment.Paid</td> <td class="text-right">@payment.Paid</td>
<td class="text-right">@payment.Due</td> <td class="text-right">@payment.Due</td>
@if(Model.StatusException == "paidOver") @if (Model.StatusException == "paidOver")
{ {
<td class="text-right">@payment.Overpaid</td> <td class="text-right">@payment.Overpaid</td>
} }
@@ -192,7 +196,7 @@
</table> </table>
</div> </div>
</div> </div>
@if(Model.OnChainPayments.Count > 0) @if (Model.OnChainPayments.Count > 0)
{ {
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
@@ -207,7 +211,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach(var payment in Model.OnChainPayments) @foreach (var payment in Model.OnChainPayments)
{ {
var replaced = payment.Replaced ? "class='linethrough'" : ""; var replaced = payment.Replaced ? "class='linethrough'" : "";
<tr @replaced> <tr @replaced>
@@ -226,7 +230,7 @@
</div> </div>
</div> </div>
} }
@if(Model.OffChainPayments.Count > 0) @if (Model.OffChainPayments.Count > 0)
{ {
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
@@ -239,7 +243,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach(var payment in Model.OffChainPayments) @foreach (var payment in Model.OffChainPayments)
{ {
<tr> <tr>
<td>@payment.Crypto</td> <td>@payment.Crypto</td>
@@ -262,7 +266,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach(var address in Model.Addresses) @foreach (var address in Model.Addresses)
{ {
var current = address.Current ? "font-weight-bold" : ""; var current = address.Current ? "font-weight-bold" : "";
<tr> <tr>
@@ -286,7 +290,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach(var evt in Model.Events) @foreach (var evt in Model.Events)
{ {
<tr> <tr>
<td>@evt.Timestamp.ToBrowserDate()</td> <td>@evt.Timestamp.ToBrowserDate()</td>

View File

@@ -32,10 +32,27 @@
If you want all confirmed and complete invoices, you can duplicate a filter <code>status:confirmed status:complete</code>. If you want all confirmed and complete invoices, you can duplicate a filter <code>status:confirmed status:complete</code>.
</p> </p>
</div> </div>
</div>
</div>
<div class="row no-gutter" style="margin-bottom: 5px;">
<div class="col-lg-4">
<a asp-action="CreateInvoice" class="btn btn-primary" role="button"><span class="fa fa-plus"></span> Create a new invoice</a>
<a class="btn btn-primary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Export
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a asp-action="Export" asp-route-format="json" asp-route-searchTerm="@Model.SearchTerm" class="dropdown-item" target="_blank">JSON</a>
</div>
</div>
<div class="col-lg-8">
<div class="form-group"> <div class="form-group">
<form asp-action="SearchInvoice" method="post"> <form asp-action="SearchInvoice" method="post" style="float:right;">
<div class="input-group"> <div class="input-group">
<input asp-for="SearchTerm" class="form-control" /> <input asp-for="SearchTerm" class="form-control" style="width:300px;" />
<span class="input-group-btn"> <span class="input-group-btn">
<button type="submit" class="btn btn-primary" title="Search invoice"> <button type="submit" class="btn btn-primary" title="Search invoice">
<span class="fa fa-search"></span> Search <span class="fa fa-search"></span> Search
@@ -50,7 +67,6 @@
</div> </div>
<div class="row"> <div class="row">
<a asp-action="CreateInvoice" class="btn btn-primary" role="button"><span class="fa fa-plus"></span> Create a new invoice</a>
<table class="table table-sm table-responsive-md"> <table class="table table-sm table-responsive-md">
<thead> <thead>
<tr> <tr>
@@ -63,12 +79,12 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach(var invoice in Model.Invoices) @foreach (var invoice in Model.Invoices)
{ {
<tr> <tr>
<td>@invoice.Date.ToTimeAgo()</td> <td>@invoice.Date.ToTimeAgo()</td>
<td> <td>
@if(invoice.RedirectUrl != string.Empty) @if (invoice.RedirectUrl != string.Empty)
{ {
<a href="@invoice.RedirectUrl">@invoice.OrderId</a> <a href="@invoice.RedirectUrl">@invoice.OrderId</a>
} }
@@ -78,7 +94,7 @@
} }
</td> </td>
<td>@invoice.InvoiceId</td> <td>@invoice.InvoiceId</td>
@if(invoice.Status == "paid") @if (invoice.Status == "paid")
{ {
<td> <td>
<div class="btn-group"> <div class="btn-group">
@@ -97,7 +113,7 @@
} }
<td style="text-align:right">@invoice.AmountCurrency</td> <td style="text-align:right">@invoice.AmountCurrency</td>
<td style="text-align:right"> <td style="text-align:right">
@if(invoice.ShowCheckout) @if (invoice.ShowCheckout)
{ {
<a asp-action="Checkout" asp-route-invoiceId="@invoice.InvoiceId">Checkout</a> <span>-</span> <a asp-action="Checkout" asp-route-invoiceId="@invoice.InvoiceId">Checkout</a> <span>-</span>
}<a asp-action="Invoice" asp-route-invoiceId="@invoice.InvoiceId">Details</a> }<a asp-action="Invoice" asp-route-invoiceId="@invoice.InvoiceId">Details</a>
@@ -107,7 +123,7 @@
</tbody> </tbody>
</table> </table>
<span> <span>
@if(Model.Skip != 0) @if (Model.Skip != 0)
{ {
<a href="@Url.Action("ListInvoices", new <a href="@Url.Action("ListInvoices", new
{ {

View File

@@ -144,7 +144,7 @@ $(document).ready(function () {
progressStart(srvModel.maxTimeSeconds); // Progress bar progressStart(srvModel.maxTimeSeconds); // Progress bar
if (srvModel.requiresRefundEmail && !validateEmail(srvModel.customerEmail)) if (srvModel.requiresRefundEmail && !validateEmail(srvModel.customerEmail))
emailForm(); // Email form Display showEmailForm();
else else
hideEmailForm(); hideEmailForm();
} }
@@ -160,7 +160,7 @@ $(document).ready(function () {
} }
// Email Form // Email Form
// Setup Email mode // Setup Email mode
function emailForm() { function showEmailForm() {
$(".modal-dialog").addClass("enter-purchaser-email"); $(".modal-dialog").addClass("enter-purchaser-email");
$("#emailAddressForm .action-button").click(function () { $("#emailAddressForm .action-button").click(function () {