Skip to content

BeamLabEU/phoenix_kit_billing

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PhoenixKitBilling

Elixir License: MIT

Billing module for PhoenixKit. Drop-in payments, subscriptions, invoices, orders, and multi-currency support with Stripe, PayPal, and Razorpay integration.

Features

  • Orders & invoices — full order-to-invoice-to-receipt workflow with status tracking and print views
  • Multi-provider payments — Stripe, PayPal, and Razorpay via a unified Provider behaviour with hosted checkout
  • Internal subscription control — subscriptions managed in your database, not by providers; automatic renewals and dunning
  • Multi-currency — currency definitions with exchange rates
  • Billing profiles — individual and company billing details with address, tax ID, and IBAN validation
  • Transactions & refunds — complete payment ledger with credit notes and partial refunds
  • Real-time updates — PubSub events for orders, invoices, transactions, subscriptions, and profiles
  • Admin dashboard — LiveViews for managing all billing entities, settings, and provider configuration
  • User dashboard — "My Orders" and "Billing Profiles" pages for end users
  • Print views — invoice, receipt, credit note, and payment confirmation print layouts
  • Auto-discovery — implements PhoenixKit.Module behaviour; PhoenixKit finds it at startup with zero config

Installation

Add phoenix_kit_billing to your dependencies in mix.exs:

def deps do
  [
    {:phoenix_kit_billing, "~> 0.1.0"}
  ]
end

Then fetch dependencies:

mix deps.get

Note: For development or if not yet published to Hex, you can use:

{:phoenix_kit_billing, github: "BeamLabEU/phoenix_kit_billing"}

PhoenixKit auto-discovers the module at startup — no additional configuration needed.

Quick Start

  1. Add the dependency to mix.exs
  2. Run mix deps.get
  3. Enable the module in admin settings (billing_enabled: true)
  4. Configure at least one payment provider in admin settings
  5. Orders and invoices are available at /admin/billing

Usage

Order-to-Invoice Workflow

alias PhoenixKit.Modules.Billing

# Create an order
{:ok, order} = Billing.create_order(user, %{
  line_items: [%{description: "Widget", quantity: 1, unit_price: Decimal.new("29.99")}],
  currency: "EUR"
})

# Confirm the order
{:ok, order} = Billing.confirm_order(order)

# Generate an invoice from the order
{:ok, invoice} = Billing.create_invoice_from_order(order)

# Send the invoice to the customer
{:ok, invoice} = Billing.send_invoice(invoice)

# Mark as paid (generates receipt automatically)
{:ok, invoice} = Billing.mark_invoice_paid(invoice)

Subscriptions

# Create a subscription type (plan)
{:ok, type} = Billing.create_subscription_type(%{
  name: "Pro Monthly",
  interval: "month",
  price: Decimal.new("19.99"),
  currency: "EUR"
})

# Create a subscription for a user
{:ok, subscription} = Billing.create_subscription(user, type)

Subscription renewals and failed-payment retries (dunning) are handled automatically by Oban workers.

Payment Providers

Providers are configured in admin settings. The system uses hosted checkout — users are redirected to the provider's payment page:

# Create a checkout session for an invoice
{:ok, session} = Billing.create_checkout_session(invoice, :stripe, %{
  success_url: "https://example.com/success",
  cancel_url: "https://example.com/cancel"
})

# Redirect user to session.url

Webhooks are handled automatically at /webhooks/billing/:provider.

Real-Time Events

Subscribe to billing events in your LiveViews:

def mount(_params, _session, socket) do
  PhoenixKit.Modules.Billing.Events.subscribe_orders()
  {:ok, socket}
end

def handle_info({:order_created, order}, socket) do
  # Update UI
  {:noreply, socket}
end

Settings

Key Type Default Description
billing_enabled boolean false Enable/disable the billing system
billing_default_currency string "EUR" Default currency for new orders
billing_tax_enabled boolean false Enable tax calculations
billing_company_name string Company name on invoices
billing_company_address string Company address on invoices

