google4r-checkout 1.1.6 → 1.2.0
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.
- 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:
|