ups-ruby 0.9.6 → 0.11.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|