ups-ruby 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://img.shields.io/gem/v/ups.svg?style=flat-square)](http://badge.fury.io/rb/ups)
|
2
|
+
[![Dependency Status](https://img.shields.io/gemnasium/ptrippett/ups.svg?style=flat-square)](https://gemnasium.com/ptrippett/ups)
|
3
|
+
[![Build Status](https://img.shields.io/travis/ptrippett/ups.svg?style=flat-square)](https://travis-ci.org/ptrippett/ups)
|
4
|
+
[![Coverage Status](https://img.shields.io/codeclimate/coverage/github/ptrippett/ups.svg?style=flat-square)](https://codeclimate.com/github/ptrippett/ups/coverage)
|
5
|
+
[![Code Climate](https://img.shields.io/codeclimate/github/ptrippett/ups.svg?style=flat-square)](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
|