fedex 3.6.1 → 3.8.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.
@@ -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