Skip to content

Commit 1f0250c

Browse files
fix(billing): guard getStripe() null + update JSDoc in invoice.payment_succeeded
/critical-review medium: add explicit `if (!stripe) throw` so the fallback warn log is meaningful ("Stripe not configured") rather than a cryptic TypeError. /critical-review low: update JSDoc @description to document V8 C1 plan-restore behavior and the non-fatal Stripe re-fetch fallback contract.
1 parent 19a49e9 commit 1f0250c

1 file changed

Lines changed: 6 additions & 1 deletion

File tree

modules/billing/services/billing.webhook.service.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,9 +538,13 @@ const handleInvoicePaymentFailed = async (invoice, event) => {
538538
};
539539

540540
/**
541-
* @description Handle invoice.payment_succeeded event — clear degraded mode (pastDueSince).
541+
* @description Handle invoice.payment_succeeded event — clear degraded mode and restore plan.
542542
* When a past-due invoice is finally paid, remove the pastDueSince marker so
543543
* the subscription exits degraded mode on next request.
544+
* V8 C1: also re-fetches the live Stripe subscription to restore the correct plan,
545+
* guarding against the case where customer.subscription.updated is dead-lettered
546+
* after a dunning sweep downgraded the plan to 'free'. Stripe re-fetch failure is
547+
* non-fatal (warn log, plan not restored, pastDueSince+status update still fires).
544548
* Uses updateIfEventNewer to guard against out-of-order webhook delivery (V5 P1 #1).
545549
* @param {Object} invoice - Stripe invoice object
546550
* @param {Object} event - Full Stripe event (with event.created and event.id for ordering)
@@ -570,6 +574,7 @@ const handleInvoicePaymentSucceeded = async (invoice, event) => {
570574
if (isPastDue) {
571575
try {
572576
const stripe = getStripe();
577+
if (!stripe) throw new Error('Stripe not configured');
573578
const stripeSub = await stripe.subscriptions.retrieve(stripeSubscriptionId);
574579
resolvedPlan = resolvePlan(stripeSub);
575580
fields.plan = resolvedPlan;

0 commit comments

Comments
 (0)