Preserving title with custom amount (#403)

* Preserving title with custom amount

* Custom button texts for complete localization

* Update tests, now checking custom amount description and button text

* Support for Custom CSS in POS
This commit is contained in:
Rockstar Developer
2018-11-16 20:39:43 -06:00
committed by Nicolas Dorier
parent 24a8c4015c
commit 9d21c89151
7 changed files with 93 additions and 20 deletions

View File

@@ -1460,12 +1460,18 @@ namespace BTCPayServer.Tests
var vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model); var vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
vmpos.Title = "hello"; vmpos.Title = "hello";
vmpos.Currency = "CAD"; vmpos.Currency = "CAD";
vmpos.Template = vmpos.ButtonText = "{0} Purchase";
"apple:\n" + vmpos.CustomButtonText = "Nicolas Sexy Hair";
" price: 5.0\n" + vmpos.Template = @"
" title: good apple\n" + apple:
"orange:\n" + price: 5.0
" price: 10.0\n"; title: good apple
orange:
price: 10.0
donation:
price: 1.02
custom: true
";
Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result); Assert.IsType<RedirectToActionResult>(apps.UpdatePointOfSale(appId, vmpos).Result);
vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model); vmpos = Assert.IsType<UpdatePointOfSaleViewModel>(Assert.IsType<ViewResult>(apps.UpdatePointOfSale(appId).Result).Model);
Assert.Equal("hello", vmpos.Title); Assert.Equal("hello", vmpos.Title);
@@ -1473,16 +1479,29 @@ namespace BTCPayServer.Tests
var publicApps = user.GetController<AppsPublicController>(); var publicApps = user.GetController<AppsPublicController>();
var vmview = Assert.IsType<ViewPointOfSaleViewModel>(Assert.IsType<ViewResult>(publicApps.ViewPointOfSale(appId).Result).Model); var vmview = Assert.IsType<ViewPointOfSaleViewModel>(Assert.IsType<ViewResult>(publicApps.ViewPointOfSale(appId).Result).Model);
Assert.Equal("hello", vmview.Title); Assert.Equal("hello", vmview.Title);
Assert.Equal(2, vmview.Items.Length); Assert.Equal(3, vmview.Items.Length);
Assert.Equal("good apple", vmview.Items[0].Title); Assert.Equal("good apple", vmview.Items[0].Title);
Assert.Equal("orange", vmview.Items[1].Title); Assert.Equal("orange", vmview.Items[1].Title);
Assert.Equal(10.0m, vmview.Items[1].Price.Value); Assert.Equal(10.0m, vmview.Items[1].Price.Value);
Assert.Equal("$5.00", vmview.Items[0].Price.Formatted); Assert.Equal("$5.00", vmview.Items[0].Price.Formatted);
Assert.Equal("{0} Purchase", vmview.ButtonText);
Assert.Equal("Nicolas Sexy Hair", vmview.CustomButtonText);
Assert.IsType<RedirectResult>(publicApps.ViewPointOfSale(appId, 0, null, null, null, null, "orange").Result); Assert.IsType<RedirectResult>(publicApps.ViewPointOfSale(appId, 0, null, null, null, null, "orange").Result);
var invoice = user.BitPay.GetInvoices().First();
Assert.Equal(10.00m, invoice.Price); //
Assert.Equal("CAD", invoice.Currency); var invoices = user.BitPay.GetInvoices();
Assert.Equal("orange", invoice.ItemDesc); var orangeInvoice = invoices.First();
Assert.Equal(10.00m, orangeInvoice.Price);
Assert.Equal("CAD", orangeInvoice.Currency);
Assert.Equal("orange", orangeInvoice.ItemDesc);
// testing custom amount
Assert.IsType<RedirectResult>(publicApps.ViewPointOfSale(appId, 5, null, null, null, null, "donation").Result);
invoices = user.BitPay.GetInvoices();
var donationInvoice = invoices.First(); // expected behavior is that new invoice should now be first
Assert.Equal(5m, donationInvoice.Price);
Assert.Equal("CAD", donationInvoice.Currency);
Assert.Equal("donation", donationInvoice.ItemDesc);
} }
} }

View File

