google_checkout 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/doc/LICENSE +19 -0
- data/doc/README +108 -0
- data/lib/google-checkout.rb +228 -0
- 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
|
+
|