google4r-checkout 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,9 +1,23 @@
1
1
  = google4r-checkout Changelog
2
2
 
3
- == HEAD
3
+ == 1.0.0 (2007-08-04)
4
4
 
5
- == 0.1.0 (2007-05-12)
5
+ * Added refund-amount-notification
6
+ * Added chargeback-amount-notification
7
+ * Added authorization-amount-notification
8
+ * Added refund command
9
+ * Added authorize command
10
+ * Added add-merchant-number command
11
+ * Added add-tracking-data command
12
+ * Added send-buyer-message command
13
+ * Added archive-order command
14
+ * Added unarchive-order command
15
+ * Refactored to_xml in the Command class
16
+ * Added CommandXmlGenerator base class
17
+ * Added ChargeOrderCommand, DeliverOrderCommand, CancelOrderCommand, ChargeAmountNotification and RiskInfoNotification (all contributed by Dan Dukeson).
18
+ * Attributes are not retrieved via XPaths with "tag/@attribute" any more but with REXML's Element#attributes. This should fix problems with Ruby 1.8.6.
6
19
 
20
+ == 0.1.0 (2007-05-12)
7
21
  * Added property "shipping_taxed" to TaxRule (contributed by Dan Dukeson).
8
22
  * Added XML generation for the tax tables in the shopping cart (contributed by Dan Dukeson).
9
23
  * Added Area subclasses WorldArea and PostalArea (contributed by Dan Dukeson).
data/README CHANGED
@@ -8,16 +8,10 @@ google4r itself is distributed under an MIT style license.
8
8
 
9
9
  However, the library includes the cacert.pem:http://curl.haxx.se/ca/cacert.pem file from the Mozilla project. This file is distributed under the MPL:http://www.mozilla.org/MPL/.
10
10
 
11
- == Status
11
+ == More Information
12
12
 
13
13
  You can find more information on the Google Checkout API here:http://code.google.com/apis/checkout/developer/index.html. Note that the API documentation assumes an understanding of the Google Checkout XML API.
14
14
 
15
- Google4R also contains a partial implementation of the level 2 of the Google Checkout API:
16
-
17
- * The <checkout-cart-command> tag and all of its subtags that are not related to the merchant calculation API can be generated.
18
- * The <new-order-notification> tag and all of its subtags which are not related to the merchant calculation API can be parsed.
19
- * The <order-state-change-notification> tag can be parsed.
20
-
21
15
  == Google Checkout Tests
22
16
 
23
17
  You have to place a file called 'frontend_configuration.rb' in the directory'test' with the configuration for the Google4R::Checkout::Frontend class to use for running the tests.
@@ -38,18 +32,6 @@ The file should contain content similar to:
38
32
  :use_sandbox => true
39
33
  }
40
34
 
41
- == TODO
42
-
43
- Notifications:
44
-
45
- * <risk-information-notification>
46
- * <charge-amount-notification>
47
- * <refund-amount-notification>
48
- * <chargeback-amount-notification>
49
- * <authorization-amount-notification>
50
-
51
- All of the Order Processing API.
52
-
53
35
  == Dependencies
54
36
 
55
37
  The unit tests use Mocha so you have to install the gem "mocha" to run the tests. You will also need the money gem library.
@@ -55,6 +55,12 @@ module Google4R #:nodoc:
55
55
  # The Frontent class that was used to create this CheckoutCommand and whose
56
56
  # configuration will be used.
57
57
  attr_reader :frontend
58
+
59
+ # The tag name of the command
60
+ attr_reader :command_tag_name
61
+
62
+ # The google order number, required, String
63
+ attr_accessor :google_order_number
58
64
 
59
65
  # Initialize the frontend attribute with the value of the frontend parameter.
60
66
  def initialize(frontend)
@@ -100,22 +106,25 @@ module Google4R #:nodoc:
100
106
 
101
107
  case xml_doc.root.name
102
108
  when 'checkout-redirect'
103
- serial_number = xml_doc.elements['/checkout-redirect/@serial-number'].value
109
+ serial_number = xml_doc.elements['/checkout-redirect'].attributes['serial-number']
104
110
  redirect_url = xml_doc.elements['/checkout-redirect/redirect-url/text()'].value
105
111
  return CheckoutRedirectResponse.new(serial_number, redirect_url)
112
+ when 'request-received'
113
+ serial_number = xml_doc.elements['/request-received'].attributes['serial-number']
114
+ return serial_number
106
115
  else
107
116
  raise "Unknown response:\n--\n#{xml_doc.to_s}\n--"
108
117
  end
