Add a new invoice event: expiredPaidPartial and fix some corner case for tolerance

This commit is contained in:
nicolas.dorier 2018-05-06 00:40:44 +09:00
parent 27a0aebd12
commit 7872b3ec55
3 changed files with 46 additions and 7 deletions

View File

@ -256,6 +256,46 @@ namespace BTCPayServer.Tests
}
[Fact]
public void CanAcceptInvoiceWithTolerance2()
{
using (var tester = ServerTester.Create())
{
tester.Start();
var user = tester.NewAccount();
user.GrantAccess();
user.RegisterDerivationScheme("BTC");
// Set tolerance to 50%
var stores = user.GetController<StoresController>();
var vm = Assert.IsType<StoreViewModel>(Assert.IsType<ViewResult>(stores.UpdateStore()).Model);
Assert.Equal(0.0, vm.PaymentTolerance);
vm.PaymentTolerance = 50.0;
Assert.IsType<RedirectToActionResult>(stores.UpdateStore(vm).Result);
var invoice = user.BitPay.CreateInvoice(new Invoice()
{
Buyer = new Buyer() { email = "test@fwf.com" },
Price = 5000.0,
Currency = "USD",
PosData = "posData",
OrderId = "orderId",
ItemDesc = "Some description",
FullNotifications = true
}, Facade.Merchant);
// Pays 75%
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, tester.ExplorerNode.Network);
tester.ExplorerNode.SendToAddress(invoiceAddress, Money.Satoshis((decimal)invoice.BtcDue.Satoshi * 0.75m));
Eventually(() =>
{
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
Assert.Equal("paid", localInvoice.Status);
});
}
}
[Fact]
public void CanPayUsingBIP70()
{

View File

@ -68,6 +68,8 @@ namespace BTCPayServer.HostedServices
context.Events.Add(new InvoiceEvent(invoice, 1004, "invoice_expired"));
invoice.Status = "expired";
if(invoice.ExceptionStatus == "paidPartial")
context.Events.Add(new InvoiceEvent(invoice, 2000, "invoice_expiredPaidPartial"));
}
var payments = invoice.GetPayments().Where(p => p.Accounted).ToArray();
@ -84,7 +86,7 @@ namespace BTCPayServer.HostedServices
{
context.Events.Add(new InvoiceEvent(invoice, 1003, "invoice_paidInFull"));
invoice.Status = "paid";
invoice.ExceptionStatus = accounting.Paid > accounting.MinimumTotalDue ? "paidOver" : null;
invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? "paidOver" : null;
await _InvoiceRepository.UnaffectAddress(invoice.Id);
context.MarkDirty();
}
@ -106,13 +108,13 @@ namespace BTCPayServer.HostedServices
// Just make sure RBF did not cancelled a payment
if (invoice.Status == "paid")
{
if (accounting.Paid == accounting.MinimumTotalDue && invoice.ExceptionStatus == "paidOver")
if (accounting.MinimumTotalDue <= accounting.Paid && accounting.Paid <= accounting.TotalDue && invoice.ExceptionStatus == "paidOver")
{
invoice.ExceptionStatus = null;
context.MarkDirty();
}
if (accounting.Paid > accounting.MinimumTotalDue && invoice.ExceptionStatus != "paidOver")
if (accounting.Paid > accounting.TotalDue && invoice.ExceptionStatus != "paidOver")
{
invoice.ExceptionStatus = "paidOver";
context.MarkDirty();

View File

@ -676,10 +676,7 @@ namespace BTCPayServer.Services.Invoices
accounting.Due = Money.Max(accounting.TotalDue - accounting.Paid, Money.Zero);
accounting.DueUncapped = accounting.TotalDue - accounting.Paid;
accounting.NetworkFee = accounting.TotalDue - totalDueNoNetworkCost;
accounting.MinimumTotalDue = new Money(Convert.ToInt32(Math.Ceiling(accounting.TotalDue.Satoshi -
(accounting.TotalDue.Satoshi *
(ParentEntity.PaymentTolerance / 100.0)
))));
accounting.MinimumTotalDue = Money.Satoshis(accounting.TotalDue.Satoshi * (1.0m - ((decimal)ParentEntity.PaymentTolerance / 100.0m)));
return accounting;
}