reactive_shipping 3.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.
Files changed (247) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +33 -0
  4. data/.yardopts +13 -0
  5. data/CHANGELOG.md +225 -0
  6. data/CONTRIBUTING.md +23 -0
  7. data/Gemfile +3 -0
  8. data/MIT-LICENSE +21 -0
  9. data/README.md +158 -0
  10. data/Rakefile +35 -0
  11. data/dev.yml +17 -0
  12. data/gemfiles/activesupport42.gemfile +5 -0
  13. data/gemfiles/activesupport50.gemfile +6 -0
  14. data/gemfiles/activesupport51.gemfile +5 -0
  15. data/gemfiles/activesupport52.gemfile +5 -0
  16. data/gemfiles/activesupport_master.gemfile +5 -0
  17. data/lib/certs/eParcel.dtd +111 -0
  18. data/lib/reactive_shipping.rb +26 -0
  19. data/lib/reactive_shipping/address_validation_response.rb +30 -0
  20. data/lib/reactive_shipping/carrier.rb +184 -0
  21. data/lib/reactive_shipping/carriers.rb +35 -0
  22. data/lib/reactive_shipping/carriers/australia_post.rb +248 -0
  23. data/lib/reactive_shipping/carriers/benchmark_carrier.rb +31 -0
  24. data/lib/reactive_shipping/carriers/bogus_carrier.rb +12 -0
  25. data/lib/reactive_shipping/carriers/canada_post.rb +263 -0
  26. data/lib/reactive_shipping/carriers/canada_post_pws.rb +908 -0
  27. data/lib/reactive_shipping/carriers/fedex.rb +797 -0
  28. data/lib/reactive_shipping/carriers/kunaki.rb +155 -0
  29. data/lib/reactive_shipping/carriers/new_zealand_post.rb +260 -0
  30. data/lib/reactive_shipping/carriers/shipwire.rb +178 -0
  31. data/lib/reactive_shipping/carriers/stamps.rb +860 -0
  32. data/lib/reactive_shipping/carriers/ups.rb +1060 -0
  33. data/lib/reactive_shipping/carriers/usps.rb +708 -0
  34. data/lib/reactive_shipping/carriers/usps_returns.rb +86 -0
  35. data/lib/reactive_shipping/delivery_date_estimate.rb +20 -0
  36. data/lib/reactive_shipping/delivery_date_estimates_response.rb +11 -0
  37. data/lib/reactive_shipping/errors.rb +35 -0
  38. data/lib/reactive_shipping/external_return_label_request.rb +417 -0
  39. data/lib/reactive_shipping/external_return_label_response.rb +26 -0
  40. data/lib/reactive_shipping/label.rb +10 -0
  41. data/lib/reactive_shipping/label_response.rb +10 -0
  42. data/lib/reactive_shipping/location.rb +166 -0
  43. data/lib/reactive_shipping/package.rb +165 -0
  44. data/lib/reactive_shipping/package_item.rb +60 -0
  45. data/lib/reactive_shipping/rate_estimate.rb +197 -0
  46. data/lib/reactive_shipping/rate_response.rb +33 -0
  47. data/lib/reactive_shipping/response.rb +44 -0
  48. data/lib/reactive_shipping/shipment_event.rb +22 -0
  49. data/lib/reactive_shipping/shipment_packer.rb +108 -0
  50. data/lib/reactive_shipping/shipping_response.rb +34 -0
  51. data/lib/reactive_shipping/tracking_response.rb +120 -0
  52. data/lib/reactive_shipping/version.rb +3 -0
  53. data/reactive_shipping.gemspec +38 -0
  54. data/shipit.rubygems.yml +1 -0
  55. data/test/console.rb +39 -0
  56. data/test/credentials.yml +76 -0
  57. data/test/fixtures/files/label1.pdf +0 -0
  58. data/test/fixtures/files/ups-shipping-label.gif +0 -0
  59. data/test/fixtures/json/australia_post/calculate_domestic.json +13 -0
  60. data/test/fixtures/json/australia_post/calculate_domestic_2.json +19 -0
  61. data/test/fixtures/json/australia_post/calculate_international.json +12 -0
  62. data/test/fixtures/json/australia_post/calculate_international_2.json +15 -0
  63. data/test/fixtures/json/australia_post/error_message.json +5 -0
  64. data/test/fixtures/json/australia_post/service_domestic.json +117 -0
  65. data/test/fixtures/json/australia_post/service_domestic_2.json +117 -0
  66. data/test/fixtures/json/australia_post/service_international.json +76 -0
  67. data/test/fixtures/json/australia_post/service_international_2.json +59 -0
  68. data/test/fixtures/json/newzealandpost/domestic_book.json +1 -0
  69. data/test/fixtures/json/newzealandpost/domestic_default.json +1 -0
  70. data/test/fixtures/json/newzealandpost/domestic_error.json +1 -0
  71. data/test/fixtures/json/newzealandpost/domestic_poster.json +1 -0
  72. data/test/fixtures/json/newzealandpost/domestic_small_half_pound.json +1 -0
  73. data/test/fixtures/json/newzealandpost/international_book.json +1 -0
  74. data/test/fixtures/json/newzealandpost/international_new_zealand_wii.json +1 -0
  75. data/test/fixtures/json/newzealandpost/international_small_half_pound.json +1 -0
  76. data/test/fixtures/json/newzealandpost/international_wii.json +1 -0
  77. data/test/fixtures/xml/canadapost/example_request.xml +25 -0
  78. data/test/fixtures/xml/canadapost/example_response.xml +130 -0
  79. data/test/fixtures/xml/canadapost/example_response_error.xml +16 -0
  80. data/test/fixtures/xml/canadapost/example_response_french.xml +122 -0
  81. data/test/fixtures/xml/canadapost/example_response_with_nil_value.xml +164 -0
  82. data/test/fixtures/xml/canadapost/example_response_with_postal_outlet.xml +155 -0
  83. data/test/fixtures/xml/canadapost/example_response_with_postal_outlet_french.xml +274 -0
  84. data/test/fixtures/xml/canadapost/example_response_with_strange_delivery_date.xml +130 -0
  85. data/test/fixtures/xml/canadapost_pws/dnc_tracking_details_en.xml +112 -0
  86. data/test/fixtures/xml/canadapost_pws/merchant_details_error.xml +7 -0
  87. data/test/fixtures/xml/canadapost_pws/merchant_details_response.xml +7 -0
  88. data/test/fixtures/xml/canadapost_pws/option_response.xml +13 -0
  89. data/test/fixtures/xml/canadapost_pws/option_response_no_conflicts.xml +7 -0
  90. data/test/fixtures/xml/canadapost_pws/rates_info.xml +190 -0
  91. data/test/fixtures/xml/canadapost_pws/rates_info_error.xml +7 -0
  92. data/test/fixtures/xml/canadapost_pws/receipt_response.xml +42 -0
  93. data/test/fixtures/xml/canadapost_pws/receipt_response_no_priced_options.xml +36 -0
  94. data/test/fixtures/xml/canadapost_pws/register_token_error.xml +7 -0
  95. data/test/fixtures/xml/canadapost_pws/register_token_response.xml +3 -0
  96. data/test/fixtures/xml/canadapost_pws/service_options_response.xml +42 -0
  97. data/test/fixtures/xml/canadapost_pws/services_error.xml +6 -0
  98. data/test/fixtures/xml/canadapost_pws/services_response.xml +32 -0
  99. data/test/fixtures/xml/canadapost_pws/shipment_domestic.xml +69 -0
  100. data/test/fixtures/xml/canadapost_pws/shipment_response.xml +20 -0
  101. data/test/fixtures/xml/canadapost_pws/shipment_us.xml +69 -0
  102. data/test/fixtures/xml/canadapost_pws/tracking_details_en.xml +152 -0
  103. data/test/fixtures/xml/canadapost_pws/tracking_details_en_error.xml +7 -0
  104. data/test/fixtures/xml/canadapost_pws/tracking_details_en_undelivered.xml +116 -0
  105. data/test/fixtures/xml/canadapost_pws/tracking_details_fr.xml +156 -0
  106. data/test/fixtures/xml/canadapost_pws/tracking_details_no_expected_delivery_date.xml +40 -0
  107. data/test/fixtures/xml/fedex/create_shipment_response.xml +2 -0
  108. data/test/fixtures/xml/fedex/freight_rate_request.xml +82 -0
  109. data/test/fixtures/xml/fedex/freight_rate_response.xml +506 -0
  110. data/test/fixtures/xml/fedex/invalid_fedex_reply.xml +27 -0
  111. data/test/fixtures/xml/fedex/ottawa_to_beverly_hills_commercial_rate_request.xml +79 -0
  112. data/test/fixtures/xml/fedex/ottawa_to_beverly_hills_no_saturday_rate_request.xml +79 -0
  113. data/test/fixtures/xml/fedex/ottawa_to_beverly_hills_rate_request.xml +80 -0
  114. data/test/fixtures/xml/fedex/ottawa_to_beverly_hills_rate_response.xml +214 -0
  115. data/test/fixtures/xml/fedex/raterequest_reply.xml +213 -0
  116. data/test/fixtures/xml/fedex/raterequest_response_with_ground_home_delivery.xml +206 -0
  117. data/test/fixtures/xml/fedex/reply_without_notifications.xml +185 -0
  118. data/test/fixtures/xml/fedex/tracking_request.xml +29 -0
  119. data/test/fixtures/xml/fedex/tracking_response_bad_tracking_number.xml +20 -0
  120. data/test/fixtures/xml/fedex/tracking_response_delivered_at_door.xml +254 -0
  121. data/test/fixtures/xml/fedex/tracking_response_delivered_at_facility.xml +403 -0
  122. data/test/fixtures/xml/fedex/tracking_response_delivered_with_signature.xml +269 -0
  123. data/test/fixtures/xml/fedex/tracking_response_empty_status_detail.xml +84 -0
  124. data/test/fixtures/xml/fedex/tracking_response_failure_code_9045.xml +52 -0
  125. data/test/fixtures/xml/fedex/tracking_response_failure_code_9080.xml +51 -0
  126. data/test/fixtures/xml/fedex/tracking_response_in_transit.xml +127 -0
  127. data/test/fixtures/xml/fedex/tracking_response_invalid_tracking_number.xml +52 -0
  128. data/test/fixtures/xml/fedex/tracking_response_missing_status_code.xml +89 -0
  129. data/test/fixtures/xml/fedex/tracking_response_multiple_results.xml +100 -0
  130. data/test/fixtures/xml/fedex/tracking_response_not_found.xml +52 -0
  131. data/test/fixtures/xml/fedex/tracking_response_shipment_exception.xml +209 -0
  132. data/test/fixtures/xml/fedex/tracking_response_unable_to_process.xml +32 -0
  133. data/test/fixtures/xml/fedex/tracking_response_with_blank_state.xml +107 -0
  134. data/test/fixtures/xml/fedex/unknown_fedex_document_reply.xml +3 -0
  135. data/test/fixtures/xml/kunaki/invalid_state_response.xml +3 -0
  136. data/test/fixtures/xml/kunaki/no_valid_items_response.xml +3 -0
  137. data/test/fixtures/xml/kunaki/successful_rates_response.xml +3 -0
  138. data/test/fixtures/xml/kunaki/unsuccessful_rates_response.xml +9 -0
  139. data/test/fixtures/xml/shipwire/international_rates_response.xml +17 -0
  140. data/test/fixtures/xml/shipwire/new_carrier_rate_response.xml +18 -0
  141. data/test/fixtures/xml/shipwire/no_rates_response.xml +7 -0
  142. data/test/fixtures/xml/shipwire/rates_response.xml +36 -0
  143. data/test/fixtures/xml/shipwire/rates_response_no_estimate.xml +14 -0
  144. data/test/fixtures/xml/stamps/authenticate_user_request.xml +15 -0
  145. data/test/fixtures/xml/stamps/authenticate_user_response.xml +10 -0
  146. data/test/fixtures/xml/stamps/cleanse_address_request.xml +19 -0
  147. data/test/fixtures/xml/stamps/cleanse_address_response.xml +27 -0
  148. data/test/fixtures/xml/stamps/create_indicium_request.xml +69 -0
  149. data/test/fixtures/xml/stamps/create_indicium_response.xml +40 -0
  150. data/test/fixtures/xml/stamps/expired_authenticator_response.xml +15 -0
  151. data/test/fixtures/xml/stamps/get_account_info_request.xml +11 -0
  152. data/test/fixtures/xml/stamps/get_account_info_response.xml +36 -0
  153. data/test/fixtures/xml/stamps/get_purchase_status_request.xml +12 -0
  154. data/test/fixtures/xml/stamps/get_purchase_status_response.xml +16 -0
  155. data/test/fixtures/xml/stamps/get_rates_request.xml +19 -0
  156. data/test/fixtures/xml/stamps/get_rates_response.xml +351 -0
  157. data/test/fixtures/xml/stamps/purchase_postage_request.xml +13 -0
  158. data/test/fixtures/xml/stamps/purchase_postage_response.xml +17 -0
  159. data/test/fixtures/xml/stamps/track_shipment_request.xml +12 -0
  160. data/test/fixtures/xml/stamps/track_shipment_response.xml +45 -0
  161. data/test/fixtures/xml/ups/access_request.xml +6 -0
  162. data/test/fixtures/xml/ups/delivered_shipment_with_refund.xml +290 -0
  163. data/test/fixtures/xml/ups/delivered_shipment_without_events_tracking_response.xml +62 -0
  164. data/test/fixtures/xml/ups/delivery_dates_response.xml +140 -0
  165. data/test/fixtures/xml/ups/example_tracking_response.xml +53 -0
  166. data/test/fixtures/xml/ups/in_transit_shipment.xml +183 -0
  167. data/test/fixtures/xml/ups/out_for_delivery_shipment.xml +165 -0
  168. data/test/fixtures/xml/ups/package_exceeds_maximum_length.xml +12 -0
  169. data/test/fixtures/xml/ups/rate_single_service.xml +54 -0
  170. data/test/fixtures/xml/ups/rescheduled_shipment.xml +204 -0
  171. data/test/fixtures/xml/ups/shipment_accept_response.xml +42 -0
  172. data/test/fixtures/xml/ups/shipment_confirm_response.xml +33 -0
  173. data/test/fixtures/xml/ups/shipment_from_tiger_direct.xml +222 -0
  174. data/test/fixtures/xml/ups/test_real_home_as_residential_destination_response.xml +290 -0
  175. data/test/fixtures/xml/ups/test_real_home_as_residential_destination_response_with_insured.xml +289 -0
  176. data/test/fixtures/xml/ups/test_real_home_as_residential_destination_with_origin_account_response.xml +311 -0
  177. data/test/fixtures/xml/ups/tracking_request.xml +9 -0
  178. data/test/fixtures/xml/ups/triple_accept_response.xml +72 -0
  179. data/test/fixtures/xml/ups/triple_confirm_response.xml +32 -0
  180. data/test/fixtures/xml/ups/void_shipment_response.xml +11 -0
  181. data/test/fixtures/xml/usps/api_error_rate_response.xml +53 -0
  182. data/test/fixtures/xml/usps/beverly_hills_to_new_york_book_commercial_base_rate_response.xml +2 -0
  183. data/test/fixtures/xml/usps/beverly_hills_to_new_york_book_commercial_plus_rate_response.xml +258 -0
  184. data/test/fixtures/xml/usps/beverly_hills_to_new_york_book_rate_response.xml +108 -0
  185. data/test/fixtures/xml/usps/beverly_hills_to_ottawa_american_wii_commercial_base_rate_response.xml +84 -0
  186. data/test/fixtures/xml/usps/beverly_hills_to_ottawa_american_wii_commercial_plus_rate_response.xml +212 -0
  187. data/test/fixtures/xml/usps/beverly_hills_to_ottawa_american_wii_rate_response.xml +230 -0
  188. data/test/fixtures/xml/usps/first_class_packages_with_invalid_mail_type_response.xml +12 -0
  189. data/test/fixtures/xml/usps/first_class_packages_with_mail_type_response.xml +16 -0
  190. data/test/fixtures/xml/usps/first_class_packages_without_mail_type_response.xml +12 -0
  191. data/test/fixtures/xml/usps/invalid_xml_response.xml +10 -0
  192. data/test/fixtures/xml/usps/invalid_xml_tracking_response_error.xml +2 -0
  193. data/test/fixtures/xml/usps/tracking_request.xml +10 -0
  194. data/test/fixtures/xml/usps/tracking_request_batch.xml +12 -0
  195. data/test/fixtures/xml/usps/tracking_response.xml +162 -0
  196. data/test/fixtures/xml/usps/tracking_response_alt.xml +53 -0
  197. data/test/fixtures/xml/usps/tracking_response_batch.xml +231 -0
  198. data/test/fixtures/xml/usps/tracking_response_failure.xml +11 -0
  199. data/test/fixtures/xml/usps/tracking_response_not_available.xml +12 -0
  200. data/test/fixtures/xml/usps/tracking_response_test_error.xml +8 -0
  201. data/test/fixtures/xml/usps/us_rate_request.xml +18 -0
  202. data/test/fixtures/xml/usps/us_rate_request_large.xml +18 -0
  203. data/test/fixtures/xml/usps/world_rate_request_only_country.xml +22 -0
  204. data/test/fixtures/xml/usps/world_rate_request_with_value.xml +24 -0
  205. data/test/fixtures/xml/usps/world_rate_request_without_value.xml +24 -0
  206. data/test/fixtures/xml/usps_returns/external_return_label_response.xml +2 -0
  207. data/test/fixtures/xml/usps_returns/external_return_label_response_failure.xml +10 -0
  208. data/test/remote/australia_post_test.rb +140 -0
  209. data/test/remote/canada_post_pws_platform_test.rb +259 -0
  210. data/test/remote/canada_post_pws_test.rb +169 -0
  211. data/test/remote/canada_post_test.rb +55 -0
  212. data/test/remote/fedex_test.rb +400 -0
  213. data/test/remote/kunaki_test.rb +37 -0
  214. data/test/remote/new_zealand_post_test.rb +149 -0
  215. data/test/remote/shipwire_test.rb +84 -0
  216. data/test/remote/stamps_test.rb +396 -0
  217. data/test/remote/usps_returns_test.rb +72 -0
  218. data/test/remote/usps_test.rb +243 -0
  219. data/test/test_helper.rb +296 -0
  220. data/test/unit/carrier_test.rb +130 -0
  221. data/test/unit/carriers/australia_post_test.rb +181 -0
  222. data/test/unit/carriers/benchmark_test.rb +18 -0
  223. data/test/unit/carriers/canada_post_pws_rating_test.rb +379 -0
  224. data/test/unit/carriers/canada_post_pws_register_test.rb +76 -0
  225. data/test/unit/carriers/canada_post_pws_shipping_test.rb +258 -0
  226. data/test/unit/carriers/canada_post_pws_test.rb +59 -0
  227. data/test/unit/carriers/canada_post_pws_tracking_test.rb +154 -0
  228. data/test/unit/carriers/canada_post_test.rb +148 -0
  229. data/test/unit/carriers/fedex_test.rb +693 -0
  230. data/test/unit/carriers/kunaki_test.rb +56 -0
  231. data/test/unit/carriers/new_zealand_post_test.rb +177 -0
  232. data/test/unit/carriers/shipwire_test.rb +188 -0
  233. data/test/unit/carriers/stamps_test.rb +245 -0
  234. data/test/unit/carriers/ups_test.rb +580 -0
  235. data/test/unit/carriers/usps_returns_test.rb +45 -0
  236. data/test/unit/carriers/usps_test.rb +633 -0
  237. data/test/unit/carriers_test.rb +16 -0
  238. data/test/unit/external_return_label_request_test.rb +258 -0
  239. data/test/unit/location_test.rb +234 -0
  240. data/test/unit/package_item_test.rb +232 -0
  241. data/test/unit/package_test.rb +404 -0
  242. data/test/unit/rate_estimate_test.rb +93 -0
  243. data/test/unit/response_test.rb +38 -0
  244. data/test/unit/shipment_event_test.rb +20 -0
  245. data/test/unit/shipment_packer_test.rb +212 -0
  246. data/test/unit/tracking_response_test.rb +41 -0
  247. metadata +684 -0