109
118
  when Net::HTTPClientError then
110
119
  xml_doc = REXML::Document.new(result.body)
111
120
 
112
- if xml_doc.elements['/error/@serial-number'].nil? or xml_doc.elements['/error/error-message/text()'].nil? then
121
+ if xml_doc.elements['/error'].attributes['serial-number'].nil? or xml_doc.elements['/error/error-message/text()'].nil? then
113
122
  raise "Invalid response from Google:\n---\n#{result.body}\n---"
114
123
  end
115
124
 
116
125
  hash =
117
126
  {
118
- :serial_number => xml_doc.elements['/error/@serial-number'].value,
127
+ :serial_number => xml_doc.elements['/error'].attributes['serial-number'],
119
128
  :message => xml_doc.elements['/error/error-message/text()'].value
120
129
  }
121
130
 
@@ -127,30 +136,33 @@ module Google4R #:nodoc:
127
136
  end
128
137
  end
129
138
 
130
- # Abstract method that is to contain the command's XML representation.
131
- #
132
- # Raises a NotImplementedError by default, override to remove this.
139
+ # Class method to return the command's XML representation.
133
140
  def to_xml
134
- raise NotImplementedError, "Command#to_xml is abstract and must be overridden in a subclass."
141
+ if self.class == Command then
142
+ raise NotImplementedError, "Command#to_xml has to be used in a subclass."
143
+ else
144
+ generator_class = Google4R::Command.get_const("#{self.class}XmlGenerator")
145
+ return generator_class.new(self).generate
146
+ end
135
147
  end
136
148
 
137
149
  protected
138
150
 
139
- # Class method to return the OpenSSL::X509::Store instance for the
140
- # CA certificates.
141
- #--
142
- # TODO: Is OpenSSL::X509::Store thread safe when reading only? This method most certainly is *not*. It must become so.
143
- #++
144
- def self.x509_store
145
- return @@x509_store if defined?(@@x509_store)
146
-
147
- cacert_path = File.expand_path(File.dirname(__FILE__) + '/../../../var/cacert.pem')
148
-
149
- @@x509_store = OpenSSL::X509::Store.new
150
- @@x509_store.add_file(cacert_path)
151
-
152
- return @@x509_store
153
- end
151
+ # Class method to return the OpenSSL::X509::Store instance for the
152
+ # CA certificates.
153
+ #--
154
+ # TODO: Is OpenSSL::X509::Store thread safe when reading only? This method most certainly is *not*. It must become so.
155
+ #++
156
+ def self.x509_store
157
+ return @@x509_store if defined?(@@x509_store)
158
+
159
+ cacert_path = File.expand_path(File.dirname(__FILE__) + '/../../../var/cacert.pem')
160
+
161
+ @@x509_store = OpenSSL::X509::Store.new
162
+ @@x509_store.add_file(cacert_path)
163
+
164
+ return @@x509_store
165
+ end
154
166
  end
155
167
 
156
168
  # The CheckoutCommand represents a <checkout-shopping-cart> command sent
@@ -207,7 +219,6 @@ module Google4R #:nodoc:
207
219
  # to create CheckoutCommand objects.
208
220
  def initialize(frontend)
209
221
  super(frontend)
210
-
211
222
  @shopping_cart = ShoppingCart.new(self)
212
223
  @tax_tables = frontend.tax_table_factory.effective_tax_tables_at(Time.new)
213
224
  @shipping_methods = Array.new
@@ -256,5 +267,179 @@ module Google4R #:nodoc:
256
267
  @redirect_url = redirect_url
257
268
  end
258
269
  end
