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 CHANGED
@@ -1,5 +1,9 @@
1
1
  =google4r-checkout Changelog
2
2
 
3
+ == 1.2.0 (2013-04-09)
4
+
5
+ * Support for the Polling API, contributed by Chance Downs and Jacob Comer
6
+
3
7
  == 1.1.6 (2012-08-01)
4
8
 
5
9
  * Bugfixes when creating recurring subscriptions parsed from XML, contributed by James Martin
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
- # Uncomment the following line if you are using Google Checkout in Great Britain
38
- # and adjust it if you want to test google4r-checkout against any other (future)
39
- # Google Checkout service.
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
- # Money.default_currency = 'GBP'
42
-
43
- # The test configuration for the Google4R::Checkout::Frontend class.
44
- FRONTEND_CONFIGURATION =
45
- {
46
- :merchant_id => '<your merchant id>',
47
- :merchant_key => '<your merchant key>',
48
- :use_sandbox => true
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
- # Create the Frontend from our configuration
58
- frontend = Google4R::Checkout::Frontend.new(
59
- :merchant_id => conf['merchant_id'],
60
- :merchant_key => conf['merchant_key'],
61
- :use_sandbox => conf['use_sandbox']
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
- # Create a new checkout command (to place an order)
65
- cmd = frontend.create_checkout_command
67
+ # Create a new checkout command (to place an order)
68
+ cmd = frontend.create_checkout_command
66
69
 
67
- # Add an item to the command's shopping cart
68
- cmd.shopping_cart.create_item do |item|
69
- item.name = "2-liter bottle of Diet Pepsi"
70
- item.quantity = 100
71
- item.unit_price = Money.new(1.99, "USD")
72
- end
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
- # Send the command to Google and capture the HTTP response
75
- response = cmd.send_to_google_checkout
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
- # Redirect the user to Google Checkout to complete the transaction
78
- redirect_to response.redirect_url
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
- class PaymentNotificationController < ApplicationController
91
- before_filter :verify_merchant_credentials, :only => [:google]
102
+ ```ruby
103
+ class PaymentNotificationController < ApplicationController
104
+ before_filter :verify_merchant_credentials, :only => [:google]
92
105
 
93
- def google
94
- frontend = Google4R::Checkout::Frontend.new(
95
- :merchant_id => conf['merchant_id'],
96
- :merchant_key => conf['merchant_key'],
97
- :use_sandbox => conf['use_sandbox']
98
- )
99
- handler = frontend.create_notification_handler
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
- notification_acknowledgement = Google4R::Checkout::NotificationAcknowledgement.new(notification)
124
- render :xml => notification_acknowledgement, :status => 200
125
- end
126
-
127
- private
128
- # make sure the request authentication headers use the right merchant_id and merchant_key
129
- def verify_merchant_credentials
130
- authenticate_or_request_with_http_basic("Google Checkout notification endpoint") do |merchant_id, merchant_key|
131
- (conf['merchant_id'].to_s == merchant_id.to_s) and (conf['merchant_key'].to_s == merchant_key.to_s)
132
- end
133
- end
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
@@ -774,7 +774,6 @@ module Google4R #:nodoc:
774
774
  # ignore
775
775
  end
776
776
  end
777
-
778
777
  return result
779
778
  end
780
779
  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
@@ -37,6 +37,7 @@ Bundler.setup(:default, :test)
37
37
 
38
38
  require 'mocha'
39
39
  require 'nokogiri'
40
+ require 'pry'
40
41
 
41
42
  class Array
42
43
  # Returns the "power set" for this Array. This means that an array with all
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: 2012-08-01 00:00:00.000000000 Z
24
+ date: 2013-04-09 00:00:00.000000000 Z
23
25
  dependencies:
24
26
  - !ruby/object:Gem::Dependency
25
- name: money
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
- version_requirements: !ruby/object:Gem::Requirement
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
- version_requirements: !ruby/object:Gem::Requirement
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
- version_requirements: !ruby/object:Gem::Requirement
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
- version_requirements: !ruby/object:Gem::Requirement
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: