mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 22:44:29 +01:00
add test and refactor for PR
This commit is contained in:
@@ -229,6 +229,33 @@ namespace BTCPayServer.Tests
|
|||||||
#pragma warning restore CS0618
|
#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]
|
[Fact]
|
||||||
public void CanPayUsingBIP70()
|
public void CanPayUsingBIP70()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -76,16 +76,15 @@ namespace BTCPayServer.HostedServices
|
|||||||
if (paymentMethod == null)
|
if (paymentMethod == null)
|
||||||
return;
|
return;
|
||||||
var network = _NetworkProvider.GetNetwork(paymentMethod.GetId().CryptoCode);
|
var network = _NetworkProvider.GetNetwork(paymentMethod.GetId().CryptoCode);
|
||||||
var isPaid = accounting.IsPaid(invoice.PaymentTolerance, out var paidOver);
|
|
||||||
if (invoice.Status == "new" || invoice.Status == "expired")
|
if (invoice.Status == "new" || invoice.Status == "expired")
|
||||||
{
|
{
|
||||||
if (isPaid)
|
if (accounting.Paid >= accounting.MinimumTotalDue)
|
||||||
{
|
{
|
||||||
if (invoice.Status == "new")
|
if (invoice.Status == "new")
|
||||||
{
|
{
|
||||||
context.Events.Add(new InvoiceEvent(invoice, 1003, "invoice_paidInFull"));
|
context.Events.Add(new InvoiceEvent(invoice, 1003, "invoice_paidInFull"));
|
||||||
invoice.Status = "paid";
|
invoice.Status = "paid";
|
||||||
invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? "paidOver" : null;
|
invoice.ExceptionStatus = accounting.Paid > accounting.MinimumTotalDue ? "paidOver" : null;
|
||||||
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
||||||
context.MarkDirty();
|
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";
|
invoice.ExceptionStatus = "paidPartial";
|
||||||
context.MarkDirty();
|
context.MarkDirty();
|
||||||
@@ -107,19 +106,19 @@ namespace BTCPayServer.HostedServices
|
|||||||
// Just make sure RBF did not cancelled a payment
|
// Just make sure RBF did not cancelled a payment
|
||||||
if (invoice.Status == "paid")
|
if (invoice.Status == "paid")
|
||||||
{
|
{
|
||||||
if (!paidOver && invoice.ExceptionStatus == "paidOver")
|
if (accounting.Paid == accounting.MinimumTotalDue && invoice.ExceptionStatus == "paidOver")
|
||||||
{
|
{
|
||||||
invoice.ExceptionStatus = null;
|
invoice.ExceptionStatus = null;
|
||||||
context.MarkDirty();
|
context.MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paidOver&& invoice.ExceptionStatus != "paidOver")
|
if (accounting.Paid > accounting.MinimumTotalDue && invoice.ExceptionStatus != "paidOver")
|
||||||
{
|
{
|
||||||
invoice.ExceptionStatus = "paidOver";
|
invoice.ExceptionStatus = "paidOver";
|
||||||
context.MarkDirty();
|
context.MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isPaid)
|
if (accounting.Paid < accounting.MinimumTotalDue)
|
||||||
{
|
{
|
||||||
invoice.Status = "new";
|
invoice.Status = "new";
|
||||||
invoice.ExceptionStatus = accounting.Paid == Money.Zero ? null : "paidPartial";
|
invoice.ExceptionStatus = accounting.Paid == Money.Zero ? null : "paidPartial";
|
||||||
@@ -130,19 +129,19 @@ namespace BTCPayServer.HostedServices
|
|||||||
if (invoice.Status == "paid")
|
if (invoice.Status == "paid")
|
||||||
{
|
{
|
||||||
var confirmedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentConfirmed(p, invoice.SpeedPolicy, network));
|
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
|
if (// Is after the monitoring deadline
|
||||||
(invoice.MonitoringExpiration < DateTimeOffset.UtcNow)
|
(invoice.MonitoringExpiration < DateTimeOffset.UtcNow)
|
||||||
&&
|
&&
|
||||||
// And not enough amount confirmed
|
// And not enough amount confirmed
|
||||||
(!confirmedIsPaid))
|
(confirmedAccounting.Paid < accounting.MinimumTotalDue))
|
||||||
{
|
{
|
||||||
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
||||||
context.Events.Add(new InvoiceEvent(invoice, 1013, "invoice_failedToConfirm"));
|
context.Events.Add(new InvoiceEvent(invoice, 1013, "invoice_failedToConfirm"));
|
||||||
invoice.Status = "invalid";
|
invoice.Status = "invalid";
|
||||||
context.MarkDirty();
|
context.MarkDirty();
|
||||||
}
|
}
|
||||||
else if (confirmedIsPaid)
|
else if (confirmedAccounting.Paid >= accounting.MinimumTotalDue)
|
||||||
{
|
{
|
||||||
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
await _InvoiceRepository.UnaffectAddress(invoice.Id);
|
||||||
context.Events.Add(new InvoiceEvent(invoice, 1005, "invoice_confirmed"));
|
context.Events.Add(new InvoiceEvent(invoice, 1005, "invoice_confirmed"));
|
||||||
@@ -154,8 +153,7 @@ namespace BTCPayServer.HostedServices
|
|||||||
if (invoice.Status == "confirmed")
|
if (invoice.Status == "confirmed")
|
||||||
{
|
{
|
||||||
var completedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentCompleted(p, network));
|
var completedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentCompleted(p, network));
|
||||||
var confirmedIsPaid = completedAccounting.IsPaid(invoice.PaymentTolerance, out var completedPaidOver);
|
if (completedAccounting.Paid >= accounting.MinimumTotalDue)
|
||||||
if (confirmedIsPaid)
|
|
||||||
{
|
{
|
||||||
context.Events.Add(new InvoiceEvent(invoice, 1006, "invoice_completed"));
|
context.Events.Add(new InvoiceEvent(invoice, 1006, "invoice_completed"));
|
||||||
invoice.Status = "complete";
|
invoice.Status = "complete";
|
||||||
|
|||||||
@@ -524,22 +524,10 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
/// Total amount of network fee to pay to the invoice
|
/// Total amount of network fee to pay to the invoice
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Money NetworkFee { get; set; }
|
public Money NetworkFee { get; set; }
|
||||||
|
/// <summary>
|
||||||
public bool IsPaid(double tolerance, out bool paidOver)
|
/// Minimum required to be paid in order to accept invocie as paid
|
||||||
{
|
/// </summary>
|
||||||
paidOver = false;
|
public Money MinimumTotalDue { get; set; }
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PaymentMethod
|
public class PaymentMethod
|
||||||
@@ -688,6 +676,10 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
accounting.Due = Money.Max(accounting.TotalDue - accounting.Paid, Money.Zero);
|
accounting.Due = Money.Max(accounting.TotalDue - accounting.Paid, Money.Zero);
|
||||||
accounting.DueUncapped = accounting.TotalDue - accounting.Paid;
|
accounting.DueUncapped = accounting.TotalDue - accounting.Paid;
|
||||||
accounting.NetworkFee = accounting.TotalDue - totalDueNoNetworkCost;
|
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;
|
return accounting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user