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,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(/&amp;/, '&')
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,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <add-merchant-order-number xmlns="http://checkout.google.com/schema/2"
3
+ google-order-number="841171949013218">
4
+ <merchant-order-number>P6502-53-7861SBJD</merchant-order-number>
5
+ </add-merchant-order-number>
@@ -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,3 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <archive-order xmlns="http://checkout.google.com/schema/2"
3
+ google-order-number="841171949013218" />
@@ -0,0 +1,2 @@
1
+ <authorize-order xmlns="http://checkout.google.com/schema/2"
2
+ google-order-number="6014423719"/>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <cancel-order xmlns="http://checkout.google.com/schema/2" google-order-number="841171949013218">
3
+ <reason>Buyer cancelled the order.</reason>
4
+ <comment>Buyer ordered another item.</comment>
5
+ </cancel-order>
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <charge-order xmlns="http://checkout.google.com/schema/2" google-order-number="6014423719">
3
+ <amount currency="USD">335.55</amount>
4
+ </charge-order>
@@ -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,2 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <process-order xmlns="http://checkout.google.com/schema/2" google-order-number="841171949013218"/>
@@ -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,2 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <unarchive-order xmlns="http://checkout.google.com/schema/2" google-order-number="841171949013218" />
@@ -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>