270
+
271
+ #
272
+ # The ChargeOrderCommand instructs Google Checkout to charge the buyer for a
273
+ # particular order.
274
+ #
275
+ class ChargeOrderCommand < Command
276
+ # The amount to charge, optional, Money
277
+ attr_accessor :amount
278
+
279
+ # frontend, required
280
+ def initialize(frontend)
281
+ super(frontend)
282
+ end
283
+
284
+ # Generates the XML for this ChargeOrderCommand
285
+ def to_xml
286
+ ChargeOrderCommandXmlGenerator.new(self).generate
287
+ end
288
+ end
289
+
290
+ # The RefundOrderCommand instructs Google Checkout to refund an order
291
+ class RefundOrderCommand < Command
292
+ # The amount to refund, optional, Money
293
+ attr_accessor :amount
294
+
295
+ # The reason that the order is to be refunded, String of maximum 140 characters, required
296
+ attr_accessor :reason
297
+
298
+ # A comment related to the refunded order, String of maximum 140 characters, optional
299
+ attr_accessor :comment
300
+
301
+ def initialize(frontend)
302
+ super(frontend)
303
+ end
304
+
305
+ def to_xml
306
+ RefundOrderCommandXmlGenerator.new(self).generate
307
+ end
308
+ end
309
+
310
+ # The CancelOrderCommand instructs Google Checkout to cancel an order
311
+ class CancelOrderCommand < Command
312
+ # The reason that the order is to be cancelled, String of maximum 140 characters, required
313
+ attr_accessor :reason
314
+
315
+ # A comment related to the cancelled order, String of maximum 140 characters, optional
316
+ attr_accessor :comment
317
+
318
+ def initialize(frontend)
319
+ super(frontend)
320
+ end
321
+
322
+ def to_xml
323
+ CancelOrderCommandXmlGenerator.new(self).generate
324
+ end
325
+ end
326
+
327
+ # The AuthorizeOrderCommand instructs Google Checkout to explicitly reauthorize
328
+ # a customer's credit card for the uncharged balance of an order to verify that
329
+ # funds for the order are available
330
+ class AuthorizeOrderCommand < Command
331
+ def initialize(frontend)
332
+ super(frontend)
333
+ end
334
+
335
+ def to_xml
336
+ AuthorizeOrderCommandXmlGenerator.new(self).generate
337
+ end
338
+ end
339
+
340
+ # The ProcessOrderCommand instructs Google Checkout to to update
341
+ # an order's fulfillment state from NEW to PROCESSING
342
+ class ProcessOrderCommand < Command
343
+ def initialize(frontend)
344
+ super(frontend)
345
+ end
346
+
347
+ def to_xml
348
+ ProcessOrderCommandXmlGenerator.new(self).generate
349
+ end
350
+ end
351
+
352
+ # The AddMerchantOrderCommand instructs Google Checkout to associate a
353
+ # merchant-assigned order number with an order
354
+ class AddMerchantOrderNumberCommand < Command
355
+ # The merchant-assigned order number associated with an order
356
+ attr_accessor :merchant_order_number
357
+
358
+ def initialize(frontend)
359
+ super(frontend)
360
+ end
361
+
362
+ def to_xml
363
+ AddMerchantOrderNumberCommandXmlGenerator.new(self).generate
364
+ end
365
+ end
366
+
367
+ # The DeliverOrderCommand indicates that Google should update an order's fulfillment order state to DELIVERED
368
+ class DeliverOrderCommand < Command
369
+ # if google checkout should email buyer to ssay order is dispatched
370
+ attr_accessor :send_email
371
+
372
+ # The name of the company responsible for shipping the item. Valid values
373
+ # for this tag are DHL, FedEx, UPS, USPS and Other.
374
+ attr_accessor :carrier
375
+
376
+ # The shipper's tracking number that is associated with an order
377
+ attr_accessor :tracking_number
378
+
379
+ def initialize(frontend)
380
+ super(frontend)
381
+ end
382
+
383
+ def to_xml
384
+ DeliverOrderCommandXmlGenerator.new(self).generate
385
+ end
386
+ end
387
+
388
+ # The AddTrackingDataCommand instructs Google Checkout to associate a shipper's tracking number with an order.
389
+ class AddTrackingDataCommand < Command
390
+ # The name of the company responsible for shipping the item. Valid values
391
+ # for this tag are DHL, FedEx, UPS, USPS and Other.
392
+ attr_accessor :carrier
393
+
394
+ # The shipper's tracking number that is associated with an order
395
+ attr_accessor :tracking_number
396
+
397
+ def initialize(frontend)
398
+ super(frontend)
399
+ end
400
+
401
+ def to_xml
402
+ AddTrackingDataCommandXmlGenerator.new(self).generate
403
+ end
404
+ end
405
+
406
+ # The SendBuyerMessageCommand instructs Google Checkout to place a message in the customer's Google Checkout account.
407
+ class SendBuyerMessageCommand < Command
408
+ # The message to the customer
409
+ attr_accessor :message
410
+
411
+ # if google checkout should email buyer to ssay order is dispatched
412
+ attr_accessor :send_email
413
+
414
+ def initialize(frontend)
415
+ super(frontend)
416
+ end
417
+
418
+ def to_xml
419
+ SendBuyerMessageCommandXmlGenerator.new(self).generate
420
+ end
421
+ end
422
+
423
+ # The ArchiveOrderCommand instructs Google Checkout to remove an order from your Merchant Center Inbox.
424
+ class ArchiveOrderCommand < Command
425
+ def initialize(frontend)
426
+ super(frontend)
427
+ end
428
+
429
+ def to_xml
430
+ ArchiveOrderCommandXmlGenerator.new(self).generate
431
+ end
432
+ end
433
+
434
+ # The UnarchiveOrderCommand instructs Google Checkout to return a previously archived order to your Merchant Center Inbox.
435
+ class UnarchiveOrderCommand < Command
436
+ def initialize(frontend)
437
+ super(frontend)
438
+ end
439
+
440
+ def to_xml
441
+ UnarchiveOrderCommandXmlGenerator.new(self).generate
442
+ end
443
+ end
259
444
  end
