POS: Fix accounting for manually entered keypad amounts (#6178)

* POS: Fix accounting for manually entered keypad amounts

For keypad orders where there are products AND manual amount entries, we didn't account for the latter.

Fixes #6168.

* Adjust wording: "Manual entry" becomes "Custom Amount"
This commit is contained in:
d11n 2024-09-12 14:36:35 +02:00 committed by GitHub
parent 666445e8f7
commit 0238dffc7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 28 additions and 15 deletions

View file

@ -2690,9 +2690,9 @@ namespace BTCPayServer.Tests
var sums = cartData.FindElements(By.CssSelector("tfoot tr"));
Assert.Equal(2, items.Count);
Assert.Equal(4, sums.Count);
Assert.Contains("Manual entry 1", items[0].FindElement(By.CssSelector("th")).Text);
Assert.Contains("Custom Amount 1", items[0].FindElement(By.CssSelector("th")).Text);
Assert.Contains("1 234,00 €", items[0].FindElement(By.CssSelector("td")).Text);
Assert.Contains("Manual entry 2", items[1].FindElement(By.CssSelector("th")).Text);
Assert.Contains("Custom Amount 2", items[1].FindElement(By.CssSelector("th")).Text);
Assert.Contains("0,56 €", items[1].FindElement(By.CssSelector("td")).Text);
Assert.Contains("Subtotal", sums[0].FindElement(By.CssSelector("th")).Text);
Assert.Contains("1 234,56 €", sums[0].FindElement(By.CssSelector("td")).Text);
@ -2713,9 +2713,9 @@ namespace BTCPayServer.Tests
sums = paymentDetails.FindElements(By.CssSelector("tr.sums-data"));
Assert.Equal(2, items.Count);
Assert.Equal(4, sums.Count);
Assert.Contains("Manual entry 1", items[0].FindElement(By.CssSelector(".key")).Text);
Assert.Contains("Custom Amount 1", items[0].FindElement(By.CssSelector(".key")).Text);
Assert.Contains("1 234,00 €", items[0].FindElement(By.CssSelector(".val")).Text);
Assert.Contains("Manual entry 2", items[1].FindElement(By.CssSelector(".key")).Text);
Assert.Contains("Custom Amount 2", items[1].FindElement(By.CssSelector(".key")).Text);
Assert.Contains("0,56 €", items[1].FindElement(By.CssSelector(".val")).Text);
Assert.Contains("Subtotal", sums[0].FindElement(By.CssSelector(".key")).Text);
Assert.Contains("1 234,56 €", sums[0].FindElement(By.CssSelector(".val")).Text);
@ -2776,7 +2776,7 @@ namespace BTCPayServer.Tests
Assert.Contains("1 x 1,00 € = 1,00 €", items[0].FindElement(By.CssSelector("td")).Text);
Assert.Contains("Green Tea", items[1].FindElement(By.CssSelector("th")).Text);
Assert.Contains("2 x 1,00 € = 2,00 €", items[1].FindElement(By.CssSelector("td")).Text);
Assert.Contains("Manual entry 1", items[2].FindElement(By.CssSelector("th")).Text);
Assert.Contains("Custom Amount 1", items[2].FindElement(By.CssSelector("th")).Text);
Assert.Contains("1,23 €", items[2].FindElement(By.CssSelector("td")).Text);
Assert.Contains("Total", sums[0].FindElement(By.CssSelector("th")).Text);
Assert.Contains("4,23 €", sums[0].FindElement(By.CssSelector("td")).Text);
@ -2795,7 +2795,7 @@ namespace BTCPayServer.Tests
Assert.Contains("1 x 1,00 € = 1,00 €", items[0].FindElement(By.CssSelector(".val")).Text);
Assert.Contains("Green Tea", items[1].FindElement(By.CssSelector(".key")).Text);
Assert.Contains("2 x 1,00 € = 2,00 €", items[1].FindElement(By.CssSelector(".val")).Text);
Assert.Contains("Manual entry 1", items[2].FindElement(By.CssSelector(".key")).Text);
Assert.Contains("Custom Amount 1", items[2].FindElement(By.CssSelector(".key")).Text);
Assert.Contains("1,23 €", items[2].FindElement(By.CssSelector(".val")).Text);
Assert.Contains("Total", sums[0].FindElement(By.CssSelector(".key")).Text);
Assert.Contains("4,23 €", sums[0].FindElement(By.CssSelector(".val")).Text);

View file

@ -377,7 +377,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
{
for (var i = 0; i < amountsArray.Count; i++)
{
cartData.Add($"Manual entry {i+1}", _displayFormatter.Currency(amountsArray[i].ToObject<decimal>(), settings.Currency, DisplayFormatter.CurrencyFormat.Symbol));
cartData.Add($"Custom Amount {i+1}", _displayFormatter.Currency(amountsArray[i].ToObject<decimal>(), settings.Currency, DisplayFormatter.CurrencyFormat.Symbol));
}
}
receiptData.Add("Cart", cartData);

View file

@ -151,9 +151,13 @@ namespace BTCPayServer.Services.Apps
{
// flatten single items from POS data
var data = e.Metadata.PosData?.ToObject<PosAppData>();
if (data is { Cart.Length: > 0 })
var hasCart = data is { Cart.Length: > 0 };
var hasAmounts = data is { Amounts.Length: > 0 };
var date = e.InvoiceTime.Date;
var itemCode = e.Metadata.ItemCode ?? typeof(Plugins.PointOfSale.PosViewType).DisplayName(Plugins.PointOfSale.PosViewType.Light.ToString());
if (hasCart)
{
foreach (var lineItem in data.Cart)
foreach (var lineItem in data!.Cart)
{
var item = items.FirstOrDefault(p => p.Id == lineItem.Id);
if (item == null)
@ -165,18 +169,23 @@ namespace BTCPayServer.Services.Apps
{
ItemCode = item.Id,
FiatPrice = lineItem.Price,
Date = e.InvoiceTime.Date
Date = date
});
}
}
}
else
if (hasAmounts)
{
res.AddRange(data!.Amounts.Select(amount => new InvoiceStatsItem { ItemCode = itemCode, FiatPrice = amount, Date = date }));
}
// no further info, just add the total amount
if (!hasCart && !hasAmounts)
{
res.Add(new InvoiceStatsItem
{
ItemCode = e.Metadata.ItemCode ?? typeof(Plugins.PointOfSale.PosViewType).DisplayName(Plugins.PointOfSale.PosViewType.Light.ToString()),
ItemCode = itemCode,
FiatPrice = e.PaidAmount.Net,
Date = e.InvoiceTime.Date
Date = date
});
}
return res;

