invoicing gem - sales & payments in your app
Post on 06-May-2015
2.315 Views
Preview:
DESCRIPTION
TRANSCRIPT
Sales & paymentsin your app
Martin Kleppmannhttp://go-test.it
http://yes-no-cancel.co.ukhttp://twitter.com/martinkl
Automated Cross-Browser Functional Testing
“Selenium in the cloud”
http://go-test.it
SaaS
Revenue model
You should be making one of
these
We needmoreofthese
We needmoreofthese
£
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 FrameworkSo… 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 moneyEnter the Ruby Invoicing Framework RubyGem, or invoicing gem for short. Itʼs a collection of tools which provide the basic mechanisms for supporting financial transactions within your own application.
Ruby Invoicing FrameworkSo… 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 moneyEnter the Ruby Invoicing Framework RubyGem, or invoicing gem for short. Itʼs a collection of tools which provide the basic mechanisms for supporting financial transactions within your own application.
http://ept.github.com/invoicing/
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
$ rake db:migrate
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 endend
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:“thanks for the cash”
Ledger items
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' endend
Fine, butso what?
http://www.flickr.com/photos/26614375@N00/381941029/
Avoid writing boring code
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 endend
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 endend
Best practices
Your investors willwant to see
your accounts
•Exact dates and periods of invoices & payments
•Reconciling bank statements
•Details of VAT & other tax
What accountants need to know
http
://w
ww
.flic
kr.c
om/p
hoto
s/87
0494
3@N
07/3
4917
7972
2/
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
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
Dates & periods
Invoice≠
Payment
(“bill”)
(“receipt”)
Your Sales Account
Customer Account
Your Bank Account
Invoice ≠ Payment
Your Sales Account
Customer Account
Your Bank Account
Invoice
–
+
Invoice ≠ Payment
Your Sales Account
Customer Account
Your Bank Account
Invoice
–
+
Payment
–
+
Invoice ≠ Payment
Charges not yet invoiced
Description Amount
Pay As You Go charges so far this month £23.45
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
Account statement
Charges not yet invoiced
Description Amount
Pay As You Go charges so far this month £23.45
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
Account statement Invoice
Credit Note
Payment
Invoice(with status=open)
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]) endend
Thomas Hawk, http://www.flickr.com/photos/thomashawk/2317826708/
VAT
Your Sales Account
Customer Account
Your Bank Account
VAT Account
Your Sales Account
Customer Account
Your Bank Account
VAT Account
Invoice
–
+
–
Your Sales Account
Customer Account
Your Bank Account
VAT Account
Payment
–
+
Invoice
–
+
–
Your Sales Account
Customer Account
Your Bank Account
VAT Account
Payment
–
+
Invoice
–
+
–
–
+
VATReturn
Urgh.(And we’ve not even started talking about EU
VAT regulations yet.)
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
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
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
VAT made easy
☺
VAT made easy
# New in invoicing gem version 0.3class MyProduct < ActiveRecord::Base acts_as_taxable :price, :tax_logic => Invoicing::Countries::UK::VAT.newend
p = MyProduct.new :price => 10p.price_with_tax_info# => "£11.50 (inc. VAT)"
p.price_taxed = 23.00p.price.to_s# => "20.0"
Paolo Màrgari, http://www.flickr.com/photos/paolomargari/3050305454/
Overview of your customers
Sales and purchases ledger
Name Currency Sales Purchases Salereceipts
Purchasepayments Balance
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
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}" # ... endend
What else?
Mar
tin K
lepp
man
n, h
ttp:
//ww
w.fl
ickr
.com
/pho
tos/
mar
tinkl
eppm
ann/
3131
1987
70/
Mar
tin K
lepp
man
n, h
ttp:
//ww
w.fl
ickr
.com
/pho
tos/
mar
tinkl
eppm
ann/
3131
1987
70/
¥1,300
Currency formatting
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
Nothing is constant
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"
John
ny V
ulka
n, h
ttp:
//ww
w.fl
ickr
.com
/pho
tos/
2661
4375
@N
00/3
8194
1029
/
Integrating with payment gateways
⇒ http://activemerchant.org
Open standards
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 endend
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 endend
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 endend
UBL? WTF?
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.
@timbray: “Don’t Invent XML Languages”http://tr.im/NoNewXML
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>...
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>
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>
@timbray: “Don’t Invent XML Languages”http://tr.im/NoNewXML
Designing XML Languages is hard. It’s boring, political, time-
consuming, unglamorous, irritating work.
Interoperability
OAccountsSage
MYOB
KashFlow
Xero
Invoicing gem
Payment provider
Shopping cart
Custom reporting
OAccountsSage
MYOB
KashFlow
Xero
Invoicing gem
Payment provider
Shopping cart
Custom reporting
OAccounts
OAccounts=
UBL + XBRL-GL + REST + Conventions +
Documentation +Collaboration +
Open source implementation
OAccounts=
UBL + XBRL-GL + REST + Conventions +
Documentation +Collaboration +
Open source implementation
http://oaccounts.org/
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/
Martin Kleppmannhttp://go-test.it
http://yes-no-cancel.co.ukhttp://twitter.com/martinkl
Thank you!
top related