nbudin-google4r-checkout 1.0.6

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