usps-fork 0.1.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.
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