using System; using System.Linq; using System.Threading.Tasks; using BTCPayServer.Client.Models; 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; namespace BTCPayServer.Tests { public class PaymentRequestTests { public PaymentRequestTests(ITestOutputHelper helper) { Logs.Tester = new XUnitLog(helper) {Name = "Tests"}; Logs.LogProvider = new XUnitLogProvider(helper); } [Fact] [Trait("Integration", "Integration")] public async Task CanCreateViewUpdateAndDeletePaymentRequest() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("BTC"); var user2 = tester.NewAccount(); user2.GrantAccess(); var paymentRequestController = user.GetController(); var guestpaymentRequestController = user2.GetController(); var request = new UpdatePaymentRequestViewModel() { Title = "original juice", Currency = "BTC", Amount = 1, StoreId = user.StoreId, Description = "description" }; var id = (Assert .IsType(await paymentRequestController.EditPaymentRequest(null, request)) .RouteValues.Values.First().ToString()); //permission guard for guests editing Assert .IsType(await guestpaymentRequestController.EditPaymentRequest(id)); 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.False(string.IsNullOrEmpty(id)); Assert.IsType(Assert .IsType(await paymentRequestController.ViewPaymentRequest(id)).Model); //Archive Assert .IsType(await paymentRequestController.TogglePaymentRequestArchival(id)); Assert.True(Assert .IsType(Assert .IsType(await paymentRequestController.ViewPaymentRequest(id)).Model).Archived); 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.Single(Assert .IsType(Assert .IsType(await paymentRequestController.GetPaymentRequests()).Model).Items); } } [Fact(Timeout = 60 * 2 * 1000)] [Trait("Integration", "Integration")] public async Task CanPayPaymentRequestWhenPossible() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("BTC"); var paymentRequestController = user.GetController(); Assert.IsType( await paymentRequestController.PayPaymentRequest(Guid.NewGuid().ToString())); var request = new UpdatePaymentRequestViewModel() { Title = "original juice", Currency = "BTC", Amount = 1, StoreId = user.StoreId, Description = "description" }; var response = Assert .IsType(paymentRequestController.EditPaymentRequest(null, request).Result) .RouteValues.First(); var invoiceId = Assert .IsType( await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false)).Value .ToString(); var actionResult = Assert .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); var invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant); Assert.Equal(1, invoice.Price); request = new UpdatePaymentRequestViewModel() { Title = "original juice with expiry", Currency = "BTC", Amount = 1, ExpiryDate = DateTime.Today.Subtract(TimeSpan.FromDays(2)), StoreId = user.StoreId, Description = "description" }; response = Assert .IsType(paymentRequestController.EditPaymentRequest(null, request).Result) .RouteValues.First(); Assert .IsType( await paymentRequestController.PayPaymentRequest(response.Value.ToString(), false)); } } [Fact(Timeout = 60 * 2 * 1000)] [Trait("Integration", "Integration")] public async Task CanCancelPaymentWhenPossible() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("BTC"); var paymentRequestController = user.GetController(); Assert.IsType(await paymentRequestController.CancelUnpaidPendingInvoice(Guid.NewGuid().ToString(), false)); var request = new UpdatePaymentRequestViewModel() { Title = "original juice", Currency = "BTC", Amount = 1, StoreId = user.StoreId, Description = "description" }; var response = Assert .IsType(paymentRequestController.EditPaymentRequest(null, request).Result) .RouteValues.First(); var paymentRequestId = response.Value.ToString(); var invoiceId = Assert .IsType(await paymentRequestController.PayPaymentRequest(paymentRequestId, false)) .Value .ToString(); var actionResult = Assert .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); var invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant); Assert.Equal(InvoiceState.ToString(InvoiceStatusLegacy.New), invoice.Status); Assert.IsType(await paymentRequestController.CancelUnpaidPendingInvoice(paymentRequestId, false)); invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant); Assert.Equal(InvoiceState.ToString(InvoiceStatusLegacy.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); } } } }