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