postalmethods 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/License.txt +21 -0
- data/Manifest.txt +31 -0
- data/PostInstall.txt +6 -0
- data/README.txt +35 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +15 -0
- data/lib/postalmethods.rb +51 -0
- data/lib/postalmethods/document_processor.rb +25 -0
- data/lib/postalmethods/exceptions.rb +97 -0
- data/lib/postalmethods/get_letter_status.rb +69 -0
- data/lib/postalmethods/send_letter.rb +46 -0
- data/lib/postalmethods/utility.rb +60 -0
- data/lib/postalmethods/version.rb +9 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/setup.rb +1585 -0
- data/spec/document_processor_spec.rb +37 -0
- data/spec/get_letter_status_spec.rb +74 -0
- data/spec/postalmethods_spec.rb +26 -0
- data/spec/rcov.opts +1 -0
- data/spec/send_letter_spec.rb +75 -0
- data/spec/spec.opts +7 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/utility_spec.rb +62 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +33 -0
- metadata +103 -0
data/History.txt
ADDED
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
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
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
|