fedex 3.6.1 → 3.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,73 @@
1
+ require 'fedex/request/base'
2
+ require 'fedex/ground_manifest'
3
+
4
+ module Fedex
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 = Fedex::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,121 @@
1
+ require 'fedex/request/base'
2
+
3
+ module Fedex
4
+ module Request
5
+ class Pickup < Base
6
+ def initialize(credentials, options={})
7
+ requires!(options, :packages, :ready_timestamp, :close_time, :carrier_code, :country_relationship)
8
+ @debug = ENV['DEBUG'] == 'true'
9
+
10
+ @credentials = credentials
11
+ @packages = options[:packages]
12
+ @ready_timestamp = options[:ready_timestamp]
13
+ @close_time = options[:close_time]
14
+ @carrier_code = options[:carrier_code]
15
+ @remarks = options[:remarks] if options[:remarks]
16
+ @pickup_location = options[:pickup_location]
17
+ @commodity_description = options[:commodity_description] if options[:commodity_description]
18
+ @country_relationship = options[:country_relationship]
19
+ end
20
+
21
+ # Sends post request to Fedex web service and parse the response, a Pickup object is created if the response is successful
22
+ def process_request
23
+ api_response = self.class.post(api_url, :body => build_xml)
24
+ puts api_response if @debug
25
+ response = parse_response(api_response)
26
+ if success?(response)
27
+ success_response(api_response, response)
28
+ else
29
+ failure_response(api_response, response)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # Build xml Fedex Web Service request
36
+ def build_xml
37
+ ns = "http://fedex.com/ws/pickup/v#{service[:version]}"
38
+ builder = Nokogiri::XML::Builder.new do |xml|
39
+ xml.CreatePickupRequest(:xmlns => ns) {
40
+ add_web_authentication_detail(xml)
41
+ add_client_detail(xml)
42
+ add_version(xml)
43
+ add_origin_detail(xml)
44
+ add_package_details(xml)
45
+ }
46
+ end
47
+ builder.doc.root.to_xml
48
+ end
49
+
50
+ def service
51
+ { :id => 'pickup', :version => Fedex::PICKUP_API_VERSION }
52
+ end
53
+
54
+ # Add shipper to xml request
55
+ def add_origin_detail(xml)
56
+ xml.OriginDetail {
57
+ if @pickup_location
58
+ xml.UseAccountAddress false
59
+ add_pickup_location(xml)
60
+ else
61
+ xml.UseAccountAddress true
62
+ end
63
+ xml.ReadyTimestamp @ready_timestamp
64
+ xml.CompanyCloseTime @close_time.strftime("%H:%M:%S")
65
+ }
66
+ end
67
+
68
+ def add_package_details(xml)
69
+ xml.PackageCount @packages[:count]
70
+ xml.TotalWeight {
71
+ xml.Units @packages[:weight][:units]
72
+ xml.Value @packages[:weight][:value]
73
+ }
74
+ xml.CarrierCode @carrier_code
75
+ xml.Remarks @remarks if @remarks
76
+ xml.CommodityDescription @commodity_description if @commodity_description
77
+ xml.CountryRelationship @country_relationship
78
+ end
79
+
80
+ def add_pickup_location(xml)
81
+ xml.PickupLocation {
82
+ xml.Contact {
83
+ xml.PersonName @pickup_location[:name]
84
+ xml.CompanyName @pickup_location[:company]
85
+ xml.PhoneNumber @pickup_location[:phone_number]
86
+ }
87
+ xml.Address {
88
+ Array(@pickup_location[:address]).take(2).each do |address_line|
89
+ xml.StreetLines address_line
90
+ end
91
+ xml.City @pickup_location[:city]
92
+ xml.StateOrProvinceCode @pickup_location[:state]
93
+ xml.PostalCode @pickup_location[:postal_code]
94
+ xml.CountryCode @pickup_location[:country_code]
95
+ }
96
+ }
97
+ end
98
+
99
+ # Callback used after a failed pickup response.
100
+ def failure_response(api_response, response)
101
+ error_message = if response[:create_pickup_reply]
102
+ [response[:create_pickup_reply][:notifications]].flatten.first[:message]
103
+ else
104
+ "#{api_response["Fault"]["detail"]["fault"]["reason"]}\n--#{Array(api_response["Fault"]["detail"]["fault"]["details"]["ValidationFailureDetail"]["message"]).join("\n--")}"
105
+ end rescue $1
106
+ raise RateError, error_message
107
+ end
108
+
109
+ # Callback used after a successful pickup response.
110
+ def success_response(api_response, response)
111
+ @response_details = response[:create_pickup_reply]
112
+ end
113
+
114
+ # Successful request
115
+ def success?(response)
116
+ response[:create_pickup_reply] &&
117
+ %w{SUCCESS WARNING NOTE}.include?(response[:create_pickup_reply][:highest_severity])
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,89 @@
1
+ require 'fedex/request/base'
2
+
3
+ module Fedex
4
+ module Request
5
+ class PickupAvailability < Base
6
+
7
+ def initialize(credentials, options={})
8
+ requires!(options, :country_code, :request_type, :carrier_code)
9
+ @debug = ENV['DEBUG'] == 'true'
10
+
11
+ @credentials = credentials
12
+
13
+ @country_code = options[:country_code]
14
+ @postal_code = options[:postal_code] if options[:postal_code]
15
+ @state_code = options[:state_code] if options[:state_code]
16
+ @request_type = options[:request_type]
17
+ @carrier_code = options[:carrier_code]
18
+ @dispatch_date = options[:dispatch_date] if options[:dispatch_date]
19
+ end
20
+
21
+ def process_request
22
+ api_response = self.class.post(api_url, :body => build_xml)
23
+ puts api_response if @debug == true
24
+ response = parse_response(api_response)
25
+ if success?(response)
26
+ success_response(api_response, response)
27
+ else
28
+ failure_response(api_response, response)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ # Build xml Fedex Web Service request
35
+ def build_xml
36
+ ns = "http://fedex.com/ws/pickup/v#{service[:version]}"
37
+ builder = Nokogiri::XML::Builder.new do |xml|
38
+ xml.PickupAvailabilityRequest(:xmlns => ns) {
39
+ add_web_authentication_detail(xml)
40
+ add_client_detail(xml)
41
+ add_version(xml)
42
+ add_pickup_address(xml)
43
+ add_other_pickup_details(xml)
44
+ }
45
+ end
46
+ builder.doc.root.to_xml
47
+ end
48
+
49
+ def service
50
+ { :id => 'pickup', :version => Fedex::PICKUP_API_VERSION }
51
+ end
52
+
53
+ def add_pickup_address(xml)
54
+ xml.PickupAddress{
55
+ xml.PostalCode @postal_code if @postal_code
56
+ xml.CountryCode @country_code
57
+ xml.StateOrProvinceCode @state_code if @state_code
58
+ }
59
+ end
60
+
61
+ def add_other_pickup_details(xml)
62
+ xml.PickupRequestType @request_type
63
+ xml.DispatchDate @dispatch_date if @dispatch_date
64
+ xml.Carriers @carrier_code
65
+ end
66
+
67
+ # Callback used after a failed pickup response.
68
+ def failure_response(api_response, response)
69
+ error_message = if response[:pickup_availability_reply]
70
+ [response[:pickup_availability_reply][:notifications]].flatten.first[:message]
71
+ else
72
+ "#{api_response["Fault"]["detail"]["fault"]["reason"]}\n--#{api_response["Fault"]["detail"]["fault"]["details"]["ValidationFailureDetail"]["message"].join("\n--")}"
73
+ end rescue $1
74
+ raise RateError, error_message
75
+ end
76
+
77
+ # Callback used after a successful pickup response.
78
+ def success_response(api_response, response)
79
+ @response_details = response[:pickup_availability_reply]
80
+ end
81
+
82
+ # Successful request
83
+ def success?(response)
84
+ response[:pickup_availability_reply] &&
85
+ %w{SUCCESS WARNING NOTE}.include?(response[:pickup_availability_reply][:highest_severity])
86
+ end
87
+ end
88
+ end
89
+ end
@@ -15,6 +15,7 @@ module Fedex
15
15
  rate_reply_details.map do |rate_reply|
