fedex 0.0.1
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.
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/Readme.md +92 -0
- data/fedex.gemspec +27 -0
- data/lib/fedex.rb +54 -0
- data/lib/fedex/rate.rb +34 -0
- data/lib/fedex/shipment.rb +280 -0
- data/lib/fedex/version.rb +4 -0
- data/spec/fedex_spec.rb +51 -0
- data/spec/spec_helper.rb +1 -0
- metadata +121 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/Readme.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# Fedex Rate Web Service
|
2
|
+
|
3
|
+
For more information visit [Fedex Web Services for Shipping](https://www.fedex.com/wpor/web/jsp/drclinks.jsp?links=wss/index.html).
|
4
|
+
|
5
|
+
This version uses the Non-SOAP Web Services so there is no need to download the Fedex WSDL files, note however that you will need to apply for
|
6
|
+
development/production credentials.
|
7
|
+
|
8
|
+
Note: This is work in progress make sure to test your results.
|
9
|
+
|
10
|
+
# Installation:
|
11
|
+
// Rails 3.x
|
12
|
+
$ gem 'fedex'
|
13
|
+
|
14
|
+
// Rails 2.x
|
15
|
+
$ gem install fedex
|
16
|
+
|
17
|
+
# Usage example:
|
18
|
+
|
19
|
+
Define the shipper:
|
20
|
+
|
21
|
+
shipper = { :name => "Sender",
|
22
|
+
:company => "Company",
|
23
|
+
:phone_number => "555-555-5555",
|
24
|
+
:address => "Main Street",
|
25
|
+
:city => "Harrison",
|
26
|
+
:state => "AR",
|
27
|
+
:postal_code => "72601",
|
28
|
+
:country_code => "US" }
|
29
|
+
|
30
|
+
Define the recipient:
|
31
|
+
|
32
|
+
recipient = { :name => "Recipient",
|
33
|
+
:company => "Company",
|
34
|
+
:phone_number => "555-555-5555",
|
35
|
+
:address => "Main Street",
|
36
|
+
:city => "City",
|
37
|
+
:state => "ST",
|
38
|
+
:postal_code => "55555",
|
39
|
+
:country_code => "US",
|
40
|
+
:residential => "false" }
|
41
|
+
Define the packages(multiple packages in a single shipment are allowed):
|
42
|
+
Note that all the Dimensions must be integers
|
43
|
+
|
44
|
+
packages = []
|
45
|
+
packages << { :weight => {:units => "LB", :value => 2},
|
46
|
+
:dimensions => {:length => 10, :width => 5, :height => 4, :units => "IN" } }
|
47
|
+
packages << { :weight => {:units => "LB", :value => 6},
|
48
|
+
:dimensions => {:length => 5, :width => 5, :height => 4, :units => "IN" } }
|
49
|
+
|
50
|
+
By Default packaging type is "YOUR PACKAGING" and the drop off type is "REGULAR PICKUP", if you need something different you can pass an extra hash for shipping details
|
51
|
+
|
52
|
+
shipping_details = { :packaging_type => "YOUR_PACKAGING", :drop_off_type => "REGULAR_PICKUP" }
|
53
|
+
|
54
|
+
|
55
|
+
Create a Fedex::Shipment object using your FedEx credentials; mode should be either production or development depending on what Fedex environment you want to use.
|
56
|
+
|
57
|
+
require 'fedex'
|
58
|
+
fedex = Fedex::Shipment.new(:key => 'xxx',
|
59
|
+
:password => 'xxxx',
|
60
|
+
:account_number => 'xxxx',
|
61
|
+
:meter => 'xxx',
|
62
|
+
:mode=>['production'|'development'])
|
63
|
+
|
64
|
+
rate = fedex.rate({:shipper=>shipper, :recipient => recipient, :packages => packages, :service_type => "FEDEX_GROUND", :shipping_details => shipping_details})
|
65
|
+
|
66
|
+
Fedex provides multiple total values; total_net_charge is the final amount you are looking for.
|
67
|
+
|
68
|
+
$ rate.total_net_charge => "34.03"
|
69
|
+
# Complete response
|
70
|
+
$ <Fedex::Rate:0x1019ba5f8
|
71
|
+
@total_net_charge="34.03",
|
72
|
+
@total_surcharges="1.93",
|
73
|
+
@total_billing_weight="8.0 LB",
|
74
|
+
@total_taxes="0.0",
|
75
|
+
@rate_type="PAYOR_ACCOUNT_PACKAGE",
|
76
|
+
@total_base_charge="32.1",
|
77
|
+
@total_freight_discounts=nil,
|
78
|
+
@total_net_freight="32.1",
|
79
|
+
@rate_zone="51">
|
80
|
+
|
81
|
+
|
82
|
+
# Services/Options Available
|
83
|
+
|
84
|
+
Fedex::Shipment::SERVICE_TYPES
|
85
|
+
Fedex::Shipment::PACKAGING_TYPES
|
86
|
+
Fedex::Shipment::DROP_OFF_TYPES
|
87
|
+
|
88
|
+
# Copyright/License:
|
89
|
+
Copyright 2011 Jazmin Schroeder
|
90
|
+
|
91
|
+
This gem is made available under the MIT license
|
92
|
+
|
data/fedex.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "fedex/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "fedex"
|
7
|
+
s.version = Fedex::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jazmin Schroeder"]
|
10
|
+
s.email = ["jazminschroeder@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/jazminschroeder/fedex"
|
12
|
+
s.summary = %q{Fedex Rate Webservice}
|
13
|
+
s.description = %q{Ruby Library to use Fedex Web Services(version 10)}
|
14
|
+
|
15
|
+
s.rubyforge_project = "fedex"
|
16
|
+
s.add_development_dependency "rspec"
|
17
|
+
s.add_dependency 'httparty'
|
18
|
+
s.add_dependency 'nokogiri'
|
19
|
+
# s.add_runtime_dependency "rest-client"
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
|
26
|
+
|
27
|
+
end
|
data/lib/fedex.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require "fedex/shipment"
|
2
|
+
require "fedex/rate"
|
3
|
+
# Get shipping rates trough Fedex Web Services
|
4
|
+
#
|
5
|
+
# In order to use the API you will need to apply for developer/production credentials,
|
6
|
+
# Visit {http://www.fedex.com/us/developer/ Fedex Developer Center} for more information about how to obtain your keys.
|
7
|
+
#
|
8
|
+
# ===Usage example
|
9
|
+
# #Use your own Fedex Keys
|
10
|
+
# fedex = Fedex::Shipment.new(:key => 'xxx',
|
11
|
+
# :password => 'xxxx',
|
12
|
+
# :account_number => 'xxxx',
|
13
|
+
# :meter => 'xxx',
|
14
|
+
# :mode=>['production'|'development'])
|
15
|
+
# shipper = {:name => "Sender",
|
16
|
+
# :company => "Company",
|
17
|
+
# :phone_number => "555-555-5555",
|
18
|
+
# :address => "Main Street",
|
19
|
+
# :city => "Harrison",
|
20
|
+
# :state => "AR",
|
21
|
+
# :postal_code => "72601",
|
22
|
+
# :country_code => "US" }
|
23
|
+
#
|
24
|
+
# recipient = { :name => "Recipient",
|
25
|
+
# :company => "Company",
|
26
|
+
# :phone_number => "555-555-5555",
|
27
|
+
# :address => "Main Street",
|
28
|
+
# :city => "City",
|
29
|
+
# :state => "ST",
|
30
|
+
# :postal_code => "55555",
|
31
|
+
# :country_code => "US",
|
32
|
+
# :residential => "false" }
|
33
|
+
# packages = []
|
34
|
+
# packages << { :weight => {:units => "LB", :value => 2},
|
35
|
+
# :dimensions => {:length => 10, :width => 5, :height => 4, :units => "IN" } }
|
36
|
+
# packages << { :weight => {:units => "LB", :value => 6},
|
37
|
+
# :dimensions => {:length => 5, :width => 5, :height => 4, :units => "IN" } }
|
38
|
+
# # "YOUR PACKAGING" and "REGULAR PICKUP" are the default options for all shipments but you can easily change them by passing an extra hash for # shipping_options
|
39
|
+
# shipping_options = { :packaging_type => "YOUR_PACKAGING", :drop_off_type => "REGULAR_PICKUP" }
|
40
|
+
# rate = fedex.rate({:shipper=>shipper, :recipient => recipient, :packages => packages, :service_type => "FEDEX_GROUND", :shipping_options => #shipping_options})
|
41
|
+
#
|
42
|
+
# $ <Fedex::Rate:0x1019ba5f8 @total_net_charge="34.03",
|
43
|
+
# @total_surcharges="1.93",
|
44
|
+
# @total_billing_weight="8.0 LB",
|
45
|
+
# @total_taxes="0.0",
|
46
|
+
# @rate_type="PAYOR_ACCOUNT_PACKAGE",
|
47
|
+
# @total_base_charge="32.1",
|
48
|
+
# @total_freight_discounts=nil,
|
49
|
+
# @total_net_freight="32.1",
|
50
|
+
# @rate_zone="51">
|
51
|
+
module Fedex
|
52
|
+
#Exceptions: Fedex::RateError
|
53
|
+
class RateError < StandardError; end
|
54
|
+
end
|
data/lib/fedex/rate.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Fedex
|
2
|
+
# Visit {http://www.fedex.com/us/developer/ Fedex Developer Center} for a complete list of values returned from the API
|
3
|
+
#
|
4
|
+
# Rate totals are contained in the node
|
5
|
+
# response[:rate_reply][:rate_reply_details][:rated_shipment_details]
|
6
|
+
class Rate
|
7
|
+
# Initialize Fedex::Rate Object
|
8
|
+
# @param [Hash] options
|
9
|
+
#
|
10
|
+
#
|
11
|
+
# return [Fedex::Rate Object]
|
12
|
+
# @rate_type #Type used for this specific set of rate data
|
13
|
+
# @rate_zone #Indicates the rate zone used(based on origin and destination)
|
14
|
+
# @total_billing_weight #The weight used to calculate these rates
|
15
|
+
# @total_freight_discounts #The toal discounts used in the rate calculation
|
16
|
+
# @total_net_charge #The net charge after applying all discounts and surcharges
|
17
|
+
# @total_taxes #Total of the transportation-based taxes
|
18
|
+
# @total_net_freight #The freight charge minus dicounts
|
19
|
+
# @total_surcharges #The total amount of all surcharges applied to this shipment
|
20
|
+
# @total_base_charge #The total base charge
|
21
|
+
attr_accessor :rate_type, :rate_zone, :total_bilint_weight, :total_freight_discounts, :total_net_charge, :total_taxes, :total_net_freight, :total_surcharges, :total_base_charge
|
22
|
+
def initialize(options = {})
|
23
|
+
@rate_type = options[:rate_type]
|
24
|
+
@rate_zone = options[:rate_zone]
|
25
|
+
@total_billing_weight = "#{options[:total_billing_weight][:value]} #{options[:total_billing_weight][:units]}"
|
26
|
+
@total_freight_discounts = options[:total_fright_discounts]
|
27
|
+
@total_net_charge = options[:total_net_charge][:amount]
|
28
|
+
@total_taxes = options[:total_taxes][:amount]
|
29
|
+
@total_net_freight = options[:total_net_freight][:amount]
|
30
|
+
@total_surcharges = options[:total_surcharges][:amount]
|
31
|
+
@total_base_charge = options[:total_base_charge][:amount]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'nokogiri'
|
3
|
+
module Fedex
|
4
|
+
#Fedex::Shipment
|
5
|
+
class Shipment
|
6
|
+
include HTTParty
|
7
|
+
format :xml
|
8
|
+
# If true the rate method will return the complete response from the Fedex Web Service
|
9
|
+
attr_accessor :raw_response
|
10
|
+
# Fedex Text URL
|
11
|
+
TEST_URL = "https://gatewaybeta.fedex.com:443/xml/"
|
12
|
+
|
13
|
+
# Fedex Production URL
|
14
|
+
PRODUCTION_URL = "https://gateway.fedex.com:443/xml/"
|
15
|
+
|
16
|
+
# Fedex Version number for the Fedex service used
|
17
|
+
VERSION = 10
|
18
|
+
|
19
|
+
# List of available Service Types
|
20
|
+
SERVICE_TYPES = %w(EUROPE_FIRST_INTERNATIONAL_PRIORITY FEDEX_1_DAY_FREIGHT FEDEX_2_DAY FEDEX_2_DAY_AM FEDEX_2_DAY_FREIGHT FEDEX_3_DAY_FREIGHT FEDEX_EXPRESS_SAVER FEDEX_FIRST_FREIGHT FEDEX_FREIGHT_ECONOMY FEDEX_FREIGHT_PRIORITY FEDEX_GROUND FIRST_OVERNIGHT GROUND_HOME_DELIVERY INTERNATIONAL_ECONOMY INTERNATIONAL_ECONOMY_FREIGHT INTERNATIONAL_FIRST INTERNATIONAL_PRIORITY INTERNATIONAL_PRIORITY_FREIGHT PRIORITY_OVERNIGHT SMART_POST STANDARD_OVERNIGHT)
|
21
|
+
|
22
|
+
# List of available Packaging Type
|
23
|
+
PACKAGING_TYPES = %w(FEDEX_10KG_BOX FEDEX_25KG_BOX FEDEX_BOX FEDEX_ENVELOPE FEDEX_PAK FEDEX_TUBE YOUR_PACKAGING)
|
24
|
+
|
25
|
+
# List of available DropOffTypes
|
26
|
+
DROP_OFF_TYPES = %w(BUSINESS_SERVICE_CENTER DROP_BOX REGULAR_PICKUP REQUEST_COURIER STATION)
|
27
|
+
|
28
|
+
# In order to use Fedex rates API you must first apply for a developer(and later production keys),
|
29
|
+
# Visit {http://www.fedex.com/us/developer/ Fedex Developer Center} for more information about how to obtain your keys.
|
30
|
+
# @param [String] key - Fedex web service key
|
31
|
+
# @param [String] password - Fedex password
|
32
|
+
# @param [String] account_number - Fedex account_number
|
33
|
+
# @param [String] meter - Fedex meter number
|
34
|
+
# @param [String] mode - [development/production]
|
35
|
+
#
|
36
|
+
# return a Fedex::Shipment object
|
37
|
+
def initialize(options={})
|
38
|
+
requires!(options, :key, :password, :account_number, :meter, :mode)
|
39
|
+
@key = options[:key]
|
40
|
+
@password = options[:password]
|
41
|
+
@account_number = options[:account_number]
|
42
|
+
@meter = options[:meter]
|
43
|
+
@mode = options[:mode]
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# @param [Hash] shipper, A hash containing the shipper information
|
48
|
+
# @param [Hash] recipient, A hash containing the recipient information
|
49
|
+
# @param [Array] packages, An arrary including a hash for each package being shipped
|
50
|
+
# @param [String] service_type, A valid fedex service type, to view a complete list of services Fedex::Shipment::SERVICE_TYPES
|
51
|
+
def rate(options = {})
|
52
|
+
requires!(options, :shipper, :recipient, :packages, :service_type)
|
53
|
+
@shipper, @recipient, @packages, @service_type = options[:shipper], options[:recipient], options[:packages], options[:service_type]
|
54
|
+
@shipping_options = options[:shipping_options] ||={}
|
55
|
+
process_request
|
56
|
+
end
|
57
|
+
|
58
|
+
# Sends post request to Fedex web service and parse the response, a Rate object is created if the response is successful
|
59
|
+
def process_request
|
60
|
+
api_response = Shipment.post(api_url, :body => build_xml)
|
61
|
+
return api_response if @raw_response == true
|
62
|
+
response = parse_response(api_response)
|
63
|
+
if success?(response)
|
64
|
+
rate_details = [response[:rate_reply][:rate_reply_details][:rated_shipment_details]].flatten.first[:shipment_rate_detail]
|
65
|
+
rate = Fedex::Rate.new(rate_details)
|
66
|
+
else
|
67
|
+
error_message = (response[:rate_reply].nil? ? api_response["Fault"]["detail"]["fault"]["details"]["ValidationFailureDetail"]["message"] : response[:rate_reply][:notifications][:message]) rescue "Unexpected error has occurred..."
|
68
|
+
raise RateError, error_message
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Build xml Fedex Web Service request
|
73
|
+
def build_xml
|
74
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
75
|
+
xml.RateRequest(:xmlns => "http://fedex.com/ws/rate/v10"){
|
76
|
+
add_web_authentication_detail(xml)
|
77
|
+
add_client_detail(xml)
|
78
|
+
add_version(xml)
|
79
|
+
add_requested_shipment(xml)
|
80
|
+
}
|
81
|
+
end
|
82
|
+
builder.doc.root.to_xml
|
83
|
+
end
|
84
|
+
|
85
|
+
# Fedex Web Service Api
|
86
|
+
def api_url
|
87
|
+
@mode == "production" ? PRODUCTION_URL : TEST_URL
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
# Helper method to validate required fields
|
92
|
+
def requires!(hash, *params)
|
93
|
+
params.each { |param| raise RateError, "Missing Required Parameter #{param}" if hash[param].nil? }
|
94
|
+
end
|
95
|
+
|
96
|
+
def camelize(str) #:nodoc:
|
97
|
+
str.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
98
|
+
end
|
99
|
+
|
100
|
+
# Add web authentication detail information(key and password) to xml request
|
101
|
+
def add_web_authentication_detail(xml)
|
102
|
+
xml.WebAuthenticationDetail{
|
103
|
+
xml.UserCredential{
|
104
|
+
xml.Key @key
|
105
|
+
xml.Password @password
|
106
|
+
}
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
# Add Client Detail information(account_number and meter_number) to xml request
|
111
|
+
def add_client_detail(xml)
|
112
|
+
xml.ClientDetail{
|
113
|
+
xml.AccountNumber @account_number
|
114
|
+
xml.MeterNumber @meter
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
# Add Version to xml request, using the latest version V10 Sept/2011
|
119
|
+
def add_version(xml)
|
120
|
+
xml.Version{
|
121
|
+
xml.ServiceId 'crs'
|
122
|
+
xml.Major VERSION
|
123
|
+
xml.Intermediate 0
|
124
|
+
xml.Minor 0
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
# Add information for shipments
|
129
|
+
def add_requested_shipment(xml)
|
130
|
+
xml.RequestedShipment{
|
131
|
+
xml.DropoffType @shipping_options[:drop_off_type] ||= "REGULAR_PICKUP"
|
132
|
+
xml.ServiceType @service_type
|
133
|
+
xml.PackagingType @shipping_options[:packaging_type] ||= "YOUR_PACKAGING"
|
134
|
+
add_shipper(xml)
|
135
|
+
add_recipient(xml)
|
136
|
+
add_shipping_charges_payment(xml)
|
137
|
+
add_commodities(xml) if @commoditites
|
138
|
+
xml.RateRequestTypes "ACCOUNT"
|
139
|
+
add_packages(xml)
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
# Add shipper to xml request
|
144
|
+
def add_shipper(xml)
|
145
|
+
xml.Shipper{
|
146
|
+
xml.Contact{
|
147
|
+
xml.PersonName @shipper[:name]
|
148
|
+
xml.CompanyName @shipper[:company]
|
149
|
+
xml.PhoneNumber @shipper[:phone_number]
|
150
|
+
}
|
151
|
+
xml.Address {
|
152
|
+
xml.StreetLines @shipper[:address]
|
153
|
+
xml.City @shipper[:city]
|
154
|
+
xml.StateOrProvinceCode @shipper[:state]
|
155
|
+
xml.PostalCode @shipper[:postal_code]
|
156
|
+
xml.CountryCode @shipper[:country_code]
|
157
|
+
}
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
# Add recipient to xml request
|
162
|
+
def add_recipient(xml)
|
163
|
+
xml.Recipient{
|
164
|
+
xml.Contact{
|
165
|
+
xml.PersonName @recipient[:name]
|
166
|
+
xml.CompanyName @recipient[:company]
|
167
|
+
xml.PhoneNumber @recipient[:phone_number]
|
168
|
+
}
|
169
|
+
xml.Address {
|
170
|
+
xml.StreetLines @recipient[:address]
|
171
|
+
xml.City @recipient[:city]
|
172
|
+
xml.StateOrProvinceCode @recipient[:state]
|
173
|
+
xml.PostalCode @recipient[:postal_code]
|
174
|
+
xml.CountryCode @recipient[:country_code]
|
175
|
+
xml.Residential @recipient[:residential]
|
176
|
+
}
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
# Add shipping charges to xml request
|
181
|
+
def add_shipping_charges_payment(xml)
|
182
|
+
xml.ShippingChargesPayment{
|
183
|
+
xml.PaymentType "SENDER"
|
184
|
+
xml.Payor{
|
185
|
+
xml.AccountNumber @account_number
|
186
|
+
xml.CountryCode @shipper[:country_code]
|
187
|
+
}
|
188
|
+
}
|
189
|
+
end
|
190
|
+
|
191
|
+
# Add packages to xml request
|
192
|
+
def add_packages(xml)
|
193
|
+
package_count = @packages.size
|
194
|
+
xml.PackageCount package_count
|
195
|
+
@packages.each do |package|
|
196
|
+
xml.RequestedPackageLineItems{
|
197
|
+
xml.GroupPackageCount 1
|
198
|
+
xml.Weight{
|
199
|
+
xml.Units package[:weight][:units]
|
200
|
+
xml.Value package[:weight][:value]
|
201
|
+
}
|
202
|
+
xml.Dimensions{
|
203
|
+
xml.Length package[:dimensions][:length]
|
204
|
+
xml.Width package[:dimensions][:width]
|
205
|
+
xml.Height package[:dimensions][:height]
|
206
|
+
xml.Units package[:dimensions][:units]
|
207
|
+
}
|
208
|
+
}
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Note: this method has not been implemented
|
213
|
+
def add_commodities(xml)
|
214
|
+
xml.CustomsClearanceDetail{
|
215
|
+
xml.Broker{
|
216
|
+
xml.AccountNumber @account_number
|
217
|
+
xml.Tins {
|
218
|
+
xml.TinType "BUSINESS_NATIONAL"
|
219
|
+
xml.Number "123456"
|
220
|
+
xml.Usage "Usage"
|
221
|
+
}
|
222
|
+
}
|
223
|
+
xml.DutiesPayment{
|
224
|
+
xml.PaymentType "SENDER"
|
225
|
+
xml.Payor{
|
226
|
+
xml.AccountNumber @account_number
|
227
|
+
xml.CountryCode @shipper[:country_code]
|
228
|
+
}
|
229
|
+
}
|
230
|
+
xml.Commodities{
|
231
|
+
xml.Name 2
|
232
|
+
xml.NumberOfPieces 2
|
233
|
+
xml.Description "Cotton Coat"
|
234
|
+
xml.CountryOfManufacture "US"
|
235
|
+
xml.HarmonizedCode "6103320000"
|
236
|
+
xml.Weight {
|
237
|
+
xml.Units "LB"
|
238
|
+
xml.Value 2
|
239
|
+
}
|
240
|
+
xml.Quantity 3
|
241
|
+
xml.UnitPrice {
|
242
|
+
xml.Currency "US"
|
243
|
+
xml.Amount "50"
|
244
|
+
}
|
245
|
+
xml.CustomsValue {
|
246
|
+
xml.Currency "US"
|
247
|
+
xml.Amount "50"
|
248
|
+
}
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
# Parse response, convert keys to underscore symbols
|
255
|
+
def parse_response(response)
|
256
|
+
response = sanitize_response_keys(response)
|
257
|
+
end
|
258
|
+
|
259
|
+
# Recursively sanitizes the response object by clenaing up any hash keys.
|
260
|
+
def sanitize_response_keys(response)
|
261
|
+
if response.is_a?(Hash)
|
262
|
+
response.inject({}) { |result, (key, value)| result[underscorize(key).to_sym] = sanitize_response_keys(value); result }
|
263
|
+
elsif response.is_a?(Array)
|
264
|
+
response.collect { |result| sanitize_response_keys(result) }
|
265
|
+
else
|
266
|
+
response
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def underscorize(key) #:nodoc:
|
271
|
+
key.to_s.sub(/^(v[0-9]+|ns):/, "").gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
|
272
|
+
end
|
273
|
+
|
274
|
+
# Successful request
|
275
|
+
def success?(response)
|
276
|
+
(!response[:rate_reply].nil? and %w{SUCCESS WARNING NOTE}.include? response[:rate_reply][:highest_severity])
|
277
|
+
end
|
278
|
+
|
279
|
+
end
|
280
|
+
end
|
data/spec/fedex_spec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Fedex::Shipment do
|
3
|
+
let(:test_keys) do
|
4
|
+
{:key => "RSkI5uThcfmtpm3I", :password => "RHhaZOG1MpDJ6QvSzxG0N06Ue", :account_number => "510087143", :meter => "118546765", :mode => "test"}
|
5
|
+
end
|
6
|
+
context "missing required parameters" do
|
7
|
+
it "should raise Fedex::Rate exception" do
|
8
|
+
lambda{ Fedex::Shipment.new}.should raise_error(Fedex::RateError)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "required parameters present" do
|
13
|
+
subject { Fedex::Shipment.new(test_keys) }
|
14
|
+
it "should create a valid instance" do
|
15
|
+
subject.should be_an_instance_of(Fedex::Shipment)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
before(:each) do
|
20
|
+
@fedex = Fedex::Shipment.new(test_keys)
|
21
|
+
@shipper = {:name => "Sender", :company => "Company", :phone_number => "555-555-5555", :address => "Main Street", :city => "Harrison", :state => "AR", :postal_code => "72601", :country_code => "US"}
|
22
|
+
@recipient = {:name => "Recipient", :company => "Company", :phone_number => "555-555-5555", :address => "Main Street", :city => "Franklin Park", :state => "IL", :postal_code => "60131", :country_code => "US", :residential => "false"}
|
23
|
+
@packages = []
|
24
|
+
@packages << { :weight => {:units => "LB", :value => 2},
|
25
|
+
:dimensions => {:length => 10, :width => 5, :height => 4, :units => "IN" } }
|
26
|
+
@packages << { :weight => {:units => "LB", :value => 6},
|
27
|
+
:dimensions => {:length => 5, :width => 5, :height => 4, :units => "IN" } }
|
28
|
+
@shipping_options = { :packaging_type => "YOUR_PACKAGING", :drop_off_type => "REGULAR_PICKUP" }
|
29
|
+
end
|
30
|
+
|
31
|
+
context "Domestic Shipment" do
|
32
|
+
describe "rate" do
|
33
|
+
it "should return rate" do
|
34
|
+
rate = @fedex.rate({:shipper=>@shipper, :recipient => @recipient, :packages => @packages, :service_type => "FEDEX_GROUND"})
|
35
|
+
rate.should be_an_instance_of(Fedex::Rate)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "Canadian Shipment" do
|
41
|
+
describe "rate" do
|
42
|
+
it "shoule return international fees" do
|
43
|
+
recipient = {:name => "Recipient", :company => "Company", :phone_number => "555-555-5555", :address=>"Address Line 1", :city => "Richmond", :state => "BC",
|
44
|
+
:postal_code => "V7C4V4", :country_code => "CA", :residential => false }
|
45
|
+
rate = @fedex.rate({:shipper => @shipper, :recipient => recipient, :packages => @packages, :service_type => "FEDEX_GROUND", :shipping_options => @shipping_options })
|
46
|
+
rate.should be_an_instance_of(Fedex::Rate)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'fedex'
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fedex
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jazmin Schroeder
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-09-29 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: httparty
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: nokogiri
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
63
|
+
description: Ruby Library to use Fedex Web Services(version 10)
|
64
|
+
email:
|
65
|
+
- jazminschroeder@gmail.com
|
66
|
+
executables: []
|
67
|
+
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
extra_rdoc_files: []
|
71
|
+
|
72
|
+
files:
|
73
|
+
- .gitignore
|
74
|
+
- .rspec
|
75
|
+
- Gemfile
|
76
|
+
- Rakefile
|
77
|
+
- Readme.md
|
78
|
+
- fedex.gemspec
|
79
|
+
- lib/fedex.rb
|
80
|
+
- lib/fedex/rate.rb
|
81
|
+
- lib/fedex/shipment.rb
|
82
|
+
- lib/fedex/version.rb
|
83
|
+
- spec/fedex_spec.rb
|
84
|
+
- spec/spec_helper.rb
|
85
|
+
has_rdoc: true
|
86
|
+
homepage: https://github.com/jazminschroeder/fedex
|
87
|
+
licenses: []
|
88
|
+
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
hash: 3
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
hash: 3
|
109
|
+
segments:
|
110
|
+
- 0
|
111
|
+
version: "0"
|
112
|
+
requirements: []
|
113
|
+
|
114
|
+
rubyforge_project: fedex
|
115
|
+
rubygems_version: 1.3.7
|
116
|
+
signing_key:
|
117
|
+
specification_version: 3
|
118
|
+
summary: Fedex Rate Webservice
|
119
|
+
test_files:
|
120
|
+
- spec/fedex_spec.rb
|
121
|
+
- spec/spec_helper.rb
|