nbudin-google4r-checkout 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGES +83 -0
  3. data/LICENSE +22 -0
  4. data/README +58 -0
  5. data/Rakefile +80 -0
  6. data/VERSION +1 -0
  7. data/lib/google4r/checkout/commands.rb +515 -0
  8. data/lib/google4r/checkout/frontend.rb +204 -0
  9. data/lib/google4r/checkout/merchant_calculation.rb +321 -0
  10. data/lib/google4r/checkout/notifications.rb +708 -0
  11. data/lib/google4r/checkout/shared.rb +1249 -0
  12. data/lib/google4r/checkout/utils.rb +94 -0
  13. data/lib/google4r/checkout/xml_generation.rb +920 -0
  14. data/lib/google4r/checkout.rb +34 -0
  15. data/test/frontend_configuration.rb +13 -0
  16. data/test/integration/checkout_command_test.rb +246 -0
  17. data/test/test_helper.rb +115 -0
  18. data/test/unit/add_merchant_order_number_command_test.rb +70 -0
  19. data/test/unit/add_tracking_data_command_test.rb +75 -0
  20. data/test/unit/address_test.rb +131 -0
  21. data/test/unit/anonymous_address_test.rb +75 -0
  22. data/test/unit/archive_order_command_test.rb +66 -0
  23. data/test/unit/area_test.rb +44 -0
  24. data/test/unit/authorization_amount_notification_test.rb +69 -0
  25. data/test/unit/authorize_order_command_test.rb +66 -0
  26. data/test/unit/backorder_items_command_test.rb +83 -0
  27. data/test/unit/callback_handler_test.rb +83 -0
  28. data/test/unit/cancel_items_command_test.rb +89 -0
  29. data/test/unit/cancel_order_command_test.rb +83 -0
  30. data/test/unit/carrier_calculated_shipping_test.rb +57 -0
  31. data/test/unit/charge_amount_notification_test.rb +64 -0
  32. data/test/unit/charge_order_command_test.rb +77 -0
  33. data/test/unit/chargeback_amount_notification_test.rb +65 -0
  34. data/test/unit/checkout_command_test.rb +125 -0
  35. data/test/unit/checkout_command_xml_generator_test.rb +218 -0
  36. data/test/unit/command_test.rb +116 -0
  37. data/test/unit/deliver_order_command_test.rb +70 -0
  38. data/test/unit/delivery_method_test.rb +42 -0
  39. data/test/unit/digital_content_test.rb +105 -0
  40. data/test/unit/flat_rate_shipping_test.rb +132 -0
  41. data/test/unit/frontend_test.rb +136 -0
  42. data/test/unit/item_info_test.rb +69 -0
  43. data/test/unit/item_test.rb +171 -0
  44. data/test/unit/marketing_preferences_test.rb +65 -0
  45. data/test/unit/merchant_calculated_shipping_test.rb +172 -0
  46. data/test/unit/merchant_calculation_callback_test.rb +137 -0
  47. data/test/unit/merchant_calculation_result_test.rb +78 -0
  48. data/test/unit/merchant_calculation_results_test.rb +178 -0
  49. data/test/unit/merchant_code_result_test.rb +51 -0
  50. data/test/unit/merchant_code_test.rb +122 -0
  51. data/test/unit/new_order_notification_test.rb +115 -0
  52. data/test/unit/notification_acknowledgement_test.rb +67 -0
  53. data/test/unit/notification_handler_test.rb +113 -0
  54. data/test/unit/order_adjustment_test.rb +119 -0
  55. data/test/unit/order_state_change_notification_test.rb +158 -0
  56. data/test/unit/pickup_shipping_test.rb +70 -0
  57. data/test/unit/postal_area_test.rb +71 -0
  58. data/test/unit/private_data_parser_test.rb +68 -0
  59. data/test/unit/refund_amount_notification_test.rb +65 -0
  60. data/test/unit/refund_order_command_test.rb +86 -0
  61. data/test/unit/reset_items_shipping_information_command_test.rb +83 -0
  62. data/test/unit/return_items_command_test.rb +83 -0
  63. data/test/unit/risk_information_notification_test.rb +98 -0
  64. data/test/unit/send_buyer_message_command_test.rb +73 -0
  65. data/test/unit/ship_items_command_test.rb +101 -0
  66. data/test/unit/shipping_adjustment_test.rb +100 -0
  67. data/test/unit/shopping_cart_test.rb +146 -0
  68. data/test/unit/tax_rule_test.rb +70 -0
  69. data/test/unit/tax_table_test.rb +82 -0
  70. data/test/unit/tracking_data_test.rb +54 -0
  71. data/test/unit/unarchive_order_command_test.rb +66 -0
  72. data/test/unit/us_country_area_test.rb +76 -0
  73. data/test/unit/us_state_area_test.rb +70 -0
  74. data/test/unit/us_zip_area_test.rb +66 -0
  75. data/test/unit/world_area_test.rb +48 -0
  76. data/test/xml/apiv2.xsd +997 -0
  77. data/test/xml/test_check_persisting_works_expected.xml +213 -0
  78. data/var/cacert.pem +7815 -0
  79. metadata +200 -0