16
16
  rate_details = [rate_reply[:rated_shipment_details]].flatten.first[:shipment_rate_detail]
17
17
  rate_details.merge!(service_type: rate_reply[:service_type])
18
+ rate_details.merge!(transit_time: rate_reply[:transit_time])
18
19
  Fedex::Rate.new(rate_details)
19
20
  end
20
21
  else
@@ -44,6 +45,11 @@ module Fedex
44
45
  }
45
46
  end
46
47
 
48
+ # Add transite time options
49
+ def add_transit_time(xml)
50
+ xml.ReturnTransitAndCommit true
51
+ end
52
+
47
53
  # Build xml Fedex Web Service request
48
54
  def build_xml
49
55
  ns = "http://fedex.com/ws/rate/v#{service[:version]}"
@@ -52,6 +58,7 @@ module Fedex
52
58
  add_web_authentication_detail(xml)
53
59
  add_client_detail(xml)
54
60
  add_version(xml)
61
+ add_transit_time(xml)
55
62
  add_requested_shipment(xml)
56
63
  }
57
64
  end
@@ -0,0 +1,86 @@
1
+ require 'fedex/request/base'
2
+
3
+ module Fedex
4
+ module Request
5
+ class ServiceAvailability < Base
6
+ def initialize(credentials, options={})
7
+ requires!(options, :origin, :destination, :ship_date, :carrier_code)
8
+
9
+ @credentials = credentials
10
+ @origin = options[:origin]
11
+ @destination = options[:destination]
12
+ @ship_date = options[:ship_date]
13
+ @carrier_code = options[:carrier_code]
14
+ end
15
+
16
+ def process_request
17
+ api_response = self.class.post api_url, :body => build_xml
18
+ puts api_response if @debug
19
+ response = parse_response(api_response)
20
+ if success?(response)
21
+ success_response(api_response, response)
22
+ else
23
+ failure_response(api_response, response)
24
+ end
25
+ end
26
+
27
+ def build_xml
28
+ builder = Nokogiri::XML::Builder.new do |xml|
29
+ xml.ServiceAvailabilityRequest(:xmlns => "http://fedex.com/ws/packagemovementinformationservice/v#{service[:version]}"){
30
+ add_web_authentication_detail(xml)
31
+ add_client_detail(xml)
32
+ add_version(xml)
33
+ add_origin(xml)
34
+ add_destination(xml)
35
+ add_other_details(xml)
36
+ }
37
+ end
38
+ builder.doc.root.to_xml
39
+ end
40
+
41
+ def add_origin(xml)
42
+ xml.Origin{
43
+ xml.PostalCode @origin[:postal_code]
44
+ xml.CountryCode @origin[:country_code]
45
+ }
46
+ end
47
+
48
+ def add_destination(xml)
49
+ xml.Destination{
50
+ xml.PostalCode @destination[:postal_code]
51
+ xml.CountryCode @destination[:country_code]
52
+ }
53
+ end
54
+
55
+ def add_other_details(xml)
56
+ xml.ShipDate @ship_date
57
+ xml.CarrierCode @carrier_code
58
+ end
59
+
60
+ # Callback used after a failed shipment response.
61
+ def failure_response(api_response, response)
62
+ error_message = if response[:service_availability_reply]
63
+ [response[:service_availability_reply][:notifications]].flatten.first[:message]
64
+ else
65
+ "#{api_response["Fault"]["detail"]["fault"]["reason"]}\n--#{api_response["Fault"]["detail"]["fault"]["details"]["ValidationFailureDetail"]["message"].join("\n--")}"
66
+ end rescue $1
67
+ raise RateError, error_message
68
+ end
69
+
70
+ # Callback used after a successful shipment response.
71
+ def success_response(api_response, response)
72
+ @response_details = response[:service_availability_reply]
73
+ end
74
+
75
+ def service
76
+ { :id => 'pmis', :version => Fedex::SERVICE_AVAILABILITY_API_VERSION }
77
+ end
78
+
79
+ # Successful request
80
+ def success?(response)
81
+ response[:service_availability_reply] &&
82
+ %w{SUCCESS WARNING NOTE}.include?(response[:service_availability_reply][:highest_severity])
83
+ end
84
+ end
85
+ end
86
+ end
@@ -15,6 +15,7 @@ module Fedex
15
15
  :label_stock_type => 'PAPER_LETTER'
