codehog-google-checkout 1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/History.txt +25 -0
  2. data/Isolate +13 -0
  3. data/MIT-LICENSE.txt +23 -0
  4. data/Manifest.txt +42 -0
  5. data/README.txt +148 -0
  6. data/Rakefile +35 -0
  7. data/examples/google_notifications_controller.rb +159 -0
  8. data/lib/duck_punches/hpricot.rb +24 -0
  9. data/lib/google-checkout.rb +61 -0
  10. data/lib/google-checkout/cart.rb +357 -0
  11. data/lib/google-checkout/command.rb +191 -0
  12. data/lib/google-checkout/notification.rb +226 -0
  13. data/spec/fixtures/google/checkout-shopping-cart.xml +22 -0
  14. data/spec/fixtures/google/commands/add-merchant-order-number.xml +5 -0
  15. data/spec/fixtures/google/commands/add-tracking-data.xml +8 -0
  16. data/spec/fixtures/google/commands/archive-order.xml +3 -0
  17. data/spec/fixtures/google/commands/authorize-order.xml +2 -0
  18. data/spec/fixtures/google/commands/cancel-order.xml +5 -0
  19. data/spec/fixtures/google/commands/charge-order.xml +4 -0
  20. data/spec/fixtures/google/commands/deliver-order.xml +9 -0
  21. data/spec/fixtures/google/commands/process-order.xml +2 -0
  22. data/spec/fixtures/google/commands/refund-order.xml +6 -0
  23. data/spec/fixtures/google/commands/send-buyer-message.xml +7 -0
  24. data/spec/fixtures/google/commands/unarchive-order.xml +2 -0
  25. data/spec/fixtures/google/notifications/authorization-amount-notification.xml +10 -0
  26. data/spec/fixtures/google/notifications/charge-amount-notification.xml +8 -0
  27. data/spec/fixtures/google/notifications/chargeback-amount-notification.xml +8 -0
  28. data/spec/fixtures/google/notifications/new-order-notification.xml +85 -0
  29. data/spec/fixtures/google/notifications/order-state-change-notification.xml +11 -0
  30. data/spec/fixtures/google/notifications/refund-amount-notification.xml +8 -0
  31. data/spec/fixtures/google/notifications/risk-information-notification.xml +23 -0
  32. data/spec/fixtures/google/responses/checkout-redirect.xml +5 -0
  33. data/spec/fixtures/google/responses/error.xml +5 -0
  34. data/spec/fixtures/google/responses/request-received.xml +3 -0
  35. data/spec/google-checkout/cart_spec.rb +165 -0
  36. data/spec/google-checkout/command_spec.rb +131 -0
  37. data/spec/google-checkout/notification_spec.rb +181 -0
  38. data/spec/google-checkout/response_spec.rb +49 -0
  39. data/spec/google-checkout_spec.rb +15 -0
  40. data/spec/spec_helper.rb +47 -0
  41. data/support/cacert.pem +7815 -0
  42. metadata +203 -0