View file

@ -11,6 +11,9 @@ public class PosAppData
[JsonProperty(PropertyName = "cart")]
public PosAppCartItem[] Cart { get; set; }
[JsonProperty(PropertyName = "amounts")]
public decimal[] Amounts { get; set; }
[JsonProperty(PropertyName = "customAmount")]
public decimal CustomAmount { get; set; }

View file

@ -32,9 +32,10 @@ document.addEventListener("DOMContentLoaded",function () {
calculation () {
if (!this.tipNumeric && !(this.discountNumeric > 0 || this.discountPercentNumeric > 0) && this.amounts.length < 2 && this.cart.length === 0) return null
let calc = ''
const hasAmounts = this.amounts.length && this.amounts.reduce((sum, amt) => sum + parseFloat(amt || 0), 0) > 0;
if (this.cart.length) calc += this.cart.map(item => `${item.count} x ${item.title} (${this.formatCurrency(item.price, true)}) = ${this.formatCurrency((item.price||0) * item.count, true)}`).join(' + ')
if (this.cart.length && this.amounts.length) calc += ' + '
if (this.amounts.length) calc += this.amounts.map(amt => this.formatCurrency(amt, true)).join(' + ')
if (this.cart.length && hasAmounts) calc += ' + '
if (hasAmounts) calc += this.amounts.map(amt => this.formatCurrency(amt || 0, true)).join(' + ')
if (this.discountNumeric > 0 || this.discountPercentNumeric > 0) calc += ` - ${this.formatCurrency(this.discountNumeric, true)} (${this.discountPercent}%)`
if (this.tipNumeric > 0) calc += ` + ${this.formatCurrency(this.tipNumeric, true)}`
if (this.tipPercent) calc += ` (${this.tipPercent}%)`