16
16
  }
17
17
  @label_specification.merge! options[:label_specification] if options[:label_specification]
18
+ @customer_specified_detail = options[:customer_specified_detail] if options[:customer_specified_detail]
18
19
  end
19
20
 
20
21
  # Sends post request to Fedex web service and parse the response.
@@ -41,10 +42,11 @@ module Fedex
41
42
  xml.DropoffType @shipping_options[:drop_off_type] ||= "REGULAR_PICKUP"
42
43
  xml.ServiceType service_type
43
44
  xml.PackagingType @shipping_options[:packaging_type] ||= "YOUR_PACKAGING"
45
+ add_total_weight(xml) if @mps.has_key? :total_weight
44
46
  add_shipper(xml)
45
47
  add_recipient(xml)
46
48
  add_shipping_charges_payment(xml)
47
- add_special_services(xml) if @shipping_options[:return_reason]
49
+ add_special_services(xml) if @shipping_options[:return_reason] || @shipping_options[:cod]
48
50
  add_customs_clearance(xml) if @customs_clearance_detail
49
51
  add_custom_components(xml)
50
52
  xml.RateRequestTypes "ACCOUNT"
@@ -52,6 +54,15 @@ module Fedex
52
54
  }
53
55
  end
54
56
 
57
+ def add_total_weight(xml)
58
+ if @mps.has_key? :total_weight
59
+ xml.TotalWeight{
60
+ xml.Units @mps[:total_weight][:units]
61
+ xml.Value @mps[:total_weight][:value]
62
+ }
63
+ end
64
+ end
65
+
55
66
  # Hook that can be used to add custom parts.
