Placing on Order

A Subscription is created when a Plan is selected and paid for. As simple as it sounds, there are many variants to implement the previous sentence.

Basic Pipeline

In the most basic pipeline, a user becomes a subscriber in 2 steps:

  1. Click a Plan on the /pricing/ page
  2. Submit credit card information

Pipeline with Multiple Periods Paid in Advance

It is always better to receive more cash up-front so an intermediate step is often introduced to enable to pre-pay multiple periods in advance at a discount.

  1. Click a Plan on the /pricing/ page
  2. Pick the number of periods paid in advance
  3. Submit credit card information

Pipeline with Multiple Products in Shopping Cart

A growing business often offers multiple products (i.e. Plan) that are cross-saled to new and existing customers. In that case, the /pricing/ page is replaced by a more complex catalog. Cart and checkout concepts appear.

  1. Add multiple Plan to a user cart
  2. Click a checkout button
  3. Submit credit card information

Pipeline to Bulk Subscribe Third-parties

Software-as-a-Service that target businesses (B2B) and/or other kind of structured groups almost always require one entity to pay for subscriptions on behalf of users that belong to it. This can be implemented through managers (or custom roles) to the subscribed entity (see Security) or through the entity buying multiple subscriptions in bluk, on behalf of its users. The later case requires an extra step to subscribe those third parties.

  1. Click a Plan on the /pricing/ page
  2. Enter email address of users to subscribe
  3. Submit credit card information

Full Pipeline

Of course, all of the above cases can be combined together, which leads to a full pipeline as such:

_images/order-pipeline.svg
  1. Add multiple Plan to a user cart
  2. Click a checkout button
  3. Pick the number of periods paid in advance
  4. Enter email address of users to subscribe
  5. Submit credit card information

Django Views

The two primary views to place an order are CartView and BalanceView. CartView is used to implement the checkout and place a new order while BalanceView is used to pay an Organization balance due, either because a charge wasn’t sucessful and/or the provider implements a subscribe-pay-later policy.

  1. CartView for items in the cart, create new subscriptions or pay in advance.
  2. BalanceView for subscriptions with balance dues
_images/order-views.svg
class saas.views.billing.CartBaseView(**kwargs)

The main pupose of CartBaseView is generate an list of invoicables from CartItem records associated to a request.user.

The invoicables list is generated from the following schema:

invoicables = [
        { "subscription": Subscription,
          "lines": [Transaction, ...],
          "options": [Transaction, ...],
        }, ...]

Each subscription is either an actual record in the database (paying more periods on a subscription) or Subscription instance that only exists in memory but will be committed on checkout.

The Transaction list keyed by “lines” contains in-memory instances for the invoice items that will be committed and charged when the order is finally placed.

The Transaction list keyed by “options” contains in-memory instances the user can choose from. Options usually include various number of periods that can be pre-paid now for a discount. ex:

$189.00 Subscription to medium-plan until 2015/11/07 (1 month) $510.30 Subscription to medium-plan until 2016/01/07 (3 months, 10% off) $907.20 Subscription to medium-plan until 2016/04/07 (6 months, 20% off)
class saas.views.billing.BalanceView(**kwargs)

Set of invoicables for all subscriptions which have a balance due.

While CartView generates the invoicables from the CartItem model, BalanceView generates the invoicables from Subscription for which the amount payable by the customer is positive.

The invoicables list is generated from the following schema:

invoicables = [
        { "subscription": Subscription,
          "name": "",
          "descr": "",
          "lines": [Transaction, ...],
          "options": [Transaction, ...],
        }, ...]
class saas.views.billing.CartView(**kwargs)

CartView derives from CartSeatsView which itself derives from CartPeriodsView, all of which overrides the get method to redirect to the appropriate step in the order pipeline no matter the original entry point.