add test and refactor for PR

This commit is contained in:
Andrew Camilleri
2018-05-05 16:07:22 +02:00
parent b002c49dac
commit 9a92646d4d
3 changed files with 45 additions and 28 deletions

View File

@@ -229,6 +229,33 @@ namespace BTCPayServer.Tests
#pragma warning restore CS0618
}
[Fact]
public void CanAcceptInvoiceWithTolerance()
{
var entity = new InvoiceEntity();
#pragma warning disable CS0618
entity.Payments = new List<PaymentEntity>();
entity.SetPaymentMethod(new PaymentMethod() { CryptoCode = "BTC", Rate = 5000, TxFee = Money.Coins(0.1m) });
entity.ProductInformation = new ProductInformation() { Price = 5000 };
entity.PaymentTolerance = 0;
var paymentMethod = entity.GetPaymentMethods(null).TryGet("BTC", PaymentTypes.BTCLike);
var accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(1.1m), accounting.Due);
Assert.Equal(Money.Coins(1.1m), accounting.TotalDue);
Assert.Equal(Money.Coins(1.1m), accounting.MinimumTotalDue);
entity.PaymentTolerance = 10;
accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(0.99m), accounting.MinimumTotalDue);
entity.PaymentTolerance = 100;
accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(0), accounting.MinimumTotalDue);
}
[Fact]
public void CanPayUsingBIP70()
{

View File

@@ -76,16 +76,15 @@ namespace BTCPayServer.HostedServices
if (paymentMethod == null)
return;
var network = _NetworkProvider.GetNetwork(paymentMethod.GetId().CryptoCode);
var isPaid = accounting.IsPaid(invoice.PaymentTolerance, out var paidOver);
if (invoice.Status == "new" || invoice.Status == "expired")
{
if (isPaid)
if (accounting.Paid >= accounting.MinimumTotalDue)
{
if (invoice.Status == "new")
{
context.Events.Add(new InvoiceEvent(invoice, 1003, "invoice_paidInFull"));
invoice.Status = "paid";
invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? "paidOver" : null;
invoice.ExceptionStatus = accounting.Paid > accounting.MinimumTotalDue ? "paidOver" : null;
await _InvoiceRepository.UnaffectAddress(invoice.Id);
context.MarkDirty();
}
@@ -97,7 +96,7 @@ namespace BTCPayServer.HostedServices
}
}
if (!isPaid && invoice.ExceptionStatus != "paidPartial" && invoice.GetPayments().Count != 0)
if (accounting.Paid < accounting.MinimumTotalDue && invoice.GetPayments().Count != 0 && invoice.ExceptionStatus != "paidPartial")
{
invoice.ExceptionStatus = "paidPartial";
context.MarkDirty();
@@ -107,19 +106,19 @@ namespace BTCPayServer.HostedServices
// Just make sure RBF did not cancelled a payment
if (invoice.Status == "paid")
{
if (!paidOver && invoice.ExceptionStatus == "paidOver")
if (accounting.Paid == accounting.MinimumTotalDue && invoice.ExceptionStatus == "paidOver")
{
invoice.ExceptionStatus = null;
context.MarkDirty();
}
if (paidOver&& invoice.ExceptionStatus != "paidOver")
if (accounting.Paid > accounting.MinimumTotalDue && invoice.ExceptionStatus != "paidOver")
{
invoice.ExceptionStatus = "paidOver";
context.MarkDirty();
}
if (!isPaid)
if (accounting.Paid < accounting.MinimumTotalDue)
{
invoice.Status = "new";
invoice.ExceptionStatus = accounting.Paid == Money.Zero ? null : "paidPartial";
@@ -130,19 +129,19 @@ namespace BTCPayServer.HostedServices
if (invoice.Status == "paid")
{
var confirmedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentConfirmed(p, invoice.SpeedPolicy, network));
var confirmedIsPaid = confirmedAccounting.IsPaid(invoice.PaymentTolerance, out var confirmedPaidOver);
if (// Is after the monitoring deadline
(invoice.MonitoringExpiration < DateTimeOffset.UtcNow)
&&
// And not enough amount confirmed
(!confirmedIsPaid))
(confirmedAccounting.Paid < accounting.MinimumTotalDue))
{
await _InvoiceRepository.UnaffectAddress(invoice.Id);
context.Events.Add(new InvoiceEvent(invoice, 1013, "invoice_failedToConfirm"));
invoice.Status = "invalid";
context.MarkDirty();
}
else if (confirmedIsPaid)
else if (confirmedAccounting.Paid >= accounting.MinimumTotalDue)
{
await _InvoiceRepository.UnaffectAddress(invoice.Id);
context.Events.Add(new InvoiceEvent(invoice, 1005, "invoice_confirmed"));
@@ -154,8 +153,7 @@ namespace BTCPayServer.HostedServices
if (invoice.Status == "confirmed")
{
var completedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentCompleted(p, network));
var confirmedIsPaid = completedAccounting.IsPaid(invoice.PaymentTolerance, out var completedPaidOver);
if (confirmedIsPaid)
if (completedAccounting.Paid >= accounting.MinimumTotalDue)
{
context.Events.Add(new InvoiceEvent(invoice, 1006, "invoice_completed"));
invoice.Status = "complete";

View File

@@ -524,22 +524,10 @@ namespace BTCPayServer.Services.Invoices
/// Total amount of network fee to pay to the invoice
/// </summary>
public Money NetworkFee { get; set; }
public bool IsPaid(double tolerance, out bool paidOver)
{
paidOver = false;
if (Paid < TotalDue)
{
var tolerantAmount = (TotalDue.Satoshi * (tolerance == 0 ? 1 : (tolerance / 100)));
var minimumTotalDue = TotalDue.Satoshi - tolerantAmount;
return Paid.Satoshi >= minimumTotalDue;
}else if (Paid > TotalDue)
{
paidOver = true;
}
return true;
}
/// <summary>
/// Minimum required to be paid in order to accept invocie as paid
/// </summary>
public Money MinimumTotalDue { get; set; }
}
public class PaymentMethod
@@ -688,6 +676,10 @@ 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)
))));
return accounting;
}