260
445
  end
@@ -70,7 +70,7 @@ module Google4R #:nodoc:
70
70
  # frontend = Google4R::Checkout::Frontend.new(configuration)
71
71
  # frontend.tax_table_factory = TaxTableFactory.new
72
72
  #
73
- # checkout_command = frontent.create_checkout_command
73
+ # checkout_command = frontend.create_checkout_command
74
74
  # # ...
75
75
  # handler = frontend.create_notification_handler
76
76
  class Frontend
@@ -91,6 +91,18 @@ module Google4R #:nodoc:
91
91
 
92
92
  @configuration = configuration.dup.freeze
93
93
  end
94
+
95
+ # Factory method to create a new DeliverOrderCommand object. Use this method to create
96
+ # your DeliverOrderCommand instances.
97
+ def create_deliver_order_command
98
+ return DeliverOrderCommand.new(self)
99
+ end
100
+
101
+ # Factory method to create a new ChargeOrderCommand object. Use this method to create
102
+ # your ChargeOrderCommand instances.
103
+ def create_charge_order_command
104
+ return ChargeOrderCommand.new(self)
105
+ end
94
106
 
95
107
  # Factory method that creates a new CheckoutCommand object. Use this method to create
96
108
  # your CheckoutCommand instances.
@@ -103,6 +115,54 @@ module Google4R #:nodoc:
103
115
  def create_notification_handler
104
116
  return NotificationHandler.new(self)
105
117
  end
118
+
119
+ # Factory method to create a new CancelOrderCommand object. Use this method to create
120
+ # your CancelOrderCommand instances.
121
+ def create_cancel_order_command
122
+ return CancelOrderCommand.new(self)
123
+ end
124
+
125
+ # Factory method to create a new RefundOrderCommand object. Use this method to create
126
+ # your RefundOrderCommand instances.
127
+ def create_refund_order_command
128
+ return RefundOrderCommand.new(self)
129
+ end
130
+
131
+ # Factory method to create a new SendBuyerMessageCommand object. Use this method to create
132
+ # your SendBuyerMessageCommand instances.
133
+ def create_send_buyer_message_command
134
+ return SendBuyerMessageCommand.new(self)
135
+ end
136
+
137
+ # Factory method to create a new AuthorizeOrderCommand object. Use this method to create
138
+ # your AuthorizeOrderCommand instances.
139
+ def create_authorize_order_command
140
+ return AuthorizeOrderCommand.new(self)
141
+ end
142
+
143
+ # Factory method to create a new AddMerchantOrderNumberCommand object. Use this method to create
144
+ # your AddMerchantOrderNumberCommand instances.
145
+ def create_add_merchant_order_number_command
146
+ return AddMerchantOrderNumberCommand.new(self)
147
+ end
148
+
149
+ # Factory method to create a new AddTrackingDataCommand object. Use this method to create
150
+ # your AddTrackingDataCommand instances.
151
+ def create_add_tracking_data_command
152
+ return AddTrackingDataCommand.new(self)
153
+ end
154
+
155
+ # Factory method to create a new ArchiveOrderCommand object. Use this method to create
156
+ # your ArchiveOrderCommand instances.
157
+ def create_archive_order_command
158
+ return ArchiveOrderCommand.new(self)
159
+ end
160
+
161
+ # Factory method to create a new UnarchiveOrderCommand object. Use this method to create
162
+ # your UnarchiveOrderCommand instances.
163
+ def create_unarchive_order_command
164
+ return UnarchiveOrderCommand.new(self)
165
+ end
106
166
  end
107
167
  end
108
- end
168
+ end
@@ -107,6 +107,16 @@ module Google4R #:nodoc:
107
107
  NewOrderNotification.create_from_element(root, frontend)
108
108
  when 'order-state-change-notification' then
109
109
  OrderStateChangeNotification.create_from_element(root, frontend)
