Fix: Custom amount in Product List mode would return error 404

This commit is contained in:
nicolas.dorier
2025-06-11 18:32:20 +09:00
parent cc5a04e8f0
commit 8f3c67b3ee
5 changed files with 73 additions and 7 deletions

View File

@@ -800,6 +800,9 @@ g:
var topupInvoice = invoices.Single(invoice => invoice.ItemCode == "g"); var topupInvoice = invoices.Single(invoice => invoice.ItemCode == "g");
Assert.Equal(0, topupInvoice.Price); Assert.Equal(0, topupInvoice.Price);
Assert.Equal("new", topupInvoice.Status); Assert.Equal("new", topupInvoice.Status);
var client = await user.CreateClient();
var inv = await client.GetInvoice(user.StoreId, topupInvoice.Id);
Assert.Equal(InvoiceType.TopUp, inv.Type);
} }
} }
} }

View File

@@ -12,6 +12,7 @@ using BTCPayServer.Plugins.PointOfSale;
using BTCPayServer.Plugins.PointOfSale.Controllers; using BTCPayServer.Plugins.PointOfSale.Controllers;
using BTCPayServer.Plugins.PointOfSale.Models; using BTCPayServer.Plugins.PointOfSale.Models;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using BTCPayServer.Views.Stores;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Playwright; using Microsoft.Playwright;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@@ -474,6 +475,66 @@ goodies:
} }
} }
[Fact]
[Trait("Playwright", "Playwright")]
public async Task CanUsePOSProductList()
{
await using var s = CreatePlaywrightTester();
await s.StartAsync();
await s.RegisterNewUser();
s.AsTestAccount();
await s.GoToHome();
await s.CreateNewStore();
await s.GoToStore();
await s.AddDerivationScheme();
// Let's check Custom amount works as expected
await s.CreateApp("PointOfSale");
var appUrl = s.Page.Url;
await s.Page.FillAsync("#Currency", "BTC");
await s.Page.SetCheckedAsync("#ShowCustomAmount", true);
await s.ClickPagePrimary();
var o = s.Page.Context.WaitForPageAsync();
await s.Page.ClickAsync("#ViewApp");
await using (_ = await s.SwitchPage(o))
{
await s.Page.FillAsync("#card_herbal-tea [name='amount']", "123");
await s.Page.PressAsync("#card_herbal-tea [name='amount']", "Enter");
await AssertInvoiceAmount(s, "123.00000000 BTC");
await s.Page.GoBackAsync();
await s.Page.FillAsync("#card_custom_amount [name='amount']", "124");
await s.Page.PressAsync("#card_custom_amount [name='amount']", "Enter");
await AssertInvoiceAmount(s, "124.00000000 BTC");
await s.Page.GoBackAsync();
}
await s.GoToStore();
await s.GoToStore(StoreNavPages.Forms);
await s.ClickPagePrimary();
await s.Page.FillAsync("[name='Name']", "test");
await s.Page.ClickAsync("[name='newField1']");
await s.Page.SelectOptionAsync("#field-editor-field-type", "number");
await s.Page.FillAsync("#field-editor-field-name", "invoice_amount_adjustment");
await s.Page.PressAsync("#field-editor-field-name", "Enter");
await s.ClickPagePrimary();
await s.GoToUrl(appUrl);
await s.Page.SelectOptionAsync("#FormId", new SelectOptionValue { Label = "test" });
await s.ClickPagePrimary();
}
private static async Task AssertInvoiceAmount(PlaywrightTester s, string expectedAmount)
{
var el = await s.Page.WaitForSelectorAsync("#AmountDue");
var content = await el!.TextContentAsync();
Assert.Equal(expectedAmount.NormalizeWhitespaces(), content.NormalizeWhitespaces());
}
[Fact] [Fact]
[Trait("Playwright", "Playwright")] [Trait("Playwright", "Playwright")]
public async Task CanUsePOSKeypad() public async Task CanUsePOSKeypad()

View File

@@ -215,15 +215,16 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
{ {
jposData.Cart = new PosAppCartItem[] { new() { Id = choiceKey, Count = 1, Price = amount ?? 0 } }; jposData.Cart = new PosAppCartItem[] { new() { Id = choiceKey, Count = 1, Price = amount ?? 0 } };
} }
jposData.Cart ??= []; jposData.Cart ??= [];
if (currentView is PosViewType.Print) if (currentView is PosViewType.Print)
return NotFound(); return NotFound();
if (currentView is PosViewType.Cart or PosViewType.Static && jposData.Cart.Length == 0) if (currentView is PosViewType.Cart && jposData.Cart.Length == 0)
return NotFound(); return NotFound();
if (jposData.Amounts is null && if (string.IsNullOrEmpty(choiceKey) &&
currentView == PosViewType.Light && jposData.Amounts is null &&
amount is { } o) amount is { } o)
{ {
order.AddLine(new("", 1, o, settings.DefaultTaxRate)); order.AddLine(new("", 1, o, settings.DefaultTaxRate));
@@ -323,7 +324,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
var receiptData = new PosReceiptData(); var receiptData = new PosReceiptData();
var summary = order.Calculate(); var summary = order.Calculate();
var isTopup = selectedChoices?.FirstOrDefault()?.Price is null && currentView == PosViewType.Static; var isTopup = currentView == PosViewType.Static &&
selectedChoices.Any(c => c.PriceType == AppItemPriceType.Topup);
if (!isTopup) if (!isTopup)
{ {
jposData.ItemsTotal = summary.ItemsTotal; jposData.ItemsTotal = summary.ItemsTotal;

View File

@@ -10,7 +10,7 @@ public class PoSOrder
private readonly int _decimals; private readonly int _decimals;
decimal _discount; decimal _discount;
decimal _tip; decimal _tip;
List<ItemLine> ItemLines = new(); public List<ItemLine> ItemLines = new();
public PoSOrder(int decimals) public PoSOrder(int decimals)
{ {

View File

@@ -35,7 +35,7 @@
: item.BuyButtonText; : item.BuyButtonText;
buttonText = buttonText.Replace("{0}", formatted).Replace("{Price}", formatted); buttonText = buttonText.Replace("{0}", formatted).Replace("{Price}", formatted);
<div class="col posItem posItem--displayed@(x == 0 ? " posItem--first" : null)@(x == Model.Items.Length - 1 && !Model.ShowCustomAmount ? " posItem--last" : null)"> <div id="card_@item.Id" class="col posItem posItem--displayed@(x == 0 ? " posItem--first" : null)@(x == Model.Items.Length - 1 && !Model.ShowCustomAmount ? " posItem--last" : null)">
<div class="tile card" data-id="@x"> <div class="tile card" data-id="@x">
@if (!string.IsNullOrWhiteSpace(item.Image)) @if (!string.IsNullOrWhiteSpace(item.Image))
{ {
@@ -92,7 +92,7 @@
} }
@if (Model.ShowCustomAmount) @if (Model.ShowCustomAmount)
{ {
<div class="col posItem posItem--displayed posItem--last@(Model.Items.Length == 0 ? " posItem--first" : null)"> <div id="card_custom_amount" class="col posItem posItem--displayed posItem--last@(Model.Items.Length == 0 ? " posItem--first" : null)">
<div class="card h-100 px-0"> <div class="card h-100 px-0">
<div class="card-body p-3 d-flex flex-column gap-2 mb-auto"> <div class="card-body p-3 d-flex flex-column gap-2 mb-auto">
<h5 class="card-title" text-translate="true">Custom Amount</h5> <h5 class="card-title" text-translate="true">Custom Amount</h5>