Fix: Impossible to edit a payment request after receiving an invoice on it

This commit is contained in:
nicolas.dorier
2025-04-10 22:40:15 +09:00
parent 8593d33879
commit 782d53c13d
2 changed files with 31 additions and 16 deletions

View File

@@ -6,6 +6,7 @@ using BTCPayServer.Data;
using BTCPayServer.Models.PaymentRequestViewModels;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.PaymentRequests;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NBitpayClient;
using Xunit;
@@ -101,7 +102,7 @@ namespace BTCPayServer.Tests
user.RegisterDerivationScheme("BTC");
var paymentRequestController = user.GetController<UIPaymentRequestController>();
var repo = tester.PayTester.GetService<PaymentRequestRepository>();
Assert.IsType<NotFoundResult>(
await paymentRequestController.PayPaymentRequest(Guid.NewGuid().ToString()));
@@ -112,20 +113,21 @@ namespace BTCPayServer.Tests
Currency = "BTC",
Amount = 1,
StoreId = user.StoreId,
Description = "description"
Description = "description",
ExpiryDate = (DateTimeOffset.UtcNow + TimeSpan.FromDays(1.0)).UtcDateTime
};
var response = Assert
var prId = Assert
.IsType<RedirectToActionResult>(paymentRequestController.EditPaymentRequest(null, request).Result)
.RouteValues.Last();
.RouteValues.Last().Value.ToString();
var invoiceId = Assert
.IsType<OkObjectResult>(
await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false)).Value
await paymentRequestController.PayPaymentRequest(prId, false)).Value
.ToString();
var actionResult = Assert
.IsType<RedirectToActionResult>(
await paymentRequestController.PayPaymentRequest(response.Value.ToString()));
await paymentRequestController.PayPaymentRequest(prId));
Assert.Equal("Checkout", actionResult.ActionName);
Assert.Equal("UIInvoice", actionResult.ControllerName);
@@ -135,6 +137,14 @@ namespace BTCPayServer.Tests
var invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant);
Assert.Equal(1, invoice.Price);
// Check if we can modify a PaymentRequest after an invoice has been made
request.ExpiryDate = null;
var paymentRequest = await repo.FindPaymentRequest(prId, null);
paymentRequestController.HttpContext.SetPaymentRequestData(paymentRequest);
Assert
.IsType<RedirectToActionResult>(paymentRequestController.EditPaymentRequest(prId, request).Result)
.RouteValues.Last().Value.ToString();
paymentRequestController.HttpContext.SetPaymentRequestData(null);
request = new UpdatePaymentRequestViewModel()
{
Title = "original juice with expiry",
@@ -145,13 +155,13 @@ namespace BTCPayServer.Tests
Description = "description"
};
response = Assert
prId = Assert
.IsType<RedirectToActionResult>(paymentRequestController.EditPaymentRequest(null, request).Result)
.RouteValues.Last();
.RouteValues.Last().Value.ToString();
Assert
.IsType<BadRequestObjectResult>(
await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false));
await paymentRequestController.PayPaymentRequest(prId, false));
}
[Fact(Timeout = 60 * 2 * 1000)]

View File

@@ -155,6 +155,7 @@ namespace BTCPayServer.Controllers
[Authorize(Policy = Policies.CanModifyPaymentRequests, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
public async Task<IActionResult> EditPaymentRequest(string payReqId, UpdatePaymentRequestViewModel viewModel)
{
viewModel.Id = payReqId;
if (!string.IsNullOrEmpty(viewModel.Currency) &&
_Currencies.GetCurrencyData(viewModel.Currency, false) == null)
ModelState.AddModelError(nameof(viewModel.Currency), "Invalid currency");
@@ -162,7 +163,8 @@ namespace BTCPayServer.Controllers
viewModel.Currency = null;
var store = GetCurrentStore();
var paymentRequest = GetCurrentPaymentRequest();
if (paymentRequest == null && !string.IsNullOrEmpty(payReqId))
if ((paymentRequest == null && !string.IsNullOrEmpty(payReqId)) ||
(paymentRequest != null && paymentRequest.Id != payReqId))
{
return NotFound();
}
@@ -180,11 +182,14 @@ namespace BTCPayServer.Controllers
data.Archived = viewModel.Archived;
var blob = data.GetBlob();
if (data.Amount != viewModel.Amount && payReqId != null)
var prInvoices = payReqId is null ? [] : (await _PaymentRequestService.GetPaymentRequest(payReqId, GetUserId())).Invoices;
viewModel.AmountAndCurrencyEditable = payReqId is null || !prInvoices.Any();
if (!viewModel.AmountAndCurrencyEditable)
{
var prInvoices = (await _PaymentRequestService.GetPaymentRequest(payReqId, GetUserId())).Invoices;
if (prInvoices.Any())
ModelState.AddModelError(nameof(viewModel.Amount), StringLocalizer["Amount and currency are not editable once payment request has invoices"]);
ModelState.Remove(nameof(data.Amount));
ModelState.Remove(nameof(data.Currency));
viewModel.Amount = data.Amount;
viewModel.Currency = data.Currency;
}
if (!ModelState.IsValid)
@@ -199,8 +204,8 @@ namespace BTCPayServer.Controllers
blob.Email = viewModel.Email;
blob.Description = viewModel.Description;
data.Amount = viewModel.Amount;
data.Expiry = viewModel.ExpiryDate?.ToUniversalTime();
data.Currency = viewModel.Currency ?? store.GetStoreBlob().DefaultCurrency;
data.Expiry = viewModel.ExpiryDate?.ToUniversalTime();
blob.AllowCustomPaymentAmounts = viewModel.AllowCustomPaymentAmounts;
blob.FormId = viewModel.FormId;