simple_shipping 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.metrics +6 -0
- data/.rspec +4 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.simplecov +43 -0
- data/Gemfile +26 -0
- data/Gemfile.lock +201 -0
- data/LICENSE.txt +21 -0
- data/README.markdown +207 -0
- data/Rakefile +68 -0
- data/VERSION +1 -0
- data/coverage/.resultset.json +1579 -0
- data/lib/colorized_text.rb +34 -0
- data/lib/simple_shipping.rb +27 -0
- data/lib/simple_shipping/abstract.rb +11 -0
- data/lib/simple_shipping/abstract/builder.rb +47 -0
- data/lib/simple_shipping/abstract/client.rb +111 -0
- data/lib/simple_shipping/abstract/model.rb +40 -0
- data/lib/simple_shipping/abstract/request.rb +27 -0
- data/lib/simple_shipping/abstract/response.rb +26 -0
- data/lib/simple_shipping/address.rb +22 -0
- data/lib/simple_shipping/contact.rb +24 -0
- data/lib/simple_shipping/demo.rb +9 -0
- data/lib/simple_shipping/demo/base.rb +71 -0
- data/lib/simple_shipping/demo/fedex.rb +46 -0
- data/lib/simple_shipping/demo/ups.rb +68 -0
- data/lib/simple_shipping/exceptions.rb +40 -0
- data/lib/simple_shipping/fedex.rb +14 -0
- data/lib/simple_shipping/fedex/client.rb +41 -0
- data/lib/simple_shipping/fedex/package_builder.rb +24 -0
- data/lib/simple_shipping/fedex/party_builder.rb +50 -0
- data/lib/simple_shipping/fedex/request.rb +54 -0
- data/lib/simple_shipping/fedex/response.rb +5 -0
- data/lib/simple_shipping/fedex/shipment_builder.rb +123 -0
- data/lib/simple_shipping/fedex/shipment_request.rb +14 -0
- data/lib/simple_shipping/fedex/shipment_response.rb +12 -0
- data/lib/simple_shipping/package.rb +43 -0
- data/lib/simple_shipping/party.rb +21 -0
- data/lib/simple_shipping/shipment.rb +42 -0
- data/lib/simple_shipping/ups.rb +24 -0
- data/lib/simple_shipping/ups/client.rb +46 -0
- data/lib/simple_shipping/ups/package_builder.rb +101 -0
- data/lib/simple_shipping/ups/party_builder.rb +38 -0
- data/lib/simple_shipping/ups/request.rb +27 -0
- data/lib/simple_shipping/ups/response.rb +63 -0
- data/lib/simple_shipping/ups/ship_accept_request.rb +21 -0
- data/lib/simple_shipping/ups/ship_accept_response.rb +6 -0
- data/lib/simple_shipping/ups/ship_client.rb +70 -0
- data/lib/simple_shipping/ups/ship_confirm_request.rb +22 -0
- data/lib/simple_shipping/ups/ship_confirm_response.rb +6 -0
- data/lib/simple_shipping/ups/shipment_builder.rb +66 -0
- data/lib/simple_shipping/ups/shipment_request.rb +22 -0
- data/lib/simple_shipping/ups/shipment_response.rb +6 -0
- data/lib/simple_shipping/ups/void_client.rb +50 -0
- data/lib/simple_shipping/ups/void_request.rb +42 -0
- data/lib/simple_shipping/ups/void_response.rb +6 -0
- data/lib/tasks/demo.rake +58 -0
- data/script/ups_certification.rb +140 -0
- data/simple_shipping.gemspec +168 -0
- data/spec/fixtures/fedex_shipment_request.soap.xml.erb +85 -0
- data/spec/fixtures/fedex_shipment_response.soap.xml.erb +182 -0
- data/spec/fixtures/ups_shipment_request.soap.xml.erb +88 -0
- data/spec/fixtures/ups_shipment_response.soap.xml.erb +58 -0
- data/spec/fixtures/ups_shipment_response_with_faked_label_data.soap.xml.erb +54 -0
- data/spec/fixtures/ups_void_request.soap.xml.erb +29 -0
- data/spec/fixtures/ups_void_response.soap.xml.erb +21 -0
- data/spec/lib/simple_shipping/address_spec.rb +19 -0
- data/spec/lib/simple_shipping/contact_spec.rb +28 -0
- data/spec/lib/simple_shipping/exceptions_spec.rb +58 -0
- data/spec/lib/simple_shipping/fedex/package_builder_spec.rb +5 -0
- data/spec/lib/simple_shipping/fedex/party_builder_spec.rb +5 -0
- data/spec/lib/simple_shipping/fedex/response/shipment_reponse_spec.rb +5 -0
- data/spec/lib/simple_shipping/fedex/response_spec.rb +5 -0
- data/spec/lib/simple_shipping/fedex/shipment_builder_spec.rb +23 -0
- data/spec/lib/simple_shipping/package_spec.rb +32 -0
- data/spec/lib/simple_shipping/party_spec.rb +18 -0
- data/spec/lib/simple_shipping/shipment_spec.rb +35 -0
- data/spec/lib/simple_shipping/ups/package_builder_spec.rb +26 -0
- data/spec/lib/simple_shipping/ups/party_builder_spec.rb +47 -0
- data/spec/lib/simple_shipping/ups/response/shipment_response_spec.rb +5 -0
- data/spec/lib/simple_shipping/ups/response_spec.rb +33 -0
- data/spec/lib/simple_shipping/ups/shipment_builder_spec.rb +19 -0
- data/spec/requests/fedex_spec.rb +47 -0
- data/spec/requests/ups_spec.rb +75 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/support/custom_matchers/basic_matcher.rb +13 -0
- data/spec/support/custom_matchers/have_attribute_matcher.rb +22 -0
- data/spec/support/custom_matchers/have_default_value_matcher.rb +26 -0
- data/spec/support/custom_matchers/have_errors_on_matcher.rb +23 -0
- data/spec/support/custom_matchers/validate_inclusion_of_matcher.rb +37 -0
- data/spec/support/custom_matchers/validate_presence_of_matcher.rb +24 -0
- data/spec/support/custom_matchers/validate_submodel_matcher.rb +44 -0
- data/spec/support/shared_behaviours/builders_behaviour.rb +9 -0
- data/spec/support/shared_behaviours/responses_behaviour.rb +10 -0
- data/tmp/metric_fu/_data/20131210.yml +9964 -0
- data/wsdl/fedex/ship_service_v10.wsdl +5566 -0
- data/wsdl/ups/Ship.wsdl +120 -0
- data/wsdl/ups/Void.wsdl +58 -0
- metadata +308 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
# Helper object to send demo requests to FedEx in order to test credentials
|
2
|
+
# and the library.
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# demo = SimpleShipping::Demo::Fedex.new(credentials)
|
6
|
+
# response = demo.shipment_request
|
7
|
+
class SimpleShipping::Demo::Fedex < SimpleShipping::Demo::Base
|
8
|
+
attr_reader :credentials
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options.reverse_merge(:log => false)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Build the package object.
|
15
|
+
#
|
16
|
+
# @return [SimpleShipping::Package]
|
17
|
+
def package
|
18
|
+
@package ||= SimpleShipping::Package.new(
|
19
|
+
:weight => 1,
|
20
|
+
:length => 2,
|
21
|
+
:height => 3,
|
22
|
+
:dimension_units => :in, # you can use :kg as well
|
23
|
+
:weight_units => :lb, # you can use :cm as well
|
24
|
+
:width => 4,
|
25
|
+
:packaging_type => :your
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Initialize the FedEx client.
|
30
|
+
#
|
31
|
+
# @return [SimpleShipping::Fedex::Client]
|
32
|
+
def fedex_client
|
33
|
+
@fedex_client ||= SimpleShipping::Fedex::Client.new(
|
34
|
+
:credentials => options.slice(:key, :password, :account_number, :meter_number),
|
35
|
+
:log => options[:log],
|
36
|
+
:live => options[:live]
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Send the shipment request to FedEx.
|
41
|
+
#
|
42
|
+
# @return [SimpleShipping::Fedex::Response]
|
43
|
+
def shipment_request
|
44
|
+
fedex_client.shipment_request(shipper, recipient, package)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Helper object to send demo requests to UPS in order to test credentials
|
2
|
+
# and the library.
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# demo = SimpleShipping::Demo::Ups.new(credentials)
|
6
|
+
# response = demo.shipment_request
|
7
|
+
class SimpleShipping::Demo::Ups < SimpleShipping::Demo::Base
|
8
|
+
attr_reader :credentials
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options.reverse_merge(
|
12
|
+
:log => false,
|
13
|
+
:service_type => :second_day_air
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Build the package object.
|
18
|
+
#
|
19
|
+
# @return [SimpleShipping::Package]
|
20
|
+
def package
|
21
|
+
@package ||= SimpleShipping::Package.new(
|
22
|
+
:weight => 0.5,
|
23
|
+
:packaging_type => :envelope
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Initialize the UPS client for shipment requests.
|
28
|
+
#
|
29
|
+
# @return [SimpleShipping::Ups::ShipClient]
|
30
|
+
def ship_client
|
31
|
+
@ship_client ||= SimpleShipping::Ups::ShipClient.new(
|
32
|
+
:credentials => options.slice(:username, :password, :access_license_number),
|
33
|
+
:log => options[:log]
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Initialize the UPS client for void requests.
|
38
|
+
#
|
39
|
+
# @return [SimpleShipping::Ups::VoidClient]
|
40
|
+
def void_client
|
41
|
+
@void_client ||= SimpleShipping::Ups::VoidClient.new(
|
42
|
+
:credentials => options.slice(:username, :password, :access_license_number),
|
43
|
+
:log => options[:log],
|
44
|
+
:live => options[:live]
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Shipment Id. The number is picked randomly.
|
49
|
+
#
|
50
|
+
# @return [String]
|
51
|
+
def shipment_identification_number
|
52
|
+
@shipment_identification_number ||= '1234567890'
|
53
|
+
end
|
54
|
+
|
55
|
+
# Send a shipment request.
|
56
|
+
#
|
57
|
+
# @return [ShipClient::Ups::ShipmentResponse]
|
58
|
+
def shipment_request
|
59
|
+
ship_client.shipment_request(shipper, recipient, package, :service_type => options[:service_type])
|
60
|
+
end
|
61
|
+
|
62
|
+
# Send a request to void a shipment.
|
63
|
+
#
|
64
|
+
# @return [ShipClient::Ups::VoidResponse]
|
65
|
+
def void_request
|
66
|
+
void_client.void_request(shipment_identification_number)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module SimpleShipping
|
2
|
+
# Parent error for all SimpleShipping errors.
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
# Error raises when response does not contain a label.
|
6
|
+
class NoLabelError < Error ; end
|
7
|
+
|
8
|
+
# Raises when some data is invalid or missing to build a request.
|
9
|
+
class ValidationError < Error
|
10
|
+
# @param model_or_msg [Abstract::Model, String]
|
11
|
+
def initialize(model_or_msg)
|
12
|
+
@message = case model_or_msg
|
13
|
+
when Abstract::Model
|
14
|
+
"Invalid model #{model_or_msg.class}. Validation errors: #{model_or_msg.errors.full_messages.join(', ')}"
|
15
|
+
when String
|
16
|
+
model_or_msg
|
17
|
+
end
|
18
|
+
|
19
|
+
super(@message)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Raised when a remote request fails.
|
24
|
+
class RequestError < Error
|
25
|
+
# @param [Savon::SOAPFault] savon_fault Savon exception
|
26
|
+
def initialize(savon_fault)
|
27
|
+
fault = savon_fault.to_hash[:fault]
|
28
|
+
|
29
|
+
@message =
|
30
|
+
if fault[:faultcode] # SOAP 1.1 fault.
|
31
|
+
detail = fault[:detail][:errors][:error_detail][:primary_error_code]
|
32
|
+
"#{fault[:faultstring]} (#{detail[:code]}) #{detail[:description]}"
|
33
|
+
elsif fault[:code] # SOAP 1.2 fault.
|
34
|
+
"(#{fault[:code][:value]}) #{fault[:reason][:text]}"
|
35
|
+
end
|
36
|
+
|
37
|
+
super(@message)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Namespace for FedEx provider.
|
2
|
+
module SimpleShipping::Fedex
|
3
|
+
extend ActiveSupport::Autoload
|
4
|
+
|
5
|
+
autoload :Client
|
6
|
+
autoload :Request
|
7
|
+
autoload :Response
|
8
|
+
autoload :ShipmentBuilder
|
9
|
+
autoload :PackageBuilder
|
10
|
+
autoload :PartyBuilder
|
11
|
+
|
12
|
+
autoload :ShipmentRequest
|
13
|
+
autoload :ShipmentResponse
|
14
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SimpleShipping::Fedex
|
2
|
+
# Required credentials:
|
3
|
+
# * _key_
|
4
|
+
# * _password_
|
5
|
+
# * _account_number_
|
6
|
+
# * _meter_number_
|
7
|
+
#
|
8
|
+
# = Usage
|
9
|
+
# client = SimpleShipping::Fedex::Client.new(:key => "KEY",
|
10
|
+
# :password => "PASSWORD",
|
11
|
+
# :account_number => "ACCOUNT NUMBER",
|
12
|
+
# :METER_NUMBER => "METER NUMBER")
|
13
|
+
# client.request(shipper, recipient, package) # => #<SimpleShipping::Fedex::Response ...>
|
14
|
+
class Client < SimpleShipping::Abstract::Client
|
15
|
+
set_required_credentials :key, :password, :account_number, :meter_number
|
16
|
+
|
17
|
+
set_wsdl_document File.join(SimpleShipping::WSDL_DIR, "fedex/ship_service_v10.wsdl")
|
18
|
+
set_testing_address "https://wsbeta.fedex.com:443/web-services/ship"
|
19
|
+
set_production_address "https://wsbeta.fedex.com:443/web-services/ship" # Not configured
|
20
|
+
|
21
|
+
# Send the shipment request to FedEx.
|
22
|
+
def shipment_request(shipper, recipient, package, opts = {})
|
23
|
+
shipment = create_shipment(shipper, recipient, package, opts)
|
24
|
+
request = ShipmentRequest.new(@credentials, shipment)
|
25
|
+
execute(request)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Send the shipment confirmation request.
|
29
|
+
def ship_confirm_request(shipper, recipient, package, opts = {})
|
30
|
+
fail "Not Implemented"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Send the ProcessShipmentRequest request to the FedEx service and return
|
34
|
+
# the response wrapped in a {Fedex::Response} object.
|
35
|
+
def execute(request)
|
36
|
+
savon_response = @client.call(request.type, :message => request.body)
|
37
|
+
request.response(savon_response)
|
38
|
+
end
|
39
|
+
private :execute
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SimpleShipping::Fedex
|
2
|
+
# Knows how to convert {Package} model to SOAP element for FedEx.
|
3
|
+
class PackageBuilder < SimpleShipping::Abstract::Builder
|
4
|
+
# FedEx mapping for weight units.
|
5
|
+
WEIGHT_UNITS = {:kg => 'KG',
|
6
|
+
:lb => 'LB'}
|
7
|
+
# FedEx mapping for dimension units.
|
8
|
+
DIMENSION_UNITS = {:in => 'IN',
|
9
|
+
:cm => 'CM'}
|
10
|
+
|
11
|
+
# Build a SOAP package element as a hash for Savon.
|
12
|
+
def build
|
13
|
+
{ 'Weight' => {'Units' => WEIGHT_UNITS[@model.weight_units],
|
14
|
+
'Value' => @model.weight,
|
15
|
+
:order! => ['Units', 'Value']},
|
16
|
+
'Dimensions' => {'Length' => @model.length,
|
17
|
+
'Width' => @model.width,
|
18
|
+
'Height' => @model.height,
|
19
|
+
'Units' => DIMENSION_UNITS[@model.dimension_units],
|
20
|
+
:order! => ['Length', 'Width', 'Height', 'Units']},
|
21
|
+
:order! => ['Weight', 'Dimensions']}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module SimpleShipping::Fedex
|
2
|
+
# Knows how to convert {Party} model to SOAP element for FedEx.
|
3
|
+
class PartyBuilder < SimpleShipping::Abstract::Builder
|
4
|
+
# Build a SOAP party element as a hash for Savon.
|
5
|
+
def build
|
6
|
+
{'Contact' => build_contact,
|
7
|
+
'Address' => build_address,
|
8
|
+
:order! => ['Contact', 'Address']}
|
9
|
+
end
|
10
|
+
|
11
|
+
# Build the body for a Contact element.
|
12
|
+
#
|
13
|
+
# @return [Hash]
|
14
|
+
def build_contact
|
15
|
+
result = {:order! => []}
|
16
|
+
contact = @model.contact
|
17
|
+
if contact.company_name
|
18
|
+
result['CompanyName'] = contact.company_name
|
19
|
+
result[:order!] << 'CompanyName'
|
20
|
+
end
|
21
|
+
if contact.person_name
|
22
|
+
result['PersonName'] = contact.person_name
|
23
|
+
result[:order!] << 'PersonName'
|
24
|
+
end
|
25
|
+
result['PhoneNumber'] = contact.phone_number
|
26
|
+
result[:order!] << 'PhoneNumber'
|
27
|
+
result
|
28
|
+
end
|
29
|
+
private :build_contact
|
30
|
+
|
31
|
+
# Build body for Address element.
|
32
|
+
#
|
33
|
+
# @return [Hash]
|
34
|
+
def build_address
|
35
|
+
addr = @model.address
|
36
|
+
{'StreetLines' => addr.street_line,
|
37
|
+
'City' => addr.city,
|
38
|
+
'StateOrProvinceCode' => addr.state_code,
|
39
|
+
'PostalCode' => addr.postal_code,
|
40
|
+
'CountryCode' => addr.country_code,
|
41
|
+
:order! => [ 'StreetLines',
|
42
|
+
'City',
|
43
|
+
'StateOrProvinceCode',
|
44
|
+
'PostalCode',
|
45
|
+
'CountryCode' ]
|
46
|
+
}
|
47
|
+
end
|
48
|
+
private :build_address
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module SimpleShipping::Fedex
|
2
|
+
# Builds a complete request for the FedEx service.
|
3
|
+
class Request < SimpleShipping::Abstract::Request
|
4
|
+
extend ActiveSupport::Autoload
|
5
|
+
|
6
|
+
autoload :ShipmentRequest
|
7
|
+
|
8
|
+
def initialize(credentials, shipment)
|
9
|
+
super(credentials)
|
10
|
+
@shipment = shipment
|
11
|
+
end
|
12
|
+
|
13
|
+
# Build a complete request from a {Shipment shipment} object.
|
14
|
+
def body(opts = {})
|
15
|
+
{'WebAuthenticationDetail' => web_authentication_detail,
|
16
|
+
'ClientDetail' => client_detail,
|
17
|
+
'Version' => version,
|
18
|
+
'RequestedShipment' => ShipmentBuilder.build(@shipment, opts),
|
19
|
+
:order! => ['WebAuthenticationDetail', 'ClientDetail', 'Version', 'RequestedShipment'] }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Build the body for the WebAuthenticationDetail element.
|
23
|
+
#
|
24
|
+
# @return [Hash]
|
25
|
+
def web_authentication_detail
|
26
|
+
{ 'UserCredential' => {'Key' => @credentials.key,
|
27
|
+
'Password' => @credentials.password,
|
28
|
+
:order! => ['Key', 'Password']}}
|
29
|
+
end
|
30
|
+
private :web_authentication_detail
|
31
|
+
|
32
|
+
# Build the body for the UserCredential element.
|
33
|
+
#
|
34
|
+
# @return [Hash]
|
35
|
+
def client_detail
|
36
|
+
{'AccountNumber' => @credentials.account_number,
|
37
|
+
'MeterNumber' => @credentials.meter_number,
|
38
|
+
:order! => ['AccountNumber', 'MeterNumber']}
|
39
|
+
end
|
40
|
+
private :client_detail
|
41
|
+
|
42
|
+
# Build the body for the Version element.
|
43
|
+
#
|
44
|
+
# @return [Hash]
|
45
|
+
def version
|
46
|
+
{'ServiceId' => 'ship',
|
47
|
+
'Major' => '10',
|
48
|
+
'Intermediate' => '0',
|
49
|
+
'Minor' => '0',
|
50
|
+
:order! => ['ServiceId', 'Major', 'Intermediate', 'Minor']}
|
51
|
+
end
|
52
|
+
private :version
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module SimpleShipping::Fedex
|
2
|
+
# Builds a shipment element for FedEx SOAP service.
|
3
|
+
class ShipmentBuilder < SimpleShipping::Abstract::Builder
|
4
|
+
# Value for RateRequestTypes XML element.
|
5
|
+
RATE_REQUEST_TYPE = 'ACCOUNT'
|
6
|
+
|
7
|
+
# Number of packages.
|
8
|
+
PACKAGE_COUNT = '1'
|
9
|
+
|
10
|
+
# Mapping for package types
|
11
|
+
PACKAGING_TYPES = {
|
12
|
+
:box_10kg => 'FEDEX_10KG_BOX',
|
13
|
+
:box_25kg => 'FEDEX_25KG_BOX',
|
14
|
+
:box => 'FEDEX_BOX',
|
15
|
+
:envelope => 'FEDEX_ENVELOPE',
|
16
|
+
:pak => 'FEDEX_PAK',
|
17
|
+
:tube => 'FEDEX_TUBE',
|
18
|
+
:your => 'YOUR_PACKAGING'
|
19
|
+
}
|
20
|
+
|
21
|
+
# Mapping for service types
|
22
|
+
SERVICE_TYPES = {
|
23
|
+
:europe_first_international_priority => 'EUROPE_FIRST_INTERNATIONAL_PRIORITY',
|
24
|
+
:fedex_1_day_freight => 'FEDEX_1_DAY_FREIGHT',
|
25
|
+
:fedex_2_day_am => 'FEDEX_2_DAY',
|
26
|
+
:fedex_2_day_freight => 'FEDEX_2_DAY_AM',
|
27
|
+
:fedex_3_day_freight => 'FEDEX_2_DAY_FREIGHT',
|
28
|
+
:fedex_3_day_freight => 'FEDEX_3_DAY_FREIGHT',
|
29
|
+
:fedex_express_saver => 'FEDEX_EXPRESS_SAVER',
|
30
|
+
:fedex_freight_economy => 'FEDEX_FIRST_FREIGHT',
|
31
|
+
:fedex_freight_economy => 'FEDEX_FREIGHT_ECONOMY',
|
32
|
+
:fedex_freight_priority => 'FEDEX_FREIGHT_PRIORITY',
|
33
|
+
:fedex_ground => 'FEDEX_GROUND',
|
34
|
+
:first_overnight => 'FIRST_OVERNIGHT',
|
35
|
+
:ground_home_delivery => 'GROUND_HOME_DELIVERY',
|
36
|
+
:international_economy => 'INTERNATIONAL_ECONOMY',
|
37
|
+
:international_economy_freight => 'INTERNATIONAL_ECONOMY_FREIGHT',
|
38
|
+
:international_first => 'INTERNATIONAL_FIRST',
|
39
|
+
:international_priority => 'INTERNATIONAL_PRIORITY',
|
40
|
+
:international_priority_freight => 'INTERNATIONAL_PRIORITY_FREIGHT',
|
41
|
+
:priority_overnight => 'PRIORITY_OVERNIGHT',
|
42
|
+
:smart_post => 'SMART_POST',
|
43
|
+
:standard_overnight => 'STANDARD_OVERNIGHT'
|
44
|
+
}
|
45
|
+
|
46
|
+
# Mapping for dropoff types.
|
47
|
+
DROPOFF_TYPES = {
|
48
|
+
:business_service_center => 'BUSINESS_SERVICE_CENTER',
|
49
|
+
:drop_box => 'DROP_BOX',
|
50
|
+
:regular_pickup => 'REGULAR_PICKUP',
|
51
|
+
:request_courier => 'REQUEST_COURIER',
|
52
|
+
:station => 'STATION'
|
53
|
+
}
|
54
|
+
|
55
|
+
set_default_opts :dropoff_type => :business_service_center,
|
56
|
+
:service_type => :fedex_ground
|
57
|
+
|
58
|
+
# Build the shipment representation as a hash for the Savon client.
|
59
|
+
def build
|
60
|
+
{'ShipTimestamp' => ship_timestamp,
|
61
|
+
'DropoffType' => DROPOFF_TYPES[@opts[:dropoff_type]],
|
62
|
+
'ServiceType' => SERVICE_TYPES[@opts[:service_type]],
|
63
|
+
'PackagingType' => PACKAGING_TYPES[@model.package.packaging_type],
|
64
|
+
'Shipper' => PartyBuilder.build(@model.shipper),
|
65
|
+
'Recipient' => PartyBuilder.build(@model.recipient),
|
66
|
+
'ShippingChargesPayment' => shipping_charges_payment,
|
67
|
+
'LabelSpecification' => label_specification,
|
68
|
+
'RateRequestTypes' => RATE_REQUEST_TYPE,
|
69
|
+
'PackageCount' => PACKAGE_COUNT,
|
70
|
+
'RequestedPackageLineItems' => PackageBuilder.build(@model.package),
|
71
|
+
:order! => ['ShipTimestamp' , 'DropoffType' , 'ServiceType' , 'PackagingType',
|
72
|
+
'Shipper' , 'Recipient' , 'ShippingChargesPayment', 'LabelSpecification',
|
73
|
+
'RateRequestTypes', 'PackageCount' , 'RequestedPackageLineItems']
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
# Perform validations.
|
78
|
+
def validate
|
79
|
+
validate_inclusion_of(:dropoff_type , DROPOFF_TYPES)
|
80
|
+
validate_inclusion_of(:service_type , SERVICE_TYPES)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get the shipping timestamps in a specific format.
|
84
|
+
#
|
85
|
+
# @example
|
86
|
+
# ship_timestamp # => "2014-01-08T14:41:53+02:00"
|
87
|
+
#
|
88
|
+
# @return [String]
|
89
|
+
def ship_timestamp
|
90
|
+
Time.new.strftime('%Y-%m-%dT%H:%M:%S%z').tap{|str| str[-2,0] = ':' }
|
91
|
+
end
|
92
|
+
private :ship_timestamp
|
93
|
+
|
94
|
+
# Build the hash for the ShippingChargesPayment element.
|
95
|
+
#
|
96
|
+
# @return [Hash]
|
97
|
+
def shipping_charges_payment
|
98
|
+
{'PaymentType' => payment_type,
|
99
|
+
'Payor' => {'AccountNumber' => @model.payor_account_number},
|
100
|
+
:order! => ['PaymentType', 'Payor']}
|
101
|
+
end
|
102
|
+
private :shipping_charges_payment
|
103
|
+
|
104
|
+
# Get the payment type.
|
105
|
+
#
|
106
|
+
# @return [String]
|
107
|
+
def payment_type
|
108
|
+
(@model.payor == :shipper) ? 'SENDER' : 'RECIPIENT'
|
109
|
+
end
|
110
|
+
private :payment_type
|
111
|
+
|
112
|
+
# Build the label parameters according to FedEx's API.
|
113
|
+
#
|
114
|
+
# @return [Hash]
|
115
|
+
def label_specification
|
116
|
+
{ 'LabelFormatType' => 'COMMON2D',
|
117
|
+
'ImageType' => 'PNG',
|
118
|
+
'LabelStockType' => 'PAPER_4X6',
|
119
|
+
:order! => ['LabelFormatType', 'ImageType', 'LabelStockType'] }
|
120
|
+
end
|
121
|
+
private :label_specification
|
122
|
+
end
|
123
|
+
end
|