diff --git a/.gitignore b/.gitignore index 5792ff9..52d3d1b 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,4 @@ bower.json # Ignore pow environment settings .powenv coverage +.env diff --git a/Gemfile b/Gemfile index f3a9b9b..1756ec2 100644 --- a/Gemfile +++ b/Gemfile @@ -26,6 +26,11 @@ gem 'sdoc', '~> 0.4.0', group: :doc # Use active_shipping for shipping amounts gem 'active_shipping' +#use dotenv for secrets +gem 'dotenv-rails' + +gem 'responders', '~> 2.0' + # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' @@ -41,6 +46,7 @@ group :development, :test do gem 'rspec-rails' gem 'simplecov', require: false gem 'factory_girl_rails' + end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index ab3fff7..b00f61c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -65,6 +65,10 @@ GEM debug_inspector (0.0.2) diff-lcs (1.2.5) docile (1.1.5) + dotenv (2.1.0) + dotenv-rails (2.1.0) + dotenv (= 2.1.0) + railties (>= 4.0, < 5.1) erubis (2.7.0) execjs (2.6.0) factory_girl (4.5.0) @@ -131,6 +135,8 @@ GEM rake (10.5.0) rdoc (4.2.1) json (~> 1.4) + responders (2.1.1) + railties (>= 4.2.0, < 5.1) rspec-core (3.4.1) rspec-support (~> 3.4.0) rspec-expectations (3.4.0) @@ -198,11 +204,13 @@ DEPENDENCIES binding_of_caller byebug coffee-rails (~> 4.1.0) + dotenv-rails factory_girl_rails jbuilder (~> 2.0) jquery-rails pry-rails rails (= 4.2.5) + responders (~> 2.0) rspec-rails sass-rails (~> 5.0) sdoc (~> 0.4.0) diff --git a/app/assets/javascripts/shipments.coffee b/app/assets/javascripts/shipments.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/shipments.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/shipments.scss b/app/assets/stylesheets/shipments.scss new file mode 100644 index 0000000..68e8f86 --- /dev/null +++ b/app/assets/stylesheets/shipments.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Shipments 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/application_controller.rb b/app/controllers/application_controller.rb index d83690e..52e0790 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,5 +1,5 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. - protect_from_forgery with: :exception + end diff --git a/app/controllers/shipments_controller.rb b/app/controllers/shipments_controller.rb new file mode 100644 index 0000000..44046a2 --- /dev/null +++ b/app/controllers/shipments_controller.rb @@ -0,0 +1,59 @@ +class ShipmentsController < ApplicationController +respond_to :json + + def estimate + begin + weight = (package_params[:weight]).to_i + dimensions = [(package_params[:length]).to_i, (package_params[:width]).to_i, (package_params[:height]).to_i] + package = ActiveShipping::Package.new(weight, dimensions) + packages = [package] + origin = ActiveShipping::Location.new(origin_params) + destination = ActiveShipping::Location.new(destination_params) + + ups = ups_rates(origin, destination, packages) + usps = usps_rates(origin, destination, packages) + rates = ups.merge(usps) + render :json => rates.as_json, :status => :ok + rescue + render :json => { error: :bad_data, message: "You must provide valid data for package size, package weight, origin location and destination location." }, status: :bad_request + end + end + +private + + def package_params + params.require(:package).permit(:weight, :length, :width, :height) + end + + def origin_params + params.require(:origin).permit(:country, :state, :province, :city, :zip, :postal_code) + end + + def destination_params + params.require(:destination).permit(:country, :state, :province, :city, :zip, :postal_code) + end + + + def ups_rates(origin, destination, packages) + ups = ActiveShipping::UPS.new(login: ENV['UPS_LOGIN'], password: ENV['UPS_PASSWORD'], key: ENV['UPS_KEY']) + response = ups.find_rates(origin, destination, packages) + + ups_rate_response = {} + response.rates.sort_by(&:price).each do |rate| + ups_rate_response[rate.service_name] = rate.price + end + return ups_rate_response + end + + def usps_rates(origin, destination, packages) + usps = ActiveShipping::USPS.new(login: ENV['USPS_USERNAME']) + response = usps.find_rates(origin, destination, packages) + + usps_rate_response = {} + response.rates.sort_by(&:price).each do |rate| + usps_rate_response[rate.service_name] = rate.price + end + return usps_rate_response + end + +end diff --git a/app/helpers/shipments_helper.rb b/app/helpers/shipments_helper.rb new file mode 100644 index 0000000..848b334 --- /dev/null +++ b/app/helpers/shipments_helper.rb @@ -0,0 +1,2 @@ +module ShipmentsHelper +end diff --git a/config/routes.rb b/config/routes.rb index 3f66539..89d574f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,56 +1,3 @@ Rails.application.routes.draw do - # The priority is based upon order of creation: first created -> highest priority. - # See how all your routes lay out with "rake routes". - - # You can have the root of your site routed with "root" - # root 'welcome#index' - - # Example of regular route: - # get 'products/:id' => 'catalog#view' - - # Example of named route that can be invoked with purchase_url(id: product.id) - # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase - - # Example resource route (maps HTTP verbs to controller actions automatically): - # resources :products - - # Example resource route with options: - # resources :products do - # member do - # get 'short' - # post 'toggle' - # end - # - # collection do - # get 'sold' - # end - # end - - # Example resource route with sub-resources: - # resources :products do - # resources :comments, :sales - # resource :seller - # end - - # Example resource route with more complex sub-resources: - # resources :products do - # resources :comments - # resources :sales do - # get 'recent', on: :collection - # end - # end - - # Example resource route with concerns: - # concern :toggleable do - # post 'toggle' - # end - # resources :posts, concerns: :toggleable - # resources :photos, concerns: :toggleable - - # Example resource route within a namespace: - # namespace :admin do - # # Directs /admin/products/* to Admin::ProductsController - # # (app/controllers/admin/products_controller.rb) - # resources :products - # end + post 'estimate' => 'shipments#estimate' end 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/spec/controllers/shipments_controller_spec.rb b/spec/controllers/shipments_controller_spec.rb new file mode 100644 index 0000000..3702900 --- /dev/null +++ b/spec/controllers/shipments_controller_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' +require 'pry' + +RSpec.describe ShipmentsController, type: :controller do + describe "POST 'estimate'" do + let(:params) do + {origin: {country: 'US', + state: 'CA', + city: 'Beverly Hills', + zip: '90210'}, + + destination: {country: 'CA', + province: 'ON', + city: 'Ottawa', + postal_code: 'K1P 1J1'}, + package: { weight: 100, + length: 93, + width: 10, + height: 10} + } + end + + it "is successful" do + post :estimate, params + expect(response.response_code).to eq 200 + end + end + + end diff --git a/spec/helpers/shipments_helper_spec.rb b/spec/helpers/shipments_helper_spec.rb new file mode 100644 index 0000000..36c5c65 --- /dev/null +++ b/spec/helpers/shipments_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the ShipmentsHelper. For example: +# +# describe ShipmentsHelper 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 ShipmentsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end