Fix: PaymentRequest get expired even if paid on time

This commit is contained in:
nicolas.dorier
2025-04-09 18:47:10 +09:00
parent 5df2ffe689
commit ba9646f486
4 changed files with 22 additions and 17 deletions

View File

@@ -1,4 +1,6 @@
using System; using System;
using System.ComponentModel.DataAnnotations.Schema;
using BTCPayServer.Client.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
@@ -18,6 +20,9 @@ namespace BTCPayServer.Data
public Client.Models.PaymentRequestStatus Status { get; set; } public Client.Models.PaymentRequestStatus Status { get; set; }
[NotMapped]
public bool Expirable => Status is PaymentRequestStatus.Pending or PaymentRequestStatus.Processing && Expiry is not null;
[Obsolete("Use Blob2 instead")] [Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; } public string Blob2 { get; set; }

View File

@@ -199,7 +199,7 @@ namespace BTCPayServer.PaymentRequest
{ {
if (data is if (data is
{ {
Status: PaymentRequestStatus.Pending or PaymentRequestStatus.Processing, Expirable: true,
Expiry: { } e Expiry: { } e
}) })
{ {

View File

@@ -10,6 +10,7 @@ using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.PaymentRequests; using BTCPayServer.Services.PaymentRequests;
using BTCPayServer.Services.Rates; using BTCPayServer.Services.Rates;
using static System.Runtime.InteropServices.JavaScript.JSType;
using PaymentRequestData = BTCPayServer.Data.PaymentRequestData; using PaymentRequestData = BTCPayServer.Data.PaymentRequestData;
namespace BTCPayServer.PaymentRequest namespace BTCPayServer.PaymentRequest
@@ -50,24 +51,21 @@ namespace BTCPayServer.PaymentRequest
public async Task UpdatePaymentRequestStateIfNeeded(PaymentRequestData pr) public async Task UpdatePaymentRequestStateIfNeeded(PaymentRequestData pr)
{ {
var blob = pr.GetBlob(); var newStatus = pr.Status;
var currentStatus = pr.Status; newStatus = pr switch
if (pr.Expiry.HasValue)
{ {
if (pr.Expiry.Value <= DateTimeOffset.UtcNow) { Expirable: true, Expiry: { } e }
currentStatus = Client.Models.PaymentRequestStatus.Expired; when e <= DateTimeOffset.UtcNow => PaymentRequestStatus.Expired,
} { Status: PaymentRequestStatus.Expired, Expiry: null } => PaymentRequestStatus.Pending,
else if (currentStatus != Client.Models.PaymentRequestStatus.Completed) _ => pr.Status
{ };
currentStatus = Client.Models.PaymentRequestStatus.Pending;
}
if (currentStatus != Client.Models.PaymentRequestStatus.Expired) if (newStatus is not (PaymentRequestStatus.Expired or PaymentRequestStatus.Completed))
{ {
var invoices = await _paymentRequestRepository.GetInvoicesForPaymentRequest(pr.Id); var invoices = await _paymentRequestRepository.GetInvoicesForPaymentRequest(pr.Id);
var contributions = _invoiceRepository.GetContributionsByPaymentMethodId(pr.Currency, invoices, true); var contributions = _invoiceRepository.GetContributionsByPaymentMethodId(pr.Currency, invoices, true);
currentStatus = newStatus =
(PaidEnough: contributions.Total >= pr.Amount, (PaidEnough: contributions.Total >= pr.Amount,
SettledEnough: contributions.TotalSettled >= pr.Amount) switch SettledEnough: contributions.TotalSettled >= pr.Amount) switch
{ {
@@ -77,10 +75,10 @@ namespace BTCPayServer.PaymentRequest
}; };
} }
if (currentStatus != pr.Status) if (newStatus != pr.Status)
{ {
pr.Status = currentStatus; pr.Status = newStatus;
await _paymentRequestRepository.UpdatePaymentRequestStatus(pr.Id, currentStatus); await _paymentRequestRepository.UpdatePaymentRequestStatus(pr.Id, newStatus);
} }
} }

View File

@@ -22,6 +22,8 @@ namespace BTCPayServer.Services
var due = ExecuteAt - DateTimeOffset.UtcNow; var due = ExecuteAt - DateTimeOffset.UtcNow;
if (due < TimeSpan.Zero) if (due < TimeSpan.Zero)
due = TimeSpan.Zero; due = TimeSpan.Zero;
else
due += TimeSpan.FromSeconds(1.0); // Better to be a bit late than too early
// Max timer needed, else dotnet crash // Max timer needed, else dotnet crash
if (due > MaxTimer) if (due > MaxTimer)
due = MaxTimer; due = MaxTimer;
@@ -61,7 +63,7 @@ namespace BTCPayServer.Services
var s = (TimerState)state!; var s = (TimerState)state!;
Task.Run(async () => Task.Run(async () =>
{ {
bool run = s.NextWait() == TimeSpan.Zero; bool run = s.NextWait() < TimeSpan.FromSeconds(5.0);
try try
{ {
if (run) if (run)