diff --git a/src/Core/Models/Stripe/StripeInvoiceListOptions.cs b/src/Core/Models/Stripe/StripeInvoiceListOptions.cs
new file mode 100644
index 0000000000..bcffc738da
--- /dev/null
+++ b/src/Core/Models/Stripe/StripeInvoiceListOptions.cs
@@ -0,0 +1,27 @@
+using Stripe;
+
+namespace Bit.Core.Models.BitStripe;
+
+///
+/// A model derived from the Stripe class that includes a flag used to
+/// retrieve all invoices from the Stripe API rather than a limited set.
+///
+public class StripeInvoiceListOptions : InvoiceListOptions
+{
+ public bool SelectAll { get; set; }
+
+ public InvoiceListOptions ToInvoiceListOptions()
+ {
+ var options = (InvoiceListOptions)this;
+
+ if (!SelectAll)
+ {
+ return options;
+ }
+
+ options.EndingBefore = null;
+ options.StartingAfter = null;
+
+ return options;
+ }
+}
diff --git a/src/Core/Services/IStripeAdapter.cs b/src/Core/Services/IStripeAdapter.cs
index 4f1cdd37eb..f79cc1200e 100644
--- a/src/Core/Services/IStripeAdapter.cs
+++ b/src/Core/Services/IStripeAdapter.cs
@@ -18,7 +18,7 @@ public interface IStripeAdapter
Task InvoiceCreateAsync(Stripe.InvoiceCreateOptions options);
Task InvoiceItemCreateAsync(Stripe.InvoiceItemCreateOptions options);
Task InvoiceGetAsync(string id, Stripe.InvoiceGetOptions options);
- Task> InvoiceListAsync(Stripe.InvoiceListOptions options);
+ Task> InvoiceListAsync(StripeInvoiceListOptions options);
IEnumerable InvoiceItemListAsync(InvoiceItemListOptions options);
Task InvoiceUpdateAsync(string id, Stripe.InvoiceUpdateOptions options);
Task InvoiceFinalizeInvoiceAsync(string id, Stripe.InvoiceFinalizeOptions options);
diff --git a/src/Core/Services/Implementations/StripeAdapter.cs b/src/Core/Services/Implementations/StripeAdapter.cs
index 478d092fdc..28dd35034c 100644
--- a/src/Core/Services/Implementations/StripeAdapter.cs
+++ b/src/Core/Services/Implementations/StripeAdapter.cs
@@ -97,9 +97,23 @@ public class StripeAdapter : IStripeAdapter
return _invoiceService.GetAsync(id, options);
}
- public Task> InvoiceListAsync(Stripe.InvoiceListOptions options)
+ public async Task> InvoiceListAsync(StripeInvoiceListOptions options)
{
- return _invoiceService.ListAsync(options);
+ if (!options.SelectAll)
+ {
+ return (await _invoiceService.ListAsync(options.ToInvoiceListOptions())).Data;
+ }
+
+ options.Limit = 100;
+
+ var invoices = new List();
+
+ await foreach (var invoice in _invoiceService.ListAutoPagingAsync(options.ToInvoiceListOptions()))
+ {
+ invoices.Add(invoice);
+ }
+
+ return invoices;
}
public IEnumerable InvoiceItemListAsync(InvoiceItemListOptions options)
diff --git a/src/Core/Services/Implementations/StripePaymentService.cs b/src/Core/Services/Implementations/StripePaymentService.cs
index 214b2bff10..67de73a188 100644
--- a/src/Core/Services/Implementations/StripePaymentService.cs
+++ b/src/Core/Services/Implementations/StripePaymentService.cs
@@ -2,6 +2,7 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
+using Bit.Core.Models.BitStripe;
using Bit.Core.Models.Business;
using Bit.Core.Repositories;
using Bit.Core.Settings;
@@ -668,7 +669,7 @@ public class StripePaymentService : IPaymentService
if (!stripePaymentMethod && subInvoiceMetadata.Any())
{
- var invoices = await _stripeAdapter.InvoiceListAsync(new Stripe.InvoiceListOptions
+ var invoices = await _stripeAdapter.InvoiceListAsync(new StripeInvoiceListOptions
{
Subscription = subscription.Id
});
@@ -2138,15 +2139,26 @@ public class StripePaymentService : IPaymentService
return null;
}
- var invoices = await _stripeAdapter.InvoiceListAsync(new Stripe.InvoiceListOptions
+ var options = new StripeInvoiceListOptions
{
Customer = customer.Id,
- Limit = 50
- });
+ SelectAll = true
+ };
- return invoices.Data.Where(i => i.Status != "void" && i.Status != "draft")
- .OrderByDescending(i => i.Created).Select(i => new BillingInfo.BillingInvoice(i));
+ try
+ {
+ var invoices = await _stripeAdapter.InvoiceListAsync(options);
+ return invoices
+ .Where(invoice => invoice.Status != "void" && invoice.Status != "draft")
+ .OrderByDescending(invoice => invoice.Created)
+ .Select(invoice => new BillingInfo.BillingInvoice(invoice));
+ }
+ catch (Stripe.StripeException exception)
+ {
+ _logger.LogError(exception, "An error occurred while listing Stripe invoices");
+ throw new GatewayException("Failed to retrieve current invoices", exception);
+ }
}
// We are taking only first 30 characters of the SubscriberName because stripe provide