110
+ when 'risk-information-notification' then
111
+ RiskInformationNotification.create_from_element(root, frontend)
112
+ when 'charge-amount-notification' then
113
+ ChargeAmountNotification.create_from_element(root, frontend)
114
+ when 'refund-amount-notification' then
115
+ RefundAmountNotification.create_from_element(root, frontend)
116
+ when 'chargeback-amount-notification' then
117
+ ChargebackAmountNotification.create_from_element(root, frontend)
118
+ when 'authorization-amount-notification' then
119
+ AuthorizationAmountNotification.create_from_element(root, frontend)
110
120
  else
111
121
  raise UnknownNotificationType, "Unknown notification type: #{root.name}"
112
122
  end
@@ -185,7 +195,7 @@ module Google4R #:nodoc:
185
195
  result = NewOrderNotification.new(frontend)
186
196
 
187
197
  result.timestamp = Time.parse(element.elements['timestamp'].text)
188
- result.serial_number = element.elements['@serial-number'].value
198
+ result.serial_number = element.attributes['serial-number']
189
199
  result.google_order_number = element.elements['google-order-number'].text
190
200
  result.buyer_billing_address = Address.create_from_element(element.elements['buyer-billing-address'])
191
201
  result.buyer_shipping_address = Address.create_from_element(element.elements['buyer-shipping-address'])
@@ -197,7 +207,7 @@ module Google4R #:nodoc:
197
207
  result.shopping_cart = ShoppingCart.create_from_element(element.elements['shopping-cart'], result)
198
208
 
199
209
  amount = element.elements['order-total'].text.to_s.gsub(/[^0-9]/, '').to_i rescue nil
200
- currency = element.elements['order-total/@currency'].value rescue nil
210
+ currency = element.elements['order-total'].attributes['currency'] rescue nil
201
211
  result.order_total = Money.new(amount, currency)
202
212
 
203
213
  return result
@@ -250,7 +260,7 @@ module Google4R #:nodoc:
250
260
  @frontend = frontend
251
261
  end
252
262
 
253
- # Factory methdo that creates a new OrderStateChangeNotification from an REXML::Element instance.
263
+ # Factory method that creates a new OrderStateChangeNotification from an REXML::Element instance.
254
264
  # Use this to create instances of OrderStateChangeNotification.
255
265
  #
256
266
  # Raises NoMethodError and RuntimeError exceptions if the given element misses required
@@ -259,8 +269,7 @@ module Google4R #:nodoc:
259
269
  result = OrderStateChangeNotification.new(frontend)
260
270
 
261
271
  result.timestamp = Time.parse(element.elements['timestamp'].text)
262
-
263
- result.serial_number = element.elements['@serial-number'].value
272
+ result.serial_number = element.attributes['serial-number']
264
273
  result.google_order_number = element.elements['google-order-number'].text
265
274
  result.new_financial_order_state = element.elements['new-financial-order-state'].text
266
275
  result.previous_financial_order_state = element.elements['previous-financial-order-state'].text
@@ -272,6 +281,288 @@ module Google4R #:nodoc:
272
281
  end
273
282
  end
274
283
 