@@ -0,0 +1,515 @@
1
+ #--
2
+ # Project: google4r
3
+ # File: lib/google4r/checkout/commands.rb
4
+ # Author: Manuel Holtgrewe <purestorm at ggnore dot net>
5
+ # Copyright: (c) 2007 by Manuel Holtgrewe
6
+ # License: MIT License as follows:
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to permit
13
+ # persons to whom the Software is furnished to do so, subject to the
14
+ # following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included
17
+ # in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25
+ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #++
27
+ # This file contains the classes and modules that are used by the command
28
+ # generating code.
29
+
30
+ require 'openssl'
31
+ require 'money'
32
+ require 'net/http'
33
+ require 'net/https'
34
+ require 'uri'
35
+
36
+ module Google4R #:nodoc:
37
+ module Checkout #:nodoc:
38
+ # Abstract super class for all commands that are to be sent to Google. Provides the base
39
+ # functionality for signing and encoding the cart.
40
+ class Command
41
+ # The URL to use for requests to the sandboxed API. The merchant id is to be
42
+ # put in via String#%.
43
+ SANDBOX_URL_PREFIX = 'https://sandbox.google.com/checkout/'
44
+
45
+ # The URL to use for real requests to the Google Checkout API. The merchant id
46
+ # is to be put in via String#%.
47
+ PRODUCTION_URL_PREFIX = 'https://checkout.google.com/'
48
+
49
+ CHECKOUT_API_URL = 'api/checkout/v2/merchantCheckout/Merchant/%s'
50
+
51
+ ORDER_PROCESSING_API_URL = 'api/checkout/v2/request/Merchant/%s'
52
+
53
+ # The Frontent class that was used to create this CheckoutCommand and whose
54
+ # configuration will be used.
55
+ attr_reader :frontend
56
+
57
+ # The tag name of the command
58
+ attr_reader :command_tag_name
59
+
60
+ # The google order number, required, String
61
+ attr_accessor :google_order_number
62
+
63
+ # Initialize the frontend attribute with the value of the frontend parameter.
64
+ def initialize(frontend)
65
+ if self.instance_of?(Command) || self.instance_of?(ItemsCommand)
66
+ raise 'Cannot instantiate abstract class ' + self.class.to_s
67
+ end
68
+ @frontend = frontend
69
+ end
70
+
71
+ # Sends the cart's XML to GoogleCheckout via HTTPs with Basic Auth.
72
+ #
73
+ # Raises an OpenSSL::SSL::SSLError when the SSL certificate verification failed.
74
+ #
75
+ # Raises a GoogleCheckoutError when Google returns an error.
76
+ #
77
+ # Raises a RuntimeException on unknown responses.
78
+ #--
79
+ # TODO: The send-and-expect-response part should be adaptable to other commands and responses.
80
+ #++
81
+ def send_to_google_checkout
82
+ # Create HTTP(S) POST command and set up Basic Authentication.
83
+ url_str =
84
+ if frontend.configuration[:use_sandbox] then
85
+ SANDBOX_URL_PREFIX
86
+ else
87
+ PRODUCTION_URL_PREFIX
88
+ end
89
+ url_str +=
90
+ if self.class == CheckoutCommand then
91
+ CHECKOUT_API_URL
92
+ else
93
+ ORDER_PROCESSING_API_URL
94
+ end
95
+ url_str = url_str % frontend.configuration[:merchant_id]
96
+ url = URI.parse(url_str)
97
+
98
+ request = Net::HTTP::Post.new(url.path)
99
+ request.basic_auth(frontend.configuration[:merchant_id], frontend.configuration[:merchant_key])
100
+
101
+ # Set up the HTTP connection object and the SSL layer.
102
+ https = Net::HTTP.new(url.host, url.port)
103
+ https.use_ssl = true
104
+ https.cert_store = self.class.x509_store
105
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
106
+ https.verify_depth = 5
107
+
108
+ # Send the request to Google.
109
+ result = https.request(request, self.to_xml)
110
+
111
+ case result
112
+ when Net::HTTPSuccess then
113
+ xml_doc = REXML::Document.new(result.body)
114
+
115
+ case xml_doc.root.name
116
+ when 'checkout-redirect'
117
+ serial_number = xml_doc.elements['/checkout-redirect'].attributes['serial-number']
118
+ redirect_url = xml_doc.elements['/checkout-redirect/redirect-url/text()'].value
119
+ return CheckoutRedirectResponse.new(serial_number, redirect_url)
120
+ when 'request-received'
121
+ serial_number = xml_doc.elements['/request-received'].attributes['serial-number']
122
+ return serial_number
123
+ else
124
+ raise "Unknown response:\n--\n#{xml_doc.to_s}\n--"
125
+ end
126
+ when Net::HTTPClientError then
127
+ xml_doc = REXML::Document.new(result.body)
128
+
129
+ if xml_doc.elements['/error'].attributes['serial-number'].nil? or xml_doc.elements['/error/error-message/text()'].nil? then
130
+ raise "Invalid response from Google:\n---\n#{result.body}\n---"
131
+ end
132
+
133
+ hash =
134
+ {
135
+ :serial_number => xml_doc.elements['/error'].attributes['serial-number'],
136
+ :message => xml_doc.elements['/error/error-message/text()'].value
137
+ }
138
+
139
+ raise GoogleCheckoutError.new(hash)
140
+ when Net::HTTPRedirection, Net::HTTPServerError, Net::HTTPInformation then
141
+ raise "Unexpected reponse code (#{result.class}): #{result.code} - #{result.message}\n#{result.body}"
142
+ else
143
+ raise "Unknown reponse code: #{result.code} - #{result.message}\n#{result.body}"
144
+ end
145
+ end
146
+
147
+ # Class method to return the command's XML representation.
148
+ def to_xml
149
+ generator_class = Google4R::Command.get_const("#{self.class}XmlGenerator")
150
+ return generator_class.new(self).generate
151
+ end
152
+
153
+ protected
154
+
155
+ # Class method to return the OpenSSL::X509::Store instance for the
156
+ # CA certificates.
157
+ #--
158
+ # TODO: Is OpenSSL::X509::Store thread safe when reading only? This method most certainly is *not*. It must become so.
159
+ #++
160
+ def self.x509_store
161
+ return @@x509_store if defined?(@@x509_store)
162
+
163
+ cacert_path = File.expand_path(File.dirname(__FILE__) + '/../../../var/cacert.pem')
164
+
165
+ @@x509_store = OpenSSL::X509::Store.new
166
+ @@x509_store.add_file(cacert_path)
167
+
168
+ return @@x509_store
169
+ end
170
+ end
171
+
172
+ # The CheckoutCommand represents a <checkout-shopping-cart> command sent
173
+ # to the server.
174
+ #
175
+ # A CheckoutCommand instance can have an arbitrary number of TaxTable
176
+ # and ShippingMethod instances. You must create these instances using the
177
+ # create_* methods which CheckoutCommand supplies.
178
+ #
179
+ # CheckoutCommand#send_to_google_checkout returns CheckoutRedirectResponse
180
+ # instances.
181
+ #
182
+ # Use the Frontend class to create new CheckoutCommand instances and do not
183
+ # instanciate the class directly.
184
+ #
185
+ # Note that you have to create/set the tax tables for CheckoutCommands before you
186
+ # can add any items to the cart that define a tax table.
187
+ #
188
+ # === Example
189
+ #
190
+ # frontend = Google4R::Checkout::Frontend.new(configuration)
191
+ # frontend.tax_table_factory = TaxTableFactory.new
192
+ # command = frontend.create_checkout_command
193
+ class CheckoutCommand < Command
194
+ # The ShoppingCart of this CheckoutCommand.
195
+ attr_reader :shopping_cart
196
+
197
+ # An array of the TaxTable objects of this CheckoutCommand. They have been
198
+ # created with the tax table factory of the frontend which created this
199
+ # command.
200
+ attr_reader :tax_tables
201
+
202
+ # An array of ShippingMethod objects of this CheckoutCommand. Use
203
+ # #create_shipping_method to create new shipping methods.
204
+ attr_reader :shipping_methods
205
+
206
+ # The URL at where the cart can be edited (String, optional).
207
+ attr_accessor :edit_cart_url
208
+
209
+ # The URL to continue shopping after completing the checkout (String, optional).
210
+ attr_accessor :continue_shopping_url
211
+
212
+ # A boolean flag; true iff the customer HAS to provide his phone number (optional).
213
+ attr_accessor :request_buyer_phone_number
214
+
215
+ # The URL of the merchant calculation callback (optional).
216
+ attr_accessor :merchant_calculations_url
217
+
218
+ # A boolean flag to indicate whether merchant coupon is supported or not (optional).
219
+ attr_accessor :accept_merchant_coupons
220
+
221
+ # A boolean flag to indicate whether gift certificate is supported or not (optional).
222
+ attr_accessor :accept_gift_certificates
223
+
224
+ # A Google Checkout merchant ID that identifies the eCommerce provider.
225
+ attr_accessor :platform_id
226
+
227
+ # Setting this allows Google Analytics to track purchases that use Checkout
228
+ # The value should be as set by the analytics javascript in the hidden form
229
+ # element names "analyticsdata" on the page with the checkout button.
230
+ # If left unset then the element will not be generated.
231
+ # see: http://code.google.com/apis/checkout/developer/checkout_analytics_integration.html
232
+ attr_accessor :analytics_data
233
+
234
+ # Generates the XML for this CheckoutCommand.
235
+ def to_xml
236
+ CheckoutCommandXmlGenerator.new(self).generate
237
+ end
238
+
239
+ # Initialize a new CheckoutCommand with a fresh CheckoutCart and an empty
240
+ # Array of tax tables and an empty array of ShippingMethod instances.
241
+ # Do not use this method directly but use Frontent#create_checkout_command
242
+ # to create CheckoutCommand objects.
243
+ def initialize(frontend)
244
+ super(frontend)
245
+ @shopping_cart = ShoppingCart.new(self)
246
+ @tax_tables = frontend.tax_table_factory.effective_tax_tables_at(Time.new)
247
+ @shipping_methods = Array.new
248
+ end
249
+
250
+ # Use this method to create a new shipping method. You have to pass in one of
251
+ # { PickupShipping, FlatRateShipping } for clazz. The method will create a
252
+ # new instance of the class you passedin object and add it to the internal list
253
+ # of shipping methods.
254
+ #
255
+ # If you pass a block to this method (preferred) then the newly created
256
+ # ShippingMethod object will be passed into this block for setting its attributes.
257
+ # The newly created shipping method will be returned in all cases.
258
+ #
259
+ # The first created shipping method will be used as the default.
260
+ #
261
+ # Raises a ArgumentError if the parameter clazz is invalid.
262
+ def create_shipping_method(clazz, &block)
263
+ if not [ PickupShipping, FlatRateShipping,
264
+ MerchantCalculatedShipping, CarrierCalculatedShipping
265
+ ].include?(clazz) then
266
+ raise ArgumentError, "Unknown shipping method: #{clazz.inspect}."
267
+ end
268
+
269
+ shipping_method = clazz.new
270
+ @shipping_methods << shipping_method
271
+
272
+ yield(shipping_method) if block_given?
273
+
274
+ return shipping_method
275
+ end
276
+ end
277
+
278
+ # CheckoutRedirectResponse instances are returned when a CheckoutCommand is successfully
279
+ # processed by Google Checkout.
280
+ class CheckoutRedirectResponse
281
+ # The serial number of the <checkout-redirect> response.
282
+ attr_reader :serial_number
283
+
284
+ # The URL to redirect to.
285
+ attr_reader :redirect_url
286
+
287
+ # Create a new CheckoutRedirectResponse with the given serial number and redirection URL.
288
+ # Do not create CheckoutRedirectResponse instances in your own code. Google4R creates them
289
+ # for you.
290
+ def initialize(serial_number, redirect_url)
291
+ @serial_number = serial_number
292
+ @redirect_url = redirect_url
293
+ end
294
+
295
+ def to_s
296
+ return @redirect_url
297
+ end
298
+ end
299
+
300
+ #
301
+ # The ChargeOrderCommand instructs Google Checkout to charge the buyer for a
302
+ # particular order.
303
+ #
304
+ class ChargeOrderCommand < Command
305
+ # The amount to charge, optional, Money
306
+ attr_accessor :amount
307
+
308
+ # Generates the XML for this ChargeOrderCommand
309
+ def to_xml
310
+ ChargeOrderCommandXmlGenerator.new(self).generate
311
+ end
312
+ end
313
+
314
+ # The RefundOrderCommand instructs Google Checkout to refund an order
315
+ class RefundOrderCommand < Command
316
+ # The amount to refund, optional, Money
317
+ attr_accessor :amount
318
+
319
+ # The reason that the order is to be refunded, String of maximum 140 characters, required
320
+ attr_accessor :reason
321
+
322
+ # A comment related to the refunded order, String of maximum 140 characters, optional
323
+ attr_accessor :comment
324
+
325
+ def to_xml
326
+ RefundOrderCommandXmlGenerator.new(self).generate
327
+ end
328
+ end
329
+
330
+ # The CancelOrderCommand instructs Google Checkout to cancel an order
331
+ class CancelOrderCommand < Command
332
+ # The reason that the order is to be cancelled, String of maximum 140 characters, required
333
+ attr_accessor :reason
334
+
335
+ # A comment related to the cancelled order, String of maximum 140 characters, optional
336
+ attr_accessor :comment
337
+
338
+ def to_xml
339
+ CancelOrderCommandXmlGenerator.new(self).generate
340
+ end
341
+ end
342
+
343
+ # The AuthorizeOrderCommand instructs Google Checkout to explicitly reauthorize
344
+ # a customer's credit card for the uncharged balance of an order to verify that
345
+ # funds for the order are available
346
+ class AuthorizeOrderCommand < Command
347
+ def to_xml
348
+ AuthorizeOrderCommandXmlGenerator.new(self).generate
349
+ end
350
+ end
351
+
352
+ # The ProcessOrderCommand instructs Google Checkout to to update
353
+ # an order's fulfillment state from NEW to PROCESSING
354
+ class ProcessOrderCommand < Command
355
+ def to_xml
356
+ ProcessOrderCommandXmlGenerator.new(self).generate
357
+ end
358
+ end
359
+
360
+ # The AddMerchantOrderCommand instructs Google Checkout to associate a
361
+ # merchant-assigned order number with an order
362
+ class AddMerchantOrderNumberCommand < Command
363
+ # The merchant-assigned order number associated with an order
364
+ attr_accessor :merchant_order_number
365
+
366
+ def to_xml
367
+ AddMerchantOrderNumberCommandXmlGenerator.new(self).generate
368
+ end
369
+ end
370
+
371
+ # The DeliverOrderCommand indicates that Google should update an order's fulfillment order state to DELIVERED
372
+ class DeliverOrderCommand < Command
373
+ # if google checkout should email buyer to ssay order is dispatched
374
+ attr_accessor :send_email
375
+
376
+ # The name of the company responsible for shipping the item. Valid values
377
+ # for this tag are DHL, FedEx, UPS, USPS and Other.
378
+ attr_accessor :carrier
379
+
380
+ # The shipper's tracking number that is associated with an order
381
+ attr_accessor :tracking_number
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 to_xml
398
+ AddTrackingDataCommandXmlGenerator.new(self).generate
399
+ end
400
+ end
401
+
402
+ # The SendBuyerMessageCommand instructs Google Checkout to place a message in the customer's Google Checkout account.
403
+ class SendBuyerMessageCommand < Command
404
+ # The message to the customer
405
+ attr_accessor :message
406
+
407
+ # if google checkout should email buyer to say order is dispatched
408
+ attr_accessor :send_email
409
+
410
+ def to_xml
411
+ SendBuyerMessageCommandXmlGenerator.new(self).generate
412
+ end
413
+ end
414
+
415
+ # The ArchiveOrderCommand instructs Google Checkout to remove an order from your Merchant Center Inbox.
416
+ class ArchiveOrderCommand < Command
417
+ def to_xml
418
+ ArchiveOrderCommandXmlGenerator.new(self).generate
419
+ end
420
+ end
421
+
422
+ # The UnarchiveOrderCommand instructs Google Checkout to return a previously archived order to your Merchant Center Inbox.
423
+ class UnarchiveOrderCommand < Command
424
+ def to_xml
425
+ UnarchiveOrderCommandXmlGenerator.new(self).generate
426
+ end
427
+ end
428
+
429
+ # The <create-order-recurrence-request> tag contains a request to charge a customer for one or more items in a subscription.
430
+ class CreateOrderRecurrenceRequestCommand < Command
431
+ # The ID that uniquely identifies this order
432
+ attr_accessor :google_order_number
433
+
434
+ attr_reader :shopping_cart
435
+
436
+ # Initialize a new CreateOrderRecurrenceRequestCommand with a fresh ShoppingCart.
437
+ def initialize(frontend)
438
+ super(frontend)
439
+ @shopping_cart = ShoppingCart.new(self)
440
+ end
441
+
442
+ def to_xml
443
+ CreateOrderRecurrenceRequestCommandXmlGenerator.new(self).generate
444
+ end
445
+ end
446
+
447
+ #
448
+ # XML API Commands for Line-item Shipping
449
+ #
450
+
451
+ # Abstract class for Line-item shipping commands
452
+ class ItemsCommand < Command
453
+ # An array of ItemInfo objects that you are marking as backordered,
454
+ # cancelled, returned or resetting shipping information
455
+ attr_accessor :item_info_arr
456
+
457
+ # if google checkout should email buyer to say order is dispatched
458
+ attr_accessor :send_email
459
+
460
+ def initialize(frontend)
461
+ super
462
+ @item_info_arr = []
463
+ @send_email = false
464
+ end
465
+ end
466
+
467
+ # The <ship-items> command specifies shipping information for one or
468
+ # more items in an order.
469
+ class ShipItemsCommand < ItemsCommand
470
+ def to_xml
471
+ ShipItemsCommandXmlGenerator.new(self).generate
472
+ end
473
+ end
474
+
475
+ # The <backorder-items> command lets you specify that one or more
476
+ # specific items in an order are out of stock.
477
+ class BackorderItemsCommand < ItemsCommand
478
+ def to_xml
479
+ BackorderItemsCommandXmlGenerator.new(self).generate
480
+ end
481
+ end
482
+
483
+ # The <cancel-items> command lets you specify that one or more
484
+ # specific items in an order have been cancelled, meaning they
485
+ # will not be delivered to the customer.
486
+ class CancelItemsCommand < ItemsCommand
487
+
488
+ # The reason that you are canceling one or more line items
489
+ attr_accessor :reason
490
+
491
+ # An optional comment related to one or more canceled line items
492
+ attr_accessor :comment
493
+
494
+ def to_xml
495
+ CancelItemsCommandXmlGenerator.new(self).generate
496
+ end
497
+ end
498
+
499
+ # The <return-items> command lets you specify that your customer
500
+ # returned one or more specific items in an order.
501
+ class ReturnItemsCommand < ItemsCommand
502
+ def to_xml
503
+ ReturnItemsCommandXmlGenerator.new(self).generate
504
+ end
505
+ end
506
+
507
+ # The <reset-items-shipping-information> command allows you to reset
508
+ # the shipping status for specific items in an order to "Not yet shipped".
509
+ class ResetItemsShippingInformationCommand < ItemsCommand
510
+ def to_xml
511
+ ResetItemsShippingInformationCommandXmlGenerator.new(self).generate
512
+ end
513
+ end
514
+ end
515
+ end