A couple of billing updates#2849
Closed
jshearer wants to merge 2 commits into
Closed
Conversation
The invoice generator's trial-run workflow ran against a sandbox Stripe account, but produced inaccurate results because the sandbox lacked livemode invoice state (manual bills with existing open/paid invoices appeared as phantom creates). `--dry-run` runs against livemode Stripe in read-only mode, showing what would happen without creating invoices, customers, or modifying anything. Structural changes: * Split `upsert_invoice` into `classify` (read-only: validation, Stripe searches) and `execute` (writes: customer/invoice creation, line items, verification). `--dry-run` stops after classify. * Decompose `get_or_create_customer_for_tenant` into `find_customer` (read-only search) and `ensure_customer_for_invoicing` (find-or-create + email backfill). * Reorder classify checks so cheap local validations (FreeTier, FutureTrialStart, LessThanMinimum) run before any Stripe API calls. * Multi-month manual bills that already have an `open`, `paid`, `void`, or `uncollectible` invoice in Stripe are now classified as `AlreadyProcessed` instead of erroring. These are expected when date-range-overlapping manual bills were invoiced in a previous billing run. * Per-tenant summary output annotates manual bills with their date range (`[manual: 2026-01-01 - 2026-06-30]`). * Dry-run with `--clean-up` previews which stale draft invoices would be deleted. `--recreate-finalized` logs which invoices would be deleted and recreated.
Customers' stored payment methods are for monthly usage overages. Manual bills (contracts, one-off charges, etc.) should be sent as invoices so the customer can decide how to pay, rather than being automatically charged to their payment method. * Override `charge_type` to `SendInvoice` for manual invoices during creation in `publish` * Switch manual invoices from `charge_automatically` to `send_invoice` during the send phase, even if the customer has a payment method on file
Contributor
Author
|
rolling into #2883 is simpler |
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.
Finally got around to adding a real
--dry-runmode. Running against the Stripe testmode API key was starting to cause too many issues. See more details in the commit messageThe invoice generator's trial-run workflow ran against a sandbox Stripe account, but produced inaccurate results because the sandbox lacked livemode invoice state (manual bills with existing open/paid invoices appeared as phantom creates).
--dry-runruns against livemode Stripe in read-only mode, showing what would happen without creating invoices, customers, or modifying anything.Change the behavior for manual bills. Contract customers don't want us to use their payment method on file to pay for their contracted invoices, just for monthly overages. So from now on, all
Manualbills will be forced tocharge_type: SendInvoiceduring the final send/charge step.