fedex 0.1.0 → 1.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.
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