usps-fork 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +89 -0
  4. data/Rakefile +15 -0
  5. data/lib/usps.rb +47 -0
  6. data/lib/usps/address.rb +72 -0
  7. data/lib/usps/client.rb +55 -0
  8. data/lib/usps/configuration.rb +17 -0
  9. data/lib/usps/errors.rb +46 -0
  10. data/lib/usps/request.rb +14 -0
  11. data/lib/usps/request/address_standardization.rb +44 -0
  12. data/lib/usps/request/base.rb +42 -0
  13. data/lib/usps/request/city_and_state_lookup.rb +32 -0
  14. data/lib/usps/request/delivery_confirmation.rb +88 -0
  15. data/lib/usps/request/delivery_confirmation_certify.rb +10 -0
  16. data/lib/usps/request/tracking_field_lookup.rb +28 -0
  17. data/lib/usps/request/tracking_lookup.rb +28 -0
  18. data/lib/usps/request/zip_code_lookup.rb +45 -0
  19. data/lib/usps/response.rb +8 -0
  20. data/lib/usps/response/address_standardization.rb +52 -0
  21. data/lib/usps/response/base.rb +13 -0
  22. data/lib/usps/response/city_and_state_lookup.rb +42 -0
  23. data/lib/usps/response/delivery_confirmation.rb +25 -0
  24. data/lib/usps/response/tracking_field_lookup.rb +34 -0
  25. data/lib/usps/response/tracking_lookup.rb +19 -0
  26. data/lib/usps/test.rb +34 -0
  27. data/lib/usps/test/address_verification.rb +31 -0
  28. data/lib/usps/test/city_and_state_lookup.rb +19 -0
  29. data/lib/usps/test/delivery_confirmation.rb +59 -0
  30. data/lib/usps/test/tracking_lookup.rb +29 -0
  31. data/lib/usps/test/zip_code_lookup.rb +37 -0
  32. data/lib/usps/track_detail.rb +49 -0
  33. data/lib/usps/version.rb +3 -0
  34. data/spec/address_spec.rb +65 -0
  35. data/spec/configuration_spec.rb +19 -0
  36. data/spec/data/address_standardization_1.xml +1 -0
  37. data/spec/data/address_standardization_2.xml +1 -0
  38. data/spec/data/city_and_state_lookup_1.xml +1 -0
  39. data/spec/data/city_and_state_lookup_2.xml +1 -0
  40. data/spec/data/delivery_confirmation_1.xml +1 -0
  41. data/spec/data/delivery_confirmation_2.xml +1 -0
  42. data/spec/data/tracking_field_lookup.xml +41 -0
  43. data/spec/data/tracking_field_lookup_2.xml +17 -0
  44. data/spec/data/tracking_lookup_1.xml +1 -0
  45. data/spec/data/tracking_lookup_2.xml +1 -0
  46. data/spec/request/address_standardization_spec.rb +45 -0
  47. data/spec/request/base_spec.rb +16 -0
  48. data/spec/request/city_and_state_lookup_spec.rb +32 -0
  49. data/spec/request/delivery_confirmation_certify_spec.rb +11 -0
  50. data/spec/request/delivery_confirmation_spec.rb +57 -0
  51. data/spec/request/tracking_field_spec.rb +20 -0
  52. data/spec/request/tracking_spec.rb +21 -0
  53. data/spec/request/zip_code_lookup_spec.rb +42 -0
  54. data/spec/response/address_standardization_spec.rb +54 -0
  55. data/spec/response/base_spec.rb +0 -0
  56. data/spec/response/city_and_state_lookup_spec.rb +27 -0
  57. data/spec/response/delivery_confirmation_spec.rb +43 -0
  58. data/spec/response/tracking_field_lookup_spec.rb +29 -0
  59. data/spec/response/tracking_lookup_spec.rb +27 -0
  60. data/spec/spec.opts +1 -0
  61. data/spec/spec_helper.rb +13 -0
  62. data/spec/track_detail_spec.rb +51 -0
  63. data/spec/usps_spec.rb +8 -0
  64. metadata +147 -0