284
+ # Google Checkout sends <charge-amount-notification> messages to the web service when the
285
+ # to confirm that the charge was successfully executed.
286
+ class ChargeAmountNotification
287
+
288
+ # The serial number of the notification (String).
289
+ attr_accessor :serial_number
290
+
291
+ # The order number in Google's database (String).
292
+ attr_accessor :google_order_number
293
+
294
+ # The timestamp of the notification
295
+ attr_accessor :timestamp
296
+
297
+ # The amount most recently charged for an order (Money)
298
+ attr_accessor :latest_charge_amount
299
+
300
+ # The total amount charged for an order (Money)
301
+ attr_accessor :total_charge_amount
302
+
303
+ # The Frontend instance for this Notification
304
+ attr_accessor :frontend
305
+
306
+ # Initializes the ChargeAmountNotification instance with the given Frontend instance.
307
+ def initialize(frontend)
308
+ @frontend = frontend
309
+ end
310
+
311
+ # Factory method that creates a new ChargeAmountNotification from an REXML::Element instance.
312
+ # Use this to create instances of ChargeAmountNotification.
313
+ #
314
+ # Raises NoMethodError and RuntimeError exceptions if the given element misses required
315
+ # elements.
316
+ def self.create_from_element(element, frontend)
317
+ charge = ChargeAmountNotification.new(frontend)
318
+
319
+ charge.serial_number = element.attributes['serial-number']
320
+ charge.google_order_number = element.elements['google-order-number'].text
321
+
322
+ currency = element.elements['latest-charge-amount'].attributes['currency']
323
+ amount = element.elements['latest-charge-amount'].text.to_f*100.round
324
+ charge.latest_charge_amount = Money.new(amount, currency)
325
+
326
+ currency = element.elements['total-charge-amount'].attributes['currency']
327
+ amount = element.elements['total-charge-amount'].text.to_f*100.round
328
+ charge.total_charge_amount = Money.new(amount, currency)
329
+
330
+ charge.timestamp = Time.parse(element.elements['timestamp'].text)
331
+
332
+ return charge
333
+ end
334
+ end
335
+
336
+ # Google Checkout sends a <refund-amount-notification> after successfully executing
337
+ # a <refund-order> order processing command. See the Google Checkout documentation for more details:
338
+ # http://code.google.com/apis/checkout/developer/index.html#refund_amount_notification
339
+ class RefundAmountNotification
340
+ # The serial number of the notification (String).
341
+ attr_accessor :serial_number
342
+
343
+ # The order number in Google's database (String).
344
+ attr_accessor :google_order_number
345
+
346
+ # The timestamp of the notification
347
+ attr_accessor :timestamp
348
+
349
+ # The amount most recently refunded for an order (Money)
350
+ attr_accessor :latest_refund_amount
351
+
352
+ # The total amount refunded for an order (Money)
353
+ attr_accessor :total_refund_amount
354
+
355
+ # The Frontend instance for this Notification
356
+ attr_accessor :frontend
357
+
358
+ # Initializes the RefundAmountNotification instance with the given Frontend instance.
359
+ def initialize(frontend)
360
+ @frontend = frontend
361
+ end
362
+
363
+ # Factory method that creates a new RefundAmountNotification from an REXML::Element instance.
364
+ # Use this to create instances of RefundAmountNotification.
365
+ #
366
+ # Raises NoMethodError and RuntimeError exceptions if the given element misses required
367
+ # elements.
368
+ def self.create_from_element(element, frontend)
369
+ refund = RefundAmountNotification.new(frontend)
370
+
371
+ refund.serial_number = element.attributes['serial-number']
372
+ refund.google_order_number = element.elements['google-order-number'].text
373
+
374
+ currency = element.elements['latest-refund-amount'].attributes['currency']
375
+ amount = element.elements['latest-refund-amount'].text.to_f*100.round
376
+ refund.latest_refund_amount = Money.new(amount, currency)
377
+
378
+ currency = element.elements['total-refund-amount'].attributes['currency']
379
+ amount = element.elements['total-refund-amount'].text.to_f*100.round
380
+ refund.total_refund_amount = Money.new(amount, currency)
381
+
382
+ refund.timestamp = Time.parse(element.elements['timestamp'].text)
383
+
384
+ return refund
385
+ end
386
+ end
387
+
388
+ # Google Checkout sends a <chargeback-amount-notification> when a customer initiates a
389
+ # chargeback against the order and Google approves the chargeback.
390
+ # See the Google Checkout documentation for more details:
391
+ # http://code.google.com/apis/checkout/developer/index.html#chargeback_amount_notification
392
+ class ChargebackAmountNotification
393
+ # The serial number of the notification (String).
394
+ attr_accessor :serial_number
395
+
396
+ # The order number in Google's database (String).
397
+ attr_accessor :google_order_number
398
+
399
+ # The timestamp of the notification
400
+ attr_accessor :timestamp
401
+
402
+ # The amount most recently charged back for an order (Money)
403
+ attr_accessor :latest_chargeback_amount
404
+
405
+ # The total amount charged back for an order (Money)
406
+ attr_accessor :total_chargeback_amount
407
+
408
+ # The Frontend instance for this Notification
409
+ attr_accessor :frontend
410
+
411
+ # Initializes the ChargebackAmountNotification instance with the given Frontend instance.
412
+ def initialize(frontend)
413
+ @frontend = frontend
414
+ end
415
+
416
+ # Factory method that creates a new ChargebackAmountNotification from an REXML::Element instance.
417
+ # Use this to create instances of ChargebackAmountNotification.
418
+ #
419
+ # Raises NoMethodError and RuntimeError exceptions if the given element misses required
420
+ # elements.
421
+ def self.create_from_element(element, frontend)
422
+ chargeback = ChargebackAmountNotification.new(frontend)
423
+
424
+ chargeback.serial_number = element.attributes['serial-number']
425
+ chargeback.google_order_number = element.elements['google-order-number'].text
426
+
427
+ currency = element.elements['latest-chargeback-amount'].attributes['currency']
428
+ amount = element.elements['latest-chargeback-amount'].text.to_f*100.round
429
+ chargeback.latest_chargeback_amount = Money.new(amount, currency)
430
+
431
+ currency = element.elements['total-chargeback-amount'].attributes['currency']
432
+ amount = element.elements['total-chargeback-amount'].text.to_f*100.round
433
+ chargeback.total_chargeback_amount = Money.new(amount, currency)
434
+
435
+ chargeback.timestamp = Time.parse(element.elements['timestamp'].text)
436
+
437
+ return chargeback
438
+ end
439
+ end
440
+
441
+ # Google Checkout sends an <authorization-amount-notification> in response to a successful
442
+ # request for an explicit credit card reauthorization.
443
+ # See the Google Checkout documentation for more details:
444
+ # http://code.google.com/apis/checkout/developer/index.html#authorization_amount_notification
445
+ class AuthorizationAmountNotification
446
+ # The serial number of the notification (String).
447
+ attr_accessor :serial_number
448
+
449
+ # The order number in Google's database (String).
450
+ attr_accessor :google_order_number
451
+
452
+ # The timestamp of the notification
453
+ attr_accessor :timestamp
454
+
455
+ # The amount that is reauthorized to be charged to the customer's credit card (Money)
456
+ attr_accessor :authorization_amount
457
+
458
+ # The time that a credit card authorization for an order expires.
459
+ attr_accessor :authorization_expiration_date
460
+
461
+ # The address verification response (String)
462
+ attr_accessor :avs_response
463
+
464
+ # Credit verification value for the order (String)
465
+ attr_accessor :cvn_response
466
+
467
+ # The Frontend instance for this Notification
468
+ attr_accessor :frontend
469
+
470
+ # Initializes the AuthorizationAmountNotification instance with the given Frontend instance.
471
+ def initialize(frontend)
472
+ @frontend = frontend
473
+ end
474
+
475
+ # Factory method that creates a new AuthorizationAmountNotification from an REXML::Element instance.
476
+ # Use this to create instances of AuthorizationAmountNotification.
477
+ #
478
+ # Raises NoMethodError and RuntimeError exceptions if the given element misses required
479
+ # elements.
480
+ def self.create_from_element(element, frontend)
481
+ authorization = AuthorizationAmountNotification.new(frontend)
482
+
483
+ authorization.serial_number = element.attributes['serial-number']
484
+ authorization.google_order_number = element.elements['google-order-number'].text
485
+
486
+ currency = element.elements['authorization-amount'].attributes['currency']
487
+ amount = element.elements['authorization-amount'].text.to_f*100.round
488
+ authorization.authorization_amount = Money.new(amount, currency)
489
+
490
+ authorization.authorization_expiration_date = Time.parse(element.elements['authorization-expiration-date'].text)
491
+
492
+ authorization.avs_response = element.elements['avs-response'].text
493
+ authorization.cvn_response = element.elements['cvn-response'].text
494
+
495
+ authorization.timestamp = Time.parse(element.elements['timestamp'].text)
496
+
497
+ return authorization
498
+ end
499
+ end
500
+
501
+ # Google Checkout sends out <risk-information-notification> messages for fraud detection
502
+ # related information. See the Google Checkout documentation for more details:
503
+ # http://code.google.com/apis/checkout/developer/index.html#risk_information_notification
504
+ class RiskInformationNotification
505
+ # The serial number of the notification (String).
506
+ attr_accessor :serial_number
507
+
508
+ # The order number in Google's database (String).
509
+ attr_accessor :google_order_number
510
+
511
+ # Is the order eligible for Google Checkout's payment guarantee policy (boolean).
512
+ attr_accessor :eligible_for_protection
513
+
514
+ # The buyer's billing address (Address).
515
+ attr_accessor :buyer_billing_address
516
+
517
+ # The address verification response (String)
518
+ attr_accessor :avs_response
519
+
520
+ # Credit verification value for the order (String)
521
+ attr_accessor :cvn_response
522
+
523
+ # The last 4 digits of the credit card used to pay for the order (integer)
524
+ attr_accessor :partial_card_number
525
+
526
+ # The buyer's IP address (String)
527
+ attr_accessor :ip_address
528
+
529
+ # The age of the buyer's google checkout account in days
530
+ attr_accessor :buyer_account_age
531
+
532
+ # The timestamp of the notification
533
+ attr_accessor :timestamp
534
+
535
+ # The Frontend instance for this Notification
536
+ attr_accessor :frontend
537
+
538
+ # Initializes the RiskInformationNotification instance with the given Frontend instance.
539
+ def initialize(frontend)
540
+ @frontend = frontend
541
+ end
542
+
543
+ # Factory method that creates a new RiskInformationNotification from an REXML::Element instance.
544
+ # Use this to create instances of RiskInformationNotification
545
+ #
546
+ # Raises NoMethodError and RuntimeError exceptions if the given element misses required
547
+ # elements.
548
+ def self.create_from_element(element, frontend)
549
+ risk = RiskInformationNotification.new(frontend)
550
+
551
+ risk.serial_number = element.attributes['serial-number']
552
+ risk.timestamp = Time.parse(element.elements['timestamp'].text)
553
+ risk.partial_card_number = element.elements['risk-information/partial-cc-number'].text
554
+ risk.ip_address = element.elements['risk-information/ip-address'].text
555
+ risk.google_order_number = element.elements['google-order-number'].text
556
+ risk.eligible_for_protection = element.elements['risk-information/eligible-for-protection'].text == 'true'
557
+ risk.cvn_response = element.elements['risk-information/cvn-response'].text
558
+ risk.buyer_billing_address = Address.create_from_element(element.elements['risk-information/billing-address'])
559
+ risk.buyer_account_age = element.elements['risk-information/buyer-account-age'].text.to_i
560
+ risk.avs_response = element.elements['risk-information/avs-response'].text
561
+
562
+ return risk
563
+ end
564
+ end
565
+
275
566
  # Container for the valid financial order states as defined in the
