fedex_ship 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/fedex_ship-0.1.0.iml +22 -0
- data/.idea/misc.xml +7 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/workspace.xml +56 -0
- data/.rspec +2 -0
- data/Gemfile +5 -0
- data/Rakefile +7 -0
- data/Readme.md +496 -0
- data/fedex_ship.gemspec +28 -0
- data/lib/fedex_ship.rb +55 -0
- data/lib/fedex_ship/address.rb +31 -0
- data/lib/fedex_ship/credentials.rb +26 -0
- data/lib/fedex_ship/document.rb +51 -0
- data/lib/fedex_ship/ground_manifest.rb +25 -0
- data/lib/fedex_ship/helpers.rb +20 -0
- data/lib/fedex_ship/label.rb +71 -0
- data/lib/fedex_ship/rate.rb +38 -0
- data/lib/fedex_ship/request/address.rb +97 -0
- data/lib/fedex_ship/request/base.rb +443 -0
- data/lib/fedex_ship/request/delete.rb +76 -0
- data/lib/fedex_ship/request/document.rb +45 -0
- data/lib/fedex_ship/request/ground_close.rb +73 -0
- data/lib/fedex_ship/request/label.rb +29 -0
- data/lib/fedex_ship/request/logs_fedex.rb +74 -0
- data/lib/fedex_ship/request/pickup.rb +135 -0
- data/lib/fedex_ship/request/pickup_availability.rb +102 -0
- data/lib/fedex_ship/request/rate.rb +94 -0
- data/lib/fedex_ship/request/service_availability.rb +86 -0
- data/lib/fedex_ship/request/shipment.rb +249 -0
- data/lib/fedex_ship/request/tracking_information.rb +119 -0
- data/lib/fedex_ship/shipment.rb +115 -0
- data/lib/fedex_ship/tracking_information.rb +54 -0
- data/lib/fedex_ship/tracking_information/event.rb +24 -0
- data/lib/fedex_ship/version.rb +6 -0
- data/spec/config/fedex_credentials.example.yml +13 -0
- data/spec/lib/fedex_ship/address_spec.rb +59 -0
- data/spec/lib/fedex_ship/delete_spec.rb +26 -0
- data/spec/lib/fedex_ship/document_spec.rb +177 -0
- data/spec/lib/fedex_ship/ground_close_spec.rb +42 -0
- data/spec/lib/fedex_ship/label_spec.rb +73 -0
- data/spec/lib/fedex_ship/pickup_availability_spec.rb +19 -0
- data/spec/lib/fedex_ship/pickup_spec.rb +32 -0
- data/spec/lib/fedex_ship/rate_spec.rb +216 -0
- data/spec/lib/fedex_ship/service_availability_spec.rb +20 -0
- data/spec/lib/fedex_ship/shipment_spec.rb +86 -0
- data/spec/lib/fedex_ship/track_spec.rb +67 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/credentials.rb +15 -0
- data/spec/support/vcr.rb +14 -0
- metadata +193 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'fedex_ship/request/shipment'
|
2
|
+
require 'fedex_ship/document'
|
3
|
+
|
4
|
+
module FedexShip
|
5
|
+
module Request
|
6
|
+
class Document < Shipment
|
7
|
+
|
8
|
+
def initialize(credentials, options={})
|
9
|
+
super(credentials, options)
|
10
|
+
|
11
|
+
@shipping_document = options[:shipping_document]
|
12
|
+
@filenames = options.fetch(:filenames) { {} }
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_custom_components(xml)
|
16
|
+
super
|
17
|
+
|
18
|
+
add_shipping_document(xml) if @shipping_document
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# Add shipping document specification
|
24
|
+
def add_shipping_document(xml)
|
25
|
+
xml.ShippingDocumentSpecification{
|
26
|
+
Array(@shipping_document[:shipping_document_types]).each do |type|
|
27
|
+
xml.ShippingDocumentTypes type
|
28
|
+
end
|
29
|
+
hash_to_xml(xml, @shipping_document.reject{ |k| k == :shipping_document_types})
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def success_response(api_response, response)
|
34
|
+
super
|
35
|
+
|
36
|
+
shipment_documents = response.merge!({
|
37
|
+
:filenames => @filenames
|
38
|
+
})
|
39
|
+
|
40
|
+
FedexShip::Document.new shipment_documents
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'fedex_ship/request/base'
|
2
|
+
require 'fedex_ship/ground_manifest'
|
3
|
+
|
4
|
+
module FedexShip
|
5
|
+
module Request
|
6
|
+
class GroundClose < Base
|
7
|
+
|
8
|
+
attr_reader :up_to_time, :filename
|
9
|
+
|
10
|
+
def initialize(credentials, options={})
|
11
|
+
requires!(options, :up_to_time)
|
12
|
+
|
13
|
+
@credentials = credentials
|
14
|
+
@up_to_time = options[:up_to_time]
|
15
|
+
@filename = options[:filename]
|
16
|
+
@debug = ENV['DEBUG'] == 'true'
|
17
|
+
end
|
18
|
+
|
19
|
+
def process_request
|
20
|
+
api_response = self.class.post(api_url, :body => build_xml)
|
21
|
+
puts api_response if @debug == true
|
22
|
+
response = parse_response(api_response)
|
23
|
+
if success?(response)
|
24
|
+
success_response(response)
|
25
|
+
else
|
26
|
+
error_message = if response[:ground_close_reply]
|
27
|
+
[response[:ground_close_reply][:notifications]].flatten.first[:message]
|
28
|
+
else
|
29
|
+
"#{api_response["Fault"]["detail"]["fault"]["reason"]}\n
|
30
|
+
--#{api_response["Fault"]["detail"]["fault"]["details"]["ValidationFailureDetail"]["message"].join("\n--")}"
|
31
|
+
end rescue $1
|
32
|
+
raise RateError, error_message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def success_response(response)
|
39
|
+
manifest_details = {
|
40
|
+
:filename => filename,
|
41
|
+
:manifest => response[:ground_close_reply][:manifest]
|
42
|
+
}
|
43
|
+
manifest = FedexShip::GroundManifest.new(manifest_details)
|
44
|
+
puts "manifest written to #{filename}" if @debug == true
|
45
|
+
manifest
|
46
|
+
end
|
47
|
+
|
48
|
+
# Build xml Fedex Web Service request
|
49
|
+
def build_xml
|
50
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
51
|
+
xml.GroundCloseRequest(:xmlns => "http://fedex.com/ws/close/v2"){
|
52
|
+
add_web_authentication_detail(xml)
|
53
|
+
add_client_detail(xml)
|
54
|
+
add_version(xml)
|
55
|
+
|
56
|
+
xml.TimeUpToWhichShipmentsAreToBeClosed up_to_time.utc.iso8601(2)
|
57
|
+
}
|
58
|
+
end
|
59
|
+
builder.doc.root.to_xml
|
60
|
+
end
|
61
|
+
|
62
|
+
def service
|
63
|
+
{ :id => 'clos', :version => '2' }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Successful request
|
67
|
+
def success?(response)
|
68
|
+
response[:ground_close_reply] &&
|
69
|
+
%w{SUCCESS WARNING NOTE}.include?(response[:ground_close_reply][:highest_severity])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'fedex_ship/request/base'
|
2
|
+
require 'fedex_ship/label'
|
3
|
+
require 'fedex_ship/request/shipment'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
module FedexShip
|
7
|
+
module Request
|
8
|
+
class Label < Shipment
|
9
|
+
def initialize(credentials, options={})
|
10
|
+
super(credentials, options)
|
11
|
+
@filename = options[:filename]
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def success_response(api_response, response)
|
17
|
+
super
|
18
|
+
|
19
|
+
label_details = response.merge!({
|
20
|
+
:format => @label_specification[:image_type],
|
21
|
+
:file_name => @filename
|
22
|
+
})
|
23
|
+
|
24
|
+
FedexShip::Label.new label_details
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'fedex_ship/request/base'
|
2
|
+
require 'logger'
|
3
|
+
module FedexShip
|
4
|
+
module Request
|
5
|
+
class LogsFedex < Base
|
6
|
+
|
7
|
+
def ship_serv_log(info)
|
8
|
+
begin
|
9
|
+
date = Date.today.to_s
|
10
|
+
info = (Time.now).to_s + ' ' + info
|
11
|
+
log = File.open('log/shipment_' + date + '.log','a')
|
12
|
+
log.puts(info)
|
13
|
+
log.close
|
14
|
+
rescue Exception => ex.to_s
|
15
|
+
puts ex.to_s
|
16
|
+
log.close
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def rate_serv_log(info)
|
21
|
+
begin
|
22
|
+
date = Date.today.to_s
|
23
|
+
info = (Time.now).to_s + ' ' + info
|
24
|
+
log = File.open('log/rate_' + date + '.log','a')
|
25
|
+
log.puts(info)
|
26
|
+
log.close
|
27
|
+
rescue Exception => ex.to_s
|
28
|
+
puts ex.to_s
|
29
|
+
log.close
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def track_serv_log(info)
|
34
|
+
begin
|
35
|
+
date = Date.today.to_s
|
36
|
+
info = (Time.now).to_s + ' ' + info
|
37
|
+
log = File.open('log/track_' + date + '.log','a')
|
38
|
+
log.puts(info)
|
39
|
+
log.close
|
40
|
+
rescue Exception => ex.to_s
|
41
|
+
puts ex.to_s
|
42
|
+
log.close
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def pickup_serv_log(info)
|
47
|
+
begin
|
48
|
+
date = Date.today.to_s
|
49
|
+
info = (Time.now).to_s + ' ' + info
|
50
|
+
log = File.open('log/pickup_' + date + '.log','a')
|
51
|
+
log.puts(info)
|
52
|
+
log.close
|
53
|
+
rescue Exception => ex.to_s
|
54
|
+
puts ex.to_s
|
55
|
+
log.close
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete_ship_serv_log(info)
|
60
|
+
begin
|
61
|
+
date = Date.today.to_s
|
62
|
+
info = (Time.now).to_s + ' ' + info
|
63
|
+
log = File.open('log/delete_shipment_' + date + '.log','a')
|
64
|
+
log.puts(info)
|
65
|
+
log.close
|
66
|
+
rescue Exception => ex.to_s
|
67
|
+
puts ex.to_s
|
68
|
+
log.close
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'fedex_ship/request/base'
|
2
|
+
require 'fedex_ship/request/logs_fedex'
|
3
|
+
|
4
|
+
module FedexShip
|
5
|
+
module Request
|
6
|
+
class Pickup < LogsFedex
|
7
|
+
def initialize(credentials, options = {})
|
8
|
+
requires!(options, :packages, :ready_timestamp, :close_time, :carrier_code, :country_relationship)
|
9
|
+
@debug = ENV['DEBUG'] == 'true'
|
10
|
+
|
11
|
+
@credentials = credentials
|
12
|
+
@packages = options[:packages]
|
13
|
+
@ready_timestamp = options[:ready_timestamp]
|
14
|
+
@close_time = options[:close_time]
|
15
|
+
@carrier_code = options[:carrier_code]
|
16
|
+
@remarks = options[:remarks] if options[:remarks]
|
17
|
+
@pickup_location = options[:pickup_location]
|
18
|
+
@commodity_description = options[:commodity_description] if options[:commodity_description]
|
19
|
+
@country_relationship = options[:country_relationship]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Sends post request to Fedex web service and parse the response, a Pickup object is created if the response is successful
|
23
|
+
def process_request
|
24
|
+
@build_xml = build_xml
|
25
|
+
pickup_serv_log('Final XML Request : ' + @build_xml.to_s)
|
26
|
+
api_url_srv = api_url + "/pickup"
|
27
|
+
pickup_serv_log('URL for API : ' + api_url_srv.to_s)
|
28
|
+
api_response = self.class.post(api_url_srv, :body => build_xml)
|
29
|
+
pickup_serv_log('API Response : ' + api_response.to_s)
|
30
|
+
puts api_response if @debug
|
31
|
+
response = parse_response(api_response)
|
32
|
+
if success?(response)
|
33
|
+
pickup_serv_log('Successfully Done : ' + response.to_s)
|
34
|
+
success_response(api_response, response)
|
35
|
+
else
|
36
|
+
failure_response(api_response, response)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Build xml Fedex Web Service request
|
43
|
+
def build_xml
|
44
|
+
ns = "http://fedex.com/ws/pickup/v17"
|
45
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
46
|
+
xml.Envelope("xmlns" => "http://fedex.com/ws/pickup/v17") {
|
47
|
+
xml.parent.namespace = xml.parent.add_namespace_definition("soapenv", "http://schemas.xmlsoap.org/soap/envelope/")
|
48
|
+
xml['soapenv'].Header {}
|
49
|
+
xml['soapenv'].Body {
|
50
|
+
xml.CreatePickupRequest() {
|
51
|
+
add_web_authentication_detail(xml)
|
52
|
+
add_client_detail(xml)
|
53
|
+
add_version(xml)
|
54
|
+
add_origin_detail(xml)
|
55
|
+
add_package_details(xml)
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
end
|
60
|
+
builder.doc.root.to_xml
|
61
|
+
end
|
62
|
+
|
63
|
+
def service
|
64
|
+
{:id => 'disp', :version => "17"}
|
65
|
+
end
|
66
|
+
|
67
|
+
# Add shipper to xml request
|
68
|
+
def add_origin_detail(xml)
|
69
|
+
xml.OriginDetail {
|
70
|
+
# if @pickup_location
|
71
|
+
if true
|
72
|
+
xml.UseAccountAddress false
|
73
|
+
add_pickup_location(xml)
|
74
|
+
else
|
75
|
+
xml.UseAccountAddress true
|
76
|
+
end
|
77
|
+
xml.ReadyTimestamp @ready_timestamp
|
78
|
+
xml.CompanyCloseTime @close_time.strftime("%H:%M:%S")
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_package_details(xml)
|
83
|
+
xml.PackageCount @packages[:count]
|
84
|
+
xml.TotalWeight {
|
85
|
+
xml.Units @packages[:weight][:units]
|
86
|
+
xml.Value @packages[:weight][:value]
|
87
|
+
}
|
88
|
+
xml.CarrierCode @carrier_code
|
89
|
+
xml.Remarks @remarks if @remarks
|
90
|
+
xml.CommodityDescription @commodity_description if @commodity_description
|
91
|
+
xml.CountryRelationship @country_relationship
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_pickup_location(xml)
|
95
|
+
xml.PickupLocation {
|
96
|
+
xml.Contact {
|
97
|
+
xml.PersonName @pickup_location[:name]
|
98
|
+
xml.CompanyName @pickup_location[:company]
|
99
|
+
xml.PhoneNumber @pickup_location[:phone_number]
|
100
|
+
}
|
101
|
+
xml.Address {
|
102
|
+
Array(@pickup_location[:address]).take(2).each do |address_line|
|
103
|
+
xml.StreetLines address_line
|
104
|
+
end
|
105
|
+
xml.City @pickup_location[:city]
|
106
|
+
xml.StateOrProvinceCode @pickup_location[:state]
|
107
|
+
xml.PostalCode @pickup_location[:postal_code]
|
108
|
+
xml.CountryCode @pickup_location[:country_code]
|
109
|
+
}
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
# Callback used after a failed pickup response.
|
114
|
+
def failure_response(api_response, response)
|
115
|
+
error_message = if response[:envelope][:body][:create_pickup_reply]
|
116
|
+
[response[:envelope][:body][:create_pickup_reply][:notifications]].flatten.first[:message]
|
117
|
+
else
|
118
|
+
"#{api_response["Fault"]["detail"]["fault"]["reason"]}\n--#{Array(api_response["Fault"]["detail"]["fault"]["details"]["ValidationFailureDetail"]["message"]).join("\n--")}"
|
119
|
+
end rescue $1
|
120
|
+
raise RateError, error_message
|
121
|
+
end
|
122
|
+
|
123
|
+
# Callback used after a successful pickup response.
|
124
|
+
def success_response(api_response, response)
|
125
|
+
@response_details = response[:envelope][:body][:create_pickup_reply]
|
126
|
+
end
|
127
|
+
|
128
|
+
# Successful request
|
129
|
+
def success?(response)
|
130
|
+
response[:envelope][:body][:create_pickup_reply] &&
|
131
|
+
%w{SUCCESS WARNING NOTE}.include?(response[:envelope][:body][:create_pickup_reply][:highest_severity])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'fedex_ship/request/base'
|
2
|
+
require 'fedex_ship/request/logs_fedex'
|
3
|
+
|
4
|
+
module FedexShip
|
5
|
+
module Request
|
6
|
+
class PickupAvailability < LogsFedex
|
7
|
+
|
8
|
+
def initialize(credentials, options = {})
|
9
|
+
requires!(options, :country_code, :request_type, :carrier_code)
|
10
|
+
@debug = ENV['DEBUG'] == 'true'
|
11
|
+
|
12
|
+
@credentials = credentials
|
13
|
+
|
14
|
+
@country_code = options[:country_code]
|
15
|
+
@postal_code = options[:postal_code] if options[:postal_code]
|
16
|
+
@state_code = options[:state_code] if options[:state_code]
|
17
|
+
@request_type = options[:request_type]
|
18
|
+
@carrier_code = options[:carrier_code]
|
19
|
+
@dispatch_date = options[:dispatch_date] if options[:dispatch_date]
|
20
|
+
end
|
21
|
+
|
22
|
+
def process_request
|
23
|
+
@build_xml = build_xml
|
24
|
+
pickup_serv_log('Final XML Request : ' + @build_xml.to_s)
|
25
|
+
api_url_srv = api_url + "/pickup"
|
26
|
+
pickup_serv_log('URL for API : ' + api_url_srv.to_s)
|
27
|
+
api_response = self.class.post(api_url_srv, :body => build_xml)
|
28
|
+
pickup_serv_log('API Response : ' + api_response.to_s)
|
29
|
+
puts api_response if @debug == true
|
30
|
+
response = parse_response(api_response)
|
31
|
+
if success?(response)
|
32
|
+
pickup_serv_log('Successfully Done : ' + response.to_s)
|
33
|
+
success_response(api_response, response)
|
34
|
+
else
|
35
|
+
failure_response(api_response, response)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Build xml Fedex Web Service request
|
42
|
+
def build_xml
|
43
|
+
ns = "http://fedex.com/ws/pickup/v17"
|
44
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
45
|
+
xml.Envelope("xmlns" => "http://fedex.com/ws/pickup/v17") {
|
46
|
+
xml.parent.namespace = xml.parent.add_namespace_definition("soapenv", "http://schemas.xmlsoap.org/soap/envelope/")
|
47
|
+
xml['soapenv'].Header {}
|
48
|
+
xml['soapenv'].Body {
|
49
|
+
xml.PickupAvailabilityRequest(:xmlns => ns) {
|
50
|
+
add_web_authentication_detail(xml)
|
51
|
+
add_client_detail(xml)
|
52
|
+
add_version(xml)
|
53
|
+
add_pickup_address(xml)
|
54
|
+
add_other_pickup_details(xml)
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
builder.doc.root.to_xml
|
60
|
+
end
|
61
|
+
|
62
|
+
def service
|
63
|
+
{:id => 'disp', :version => "17"}
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_pickup_address(xml)
|
67
|
+
xml.PickupAddress {
|
68
|
+
xml.PostalCode @postal_code if @postal_code
|
69
|
+
xml.CountryCode @country_code
|
70
|
+
xml.StateOrProvinceCode @state_code if @state_code
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_other_pickup_details(xml)
|
75
|
+
xml.PickupRequestType @request_type
|
76
|
+
xml.DispatchDate @dispatch_date if @dispatch_date
|
77
|
+
xml.Carriers @carrier_code
|
78
|
+
end
|
79
|
+
|
80
|
+
# Callback used after a failed pickup response.
|
81
|
+
def failure_response(api_response, response)
|
82
|
+
error_message = if response[:envelope][:body][:pickup_availability_reply]
|
83
|
+
[response[:envelope][:body][:pickup_availability_reply][:notifications]].flatten.first[:message]
|
84
|
+
else
|
85
|
+
"#{api_response["Fault"]["detail"]["fault"]["reason"]}\n--#{api_response["Fault"]["detail"]["fault"]["details"]["ValidationFailureDetail"]["message"].join("\n--")}"
|
86
|
+
end rescue $1
|
87
|
+
raise RateError, error_message
|
88
|
+
end
|
89
|
+
|
90
|
+
# Callback used after a successful pickup response.
|
91
|
+
def success_response(api_response, response)
|
92
|
+
@response_details = response[:envelope][:body][:pickup_availability_reply]
|
93
|
+
end
|
94
|
+
|
95
|
+
# Successful request
|
96
|
+
def success?(response)
|
97
|
+
response[:envelope][:body][:pickup_availability_reply] &&
|
98
|
+
%w{SUCCESS WARNING NOTE}.include?(response[:envelope][:body][:pickup_availability_reply][:highest_severity])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|