@@ -0,0 +1,25 @@
1
+ == 0.5.1 / 2011-02-08
2
+
3
+ * Bugfix
4
+ * Include missing fixture file for apps that
5
+ need to use it for tests.
6
+
7
+ == 0.5.0 / 2011-02-08
8
+
9
+ * Use Nokogiri
10
+ * Use Nokogiri instead of Hpricot
11
+
12
+ == 0.2.0 / 2007-08-14
13
+
14
+ * Significant rewrite!
15
+ * Added rSpec specifications.
16
+ * Added level 2 integration for sending and
17
+ and parsing notifications from Google.
18
+ * Shipping temporarily hard-coded to
19
+ "Digital Download"
20
+ * Added merchant-private-data for sending
21
+ one's own tracking number to Google.
22
+ * Defaults to live system but you can call
23
+ GoogleCheckout.use_sandbox to use the
24
+ sandbox instead.
25
+ * Fixtures for Google commands and notifications.
data/Isolate ADDED
@@ -0,0 +1,13 @@
1
+
2
+ gem "builder"
3
+ gem "nokogiri"
4
+ gem "money", ">= 3.0"
5
+ gem "activesupport"
6
+
7
+ env :development, :test do
8
+ gem "hoe", "2.8"
9
+ gem "hoe-doofus", "1.0.0"
10
+ gem "hoe-git", "1.3.0"
11
+ gem "rspec", "1.3.0"
12
+ end
13
+
@@ -0,0 +1,23 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2006-2008 Peter Elmore (pete.elmore at gmail.com) and Topfunky Corporation
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
@@ -0,0 +1,42 @@
1
+ History.txt
2
+ Isolate
3
+ MIT-LICENSE.txt
4
+ Manifest.txt
5
+ README.txt
6
+ Rakefile
7
+ examples/google_notifications_controller.rb
8
+ lib/duck_punches/hpricot.rb
9
+ lib/google-checkout.rb
10
+ lib/google-checkout/cart.rb
11
+ lib/google-checkout/command.rb
12
+ lib/google-checkout/notification.rb
13
+ spec/fixtures/google/checkout-shopping-cart.xml
14
+ spec/fixtures/google/commands/add-merchant-order-number.xml
15
+ spec/fixtures/google/commands/add-tracking-data.xml
16
+ spec/fixtures/google/commands/archive-order.xml
17
+ spec/fixtures/google/commands/authorize-order.xml
18
+ spec/fixtures/google/commands/cancel-order.xml
19
+ spec/fixtures/google/commands/charge-order.xml
20
+ spec/fixtures/google/commands/deliver-order.xml
21
+ spec/fixtures/google/commands/process-order.xml
22
+ spec/fixtures/google/commands/refund-order.xml
23
+ spec/fixtures/google/commands/send-buyer-message.xml
24
+ spec/fixtures/google/commands/unarchive-order.xml
25
+ spec/fixtures/google/notifications/authorization-amount-notification.xml
26
+ spec/fixtures/google/notifications/charge-amount-notification.xml
27
+ spec/fixtures/google/notifications/chargeback-amount-notification.xml
28
+ spec/fixtures/google/notifications/new-order-notification.xml
29
+ spec/fixtures/google/notifications/order-state-change-notification-missing.xml
30
+ spec/fixtures/google/notifications/order-state-change-notification.xml
31
+ spec/fixtures/google/notifications/refund-amount-notification.xml
32
+ spec/fixtures/google/notifications/risk-information-notification.xml
33
+ spec/fixtures/google/responses/checkout-redirect.xml
34
+ spec/fixtures/google/responses/error.xml
35
+ spec/fixtures/google/responses/request-received.xml
36
+ spec/google-checkout/cart_spec.rb
37
+ spec/google-checkout/command_spec.rb
38
+ spec/google-checkout/notification_spec.rb
39
+ spec/google-checkout/response_spec.rb
40
+ spec/google-checkout_spec.rb
41
+ spec/spec_helper.rb
42
+ support/cacert.pem
@@ -0,0 +1,148 @@
1
+ = Google Checkout
2
+
3
+ * http://github.com/topfunky/google-checkout
4
+
5
+ == DESCRIPTION:
6
+
7
+ Experimental library for working with GoogleCheckout. Currently in use for payment at http://peepcode.com.
8
+
9
+ == Authors
10
+
11
+ Original by Peter Elmore.
12
+
13
+ Enhanced and maintained by Geoffrey Grosenbach.
14
+
15
+ == Installation
16
+
17
+ sudo gem install google-checkout
18
+
19
+ Or straight from the source at
20
+
21
+ sudo gem install topfunky-google-checkout --source http://gems.github.com
22
+
23
+ == What is Google Checkout?
24
+
25
+ Well, according to Google, "Google Checkout helps you increase sales. And
26
+ process them for free when you advertise with Google." What it really amounts
27
+ to is that Google will process your orders for a 10% fee and you get a little
28
+ shopping cart icon in your ad if you advertise through AdWords. The fee can
29
+ be paid by running AdWords ads on your site. You can read about it and get an
30
+ account at http://checkout.google.com/sell.
31
+
32
+ == What is google-checkout?
33
+
34
+ google-checkout is a module for working with the Google Checkout API
35
+ (http://code.google.com/apis/checkout/index.html). Specifically, if you have
36
+ a Google Checkout account, you can use this module to do things like add
37
+ "Checkout" and "Buy Now" buttons to your site.
38
+
39
+ == Brief Example
40
+
41
+ require 'rubygems'
42
+ require 'google-checkout'
43
+
44
+ merchant_id = 'Your merchant id.'
45
+ merchant_key = 'Your merchant key. Keep this a secret!'
46
+
47
+ cart = GoogleCheckout::Cart.new(merchant_id, merchant_key)
48
+ cart.add_item(:name => 'Chair', :description => 'A sturdy, wooden chair',
49
+ :price => 44.99)
50
+ puts cart.checkout_button
51
+
52
+ == Usage
53
+
54
+ First, you'll need a merchant ID and a merchant key, which you can get from
55
+ the Google Checkout site once you have an account. After you have that, you
56
+ can start writing code.
57
+
58
+ The class you'll be working with is GoogleCheckout::Cart. Of course, it
59
+ represents a cart, and you can fill it with items.
60
+
61
+ cart = GoogleCheckout::Cart.new(merchant_id, merchant_key, item1, item2)
62
+ cart.add_item item3
63
+
64
+ The items you put into the cart should be one of two types:
65
+ * A Hash containing the following
66
+ ** :name
67
+ ** :description
68
+ ** :price
69
+ ** :quantity (default 1)
70
+ ** :currency (default 'USD')
71
+ ** :regular_shipping, the shipping cost (default $0)
72
+ * Or any Object that has a method called to_google_product that returns a hash
73
+ like the one described.
74
+
75
+ Once you have a cart full of items, you can generate the XML for the API call
76
+ by calling Cart#checkout_xml, although you'll probably just want to add a
77
+ checkout button to your page with Cart#checkout_button. This method generates
78
+ HTML for a form containing a button and the hidden inputs necessary to call
79
+ Google Checkout. Cart#checkout_button has plenty of options for controlling
80
+ the look of the button. Once again, the arguments are passed as a hash,
81
+ although the defaults are usually reasonable so you might not need to pass
82
+ anything.
83
+
84
+ * :size is the size of the button, one of :small, :medium, or :large. Google
85
+ is picky about the sizes of these buttons. See GoogleCheckout::ButtonSizes
86
+ for more information. The default is :medium.
87
+ * :variant is one of 'disabled' or 'text'. 'disabled' means that the button
88
+ should be greyed-out; it is used in cases that the item you are selling
89
+ cannot be bought via Google Checkout. (There's a long list of items that
90
+ are not allowed at https://checkout.google.com/seller/content_policies.html
91
+ * :buy_or_checkout must be one of :buy_now or :checkout . This determines the
92
+ look of the button that will be displayed. The default is to use :checkout
93
+ if there are two or more items in the cart.
94
+ * :style must be one of 'white' or 'trans'. 'white' gets you a white button,
95
+ while 'trans' gets you a transparent button suitable for use on non-white
96
+ backgrounds. The default is 'white'.
97
+
98
+ cart.checkout_button :size => :small, :style => 'trans'
99
+
100
+ When users click the button, they will be taken to the Google Checkout page
101
+ with a cart full of the products you specified, and your work is done.
102
+
103
+ == Missing Features
104
+
105
+ * Level 1 integration is complete except for tax tables
106
+ * Level 2 integration has been partly implemented and is in use at http://peepcode.com.
107
+
108
+ See
109
+ http://checkout.google.com/support/sell/bin/answer.py?answer=42917&topic=8671
110
+ for more information about the two integration levels.
111
+
112
+ If there are missing features I haven't thought of, let me know.
113
+
114
+ == Bugs
115
+
116
+ No 'hard' bugs, I hope. Pete's contact information is at the bottom of the page if you find one. There may be more subjective bugs (e.g., design issues); feel free to tell me about these, too.
117
+
118
+ == Contact Information
119
+
120
+ The home page is at http://debu.gs/google-checkout . You can email me at pete
121
+ dot elmore at gmail dot com. Try to mention Google Checkout in the subject
122
+ line.
123
+
124
+ == LICENSE:
125
+
126
+ (The MIT License)
127
+
128
+ Copyright (c) 2006-2007 Peter Elmore (pete.elmore at gmail.com) and Topfunky Corporation
129
+
130
+ Permission is hereby granted, free of charge, to any person obtaining
131
+ a copy of this software and associated documentation files (the
132
+ 'Software'), to deal in the Software without restriction, including
133
+ without limitation the rights to use, copy, modify, merge, publish,
134
+ distribute, sublicense, and/or sell copies of the Software, and to
135
+ permit persons to whom the Software is furnished to do so, subject to
136
+ the following conditions:
137
+
138
+ The above copyright notice and this permission notice shall be
139
+ included in all copies or substantial portions of the Software.
140
+
141
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
142
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
143
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
144
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
145
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
146
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
147
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
148
+
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'isolate/now'
3
+ require 'hoe'
4
+
5
+ Hoe.plugin :doofus, :git, :isolate
6
+ Hoe.spec "google-checkout" do
7
+ developer "Geoffrey Grosenbach", "boss@topfunky.com"
8
+
9
+ #require_ruby_version ">= 1.8.7"
10
+
11
+ #self.extra_rdoc_files = Dir["*.rdoc"]
12
+ #self.history_file = "CHANGELOG.rdoc"
13
+ #self.readme_file = "README.rdoc"
14
+ self.testlib = :rspec
15
+
16
+ self.remote_rdoc_dir = '' # Release docs to root
17
+ end
18
+
19
+
20
+ # Hoe.plugin :isolate
21
+ # Hoe.new('google-checkout', GoogleCheckout::VERSION) do |p|
22
+ # p.name = "google-checkout"
23
+ # p.author = ["Peter Elmore", "Geoffrey Grosenbach"]
24
+ # p.email = 'boss@topfunky.com'
25
+ # p.summary = "An experimental library for sending payment requests to Google Checkout."
26
+ # p.description = p.paragraphs_of('README.txt', 1..1).join("\n\n")
27
+ # p.url = "http://rubyforge.org/projects/google-checkout"
28
+ # p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
29
+ # p.remote_rdoc_dir = '' # Release docs to root
30
+ # end
31
+
32
+ # desc "Run specs"
33
+ # task :default do
34
+ # system 'spec spec --format specdoc --color'
35
+ # end
@@ -0,0 +1,159 @@
1
+ ##
2
+ # Skeleton for handing Level 2 notifications from GoogleCheckout with Rails.
3
+ #
4
+ # You'll need to write the individual handlers. SSL is required.
5
+ #
6
+ # SAMPLE ONLY! Modify for your own use. Extra error handling may be needed.
7
+
8
+ class GoogleNotificationsController < ApplicationController
9
+
10
+ before_filter :verify_access
11
+ after_filter :log_google_notification
12
+
13
+ ##
14
+ # Google calls this with notifications.
15
+
16
+ def create
17
+ @notification = GoogleCheckout::Notification.parse(request.raw_post)
18
+
19
+ case @notification
20
+ when GoogleCheckout::NewOrderNotification
21
+ handle_new_order_notification(@notification)
22
+
23
+ when GoogleCheckout::OrderStateChangeNotification
24
+ handle_order_state_change_notification(@notification)
25
+
26
+ when GoogleCheckout::RiskInformationNotification
27
+ handle_risk_information_notification(@notification)
28
+
29
+ when GoogleCheckout::ChargeAmountNotification
30
+ handle_charge_amount_notification(@notification)
31
+
32
+ when GoogleCheckout::AuthorizationAmountNotification
33
+ handle_authorization_amount_notification(@notification)
34
+
35
+ when GoogleCheckout::ChargebackAmountNotification
36
+ handle_chargeback_amount_notification(@notification)
37
+
38
+ when GoogleCheckout::RefundAmountNotification
39
+ handle_refund_amount_notification(@notification)
40
+ end
41
+
42
+ render :xml => @notification.acknowledgment_xml
43
+ end
44
+
45
+ private
46
+
47
+ ##
48
+ # Use basic authentication in my realm to get a user object.
49
+ # Since this is a security filter - return false if the user is not authenticated.
50
+
51
+ def verify_access
52
+ return false unless (request.ssl? || (RAILS_ENV == 'development') || (RAILS_ENV == 'test'))
53
+ authenticate_or_request_with_http_basic("PeepCode") do |merchant_id, merchant_key|
54
+ (merchant_id == GOOGLE_ID) && (merchant_key == GOOGLE_KEY)
55
+ end
56
+ end
57
+
58
+ ##
59
+ #
60
+
61
+ def log_google_notification
62
+ # TODO Write to your log or to a DB table
63
+ end
64
+
65
+ ##
66
+ #
67
+
68
+ def handle_new_order_notification(notification)
69
+ logger.info "Got NewOrderNotification"
70
+
71
+ # NOTE You should have passed your own order number to Google when
72
+ # making the initial order. Subsequent notifications will use
73
+ # Google's order number instead.
74
+ @order = Order.find_by_order_number(notification.my_order_number)
75
+ if @order
76
+ # NOTE You may want to check the amount being charged vs. the amount
77
+ # you expected the user to pay.
78
+
79
+ @order.google_order_number = notification.google_order_number
80
+ @order.email = notification.email
81
+
82
+ # Fee is 20 cents plus 2% of total.
83
+ @order.fee_cents = (20 + (notification.order_total.cents * 0.02)).round
84
+ @order.gross_cents = notification.order_total.cents
85
+ @order.net_cents = @order.gross_cents - @order.fee_cents
86
+
87
+ # NOTE Also of interest is notification.email_allowed, a boolean
88
+ @order.save
89
+ @order.new_order!
90
+ end
91
+ end
92
+
93
+ ##
94
+ #
95
+
96
+ def handle_order_state_change_notification(notification)
97
+ @order = Order.find_for_notification(notification)
98
+ @order.update_attribute(:google_state, notification.state)
99
+
100
+ case notification.state
101
+ when "REVIEWING" # Initial state of orders. Rarely seen by client.
102
+
103
+ when "CHARGEABLE" # You can now charge the customer for the order.
104
+ @order.chargeable!
105
+ when "CHARGING" # Google is charging the customer.
106
+ @order.charging!
107
+ when "CHARGED" # You have charged the customer.
108
+ @order.charged!
109
+ when "PAYMENT_DECLINED" # Google was unable to charge the client
110
+ @order.denied!
111
+ when "CANCELLED" # Order was cancelled by the merchant
112
+ @order.denied!
113
+ @order.update_attribute(:payment_note, notification.reason) rescue nil
114
+ when "CANCELLED_BY_GOOGLE" # Order was cancelled by Google
115
+ @order.denied!
116
+ # notification.reason
117
+ end
118
+ end
119
+
120
+ ##
121
+ #
122
+
123
+ def handle_risk_information_notification(notification)
124
+ logger.info "Got RiskInformationNotification"
125
+
126
+ @order = Order.find_for_notification(notification)
127
+ @order.risk!
128
+
129
+ # TODO You need to ping Google after this to trigger the next state.
130
+ # Do this in the model, but for reference, here's the basic code.
131
+ if @order.google_state == "CHARGEABLE"
132
+ charge_order_command = GoogleCheckout::ChargeOrder.new(GOOGLE_ID, GOOGLE_KEY, @order.google_order_number)
133
+ # To string, to float in order to get a float representation of the money
134
+ charge_order_command.amount = total_price.to_s.to_f
135
+ # Will throw error on failure
136
+ notification = charge_order_command.post
137
+ else
138
+ logger.error("Order was not in CHARGEABLE state")
139
+ end
140
+ end
141
+
142
+ ##
143
+ #
144
+
145
+ def handle_charge_amount_notification(notification)
146
+ @order = Order.find_for_notification(notification)
147
+ @order.charge!
148
+ end
149
+
150
+ ##
151
+ #
152
+
153
+ def handle_refund_amount_notification(notification)
154
+ # NOTE Notification includes amount refunded.
155
+ @order = Order.find_for_notification(notification)
156
+ @order.refund!
157
+ end
158
+
159
+ end