Simulates Stripe's subscription billing lifecycle.
The billing engine processes subscriptions whose current_period_end has passed,
creating invoices, processing payments, and firing appropriate webhooks.
Billing Modes
Payment chaos is now managed by PaperTiger.ChaosCoordinator. Use:
PaperTiger.ChaosCoordinator.configure(%{
payment: %{
failure_rate: 0.1,
decline_codes: [:card_declined, :insufficient_funds],
decline_weights: %{card_declined: 0.7, insufficient_funds: 0.3}
}
})Legacy set_mode/2 API is still supported for backwards compatibility.
Clock Integration
The billing engine respects PaperTiger's clock modes:
:real- Polls every second for due subscriptions:accelerated- Same polling, but time moves faster:manual- Callprocess_billing/0afteradvance_time/1
Usage
# Process all due subscriptions immediately
PaperTiger.BillingEngine.process_billing()
# Simulate payment failure for a specific customer (delegates to ChaosCoordinator)
PaperTiger.ChaosCoordinator.simulate_failure("cus_xxx", :card_declined)
# Clear failure simulation
PaperTiger.ChaosCoordinator.clear_simulation("cus_xxx")
Summary
Functions
Returns a specification to start this module under a supervisor.
Clears any payment simulation for a customer (delegates to ChaosCoordinator).
Gets the current billing mode (legacy API).
Processes the subscriptions that are due for billing.
Sets the billing mode (legacy API, delegates to ChaosCoordinator).
Simulates a payment failure for a specific customer (delegates to ChaosCoordinator).
Starts the billing engine.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec clear_simulation(String.t()) :: :ok
Clears any payment simulation for a customer (delegates to ChaosCoordinator).
@spec get_mode() :: atom()
Gets the current billing mode (legacy API).
Returns :chaos if payment failure rate > 0, otherwise :happy_path.
@spec process_billing(:current | :all) :: {:ok, map()}
Processes the subscriptions that are due for billing.
With :current (the default) only the caller's storage namespace is
processed: its sandbox and, when set, its connected account. That is the
right scope after advancing a manual clock in a test. With :all every
namespace that holds subscriptions is processed, which is what the
automatic poll does.
Sets the billing mode (legacy API, delegates to ChaosCoordinator).
Modes
:happy_path- All payments succeed:chaos- Random failures based on configured rates
Options (for chaos mode)
:payment_failure_rate- Probability of payment failure (0.0 - 1.0):decline_codes- List of decline codes to use randomly:decline_code_weights- Map of decline code to weight for realistic distribution
Prefer using PaperTiger.ChaosCoordinator.configure/1 directly for new code.
Simulates a payment failure for a specific customer (delegates to ChaosCoordinator).
Starts the billing engine.