PaperTiger.BillingEngine (PaperTiger v1.0.2)

Copy Markdown View Source

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 - Call process_billing/0 after advance_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 all 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

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

clear_simulation(customer_id)

@spec clear_simulation(String.t()) :: :ok

Clears any payment simulation for a customer (delegates to ChaosCoordinator).

get_mode()

@spec get_mode() :: atom()

Gets the current billing mode (legacy API).

Returns :chaos if payment failure rate > 0, otherwise :happy_path.

process_billing()

@spec process_billing() :: {:ok, map()}

Processes all subscriptions that are due for billing.

This is called automatically on each poll interval, but can also be called manually (useful in manual clock mode after advancing time).

set_mode(mode, opts \\ [])

@spec set_mode(
  atom(),
  keyword()
) :: :ok

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.

simulate_failure(customer_id, decline_code)

@spec simulate_failure(String.t(), atom()) :: :ok

Simulates a payment failure for a specific customer (delegates to ChaosCoordinator).

start_link(opts \\ [])

Starts the billing engine.