56
67
  def add_custom_components(xml)
57
68
  add_label_specification xml
@@ -63,18 +74,31 @@ module Fedex
63
74
  xml.LabelFormatType @label_specification[:label_format_type]
64
75
  xml.ImageType @label_specification[:image_type]
65
76
  xml.LabelStockType @label_specification[:label_stock_type]
77
+ xml.CustomerSpecifiedDetail{ hash_to_xml(xml, @customer_specified_detail) } if @customer_specified_detail
66
78
  }
67
79
  end
68
80
 
69
81
  def add_special_services(xml)
70
82
  xml.SpecialServicesRequested {
71
- xml.SpecialServiceTypes "RETURN_SHIPMENT"
72
- xml.ReturnShipmentDetail {
73
- xml.ReturnType "PRINT_RETURN_LABEL"
74
- xml.Rma {
75
- xml.Reason "#{@shipping_options[:return_reason]}"
83
+ if @shipping_options[:return_reason]
84
+ xml.SpecialServiceTypes "RETURN_SHIPMENT"
85
+ xml.ReturnShipmentDetail {
86
+ xml.ReturnType "PRINT_RETURN_LABEL"
87
+ xml.Rma {
88
+ xml.Reason "#{@shipping_options[:return_reason]}"
89
+ }
76
90
  }
77
- }
91
+ end
92
+ if @shipping_options[:cod]
93
+ xml.SpecialServiceTypes "COD"
94
+ xml.CodDetail {
95
+ xml.CodCollectionAmount {
96
+ xml.Currency @shipping_options[:cod][:currency].upcase if @shipping_options[:cod][:currency]
97
+ xml.Amount @shipping_options[:cod][:amount] if @shipping_options[:cod][:amount]
98
+ }
99
+ xml.CollectionType @shipping_options[:cod][:collection_type] if @shipping_options[:cod][:collection_type]
100
+ }
101
+ end
78
102
  }
79
103
  end
80
104