From 40fbdeb0ee88af27ffda256bbc8b3337158f0d15 Mon Sep 17 00:00:00 2001 From: Nicolas Dorier Date: Tue, 20 May 2025 09:39:02 +0900 Subject: [PATCH 1/4] BTCpayServerTester.WaitIsFullySynched should not wait only NBX (#6740) --- BTCPayServer.Tests/BTCPayServerTester.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BTCPayServer.Tests/BTCPayServerTester.cs b/BTCPayServer.Tests/BTCPayServerTester.cs index b339d56d8..643ba9ad6 100644 --- a/BTCPayServer.Tests/BTCPayServerTester.cs +++ b/BTCPayServer.Tests/BTCPayServerTester.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using BTCPayServer.Abstractions.Constants; +using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Configuration; using BTCPayServer.HostedServices; using BTCPayServer.Hosting; @@ -260,8 +261,8 @@ namespace BTCPayServer.Tests private async Task WaitIsFullySynched(CancellationToken cancellationToken) { - var dashBoard = GetService(); - while (!dashBoard.IsFullySynched()) + var o = GetService>().ToArray(); + while (!o.All(d => d.AllAvailable())) { await Task.Delay(10, cancellationToken).ConfigureAwait(false); } From c4097b5dddca118beef43ee4ee45f7f0606b043f Mon Sep 17 00:00:00 2001 From: napoly Date: Tue, 20 May 2025 00:40:12 +0000 Subject: [PATCH 2/4] Enable XMR plugin test setup (#6722) * Enable XMR plugin tests setup * BTCpayServerTester.WaitIsFullySynched should not wait only NBX --- BTCPayServer.Tests/TestUtils.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BTCPayServer.Tests/TestUtils.cs b/BTCPayServer.Tests/TestUtils.cs index 47f1405e8..7e0788177 100644 --- a/BTCPayServer.Tests/TestUtils.cs +++ b/BTCPayServer.Tests/TestUtils.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using NBitcoin; using OpenQA.Selenium; using Xunit; using Xunit.Sdk; @@ -22,7 +21,8 @@ namespace BTCPayServer.Tests #endif public static DirectoryInfo TryGetSolutionDirectoryInfo() { - var directory = new DirectoryInfo(TestDirectory); + var btcPayDirectory = ((OutputPathAttribute)typeof(TestUtils).Assembly.GetCustomAttributes(typeof(OutputPathAttribute), true)[0]).BuiltPath; + var directory = new DirectoryInfo(btcPayDirectory); while (directory != null && !directory.GetFiles("*.sln").Any()) { directory = directory.Parent; @@ -32,9 +32,9 @@ namespace BTCPayServer.Tests static TestUtils() { - TestDirectory = ((OutputPathAttribute)typeof(TestUtils).Assembly.GetCustomAttributes(typeof(OutputPathAttribute), true)[0]).BuiltPath; + TestDirectory = AppContext.BaseDirectory; } - public readonly static string TestDirectory; + public static readonly string TestDirectory; public static string GetTestDataFullPath(string relativeFilePath) { From 5f7a68683378eeb4a3eb975b5ccf96d5ff2b3098 Mon Sep 17 00:00:00 2001 From: Nicolas Dorier Date: Tue, 20 May 2025 13:31:29 +0900 Subject: [PATCH 3/4] Show tax rate in receipt, adjust keypad display (#6739) * Show tax rate in receipt, adjust keypad display * Adjust small nits in the view --- BTCPayServer.Tests/POSTests.cs | 18 ++++++++-------- .../Controllers/UIPointOfSaleController.cs | 2 ++ BTCPayServer/Plugins/PointOfSale/PoSOrder.cs | 15 +++++++++++++ .../Shared/PointOfSale/Public/Cart.cshtml | 14 +++++++------ .../Shared/PointOfSale/Public/VueLight.cshtml | 2 +- BTCPayServer/Views/Shared/PosData.cshtml | 4 ++-- .../UIInvoice/InvoiceReceiptPrint.cshtml | 3 --- BTCPayServer/wwwroot/pos/common.js | 21 +++++++++++++++++++ BTCPayServer/wwwroot/pos/keypad.js | 12 +++++++++-- 9 files changed, 68 insertions(+), 23 deletions(-) diff --git a/BTCPayServer.Tests/POSTests.cs b/BTCPayServer.Tests/POSTests.cs index 1537e89c4..b229525bc 100644 --- a/BTCPayServer.Tests/POSTests.cs +++ b/BTCPayServer.Tests/POSTests.cs @@ -522,23 +522,23 @@ donation: Assert.Equal("1.234,00", await s.Page.TextContentAsync("#Amount")); Assert.Equal("", await s.Page.TextContentAsync("#Calculation")); await EnterKeypad(s, "+56"); - Assert.Equal("1.234,56", await s.Page.TextContentAsync("#Amount")); + Assert.Equal("0,56", await s.Page.TextContentAsync("#Amount")); Assert.True(await s.Page.IsEnabledAsync("#ModeTablist-discount")); Assert.True(await s.Page.IsEnabledAsync("#ModeTablist-tip")); - await AssertKeypadCalculation(s, "1.234,00 € + 0,56 €"); + await AssertKeypadCalculation(s, "1.234,00 € + 0,56 € = 1.234,56 €"); // Discount: 10% await s.Page.ClickAsync("label[for='ModeTablist-discount']"); await EnterKeypad(s, "10"); - Assert.Contains("1.111,10", await s.Page.TextContentAsync("#Amount")); + Assert.Contains("0,56", await s.Page.TextContentAsync("#Amount")); Assert.Contains("10% discount", await s.Page.TextContentAsync("#Discount")); - await AssertKeypadCalculation(s, "1.234,00 € + 0,56 € - 123,46 € (10%)"); + await AssertKeypadCalculation(s, "1.234,00 € + 0,56 € - 123,46 € (10%) = 1.111,10 €"); // Tip: 10% await s.Page.ClickAsync("label[for='ModeTablist-tip']"); await s.Page.ClickAsync("#Tip-10"); - Assert.Contains("1.222,21", await s.Page.TextContentAsync("#Amount")); - await AssertKeypadCalculation(s, "1.234,00 € + 0,56 € - 123,46 € (10%) + 111,11 € (10%)"); + Assert.Contains("0,56", await s.Page.TextContentAsync("#Amount")); + await AssertKeypadCalculation(s, "1.234,00 € + 0,56 € - 123,46 € (10%) + 111,11 € (10%) = 1.222,21 €"); // Pay await s.Page.ClickAsync("#pay-button"); @@ -580,8 +580,8 @@ donation: await s.Page.ClickAsync("#ItemsListOffcanvas button[data-bs-dismiss='offcanvas']"); await EnterKeypad(s, "123"); - Assert.Contains("4,65", await s.Page.TextContentAsync("#Amount")); - await AssertKeypadCalculation(s, "2 x Green Tea (1,00 €) = 2,00 € + 1 x Black Tea (1,00 €) = 1,00 € + 1,23 € + 0,42 € (10%)"); + Assert.Contains("1,23", await s.Page.TextContentAsync("#Amount")); + await AssertKeypadCalculation(s, "2 x Green Tea (1,00 €) = 2,00 € + 1 x Black Tea (1,00 €) = 1,00 € + 1,23 € + 0,42 € (10%) = 4,65 €"); // Pay await s.Page.ClickAsync("#pay-button"); @@ -604,7 +604,7 @@ donation: ], Sums = [ new("Subtotal", "4,23 €"), - new("Tax", "0,42 €"), + new("Tax", "0,42 € (10%)"), new("Total", "4,65 €") ] }); diff --git a/BTCPayServer/Plugins/PointOfSale/Controllers/UIPointOfSaleController.cs b/BTCPayServer/Plugins/PointOfSale/Controllers/UIPointOfSaleController.cs index 2e0cc6c38..729447c7a 100644 --- a/BTCPayServer/Plugins/PointOfSale/Controllers/UIPointOfSaleController.cs +++ b/BTCPayServer/Plugins/PointOfSale/Controllers/UIPointOfSaleController.cs @@ -345,6 +345,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers if (jposData.Tax > 0) { var taxFormatted = _displayFormatter.Currency(jposData.Tax, settings.Currency, DisplayFormatter.CurrencyFormat.Symbol); + if (order.GetTaxRate() is { } r) + taxFormatted = $"{taxFormatted} ({r:0.######}%)"; receiptData.Tax = taxFormatted; } diff --git a/BTCPayServer/Plugins/PointOfSale/PoSOrder.cs b/BTCPayServer/Plugins/PointOfSale/PoSOrder.cs index a74445075..6bbce9f6a 100644 --- a/BTCPayServer/Plugins/PointOfSale/PoSOrder.cs +++ b/BTCPayServer/Plugins/PointOfSale/PoSOrder.cs @@ -1,6 +1,7 @@ #nullable enable using System; using System.Collections.Generic; +using System.Linq; namespace BTCPayServer.Plugins.PointOfSale; @@ -64,6 +65,20 @@ public class PoSOrder _tip = Round(tip); } + /// + /// Returns the tax rate of the items in the cart. + /// If the tax rates are not all the same, returns null. + /// If the cart is empty, returns null. + /// Else, returns the tax rate shared by all items + /// + /// + public decimal? GetTaxRate() + { + if (!ItemLines.Any()) + return null; + return ItemLines.GroupBy(i => i.TaxRate).Count() == 1 ? ItemLines[0].TaxRate : null; + } + /// /// /// diff --git a/BTCPayServer/Views/Shared/PointOfSale/Public/Cart.cshtml b/BTCPayServer/Views/Shared/PointOfSale/Public/Cart.cshtml index ca941cf22..357c3be96 100644 --- a/BTCPayServer/Views/Shared/PointOfSale/Public/Cart.cshtml +++ b/BTCPayServer/Views/Shared/PointOfSale/Public/Cart.cshtml @@ -191,9 +191,11 @@ Discount -
- - % +
+
+ + % +
@@ -233,7 +235,7 @@ Discount - {{ formatCurrency(discountNumeric, true) }} ({{discountPercent}}%) + {{ formatCurrency(discountNumeric, true) }} ({{discountPercent}}%) @@ -243,13 +245,13 @@ Tip - {{ formatCurrency(tipNumeric, true) }} ({{tipPercent}}%) + {{ formatCurrency(tipNumeric, true) }} ({{tipPercent}}%) Taxes - {{ formatCurrency(taxNumeric, true) }} + {{ formatCurrency(taxNumeric, true) }} ({{taxPercent}}%) diff --git a/BTCPayServer/Views/Shared/PointOfSale/Public/VueLight.cshtml b/BTCPayServer/Views/Shared/PointOfSale/Public/VueLight.cshtml index 745b772ad..af9d470f2 100644 --- a/BTCPayServer/Views/Shared/PointOfSale/Public/VueLight.cshtml +++ b/BTCPayServer/Views/Shared/PointOfSale/Public/VueLight.cshtml @@ -22,7 +22,7 @@
{{currencyCode}}
-
{{ formatCurrency(totalNumeric, false) }}
+
{{ formatCurrency(lastAmount, false) }}
{{ calculation }}
diff --git a/BTCPayServer/Views/Shared/PosData.cshtml b/BTCPayServer/Views/Shared/PosData.cshtml index 49c99afde..c820de536 100644 --- a/BTCPayServer/Views/Shared/PosData.cshtml +++ b/BTCPayServer/Views/Shared/PosData.cshtml @@ -34,7 +34,7 @@ @if (posData.ItemsTotal != null) { - + Items total @posData.ItemsTotal @@ -48,7 +48,7 @@ } @if (posData.Subtotal != null) { - + Subtotal @posData.Subtotal diff --git a/BTCPayServer/Views/UIInvoice/InvoiceReceiptPrint.cshtml b/BTCPayServer/Views/UIInvoice/InvoiceReceiptPrint.cshtml index 02029e736..9b6c031d2 100644 --- a/BTCPayServer/Views/UIInvoice/InvoiceReceiptPrint.cshtml +++ b/BTCPayServer/Views/UIInvoice/InvoiceReceiptPrint.cshtml @@ -139,9 +139,6 @@ @if (posData.ItemsTotal != null) { - -
- Items total @posData.ItemsTotal diff --git a/BTCPayServer/wwwroot/pos/common.js b/BTCPayServer/wwwroot/pos/common.js index 09d6201ad..21f9959c0 100644 --- a/BTCPayServer/wwwroot/pos/common.js +++ b/BTCPayServer/wwwroot/pos/common.js @@ -50,6 +50,21 @@ class PoSOrder { } } + // Returns the tax rate of the items in the cart. + // If the tax rates are not all the same, returns null. + // If the cart is empty, returns null. + // Else, returns the tax rate shared by all items + getTaxRate() { + if (this.itemLines.length === 0) return null; + var rate = this.itemLines[0].taxRate ?? 0; + for (const line of this.itemLines.slice(1)) { + if (rate !== line.taxRate) + { + return null; + } + } + return rate; + } calculate() { const ctx = { discount: 0, @@ -159,6 +174,9 @@ const posCommon = { taxNumeric() { return this.summary.tax; }, + taxPercent() { + return this.posOrder.getTaxRate(); + }, subtotalNumeric () { // We don't want to show the subtotal if there is no tax or tips if (this.summary.priceTaxExcluded === this.summary.priceTaxIncludedWithTips) return 0; @@ -185,6 +203,9 @@ const posCommon = { tipNumeric () { return this.summary.tip; }, + lastAmount() { + return this.amounts[this.amounts.length - 1] = this.amounts[this.amounts.length - 1] || 0; + }, totalNumeric () { return this.summary.priceTaxIncludedWithTips; }, diff --git a/BTCPayServer/wwwroot/pos/keypad.js b/BTCPayServer/wwwroot/pos/keypad.js index a748758cf..2c7ba6171 100644 --- a/BTCPayServer/wwwroot/pos/keypad.js +++ b/BTCPayServer/wwwroot/pos/keypad.js @@ -1,4 +1,5 @@ document.addEventListener("DOMContentLoaded",function () { + const displayFontSize = 64; new Vue({ el: '#app', @@ -39,8 +40,15 @@ document.addEventListener("DOMContentLoaded",function () { if (this.discountNumeric > 0 || this.discountPercentNumeric > 0) calc += ` - ${this.formatCurrency(this.discountNumeric, true)} (${this.discountPercent}%)` if (this.summary.tip > 0) calc += ` + ${this.formatCurrency(this.summary.tip, true)}` if (this.tipPercent) calc += ` (${this.tipPercent}%)` - if (this.summary.tax) calc += ` + ${this.formatCurrency(this.summary.tax, true)}` - if (this.defaultTaxRate) calc += ` (${this.defaultTaxRate}%)` + if (this.summary.tax) + { + calc += ` + ${this.formatCurrency(this.summary.tax, true)}` + if (this.posOrder.getTaxRate()) + { + calc += ` (${this.posOrder.getTaxRate()}%)` + } + } + calc += ` = ${this.formatCurrency(this.summary.priceTaxIncludedWithTips, true)}` return calc } }, From 417e167a39ca3c027b06ec14875e073a64b1166c Mon Sep 17 00:00:00 2001 From: Abhijay Jain Date: Wed, 21 May 2025 09:13:44 +0530 Subject: [PATCH 4/4] (Fix): Fixed Yadio exchange rate lookup failing (#6743) * (Fix): Fixed Yadio exchange rate lookup failing Signed-off-by: Abhijay jain * Adding XPT check as well, since it was causing failures --------- Signed-off-by: Abhijay jain Co-authored-by: rockstardev <5191402+rockstardev@users.noreply.github.com> --- BTCPayServer.Rating/Providers/YadioRateProvider.cs | 6 +++--- BTCPayServer.Tests/ThirdPartyTests.cs | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/BTCPayServer.Rating/Providers/YadioRateProvider.cs b/BTCPayServer.Rating/Providers/YadioRateProvider.cs index ed1652583..5f331cbaa 100644 --- a/BTCPayServer.Rating/Providers/YadioRateProvider.cs +++ b/BTCPayServer.Rating/Providers/YadioRateProvider.cs @@ -30,10 +30,10 @@ namespace BTCPayServer.Services.Rates var list = new List(); foreach (var item in results) { - string name = ((JProperty)item).Name; - var value = results[name].Value(); - list.Add(new PairRate(new CurrencyPair("BTC", name), new BidAsk(value))); + var value = results[name].Value(); + if (value.HasValue) + list.Add(new PairRate(new CurrencyPair("BTC", name), new BidAsk(value.Value))); } return list.ToArray(); diff --git a/BTCPayServer.Tests/ThirdPartyTests.cs b/BTCPayServer.Tests/ThirdPartyTests.cs index f88706fa2..768ec5669 100644 --- a/BTCPayServer.Tests/ThirdPartyTests.cs +++ b/BTCPayServer.Tests/ThirdPartyTests.cs @@ -138,13 +138,14 @@ namespace BTCPayServer.Tests var factory = FastTests.CreateBTCPayRateFactory(); var directlySupported = factory.AvailableRateProviders.Where(s => s.Source == RateSource.Direct) .Select(s => s.Id).ToHashSet(); - foreach (var result in factory + var providerList = factory .Providers .Where(p => p.Value is BackgroundFetcherRateProvider bf && !(bf.Inner is CoinGeckoRateProvider cg && cg.UnderlyingExchange != null)) .Select(p => (ExpectedName: p.Key, ResultAsync: p.Value.GetRatesAsync(default), Fetcher: (BackgroundFetcherRateProvider)p.Value)) - .ToList()) + .ToList(); + foreach (var result in providerList) { var name = result.ExpectedName; if (brokenShitcoinCasinos.Contains(name)) @@ -207,6 +208,9 @@ namespace BTCPayServer.Tests Assert.Contains(exchangeRates.ByExchange[name], e => e.CurrencyPair == new CurrencyPair("BTC", "LBP") && e.BidAsk.Bid > 1.0m); // 1 BTC will always be more than 1 LBP (I hope) + Assert.Contains(exchangeRates.ByExchange[name], + e => e.CurrencyPair == new CurrencyPair("BTC", "XPT") && + e.BidAsk.Bid > 1.0m); // 1 BTC will always be more than 1 LBP (I hope) } else if (name == "bitmynt") {