@@ -56,6 +56,13 @@ namespace BTCPayServer.Controllers
public string Currency { get; set; } public string Currency { get; set; }
public string Template { get; set; } public string Template { get; set; }
public bool ShowCustomAmount { get; set; } public bool ShowCustomAmount { get; set; }
public const string BUTTON_TEXT_DEF = "Buy for {0}";
public string ButtonText { get; set; } = BUTTON_TEXT_DEF;
public const string CUSTOM_BUTTON_TEXT_DEF = "Pay";
public string CustomButtonText { get; set; } = CUSTOM_BUTTON_TEXT_DEF;
public string CustomCSSLink { get; set; }
} }
[HttpGet] [HttpGet]
@@ -71,7 +78,10 @@ namespace BTCPayServer.Controllers
Title = settings.Title, Title = settings.Title,
ShowCustomAmount = settings.ShowCustomAmount, ShowCustomAmount = settings.ShowCustomAmount,
Currency = settings.Currency, Currency = settings.Currency,
Template = settings.Template Template = settings.Template,
ButtonText = settings.ButtonText ?? PointOfSaleSettings.BUTTON_TEXT_DEF,
CustomButtonText = settings.CustomButtonText ?? PointOfSaleSettings.CUSTOM_BUTTON_TEXT_DEF,
CustomCSSLink = settings.CustomCSSLink
}; };
if (HttpContext?.Request != null) if (HttpContext?.Request != null)
{ {
@@ -136,7 +146,10 @@ namespace BTCPayServer.Controllers
Title = vm.Title, Title = vm.Title,
ShowCustomAmount = vm.ShowCustomAmount, ShowCustomAmount = vm.ShowCustomAmount,
Currency = vm.Currency.ToUpperInvariant(), Currency = vm.Currency.ToUpperInvariant(),
Template = vm.Template Template = vm.Template,
ButtonText = vm.ButtonText,
CustomButtonText = vm.CustomButtonText,
CustomCSSLink = vm.CustomCSSLink
}); });
await UpdateAppSettings(app); await UpdateAppSettings(app);
StatusMessage = "App updated"; StatusMessage = "App updated";

View File

@@ -47,7 +47,10 @@ namespace BTCPayServer.Controllers
Step = step.ToString(CultureInfo.InvariantCulture), Step = step.ToString(CultureInfo.InvariantCulture),
ShowCustomAmount = settings.ShowCustomAmount, ShowCustomAmount = settings.ShowCustomAmount,
CurrencySymbol = currency.Symbol, CurrencySymbol = currency.Symbol,
Items = _AppsHelper.Parse(settings.Template, settings.Currency) Items = _AppsHelper.Parse(settings.Template, settings.Currency),
ButtonText = settings.ButtonText,
CustomButtonText = settings.CustomButtonText,
CustomCSSLink = settings.CustomCSSLink
}); });
} }
@@ -85,6 +88,8 @@ namespace BTCPayServer.Controllers
return NotFound(); return NotFound();
title = choice.Title; title = choice.Title;
price = choice.Price.Value; price = choice.Price.Value;
if (amount > price)
price = amount;
} }
else else
{ {

View File

@@ -23,5 +23,15 @@ namespace BTCPayServer.Models.AppViewModels
public string Example2 { get; internal set; } public string Example2 { get; internal set; }
public string ExampleCallback { get; internal set; } public string ExampleCallback { get; internal set; }
public string InvoiceUrl { get; internal set; } public string InvoiceUrl { get; internal set; }
[Required]
[MaxLength(30)]
public string ButtonText { get; set; }
[Required]
[MaxLength(30)]
public string CustomButtonText { get; set; }
[MaxLength(500)]
public string CustomCSSLink { get; set; }
} }
} }

View File

@@ -27,5 +27,10 @@ namespace BTCPayServer.Models.AppViewModels
public string Title { get; set; } public string Title { get; set; }
public Item[] Items { get; set; } public Item[] Items { get; set; }
public string CurrencySymbol { get; set; } public string CurrencySymbol { get; set; }
public string ButtonText { get; set; }
public string CustomButtonText { get; set; }
public string CustomCSSLink { get; set; }
} }
} }

View File

