No description, website, or topics provided.
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Build Status

Billing is a simple library to credit and debit accounts. It provides a simple interface to calculate costs for individual things inside an application. It also provides a way to charge accounts with those costs. It is a very lightweight library.

Billing is designed as an abstract process where the implementation details are left to the user.

It does not do any of the following things:

  1. Accept credit cards
  2. Talk to payment processors
  3. Manage application subscriptions
  4. Manage application service plans
  5. Make any assumptions about the billing/finanical side of your application

It does do the following:

  1. Allow you to debit accounts
  2. Allow you to hold funds in accounts
  3. Allow you to release funds in accounts
  4. Define cost classes for calculating services fees for individual resources.
  5. Allow you to implement any of the things it does not do in a standard fashion.
  6. Give you a mixin to allow you to manage billing in any part of your application.
  7. Allow you to implement guards based on an account's finanical standing.
  8. Allow you to do the things it does not do by including extensions.

General Use

Billing is generally insipired by CanCan. You include functionality into what objects you want via modules. You define costs by creating one or more classes and include a module. Billing only makes 3 fundamental assumptions:

  1. You will have a class that acts like Billing::AccountExample
  2. You will have classes that include Billing::Cost
  3. You will manage the accounts by including Billing::Tab

Defining An Account

Here is an example account

class Account
  # You do not have to check if there are enough
  # funds in the account. Billing does that sort
  # of stuff for you.
  # The actions should be atomic!

  def debit_authorized?(amount)

  def debit(amount)

  def credit(amount)

You could implement a stateless Account like this:

class Account
  def initialize
    @balance = 0

  def debit_authorized?(amount)
    @balance >= amount

  def debit(amount)
    @balance = @balance - amount

  def credit(amount)
    @balance = @balance + amount

Defining Costs

Now let's say your application deals with SMS. Sending a SMS costs a fixed amount of money (for simplicity). Define a cost class to handle that calcation. You can do more complex calculations, but we'll go over that later.

class SmsCalculator
  include Billing::Cost

  def sms

Creating an Account Manager

Now the final step is to create a handler. This class should do two things:

  1. respond_to :current_tab => true
  2. include Billing::Tab

Here is an exampler

class Biller
  include Billing::Tab

  def initialize(account)
    @account = account

  def current_tab

Using the interface

At this point we are ready to start doing things on the account. Here is an example:

account =
bank = account

# this ensures that the account has at least "1" in it. 
# It puts "1" into holds ensuring that it will be available
# when account is ready to take the debit
bank.charge_authorized? :sms 

# Charge something to their account
# This changes the account balance!
bank.debit :sms

# Add something to their account
# This change the account balance! :sms

# You can also use a Fixnum or Float
# if you want to credit or debit an arbitrary amount 591
bank.debit 382.75

# alias exists so you can use charge for `charge` for `debit` and
# `refund` for `credit`. Bang methods exist as well, altough there is not
# difference between them and the other methods. Use which ever syntax
# you prefer

bank.charge 55
bank.refund! :sms

bank.charge_for 16, :contacts
bank.refund_for! 4, :emails

Calculating Costs

Cost class methods may be called in a variety of ways. Here are some examples and the corresponding method call. Assume the cost refers to an instance of a class with Billing::Cost included. Assume bank is includes Billing::Helpers

Scenario: something always costs the same

bank.debit :sms
# means

Scenario: cost depends on an instance of the object

sms =
bank.debit sms
# means

Scenario: More information is needed to calculate a cost

bank.debit :sms, :region => :north_america
# means
cost.sms(:region => :north_america)
bank.debit Sms
# means
bank.debit :sms

Handling Failure & Advanced Usage

Perhaps you want to hit the account only after you do some code. You can pass the the debit and credit methods blocks. The debit or credit will only hit the account if the block does not raise an error.

bank.debit :sms, :region => :north_america do
    Gateway.deliver sms
  rescue GatewayError => ex
    # oh damn, the gateway may an error or something
    # even though the user's SMS is valid
    # they shouldn't be charged for this.
    log_exception ex
    raise RuntimeError

You can credit/debit for multiple charges at once using _for methods. They work the same way, except take an a numeric argument first to multiply the charge by.

bank.debit_for 5, :sms

bank.credit_for 13, :searches

bank.credit_for 5, :search, :engine => :hoovers do
  # whatever you need to do


Billings is designed to be extended via Modules. You can include more modules into the managing class. Here is the current extension list:

  1. Logging (can also be used for auditing)
  2. Callbacks
  3. Observing


You can log (and audit) all transcations made through your managers by including the Billing::Extensions::Logging into your class. The default logger is$stdout). Here is an example

class Bank
  include Billings::Tab
  include Billings::Extensions::Logging

  # redefine the logger method if you want to use your own
  # custom logger.
  # The class uses the "info" log level
  def logger $stdout


Enables before_* and after_ callbacks on debit and credit

class Bank
  include Billings::Tab
  include Billings::Extensions::Callbacks

  after_debit :send_charge_notification

  after_credit :send_refund_notification

  def send_charge_notification
    # weeee

  def send_refund_notification
    # weee


Enables before_* and after_ callbacks on debit and credit for observers

class Bank
  include Billings::Tab
  include Billings::Extensions::Observers

class BankObserver < ActiveModel::Observer
  def before_debit(*args)

  def after_debit(*args)

  def before_credit(*args)

  def after_credit(*args)

The Future

Billing's future is solving the things it does not do by adding them through extensions. Billing will never do everything financially related. There are things Billing will never know about your application so it will always try to remain as abstract as possible. It will slowly creep toward this boundary: charging credit cards. I would like to see Billing go into the direction of doing everything but that while remaining as abstract as possible leaving only one implementation detail: charging credit cards.

I will add functionality as I need it. Look at extensions and other billings gems.