codehog-google-checkout 1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +25 -0
- data/Isolate +13 -0
- data/MIT-LICENSE.txt +23 -0
- data/Manifest.txt +42 -0
- data/README.txt +148 -0
- data/Rakefile +35 -0
- data/examples/google_notifications_controller.rb +159 -0
- data/lib/duck_punches/hpricot.rb +24 -0
- data/lib/google-checkout.rb +61 -0
- data/lib/google-checkout/cart.rb +357 -0
- data/lib/google-checkout/command.rb +191 -0
- data/lib/google-checkout/notification.rb +226 -0
- data/spec/fixtures/google/checkout-shopping-cart.xml +22 -0
- data/spec/fixtures/google/commands/add-merchant-order-number.xml +5 -0
- data/spec/fixtures/google/commands/add-tracking-data.xml +8 -0
- data/spec/fixtures/google/commands/archive-order.xml +3 -0
- data/spec/fixtures/google/commands/authorize-order.xml +2 -0
- data/spec/fixtures/google/commands/cancel-order.xml +5 -0
- data/spec/fixtures/google/commands/charge-order.xml +4 -0
- data/spec/fixtures/google/commands/deliver-order.xml +9 -0
- data/spec/fixtures/google/commands/process-order.xml +2 -0
- data/spec/fixtures/google/commands/refund-order.xml +6 -0
- data/spec/fixtures/google/commands/send-buyer-message.xml +7 -0
- data/spec/fixtures/google/commands/unarchive-order.xml +2 -0
- data/spec/fixtures/google/notifications/authorization-amount-notification.xml +10 -0
- data/spec/fixtures/google/notifications/charge-amount-notification.xml +8 -0
- data/spec/fixtures/google/notifications/chargeback-amount-notification.xml +8 -0
- data/spec/fixtures/google/notifications/new-order-notification.xml +85 -0
- data/spec/fixtures/google/notifications/order-state-change-notification.xml +11 -0
- data/spec/fixtures/google/notifications/refund-amount-notification.xml +8 -0
- data/spec/fixtures/google/notifications/risk-information-notification.xml +23 -0
- data/spec/fixtures/google/responses/checkout-redirect.xml +5 -0
- data/spec/fixtures/google/responses/error.xml +5 -0
- data/spec/fixtures/google/responses/request-received.xml +3 -0
- data/spec/google-checkout/cart_spec.rb +165 -0
- data/spec/google-checkout/command_spec.rb +131 -0
- data/spec/google-checkout/notification_spec.rb +181 -0
- data/spec/google-checkout/response_spec.rb +49 -0
- data/spec/google-checkout_spec.rb +15 -0
- data/spec/spec_helper.rb +47 -0
- data/support/cacert.pem +7815 -0
- metadata +203 -0
@@ -0,0 +1,226 @@
|
|
1
|
+
|
2
|
+
module GoogleCheckout
|
3
|
+
|
4
|
+
##
|
5
|
+
# Base notification class. Parses incoming XML and returns a class
|
6
|
+
# matching the kind of notification being received.
|
7
|
+
#
|
8
|
+
# This makes it easy to handle events in your code.
|
9
|
+
#
|
10
|
+
# notification = GoogleCheckout::Notification.parse(request.raw_post)
|
11
|
+
# case notification
|
12
|
+
# when GoogleCheckout::NewOrderNotification
|
13
|
+
# do_something_with_new_order
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# TODO Document field access and Nokogiri object access.
|
17
|
+
#
|
18
|
+
# For the details, see http://code.google.com/apis/checkout/developer/index.html
|
19
|
+
|
20
|
+
class Notification
|
21
|
+
|
22
|
+
# The Nokogiri XML document received from Google.
|
23
|
+
attr_accessor :doc
|
24
|
+
|
25
|
+
##
|
26
|
+
# The entry point for notifications.
|
27
|
+
#
|
28
|
+
# Returns a corresponding notification object based on
|
29
|
+
# the XML received.
|
30
|
+
|
31
|
+
def self.parse(raw_xml)
|
32
|
+
doc = Nokogiri::XML(raw_xml)
|
33
|
+
|
34
|
+
# Convert +request-received+ to +request_received+,
|
35
|
+
# then to a +RequestReceived+ object of the proper class
|
36
|
+
# which will be created and returned.
|
37
|
+
inflector_klass = Inflector rescue nil
|
38
|
+
if inflector_klass.nil?
|
39
|
+
inflector_klass = ActiveSupport::Inflector
|
40
|
+
end
|
41
|
+
const_name = inflector_klass.camelize(doc.root.name.gsub('-', '_'))
|
42
|
+
if GoogleCheckout.const_get(const_name)
|
43
|
+
return GoogleCheckout.const_get(const_name).new(doc)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(doc) # :nodoc:
|
48
|
+
@doc = doc
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Returns the financial-order-state (or new-financial-order-state).
|
53
|
+
#
|
54
|
+
# This is a shortcut since this state will be accessed frequently.
|
55
|
+
#
|
56
|
+
# The fulfillment-order-state (and variations) can be accessed
|
57
|
+
# with the more explicit syntax:
|
58
|
+
#
|
59
|
+
# notification.fulfillment_order_state
|
60
|
+
#
|
61
|
+
# The following is from http://code.google.com/apis/checkout/developer/index.html
|
62
|
+
#
|
63
|
+
# The <financial-order-state> tag identifies the financial status of an order. Valid values for this tag are:
|
64
|
+
#
|
65
|
+
# REVIEWING - Google Checkout is reviewing the order.
|
66
|
+
# CHARGEABLE - The order is ready to be charged.
|
67
|
+
# CHARGING - The order is being charged; you may not refund or cancel an
|
68
|
+
# order until is the charge is completed.
|
69
|
+
# CHARGED - The order has been successfully charged; if the order was
|
70
|
+
# only partially charged, the buyer's account page will
|
71
|
+
# reflect the partial charge.
|
72
|
+
# PAYMENT_DECLINED - The charge attempt failed.
|
73
|
+
# CANCELLED - The seller canceled the order; an order's financial state
|
74
|
+
# cannot be changed after the order is canceled.
|
75
|
+
# CANCELLED_BY_GOOGLE - Google canceled the order. Google may cancel
|
76
|
+
# orders due to a failed charge without a replacement credit
|
77
|
+
# card being provided within a set period of time or due to a
|
78
|
+
# failed risk check. If Google cancels an order, you will be
|
79
|
+
# notified of the reason the order was canceled in the <reason>
|
80
|
+
# tag of an <order-state-change-notification>.
|
81
|
+
#
|
82
|
+
# Please see the Order States section for more information about these states.
|
83
|
+
|
84
|
+
def state
|
85
|
+
if (@doc.at 'financial-order-state')
|
86
|
+
return (@doc/'financial-order-state').inner_html
|
87
|
+
elsif (@doc.at 'new-financial-order-state')
|
88
|
+
return (@doc/'new-financial-order-state').inner_html
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Returns the serial number from the root element.
|
94
|
+
|
95
|
+
def serial_number
|
96
|
+
doc.root['serial-number']
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# Returns an XML string that can be sent back to Google to
|
101
|
+
# communicate successful receipt of the notification.
|
102
|
+
|
103
|
+
def acknowledgment_xml
|
104
|
+
xml = Builder::XmlMarkup.new
|
105
|
+
xml.instruct!
|
106
|
+
@xml = xml.tag!('notification-acknowledgment', {
|
107
|
+
:xmlns => "http://checkout.google.com/schema/2"
|
108
|
+
})
|
109
|
+
@xml
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Returns true if this is a GoogleCheckout::Error object.
|
114
|
+
|
115
|
+
def error?
|
116
|
+
self.class == GoogleCheckout::Error
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Take requests for an XML element and returns its value.
|
121
|
+
#
|
122
|
+
# notification.google_order_number
|
123
|
+
# => Returns value of '<google-order-number>'
|
124
|
+
#
|
125
|
+
# Because of how Nokogiri#at works, it will even dig into subtags
|
126
|
+
# and return the value of the first matching tag. For example,
|
127
|
+
# there is an +email+ field in +buyer-shipping-address+ and also
|
128
|
+
# in +buyer-billing-address+, but only the first will be returned.
|
129
|
+
#
|
130
|
+
# If you want to get at a value explicitly, use +notification.doc+
|
131
|
+
# and search the Nokogiri document manually.
|
132
|
+
|
133
|
+
def method_missing(method_name, *args)
|
134
|
+
element_name = method_name.to_s.gsub(/_/, '-')
|
135
|
+
if element = (@doc.at element_name)
|
136
|
+
if element.respond_to?(:inner_html)
|
137
|
+
return element.inner_html
|
138
|
+
end
|
139
|
+
end
|
140
|
+
super
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
class AuthorizationAmountNotification < Notification; end
|
146
|
+
|
147
|
+
class ChargeAmountNotification < Notification
|
148
|
+
|
149
|
+
def latest_charge_amount
|
150
|
+
(@doc/"latest-charge-amount").to_money
|
151
|
+
end
|
152
|
+
|
153
|
+
def total_charge_amount
|
154
|
+
(@doc/"total-charge-amount").to_money
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
class ChargebackAmountNotification < Notification
|
160
|
+
|
161
|
+
def latest_chargeback_amount
|
162
|
+
(@doc/"latest-chargeback-amount").to_money
|
163
|
+
end
|
164
|
+
|
165
|
+
def total_chargeback_amount
|
166
|
+
(@doc/"total-chargeback-amount").to_money
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
class NewOrderNotification < Notification
|
172
|
+
|
173
|
+
##
|
174
|
+
# Returns a Money object representing the total price of the order.
|
175
|
+
|
176
|
+
def order_total
|
177
|
+
(@doc/"order-total").to_money
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Returns a Money object representing the total tax added.
|
182
|
+
|
183
|
+
def total_tax
|
184
|
+
(@doc/"total-tax").to_money
|
185
|
+
end
|
186
|
+
|
187
|
+
##
|
188
|
+
# Returns true if the buyer wants to received marketing emails.
|
189
|
+
|
190
|
+
def email_allowed
|
191
|
+
(@doc/"buyer-marketing-preferences"/"email-allowed").to_boolean
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
class OrderStateChangeNotification < Notification; end
|
197
|
+
|
198
|
+
class RefundAmountNotification < Notification; end
|
199
|
+
|
200
|
+
class RiskInformationNotification < Notification; end
|
201
|
+
|
202
|
+
class CheckoutRedirect < Notification
|
203
|
+
|
204
|
+
##
|
205
|
+
# Returns redirect-url with ampersands escaped, as specified by Google API docs.
|
206
|
+
|
207
|
+
def redirect_url
|
208
|
+
(@doc/"redirect-url").inner_html.gsub(/&/, '&')
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
class Error < Notification
|
214
|
+
|
215
|
+
##
|
216
|
+
# Alias for +error_message+
|
217
|
+
|
218
|
+
def message
|
219
|
+
(@doc/'error-message').inner_html
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
class RequestReceived < Notification; end
|
225
|
+
|
226
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2">
|
3
|
+
<shopping-cart>
|
4
|
+
<items>
|
5
|
+
<item>
|
6
|
+
<item-name>HelloWorld 2GB MP3 Player</item-name>
|
7
|
+
<item-description>HelloWorld, the simple MP3 player</item-description>
|
8
|
+
<unit-price currency="USD">159.99</unit-price>
|
9
|
+
<quantity>1</quantity>
|
10
|
+
</item>
|
11
|
+
</items>
|
12
|
+
</shopping-cart>
|
13
|
+
<checkout-flow-support>
|
14
|
+
<merchant-checkout-flow-support>
|
15
|
+
<shipping-methods>
|
16
|
+
<flat-rate-shipping name="SuperShip Ground">
|
17
|
+
<price currency="USD">9.99</price>
|
18
|
+
</flat-rate-shipping>
|
19
|
+
</shipping-methods>
|
20
|
+
</merchant-checkout-flow-support>
|
21
|
+
</checkout-flow-support>
|
22
|
+
</checkout-shopping-cart>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<add-tracking-data xmlns="http://checkout.google.com/schema/2"
|
3
|
+
google-order-number="841171949013218">
|
4
|
+
<tracking-data>
|
5
|
+
<carrier>UPS</carrier>
|
6
|
+
<tracking-number>Z9842W69871281267</tracking-number>
|
7
|
+
</tracking-data>
|
8
|
+
</add-tracking-data>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<deliver-order xmlns="http://checkout.google.com/schema/2"
|
3
|
+
google-order-number="841171949013218">
|
4
|
+
<tracking-data>
|
5
|
+
<carrier>UPS</carrier>
|
6
|
+
<tracking-number>Z5498W45987123684</tracking-number>
|
7
|
+
</tracking-data>
|
8
|
+
<send-email>false</send-email>
|
9
|
+
</deliver-order>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<refund-order xmlns="http://checkout.google.com/schema/2" google-order-number="6014423719">
|
3
|
+
<amount currency="USD">15.00</amount>
|
4
|
+
<comment>Discount for inconvenience; ship replacement item</comment>
|
5
|
+
<reason>Damaged Merchandise</reason>
|
6
|
+
</refund-order>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<send-buyer-message xmlns="http://checkout.google.com/schema/2"
|
3
|
+
google-order-number="841171949013218">
|
4
|
+
<message>Due to high volume, your order will ship
|
5
|
+
next week. Thank you for your patience.</message>
|
6
|
+
<send-email>true</send-email>
|
7
|
+
</send-buyer-message>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<authorization-amount-notification xmlns="http://checkout.google.com/schema/2"
|
3
|
+
serial-number="bea6bc1b-e1e2-44fe-80ff-0180e33a2614">
|
4
|
+
<google-order-number>841171949013218</google-order-number>
|
5
|
+
<authorization-amount currency="USD">226.06</authorization-amount>
|
6
|
+
<authorization-expiration-date>2006-03-18T20:25:31</authorization-expiration-date>
|
7
|
+
<avs-response>Y</avs-response>
|
8
|
+
<cvn-response>Y</cvn-response>
|
9
|
+
<timestamp>2006-03-18T20:25:31</timestamp>
|
10
|
+
</authorization-amount-notification>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<charge-amount-notification xmlns="http://checkout.google.com/schema/2"
|
3
|
+
serial-number="bea6bc1b-e1e2-44fe-80ff-0180e33a2614">
|
4
|
+
<google-order-number>841171949013218</google-order-number>
|
5
|
+
<latest-charge-amount currency="USD">226.06</latest-charge-amount>
|
6
|
+
<total-charge-amount currency="USD">226.06</total-charge-amount>
|
7
|
+
<timestamp>2006-03-18T18:25:31</timestamp>
|
8
|
+
</charge-amount-notification>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<chargeback-amount-notification xmlns="http://checkout.google.com/schema/2"
|
3
|
+
serial-number="bea6bc1b-e1e2-44fe-80ff-0180e33a2614">
|
4
|
+
<google-order-number>841171949013218</google-order-number>
|
5
|
+
<latest-chargeback-amount currency="USD">226.06</latest-chargeback-amount>
|
6
|
+
<total-chargeback-amount currency="USD">226.06</total-chargeback-amount>
|
7
|
+
<timestamp>2006-03-18T20:25:31</timestamp>
|
8
|
+
</chargeback-amount-notification>
|
@@ -0,0 +1,85 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<new-order-notification xmlns="http://checkout.google.com/schema/2"
|
3
|
+
serial-number="bea6bc1b-e1e2-44fe-80ff-0180e33a2614">
|
4
|
+
<google-order-number>841171949013218</google-order-number>
|
5
|
+
<buyer-shipping-address>
|
6
|
+
|
7
|
+
<contact-name>John Smith</contact-name>
|
8
|
+
<email>johnsmith@example.com</email>
|
9
|
+
<address1>10 Example Road</address1>
|
10
|
+
<city>Sampleville</city>
|
11
|
+
<region>CA</region>
|
12
|
+
<postal-code>94141</postal-code>
|
13
|
+
<country-code>US</country-code>
|
14
|
+
</buyer-shipping-address>
|
15
|
+
<buyer-billing-address>
|
16
|
+
<contact-name>Bill Hu</contact-name>
|
17
|
+
<email>billhu@example.com</email>
|
18
|
+
<address1>99 Credit Lane</address1>
|
19
|
+
<city>Mountain View</city>
|
20
|
+
<region>CA</region>
|
21
|
+
<postal-code>94043</postal-code>
|
22
|
+
<country-code>US</country-code>
|
23
|
+
</buyer-billing-address>
|
24
|
+
<buyer-id>294873009217523</buyer-id>
|
25
|
+
<fulfillment-order-state>NEW</fulfillment-order-state>
|
26
|
+
<financial-order-state>REVIEWING</financial-order-state>
|
27
|
+
|
28
|
+
<shopping-cart>
|
29
|
+
<cart-expiration>
|
30
|
+
<good-until-date>2007-12-31T23:59:59-05:00</good-until-date>
|
31
|
+
</cart-expiration>
|
32
|
+
<items>
|
33
|
+
<item>
|
34
|
+
<merchant-item-id>GGLAA1453</merchant-item-id>
|
35
|
+
<item-name>Dry Food Pack</item-name>
|
36
|
+
<item-description>One pack of nutritious dried food for emergencies.</item-description>
|
37
|
+
<quantity>1</quantity>
|
38
|
+
<tax-table-selector>food</tax-table-selector>
|
39
|
+
<unit-price currency="USD">4.99</unit-price>
|
40
|
+
</item>
|
41
|
+
<item>
|
42
|
+
<merchant-item-id>MGS2GBMP3</merchant-item-id>
|
43
|
+
<item-name>Megasound 2GB MP3 Player</item-name>
|
44
|
+
<item-description>This portable MP3 player stores 500 songs.</item-description>
|
45
|
+
<quantity>1</quantity>
|
46
|
+
<unit-price currency="USD">179.99</unit-price>
|
47
|
+
<merchant-private-item-data>
|
48
|
+
<merchant-product-id>1234567890</merchant-product-id>
|
49
|
+
</merchant-private-item-data>
|
50
|
+
</item>
|
51
|
+
</items>
|
52
|
+
<merchant-private-data>
|
53
|
+
<peepcode-order-number>1234-5678-9012</peepcode-order-number>
|
54
|
+
</merchant-private-data>
|
55
|
+
</shopping-cart>
|
56
|
+
<order-adjustment>
|
57
|
+
<merchant-calculation-successful>true</merchant-calculation-successful>
|
58
|
+
<merchant-codes>
|
59
|
+
<coupon-adjustment>
|
60
|
+
<applied-amount currency="USD">5.00</applied-amount>
|
61
|
+
<code>FirstVisitCoupon</code>
|
62
|
+
<calculated-amount currency="USD">5.00</calculated-amount>
|
63
|
+
<message>You saved $5.00 for your first visit!</message>
|
64
|
+
</coupon-adjustment>
|
65
|
+
<gift-certificate-adjustment>
|
66
|
+
<applied-amount currency="USD">10.00</applied-amount>
|
67
|
+
<code>GiftCert12345</code>
|
68
|
+
<calculated-amount currency="USD">10.00</calculated-amount>
|
69
|
+
<message>You saved $10.00 with this gift certificate!</message>
|
70
|
+
</gift-certificate-adjustment>
|
71
|
+
</merchant-codes>
|
72
|
+
<total-tax currency="USD">0.0</total-tax>
|
73
|
+
<shipping>
|
74
|
+
<merchant-calculated-shipping-adjustment>
|
75
|
+
<shipping-name>SuperShip</shipping-name>
|
76
|
+
<shipping-cost currency="USD">9.95</shipping-cost>
|
77
|
+
</merchant-calculated-shipping-adjustment>
|
78
|
+
</shipping>
|
79
|
+
</order-adjustment>
|
80
|
+
<order-total currency="USD">190.98</order-total>
|
81
|
+
<buyer-marketing-preferences>
|
82
|
+
<email-allowed>false</email-allowed>
|
83
|
+
</buyer-marketing-preferences>
|
84
|
+
<timestamp>2006-05-03T17:32:11</timestamp>
|
85
|
+
</new-order-notification>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<order-state-change-notification xmlns="http://checkout.google.com/schema/2"
|
3
|
+
serial-number="bea6bc1b-e1e2-44fe-80ff-0180e33a2614">
|
4
|
+
<google-order-number>841171949013218</google-order-number>
|
5
|
+
<new-financial-order-state>CHARGING</new-financial-order-state>
|
6
|
+
<new-fulfillment-order-state>NEW</new-fulfillment-order-state>
|
7
|
+
<previous-financial-order-state>CHARGEABLE</previous-financial-order-state>
|
8
|
+
<previous-fulfillment-order-state>NEW</previous-fulfillment-order-state>
|
9
|
+
<reason>The reason goes here, if there is one.</reason>
|
10
|
+
<timestamp>2006-05-03T17:32:11</timestamp>
|
11
|
+
</order-state-change-notification>
|