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,14 @@
|
|
1
|
+
module SimpleShipping::Fedex
|
2
|
+
# The model that represents shipment request to FedEx.
|
3
|
+
class ShipmentRequest < Request
|
4
|
+
def initialize(credentials, shipment)
|
5
|
+
super
|
6
|
+
@type = :process_shipment
|
7
|
+
end
|
8
|
+
|
9
|
+
# :nodoc:
|
10
|
+
def response_class
|
11
|
+
ShipmentResponse
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module SimpleShipping::Fedex
|
2
|
+
# A wrapper for UPS ShipmentResponse.
|
3
|
+
class ShipmentResponse < Response
|
4
|
+
# Get the label as abstract64 encoded data
|
5
|
+
# response.label_image_base64 # => "odGqk/KmgLaawV..."
|
6
|
+
# This can be used directly in an HTML image tag with
|
7
|
+
# src="data:image/gif;base64,..."
|
8
|
+
def label_image_base64
|
9
|
+
value_of(:process_shipment_reply, :completed_shipment_detail, :completed_package_details, :label, :parts, :image)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SimpleShipping
|
2
|
+
# Represents a package which should be sent from {SimpleShipping::Party shipper}
|
3
|
+
# to {SimpleShipping::Party recipient}.
|
4
|
+
#
|
5
|
+
# == Attributes:
|
6
|
+
# * _dimenstion_units_ (:in, :cm). Default is :in.
|
7
|
+
# * _weight_units_ (:kg, :lb). Default is :lb.
|
8
|
+
# * _legth_ (in dimension units)
|
9
|
+
# * _width_ (in dimension units)
|
10
|
+
# * _height_ (in dimension units)
|
11
|
+
# * _weight_ (in weight units)
|
12
|
+
# * _packaging_type_
|
13
|
+
#
|
14
|
+
# == Packaging type values:
|
15
|
+
# * :envelope
|
16
|
+
# * :your
|
17
|
+
# * :tube
|
18
|
+
# * :pak
|
19
|
+
# * :box
|
20
|
+
# * :box_10kg
|
21
|
+
# * :box_25kg
|
22
|
+
class Package < Abstract::Model
|
23
|
+
attr_accessor :length, :width, :height, :dimension_units
|
24
|
+
attr_accessor :weight, :weight_units, :packaging_type
|
25
|
+
attr_accessor :insured_value, :declared_value
|
26
|
+
|
27
|
+
validates_presence_of :length, :width, :height, :dimension_units, :if => :custom_package?
|
28
|
+
validates_presence_of :weight, :weight_units
|
29
|
+
|
30
|
+
validates_inclusion_of :weight_units , :in => [:kg, :lb]
|
31
|
+
validates_inclusion_of :dimension_units, :in => [:in, :cm], :if => :custom_package?
|
32
|
+
validates_inclusion_of :packaging_type , :in => [:envelope, :pak, :tube, :your, :box, :box_10kg, :box_25kg]
|
33
|
+
|
34
|
+
set_default_values :packaging_type => :your,
|
35
|
+
:weight_units => :lb,
|
36
|
+
:dimension_units => :in
|
37
|
+
|
38
|
+
# Whether the package is a custom package.
|
39
|
+
def custom_package?
|
40
|
+
packaging_type == :your
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SimpleShipping
|
2
|
+
# Party is a person or company who takes a part in shipment process.
|
3
|
+
# Party is used to represent a shipper or a recipient.
|
4
|
+
#
|
5
|
+
# == Attributes
|
6
|
+
# * _contact_ (instance of {SimpleShipping::Contact})
|
7
|
+
# * _address_ (instance of {SimpleShipping::Address})
|
8
|
+
# * _account_number_ (optional, but in some cases required)
|
9
|
+
#
|
10
|
+
# If one of attributes is missed an appropriate exception will be raised
|
11
|
+
# when you build a request.
|
12
|
+
class Party < Abstract::Model
|
13
|
+
attr_accessor :contact,
|
14
|
+
:address,
|
15
|
+
:account_number
|
16
|
+
|
17
|
+
validates_presence_of :contact, :address
|
18
|
+
validates_submodel :address, :as => SimpleShipping::Address
|
19
|
+
validates_submodel :contact, :as => SimpleShipping::Contact
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module SimpleShipping
|
2
|
+
# Represents a shipment.
|
3
|
+
#
|
4
|
+
# == Attributes:
|
5
|
+
# * _shipper_ (an instance of {SimpleShipping::Party}
|
6
|
+
# * _recipient_ (an instance of {SimpleShipping::Party}
|
7
|
+
# * _package_ (an instance of {SimpleShipping::Package}
|
8
|
+
# * _payor_ (:shipper, :recipient). Default value is :shipper
|
9
|
+
class Shipment < Abstract::Model
|
10
|
+
attr_accessor :shipper,
|
11
|
+
:recipient,
|
12
|
+
:package,
|
13
|
+
:payor
|
14
|
+
|
15
|
+
set_default_values :payor => :shipper
|
16
|
+
|
17
|
+
validates_presence_of :shipper, :recipient, :package, :payor
|
18
|
+
validates_inclusion_of :payor, :in => [:shipper, :recipient]
|
19
|
+
validates_submodel :shipper , :as => SimpleShipping::Party
|
20
|
+
validates_submodel :recipient, :as => SimpleShipping::Party
|
21
|
+
validates_submodel :package , :as => SimpleShipping::Package
|
22
|
+
validate :validate_payor_account_number
|
23
|
+
|
24
|
+
# Account number of payor.
|
25
|
+
def payor_account_number
|
26
|
+
case payor
|
27
|
+
when :shipper
|
28
|
+
shipper.account_number if shipper.respond_to?(:account_number)
|
29
|
+
when :recipient
|
30
|
+
recipient.account_number if recipient.respond_to?(:account_number)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Validate presence of payor account number.
|
35
|
+
#
|
36
|
+
# @return [void]
|
37
|
+
def validate_payor_account_number
|
38
|
+
errors.add(:abstract, "Payor account number is missing") unless payor_account_number
|
39
|
+
end
|
40
|
+
private :validate_payor_account_number
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Namespace for UPS provider.
|
2
|
+
module SimpleShipping::Ups
|
3
|
+
extend ActiveSupport::Autoload
|
4
|
+
|
5
|
+
autoload :Client
|
6
|
+
autoload :ShipClient
|
7
|
+
autoload :VoidClient
|
8
|
+
|
9
|
+
autoload :Request
|
10
|
+
autoload :Response
|
11
|
+
autoload :PackageBuilder
|
12
|
+
autoload :PartyBuilder
|
13
|
+
autoload :ShipmentBuilder
|
14
|
+
|
15
|
+
autoload :ShipConfirmResponse
|
16
|
+
autoload :ShipAcceptResponse
|
17
|
+
autoload :ShipmentResponse
|
18
|
+
autoload :VoidResponse
|
19
|
+
|
20
|
+
autoload :ShipConfirmRequest
|
21
|
+
autoload :ShipAcceptRequest
|
22
|
+
autoload :ShipmentRequest
|
23
|
+
autoload :VoidRequest
|
24
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module SimpleShipping::Ups
|
2
|
+
# Abstract class for all UPS clients.
|
3
|
+
# The problem with UPS is that its WSDL imports schemas. However schema imports are not supported
|
4
|
+
# by Savon as by v.2.1.0. See: https://github.com/savonrb/wasabi/issues/1
|
5
|
+
# Because of this we have to manually:
|
6
|
+
# 1. Assign additional namespaces
|
7
|
+
# 2. Switch to :qualified :elemen_form_default
|
8
|
+
# (to have all requests elements prepended with namespace
|
9
|
+
# if its namespace is not specified explicitly)
|
10
|
+
# 3. Explicitly prepend namespace to all elements which not belong to WSDL target namespace
|
11
|
+
# i.e. UPSSecurity, Request/RequestOptions etc
|
12
|
+
#
|
13
|
+
class Client < SimpleShipping::Abstract::Client
|
14
|
+
|
15
|
+
# @param [Hash] options Savon client options
|
16
|
+
def client_options(options = {})
|
17
|
+
super.deep_merge(
|
18
|
+
:element_form_default => :qualified,
|
19
|
+
:namespaces => {
|
20
|
+
'xmlns:upss' => "http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0",
|
21
|
+
'xmlns:common' => "http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0",
|
22
|
+
},
|
23
|
+
:soap_header => soap_header
|
24
|
+
)
|
25
|
+
end
|
26
|
+
protected :client_options
|
27
|
+
|
28
|
+
# @return [Hash] of SOAP envelope header contents
|
29
|
+
def soap_header
|
30
|
+
{
|
31
|
+
'upss:UPSSecurity' => {
|
32
|
+
'upss:UsernameToken' => {
|
33
|
+
'upss:Username' => @credentials.username,
|
34
|
+
'upss:Password' => @credentials.password,
|
35
|
+
:order! => ['upss:Username', 'upss:Password']
|
36
|
+
},
|
37
|
+
'upss:ServiceAccessToken' => {
|
38
|
+
'upss:AccessLicenseNumber' => @credentials.access_license_number
|
39
|
+
},
|
40
|
+
:order! => ['upss:UsernameToken', 'upss:ServiceAccessToken']
|
41
|
+
}
|
42
|
+
}
|
43
|
+
end
|
44
|
+
protected :soap_header
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# Builds hash for Savon which represents {Package package}.
|
2
|
+
module SimpleShipping::Ups
|
3
|
+
# Builds hash structure for Savon that represents package element in UPS's API.
|
4
|
+
class PackageBuilder < SimpleShipping::Abstract::Builder
|
5
|
+
# Mapping for UPS packaging types
|
6
|
+
# Not all UPS values listed here in order to provide common interface with FedEx.
|
7
|
+
PACKAGING_TYPES = {
|
8
|
+
:envelope => '01', # letter
|
9
|
+
:your => '02', # customer supplied
|
10
|
+
:tube => '03', # tube
|
11
|
+
:pak => '04', # UPS Packaging
|
12
|
+
:box => '2b', # medium box
|
13
|
+
:box_10kg => '25',
|
14
|
+
:box_10kg => '24'
|
15
|
+
}
|
16
|
+
|
17
|
+
# Mapping for UPS weight units.
|
18
|
+
WEIGHT_UNITS = {
|
19
|
+
:kg => 'KGS',
|
20
|
+
:lb => 'LBS'
|
21
|
+
}
|
22
|
+
|
23
|
+
# Mapping for UPS dimension units.
|
24
|
+
DIMENSION_UNITS = {
|
25
|
+
:in => 'IN',
|
26
|
+
:cm => 'CM'
|
27
|
+
}
|
28
|
+
|
29
|
+
# Custom package order.
|
30
|
+
CUSTOM_PACKAGE_ORDER = %w(Packaging PackageServiceOptions Dimensions PackageWeight)
|
31
|
+
|
32
|
+
# Standard package order.
|
33
|
+
STANDARD_PACKAGE_ORDER = %w(Packaging PackageServiceOptions PackageWeight)
|
34
|
+
|
35
|
+
# Build basic skeleton for package element. It can be customized by
|
36
|
+
# overriding some subelements.
|
37
|
+
#
|
38
|
+
# @return [Hash]
|
39
|
+
def base_package
|
40
|
+
base = {
|
41
|
+
'Packaging' => {
|
42
|
+
'Code' => PACKAGING_TYPES[@model.packaging_type]
|
43
|
+
},
|
44
|
+
'PackageWeight' => {
|
45
|
+
'UnitOfMeasurement' => {
|
46
|
+
'Code' => WEIGHT_UNITS[@model.weight_units]
|
47
|
+
},
|
48
|
+
'Weight' => @model.weight,
|
49
|
+
:order! => ['UnitOfMeasurement', 'Weight']
|
50
|
+
},
|
51
|
+
'PackageServiceOptions' => {}
|
52
|
+
}
|
53
|
+
|
54
|
+
if @model.insured_value
|
55
|
+
base['PackageServiceOptions']['InsuredValue'] = {
|
56
|
+
'CurrencyCode' => 'USD',
|
57
|
+
'MonetaryValue' => @model.insured_value
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
if @model.declared_value
|
62
|
+
base['PackageServiceOptions']['DeclaredValue'] = {
|
63
|
+
'CurrencyCode' => 'USD',
|
64
|
+
'MonetaryValue' => @model.declared_value
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
base
|
69
|
+
end
|
70
|
+
|
71
|
+
# Build a hash from a custom {Package package} which will be used by Savon.
|
72
|
+
# A custom package requires specification of LWH dimensions.
|
73
|
+
def custom_package
|
74
|
+
base_package.tap do |package|
|
75
|
+
package['Dimensions'] = {
|
76
|
+
'UnitOfMeasurement' => {
|
77
|
+
'Code' => DIMENSION_UNITS[@model.dimension_units].clone
|
78
|
+
},
|
79
|
+
'Length' => @model.length,
|
80
|
+
'Width' => @model.width,
|
81
|
+
'Height' => @model.height,
|
82
|
+
:order! => ['UnitOfMeasurement', 'Length', 'Width', 'Height']
|
83
|
+
}
|
84
|
+
package[:order!] = CUSTOM_PACKAGE_ORDER.clone
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Build a hash from a standard {Package package} which will be used by Savon.
|
89
|
+
# A standard package requires no specification of LWH dimensions.
|
90
|
+
def standard_package
|
91
|
+
base_package.tap do |package|
|
92
|
+
package[:order!] = STANDARD_PACKAGE_ORDER.clone
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Build the package, whether custom or standard.
|
97
|
+
def build
|
98
|
+
@model.custom_package? ? custom_package : standard_package
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module SimpleShipping::Ups
|
2
|
+
# Knows how to convert {Party} model to SOAP element for UPS.
|
3
|
+
class PartyBuilder < SimpleShipping::Abstract::Builder
|
4
|
+
# Builds a hash for Savon which represents {Party party}.
|
5
|
+
def build
|
6
|
+
contact = @model.contact
|
7
|
+
{'Name' => (contact.person_name || contact.company_name),
|
8
|
+
'Phone' => {'Number' => contact.phone_number},
|
9
|
+
'ShipperNumber' => @model.account_number,
|
10
|
+
'Address' => build_address,
|
11
|
+
:order! => ['Name', 'Phone', 'ShipperNumber', 'Address']
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Build address element.
|
16
|
+
#
|
17
|
+
# @return [Hash]
|
18
|
+
def build_address
|
19
|
+
addr = @model.address
|
20
|
+
{'AddressLine' => [addr.street_line, addr.street_line_2, addr.street_line_3].compact,
|
21
|
+
'City' => addr.city,
|
22
|
+
'StateProvinceCode' => addr.state_code,
|
23
|
+
'PostalCode' => addr.postal_code,
|
24
|
+
'CountryCode' => addr.country_code,
|
25
|
+
:order! => ['AddressLine', 'City', 'StateProvinceCode', 'PostalCode', 'CountryCode']
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
# Validate presence of account_number.
|
30
|
+
#
|
31
|
+
# @return [void]
|
32
|
+
def validate
|
33
|
+
if @opts[:shipper] && !@model.account_number
|
34
|
+
raise SimpleShipping::ValidationError.new("account_number is required for party who is shipper")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SimpleShipping::Ups
|
2
|
+
# Builds complete request for UPS
|
3
|
+
class Request < SimpleShipping::Abstract::Request
|
4
|
+
# Value for <common:RequestOption> XML element in request.
|
5
|
+
REQUEST_OPTION = 'nonvalidate'
|
6
|
+
|
7
|
+
# Define label parameters according to UPS's API.
|
8
|
+
#
|
9
|
+
# @return [Hash]
|
10
|
+
def label_specification
|
11
|
+
{ 'LabelImageFormat' => {'Code' => 'GIF'},
|
12
|
+
'LabelStockSize' => {
|
13
|
+
'Height' => '6',
|
14
|
+
'Width' => '4',
|
15
|
+
:order! => ['Height', 'Width']
|
16
|
+
},
|
17
|
+
:order! => ['LabelImageFormat', 'LabelStockSize']
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
# The class of the response in the same name space.
|
22
|
+
def response_class
|
23
|
+
self.class.name.sub(/Request/, 'Response').constantize
|
24
|
+
end
|
25
|
+
private :response_class
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module SimpleShipping::Ups
|
2
|
+
# Response from UPS.
|
3
|
+
class Response < SimpleShipping::Abstract::Response
|
4
|
+
# Digest what can be used to get a label.
|
5
|
+
#
|
6
|
+
# @return [String]
|
7
|
+
def digest
|
8
|
+
value_of(:shipment_results, :shipment_digest)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Unique shipment ID returned by UPS.
|
12
|
+
#
|
13
|
+
# @return [Strig]
|
14
|
+
def shipment_identification_number
|
15
|
+
value_of(:shipment_results, :shipment_identification_number)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get package tracking number to look for delivery process on UPS site.
|
19
|
+
#
|
20
|
+
# @return [String] tracking number
|
21
|
+
def tracking_number
|
22
|
+
value_of(:shipment_results, :package_results, :tracking_number)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get the label as base64 encoded data
|
26
|
+
# response.label_image_base64 # => "odGqk/KmgLaawV..."
|
27
|
+
# This can be used directly in an HTML image tag with
|
28
|
+
# src="data:image/gif;base64,..."
|
29
|
+
def label_image_base64
|
30
|
+
value_of(:shipment_results, :package_results, :shipping_label, :graphic_image)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Label image.
|
34
|
+
#
|
35
|
+
# @return [String] binary
|
36
|
+
def label_html
|
37
|
+
value = value_of(:shipment_results, :package_results, :shipping_label, :html_image)
|
38
|
+
Base64.decode64(value) if value
|
39
|
+
end
|
40
|
+
|
41
|
+
# Receipt.
|
42
|
+
#
|
43
|
+
# @return [String] binary
|
44
|
+
def receipt_html
|
45
|
+
value = value_of(:shipment_results, :control_log_receipt, :graphic_image)
|
46
|
+
Base64.decode64(value) if value
|
47
|
+
end
|
48
|
+
|
49
|
+
# Fetch the value of an XML attribute at the path specified as an array
|
50
|
+
# of node names but appends the implicit namespace on to the front of the
|
51
|
+
# path.
|
52
|
+
def value_of(*path)
|
53
|
+
super(*path.unshift(name_token))
|
54
|
+
end
|
55
|
+
|
56
|
+
# All UPS requests are namespaced within the same name of the class by
|
57
|
+
# convention.
|
58
|
+
def name_token
|
59
|
+
self.class.name.split('::').last.underscore.to_sym
|
60
|
+
end
|
61
|
+
private :name_token
|
62
|
+
end
|
63
|
+
end
|