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 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