276
567
  # Google Checkout API.
277
568
  module FinancialOrderState
@@ -351,7 +642,7 @@ module Google4R #:nodoc:
351
642
 
352
643
  # The marketing preferences of a customer.
353
644
  class MarketingPreferences
354
- # Boolean, true iff the customer wants to receive emails.
645
+ # Boolean, true if the customer wants to receive emails.
355
646
  attr_accessor :email_allowed
356
647
 
357
648
  # Creates a new MarketingPreferences object from a given REXML::Element instance.
@@ -404,11 +695,11 @@ module Google4R #:nodoc:
404
695
  result.code = element.elements['code'].text
405
696
 
406
697
  amount = element.elements['calculated-amount'].text.to_s.gsub(/[^0-9]/, '').to_i rescue nil
407
- currency = element.elements['calculated-amount/@currency'].value rescue nil
698
+ currency = element.elements['calculated-amount'].attributes['currency'] rescue nil
408
699
  result.calculated_amount = Money.new(amount, currency) unless amount.nil?
409
700
 
410
701
  amount = element.elements['applied-amount'].text.to_s.gsub(/[^0-9]/, '').to_i
411
- currency = element.elements['applied-amount/@currency'].value
702
+ currency = element.elements['applied-amount'].attributes['currency']
412
703
  result.applied_amount = Money.new(amount, currency)
