google_checkout 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/doc/LICENSE +19 -0
  2. data/doc/README +108 -0
  3. data/lib/google-checkout.rb +228 -0
  4. metadata +46 -0
data/doc/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2006 Peter Elmore (pete.elmore at gmail.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a
4
+ copy of this software and associated documentation files (the "Software"),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
data/doc/README ADDED
@@ -0,0 +1,108 @@
1
+ = GoogleCheckout
2
+
3
+ == Installation
4
+
5
+ Currently, it's only available as a gem.
6
+
7
+ == What is Google Checkout?
8
+
9
+ Well, according to Google, "Google Checkout helps you increase sales. And
10
+ process them for free when you advertise with Google." What it really amounts
11
+ to is that Google will process your orders for a 10% fee and you get a little
12
+ shopping cart icon in your ad if you advertise through AdWords. The fee can
13
+ be paid by running AdWords ads on your site. You can read about it and get an
14
+ account at http://checkout.google.com/sell .
15
+
16
+ == What is google-checkout?
17
+
18
+ google-checkout is a module for working with the Google Checkout API
19
+ (http://code.google.com/apis/checkout/index.html). Specifically, if you have
20
+ a Google Checkout account, you can use this module to do things like add
21
+ "Checkout" and "Buy Now" buttons to your site.
22
+
23
+ == Brief Example
24
+
25
+ require 'rubygems'
26
+ require 'google-checkout'
27
+
28
+ merchant_id = 'Your merchant id.'
29
+ merchant_key = 'Your merchant key. Keep this a secret!'
30
+
31
+ cart = GoogleCheckout::Cart.new(merchant_id, merchant_key)
32
+ cart.add_item(:name => 'Chair', :description => 'A sturdy, wooden chair',
33
+ :price => 44.99)
34
+ puts cart.checkout_button
35
+
36
+ == Usage
37
+
38
+ First, you'll need a merchant ID and a merchant key, which you can get from
39
+ the Google Checkout site once you have an account. After you have that, you
40
+ can start writing code.
41
+
42
+ The class you'll be working with is GoogleCheckout::Cart. Of course, it
43
+ represents a cart, and you can fill it with items.
44
+
45
+ cart = GoogleCheckout::Cart.new(merchant_id, merchant_key, item1, item2)
46
+ cart.add_item item3
47
+
48
+ The items you put into the cart should be one of two types:
49
+ * A Hash containing the following
50
+ ** :name
51
+ ** :description
52
+ ** :price
53
+ ** :quantity (default 1)
54
+ ** :currency (default 'USD')
55
+ ** :regular_shipping, the shipping cost (default $0)
56
+ * Or any Object that has a method called to_google_product that returns a hash
57
+ like the one described.
58
+
59
+ Once you have a cart full of items, you can generate the XML for the API call
60
+ by calling Cart#checkout_xml, although you'll probably just want to add a
61
+ checkout button to your page with Cart#checkout_button. This method generates
62
+ HTML for a form containing a button and the hidden inputs necessary to call
63
+ Google Checkout. Cart#checkout_button has plenty of options for controlling
64
+ the look of the button. Once again, the arguments are passed as a hash,
65
+ although the defaults are usually reasonable so you might not need to pass
66
+ anything.
67
+
68
+ * :size is the size of the button, one of :small, :medium, or :large. Google
69
+ is picky about the sizes of these buttons. See GoogleCheckout::ButtonSizes
70
+ for more information. The default is :medium.
71
+ * :variant is one of 'disabled' or 'text'. 'disabled' means that the button
72
+ should be greyed-out; it is used in cases that the item you are selling
73
+ cannot be bought via Google Checkout. (There's a long list of items that
74
+ are not allowed at https://checkout.google.com/seller/content_policies.html
75
+ * :buy_or_checkout must be one of :buy_now or :checkout . This determines the
76
+ look of the button that will be displayed. The default is to use :checkout
77
+ if there are two or more items in the cart.
78
+ * :style must be one of 'white' or 'trans'. 'white' gets you a white button,
79
+ while 'trans' gets you a transparent button suitable for use on non-white
80
+ backgrounds. The default is 'white'.
81
+
82
+ cart.checkout_button :size => :small, :style => 'trans'
83
+
84
+ When users click the button, they will be taken to the Google Checkout page
85
+ with a cart full of the products you specified, and your work is done.
86
+
87
+ == Missing Features
88
+
89
+ * Level 1 integration is complete except for tax tables
90
+ * Level 2 integration is missing.
91
+
92
+ See
93
+ http://checkout.google.com/support/sell/bin/answer.py?answer=42917&topic=8671
94
+ for more information about the two integration levels.
95
+
96
+ If there are missing features I haven't thought of, let me know.
97
+
98
+ == Bugs
99
+
100
+ No 'hard' bugs, I hope. My contact information is at the bottom of the page
101
+ if you find one. There may be more subjective bugs (e.g., design issues);
102
+ feel free to tell me about these, too.
103
+
104
+ == Contact Information
105
+
106
+ The home page is at http://debu.gs/google-checkout . You can email me at pete
107
+ dot elmore at gmail dot com. Try to mention Google Checkout in the subject
108
+ line.
@@ -0,0 +1,228 @@
1
+ require 'rubygems'
2
+
3
+ require 'hmac-sha1'
4
+ require 'base64'
5
+
6
+ require 'builder/xmlmarkup'
7
+
8
+ # For the impatient or forgetful:
9
+ # item = { :name => 'A Quarter', :description => 'One shiny quarter.',
10
+ # :price => 0.25 }
11
+ # cart = GoogleCheckout::Cart.new(merchant_id, merchant_key, item)
12
+ # cart.add_item(:name => "Pancakes", :description => "Flapjacks by mail."
13
+ # :price => 0.50, :quantity => 10)
14
+ # File.open('commerce.html', 'w') { |f|
15
+ # f.write(
16
+ # "<html><body>Click this button to buy a quarter and ten pancakes:" +
17
+ # cart.checkout_button + "</body></html>")
18
+ # }
19
+ #
20
+ # If you're interested in a little more detail, you'll want to have a look at
21
+ # GoogleCheckout::Cart, Cart#add_item, Cart#checkout_xml, and
22
+ # Cart#checkout_button.
23
+ module GoogleCheckout
24
+ CheckoutURL = "checkout.google.com"
25
+ SubmitURL = "https://#{CheckoutURL}/cws/v2/Merchant"
26
+
27
+
28
+ # These are the only sizes allowed by Google. These shouldn't be needed
29
+ # by most people; just specify the :size and :buy_or_checkout options to
30
+ # Cart#checkout_button and the sizes are filled in automatically.
31
+ ButtonSizes = {
32
+ :checkout => {
33
+ :small => { :w => 160, :h => 43 },
34
+ :medium => { :w => 168, :h => 44 },
35
+ :large => { :w => 180, :h => 46 },
36
+ },
37
+
38
+ :buy_now => {
39
+ :small => { :w => 117, :h => 48 },
40
+ :medium => { :w => 121, :h => 44 },
41
+ :large => { :w => 121, :h => 44 },
42
+ },
43
+ }
44
+
45
+ # This class represents a cart for Google Checkout. After initializing it
46
+ # with a +merchant_id+ and +merchant_key+, you add items via add_item,
47
+ # and can then get xml via checkout_xml, or html code for a form that
48
+ # provides a checkout button via checkout_button.
49
+ class Cart
50
+ attr_accessor :merchant_id, :merchant_key
51
+
52
+ include GoogleCheckout
53
+
54
+ # The default options for drawing in the button that are filled in when
55
+ # checkout_button or button_url is called.
56
+ DefaultButtonOpts = {
57
+ :size => :medium,
58
+ :style => 'white',
59
+ :variant => 'text',
60
+ :loc => 'en_US',
61
+ :buy_or_checkout => nil,
62
+ }
63
+
64
+ # You need to supply, as strings, the +merchant_id+ and +merchant_key+
65
+ # used to identify your store to Google. You may optionally supply one
66
+ # or more items to put inside the cart.
67
+ def initialize(merchant_id, merchant_key, *items)
68
+ @merchant_id = merchant_id
69
+ @merchant_key = merchant_key
70
+ @contents = []
71
+ items.each { |i| add_item i }
72
+ end
73
+
74
+ def empty?
75
+ @contents.empty?
76
+ end
77
+
78
+ # Number of items in the cart.
79
+ def size
80
+ @contents.size
81
+ end
82
+
83
+ # This method returns the URL to which the form should be submitted.
84
+ def submit_url
85
+ [SubmitURL, @merchant_id, 'checkout'].join('/')
86
+ end
87
+
88
+ # This method puts items in the cart.
89
+ # +item+ may be a hash, or have a method named +to_google_product+ that
90
+ # returns a hash with the required values.
91
+ # * name
92
+ # * description (a brief description as it will appear on the bill)
93
+ # * price
94
+ # You may fill in some optional values as well:
95
+ # * quantity (defaults to 1)
96
+ # * currency (defaults to 'USD')
97
+ def add_item(item)
98
+ @xml = nil
99
+ if item.respond_to? :to_google_product
100
+ item = item.to_google_product
101
+ end
102
+
103
+ # We need to check that the necessary keys are in the hash,
104
+ # Otherwise the error will happen in the middle of checkout_xml,
105
+ # and the bug will be harder to track.
106
+ missing_keys = [ :name, :description, :price ].select { |key|
107
+ !item.include? key
108
+ }
109
+
110
+ unless missing_keys.empty?
111
+ raise ArgumentError,
112
+ "Required keys missing: #{missing_keys.inspect}"
113
+ end
114
+
115
+ @contents << { :quantity => 1, :currency => 'USD' }.merge(item)
116
+ item
117
+ end
118
+
119
+ # This is the important method; it generatest the XML call.
120
+ # It's fairly lengthy, but trivial. It follows the docs at
121
+ # http://code.google.com/apis/checkout/developer/index.html#checkout_api
122
+ #
123
+ # It returns the raw XML string, not encoded.
124
+ def checkout_xml
125
+ raise RuntimeError, "Empty cart" if self.empty?
126
+
127
+ xml = Builder::XmlMarkup.new
128
+ xml.instruct!
129
+ @xml = xml.tag!('checkout-shopping-cart',
130
+ :xmlns => "http://checkout.google.com/schema/2") {
131
+ xml.tag!("shopping-cart") {
132
+ xml.items {
133
+ @contents.each { |item|
134
+ xml.item {
135
+ xml.tag!('item-name') {
136
+ xml.text! item[:name].to_s
137
+ }
138
+ xml.tag!('item-description') {
139
+ xml.text! item[:description].to_s
140
+ }
141
+ xml.tag!('unit-price',
142
+ :currency => (item[:currency] || 'USD')) {
143
+ xml.text! item[:price].to_s
144
+ }
145
+ xml.quantity {
146
+ xml.text! item[:quantity].to_s
147
+ }
148
+ }
149
+ }
150
+ }
151
+ }
152
+ xml.tag!('checkout-flow-support') {
153
+ xml.tag!('merchant-checkout-flow-support') {
154
+ xml.tag!('shipping-methods') {
155
+ xml.tag!('flat-rate-shipping', :name =>'Shipping') {
156
+ currency = 'USD'
157
+ shipping = @contents.inject(0) { |total,i|
158
+ # Mixing currency not allowed; this library
159
+ # can't convert between currencies.
160
+ currency = i[:currency] || currency
161
+ total + i[:regular_shipping].to_i
162
+ }.to_s
163
+ xml.price(:currency => currency) {
164
+ xml.text! shipping
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+ @xml.dup
172
+ end
173
+
174
+ # Returns the signature for the cart XML.
175
+ def signature
176
+ @xml or checkout_xml
177
+ HMAC::SHA1.digest(@merchant_key, @xml)
178
+ end
179
+
180
+ # Returns HTML for a checkout form for buying all the items in the
181
+ # cart.
182
+ def checkout_button(button_opts = {})
183
+ @xml or checkout_xml
184
+ burl = button_url(button_opts)
185
+ html = Builder::XmlMarkup.new(:indent => 2)
186
+ html.form(:action => submit_url, :style => 'border: 0;',
187
+ :id => 'BB_BuyButtonForm', :method => 'post',
188
+ :name => 'BB_BuyButtonForm') {
189
+ html.input(:name => 'cart', :type => 'hidden',
190
+ :value => Base64.encode64(@xml).gsub("\n", ''))
191
+ html.input(:name => 'signature', :type => 'hidden',
192
+ :value => Base64.encode64(signature).gsub("\n", ''))
193
+ html.input(:alt => 'Google Checkout',
194
+ :style => "width: auto;",
195
+ :src => button_url(button_opts),
196
+ :type => 'image')
197
+ }
198
+ end
199
+
200
+ # Given a set of options for the button, button_url returns the URL
201
+ # for the button image.
202
+ # The options are the same as those specified on
203
+ # http://checkout.google.com/seller/checkout_buttons.html , with a
204
+ # couple of extra options for convenience. Rather than specifying the
205
+ # width and height manually, you may specify :size to be one of
206
+ # :small, :medium, or :large, and that you may set :buy_or_checkout
207
+ # to :buy_now or :checkout to get a 'Buy Now' button versus a
208
+ # 'Checkout' button. If you don't specify :buy_or_checkout, the Cart
209
+ # will try to guess based on if the cart has more than one item in
210
+ # it. Whatever you don't pass will be filled in with the defaults from
211
+ # DefaultButtonOpts.
212
+ def button_url(opts = {})
213
+ opts = DefaultButtonOpts.merge opts
214
+ opts[:buy_or_checkout] ||= @contents.size > 1 ? :checkout :
215
+ :buy_now
216
+ opts.merge! ButtonSizes[opts[:buy_or_checkout]][opts[:size]]
217
+ bname = opts[:buy_or_checkout] == :buy_now ? 'buy.gif' :
218
+ 'checkout.gif'
219
+ opts.delete :size
220
+ opts.delete :buy_or_checkout
221
+ opts[:merchant_id] = @merchant_id
222
+
223
+ path = opts.map { |k,v| "#{k}=#{v}" }.join('&')
224
+
225
+ "http://#{CheckoutURL}/buttons/#{bname}?#{path}"
226
+ end
227
+ end
228
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.8
3
+ specification_version: 1
4
+ name: google_checkout
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2006-12-17
8
+ summary: An interface to the Google Checkout API.
9
+ require_paths:
10
+ - lib
11
+ email: pete.elmore@gmail.com
12
+ homepage: http://debu.gs/google-checkout
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: google-checkout
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ authors:
27
+ - Pete Elmore
28
+ files:
29
+ - doc/LICENSE
30
+ - doc/README
31
+ - lib/google-checkout.rb
32
+ test_files: []
33
+
34
+ rdoc_options: []
35
+
36
+ extra_rdoc_files:
37
+ - doc/README
38
+ - doc/LICENSE
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ requirements: []
44
+
45
+ dependencies: []
46
+