google4r-checkout 1.1.6 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +4 -0
- data/README.md +86 -72
- data/lib/google4r/checkout/commands.rb +62 -0
- data/lib/google4r/checkout/frontend.rb +8 -0
- data/lib/google4r/checkout/notifications.rb +0 -1
- data/lib/google4r/checkout/xml_generation.rb +40 -0
- data/test/test_helper.rb +1 -0
- metadata +39 -22
data/CHANGES
CHANGED
data/README.md
CHANGED
@@ -34,19 +34,21 @@ You have to place a file called 'frontend_configuration.rb' in the directory'tes
|
|
34
34
|
|
35
35
|
The file should contain content similar to:
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
```ruby
|
38
|
+
# Uncomment the following line if you are using Google Checkout in Great Britain
|
39
|
+
# and adjust it if you want to test google4r-checkout against any other (future)
|
40
|
+
# Google Checkout service.
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
# Money.default_currency = 'GBP'
|
43
|
+
|
44
|
+
# The test configuration for the Google4R::Checkout::Frontend class.
|
45
|
+
FRONTEND_CONFIGURATION =
|
46
|
+
{
|
47
|
+
:merchant_id => '<your merchant id>',
|
48
|
+
:merchant_key => '<your merchant key>',
|
49
|
+
:use_sandbox => true
|
50
|
+
}
|
51
|
+
```
|
50
52
|
|
51
53
|
## Sending Commands to Google Checkout
|
52
54
|
|
@@ -54,28 +56,38 @@ To send commands to Google Checkout, use a Google4R::Checkout::Frontend object.
|
|
54
56
|
|
55
57
|
Here's an example:
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
```ruby
|
60
|
+
# Create the Frontend from our configuration
|
61
|
+
frontend = Google4R::Checkout::Frontend.new(
|
62
|
+
:merchant_id => conf['merchant_id'],
|
63
|
+
:merchant_key => conf['merchant_key'],
|
64
|
+
:use_sandbox => conf['use_sandbox']
|
65
|
+
)
|
63
66
|
|
64
|
-
|
65
|
-
|
67
|
+
# Create a new checkout command (to place an order)
|
68
|
+
cmd = frontend.create_checkout_command
|
66
69
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
70
|
+
# Add an item to the command's shopping cart
|
71
|
+
cmd.shopping_cart.create_item do |item|
|
72
|
+
item.name = "2-liter bottle of Diet Pepsi"
|
73
|
+
item.quantity = 100
|
74
|
+
item.unit_price = Money.new(1.99, "USD")
|
75
|
+
end
|
73
76
|
|
74
|
-
|
75
|
-
|
77
|
+
# Send the command to Google and capture the HTTP response
|
78
|
+
begin
|
79
|
+
response = cmd.send_to_google_checkout
|
80
|
+
rescue Net::HTTPServerError => e
|
81
|
+
# Sometimes Google Checkout is unavailable for internal reasons.
|
82
|
+
# Because of this, it's a good idea to catch Net::HTTPServerError
|
83
|
+
# and retry.
|
84
|
+
|
85
|
+
response = cmd.send_to_google_checkout
|
86
|
+
end
|
76
87
|
|
77
|
-
|
78
|
-
|
88
|
+
# Redirect the user to Google Checkout to complete the transaction
|
89
|
+
redirect_to response.redirect_url
|
90
|
+
```
|
79
91
|
|
80
92
|
For more information, see the Frontend class's RDocs and the Google Checkout API documentation.
|
81
93
|
|
@@ -87,51 +99,53 @@ It's a good idea to verify the HTTP authentication headers for incoming requests
|
|
87
99
|
|
88
100
|
Here is an example of how one might do this in Rails:
|
89
101
|
|
90
|
-
|
91
|
-
|
102
|
+
```ruby
|
103
|
+
class PaymentNotificationController < ApplicationController
|
104
|
+
before_filter :verify_merchant_credentials, :only => [:google]
|
92
105
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
begin
|
102
|
-
notification = handler.handle(request.raw_post) # raw_post contains the XML
|
103
|
-
rescue Google4R::Checkout::UnknownNotificationType
|
104
|
-
# This can happen if Google adds new commands and Google4R has not been
|
105
|
-
# upgraded yet. It is not fatal.
|
106
|
-
logger.warn "Unknown notification type"
|
107
|
-
return render :text => 'ignoring unknown notification type', :status => 200
|
108
|
-
end
|
109
|
-
|
110
|
-
case notification
|
111
|
-
when Google4R::Checkout::NewOrderNotification then
|
112
|
-
|
113
|
-
# handle a NewOrderNotification
|
114
|
-
|
115
|
-
when Google4R::Checkout::OrderStateChangeNotification then
|
116
|
-
|
117
|
-
# handle an OrderStateChangeNotification
|
118
|
-
|
119
|
-
else
|
120
|
-
return head :text => "I don't know how to handle a #{notification.class}", :status => 500
|
121
|
-
end
|
106
|
+
def google
|
107
|
+
frontend = Google4R::Checkout::Frontend.new(
|
108
|
+
:merchant_id => conf['merchant_id'],
|
109
|
+
:merchant_key => conf['merchant_key'],
|
110
|
+
:use_sandbox => conf['use_sandbox']
|
111
|
+
)
|
112
|
+
handler = frontend.create_notification_handler
|
122
113
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
114
|
+
begin
|
115
|
+
notification = handler.handle(request.raw_post) # raw_post contains the XML
|
116
|
+
rescue Google4R::Checkout::UnknownNotificationType
|
117
|
+
# This can happen if Google adds new commands and Google4R has not been
|
118
|
+
# upgraded yet. It is not fatal.
|
119
|
+
logger.warn "Unknown notification type"
|
120
|
+
return render :text => 'ignoring unknown notification type', :status => 200
|
121
|
+
end
|
122
|
+
|
123
|
+
case notification
|
124
|
+
when Google4R::Checkout::NewOrderNotification then
|
125
|
+
|
126
|
+
# handle a NewOrderNotification
|
127
|
+
|
128
|
+
when Google4R::Checkout::OrderStateChangeNotification then
|
129
|
+
|
130
|
+
# handle an OrderStateChangeNotification
|
131
|
+
|
132
|
+
else
|
133
|
+
return head :text => "I don't know how to handle a #{notification.class}", :status => 500
|
134
|
+
end
|
135
|
+
|
136
|
+
notification_acknowledgement = Google4R::Checkout::NotificationAcknowledgement.new(notification)
|
137
|
+
render :xml => notification_acknowledgement.to_xml, :status => 200
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
# make sure the request authentication headers use the right merchant_id and merchant_key
|
142
|
+
def verify_merchant_credentials
|
143
|
+
authenticate_or_request_with_http_basic("Google Checkout notification endpoint") do |merchant_id, merchant_key|
|
144
|
+
(conf['merchant_id'].to_s == merchant_id.to_s) and (conf['merchant_key'].to_s == merchant_key.to_s)
|
134
145
|
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
```
|
135
149
|
|
136
150
|
## Dependencies
|
137
151
|
|
@@ -50,6 +50,7 @@ module Google4R #:nodoc:
|
|
50
50
|
CHECKOUT_API_URL = 'api/checkout/v2/merchantCheckout/Merchant/%s'
|
51
51
|
ORDER_PROCESSING_API_URL = 'api/checkout/v2/request/Merchant/%s'
|
52
52
|
ORDER_REPORT_API_URL = 'api/checkout/v2/reports/Merchant/%s'
|
53
|
+
POLLING_API_URL = 'api/checkout/v2/reports/Merchant/%s'
|
53
54
|
|
54
55
|
# Donations
|
55
56
|
DONATE_CHECKOUT_API_URL = 'api/checkout/v2/merchantCheckout/Donations/%s'
|
@@ -108,6 +109,8 @@ module Google4R #:nodoc:
|
|
108
109
|
CHECKOUT_API_URL
|
109
110
|
elsif self.class == OrderReportCommand || self.class == NotificationHistoryRequestCommand then
|
110
111
|
ORDER_REPORT_API_URL
|
112
|
+
elsif self.class == NotificationDataRequestCommand || self.class == NotificationDataTokenRequestCommand then
|
113
|
+
POLLING_API_URL
|
111
114
|
else
|
112
115
|
ORDER_PROCESSING_API_URL
|
113
116
|
end
|
@@ -189,6 +192,33 @@ module Google4R #:nodoc:
|
|
189
192
|
end
|
190
193
|
end
|
191
194
|
{ :notifications => notifications, :next_page_token => next_page_token }
|
195
|
+
when 'notification-data-token-response'
|
196
|
+
serial_number = xml_doc.elements['/notification-data-token-response'].attributes['serial-number']
|
197
|
+
continue_token = xml_doc.root.elements['continue-token/text()'].value
|
198
|
+
{ :continue_token => continue_token, :serial_number => serial_number}
|
199
|
+
when 'notification-data-response'
|
200
|
+
serial_number = xml_doc.elements['/notification-data-response'].attributes['serial-number']
|
201
|
+
continue_token = xml_doc.root.elements['continue-token/text()'].value
|
202
|
+
has_more_notifications = xml_doc.root.elements['has-more-notifications/text()'].value
|
203
|
+
notifications = xml_doc.root.elements['notifications'].elements.map do |element|
|
204
|
+
case element.name
|
205
|
+
when 'new-order-notification'
|
206
|
+
NewOrderNotification.create_from_element element, @frontend
|
207
|
+
when 'risk-information-notification'
|
208
|
+
RiskInformationNotification.create_from_element element, @frontend
|
209
|
+
when 'order-state-change-notification'
|
210
|
+
OrderStateChangeNotification.create_from_element element, @frontend
|
211
|
+
when 'charge-amount-notification'
|
212
|
+
ChargeAmountNotification.create_from_element element, @frontend
|
213
|
+
when 'authorization-amount-notification'
|
214
|
+
AuthorizationAmountNotification.create_from_element element, @frontend
|
215
|
+
when 'refund-amount-notification'
|
216
|
+
RefundAmountNotification.create_from_element element, @frontend
|
217
|
+
when 'chargeback-amount-notification'
|
218
|
+
ChargebackAmountNotification.create_from_element element, @frontend
|
219
|
+
end
|
220
|
+
end
|
221
|
+
{ :notifications => notifications, :continue_token => continue_token, :serial_number => serial_number, :has_more_notifications => has_more_notifications }
|
192
222
|
else
|
193
223
|
raise "Unknown response:\n--\n#{xml_doc.to_s}\n--"
|
194
224
|
end
|
@@ -741,5 +771,37 @@ module Google4R #:nodoc:
|
|
741
771
|
NotificationHistoryReportCommandXmlGenerator.new(self).generate
|
742
772
|
end
|
743
773
|
end
|
774
|
+
|
775
|
+
|
776
|
+
class NotificationDataRequestCommand < Command
|
777
|
+
|
778
|
+
attr_reader :continue_token
|
779
|
+
|
780
|
+
def initialize(frontend, continue_token)
|
781
|
+
super frontend
|
782
|
+
|
783
|
+
@continue_token = continue_token
|
784
|
+
end
|
785
|
+
|
786
|
+
def to_xml
|
787
|
+
NotificationDataRequestCommandXmlGenerator.new(self).generate
|
788
|
+
end
|
789
|
+
end
|
790
|
+
|
791
|
+
|
792
|
+
class NotificationDataTokenRequestCommand < Command
|
793
|
+
# The earliest time that an order could have been submitted to be
|
794
|
+
# included in the API response (Time)
|
795
|
+
attr_reader :start_time
|
796
|
+
|
797
|
+
def initialize(frontend, options = {})
|
798
|
+
super frontend
|
799
|
+
@start_time = options[:start_time] if options.has_key?(:start_time)
|
800
|
+
end
|
801
|
+
|
802
|
+
def to_xml
|
803
|
+
NotificationDataTokenRequestCommandXmlGenerator.new(self).generate
|
804
|
+
end
|
805
|
+
end
|
744
806
|
end
|
745
807
|
end
|
@@ -235,6 +235,14 @@ module Google4R #:nodoc:
|
|
235
235
|
def create_notification_history_request_command(serial_number)
|
236
236
|
return NotificationHistoryRequestCommand.new(self, serial_number)
|
237
237
|
end
|
238
|
+
|
239
|
+
def create_notification_data_request_command(continue_token)
|
240
|
+
return NotificationDataRequestCommand.new(self, continue_token)
|
241
|
+
end
|
242
|
+
|
243
|
+
def create_notification_data_token_request_command(options={})
|
244
|
+
return NotificationDataTokenRequestCommand.new(self, options)
|
245
|
+
end
|
238
246
|
end
|
239
247
|
end
|
240
248
|
end
|
@@ -77,6 +77,8 @@ module Google4R #:nodoc:
|
|
77
77
|
ResetItemsShippingInformationCommand => 'reset-items-shipping-information',
|
78
78
|
OrderReportCommand => 'order-list-request',
|
79
79
|
NotificationHistoryRequestCommand => 'notification-history-request',
|
80
|
+
NotificationDataTokenRequestCommand => 'notification-data-token-request',
|
81
|
+
NotificationDataRequestCommand => 'notification-data-request'
|
80
82
|
}
|
81
83
|
|
82
84
|
def initialize(command)
|
@@ -1070,5 +1072,43 @@ module Google4R #:nodoc:
|
|
1070
1072
|
|
1071
1073
|
end
|
1072
1074
|
end
|
1075
|
+
|
1076
|
+
class NotificationDataRequestCommandXmlGenerator < CommandXmlGenerator
|
1077
|
+
|
1078
|
+
def initialize(command)
|
1079
|
+
@command = command
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
protected
|
1083
|
+
|
1084
|
+
def process_command(command)
|
1085
|
+
root = super
|
1086
|
+
|
1087
|
+
if command.continue_token
|
1088
|
+
element = root.add_element('continue-token')
|
1089
|
+
element.text = command.continue_token
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
class NotificationDataTokenRequestCommandXmlGenerator < CommandXmlGenerator
|
1096
|
+
|
1097
|
+
def initialize(command)
|
1098
|
+
@command = command
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
protected
|
1102
|
+
|
1103
|
+
def process_command(command)
|
1104
|
+
root = super
|
1105
|
+
|
1106
|
+
if command.start_time
|
1107
|
+
element = root.add_element('start-time')
|
1108
|
+
element.text = command.start_time.xmlschema
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
end
|
1112
|
+
end
|
1073
1113
|
end
|
1074
1114
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google4r-checkout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.6
|
5
4
|
prerelease:
|
5
|
+
version: 1.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Tony Chan
|
@@ -16,75 +16,93 @@ authors:
|
|
16
16
|
- Paul Schreiber
|
17
17
|
- Ben Hutton
|
18
18
|
- James Martin
|
19
|
+
- Jacob Comer
|
20
|
+
- Chance Downs
|
19
21
|
autorequire:
|
20
22
|
bindir: bin
|
21
23
|
cert_chain: []
|
22
|
-
date:
|
24
|
+
date: 2013-04-09 00:00:00.000000000 Z
|
23
25
|
dependencies:
|
24
26
|
- !ruby/object:Gem::Dependency
|
25
|
-
|
26
|
-
requirement: !ruby/object:Gem::Requirement
|
27
|
-
none: false
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
28
|
requirements:
|
29
29
|
- - ! '>='
|
30
30
|
- !ruby/object:Gem::Version
|
31
31
|
version: 2.3.0
|
32
|
+
none: false
|
33
|
+
name: money
|
32
34
|
type: :runtime
|
33
35
|
prerelease: false
|
34
|
-
|
35
|
-
none: false
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
36
37
|
requirements:
|
37
38
|
- - ! '>='
|
38
39
|
- !ruby/object:Gem::Version
|
39
40
|
version: 2.3.0
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: mocha
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
43
41
|
none: false
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ! '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
|
+
none: false
|
49
|
+
name: mocha
|
48
50
|
type: :development
|
49
51
|
prerelease: false
|
50
|
-
|
51
|
-
none: false
|
52
|
+
requirement: !ruby/object:Gem::Requirement
|
52
53
|
requirements:
|
53
54
|
- - ! '>='
|
54
55
|
- !ruby/object:Gem::Version
|
55
56
|
version: '0'
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: nokogiri
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
59
57
|
none: false
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
61
|
- - ! '>='
|
62
62
|
- !ruby/object:Gem::Version
|
63
63
|
version: '0'
|
64
|
+
none: false
|
65
|
+
name: nokogiri
|
64
66
|
type: :development
|
65
67
|
prerelease: false
|
66
|
-
|
67
|
-
none: false
|
68
|
+
requirement: !ruby/object:Gem::Requirement
|
68
69
|
requirements:
|
69
70
|
- - ! '>='
|
70
71
|
- !ruby/object:Gem::Version
|
71
72
|
version: '0'
|
73
|
+
none: false
|
72
74
|
- !ruby/object:Gem::Dependency
|
75
|
+
version_requirements: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
none: false
|
73
81
|
name: rake
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
74
84
|
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
75
89
|
none: false
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
76
92
|
requirements:
|
77
93
|
- - ! '>='
|
78
94
|
- !ruby/object:Gem::Version
|
79
95
|
version: '0'
|
96
|
+
none: false
|
97
|
+
name: pry
|
80
98
|
type: :development
|
81
99
|
prerelease: false
|
82
|
-
|
83
|
-
none: false
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
84
101
|
requirements:
|
85
102
|
- - ! '>='
|
86
103
|
- !ruby/object:Gem::Version
|
87
104
|
version: '0'
|
105
|
+
none: false
|
88
106
|
description: ! " google4r-checkout is a lightweight, framework-agnostic Ruby library
|
89
107
|
to access the Google Checkout service and implement \n notification handlers. It
|
90
108
|
exposes object-oriented wrappers for all of Google Checkout's API commands and notifications.\n"
|
@@ -181,17 +199,17 @@ rdoc_options: []
|
|
181
199
|
require_paths:
|
182
200
|
- lib
|
183
201
|
required_ruby_version: !ruby/object:Gem::Requirement
|
184
|
-
none: false
|
185
202
|
requirements:
|
186
203
|
- - ! '>='
|
187
204
|
- !ruby/object:Gem::Version
|
188
205
|
version: 1.8.4
|
189
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
190
206
|
none: false
|
207
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
208
|
requirements:
|
192
209
|
- - ! '>='
|
193
210
|
- !ruby/object:Gem::Version
|
194
211
|
version: '0'
|
212
|
+
none: false
|
195
213
|
requirements: []
|
196
214
|
rubyforge_project:
|
197
215
|
rubygems_version: 1.8.23
|
@@ -265,4 +283,3 @@ test_files:
|
|
265
283
|
- test/unit/us_zip_area_test.rb
|
266
284
|
- test/unit/world_area_test.rb
|
267
285
|
- test/test_helper.rb
|
268
|
-
has_rdoc:
|