sumskyi-google-checkout 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/History.txt +14 -0
  2. data/MIT-LICENSE.txt +23 -0
  3. data/Manifest.txt +41 -0
  4. data/README.txt +148 -0
  5. data/Rakefile +34 -0
  6. data/examples/google_notifications_controller.rb +159 -0
  7. data/lib/duck_punches/hpricot.rb +24 -0
  8. data/lib/google-checkout.rb +61 -0
  9. data/lib/google-checkout/cart.rb +351 -0
  10. data/lib/google-checkout/command.rb +191 -0
  11. data/lib/google-checkout/notification.rb +226 -0
  12. data/spec/fixtures/google/checkout-shopping-cart.xml +22 -0
  13. data/spec/fixtures/google/commands/add-merchant-order-number.xml +5 -0
  14. data/spec/fixtures/google/commands/add-tracking-data.xml +8 -0
  15. data/spec/fixtures/google/commands/archive-order.xml +3 -0
  16. data/spec/fixtures/google/commands/authorize-order.xml +2 -0
  17. data/spec/fixtures/google/commands/cancel-order.xml +5 -0
  18. data/spec/fixtures/google/commands/charge-order.xml +4 -0
  19. data/spec/fixtures/google/commands/deliver-order.xml +9 -0
  20. data/spec/fixtures/google/commands/process-order.xml +2 -0
  21. data/spec/fixtures/google/commands/refund-order.xml +6 -0
  22. data/spec/fixtures/google/commands/send-buyer-message.xml +7 -0
  23. data/spec/fixtures/google/commands/unarchive-order.xml +2 -0
  24. data/spec/fixtures/google/notifications/authorization-amount-notification.xml +10 -0
  25. data/spec/fixtures/google/notifications/charge-amount-notification.xml +8 -0
  26. data/spec/fixtures/google/notifications/chargeback-amount-notification.xml +8 -0
  27. data/spec/fixtures/google/notifications/new-order-notification.xml +85 -0
  28. data/spec/fixtures/google/notifications/order-state-change-notification.xml +11 -0
  29. data/spec/fixtures/google/notifications/refund-amount-notification.xml +8 -0
  30. data/spec/fixtures/google/notifications/risk-information-notification.xml +23 -0
  31. data/spec/fixtures/google/responses/checkout-redirect.xml +5 -0
  32. data/spec/fixtures/google/responses/error.xml +5 -0
  33. data/spec/fixtures/google/responses/request-received.xml +3 -0
  34. data/spec/google-checkout/cart_spec.rb +101 -0
  35. data/spec/google-checkout/command_spec.rb +131 -0
  36. data/spec/google-checkout/notification_spec.rb +181 -0
  37. data/spec/google-checkout/response_spec.rb +49 -0
  38. data/spec/google-checkout_spec.rb +15 -0
  39. data/spec/spec_helper.rb +47 -0
  40. data/support/cacert.pem +7815 -0
  41. metadata +140 -0
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <refund-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-refund-amount currency="USD">226.06</latest-refund-amount>
6
+ <total-refund-amount currency="USD">226.06</total-refund-amount>
7
+ <timestamp>2006-03-18T20:25:31</timestamp>
8
+ </refund-amount-notification>
@@ -0,0 +1,23 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <risk-information-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
+ <risk-information>
6
+ <eligible-for-protection>true</eligible-for-protection>
7
+ <billing-address id="BuyerBillingAddress">
8
+ <contact-name>John Smith</contact-name>
9
+ <email>johnsmith@example.com</email>
10
+ <address1>10 Example Road</address1>
11
+ <city>Sampleville</city>
12
+ <region>CA</region>
13
+ <postal-code>94141</postal-code>
14
+ <country-code>US</country-code>
15
+ </billing-address>
16
+ <avs-response>Y</avs-response>
17
+ <cvn-response>M</cvn-response>
18
+ <partial-cc-number>3719</partial-cc-number>
19
+ <ip-address>10.11.12.13</ip-address>
20
+ <buyer-account-age>6</buyer-account-age>
21
+ </risk-information>
22
+ <timestamp>2006-01-15T10:44:06</timestamp>
23
+ </risk-information-notification>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <checkout-redirect xmlns="http://checkout.google.com/schema/2"
3
+ serial-number="bea6bc1b-e1e2-44fe-80ff-0180e33a2614">
4
+ <redirect-url>https://checkout.google.com/buy?foo=bar&amp;id=8572098456</redirect-url>
5
+ </checkout-redirect>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <error xmlns="http://checkout.google.com/schema/2"
3
+ serial-number="bea6bc1b-e1e2-44fe-80ff-0180e33a2614">
4
+ <error-message>Bad username and/or password for API Access.</error-message>
5
+ </error>
@@ -0,0 +1,3 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <request-received xmlns="http://checkout.google.com/schema/2"
3
+ serial-number="bea6bc1b-e1e2-44fe-80ff-0180e33a2614"/>
@@ -0,0 +1,101 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe GoogleCheckout, "Cart (generic)" do
4
+
5
+ before(:each) do
6
+ @cart = GoogleCheckout::Cart.new("my_id", "my_key", {
7
+ :name => "PeepCode Screencast",
8
+ :description => "A few screencasts",
9
+ :price => 9.00
10
+ })
11
+ GoogleCheckout.use_sandbox
12
+ end
13
+
14
+ it "should generate proper live buy button_url" do
15
+ GoogleCheckout.use_production
16
+ @cart.button_url.should match(%r{http://checkout\.google\.com/buttons/buy\.gif})
17
+ end
18
+
19
+ it "should generate proper live checkout button_url" do
20
+ GoogleCheckout.use_production
21
+ @cart.button_url(:buy_or_checkout => :checkout).should match(%r{http://checkout\.google\.com/buttons/checkout\.gif})
22
+ end
23
+
24
+ it "should generate proper sandbox buy button_url" do
25
+ @cart.button_url.should match(%r{http://sandbox\.google\.com/buttons/buy\.gif})
26
+ end
27
+
28
+ it "should generate proper sandbox checkout button_url" do
29
+ @cart.button_url(:buy_or_checkout => :checkout).should match(%r{http://sandbox\.google\.com/checkout/buttons/checkout\.gif})
30
+ end
31
+
32
+ it "should generate checkout button" do
33
+ @cart.checkout_button.should match(/buy\.gif/)
34
+ end
35
+
36
+ end
37
+
38
+ describe GoogleCheckout, "Cart Post" do
39
+
40
+ before(:each) do
41
+ @cart = GoogleCheckout::Cart.new("my_id", "my_key", {
42
+ :name => "PeepCode Screencast",
43
+ :description => "One screencast",
44
+ :price => 9.00
45
+ })
46
+ GoogleCheckout.use_sandbox
47
+ end
48
+
49
+ it "should get merchant_id" do
50
+ @cart.merchant_id.should == 'my_id'
51
+ end
52
+
53
+ it "should get merchant_key" do
54
+ @cart.merchant_key.should == 'my_key'
55
+ end
56
+
57
+ it "should post request to Google" do
58
+ # :null_object means eat all other methods and return self
59
+ net_http = mock("net_http", { :null_object => true })
60
+ Net::HTTP.should_receive(:new).and_return(net_http)
61
+
62
+ success_response = Net::HTTPSuccess.new(Net::HTTP.version_1_2, 200, "OK")
63
+ success_response.should_receive(:body).and_return(read_xml_fixture('responses/checkout-redirect'))
64
+ net_http.should_receive(:request).and_return(success_response)
65
+
66
+ response = @cart.post
67
+ response.should be_kind_of(GoogleCheckout::CheckoutRedirect)
68
+ response.serial_number.should == 'bea6bc1b-e1e2-44fe-80ff-0180e33a2614'
69
+ response.redirect_url.should == 'https://checkout.google.com/buy?foo=bar&id=8572098456'
70
+ end
71
+
72
+ it "should set merchant private data" do
73
+ @cart.merchant_private_data = { "merchant-order-number" => "1234-5678-9012" }
74
+ @cart.merchant_private_data["merchant-order-number"].should == "1234-5678-9012"
75
+ end
76
+
77
+ it "should include merchant private in the generated xml" do
78
+ @cart.merchant_private_data = { "merchant-order-number" => "1234-5678-9012" }
79
+ @cart.to_xml.should match(/<merchant-order-number>1234-5678-9012<\/merchant-order-number>/)
80
+ end
81
+
82
+ it "should not include merchant private data if none is set" do
83
+ @cart.to_xml.should_not match(/<merchant-private-data>/)
84
+ end
85
+
86
+ it "should include merchant-item-id in XML if :item_id was passed with the item" do
87
+ @cart.add_item({
88
+ :name => "Item",
89
+ :description => "Item description",
90
+ :price => "1.00",
91
+ :quantity => 1,
92
+ :item_id => "ITEM-007"
93
+ })
94
+ @cart.to_xml.should match(%r{<merchant-item-id>ITEM-007</merchant-item-id>})
95
+ end
96
+
97
+ it "should generate XML"
98
+
99
+ it "should receive error when placing false request"
100
+
101
+ end
@@ -0,0 +1,131 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe "basic command", :shared => true do
4
+
5
+ it "should include XML header" do
6
+ @order.to_xml.should match(/^<\?xml version=\"1\.0\" encoding=\"UTF-8\"\?>/)
7
+ end
8
+
9
+ end
10
+
11
+ describe GoogleCheckout, "Command class" do
12
+
13
+ it "should read SSL certs" do
14
+ GoogleCheckout::Command.x509_store.should be_kind_of(OpenSSL::X509::Store)
15
+ end
16
+
17
+ end
18
+
19
+ describe GoogleCheckout, "Command instance" do
20
+
21
+ before(:each) do
22
+ @command = GoogleCheckout::Command.new("my_id", "my_key")
23
+ end
24
+
25
+ it "should generate sandbox url" do
26
+ GoogleCheckout.use_sandbox
27
+ @command.url.should match(/sandbox/)
28
+ end
29
+
30
+ it "should generate production url" do
31
+ GoogleCheckout.use_production
32
+ @command.url.should match(/checkout\.google\.com/)
33
+ end
34
+
35
+ end
36
+
37
+ describe GoogleCheckout, "Charge Order" do
38
+
39
+ before(:each) do
40
+ @order = GoogleCheckout::ChargeOrder.new("my_id", "my_key", "1234567890")
41
+ GoogleCheckout.use_sandbox
42
+ @order.amount = 123.45
43
+ end
44
+
45
+ it_should_behave_like "basic command"
46
+
47
+ it "should retrieve order number" do
48
+ @order.google_order_number.should == '1234567890'
49
+ end
50
+
51
+ it "should get merchant_id" do
52
+ @order.merchant_id.should == 'my_id'
53
+ end
54
+
55
+ it "should get merchant_key" do
56
+ @order.merchant_key.should == 'my_key'
57
+ end
58
+
59
+ it "should generate XML" do
60
+ @order.to_xml.should match(/amount currency="USD"/)
61
+ @order.to_xml.should match(/123\.45<\/amount>/)
62
+ end
63
+
64
+ it "should post request to Google successfully" do
65
+ # :null_object means eat all other methods and return self
66
+ net_http = mock("net_http", { :null_object => true })
67
+ Net::HTTP.should_receive(:new).and_return(net_http)
68
+
69
+ success_response = Net::HTTPSuccess.new(Net::HTTP.version_1_2, 200, "OK")
70
+ success_response.should_receive(:body).and_return(read_xml_fixture('responses/request-received'))
71
+ net_http.should_receive(:request).and_return(success_response)
72
+
73
+ response = @order.post
74
+ response.should be_kind_of(GoogleCheckout::RequestReceived)
75
+ response.should_not be_error
76
+ response.serial_number.should == 'bea6bc1b-e1e2-44fe-80ff-0180e33a2614'
77
+ end
78
+
79
+ it "should post request to Google and return error" do
80
+ # :null_object means eat all other methods and return self
81
+ net_http = mock("net_http", { :null_object => true })
82
+ Net::HTTP.should_receive(:new).and_return(net_http)
83
+
84
+ # NOTE HTTP response code is irrelevant here.
85
+ error_response = Net::HTTPSuccess.new(Net::HTTP.version_1_2, 200, "OK")
86
+ error_response.should_receive(:body).and_return(read_xml_fixture('responses/error'))
87
+ net_http.should_receive(:request).and_return(error_response)
88
+
89
+ lambda { @order.post }.should raise_error(GoogleCheckout::APIError)
90
+ end
91
+
92
+ end
93
+
94
+ describe GoogleCheckout, "Checkout API Request (with Cart)" do
95
+
96
+ it "should use HTTP Basic Auth"
97
+
98
+ it "should use proper content type"
99
+
100
+ it "should use proper accept type"
101
+
102
+ it "should report success of request"
103
+
104
+ it "should report error and error message"
105
+
106
+ it "should return redirect url"
107
+
108
+ end
109
+
110
+
111
+ describe GoogleCheckout, "Send Buyer Email" do
112
+
113
+ before(:each) do
114
+ @command = GoogleCheckout::SendBuyerMessage.new("my_id", "my_key", "1234567890", "Thanks for the order!")
115
+ end
116
+
117
+ # <send-buyer-message xmlns="http://checkout.google.com/schema/2"
118
+ # google-order-number="841171949013218">
119
+ # <message>Due to high volume, your order will ship
120
+ # next week. Thank you for your patience.</message>
121
+ # <send-email>true</send-email>
122
+ # </send-buyer-message>
123
+
124
+ it "should post email to the buyer" do
125
+ xml = @command.to_xml
126
+ xml.should match(%r{google-order-number="1234567890"})
127
+ xml.should match(%r{<message>Thanks for the order!</message>})
128
+ xml.should match(%r{<send-email>true</send-email>})
129
+ end
130
+
131
+ end
@@ -0,0 +1,181 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe "basic notification", :shared => true do
4
+
5
+ it "should get serial number" do
6
+ @notification.serial_number.should == 'bea6bc1b-e1e2-44fe-80ff-0180e33a2614'
7
+ end
8
+
9
+ it "should get google order number" do
10
+ @notification.google_order_number.should == '841171949013218'
11
+ end
12
+
13
+ it "should generate acknowledgment XML" do
14
+ @notification.acknowledgment_xml.should match(/notification-acknowledgment/)
15
+ end
16
+
17
+ end
18
+
19
+ describe GoogleCheckout, "New Order Notification" do
20
+
21
+ before(:each) do
22
+ @notification = GoogleCheckout::Notification.parse(read_xml_fixture('notifications/new-order-notification'))
23
+ end
24
+
25
+ it "should identify type of notification" do
26
+ @notification.should be_kind_of(GoogleCheckout::NewOrderNotification)
27
+ end
28
+
29
+ it_should_behave_like "basic notification"
30
+
31
+ it "should find fulfillment order state" do
32
+ @notification.fulfillment_order_state.should == 'NEW'
33
+ end
34
+
35
+ it "should find financial order state" do
36
+ @notification.financial_order_state.should == 'REVIEWING'
37
+ end
38
+
39
+ it "should use financial state shortcut" do
40
+ @notification.state.should == "REVIEWING"
41
+ end
42
+
43
+ it "should create Money object from order total" do
44
+ @notification.order_total.should be_kind_of(Money)
45
+ @notification.order_total.cents.should == 19098
46
+ @notification.order_total.currency.iso_code.should == 'USD'
47
+ end
48
+
49
+ it "should throw error when accessing non-existent value" do
50
+ lambda { @notification.there_is_no_field_with_this_name }.should raise_error(NoMethodError)
51
+ end
52
+
53
+ it "should find sub-keys of merchant-private-data as if they were at the root" do
54
+ @notification.peepcode_order_number.should == '1234-5678-9012'
55
+ end
56
+
57
+ it "should find total tax" do
58
+ @notification.total_tax.should be_kind_of(Money)
59
+ @notification.total_tax.cents.should == 0
60
+ end
61
+
62
+ it "should find email marketing allowed" do
63
+ @notification.email_allowed.should be_false
64
+ end
65
+
66
+ it "should get email or buyer-shipping-address/email or buyer-billing-address/email"
67
+
68
+ end
69
+
70
+
71
+ describe GoogleCheckout, "Order State Change Notification" do
72
+
73
+ before(:each) do
74
+ @notification = GoogleCheckout::Notification.parse(read_xml_fixture('notifications/order-state-change-notification'))
75
+ end
76
+
77
+ it_should_behave_like "basic notification"
78
+
79
+ it "should identify type of notification" do
80
+ @notification.should be_kind_of(GoogleCheckout::OrderStateChangeNotification)
81
+ end
82
+
83
+ it "should find new financial state" do
84
+ @notification.new_financial_order_state.should == 'CHARGING'
85
+ end
86
+
87
+ it "should find new fulfillment state" do
88
+ @notification.new_fulfillment_order_state.should == 'NEW'
89
+ end
90
+
91
+ it "should use financial state shortcut" do
92
+ @notification.state.should == 'CHARGING'
93
+ end
94
+
95
+ end
96
+
97
+ describe GoogleCheckout, "Risk Information Notification" do
98
+
99
+ before(:each) do
100
+ @notification = GoogleCheckout::Notification.parse(read_xml_fixture('notifications/risk-information-notification'))
101
+ end
102
+
103
+ it "should identify type of notification" do
104
+ @notification.should be_kind_of(GoogleCheckout::RiskInformationNotification)
105
+ end
106
+
107
+ it_should_behave_like "basic notification"
108
+
109
+ end
110
+
111
+ describe GoogleCheckout, "Charge Amount Notification" do
112
+
113
+ before(:each) do
114
+ @notification = GoogleCheckout::Notification.parse(read_xml_fixture('notifications/charge-amount-notification'))
115
+ end
116
+
117
+ it_should_behave_like "basic notification"
118
+
119
+ it "should identify type of notification" do
120
+ @notification.should be_kind_of(GoogleCheckout::ChargeAmountNotification)
121
+ end
122
+
123
+ it "should get latest charge amount" do
124
+ @notification.latest_charge_amount.should be_kind_of(Money)
125
+ end
126
+
127
+ it "should get total charge amount" do
128
+ @notification.total_charge_amount.should be_kind_of(Money)
129
+ @notification.total_charge_amount.cents.should == 22606
130
+ end
131
+
132
+ end
133
+
134
+ describe GoogleCheckout, "Authorization Amount Notification" do
135
+
136
+ before(:each) do
137
+ @notification = GoogleCheckout::Notification.parse(read_xml_fixture('notifications/authorization-amount-notification'))
138
+ end
139
+
140
+ it_should_behave_like "basic notification"
141
+
142
+ it "should identify type of notification" do
143
+ @notification.should be_kind_of(GoogleCheckout::AuthorizationAmountNotification)
144
+ end
145
+
146
+ end
147
+
148
+ describe GoogleCheckout, "Chargeback Amount Notification" do
149
+
150
+ before(:each) do
151
+ @notification = GoogleCheckout::Notification.parse(read_xml_fixture('notifications/chargeback-amount-notification'))
152
+ end
153
+
154
+ it_should_behave_like "basic notification"
155
+
156
+ it "identifies type of notification" do
157
+ @notification.should be_kind_of(GoogleCheckout::ChargebackAmountNotification)
158
+ end
159
+
160
+ it "parses chargeback amounts as money objects" do
161
+ @notification.latest_chargeback_amount.cents.should == 22606
162
+ @notification.total_chargeback_amount.cents.should == 22606
163
+ @notification.latest_chargeback_amount.currency.iso_code.should == "USD"
164
+ end
165
+
166
+ end
167
+
168
+ describe GoogleCheckout, "Refund Amount Notification" do
169
+
170
+ before(:each) do
171
+ @notification = GoogleCheckout::Notification.parse(read_xml_fixture('notifications/refund-amount-notification'))
172
+ end
173
+
174
+ it_should_behave_like "basic notification"
175
+
176
+ it "should identify type of notification" do
177
+ @notification.should be_kind_of(GoogleCheckout::RefundAmountNotification)
178
+ end
179
+
180
+ end
181
+