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,35 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ desc "Run the unit and functional remote tests"
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.libs << "test"
7
+ t.pattern = 'test/**/*_test.rb'
8
+ t.verbose = true
9
+ t.warning = false
10
+ end
11
+
12
+ namespace :test do
13
+ desc "Run unit tests"
14
+ Rake::TestTask.new(:unit) do |t|
15
+ t.libs << "test"
16
+ t.pattern = 'test/unit/**/*_test.rb'
17
+ t.verbose = true
18
+ t.warning = false
19
+ end
20
+
21
+ desc "Run functional remote tests"
22
+ Rake::TestTask.new(:remote) do |t|
23
+ t.libs << "test"
24
+ t.pattern = 'test/remote/*_test.rb'
25
+ t.verbose = true
26
+ t.warning = false
27
+ end
28
+ end
29
+
30
+ desc "Open a pry session preloaded with this library"
31
+ task :console do
32
+ sh 'ruby -Ilib -Itest test/console.rb'
33
+ end
34
+
35
+ task :default => 'test'
data/dev.yml ADDED
@@ -0,0 +1,17 @@
1
+ name: active-shipping
2
+
3
+ up:
4
+ - ruby: 2.3.1
5
+ - bundler
6
+
7
+ commands:
8
+ test:
9
+ syntax:
10
+ optional: file args...
11
+ desc: 'run all tests or a specific test file'
12
+ run: |
13
+ if [[ $# -eq 0 ]]; then
14
+ bundle exec rake test
15
+ else
16
+ bundle exec ruby -Itest "$@"
17
+ fi
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'activesupport', '~> 4.2.0'
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'activesupport', '~> 5.0.0'
6
+ gem 'active_utils', '~> 3.3.0'
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'activesupport', '~> 5.1.0'
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'activesupport', '~> 5.2.0'
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'activesupport', github: 'rails/rails'
@@ -0,0 +1,111 @@
1
+ <!-- EVERY REQUEST CONTAIN THE eparcel TAG -->
2
+ <!ELEMENT eparcel (language?,
3
+ ( ratesAndServicesRequest |
4
+ ratesAndServicesResponse |
5
+ error
6
+ )+)>
7
+
8
+ <!ELEMENT language (#PCDATA)>
9
+ <!ELEMENT comment (#PCDATA)>
10
+
11
+
12
+ <!-- Standard request to ask for rates and services -->
13
+ <!ELEMENT ratesAndServicesRequest ( merchantCPCID,
14
+ fromPostalCode?,
15
+ turnAroundTime?,
16
+ itemsPrice?,
17
+ lineItems,
18
+ city?,
19
+ provOrState,
20
+ country,
21
+ postalCode)>
22
+ <!ELEMENT merchantID (#PCDATA)>
23
+ <!ELEMENT fromPostalCode (#PCDATA)>
24
+ <!ELEMENT turnAroundTime (#PCDATA)>
25
+ <!ELEMENT itemsPrice (#PCDATA)>
26
+ <!ELEMENT merchantCPCID (#PCDATA)>
27
+ <!ELEMENT lineItems (item)+>
28
+ <!ELEMENT item (quantity, weight, length, width, height, description, imageURL?, readyToShip)>
29
+ <!ELEMENT quantity (#PCDATA)>
30
+ <!ELEMENT weight (#PCDATA)>
31
+ <!ELEMENT length (#PCDATA)>
32
+ <!ELEMENT width (#PCDATA)>
33
+ <!ELEMENT height (#PCDATA)>
34
+ <!ELEMENT description (#PCDATA)>
35
+ <!ELEMENT imageURL (#PCDATA)>
36
+ <!ELEMENT readyToShip (#PCDATA)>
37
+ <!ELEMENT city (#PCDATA)>
38
+ <!ELEMENT provOrState (#PCDATA)>
39
+ <!ELEMENT country (#PCDATA)>
40
+ <!ELEMENT postalCode (#PCDATA)>
41
+
42
+ <!-- Standard response for request for rates and services -->
43
+ <!ELEMENT ratesAndServicesResponse (statusCode,
44
+ statusMessage+,
45
+ requestID,
46
+ handling,
47
+ language,
48
+ product+,
49
+ packing*,
50
+ emptySpace*,
51
+ shippingOptions,
52
+ comment,
53
+ nearestPostalOutlet*)>
54
+
55
+ <!ELEMENT statusCode (#PCDATA)>
56
+ <!ELEMENT statusMessage (#PCDATA)>
57
+ <!ELEMENT requestID (#PCDATA)>
58
+ <!ELEMENT handling (#PCDATA)>
59
+
60
+ <!ELEMENT product (name, rate, shippingDate, deliveryDate, deliveryDayOfWeek, nextDayAM?, packingID)>
61
+ <!ATTLIST product id CDATA #REQUIRED>
62
+ <!ATTLIST product sequence CDATA #REQUIRED>
63
+ <!ELEMENT name (#PCDATA)>
64
+ <!ELEMENT rate (#PCDATA)>
65
+ <!ELEMENT shippingDate (#PCDATA)>
66
+ <!ELEMENT deliveryDate (#PCDATA)>
67
+ <!ELEMENT deliveryDayOfWeek (#PCDATA)>
68
+ <!ELEMENT nextDayAM (#PCDATA)>
69
+ <!ELEMENT packingID (#PCDATA)>
70
+
71
+ <!ELEMENT packing (packingID, box+)>
72
+ <!ELEMENT box (name, weight, expediterWeight, length, width, height, packedItem+)>
73
+ <!ELEMENT expediterWeight (#PCDATA)>
74
+ <!ELEMENT packedItem (quantity, description)>
75
+
76
+ <!ELEMENT emptySpace (length, width, height, weight)>
77
+
78
+ <!ELEMENT shippingOptions (insurance, deliveryConfirmation, signature)>
79
+ <!ELEMENT insurance (#PCDATA)>
80
+ <!ELEMENT deliveryConfirmation (#PCDATA)>
81
+ <!ELEMENT signature (#PCDATA)>
82
+
83
+
84
+ <!-- ********************************************************* -->
85
+ <!-- * 'nearestPostalOutlet' is optional and is returned * -->
86
+ <!-- * only if the merchant profile has this option enabled * -->
87
+ <!-- ********************************************************* -->
88
+ <!ELEMENT nearestPostalOutlet (postalOutletSequenceNo,
89
+ distance,
90
+ outletName,
91
+ businessName ,
92
+ postalAddress,
93
+ phoneNumber,
94
+ businessHours+)>
95
+ <!ELEMENT postalOutletSequenceNo (#PCDATA)>
96
+ <!ELEMENT distance (#PCDATA)>
97
+ <!ELEMENT outletName (#PCDATA)>
98
+ <!ELEMENT businessName (#PCDATA)>
99
+ <!ELEMENT postalAddress (addressLine+, postalCode , municipality)>
100
+ <!ELEMENT addressLine (#PCDATA)>
101
+ <!ELEMENT municipality (#PCDATA)>
102
+ <!ELEMENT phoneNumber (#PCDATA)>
103
+ <!ELEMENT businessHours (dayId, dayOfWeek, time)>
104
+ <!ELEMENT dayId (#PCDATA)>
105
+ <!ELEMENT dayOfWeek (#PCDATA)>
106
+ <!ELEMENT time (#PCDATA)>
107
+
108
+
109
+ <!-- Standard error format returned -->
110
+ <!ELEMENT error (statusCode,statusMessage*)>
111
+
@@ -0,0 +1,26 @@
1
+ require 'active_support/all'
2
+ require 'active_utils'
3
+
4
+ require 'nokogiri'
5
+ require 'measured'
6
+
7
+ require 'reactive_shipping/response'
8
+ require 'reactive_shipping/rate_response'
9
+ require 'reactive_shipping/tracking_response'
10
+ require 'reactive_shipping/delivery_date_estimates_response'
11
+ require 'reactive_shipping/shipping_response'
12
+ require 'reactive_shipping/label_response'
13
+ require 'reactive_shipping/label'
14
+ require 'reactive_shipping/package_item'
15
+ require 'reactive_shipping/package'
16
+ require 'reactive_shipping/location'
17
+ require 'reactive_shipping/rate_estimate'
18
+ require 'reactive_shipping/delivery_date_estimate'
19
+ require 'reactive_shipping/shipment_event'
20
+ require 'reactive_shipping/shipment_packer'
21
+ require 'reactive_shipping/carrier'
22
+ require 'reactive_shipping/carriers'
23
+ require 'reactive_shipping/errors'
24
+ require 'reactive_shipping/external_return_label_request'
25
+ require 'reactive_shipping/external_return_label_response'
26
+ require 'reactive_shipping/address_validation_response'
@@ -0,0 +1,30 @@
1
+ module ReactiveShipping
2
+
3
+ # Response object class for calls to {ReactiveShipping::Carrier#validate_address}.
4
+ #
5
+ # @!attribute location
6
+ # The Location to be validated
7
+ # @return [String]
8
+ class AddressValidationResponse < Response
9
+ attr_reader :validity, :classification, :candidate_addresses, :options, :params
10
+
11
+ def initialize(success, message, params = {}, options = {})
12
+ @validity = options[:validity]
13
+ @candidate_addresses = options[:candidate_addresses]
14
+ @classification = options[:classification]
15
+ super
16
+ end
17
+
18
+ def address_match?
19
+ @validity == :valid
20
+ end
21
+
22
+ def residential?
23
+ @classification == :residential
24
+ end
25
+
26
+ def commercial?
27
+ @classification == :commercial
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,184 @@
1
+ module ReactiveShipping
2
+
3
+ # Carrier is the abstract base class for all supported carriers.
4
+ #
5
+ # To implement support for a carrier, you should subclass this class and
6
+ # implement all the methods that the carrier supports.
7
+ #
8
+ # @see #find_rates
9
+ # @see #create_shipment
10
+ # @see #cancel_shipment
11
+ # @see #find_tracking_info
12
+ #
13
+ # @!attribute test_mode
14
+ # Whether to interact with the carrier's sandbox environment.
15
+ # @return [Boolean]
16
+ #
17
+ # @!attribute last_request
18
+ # The last request performed against the carrier's API.
19
+ # @see #save_request
20
+ class Carrier
21
+ attr_reader :last_request
22
+ attr_accessor :test_mode
23
+ alias_method :test_mode?, :test_mode
24
+
25
+ # Credentials should be in options hash under keys :login, :password and/or :key.
26
+ # @param options [Hash] The details needed to connect to the carrier's API.
27
+ # @option options [Boolean] :test Set this to true to connect to the carrier's
28
+ # sandbox environment instead of the production environment.
29
+ def initialize(options = {})
30
+ requirements.each { |key| requires!(options, key) }
31
+ @options = options
32
+ @last_request = nil
33
+ @test_mode = @options[:test]
34
+ end
35
+
36
+ # Asks the carrier for rate estimates for a given shipment.
37
+ #
38
+ # @note Override with whatever you need to get the rates from the carrier.
39
+ #
40
+ # @param origin [ReactiveShipping::Location] Where the shipment will originate from.
41
+ # @param destination [ReactiveShipping::Location] Where the package will go.
42
+ # @param packages [Array<ReactiveShipping::Package>] The list of packages that will
43
+ # be in the shipment.
44
+ # @param options [Hash] Carrier-specific parameters.
45
+ # @return [ReactiveShipping::RateResponse] The response from the carrier, which
46
+ # includes 0 or more rate estimates for different shipping products
47
+ def find_rates(origin, destination, packages, options = {})
48
+ raise NotImplementedError, "#find_rates is not supported by #{self.class.name}."
49
+ end
50
+
51
+ # Registers a new shipment with the carrier, to get a tracking number and
52
+ # potentially shipping labels
53
+ #
54
+ # @note Override with whatever you need to register a shipment, and obtain
55
+ # shipping labels if supported by the carrier.
56
+ #
57
+ # @param origin [ReactiveShipping::Location] Where the shipment will originate from.
58
+ # @param destination [ReactiveShipping::Location] Where the package will go.
59
+ # @param packages [Array<ReactiveShipping::Package>] The list of packages that will
60
+ # be in the shipment.
61
+ # @param options [Hash] Carrier-specific parameters.
62
+ # @return [ReactiveShipping::ShipmentResponse] The response from the carrier. This
63
+ # response should include a shipment identifier or tracking_number if successful,
64
+ # and potentially shipping labels.
65
+ def create_shipment(origin, destination, packages, options = {})
66
+ raise NotImplementedError, "#create_shipment is not supported by #{self.class.name}."
67
+ end
68
+
69
+ # Cancels a shipment with a carrier.
70
+ #
71
+ # @note Override with whatever you need to cancel a shipping label
72
+ #
73
+ # @param shipment_id [String] The unique identifier of the shipment to cancel.
74
+ # This can be shipment_id or tracking number depending on carrier. Up to you and
75
+ # the carrier
76
+ # @param options [Hash] Carrier-specific parameters.
77
+ # @return [ReactiveShipping::ShipmentResponse] The response from the carrier. This
78
+ # response in most cases has a cancellation id.
79
+ def cancel_shipment(shipment_id, options = {})
80
+ raise NotImplementedError, "#cancel_shipment is not supported by #{self.class.name}."
81
+ end
82
+
83
+ # Retrieves tracking information for a previous shipment
84
+ #
85
+ # @note Override with whatever you need to get a shipping label
86
+ #
87
+ # @param tracking_number [String] The unique identifier of the shipment to track.
88
+ # @param options [Hash] Carrier-specific parameters.
89
+ # @return [ReactiveShipping::TrackingResponse] The response from the carrier. This
90
+ # response should a list of shipment tracking events if successful.
91
+ def find_tracking_info(tracking_number, options = {})
92
+ raise NotImplementedError, "#find_tracking_info is not supported by #{self.class.name}."
93
+ end
94
+
95
+ # Get a list of services available for the a specific route
96
+ #
97
+ # @param origin_country_code [String] The country of origin
98
+ # @param destination_country_code [String] The destination country
99
+ # @return [Array<String>] A list of names of the available services
100
+ #
101
+ def available_services(origin_country_code, destination_country_code, options = {})
102
+ raise NotImplementedError, "#available_services is not supported by #{self.class.name}."
103
+ end
104
+
105
+ # Validate credentials with a call to the API.
106
+ #
107
+ # By default this just does a `find_rates` call with the origin and destination both as
108
+ # the carrier's default_location. Override to provide alternate functionality, such as
109
+ # checking for `test_mode` to use test servers, etc.
110
+ #
111
+ # @return [Boolean] Should return `true` if the provided credentials proved to work,
112
+ # `false` otherswise.
113
+ def valid_credentials?
114
+ location = self.class.default_location
115
+ find_rates(location, location, Package.new(100, [5, 15, 30]), :test => test_mode)
116
+ rescue ReactiveShipping::ResponseError
117
+ false
118
+ else
119
+ true
120
+ end
121
+
122
+ # The maximum weight the carrier will accept.
123
+ # @return [Measured::Weight]
124
+ def maximum_weight
125
+ Measured::Weight.new(150, :pounds)
126
+ end
127
+
128
+ # The address field maximum length accepted by the carrier
129
+ # @return [Integer]
130
+ def maximum_address_field_length
131
+ 255
132
+ end
133
+
134
+ protected
135
+
136
+ include ActiveUtils::RequiresParameters
137
+ include ActiveUtils::PostsData
138
+
139
+ # Returns the keys that are required to be passed to the options hash
140
+ # @note Override to return required keys in options hash for initialize method.
141
+ # @return [Array<Symbol>]
142
+ def requirements
143
+ []
144
+ end
145
+
146
+ # The default location to use for {#valid_credentials?}.
147
+ # @note Override for non-U.S.-based carriers.
148
+ # @return [ReactiveShipping::Location]
149
+ def self.default_location
150
+ Location.new( :country => 'US',
151
+ :state => 'CA',
152
+ :city => 'Beverly Hills',
153
+ :address1 => '455 N. Rexford Dr.',
154
+ :address2 => '3rd Floor',
155
+ :zip => '90210',
156
+ :phone => '1-310-285-1013',
157
+ :fax => '1-310-275-8159')
158
+ end
159
+
160
+ # Use after building the request to save for later inspection.
161
+ # @return [void]
162
+ def save_request(r)
163
+ @last_request = r
164
+ end
165
+
166
+ # Calculates a timestamp that corresponds a given number of business days in the future
167
+ #
168
+ # @param days [Integer] The number of business days from now.
169
+ # @return [DateTime] A timestamp, the provided number of business days in the future.
170
+ def timestamp_from_business_day(days)
171
+ return unless days
172
+ date = DateTime.now.utc
173
+
174
+ days.times do
175
+ date += 1.day
176
+
177
+ date += 2.days if date.saturday?
178
+ date += 1.day if date.sunday?
179
+ end
180
+
181
+ date.to_datetime
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,35 @@
1
+ module ReactiveShipping
2
+ module Carriers
3
+ extend self
4
+
5
+ attr_reader :registered
6
+ @registered = []
7
+
8
+ def register(class_name, autoload_require)
9
+ ReactiveShipping.autoload(class_name, autoload_require)
10
+ self.registered << class_name
11
+ end
12
+
13
+ def all
14
+ ReactiveShipping::Carriers.registered.map { |name| ReactiveShipping.const_get(name) }
15
+ end
16
+
17
+ def find(name)
18
+ all.find { |c| c.name.downcase == name.to_s.downcase } or raise NameError, "unknown carrier #{name}"
19
+ end
20
+ end
21
+ end
22
+
23
+ ReactiveShipping::Carriers.register :BenchmarkCarrier, 'reactive_shipping/carriers/benchmark_carrier'
24
+ ReactiveShipping::Carriers.register :BogusCarrier, 'reactive_shipping/carriers/bogus_carrier'
25
+ ReactiveShipping::Carriers.register :UPS, 'reactive_shipping/carriers/ups'
26
+ ReactiveShipping::Carriers.register :USPS, 'reactive_shipping/carriers/usps'
27
+ ReactiveShipping::Carriers.register :USPSReturns, 'reactive_shipping/carriers/usps_returns'
28
+ ReactiveShipping::Carriers.register :FedEx, 'reactive_shipping/carriers/fedex'
29
+ ReactiveShipping::Carriers.register :Shipwire, 'reactive_shipping/carriers/shipwire'
30
+ ReactiveShipping::Carriers.register :Kunaki, 'reactive_shipping/carriers/kunaki'
31
+ ReactiveShipping::Carriers.register :CanadaPost, 'reactive_shipping/carriers/canada_post'
32
+ ReactiveShipping::Carriers.register :NewZealandPost, 'reactive_shipping/carriers/new_zealand_post'
33
+ ReactiveShipping::Carriers.register :CanadaPostPWS, 'reactive_shipping/carriers/canada_post_pws'
34
+ ReactiveShipping::Carriers.register :Stamps, 'reactive_shipping/carriers/stamps'
35
+ ReactiveShipping::Carriers.register :AustraliaPost, 'reactive_shipping/carriers/australia_post'