POS: Account for custom amount in cart view (#5151)

* Add failing test

* Account for custom amount

* Test fix
This commit is contained in:
d11n 2023-07-05 10:23:15 +02:00 committed by GitHub
parent f6b27cc5f9
commit e998340387
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 28 deletions

View File

@ -2161,6 +2161,70 @@ namespace BTCPayServer.Tests
Assert.Contains("1 222,21 €", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
}
[Fact]
[Trait("Selenium", "Selenium")]
[Trait("Lightning", "Lightning")]
public async Task CanUsePOSCart()
{
using var s = CreateSeleniumTester();
s.Server.ActivateLightning();
await s.StartAsync();
await s.Server.EnsureChannelsSetup();
s.RegisterNewUser(true);
s.CreateNewStore();
s.GoToStore();
s.AddLightningNode(LightningConnectionType.CLightning, false);
s.Driver.FindElement(By.Id("StoreNav-CreatePointOfSale")).Click();
s.Driver.FindElement(By.Id("AppName")).SendKeys(Guid.NewGuid().ToString());
s.Driver.FindElement(By.Id("Create")).Click();
Assert.Contains("App successfully created", s.FindAlertMessage().Text);
s.Driver.FindElement(By.CssSelector("label[for='DefaultView_Cart']")).Click();
s.Driver.FindElement(By.Id("Currency")).SendKeys("EUR");
s.Driver.FindElement(By.Id("ShowCustomAmount")).Click();
s.Driver.FindElement(By.Id("SaveSettings")).Click();
Assert.Contains("App updated", s.FindAlertMessage().Text);
s.Driver.FindElement(By.Id("ViewApp")).Click();
var windows = s.Driver.WindowHandles;
Assert.Equal(2, windows.Count);
s.Driver.SwitchTo().Window(windows[1]);
s.Driver.WaitForElement(By.Id("js-cart-list"));
Assert.Empty(s.Driver.FindElements(By.CssSelector("#js-cart-list tbody tr")));
Assert.Equal("0,00 €", s.Driver.FindElement(By.Id("CartTotal")).Text);
Assert.False(s.Driver.FindElement(By.Id("CartClear")).Displayed);
// Select and clear
s.Driver.FindElement(By.CssSelector(".card.js-add-cart:nth-child(1)")).Click();
Assert.Single(s.Driver.FindElements(By.CssSelector("#js-cart-list tbody tr")));
s.Driver.FindElement(By.Id("CartClear")).Click();
Assert.Empty(s.Driver.FindElements(By.CssSelector("#js-cart-list tbody tr")));
Thread.Sleep(250);
// Select items
s.Driver.FindElement(By.CssSelector(".card.js-add-cart:nth-child(2)")).Click();
Thread.Sleep(250);
s.Driver.FindElement(By.CssSelector(".card.js-add-cart:nth-child(1)")).Click();
Thread.Sleep(250);
Assert.Equal(2, s.Driver.FindElements(By.CssSelector("#js-cart-list tbody tr")).Count);
Assert.Equal("2,00 €", s.Driver.FindElement(By.Id("CartTotal")).Text);
// Custom amount
s.Driver.FindElement(By.Id("CartCustomAmount")).SendKeys("1.5");
s.Driver.FindElement(By.Id("CartTotal")).Click();
Assert.Equal("3,50 €", s.Driver.FindElement(By.Id("CartTotal")).Text);
s.Driver.FindElement(By.Id("js-cart-confirm")).Click();
// Pay
Assert.Equal("3,50 €", s.Driver.FindElement(By.Id("CartSummaryTotal")).Text);
s.Driver.FindElement(By.Id("js-cart-pay")).Click();
s.Driver.WaitUntilAvailable(By.Id("Checkout-v2"));
s.Driver.FindElement(By.Id("DetailsToggle")).Click();
s.Driver.WaitForElement(By.Id("PaymentDetails-TotalFiat"));
Assert.Contains("3,50 €", s.Driver.FindElement(By.Id("PaymentDetails-TotalFiat")).Text);
}
[Fact]
[Trait("Selenium", "Selenium")]
[Trait("Lightning", "Lightning")]

View File

@ -133,6 +133,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal? amount = null,
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal? tip = null,
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal? discount = null,
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal? customAmount = null,
string email = null,
string orderId = null,
string notificationUrl = null,
@ -232,9 +233,11 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
price += expectedCartItemPrice * cartItem.Value;
}
if (discount is decimal d)
if (customAmount is { } c)
price += c;
if (discount is { } d)
price -= price * d/100.0m;
if (tip is decimal t)
if (tip is { } t)
price += t;
}
}

View File

