Invoice: Improve zero amount invoice handling (#6199)

This is for the checkout page to properly redirect paid invoices with no payment methods (e.g. free invoices with zero amount) to either the receipt page or redirect URL. Only fall back to 404 if there is neither.

Fixes #6123.
This commit is contained in:
d11n
2024-09-09 04:05:03 +02:00
committed by GitHub
parent 73dcde7780
commit 841f41da2f
4 changed files with 24 additions and 9 deletions

View File

@@ -34,7 +34,7 @@
<PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.15" /> <PackageReference Include="Newtonsoft.Json.Schema" Version="3.0.15" />
<PackageReference Include="Selenium.Support" Version="4.1.1" /> <PackageReference Include="Selenium.Support" Version="4.1.1" />
<PackageReference Include="Selenium.WebDriver" Version="4.22.0" /> <PackageReference Include="Selenium.WebDriver" Version="4.22.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="125.0.6422.14100" /> <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="128.0.6613.11900" />
<PackageReference Include="xunit" Version="2.6.6" /> <PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6"> <PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>

View File

@@ -55,6 +55,7 @@ namespace BTCPayServer.Tests
options.AddArguments($"window-size={windowSize.Width}x{windowSize.Height}"); options.AddArguments($"window-size={windowSize.Width}x{windowSize.Height}");
options.AddArgument("shm-size=2g"); options.AddArgument("shm-size=2g");
options.AddArgument("start-maximized"); options.AddArgument("start-maximized");
options.AddArgument("disable-search-engine-choice-screen");
if (Server.PayTester.InContainer) if (Server.PayTester.InContainer)
{ {
// Shot in the dark to fix https://stackoverflow.com/questions/53902507/unknown-error-session-deleted-because-of-page-crash-from-unknown-error-cannot // Shot in the dark to fix https://stackoverflow.com/questions/53902507/unknown-error-session-deleted-because-of-page-crash-from-unknown-error-cannot

View File

@@ -745,6 +745,14 @@ namespace BTCPayServer.Tests
s.Driver.FindElement(By.CssSelector("[data-invoice-state-badge] .dropdown-toggle")).Click(); s.Driver.FindElement(By.CssSelector("[data-invoice-state-badge] .dropdown-toggle")).Click();
s.Driver.FindElements(By.CssSelector("[data-invoice-state-badge] .dropdown-menu button"))[0].Click(); s.Driver.FindElements(By.CssSelector("[data-invoice-state-badge] .dropdown-menu button"))[0].Click();
TestUtils.Eventually(() => Assert.Contains("Settled (marked)", s.Driver.PageSource)); TestUtils.Eventually(() => Assert.Contains("Settled (marked)", s.Driver.PageSource));
// zero amount invoice should redirect to receipt
var zeroAmountId = s.CreateInvoice(0);
s.GoToUrl($"/i/{zeroAmountId}");
Assert.EndsWith("/receipt", s.Driver.Url);
Assert.Contains("$0.00", s.Driver.PageSource);
s.GoToInvoice(zeroAmountId);
Assert.Equal("Settled", s.Driver.FindElement(By.CssSelector("[data-invoice-state-badge]")).Text);
} }
[Fact(Timeout = TestTimeout)] [Fact(Timeout = TestTimeout)]

View File

@@ -199,16 +199,13 @@ namespace BTCPayServer.Controllers
return NotFound(); return NotFound();
var receipt = InvoiceDataBase.ReceiptOptions.Merge(store.GetStoreBlob().ReceiptOptions, i.ReceiptOptions); var receipt = InvoiceDataBase.ReceiptOptions.Merge(store.GetStoreBlob().ReceiptOptions, i.ReceiptOptions);
if (receipt.Enabled is not true) if (receipt.Enabled is not true)
{ {
if (i.RedirectURL is not null) return i.RedirectURL is not null
{ ? Redirect(i.RedirectURL.ToString())
return Redirect(i.RedirectURL.ToString()); : NotFound();
}
return NotFound();
} }
var storeBlob = store.GetStoreBlob(); var storeBlob = store.GetStoreBlob();
var vm = new InvoiceReceiptViewModel var vm = new InvoiceReceiptViewModel
{ {
@@ -699,7 +696,16 @@ namespace BTCPayServer.Controllers
var model = await GetInvoiceModel(invoiceId, paymentMethodId == null ? null : PaymentMethodId.Parse(paymentMethodId), lang); var model = await GetInvoiceModel(invoiceId, paymentMethodId == null ? null : PaymentMethodId.Parse(paymentMethodId), lang);
if (model == null) if (model == null)
return NotFound(); {
// see if the invoice actually exists and is in a state for which we do not display the checkout
var invoice = await _InvoiceRepository.GetInvoice(invoiceId);
var store = invoice != null ? await _StoreRepository.GetStoreByInvoiceId(invoice.Id) : null;
var receipt = invoice != null && store != null ? InvoiceDataBase.ReceiptOptions.Merge(store.GetStoreBlob().ReceiptOptions, invoice.ReceiptOptions) : null;
var redirectUrl = invoice?.RedirectURL?.ToString();
return receipt?.Enabled is true
? RedirectToAction(nameof(InvoiceReceipt), new { invoiceId })
: !string.IsNullOrEmpty(redirectUrl) ? Redirect(redirectUrl) : NotFound();
}
if (view == "modal") if (view == "modal")
model.IsModal = true; model.IsModal = true;