fedex_web_service 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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 bryce mcdonnell
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,31 @@
1
+ = Fedex Web Service
2
+
3
+ This is a ruby interface to the Fedex Web Services API. It's nowhere near complete and could use a lot of DRY'ing up, but I had an immediate need in a project I'm working on and thus began the gem.
4
+
5
+ Right now it only supports the address verification and shipping label APIs. Later, it will support the track and rate (among others) APIs.
6
+
7
+ == Dependencies
8
+ Dependencies for this gem are a WSDL issued by fedex. You'll also need to apply for and be blessed with a Fedex key, password, account number and meter number. While in development, you can get away with testing credentials but you'll need production credentials to go live.
9
+
10
+ Put wsdls in the lib/wsdl directory. That's where this looks for them.
11
+
12
+ Put your credentials in the config/fedex_config.yml file.
13
+
14
+ *Give yourself a month to get the production keys.* It won't take that long, but it's an arduous process requiring input from several levels of Fedex and your (clients) company.
15
+
16
+ == TODO
17
+ *lots of coding
18
+ *everything else
19
+ == Note on Patches/Pull Requests
20
+
21
+ * Fork the project.
22
+ * Make your feature addition or bug fix.
23
+ * Add tests for it. This is important so I don't break it in a
24
+ future version unintentionally.
25
+ * Commit, do not mess with rakefile, version, or history.
26
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
27
+ * Send me a pull request. Bonus points for topic branches.
28
+
29
+ == Copyright
30
+
31
+ Copyright (c) 2010-present bryce mcdonnell. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "fedex_web_service"
8
+ gem.summary = %Q{A quick and easy interface to the Fedex Web Services API}
9
+ gem.description = %Q{Provides an interface to several, but not all, of the FedEx web services. Currently provides Ship service and Address Verification. Utilizes the SOAP (blech) service so you must get a wsdl and production keys from FedEx}
10
+ gem.email = "bryce@bridgetownint.com"
11
+ gem.homepage = "http://github.com/brycem/fedex_web_service"
12
+ gem.authors = ["bryce mcdonnell"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "fedex_web_service #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,55 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{fedex_web_service}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["bryce mcdonnell"]
12
+ s.date = %q{2010-04-13}
13
+ s.description = %q{Provides an interface to several, but not all, of the FedEx web services. Currently provides Ship service and Address Verification. Utilizes the SOAP (blech) service so you must get a wsdl and production keys from FedEx}
14
+ s.email = %q{bryce@bridgetownint.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "fedex_web_service.gemspec",
27
+ "lib/fedex_web_service.rb",
28
+ "lib/fedex_web_service/address_verification.rb",
29
+ "test/helper.rb",
30
+ "test/test_fedex_web_service.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/brycem/fedex_web_service}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.5}
36
+ s.summary = %q{A quick and easy interface to the Fedex Web Services API}
37
+ s.test_files = [
38
+ "test/helper.rb",
39
+ "test/test_fedex_web_service.rb"
40
+ ]
41
+
42
+ if s.respond_to? :specification_version then
43
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
47
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
50
+ end
51
+ else
52
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
53
+ end
54
+ end
55
+
@@ -0,0 +1,101 @@
1
+ class FedexWebService
2
+ class AddressVerification < FedexWebService
3
+ #receives an order_info object and parses it into a verification request. Returns an AddressVerificationResponse (object)
4
+ def verify_address(order)
5
+ puts wsdl = wsdl = File.expand_path( RAILS_ROOT + "/lib/wsdl/" + @fedex_conf[:av_wsdl] )
6
+ driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
7
+
8
+ call = { :WebAuthenticationDetail => {
9
+ :UserCredential => {
10
+ :Key => @key,
11
+ :Password => @password
12
+ }
13
+ },
14
+ :ClientDetail => {
15
+ :AccountNumber => @accountnumber,
16
+ :MeterNumber => @meternumber
17
+ },
18
+ :TransactionDetail => {
19
+ :CustomerTransactionId => "WSVC_addressvalidation"
20
+ },
21
+ :Version => {:ServiceId => 'aval', :Major => '2', :Intermediate => '0', :Minor => '0'},
22
+ :RequestTimestamp => self.fedex_time_stamp(),
23
+ :Options => {
24
+ :VerifyAddresses => 1,
25
+ :CheckResidentialStatus => 1
26
+ },
27
+ :AddressesToValidate =>
28
+ [:Address => {
29
+ :CountryCode => 'US',
30
+ :StreetLines => order.shipping_address_1,
31
+ :City => order.shipping_city,
32
+ :StateOrProvinceCode => order.shipping_state,
33
+ :PostalCode => order.shipping_zip,
34
+ :Residential => true
35
+ }]
36
+
37
+ }
38
+
39
+ result = driver.addressValidation(call)
40
+ AddressVerificationResponse.new(result)
41
+ end
42
+ end #end Class AddressVerification
43
+
44
+ class AddressVerificationResponse
45
+ # this is really just a data translation object. It receives a SOAP response (blech) and translates it into a Ruby
46
+ # object. Where it's not blindingly obvious, I've included notes for each attribute
47
+
48
+ attr_accessor :responseString,
49
+ :deliveryPointValidation, #is either CONFIRMED, UNCONFIRMED, UNAVAILABLE
50
+ :changes,
51
+ :score, #the score Fedex gives it based on how confident they are 0..100
52
+ :residentialStatus, #one of UNDETERMINED, BUSINESS, RESIDENTIAL, INSUFFICIENT_DATA, UNAVAILABLE, NOT_APPLICABLE_TO_COUNTRY
53
+ :changedAddress, #address streetlines, modified by Fedex
54
+ :changedCity,
55
+ :changedState,
56
+ :changedPostal,
57
+ :responses
58
+
59
+ def initialize(soap_response)
60
+ @soap_response = soap_response #so we can use it with other methods in this class
61
+
62
+ address_results = address_results_an_array? ? @soap_response.addressResults.proposedAddressDetails[0] : @soap_response.addressResults.proposedAddressDetails
63
+
64
+ self.responseString = soap_response.notifications.severity
65
+ self.changes = address_results.changes
66
+ self.deliveryPointValidation = address_results.deliveryPointValidation
67
+ self.score = address_results.score.to_i
68
+ self.residentialStatus = address_results.residentialStatus
69
+ self.changedAddress = address_results.address.streetLines.to_s
70
+ self.changedCity = address_results.address.city
71
+ self.changedState = address_results.address.stateOrProvinceCode
72
+ self.changedPostal = address_results.address.postalCode
73
+ self.responses = []
74
+
75
+ set_other_responses if address_results_an_array?
76
+
77
+ end
78
+
79
+ protected
80
+
81
+ def set_other_responses
82
+
83
+ @soap_response.addressResults.proposedAddressDetails.each do |address_results|
84
+ response = {}
85
+ response[:changes] = address_results.changes
86
+ response[:deliveryPointValidation] = address_results.deliveryPointValidation
87
+ response[:score] = address_results.score.to_i
88
+ response[:residentialStatus] = address_results.residentialStatus
89
+ response[:changedAddress] = address_results.address.streetLines.to_s
90
+ response[:changedCity] = address_results.address.city
91
+ response[:changedState] = address_results.address.stateOrProvinceCode
92
+ response[:changedPostal] = address_results.address.postalCode
93
+ self.responses << response
94
+ end
95
+ end
96
+
97
+ def address_results_an_array?
98
+ @soap_response.addressResults.proposedAddressDetails.is_a?(Array)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,147 @@
1
+ require "soap/wsdlDriver" #FIXME MAKE SURE TO REMOVE NEW VERSIONS OF SOAP4R 1.5.5 is the last version that is supported here
2
+ require 'xmlrpc/client'
3
+ require 'net/ftp'
4
+
5
+ require "fedex_web_service/address_verification"
6
+
7
+ class FedexWebService
8
+ attr_accessor :tracking_number, :label, :full_response, :temp_image
9
+
10
+ # There are three types of options designed to save keystokes. Gem default options are the options I use for this particular project
11
+ # I'm working on. These are easily overridden by providing options of the same name in the config/fedex_config.yml file. This will set
12
+ # the options per project. If you want to change the options PER LABEL, then just pass them in when you call the method
13
+ #
14
+ # EX: if you want to default residential to false for this project, then the yml file would look like:
15
+ # common: &testing
16
+ # key: lotsoflettersandnumbers
17
+ # ....
18
+ # defaults:
19
+ # residential: false
20
+
21
+
22
+ @@gem_default_options ={
23
+ :drop_off_type => "REGULAR_PICKUP",
24
+ :residential => true,
25
+ :label => 'GROUND_HOME_DELIVERY',
26
+ :drop_off_type => 'REGULAR_PICKUP',
27
+ :packaging_type => 'YOUR_PACKAGING',
28
+ :label_format_type => 'COMMON2D',
29
+ :label_stock_type => 'PAPER_4X6',
30
+ :image_type => "PNG",
31
+ :dimensions => {:length => 5, :width => 5, :height => 5}
32
+ }
33
+ def initialize
34
+ raw_config = File.read(RAILS_ROOT + "/config/fedex_config.yml")
35
+ @fedex_conf = YAML.load(raw_config)[RAILS_ENV].symbolize_keys
36
+
37
+ @key = @fedex_conf[:key]
38
+ @password = @fedex_conf[:password]
39
+ @accountnumber = @fedex_conf[:accountnumber]
40
+ @meternumber = @fedex_conf[:meternumber]
41
+ @ss_wsdl = @fedex_conf[:ss_wsdl]
42
+ @default_options= @@gem_default_options.merge( @fedex_conf[:defaults] )
43
+ end
44
+
45
+ def future_shipment(address_info, options = {})
46
+ # this method sends a request to Fedex to get the future shipment date, a tracking number and the image file of a label
47
+ # the method returns the tracking number as a result to show that the request was done correctly, those class attributes
48
+ # are set to include the tracking number, the label (img) and the full response (SOAP object ... yech)
49
+
50
+ options = @default_options.merge( options ).symbolize_keys!
51
+
52
+ wsdl = File.expand_path( RAILS_ROOT + '/lib/wsdl/' + @fedex_conf[:ss_wsdl] )
53
+ driver = build_wsdl_driver(wsdl)
54
+
55
+
56
+ call = {:WebAuthenticationDetail => {:UserCredential => {:Key => @key, :Password => @password} },
57
+ :ClientDetail => {:AccountNumber => @accountnumber, :MeterNumber => @meternumber },
58
+ :TransactionDetail=> {:CustomerTransactionId => '*** Ground Domestic Shipping Request v7' },
59
+ :Version => {:ServiceId => 'ship', :Major => '7', :Intermediate => '0', :Minor => '0'},
60
+ :RequestedShipment => {
61
+ :ShipTimestamp => "#{3.days.from_now.strftime("%Y-%m-%d")}T9:00:00-07:00",
62
+ :DropoffType => options[:drop_off_type],
63
+ :ServiceType => options[:label], # 'FEDEX_2_DAY' 'FEDEX_GROUND' 'GROUND_HOME_DELIVERY'
64
+ :PackagingType => options[:packaging_type], # valid values FEDEX_BOX, FEDEX_PAK, FEDEX_TUBE, YOUR_PACKAGING, ...
65
+ :SpecialServicesRequested => {:SpecialServiceType => "FUTURE_DATE_SHIPMENT"},
66
+ :Recipient => { #should have same address as Origin per docs
67
+ :Contact => {
68
+ :PersonName => address_info.first_name + " " + address_info.last_name,
69
+ :PhoneNumber => address_info.phone #params[:phone]
70
+
71
+ },
72
+ :Address => {
73
+ :CountryCode => 'US',
74
+ :StreetLines => address_info.shipping_address_1, #params[:shipAddress],
75
+ :City => address_info.shipping_city, #params[:shipCity],
76
+ :StateOrProvinceCode => address_info.shipping_state, #params[:shipState],
77
+ :PostalCode => address_info.shipping_zip, #params[:shipZip]
78
+ :Residential => options[:residential]
79
+ }
80
+ },
81
+ :Shipper => {
82
+ :Contact => {
83
+ :PersonName => options[:person_name],
84
+ :PhoneNumber => options[:phone_number]
85
+ },
86
+ :Address => {
87
+ :CountryCode => 'US',
88
+ :StreetLines => options[:address],
89
+ :City => options[:city],
90
+ :StateOrProvinceCode => options[:state],
91
+ :PostalCode => options[:postal_code]
92
+ #:Residential => TRUE
93
+ }
94
+ },
95
+ :ShippingChargesPayment => {
96
+ :PaymentType => 'SENDER',
97
+ :Payor => {
98
+ :AccountNumber => @accountnumber,
99
+ :CountryCode => 'US'
100
+ }
101
+ },
102
+ :LabelSpecification => {
103
+ :LabelFormatType => options[:label_format_type],
104
+ :LabelStockType => options[:label_stock_type],
105
+ :ImageType => options[:image_type], #// valid values DPL, EPL2, PDF, ZPLII and PNG
106
+ :CustomerSpecifiedDetail => {:MaskedData => "SHIPPER_ACCOUNT_NUMBER"}
107
+ },
108
+ :RateRequestTypes => 'ACCOUNT', #, // valid values ACCOUNT and LIST
109
+ :PackageCount => 1,
110
+ :PackageDetail => "INDIVIDUAL_PACKAGES",
111
+ :RequestedPackageLineItems => [{
112
+ :SequenceNumber=>1,
113
+ :Weight => { :Units => "LB", :Value => 1 },
114
+ :Dimensions => {
115
+ :Length => options[:dimensions][:length],
116
+ :Width => options[:dimensions][:width],
117
+ :Height => options[:dimensions][:height],
118
+ :Units => "IN"
119
+ },
120
+ :CustomerReferences => [{:CustomerReferenceType => "INVOICE_NUMBER", :Value => "#{options[:invoice_number]}"} ], #in a string so if it's empty it's just an empty string
121
+ }]
122
+ }
123
+ }
124
+ result = driver.processShipment(call)
125
+ begin
126
+ self.label = Base64.decode64(result.completedShipmentDetail.completedPackageDetails.label.parts.image)
127
+ self.full_response = result
128
+ self.tracking_number = result.completedShipmentDetail.completedPackageDetails.trackingIds.trackingNumber
129
+ rescue Exception => e
130
+ #the FEDEX call returned an error
131
+ self.label = "error"
132
+ self.full_response = result
133
+ self.tracking_number = "error"
134
+ end
135
+ end
136
+
137
+ protected
138
+
139
+ def build_wsdl_driver(wsdl)
140
+ driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
141
+ end
142
+
143
+ def fedex_time_stamp
144
+ "#{Time.now.year}-#{Time.now.month}-#{Time.now.day}T#{Time.now.hour}:#{Time.now.min}:#{Time.now.sec}-08:00"
145
+ end
146
+ end
147
+
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'fedex_web_service'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestFedexWebService < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fedex_web_service
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - bryce mcdonnell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-04-13 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: thoughtbot-shoulda
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Provides an interface to several, but not all, of the FedEx web services. Currently provides Ship service and Address Verification. Utilizes the SOAP (blech) service so you must get a wsdl and production keys from FedEx
26
+ email: bryce@bridgetownint.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - .document
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.rdoc
39
+ - Rakefile
40
+ - VERSION
41
+ - fedex_web_service.gemspec
42
+ - lib/fedex_web_service.rb
43
+ - lib/fedex_web_service/address_verification.rb
44
+ - test/helper.rb
45
+ - test/test_fedex_web_service.rb
46
+ has_rdoc: true
47
+ homepage: http://github.com/brycem/fedex_web_service
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --charset=UTF-8
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.5
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: A quick and easy interface to the Fedex Web Services API
74
+ test_files:
75
+ - test/helper.rb
76
+ - test/test_fedex_web_service.rb