diff --git a/BTCPayServer.Tests/PaymentRequestTests.cs b/BTCPayServer.Tests/PaymentRequestTests.cs index 9c2158e98..4ef4f0659 100644 --- a/BTCPayServer.Tests/PaymentRequestTests.cs +++ b/BTCPayServer.Tests/PaymentRequestTests.cs @@ -3,9 +3,13 @@ using System.Linq; using System.Threading.Tasks; using BTCPayServer.Controllers; using BTCPayServer.Models.PaymentRequestViewModels; +using BTCPayServer.PaymentRequest; using BTCPayServer.Services.Invoices; +using BTCPayServer.Services.PaymentRequests; using BTCPayServer.Tests.Logging; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using NBitcoin; using NBitpayClient; using Xunit; using Xunit.Abstractions; @@ -16,7 +20,7 @@ namespace BTCPayServer.Tests { public PaymentRequestTests(ITestOutputHelper helper) { - Logs.Tester = new XUnitLog(helper) { Name = "Tests" }; + Logs.Tester = new XUnitLog(helper) {Name = "Tests"}; Logs.LogProvider = new XUnitLogProvider(helper); } @@ -46,8 +50,8 @@ namespace BTCPayServer.Tests Description = "description" }; var id = (Assert - .IsType(await paymentRequestController.EditPaymentRequest(null, request)).RouteValues.Values.First().ToString()); - + .IsType(await paymentRequestController.EditPaymentRequest(null, request)) + .RouteValues.Values.First().ToString()); //permission guard for guests editing @@ -57,7 +61,9 @@ namespace BTCPayServer.Tests request.Title = "update"; Assert.IsType(await paymentRequestController.EditPaymentRequest(id, request)); - Assert.Equal(request.Title, Assert.IsType(Assert.IsType(await paymentRequestController.ViewPaymentRequest(id)).Model).Title); + Assert.Equal(request.Title, + Assert.IsType(Assert + .IsType(await paymentRequestController.ViewPaymentRequest(id)).Model).Title); Assert.False(string.IsNullOrEmpty(id)); @@ -68,16 +74,24 @@ namespace BTCPayServer.Tests Assert .IsType(await paymentRequestController.TogglePaymentRequestArchival(id)); - Assert.True(Assert.IsType(Assert.IsType(await paymentRequestController.ViewPaymentRequest(id)).Model).Archived); + Assert.True(Assert + .IsType(Assert + .IsType(await paymentRequestController.ViewPaymentRequest(id)).Model).Archived); - Assert.Empty(Assert.IsType(Assert.IsType(await paymentRequestController.GetPaymentRequests()).Model).Items); + Assert.Empty(Assert + .IsType(Assert + .IsType(await paymentRequestController.GetPaymentRequests()).Model).Items); //unarchive Assert .IsType(await paymentRequestController.TogglePaymentRequestArchival(id)); - Assert.False(Assert.IsType(Assert.IsType(await paymentRequestController.ViewPaymentRequest(id)).Model).Archived); + Assert.False(Assert + .IsType(Assert + .IsType(await paymentRequestController.ViewPaymentRequest(id)).Model).Archived); - Assert.Single(Assert.IsType(Assert.IsType(await paymentRequestController.GetPaymentRequests()).Model).Items); + Assert.Single(Assert + .IsType(Assert + .IsType(await paymentRequestController.GetPaymentRequests()).Model).Items); } } @@ -94,7 +108,8 @@ namespace BTCPayServer.Tests var paymentRequestController = user.GetController(); - Assert.IsType(await paymentRequestController.PayPaymentRequest(Guid.NewGuid().ToString())); + Assert.IsType( + await paymentRequestController.PayPaymentRequest(Guid.NewGuid().ToString())); var request = new UpdatePaymentRequestViewModel() @@ -110,15 +125,18 @@ namespace BTCPayServer.Tests .RouteValues.First(); var invoiceId = Assert - .IsType(await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false)).Value + .IsType( + await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false)).Value .ToString(); var actionResult = Assert - .IsType(await paymentRequestController.PayPaymentRequest(response.Value.ToString())); + .IsType( + await paymentRequestController.PayPaymentRequest(response.Value.ToString())); Assert.Equal("Checkout", actionResult.ActionName); Assert.Equal("Invoice", actionResult.ControllerName); - Assert.Contains(actionResult.RouteValues, pair => pair.Key == "Id" && pair.Value.ToString() == invoiceId); + Assert.Contains(actionResult.RouteValues, + pair => pair.Key == "Id" && pair.Value.ToString() == invoiceId); var invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant); Assert.Equal(1, invoice.Price); @@ -138,8 +156,8 @@ namespace BTCPayServer.Tests .RouteValues.First(); Assert - .IsType(await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false)); - + .IsType( + await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false)); } } @@ -156,11 +174,9 @@ namespace BTCPayServer.Tests var paymentRequestController = user.GetController(); - Assert.IsType(await paymentRequestController.CancelUnpaidPendingInvoice(Guid.NewGuid().ToString(), false)); - var request = new UpdatePaymentRequestViewModel() { Title = "original juice", @@ -176,15 +192,18 @@ namespace BTCPayServer.Tests var paymentRequestId = response.Value.ToString(); var invoiceId = Assert - .IsType(await paymentRequestController.PayPaymentRequest(paymentRequestId, false)).Value + .IsType(await paymentRequestController.PayPaymentRequest(paymentRequestId, false)) + .Value .ToString(); var actionResult = Assert - .IsType(await paymentRequestController.PayPaymentRequest(response.Value.ToString())); + .IsType( + await paymentRequestController.PayPaymentRequest(response.Value.ToString())); Assert.Equal("Checkout", actionResult.ActionName); Assert.Equal("Invoice", actionResult.ControllerName); - Assert.Contains(actionResult.RouteValues, pair => pair.Key == "Id" && pair.Value.ToString() == invoiceId); + Assert.Contains(actionResult.RouteValues, + pair => pair.Key == "Id" && pair.Value.ToString() == invoiceId); var invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant); Assert.Equal(InvoiceState.ToString(InvoiceStatus.New), invoice.Status); @@ -194,11 +213,24 @@ namespace BTCPayServer.Tests invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant); Assert.Equal(InvoiceState.ToString(InvoiceStatus.Invalid), invoice.Status); - Assert.IsType(await paymentRequestController.CancelUnpaidPendingInvoice(paymentRequestId, false)); + invoiceId = Assert + .IsType(await paymentRequestController.PayPaymentRequest(paymentRequestId, false)) + .Value + .ToString(); + invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant); + + //a hack to generate invoices for the payment request is to manually create an invocie with an order id that matches: + user.BitPay.CreateInvoice(new Invoice(1, "USD") + { + OrderId = PaymentRequestRepository.GetOrderIdForPaymentRequest(paymentRequestId) + }); + //shouldnt crash + await paymentRequestController.ViewPaymentRequest(paymentRequestId); + await paymentRequestController.CancelUnpaidPendingInvoice(paymentRequestId); } } } diff --git a/BTCPayServer/Controllers/PaymentRequestController.cs b/BTCPayServer/Controllers/PaymentRequestController.cs index a2491ea61..ebbcd790b 100644 --- a/BTCPayServer/Controllers/PaymentRequestController.cs +++ b/BTCPayServer/Controllers/PaymentRequestController.cs @@ -292,18 +292,21 @@ namespace BTCPayServer.Controllers return NotFound(); } - var invoice = result.Invoices.SingleOrDefault(requestInvoice => + var invoices = result.Invoices.Where(requestInvoice => requestInvoice.Status.Equals(InvoiceState.ToString(InvoiceStatus.New), StringComparison.InvariantCulture) && !requestInvoice.Payments.Any()); - if (invoice == null) + if (!invoices.Any()) { return BadRequest("No unpaid pending invoice to cancel"); } - await _InvoiceRepository.UpdatePaidInvoiceToInvalid(invoice.Id); - _EventAggregator.Publish(new InvoiceEvent(await _InvoiceRepository.GetInvoice(invoice.Id), 1008, - InvoiceEvent.MarkedInvalid)); + foreach (var invoice in invoices) + { + await _InvoiceRepository.UpdatePaidInvoiceToInvalid(invoice.Id); + _EventAggregator.Publish(new InvoiceEvent(await _InvoiceRepository.GetInvoice(invoice.Id), 1008, + InvoiceEvent.MarkedInvalid)); + } if (redirect) { diff --git a/BTCPayServer/PaymentRequest/PaymentRequestService.cs b/BTCPayServer/PaymentRequest/PaymentRequestService.cs index e684fe7f3..72f873a6c 100644 --- a/BTCPayServer/PaymentRequest/PaymentRequestService.cs +++ b/BTCPayServer/PaymentRequest/PaymentRequestService.cs @@ -80,7 +80,8 @@ namespace BTCPayServer.PaymentRequest var paymentStats = _AppService.GetContributionsByPaymentMethodId(blob.Currency, invoices, true); var amountDue = blob.Amount - paymentStats.TotalCurrency; - var pendingInvoice = invoices.SingleOrDefault(entity => entity.Status == InvoiceStatus.New); + var pendingInvoice = invoices.OrderByDescending(entity => entity.InvoiceTime) + .FirstOrDefault(entity => entity.Status == InvoiceStatus.New); return new ViewPaymentRequestViewModel(pr) {