@@ -0,0 +1,580 @@
1
+ require 'test_helper'
2
+
3
+ class UPSTest < ActiveSupport::TestCase
4
+ include ReactiveShipping::Test::Fixtures
5
+
6
+ def setup
7
+ @carrier = UPS.new(
8
+ :key => 'key',
9
+ :login => 'login',
10
+ :password => 'password'
11
+ )
12
+ @tracking_response = xml_fixture('ups/shipment_from_tiger_direct')
13
+ @delivery_dates_response = xml_fixture('ups/delivery_dates_response')
14
+ end
15
+
16
+ def test_initialize_options_requirements
17
+ assert_raises(ArgumentError) { UPS.new }
18
+ assert_raises(ArgumentError) { UPS.new(:login => 'blah', :password => 'bloo') }
19
+ assert_raises(ArgumentError) { UPS.new(:login => 'blah', :key => 'kee') }
20
+ assert_raises(ArgumentError) { UPS.new(:password => 'bloo', :key => 'kee') }
21
+ assert UPS.new(:login => 'blah', :password => 'bloo', :key => 'kee')
22
+ end
23
+
24
+ def test_find_tracking_info_should_create_correct_xml
25
+ xml_request = xml_fixture('ups/access_request') + xml_fixture('ups/tracking_request')
26
+ @carrier.expects(:commit).with(:track, xml_request, true).returns(@tracking_response)
27
+ @carrier.find_tracking_info('1Z5FX0076803466397', :tracking_option => '03', :test => true)
28
+ end
29
+
30
+ def test_find_tracking_info_should_return_a_tracking_response
31
+ @carrier.expects(:commit).returns(@tracking_response)
32
+ assert_equal 'ReactiveShipping::TrackingResponse', @carrier.find_tracking_info('1Z5FX0076803466397').class.name
33
+ end
34
+
35
+ def test_find_tracking_info_should_mark_shipment_as_delivered
36
+ @carrier.expects(:commit).returns(@tracking_response)
37
+ assert_equal true, @carrier.find_tracking_info('1Z5FX0076803466397').delivered?
38
+ end
39
+
40
+ def test_find_tracking_info_should_return_correct_carrier
41
+ @carrier.expects(:commit).returns(@tracking_response)
42
+ assert_equal :ups, @carrier.find_tracking_info('1Z5FX0076803466397').carrier
43
+ end
44
+
45
+ def test_find_tracking_info_should_return_correct_carrier_name
46
+ @carrier.expects(:commit).returns(@tracking_response)
47
+ assert_equal 'UPS', @carrier.find_tracking_info('1Z5FX0076803466397').carrier_name
48
+ end
49
+
50
+ def test_find_tracking_info_should_return_correct_status
51
+ @carrier.expects(:commit).returns(@tracking_response)
52
+ assert_equal :delivered, @carrier.find_tracking_info('1Z5FX0076803466397').status
53
+ end
54
+
55
+ def test_find_tracking_info_should_return_correct_status_code
56
+ @carrier.expects(:commit).returns(@tracking_response)
57
+ assert_equal 'd', @carrier.find_tracking_info('1Z5FX0076803466397').status_code.downcase
58
+ end
59
+
60
+ def test_find_tracking_info_should_return_correct_status_description
61
+ @carrier.expects(:commit).returns(@tracking_response)
62
+ assert_equal 'delivered', @carrier.find_tracking_info('1Z5FX0076803466397').status_description.downcase
63
+ end
64
+
65
+ def test_find_tracking_info_should_return_delivery_signature
66
+ @carrier.expects(:commit).returns(@tracking_response)
67
+ assert_equal 'MCAULEY', @carrier.find_tracking_info('1Z5FX0076803466397').delivery_signature
68
+ end
69
+
70
+ def test_find_tracking_info_should_have_an_out_for_delivery_status
71
+ out_for_delivery_tracking_response = xml_fixture('ups/out_for_delivery_shipment')
72
+ @carrier.expects(:commit).returns(out_for_delivery_tracking_response)
73
+ assert_equal :out_for_delivery, @carrier.find_tracking_info('1Z5FX0076803466397').status
74
+ end
75
+
76
+ def test_find_tracking_info_should_return_destination_address
77
+ @carrier.expects(:commit).returns(@tracking_response)
78
+ result = @carrier.find_tracking_info('1Z5FX0076803466397')
79
+ assert_equal 'ottawa', result.destination.city.downcase
80
+ assert_equal 'ON', result.destination.state
81
+ end
82
+
83
+ def test_find_tracking_info_should_return_destination_address_for_abbreviated_response
84
+ tracking_response = xml_fixture('ups/delivered_shipment_without_events_tracking_response')
85
+ @carrier.expects(:commit).returns(tracking_response)
86
+ result = @carrier.find_tracking_info('1Z5FX0076803466397')
87
+ assert_equal 'cypress', result.destination.city.downcase
88
+ assert_equal 'TX', result.destination.state
89
+ end
90
+
91
+ def test_find_tracking_info_should_return_delivered_if_event_is_not_latest
92
+ tracking_response = xml_fixture('ups/delivered_shipment_with_refund')
93
+ @carrier.expects(:commit).returns(tracking_response)
94
+ result = @carrier.find_tracking_info('1Z5FX0076803466397')
95
+ assert_equal :delivered, result.status
96
+ assert_equal true, result.delivered?
97
+ end
98
+
99
+ def test_find_tracking_info_should_return_origin_address
100
+ @carrier.expects(:commit).returns(@tracking_response)
101
+ result = @carrier.find_tracking_info('1Z5FX0076803466397')
102
+ assert_equal 'naperville', result.origin.city.downcase
103
+ assert_equal 'IL', result.origin.state
104
+ end
105
+
106
+ def test_find_tracking_info_should_parse_response_into_correct_number_of_shipment_events
107
+ @carrier.expects(:commit).returns(@tracking_response)
108
+ response = @carrier.find_tracking_info('1Z5FX0076803466397')
109
+ assert_equal 8, response.shipment_events.size
110
+ end
111
+
112
+ def test_find_tracking_info_should_return_shipment_events_in_ascending_chronological_order
113
+ @carrier.expects(:commit).returns(@tracking_response)
114
+ response = @carrier.find_tracking_info('1Z5FX0076803466397')
115
+ assert_equal response.shipment_events.map(&:time).sort, response.shipment_events.map(&:time)
116
+ end
117
+
118
+ def test_find_tracking_info_should_have_correct_names_for_shipment_events
119
+ @carrier.expects(:commit).returns(@tracking_response)
120
+ response = @carrier.find_tracking_info('1Z5FX0076803466397')
121
+ assert_equal ["BILLING INFORMATION RECEIVED",
122
+ "IMPORT SCAN",
123
+ "LOCATION SCAN",
124
+ "LOCATION SCAN",
125
+ "DEPARTURE SCAN",
126
+ "ARRIVAL SCAN",
127
+ "OUT FOR DELIVERY",
128
+ "DELIVERED"], response.shipment_events.map(&:name)
129
+ end
130
+
131
+ def test_find_tracking_info_should_have_correct_type_codes_for_shipment_events
132
+ @carrier.expects(:commit).returns(@tracking_response)
133
+ response = @carrier.find_tracking_info('1Z5FX0076803466397')
134
+ assert_equal ["M", "I", "I", "I", "I", "I", "I", "D"], response.shipment_events.map(&:type_code)
135
+ end
136
+
137
+ def test_add_origin_and_destination_data_to_shipment_events_where_appropriate
138
+ @carrier.expects(:commit).returns(@tracking_response)
139
+ response = @carrier.find_tracking_info('1Z5FX0076803466397')
140
+ assert_equal '175 AMBASSADOR', response.shipment_events.first.location.address1
141
+ assert_equal 'K1N5X8', response.shipment_events.last.location.postal_code
142
+ end
143
+
144
+ def test_find_tracking_info_should_return_correct_actual_delivery_date
145
+ @carrier.expects(:commit).returns(@tracking_response)
146
+ response = @carrier.find_tracking_info('1Z5FX0076803466397')
147
+ assert_equal Time.parse('2008-06-25 11:19:00 UTC'), response.actual_delivery_date
148
+ end
149
+
150
+ def test_find_tracking_info_should_return_correct_rescheduled_delivery_date
151
+ @carrier.expects(:commit).returns(xml_fixture('ups/rescheduled_shipment'))
152
+ response = @carrier.find_tracking_info('1Z5FX0076803466397')
153
+ assert_equal Time.parse('2015-01-29 00:00:00 UTC'), response.scheduled_delivery_date
154
+ end
155
+
156
+ def test_response_parsing_an_oversize_package
157
+ mock_response = xml_fixture('ups/package_exceeds_maximum_length')
158
+ @carrier.expects(:commit).returns(mock_response)
159
+
160
+ e = assert_raises(ReactiveShipping::ResponseError) do
161
+ @carrier.find_rates(location_fixtures[:beverly_hills],
162
+ location_fixtures[:real_home_as_residential],
163
+ package_fixtures.values_at(:chocolate_stuff))
164
+ end
165
+
166
+ assert_equal "Failure: Package exceeds the maximum length constraint of 108 inches. Length is the longest side of a package.", e.message
167
+ end
168
+
169
+ def test_response_parsing_an_unknown_error
170
+ mock_response = '<RatingServiceSelectionResponse><Response><ResponseStatusCode>0</ResponseStatusCode></Response></RatingServiceSelectionResponse>'
171
+ @carrier.expects(:commit).returns(mock_response)
172
+
173
+ e = assert_raises(ReactiveShipping::ResponseError) do
174
+ @carrier.find_rates(location_fixtures[:beverly_hills],
175
+ location_fixtures[:real_home_as_residential],
176
+ package_fixtures.values_at(:chocolate_stuff))
177
+ end
178
+
179
+ assert_equal "UPS could not process the request.", e.message
180
+ end
181
+
182
+ def test_response_parsing
183
+ mock_response = xml_fixture('ups/test_real_home_as_residential_destination_response')
184
+ @carrier.expects(:commit).returns(mock_response)
185
+ response = @carrier.find_rates( location_fixtures[:beverly_hills],
186
+ location_fixtures[:real_home_as_residential],
187
+ package_fixtures.values_at(:chocolate_stuff))
188
+ assert_equal ["UPS Ground",
189
+ "UPS Three-Day Select",
190
+ "UPS Second Day Air",
191
+ "UPS Next Day Air Saver",
192
+ "UPS Next Day Air Early A.M.",
193
+ "UPS Next Day Air"], response.rates.map(&:service_name)
194
+ assert_equal [992, 2191, 3007, 5509, 9401, 6124], response.rates.map(&:price)
195
+ assert_equal [0, 0, 0, 0, 0, 0], response.rates.map(&:negotiated_rate)
196
+ end
197
+
198
+ def test_response_with_insured_value
199
+ mock_response = xml_fixture('ups/test_real_home_as_residential_destination_response_with_insured')
200
+ @carrier.expects(:commit).returns(mock_response)
201
+ response = @carrier.find_rates( location_fixtures[:beverly_hills],
202
+ location_fixtures[:real_home_as_residential],
203
+ package_fixtures.values_at(:declared_value))
204
+ assert_equal ["UPS Ground",
205
+ "UPS Three-Day Select",
206
+ "UPS Second Day Air",
207
+ "UPS Next Day Air Saver",
208
+ "UPS Next Day Air Early A.M.",
209
+ "UPS Next Day Air"], response.rates.map(&:service_name)
210
+ assert_equal [2254, 4002, 5107, 8726, 12730, 9430], response.rates.map(&:price)
211
+ assert_equal [850, 850, 850, 850, 850, 850], response.rates.map(&:insurance_price)
212
+ assert_equal [0, 0, 0, 0, 0, 0], response.rates.map(&:negotiated_rate)
213
+ end
214
+
215
+ def test_response_with_origin_account_parsing
216
+ mock_response = xml_fixture('ups/test_real_home_as_residential_destination_with_origin_account_response')
217
+ @carrier.expects(:commit).returns(mock_response)
218
+ response = @carrier.find_rates( location_fixtures[:beverly_hills],
219
+ location_fixtures[:real_home_as_residential],
220
+ package_fixtures[:chocolate_stuff])
221
+ assert_equal ["UPS Express",
222
+ "UPS Worldwide Expedited",
223
+ "UPS Worldwide Express Plus",
224
+ "UPS Saver"], response.rates.map(&:service_name)
225
+ assert_equal [18893, 17856, 23473, 18286], response.rates.map(&:price)
226
+ assert_equal [18704, 17677, 23238, 18103], response.rates.map(&:negotiated_rate)
227
+ end
228
+
229
+ def test_delivery_range_takes_weekend_into_consideration
230
+ mock_response = xml_fixture('ups/test_real_home_as_residential_destination_response')
231
+ @carrier.expects(:commit).returns(mock_response)
232
+ Timecop.freeze(DateTime.new(2012, 6, 15))
233
+ response = @carrier.find_rates( location_fixtures[:beverly_hills],
234
+ location_fixtures[:real_home_as_residential],
235
+ package_fixtures.values_at(:chocolate_stuff))
236
+
237
+ date_test = [nil, 3, 2, 1, 1, 1].map do |days|
238
+ if days.nil?
239
+ nil
240
+ else
241
+ DateTime.now.utc + days.day + 2.day
242
+ end
243
+ end
244
+ Timecop.return
245
+ assert_equal date_test, response.rates.map(&:delivery_date)
246
+ end
247
+
248
+ def test_maximum_weight
249
+ assert Package.new(150 * 16, [5, 5, 5], :units => :imperial).mass == @carrier.maximum_weight
250
+ assert Package.new((150 * 16) + 0.01, [5, 5, 5], :units => :imperial).mass > @carrier.maximum_weight
251
+ assert Package.new((150 * 16) - 0.01, [5, 5, 5], :units => :imperial).mass < @carrier.maximum_weight
252
+ end
253
+
254
+ def test_obtain_multiple_labels
255
+ confirm_response = xml_fixture('ups/triple_confirm_response')
256
+ accept_response = xml_fixture('ups/triple_accept_response')
257
+ @carrier.stubs(:commit).returns(confirm_response, accept_response)
258
+
259
+ response = @carrier.create_shipment(
260
+ location_fixtures[:beverly_hills],
261
+ location_fixtures[:new_york],
262
+ package_fixtures.values_at(:chocolate_stuff, :book, :american_wii),
263
+ :test => true,
264
+ :destination => {
265
+ :company_name => 'N.A.',
266
+ :phone_number => '123-123-1234',
267
+ :attention_name => 'Jane Doe'
268
+ }
269
+
270
+ )
271
+
272
+ # Sanity checks. Hmm. That looks a lot like a type check.
273
+ assert_instance_of LabelResponse, response
274
+ assert_equal 3, response.labels.count
275
+
276
+ # These tracking numbers are part of the fixture data. What we're trying
277
+ # to verify is that the data in the XML is extracted properly.
278
+ tracking = response.labels.map { |label| label.tracking_number }
279
+ assert_includes tracking, "1ZA03R691594829862"
280
+ assert_includes tracking, "1ZA03R691592132475"
281
+ assert_includes tracking, "1ZA03R691590470881"
282
+
283
+ pictures = response.labels.map { |label| label.img_data }
284
+ refute_includes pictures, nil
285
+ end
286
+
287
+ def test_obtain_single_label
288
+ confirm_response = xml_fixture('ups/shipment_confirm_response')
289
+ accept_response = xml_fixture('ups/shipment_accept_response')
290
+ @carrier.stubs(:commit).returns(confirm_response, accept_response)
291
+
292
+ response = @carrier.create_shipment(
293
+ location_fixtures[:beverly_hills],
294
+ location_fixtures[:new_york],
295
+ package_fixtures.values_at(:chocolate_stuff),
296
+ :test => true,
297
+ :destination => {
298
+ :company_name => 'N.A.',
299
+ :phone_number => '123-123-1234',
300
+ :attention_name => 'Jane Doe'
301
+ }
302
+
303
+ )
304
+
305
+ # Sanity checks. Hmm. That looks a lot like a type check.
306
+ assert_instance_of LabelResponse, response
307
+ assert_equal 1, response.labels.count
308
+
309
+ # These tracking numbers are part of the fixture data. What we're trying
310
+ # to verify is that the data in the XML is extracted properly.
311
+ tracking = response.labels.map { |label| label.tracking_number }
312
+ assert_includes tracking, "1ZA03R691591538440"
313
+
314
+ pictures = response.labels.map { |label| label.img_data }
315
+ refute_includes pictures, nil
316
+ end
317
+
318
+ def test_saturday_delivery
319
+ response = Nokogiri::XML @carrier.send(:build_shipment_request,
320
+ location_fixtures[:beverly_hills],
321
+ location_fixtures[:annapolis],
322
+ package_fixtures.values_at(:chocolate_stuff),
323
+ :test => true,
324
+ :saturday_delivery => true
325
+ )
326
+
327
+ saturday = response.search '/ShipmentConfirmRequest/Shipment/ShipmentServiceOptions/SaturdayDelivery'
328
+ refute_empty saturday
329
+ end
330
+
331
+ def test_label_request_prepay
332
+ response = Nokogiri::XML @carrier.send(:build_shipment_request,
333
+ location_fixtures[:beverly_hills],
334
+ location_fixtures[:annapolis],
335
+ package_fixtures.values_at(:chocolate_stuff),
336
+ :test => true,
337
+ :prepay => true
338
+ )
339
+
340
+ prepay = response.search '/ShipmentConfirmRequest/Shipment/PaymentInformation/Prepaid'
341
+ refute_empty prepay
342
+ end
343
+
344
+ def test_label_request_bill_third_party
345
+ expected_account_number = "A01B24"
346
+ expected_postal_code_number = "97013"
347
+ expected_country_code = "US"
348
+ response = Nokogiri::XML @carrier.send(:build_shipment_request,
349
+ location_fixtures[:beverly_hills],
350
+ location_fixtures[:annapolis],
351
+ package_fixtures.values_at(:chocolate_stuff),
352
+ :test => true,
353
+ :bill_third_party => true,
354
+ :billing_account => expected_account_number,
355
+ :billing_zip => expected_postal_code_number,
356
+ :billing_country => expected_country_code)
357
+
358
+ assert_equal expected_account_number, response.search('ShipmentConfirmRequest/Shipment/PaymentInformation/BillThirdParty/BillThirdPartyShipper/AccountNumber').text
359
+ assert_equal expected_postal_code_number, response.search('/ShipmentConfirmRequest/Shipment/PaymentInformation/BillThirdParty/BillThirdPartyShipper/ThirdParty/Address/PostalCode').text
360
+ assert_equal expected_country_code, response.search('/ShipmentConfirmRequest/Shipment/PaymentInformation/BillThirdParty/BillThirdPartyShipper/ThirdParty/Address/CountryCode').text
361
+ end
362
+
363
+ def test_label_request_negotiated_rates_presence
364
+ response = Nokogiri::XML @carrier.send(:build_shipment_request,
365
+ location_fixtures[:beverly_hills],
366
+ location_fixtures[:annapolis],
367
+ package_fixtures.values_at(:chocolate_stuff),
368
+ :test => true,
369
+ :saturday_delivery => true,
370
+ :origin_account => 'A01B23' # without this option, a negotiated rate will not be requested
371
+ )
372
+
373
+ negotiated_rates = response.search '/ShipmentConfirmRequest/Shipment/RateInformation/NegotiatedRatesIndicator'
374
+ refute_empty negotiated_rates
375
+ end
376
+
377
+ def test_label_request_different_shipper
378
+ pickup = location_fixtures[:beverly_hills]
379
+ deliver = location_fixtures[:annapolis]
380
+ shipper = location_fixtures[:fake_google_as_commercial]
381
+ packages = package_fixtures.values_at(:chocolate_stuff)
382
+
383
+ result = Nokogiri::XML(@carrier.send(:build_shipment_request,
384
+ pickup, deliver, packages, :test => true, :shipper => shipper ))
385
+
386
+ address = result.search '/ShipmentConfirmRequest/Shipment/Shipper/Address/AddressLine1'
387
+ assert_equal address.text, shipper.address1
388
+ refute_equal address.text, pickup.address1
389
+ end
390
+
391
+ def test_label_request_domestic_reference_numbers
392
+ # Domestic Shipments use package level reference numbers
393
+ response = Nokogiri::XML @carrier.send(:build_shipment_request,
394
+ location_fixtures[:beverly_hills],
395
+ location_fixtures[:annapolis],
396
+ package_fixtures.values_at(:chocolate_stuff),
397
+ :test => true,
398
+ :reference_numbers => [{value: 'REF_NUM'}]
399
+ )
400
+ ref_vals = response.search '/ShipmentConfirmRequest/Shipment/Package/ReferenceNumber/Value'
401
+ assert_equal ref_vals.first.text, 'REF_NUM'
402
+ end
403
+
404
+ def test_label_request_international_reference_numbers
405
+ # International Shipments use shipment level reference numbers
406
+ response = Nokogiri::XML @carrier.send(:build_shipment_request,
407
+ location_fixtures[:beverly_hills],
408
+ location_fixtures[:ottawa_with_name],
409
+ package_fixtures.values_at(:books),
410
+ :test => true,
411
+ :reference_numbers => [{value: 'REF_NUM'}]
412
+ )
413
+ ref_vals = response.search '/ShipmentConfirmRequest/Shipment/ReferenceNumber/Value'
414
+ assert_equal ref_vals.first.text, 'REF_NUM'
415
+ end
416
+
417
+ def test_label_request_international_with_paperless_invoice
418
+ response = Nokogiri::XML @carrier.send(:build_shipment_request,
419
+ location_fixtures[:beverly_hills],
420
+ location_fixtures[:ottawa_with_name],
421
+ package_fixtures.values_at(:books),
422
+ :test => true,
423
+ :paperless_invoice => true
424
+ )
425
+ international_form = response.search '/ShipmentConfirmRequest/Shipment/ShipmentServiceOptions/InternationalForms'
426
+ refute_empty international_form
427
+ end
428
+
429
+ def test_label_request_international_with_delivery_duty_paid
430
+ # setting terms_of_shipment to DDP, Delivery Duty Paid, means the shipper will pay duties and taxes
431
+ response = Nokogiri::XML @carrier.send(:build_shipment_request,
432
+ location_fixtures[:beverly_hills],
433
+ location_fixtures[:ottawa_with_name],
434
+ package_fixtures.values_at(:books),
435
+ :test => true,
436
+ :paperless_invoice => true,
437
+ :terms_of_shipment => 'DDP'
438
+ )
439
+ terms_of_shipment = response.search '/ShipmentConfirmRequest/Shipment/ShipmentServiceOptions/InternationalForms/TermsOfShipment'
440
+ duties_and_taxes_payment_info = response.css('ShipmentCharge Type:contains("02")').first.parent
441
+
442
+ refute_empty terms_of_shipment
443
+ refute_empty duties_and_taxes_payment_info.search('BillShipper')
444
+ end
445
+
446
+ def test_label_request_shipment_level_delivery_confirmation
447
+ result = Nokogiri::XML(@carrier.send(:build_shipment_request,
448
+ location_fixtures[:beverly_hills],
449
+ location_fixtures[:ottawa_with_name],
450
+ package_fixtures.values_at(:chocolate_stuff),
451
+ :test => true,
452
+ :delivery_confirmation => :delivery_confirmation_adult_signature_required))
453
+ assert_equal '2', result.search('/ShipmentConfirmRequest/Shipment/ShipmentServiceOptions/DeliveryConfirmation/DCISType').text
454
+ end
455
+
456
+ def test_label_request_package_level_delivery_confirmation
457
+ packages = package_fixtures.values_at(:chocolate_stuff)
458
+ packages.each {|p| p.options[:delivery_confirmation] = :delivery_confirmation }
459
+ result = Nokogiri::XML(@carrier.send(:build_shipment_request,
460
+ location_fixtures[:beverly_hills],
461
+ location_fixtures[:annapolis],
462
+ packages,
463
+ :test => true))
464
+ assert_equal '1', result.search('/ShipmentConfirmRequest/Shipment/Package/PackageServiceOptions/DeliveryConfirmation/DCISType').text
465
+ end
466
+
467
+ def test_label_request_shipment_level_delivery_confirmation_moved_to_package_level
468
+ # Domestic shipments should have their delivery confirmation specified at package level and not shipment-level
469
+ result = Nokogiri::XML(@carrier.send(:build_shipment_request,
470
+ location_fixtures[:beverly_hills],
471
+ location_fixtures[:annapolis],
472
+ package_fixtures.values_at(:chocolate_stuff),
473
+ :test => true,
474
+ :delivery_confirmation => :delivery_confirmation))
475
+ assert_equal '1', result.search('/ShipmentConfirmRequest/Shipment/Package/PackageServiceOptions/DeliveryConfirmation/DCISType').text
476
+ assert_empty result.search('/ShipmentConfirmRequest/Shipment/ShipmentServiceOptions/DeliveryConfirmation/DCISType').text
477
+ end
478
+
479
+ def test_get_delivery_date_estimates_can_parse_delivery_estimates
480
+ @carrier.expects(:commit).returns(@delivery_dates_response)
481
+ monday = Date.parse('0201', '%m%d') # Feb to avoid holidays http://www.ups.com/content/us/en/resources/ship/imp_exp/operation.html
482
+ monday += 1.day while monday.wday != 1
483
+
484
+ response = @carrier.get_delivery_date_estimates(
485
+ location_fixtures[:new_york_with_name],
486
+ location_fixtures[:real_home_as_residential],
487
+ package_fixtures.values_at(:books),
488
+ pickup_date=monday,
489
+ {
490
+ :test => true
491
+ }
492
+ )
493
+ assert response.is_a?(ReactiveShipping::DeliveryDateEstimatesResponse)
494
+ assert_equal 6, response.delivery_estimates.size
495
+ ground_estimate = response.delivery_estimates.select{ |de| de.service_name == "UPS Ground"}.first
496
+ assert_equal Date.parse('2015-02-5'), ground_estimate.date
497
+ assert_equal 3, ground_estimate.business_transit_days
498
+ end
499
+
500
+ def test_get_delivery_date_estimates_can_translate_service_codes
501
+ # The TimeInTransit API returns service codes that are different from those used by
502
+ # other API's. So we need to translate the codes into the ones used elsewhere.
503
+ @carrier.expects(:commit).returns(@delivery_dates_response)
504
+ monday = Date.parse('0201', '%m%d') # Feb to avoid holidays http://www.ups.com/content/us/en/resources/ship/imp_exp/operation.html
505
+ monday += 1.day while monday.wday != 1
506
+
507
+ response = @carrier.get_delivery_date_estimates(
508
+ location_fixtures[:new_york_with_name],
509
+ location_fixtures[:real_home_as_residential],
510
+ package_fixtures.values_at(:books),
511
+ pickup_date=monday,
512
+ {
513
+ :test => true
514
+ }
515
+ )
516
+
517
+ response.delivery_estimates.each do |delivery_estimate|
518
+ assert delivery_estimate.service_name, UPS::DEFAULT_SERVICES[delivery_estimate.service_code]
519
+ end
520
+ end
521
+
522
+ def test_get_rates_for_single_serivce
523
+ mock_response = xml_fixture("ups/rate_single_service")
524
+ @carrier.expects(:commit).returns(mock_response)
525
+
526
+ response = @carrier.find_rates(
527
+ location_fixtures[:new_york_with_name],
528
+ location_fixtures[:real_home_as_residential],
529
+ package_fixtures.values_at(:books),
530
+ {
531
+ :service => UPS::DEFAULT_SERVICE_NAME_TO_CODE["UPS Ground"],
532
+ :test => true
533
+ }
534
+ )
535
+ assert_equal ["UPS Ground"], response.rates.map(&:service_name)
536
+ end
537
+
538
+ def test_void_shipment
539
+ mock_response = xml_fixture("ups/void_shipment_response")
540
+ @carrier.expects(:commit).returns(mock_response)
541
+ response = @carrier.void_shipment('1Z12345E0390817264')
542
+ assert response
543
+ end
544
+
545
+ def test_maximum_address_field_length
546
+ assert_equal 35, @carrier.maximum_address_field_length
547
+ end
548
+
549
+ def test_package_surepost_less_than_one_lb_service
550
+ xml_builder = Nokogiri::XML::Builder.new do |xml|
551
+ @carrier.send(:build_package_node,
552
+ xml,
553
+ package_fixtures[:small_half_pound],
554
+ {
555
+ :service => "92",
556
+ :imperial => true
557
+ }
558
+ )
559
+ end
560
+ request = Nokogiri::XML(xml_builder.to_xml)
561
+ assert_equal 'OZS', request.search('/Package/PackageWeight/UnitOfMeasurement/Code').text
562
+ assert_equal '8.0', request.search('/Package/PackageWeight/Weight').text
563
+ end
564
+
565
+ def test_package_surepost_less_than_one_lb_service_code
566
+ xml_builder = Nokogiri::XML::Builder.new do |xml|
567
+ @carrier.send(:build_package_node,
568
+ xml,
569
+ package_fixtures[:small_half_pound],
570
+ {
571
+ :service_code => "92",
572
+ :imperial => true
573
+ }
574
+ )
575
+ end
576
+ request = Nokogiri::XML(xml_builder.to_xml)
577
+ assert_equal 'OZS', request.search('/Package/PackageWeight/UnitOfMeasurement/Code').text
578
+ assert_equal '8.0', request.search('/Package/PackageWeight/Weight').text
579
+ end
580
+ end