stamps 0.2.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/.gitignore +5 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +49 -0
- data/README.md +186 -0
- data/Rakefile +13 -0
- data/lib/stamps.rb +33 -0
- data/lib/stamps/api.rb +18 -0
- data/lib/stamps/client.rb +12 -0
- data/lib/stamps/client/account.rb +36 -0
- data/lib/stamps/client/address.rb +16 -0
- data/lib/stamps/client/rate.rb +39 -0
- data/lib/stamps/client/stamp.rb +62 -0
- data/lib/stamps/configuration.rb +69 -0
- data/lib/stamps/errors.rb +34 -0
- data/lib/stamps/mapping.rb +247 -0
- data/lib/stamps/request.rb +55 -0
- data/lib/stamps/response.rb +71 -0
- data/lib/stamps/trash.rb +29 -0
- data/lib/stamps/types.rb +68 -0
- data/lib/stamps/version.rb +3 -0
- data/stamps.gemspec +33 -0
- data/test/client/account_test.rb +64 -0
- data/test/client/address_test.rb +36 -0
- data/test/client/rate_test.rb +44 -0
- data/test/client/stamp_test.rb +89 -0
- data/test/fixtures/AuthenticateUser.xml +9 -0
- data/test/fixtures/CancelIndicium.xml +8 -0
- data/test/fixtures/CarrierPickup.xml +11 -0
- data/test/fixtures/CleanseAddress.xml +24 -0
- data/test/fixtures/CreateIndicium.xml +32 -0
- data/test/fixtures/GetAccountInfo.xml +87 -0
- data/test/fixtures/GetRate.xml +163 -0
- data/test/fixtures/GetRates.xml +645 -0
- data/test/fixtures/InsufficientPostage.xml +14 -0
- data/test/fixtures/InvalidSoap.xml +13 -0
- data/test/fixtures/PurchasePostage.xml +16 -0
- data/test/fixtures/TrackShipment.xml +43 -0
- data/test/helper.rb +58 -0
- data/test/mapping_test.rb +33 -0
- data/test/response_test.rb +66 -0
- data/test/stamps_test.rb +26 -0
- data/test/types_test.rb +25 -0
- metadata +228 -0
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.2@stamps --create
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
stamps (0.0.1)
|
5
|
+
hashie (~> 1.0.0)
|
6
|
+
httpi (= 0.7.9)
|
7
|
+
json (~> 1.5.1)
|
8
|
+
multi_json (~> 0.0.5)
|
9
|
+
savon (>= 0.8.6)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: http://rubygems.org/
|
13
|
+
specs:
|
14
|
+
addressable (2.2.4)
|
15
|
+
awesome_print (0.3.2)
|
16
|
+
builder (2.1.2)
|
17
|
+
crack (0.1.8)
|
18
|
+
gyoku (0.4.2)
|
19
|
+
builder (>= 2.1.2)
|
20
|
+
hashie (1.0.0)
|
21
|
+
httpi (0.7.9)
|
22
|
+
rack
|
23
|
+
json (1.5.1)
|
24
|
+
mocha (0.9.12)
|
25
|
+
multi_json (0.0.5)
|
26
|
+
rack (1.2.2)
|
27
|
+
savon (0.8.6)
|
28
|
+
builder (>= 2.1.2)
|
29
|
+
crack (~> 0.1.8)
|
30
|
+
gyoku (>= 0.3.0)
|
31
|
+
httpi (>= 0.7.8)
|
32
|
+
shoulda (2.11.3)
|
33
|
+
simplecov (0.4.1)
|
34
|
+
simplecov-html (~> 0.4.3)
|
35
|
+
simplecov-html (0.4.3)
|
36
|
+
webmock (1.6.2)
|
37
|
+
addressable (>= 2.2.2)
|
38
|
+
crack (>= 0.1.7)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
awesome_print
|
45
|
+
mocha (~> 0.9.11)
|
46
|
+
shoulda (~> 2.11.3)
|
47
|
+
simplecov (~> 0.4.0)
|
48
|
+
stamps!
|
49
|
+
webmock (~> 1.6.2)
|
data/README.md
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
Stamps
|
2
|
+
==========
|
3
|
+
|
4
|
+
Stamps is Stamps.com backed library for creating postage labels,
|
5
|
+
calculate the shipping cost of packages, standardize domestic
|
6
|
+
addresses via USPS CASS certified Address Matching Software, and track
|
7
|
+
shipments.
|
8
|
+
|
9
|
+
Main Features
|
10
|
+
----------
|
11
|
+
|
12
|
+
1. Create postage stamp labels in png and pdf formats.
|
13
|
+
|
14
|
+
2. Standardizes shipping address that complies with the USPS address
|
15
|
+
formatting guidelines.
|
16
|
+
|
17
|
+
3. Validates city, state, and postal code combinations.
|
18
|
+
|
19
|
+
4. Calculate shipping rates based on distance and package weight.
|
20
|
+
|
21
|
+
5. Request USPS carrier pick ups.
|
22
|
+
|
23
|
+
6. Track shipment history.
|
24
|
+
|
25
|
+
7. Purchase postage.
|
26
|
+
|
27
|
+
Pre-requisites
|
28
|
+
----------
|
29
|
+
Register for the Stamps.com [Developer
|
30
|
+
Program](http://developer.stamps.com/developer) to receive a free
|
31
|
+
test account.
|
32
|
+
|
33
|
+
Sample Workflow
|
34
|
+
----------
|
35
|
+
|
36
|
+
1. Standardize Shipping Address - Ship-to addresses must be
|
37
|
+
standardized based on USPS rules for proper address conventions before
|
38
|
+
a shipping label can be issued.
|
39
|
+
|
40
|
+
2. Get Rates - allow users to view and select the best shipping
|
41
|
+
service for their needs.
|
42
|
+
|
43
|
+
3. Generate the Shipping Label - after choosing a shipping
|
44
|
+
service and ship-to address is standardized, the `Stamps.create` method
|
45
|
+
will generate the indicium required to ship the item. If
|
46
|
+
the customer changes their mind, they may want to select an option
|
47
|
+
that initiates a `Stamps.cancel`. `Stamps.cancel` refunds postage and
|
48
|
+
voids the shipping label.
|
49
|
+
|
50
|
+
4. Print the Shipping Label - Call the returned URL to obtain the shipping label image.
|
51
|
+
A URL is returned by the `Stamps.create` call in the :url item. The
|
52
|
+
integration will connect to this URL to retrieve their shipping label
|
53
|
+
and customs forms for printing.
|
54
|
+
|
55
|
+
Getting Started
|
56
|
+
----------
|
57
|
+
Once you have a test account with integration id, we can simple pass
|
58
|
+
them to the configure block:
|
59
|
+
|
60
|
+
# Authenticate you stamps.com credentials
|
61
|
+
Stamps.configure do |config|
|
62
|
+
config.integration_id = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX'
|
63
|
+
config.username = 'STAMPS USERNAME'
|
64
|
+
config.password = 'STAMPS PASSWORD'
|
65
|
+
end
|
66
|
+
|
67
|
+
Now we can now be able to retrieve information about our account:
|
68
|
+
|
69
|
+
Stamps.account
|
70
|
+
|
71
|
+
Standardized Shipping Address
|
72
|
+
----------
|
73
|
+
Standardizes shipping address that complies with the USPS address
|
74
|
+
formatting guidelines
|
75
|
+
|
76
|
+
standardized_address = Stamps.clean_address(
|
77
|
+
:address => {
|
78
|
+
:full_name => 'The White House',
|
79
|
+
:address1 => '1600 Pennsylvania Avenue, NW',
|
80
|
+
:city => 'Washington',
|
81
|
+
:state => 'DC',
|
82
|
+
:zip_code => '20500'
|
83
|
+
})
|
84
|
+
|
85
|
+
Get Rates
|
86
|
+
----------
|
87
|
+
To get a list of rates for all available USPS services based on the
|
88
|
+
ZIP Code or the foreign country being shipped to for a given package
|
89
|
+
weight and size.
|
90
|
+
|
91
|
+
rates = Stamps.get_rates(
|
92
|
+
:from_zip_code => '45440',
|
93
|
+
:to_zip_code => '20500',
|
94
|
+
:weight_lb => '0.5',
|
95
|
+
:ship_date => '2011-04-07'
|
96
|
+
)
|
97
|
+
|
98
|
+
Creating a shipping label
|
99
|
+
----------
|
100
|
+
To generate the postage based on the shipping information provided in the request.
|
101
|
+
The `create!` method will return a URL that references either an image of the
|
102
|
+
domestic shipping label or a multi-page PDF document for international
|
103
|
+
labels with customs forms.
|
104
|
+
|
105
|
+
stamp = Stamps.create!(
|
106
|
+
:tracking_number => true,
|
107
|
+
:rate => rates.first,
|
108
|
+
:to => standardized_address,
|
109
|
+
:from => {
|
110
|
+
:full_name => 'Littlelines',
|
111
|
+
:address1 => '50 Chestnut Street',
|
112
|
+
:address2 => 'Suite 234',
|
113
|
+
:city => 'Beavervcreek',
|
114
|
+
:state => 'OH',
|
115
|
+
:zip_code => '45440'
|
116
|
+
},
|
117
|
+
:memo => 'Thanks for shopping with us!'
|
118
|
+
)
|
119
|
+
|
120
|
+
Now we can view or print the postage label:
|
121
|
+
|
122
|
+
stamp.url
|
123
|
+
|
124
|
+
General Configuration
|
125
|
+
----------
|
126
|
+
If you want to see the data logged to and from the api:
|
127
|
+
|
128
|
+
Stamps.configure do |config|
|
129
|
+
config.log_messages = true
|
130
|
+
end
|
131
|
+
|
132
|
+
By default Stamps will return responses as a Hash. To make Stamps
|
133
|
+
return a Hashie instead:
|
134
|
+
|
135
|
+
Stamps.configure do |config|
|
136
|
+
config.format = :hashie
|
137
|
+
end
|
138
|
+
|
139
|
+
A return address can be specified in the configuration block as
|
140
|
+
well. This address will be used when the :from address is not specified
|
141
|
+
when creating new stamps
|
142
|
+
|
143
|
+
Stamps.configure do |config|
|
144
|
+
config.return_address = {
|
145
|
+
:full_name => 'Littlelines',
|
146
|
+
:address1 => '50 Chestnut Street',
|
147
|
+
:address2 => 'Suite 234',
|
148
|
+
:city => 'Beavercreek',
|
149
|
+
:state => 'OH',
|
150
|
+
:zip_code => '45440',
|
151
|
+
:phone_number => '9375545027'
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
Installation Steps
|
156
|
+
----------
|
157
|
+
First install the gem:
|
158
|
+
|
159
|
+
gem install stamps
|
160
|
+
|
161
|
+
Add it to your Gemfile:
|
162
|
+
|
163
|
+
gem 'stamps'
|
164
|
+
|
165
|
+
Development
|
166
|
+
-----------
|
167
|
+
|
168
|
+
* Source hosted at [GitHub](https://github.com/mattsears/stamps).
|
169
|
+
* Report Issues/Questions/Feature requests on [GitHub Issues](https://github.com/mattsears/stamps/issues).
|
170
|
+
|
171
|
+
Pull requests are very welcome! Make sure your patches are well tested. Please create a topic branch for every separate change
|
172
|
+
you make.
|
173
|
+
|
174
|
+
Author
|
175
|
+
------
|
176
|
+
[Matt Sears](https://github.com/mattsears)
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
task :default => :test
|
6
|
+
|
7
|
+
desc 'Run tests (default)'
|
8
|
+
Rake::TestTask.new(:test) do |t|
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
10
|
+
t.ruby_opts = ['-Itest']
|
11
|
+
t.libs << "lib" << "test"
|
12
|
+
t.ruby_opts << '-rubygems' if defined? Gem
|
13
|
+
end
|
data/lib/stamps.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'stamps/errors'
|
2
|
+
require 'stamps/trash'
|
3
|
+
require 'stamps/configuration'
|
4
|
+
require 'stamps/api'
|
5
|
+
require 'stamps/mapping'
|
6
|
+
require 'stamps/types'
|
7
|
+
require 'stamps/client'
|
8
|
+
|
9
|
+
module Stamps
|
10
|
+
extend Configuration
|
11
|
+
|
12
|
+
API_VERSION = '1_0' # Stamps API version
|
13
|
+
|
14
|
+
# Alias for Stamps::Client.new
|
15
|
+
#
|
16
|
+
# @return [Stamps::Client]
|
17
|
+
#
|
18
|
+
def self.client(options={})
|
19
|
+
Stamps::Client.new(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Delegate to Stamps::Client
|
23
|
+
def self.method_missing(method, *args, &block)
|
24
|
+
return super unless client.respond_to?(method)
|
25
|
+
client.send(method, *args, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Delegate to Stamps::Client
|
29
|
+
def self.respond_to?(method)
|
30
|
+
return client.respond_to?(method) || super
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/stamps/api.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path('../request', __FILE__)
|
2
|
+
|
3
|
+
module Stamps
|
4
|
+
# @private
|
5
|
+
class API
|
6
|
+
# @private
|
7
|
+
attr_accessor *Configuration::VALID_OPTIONS_KEYS
|
8
|
+
|
9
|
+
# Creates a new API
|
10
|
+
def initialize(options={})
|
11
|
+
options = Stamps.options.merge(options)
|
12
|
+
Configuration::VALID_OPTIONS_KEYS.each do |key|
|
13
|
+
send("#{key}=", options[key])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
include Request
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Stamps
|
2
|
+
# Wrapper for the Stamps Web Services API
|
3
|
+
#
|
4
|
+
class Client < API
|
5
|
+
Dir[File.expand_path('../client/*.rb', __FILE__)].each{|f| require f}
|
6
|
+
include Stamps::Mapping
|
7
|
+
include Stamps::Client::Account
|
8
|
+
include Stamps::Client::Address
|
9
|
+
include Stamps::Client::Rate
|
10
|
+
include Stamps::Client::Stamp
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Stamps
|
2
|
+
class Client
|
3
|
+
module Account
|
4
|
+
|
5
|
+
# Returns information about the stamps account
|
6
|
+
#
|
7
|
+
# @param params [Hash] authenticator, address, rates.
|
8
|
+
# @return [Hash]
|
9
|
+
#
|
10
|
+
def account(params = {})
|
11
|
+
params[:authenticator] = authenticator_token
|
12
|
+
response = request('GetAccountInfo', Stamps::Mapping::Account.new(params) )
|
13
|
+
response[:get_account_info_response][:account_info] if response
|
14
|
+
end
|
15
|
+
|
16
|
+
# Add funds to postage account
|
17
|
+
#
|
18
|
+
def purchase_postage(params = {})
|
19
|
+
params[:authenticator] = authenticator_token
|
20
|
+
response = request('PurchasePostage', Stamps::Mapping::PurchasePostage.new(params))
|
21
|
+
response[:purchase_postage_response] if response
|
22
|
+
end
|
23
|
+
|
24
|
+
# Request carrier pickup
|
25
|
+
# TODO: Should this go somewhere else?
|
26
|
+
#
|
27
|
+
def carrier_pickup(params = {})
|
28
|
+
params[:authenticator] = authenticator_token
|
29
|
+
response = request('CarrierPickup', Stamps::Mapping::CarrierPickup.new(params))
|
30
|
+
response[:carrier_pickup_response] if response
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Stamps
|
2
|
+
class Client
|
3
|
+
module Address
|
4
|
+
|
5
|
+
# Authorizes the User and returns authenticator token
|
6
|
+
#
|
7
|
+
def clean_address(params = {})
|
8
|
+
params[:authenticator] = authenticator_token
|
9
|
+
response = request('CleanseAddress', Stamps::Mapping::CleanseAddress.new(params))
|
10
|
+
response[:errors].empty? ? response[:cleanse_address_response] : response
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Stamps
|
2
|
+
class Client
|
3
|
+
|
4
|
+
# Produces a list of rates for all available USPS services based
|
5
|
+
# on the ZIP Code or the foreign country being shipped to for
|
6
|
+
# a given package weight and size.
|
7
|
+
#
|
8
|
+
# == Examples:
|
9
|
+
#
|
10
|
+
# Stamps.get_rates(
|
11
|
+
# :from_zip_code => '45440',
|
12
|
+
# :to_zip_code => '45458',
|
13
|
+
# :weight_oz => '8.0',
|
14
|
+
# :ship_date => '2011-06-01'
|
15
|
+
# )
|
16
|
+
#
|
17
|
+
module Rate
|
18
|
+
|
19
|
+
# Produces a list of rates matching the criteria provided in
|
20
|
+
# the parameters
|
21
|
+
#
|
22
|
+
def get_rates(params = {})
|
23
|
+
rates = Stamps::Mapping::Rates.new({
|
24
|
+
:authenticator => authenticator_token,
|
25
|
+
:rate => Stamps::Mapping::Rate.new(params)
|
26
|
+
})
|
27
|
+
response = request('GetRates', rates)
|
28
|
+
response[:get_rates_response].nil? ? response : [response[:get_rates_response][:rates][:rate]].flatten
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_rate(params = {})
|
32
|
+
rates = get_rates(params)
|
33
|
+
rates.is_a?(Array) ? rates.first : rates
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Stamps
|
2
|
+
class Client
|
3
|
+
|
4
|
+
# == Stamp Module
|
5
|
+
#
|
6
|
+
# Stamp provides an interface to creating and cancelling postage labels
|
7
|
+
#
|
8
|
+
#
|
9
|
+
module Stamp
|
10
|
+
|
11
|
+
# Creates postage labels.
|
12
|
+
#
|
13
|
+
# In order to successfully create postage labels, the following steps
|
14
|
+
# must happen:
|
15
|
+
#
|
16
|
+
# 1. Authentiation - identify the user and ensure that the user is
|
17
|
+
# authorized to perform the operation.
|
18
|
+
#
|
19
|
+
# 2. CleanseAddress - Ship-to addresses must be standardized based on
|
20
|
+
# USPS rules for proper address conventions before a shipping label
|
21
|
+
# can be issued.
|
22
|
+
#
|
23
|
+
# 3. GetRates - A call to GetRates will allow users to view and select
|
24
|
+
# the best shipping service for their needs.
|
25
|
+
#
|
26
|
+
# @param params [Hash] authenticator, address, rates.
|
27
|
+
# @return [Hash]
|
28
|
+
#
|
29
|
+
def create!(params = {})
|
30
|
+
params[:authenticator] = authenticator_token unless params[:authenticator]
|
31
|
+
params[:from] ||= Hash.new
|
32
|
+
response = request('CreateIndicium', Stamps::Mapping::Stamp.new(params))
|
33
|
+
response[:errors].empty? ? response[:create_indicium_response] : response
|
34
|
+
end
|
35
|
+
|
36
|
+
# Refunds postage and voids the shipping label
|
37
|
+
#
|
38
|
+
# @param [Hash] authenticator
|
39
|
+
#
|
40
|
+
def cancel!(params = {})
|
41
|
+
params[:authenticator] = authenticator_token unless params[:authenticator]
|
42
|
+
response = request('CancelIndicium', Stamps::Mapping::CancelStamp.new(params))
|
43
|
+
response[:errors].empty? ? response[:cancel_indicium_response] : response
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns an array of tracking events
|
47
|
+
#
|
48
|
+
# @param [String] the transaction id of the stamp
|
49
|
+
#
|
50
|
+
def track(stamps_transaction_id)
|
51
|
+
params = {
|
52
|
+
:authenticator => authenticator_token,
|
53
|
+
:stamps_transaction_id => stamps_transaction_id
|
54
|
+
}
|
55
|
+
response = request('TrackShipment', Stamps::Mapping::TrackShipment.new(params))
|
56
|
+
response[:errors].empty? ? response[:track_shipment_response] : response
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|