mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 06:21:44 +01:00
Handle multiple new invoices in payment requests
This commit is contained in:
parent
4dca905a91
commit
b381e629f1
3 changed files with 62 additions and 26 deletions
|
@ -3,9 +3,13 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Controllers;
|
using BTCPayServer.Controllers;
|
||||||
using BTCPayServer.Models.PaymentRequestViewModels;
|
using BTCPayServer.Models.PaymentRequestViewModels;
|
||||||
|
using BTCPayServer.PaymentRequest;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
|
using BTCPayServer.Services.PaymentRequests;
|
||||||
using BTCPayServer.Tests.Logging;
|
using BTCPayServer.Tests.Logging;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
|
using NBitcoin;
|
||||||
using NBitpayClient;
|
using NBitpayClient;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
@ -16,7 +20,7 @@ namespace BTCPayServer.Tests
|
||||||
{
|
{
|
||||||
public PaymentRequestTests(ITestOutputHelper helper)
|
public PaymentRequestTests(ITestOutputHelper helper)
|
||||||
{
|
{
|
||||||
Logs.Tester = new XUnitLog(helper) { Name = "Tests" };
|
Logs.Tester = new XUnitLog(helper) {Name = "Tests"};
|
||||||
Logs.LogProvider = new XUnitLogProvider(helper);
|
Logs.LogProvider = new XUnitLogProvider(helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,8 +50,8 @@ namespace BTCPayServer.Tests
|
||||||
Description = "description"
|
Description = "description"
|
||||||
};
|
};
|
||||||
var id = (Assert
|
var id = (Assert
|
||||||
.IsType<RedirectToActionResult>(await paymentRequestController.EditPaymentRequest(null, request)).RouteValues.Values.First().ToString());
|
.IsType<RedirectToActionResult>(await paymentRequestController.EditPaymentRequest(null, request))
|
||||||
|
.RouteValues.Values.First().ToString());
|
||||||
|
|
||||||
|
|
||||||
//permission guard for guests editing
|
//permission guard for guests editing
|
||||||
|
@ -57,7 +61,9 @@ namespace BTCPayServer.Tests
|
||||||
request.Title = "update";
|
request.Title = "update";
|
||||||
Assert.IsType<RedirectToActionResult>(await paymentRequestController.EditPaymentRequest(id, request));
|
Assert.IsType<RedirectToActionResult>(await paymentRequestController.EditPaymentRequest(id, request));
|
||||||
|
|
||||||
Assert.Equal(request.Title, Assert.IsType<ViewPaymentRequestViewModel>(Assert.IsType<ViewResult>(await paymentRequestController.ViewPaymentRequest(id)).Model).Title);
|
Assert.Equal(request.Title,
|
||||||
|
Assert.IsType<ViewPaymentRequestViewModel>(Assert
|
||||||
|
.IsType<ViewResult>(await paymentRequestController.ViewPaymentRequest(id)).Model).Title);
|
||||||
|
|
||||||
Assert.False(string.IsNullOrEmpty(id));
|
Assert.False(string.IsNullOrEmpty(id));
|
||||||
|
|
||||||
|
@ -68,16 +74,24 @@ namespace BTCPayServer.Tests
|
||||||
|
|
||||||
Assert
|
Assert
|
||||||
.IsType<RedirectToActionResult>(await paymentRequestController.TogglePaymentRequestArchival(id));
|
.IsType<RedirectToActionResult>(await paymentRequestController.TogglePaymentRequestArchival(id));
|
||||||
Assert.True(Assert.IsType<ViewPaymentRequestViewModel>(Assert.IsType<ViewResult>(await paymentRequestController.ViewPaymentRequest(id)).Model).Archived);
|
Assert.True(Assert
|
||||||
|
.IsType<ViewPaymentRequestViewModel>(Assert
|
||||||
|
.IsType<ViewResult>(await paymentRequestController.ViewPaymentRequest(id)).Model).Archived);
|
||||||
|
|
||||||
Assert.Empty(Assert.IsType<ListPaymentRequestsViewModel>(Assert.IsType<ViewResult>(await paymentRequestController.GetPaymentRequests()).Model).Items);
|
Assert.Empty(Assert
|
||||||
|
.IsType<ListPaymentRequestsViewModel>(Assert
|
||||||
|
.IsType<ViewResult>(await paymentRequestController.GetPaymentRequests()).Model).Items);
|
||||||
//unarchive
|
//unarchive
|
||||||
Assert
|
Assert
|
||||||
.IsType<RedirectToActionResult>(await paymentRequestController.TogglePaymentRequestArchival(id));
|
.IsType<RedirectToActionResult>(await paymentRequestController.TogglePaymentRequestArchival(id));
|
||||||
|
|
||||||
Assert.False(Assert.IsType<ViewPaymentRequestViewModel>(Assert.IsType<ViewResult>(await paymentRequestController.ViewPaymentRequest(id)).Model).Archived);
|
Assert.False(Assert
|
||||||
|
.IsType<ViewPaymentRequestViewModel>(Assert
|
||||||
|
.IsType<ViewResult>(await paymentRequestController.ViewPaymentRequest(id)).Model).Archived);
|
||||||
|
|
||||||
Assert.Single(Assert.IsType<ListPaymentRequestsViewModel>(Assert.IsType<ViewResult>(await paymentRequestController.GetPaymentRequests()).Model).Items);
|
Assert.Single(Assert
|
||||||
|
.IsType<ListPaymentRequestsViewModel>(Assert
|
||||||
|
.IsType<ViewResult>(await paymentRequestController.GetPaymentRequests()).Model).Items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +108,8 @@ namespace BTCPayServer.Tests
|
||||||
|
|
||||||
var paymentRequestController = user.GetController<PaymentRequestController>();
|
var paymentRequestController = user.GetController<PaymentRequestController>();
|
||||||
|
|
||||||
Assert.IsType<NotFoundResult>(await paymentRequestController.PayPaymentRequest(Guid.NewGuid().ToString()));
|
Assert.IsType<NotFoundResult>(
|
||||||
|
await paymentRequestController.PayPaymentRequest(Guid.NewGuid().ToString()));
|
||||||
|
|
||||||
|
|
||||||
var request = new UpdatePaymentRequestViewModel()
|
var request = new UpdatePaymentRequestViewModel()
|
||||||
|
@ -110,15 +125,18 @@ namespace BTCPayServer.Tests
|
||||||
.RouteValues.First();
|
.RouteValues.First();
|
||||||
|
|
||||||
var invoiceId = Assert
|
var invoiceId = Assert
|
||||||
.IsType<OkObjectResult>(await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false)).Value
|
.IsType<OkObjectResult>(
|
||||||
|
await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false)).Value
|
||||||
.ToString();
|
.ToString();
|
||||||
|
|
||||||
var actionResult = Assert
|
var actionResult = Assert
|
||||||
.IsType<RedirectToActionResult>(await paymentRequestController.PayPaymentRequest(response.Value.ToString()));
|
.IsType<RedirectToActionResult>(
|
||||||
|
await paymentRequestController.PayPaymentRequest(response.Value.ToString()));
|
||||||
|
|
||||||
Assert.Equal("Checkout", actionResult.ActionName);
|
Assert.Equal("Checkout", actionResult.ActionName);
|
||||||
Assert.Equal("Invoice", actionResult.ControllerName);
|
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);
|
var invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant);
|
||||||
Assert.Equal(1, invoice.Price);
|
Assert.Equal(1, invoice.Price);
|
||||||
|
@ -138,8 +156,8 @@ namespace BTCPayServer.Tests
|
||||||
.RouteValues.First();
|
.RouteValues.First();
|
||||||
|
|
||||||
Assert
|
Assert
|
||||||
.IsType<BadRequestObjectResult>(await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false));
|
.IsType<BadRequestObjectResult>(
|
||||||
|
await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,11 +174,9 @@ namespace BTCPayServer.Tests
|
||||||
|
|
||||||
var paymentRequestController = user.GetController<PaymentRequestController>();
|
var paymentRequestController = user.GetController<PaymentRequestController>();
|
||||||
|
|
||||||
|
|
||||||
Assert.IsType<NotFoundResult>(await
|
Assert.IsType<NotFoundResult>(await
|
||||||
paymentRequestController.CancelUnpaidPendingInvoice(Guid.NewGuid().ToString(), false));
|
paymentRequestController.CancelUnpaidPendingInvoice(Guid.NewGuid().ToString(), false));
|
||||||
|
|
||||||
|
|
||||||
var request = new UpdatePaymentRequestViewModel()
|
var request = new UpdatePaymentRequestViewModel()
|
||||||
{
|
{
|
||||||
Title = "original juice",
|
Title = "original juice",
|
||||||
|
@ -176,15 +192,18 @@ namespace BTCPayServer.Tests
|
||||||
var paymentRequestId = response.Value.ToString();
|
var paymentRequestId = response.Value.ToString();
|
||||||
|
|
||||||
var invoiceId = Assert
|
var invoiceId = Assert
|
||||||
.IsType<OkObjectResult>(await paymentRequestController.PayPaymentRequest(paymentRequestId, false)).Value
|
.IsType<OkObjectResult>(await paymentRequestController.PayPaymentRequest(paymentRequestId, false))
|
||||||
|
.Value
|
||||||
.ToString();
|
.ToString();
|
||||||
|
|
||||||
var actionResult = Assert
|
var actionResult = Assert
|
||||||
.IsType<RedirectToActionResult>(await paymentRequestController.PayPaymentRequest(response.Value.ToString()));
|
.IsType<RedirectToActionResult>(
|
||||||
|
await paymentRequestController.PayPaymentRequest(response.Value.ToString()));
|
||||||
|
|
||||||
Assert.Equal("Checkout", actionResult.ActionName);
|
Assert.Equal("Checkout", actionResult.ActionName);
|
||||||
Assert.Equal("Invoice", actionResult.ControllerName);
|
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);
|
var invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant);
|
||||||
Assert.Equal(InvoiceState.ToString(InvoiceStatus.New), invoice.Status);
|
Assert.Equal(InvoiceState.ToString(InvoiceStatus.New), invoice.Status);
|
||||||
|
@ -194,11 +213,24 @@ namespace BTCPayServer.Tests
|
||||||
invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant);
|
invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant);
|
||||||
Assert.Equal(InvoiceState.ToString(InvoiceStatus.Invalid), invoice.Status);
|
Assert.Equal(InvoiceState.ToString(InvoiceStatus.Invalid), invoice.Status);
|
||||||
|
|
||||||
|
|
||||||
Assert.IsType<BadRequestObjectResult>(await
|
Assert.IsType<BadRequestObjectResult>(await
|
||||||
paymentRequestController.CancelUnpaidPendingInvoice(paymentRequestId, false));
|
paymentRequestController.CancelUnpaidPendingInvoice(paymentRequestId, false));
|
||||||
|
|
||||||
|
invoiceId = Assert
|
||||||
|
.IsType<OkObjectResult>(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -292,18 +292,21 @@ namespace BTCPayServer.Controllers
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var invoice = result.Invoices.SingleOrDefault(requestInvoice =>
|
var invoices = result.Invoices.Where(requestInvoice =>
|
||||||
requestInvoice.Status.Equals(InvoiceState.ToString(InvoiceStatus.New),
|
requestInvoice.Status.Equals(InvoiceState.ToString(InvoiceStatus.New),
|
||||||
StringComparison.InvariantCulture) && !requestInvoice.Payments.Any());
|
StringComparison.InvariantCulture) && !requestInvoice.Payments.Any());
|
||||||
|
|
||||||
if (invoice == null)
|
if (!invoices.Any())
|
||||||
{
|
{
|
||||||
return BadRequest("No unpaid pending invoice to cancel");
|
return BadRequest("No unpaid pending invoice to cancel");
|
||||||
}
|
}
|
||||||
|
|
||||||
await _InvoiceRepository.UpdatePaidInvoiceToInvalid(invoice.Id);
|
foreach (var invoice in invoices)
|
||||||
_EventAggregator.Publish(new InvoiceEvent(await _InvoiceRepository.GetInvoice(invoice.Id), 1008,
|
{
|
||||||
InvoiceEvent.MarkedInvalid));
|
await _InvoiceRepository.UpdatePaidInvoiceToInvalid(invoice.Id);
|
||||||
|
_EventAggregator.Publish(new InvoiceEvent(await _InvoiceRepository.GetInvoice(invoice.Id), 1008,
|
||||||
|
InvoiceEvent.MarkedInvalid));
|
||||||
|
}
|
||||||
|
|
||||||
if (redirect)
|
if (redirect)
|
||||||
{
|
{
|
||||||
|
|
|
@ -80,7 +80,8 @@ namespace BTCPayServer.PaymentRequest
|
||||||
|
|
||||||
var paymentStats = _AppService.GetContributionsByPaymentMethodId(blob.Currency, invoices, true);
|
var paymentStats = _AppService.GetContributionsByPaymentMethodId(blob.Currency, invoices, true);
|
||||||
var amountDue = blob.Amount - paymentStats.TotalCurrency;
|
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)
|
return new ViewPaymentRequestViewModel(pr)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue