usps 0.1.2 → 0.1.3

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 (39) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +84 -0
  3. data/Rakefile +6 -8
  4. data/lib/usps.rb +6 -5
  5. data/lib/usps/address.rb +1 -1
  6. data/lib/usps/configuration.rb +1 -1
  7. data/lib/usps/request.rb +2 -1
  8. data/lib/usps/request/tracking_field_lookup.rb +28 -0
  9. data/lib/usps/response.rb +1 -0
  10. data/lib/usps/response/address_standardization.rb +15 -1
  11. data/lib/usps/response/city_and_state_lookup.rb +16 -2
  12. data/lib/usps/response/tracking_field_lookup.rb +34 -0
  13. data/lib/usps/response/tracking_lookup.rb +1 -1
  14. data/lib/usps/track_detail.rb +49 -0
  15. data/lib/usps/version.rb +1 -1
  16. data/spec/address_spec.rb +14 -14
  17. data/spec/configuration_spec.rb +4 -4
  18. data/spec/data/tracking_field_lookup.xml +41 -0
  19. data/spec/data/tracking_field_lookup_2.xml +17 -0
  20. data/spec/request/address_standardization_spec.rb +13 -13
  21. data/spec/request/base_spec.rb +2 -2
  22. data/spec/request/city_and_state_lookup_spec.rb +10 -10
  23. data/spec/request/delivery_confirmation_certify_spec.rb +3 -3
  24. data/spec/request/delivery_confirmation_spec.rb +27 -27
  25. data/spec/request/tracking_field_spec.rb +20 -0
  26. data/spec/request/tracking_spec.rb +5 -5
  27. data/spec/request/zip_code_lookup_spec.rb +11 -11
  28. data/spec/response/address_standardization_spec.rb +9 -9
  29. data/spec/response/city_and_state_lookup_spec.rb +6 -6
  30. data/spec/response/delivery_confirmation_spec.rb +19 -19
  31. data/spec/response/tracking_field_lookup_spec.rb +28 -0
  32. data/spec/response/tracking_lookup_spec.rb +10 -10
  33. data/spec/track_detail_spec.rb +51 -0
  34. data/spec/usps_spec.rb +1 -1
  35. metadata +66 -90
  36. data/README.rdoc +0 -60
  37. data/lib/usps/request/signature_confirmation.rb +0 -44
  38. data/spec/request/signature_confirmation_spec.rb +0 -0
  39. data/spec/response/signature_confirmation_spec.rb +0 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 32013f6daa8af9cd35517d0b37b200bf9db91974
