fedex 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -7,3 +7,4 @@ doc/*
7
7
  .yardoc/*
8
8
  pkg/*
9
9
  .yardopts
10
+ fedex_credentials.yml
data/Rakefile CHANGED
@@ -1 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
5
+
6
+ # If you want to make this the default task
7
+ task :default => :spec
data/Readme.md CHANGED
@@ -59,7 +59,7 @@ Create a Fedex::Shipment object using your FedEx credentials; mode should be eit
59
59
  :password => 'xxxx',
60
60
  :account_number => 'xxxx',
61
61
  :meter => 'xxx',
62
- :mode=>['production'|'development'])
62
+ :mode=>'production')
63
63
 
64
64
  rate = fedex.rate({:shipper=>shipper, :recipient => recipient, :packages => packages, :service_type => "FEDEX_GROUND", :shipping_details => shipping_details})
65
65
 
data/lib/fedex/rate.rb CHANGED
@@ -23,12 +23,14 @@ module Fedex
23
23
  @rate_type = options[:rate_type]
24
24
  @rate_zone = options[:rate_zone]
25
25
  @total_billing_weight = "#{options[:total_billing_weight][:value]} #{options[:total_billing_weight][:units]}"
26
- @total_freight_discounts = options[:total_fright_discounts]
26
+ @total_freight_discounts = options[:total_freight_discounts]
27
27
  @total_net_charge = options[:total_net_charge][:amount]
28
28
  @total_taxes = options[:total_taxes][:amount]
29
29
  @total_net_freight = options[:total_net_freight][:amount]
30
30
  @total_surcharges = options[:total_surcharges][:amount]
31
31
  @total_base_charge = options[:total_base_charge][:amount]
32
+ @total_net_fedex_charge = (options[:total_net_fe_dex_charge]||={})[:amount]
33
+ @total_rebates = (options[:total_rebates]||={})[:amount]
32
34
  end
33
35
  end
34
36
  end
@@ -6,7 +6,7 @@ module Fedex
6
6
  include HTTParty
7
7
  format :xml
8
8
  # If true the rate method will return the complete response from the Fedex Web Service
9
- attr_accessor :raw_response
9
+ attr_accessor :debug
10
10
  # Fedex Text URL
11
11
  TEST_URL = "https://gatewaybeta.fedex.com:443/xml/"
12
12
 
@@ -25,6 +25,12 @@ module Fedex
25
25
  # List of available DropOffTypes
26
26
  DROP_OFF_TYPES = %w(BUSINESS_SERVICE_CENTER DROP_BOX REGULAR_PICKUP REQUEST_COURIER STATION)
27
27
 
28
+ # Clearance Brokerage Type
29
+ CLEARANCE_BROKERAGE_TYPE = %w(BROKER_INCLUSIVE BROKER_INCLUSIVE_NON_RESIDENT_IMPORTER BROKER_SELECT BROKER_SELECT_NON_RESIDENT_IMPORTER BROKER_UNASSIGNED)
30
+
31
+ # Recipient Custom ID Type
32
+ RECIPIENT_CUSTOM_ID_TYPE = %w(COMPANY INDIVIDUAL PASSPORT)
33
+
28
34
  # In order to use Fedex rates API you must first apply for a developer(and later production keys),
29
35
  # Visit {http://www.fedex.com/us/developer/ Fedex Developer Center} for more information about how to obtain your keys.
30
36
  # @param [String] key - Fedex web service key
@@ -50,7 +56,7 @@ module Fedex
50
56
  # @param [String] service_type, A valid fedex service type, to view a complete list of services Fedex::Shipment::SERVICE_TYPES
51
57
  def rate(options = {})
52
58
  requires!(options, :shipper, :recipient, :packages, :service_type)
53
- @shipper, @recipient, @packages, @service_type = options[:shipper], options[:recipient], options[:packages], options[:service_type]
59
+ @shipper, @recipient, @packages, @service_type, @customs_clearance, @debug = options[:shipper], options[:recipient], options[:packages], options[:service_type], options[:customs_clearance], options[:debug]
54
60
  @shipping_options = options[:shipping_options] ||={}
55
61
  process_request
56
62
  end
@@ -58,13 +64,13 @@ module Fedex
58
64
  # Sends post request to Fedex web service and parse the response, a Rate object is created if the response is successful
59
65
  def process_request
60
66
  api_response = Shipment.post(api_url, :body => build_xml)
61
- return api_response if @raw_response == true
67
+ puts api_response if @debug == true
62
68
  response = parse_response(api_response)
63
69
  if success?(response)
64
70
  rate_details = [response[:rate_reply][:rate_reply_details][:rated_shipment_details]].flatten.first[:shipment_rate_detail]
65
71
  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]].flatten.first[:message]) rescue "Unexpected error has occurred"
72
+ else
73
+ error_message = (response[:rate_reply].nil? ? api_response["Fault"]["detail"]["fault"]["reason"] : [response[:rate_reply][:notifications]].flatten.first[:message]) rescue $1
68
74
  raise RateError, error_message
69
75
  end
70
76
  end
@@ -134,7 +140,7 @@ module Fedex
134
140
  add_shipper(xml)
135
141
  add_recipient(xml)
136
142
  add_shipping_charges_payment(xml)
137
- add_commodities(xml) if @commoditites
143
+ add_customs_clearance(xml) if @customs_clearance
138
144
  xml.RateRequestTypes "ACCOUNT"
139
145
  add_packages(xml)
140
146
  }
@@ -209,48 +215,33 @@ module Fedex
209
215
  end
210
216
  end
211
217
 
212
- # Note: this method has not been implemented
213
- def add_commodities(xml)
218
+ # Add customs clearance(for international shipments)
219
+ def add_customs_clearance(xml)
214
220
  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
- }
221
+ customs_to_xml(xml, @customs_clearance)
250
222
  }
251
-
252
223
  end
253
224
 
225
+ # Build nodes dinamically from the provided customs clearance hash
226
+ def customs_to_xml(xml, hash)
227
+ hash.each do |key, value|
228
+ if value.is_a?(Hash)
229
+ xml.send "#{camelize(key.to_s)}" do |x|
230
+ customs_to_xml(x, value)
231
+ end
232
+ elsif value.is_a?(Array)
233
+ node = key
234
+ value.each do |v|
235
+ xml.send "#{camelize(node.to_s)}" do |x|
236
+ customs_to_xml(x, v)
237
+ end
238
+ end
239
+ else
240
+ xml.send "#{camelize(key.to_s)}", value unless key.is_a?(Hash)
241
+ end
242
+ end
243
+ end
244
+
254
245
  # Parse response, convert keys to underscore symbols
255
246
  def parse_response(response)
256
247
  response = sanitize_response_keys(response)
@@ -284,5 +275,11 @@ module Fedex
284
275
  @service_type
285
276
  end
286
277
  end
278
+
279
+ # String to CamelCase
280
+ def camelize(str)
281
+ str.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
282
+ end
283
+
287
284
  end
288
285
  end
data/lib/fedex/version.rb CHANGED
@@ -1,4 +1,3 @@
1
- #Sept-2011
2
1
  module Fedex
3
- VERSION = "0.1.0"
2
+ VERSION = "1.0.0"
4
3
  end
@@ -0,0 +1,13 @@
1
+ development:
2
+ :key: 'xxx'
3
+ :password: 'xxx'
4
+ :account_number: 'xxx'
5
+ :meter: 'xxx'
6
+ :mode: 'test'
7
+
8
+ production:
9
+ :key: 'xxx'
10
+ :password: 'xxx'
11
+ :account_number: 'xxx'
12
+ :meter: 'xxx'
13
+ :mode: 'production'
data/spec/fedex_spec.rb CHANGED
@@ -1,12 +1,6 @@
1
1
  require 'spec_helper'
2
2
  describe Fedex::Shipment do
3
- let(:test_keys) do
4
- {:key => "xxxx", :password => "xxxx", :account_number => "xxxx", :meter => "xxxx", :mode => "test"}
5
- end
6
-
7
- let(:production_keys) do
8
- {:key => "xxxx", :password => "xxxx", :account_number => "xxxx", :meter => "xxxx", :mode => "production"}
9
- end
3
+ fedex_credentials ||= YAML.load(File.read("#{File.dirname(__FILE__)}/config/fedex_credentials.yml"))["development"]
10
4
 
11
5
  context "missing required parameters" do
12
6
  it "should raise Fedex::Rate exception" do
@@ -15,15 +9,15 @@ describe Fedex::Shipment do
15
9
  end
16
10
 
17
11
  context "required parameters present" do
18
- subject { Fedex::Shipment.new(test_keys) }
12
+ subject { Fedex::Shipment.new(fedex_credentials) }
19
13
  it "should create a valid instance" do
20
14
  subject.should be_an_instance_of(Fedex::Shipment)
21
15
  end
22
16
  end
23
17
 
24
- context "Published Rates(Development Mode)" do
18
+ describe "rate service" do
25
19
  before(:each) do
26
- @fedex = Fedex::Shipment.new(test_keys)
20
+ @fedex = Fedex::Shipment.new(fedex_credentials)
27
21
  @shipper = {:name => "Sender", :company => "Company", :phone_number => "555-555-5555", :address => "Main Street", :city => "Harrison", :state => "AR", :postal_code => "72601", :country_code => "US"}
28
22
  @recipient = {:name => "Recipient", :company => "Company", :phone_number => "555-555-5555", :address => "Main Street", :city => "Frankin Park", :state => "IL", :postal_code => "60131", :country_code => "US", :residential => true }
29
23
  @packages = []
@@ -31,68 +25,112 @@ describe Fedex::Shipment do
31
25
  :dimensions => {:length => 10, :width => 5, :height => 4, :units => "IN" } }
32
26
  @packages << { :weight => {:units => "LB", :value => 6},
33
27
  :dimensions => {:length => 5, :width => 5, :height => 4, :units => "IN" } }
34
- @shipping_options = { :packaging_type => "YOUR_PACKAGING", :drop_off_type => "REGULAR_PICKUP" }
28
+ @shipping_options = { :packaging_type => "YOUR_PACKAGING", :drop_off_type => "REGULAR_PICKUP" }
29
+
35
30
  end
36
-
37
- context "Domestic Shipment" do
38
- describe "rate" do
39
- it "should return rate" do
40
- rate = @fedex.rate({:shipper=>@shipper, :recipient => @recipient, :packages => @packages, :service_type => "FEDEX_GROUND"})
41
- rate.should be_an_instance_of(Fedex::Rate)
42
- puts rate.total_net_charge
43
-
44
- end
31
+
32
+ context "domestic shipment" do
33
+ it "should return a 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)
45
36
  end
46
37
  end
47
-
48
- context "Canadian Shipment" do
49
- describe "rate" do
50
- it "shoule return international fees" do
51
- recipient = {:name => "Recipient", :company => "Company", :phone_number => "555-555-5555", :address=>"Address Line 1", :city => "Richmond", :state => "BC",
52
- :postal_code => "V7C4V4", :country_code => "CA", :residential => "true" }
53
- rate = @fedex.rate({:shipper => @shipper, :recipient => recipient, :packages => @packages, :service_type => "FEDEX_GROUND", :shipping_options => @shipping_options })
54
- rate.should be_an_instance_of(Fedex::Rate)
55
- puts rate.total_net_charge
56
- end
38
+
39
+ context "canadian shipment" do
40
+ it "should return a rate" do
41
+ canadian_recipient = {:name => "Recipient", :company => "Company", :phone_number => "555-555-5555", :address=>"Address Line 1", :city => "Richmond", :state => "BC", :postal_code => "V7C4V4", :country_code => "CA", :residential => "true" }
42
+ rate = @fedex.rate({:shipper => @shipper, :recipient => canadian_recipient, :packages => @packages, :service_type => "FEDEX_GROUND"})
43
+ rate.should be_an_instance_of(Fedex::Rate)
57
44
  end
58
- end
59
- end
60
-
61
- context "Discounted Rates(Production Mode)" do
62
- before(:each) do
63
- @fedex = Fedex::Shipment.new(production_keys)
64
- @shipper = {:name => "Sender", :company => "Company", :phone_number => "555-555-5555", :address => "Main Street", :city => "Harrison", :state => "AR", :postal_code => "72601", :country_code => "US"}
65
- @recipient = {:name => "Recipient", :company => "Company", :phone_number => "555-555-5555", :address => "Main Street", :city => "Frankin Park", :state => "IL", :postal_code => "60131", :country_code => "US", :residential => true }
66
- @packages = []
67
- @packages << { :weight => {:units => "LB", :value => 2},
68
- :dimensions => {:length => 10, :width => 5, :height => 4, :units => "IN" } }
69
- @packages << { :weight => {:units => "LB", :value => 6},
70
- :dimensions => {:length => 5, :width => 5, :height => 4, :units => "IN" } }
71
- @shipping_options = { :packaging_type => "YOUR_PACKAGING", :drop_off_type => "REGULAR_PICKUP" }
72
45
  end
73
-
74
- context "Domestic Shipment" do
75
- describe "rate" do
76
- it "should return rate" do
77
- rate = @fedex.rate({:shipper=>@shipper, :recipient => @recipient, :packages => @packages, :service_type => "FEDEX_GROUND"})
78
- rate.should be_an_instance_of(Fedex::Rate)
79
- puts rate.total_net_charge
80
-
81
- end
46
+
47
+ context "canadian shipment including customs" do
48
+ it "should return a rate including international fees" do
49
+ canadian_recipient = {:name => "Recipient", :company => "Company", :phone_number => "555-555-5555", :address=>"Address Line 1", :city => "Richmond", :state => "BC", :postal_code => "V7C4V4", :country_code => "CA", :residential => "true" }
50
+ broker = {
51
+ :account_number => "510087143",
52
+ :tins => { :tin_type => "BUSINESS_NATIONAL",
53
+ :number => "431870271",
54
+ :usage => "Usage" },
55
+ :contact => { :contact_id => "1",
56
+ :person_name => "Broker Name",
57
+ :title => "Broker",
58
+ :company_name => "Broker One",
59
+ :phone_number => "555-555-5555",
60
+ :phone_extension => "555-555-5555",
61
+ :pager_number => "555",
62
+ :fax_number=> "555-555-5555",
63
+ :e_mail_address => "contact@me.com" },
64
+ :address => { :street_lines => "Main Street",
65
+ :city => "Franklin Park",
66
+ :state_or_province_code => 'IL',
67
+ :postal_code => '60131',
68
+ :urbanization_code => '123',
69
+ :country_code => 'US',
70
+ :residential => 'false' }
71
+ }
72
+
73
+ clearance_brokerage = "BROKER_INCLUSIVE"
74
+
75
+ importer_of_record= {
76
+ :account_number => "22222",
77
+ :tins => { :tin_type => "BUSINESS_NATIONAL",
78
+ :number => "22222",
79
+ :usage => "Usage" },
80
+ :contact => { :contact_id => "1",
81
+ :person_name => "Importer Name",
82
+ :title => "Importer",
83
+ :company_name => "Importer One",
84
+ :phone_number => "555-555-5555",
85
+ :phone_extension => "555-555-5555",
86
+ :pager_number => "555",
87
+ :fax_number=> "555-555-5555",
88
+ :e_mail_address => "contact@me.com" },
89
+ :address => { :street_lines => "Main Street",
90
+ :city => "Chicago",
91
+ :state_or_province_code => 'IL',
92
+ :postal_code => '60611',
93
+ :urbanization_code => '2308',
94
+ :country_code => 'US',
95
+ :residential => 'false' }
96
+ }
97
+
98
+ recipient_customs_id = { :type => 'COMPANY',
99
+ :value => '1254587' }
100
+
101
+
102
+ duties_payment = { :payment_type => "SENDER",
103
+ :payor => { :account_number => "510087143",
104
+ :country_code => "US" } }
105
+
106
+ customs_value = { :currency => "USD",
107
+ :amount => "200" }
108
+ commodities = []
109
+ commodities << { :name => "Cotton Coat",
110
+ :number_of_pieces => "2",
111
+ :description => "Cotton Coat",
112
+ :country_of_manufacture => "US",
113
+ :harmonized_code => "6103320000",
114
+ :weight => {:units => "LB", :value => "2"},
115
+ :quantity => "3",
116
+ :unit_price => {:currency => "USD", :amount => "50" },
117
+ :customs_value => {:currency => "USD", :amount => "150" } }
118
+
119
+ commodities << { :name => "Poster",
120
+ :number_of_pieces => "1",
121
+ :description => "Paper Poster",
122
+ :country_of_manufacture => "US",
123
+ :harmonized_code => "4817100000",
124
+ :weight => {:units => "LB", :value => "0.2"},
125
+ :quantity => "3",
126
+ :unit_price => {:currency => "USD", :amount => "50" },
127
+ :customs_value => {:currency => "USD", :amount => "150" } }
128
+
129
+ customs_clearance = { :broker => broker, :clearance_brokerage => clearance_brokerage, :importer_of_record => importer_of_record, :recipient_customs_id => recipient_customs_id, :duties_payment => duties_payment, :commodities => commodities }
130
+ rate = @fedex.rate({:shipper => @shipper, :recipient => canadian_recipient, :packages => @packages, :service_type => "FEDEX_GROUND", :customs_clearance => customs_clearance})
131
+ rate.should be_an_instance_of(Fedex::Rate)
82
132
  end
83
133
  end
84
-
85
- context "Canadian Shipment" do
86
- describe "rate" do
87
- it "shoule return international fees" do
88
- recipient = {:name => "Recipient", :company => "Company", :phone_number => "555-555-5555", :address=>"Address Line 1", :city => "Richmond", :state => "BC",
89
- :postal_code => "V7C4V4", :country_code => "CA", :residential => "true" }
90
- rate = @fedex.rate({:shipper => @shipper, :recipient => recipient, :packages => @packages, :service_type => "FEDEX_GROUND", :shipping_options => @shipping_options })
91
- rate.should be_an_instance_of(Fedex::Rate)
92
- puts rate.total_net_charge
93
- end
94
- end
95
- end
96
134
  end
97
-
98
- end
135
+ end
136
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fedex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-03 00:00:00.000000000Z
12
+ date: 2012-03-18 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70151002532920 !ruby/object:Gem::Requirement
16
+ requirement: &70272415391000 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 2.6.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70151002532920
24
+ version_requirements: *70272415391000
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: httparty
27
- requirement: &70151002532420 !ruby/object:Gem::Requirement
27
+ requirement: &70272415390500 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.8.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70151002532420
35
+ version_requirements: *70272415390500
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: nokogiri
38
- requirement: &70151002531960 !ruby/object:Gem::Requirement
38
+ requirement: &70272415390040 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 1.5.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70151002531960
46
+ version_requirements: *70272415390040
47
47
  description: Ruby Library to use Fedex Web Services(version 10)
48
48
  email:
49
49
  - jazminschroeder@gmail.com
@@ -61,6 +61,7 @@ files:
61
61
  - lib/fedex/rate.rb
62
62
  - lib/fedex/shipment.rb
63
63
  - lib/fedex/version.rb
64
+ - spec/config/fedex_credentials.example.yml
64
65
  - spec/fedex_spec.rb
65
66
  - spec/spec_helper.rb
66
67
  homepage: https://github.com/jazminschroeder/fedex
@@ -88,5 +89,6 @@ signing_key:
88
89
  specification_version: 3
89
90
  summary: Fedex Rate Webservice
90
91
  test_files:
92
+ - spec/config/fedex_credentials.example.yml
91
93
  - spec/fedex_spec.rb
92
94
  - spec/spec_helper.rb