postalmethods 1.0.0

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.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 1.0.0 2008-09-22
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2008 Postal Methods, Inc
2
+ Created 2008 by James Cox <james-at-imaj.es>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,31 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ PostInstall.txt
5
+ README.txt
6
+ Rakefile
7
+ config/hoe.rb
8
+ config/requirements.rb
9
+ lib/postalmethods.rb
10
+ lib/postalmethods/version.rb
11
+ lib/postalmethods/document_processor.rb
12
+ lib/postalmethods/exceptions.rb
13
+ lib/postalmethods/get_letter_status.rb
14
+ lib/postalmethods/send_letter.rb
15
+ lib/postalmethods/utility.rb
16
+ script/console
17
+ script/destroy
18
+ script/generate
19
+ setup.rb
20
+ spec/document_processor_spec.rb
21
+ spec/get_letter_status_spec.rb
22
+ spec/postalmethods_spec.rb
23
+ spec/send_letter_spec.rb
24
+ spec/utility_spec.rb
25
+ spec/rcov.opts
26
+ spec/spec.opts
27
+ spec/spec_helper.rb
28
+ tasks/deployment.rake
29
+ tasks/environment.rake
30
+ tasks/rspec.rake
31
+
data/PostInstall.txt ADDED
@@ -0,0 +1,6 @@
1
+
2
+ For more information on working with Postal Methods,
3
+ see the API reference here:
4
+
5
+ http://www.postalmethods.com/resources/quickstart
6
+
data/README.txt ADDED
@@ -0,0 +1,35 @@
1
+ = postalmethods
2
+
3
+ * Info: http://www.postalmethods.com/resources/quickstart
4
+ * Code: http://github.com/imajes/postalmethods/tree/master
5
+
6
+ == DESCRIPTION:
7
+
8
+ API wrapper library for the postal methods api.
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ * Provides access to all of the API methods with appropriate
13
+ exceptions as necessary.
14
+
15
+ == SYNOPSIS:
16
+
17
+ require 'postalmethods'
18
+
19
+ @doc = open(File.dirname(__FILE__) + '/../doc/sample.pdf')
20
+ @client = PostalMethods::Client.new(:user => "user", :password => "password")
21
+ rv = @client.send_letter(@doc, "description of doc")
22
+ puts rv
23
+
24
+ == REQUIREMENTS:
25
+
26
+ * This gem relies on the soap4r gem.
27
+
28
+ == INSTALL:
29
+
30
+ * sudo gem install postalmethods
31
+ * get a developer account at postalmethods.com
32
+
33
+ == LICENSE:
34
+
35
+ * See License.txt
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/config/hoe.rb ADDED
@@ -0,0 +1,73 @@
1
+ require 'postalmethods/version'
2
+
3
+ AUTHOR = 'James Cox' # can also be an array of Authors
4
+ EMAIL = "james-at-imaj.es"
5
+ DESCRIPTION = "Wrapper for the Postal Methods API"
6
+ GEM_NAME = 'postalmethods' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'postalmethods' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+ EXTRA_DEPENDENCIES = [
11
+ # ['activesupport', '>= 1.3.1']
12
+ ] # An array of rubygem dependencies [name, version]
13
+
14
+ @config_file = "~/.rubyforge/user-config.yml"
15
+ @config = nil
16
+ RUBYFORGE_USERNAME = "imajes"
17
+ def rubyforge_username
18
+ unless @config
19
+ begin
20
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
21
+ rescue
22
+ puts <<-EOS
23
+ ERROR: No rubyforge config file found: #{@config_file}
24
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
25
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
26
+ EOS
27
+ exit
28
+ end
29
+ end
30
+ RUBYFORGE_USERNAME.replace @config["username"]
31
+ end
32
+
33
+
34
+ REV = nil
35
+ # UNCOMMENT IF REQUIRED:
36
+ # REV = YAML.load(`svn info`)['Revision']
37
+ VERS = Postalmethods::VERSION::STRING + (REV ? ".#{REV}" : "")
38
+ RDOC_OPTS = ['--quiet', '--title', 'postalmethods documentation',
39
+ "--opname", "index.html",
40
+ "--line-numbers",
41
+ "--main", "README",
42
+ "--inline-source"]
43
+
44
+ class Hoe
45
+ def extra_deps
46
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
47
+ @extra_deps
48
+ end
49
+ end
50
+
51
+ # Generate all the Rake tasks
52
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
53
+ $hoe = Hoe.new(GEM_NAME, VERS) do |p|
54
+ p.developer(AUTHOR, EMAIL)
55
+ p.description = DESCRIPTION
56
+ p.summary = DESCRIPTION
57
+ p.url = HOMEPATH
58
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
59
+ p.test_globs = ["test/**/test_*.rb"]
60
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
61
+
62
+ # == Optional
63
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
64
+ #p.extra_deps = EXTRA_DEPENDENCIES
65
+
66
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
67
+ end
68
+
69
+ CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
70
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
71
+ $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
72
+ $hoe.rsync_args = '-av --delete --ignore-errors'
73
+ $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
@@ -0,0 +1,15 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
@@ -0,0 +1,51 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module PostalMethods
5
+
6
+ class Client
7
+
8
+ require 'rubygems'
9
+ gem 'soap4r'
10
+ require 'soap/rpc/driver'
11
+ require 'soap/wsdlDriver'
12
+
13
+ require 'postalmethods/exceptions.rb'
14
+ require 'postalmethods/document_processor.rb'
15
+ require 'postalmethods/send_letter.rb'
16
+ require 'postalmethods/get_letter_status.rb'
17
+ require 'postalmethods/utility.rb'
18
+
19
+
20
+ # include modules
21
+ include SendLetter
22
+ include DocumentProcessor
23
+ include GetLetterStatus
24
+ include UtilityMethods
25
+
26
+ attr_accessor :api_uri, :username, :password, :to_send, :rpc_driver, :prepared
27
+
28
+ def initialize(opts = {})
29
+ if opts[:username].nil? || opts[:password].nil?
30
+ raise PostalMethods::NoCredentialsException
31
+ end
32
+
33
+ ## declare here so we can override in tests, etc.
34
+ self.api_uri = "http://api.postalmethods.com/PostalWS.asmx?WSDL"
35
+
36
+ self.username = opts[:username]
37
+ self.password = opts[:password]
38
+ end
39
+
40
+ def prepare!
41
+ begin
42
+ self.rpc_driver ||= SOAP::WSDLDriverFactory.new(self.api_uri).create_rpc_driver
43
+ rescue SocketError, RuntimeError
44
+ raise PostalMethods::NoConnectionError
45
+ end
46
+ self.prepared = true
47
+ return self
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ module PostalMethods
2
+ module DocumentProcessor
3
+
4
+ def document=(doc)
5
+ unless doc.class == File
6
+ doc = open(doc)
7
+ end
8
+
9
+ self.to_send = {} if self.to_send.nil?
10
+
11
+ self.to_send[:extension] = doc.path.to_s.split('.').last
12
+ self.to_send[:bytes] = doc.read
13
+ self.to_send[:name] = File.basename(doc.path)
14
+ self.to_send[:file_obj] = doc
15
+ end
16
+
17
+ def document?
18
+ true unless self.to_send.nil?
19
+ end
20
+
21
+ def document
22
+ self.to_send
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,97 @@
1
+ module PostalMethods
2
+
3
+ class GenericCodeError < Exception
4
+ def initialize
5
+ super("You have reached a code error in the ruby gem. Please report to the forums")
6
+ end
7
+ end
8
+
9
+ class NoCredentialsException < Exception
10
+ def initialize
11
+ super("You have failed to provide any credentials")
12
+ end
13
+ end
14
+
15
+ class NoPreparationException < Exception
16
+ def initialize
17
+ super("You must prepare the client first with @client.prepare!")
18
+ end
19
+ end
20
+
21
+ class InvalidLetterIDsRange < Exception
22
+ def initialize
23
+ super("You need to supply an array or a list of ids, comma seperated.")
24
+ end
25
+ end
26
+
27
+ class NoConnectionError < Exception
28
+ def initialize
29
+ super("Error connecting to the API server. If you are sure you are online, Please call support.")
30
+ end
31
+ end
32
+
33
+ ## base api exception - stolen from Halcyon
34
+ ## http://github.com/mtodd/halcyon/tree/master/LICENSE
35
+
36
+ class APIException < Exception
37
+ attr_accessor :status, :body
38
+ def initialize(status, body)
39
+ @status = status
40
+ @body = body
41
+ super "[#{@status}] #{@body}"
42
+ end
43
+ end
44
+
45
+ API_STATUS_CODES = {
46
+ -3000 => "OK: Successfully received the request",
47
+ -3001 => "This user is not authorized to access the specified item",
48
+ -3003 => "Not Authenticated",
49
+ -3004 => "The specified extension is not supported",
50
+ -3010 => "Rejected: no funds available",
51
+ -3020 => "The file specified is unavailable (it may still be being processed, please try later)",
52
+ -3022 => "Cancellation Denied: The letter was physically processed and cannot be cancelled",
53
+ -3113 => "Rejected: the city field contains more than 30 characters",
54
+ -3114 => "Rejected: the state field contains more than 30 characters",
55
+ -3115 => "There was no data returned for your query",
56
+ -3116 => "The specified letter (ID) does not exist in the system",
57
+ -3117 => "Rejected: the company field contains more than 45 characters",
58
+ -3118 => "Rejected: the address1 field contains more than 45 characters",
59
+ -3119 => "Rejected: the address2 field contains more than 45 characters",
60
+ -3120 => "Rejected: the AttentionLine1 field contains more than 45 characters",
61
+ -3121 => "Rejected: the AttentionLine2 field contains more than 45 characters",
62
+ -3122 => "Rejected: the AttentionLine3 field contains more than 45 characters",
63
+ -3123 => "Rejected: the PostalCode/ZIP field contains more than 15 characters",
64
+ -3124 => "Rejected: the Country field contains more than 30 characters",
65
+ -3150 => "General System Error: Contact technical support",
66
+ -3500 => "Warning: too many attempts were made for this method",
67
+ -4001 => "The username field is empty or missing",
68
+ -4002 => "The password field is empty or missing",
69
+ -4003 => "The MyDescription field is empty or missing - please contact support",
70
+ -4004 => "The FileExtension field is empty or missing - please contact support",
71
+ -4005 => "The FileBinaryData field is empty or missing - please contact support",
72
+ -4006 => "The Address1 field is empty or missing",
73
+ -4007 => "The city field is empty or missing",
74
+ -4008 => "The Attention1 or Company fields are empty or missing",
75
+ -4009 => "The ID field is empty or missing.",
76
+ -4010 => "The MinID field is empty or missing",
77
+ -4011 => "The MaxID field is empty or missing",
78
+ }
79
+
80
+ #--
81
+ # Classify Status Codes
82
+ #++
83
+
84
+ API_STATUS_CODES.to_a.each do |http_status|
85
+ status, body = http_status
86
+ class_eval <<-"end;"
87
+ class APIStatusCode#{status.to_s.gsub(/( |\-)/,'')}Exception < PostalMethods::APIException
88
+ def initialize(body=nil)
89
+ body = '#{body}' if body.nil?
90
+ super(#{status}, body)
91
+ end
92
+ end
93
+ end;
94
+ end
95
+
96
+
97
+ end
@@ -0,0 +1,69 @@
1
+ module PostalMethods
2
+
3
+ module GetLetterStatus
4
+
5
+ def get_letter_status(id)
6
+ raise PostalMethods::NoPreparationException unless self.prepared
7
+
8
+ ## get status
9
+ opts = {:Username => self.username, :Password => self.password, :ID => id}
10
+
11
+ rv = @rpc_driver.getLetterStatus(opts)
12
+
13
+ ws_status = rv.getLetterStatusResult.resultCode.to_i
14
+ delivery_status = rv.getLetterStatusResult.status.to_i
15
+ last_update = rv.getLetterStatusResult.lastUpdateTime
16
+
17
+ if ws_status == -3000
18
+ return [delivery_status, last_update]
19
+ elsif API_STATUS_CODES.has_key?(ws_status)
20
+ instance_eval("raise APIStatusCode#{ws_status.to_s.gsub(/( |\-)/,'')}Exception")
21
+ end
22
+
23
+ end
24
+
25
+ def get_letter_status_multiple(ids)
26
+ raise PostalMethods::NoPreparationException unless self.prepared
27
+
28
+ if ids.class == Array
29
+ ids = ids.join(",")
30
+ end
31
+
32
+ # minimal input checking - let api take care of it
33
+ return PostalMethods::InvalidLetterIDsRange unless ids.class == String
34
+
35
+ ## get status
36
+ opts = {:Username => self.username, :Password => self.password, :ID => ids}
37
+
38
+ rv = @rpc_driver.getLetterStatus_Multiple(opts)
39
+
40
+ ws_status = rv.getLetterStatus_MultipleResult.resultCode.to_i
41
+
42
+ if ws_status == -3000
43
+ return rv.getLetterStatus_MultipleResult.letterStatuses.letterStatus
44
+ elsif API_STATUS_CODES.has_key?(ws_status)
45
+ instance_eval("raise APIStatusCode#{ws_status.to_s.gsub(/( |\-)/,'')}Exception")
46
+ end
47
+
48
+ end
49
+
50
+ def get_letter_status_range(minid, maxid)
51
+ raise PostalMethods::NoPreparationException unless self.prepared
52
+
53
+ ## get status
54
+ opts = {:Username => self.username, :Password => self.password, :MinID => minid.to_i, :MaxID => maxid.to_i}
55
+
56
+ rv = @rpc_driver.getLetterStatus_Range(opts)
57
+
58
+ ws_status = rv.getLetterStatus_RangeResult.resultCode.to_i
59
+
60
+ if ws_status == -3000
61
+ return rv.getLetterStatus_RangeResult.letterStatuses.letterStatus
62
+ elsif API_STATUS_CODES.has_key?(ws_status)
63
+ instance_eval("raise APIStatusCode#{ws_status.to_s.gsub(/( |\-)/,'')}Exception")
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+ end