ups-ruby 0.9.6 → 0.11.8
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 +5 -5
- data/.travis.yml +4 -4
- data/Gemfile.lock +8 -11
- data/README.md +2 -2
- data/lib/ups.rb +8 -0
- data/lib/ups/builders/address_builder.rb +13 -9
- data/lib/ups/builders/organisation_builder.rb +1 -0
- data/lib/ups/connection.rb +10 -20
- data/lib/ups/models/package_result.rb +27 -0
- data/lib/ups/parsers/base_parser.rb +50 -0
- data/lib/ups/parsers/rate_parser.rb +59 -0
- data/lib/ups/parsers/rates_parser.rb +9 -47
- data/lib/ups/parsers/ship_accept_parser.rb +40 -57
- data/lib/ups/parsers/ship_confirm_parser.rb +13 -9
- data/lib/ups/services.rb +1 -1
- data/lib/ups/utils.rb +14 -0
- data/lib/ups/version.rb +2 -2
- data/spec/stubs/multi_package/ship_accept_success.xml +64 -0
- data/spec/stubs/multi_package/ship_confirm_success.xml +30 -0
- data/spec/stubs/rates_error_multi_error.xml +17 -0
- data/spec/stubs/rates_error_single_error.xml +12 -0
- data/spec/stubs/rates_success_single_rate.xml +55 -0
- data/spec/support/shipping_options.rb +13 -0
- data/spec/ups/builders/address_builder_spec.rb +20 -0
- data/spec/ups/builders/organisation_builder_spec.rb +21 -0
- data/spec/ups/connection/rates_negotiated_spec.rb +1 -1
- data/spec/ups/connection/rates_standard_spec.rb +105 -41
- data/spec/ups/connection/ship_spec.rb +144 -36
- metadata +19 -11
- data/lib/ups/parsers/parser_base.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ce31214234663e90d8d7ce00b51e518ce19e65cd6accc3b340b63f77b57c00a4
|
4
|
+
data.tar.gz: 0aaca2ab7195698e301cdfd5090de7eac7bde4da97121e7a862b18b44093da78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 499730f5860fd137c4bc58e34b4411e0b07573262532acdd8abf20b1495490a05aa1eebe74192b021550fb2094aabcade89664e1e50d98ff4a0480e74c5873c0
|
7
|
+
data.tar.gz: 53f17acb18c5476a36b83a799b3599501ed1c56aa12178d9ec477ee448b948dd6fe833cec37258be4072b336a44f2a0fd3451ebfc93543f4826c7bc6454569d1
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ups-ruby (0.
|
4
|
+
ups-ruby (0.11.8)
|
5
5
|
excon (~> 0.45, >= 0.45.3)
|
6
6
|
insensitive_hash (~> 0.3.3)
|
7
7
|
levenshtein-ffi (~> 1.1)
|
@@ -13,17 +13,17 @@ GEM
|
|
13
13
|
codeclimate-test-reporter (1.0.5)
|
14
14
|
simplecov
|
15
15
|
docile (1.1.5)
|
16
|
-
excon (0.
|
17
|
-
ffi (1.
|
16
|
+
excon (0.68.0)
|
17
|
+
ffi (1.11.1)
|
18
18
|
insensitive_hash (0.3.3)
|
19
|
-
json (1.8.
|
19
|
+
json (1.8.6)
|
20
20
|
levenshtein-ffi (1.1.0)
|
21
21
|
ffi (~> 1.9)
|
22
|
-
|
22
|
+
mini_portile2 (2.4.0)
|
23
23
|
minitest (5.7.0)
|
24
|
-
nokogiri (1.
|
25
|
-
|
26
|
-
ox (2.
|
24
|
+
nokogiri (1.10.3)
|
25
|
+
mini_portile2 (~> 2.4.0)
|
26
|
+
ox (2.11.0)
|
27
27
|
rake (12.0.0)
|
28
28
|
simplecov (0.10.0)
|
29
29
|
docile (~> 1.1.0)
|
@@ -41,6 +41,3 @@ DEPENDENCIES
|
|
41
41
|
rake
|
42
42
|
simplecov
|
43
43
|
ups-ruby!
|
44
|
-
|
45
|
-
BUNDLED WITH
|
46
|
-
1.15.4
|
data/README.md
CHANGED
@@ -60,7 +60,7 @@ end
|
|
60
60
|
```ruby
|
61
61
|
require 'ups-ruby'
|
62
62
|
server = UPS::Connection.new(test_mode: true)
|
63
|
-
|
63
|
+
response = server.ship do |shipment_builder|
|
64
64
|
shipment_builder.add_access_request 'API_KEY', 'USERNAME', 'PASSWORD'
|
65
65
|
shipment_builder.add_shipper company_name: 'Veeqo Limited',
|
66
66
|
phone_number: '01792 123456',
|
@@ -110,7 +110,7 @@ response.tracking_number
|
|
110
110
|
```ruby
|
111
111
|
require 'ups-ruby'
|
112
112
|
server = UPS::Connection.new(test_mode: true)
|
113
|
-
|
113
|
+
response = server.ship do |shipment_builder|
|
114
114
|
shipment_builder.add_access_request 'API_KEY', 'USERNAME', 'PASSWORD'
|
115
115
|
shipment_builder.add_shipper company_name: 'Veeqo Limited',
|
116
116
|
phone_number: '01792 123456',
|
data/lib/ups.rb
CHANGED
@@ -6,6 +6,8 @@ module UPS
|
|
6
6
|
autoload :Connection, 'ups/connection'
|
7
7
|
autoload :Exceptions, 'ups/exceptions'
|
8
8
|
|
9
|
+
autoload :Utils, 'ups/utils'
|
10
|
+
|
9
11
|
autoload :Data, 'ups/data'
|
10
12
|
module Data
|
11
13
|
autoload :US_STATES, 'ups/data/us_states'
|
@@ -14,9 +16,15 @@ module UPS
|
|
14
16
|
autoload :IE_COUNTY_PREFIXES, 'ups/data/ie_county_prefixes'
|
15
17
|
end
|
16
18
|
|
19
|
+
module Models
|
20
|
+
autoload :PackageResult, 'ups/models/package_result'
|
21
|
+
end
|
22
|
+
|
17
23
|
module Parsers
|
24
|
+
autoload :BaseParser, 'ups/parsers/base_parser'
|
18
25
|
autoload :ParserBase, 'ups/parsers/parser_base'
|
19
26
|
autoload :RatesParser, 'ups/parsers/rates_parser'
|
27
|
+
autoload :RateParser, 'ups/parsers/rate_parser'
|
20
28
|
autoload :ShipConfirmParser, 'ups/parsers/ship_confirm_parser'
|
21
29
|
autoload :ShipAcceptParser, 'ups/parsers/ship_accept_parser'
|
22
30
|
end
|
@@ -34,15 +34,19 @@ module UPS
|
|
34
34
|
# @return [void]
|
35
35
|
def validate
|
36
36
|
opts[:state] = case opts[:country].downcase
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
37
|
+
when 'us'
|
38
|
+
normalize_us_state(opts[:state])
|
39
|
+
when 'ca'
|
40
|
+
normalize_ca_state(opts[:state])
|
41
|
+
when 'ie'
|
42
|
+
if opts[:skip_ireland_state_validation]
|
43
|
+
'_' # UPS requires at least one character for Ireland
|
44
|
+
else
|
45
|
+
UPS::Data.ie_state_matcher(opts[:state])
|
46
|
+
end
|
47
|
+
else
|
48
|
+
''
|
49
|
+
end
|
46
50
|
end
|
47
51
|
|
48
52
|
# Changes :state based on UPS requirements for US Addresses
|
data/lib/ups/connection.rb
CHANGED
@@ -52,10 +52,8 @@ module UPS
|
|
52
52
|
yield rate_builder
|
53
53
|
end
|
54
54
|
|
55
|
-
response =
|
56
|
-
UPS::Parsers::RatesParser.new.
|
57
|
-
Ox.sax_parse(parser, response)
|
58
|
-
end
|
55
|
+
response = get_response(RATE_PATH, rate_builder.to_xml)
|
56
|
+
UPS::Parsers::RatesParser.new(response.body)
|
59
57
|
end
|
60
58
|
|
61
59
|
# Makes a request to ship a package
|
@@ -77,9 +75,8 @@ module UPS
|
|
77
75
|
confirm_response = make_confirm_request(confirm_builder)
|
78
76
|
return confirm_response unless confirm_response.success?
|
79
77
|
|
80
|
-
accept_builder = build_accept_request_from_confirm(confirm_builder,
|
81
|
-
|
82
|
-
make_accept_request accept_builder
|
78
|
+
accept_builder = build_accept_request_from_confirm(confirm_builder, confirm_response)
|
79
|
+
make_accept_request(accept_builder)
|
83
80
|
end
|
84
81
|
|
85
82
|
private
|
@@ -88,28 +85,21 @@ module UPS
|
|
88
85
|
"#{url}#{path}"
|
89
86
|
end
|
90
87
|
|
91
|
-
def
|
92
|
-
|
93
|
-
StringIO.new(response.body)
|
88
|
+
def get_response(path, body)
|
89
|
+
Excon.post(build_url(path), body: body)
|
94
90
|
end
|
95
91
|
|
96
92
|
def make_confirm_request(confirm_builder)
|
97
|
-
make_ship_request
|
98
|
-
SHIP_CONFIRM_PATH,
|
99
|
-
Parsers::ShipConfirmParser.new
|
93
|
+
make_ship_request(confirm_builder, SHIP_CONFIRM_PATH, Parsers::ShipConfirmParser)
|
100
94
|
end
|
101
95
|
|
102
96
|
def make_accept_request(accept_builder)
|
103
|
-
make_ship_request
|
104
|
-
SHIP_ACCEPT_PATH,
|
105
|
-
Parsers::ShipAcceptParser.new
|
97
|
+
make_ship_request(accept_builder, SHIP_ACCEPT_PATH, Parsers::ShipAcceptParser)
|
106
98
|
end
|
107
99
|
|
108
100
|
def make_ship_request(builder, path, ship_parser)
|
109
|
-
response =
|
110
|
-
ship_parser.
|
111
|
-
Ox.sax_parse(parser, response)
|
112
|
-
end
|
101
|
+
response = get_response(path, builder.to_xml)
|
102
|
+
ship_parser.new(response.body)
|
113
103
|
end
|
114
104
|
|
115
105
|
def build_accept_request_from_confirm(confirm_builder, confirm_response)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module UPS
|
2
|
+
module Models
|
3
|
+
class PackageResult
|
4
|
+
attr_reader :package_result
|
5
|
+
|
6
|
+
def initialize(package_result)
|
7
|
+
@package_result = package_result
|
8
|
+
end
|
9
|
+
|
10
|
+
def tracking_number
|
11
|
+
package_result[:TrackingNumber]
|
12
|
+
end
|
13
|
+
|
14
|
+
def label_graphic_extension
|
15
|
+
".#{package_result[:LabelImage][:LabelImageFormat][:Code].downcase}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def label_graphic_image
|
19
|
+
Utils.base64_to_file(package_result[:LabelImage][:GraphicImage], label_graphic_extension)
|
20
|
+
end
|
21
|
+
|
22
|
+
def label_html_image
|
23
|
+
Utils.base64_to_file(package_result[:LabelImage][:HTMLImage], label_graphic_extension)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'ox'
|
3
|
+
|
4
|
+
module UPS
|
5
|
+
module Parsers
|
6
|
+
class BaseParser
|
7
|
+
attr_reader :response
|
8
|
+
|
9
|
+
def initialize(response)
|
10
|
+
@response = response
|
11
|
+
end
|
12
|
+
|
13
|
+
def success?
|
14
|
+
status_code == '1'
|
15
|
+
end
|
16
|
+
|
17
|
+
def status_code
|
18
|
+
root_response[:Response][:ResponseStatusCode]
|
19
|
+
end
|
20
|
+
|
21
|
+
def status_description
|
22
|
+
root_response[:Response][:ResponseStatusDescription]
|
23
|
+
end
|
24
|
+
|
25
|
+
def error_description
|
26
|
+
build_error_description(error_response)
|
27
|
+
end
|
28
|
+
|
29
|
+
def parsed_response
|
30
|
+
@parsed_response ||= Ox.load(response, mode: :hash)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def normalize_response_into_array(response_node)
|
36
|
+
[response_node].flatten
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_error_description(errors_node)
|
40
|
+
return errors_node.last[:ErrorDescription] if errors_node.is_a?(Array)
|
41
|
+
|
42
|
+
errors_node[:ErrorDescription]
|
43
|
+
end
|
44
|
+
|
45
|
+
def error_response
|
46
|
+
root_response[:Response][:Error]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'ox'
|
3
|
+
|
4
|
+
module UPS
|
5
|
+
module Parsers
|
6
|
+
class RateParser
|
7
|
+
attr_reader :rate
|
8
|
+
|
9
|
+
def initialize(rate)
|
10
|
+
@rate = rate
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
{
|
15
|
+
service_code: rate_service_code,
|
16
|
+
service_name: rate_service_name,
|
17
|
+
warnings: rate_warnings,
|
18
|
+
total: rate_total
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def rate_service_name
|
23
|
+
UPS::SERVICES[rate_service_code]
|
24
|
+
end
|
25
|
+
|
26
|
+
def rate_service_code
|
27
|
+
rate_service[:Code]
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def rate_total
|
33
|
+
return total_charges[:MonetaryValue] unless negotiated_rates
|
34
|
+
|
35
|
+
negotiated_rates[:NetSummaryCharges][:GrandTotal][:MonetaryValue]
|
36
|
+
end
|
37
|
+
|
38
|
+
def rate_warnings
|
39
|
+
rated_shipment_warning.is_a?(Array) ? rated_shipment_warning : [rated_shipment_warning]
|
40
|
+
end
|
41
|
+
|
42
|
+
def rate_service
|
43
|
+
rate[:Service]
|
44
|
+
end
|
45
|
+
|
46
|
+
def rated_shipment_warning
|
47
|
+
rate[:RatedShipmentWarning]
|
48
|
+
end
|
49
|
+
|
50
|
+
def total_charges
|
51
|
+
rate[:TotalCharges]
|
52
|
+
end
|
53
|
+
|
54
|
+
def negotiated_rates
|
55
|
+
rate[:NegotiatedRates]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -1,59 +1,21 @@
|
|
1
1
|
module UPS
|
2
2
|
module Parsers
|
3
|
-
class RatesParser <
|
4
|
-
attr_accessor :rated_shipments
|
3
|
+
class RatesParser < BaseParser
|
5
4
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
@current_rate = {}
|
10
|
-
end
|
11
|
-
|
12
|
-
def start_element(name)
|
13
|
-
super
|
14
|
-
end
|
15
|
-
|
16
|
-
def end_element(name)
|
17
|
-
super
|
18
|
-
return unless name == :RatedShipment
|
19
|
-
rated_shipments << @current_rate.tap do |c|
|
20
|
-
if c.key? :negotiated_rate
|
21
|
-
c[:total] = c[:negotiated_rate]
|
22
|
-
c.delete :negotiated_rate
|
23
|
-
end
|
24
|
-
end
|
25
|
-
@current_rate = {}
|
26
|
-
end
|
27
|
-
|
28
|
-
def value(value)
|
29
|
-
super
|
30
|
-
if switch_active?(:RatedShipment, :Service, :Code)
|
31
|
-
parse_service_code value
|
32
|
-
elsif switch_active?(:RatedShipment, :TotalCharges)
|
33
|
-
parse_total_charges value
|
34
|
-
elsif switch_active?(:RatedShipment, :NegotiatedRates, :MonetaryValue)
|
35
|
-
parse_negotiated_rate value
|
36
|
-
elsif switch_active?(:RatedShipment, :RatedShipmentWarning)
|
37
|
-
parse_rated_shipment_warning value
|
5
|
+
def rated_shipments
|
6
|
+
rates.map do |rated_shipment|
|
7
|
+
RateParser.new(rated_shipment).to_h
|
38
8
|
end
|
39
9
|
end
|
40
10
|
|
41
|
-
|
42
|
-
@current_rate[:negotiated_rate] = value.as_s
|
43
|
-
end
|
44
|
-
|
45
|
-
def parse_rated_shipment_warning(value)
|
46
|
-
@current_rate[:warnings] ||= []
|
47
|
-
@current_rate[:warnings] << value.as_s
|
48
|
-
end
|
11
|
+
private
|
49
12
|
|
50
|
-
def
|
51
|
-
|
52
|
-
@current_rate[:service_name] = UPS::SERVICES[value.as_s]
|
13
|
+
def rates
|
14
|
+
normalize_response_into_array(root_response[:RatedShipment])
|
53
15
|
end
|
54
16
|
|
55
|
-
def
|
56
|
-
|
17
|
+
def root_response
|
18
|
+
parsed_response[:RatingServiceSelectionResponse]
|
57
19
|
end
|
58
20
|
end
|
59
21
|
end
|
@@ -3,82 +3,65 @@ require 'tempfile'
|
|
3
3
|
|
4
4
|
module UPS
|
5
5
|
module Parsers
|
6
|
-
class ShipAcceptParser <
|
7
|
-
|
8
|
-
|
9
|
-
:graphic_image,
|
10
|
-
:graphic_extension,
|
11
|
-
:html_image,
|
12
|
-
:label_graphic_image,
|
13
|
-
:label_graphic_extension,
|
14
|
-
:label_html_image,
|
15
|
-
:form_graphic_image,
|
16
|
-
:form_graphic_extension,
|
17
|
-
:tracking_number
|
18
|
-
|
19
|
-
def value(value)
|
20
|
-
initialize_document_root_paths
|
21
|
-
|
22
|
-
parse_document_data(value, 'label')
|
23
|
-
parse_document_data(value, 'form')
|
24
|
-
parse_tracking_number(value)
|
25
|
-
|
26
|
-
super
|
6
|
+
class ShipAcceptParser < BaseParser
|
7
|
+
def tracking_number
|
8
|
+
packages[0].tracking_number
|
27
9
|
end
|
28
10
|
|
29
|
-
def
|
30
|
-
|
31
|
-
self.form_root_path = [:ShipmentResults, :Form, :Image]
|
11
|
+
def label_graphic_extension
|
12
|
+
packages[0].label_graphic_extension
|
32
13
|
end
|
33
14
|
|
34
|
-
def
|
35
|
-
|
15
|
+
def label_graphic_image
|
16
|
+
packages[0].label_graphic_image
|
17
|
+
end
|
18
|
+
|
19
|
+
def label_html_image
|
20
|
+
packages[0].label_html_image
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :graphic_extension, :label_graphic_extension
|
24
|
+
alias_method :graphic_image, :label_graphic_image
|
25
|
+
alias_method :html_image, :label_html_image
|
36
26
|
|
37
|
-
|
38
|
-
|
39
|
-
|
27
|
+
def form_graphic_extension
|
28
|
+
return unless has_form_graphic?
|
29
|
+
|
30
|
+
".#{form_graphic[:Image][:ImageFormat][:Code].downcase}"
|
40
31
|
end
|
41
32
|
|
42
|
-
def
|
43
|
-
|
44
|
-
return unless switch_active?(switch_path)
|
33
|
+
def form_graphic_image
|
34
|
+
return unless has_form_graphic?
|
45
35
|
|
46
|
-
|
47
|
-
self.send("graphic_image=".to_sym, base64_to_file(value.as_s, type)) if type == 'label'
|
36
|
+
Utils.base64_to_file(form_graphic[:Image][:GraphicImage], form_graphic_extension)
|
48
37
|
end
|
49
38
|
|
50
|
-
def
|
51
|
-
|
52
|
-
return unless switch_active?(switch_path)
|
39
|
+
def packages
|
40
|
+
return package_results.map { |package_result| UPS::Models::PackageResult.new(package_result) } if package_results.is_a?(Array)
|
53
41
|
|
54
|
-
|
55
|
-
self.send("html_image=".to_sym, base64_to_file(value.as_s, type)) if type == 'label'
|
42
|
+
[UPS::Models::PackageResult.new(package_results)]
|
56
43
|
end
|
57
44
|
|
58
|
-
|
59
|
-
|
45
|
+
private
|
46
|
+
|
47
|
+
def form_graphic
|
48
|
+
shipment_results[:Form]
|
49
|
+
end
|
60
50
|
|
61
|
-
|
62
|
-
|
51
|
+
def has_form_graphic?
|
52
|
+
shipment_results.key?(:Form)
|
53
|
+
end
|
63
54
|
|
64
|
-
|
65
|
-
|
55
|
+
def package_results
|
56
|
+
shipment_results[:PackageResults]
|
66
57
|
end
|
67
58
|
|
68
|
-
def
|
69
|
-
|
70
|
-
self.tracking_number = value.as_s
|
59
|
+
def shipment_results
|
60
|
+
root_response[:ShipmentResults]
|
71
61
|
end
|
72
62
|
|
73
|
-
def
|
74
|
-
|
75
|
-
Tempfile.new(file_config, nil, encoding: 'ascii-8bit').tap do |file|
|
76
|
-
begin
|
77
|
-
file.write Base64.decode64(contents)
|
78
|
-
ensure
|
79
|
-
file.rewind
|
80
|
-
end
|
81
|
-
end
|
63
|
+
def root_response
|
64
|
+
parsed_response[:ShipmentAcceptResponse]
|
82
65
|
end
|
83
66
|
end
|
84
67
|
end
|