Fix manual invoicing bugs#673
Merged
Merged
Conversation
Invoices created outside of our subscription flow (manual Stripe invoices, quote-based invoices) were being saved to our database with no subscription link, then picked up by overdue processing causing erroneous emails and subscription cancellations. handle_invoice_created now returns early if no subscription can be resolved from the webhook data, preventing orphaned invoice records. Closes #670 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Invoice webhook handlers for finalized and paid events only updated individual fields (status, due_date) but not amount. There was also no handler for invoice.updated events. This meant amount changes (e.g. line items added after creation) were never captured in our system. - Add handle_invoice_updated task and wire invoice.updated webhook - Refactor handle_invoice_finalized and handle_invoice_paid to use Invoice.create_or_update_from_stripe() for full state sync - Preserve payment_failed flag clearing in the paid handler Closes #669 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
$0 invoices were being processed by the overdue invoice system, triggering warning emails and eventually cancelling subscriptions over invoices where no payment is actually owed. - Add amount__gt=0 filter to check_overdue_invoices query - Add early return in process_overdue_invoice for $0 invoices Closes #671 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
process_overdue_invoice was calling organization.subscription_cancelled() which always cancels the org's current subscription. When an overdue invoice was linked to a different subscription (or had no subscription at all), this cancelled the wrong subscription entirely. - Change process_overdue_invoice to pass invoice.subscription explicitly - Add optional subscription parameter to Organization.subscription_cancelled - Skip cancellation when invoice has no linked subscription Closes #672 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mitchelljkotler
approved these changes
May 6, 2026
eyeseast
approved these changes
May 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a chain of bugs that caused a customer to receive an erroneous subscription cancellation email. A manually-created Stripe invoice was saved with
amount=0(captured before line items were added), subsequent updates were never synced to our system, and overdue processing could (in theory) cancel the customer's unrelated subscription.handle_invoice_creatednow skips invoices that can't be linked to a subscription record (manual invoices, quote-based invoices). Closes Don't track invoices that have no associated subscription #670invoice.updatedwebhook handler, refactorhandle_invoice_finalizedandhandle_invoice_paidto useInvoice.create_or_update_from_stripe()so amount/status/due_date changes are always captured. Closes Invoice webhook handlers don't keep invoice state in sync #669check_overdue_invoicesfilters out zero-amount invoices, with a defense-in-depth early return inprocess_overdue_invoice. Closes Overdue invoice processing should skip $0 invoices #671process_overdue_invoicenow cancelsinvoice.subscriptioninstead oforganization.subscription, preventing unrelated subscriptions from being cancelled. Closes Overdue invoice processing cancels the wrong subscription #672Co-authored with Claude Opus 4.6