413
704
 
414
705
  result.message = element.elements['message'].text rescue nil
@@ -454,7 +745,7 @@ module Google4R #:nodoc:
454
745
  result.name = element.elements['shipping-name'].text
455
746
 
456
747
  amount = element.elements['shipping-cost'].text.to_s.gsub(/[^0-9]/, '').to_i
457
- currency = element.elements['shipping-cost/@currency'].value
748
+ currency = element.elements['shipping-cost'].attributes['currency']
458
749
  result.cost = Money.new(amount, currency)
459
750
 
460
751
  return result
@@ -486,7 +777,7 @@ module Google4R #:nodoc:
486
777
  result = OrderAdjustment.new
487
778
 
488
779
  amount = element.elements['total-tax'].text.to_s.gsub(/[^0-9]/, '').to_i rescue nil
489
- currency = element.elements['total-tax/@currency'].value rescue nil
780
+ currency = element.elements['total-tax'].attributes['currency'] rescue nil
490
781
  result.total_tax = Money.new(amount, currency) unless amount.nil?
491
782
 
492
783
  shipping_element = element.elements["shipping/*"]
@@ -498,7 +789,7 @@ module Google4R #:nodoc:
498
789
  result.merchant_calculation_successful = (element.elements['merchant-calculation-successful'].text.downcase == 'true') rescue nil
499
790
 
500
791
  amount = element.elements['adjustment-total'].text.to_s.gsub(/[^0-9]/, '').to_i rescue nil
501
- currency = element.elements['adjustment-total/@currency'].value rescue nil
792
+ currency = element.elements['adjustment-total'].attributes['currency'] rescue nil
502
793
  result.adjustment_total = Money.new(amount, currency) unless amount.nil?
503
794
 
504
795
  return result