4
+ data.tar.gz: d9309024e63911cf3cb3d3b150160e77963f4ee3
5
+ SHA512:
6
+ metadata.gz: 391f24ffa46925ac60facbfa9ee5ab1add219781d35c216b093257c12866ffc329f59f2ca8d89165567bbae8a051f57be706329366c3d7e84d3edfb28dee21d6
7
+ data.tar.gz: c1f48611b6b72cd797266ddb77efba8d5a7736fdedfeaebc4a3d839e63c543720cdedfa9c5f2e93be35d436c02c02c626ab41cd4652bc60c288ede67098a6992
@@ -0,0 +1,84 @@
1
+ # usps
2
+
3
+ [![Build Status](https://travis-ci.org/gaffneyc/usps.svg?branch=master)](https://travis-ci.org/gaffneyc/usps)
4
+
5
+ Ruby API for accessing the USPS WebTools API found here: https://www.usps.com/business/webtools.htm
6
+
7
+ PDF Guides can be found here: https://www.usps.com/business/webtools-technical-guides.htm
8
+
9
+ Usage of this library assumes you already have a USPS API account and that all priviledges have been granted.
10
+
11
+ ## Project Status - Looking for a Maintainer
12
+
13
+ This code is no longer properly maintained as I'm no longer with the company it was developed for.
14
+ If you're using it and would be interested in maintaining it please send me a message and I can
15
+ get you set up.
16
+
17
+ ## Exposed API Calls
18
+
19
+ The following USPS API calls are currently exposed through this library:
20
+
21
+ ```
22
+ <AddressValidateRequest> -- USPS::Request::AddressStandardization
23
+ <CityStateLookupRequest> -- USPS::Request::CityAndStateLookup
24
+ <ZipCodeLookupRequest> -- USPS::Request::ZipCodeLookup
25
+ <TrackRequest> -- USPS::Request::TrackingLookup
26
+ <TrackFieldRequest> -- USPS::Request::TrackingFieldLookup
27
+
28
+ <DeliveryConfirmationV3.0Request> -- USPS::Request::DeliveryConfirmation (for production)
29
+ <DeliveryConfirmCertifyV3.0Request> -- USPS::Request::DeliveryConfirmationCertify (for testing)
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ Using the library is as simple as building a new USPS::Request::[type] object, calling #send! and using the response.
35
+ For example, to send a tracking request you'd do the following:
36
+
37
+ ```ruby
38
+ request = USPS::Request::TrackingLookup.new(tracking_number)
39
+ response = request.send!
40
+
41
+ response.summary
42
+ response.details
43
+ ```
44
+
45
+ The library assumes that either ENV['USPS_USER'] is set, or that you set USPS.username to your USPS API username.
46
+
47
+ See the individual USPS::Request classes for details on how to use them.
48
+
49
+ ## USPS API Certification
50
+
51
+ Part of the process of setting up an account with the USPS API is to run certain tests against the USPS API.
52
+ This library has all the requisite tests built in, runnable with rake:
53
+
54
+ ```
55
+ $ USPS_USER="[username]" rake certify
56
+ ```
57
+
58
+ or as an installed gem:
59
+
60
+ ```
61
+ $ USPS_USER="[username]" ruby -rubygems -e "require 'usps/test'"
62
+ ```
63
+
64
+ If any of the tests fail, you don't have access to that API and may need to work with USPS to fix it.
65
+
66
+ ## Note on Patches/Pull Requests
67
+
68
+ * Fork the project.
69
+ * Make your feature addition or bug fix.
70
+ * Add tests for it. This is important so I don't break it in a
71
+ future version unintentionally.
72
+ * Commit, do not mess with rakefile, version, or history.
73
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
74
+ * Send me a pull request. Bonus points for topic branches.
75
+
76
+ ## Testing
77
+
78
+ ```
79
+ $ rspec
80
+ ```
81
+
82
+ ## Copyright
83
+
84
+ Copyright (c) 2014 Chris Gaffney. See LICENSE for details.
data/Rakefile CHANGED
@@ -2,16 +2,14 @@ require 'bundler/setup'
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
4
  require 'rake'
5
- require 'spec/rake/spectask'
6
-
7
- Spec::Rake::SpecTask.new(:spec) do |spec|
8
- spec.libs << 'lib' << 'spec'
9
- spec.spec_files = FileList['spec/**/*_spec.rb']
10
- end
11
-
12
- task :default => :spec
5
+ require 'rspec/core/rake_task'
13
6
 
14
7
  desc "Run the certification tests against USPS's API. Requires ENV['USPS_USER'] to be set or passed in."
15
8
  task :certify do
16
9
  ruby "-rubygems -Ilib lib/usps/test.rb"
17
10
  end
11
+
12
+ desc "Run RSpec tests"
13
+ RSpec::Core::RakeTask.new
14
+
15
+ task :default => :spec
@@ -5,11 +5,12 @@ module USPS
5
5
  require 'usps/errors'
6
6
  require 'usps/configuration'
7
7
 
8
- autoload :Client, 'usps/client'
9
- autoload :Address, 'usps/address'
10
- autoload :Request, 'usps/request'
11
- autoload :VERSION, 'usps/version'
12
- autoload :Response, 'usps/response'
8
+ autoload :Client, 'usps/client'
9
+ autoload :Address, 'usps/address'
10
+ autoload :Request, 'usps/request'
11
+ autoload :VERSION, 'usps/version'
12
+ autoload :Response, 'usps/response'
13
+ autoload :TrackDetail, 'usps/track_detail'
13
14
 
14
15
  class << self
15
16
  attr_writer :config
@@ -4,7 +4,7 @@
4
4
  # the apartment, suite, etc... I have switched them to match how I see them on an envelope.
5
5
  # Additionally they are refered to address and extra_address though both address1 and address2
6
6
  # work. Just remember they are flip flopped based on the USPS documentation.
7
- class USPS::Address < Struct.new(:name, :company, :address1, :address2, :city, :state, :zip5, :zip4)
7
+ class USPS::Address < Struct.new(:name, :company, :address1, :address2, :city, :state, :zip5, :zip4, :return_text)
8
8
 
9
9
  # Alias address getters and setters for a slightly more expressive api
10
10
  alias :address :address1
@@ -6,7 +6,7 @@ module USPS
6
6
  # (only specific requests are supported).
7
7
  class Configuration < Struct.new(:username, :timeout, :testing)
8
8
  def initialize
9
- self.timeout = 5000
9
+ self.timeout = 5
10
10
  self.testing = false
11
11
  self.username = ENV['USPS_USER']
12
12
  end
@@ -9,5 +9,6 @@ module USPS::Request
9
9
  autoload :DeliveryConfirmation, 'usps/request/delivery_confirmation'
10
10
  autoload :DeliveryConfirmationCertify, 'usps/request/delivery_confirmation_certify'
11
11
 
12
- autoload :TrackingLookup, 'usps/request/tracking_lookup'
12
+ autoload :TrackingLookup, 'usps/request/tracking_lookup'
13
+ autoload :TrackingFieldLookup, 'usps/request/tracking_field_lookup'
13
14
  end
@@ -0,0 +1,28 @@
1
+ module USPS::Request
2
+ # Given a valid USPS tracking number, use this class to request
3
+ # tracking information from USPS's systems.
4
+ #
5
+ # Returns a USPS::Response::TrackingFieldLookup object with the pertinent
6
+ # information
7
+ class TrackingFieldLookup < Base
8
+ config(
9
+ :api => 'TrackV2',
10
+ :tag => 'TrackFieldRequest',
11
+ :secure => false,
12
+ :response => USPS::Response::TrackingFieldLookup
13
+ )
14
+
15
+ # Build a new TrackingLookup request.
16
+ # Takes the USPS tracking number to request information for
17
+ def initialize(track_id)
18
+ @track_id = track_id
19
+ end
20
+
21
+ def build
22
+ super do |builder|
23
+ builder.tag!('TrackID', :ID => @track_id)
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -4,4 +4,5 @@ module USPS::Response
4
4
  autoload :DeliveryConfirmation, 'usps/response/delivery_confirmation'
5
5
  autoload :AddressStandardization, 'usps/response/address_standardization'
6
6
  autoload :TrackingLookup, 'usps/response/tracking_lookup'
7
+ autoload :TrackingFieldLookup, 'usps/response/tracking_field_lookup'
7
8
  end
@@ -21,6 +21,19 @@ module USPS::Response
21
21
  @addresses[address]
22
22
  end
23
23
  alias :[] :get
24
+
25
+ def addresses
26
+ @addresses
27
+ end
28
+
29
+ def to_h
30
+ hash = {}
31
+ @addresses.each_pair do |key, value|
32
+ hash[key.to_h] = value.to_h
33
+ end
34
+
35
+ hash
36
+ end
24
37
 
25
38
  private
26
39
  def parse(node)
@@ -31,7 +44,8 @@ module USPS::Response
31
44
  :city => node.search('City').text,
32
45
  :state => node.search('State').text,
33
46
  :zip5 => node.search('Zip5').text,
34
- :zip4 => node.search('Zip4').text
47
+ :zip4 => node.search('Zip4').text,
48
+ :return_text => node.search('ReturnText').text,
35
49
  )
36
50
  end
37
51
  end
@@ -17,12 +17,26 @@ module USPS::Response
17
17
  end
18
18
  end
19
19
 
20
- # Returns an address representing the standardized version of the given
21
- # address from the results of the query.
20
+ # Returns a single city/state pair given a zip5
22
21
  def get(zip)
23
22
  @data[zip.to_i]
24
23
  end
25
24
  alias :[] :get
25
+
26
+ # Returns all city/state data from the query results
27
+ def data
28
+ @data
29
+ end
30
+
31
+ # Returns all city/state data as a pure Ruby hash (e.g. no Structs as values)
32
+ def to_h
33
+ hash = {}
34
+ @data.each_pair do |key, value|
35
+ hash[key] = value.to_h
36
+ end
37
+
38
+ hash
39
+ end
26
40
  end
27
41
  end
28
42
 
@@ -0,0 +1,34 @@
1
+ module USPS::Response
2
+ # Response object from a USPS::Request::TrackingLookup request.
3
+ # Includes a summary of the current status of the shipment, along with
4
+ # an array of details of the shipment's progress
5
+ class TrackingFieldLookup < Base
6
+
7
+ attr_accessor :summary, :details
8
+
9
+
10
+ def initialize(xml)
11
+ @summary = parse(xml.search("TrackSummary"))
12
+ @details = []
13
+ xml.search("TrackDetail").each do |detail|
14
+ @details << parse(detail)
15
+ end
16
+ end
17
+
18
+ private
19
+ def parse(node)
20
+ USPS::TrackDetail.new(
21
+ :event_time => node.search('EventTime').text,
22
+ :event_date => node.search('EventDate').text,
23
+ :event => node.search('Event').text,
24
+ :event_city => node.search('EventCity').text,
25
+ :event_state => node.search('EventState').text,
26
+ :event_zip_code => node.search('EventZIPCode').text,
27
+ :event_country => node.search('EventCountry').text,
28
+ :firm_name => node.search('FirmName').text,
29
+ :name => node.search('Name').text,
30
+ :authorized_agent => node.search('AuthorizedAgent').text
31
+ )
32
+ end
33
+ end
34
+ end
@@ -14,6 +14,6 @@ module USPS::Response
14
14
  @details << detail.text
15
15
  end
16
16
  end
17
-
17
+
18
18
  end
19
19
  end
@@ -0,0 +1,49 @@
1
+ require 'time'
2
+ # TODO: Documentation
3
+ #
4
+ class USPS::TrackDetail < Struct.new(:event_time, :event_date, :event, :event_city, :event_state, :event_zip_code, :event_country, :firm_name, :name, :authorized_agent)
5
+
6
+ # Alias address getters and setters for a slightly more expressive api
7
+ alias :city :event_city
8
+ alias :city= :event_city=
9
+ alias :state :event_state
10
+ alias :state= :event_state=
11
+ alias :zip_code :event_zip_code
12
+ alias :zip_code= :event_zip_code=
13
+ alias :country :event_country
14
+ alias :country= :event_country=
15
+
16
+ attr_reader :error
17
+
18
+ def initialize(options = {}, &block)
19
+ options.each_pair do |k, v|
20
+ self.send("#{k}=", v)
21
+ end
22
+
23
+ block.call(self) if block
24
+ end
25
+
26
+ def date
27
+ time = "#{event_date} #{event_time}".strip
28
+ begin
29
+ Time.parse(time) unless time.empty?
30
+ rescue ArgumentError
31
+ return nil
32
+ end
33
+ end
34
+
35
+ # Similar to Hash#replace, overwrite the values of this object with the other.
36
+ # It will not replace a provided key on the original object that does not exist
37
+ # on the replacing object (such as name with verification requests).
38
+ def replace(other)
39
+ raise ArgumentError unless other.is_a?(USPS::Address)
40
+
41
+ other.each_pair do |key, val|
42
+ # Do not overwrite values that may exist on the original but not on
43
+ # the replacement.
44
+ self[key] = val unless val.nil?
45
+ end
46
+
47
+ self
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module USPS
2
- VERSION = '0.1.2'
2
+ VERSION = '0.1.3'
3
3
  end
@@ -4,7 +4,7 @@ describe USPS::Address do
4
4
  it "should have the expected fields" do
5
5
  address = USPS::Address.new
6
6
 
7
- address.should respond_to(
7
+ expect(address).to respond_to(
8
8
  :name, :name=,
9
9
  :address1, :address1=,
10
10
  :address2, :address2=,
@@ -22,21 +22,21 @@ describe USPS::Address do
22
22
  :city => 'Holland'
23
23
  )
24
24
 
25
- address.name.should == 'Chris'
26
- address.address.should == '123 Main St'
27
- address.city.should == 'Holland'
25
+ expect(address.name).to eq('Chris')
26
+ expect(address.address).to eq('123 Main St')
27
+ expect(address.city).to eq('Holland')
28
28
  end
29
29
 
30
30
  it "know how to combine the zip coes" do
31
- USPS::Address.new(:zip5 => 12345).zip.should == '12345'
32
- USPS::Address.new(:zip5 => 12345, :zip4 => 9999).zip.should == '12345-9999'
31
+ expect(USPS::Address.new(:zip5 => 12345).zip).to eq('12345')
32
+ expect(USPS::Address.new(:zip5 => 12345, :zip4 => 9999).zip).to eq('12345-9999')
33
33
  end
34
34
 
35
35
  it "should be able to parse zip into individual parts" do
36
36
  addy = USPS::Address.new(:zip => '12345-9988')
37
- addy.zip5.should == '12345'
38
- addy.zip4.should == '9988'
39
- addy.zip.should == '12345-9988'
37
+ expect(addy.zip5).to eq('12345')
38
+ expect(addy.zip4).to eq('9988')
39
+ expect(addy.zip).to eq('12345-9988')
40
40
  end
41
41
 
42
42
  it "should be able to be verified with the USPS" do
@@ -48,18 +48,18 @@ describe USPS::Address do
48
48
  :zip => 20006
49
49
  )
50
50
 
51
- USPS.client.should_receive(:request).and_return(
51
+ expect(USPS.client).to receive(:request).and_return(
52
52
  USPS::Response::AddressStandardization.new(
53
53
  addy, load_xml('address_standardization_1.xml')
54
54
  )
55
55
  )
56
56
 
57
- addy.valid?.should be_true
57
+ expect(addy.valid?).to be_truthy
58
58
 
59
59
  error = USPS::Error.new('error', '1234', 'source')
60
60
  # Failure
61
- USPS.client.should_receive(:request).and_raise(error)
62
- addy.valid?.should be_false
63
- addy.error.should be(error)
61
+ expect(USPS.client).to receive(:request).and_raise(error)
62
+ expect(addy.valid?).to be_falsey
63
+ expect(addy.error).to be(error)
64
64
  end
65
65
  end
@@ -7,13 +7,13 @@ describe USPS::Configuration do
7
7
  end
8
8
 
9
9
  it "should have some sensible defaults" do
10
- @config.username.should be_nil
11
- @config.timeout.should == 5000
12
- @config.testing.should be_false
10
+ expect(@config.username).to be_nil
11
+ expect(@config.timeout).to eq(5)
12
+ expect(@config.testing).to be_falsey
13
13
  end
14
14
 
15
15
  it "should grab the username from the environment if available" do
16
16
  ENV['USPS_USER'] = 'malcom77'
17
- USPS::Configuration.new.username.should == 'malcom77'
17
+ expect(USPS::Configuration.new.username).to eq('malcom77')
18
18
  end
19
19
  end
@@ -0,0 +1,41 @@
1
+ <?xml version="1.0"?>
2
+ <TrackResponse>
3
+ <TrackInfo ID="01805213907042762274">
4
+ <TrackSummary>
5
+ <EventTime>12:12 pm</EventTime>
6
+ <EventDate>May 21, 2001</EventDate>
7
+ <Event>DELIVERED</Event>
8
+ <EventCity>NEWTON</EventCity>
9
+ <EventState>IA</EventState>
10
+ <EventZIPCode>50208</EventZIPCode>
11
+ <EventCountry/>
12
+ <FirmName></FirmName>
13
+ <Name></Name>
14
+ <AuthorizedAgent></AuthorizedAgent>
15
+ </TrackSummary>
16
+ <TrackDetail>
17
+ <EventTime>9:24 pm</EventTime>
18
+ <EventDate>March 28, 2001</EventDate>
19
+ <Event>ENROUTE</Event>
20
+ <EventCity>DES MOINES</EventCity>
21
+ <EventState>IA</EventState>
22
+ <EventZIPCode>50395</EventZIPCode>
23
+ <EventCountry/>
24
+ <FirmName/>
25
+ <Name/>
26
+ <AuthorizedAgent/>
27
+ </TrackDetail>
28
+ <TrackDetail>
29
+ <EventTime>10:00 pm</EventTime>
30
+ <EventDate>March 27, 2001</EventDate>
31
+ <Event>ACCEPTANCE</Event>
32
+ <EventCity>BLAINE</EventCity>
33
+ <EventState>WA</EventState>
34
+ <EventZIPCode>98231</EventZIPCode>
35
+ <EventCountry/>
36
+ <FirmName/>
37
+ <Name/>
38
+ <AuthorizedAgent/>
39
+ </TrackDetail>
40
+ </TrackInfo>
41
+ </TrackResponse>