@ -51,17 +51,15 @@
<td class="align-middle text-end">{price}</td>
</tr>
</script>
<script id="template-cart-item-image" type="text/template">
<img class="cart-item-image" src="{image}" alt="">
</script>
<script id="template-cart-custom-amount" type="text/template">
<tr>
<td colspan="5">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-shopping-cart fa-fw"></i></span>
<input class="js-cart-custom-amount form-control" type="number" min="0" step="@Model.Step" name="amount" placeholder="Pay what you want">
<input class="js-cart-custom-amount form-control" type="number" min="0" step="@Model.Step" name="amount" placeholder="Pay what you want" id="CartCustomAmount">
<div class="input-group-text">
<a class="js-cart-custom-amount-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
</div>
@ -69,7 +67,6 @@
</td>
</tr>
</script>
<script id="template-cart-extra" type="text/template">
@if (Model.ShowCustomAmount)
{
@ -77,7 +74,7 @@
<th colspan="5" class="border-0 pb-0">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-shopping-cart fa-fw"></i></span>
<input class="js-cart-custom-amount form-control" type="number" min="0" step="@Model.Step" name="amount" value="{customAmount}" placeholder="Pay what you want">
<input class="js-cart-custom-amount form-control" type="number" min="0" step="@Model.Step" name="amount" value="{customAmount}" placeholder="Pay what you want" id="CartCustomAmount">
<a class="js-cart-custom-amount-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
</div>
</th>
@ -89,14 +86,13 @@
<th colspan="5" class="border-top-0">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-percent fa-fw"></i></span>
<input class="js-cart-discount form-control" type="number" min="0" step="@Model.Step" value="{discount}" name="discount" placeholder="Discount in %">
<input class="js-cart-discount form-control" type="number" min="0" step="@Model.Step" value="{discount}" name="discount" placeholder="Discount in %" id="CartDiscount">
<a class="js-cart-discount-remove btn btn-danger" href="#"><i class="fa fa-times"></i></a>
</div>
</th>
</tr>
}
</script>
<script id="template-cart-tip" type="text/template">
@if (Model.EnableTips)
{
@ -135,12 +131,11 @@
</tr>
}
</script>
<script id="template-cart-total" type="text/template">
<tr>
<th colspan="1" class="pb-4 h4">Total</th>
<th colspan="4" class="pb-4 h4 text-end">
<span class="js-cart-total">{total}</span>
<span class="js-cart-total" id="CartTotal">{total}</span>
</th>
</tr>
</script>
@ -162,7 +157,7 @@
</tr>
<tr>
<td class="border-0 pb-0 h6">Total products</td>
<td align="right" class="border-0 pb-0 h6">
<td class="text-end border-0 pb-0 h6">
<span class="js-cart-summary-products text-nowrap"></span>
</td>
</tr>
@ -170,8 +165,8 @@
{
<tr>
<td class="border-0 pb-y h6">Discount</td>
<td align="right" class="border-0 pb-y h6">
<span class="js-cart-summary-discount text-nowrap"></span>
<td class="text-end border-0 pb-y h6">
<span class="js-cart-summary-discount text-nowrap" id="CartSummaryDiscount"></span>
</td>
</tr>
}
@ -179,15 +174,15 @@
{
<tr>
<td class="border-top-0 pt-0 h6">Tip</td>
<td align="right" class="border-top-0 pt-0 h6">
<span class="js-cart-summary-tip text-nowrap"></span>
<td class="text-end border-top-0 pt-0 h6">
<span class="js-cart-summary-tip text-nowrap" id="CartSummaryTip"></span>
</td>
</tr>
}
<tr>
<td class="h3 table-light">Total</td>
<td class="h3 table-light text-end">
<span class="js-cart-summary-total text-nowrap"></span>
<span class="js-cart-summary-total text-nowrap" id="CartSummaryTotal"></span>
</td>
</tr>
</tbody>
@ -202,10 +197,11 @@
asp-antiforgery="false"
data-buy
>
<input id="js-cart-amount" class="form-control" type="hidden" name="amount">
<input id="js-cart-tip" class="form-control" type="hidden" name="tip">
<input id="js-cart-discount" class="form-control" type="hidden" name="discount">
<input id="js-cart-posdata" class="form-control" type="hidden" name="posdata">
<input id="js-cart-amount" type="hidden" name="amount">
<input id="js-cart-custom-amount" type="hidden" name="customAmount">
<input id="js-cart-tip" type="hidden" name="tip">
<input id="js-cart-discount" type="hidden" name="discount">
<input id="js-cart-posdata" type="hidden" name="posdata">
<button id="js-cart-pay" class="btn btn-primary btn-lg" type="submit">
<b>@Model.CustomButtonText</b>
</button>
@ -318,7 +314,7 @@
<a class="js-cart btn btn-sm bg-white text-black pull-right ms-5" href="#">
<i class="fa fa-times fa-lg"></i>
</a>
<a class="js-cart-destroy btn btn-danger pull-right" href="#" style="display: none;">Empty cart <i class="fa fa-trash fa-fw fa-lg"></i></a>
<a class="js-cart-destroy btn btn-danger pull-right" href="#" style="display: none;" id="CartClear">Empty cart <i class="fa fa-trash fa-fw fa-lg"></i></a>
</div>
<table id="js-cart-list" class="table table-responsive table-light mt-0 mb-0">

View File

@ -330,9 +330,9 @@ Cart.prototype.updateAmount = function() {
$('#js-cart-amount').val(this.getTotal(true));
$('#js-cart-tip').val(this.tip);
$('#js-cart-discount').val(this.discount);
$('#js-cart-custom-amount').val(this.customAmount);
}
Cart.prototype.updatePosData = function() {
var result = {
cart: this.content,
customAmount: this.fromCents(this.getCustomAmount()),