mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-28 19:34:23 +01:00
@@ -1,6 +1,6 @@
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Hosting;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using BTCPayServer.Tests.Mocks;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Models.AccountViewModels;
|
||||
using BTCPayServer.Models.StoreViewModels;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NBitcoin;
|
||||
using NBitpayClient;
|
||||
|
||||
@@ -9,340 +9,341 @@ using System.Threading;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using BTCPayServer.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using BTCPayServer.Authentication;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
public class UnitTest1
|
||||
{
|
||||
public UnitTest1(ITestOutputHelper helper)
|
||||
{
|
||||
Logs.Tester = new XUnitLog(helper) { Name = "Tests" };
|
||||
Logs.LogProvider = new XUnitLogProvider(helper);
|
||||
}
|
||||
public class UnitTest1
|
||||
{
|
||||
public UnitTest1(ITestOutputHelper helper)
|
||||
{
|
||||
Logs.Tester = new XUnitLog(helper) { Name = "Tests" };
|
||||
Logs.LogProvider = new XUnitLogProvider(helper);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanCalculateCryptoDue()
|
||||
{
|
||||
var entity = new InvoiceEntity();
|
||||
entity.TxFee = Money.Coins(0.1m);
|
||||
entity.Rate = 5000;
|
||||
entity.Payments = new System.Collections.Generic.List<PaymentEntity>();
|
||||
entity.ProductInformation = new ProductInformation() { Price = 5000 };
|
||||
[Fact]
|
||||
public void CanCalculateCryptoDue()
|
||||
{
|
||||
var entity = new InvoiceEntity();
|
||||
entity.TxFee = Money.Coins(0.1m);
|
||||
entity.Rate = 5000;
|
||||
entity.Payments = new System.Collections.Generic.List<PaymentEntity>();
|
||||
entity.ProductInformation = new ProductInformation() { Price = 5000 };
|
||||
|
||||
Assert.Equal(Money.Coins(1.1m), entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.1m), entity.GetTotalCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.1m), entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.1m), entity.GetTotalCryptoDue());
|
||||
|
||||
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.5m), new Key()) });
|
||||
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.5m), new Key()) });
|
||||
|
||||
//Since we need to spend one more txout, it should be 1.1 - 0,5 + 0.1
|
||||
Assert.Equal(Money.Coins(0.7m), entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.2m), entity.GetTotalCryptoDue());
|
||||
//Since we need to spend one more txout, it should be 1.1 - 0,5 + 0.1
|
||||
Assert.Equal(Money.Coins(0.7m), entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.2m), entity.GetTotalCryptoDue());
|
||||
|
||||
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) });
|
||||
Assert.Equal(Money.Coins(0.6m), entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue());
|
||||
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) });
|
||||
Assert.Equal(Money.Coins(0.6m), entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue());
|
||||
|
||||
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.6m), new Key()) });
|
||||
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.6m), new Key()) });
|
||||
|
||||
Assert.Equal(Money.Zero, entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue());
|
||||
Assert.Equal(Money.Zero, entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue());
|
||||
|
||||
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) });
|
||||
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) });
|
||||
|
||||
Assert.Equal(Money.Zero, entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue());
|
||||
}
|
||||
Assert.Equal(Money.Zero, entity.GetCryptoDue());
|
||||
Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanPayUsingBIP70()
|
||||
{
|
||||
using(var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
var invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Buyer = new Buyer() { email = "test@fwf.com" },
|
||||
Price = 5000.0,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
//RedirectURL = redirect + "redirect",
|
||||
//NotificationURL = CallbackUri + "/notification",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
[Fact]
|
||||
public void CanPayUsingBIP70()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
var invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Buyer = new Buyer() { email = "test@fwf.com" },
|
||||
Price = 5000.0,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
//RedirectURL = redirect + "redirect",
|
||||
//NotificationURL = CallbackUri + "/notification",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
Assert.False(invoice.Refundable);
|
||||
Assert.False(invoice.Refundable);
|
||||
|
||||
var url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP72);
|
||||
var request = url.GetPaymentRequest();
|
||||
var payment = request.CreatePayment();
|
||||
var url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP72);
|
||||
var request = url.GetPaymentRequest();
|
||||
var payment = request.CreatePayment();
|
||||
|
||||
Transaction tx = new Transaction();
|
||||
tx.Outputs.AddRange(request.Details.Outputs.Select(o => new TxOut(o.Amount, o.Script)));
|
||||
var cashCow = tester.ExplorerNode;
|
||||
tx = cashCow.FundRawTransaction(tx).Transaction;
|
||||
tx = cashCow.SignRawTransaction(tx);
|
||||
Transaction tx = new Transaction();
|
||||
tx.Outputs.AddRange(request.Details.Outputs.Select(o => new TxOut(o.Amount, o.Script)));
|
||||
var cashCow = tester.ExplorerNode;
|
||||
tx = cashCow.FundRawTransaction(tx).Transaction;
|
||||
tx = cashCow.SignRawTransaction(tx);
|
||||
|
||||
payment.Transactions.Add(tx);
|
||||
payment.Transactions.Add(tx);
|
||||
|
||||
payment.RefundTo.Add(new PaymentOutput(Money.Coins(1.0m), new Key().ScriptPubKey));
|
||||
var ack = payment.SubmitPayment();
|
||||
Assert.NotNull(ack);
|
||||
payment.RefundTo.Add(new PaymentOutput(Money.Coins(1.0m), new Key().ScriptPubKey));
|
||||
var ack = payment.SubmitPayment();
|
||||
Assert.NotNull(ack);
|
||||
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback(url.Address);
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paid", localInvoice.Status);
|
||||
Assert.True(localInvoice.Refundable);
|
||||
});
|
||||
}
|
||||
}
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback(url.Address);
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paid", localInvoice.Status);
|
||||
Assert.True(localInvoice.Refundable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanUseServerInitiatedPairingCode()
|
||||
{
|
||||
using(var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var acc = tester.NewAccount();
|
||||
acc.Register();
|
||||
acc.CreateStore();
|
||||
[Fact]
|
||||
public void CanUseServerInitiatedPairingCode()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var acc = tester.NewAccount();
|
||||
acc.Register();
|
||||
acc.CreateStore();
|
||||
|
||||
var controller = tester.PayTester.GetController<StoresController>(acc.UserId);
|
||||
var token = (RedirectToActionResult)controller.CreateToken(acc.StoreId, new Models.StoreViewModels.CreateTokenViewModel()
|
||||
{
|
||||
Facade = Facade.Merchant.ToString(),
|
||||
Label = "bla",
|
||||
PublicKey = null
|
||||
}).GetAwaiter().GetResult();
|
||||
var controller = tester.PayTester.GetController<StoresController>(acc.UserId);
|
||||
var token = (RedirectToActionResult)controller.CreateToken(acc.StoreId, new Models.StoreViewModels.CreateTokenViewModel()
|
||||
{
|
||||
Facade = Facade.Merchant.ToString(),
|
||||
Label = "bla",
|
||||
PublicKey = null
|
||||
}).GetAwaiter().GetResult();
|
||||
|
||||
var pairingCode = (string)token.RouteValues["pairingCode"];
|
||||
var pairingCode = (string)token.RouteValues["pairingCode"];
|
||||
|
||||
acc.BitPay.AuthorizeClient(new PairingCode(pairingCode)).GetAwaiter().GetResult();
|
||||
Assert.True(acc.BitPay.TestAccess(Facade.Merchant));
|
||||
}
|
||||
}
|
||||
acc.BitPay.AuthorizeClient(new PairingCode(pairingCode)).GetAwaiter().GetResult();
|
||||
Assert.True(acc.BitPay.TestAccess(Facade.Merchant));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanSendIPN()
|
||||
{
|
||||
using(var callbackServer = new CustomServer())
|
||||
{
|
||||
using(var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var acc = tester.NewAccount();
|
||||
acc.GrantAccess();
|
||||
var invoice = acc.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Price = 5.0,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
NotificationURL = callbackServer.GetUri().AbsoluteUri,
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
});
|
||||
BitcoinUrlBuilder url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP21);
|
||||
tester.ExplorerNode.SendToAddress(url.Address, url.Amount);
|
||||
Thread.Sleep(5000);
|
||||
tester.SimulateCallback(url.Address);
|
||||
callbackServer.ProcessNextRequest((ctx) =>
|
||||
{
|
||||
var ipn = new StreamReader(ctx.Request.Body).ReadToEnd();
|
||||
JsonConvert.DeserializeObject<InvoicePaymentNotification>(ipn); //can deserialize
|
||||
});
|
||||
var invoice2 = acc.BitPay.GetInvoice(invoice.Id);
|
||||
Assert.NotNull(invoice2);
|
||||
}
|
||||
}
|
||||
}
|
||||
[Fact]
|
||||
public void CanSendIPN()
|
||||
{
|
||||
using (var callbackServer = new CustomServer())
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var acc = tester.NewAccount();
|
||||
acc.GrantAccess();
|
||||
var invoice = acc.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Price = 5.0,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
NotificationURL = callbackServer.GetUri().AbsoluteUri,
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
});
|
||||
BitcoinUrlBuilder url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP21);
|
||||
tester.ExplorerNode.SendToAddress(url.Address, url.Amount);
|
||||
Thread.Sleep(5000);
|
||||
tester.SimulateCallback(url.Address);
|
||||
callbackServer.ProcessNextRequest((ctx) =>
|
||||
{
|
||||
var ipn = new StreamReader(ctx.Request.Body).ReadToEnd();
|
||||
JsonConvert.DeserializeObject<InvoicePaymentNotification>(ipn); //can deserialize
|
||||
});
|
||||
var invoice2 = acc.BitPay.GetInvoice(invoice.Id);
|
||||
Assert.NotNull(invoice2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CantPairTwiceWithSamePubkey()
|
||||
{
|
||||
using(var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var acc = tester.NewAccount();
|
||||
acc.Register();
|
||||
var store = acc.CreateStore();
|
||||
var pairingCode = acc.BitPay.RequestClientAuthorization("test", Facade.Merchant);
|
||||
Assert.IsType<RedirectToActionResult>(store.Pair(pairingCode.ToString(), acc.StoreId).GetAwaiter().GetResult());
|
||||
[Fact]
|
||||
public void CantPairTwiceWithSamePubkey()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var acc = tester.NewAccount();
|
||||
acc.Register();
|
||||
var store = acc.CreateStore();
|
||||
var pairingCode = acc.BitPay.RequestClientAuthorization("test", Facade.Merchant);
|
||||
Assert.IsType<RedirectToActionResult>(store.Pair(pairingCode.ToString(), acc.StoreId).GetAwaiter().GetResult());
|
||||
|
||||
pairingCode = acc.BitPay.RequestClientAuthorization("test1", Facade.Merchant);
|
||||
var store2 = acc.CreateStore();
|
||||
store2.Pair(pairingCode.ToString(), store2.CreatedStoreId).GetAwaiter().GetResult();
|
||||
Assert.Contains(nameof(PairingResult.ReusedKey), store2.StatusMessage);
|
||||
}
|
||||
}
|
||||
pairingCode = acc.BitPay.RequestClientAuthorization("test1", Facade.Merchant);
|
||||
var store2 = acc.CreateStore();
|
||||
store2.Pair(pairingCode.ToString(), store2.CreatedStoreId).GetAwaiter().GetResult();
|
||||
Assert.Contains(nameof(PairingResult.ReusedKey), store2.StatusMessage);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvoiceFlowThroughDifferentStatesCorrectly()
|
||||
{
|
||||
using(var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var user = tester.NewAccount();
|
||||
Assert.False(user.BitPay.TestAccess(Facade.Merchant));
|
||||
user.GrantAccess();
|
||||
Assert.True(user.BitPay.TestAccess(Facade.Merchant));
|
||||
var invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Price = 5000.0,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
//RedirectURL = redirect + "redirect",
|
||||
//NotificationURL = CallbackUri + "/notification",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
[Fact]
|
||||
public void InvoiceFlowThroughDifferentStatesCorrectly()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var user = tester.NewAccount();
|
||||
Assert.False(user.BitPay.TestAccess(Facade.Merchant));
|
||||
user.GrantAccess();
|
||||
Assert.True(user.BitPay.TestAccess(Facade.Merchant));
|
||||
var invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Price = 5000.0,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
//RedirectURL = redirect + "redirect",
|
||||
//NotificationURL = CallbackUri + "/notification",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
var textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery()
|
||||
{
|
||||
StoreId = user.StoreId,
|
||||
TextSearch = invoice.OrderId
|
||||
}).GetAwaiter().GetResult();
|
||||
var textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery()
|
||||
{
|
||||
StoreId = user.StoreId,
|
||||
TextSearch = invoice.OrderId
|
||||
}).GetAwaiter().GetResult();
|
||||
|
||||
Assert.Equal(1, textSearchResult.Length);
|
||||
Assert.Equal(1, textSearchResult.Length);
|
||||
|
||||
textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery()
|
||||
{
|
||||
StoreId = user.StoreId,
|
||||
TextSearch = invoice.Id
|
||||
}).GetAwaiter().GetResult();
|
||||
textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery()
|
||||
{
|
||||
StoreId = user.StoreId,
|
||||
TextSearch = invoice.Id
|
||||
}).GetAwaiter().GetResult();
|
||||
|
||||
Assert.Equal(1, textSearchResult.Length);
|
||||
Assert.Equal(1, textSearchResult.Length);
|
||||
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal(Money.Coins(0), invoice.BtcPaid);
|
||||
Assert.Equal("new", invoice.Status);
|
||||
Assert.Equal(false, (bool)((JValue)invoice.ExceptionStatus).Value);
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal(Money.Coins(0), invoice.BtcPaid);
|
||||
Assert.Equal("new", invoice.Status);
|
||||
Assert.Equal(false, (bool)((JValue)invoice.ExceptionStatus).Value);
|
||||
|
||||
Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime).Length);
|
||||
Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime + TimeSpan.FromDays(1)).Length);
|
||||
Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5)).Length);
|
||||
Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime).Length);
|
||||
Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime - TimeSpan.FromDays(1)).Length);
|
||||
Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime).Length);
|
||||
Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime + TimeSpan.FromDays(1)).Length);
|
||||
Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5)).Length);
|
||||
Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime).Length);
|
||||
Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime - TimeSpan.FromDays(1)).Length);
|
||||
|
||||
|
||||
var firstPayment = Money.Coins(0.04m);
|
||||
var firstPayment = Money.Coins(0.04m);
|
||||
|
||||
var txFee = Money.Zero;
|
||||
var txFee = Money.Zero;
|
||||
|
||||
var rate = user.BitPay.GetRates();
|
||||
var rate = user.BitPay.GetRates();
|
||||
|
||||
var cashCow = tester.ExplorerNode;
|
||||
var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
|
||||
cashCow.SendToAddress(invoiceAddress, firstPayment);
|
||||
var cashCow = tester.ExplorerNode;
|
||||
var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
|
||||
cashCow.SendToAddress(invoiceAddress, firstPayment);
|
||||
|
||||
Money secondPayment = Money.Zero;
|
||||
Money secondPayment = Money.Zero;
|
||||
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback(invoiceAddress);
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paidPartial", localInvoice.Status);
|
||||
Assert.Equal(firstPayment, localInvoice.BtcPaid);
|
||||
txFee = localInvoice.BtcDue - invoice.BtcDue;
|
||||
Assert.Equal("paidPartial", localInvoice.ExceptionStatus);
|
||||
secondPayment = localInvoice.BtcDue;
|
||||
});
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback(invoiceAddress);
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paidPartial", localInvoice.Status);
|
||||
Assert.Equal(firstPayment, localInvoice.BtcPaid);
|
||||
txFee = localInvoice.BtcDue - invoice.BtcDue;
|
||||
Assert.Equal("paidPartial", localInvoice.ExceptionStatus);
|
||||
secondPayment = localInvoice.BtcDue;
|
||||
});
|
||||
|
||||
cashCow.SendToAddress(invoiceAddress, secondPayment);
|
||||
cashCow.SendToAddress(invoiceAddress, secondPayment);
|
||||
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback(invoiceAddress);
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paid", localInvoice.Status);
|
||||
Assert.Equal(firstPayment + secondPayment, localInvoice.BtcPaid);
|
||||
Assert.Equal(Money.Zero, localInvoice.BtcDue);
|
||||
Assert.Equal(false, (bool)((JValue)localInvoice.ExceptionStatus).Value);
|
||||
});
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback(invoiceAddress);
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paid", localInvoice.Status);
|
||||
Assert.Equal(firstPayment + secondPayment, localInvoice.BtcPaid);
|
||||
Assert.Equal(Money.Zero, localInvoice.BtcDue);
|
||||
Assert.Equal(false, (bool)((JValue)localInvoice.ExceptionStatus).Value);
|
||||
});
|
||||
|
||||
cashCow.Generate(1); //The user has medium speed settings, so 1 conf is enough to be confirmed
|
||||
cashCow.Generate(1); //The user has medium speed settings, so 1 conf is enough to be confirmed
|
||||
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback();
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("confirmed", localInvoice.Status);
|
||||
});
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback();
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("confirmed", localInvoice.Status);
|
||||
});
|
||||
|
||||
cashCow.Generate(5); //Now should be complete
|
||||
cashCow.Generate(5); //Now should be complete
|
||||
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback();
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("complete", localInvoice.Status);
|
||||
});
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback();
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("complete", localInvoice.Status);
|
||||
});
|
||||
|
||||
invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Price = 5000.0,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
//RedirectURL = redirect + "redirect",
|
||||
//NotificationURL = CallbackUri + "/notification",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
|
||||
invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Price = 5000.0,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
//RedirectURL = redirect + "redirect",
|
||||
//NotificationURL = CallbackUri + "/notification",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
|
||||
|
||||
cashCow.SendToAddress(invoiceAddress, invoice.BtcDue + Money.Coins(1));
|
||||
cashCow.SendToAddress(invoiceAddress, invoice.BtcDue + Money.Coins(1));
|
||||
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback(invoiceAddress);
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paidOver", localInvoice.Status);
|
||||
Assert.Equal(Money.Zero, localInvoice.BtcDue);
|
||||
Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value);
|
||||
});
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback(invoiceAddress);
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paidOver", localInvoice.Status);
|
||||
Assert.Equal(Money.Zero, localInvoice.BtcDue);
|
||||
Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value);
|
||||
});
|
||||
|
||||
cashCow.Generate(1);
|
||||
cashCow.Generate(1);
|
||||
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback();
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("confirmed", localInvoice.Status);
|
||||
Assert.Equal(Money.Zero, localInvoice.BtcDue);
|
||||
Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value);
|
||||
});
|
||||
}
|
||||
}
|
||||
Eventually(() =>
|
||||
{
|
||||
tester.SimulateCallback();
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("confirmed", localInvoice.Status);
|
||||
Assert.Equal(Money.Zero, localInvoice.BtcDue);
|
||||
Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void Eventually(Action act)
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource(10000);
|
||||
while(true)
|
||||
{
|
||||
try
|
||||
{
|
||||
act();
|
||||
break;
|
||||
}
|
||||
catch(XunitException) when(!cts.Token.IsCancellationRequested)
|
||||
{
|
||||
cts.Token.WaitHandle.WaitOne(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void Eventually(Action act)
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource(10000);
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
act();
|
||||
break;
|
||||
}
|
||||
catch (XunitException) when (!cts.Token.IsCancellationRequested)
|
||||
{
|
||||
cts.Token.WaitHandle.WaitOne(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
50
BTCPayServer.Tests/UnitTestPeusa.cs
Normal file
50
BTCPayServer.Tests/UnitTestPeusa.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBitpayClient;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
// Helper class for testing functionality and generating data needed during coding/debuging
|
||||
public class UnitTestPeusa
|
||||
{
|
||||
// Unit test that generates temorary checkout Bitpay page
|
||||
// https://forkbitpay.slack.com/archives/C7M093Z55/p1508293682000217
|
||||
[Fact]
|
||||
public void BitpayCheckout()
|
||||
{
|
||||
var key = new Key(Encoders.Hex.DecodeData("7b70a06f35562873e3dcb46005ed0fe78e1991ad906e56adaaafa40ba861e056"));
|
||||
var url = new Uri("https://test.bitpay.com/");
|
||||
var btcpay = new Bitpay(key, url);
|
||||
var invoice = btcpay.CreateInvoice(new Invoice()
|
||||
{
|
||||
|
||||
Price = 5.0,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "cdfd8a5f-6928-4c3b-ba9b-ddf438029e73",
|
||||
ItemDesc = "Hello from the otherside"
|
||||
}, Facade.Merchant);
|
||||
|
||||
// go to invoice.Url
|
||||
Console.WriteLine(invoice.Url);
|
||||
}
|
||||
|
||||
// Generating Extended public key to use on http://localhost:14142/stores/{storeId}
|
||||
[Fact]
|
||||
public void GeneratePubkey()
|
||||
{
|
||||
var network = Network.RegTest;
|
||||
|
||||
ExtKey masterKey = new ExtKey();
|
||||
Console.WriteLine("Master key : " + masterKey.ToString(network));
|
||||
ExtPubKey masterPubKey = masterKey.Neuter();
|
||||
|
||||
ExtPubKey pubkey = masterPubKey.Derive(0);
|
||||
Console.WriteLine("PubKey " + 0 + " : " + pubkey.ToString(network));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
|
||||
namespace BTCPayServer.Configuration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using BTCPayServer.Services.Stores;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Filters;
|
||||
using BTCPayServer.Models.InvoicingModels;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -268,7 +268,7 @@ namespace BTCPayServer.Controllers
|
||||
ItemDesc = model.ItemDesc,
|
||||
FullNotifications = true,
|
||||
BuyerEmail = model.BuyerEmail,
|
||||
}, store, HttpContext.Request.GetAbsoluteRoot());
|
||||
}, store, HttpContext.Request.GetAbsoluteRoot(), 120);
|
||||
|
||||
StatusMessage = $"Invoice {result.Data.Id} just created!";
|
||||
return RedirectToAction(nameof(ListInvoices));
|
||||
|
||||
@@ -29,7 +29,7 @@ using BTCPayServer.Services;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.RegularExpressions;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using BTCPayServer.Validations;
|
||||
@@ -75,7 +75,7 @@ namespace BTCPayServer.Controllers
|
||||
_FeeProvider = feeProvider ?? throw new ArgumentNullException(nameof(feeProvider));
|
||||
}
|
||||
|
||||
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl)
|
||||
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl, double expiryMinutes = 15)
|
||||
{
|
||||
var derivationStrategy = store.DerivationStrategy;
|
||||
var entity = new InvoiceEntity
|
||||
@@ -87,7 +87,7 @@ namespace BTCPayServer.Controllers
|
||||
if(notificationUri == null || (notificationUri.Scheme != "http" && notificationUri.Scheme != "https")) //TODO: Filer non routable addresses ?
|
||||
notificationUri = null;
|
||||
EmailAddressAttribute emailValidator = new EmailAddressAttribute();
|
||||
entity.ExpirationTime = entity.InvoiceTime + TimeSpan.FromMinutes(15.0);
|
||||
entity.ExpirationTime = entity.InvoiceTime.AddMinutes(expiryMinutes);
|
||||
entity.ServerUrl = serverUrl;
|
||||
entity.FullNotifications = invoice.FullNotifications;
|
||||
entity.NotificationURL = notificationUri?.AbsoluteUri;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
@@ -16,7 +16,7 @@ using NBXplorer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using BTCPayServer.Services.Fees;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// <auto-generated />
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// <auto-generated />
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// <auto-generated />
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// <auto-generated />
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// <auto-generated />
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// <auto-generated />
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Models.InvoicingModels
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using BTCPayServer.Servcices.Invoices;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Validations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -9,7 +9,7 @@ using NBitpayClient;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NBitcoin.DataEncoders;
|
||||
|
||||
namespace BTCPayServer.Servcices.Invoices
|
||||
namespace BTCPayServer.Services.Invoices
|
||||
{
|
||||
public class BuyerInformation
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace BTCPayServer.Servcices.Invoices
|
||||
namespace BTCPayServer.Services.Invoices
|
||||
{
|
||||
public class InvoiceNotificationManager
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ using BTCPayServer.Data;
|
||||
using System.Globalization;
|
||||
using BTCPayServer.Models.InvoicingModels;
|
||||
|
||||
namespace BTCPayServer.Servcices.Invoices
|
||||
namespace BTCPayServer.Services.Invoices
|
||||
{
|
||||
public class InvoiceRepository
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ using System.Collections.Concurrent;
|
||||
using Hangfire;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
|
||||
namespace BTCPayServer.Servcices.Invoices
|
||||
namespace BTCPayServer.Services.Invoices
|
||||
{
|
||||
public class InvoiceWatcher : IHostedService
|
||||
{
|
||||
|
||||
@@ -543,13 +543,13 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="action-button" style="margin-top: 20px;">
|
||||
<a href="/invoices" class="action-button" style="margin-top: 20px;">
|
||||
<bp-done-text>
|
||||
<!---->
|
||||
<!---->
|
||||
<span i18n="" class="i18n-return-to-merchant">Return to @Model.StoreName</span>
|
||||
</bp-done-text>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
ViewData["Title"] = "Invoice " + Model.Id;
|
||||
}
|
||||
|
||||
<style type="text/css">
|
||||
.overflowbox {
|
||||
max-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
<section>
|
||||
<div class="container">
|
||||
|
||||
@@ -86,7 +95,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Payment Url</th>
|
||||
<td><a href="@Model.PaymentUrl">@Model.PaymentUrl</a></td>
|
||||
<td class="overflowbox"><a href="@Model.PaymentUrl">@Model.PaymentUrl</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user