Provider-specific settings (API keys, webhook secrets) are configured per-provider in the admin panel at /admin/settings/billing/providers.

Invoice Status Workflow

Status Description
"draft" Invoice created, not yet sent
"sent" Invoice sent to customer
"paid" Payment received, receipt generated
"overdue" Past due date, not yet paid
"void" Cancelled / voided
draft → sent → paid
            ↘
           overdue → paid
            ↘
            void

Permissions

The module declares permissions via permission_metadata/0:

  • "billing" — access to billing admin dashboard and all sub-pages
  • Settings pages require the same "billing" permission

Use Scope.has_module_access?/2 to check permissions in your application.

CSS Requirements

This module implements css_sources/0 returning [:phoenix_kit_billing], so PhoenixKit's installer automatically adds the correct @source directive to your app.css for Tailwind scanning. No manual configuration needed.

Architecture

lib/
├── mix/tasks/phoenix_kit_billing.install.ex  # Install mix task
└── phoenix_kit/modules/billing/
    ├── billing.ex                    # Main module (context + PhoenixKit.Module behaviour)
    ├── events.ex                     # PubSub event broadcasts
    ├── paths.ex                      # Centralized URL path helpers
    ├── supervisor.ex                 # OTP Supervisor
    ├── providers/
    │   ├── provider.ex               # Provider behaviour (9 callbacks)
    │   ├── providers.ex              # Provider registry and routing
    │   ├── stripe.ex                 # Stripe implementation
    │   ├── paypal.ex                 # PayPal implementation
    │   └── razorpay.ex               # Razorpay implementation
    ├── schemas/
    │   ├── billing_profile.ex        # User billing information
    │   ├── currency.ex               # Currency definitions
    │   ├── invoice.ex                # Invoice with receipt
    │   ├── order.ex                  # Order with line items
    │   ├── payment_method.ex         # Saved payment methods
    │   ├── subscription.ex           # Subscription records
    │   ├── subscription_type.ex      # Subscription plan definitions
    │   ├── transaction.ex            # Payment/refund transactions
    │   └── webhook_event.ex          # Provider webhook log
    ├── workers/
    │   ├── subscription_renewal_worker.ex   # Oban: subscription renewals
    │   └── subscription_dunning_worker.ex   # Oban: failed payment retries
    └── web/                          # Admin LiveViews, controllers, components

Database Tables

Table Description
phoenix_kit_billing_profiles User billing information (UUIDv7 PK)
phoenix_kit_currencies Currency definitions
phoenix_kit_orders Orders with line items
phoenix_kit_invoices Invoices with receipt data
phoenix_kit_transactions Payment/refund transaction ledger
phoenix_kit_subscriptions Active subscriptions
phoenix_kit_subscription_types Subscription plan definitions
phoenix_kit_payment_methods Saved payment methods from providers
phoenix_kit_payment_options Available payment options
phoenix_kit_webhook_events Provider webhook event log

Development

mix deps.get       # Install dependencies
mix test           # Run tests
mix format         # Format code
mix credo --strict # Static analysis (strict mode)
mix dialyzer       # Type checking
mix docs           # Generate documentation
mix precommit      # Compile + format + credo + dialyzer
mix quality        # Format + credo + dialyzer

Troubleshooting

Billing not appearing in admin

  • Verify billing_enabled is true in settings
  • Ensure the module is listed as a dependency in the parent app's mix.exs
  • Check that enabled?/0 is not returning false (requires database access)

Webhooks not processing

  • Verify webhook secrets are configured in provider settings
  • Check that webhook URLs are registered with the provider (e.g., https://yourdomain.com/webhooks/billing/stripe)
  • Review phoenix_kit_webhook_events table for received events

Subscription renewals not running

  • Ensure Oban is configured in the parent app with the billing queue
  • Check Oban dashboard for failed jobs

License

MIT — see LICENSE for details.

About

PhoenixKit Billing Module

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors