ups-ruby 0.8.3
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 +22 -0
- data/.hound.yml +2 -0
- data/.rubocop.yml +1064 -0
- data/.travis.yml +10 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +46 -0
- data/LICENSE.txt +14 -0
- data/README.md +78 -0
- data/Rakefile +17 -0
- data/lib/ups-ruby.rb +2 -0
- data/lib/ups.rb +33 -0
- data/lib/ups/builders/address_builder.rb +135 -0
- data/lib/ups/builders/builder_base.rb +216 -0
- data/lib/ups/builders/organisation_builder.rb +74 -0
- data/lib/ups/builders/rate_builder.rb +21 -0
- data/lib/ups/builders/ship_accept_builder.rb +30 -0
- data/lib/ups/builders/ship_confirm_builder.rb +103 -0
- data/lib/ups/builders/shipper_builder.rb +88 -0
- data/lib/ups/connection.rb +124 -0
- data/lib/ups/data.rb +50 -0
- data/lib/ups/data/canadian_states.rb +21 -0
- data/lib/ups/data/ie_counties.rb +10 -0
- data/lib/ups/data/ie_county_prefixes.rb +15 -0
- data/lib/ups/data/us_states.rb +59 -0
- data/lib/ups/exceptions.rb +7 -0
- data/lib/ups/packaging.rb +27 -0
- data/lib/ups/parsers/parser_base.rb +48 -0
- data/lib/ups/parsers/rates_parser.rb +60 -0
- data/lib/ups/parsers/ship_accept_parser.rb +52 -0
- data/lib/ups/parsers/ship_confirm_parser.rb +16 -0
- data/lib/ups/services.rb +21 -0
- data/lib/ups/version.rb +10 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/stubs/rates_negotiated_success.xml +227 -0
- data/spec/stubs/rates_success.xml +196 -0
- data/spec/stubs/ship_accept_failure.xml +12 -0
- data/spec/stubs/ship_accept_success.xml +56 -0
- data/spec/stubs/ship_confirm_failure.xml +12 -0
- data/spec/stubs/ship_confirm_success.xml +50 -0
- data/spec/support/RateRequest.xsd +1 -0
- data/spec/support/ShipAcceptRequest.xsd +36 -0
- data/spec/support/ShipConfirmRequest.xsd +996 -0
- data/spec/support/schema_path.rb +5 -0
- data/spec/support/shipping_options.rb +48 -0
- data/spec/support/xsd_validator.rb +11 -0
- data/spec/ups/builders/address_builder_spec.rb +97 -0
- data/spec/ups/builders/rate_builder_spec.rb +20 -0
- data/spec/ups/builders/ship_accept_builder_spec.rb +16 -0
- data/spec/ups/builders/ship_confirm_builder_spec.rb +23 -0
- data/spec/ups/connection/rates_negotiated_spec.rb +69 -0
- data/spec/ups/connection/rates_standard_spec.rb +71 -0
- data/spec/ups/connection/ship_spec.rb +111 -0
- data/spec/ups/connection_spec.rb +20 -0
- data/ups.gemspec +24 -0
- metadata +166 -0
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ups-ruby (0.8.3)
|
5
|
+
excon (~> 0.45, >= 0.45.3)
|
6
|
+
insensitive_hash (~> 0.3.3)
|
7
|
+
levenshtein-ffi (~> 1.1)
|
8
|
+
ox (~> 2.2, >= 2.2.0)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: http://rubygems.org/
|
12
|
+
specs:
|
13
|
+
codeclimate-test-reporter (1.0.5)
|
14
|
+
simplecov
|
15
|
+
docile (1.1.5)
|
16
|
+
excon (0.54.0)
|
17
|
+
ffi (1.9.14)
|
18
|
+
insensitive_hash (0.3.3)
|
19
|
+
json (1.8.3)
|
20
|
+
levenshtein-ffi (1.1.0)
|
21
|
+
ffi (~> 1.9)
|
22
|
+
mini_portile (0.6.2)
|
23
|
+
minitest (5.7.0)
|
24
|
+
nokogiri (1.6.6.2)
|
25
|
+
mini_portile (~> 0.6.0)
|
26
|
+
ox (2.4.9)
|
27
|
+
rake (12.0.0)
|
28
|
+
simplecov (0.10.0)
|
29
|
+
docile (~> 1.1.0)
|
30
|
+
json (~> 1.8)
|
31
|
+
simplecov-html (~> 0.10.0)
|
32
|
+
simplecov-html (0.10.0)
|
33
|
+
|
34
|
+
PLATFORMS
|
35
|
+
ruby
|
36
|
+
|
37
|
+
DEPENDENCIES
|
38
|
+
codeclimate-test-reporter (~> 1.0.0)
|
39
|
+
minitest
|
40
|
+
nokogiri
|
41
|
+
rake
|
42
|
+
simplecov
|
43
|
+
ups-ruby!
|
44
|
+
|
45
|
+
BUNDLED WITH
|
46
|
+
1.13.6
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Copyright (c) 2017 Paul Trippett and Veeqo Ltd
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU Affero General Public License as
|
5
|
+
published by the Free Software Foundation, either version 3 of the
|
6
|
+
License, or (at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU Affero General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU Affero General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
[](http://badge.fury.io/rb/ups)
|
2
|
+
[](https://gemnasium.com/ptrippett/ups)
|
3
|
+
[](https://travis-ci.org/ptrippett/ups)
|
4
|
+
[](https://codeclimate.com/github/ptrippett/ups/coverage)
|
5
|
+
[](https://codeclimate.com/github/ptrippett/ups)
|
6
|
+
|
7
|
+
# UPS
|
8
|
+
|
9
|
+
UPS Gem for accessing the UPS API from Ruby. Using the gem you can:
|
10
|
+
- Return quotes from the UPS API
|
11
|
+
- Book shipments
|
12
|
+
- Return labels and tracking numbers for a shipment
|
13
|
+
|
14
|
+
This gem is currently used in production at [Veeqo](http://www.veeqo.com)
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
gem install ups-ruby
|
19
|
+
|
20
|
+
...or add it to your project's [Gemfile](http://bundler.io/).
|
21
|
+
|
22
|
+
## Documentation
|
23
|
+
|
24
|
+
Yard documentation can be found at [RubyDoc](http://www.rubydoc.info/github/ptrippett/ups).
|
25
|
+
|
26
|
+
## Sample Usage
|
27
|
+
|
28
|
+
### Return rates
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'ups'
|
32
|
+
server = UPS::Connection.new(test_mode: true)
|
33
|
+
response = server.rates do |rate_builder|
|
34
|
+
rate_builder.add_access_request 'API_KEY', 'USERNAME', 'PASSWORD'
|
35
|
+
rate_builder.add_shipper company_name: 'Veeqo Limited',
|
36
|
+
phone_number: '01792 123456',
|
37
|
+
address_line_1: '11 Wind Street',
|
38
|
+
city: 'Swansea',
|
39
|
+
state: 'Wales',
|
40
|
+
postal_code: 'SA1 1DA',
|
41
|
+
country: 'GB',
|
42
|
+
shipper_number: 'ACCOUNT_NUMBER'
|
43
|
+
rate_builder.add_ship_from company_name: 'Veeqo Limited',
|
44
|
+
phone_number: '01792 123456',
|
45
|
+
address_line_1: '11 Wind Street',
|
46
|
+
city: 'Swansea',
|
47
|
+
state: 'Wales',
|
48
|
+
postal_code: 'SA1 1DA',
|
49
|
+
country: 'GB',
|
50
|
+
shipper_number: ENV['UPS_ACCOUNT_NUMBER']
|
51
|
+
rate_builder.add_ship_to company_name: 'Google Inc.',
|
52
|
+
phone_number: '0207 031 3000',
|
53
|
+
address_line_1: '1 St Giles High Street',
|
54
|
+
city: 'London',
|
55
|
+
state: 'England',
|
56
|
+
postal_code: 'WC2H 8AG',
|
57
|
+
country: 'GB'
|
58
|
+
rate_builder.add_package weight: '0.5',
|
59
|
+
unit: 'KGS'
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
# Then use...
|
65
|
+
response.success?
|
66
|
+
response.graphic_image
|
67
|
+
response.tracking_number
|
68
|
+
```
|
69
|
+
|
70
|
+
## Running the tests
|
71
|
+
|
72
|
+
After installing dependencies with `bundle install`, you can run the unit tests using `rake`.
|
73
|
+
|
74
|
+
## Contributers
|
75
|
+
|
76
|
+
Thanks to the following contributers to this project.
|
77
|
+
|
78
|
+
- [CJ](https://github.com/chirag7jain) - Method to generate labels in available other formats [EPL, ZPL], Constant for packaging type.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.setup
|
3
|
+
Bundler::GemHelper.install_tasks
|
4
|
+
|
5
|
+
require 'rake'
|
6
|
+
require 'rake/testtask'
|
7
|
+
|
8
|
+
Rake::TestTask.new do |t|
|
9
|
+
t.pattern = 'spec/**/*_spec.rb'
|
10
|
+
t.libs.push 'spec'
|
11
|
+
end
|
12
|
+
|
13
|
+
task default: :test
|
14
|
+
|
15
|
+
task :console do
|
16
|
+
exec 'irb -r ups -I ./lib'
|
17
|
+
end
|
data/lib/ups-ruby.rb
ADDED
data/lib/ups.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module UPS
|
2
|
+
autoload :SERVICES, 'ups/services'
|
3
|
+
autoload :PACKAGING, 'ups/packaging'
|
4
|
+
|
5
|
+
autoload :Version, 'ups/version'
|
6
|
+
autoload :Connection, 'ups/connection'
|
7
|
+
autoload :Exceptions, 'ups/exceptions'
|
8
|
+
|
9
|
+
autoload :Data, 'ups/data'
|
10
|
+
module Data
|
11
|
+
autoload :US_STATES, 'ups/data/us_states'
|
12
|
+
autoload :CANADIAN_STATES, 'ups/data/canadian_states'
|
13
|
+
autoload :IE_COUNTIES, 'ups/data/ie_counties'
|
14
|
+
autoload :IE_COUNTY_PREFIXES, 'ups/data/ie_county_prefixes'
|
15
|
+
end
|
16
|
+
|
17
|
+
module Parsers
|
18
|
+
autoload :ParserBase, 'ups/parsers/parser_base'
|
19
|
+
autoload :RatesParser, 'ups/parsers/rates_parser'
|
20
|
+
autoload :ShipConfirmParser, 'ups/parsers/ship_confirm_parser'
|
21
|
+
autoload :ShipAcceptParser, 'ups/parsers/ship_accept_parser'
|
22
|
+
end
|
23
|
+
|
24
|
+
module Builders
|
25
|
+
autoload :BuilderBase, 'ups/builders/builder_base'
|
26
|
+
autoload :RateBuilder, 'ups/builders/rate_builder'
|
27
|
+
autoload :AddressBuilder, 'ups/builders/address_builder'
|
28
|
+
autoload :ShipConfirmBuilder, 'ups/builders/ship_confirm_builder'
|
29
|
+
autoload :ShipAcceptBuilder, 'ups/builders/ship_accept_builder'
|
30
|
+
autoload :OrganisationBuilder, 'ups/builders/organisation_builder'
|
31
|
+
autoload :ShipperBuilder, 'ups/builders/shipper_builder'
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'ox'
|
2
|
+
|
3
|
+
module UPS
|
4
|
+
module Builders
|
5
|
+
# The {AddressBuilder} class builds UPS XML Address Objects.
|
6
|
+
#
|
7
|
+
# @author Paul Trippett
|
8
|
+
# @since 0.1.0
|
9
|
+
# @attr [Hash] opts The Address Parts
|
10
|
+
class AddressBuilder < BuilderBase
|
11
|
+
include Ox
|
12
|
+
|
13
|
+
attr_accessor :opts
|
14
|
+
|
15
|
+
# Initializes a new {AddressBuilder} object
|
16
|
+
#
|
17
|
+
# @param [Hash] opts The Address Parts
|
18
|
+
# @option opts [String] :address_line_1 Address Line 1
|
19
|
+
# @option opts [String] :city City
|
20
|
+
# @option opts [String] :state State
|
21
|
+
# @option opts [String] :postal_code Zip or Postal Code
|
22
|
+
# @option opts [String] :country Country
|
23
|
+
# @raise [InvalidAttributeError] If the passed :state is nil or an
|
24
|
+
# empty string and the :country is IE
|
25
|
+
def initialize(opts = {})
|
26
|
+
self.opts = opts
|
27
|
+
validate
|
28
|
+
end
|
29
|
+
|
30
|
+
# Changes :state part of the address based on UPS requirements
|
31
|
+
#
|
32
|
+
# @raise [InvalidAttributeError] If the passed :state is nil or an
|
33
|
+
# empty string and the :country is IE
|
34
|
+
# @return [void]
|
35
|
+
def validate
|
36
|
+
opts[:state] = case opts[:country].downcase
|
37
|
+
when 'us'
|
38
|
+
normalize_us_state(opts[:state])
|
39
|
+
when 'ca'
|
40
|
+
normalize_ca_state(opts[:state])
|
41
|
+
when 'ie'
|
42
|
+
UPS::Data.ie_state_matcher(opts[:state])
|
43
|
+
else
|
44
|
+
''
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Changes :state based on UPS requirements for US Addresses
|
49
|
+
#
|
50
|
+
# @param [String] state The US State to normalize
|
51
|
+
# @return [String]
|
52
|
+
def normalize_us_state(state)
|
53
|
+
if state.to_str.length > 2
|
54
|
+
UPS::Data::US_STATES[state] || state
|
55
|
+
else
|
56
|
+
state.upcase
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Changes :state based on UPS requirements for CA Addresses
|
61
|
+
#
|
62
|
+
# @param [String] state The CA State to normalize
|
63
|
+
# @return [String]
|
64
|
+
def normalize_ca_state(state)
|
65
|
+
if state.to_str.length > 2
|
66
|
+
UPS::Data::CANADIAN_STATES[state] || state
|
67
|
+
else
|
68
|
+
state.upcase
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns an XML representation of address_line_1
|
73
|
+
#
|
74
|
+
# @return [Ox::Element] XML representation of address_line_1 address part
|
75
|
+
def address_line_1
|
76
|
+
element_with_value('AddressLine1', opts[:address_line_1][0..34])
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns an XML representation of address_line_2
|
80
|
+
#
|
81
|
+
# @return [Ox::Element] XML representation of address_line_2 address part
|
82
|
+
def address_line_2
|
83
|
+
data = (opts.key? :address_line_2) ? opts[:address_line_2][0..34] : ''
|
84
|
+
element_with_value('AddressLine2', data)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns an XML representation of city
|
88
|
+
#
|
89
|
+
# @return [Ox::Element] XML representation of the city address part
|
90
|
+
def city
|
91
|
+
element_with_value('City', opts[:city][0..29])
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns an XML representation of state
|
95
|
+
#
|
96
|
+
# @return [Ox::Element] XML representation of the state address part
|
97
|
+
def state
|
98
|
+
element_with_value('StateProvinceCode', opts[:state])
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns an XML representation of postal_code
|
102
|
+
#
|
103
|
+
# @return [Ox::Element] XML representation of the postal_code address part
|
104
|
+
def postal_code
|
105
|
+
element_with_value('PostalCode', opts[:postal_code][0..9])
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns an XML representation of country
|
109
|
+
#
|
110
|
+
# @return [Ox::Element] XML representation of the country address part
|
111
|
+
def country
|
112
|
+
element_with_value('CountryCode', opts[:country][0..1])
|
113
|
+
end
|
114
|
+
|
115
|
+
def email_address
|
116
|
+
element_with_value('EmailAddress', opts[:email_address][0..49])
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns an XML representation of a UPS Address
|
120
|
+
#
|
121
|
+
# @return [Ox::Element] XML representation of the current object
|
122
|
+
def to_xml
|
123
|
+
Element.new('Address').tap do |address|
|
124
|
+
address << address_line_1
|
125
|
+
address << address_line_2
|
126
|
+
address << email_address if opts[:email_address]
|
127
|
+
address << city
|
128
|
+
address << state
|
129
|
+
address << postal_code
|
130
|
+
address << country
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'ox'
|
2
|
+
|
3
|
+
module UPS
|
4
|
+
module Builders
|
5
|
+
# The {BuilderBase} class builds UPS XML Address Objects.
|
6
|
+
#
|
7
|
+
# @author Paul Trippett
|
8
|
+
# @since 0.1.0
|
9
|
+
# @abstract
|
10
|
+
# @attr [Ox::Document] document The XML Document being built
|
11
|
+
# @attr [Ox::Element] root The XML Root
|
12
|
+
# @attr [Ox::Element] shipment_root The XML Shipment Element
|
13
|
+
# @attr [Ox::Element] access_request The XML AccessRequest Element
|
14
|
+
# @attr [String] license_number The UPS API Key
|
15
|
+
# @attr [String] user_id The UPS Username
|
16
|
+
# @attr [String] password The UPS Password
|
17
|
+
class BuilderBase
|
18
|
+
include Ox
|
19
|
+
include Exceptions
|
20
|
+
|
21
|
+
attr_accessor :document,
|
22
|
+
:root,
|
23
|
+
:shipment_root,
|
24
|
+
:access_request,
|
25
|
+
:license_number,
|
26
|
+
:user_id,
|
27
|
+
:password
|
28
|
+
|
29
|
+
# Initializes a new {BuilderBase} object
|
30
|
+
#
|
31
|
+
# @param [String] root_name The Name of the XML Root
|
32
|
+
# @return [void]
|
33
|
+
def initialize(root_name)
|
34
|
+
initialize_xml_roots root_name
|
35
|
+
|
36
|
+
document << access_request
|
37
|
+
document << root
|
38
|
+
|
39
|
+
yield self if block_given?
|
40
|
+
end
|
41
|
+
|
42
|
+
# Initializes a new {BuilderBase} object
|
43
|
+
#
|
44
|
+
# @param [String] license_number The UPS API Key
|
45
|
+
# @param [String] user_id The UPS Username
|
46
|
+
# @param [String] password The UPS Password
|
47
|
+
# @return [void]
|
48
|
+
def add_access_request(license_number, user_id, password)
|
49
|
+
self.license_number = license_number
|
50
|
+
self.user_id = user_id
|
51
|
+
self.password = password
|
52
|
+
|
53
|
+
access_request << element_with_value('AccessLicenseNumber',
|
54
|
+
license_number)
|
55
|
+
access_request << element_with_value('UserId', user_id)
|
56
|
+
access_request << element_with_value('Password', password)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Adds a Request section to the XML document being built
|
60
|
+
#
|
61
|
+
# @param [String] action The UPS API Action requested
|
62
|
+
# @param [String] option The UPS API Option
|
63
|
+
# @return [void]
|
64
|
+
def add_request(action, option)
|
65
|
+
root << Element.new('Request').tap do |request|
|
66
|
+
request << element_with_value('RequestAction', action)
|
67
|
+
request << element_with_value('RequestOption', option)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Adds a Shipper section to the XML document being built
|
72
|
+
#
|
73
|
+
# @param [Hash] opts A Hash of data to build the requested section
|
74
|
+
# @option opts [String] :company_name Company Name
|
75
|
+
# @option opts [String] :phone_number Phone Number
|
76
|
+
# @option opts [String] :address_line_1 Address Line 1
|
77
|
+
# @option opts [String] :city City
|
78
|
+
# @option opts [String] :state State
|
79
|
+
# @option opts [String] :postal_code Zip or Postal Code
|
80
|
+
# @option opts [String] :country Country
|
81
|
+
# @option opts [String] :shipper_number UPS Account Number
|
82
|
+
# @return [void]
|
83
|
+
def add_shipper(opts = {})
|
84
|
+
shipment_root << ShipperBuilder.new(opts).to_xml
|
85
|
+
end
|
86
|
+
|
87
|
+
# Adds a ShipTo section to the XML document being built
|
88
|
+
#
|
89
|
+
# @param [Hash] opts A Hash of data to build the requested section
|
90
|
+
# @option opts [String] :company_name Company Name
|
91
|
+
# @option opts [String] :phone_number Phone Number
|
92
|
+
# @option opts [String] :address_line_1 Address Line 1
|
93
|
+
# @option opts [String] :city City
|
94
|
+
# @option opts [String] :state State
|
95
|
+
# @option opts [String] :postal_code Zip or Postal Code
|
96
|
+
# @option opts [String] :country Country
|
97
|
+
# @return [void]
|
98
|
+
def add_ship_to(opts = {})
|
99
|
+
shipment_root << OrganisationBuilder.new('ShipTo', opts).to_xml
|
100
|
+
end
|
101
|
+
|
102
|
+
# Adds a ShipFrom section to the XML document being built
|
103
|
+
#
|
104
|
+
# @param [Hash] opts A Hash of data to build the requested section
|
105
|
+
# @option opts [String] :company_name Company Name
|
106
|
+
# @option opts [String] :phone_number Phone Number
|
107
|
+
# @option opts [String] :address_line_1 Address Line 1
|
108
|
+
# @option opts [String] :city City
|
109
|
+
# @option opts [String] :state State
|
110
|
+
# @option opts [String] :postal_code Zip or Postal Code
|
111
|
+
# @option opts [String] :country Country
|
112
|
+
# @option opts [String] :shipper_number UPS Account Number
|
113
|
+
# @return [void]
|
114
|
+
def add_ship_from(opts = {})
|
115
|
+
shipment_root << OrganisationBuilder.new('ShipFrom', opts).to_xml
|
116
|
+
end
|
117
|
+
|
118
|
+
# Adds a Package section to the XML document being built
|
119
|
+
#
|
120
|
+
# @param [Hash] opts A Hash of data to build the requested section
|
121
|
+
# @return [void]
|
122
|
+
def add_package(opts = {})
|
123
|
+
shipment_root << Element.new('Package').tap do |org|
|
124
|
+
org << packaging_type
|
125
|
+
org << element_with_value('Description', 'Rate')
|
126
|
+
org << package_weight(opts[:weight], opts[:unit])
|
127
|
+
org << package_dimensions(opts[:dimensions]) if opts[:dimensions]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Adds a PaymentInformation section to the XML document being built
|
132
|
+
#
|
133
|
+
# @param [String] ship_number The UPS Shipper Number
|
134
|
+
# @return [void]
|
135
|
+
def add_payment_information(ship_number)
|
136
|
+
shipment_root << Element.new('PaymentInformation').tap do |payment|
|
137
|
+
payment << Element.new('Prepaid').tap do |prepaid|
|
138
|
+
prepaid << Element.new('BillShipper').tap do |bill_shipper|
|
139
|
+
bill_shipper << element_with_value('AccountNumber', ship_number)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Adds a RateInformation/NegotiatedRatesIndicator section to the XML
|
146
|
+
# document being built
|
147
|
+
#
|
148
|
+
# @return [void]
|
149
|
+
def add_rate_information
|
150
|
+
shipment_root << Element.new('RateInformation').tap do |rate_info|
|
151
|
+
rate_info << element_with_value('NegotiatedRatesIndicator', '1')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns a String representation of the XML document being built
|
156
|
+
#
|
157
|
+
# @return [String]
|
158
|
+
def to_xml
|
159
|
+
Ox.to_xml document
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def initialize_xml_roots(root_name)
|
165
|
+
self.document = Document.new
|
166
|
+
self.root = Element.new(root_name)
|
167
|
+
self.shipment_root = Element.new('Shipment')
|
168
|
+
self.access_request = Element.new('AccessRequest')
|
169
|
+
root << shipment_root
|
170
|
+
end
|
171
|
+
|
172
|
+
def packaging_type
|
173
|
+
code_description 'PackagingType', '02', 'Customer Supplied'
|
174
|
+
end
|
175
|
+
|
176
|
+
def package_weight(weight, unit)
|
177
|
+
Element.new('PackageWeight').tap do |org|
|
178
|
+
org << unit_of_measurement(unit)
|
179
|
+
org << element_with_value('Weight', weight)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def package_dimensions(dimensions)
|
184
|
+
Element.new('Dimensions').tap do |org|
|
185
|
+
org << unit_of_measurement(dimensions[:unit])
|
186
|
+
org << element_with_value('Length', dimensions[:length].to_s[0..8])
|
187
|
+
org << element_with_value('Width', dimensions[:width].to_s[0..8])
|
188
|
+
org << element_with_value('Height', dimensions[:height].to_s[0..8])
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def unit_of_measurement(unit)
|
193
|
+
Element.new('UnitOfMeasurement').tap do |org|
|
194
|
+
org << element_with_value('Code', unit.to_s)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def element_with_value(name, value)
|
199
|
+
fail InvalidAttributeError, name unless value.respond_to?(:to_str)
|
200
|
+
Element.new(name).tap do |request_action|
|
201
|
+
request_action << value.to_str
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def code_description(name, code, description)
|
206
|
+
multi_valued(name, Code: code, Description: description)
|
207
|
+
end
|
208
|
+
|
209
|
+
def multi_valued(name, params)
|
210
|
+
Element.new(name).tap do |e|
|
211
|
+
params.each { |key, value| e << element_with_value(key, value) }
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|