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,148 @@
1
+ require 'test_helper'
2
+
3
+ class CanadaPostTest < ActiveSupport::TestCase
4
+ include ReactiveShipping::Test::Fixtures
5
+
6
+ def setup
7
+ login = { login: 'CPC_DEMO_XML' }
8
+
9
+ @carrier = CanadaPost.new(login)
10
+ @french_carrier = CanadaPost.new(login.merge(french: true))
11
+
12
+ @request = xml_fixture('canadapost/example_request')
13
+ @response = xml_fixture('canadapost/example_response')
14
+ @response_french = xml_fixture('canadapost/example_response_french')
15
+ @bad_response = xml_fixture('canadapost/example_response_error')
16
+
17
+ @origin = {:address1 => "61A York St", :city => "Ottawa", :province => "ON", :country => "Canada", :postal_code => "K1N 5T2"}
18
+ @destination = {:city => "Beverly Hills", :state => "CA", :country => "United States", :postal_code => "90210"}
19
+ @line_items = [Package.new(500, [2, 3, 4], :description => "a box full of stuff", :value => 2500)]
20
+ end
21
+
22
+ def test_parse_rate_response_french
23
+ @french_carrier.expects(:ssl_post).returns(@response_french)
24
+ rate_estimates = @french_carrier.find_rates(@origin, @destination, @line_items)
25
+
26
+ rate_estimates.rates.each do |rate|
27
+ assert_instance_of RateEstimate, rate
28
+ assert_instance_of Date, rate.delivery_date
29
+ assert_instance_of Date, rate.shipping_date
30
+ assert_instance_of String, rate.service_name
31
+ assert_kind_of Integer, rate.total_price
32
+ end
33
+
34
+ rate_estimates.boxes.each do |box|
35
+ assert_instance_of CanadaPost::Box, box
36
+ assert_instance_of String, box.name
37
+ assert_instance_of Float, box.weight
38
+ assert_instance_of Float, box.expediter_weight
39
+ assert_instance_of Float, box.length
40
+ assert_instance_of Float, box.height
41
+ assert_instance_of Float, box.width
42
+
43
+ box.packedItems.each do |p|
44
+ assert_kind_of Integer, p.quantity
45
+ assert_instance_of String, p.description
46
+ end
47
+ end
48
+ end
49
+
50
+ def test_build_rate_request
51
+ @carrier.expects(:commit).with(@request, @origin, @destination, {})
52
+ @carrier.find_rates(@origin, @destination, @line_items)
53
+ end
54
+
55
+ def test_parse_rate_response
56
+ @carrier.expects(:ssl_post).returns(@response)
57
+ rate_estimates = @carrier.find_rates(@origin, @destination, @line_items)
58
+
59
+ rate_estimates.rates.each do |rate|
60
+ assert_instance_of RateEstimate, rate
61
+ assert_instance_of Date, rate.delivery_date
62
+ assert_instance_of Date, rate.shipping_date
63
+ assert_instance_of String, rate.service_name
64
+ assert_kind_of Integer, rate.total_price
65
+ end
66
+
67
+ rate_estimates.boxes.each do |box|
68
+ assert_instance_of CanadaPost::Box, box
69
+ assert_instance_of String, box.name
70
+ assert_instance_of Float, box.weight
71
+ assert_instance_of Float, box.expediter_weight
72
+ assert_instance_of Float, box.length
73
+ assert_instance_of Float, box.height
74
+ assert_instance_of Float, box.width
75
+
76
+ box.packedItems.each do |p|
77
+ assert_kind_of Integer, p.quantity
78
+ assert_instance_of String, p.description
79
+ end
80
+ end
81
+ end
82
+
83
+ def test_non_success_parse_rate_response
84
+ @carrier.expects(:ssl_post).returns(@bad_response)
85
+
86
+ error = assert_raises(ReactiveShipping::ResponseError) do
87
+ @carrier.find_rates(@origin, @destination, @line_items)
88
+ end
89
+
90
+ assert_equal 'Parcel too heavy to be shipped with CPC.', error.message
91
+ end
92
+
93
+ def test_turn_around_time
94
+ @carrier.expects(:commit).with do |request, _options|
95
+ parsed_request = Hash.from_xml(request)
96
+ parsed_request['eparcel']['ratesAndServicesRequest']['turnAroundTime'] == "0"
97
+ end
98
+ @carrier.find_rates(@origin, @destination, @line_items, :turn_around_time => 0)
99
+ end
100
+
101
+ def test_build_line_items
102
+ line_items_xml = Nokogiri::XML::Builder.new do |xml|
103
+ @carrier.send(:build_line_items, xml, @line_items)
104
+ end
105
+
106
+ assert_instance_of Nokogiri::XML::Builder, line_items_xml
107
+ assert_equal "a box full of stuff", line_items_xml.doc.at_xpath('//description').text
108
+ assert_equal "0.5", line_items_xml.doc.at_xpath('//weight').text
109
+ end
110
+
111
+ def test_non_iso_country_names
112
+ @destination[:country] = 'RU'
113
+ @carrier.expects(:ssl_post).with(anything, regexp_matches(%r{<country>Russia</country>})).returns(@response)
114
+ @carrier.find_rates(@origin, @destination, @line_items)
115
+ end
116
+
117
+ def test_delivery_range_based_on_delivery_date
118
+ @carrier.expects(:ssl_post).returns(@response)
119
+ rate_estimates = @carrier.find_rates(@origin, @destination, @line_items)
120
+
121
+ delivery_date = Date.new(2010, 8, 4)
122
+ assert_equal [delivery_date] * 2, rate_estimates.rates[0].delivery_range
123
+ assert_equal [delivery_date] * 2, rate_estimates.rates[1].delivery_range
124
+ assert_equal [delivery_date + 2.days] * 2, rate_estimates.rates[2].delivery_range
125
+ end
126
+
127
+ def test_delivery_range_with_invalid_date
128
+ @response = xml_fixture('canadapost/example_response_with_strange_delivery_date')
129
+ @carrier.expects(:ssl_post).returns(@response)
130
+ rate_estimates = @carrier.find_rates(@origin, @destination, @line_items)
131
+
132
+ assert_equal [], rate_estimates.rates[0].delivery_range
133
+ end
134
+
135
+ def test_line_items_with_nil_values
136
+ @response = xml_fixture('canadapost/example_response_with_nil_value')
137
+ @carrier.expects(:ssl_post).returns(@response)
138
+
139
+ @line_items << Package.new(500, [2, 3, 4], :description => "another box full of stuff", :value => nil)
140
+ rate_response = @carrier.find_rates(@origin, @destination, @line_items)
141
+
142
+ assert rate_response.rates.length > 0, "Expecting rateestimates even without a value specified."
143
+ end
144
+
145
+ def test_maximum_address_field_length
146
+ assert_equal 44, @carrier.maximum_address_field_length
147
+ end
148
+ end
@@ -0,0 +1,693 @@
1
+ require 'test_helper'
2
+
3
+ class FedExTest < ActiveSupport::TestCase
4
+ include ReactiveShipping::Test::Fixtures
5
+
6
+ def setup
7
+ @carrier = FedEx.new(:key => '1111', :password => '2222', :account => '3333', :login => '4444')
8
+ end
9
+
10
+ def test_initialize_options_requirements
11
+ assert_raises(ArgumentError) { FedEx.new }
12
+ assert_raises(ArgumentError) { FedEx.new(:login => '999999999') }
13
+ assert_raises(ArgumentError) { FedEx.new(:password => '7777777') }
14
+ FedEx.new(:key => '999999999', :password => '7777777', :account => '123', :login => '123')
15
+ end
16
+
17
+ def test_business_days
18
+ today = DateTime.parse("Tue 12 Mar 2013 00:00:00-0400")
19
+
20
+ Timecop.freeze(today) do
21
+ assert_equal DateTime.parse("Wed 13 Mar 2013 00:00:00-0400"), @carrier.send(:business_days_from, today, 1)
22
+ assert_equal DateTime.parse("Fri 15 Mar 2013 00:00:00-0400"), @carrier.send(:business_days_from, today, 3)
23
+ assert_equal DateTime.parse("Mon 18 Mar 2013 00:00:00-0400"), @carrier.send(:business_days_from, today, 4)
24
+ assert_equal DateTime.parse("Tue 19 Mar 2013 00:00:00-0400"), @carrier.send(:business_days_from, today, 5)
25
+ end
26
+ end
27
+
28
+ def test_home_delivery_business_days
29
+ today = DateTime.parse("Tue 12 Mar 2013 00:00:00-0400")
30
+
31
+ Timecop.freeze(today) do
32
+ assert_equal DateTime.parse("Wed 13 Mar 2013 00:00:00-0400"), @carrier.send(:business_days_from, today, 1, true)
33
+ assert_equal DateTime.parse("Fri 15 Mar 2013 00:00:00-0400"), @carrier.send(:business_days_from, today, 3, true)
34
+ assert_equal DateTime.parse("Sat 16 Mar 2013 00:00:00-0400"), @carrier.send(:business_days_from, today, 4, true)
35
+ assert_equal DateTime.parse("Tue 19 Mar 2013 00:00:00-0400"), @carrier.send(:business_days_from, today, 5, true)
36
+ end
37
+ end
38
+
39
+ def test_turn_around_time_default
40
+ mock_response = xml_fixture('fedex/ottawa_to_beverly_hills_rate_response').gsub('<v6:DeliveryTimestamp>2011-07-29</v6:DeliveryTimestamp>', '')
41
+
42
+ today = Date.parse("Mon 11 Mar 2013")
43
+
44
+ Timecop.freeze(today) do
45
+ delivery_date = Date.today + 7.days # FIVE_DAYS in fixture response, plus weekend
46
+ timestamp = Time.now.iso8601
47
+ @carrier.expects(:commit).with do |request, _options|
48
+ parsed_response = Hash.from_xml(request)
49
+ parsed_response['RateRequest']['RequestedShipment']['ShipTimestamp'] == timestamp
50
+ end.returns(mock_response)
51
+
52
+ destination = ReactiveShipping::Location.from(location_fixtures[:beverly_hills].to_hash, :address_type => :commercial)
53
+ response = @carrier.find_rates location_fixtures[:ottawa], destination, package_fixtures[:book], :test => true
54
+ assert_equal [delivery_date, delivery_date], response.rates.first.delivery_range
55
+ end
56
+ end
57
+
58
+ def test_turn_around_time
59
+ mock_response = xml_fixture('fedex/ottawa_to_beverly_hills_rate_response').gsub('<v6:DeliveryTimestamp>2011-07-29</v6:DeliveryTimestamp>', '')
60
+ Timecop.freeze(DateTime.new(2013, 3, 11)) do
61
+ delivery_date = Date.today + 8.days # FIVE_DAYS in fixture response, plus turn_around_time, plus weekend
62
+ timestamp = (Time.now + 1.day).iso8601
63
+ @carrier.expects(:commit).with do |request, _options|
64
+ parsed_response = Hash.from_xml(request)
65
+ parsed_response['RateRequest']['RequestedShipment']['ShipTimestamp'] == timestamp
66
+ end.returns(mock_response)
67
+
68
+ destination = ReactiveShipping::Location.from(location_fixtures[:beverly_hills].to_hash, :address_type => :commercial)
69
+ response = @carrier.find_rates location_fixtures[:ottawa], destination, package_fixtures[:book], :turn_around_time => 24, :test => true
70
+
71
+ assert_equal [delivery_date, delivery_date], response.rates.first.delivery_range
72
+ end
73
+ end
74
+
75
+ def test_transaction_id_sent_as_customer_transaction_id
76
+ transaction_id = '9999-test'
77
+ @carrier = FedEx.new(:key => '1111', :password => '2222', :account => '3333', :login => '4444', :transaction_id => transaction_id)
78
+ @carrier.expects(:commit).with do |request, _options|
79
+ parsed_request = Hash.from_xml(request)
80
+ parsed_request['RateRequest']['TransactionDetail']['CustomerTransactionId'] == transaction_id
81
+ end.returns(xml_fixture('fedex/ottawa_to_beverly_hills_rate_response'))
82
+
83
+ destination = ReactiveShipping::Location.from(location_fixtures[:beverly_hills].to_hash, :address_type => :commercial)
84
+ @carrier.find_rates location_fixtures[:ottawa], destination, package_fixtures[:book], :test => true
85
+ end
86
+
87
+ def test_building_request_with_address_type_commercial_should_not_include_residential
88
+ mock_response = xml_fixture('fedex/ottawa_to_beverly_hills_rate_response')
89
+ expected_request = xml_fixture('fedex/ottawa_to_beverly_hills_commercial_rate_request')
90
+
91
+ @carrier.expects(:ship_timestamp).returns(Time.parse("2009-07-20T12:01:55-04:00").in_time_zone('US/Eastern'))
92
+ @carrier.expects(:commit).with { |request, test_mode| Hash.from_xml(request) == Hash.from_xml(expected_request) && test_mode }.returns(mock_response)
93
+ destination = ReactiveShipping::Location.from(location_fixtures[:beverly_hills].to_hash, :address_type => :commercial)
94
+ @carrier.find_rates( location_fixtures[:ottawa],
95
+ destination,
96
+ package_fixtures.values_at(:book, :wii), test: true, saturday_delivery: true)
97
+ end
98
+
99
+ def test_building_request_with_no_saturday_delivery_should_not_have_saturday_option_set
100
+ mock_response = xml_fixture('fedex/ottawa_to_beverly_hills_rate_response')
101
+ expected_request = xml_fixture('fedex/ottawa_to_beverly_hills_no_saturday_rate_request')
102
+
103
+ @carrier.expects(:ship_timestamp).returns(Time.parse("2009-07-20T12:01:55-04:00").in_time_zone('US/Eastern'))
104
+ @carrier.expects(:commit).with { |request, test_mode| Hash.from_xml(request) == Hash.from_xml(expected_request) && test_mode }.returns(mock_response)
105
+ destination = ReactiveShipping::Location.from(location_fixtures[:beverly_hills].to_hash)
106
+ @carrier.find_rates( location_fixtures[:ottawa],
107
+ destination,
108
+ package_fixtures.values_at(:book, :wii), test: true)
109
+ end
110
+
111
+ def test_building_freight_request_and_parsing_response
112
+ expected_request = xml_fixture('fedex/freight_rate_request')
113
+ mock_response = xml_fixture('fedex/freight_rate_response')
114
+
115
+ @carrier.expects(:ship_timestamp).returns(Time.parse("2013-11-01T14:04:01-07:00").in_time_zone('US/Pacific'))
116
+ @carrier.expects(:commit).with { |request, test_mode| Hash.from_xml(request) == Hash.from_xml(expected_request) && test_mode }.returns(mock_response)
117
+
118
+ # shipping and billing addresses below are provided by fedex test credentials
119
+
120
+ shipping_location = Location.new( address1: '1202 Chalet Ln',
121
+ address2: 'Do Not Delete - Test Account',
122
+ city: 'Harrison',
123
+ state: 'AR',
124
+ postal_code: '72601',
125
+ country: 'US')
126
+
127
+ billing_location = Location.new( address1: '2000 Freight LTL Testing',
128
+ address2: 'Do Not Delete - Test Account',
129
+ city: 'Harrison',
130
+ state: 'AR',
131
+ postal_code: '72601',
132
+ country: 'US')
133
+
134
+ freight_options = {
135
+ account: '5555',
136
+ billing_location: billing_location,
137
+ payment_type: 'SENDER',
138
+ freight_class: 'CLASS_050',
139
+ packaging: 'PALLET',
140
+ role: 'SHIPPER'
141
+ }
142
+
143
+ response = @carrier.find_rates( shipping_location,
144
+ location_fixtures[:ottawa],
145
+ [package_fixtures[:wii]], freight: freight_options, test: true, saturday_delivery: true )
146
+
147
+ assert_equal ["FedEx Freight Economy", "FedEx Freight Priority"], response.rates.map(&:service_name)
148
+ assert_equal [66263, 68513], response.rates.map(&:price)
149
+
150
+ assert response.success?, response.message
151
+ assert_instance_of Hash, response.params
152
+ assert_instance_of String, response.xml
153
+ assert_instance_of Array, response.rates
154
+ assert response.rates.length > 0, "There should've been more than 0 rates returned"
155
+
156
+ rate = response.rates.first
157
+ assert_equal 'FedEx', rate.carrier
158
+ assert_equal 'USD', rate.currency
159
+ assert_kind_of Integer, rate.total_price
160
+ assert_kind_of Integer, rate.price
161
+ assert_instance_of String, rate.service_name
162
+ assert_instance_of String, rate.service_code
163
+ assert_instance_of Array, rate.package_rates
164
+ assert_equal [package_fixtures[:wii]], rate.packages
165
+
166
+ package_rate = rate.package_rates.first
167
+ assert_instance_of Hash, package_rate
168
+ assert_instance_of Package, package_rate[:package]
169
+ assert_nil package_rate[:rate]
170
+ end
171
+
172
+ def test_building_request_and_parsing_response
173
+ expected_request = xml_fixture('fedex/ottawa_to_beverly_hills_rate_request')
174
+ mock_response = xml_fixture('fedex/ottawa_to_beverly_hills_rate_response')
175
+ @carrier.expects(:ship_timestamp).returns(Time.parse("2009-07-20T12:01:55-04:00").in_time_zone('US/Eastern'))
176
+ @carrier.expects(:commit).with { |request, test_mode| Hash.from_xml(request) == Hash.from_xml(expected_request) && test_mode }.returns(mock_response)
177
+ response = @carrier.find_rates( location_fixtures[:ottawa],
178
+ location_fixtures[:beverly_hills],
179
+ package_fixtures.values_at(:book, :wii), test: true, saturday_delivery: true)
180
+ assert_equal ["FedEx Ground"], response.rates.map(&:service_name)
181
+ assert_equal [3836], response.rates.map(&:price)
182
+
183
+ assert response.success?, response.message
184
+ assert_instance_of Hash, response.params
185
+ assert_instance_of String, response.xml
186
+ assert_instance_of Array, response.rates
187
+ assert response.rates.length > 0, "There should've been more than 0 rates returned"
188
+
189
+ rate = response.rates.first
190
+ assert_equal 'FedEx', rate.carrier
191
+ assert_equal 'CAD', rate.currency
192
+ assert_kind_of Integer, rate.total_price
193
+ assert_kind_of Integer, rate.price
194
+ assert_instance_of String, rate.service_name
195
+ assert_instance_of String, rate.service_code
196
+ assert_instance_of Array, rate.package_rates
197
+ assert_equal package_fixtures.values_at(:book, :wii), rate.packages
198
+
199
+ package_rate = rate.package_rates.first
200
+ assert_instance_of Hash, package_rate
201
+ assert_instance_of Package, package_rate[:package]
202
+ assert_nil package_rate[:rate]
203
+ end
204
+
205
+ def test_parsing_response_with_no_rate_reply
206
+ expected_request = xml_fixture('fedex/ottawa_to_beverly_hills_rate_request')
207
+ mock_response = xml_fixture('fedex/unknown_fedex_document_reply')
208
+
209
+ @carrier.expects(:ship_timestamp).returns(Time.parse("2009-07-20T12:01:55-04:00").in_time_zone('US/Eastern'))
210
+ @carrier.expects(:commit).with { |request, test_mode| Hash.from_xml(request) == Hash.from_xml(expected_request) && test_mode }.returns(mock_response)
211
+ exception = assert_raises(ReactiveShipping::ResponseContentError) do
212
+ @carrier.find_rates( location_fixtures[:ottawa],
213
+ location_fixtures[:beverly_hills],
214
+ package_fixtures.values_at(:book, :wii), test: true, saturday_delivery: true)
215
+ end
216
+ message = "Invalid document \n\n#{mock_response}"
217
+ assert_equal message, exception.message
218
+ end
219
+
220
+ def test_parsing_response_with_no_system_code_for_one_rate_does_not_crash
221
+ mock_response = xml_fixture('fedex/freight_rate_response').gsub('<v13:ServiceType>FEDEX_FREIGHT_ECONOMY</v13:ServiceType>','')
222
+
223
+ @carrier.expects(:commit).returns(mock_response)
224
+ @carrier.logger = Logger.new(StringIO.new)
225
+ @carrier.logger.expects(:warn).once.with("[FedexParseRateError] Some fields where missing in the response: #{mock_response}")
226
+
227
+ rates = @carrier.find_rates( location_fixtures[:ottawa], location_fixtures[:beverly_hills], package_fixtures.values_at(:book, :wii), :test => true)
228
+ assert rates.rates.length == 1
229
+ assert_equal rates.rates[0].service_code, 'FEDEX_FREIGHT_PRIORITY'
230
+ end
231
+
232
+ def test_parsing_response_with_no_system_code_on_any_shipping_rate
233
+ mock_response = xml_fixture('fedex/freight_rate_response').gsub('<v13:ServiceType>FEDEX_FREIGHT_ECONOMY</v13:ServiceType>','').gsub('<v13:ServiceType>FEDEX_FREIGHT_PRIORITY</v13:ServiceType>','')
234
+
235
+ @carrier.expects(:commit).returns(mock_response)
236
+ @carrier.logger = Logger.new(StringIO.new)
237
+ @carrier.logger.expects(:warn).once.with("[FedexParseRateError] Some fields where missing in the response: #{mock_response}")
238
+
239
+ exception = assert_raises(ReactiveShipping::ResponseError) do
240
+ @carrier.find_rates( location_fixtures[:ottawa], location_fixtures[:beverly_hills], package_fixtures.values_at(:book, :wii), :test => true)
241
+ end
242
+ message = "The response from the carrier contained errors and could not be treated"
243
+ assert_equal exception.message, message
244
+ end
245
+
246
+ def test_service_name_for_code
247
+ FedEx::SERVICE_TYPES.each do |capitalized_name, readable_name|
248
+ assert_equal readable_name, FedEx.service_name_for_code(capitalized_name)
249
+ end
250
+ end
251
+
252
+ def test_service_name_for_code_handles_yet_unknown_codes
253
+ assert_equal "FedEx Express Saver Saturday Delivery", FedEx.service_name_for_code('FEDEX_EXPRESS_SAVER_SATURDAY_DELIVERY')
254
+ assert_equal "FedEx Some Weird Rate", FedEx.service_name_for_code('SOME_WEIRD_RATE')
255
+ end
256
+
257
+ def test_delivery_range_based_on_delivery_date
258
+ mock_response = xml_fixture('fedex/ottawa_to_beverly_hills_rate_response').gsub('CAD', 'UKL')
259
+
260
+ @carrier.expects(:commit).returns(mock_response)
261
+ rate_estimates = @carrier.find_rates( location_fixtures[:ottawa],
262
+ location_fixtures[:beverly_hills],
263
+ package_fixtures.values_at(:book, :wii), :test => true)
264
+
265
+ delivery_date = Date.new(2011, 7, 29)
266
+ assert_equal delivery_date, rate_estimates.rates[0].delivery_date
267
+ assert_equal [delivery_date] * 2, rate_estimates.rates[0].delivery_range
268
+ end
269
+
270
+ def test_delivery_date_from_transit_time
271
+ mock_response = xml_fixture('fedex/raterequest_reply').gsub('CAD', 'UKL')
272
+
273
+ @carrier.expects(:commit).returns(mock_response)
274
+
275
+ today = Date.parse("Fri 15 Mar 2013")
276
+
277
+ Timecop.freeze(today) do
278
+ rate_estimates = @carrier.find_rates( location_fixtures[:ottawa],
279
+ location_fixtures[:beverly_hills],
280
+ package_fixtures.values_at(:book, :wii), :test => true)
281
+
282
+ # the above fixture will specify a transit time of 5 days, with 2 weekend days accounted for
283
+ delivery_date = Date.today + 5 + 2
284
+ assert_equal delivery_date, rate_estimates.rates[0].delivery_date
285
+ end
286
+ end
287
+
288
+ def test_delivery_date_from_ground_home_transit_time
289
+ mock_response = xml_fixture('fedex/raterequest_response_with_ground_home_delivery')
290
+
291
+ @carrier.expects(:commit).returns(mock_response)
292
+
293
+ today = Date.parse("Thursday 04 Jun 2015")
294
+
295
+ Timecop.freeze(today) do
296
+ rate_estimates = @carrier.find_rates( location_fixtures[:ottawa],
297
+ location_fixtures[:beverly_hills],
298
+ package_fixtures.values_at(:book, :wii), :test => true)
299
+
300
+ # the above fixture will specify a transit time of 3 days
301
+ # for ground home, sunday and monday are non-biz days
302
+ # so it is delivered on Tuesday
303
+ delivery_date = Date.today + 3 + 2
304
+ assert_equal delivery_date, rate_estimates.rates.first.delivery_date
305
+ end
306
+ end
307
+
308
+ def test_delivery_date_from_ground_home_transit_time_on_saturday
309
+ mock_response = xml_fixture('fedex/raterequest_response_with_ground_home_delivery')
310
+
311
+ @carrier.expects(:commit).returns(mock_response)
312
+
313
+ today = Date.parse("Wed 03 Jun 2015") #Wednesday
314
+
315
+ Timecop.freeze(today) do
316
+ rate_estimates = @carrier.find_rates( location_fixtures[:ottawa],
317
+ location_fixtures[:beverly_hills],
318
+ package_fixtures.values_at(:book, :wii), :test => true)
319
+
320
+ # the above fixture will specify a transit time of 3 days
321
+ # since ground home delivers on Saturday, there is no delay
322
+ delivery_date = Date.today + 3
323
+ assert_equal delivery_date, rate_estimates.rates.first.delivery_date
324
+ end
325
+ end
326
+
327
+ def test_failure_to_parse_invalid_xml_results_in_a_useful_error
328
+ mock_response = xml_fixture('fedex/invalid_fedex_reply')
329
+
330
+ @carrier.expects(:commit).returns(mock_response)
331
+
332
+ assert_raises ReactiveShipping::ResponseContentError do
333
+ @carrier.find_rates(
334
+ location_fixtures[:ottawa],
335
+ location_fixtures[:beverly_hills],
336
+ package_fixtures.values_at(:book, :wii),
337
+ test: true
338
+ )
339
+ end
340
+ end
341
+
342
+ def test_parsing_response_without_notifications
343
+ mock_response = xml_fixture('fedex/reply_without_notifications')
344
+
345
+ @carrier.expects(:commit).returns(mock_response)
346
+
347
+ response = @carrier.find_rates(
348
+ location_fixtures[:ottawa],
349
+ location_fixtures[:beverly_hills],
350
+ package_fixtures.values_at(:book, :wii),
351
+ test: true
352
+ )
353
+
354
+ assert_predicate response, :success?
355
+ end
356
+
357
+ ### find_tracking_info
358
+
359
+ def test_response_transient_failure
360
+ mock_response = xml_fixture('fedex/tracking_response_failure_code_9045')
361
+ @carrier.expects(:commit).returns(mock_response)
362
+
363
+ error = assert_raises(ReactiveShipping::ShipmentNotFound) do
364
+ @carrier.find_tracking_info('123456789013')
365
+ end
366
+
367
+ msg = 'Sorry, we are unable to process your tracking request. Please retry later, or contact Customer Service at 1.800.Go.FedEx(R) 800.463.3339.'
368
+ assert_equal msg, error.message
369
+ end
370
+
371
+ def test_response_with_failure_nested_in_track_details
372
+ mock_response = xml_fixture('fedex/tracking_response_failure_code_9080')
373
+ @carrier.expects(:commit).returns(mock_response)
374
+
375
+ error = assert_raises(ReactiveShipping::ResponseContentError) do
376
+ @carrier.find_tracking_info('123456789013')
377
+ end
378
+
379
+ msg = 'Sorry, we are unable to process your tracking request. Please contact Customer Service at 1.800.Go.FedEx(R) 800.463.3339.'
380
+ assert_equal msg, error.message
381
+ end
382
+
383
+ def test_response_with_failure_nested_in_completed_track_details
384
+ mock_response = xml_fixture('fedex/tracking_response_unable_to_process')
385
+ @carrier.expects(:commit).returns(mock_response)
386
+
387
+ error = assert_raises(ReactiveShipping::ResponseError) do
388
+ @carrier.find_tracking_info('123456789013')
389
+ end
390
+
391
+ msg = 'FAILURE - 6330: Sorry, we are unable to process your tracking request. Please retry later, or contact Customer Service at 1.800.Go.FedEx(R) 800.463.3339.'
392
+ assert_equal msg, error.message
393
+ end
394
+
395
+ def test_tracking_info_for_delivered_with_signature
396
+ mock_response = xml_fixture('fedex/tracking_response_delivered_with_signature')
397
+ @carrier.expects(:commit).returns(mock_response)
398
+
399
+ response = @carrier.find_tracking_info('449044304137821')
400
+ assert_equal '449044304137821', response.tracking_number
401
+ assert_equal 'AVILLALON', response.delivery_signature
402
+ assert response.delivered?
403
+ refute response.exception?
404
+
405
+ assert_equal Date.parse('2013-12-30'), response.ship_time
406
+ assert_nil response.scheduled_delivery_date
407
+ assert_equal Time.parse('2014-01-02T18:23:29Z'), response.actual_delivery_date
408
+
409
+ origin_address = ReactiveShipping::Location.new(
410
+ city: 'JEFFERSONVILLE',
411
+ country: 'US',
412
+ state: 'IN'
413
+ )
414
+ assert_equal origin_address.to_hash, response.origin.to_hash
415
+
416
+ destination_address = ReactiveShipping::Location.new(
417
+ city: 'Miami',
418
+ country: 'US',
419
+ state: 'FL'
420
+ )
421
+ assert_equal destination_address.to_hash, response.destination.to_hash
422
+
423
+ assert_equal 11, response.shipment_events.length
424
+ assert_equal 'Delivered', response.latest_event.name
425
+ assert_equal 'PU', response.shipment_events.first.type_code
426
+ assert_equal 'OC', response.shipment_events.second.type_code
427
+ assert_equal 'AR', response.shipment_events.third.type_code
428
+ end
429
+
430
+ def test_tracking_info_for_delivered_at_door
431
+ mock_response = xml_fixture('fedex/tracking_response_delivered_at_door')
432
+ @carrier.expects(:commit).returns(mock_response)
433
+
434
+ response = @carrier.find_tracking_info('403934084723025')
435
+ assert_equal '403934084723025', response.tracking_number
436
+ assert response.delivered?
437
+ refute response.exception?
438
+ assert_equal 10, response.shipment_events.length
439
+ assert_equal 'PU', response.shipment_events.first.type_code
440
+ assert_equal 'OC', response.shipment_events.second.type_code
441
+ assert_equal 'AR', response.shipment_events.third.type_code
442
+ assert_equal 'Delivered', response.latest_event.name
443
+ assert_equal 'DL', response.latest_event.type_code
444
+ assert_nil response.delivery_signature
445
+ end
446
+
447
+ def test_state_degrades_to_unknown
448
+ mock_response = xml_fixture('fedex/tracking_response_with_blank_state')
449
+ @carrier.expects(:commit).returns(mock_response)
450
+
451
+ response = @carrier.find_tracking_info('798701052354')
452
+
453
+ destination_address = ReactiveShipping::Location.new(
454
+ city: 'SAITAMA',
455
+ country: 'Japan',
456
+ state: 'unknown'
457
+ )
458
+
459
+ assert_equal destination_address.to_hash, response.destination.to_hash
460
+ end
461
+
462
+ def test_tracking_info_for_in_transit
463
+ mock_response = xml_fixture('fedex/tracking_response_in_transit')
464
+ @carrier.expects(:commit).returns(mock_response)
465
+
466
+ response = @carrier.find_tracking_info('123456789012')
467
+ refute response.delivered?
468
+ refute response.exception?
469
+
470
+ assert_equal '123456789012', response.tracking_number
471
+ assert_equal :fedex, response.carrier
472
+ assert_equal 'FedEx', response.carrier_name
473
+ assert_equal :in_transit, response.status
474
+ assert_equal 'IT', response.status_code
475
+ assert_equal "Package available for clearance", response.status_description
476
+ assert_nil response.delivery_signature
477
+
478
+ assert_equal Time.parse('2014-11-17T22:39:00+11:00'), response.ship_time
479
+ assert_nil response.scheduled_delivery_date
480
+ assert_nil response.actual_delivery_date
481
+
482
+ assert_nil response.origin
483
+
484
+ destination_address = ReactiveShipping::Location.new(
485
+ city: 'GRAFTON',
486
+ country: 'AU',
487
+ state: 'ON'
488
+ )
489
+ assert_equal destination_address.to_hash, response.destination.to_hash
490
+
491
+ assert_equal 1, response.shipment_events.length
492
+ assert_equal 'In transit', response.latest_event.name
493
+ assert_equal 'IT', response.latest_event.type_code
494
+ end
495
+
496
+ def test_tracking_info_for_shipment_exception
497
+ mock_response = xml_fixture('fedex/tracking_response_shipment_exception')
498
+ @carrier.expects(:commit).returns(mock_response)
499
+
500
+ response = @carrier.find_tracking_info('957794015041323')
501
+ assert_equal '957794015041323', response.tracking_number
502
+ refute response.delivered?
503
+ assert response.exception?
504
+ assert_equal :exception, response.status
505
+ assert_equal "Unable to deliver", response.status_description
506
+
507
+ assert_equal Date.parse('2014-01-27'), response.ship_time
508
+ assert_nil response.scheduled_delivery_date
509
+ assert_nil response.actual_delivery_date
510
+
511
+ origin_address = ReactiveShipping::Location.new(
512
+ city: 'AUSTIN',
513
+ country: 'US',
514
+ state: 'TX'
515
+ )
516
+ assert_equal origin_address.to_hash, response.origin.to_hash
517
+
518
+ destination_address = ReactiveShipping::Location.new(
519
+ city: 'GOOSE CREEK',
520
+ country: 'US',
521
+ state: 'SC'
522
+ )
523
+ assert_equal destination_address.to_hash, response.destination.to_hash
524
+
525
+ assert_equal 8, response.shipment_events.length
526
+ assert_equal "Shipment exception", response.latest_event.name
527
+ assert_equal "SE", response.latest_event.type_code
528
+ end
529
+
530
+ def test_tracking_info_without_status
531
+ mock_response = xml_fixture('fedex/tracking_response_multiple_results')
532
+ @carrier.expects(:commit).returns(mock_response)
533
+
534
+ error = assert_raises(ReactiveShipping::ResponseError) do
535
+ @carrier.find_tracking_info('123456789012')
536
+ end
537
+
538
+ msg = 'Multiple matches were found. Specify a unqiue identifier: 2456987000~123456789012~FX, 2456979001~123456789012~FX, 2456979000~123456789012~FX'
539
+ assert_equal msg, error.message
540
+ end
541
+
542
+ def test_tracking_info_with_unknown_tracking_number
543
+ mock_response = xml_fixture('fedex/tracking_response_not_found')
544
+ @carrier.expects(:commit).returns(mock_response)
545
+
546
+ error = assert_raises(ReactiveShipping::ShipmentNotFound) do
547
+ @carrier.find_tracking_info('123456789013')
548
+ end
549
+
550
+ msg = 'This tracking number cannot be found. Please check the number or contact the sender.'
551
+ assert_equal msg, error.message
552
+ end
553
+
554
+ def test_tracking_info_with_bad_tracking_number
555
+ mock_response = xml_fixture('fedex/tracking_response_bad_tracking_number')
556
+ @carrier.expects(:commit).returns(mock_response)
557
+
558
+ assert_raises(ReactiveShipping::ResponseError) do
559
+ @carrier.find_tracking_info('abc')
560
+ end
561
+ end
562
+
563
+ def test_tracking_info_with_uncovered_error
564
+ mock_response = xml_fixture('fedex/tracking_response_invalid_tracking_number')
565
+ @carrier.expects(:commit).returns(mock_response)
566
+
567
+ error = assert_raises(ReactiveShipping::ResponseContentError) do
568
+ @carrier.find_tracking_info('123456789013')
569
+ end
570
+
571
+ msg = 'Invalid tracking numbers. Please check the following numbers and resubmit.'
572
+ assert_equal msg, error.message
573
+ end
574
+
575
+ def test_tracking_info_with_empty_status_detail
576
+ mock_response = xml_fixture('fedex/tracking_response_empty_status_detail')
577
+ @carrier.expects(:commit).returns(mock_response)
578
+ response = @carrier.find_tracking_info('123456789012')
579
+
580
+ assert_equal '123456789012', response.tracking_number
581
+ assert_nil response.status_code
582
+ assert_nil response.status
583
+ assert_nil response.status_description
584
+ assert_nil response.delivery_signature
585
+ assert_empty response.shipment_events
586
+ end
587
+
588
+ def test_tracking_info_with_missing_status_code
589
+ mock_response = xml_fixture('fedex/tracking_response_missing_status_code')
590
+ @carrier.expects(:commit).returns(mock_response)
591
+
592
+ response = @carrier.find_tracking_info('123456789012')
593
+ assert_equal '123456789012', response.tracking_number
594
+ assert_nil response.status_code
595
+ assert_nil response.status
596
+ assert_nil response.status_description
597
+ assert_nil response.delivery_signature
598
+ assert_empty response.shipment_events
599
+ end
600
+
601
+ ### create_shipment
602
+
603
+ def test_create_shipment
604
+ confirm_response = xml_fixture('fedex/create_shipment_response')
605
+ @carrier.stubs(:commit).returns(confirm_response)
606
+
607
+ response = @carrier.create_shipment(
608
+ location_fixtures[:beverly_hills],
609
+ location_fixtures[:new_york],
610
+ package_fixtures.values_at(:chocolate_stuff),
611
+ :test => true
612
+ )
613
+
614
+ # These assertions are to check that the xml fixture is extracted properly.
615
+ assert_equal 1, response.labels.count
616
+ assert_equal response.labels.first.tracking_number, "794637052920"
617
+ assert_equal response.labels.first.img_data.size, 8286
618
+ end
619
+
620
+ def test_create_shipment_signature_option
621
+ packages = package_fixtures.values_at(:chocolate_stuff)
622
+ packages.each {|p| p.options[:signature_option] = :indirect }
623
+ result = Nokogiri::XML(@carrier.send(:build_shipment_request,
624
+ location_fixtures[:beverly_hills],
625
+ location_fixtures[:annapolis],
626
+ packages,
627
+ :test => true))
628
+ assert_equal result.search('SpecialServicesRequested/SpecialServiceTypes').text, "SIGNATURE_OPTION"
629
+ assert_equal result.search('SpecialServicesRequested/SignatureOptionDetail').text.strip, "INDIRECT"
630
+ end
631
+
632
+ def test_create_shipment_reference
633
+ packages = package_fixtures.values_at(:wii)
634
+ packages.each do |p|
635
+ p.options[:reference_numbers] = [
636
+ { :value => "FOO-123"},
637
+ { :type => "INVOICE_NUMBER", :value => "BAR-456" }
638
+ ]
639
+ end
640
+
641
+ result = Nokogiri::XML(@carrier.send(:build_shipment_request,
642
+ location_fixtures[:beverly_hills],
643
+ location_fixtures[:annapolis],
644
+ packages,
645
+ :test => true))
646
+
647
+ assert_equal result.search('RequestedPackageLineItems/CustomerReferences[first()]/Value').text, "FOO-123"
648
+ assert_equal result.search('RequestedPackageLineItems/CustomerReferences[first()]/CustomerReferenceType').text, "CUSTOMER_REFERENCE"
649
+ assert_equal result.search('RequestedPackageLineItems/CustomerReferences[last()]/Value').text, "BAR-456"
650
+ assert_equal result.search('RequestedPackageLineItems/CustomerReferences[last()]/CustomerReferenceType').text, "INVOICE_NUMBER"
651
+ end
652
+
653
+ def test_create_shipment_label_format_option
654
+ packages = package_fixtures.values_at(:chocolate_stuff)
655
+ result = Nokogiri::XML(@carrier.send(:build_shipment_request,
656
+ location_fixtures[:beverly_hills],
657
+ location_fixtures[:annapolis],
658
+ packages,
659
+ :label_format => 'ZPLII',
660
+ :test => true))
661
+ assert_equal result.search('RequestedShipment/LabelSpecification/ImageType').text, "ZPLII"
662
+ end
663
+
664
+ def test_create_shipment_default_label_stock_type
665
+ packages = package_fixtures.values_at(:wii)
666
+
667
+ result = Nokogiri::XML(@carrier.send(:build_shipment_request,
668
+ location_fixtures[:beverly_hills],
669
+ location_fixtures[:annapolis],
670
+ packages,
671
+ :test => true))
672
+
673
+ assert_equal result.search('RequestedShipment/LabelSpecification/LabelStockType').text, FedEx::DEFAULT_LABEL_STOCK_TYPE
674
+ end
675
+
676
+ def test_create_shipment_label_stock_type
677
+ label_stock_type = 'PAPER_4X6'
678
+ packages = package_fixtures.values_at(:wii)
679
+
680
+ result = Nokogiri::XML(@carrier.send(:build_shipment_request,
681
+ location_fixtures[:beverly_hills],
682
+ location_fixtures[:annapolis],
683
+ packages,
684
+ :test => true,
685
+ :label_stock_type => label_stock_type))
686
+
687
+ assert_equal result.search('RequestedShipment/LabelSpecification/LabelStockType').text, label_stock_type
688
+ end
689
+
690
+ def test_maximum_address_field_length
691
+ assert_equal 35, @carrier.maximum_address_field_length
692
+ end
693
+ end