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