@@ -33,20 +33,35 @@
<label asp-for="ShowCustomAmount"></label> <label asp-for="ShowCustomAmount"></label>
<input asp-for="ShowCustomAmount" type="checkbox" class="form-check" /> <input asp-for="ShowCustomAmount" type="checkbox" class="form-check" />
</div> </div>
<div class="form-group">
<label asp-for="ButtonText" class="control-label"></label>*
<input asp-for="ButtonText" class="form-control" />
<span asp-validation-for="ButtonText" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CustomButtonText" class="control-label"></label>*
<input asp-for="CustomButtonText" class="form-control" />
<span asp-validation-for="CustomButtonText" class="text-danger"></span>
</div>
<div class="form-group"> <div class="form-group">
<label asp-for="Template" class="control-label"></label>* <label asp-for="Template" class="control-label"></label>*
<textarea asp-for="Template" rows="20" cols="40" class="form-control"></textarea> <textarea asp-for="Template" rows="20" cols="40" class="form-control"></textarea>
<span asp-validation-for="Template" class="text-danger"></span> <span asp-validation-for="Template" class="text-danger"></span>
</div> </div>
<div class="form-group">
<label asp-for="CustomCSSLink" class="control-label"></label>
<input asp-for="CustomCSSLink" class="form-control" />
<span asp-validation-for="CustomCSSLink" class="text-danger"></span>
</div>
<div class="form-group"> <div class="form-group">
<h5>Host button externally</h5> <h5>Host button externally</h5>
<p>You can host point of sale buttons in an external website with the following code.</p> <p>You can host point of sale buttons in an external website with the following code.</p>
@if(Model.Example1 != null) @if (Model.Example1 != null)
{ {
<span>For anything with a custom amount</span> <span>For anything with a custom amount</span>
<pre><code class="html">@Model.Example1</code></pre> <pre><code class="html">@Model.Example1</code></pre>
} }
@if(Model.Example2 != null) @if (Model.Example2 != null)
{ {
<span>For a specific item of your template</span> <span>For a specific item of your template</span>
<pre><code class="html">@Model.Example2</code></pre> <pre><code class="html">@Model.Example2</code></pre>
@@ -63,7 +78,7 @@
</p> </p>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="submit" class="btn btn-primary" /> <input type="submit" class="btn btn-primary" value="Save Settings" />
</div> </div>
</form> </form>
<a asp-action="ListApps">Back to the app list</a> <a asp-action="ListApps">Back to the app list</a>

View File

@@ -14,6 +14,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<link href="@this.Context.Request.GetAbsoluteUri(themeManager.BootstrapUri)" rel="stylesheet" /> <link href="@this.Context.Request.GetAbsoluteUri(themeManager.BootstrapUri)" rel="stylesheet" />
@if (Model.CustomCSSLink != null)
{
<link href="@Model.CustomCSSLink" rel="stylesheet" />
}
</head> </head>
<body class="h-100"> <body class="h-100">
<div class="container d-flex h-100"> <div class="container d-flex h-100">
@@ -41,6 +45,7 @@
@if (item.Custom) @if (item.Custom)
{ {
<form method="post" asp-antiforgery="false" data-buy> <form method="post" asp-antiforgery="false" data-buy>
<input type="hidden" name="choicekey" value="@item.Id" />
<div class="input-group"> <div class="input-group">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">@Model.CurrencySymbol</span> <span class="input-group-text">@Model.CurrencySymbol</span>
@@ -48,7 +53,7 @@
<input class="form-control" type="number" min="@item.Price.Value" step="@Model.Step" name="amount" <input class="form-control" type="number" min="@item.Price.Value" step="@Model.Step" name="amount"
value="@item.Price.Value" placeholder="Amount"> value="@item.Price.Value" placeholder="Amount">
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-primary" type="submit">Pay</button> <button class="btn btn-primary" type="submit">@Model.CustomButtonText</button>
</div> </div>
</div> </div>
</form> </form>
@@ -56,7 +61,8 @@
else else
{ {
<form method="post" asp-antiforgery="false"> <form method="post" asp-antiforgery="false">
<button type="submit" name="choiceKey" class="btn btn-primary" value="@item.Id">Buy for @item.Price.Formatted</button> <button type="submit" name="choiceKey" class="btn btn-primary" value="@item.Id">
@String.Format(Model.ButtonText, @item.Price.Formatted)</button>
</form> </form>
} }
</div> </div>
@@ -78,7 +84,7 @@
<span class="input-group-text">@Model.CurrencySymbol</span> <span class="input-group-text">@Model.CurrencySymbol</span>
</div> </div>
<input class="form-control" type="number" min="0" step="@Model.Step" name="amount" placeholder="Amount"> <input class="form-control" type="number" min="0" step="@Model.Step" name="amount" placeholder="Amount">
<div class="input-group-append"><button class="btn btn-primary" type="submit">Pay</button></div> <div class="input-group-append"><button class="btn btn-primary" type="submit">@Model.CustomButtonText</button></div>
</div> </div>
</form> </form>
</div> </div>