0
Sales & payments
   in your app
      Martin Kleppmann
         http://go-test.it
  http://yes-no-cancel.co.uk
  http://tw...
Automated Cross-Browser Functional Testing




          “Selenium in the cloud”
http://go-test.it
SaaS
Revenue model
You should be
making one of
    these
We need
more
of
these
We need
more
of
these

 £
Your £1m business


e.g. £42/mon × 12 mon ×
     2,000 customers
Your £1m business


e.g. £42/mon × 12 mon ×
     2,000 customers

         Automation!
B2B
Ruby Invoicing
Framework
So… youʼve spent many nights developing your awesome application. Itʼs coming together
nicely, an...
Ruby Invoicing
Framework                                                                      ic in g/
                   ...
Richard Messenger, http://www.flickr.com/photos/richardmessenger/2626927255/
Production use
A solid foundation for
 building commercial
       web apps
I’m not an
accountant
Jargon
Jargon
(as far as we can avoid it)
Installing

$ gem install invoicing invoicing_generator

$ script/generate invoicing_ledger billing 
    --currency=GBP

$...
Model classes
module Billing
  class Invoice < LedgerItem
    acts_as_invoice
  end
  class CreditNote < LedgerItem
    ac...
Ledger items
Ledger items

•   Invoice:
    “you owe us money”
Ledger items

•   Invoice:
    “you owe us money”
•   Credit Note:
    “oops, billed you too much”
Ledger items

•   Invoice:
    “you owe us money”
•   Credit Note:
    “oops, billed you too much”
•   Payment:
    “thank...
acts_as_ledger_item

module Billing
  class LedgerItem < ActiveRecord::Base
    acts_as_ledger_item
    has_many :line_ite...
Fine, but
so what?
http://www.flickr.com/photos/26614375@N00/381941029/
Avoid writing
boring code
Displaying an invoice
class BillingController < ApplicationController
  def document
    @document = Billing::LedgerItem.f...
Displaying an invoice
class BillingController < ApplicationController
  def document
    @document = Billing::LedgerItem.f...
Best practices
Your investors will
       want to see
    your accounts
What accountants
         need to know
•   Exact dates and periods of
    invoices & payments
•   Reconciling bank stateme...
http://www.flickr.com/photos/8704943@N07/3491779722/
Dates & periods
create_table   "ledger_items" do |t|
  t.string     "type"
  t.integer    "sender_id"
  t.integer    "reci...
Dates & periods
create_table   "ledger_items" do |t|
  t.string     "type"
  t.integer    "sender_id"
  t.integer    "reci...
Invoice     (“bill”)


    ≠
Payment    (“receipt”)
Invoice ≠ Payment
 Your Sales Account



 Customer Account



 Your Bank Account
Invoice ≠ Payment
       Your Sales Account
–
    Invoice
+
       Customer Account



       Your Bank Account
Invoice ≠ Payment
       Your Sales Account
–
    Invoice
+
       Customer Account
                            –
        ...
Account statement
No.      Date         Description                                    Amount

100      2009-06-01   Subsc...
Account statement                                     Invoice

No.      Date         Description
                         ...
Account statement
  class BillingController < ApplicationController
    def statement
      scope = Billing::LedgerItem.
 ...
Thomas Hawk, http://www.flickr.com/photos/thomashawk/2317826708/
VAT
Your Sales Account      VAT Account



     Customer Account



           Your Bank Account
Your Sales Account          VAT Account
               –        –
     Invoice
               +
     Customer Account



 ...
Your Sales Account           VAT Account
               –         –
     Invoice
               +
     Customer Account
  ...
Your Sales Account           VAT Account
               –         –          +
     Invoice
               +              ...
Urgh.
(And we’ve not even started talking about EU
           VAT regulations yet.)
VAT made easy
create_table   "ledger_items" do |t|
  t.string     "type"
  t.integer    "sender_id"
  t.integer    "recipi...
VAT made easy
create_table   "ledger_items" do |t|
  t.string     "type"
  t.integer    "sender_id"
  t.integer    "recipi...
VAT made easy
create_table   "ledger_items" do |t|
  t.string     "type"
  t.integer    "sender_id"
  t.integer    "recipi...