@@ -0,0 +1,31 @@
1
+ class USPS::Test
2
+ module AddressVerification
3
+ def test_address_standardization_1
4
+ address = USPS::Address.new(
5
+ :address => '6406 Ivy Lane',
6
+ :city => 'Greenbelt',
7
+ :state => 'MD'
8
+ ).standardize!
9
+
10
+ assert_equal '6406 IVY LN', address.address
11
+ assert_equal 'GREENBELT', address.city
12
+ assert_equal 'MD', address.state
13
+ assert_equal '20770', address.zip5
14
+ assert_equal '1440', address.zip4
15
+ end
16
+
17
+ def test_address_standardization_2
18
+ address = USPS::Address.new(
19
+ :address => '8 Wildwood Drive',
20
+ :city => 'Old Lyme',
21
+ :state => 'CT'
22
+ ).standardize!
23
+
24
+ assert_equal '8 WILDWOOD DR', address.address
25
+ assert_equal 'OLD LYME', address.city
26
+ assert_equal 'CT', address.state
27
+ assert_equal '06371', address.zip5
28
+ assert_equal '1844', address.zip4
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ class USPS::Test
2
+ module CityAndStateLookup
3
+ def test_city_and_state_lookup_1
4
+ data = USPS.get_city_and_state_for_zip(90210)
5
+
6
+ assert_equal 90210, data[:zip]
7
+ assert_equal 'BEVERLY HILLS', data[:city]
8
+ assert_equal 'CA', data[:state]
9
+ end
10
+
11
+ def test_city_and_state_lookup_2
12
+ data = USPS.get_city_and_state_for_zip(20770)
13
+
14
+ assert_equal 20770, data.zip
15
+ assert_equal 'GREENBELT', data.city
16
+ assert_equal 'MD', data.state
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ class USPS::Test
2
+ # This module is here only for completeness. The USPS test server does not
3
+ # currently support the label printing APIs despite what the documentation
4
+ # says.
5
+ module DeliveryConfirmation
6
+ def test_delivery_confirmation_1
7
+ from = USPS::Address.new(
8
+ :name => 'John Smith',
9
+ :address => "475 L'Enfant Plaza, SW",
10
+ :city => 'Washington',
11
+ :state => 'DC',
12
+ :zip => '20260'
13
+ )
14
+
15
+ to = USPS::Address.new(
16
+ :name => 'Joe Customer',
17
+ :address => '6060 PRIMACY PKWY',
18
+ :address2 => 'STE 201',
19
+ :state => 'TN',
20
+ :city => 'MEMPHIS'
21
+ )
22
+
23
+ request = USPS::Request::DeliveryConfirmationCertify.new(to, from, 2)
24
+ request.send!
25
+ end
26
+
27
+ def test_delivery_confirmation_2
28
+ from = USPS::Address.new(
29
+ :name => 'John Smith',
30
+ :company => 'U.S. Postal Headquarters',
31
+ :address => "475 L'Enfant Plaza, SW",
32
+ :city => 'Washington',
33
+ :state => 'DC',
34
+ :zip => '20260-0004'
35
+ )
36
+
37
+ to = USPS::Address.new(
38
+ :name => 'Joe Customer',
39
+ :address => '6060 PRIMACY PKWY',
40
+ :address2 => 'STE 201',
41
+ :state => 'TN',
42
+ :city => 'MEMPHIS',
43
+ :zip => '38119-5718'
44
+ )
45
+
46
+ options = {
47
+ :service_type => 'Priority',
48
+ :po_zip_code => 20260,
49
+ :format => 'tif',
50
+ :label_date => '07/08/2004',
51
+ :customer_reference => 'A45-3928',
52
+ :address_service => true
53
+ }
54
+
55
+ request = USPS::Request::DeliveryConfirmationCertify.new(to, from, 2, options)
56
+ request.send!
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,29 @@
1
+ class USPS::Test
2
+ module TrackingLookup
3
+ def test_tracking_lookup_1
4
+ tracker_id = "EJ958083578US"
5
+ request = USPS::Request::TrackingLookup.new(tracker_id)
6
+ results = request.send!
7
+
8
+ assert_equal "Your item was delivered at 8:10 am on June 1 in Wilmington DE 19801.", results.summary
9
+ assert_equal 3, results.details.length
10
+
11
+ assert_equal "May 30 11:07 am NOTICE LEFT WILMINGTON DE 19801.", results.details[0]
12
+ assert_equal "May 30 10:08 am ARRIVAL AT UNIT WILMINGTON DE 19850.", results.details[1]
13
+ assert_equal "May 29 9:55 am ACCEPT OR PICKUP EDGEWATER NJ 07020.", results.details[2]
14
+ end
15
+
16
+ def test_tracking_lookup_2
17
+ tracker_id = "EJ958088694US"
18
+ request = USPS::Request::TrackingLookup.new(tracker_id)
19
+ results = request.send!
20
+
21
+ assert_equal "Your item was delivered at 1:39 pm on June 1 in WOBURN MA 01815.", results.summary
22
+ assert_equal 3, results.details.length
23
+
24
+ assert_equal "May 30 7:44 am NOTICE LEFT WOBURN MA 01815.", results.details[0]
25
+ assert_equal "May 30 7:36 am ARRIVAL AT UNIT NORTH READING MA 01889.", results.details[1]
26
+ assert_equal "May 29 6:00 pm ACCEPT OR PICKUP PORTSMOUTH NH 03801.", results.details[2]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ class USPS::Test
2
+ module ZipCodeLookup
3
+ def test_zip_code_lookup_1
4
+ address = USPS::Address.new(
5
+ :address => '6406 Ivy Lane',
6
+ :city => 'Greenbelt',
7
+ :state => 'MD'
8
+ )
9
+
10
+ request = USPS::Request::ZipCodeLookup.new(address)
11
+ address = request.send![address]
12
+
13
+ assert_equal '6406 IVY LN', address.address
14
+ assert_equal 'GREENBELT', address.city
15
+ assert_equal 'MD', address.state
16
+ assert_equal '20770', address.zip5
17
+ assert_equal '1440', address.zip4
18
+ end
19
+
20
+ def test_zip_code_lookup_2
21
+ address = USPS::Address.new(
22
+ :address => '8 Wildwood Drive',
23
+ :city => 'Old Lyme',
24
+ :state => 'CT'
25
+ )
26
+
27
+ request = USPS::Request::ZipCodeLookup.new(address)
28
+ address = request.send![address]
29
+
30
+ assert_equal '8 WILDWOOD DR', address.address
31
+ assert_equal 'OLD LYME', address.city
32
+ assert_equal 'CT', address.state
33
+ assert_equal '06371', address.zip5
34
+ assert_equal '1844', address.zip4
35
+ end
36
+ end
37
+ 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
@@ -0,0 +1,3 @@
1
+ module USPS
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe USPS::Address do
4
+ it "should have the expected fields" do
5
+ address = USPS::Address.new
6
+
7
+ expect(address).to respond_to(
8
+ :name, :name=,
9
+ :address1, :address1=,
10
+ :address2, :address2=,
11
+ :city, :city=,
12
+ :state, :state=,
13
+ :zip5, :zip5=,
14
+ :zip4, :zip4=
15
+ )
16
+ end
17
+
18
+ it "should be initializable with a hash" do
19
+ address = USPS::Address.new(
20
+ :name => 'Chris',
21
+ :address => '123 Main St',
22
+ :city => 'Holland'
23
+ )
24
+
25
+ expect(address.name).to eq('Chris')
26
+ expect(address.address).to eq('123 Main St')
27
+ expect(address.city).to eq('Holland')
28
+ end
29
+
30
+ it "know how to combine the zip coes" do
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
+ end
34
+
35
+ it "should be able to parse zip into individual parts" do
36
+ addy = USPS::Address.new(:zip => '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
+ end
41
+
42
+ it "should be able to be verified with the USPS" do
43
+ addy = USPS::Address.new(
44
+ :name => 'President Lincoln',
45
+ :address => '1600 Pennsylvania Avenue NW',
46
+ :city => 'Washington',
47
+ :state => 'DC',
48
+ :zip => 20006
49
+ )
50
+
51
+ expect(USPS.client).to receive(:request).and_return(
52
+ USPS::Response::AddressStandardization.new(
53
+ addy, load_xml('address_standardization_1.xml')
54
+ )
55
+ )
56
+
57
+ expect(addy.valid?).to be_truthy
58
+
59
+ error = USPS::Error.new('error', '1234', 'source')
60
+ # Failure
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
+ end
65
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe USPS::Configuration do
4
+ before(:each) do
5
+ ENV['USPS_USER'] = nil
6
+ @config = USPS::Configuration.new
7
+ end
8
+
9
+ it "should have some sensible defaults" do
10
+ expect(@config.username).to be_nil
11
+ expect(@config.timeout).to eq(5)
12
+ expect(@config.testing).to be_falsey
13
+ end
14
+
15
+ it "should grab the username from the environment if available" do
16
+ ENV['USPS_USER'] = 'malcom77'
17
+ expect(USPS::Configuration.new.username).to eq('malcom77')
18
+ end
19
+ end
@@ -0,0 +1 @@
1
+ <?xml version="1.0"?><AddressValidateResponse><Address ID="0"><Address2>6406 IVY LN</Address2><City>GREENBELT</City><State>MD</State><Zip5>20770</Zip5><Zip4>1441</Zip4></Address></AddressValidateResponse>
@@ -0,0 +1 @@
1
+ <?xml version="1.0"?><AddressValidateResponse><Address ID="0"><Address2>8 WILDWOOD DR</Address2><City>OLD LYME</City><State>CT</State><Zip5>06371</Zip5><Zip4>1844</Zip4></Address></AddressValidateResponse>
@@ -0,0 +1 @@
1
+ <?xml version="1.0"?><CityStateLookupResponse><ZipCode ID="0"><Zip5>90210</Zip5><City>BEVERLY HILLS</City><State>CA</State></ZipCode></CityStateLookupResponse>
@@ -0,0 +1 @@
1
+ <?xml version="1.0"?><CityStateLookupResponse><ZipCode ID="0"><Zip5>20770</Zip5><City>GREENBELT</City><State>MD</State></ZipCode></CityStateLookupResponse>
@@ -0,0 +1 @@
1
+ <DeliveryConfirmationV3.0Response><DeliveryConfirmationNumber>420381199101805213907126809651</DeliveryConfirmationNumber><DeliveryConfirmationLabel>TEFCRUwgREFUQSBHT0VTIEhFUkU=</DeliveryConfirmationLabel><ToName>Joe Customer</ToName><ToFirm /><ToAddress1>STE 201</ToAddress1><ToAddress2>6060 PRIMACY PKWY</ToAddress2><ToCity>Memphis</ToCity><ToState>TN</ToState><ToZip5>38119</ToZip5><ToZip4>5718</ToZip4><Postnet>38119571851</Postnet></DeliveryConfirmationV3.0Response>
@@ -0,0 +1 @@
1
+ <DeliveryConfirmationV3.0Response><DeliveryConfirmationNumber>420381199101805213907116323891</DeliveryConfirmationNumber><DeliveryConfirmationLabel>TEFCRUwgREFUQSBHT0VTIEhFUkU=</DeliveryConfirmationLabel><ToName>Joe Customer</ToName><ToFirm>U.S. Postal Service NCSC</ToFirm><ToAddress1>STE 201</ToAddress1><ToAddress2>6060 PRIMACY PKWY</ToAddress2><ToCity>MEMPHIS</ToCity><ToState>TN</ToState><ToZip5>38119</ToZip5><ToZip4>5718</ToZip4><Postnet>38119571851</Postnet></DeliveryConfirmationV3.0Response>
@@ -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>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0"?>
2
+ <TrackResponse>
3
+ <TrackInfo ID="01805213907042762274">
4
+ <TrackSummary>
5
+ <EventTime></EventTime>
6
+ <EventDate></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
+ </TrackInfo>
17
+ </TrackResponse>
@@ -0,0 +1 @@
1
+ <?xml version="1.0"?><TrackResponse><TrackInfo ID="EJ958083578US"><TrackSummary>Your item was delivered at 8:10 am on June 1 in Wilmington DE 19801.</TrackSummary><TrackDetail>May 30 11:07 am NOTICE LEFT WILMINGTON DE 19801.</TrackDetail><TrackDetail>May 30 10:08 am ARRIVAL AT UNIT WILMINGTON DE 19850.</TrackDetail><TrackDetail>May 29 9:55 am ACCEPT OR PICKUP EDGEWATER NJ 07020.</TrackDetail></TrackInfo></TrackResponse>
@@ -0,0 +1 @@
1
+ <?xml version="1.0"?><TrackResponse><TrackInfo ID="EJ958088694US"><TrackSummary>Your item was delivered at 1:39 pm on June 1 in WOBURN MA 01815.</TrackSummary><TrackDetail>May 30 7:44 am NOTICE LEFT WOBURN MA 01815.</TrackDetail><TrackDetail>May 30 7:36 am ARRIVAL AT UNIT NORTH READING MA 01889.</TrackDetail><TrackDetail>May 29 6:00 pm ACCEPT OR PICKUP PORTSMOUTH NH 03801.</TrackDetail></TrackInfo></TrackResponse>
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe USPS::Request::AddressStandardization do
4
+ it "should be using the proper USPS api settings" do
5
+ USPS::Request::AddressStandardization.tap do |klass|
6
+ expect(klass.secure).to be_falsey
7
+ expect(klass.api).to eq('Verify')
8
+ expect(klass.tag).to eq('AddressValidateRequest')
9
+ end
10
+ end
11
+
12
+ it "should not allow more than 5 addresses" do
13
+ expect do
14
+ USPS::Request::AddressStandardization.new([USPS::Address.new] * 6)
15
+ end.to raise_exception(ArgumentError)
16
+ end
17
+
18
+ it "should be able to build a proper request" do
19
+ request = USPS::Request::AddressStandardization.new(
20
+ USPS::Address.new(
21
+ :name => 'Joe Jackson',
22
+ :company => 'Widget Tel Co.',
23
+ :address => '999 Serious Business Av',
24
+ :address2 => 'Suite 2000',
25
+ :city => 'Awesome Town',
26
+ :state => 'FL',
27
+ :zip => '12345-9900'
28
+ )
29
+ )
30
+
31
+ xml = Nokogiri::XML.parse(request.build)
32
+
33
+ xml.search('Address').first.tap do |node|
34
+ expect(node.attr('ID')).to eq('0')
35
+
36
+ expect(node.search('FirmName').text).to eq('Widget Tel Co.')
37
+ expect(node.search('Address1').text).to eq('Suite 2000')
38
+ expect(node.search('Address2').text).to eq('999 Serious Business Av')
39
+ expect(node.search('City').text).to eq('Awesome Town')
40
+ expect(node.search('State').text).to eq('FL')
41
+ expect(node.search('Zip5').text).to eq('12345')
42
+ expect(node.search('Zip4').text).to eq('9900')
43
+ end
44
+ end
45
+ end