Better handle transition from paid to invalid

This commit is contained in:
nicolas.dorier
2017-10-23 18:07:50 +09:00
parent 6ba6a34df2
commit 4dca81403b
4 changed files with 74 additions and 57 deletions

View File

@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<Version>1.0.0.21</Version> <Version>1.0.0.22</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="Build\dockerfiles\**" /> <Compile Remove="Build\dockerfiles\**" />

View File

@@ -75,8 +75,9 @@ namespace BTCPayServer.Controllers
_FeeProvider = feeProvider ?? throw new ArgumentNullException(nameof(feeProvider)); _FeeProvider = feeProvider ?? throw new ArgumentNullException(nameof(feeProvider));
} }
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl, double expiryMinutes = 15) internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl, double expiryMinutes = 15, double monitoringMinutes = 60)
{ {
//TODO: expiryMinutes (time before a new invoice can become paid) and monitoringMinutes (time before a paid invoice becomes invalid) should be configurable at store level
var derivationStrategy = store.DerivationStrategy; var derivationStrategy = store.DerivationStrategy;
var entity = new InvoiceEntity var entity = new InvoiceEntity
{ {
@@ -88,6 +89,7 @@ namespace BTCPayServer.Controllers
notificationUri = null; notificationUri = null;
EmailAddressAttribute emailValidator = new EmailAddressAttribute(); EmailAddressAttribute emailValidator = new EmailAddressAttribute();
entity.ExpirationTime = entity.InvoiceTime.AddMinutes(expiryMinutes); entity.ExpirationTime = entity.InvoiceTime.AddMinutes(expiryMinutes);
entity.MonitoringExpiration = entity.InvoiceTime.AddMinutes(monitoringMinutes);
entity.OrderId = invoice.OrderId; entity.OrderId = invoice.OrderId;
entity.ServerUrl = serverUrl; entity.ServerUrl = serverUrl;
entity.FullNotifications = invoice.FullNotifications; entity.FullNotifications = invoice.FullNotifications;

View File

@@ -248,6 +248,11 @@ namespace BTCPayServer.Services.Invoices
get; get;
set; set;
} }
public DateTimeOffset? MonitoringExpiration
{
get;
set;
}
public bool IsExpired() public bool IsExpired()
{ {

View File

@@ -80,7 +80,9 @@ namespace BTCPayServer.Services.Invoices
Logs.PayServer.LogInformation($"Invoice {invoice.Id}: {stateBefore} => {invoice.Status}"); Logs.PayServer.LogInformation($"Invoice {invoice.Id}: {stateBefore} => {invoice.Status}");
} }
if(invoice.Status == "complete" || invoice.Status == "invalid") var expirationMonitoring = invoice.MonitoringExpiration.HasValue ? invoice.MonitoringExpiration.Value : invoice.InvoiceTime + TimeSpan.FromMinutes(60);
if(invoice.Status == "complete" ||
((invoice.Status == "invalid" || invoice.Status == "expired") && expirationMonitoring < DateTimeOffset.UtcNow))
{ {
if(await _InvoiceRepository.RemovePendingInvoice(invoice.Id).ConfigureAwait(false)) if(await _InvoiceRepository.RemovePendingInvoice(invoice.Id).ConfigureAwait(false))
Logs.PayServer.LogInformation("Stopped watching invoice " + invoiceId); Logs.PayServer.LogInformation("Stopped watching invoice " + invoiceId);
@@ -106,15 +108,7 @@ namespace BTCPayServer.Services.Invoices
private async Task<(bool NeedSave, UTXOChanges Changes)> UpdateInvoice(UTXOChanges changes, InvoiceEntity invoice) private async Task<(bool NeedSave, UTXOChanges Changes)> UpdateInvoice(UTXOChanges changes, InvoiceEntity invoice)
{ {
bool needSave = false; bool needSave = false;
//Fetch unknown payments
if(invoice.Status == "new" && invoice.ExpirationTime < DateTimeOffset.UtcNow)
{
needSave = true;
invoice.Status = "expired";
}
if(invoice.Status == "expired" || invoice.Status == "new" || invoice.Status == "invalid")
{
var strategy = _DerivationFactory.Parse(invoice.DerivationStrategy); var strategy = _DerivationFactory.Parse(invoice.DerivationStrategy);
changes = await _ExplorerClient.SyncAsync(strategy, changes, !LongPollingMode, _Cts.Token).ConfigureAwait(false); changes = await _ExplorerClient.SyncAsync(strategy, changes, !LongPollingMode, _Cts.Token).ConfigureAwait(false);
@@ -135,19 +129,21 @@ namespace BTCPayServer.Services.Invoices
{ {
var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin).ConfigureAwait(false); var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin).ConfigureAwait(false);
invoice.Payments.Add(payment); invoice.Payments.Add(payment);
if(invoice.Status == "expired") }
//////
if(invoice.Status == "new" && invoice.ExpirationTime < DateTimeOffset.UtcNow)
{ {
if(invoice.ExceptionStatus == null)
invoice.ExceptionStatus = "paidLate";
needSave = true; needSave = true;
} invoice.Status = "expired";
}
} }
if(invoice.Status == "new") if(invoice.Status == "new" || invoice.Status == "expired")
{ {
var totalPaid = invoice.Payments.Select(p => p.Output.Value).Sum(); var totalPaid = invoice.Payments.Select(p => p.Output.Value).Sum();
if(totalPaid >= invoice.GetTotalCryptoDue()) if(totalPaid >= invoice.GetTotalCryptoDue())
{
if(invoice.Status == "new")
{ {
invoice.Status = "paid"; invoice.Status = "paid";
if(invoice.FullNotifications) if(invoice.FullNotifications)
@@ -157,6 +153,12 @@ namespace BTCPayServer.Services.Invoices
invoice.ExceptionStatus = null; invoice.ExceptionStatus = null;
needSave = true; needSave = true;
} }
else if(invoice.Status == "expired")
{
invoice.ExceptionStatus = "paidLate";
needSave = true;
}
}
if(totalPaid > invoice.GetTotalCryptoDue() && invoice.ExceptionStatus != "paidOver") if(totalPaid > invoice.GetTotalCryptoDue() && invoice.ExceptionStatus != "paidOver")
{ {
@@ -172,6 +174,8 @@ namespace BTCPayServer.Services.Invoices
} }
if(invoice.Status == "paid") if(invoice.Status == "paid")
{
if(!invoice.MonitoringExpiration.HasValue || invoice.MonitoringExpiration > DateTimeOffset.UtcNow)
{ {
var transactions = await GetPaymentsWithTransaction(invoice); var transactions = await GetPaymentsWithTransaction(invoice);
if(invoice.SpeedPolicy == SpeedPolicy.HighSpeed) if(invoice.SpeedPolicy == SpeedPolicy.HighSpeed)
@@ -195,6 +199,12 @@ namespace BTCPayServer.Services.Invoices
needSave = true; needSave = true;
} }
} }
else
{
invoice.Status = "invalid";
needSave = true;
}
}
if(invoice.Status == "confirmed") if(invoice.Status == "confirmed")
{ {