VAT made easy
# New in invoicing gem version 0.3
class MyProduct < ActiveRecord::Base
  acts_as_taxable :price,
    :tax_l...
Paolo Màrgari, http://www.flickr.com/photos/paolomargari/3050305454/
Overview of your
   customers
Sales and purchases ledger

                                                    Sale         Purchase
Name            Curr...
Sales/purchase ledger
@summaries =

Billing::LedgerItem.account_summaries(params[:id])

@summaries.each_pair do |id, by_cu...
What else?
Martin Kleppmann, http://www.flickr.com/photos/martinkleppmann/3131198770/
¥1,300




Martin Kleppmann, http://www.flickr.com/photos/martinkleppmann/3131198770/
Currency
formatting
Currency formatting
inv = Billing::MyInvoice.new :currency =>
'JPY'
nov = Billing::LineItem.new(
  :description => 'Novemb...
Nothing is
constant
VAT change 1/12/09
dec = Billing::LineItem.new(
  :description => 'December charge',
  :net_amount => 10,
  :tax_point => ...
Johnny Vulkan, http://www.flickr.com/photos/26614375@N00/381941029/
Integrating with
payment gateways

http://activemerchant.org
Open
standards
Displaying an invoice
  class BillingController < ApplicationController
    def document
      @document = Billing::Ledger...
Displaying an invoice
  class BillingController < ApplicationController
    def document
      @document = Billing::Ledger...
Displaying an invoice
  class BillingController < ApplicationController
    def document
      @document = Billing::Ledger...
UBL = “Universal
 Business Language”

OASIS Open Standard
UBL: If you’re working with
 invoices and purchase orders
and that kind of stuff (and who
   isn’t?) [...] Look no further...
UBL Example (1/3)
<ubl:Invoice xmlns:ubl="..." xmlns:cbc="..."
        xmlns:cac="...">
    <cbc:ID>1</cbc:ID>
    <cbc:Is...
UBL Example (2/3)
<cac:TaxTotal>
    <cbc:TaxAmount currencyID="GBP">
        15.00
    </cbc:TaxAmount>
</cac:TaxTotal>
<...
UBL Example (3/3)
    <cac:InvoiceLine>
        <cbc:ID>42</cbc:ID>
        <cbc:LineExtensionAmount currencyID="GBP">
   ...
Designing XML Languages is
hard. It’s boring, political, time-
  consuming, unglamorous,
         irritating work.




  @...
Interoperability
OAccounts
Sage         Invoicing gem


MYOB         Payment provider


KashFlow     Shopping cart


Xero         Custom re...
OAccounts
Sage                     Invoicing gem


MYOB                     Payment provider
             OAccounts
KashFl...
OAccounts
          =
 UBL + XBRL-GL + REST +
      Conventions +
    Documentation +
     Collaboration +
Open source imp...
OAccounts
           =
 UBL + XBRL-GL ts. REST+ or g/ +
       Conventionsco un +
          ://o ac
    ht tp
     Documen...
Image credits

Screenshots of:
http://basecamphq.com/signup, http://freshbooks.com/pricing.php, http://fogcreek.com/FogBug...
Thank you!


    Martin Kleppmann
       http://go-test.it
http://yes-no-cancel.co.uk
http://twitter.com/martinkl
Invoicing Gem - Sales & Payments In Your App
Invoicing Gem - Sales & Payments In Your App
Invoicing Gem - Sales & Payments In Your App
Invoicing Gem - Sales & Payments In Your App
Invoicing Gem - Sales & Payments In Your App
Invoicing Gem - Sales & Payments In Your App
Invoicing Gem - Sales & Payments In Your App
Invoicing Gem - Sales & Payments In Your App
Invoicing Gem - Sales & Payments In Your App
Invoicing Gem - Sales & Payments In Your App
Upcoming SlideShare
Loading in...5
×

Invoicing Gem - Sales & Payments In Your App

2,401

Published on

Presentation given by Martin Kleppmann at Rails Underground in London on 24 July 2009. Gives an overview of how to develop a commercial B2B SaaS web app using Rails or other Ruby web frameworks, including best practices of structuring accouting data.

Published in: Technology, Business
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,401
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
44
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Transcript of "Invoicing Gem - Sales & Payments In Your App"

  1. 1. Sales & payments in your app Martin Kleppmann http://go-test.it http://yes-no-cancel.co.uk http://twitter.com/martinkl
  2. 2. Automated Cross-Browser Functional Testing “Selenium in the cloud”
  3. 3. http://go-test.it
  4. 4. SaaS
  5. 5. Revenue model
  6. 6. You should be making one of these
  7. 7. We need more of these
  8. 8. We need more of these £
  9. 9. Your £1m business e.g. £42/mon × 12 mon × 2,000 customers
  10. 10. Your £1m business e.g. £42/mon × 12 mon × 2,000 customers Automation!
  11. 11. B2B
  12. 12. Ruby Invoicing Framework So… youʼve spent many nights developing your awesome application. Itʼs coming together nicely, and youʼve showed it to your friends, who got very excited about it too. In fact, people love your app so much that they are willing to pay you money to use it. Great news! Keeping it simple, you start taking payments trough PayPal or even accept cheques through the post. Later you maybe integrate with the API of a more flexible credit card handling provider. Money is coming in – even better news! The problems become apparent when you try to turn your app into a business. Suddenly everything becomes a lot more complicated. You need to start thinking about ugly things like tax and you need to pay an accountant to sort out the paperwork for you. You need to start bookkeeping, a prospect which gives you the shivers. Maybe some of your customers are awkward, accepting billing only in their own currency or requiring a special tax status. Itʼs all a bit of a mess, and as you grudgingly start ploughing through the Wikipedia page on “credits and debits”, you wish that you could just get the money and leave it at that. The missing link between your app and the money Enter the Ruby Invoicing Framework RubyGem, or invoicing gem for short. Itʼs a collection
  13. 13. Ruby Invoicing Framework ic in g/ /invo m So… youʼve spent many nights developing your awesome application. Itʼs coming together co nicely, and youʼve showed it to your friends, who got very excited about it too. In fact, u b. people love your app so much that they are willing to pay you money to use it. Great news! t.gith Keeping it simple, you start taking payments trough PayPal or even accept cheques p through the post. Later you maybe integrate with the API of a more flexible credit card //e handling provider. Money is coming in – even better news! tt p: The problems become apparent when you try to turn your app into a business. Suddenly h everything becomes a lot more complicated. You need to start thinking about ugly things like tax and you need to pay an accountant to sort out the paperwork for you. You need to start bookkeeping, a prospect which gives you the shivers. Maybe some of your customers are awkward, accepting billing only in their own currency or requiring a special tax status. Itʼs all a bit of a mess, and as you grudgingly start ploughing through the Wikipedia page on “credits and debits”, you wish that you could just get the money and leave it at that. The missing link between your app and the money Enter the Ruby Invoicing Framework RubyGem, or invoicing gem for short. Itʼs a collection
  14. 14. Richard Messenger, http://www.flickr.com/photos/richardmessenger/2626927255/
  15. 15. Production use
  16. 16. A solid foundation for building commercial web apps
  17. 17. I’m not an accountant
  18. 18. Jargon
  19. 19. Jargon (as far as we can avoid it)
  20. 20. Installing $ gem install invoicing invoicing_generator $ script/generate invoicing_ledger billing --currency=GBP $ rake db:migrate
  21. 21. Model classes module Billing class Invoice < LedgerItem acts_as_invoice end class CreditNote < LedgerItem acts_as_credit_note end class Payment < LedgerItem acts_as_payment end end
  22. 22. Ledger items
  23. 23. Ledger items • Invoice: “you owe us money”
  24. 24. Ledger items • Invoice: “you owe us money” • Credit Note: “oops, billed you too much”
  25. 25. Ledger items • Invoice: “you owe us money” • Credit Note: “oops, billed you too much” • Payment: “thanks for the cash”
  26. 26. acts_as_ledger_item module Billing class LedgerItem < ActiveRecord::Base acts_as_ledger_item has_many :line_items, :class_name => 'Billing::LineItem' belongs_to :sender, :class_name => 'Company' belongs_to :recipient, :class_name => 'Company' end end
  27. 27. Fine, but so what?
  28. 28. http://www.flickr.com/photos/26614375@N00/381941029/
  29. 29. Avoid writing boring code
  30. 30. Displaying an invoice class BillingController < ApplicationController def document @document = Billing::LedgerItem.find(params[:id]) respond_to do |format| format.html { render :text => @document.render_html, :layout => true } format.xml { render :xml => @document.render_ubl } end end end
  31. 31. Displaying an invoice class BillingController < ApplicationController def document @document = Billing::LedgerItem.find(params[:id]) respond_to do |format| format.html { render :text => @document.render_html, :layout => true } format.xml { render :xml => @document.render_ubl } end end end
  32. 32. Best practices
  33. 33. Your investors will want to see your accounts
  34. 34. What accountants need to know • Exact dates and periods of invoices & payments • Reconciling bank statements • Details of VAT & other tax
  35. 35. http://www.flickr.com/photos/8704943@N07/3491779722/
  36. 36. Dates & periods create_table "ledger_items" do |t| t.string "type" t.integer "sender_id" t.integer "recipient_id" t.string "currency", :default => "GBP", :null => false t.decimal "total_amount", :precision => 20, :scale => 4 t.decimal "tax_amount", :precision => 20, :scale => 4 t.string "status", :limit => 20 t.string "description" t.datetime "issue_date" t.datetime "period_start" t.datetime "period_end" t.datetime "created_at" t.datetime "updated_at" end
  37. 37. Dates & periods create_table "ledger_items" do |t| t.string "type" t.integer "sender_id" t.integer "recipient_id" t.string "currency", :default => "GBP", :null => false t.decimal "total_amount", :precision => 20, :scale => 4 t.decimal "tax_amount", :precision => 20, :scale => 4 t.string "status", :limit => 20 t.string "description" t.datetime "issue_date" t.datetime "period_start" t.datetime "period_end" t.datetime "created_at" t.datetime "updated_at" end
  38. 38. Invoice (“bill”) ≠ Payment (“receipt”)
  39. 39. Invoice ≠ Payment Your Sales Account Customer Account Your Bank Account
  40. 40. Invoice ≠ Payment Your Sales Account – Invoice + Customer Account Your Bank Account
  41. 41. Invoice ≠ Payment Your Sales Account – Invoice + Customer Account – Payment + Your Bank Account
  42. 42. Account statement No. Date Description Amount 100 2009-06-01 Subscription for June £115.00 101 2009-06-24 Referral fee – thanks for inviting 3 friends –£10.00 102 2009-06-30 Credit card payment including PAYG credit –£200.00 Current account balance (GBP) –£75.00 Charges not yet invoiced Description Amount Pay As You Go charges so far this month £23.45
  43. 43. Account statement Invoice No. Date Description Credit Note Amount 100 2009-06-01 Subscription for June Payment £115.00 101 2009-06-24 Referral fee – thanks for inviting 3 friends –£10.00 102 2009-06-30 Credit card payment including PAYG credit –£200.00 Current account balance (GBP) –£75.00 Invoice Charges not yet invoiced (with status=open) Description Amount Pay As You Go charges so far this month £23.45
  44. 44. Account statement class BillingController < ApplicationController def statement scope = Billing::LedgerItem. exclude_empty_invoices. sent_or_received_by(params[:id]). sorted(:issue_date) @in_effect = scope.in_effect.all @open_or_pending = scope.open_or_pending.all @summary = Billing::LedgerItem.account_summary( params[:id]) end end
  45. 45. Thomas Hawk, http://www.flickr.com/photos/thomashawk/2317826708/
  46. 46. VAT
  47. 47. Your Sales Account VAT Account Customer Account Your Bank Account
  48. 48. Your Sales Account VAT Account – – Invoice + Customer Account Your Bank Account
  49. 49. Your Sales Account VAT Account – – Invoice + Customer Account – Payment + Your Bank Account
  50. 50. Your Sales Account VAT Account – – + Invoice + VAT Customer Account Return – Payment + – Your Bank Account
  51. 51. Urgh. (And we’ve not even started talking about EU VAT regulations yet.)
  52. 52. VAT made easy create_table "ledger_items" do |t| t.string "type" t.integer "sender_id" t.integer "recipient_id" t.string "currency", :default => "GBP", :null => false t.decimal "total_amount", :precision => 20, :scale => 4 t.decimal "tax_amount", :precision => 20, :scale => 4 t.string "status", :limit => 20 t.string "description" t.datetime "issue_date" t.datetime "period_start" t.datetime "period_end" t.datetime "created_at" t.datetime "updated_at" end
  53. 53. VAT made easy create_table "ledger_items" do |t| t.string "type" t.integer "sender_id" t.integer "recipient_id" t.string "currency", :default => "GBP", :null => false t.decimal "total_amount", :precision => 20, :scale => 4 t.decimal "tax_amount", :precision => 20, :scale => 4 t.string "status", :limit => 20 t.string "description" t.datetime "issue_date" t.datetime "period_start" t.datetime "period_end" t.datetime "created_at" t.datetime "updated_at" end
  54. 54. VAT made easy create_table "ledger_items" do |t| t.string "type" t.integer "sender_id" t.integer "recipient_id" t.string "currency", :default => "GBP", :null => false t.decimal "total_amount", :precision => 20, :scale => 4 t.decimal "tax_amount", :precision => 20, :scale => 4 t.string "status", :limit => 20 ☺ t.string "description" t.datetime "issue_date" t.datetime "period_start" t.datetime "period_end" t.datetime "created_at" t.datetime "updated_at" end
  55. 55. VAT made easy # New in invoicing gem version 0.3 class MyProduct < ActiveRecord::Base acts_as_taxable :price, :tax_logic => Invoicing::Countries::UK::VAT.new end p = MyProduct.new :price => 10 p.price_with_tax_info # => "£11.50 (inc. VAT)" p.price_taxed = 23.00 p.price.to_s # => "20.0"
  56. 56. Paolo Màrgari, http://www.flickr.com/photos/paolomargari/3050305454/
  57. 57. Overview of your customers
  58. 58. Sales and purchases ledger Sale Purchase Name Currency Sales Purchases Balance receipts payments A. N. Other GBP £400.00 £0.00 £400.00 £0.00 £0.00 Some Customer GBP £0.00 £395.00 £0.00 £250.00 –£145.00 Some Customer USD $2,782.31 $0.00 $2,160.61 $0.00 $621.70 Widgets Ltd GBP £229.63 £12.00 £300.00 £0.00 £82.37
  59. 59. Sales/purchase ledger @summaries = Billing::LedgerItem.account_summaries(params[:id]) @summaries.each_pair do |id, by_currency| by_currency.each_pair do |currency, data| puts "Sales: #{data.sales_formatted}" puts "Purchases: #{data.purchases_formatted}" # ... end end
  60. 60. What else?
  61. 61. Martin Kleppmann, http://www.flickr.com/photos/martinkleppmann/3131198770/
  62. 62. ¥1,300 Martin Kleppmann, http://www.flickr.com/photos/martinkleppmann/3131198770/
  63. 63. Currency formatting
  64. 64. Currency formatting inv = Billing::MyInvoice.new :currency => 'JPY' nov = Billing::LineItem.new( :description => 'November charge', :net_amount => 10, :tax_point => '2008-11-30') inv.line_items << nov; inv.save! nov.amount_formatted # => "¥10" inv.currency = 'GBP' nov.amount_formatted
  65. 65. Nothing is constant
  66. 66. VAT change 1/12/09 dec = Billing::LineItem.new( :description => 'December charge', :net_amount => 10, :tax_point => '2008-12-01') inv.line_items << dec nov.amount_taxed_formatted # => "£11.75" dec.amount_taxed_formatted # => "£11.50"
  67. 67. Johnny Vulkan, http://www.flickr.com/photos/26614375@N00/381941029/
  68. 68. Integrating with payment gateways http://activemerchant.org
  69. 69. Open standards
  70. 70. Displaying an invoice class BillingController < ApplicationController def document @document = Billing::LedgerItem.find(params[:id]) respond_to do |format| format.html { render :text => @document.render_html, :layout => true } format.xml { render :xml => @document.render_ubl } end end end
  71. 71. Displaying an invoice class BillingController < ApplicationController def document @document = Billing::LedgerItem.find(params[:id]) respond_to do |format| format.html { render :text => @document.render_html, :layout => true } format.xml { render :xml => @document.render_ubl } end end end
  72. 72. Displaying an invoice class BillingController < ApplicationController def document @document = Billing::LedgerItem.find(params[:id]) UBL? WTF? respond_to do |format| format.html { render :text => @document.render_html, :layout => true } format.xml { render :xml => @document.render_ubl } end end end
  73. 73. UBL = “Universal Business Language” OASIS Open Standard
  74. 74. UBL: If you’re working with invoices and purchase orders and that kind of stuff (and who isn’t?) [...] Look no further. @timbray: “Don’t Invent XML Languages” http://tr.im/NoNewXML
  75. 75. UBL Example (1/3) <ubl:Invoice xmlns:ubl="..." xmlns:cbc="..." xmlns:cac="..."> <cbc:ID>1</cbc:ID> <cbc:IssueDate>2008-06-30</cbc:IssueDate> <cac:InvoicePeriod> <cbc:StartDate>2008-06-01</cbc:StartDate> <cbc:EndDate>2008-07-01</cbc:EndDate> </cac:InvoicePeriod> <cac:AccountingSupplierParty> ... </cac:AccountingSupplierParty> <cac:AccountingCustomerParty> ... </cac:AccountingCustomerParty> ...
  76. 76. UBL Example (2/3) <cac:TaxTotal> <cbc:TaxAmount currencyID="GBP"> 15.00 </cbc:TaxAmount> </cac:TaxTotal> <cac:LegalMonetaryTotal> <cbc:TaxExclusiveAmount currencyID="GBP"> 100.00 </cbc:TaxExclusiveAmount> <cbc:PayableAmount currencyID="GBP"> 115.00 </cbc:PayableAmount> </cac:LegalMonetaryTotal>
  77. 77. UBL Example (3/3) <cac:InvoiceLine> <cbc:ID>42</cbc:ID> <cbc:LineExtensionAmount currencyID="GBP"> 100.00 </cbc:LineExtensionAmount> <cac:Item> <cbc:Description> Subscription for my fantastic app </cbc:Description> </cac:Item> </cac:InvoiceLine> </ubl:Invoice>
  78. 78. Designing XML Languages is hard. It’s boring, political, time- consuming, unglamorous, irritating work. @timbray: “Don’t Invent XML Languages” http://tr.im/NoNewXML
  79. 79. Interoperability
  80. 80. OAccounts Sage Invoicing gem MYOB Payment provider KashFlow Shopping cart Xero Custom reporting
  81. 81. OAccounts Sage Invoicing gem MYOB Payment provider OAccounts KashFlow Shopping cart Xero Custom reporting
  82. 82. OAccounts = UBL + XBRL-GL + REST + Conventions + Documentation + Collaboration + Open source implementation
  83. 83. OAccounts = UBL + XBRL-GL ts. REST+ or g/ + Conventionsco un + ://o ac ht tp Documentation + Collaboration + Open source implementation
  84. 84. Image credits Screenshots of: http://basecamphq.com/signup, http://freshbooks.com/pricing.php, http://fogcreek.com/FogBugz/, http://github.com/plans, http://lessaccounting.com/pricing, http://freeagentcentral.com/pricing, http://huddle.net/huddle-price-plans/, http://twitter.com/bensummers/status/1199722134, http://oneis.co.uk/, http://bidforwine.co.uk Building site: Richard Messenger, http://www.flickr.com/photos/richardmessenger/2626927255/ Tim Bray: http://en.wikipedia.org/wiki/File:Tim_Bray.jpg Pile of money: Johnny Vulkan, http://www.flickr.com/photos/26614375@N00/381941029/ Astronomical clock: magro_kr, http://www.flickr.com/photos/8704943@N07/3491779722/ Tax Service: Thomas Hawk, http://www.flickr.com/photos/thomashawk/2317826708/ Man in a shop: Paolo Màrgari, http://www.flickr.com/photos/paolomargari/3050305454/ Hands full of money: Marshall Astor, http://www.flickr.com/photos/lifeontheedge/2672465894/
  85. 85. Thank you! Martin Kleppmann http://go-test.it http://yes-no-cancel.co.uk http://twitter.com/martinkl
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×