codehog-google-checkout 1

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.
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>