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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ae8eb61dda03ca960a88a1214bc5c6abe98a6efb
4
- data.tar.gz: 5a99fe38d9629c931c8a321c163c0318a2500ad4
2
+ SHA256:
3
+ metadata.gz: ce31214234663e90d8d7ce00b51e518ce19e65cd6accc3b340b63f77b57c00a4
4
+ data.tar.gz: 0aaca2ab7195698e301cdfd5090de7eac7bde4da97121e7a862b18b44093da78
5
5
  SHA512:
6
- metadata.gz: ac5aaa642c66ace7d48869bd03e1db9140c7ab0af1480e9a734f8237ecd84558395d98d4b18396d8a6c22033e9309f4df3abc530f027405604e0155d404f4ca9
7
- data.tar.gz: eeb86df6170b12351baaaaa637f7e0e75d726cef2fbed025aa181b4b714c9d68463906d48ff3fd40d49597c6b7681520f182faddf603b6ab6e0c2d12c43a83ec
6
+ metadata.gz: 499730f5860fd137c4bc58e34b4411e0b07573262532acdd8abf20b1495490a05aa1eebe74192b021550fb2094aabcade89664e1e50d98ff4a0480e74c5873c0
7
+ data.tar.gz: 53f17acb18c5476a36b83a799b3599501ed1c56aa12178d9ec477ee448b948dd6fe833cec37258be4072b336a44f2a0fd3451ebfc93543f4826c7bc6454569d1
data/.travis.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  rvm:
2
- - 1.9.3
3
- - 2.0.0
4
- - 2.1.6
5
- - 2.2.2
2
+ - 2.3.8
3
+ - 2.4.6
4
+ - 2.5.5
5
+ - 2.6.3
6
6
  - ruby-head
7
7
  cache: bundler
8
8
  matrix:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ups-ruby (0.9.6)
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.59.0)
17
- ffi (1.9.18)
16
+ excon (0.68.0)
17
+ ffi (1.11.1)
18
18
  insensitive_hash (0.3.3)
19
- json (1.8.3)
19
+ json (1.8.6)
20
20
  levenshtein-ffi (1.1.0)
21
21
  ffi (~> 1.9)
22
- mini_portile (0.6.2)
22
+ mini_portile2 (2.4.0)
23
23
  minitest (5.7.0)
24
- nokogiri (1.6.6.2)
25
- mini_portile (~> 0.6.0)
26
- ox (2.6.0)
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
- ship_response = server.ship do |shipment_builder|
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
- ship_response = server.ship do |shipment_builder|
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
- 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
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
@@ -26,6 +26,7 @@ module UPS
26
26
  def initialize(name, opts = {})
27
27
  self.name = name
28
28
  self.opts = opts
29
+ self.opts[:skip_ireland_state_validation] = (name == 'SoldTo')
29
30
  end
30
31
 
31
32
  # Returns an XML representation of company_name
@@ -52,10 +52,8 @@ module UPS
52
52
  yield rate_builder
53
53
  end
54
54
 
55
- response = get_response_stream RATE_PATH, rate_builder.to_xml
56
- UPS::Parsers::RatesParser.new.tap do |parser|
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
- confirm_response)
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 get_response_stream(path, body)
92
- response = Excon.post(build_url(path), body: body)
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 confirm_builder,
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 accept_builder,
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 = get_response_stream path, builder.to_xml
110
- ship_parser.tap do |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 < ParserBase
4
- attr_accessor :rated_shipments
3
+ class RatesParser < BaseParser
5
4
 
6
- def initialize
7
- super
8
- self.rated_shipments = []
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
- def parse_negotiated_rate(value)
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 parse_service_code(value)
51
- @current_rate[:service_code] = value.as_s
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 parse_total_charges(value)
56
- @current_rate[:total] = value.as_s
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 < ParserBase
7
- attr_accessor :label_root_path,
8
- :form_root_path,
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 initialize_document_root_paths
30
- self.label_root_path = [:ShipmentResults, :PackageResults, :LabelImage]
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 parse_document_data(value, type)
35
- root_path = self.send("#{type}_root_path")
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
- parse_graphic_extension(root_path, value, type)
38
- parse_graphic_image(root_path, value, type)
39
- parse_html_image(root_path, value, type)
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 parse_graphic_image(root_path, value, type)
43
- switch_path = build_switch_path(root_path, :GraphicImage)
44
- return unless switch_active?(switch_path)
33
+ def form_graphic_image
34
+ return unless has_form_graphic?
45
35
 
46
- self.send("#{type}_graphic_image=".to_sym, base64_to_file(value.as_s, type))
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 parse_html_image(root_path, value, type)
51
- switch_path = build_switch_path(root_path, :HTMLImage)
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
- self.send("#{type}_html_image=".to_sym, base64_to_file(value.as_s, type))
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
- def parse_graphic_extension(root_path, value, type)
59
- graphic_extension_subpath = (type == 'label' ? :LabelImageFormat : :ImageFormat)
45
+ private
46
+
47
+ def form_graphic
48
+ shipment_results[:Form]
49
+ end
60
50
 
61
- switch_path = build_switch_path(root_path, graphic_extension_subpath, :Code)
62
- return unless switch_active?(switch_path)
51
+ def has_form_graphic?
52
+ shipment_results.key?(:Form)
53
+ end
63
54
 
64
- self.send("#{type}_graphic_extension=".to_sym, ".#{value.as_s.downcase}")
65
- self.send("graphic_extension=".to_sym, ".#{value.as_s.downcase}") if type == 'label'
55
+ def package_results
56
+ shipment_results[:PackageResults]
66
57
  end
67
58
 
68
- def parse_tracking_number(value)
69
- return unless switch_active?(:ShipmentIdentificationNumber)
70
- self.tracking_number = value.as_s
59
+ def shipment_results
60
+ root_response[:ShipmentResults]
71
61
  end
72
62
 
73
- def base64_to_file(contents, type)
74
- file_config = ['ups', self.send("#{type}_graphic_extension".to_sym)]
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