From 2f8be8c9f085febf0a9caa4f00fd8fecb5609143 Mon Sep 17 00:00:00 2001 From: Nicolas Dorier Date: Wed, 19 Nov 2025 15:00:39 +0900 Subject: [PATCH] Add a 'Pending invoice' pill in portal subscription when invoice processing --- .../Data/Subscriptions/SubscriberData.cs | 3 +++ BTCPayServer.Data/Migrations/20251028061727_subs.cs | 1 + .../Migrations/ApplicationDbContextModelSnapshot.cs | 4 ++++ .../Subscriptions/SubscriptionHostedService.cs | 11 ++++++++++- .../Views/UISubscriberPortal/SubscriberPortal.cshtml | 4 ++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/BTCPayServer.Data/Data/Subscriptions/SubscriberData.cs b/BTCPayServer.Data/Data/Subscriptions/SubscriberData.cs index 4535faf49..43a9d8c96 100644 --- a/BTCPayServer.Data/Data/Subscriptions/SubscriberData.cs +++ b/BTCPayServer.Data/Data/Subscriptions/SubscriberData.cs @@ -56,6 +56,9 @@ public class SubscriberData : BaseEntityData public decimal MissingCredit() => Math.Max(0m, NextPlan.Price - GetCredit(NextPlan.Currency)); + [Column("processing_invoice_id")] + public string? ProcessingInvoiceId { get; set; } + [Required] [Column("phase")] public PhaseTypes Phase { get; set; } = PhaseTypes.Expired; diff --git a/BTCPayServer.Data/Migrations/20251028061727_subs.cs b/BTCPayServer.Data/Migrations/20251028061727_subs.cs index 744cac667..03b87744f 100644 --- a/BTCPayServer.Data/Migrations/20251028061727_subs.cs +++ b/BTCPayServer.Data/Migrations/20251028061727_subs.cs @@ -200,6 +200,7 @@ namespace BTCPayServer.Migrations plan_id = table.Column(type: "text", nullable: false), new_plan_id = table.Column(type: "text", nullable: true), paid_amount = table.Column(type: "numeric", nullable: true), + processing_invoice_id = table.Column(type: "text", nullable: true), phase = table.Column(type: "text", nullable: false, defaultValueSql: "'Expired'::TEXT"), plan_started = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"), period_end = table.Column(type: "timestamp with time zone", nullable: true), diff --git a/BTCPayServer.Data/Migrations/ApplicationDbContextModelSnapshot.cs b/BTCPayServer.Data/Migrations/ApplicationDbContextModelSnapshot.cs index 4ab9fe105..b7c9af182 100644 --- a/BTCPayServer.Data/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/BTCPayServer.Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1567,6 +1567,10 @@ namespace BTCPayServer.Migrations .HasColumnName("plan_started") .HasDefaultValueSql("now()"); + b.Property("ProcessingInvoiceId") + .HasColumnType("text") + .HasColumnName("processing_invoice_id"); + b.Property("SuspensionReason") .HasColumnType("text") .HasColumnName("suspension_reason"); diff --git a/BTCPayServer/Plugins/Subscriptions/SubscriptionHostedService.cs b/BTCPayServer/Plugins/Subscriptions/SubscriptionHostedService.cs index 34c04f052..04701f64a 100644 --- a/BTCPayServer/Plugins/Subscriptions/SubscriptionHostedService.cs +++ b/BTCPayServer/Plugins/Subscriptions/SubscriptionHostedService.cs @@ -375,7 +375,6 @@ public class SubscriptionHostedService( var checkout = await ctx.PlanCheckouts.GetCheckout(checkoutId); var plan = checkout?.Plan; if (checkout is null || plan is null || - (invoice.Status == InvoiceStatus.Processing && !plan.OptimisticActivation) || checkout.Plan.Offering.App.StoreDataId != invoice.StoreId) return; @@ -384,6 +383,16 @@ public class SubscriptionHostedService( throw new InvalidOperationException("Bug: Subscriber is null and not a new subscriber"); var sub = checkout.Subscriber; + var processingInvoiceId = invoice.Status == InvoiceStatus.Processing ? invoice.Id : null; + if (sub is not null && + sub.ProcessingInvoiceId != processingInvoiceId) + { + sub.ProcessingInvoiceId = processingInvoiceId; + await ctx.SaveChangesAsync(); + } + + if (invoice.Status == InvoiceStatus.Processing && !plan.OptimisticActivation) + return; if (invoice.Status is InvoiceStatus.Settled or InvoiceStatus.Processing) { diff --git a/BTCPayServer/Plugins/Subscriptions/Views/UISubscriberPortal/SubscriberPortal.cshtml b/BTCPayServer/Plugins/Subscriptions/Views/UISubscriberPortal/SubscriberPortal.cshtml index e56786f7b..3b8334489 100644 --- a/BTCPayServer/Plugins/Subscriptions/Views/UISubscriberPortal/SubscriberPortal.cshtml +++ b/BTCPayServer/Plugins/Subscriptions/Views/UISubscriberPortal/SubscriberPortal.cshtml @@ -280,6 +280,10 @@ { Grace } + @if (Model.Data.Subscriber is { ProcessingInvoiceId: {} pendingInvoiceId, OptimisticActivation: false }) + { + Pending invoice + } @if (Model.Subscriber.Plan.Description is not null) {