endicia_label_server-ruby 0.2.2

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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.hound.yml +2 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +1065 -0
  6. data/.travis.yml +10 -0
  7. data/Gemfile +11 -0
  8. data/Gemfile.lock +62 -0
  9. data/LICENSE.txt +14 -0
  10. data/README.md +66 -0
  11. data/Rakefile +19 -0
  12. data/endicia.wsdl +4272 -0
  13. data/endicia_label_server.gemspec +23 -0
  14. data/lib/endicia_label_server-ruby.rb +2 -0
  15. data/lib/endicia_label_server.rb +33 -0
  16. data/lib/endicia_label_server/builders/builder_base.rb +91 -0
  17. data/lib/endicia_label_server/builders/change_pass_phrase_builder.rb +18 -0
  18. data/lib/endicia_label_server/builders/postage_label_builder.rb +24 -0
  19. data/lib/endicia_label_server/builders/postage_rate_builder.rb +23 -0
  20. data/lib/endicia_label_server/builders/postage_rates_builder.rb +23 -0
  21. data/lib/endicia_label_server/builders/user_sign_up_builder.rb +24 -0
  22. data/lib/endicia_label_server/connection.rb +96 -0
  23. data/lib/endicia_label_server/exceptions.rb +5 -0
  24. data/lib/endicia_label_server/parsers/change_pass_phrase_parser.rb +20 -0
  25. data/lib/endicia_label_server/parsers/parser_base.rb +42 -0
  26. data/lib/endicia_label_server/parsers/postage_label_parser.rb +52 -0
  27. data/lib/endicia_label_server/parsers/postage_rate_parser.rb +43 -0
  28. data/lib/endicia_label_server/parsers/postage_rates_parser.rb +16 -0
  29. data/lib/endicia_label_server/parsers/user_sign_up_parser.rb +24 -0
  30. data/lib/endicia_label_server/service/mailpiece_shape.rb +92 -0
  31. data/lib/endicia_label_server/services.rb +37 -0
  32. data/lib/endicia_label_server/util.rb +29 -0
  33. data/lib/endicia_label_server/version.rb +10 -0
  34. data/spec/endicia_label_server/builders/builder_base_spec.rb +47 -0
  35. data/spec/endicia_label_server/connection/change_pass_phrase_spec.rb +45 -0
  36. data/spec/endicia_label_server/connection/multiple_rate_spec.rb +96 -0
  37. data/spec/endicia_label_server/connection/postage_label_spec.rb +67 -0
  38. data/spec/endicia_label_server/connection/single_rate_spec.rb +57 -0
  39. data/spec/endicia_label_server/connection/user_sign_up_spec.rb +93 -0
  40. data/spec/endicia_label_server/connection_spec.rb +21 -0
  41. data/spec/endicia_label_server/service/mailpiece_shape_spec.rb +159 -0
  42. data/spec/spec_helper.rb +18 -0
  43. data/spec/stubs/change_pass_phrase_success.xml +8 -0
  44. data/spec/stubs/postage_label_success.xml +17 -0
  45. data/spec/stubs/postage_rate_success.xml +147 -0
  46. data/spec/stubs/postage_rates_success.xml +184 -0
  47. data/spec/stubs/user_sign_up_success.xml +7 -0
  48. metadata +150 -0
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../lib/endicia_label_server/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'endicia_label_server-ruby'
5
+ gem.version = EndiciaLabelServer::Version::STRING
6
+ gem.platform = Gem::Platform::RUBY
7
+ gem.authors = ['Veeqo']
8
+ gem.email = ['helpme@veeqo.com']
9
+ gem.homepage = 'https://github.com/veeqo/endicia_label_server-ruby'
10
+ gem.summary = 'Endicia Label Server'
11
+ gem.description = 'Gem for accessing the Endicia Label Server XML API from Ruby'
12
+
13
+ gem.license = 'AGPL-3.0'
14
+
15
+ gem.required_rubygems_version = '>= 1.3.6'
16
+
17
+ gem.add_runtime_dependency 'ox', '~> 2.2', '>= 2.2.0'
18
+ gem.add_runtime_dependency 'excon', '~> 0.45', '>= 0.45.3'
19
+ gem.add_runtime_dependency 'insensitive_hash', '~> 0.3.3', '>= 0.3.3'
20
+
21
+ gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
22
+ gem.require_path = 'lib'
23
+ end
@@ -0,0 +1,2 @@
1
+ # This file is automatically loaded by Bundler
2
+ require 'endicia_label_server'
@@ -0,0 +1,33 @@
1
+ module EndiciaLabelServer
2
+ GEM_NAME = 'endicia_label_server'
3
+
4
+ autoload :SERVICES, "#{GEM_NAME}/services"
5
+ autoload :MAILPIECESHAPES, "#{GEM_NAME}/services"
6
+
7
+ module Service
8
+ autoload :MailpieceShape, "#{GEM_NAME}/service/mailpiece_shape"
9
+ end
10
+
11
+ autoload :Version, "#{GEM_NAME}/version"
12
+ autoload :Connection, "#{GEM_NAME}/connection"
13
+ autoload :Exceptions, "#{GEM_NAME}/exceptions"
14
+ autoload :Util, "#{GEM_NAME}/util"
15
+
16
+ module Builders
17
+ autoload :BuilderBase, "#{GEM_NAME}/builders/builder_base"
18
+ autoload :PostageRateBuilder, "#{GEM_NAME}/builders/postage_rate_builder"
19
+ autoload :PostageRatesBuilder, "#{GEM_NAME}/builders/postage_rates_builder"
20
+ autoload :UserSignUpBuilder, "#{GEM_NAME}/builders/user_sign_up_builder"
21
+ autoload :PostageLabelBuilder, "#{GEM_NAME}/builders/postage_label_builder"
22
+ autoload :ChangePassPhraseBuilder, "#{GEM_NAME}/builders/change_pass_phrase_builder"
23
+ end
24
+
25
+ module Parsers
26
+ autoload :ParserBase, "#{GEM_NAME}/parsers/parser_base"
27
+ autoload :PostageRateParser, "#{GEM_NAME}/parsers/postage_rate_parser"
28
+ autoload :PostageRatesParser, "#{GEM_NAME}/parsers/postage_rates_parser"
29
+ autoload :UserSignUpParser, "#{GEM_NAME}/parsers/user_sign_up_parser"
30
+ autoload :PostageLabelParser, "#{GEM_NAME}/parsers/postage_label_parser"
31
+ autoload :ChangePassPhraseParser, "#{GEM_NAME}/parsers/change_pass_phrase_parser"
32
+ end
33
+ end
@@ -0,0 +1,91 @@
1
+ require 'ox'
2
+
3
+ module EndiciaLabelServer
4
+ module Builders
5
+ # The {BuilderBase} class builds Endicia XML 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
+ class BuilderBase
13
+ include Ox
14
+ include Exceptions
15
+
16
+ attr_accessor :document,
17
+ :root
18
+
19
+ # Initializes a new {BuilderBase} object
20
+ #
21
+ # @param [String] root_name The Name of the XML Root
22
+ # @return [void]
23
+ def initialize(root_name, opts = {})
24
+ initialize_xml_roots root_name
25
+
26
+ document << root
27
+
28
+ opts.each_pair { |k, v| add(k, v) }
29
+ end
30
+
31
+ def add(*args)
32
+ first_arg = args.first
33
+ last_arg = args.last
34
+ root_key = Util.camelize(first_arg)
35
+
36
+ if last_arg.is_a? Hash
37
+ add_hash root_key, last_arg
38
+ elsif last_arg.is_a? Array
39
+
40
+ else
41
+ root << element_with_value(root_key, last_arg)
42
+ end
43
+ end
44
+
45
+ def add_hash(root_key, data)
46
+ xml_root_key = (root_key.is_a? String) ? root_key : Util.camelize(root_key)
47
+ root << Element.new(xml_root_key).tap do |org|
48
+ data.each_pair do |key, value|
49
+ xml_child_key = (key.is_a? String) ? key : Util.camelize(key)
50
+ org << element_with_value(xml_child_key, value)
51
+ end
52
+ end
53
+ end
54
+
55
+ def add_array(root_key, data)
56
+ xml_root_key = Util.camelize(root_key)
57
+ root << Element.new(xml_root_key).tap do |org|
58
+ child_key = "#{Util.singularize(xml_root_key)}ID"
59
+ data.each do |value|
60
+ org << element_with_value(child_key, value)
61
+ end
62
+ end
63
+ end
64
+
65
+ # Returns a String representation of the XML document being built
66
+ #
67
+ # @return [String]
68
+ def to_xml
69
+ Ox.to_xml document
70
+ end
71
+
72
+ def to_http_post
73
+ "#{post_field}=#{to_xml}"
74
+ end
75
+
76
+ private
77
+
78
+ def initialize_xml_roots(root_name)
79
+ self.document = Document.new
80
+ self.root = Element.new(root_name)
81
+ end
82
+
83
+ def element_with_value(name, value)
84
+ fail InvalidAttributeError, name unless value.respond_to?(:to_str)
85
+ Element.new(name).tap do |request_action|
86
+ request_action << value.to_str
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,18 @@
1
+ require 'ox'
2
+
3
+ module EndiciaLabelServer
4
+ module Builders
5
+ class ChangePassPhraseBuilder < BuilderBase
6
+ include Ox
7
+
8
+ def initialize(opts = {})
9
+ super 'ChangePassPhraseRequest', opts
10
+ root[:TokenRequested] = 'false'
11
+ end
12
+
13
+ def post_field
14
+ 'ChangePassPhraseRequestXML'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ require 'ox'
2
+
3
+ module EndiciaLabelServer
4
+ module Builders
5
+ # The {PostageLabelBuilder} class builds Endicia XML LabelRequest
6
+ # Objects.
7
+ #
8
+ # @author Paul Trippett
9
+ # @since 0.1.0
10
+ class PostageLabelBuilder < BuilderBase
11
+ include Ox
12
+
13
+ # Initializes a new {RateBuilder} object
14
+ #
15
+ def initialize(opts = {})
16
+ super 'LabelRequest', opts
17
+ end
18
+
19
+ def post_field
20
+ 'labelRequestXML'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ require 'ox'
2
+
3
+ module EndiciaLabelServer
4
+ module Builders
5
+ # The {PostageRateBuilder} class builds Endicia XML PostageRate Objects.
6
+ #
7
+ # @author Paul Trippett
8
+ # @since 0.1.0
9
+ class PostageRateBuilder < BuilderBase
10
+ include Ox
11
+
12
+ # Initializes a new {RateBuilder} object
13
+ #
14
+ def initialize(opts = {})
15
+ super 'PostageRateRequest', opts
16
+ end
17
+
18
+ def post_field
19
+ 'postageRateRequestXML'
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'ox'
2
+
3
+ module EndiciaLabelServer
4
+ module Builders
5
+ # The {PostageRatesBuilder} class builds Endicia XML Rate Objects.
6
+ #
7
+ # @author Paul Trippett
8
+ # @since 0.1.0
9
+ class PostageRatesBuilder < BuilderBase
10
+ include Ox
11
+
12
+ # Initializes a new {RateBuilder} object
13
+ #
14
+ def initialize(opts = {})
15
+ super 'PostageRatesRequest', opts
16
+ end
17
+
18
+ def post_field
19
+ 'postageRatesRequestXML'
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ require 'ox'
2
+
3
+ module EndiciaLabelServer
4
+ module Builders
5
+ # The {UserSignUpBuilder} class builds Endicia XML Rate Objects.
6
+ #
7
+ # @author Paul Trippett
8
+ # @since 0.1.0
9
+ class UserSignUpBuilder < BuilderBase
10
+ include Ox
11
+
12
+ # Initializes a new {RateBuilder} object
13
+ #
14
+ def initialize(opts = {})
15
+ super 'UserSignUpRequest', opts
16
+ root[:TokenRequested] = 'true'
17
+ end
18
+
19
+ def post_field
20
+ 'UserSignUpRequestXML'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,96 @@
1
+ require 'uri'
2
+ require 'excon'
3
+ require 'digest/md5'
4
+ require 'ox'
5
+
6
+ module EndiciaLabelServer
7
+ # The {Connection} class acts as the main entry point to performing rate and
8
+ # ship operations against the Endicia API.
9
+ #
10
+ # @author Paul Trippett
11
+ # @abstract
12
+ # @since 0.1.0
13
+ # @attr [String] url The base url to use either TEST_URL or LIVE_URL
14
+ class Connection
15
+ include EndiciaLabelServer::Builders
16
+ include EndiciaLabelServer::Parsers
17
+
18
+ attr_accessor :url
19
+
20
+ TEST_URL = 'https://elstestserver.endicia.com'
21
+ LIVE_URL = 'https://labelserver.endicia.com'
22
+ ROOT_PATH = '/LabelService/EwsLabelService.asmx/'
23
+
24
+ GET_POSTAGE_LABEL_ENDPOINT = 'GetPostageLabelXML'
25
+ REQUEST_RATE_ENDPOINT = 'CalculatePostageRateXML'
26
+ REQUEST_RATES_ENDPOINT = 'CalculatePostageRatesXML'
27
+ GET_USER_SIGNUP_ENDPOINT = 'GetUserSignUpXML'
28
+ CHANGE_PASS_PHRASE_ENDPOINT = 'ChangePassPhraseXML'
29
+
30
+ DEFAULT_PARAMS = {
31
+ test_mode: false
32
+ }
33
+
34
+ HEADERS = {
35
+ 'Content-Type' => 'application/x-www-form-urlencoded'
36
+ }
37
+
38
+ # Initializes a new {Connection} object
39
+ #
40
+ # @param [Hash] params The initialization options
41
+ # @option params [Boolean] :test_mode If TEST_URL should be used for
42
+ # requests to the Endicia Label Server URL
43
+ def initialize(params = {})
44
+ params = DEFAULT_PARAMS.merge(params)
45
+ self.url = (params[:test_mode]) ? TEST_URL : LIVE_URL
46
+ end
47
+
48
+ def rate(builder = nil, &block)
49
+ builder_proxy(builder, REQUEST_RATE_ENDPOINT, PostageRateBuilder,
50
+ PostageRateParser, block)
51
+ end
52
+
53
+ def rates(builder = nil, &block)
54
+ builder_proxy(builder, REQUEST_RATES_ENDPOINT, PostageRatesBuilder,
55
+ PostageRatesParser, block)
56
+ end
57
+
58
+ def get_label(builder = nil, &block)
59
+ builder_proxy(builder, GET_POSTAGE_LABEL_ENDPOINT, PostageLabelBuilder,
60
+ PostageLabelParser, block)
61
+ end
62
+
63
+ def sign_up(builder = nil, &block)
64
+ builder_proxy(builder, GET_USER_SIGNUP_ENDPOINT, UserSignUpBuilder,
65
+ UserSignUpParser, block)
66
+ end
67
+
68
+ def change_pass_phrase(builder = nil, &block)
69
+ builder_proxy(builder, CHANGE_PASS_PHRASE_ENDPOINT, ChangePassPhraseBuilder,
70
+ ChangePassPhraseParser, block)
71
+ end
72
+
73
+ private
74
+
75
+ def build_url(endpoint)
76
+ "#{url}#{ROOT_PATH}#{endpoint}"
77
+ end
78
+
79
+ def get_response_stream(path, body)
80
+ response = Excon.post(build_url(path), body: body, headers: HEADERS)
81
+ StringIO.new(response.body)
82
+ end
83
+
84
+ def builder_proxy(builder, path, builder_type, parser, block)
85
+ if builder.nil? && block
86
+ builder = builder_type.new
87
+ block.call builder
88
+ end
89
+
90
+ response = get_response_stream path, builder.to_http_post
91
+ parser.new.tap do |p|
92
+ Ox.sax_parse(p, response)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,5 @@
1
+ module EndiciaLabelServer
2
+ module Exceptions
3
+ class InvalidAttributeError < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ module EndiciaLabelServer
2
+ module Parsers
3
+ class ChangePassPhraseParser < ParserBase
4
+ attr_accessor :requester_id, :request_id, :token
5
+
6
+ def value(value)
7
+ super
8
+
9
+ string_value = value.as_s
10
+ if switch_active? :RequesterID
11
+ self.requester_id = string_value
12
+ elsif switch_active? :RequestID
13
+ self.request_id = string_value
14
+ elsif switch_active? :Token
15
+ self.token = string_value
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ require 'uri'
2
+ require 'ox'
3
+
4
+ module EndiciaLabelServer
5
+ module Parsers
6
+ class ParserBase < ::Ox::Sax
7
+ attr_accessor :switches,
8
+ :status_code,
9
+ :error_description
10
+
11
+ def initialize
12
+ self.switches = {}
13
+ end
14
+
15
+ def start_element(name)
16
+ element_tracker_switch name, true
17
+ end
18
+
19
+ def end_element(name)
20
+ element_tracker_switch name, false
21
+ end
22
+
23
+ def value(value)
24
+ string_value = value.as_s
25
+ self.status_code = string_value if switch_active? :Status
26
+ self.error_description = string_value if switch_active? :ErrorMessage
27
+ end
28
+
29
+ def element_tracker_switch(element, currently_in)
30
+ switches[element] = currently_in
31
+ end
32
+
33
+ def switch_active?(*elements)
34
+ elements.all? { |element| switches[element] == true }
35
+ end
36
+
37
+ def success?
38
+ ['0', 0].include? status_code
39
+ end
40
+ end
41
+ end
42
+ end