Fix: Applying a discount in PoS with cart wasn't working (#5079)

This commit is contained in:
Nicolas Dorier 2023-06-16 23:02:14 +09:00 committed by GitHub
parent f11424f73a
commit e81403ec3f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 24 additions and 21 deletions

View file

@ -669,7 +669,7 @@ donation:
Assert.Equal("Wanna tip?", vmview.CustomTipText);
Assert.Equal("15,18,20", string.Join(',', vmview.CustomTipPercentages));
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, null, null, null, null, "orange").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, choiceKey: "orange").Result);
//
var invoices = await user.BitPay.GetInvoicesAsync();
@ -678,7 +678,7 @@ donation:
Assert.Equal("CAD", orangeInvoice.Currency);
Assert.Equal("orange", orangeInvoice.ItemDesc);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, null, null, null, null, "apple").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, choiceKey: "apple").Result);
invoices = user.BitPay.GetInvoices();
var appleInvoice = invoices.SingleOrDefault(invoice => invoice.ItemCode.Equals("apple"));
@ -687,7 +687,7 @@ donation:
// testing custom amount
var action = Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 6.6m, null, null, null, null, "donation").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 6.6m, choiceKey: "donation").Result);
Assert.Equal(nameof(UIInvoiceController.Checkout), action.ActionName);
invoices = user.BitPay.GetInvoices();
var donationInvoice = invoices.Single(i => i.Price == 6.6m);
@ -760,20 +760,20 @@ noninventoryitem:
await tester.WaitForEvent<AppInventoryUpdaterHostedService.UpdateAppInventory>(() =>
{
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "inventoryitem").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, choiceKey: "inventoryitem").Result);
return Task.CompletedTask;
});
//we already bought all available stock so this should fail
await Task.Delay(100);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "inventoryitem").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, choiceKey: "inventoryitem").Result);
//inventoryitem has unlimited items available
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "noninventoryitem").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, choiceKey: "noninventoryitem").Result);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "noninventoryitem").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, choiceKey: "noninventoryitem").Result);
//verify invoices where created
invoices = user.BitPay.GetInvoices();
@ -809,9 +809,9 @@ normal:
vmpos.Template = AppService.SerializeTemplate(MigrationStartupTask.ParsePOSYML(vmpos.Template));
Assert.IsType<RedirectToActionResult>(pos.UpdatePointOfSale(app.Id, vmpos).Result);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "btconly").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, choiceKey: "btconly").Result);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, null, null, null, null, "normal").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 1, choiceKey: "normal").Result);
invoices = user.BitPay.GetInvoices();
var normalInvoice = invoices.Single(invoice => invoice.ItemCode == "normal");
var btcOnlyInvoice = invoices.Single(invoice => invoice.ItemCode == "btconly");
@ -865,7 +865,7 @@ g:
Assert.Contains(items, item => item.Id == "g" && item.PriceType == ViewPointOfSaleViewModel.ItemPriceType.Topup);
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Static, null, null, null, null, null, "g").Result);
.ViewPointOfSale(app.Id, PosViewType.Static, choiceKey: "g").Result);
invoices = user.BitPay.GetInvoices();
var topupInvoice = invoices.Single(invoice => invoice.ItemCode == "g");
Assert.Equal(0, topupInvoice.Price);

View file

@ -135,10 +135,10 @@ donation:
Assert.Equal("donation", vmview.Items[1].Title);
// orange is available
Assert.IsType<RedirectToActionResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, null, null, null, null, "orange").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, choiceKey: "orange").Result);
// apple is not found
Assert.IsType<NotFoundResult>(publicApps
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, null, null, null, null, "apple").Result);
.ViewPointOfSale(app.Id, PosViewType.Cart, 0, choiceKey: "apple").Result);
}
}
}

View file

@ -131,6 +131,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
public async Task<IActionResult> ViewPointOfSale(string appId,
PosViewType? viewType = null,
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal? amount = null,
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal? tip = null,
[ModelBinder(typeof(InvariantDecimalModelBinder))] decimal? discount = null,
string email = null,
string orderId = null,
string notificationUrl = null,
@ -197,7 +199,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
if (!settings.ShowCustomAmount && currentView != PosViewType.Cart && currentView != PosViewType.Light)
return NotFound();
price = amount;
price = 0.0m;
title = settings.Title;
//if cart IS enabled and we detect posdata that matches the cart system's, check inventory for the items
@ -205,7 +207,6 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
AppService.TryParsePosCartItems(jposData, out cartItems))
{
choices = AppService.Parse(settings.Template, false);
var expectedMinimumAmount = 0m;
foreach (var cartItem in cartItems)
{
var itemChoice = choices.FirstOrDefault(c => c.Id == cartItem.Key);
@ -229,13 +230,12 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
expectedCartItemPrice = itemChoice.Price ?? 0;
}
expectedMinimumAmount += expectedCartItemPrice * cartItem.Value;
}
if (expectedMinimumAmount > amount)
{
return RedirectToAction(nameof(ViewPointOfSale), new { appId });
price += expectedCartItemPrice * cartItem.Value;
}
if (discount is decimal d)
price -= price * d/100.0m;
if (tip is decimal t)
price += t;
}
}

View file

@ -197,6 +197,8 @@
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">
<button id="js-cart-pay" class="btn btn-primary btn-lg" type="submit">
<b>@Model.CustomButtonText</b>

View file

@ -328,6 +328,8 @@ Cart.prototype.updateTip = function(amount) {
// Update hidden total amount value to be sent to the checkout page
Cart.prototype.updateAmount = function() {
$('#js-cart-amount').val(this.getTotal(true));
$('#js-cart-tip').val(this.tip);
$('#js-cart-discount').val(this.discount);
}
Cart.prototype.updatePosData = function() {
@ -690,7 +692,6 @@ Cart.prototype.destroy = function(keepAmount) {
} else {
this.removeItemAll();
}
localStorage.removeItem(this.getStorageKey('cart'));
}