diff --git a/.gitignore b/.gitignore
index 4203e5c..b33710a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,5 @@
*.DS_Store
*.keep
coverage
+
+/spec/vcr/*.yml
diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..83e16f8
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,2 @@
+--color
+--require spec_helper
diff --git a/Gemfile b/Gemfile
index e1378ac..5255f98 100644
--- a/Gemfile
+++ b/Gemfile
@@ -23,6 +23,10 @@ gem 'sdoc', '~> 0.4.0', group: :doc
gem 'pg'
+gem 'active_shipping'
+
+gem 'rails_12factor', group: :production
+
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
@@ -41,6 +45,11 @@ group :development, :test do
gem 'sqlite3'
gem 'pry-rails'
gem 'factory_girl_rails'
+ gem 'vcr'
+end
+
+group :test do
+ gem 'webmock'
end
group :development do
diff --git a/Gemfile.lock b/Gemfile.lock
index 90797c7..d790ee4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -20,6 +20,14 @@ GEM
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
+ active_shipping (1.6.5)
+ active_utils (~> 3.2.0)
+ activesupport (>= 3.2, < 5.0.0)
+ nokogiri (>= 1.6)
+ quantified (~> 1.0.1)
+ active_utils (3.2.0)
+ activesupport (>= 3.2)
+ i18n
activejob (4.2.5)
activesupport (= 4.2.5)
globalid (>= 0.3.0)
@@ -36,6 +44,7 @@ GEM
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
+ addressable (2.4.0)
arel (6.0.3)
better_errors (2.1.1)
coderay (>= 1.0.0)
@@ -54,6 +63,8 @@ GEM
execjs
coffee-script-source (1.10.0)
concurrent-ruby (1.0.0)
+ crack (0.4.3)
+ safe_yaml (~> 1.0.0)
debug_inspector (0.0.2)
diff-lcs (1.2.5)
docile (1.1.5)
@@ -70,6 +81,7 @@ GEM
railties (>= 3.0.0)
globalid (0.3.6)
activesupport (>= 4.1.0)
+ hashdiff (0.2.3)
i18n (0.7.0)
jbuilder (2.4.0)
activesupport (>= 3.0.0, < 5.1)
@@ -97,6 +109,7 @@ GEM
slop (~> 3.4)
pry-rails (0.3.4)
pry (>= 0.9.10)
+ quantified (1.0.1)
rack (1.6.4)
rack-test (0.6.3)
rack (>= 1.0)
@@ -119,6 +132,11 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.2)
loofah (~> 2.0)
+ rails_12factor (0.0.3)
+ rails_serve_static_assets
+ rails_stdout_logging
+ rails_serve_static_assets (0.0.4)
+ rails_stdout_logging (0.0.4)
railties (4.2.5)
actionpack (= 4.2.5)
activesupport (= 4.2.5)
@@ -144,6 +162,7 @@ GEM
rspec-mocks (~> 3.4.0)
rspec-support (~> 3.4.0)
rspec-support (3.4.1)
+ safe_yaml (1.0.4)
sass (3.4.21)
sass-rails (5.0.4)
railties (>= 4.0.0, < 5.0)
@@ -179,16 +198,22 @@ GEM
uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
+ vcr (3.0.1)
web-console (2.2.1)
activemodel (>= 4.0)
binding_of_caller (>= 0.7.2)
railties (>= 4.0)
sprockets-rails (>= 2.0, < 4.0)
+ webmock (1.22.6)
+ addressable (>= 2.3.6)
+ crack (>= 0.3.2)
+ hashdiff
PLATFORMS
ruby
DEPENDENCIES
+ active_shipping
better_errors
binding_of_caller
byebug
@@ -200,6 +225,7 @@ DEPENDENCIES
pg
pry-rails
rails (= 4.2.5)
+ rails_12factor
rspec-rails
sass-rails (~> 5.0)
sdoc (~> 0.4.0)
@@ -208,7 +234,9 @@ DEPENDENCIES
sqlite3
turbolinks
uglifier (>= 1.3.0)
+ vcr
web-console (~> 2.0)
+ webmock
BUNDLED WITH
1.11.2
diff --git a/app/assets/javascripts/estimates.coffee b/app/assets/javascripts/estimates.coffee
new file mode 100644
index 0000000..24f83d1
--- /dev/null
+++ b/app/assets/javascripts/estimates.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/stylesheets/estimates.scss b/app/assets/stylesheets/estimates.scss
new file mode 100644
index 0000000..602fef5
--- /dev/null
+++ b/app/assets/stylesheets/estimates.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the estimates controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/controllers/estimates_controller.rb b/app/controllers/estimates_controller.rb
new file mode 100644
index 0000000..8fdcb47
--- /dev/null
+++ b/app/controllers/estimates_controller.rb
@@ -0,0 +1,84 @@
+require 'active_shipping'
+require './lib/ups_services'
+
+class EstimatesController < ApplicationController
+ # create constants for origin object, package grams_or_ounces and package dimensions, and country
+ # also create carrier constants which is a ups carrier and a fedex carrier?
+ UPS = ActiveShipping::UPS.new(login: ENV['UPS_LOGIN'], password: ENV['UPS_PASSWORD'], key: ENV['UPS_KEY'])
+
+ USPS = ActiveShipping::USPS.new(login: ENV['USPS_LOGIN'])
+
+ # assume all packages are being sent within the US
+ COUNTRY = "US"
+ # assume all packages are originating from Ada's betsy distribution center
+ ORIGIN = ActiveShipping::Location.new(country: COUNTRY, state: 'WA', city: 'Seattle', zip: '98101')
+ # assume all packages have the same ounces and dimensions, for now
+ OUNCES = 120
+ DIMENSIONS = [15, 10, 4.5]
+
+ def estimate
+ # only one package for all products in order, for now
+ package = [ActiveShipping::Package.new(OUNCES, DIMENSIONS, units: :imperial, value: params[:value])]
+ # destination address info comes from query params provided from betsy app's API call
+ destination = ActiveShipping::Location.new(country: COUNTRY, state: params[:destination][:state], city: params[:destination][:city], zip: params[:destination][:zip])
+ # method call
+ begin
+ ups_estimates = UpsServices.transform_codes_into_names(get_ups_estimates(ORIGIN, destination, package))
+ rescue
+ return render :json => [], :status => :bad_request
+ end
+ # method call
+ begin
+ usps_estimates = get_usps_estimates(ORIGIN, destination, package)
+ rescue
+ return render :json => [], :status => :bad_request
+ end
+ # response includes rates and dates from both UPS and USPS
+ response = {"UPS Service Options" => ups_estimates, "USPS Service Options" => usps_estimates }
+ render :json => response.as_json, :status => :ok
+ end
+
+private
+
+ def get_ups_estimates(origin, destination, package)
+ rates_response = UPS.find_rates(ORIGIN, destination, package)
+ delivery_dates_response = UPS.get_delivery_date_estimates(ORIGIN, destination, package)
+ # shipping_estimate will be a hash made up of service_code keys
+ # each key points to a hash which contains the cost and delivery date estimate
+ # for the corresponding service type.
+ shipping_estimate = Hash.new
+ rates_response.rates.each do |rate|
+ # skip this rate if service code is nil
+ next if rate.service_code.nil?
+ # otherwise, create a key for the corresponding service code
+ # the value is a hash containing the corresponding cost
+ shipping_estimate["#{rate.service_code}"] = { "cost" => "#{rate.total_price}" }
+ end
+ delivery_dates_response.delivery_estimates.each do |estimate|
+ # skip this estimate if service code is nil
+ next if estimate.service_code.nil?
+ # otherwise check to see if the service code already exists in the hash
+ if shipping_estimate["#{estimate.service_code}"].nil?
+ # if the service code doesn't yet exist in the hash, create a key for it
+ # with the value being a hash corresponding to the date
+ shipping_estimate["#{estimate.service_code}"] = { "date" => "#{estimate.date}" }
+ else
+ # if it already exists, merge the date corresponding to this estimate into the the
+ # hash associated with this service code key
+ shipping_estimate["#{estimate.service_code}"].merge!({ "date" => "#{estimate.date}"})
+ end
+ end
+ return shipping_estimate
+ end
+
+ def get_usps_estimates(origin, destination, package)
+ rates_response = USPS.find_rates(ORIGIN, destination, package)
+ usps_rates = rates_response.rates
+ shipping_estimate = Hash.new
+ usps_rates.each do |rate|
+ next if rate.service_name.nil?
+ shipping_estimate["#{rate.service_name}"] = { "cost" => "#{rate.price}", "date" => "#{rate.delivery_date}"}
+ end
+ return shipping_estimate
+ end
+end
diff --git a/app/helpers/estimates_helper.rb b/app/helpers/estimates_helper.rb
new file mode 100644
index 0000000..019d7a6
--- /dev/null
+++ b/app/helpers/estimates_helper.rb
@@ -0,0 +1,2 @@
+module EstimatesHelper
+end
diff --git a/config/application.rb b/config/application.rb
index 84b564d..2e04936 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -9,6 +9,7 @@
require "action_mailer/railtie"
require "action_view/railtie"
require "sprockets/railtie"
+# require "dotenv"
# require "rails/test_unit/railtie"
# Require the gems listed in Gemfile, including any gems
diff --git a/config/routes.rb b/config/routes.rb
index 3f66539..4a8dda8 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,4 +1,5 @@
Rails.application.routes.draw do
+ get '/' => 'estimates#estimate'
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
diff --git a/db/schema.rb b/db/schema.rb
new file mode 100644
index 0000000..4dfbb16
--- /dev/null
+++ b/db/schema.rb
@@ -0,0 +1,16 @@
+# encoding: UTF-8
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your
+# database schema. If you need to create the application database on another
+# system, you should be using db:schema:load, not running all the migrations
+# from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema.define(version: 0) do
+
+end
diff --git a/lib/ups_services.rb b/lib/ups_services.rb
new file mode 100644
index 0000000..e1596a5
--- /dev/null
+++ b/lib/ups_services.rb
@@ -0,0 +1,29 @@
+class UpsServices
+ SERVICES = {
+ "01" => "UPS Next Day Air",
+ "02" => "UPS Second Day Air",
+ "03" => "UPS Ground",
+ "07" => "UPS Worldwide Express",
+ "08" => "UPS Worldwide Expedited",
+ "11" => "UPS Standard",
+ "12" => "UPS Three-Day Select",
+ "13" => "UPS Next Day Air Saver",
+ "14" => "UPS Next Day Air Early A.M.",
+ "54" => "UPS Worldwide Express Plus",
+ "59" => "UPS Second Day Air A.M.",
+ "65" => "UPS Saver",
+ "82" => "UPS Today Standard",
+ "83" => "UPS Today Dedicated Courier",
+ "84" => "UPS Today Intercity",
+ "85" => "UPS Today Express",
+ "86" => "UPS Today Express Saver"
+ }
+
+ def self.transform_codes_into_names(hash)
+ mappings = Hash.new
+ hash.keys.each do |key|
+ mappings[key] = SERVICES[key]
+ end
+ Hash[hash.map {|k, v| [mappings[k], v] }]
+ end
+end
diff --git a/spec/controllers/estimates_controller_spec.rb b/spec/controllers/estimates_controller_spec.rb
new file mode 100644
index 0000000..1bd6c22
--- /dev/null
+++ b/spec/controllers/estimates_controller_spec.rb
@@ -0,0 +1,34 @@
+require 'rails_helper'
+require 'support/vcr_setup'
+
+RSpec.describe EstimatesController, type: :controller do
+ let!(:package) do
+ {
+ value: 2000
+ }
+ end
+
+ let!(:destination) do
+ {
+ destination: {
+ state: "CA",
+ city: "San Francisco",
+ zip: 94104
+ }
+ }
+ end
+
+ describe "GET 'estimate'" do
+
+ it "is successful", :vcr do
+ get :estimate, destination.merge(package)
+ expect(response.response_code).to eq 200
+ end
+
+ # describe 'get_usps_estimates' do
+ # it 'returns a hash with service names and cost' do
+ # expect(response.body).to eq ""
+ # end
+ # end
+ end
+end
diff --git a/spec/helpers/estimates_helper_spec.rb b/spec/helpers/estimates_helper_spec.rb
new file mode 100644
index 0000000..0cba7f7
--- /dev/null
+++ b/spec/helpers/estimates_helper_spec.rb
@@ -0,0 +1,15 @@
+require 'rails_helper'
+
+# Specs in this file have access to a helper object that includes
+# the EstimatesHelper. For example:
+#
+# describe EstimatesHelper do
+# describe "string concat" do
+# it "concats two strings with spaces" do
+# expect(helper.concat_strings("this","that")).to eq("this that")
+# end
+# end
+# end
+RSpec.describe EstimatesHelper, type: :helper do
+ # pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
new file mode 100644
index 0000000..6f1ab14
--- /dev/null
+++ b/spec/rails_helper.rb
@@ -0,0 +1,57 @@
+# This file is copied to spec/ when you run 'rails generate rspec:install'
+ENV['RAILS_ENV'] ||= 'test'
+require File.expand_path('../../config/environment', __FILE__)
+# Prevent database truncation if the environment is production
+abort("The Rails environment is running in production mode!") if Rails.env.production?
+require 'spec_helper'
+require 'rspec/rails'
+# Add additional requires below this line. Rails is not loaded until this point!
+
+# Requires supporting ruby files with custom matchers and macros, etc, in
+# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
+# run as spec files by default. This means that files in spec/support that end
+# in _spec.rb will both be required and run as specs, causing the specs to be
+# run twice. It is recommended that you do not name files matching this glob to
+# end with _spec.rb. You can configure this pattern with the --pattern
+# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
+#
+# The following line is provided for convenience purposes. It has the downside
+# of increasing the boot-up time by auto-requiring all files in the support
+# directory. Alternatively, in the individual `*_spec.rb` files, manually
+# require only the support files necessary.
+#
+# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
+
+# Checks for pending migration and applies them before tests are run.
+# If you are not using ActiveRecord, you can remove this line.
+ActiveRecord::Migration.maintain_test_schema!
+
+RSpec.configure do |config|
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
+
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
+ # examples within a transaction, remove the following line or assign false
+ # instead of true.
+ config.use_transactional_fixtures = true
+
+ # RSpec Rails can automatically mix in different behaviours to your tests
+ # based on their file location, for example enabling you to call `get` and
+ # `post` in specs under `spec/controllers`.
+ #
+ # You can disable this behaviour by removing the line below, and instead
+ # explicitly tag your specs with their type, e.g.:
+ #
+ # RSpec.describe UsersController, :type => :controller do
+ # # ...
+ # end
+ #
+ # The different available types are documented in the features, such as in
+ # https://relishapp.com/rspec/rspec-rails/docs
+ config.infer_spec_type_from_file_location!
+
+ # Filter lines from Rails gems in backtraces.
+ config.filter_rails_from_backtrace!
+ # arbitrary gems may also be filtered via:
+ # config.filter_gems_from_backtrace("gem name")
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..fdf3f19
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,104 @@
+# This file was generated by the `rails generate rspec:install` command. Conventionally, all
+# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
+# The generated `.rspec` file contains `--require spec_helper` which will cause
+# this file to always be loaded, without a need to explicitly require it in any
+# files.
+#
+# Given that it is always loaded, you are encouraged to keep this file as
+# light-weight as possible. Requiring heavyweight dependencies from this file
+# will add to the boot time of your test suite on EVERY test run, even for an
+# individual file that may not need all of that loaded. Instead, consider making
+# a separate helper file that requires the additional dependencies and performs
+# the additional setup, and require it from the spec files that actually need
+# it.
+#
+# The `.rspec` file also contains a few flags that are not defaults but that
+# users commonly want.
+#
+# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
+
+require 'simplecov'
+SimpleCov.start do
+ add_filter '/spec/'
+end
+
+RSpec.configure do |config|
+ # rspec-expectations config goes here. You can use an alternate
+ # assertion/expectation library such as wrong or the stdlib/minitest
+ # assertions if you prefer.
+ config.expect_with :rspec do |expectations|
+ # This option will default to `true` in RSpec 4. It makes the `description`
+ # and `failure_message` of custom matchers include text for helper methods
+ # defined using `chain`, e.g.:
+ # be_bigger_than(2).and_smaller_than(4).description
+ # # => "be bigger than 2 and smaller than 4"
+ # ...rather than:
+ # # => "be bigger than 2"
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+ end
+
+ # rspec-mocks config goes here. You can use an alternate test double
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
+ config.mock_with :rspec do |mocks|
+ # Prevents you from mocking or stubbing a method that does not exist on
+ # a real object. This is generally recommended, and will default to
+ # `true` in RSpec 4.
+ mocks.verify_partial_doubles = true
+ end
+
+# The settings below are suggested to provide a good initial experience
+# with RSpec, but feel free to customize to your heart's content.
+=begin
+ # These two settings work together to allow you to limit a spec run
+ # to individual examples or groups you care about by tagging them with
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
+ # get run.
+ config.filter_run :focus
+ config.run_all_when_everything_filtered = true
+
+ # Allows RSpec to persist some state between runs in order to support
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
+ # you configure your source control system to ignore this file.
+ config.example_status_persistence_file_path = "spec/examples.txt"
+
+ # Limits the available syntax to the non-monkey patched syntax that is
+ # recommended. For more details, see:
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
+ config.disable_monkey_patching!
+
+ # Many RSpec users commonly either run the entire suite or an individual
+ # file, and it's useful to allow more verbose output when running an
+ # individual spec file.
+ if config.files_to_run.one?
+ # Use the documentation formatter for detailed output,
+ # unless a formatter has already been configured
+ # (e.g. via a command-line flag).
+ config.default_formatter = 'doc'
+ end
+
+ # Print the 10 slowest examples and example groups at the
+ # end of the spec run, to help surface which specs are running
+ # particularly slow.
+ config.profile_examples = 10
+
+ # Run specs in random order to surface order dependencies. If you find an
+ # order dependency and want to debug it, you can fix the order by providing
+ # the seed, which is printed after each run.
+ # --seed 1234
+ config.order = :random
+
+ # Seed global randomization in this process using the `--seed` CLI option.
+ # Setting this allows you to use `--seed` to deterministically reproduce
+ # test failures related to randomization by passing the same `--seed` value
+ # as the one that triggered the failure.
+ Kernel.srand config.seed
+=end
+
+end
+shared_context 'vcr helpers', :vcr do
+ def only_when_recording
+ yield if VCR.current_cassette.recording?
+ end
+end
diff --git a/spec/support/vcr_setup.rb b/spec/support/vcr_setup.rb
new file mode 100644
index 0000000..d277646
--- /dev/null
+++ b/spec/support/vcr_setup.rb
@@ -0,0 +1,7 @@
+VCR.configure do |c|
+ #the directory where your cassettes will be saved
+ c.cassette_library_dir = 'spec/vcr'
+ # your HTTP request service.
+ c.hook_into :webmock
+ c.configure_rspec_metadata!
+end
diff --git a/spec/vcr/EstimatesController/GET_estimate_/is_successful.yml b/spec/vcr/EstimatesController/GET_estimate_/is_successful.yml
new file mode 100644
index 0000000..074b5b5
--- /dev/null
+++ b/spec/vcr/EstimatesController/GET_estimate_/is_successful.yml
@@ -0,0 +1,252 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://onlinetools.ups.com/ups.app/xml/Rate
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ 6D02C98DCD321654
+ meighanr
+ Fuzzyfionas123
+
+
+
+
+ Rate
+ Shop
+
+
+ 01
+
+
+ 01
+
+
+
+
+ Seattle
+ WA
+ 98101
+ US
+ true
+
+
+
+
+ San Francisco
+ CA
+ 94104
+ US
+ true
+
+
+
+
+ 02
+
+
+
+ IN
+
+ 15.0
+ 10.0
+ 4.5
+
+
+
+ LBS
+
+ 7.5
+
+
+
+
+
+ headers:
+ Content-Type:
+ - application/x-www-form-urlencoded
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Fri, 22 Jan 2016 22:47:13 GMT
+ Server:
+ - Apache
+ X-Frame-Options:
+ - SAMEORIGIN
+ Pragma:
+ - no-cache
+ Content-Length:
+ - '7200'
+ X-Content-Type-Options:
+ - nosniff
+ Content-Type:
+ - application/xml
+ body:
+ encoding: UTF-8
+ string: |-
+
+ 1Success03Your invoice may vary from the displayed reference ratesLBS8.0USD15.36USD0.00USD15.36USD15.36USD0.00USD15.367.5LBS8.012Your invoice may vary from the displayed reference ratesLBS8.0USD29.97USD0.00USD29.973USD29.97USD0.00USD29.977.5LBS8.002Your invoice may vary from the displayed reference ratesLBS8.0USD42.89USD0.00USD42.892USD42.89USD0.00USD42.897.5LBS8.013Your invoice may vary from the displayed reference ratesLBS8.0USD95.35USD0.00USD95.351USD95.35USD0.00USD95.357.5LBS8.014Your invoice may vary from the displayed reference ratesLBS8.0USD135.48USD0.00USD135.4818:00 A.M.USD135.48USD0.00USD135.487.5LBS8.001Your invoice may vary from the displayed reference ratesLBS8.0USD104.21USD0.00USD104.21110:30 A.M.USD104.21USD0.00USD104.217.5LBS8.0
+ http_version:
+ recorded_at: Fri, 22 Jan 2016 22:47:14 GMT
+- request:
+ method: post
+ uri: https://onlinetools.ups.com/ups.app/xml/TimeInTransit
+ body:
+ encoding: UTF-8
+ string: |
+
+
+ 6D02C98DCD321654
+ meighanr
+ Fuzzyfionas123
+
+
+
+
+ TimeInTransit
+
+
+
+ Seattle
+ WA
+ US
+ 98101
+ true
+
+
+
+
+ San Francisco
+ CA
+ US
+ 94104
+ true
+
+
+
+
+ KGS
+
+ 3.402
+
+
+ USD
+ 2000
+
+ 20160122
+
+ headers:
+ Content-Type:
+ - application/x-www-form-urlencoded
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Fri, 22 Jan 2016 22:47:14 GMT
+ Server:
+ - Apache
+ X-Frame-Options:
+ - SAMEORIGIN
+ Pragma:
+ - no-cache
+ Content-Length:
+ - '4779'
+ X-Content-Type-Options:
+ - nosniff
+ Content-Type:
+ - application/xml
+ body:
+ encoding: UTF-8
+ string: 1Success2016-01-22SEATTLEWAUNITED
+ STATESUS98101SAN
+ FRANCISCOCAUNITED
+ STATESUS94104KGS3.4USD2000.00Services
+ listed as guaranteed are backed by a money-back guarantee for transportation
+ charges only. UPS guarantees the day of delivery for every ground package
+ you ship to any address within all 50 states and Puerto Rico. See Terms and
+ Conditions in the Service Guide for details.1DMSUPS
+ Next Day Air Early (Saturday Delivery)N12016-01-2217:00:002016-01-23SAT16:00:001Saturday
+ Delivery is available for an additional charge.1DASUPS
+ Next Day Air (Saturday Delivery)N12016-01-2217:00:002016-01-23SAT16:00:001Saturday
+ Delivery is available for an additional charge.1DMUPS
+ Next Day Air EarlyN12016-01-2217:00:002016-01-25MON16:00:001DAUPS
+ Next Day AirN12016-01-2217:00:002016-01-25MON16:00:001DPUPS
+ Next Day Air SaverN12016-01-2217:00:002016-01-25MON16:00:002DAUPS
+ 2nd Day AirN22016-01-2217:00:002016-01-26TUE16:00:00GNDUPS
+ GroundN22016-01-2217:00:002016-01-26TUE16:00:0035
+ http_version:
+ recorded_at: Fri, 22 Jan 2016 22:47:15 GMT
+- request:
+ method: get
+ uri: http://production.shippingapis.com/ShippingAPI.dll?API=RateV4&XML=%3C?xml%20version=%221.0%22?%3E%0A%3CRateV4Request%20USERID=%22677JADED7283%22%3E%0A%20%20%3CPackage%20ID=%220%22%3E%0A%20%20%20%20%3CService%3EALL%3C/Service%3E%0A%20%20%20%20%3CFirstClassMailType/%3E%0A%20%20%20%20%3CZipOrigination%3E98101%3C/ZipOrigination%3E%0A%20%20%20%20%3CZipDestination%3E94104%3C/ZipDestination%3E%0A%20%20%20%20%3CPounds%3E0%3C/Pounds%3E%0A%20%20%20%20%3COunces%3E120.0%3C/Ounces%3E%0A%20%20%20%20%3CContainer%3ERECTANGULAR%3C/Container%3E%0A%20%20%20%20%3CSize%3ELARGE%3C/Size%3E%0A%20%20%20%20%3CWidth%3E10.00%3C/Width%3E%0A%20%20%20%20%3CLength%3E15.00%3C/Length%3E%0A%20%20%20%20%3CHeight%3E4.50%3C/Height%3E%0A%20%20%20%20%3CGirth%3E29.00%3C/Girth%3E%0A%20%20%20%20%3CMachinable%3ETRUE%3C/Machinable%3E%0A%20%20%3C/Package%3E%0A%3C/RateV4Request%3E%0A
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ X-Backside-Transport:
+ - OK OK
+ Cache-Control:
+ - private
+ Content-Type:
+ - text/xml
+ Server:
+ - Microsoft-IIS/7.5
+ X-Aspnet-Version:
+ - 2.0.50727
+ X-Powered-By:
+ - ASP.NET
+ Date:
+ - Fri, 22 Jan 2016 22:47:14 GMT
+ X-Client-Ip:
+ - 56.0.33.9
+ X-Global-Transaction-Id:
+ - '3076197101'
+ Access-Control-Allow-Origin:
+ - "*"
+ Connection:
+ - Keep-Alive
+ Cteonnt-Length:
+ - '1072'
+ X-Frame-Options:
+ - SAMEORIGIN
+ Content-Length:
+ - '393'
+ body:
+ encoding: ASCII-8BIT
+ string: |-
+
+ 98101941040120.0LARGETRUE5Priority Mail Express 1-Day<sup>™</sup>65.50Priority Mail Express 1-Day<sup>™</sup> Hold For Pickup65.50Priority Mail 2-Day<sup>™</sup>22.65USPS Retail Ground<sup>™</sup>19.27Media Mail Parcel6.22Library Mail Parcel5.95
+ http_version:
+ recorded_at: Fri, 22 Jan 2016 22:47:15 GMT
+recorded_with: VCR 3.0.1