google4r-checkout 0.1.0 → 1.0.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,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