Business-US-USPS-WebTools-1.125/0000755000175000017500000000000014051301664016130 5ustar smsimmssmsimmsBusiness-US-USPS-WebTools-1.125/examples/0000755000175000017500000000000014051301664017746 5ustar smsimmssmsimmsBusiness-US-USPS-WebTools-1.125/examples/track.pl0000644000175000017500000000075413723267663021434 0ustar smsimmssmsimms#!perl use v5.10; use Data::Dumper; use Business::US::USPS::WebTools::TrackConfirm; my $tracker = Business::US::USPS::WebTools::TrackConfirm->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, # Testing => 1, } ); say "ARGV is @ARGV"; my $tracking_number = $tracker->is_valid_tracking_number( $ARGV[0] ); say "Tracking number is $tracking_number"; my $data = $tracker->track( TrackID => $ARGV[0] ); say $tracker->response; say Dumper( $data ); Business-US-USPS-WebTools-1.125/examples/address_standardization.pl0000644000175000017500000000172613723267663025233 0ustar smsimmssmsimms#!/usr/bin/perl use Business::US::USPS::WebTools::AddressStandardization; my $verifier = Business::US::USPS::WebTools::AddressStandardization->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, # Testing => 1, } ); my $address1 = prompt( "Address1" ); my $address2 = prompt( "Address2" ); my $city = prompt( "City" ); my $state = prompt( "State" ); my $zip5 = prompt( "Zip Code" ); my $hash = $verifier->verify_address( FirmName => '', Address1 => $address1, Address2 => $address2, City => $city, State => $state, Zip5 => $zip5, Zip4 => '', ); if( $verifier->is_error ) { warn "Oops!\n"; print $verifier->response; print "\n"; } else { print <<"HERE"; $hash->{FirmName} $hash->{Address1} $hash->{Address2} $hash->{City} $hash->{State} $hash->{Zip5} $hash->{Zip4} HERE } sub prompt { my $prompt = shift; print "$prompt > "; my $line = ; chomp( $line ); $line; }Business-US-USPS-WebTools-1.125/examples/zip_code_lookup.pl0000644000175000017500000000155113723267663023511 0ustar smsimmssmsimms#!/usr/bin/perl use Business::US::USPS::WebTools::ZipCodeLookup; my $verifier = Business::US::USPS::WebTools::ZipCodeLookup->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, # Testing => 1, } ); my $address2 = prompt( "Address2" ); my $city = prompt( "City" ); my $state = prompt( "State" ); my $hash = $verifier->lookup_zipcode( FirmName => '', Address1 => $address1, Address2 => $address2, City => $city, State => $state, Zip5 => $zip5, Zip4 => '', ); if( $verifier->is_error ) { warn "Oops!\n"; print $verifier->response; print "\n"; } else { print <<"HERE"; $hash->{FirmName} $hash->{Address1} $hash->{Address2} $hash->{City} $hash->{State} $hash->{Zip5} $hash->{Zip4} HERE } sub prompt { my $prompt = shift; print "$prompt > "; my $line = ; chomp( $line ); $line; } Business-US-USPS-WebTools-1.125/MANIFEST0000644000175000017500000000136614051301664017267 0ustar smsimmssmsimmsChanges CONTRIBUTING.md examples/address_standardization.pl examples/track.pl examples/zip_code_lookup.pl INSTALL.SKIP lib/Business/US/USPS/WebTools.pm lib/Business/US/USPS/WebTools/AddressStandardization.pm lib/Business/US/USPS/WebTools/CityStateLookup.pm lib/Business/US/USPS/WebTools/TrackConfirm.pm lib/Business/US/USPS/WebTools/ZipCodeLookup.pm LICENSE Makefile.PL MANIFEST This list of files MANIFEST.SKIP README.pod t/address_verification.t t/city_state_lookup.t t/load.t t/pod.t t/pod_coverage.t t/test_manifest t/test_or_live.t t/track_confirm.t t/zip_code_lookup.t xt/changes.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Business-US-USPS-WebTools-1.125/LICENSE0000644000175000017500000001742313723267663017163 0ustar smsimmssmsimmsThe Business::US::USPS::WebTools module is licensed under the same terms as perl itself, under the Artistic License 2.0. Artistic License 2.0 Copyright (c) 2000-2006, The Perl Foundation. http://www.perlfoundation.org/artistic_license_2_0 Preamble This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. Definitions "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. "You" and "your" means any person who would like to copy, distribute, or modify the Package. "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. "Source" form means the source code, documentation source, and configuration files for the Package. "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. Permission for Use and Modification Without Distribution (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. Permissions for Redistribution of the Standard Version (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. Distribution of Modified Versions of the Package as Source (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under (i) the Original License or (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. Aggregating or Linking the Package (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. Items That are Not Considered Part of a Modified Version (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. General Provisions (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation Business-US-USPS-WebTools-1.125/lib/0000755000175000017500000000000014051301664016676 5ustar smsimmssmsimmsBusiness-US-USPS-WebTools-1.125/lib/Business/0000755000175000017500000000000014051301664020471 5ustar smsimmssmsimmsBusiness-US-USPS-WebTools-1.125/lib/Business/US/0000755000175000017500000000000014051301664021020 5ustar smsimmssmsimmsBusiness-US-USPS-WebTools-1.125/lib/Business/US/USPS/0000755000175000017500000000000014051301664021612 5ustar smsimmssmsimmsBusiness-US-USPS-WebTools-1.125/lib/Business/US/USPS/WebTools.pm0000644000175000017500000001365714051301447023721 0ustar smsimmssmsimmsuse v5.10; use utf8; package Business::US::USPS::WebTools; use strict; no warnings 'uninitialized'; use Carp qw(carp croak); use subs qw(); use vars qw($VERSION); $VERSION = '1.125'; =encoding utf8 =head1 NAME Business::US::USPS::WebTools - Use the US Postal Service Web Tools =head1 SYNOPSIS use Business::US::USPS::WebTools; # see subclasses for API details =head1 DESCRIPTION *** THIS IS ALPHA SOFTWARE *** This is the base class for the WebTools web service from the US Postal Service. The USPS offers several services, and this module handles the parts common to all of them: making the request, getting the response, parsing error reponses, and so on. The interesting stuff happens in one of the subclasses which implement a particular service. So far, the only subclass in this distribution is C. =over =cut =item new( ANONYMOUS_HASH ) Make the web service object. Pass is an anonymous hash with these keys: UserID the user id provided by the USPS Password the password provided by the USPS Testing true or false, to select the right server If you don't pass the UserID or Password entries, C looks in the environment variables USPS_WEBTOOLS_USERID and USPS_WEBTOOLS_PASSWORD. If C cannot find both the User ID and the Password, it croaks. If you pass a true value with the Testing key, the object will use the testing server host name and the testing URL path. If the Testing key is false or not present, the object uses the live server details. =cut sub new { my( $class, $args ) = @_; my $user_id = $args->{UserID} || $ENV{USPS_WEBTOOLS_USERID} || croak "No user ID for USPS WebTools! Pass UserID or set the USPS_WEBTOOLS_USERID environment varaible."; my $password = $args->{Password} || $ENV{USPS_WEBTOOLS_PASSWORD} || croak "No password for USPS WebTools! Pass Password or set the USPS_WEBTOOLS_PASSWORD environment variable."; $args->{UserID} = $user_id; $args->{Password} = $password; $args->{testing} = $args->{Testing} || 0; $args->{live} = ! $args->{Testing}; bless $args, $class; } sub _testing { $_[0]->{testing} } sub _live { $_[0]->{live} } =item userid Returns the User ID for the web service. You need to get this from the US Postal Service. =item password Returns the Password for the web service. You need to get this from the US Postal Service. =item url Returns the URL for the request to the web service. So far, all requests are GET request with all of the data in the query string. =item tx Returns the transaction from the Mojo::UserAgent request. =item response Returns the response from the web service. This is the slightly modified response. So far it only fixes up line endings and normalizes some error output for inconsistent responses from different physical servers. =cut sub userid { $_[0]->{UserID} } sub password { $_[0]->{Password} } sub url { $_[0]->{url} || $_[0]->_make_url( $_[1] ) } sub tx { $_[0]->{transaction} } sub response { $_[0]->{response} } sub _api_host { my $self = shift; if( $self->_testing ) { $self->test_server_host } elsif( $self->_live ) { $self->live_server_host } else { die "Am I testing or live?" } } sub _api_path { $_[0]->_live ? "/ShippingAPI.dll" : "/ShippingAPI.dll" } sub _make_url { state $rc = require Mojo::URL; my( $self, $hash ) = @_; $self->{url} = Mojo::URL->new ->scheme('https') ->host( $self->_api_host ) ->path( $self->_api_path ) ->query( API => $self->_api_name, XML => $self->_make_query_xml( $hash ) ); } sub _make_request { my( $self, $url ) = @_; state $rc = require Mojo::UserAgent; state $ua = Mojo::UserAgent->new; $self->{error} = undef; $self->{transaction} = $ua->get( $self->url ); $self->{response} = $self->{transaction}->result->body; $self->is_error; use Data::Dumper; # print STDERR "In _make_request:\n" . Dumper( $self ) . "\n"; $self->{response}; } sub _clone { my $rc = require Storable; my( $self ) = @_; my $clone = Storable::dclone( $self ); } =item is_error Returns true if the response to the last request was an error, and false otherwise. If the response was an error, this method sets various fields in the object: $self->{error}{number} $self->{error}{source} $self->{error}{description} $self->{error}{help_file} $self->{error}{help_context} =cut sub is_error { my $self = shift; return 0 unless $self->response =~ ""; $self->{error} = {}; # Apparently not all servers return this string in the # same way. Some have SOL and some have SoL $self->{response} =~ s/SOLServer/SOLServer/ig; ( $self->{error}{number} ) = $self->response =~ m|(-?\d+)|g; ( $self->{error}{source} ) = $self->response =~ m|(.*?)|g; ( $self->{error}{description} ) = $self->response =~ m|(.*?)|g; ( $self->{error}{help_file} ) = $self->response =~ m|(.*?)|ig; ( $self->{error}{help_context} ) = $self->response =~ m|(.*?)|ig; 1; } =item live_server_host This is production.shippingapis.com. The modules choose this host when you have not set C to a true value. =item test_server_host For most APIs, this is testing.shippingapis.com. The modules choose this host when you have set C to a true value. =cut sub live_server_host { "production.shippingapis.com" }; sub test_server_host { "stg-production.shippingapis.com" }; =back =head1 SEE ALSO The WebTools API is documented on the US Postal Service's website: http://www.usps.com/webtools/htm/Address-Information.htm =head1 SOURCE AVAILABILITY This source is in GitHub: https://github.com/ssimms/business-us-usps-webtools =head1 AUTHOR brian d foy =head1 MAINTAINER Steve Simms =head1 COPYRIGHT AND LICENSE Copyright © 2020, Steve Simms. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0. =cut 1; Business-US-USPS-WebTools-1.125/lib/Business/US/USPS/WebTools/0000755000175000017500000000000014051301664023350 5ustar smsimmssmsimmsBusiness-US-USPS-WebTools-1.125/lib/Business/US/USPS/WebTools/ZipCodeLookup.pm0000644000175000017500000000622614051301453026437 0ustar smsimmssmsimmsuse v5.10; use utf8; package Business::US::USPS::WebTools::ZipCodeLookup; use strict; no warnings 'uninitialized'; use parent qw(Business::US::USPS::WebTools); use subs qw(); use vars qw($VERSION); $VERSION = '1.125'; =encoding utf8 =head1 NAME Business::US::USPS::WebTools::ZipCodeLookup - lookup a Zip Code using the USPS Web Tools =head1 SYNOPSIS use Business::US::USPS::WebTools::ZipCodeLookup; my $looker_upper = Business::US::USPS::WebTools::ZipCodeLookup->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, Testing => 1, } ); my $hash = $looker_upper->lookup_zipcode( ); if( $looker_upper->is_error ) { warn "Oh No! $looker_upper->{error}{description}\n"; } else { print join "\n", map { "$_: $hash->{$_}" } qw(FirmName Address1 Address2 City State Zip5 Zip4); } =head1 DESCRIPTION *** THIS IS ALPHA SOFTWARE *** This module implements the Zip Code Lookup web service from the US Postal Service. It is a subclass of Business::US::USPS::WebTools. =cut =over 4 =cut sub _fields { qw( FirmName Address1 Address2 City State) } sub _required { qw( Address2 City State ) } =item lookup_zipcode( KEY, VALUE, ... ) The C method takes the following keys, which come directly from the USPS web service interface: Address2 The street address City The name of the city State The two letter state abbreviation Zip5 The 5 digit zip code Zip4 The 4 digit extension to the zip code It returns an anonymous hash with the same keys, but the values are the USPS's canonicalized address. If there is an error, the hash values will be the empty string, and the error flag is set. Check is with C: $verifier->is_error; See the C documentation in Business::US::USPS::WebTools for more details on error information. =cut sub lookup_zipcode { my( $self, %hash ) = @_; $self->_make_url( \%hash ); $self->_make_request; $self->_parse_response; } sub _api_name { "ZipCodeLookup" } sub _make_query_xml { my( $self, $hash ) = @_; my $user = $self->userid; my $pass = $self->password; my $xml = qq|| . qq|
|; foreach my $field ( $self->_fields ) { $xml .= "<$field>$$hash{$field}"; } $xml .= qq|
|; return $xml; } sub _parse_response { my( $self ) = @_; #require 'Hash::AsObject'; my %hash = (); foreach my $field ( $self->_fields, qw( Zip5 Zip4 ) ) { my( $value ) = $self->response =~ m|<$field>(.*?)|g; $hash{$field} = $value || ''; } bless \%hash, ref $self; # 'Hash::AsObject'; } =back =head1 TO DO =head1 SEE ALSO L The WebTools API is documented on the US Postal Service's website: http://www.usps.com/webtools/htm/Address-Information.htm =head1 SOURCE AVAILABILITY This source is in GitHub: https://github.com/ssimms/business-us-usps-webtools =head1 AUTHOR brian d foy =head1 COPYRIGHT AND LICENSE Copyright © 2020, Steve Simms. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0. =cut 1; Business-US-USPS-WebTools-1.125/lib/Business/US/USPS/WebTools/AddressStandardization.pm0000644000175000017500000000751314051301460030352 0ustar smsimmssmsimmsuse v5.10; use utf8; package Business::US::USPS::WebTools::AddressStandardization; use strict; no warnings 'uninitialized'; use parent qw(Business::US::USPS::WebTools); use subs qw(); use vars qw($VERSION); $VERSION = '1.125'; =encoding utf8 =head1 NAME Business::US::USPS::WebTools::AddressStandardization - canonicalize a US address =head1 SYNOPSIS use Business::US::USPS::WebTools::AddressStandardization; my $verifier = Business::US::USPS::WebTools::AddressStandardization->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, Testing => 1, } ); my $hash = $verifier->verify_address( FirmName => '', Address1 => '', Address2 => '6406 Ivy Lane', City => 'Greenbelt', State => 'MD', Zip5 => '', Zip4 => '', ); if( $verifier->is_error ) { warn "Oh No! $verifier->{error}{description}\n"; } else { print join "\n", map { "$_: $hash->{$_}" } qw(FirmName Address1 Address2 City State Zip5 Zip4 DeliveryPoint CarrierRoute ReturnText); } =head1 DESCRIPTION *** THIS IS ALPHA SOFTWARE *** This module implements the Address Standardization web service from the US Postal Service. It is a subclass of Business::US::USPS::WebTools. =cut =over 4 =cut sub _fields { qw( FirmName Address1 Address2 City State Zip5 Zip4 ) } sub _required { qw( Address2 City State ) } sub _response { (_fields(), qw( DeliveryPoint CarrierRoute ReturnText )) } =item verify_address( KEY, VALUE, ... ) The C method takes the following keys, which come directly from the USPS web service interface: FirmName The name of the company Address1 The suite or apartment Address2 The street address City The name of the city State The two letter state abbreviation Zip5 The 5 digit ZIP code Zip4 The 4 digit extension to the ZIP code It returns an anonymous hash with the same keys, but the values are the USPS's canonicalized address, plus three additional keys: DeliveryPoint The 2 digit extension to the ZIP+4 code CarrierRoute The 4 character postal carrier route ReturnText An error message when multiple addresses are found If there is an error, the hash values will be the empty string, and the error flag is set. Check is with C: $verifier->is_error; See the C documentation in Business::US::USPS::WebTools for more details on error information. =cut sub verify_address { my( $self, %hash ) = @_; $self->_make_url( \%hash ); $self->_make_request; $self->_parse_response; } sub _api_name { "Verify" } sub _make_query_xml { my( $self, $hash ) = @_; my $user = $self->userid; my $pass = $self->password; my $xml = qq|| . qq|true| . qq|true| . qq|
|; foreach my $field ( $self->_fields ) { $xml .= "<$field>$$hash{$field}"; } $xml .= qq|
|; return $xml; } sub _parse_response { my( $self ) = @_; #require 'Hash::AsObject'; my %hash = (); foreach my $field ( $self->_response ) { my( $value ) = $self->response =~ m|<$field>(.*?)|g; $hash{$field} = $value || ''; } bless \%hash, ref $self; # 'Hash::AsObject'; } =back =head1 TO DO =head1 SEE ALSO L The WebTools API is documented on the US Postal Service's website: https://www.usps.com/business/web-tools-apis/address-information-api.pdf =head1 SOURCE AVAILABILITY This source is in GitHub: https://github.com/ssimms/business-us-usps-webtools =head1 AUTHOR brian d foy =head1 MAINTAINER Steve Simms =head1 COPYRIGHT AND LICENSE Copyright © Steve Simms. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0. =cut 1; Business-US-USPS-WebTools-1.125/lib/Business/US/USPS/WebTools/CityStateLookup.pm0000644000175000017500000000633514051301464027016 0ustar smsimmssmsimmsuse v5.10; use utf8; package Business::US::USPS::WebTools::CityStateLookup; use strict; no warnings 'uninitialized'; use parent qw(Business::US::USPS::WebTools); use subs qw(); use vars qw($VERSION); $VERSION = '1.125'; =encoding utf8 =head1 NAME Business::US::USPS::WebTools::CityStateLookup - lookup a City and State by Zip Code =head1 SYNOPSIS use Business::US::USPS::WebTools::AddressStandardization; my $looker_upper = Business::US::USPS::WebTools::CityStateLookup->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, Testing => 1, } ); my $hash = $looker_upper->lookup_city_state( ); if( $looker_upper->is_error ) { warn "Oh No! $looker_upper->{error}{description}\n"; } else { print join "\n", map { "$_: $hash->{$_}" } qw(FirmName Address1 Address2 City State Zip5 Zip4); } =head1 DESCRIPTION *** THIS IS ALPHA SOFTWARE *** This module implements the Address Standardization web service from the US Postal Service. It is a subclass of Business::US::USPS::WebTools. =cut =over 4 =cut sub _fields { qw( FirmName Address1 Address2 City State Zip5 Zip4 ) } sub _required { qw( Address2 City State ) } =item lookup_city_state( KEY, VALUE, ... ) The C method takes the following keys, which come directly from the USPS web service interface: FirmName The name of the company Address1 The suite or apartment Address2 The street address City The name of the city State The two letter state abbreviation Zip5 The 5 digit zip code Zip4 The 4 digit extension to the zip code It returns an anonymous hash with the same keys, but the values are the USPS's canonicalized address. If there is an error, the hash values will be the empty string, and the error flag is set. Check is with C: $verifier->is_error; See the C documentation in Business::US::USPS::WebTools for more details on error information. =cut sub lookup_city_state { my( $self, $zip_code ) = @_; $self->_make_url( { Zip5 => $zip_code } ); $self->_make_request; $self->_parse_response; } sub _api_name { "CityStateLookup" } sub _make_query_xml { my( $self, $hash ) = @_; my $user = $self->userid; my $pass = $self->password; my $xml = qq|| . qq|$$hash{Zip5}| . qq||; } sub _parse_response { my( $self ) = @_; #require 'Hash::AsObject'; my %hash = (); foreach my $field ( $self->_fields ) { my( $value ) = $self->response =~ m|<$field>(.*?)|g; $hash{$field} = $value || ''; } bless \%hash, ref $self; # 'Hash::AsObject'; } =back =head1 TO DO =head1 SEE ALSO L The WebTools API is documented on the US Postal Service's website: https://www.usps.com/business/web-tools-apis/address-information-api.pdf =head1 SOURCE AVAILABILITY This source is in GitHub: https://github.com/ssimms/business-us-usps-webtools =head1 AUTHOR brian d foy =head1 MAINTAINER Steve Simms =head1 COPYRIGHT AND LICENSE Copyright © 2020, Steve Simms. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0. =cut 1; Business-US-USPS-WebTools-1.125/lib/Business/US/USPS/WebTools/TrackConfirm.pm0000644000175000017500000001754214051301472026276 0ustar smsimmssmsimmsuse v5.10; use utf8; package Business::US::USPS::WebTools::TrackConfirm; use strict; no warnings 'uninitialized'; use parent qw(Business::US::USPS::WebTools); use subs qw(); use vars qw($VERSION); use Carp qw(croak carp); $VERSION = '1.125'; =encoding utf8 =head1 NAME Business::US::USPS::WebTools::TrackConfirm - track a shipment using the USPS Web Tools =head1 SYNOPSIS use Business::US::USPS::WebTools::TrackConfirm; my $tracker = Business::US::USPS::WebTools::TrackConfirm->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, Testing => 1, } ); my $array_of_hashes = $tracker->track( TrackID => $tracking_number ); if( $tracker->is_error ) { warn "Oh No! $tracker->{error}{description}\n"; } else { foreach my $hash ( reverse $hash->{TrackDetail}->@* ) { say '-' x 50; say join "\n", map { "$_: $hash->{$_}" } qw(Event EventCity EventDate EventTime); } } =head1 DESCRIPTION *** THIS IS ALPHA SOFTWARE *** This module implements the Track & Confirm web service from the US Postal Service. It is a subclass of Business::US::USPS::WebTools. =cut =over 4 =cut sub _fields { qw( TrackID DestinationZipCode MailingDate ClientIp SourceId ) } sub _required { qw( TrackID ) } =item track( TrackID => VALUE ) Although the USPS API allows to make multiple queries in a single request, this method one queries only one. The C method takes the following keys, which come directly from the USPS web service interface: TrackID The tracking number It returns an anonymous array of hashes with the data from the response. Each hash represents one step in the tracking and is blessed into L. The array is in reverse chronological order (so the oldest detail is the last element). The first element is the latest status (and is mostly the same as TrackSummary from the API). If you want to see if something went wrong, check: $tracker->is_error; See the C documentation in L for more details on error information. =cut sub track { my( $self, %hash ) = @_; my $clone = $self->_clone; foreach my $field ( $clone->_required ) { next if exists $hash{$field}; carp "Missing field [$field] for track()"; return; } my $tracking_number = $clone->is_valid_tracking_number( $hash{'TrackID'} ); unless( $tracking_number ) { carp "String [$hash{'TrackID'}] does not look like a valid USPS tracking number"; return; } $clone->_make_url( \%hash ); $clone->_make_request; $clone->_parse_response; } =item tracking_number_regex Returns the regex that checks a tracking number. I have it in its own method so you can easily override it if I got it wrong. The USPS shows the valid forms at https://tools.usps.com/go/TrackConfirmAction!input.action USPS Tracking® 9400 1000 0000 0000 0000 00 Priority Mail® 9205 5000 0000 0000 0000 00 Certified Mail® 9407 3000 0000 0000 0000 00 Collect on Delivery 9303 3000 0000 0000 0000 00 Global Express Guaranteed® 82 000 000 00 Priority Mail Express International™ EC 000 000 000 US Priority Mail Express™ 9270 1000 0000 0000 0000 00 EA 000 000 000 US Priority Mail International® CP 000 000 000 US Registered Mail™ 9208 8000 0000 0000 0000 00 Signature Confirmation™ 9202 1000 0000 0000 0000 00 =cut sub tracking_number_regex { state $regex = qr/ \A 9 [234] [0-9]{20} | 82 [0-9]{8} | [A-Z]{2}[0-9]{9}US \z /x; return $regex; } =item is_valid_tracking_number( ID ) Returns a normalized version of the tracking number if ID looks like a tracking number, based on the regex from C. Returns false otherwise. Normalizing ID merely removes all whitespace. Sometimes the USPS shows the numbers with whitespace. =cut sub is_valid_tracking_number { my( $self, $tracking_number ) = @_; $tracking_number =~ s/\s+//g; return unless $tracking_number =~ $self->tracking_number_regex; $tracking_number; } =item service_type( ID ) Returns the service type, based on the examples shown by the USPS and shown in C. I know this is wrong because I have tracking numbers that don't have the same leading characters for Priority Mail International. =cut sub service_type { my( $self, $tracking_number ); return unless $tracking_number =~ $self->tracking_number_regex; return do { local $_ = $tracking_number; if( / \A 94 /x ) { 'USPS Tracking' } elsif( / \A 9205 /x ) { 'Priority Mail' } elsif( / \A 9407 /x ) { 'Certified Mail' } elsif( / \A 9303 /x ) { 'Collect on Delivery' } elsif( / \A 82 /x ) { 'Global Express Guaranteed' } elsif( / \A 9270 /x ) { 'Priority Mail Express' } elsif( / \A 9208 /x ) { 'Registered Mail' } elsif( / \A 9202 /x ) { 'Signature Confirmation' } elsif( / \A RA .* US \z /x ) { 'Registered Mail' } elsif( / \A EA .* US \z /x ) { 'Priority Mail Express' } elsif( / \A EC .* US \z /x ) { 'Priority Mail Express International' } elsif( / \A CP .* US \z /x ) { 'Priority Mail International' } else { 'Unknown' } }; } sub _api_name { "TrackV2" } sub _make_query_xml { my( $self, $hash ) = @_; my $user = $self->userid; my $pass = $self->password; my $id = $hash->{'TrackID'}; my $ip = $hash->{'ClientIp'} // '127.0.0.1'; my $source = $hash->{'SourceId'} // __PACKAGE__; my $xml = qq|| . qq|1| . qq|| . qq|| . qq||; foreach my $field ( $self->_fields ) { next if $field eq 'TrackID'; next unless defined $hash->{$field}; $xml .= "<$field>$$hash{$field}"; } $xml .= qq||; return $xml; } =pod 8:34 pm September 25, 2018 Departed NEWARK UNITED STATES false AT " =cut sub _parse_response { my( $self ) = @_; my $res = $self->tx->result; my( $summary ) = $res->dom->at( 'TrackSummary' ); my $details = $res->dom->find( 'TrackDetail' ); #my %hash = (); #$hash{'TrackSummary'} = $summary->to_string; my $summary_parsed = $self->_parse_subbits( $summary ); my $array = $details->map( sub { $self->_parse_subbits( $_ ) } )->to_array; unshift @$array, $summary_parsed; bless $array, ref $self; # 'Hash::AsObject'; } sub _parse_subbits { state $rc = require Hash::AsObject; state $fields = [ qw( EventTime EventDate Event EventCity EventState EventZIPCode EventCountry FirmName Name AuthorizedAgent ) ]; my( $self, $subbit ) = @_; my %hash; foreach my $field ( @$fields ) { my( $value ) = eval { $subbit->at( $field )->text }; $hash{$field} = $value // ''; } bless \%hash, 'Hash::AsObject'; } =item test_server_host The testing API uses stg-production.shippingapis.com instead of the usual testing server. =cut sub test_server_host { "stg-production.shippingapis.com" }; sub _api_path { "/ShippingAPI.dll" } =back =head1 TO DO =head1 SEE ALSO L The WebTools API is documented on the US Postal Service's website: https://www.usps.com/business/web-tools-apis/track-and-confirm-api.htm =head1 SOURCE AVAILABILITY This source is in GitHub: https://github.com/ssimms/business-us-usps-webtools =head1 AUTHOR brian d foy =head1 MAINTAINER Steve Simms =head1 COPYRIGHT AND LICENSE Copyright © 2020, Steve Simms. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0. =cut 1; Business-US-USPS-WebTools-1.125/META.yml0000644000175000017500000000155214051301664017404 0ustar smsimmssmsimms--- abstract: 'Use the US Postal Service Web Tools' author: - 'Steve Simms ' build_requires: Test::More: '0.98' configure_requires: ExtUtils::MakeMaker: '6.64' File::Spec::Functions: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Business-US-USPS-WebTools no_index: directory: - t - inc requires: Hash::AsObject: '0' Mojolicious: '7' URI: '0' perl: '5.010' resources: bugtracker: https://github.com/ssimms/business-us-usps-webtools/issues homepage: https://github.com/ssimms/business-us-usps-webtools repository: https://github.com/ssimms/business-us-usps-webtools.git version: '1.125' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Business-US-USPS-WebTools-1.125/xt/0000755000175000017500000000000014051301664016563 5ustar smsimmssmsimmsBusiness-US-USPS-WebTools-1.125/xt/changes.t0000644000175000017500000000020313723267663020372 0ustar smsimmssmsimmsuse Test::More; eval 'use Test::CPAN::Changes'; plan skip_all => 'Test::CPAN::Changes required for this test' if $@; changes_ok(); Business-US-USPS-WebTools-1.125/MANIFEST.SKIP0000644000175000017500000000226113723267663020046 0ustar smsimmssmsimms #!start included /usr/local/perls/perl-5.22.0/lib/5.22.0/ExtUtils/MANIFEST.SKIP # Avoid version control files. \bRCS\b \bCVS\b \bSCCS\b ,v$ \B\.svn\b \B\.git\b \B\.gitignore\b \b_darcs\b \B\.cvsignore$ # Avoid VMS specific MakeMaker generated files \bDescrip.MMS$ \bDESCRIP.MMS$ \bdescrip.mms$ # Avoid Makemaker generated and utility files. \bMANIFEST\.bak \bMakefile$ \bblib/ \bMakeMaker-\d \bpm_to_blib\.ts$ \bpm_to_blib$ \bblibdirs\.ts$ # 6.18 through 6.25 generated this \b_eumm/ # 7.05_05 and above # Avoid Module::Build generated and utility files. \bBuild$ \b_build/ \bBuild.bat$ \bBuild.COM$ \bBUILD.COM$ \bbuild.com$ # and Module::Build::Tiny generated files \b_build_params$ # Avoid temp and backup files. ~$ \.old$ \#$ \b\.# \.bak$ \.tmp$ \.# \.rej$ \..*\.sw.?$ # Avoid OS-specific files/dirs # Mac OSX metadata \B\.DS_Store # Mac OSX SMB mount metadata files \B\._ # Avoid Devel::Cover and Devel::CoverX::Covered files. \bcover_db\b \bcovered\b # Avoid prove files \B\.prove$ # Avoid MYMETA files ^MYMETA\. #!end included /usr/local/perls/perl-5.22.0/lib/5.22.0/ExtUtils/MANIFEST.SKIP \.travis\.yml \.?appveyor.yml \.releaserc \.lwpcookies t/\d t/env.t Business-US-USPS-WebTools-1.125/META.json0000644000175000017500000000301614051301664017551 0ustar smsimmssmsimms{ "abstract" : "Use the US Postal Service Web Tools", "author" : [ "Steve Simms " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "license" : [ "artistic_2" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Business-US-USPS-WebTools", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : {} }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "6.64", "File::Spec::Functions" : "0" } }, "runtime" : { "requires" : { "Hash::AsObject" : "0", "Mojolicious" : "7", "URI" : "0", "perl" : "5.010" } }, "test" : { "requires" : { "Test::More" : "0.98" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/ssimms/business-us-usps-webtools/issues" }, "homepage" : "https://github.com/ssimms/business-us-usps-webtools", "repository" : { "type" : "git", "url" : "https://github.com/ssimms/business-us-usps-webtools.git", "web" : "https://github.com/ssimms/business-us-usps-webtools" } }, "version" : "1.125", "x_serialization_backend" : "JSON::PP version 2.97001" } Business-US-USPS-WebTools-1.125/README.pod0000644000175000017500000000716413731215510017577 0ustar smsimmssmsimms=pod =encoding utf8 =for HTML =for HTML Coverage Status =for HTML =for HTML =head1 The Business::US::USPS::WebTools module This is the I for the L Perl module. You're probably looking at this because you don't know where else to find what you're looking for. Read this once and you might never have to read one again for any Perl module. =head2 Documentation To read about L, look at the embedded documentation in the module itself. Inside the distribution, you can format it with L: % perldoc lib/Business/US/USPS/WebTools.pm If you have already installed the module, you can specify the module name instead of the file location: % perldoc Business::US::USPS::WebTools You can read the documentation and inspect the meta data at L. The standard module documentation has example uses in the SYNOPSIS section, but you can also look in the I directory (if it's there), or look at the test files in I. =head2 Installation You can install this module with a CPAN client, which will resolve and install the dependencies: % cpan Business::US::USPS::WebTools % cpanm Business::US::USPS::WebTools You can also install directly from the distribution directory, which will also install the dependencies: % cpan . % cpanm . You could install just this module manually: % perl Makefile.PL % make % make test % make install You probably don't want to do that unless you're fiddling with the module and only want to run the tests without installing anything. =head2 Source location The meta data, such as the source repository and bug tracker, is in I or the I files it creates. You can find that on those CPAN web interfaces, but you can also look at files directly in the source repository: =over 4 =item * L =back If you find a problem, file a ticket in the L: =over 4 =item * L =back =head2 Getting help Although I'm happy to hear from module users in private email, that's the best way for me to forget to do something. Besides the issue trackers, you can find help at L or L, both of which have many competent Perlers who can answer your question, almost in real time. They might not know the particulars of this module, but they can help you diagnose your problem. You might like to read L. =head2 Copyright and License You should have received a I file, but the license is also noted in the module files. About the only thing you can't do is pretend that you wrote code that you didn't. Business-US-USPS-WebTools-1.125/Makefile.PL0000644000175000017500000000627413731215576020125 0ustar smsimmssmsimmspackage Business::US::USPS::WebTools; use strict; use warnings; =encoding utf8 =head1 The build file for Business::US::USPS::WebTools This build file is a modulino; it works as both a build script and a module. To build the distribution, run this file normally: % perl Makefile.PL But, it's more interesting than that. You can load it with C and call C to get the data structure it passes to C: my $package = require '/path/to/Makefile.PL'; my $arguments = $package->arguments; Note that C-ing a file makes an entry in C<%INC> for exactly that name. If you try to C another file with the same name, even from a different path, C thinks it has already loaded the file. As such, I recommend you always require the full path to the file. The return value of the C is a package name (in this case, the name of the main module). Use that to call the C method. Even if this distribution needs a higher version of Perl, this bit only needs v5.8. You can play with the data structure with a primitive Perl. =cut print <<"HERE" unless( $ENV{USPS_WEBTOOLS_USERID} and $ENV{USPS_WEBTOOLS_PASSWORD} ); ---------------------------------------------------------------------------- To use these modules, you need a User ID and Password from the US Postal Service. See the USPS website for details: http://www.usps.com/webtools/htm/Address-Information.htm Set the USPS_WEBTOOLS_USERID and USPS_WEBTOOLS_PASSWORD environment variables. ---------------------------------------------------------------------------- HERE use File::Spec::Functions qw(catfile); my $module = __PACKAGE__; ( my $dist = $module ) =~ s/::/-/g; my $github = 'https://github.com/ssimms/business-us-usps-webtools'; my $main_file = catfile( 'lib', split /::/, "$module.pm" ); my %WriteMakefile = ( 'MIN_PERL_VERSION' => '5.010', 'NAME' => $module, 'VERSION_FROM' => $main_file, 'ABSTRACT_FROM' => $main_file, 'LICENSE' => 'artistic_2', 'AUTHOR' => 'Steve Simms ', 'CONFIGURE_REQUIRES' => { 'ExtUtils::MakeMaker' => '6.64', 'File::Spec::Functions' => '0', }, 'BUILD_REQUIRES' => { }, 'TEST_REQUIRES' => { 'Test::More' => '0.98', }, 'PREREQ_PM' => { 'Hash::AsObject' => '0', 'Mojolicious' => '7', 'URI' => '0', }, 'META_MERGE' => { 'meta-spec' => { version => 2 }, resources => { repository => { type => 'git', url => "$github.git", web => $github, }, bugtracker => { web => "$github/issues", }, homepage => $github, }, }, clean => { FILES => "$dist-*" }, ); sub arguments { \%WriteMakefile } do_it() unless caller; sub do_it { require File::Spec; my $MM ='ExtUtils::MakeMaker'; my $MM_version = eval{ "$MM " . $WriteMakefile{'CONFIGURE_REQUIRES'}{'ExtUtils::MakeMaker'} } || "$MM 6.64"; eval "use $MM_version; 1" or die "Could not load $MM_version: $@"; eval "use Test::Manifest 1.21" if -e File::Spec->catfile( qw(t test_manifest) ); my $arguments = arguments(); my $minimum_perl = $arguments->{MIN_PERL_VERSION} || '5.008'; eval "require $minimum_perl;" or die $@; WriteMakefile( %$arguments ); } no warnings; __PACKAGE__; Business-US-USPS-WebTools-1.125/Changes0000644000175000017500000000370114051301212017411 0ustar smsimmssmsimmsRevision history for Perl module Business::US::USPS::WebTools 1.125 2021-05-19 * Updated API endpoints. Always use HTTPS. * Removed two tests that started failing due to changes in the API response. * Skip tracking tests (which are disabled anyway) rather than failing if test credentials aren't set. * Access to the testing/staging environment is no longer granted by default and testing against the production environment is allowed (load/stress testing isn't), so tests are now run against the production API by default. To run against the testing/staging environment, set USPS_WEBTOOLS_ENVIRONMENT to TESTING while setting up your credentials. 1.124 2020-09-18 * New maintainer 1.122 2016-10-13T00:13:29Z * Another release because the last one wasn't indexed. ADOPTME has permissions on it. 1.121 2016-06-07T19:29:22Z * Bump to release version 1.12_01 2016-01-07T04:27:51Z * Add the Track & Confirm API 1.12 2015-09-29T19:45:43Z * Update for the latest API changes and test responses * Get DeliveryPoint, CarrierRoute, and ReturnText fields 1.11 - 2007-11-03 * cleanups to move from CVS to SVN * now requires perl 5.6 * cleanups to the disto; no need to upgrade if you already have this 0.00 - 2007-10-25 * distro adjustments. no big whoop. 1.09 - 2007-02-05 * Jay Buffington noted I wasn't escaping the query strings correctly (meaning, at all), so I fixed that. * This is an important fix that everyone should upgrade too. 1.06 - 2007-01-10 * First official release :) 0.10 - 2006-09-26 * Changed namespace to Business::US::USPS::* * More docs to point out you need the USPS UserID to use any of this * See http://www.usps.com/webtools/ 0.10 - 2006-09-16 * This is the initial release of a group of modules which implement the web services of the US Postal Service. This isn't screen scraping! * See http://www.usps.com/webtools/ Business-US-USPS-WebTools-1.125/INSTALL.SKIP0000644000175000017500000000015613723267663017747 0ustar smsimmssmsimmsREADME\.pod README.* # things that might be in local directories after fooling # around with them \.DS_Store Business-US-USPS-WebTools-1.125/t/0000755000175000017500000000000014051301664016373 5ustar smsimmssmsimmsBusiness-US-USPS-WebTools-1.125/t/city_state_lookup.t0000644000175000017500000002230614051276732022333 0ustar smsimmssmsimms#!/usr/bin/perl # See http://www.usps.com/webtools/htm/Address-Information.htm for # the test requirements. The headings ( "Good response #1", etc ) # correspond to the USPS test specification # # the sample requests are now at https://www.usps.com/business/web-tools-apis/general-api-developer-guide.htm#_Toc423593927 # but I haven't updated this. Some requests no longer appear there but # they still work. use Test::More 0.98; my $class = "Business::US::USPS::WebTools::CityStateLookup"; my $method = 'lookup_city_state'; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # unless( $ENV{USPS_WEBTOOLS_USERID} and $ENV{USPS_WEBTOOLS_PASSWORD} ) { plan skip_all => "You must set the USPS_WEBTOOLS_USERID and USPS_WEBTOOLS_PASSWORD " . "environment variables to run these tests\n"; } my $is_testing = uc($ENV{USPS_WEBTOOLS_ENVIRONMENT}) eq 'TESTING'; my $base = 'https://' . ($is_testing ? 'stg-' : '') . 'production.shippingapis.com/ShippingAPI.dll'; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # use_ok( $class ); my $verifier; subtest setup => sub { $verifier = $class->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, Testing => $is_testing, } ); isa_ok( $verifier, $class ); can_ok( $verifier, $method ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good response #1 subtest good_response_1 => sub { my $url = $verifier->_make_url( { Zip5 => 90210, } ); is( $url, qq|$base?API=CityStateLookup&XML=%3CCityStateLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CZipCode+ID%3D%220%22%3E%3CZip5%3E90210%3C%2FZip5%3E%3C%2FZipCode%3E%3C%2FCityStateLookupRequest%3E|, "URL for 90210 is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "90210 response is not an error" ); my $expected = <<"XML"; 90210BEVERLY HILLSCA XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{City}, 'BEVERLY HILLS', 'City matches for 90210' ); is( $hash->{State}, 'CA', 'State matches for 90210' ); is( $hash->{Zip5}, '90210', 'Zip5 matches for 90210' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good response #2 subtest good_response_2 => sub { my $url = $verifier->_make_url( { Zip5 => '20770', } ); is( $url, qq|$base?API=CityStateLookup&XML=%3CCityStateLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CZipCode+ID%3D%220%22%3E%3CZip5%3E20770%3C%2FZip5%3E%3C%2FZipCode%3E%3C%2FCityStateLookupRequest%3E|, "URL for 20770 is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "20770 response is not an error" ); my $expected = <<"XML"; 20770GREENBELTMD XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{City}, 'GREENBELT', 'City matches for 20770' ); is( $hash->{State}, 'MD', 'State matches for 20770' ); is( $hash->{Zip5}, '20770', 'Zip5 matches for 20770' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good response #3 subtest good_response_3 => sub { my $url = $verifier->_make_url( { Zip5 => '21113', } ); is( $url, qq|$base?API=CityStateLookup&XML=%3CCityStateLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CZipCode+ID%3D%220%22%3E%3CZip5%3E21113%3C%2FZip5%3E%3C%2FZipCode%3E%3C%2FCityStateLookupRequest%3E|, "URL for 21113 is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "Response is not an error" ); my $expected = <<"XML"; 21113ODENTONMD XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{City}, 'ODENTON', 'City matches for 21113' ); is( $hash->{State}, 'MD', 'State matches for 21113' ); is( $hash->{Zip5}, '21113', 'Zip5 matches for 21113' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good response #4 subtest good_response_4 => sub { my $url = $verifier->_make_url( { Zip5 => '21032', } ); is( $url, qq|$base?API=CityStateLookup&XML=%3CCityStateLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CZipCode+ID%3D%220%22%3E%3CZip5%3E21032%3C%2FZip5%3E%3C%2FZipCode%3E%3C%2FCityStateLookupRequest%3E|, "URL for 21032 is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "21032 response is not an error" ); my $expected = <<"XML"; 21032CROWNSVILLEMD XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{City}, 'CROWNSVILLE', 'City matches for 21032' ); is( $hash->{State}, 'MD', 'State matches for 21032' ); is( $hash->{Zip5}, '21032', 'Zip5 matches for 21032' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good response #5 =pod # this no longer works subtest good_response_5 => sub { my $url = $verifier->_make_url( { Zip5 => '21117', } ); is( $url, qq|$base?API=CityStateLookup&XML=%3CCityStateLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CZipCode+ID%3D%220%22%3E%3CZip5%3E21117%3C%2FZip5%3E%3C%2FZipCode%3E%3C%2FCityStateLookupRequest%3E|, "URL for Sharonwood Road is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "21117 response is not an error" ); my $expected = <<"XML"; -2147219399WebtoolsAMS;CityStateLookupInvalid Zip Code. XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{City}, 'OWINGS MILLS', 'City matches for 21117' ); is( $hash->{State}, 'MD', 'State matches for 21117' ); is( $hash->{Zip5}, '21117', 'Zip5 matches for 21117' ); }; =cut # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error Requests # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error response #1 subtest error_response_1 => sub { my $url = $verifier->_make_url( { Zip5 => '99999', } ); is( $url, qq|$base?API=CityStateLookup&XML=%3CCityStateLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CZipCode+ID%3D%220%22%3E%3CZip5%3E99999%3C%2FZip5%3E%3C%2FZipCode%3E%3C%2FCityStateLookupRequest%3E|, "URL for Sharonwood Road Error is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( $verifier->is_error, "Error request gets an error response" ); my $expected = <<"XML"; -2147219399WebtoolsAMS;CityStateLookupInvalid Zip Code. XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); is( $verifier->{error}{number}, -2147219399, 'Error number matches for 99999 error' ); is( $verifier->{error}{source}, 'WebtoolsAMS;CityStateLookup', 'Error source matches for 99999 error' ); is( $verifier->{error}{description}, 'Invalid Zip Code.', 'Error description matches for 99999 error' ); is( $verifier->{error}{help_file}, undef, 'Error help file matches for 99999 error' ); is( $verifier->{error}{help_context}, undef, 'Error help context matches for 99999 error' ); my $hash = $verifier->_parse_response; is( $hash->{City}, '', 'City is empty for Sharonwood error' ); is( $hash->{State}, '', 'State is empty for Sharonwood error' ); is( $hash->{Zip5}, '', 'Zip5 is empty for Sharonwood error' ); }; done_testing(); Business-US-USPS-WebTools-1.125/t/address_verification.t0000644000175000017500000004617714051276653022777 0ustar smsimmssmsimms#!/usr/bin/perl # See http://www.usps.com/webtools/htm/Address-Information.htm for # the test requirements. The headings ( "Good response #1", etc ) # correspond to the USPS test specification # # the sample requests are now at https://www.usps.com/business/web-tools-apis/general-api-developer-guide.htm#_Toc423593927 # but I haven't updated this. Some requests no longer appear there but # they still work. use Test::More; my $class = "Business::US::USPS::WebTools::AddressStandardization"; my $method = 'verify_address'; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # unless( $ENV{USPS_WEBTOOLS_USERID} and $ENV{USPS_WEBTOOLS_PASSWORD} ) { plan skip_all => "You must set the USPS_WEBTOOLS_USERID and USPS_WEBTOOLS_PASSWORD " . "environment variables to run these tests\n"; } my $is_testing = uc($ENV{USPS_WEBTOOLS_ENVIRONMENT}) eq 'TESTING'; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # use_ok( $class ); my $verifier; my $base = 'https://' . ($is_testing ? 'stg-' : '') . qq|production.shippingapis.com/ShippingAPI.dll?API=Verify&XML=%3CAddressValidateRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CIncludeOptionalElements%3Etrue%3C%2FIncludeOptionalElements%3E%3CReturnCarrierRoute%3Etrue%3C%2FReturnCarrierRoute%3E|; subtest setup => sub { $verifier = $class->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, Testing => $is_testing, } ); isa_ok( $verifier, $class ); can_ok( $verifier, $method ); }; =pod 2021-05-19: This test is failing because the API is no longer returning the expected output; it now includes the following warning: Default address: The address you entered was found but more information is needed (such as an apartment, suite, or box number) to match to a specific address. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good response #1 subtest good_response_1 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '6406 Ivy Lane', City => 'Greenbelt', State => 'MD', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E6406+Ivy+Lane%3C%2FAddress2%3E%3CCity%3EGreenbelt%3C%2FCity%3E%3CState%3EMD%3C%2FState%3E%3CZip5%3E%3C%2FZip5%3E%3CZip4%3E%3C%2FZip4%3E%3C%2FAddress%3E%3C%2FAddressValidateRequest%3E|, "URL for Ivy Lane is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "Response is not an error" ); my $expected = <<"XML";
6406 IVY LNGREENBELTMD20770144106C023
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{FirmName}, '', 'FirmName matches for Ivy Lane' ); is( $hash->{Address1}, '', 'Address1 matches for Ivy Lane' ); is( $hash->{Address2}, '6406 IVY LN', 'Address2 matches for Ivy Lane' ); is( $hash->{City}, 'GREENBELT', 'City matches for Ivy Lane' ); is( $hash->{State}, 'MD', 'State matches for Ivy Lane' ); is( $hash->{Zip5}, '20770', 'Zip5 matches for Ivy Lane' ); is( $hash->{Zip4}, '1441', 'Zip4 matches for Ivy Lane' ); }; =cut # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good response #2 subtest good_response_1 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '8 Wildwood Drive', City => 'Old Lyme', State => 'CT', Zip5 => '06371', Zip4 => '', } ); is( $url, qq|$base%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E8+Wildwood+Drive%3C%2FAddress2%3E%3CCity%3EOld+Lyme%3C%2FCity%3E%3CState%3ECT%3C%2FState%3E%3CZip5%3E06371%3C%2FZip5%3E%3CZip4%3E%3C%2FZip4%3E%3C%2FAddress%3E%3C%2FAddressValidateRequest%3E|, "URL for Wildwood Drive is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "Response is not an error" ); my $expected = <<"XML";
8 WILDWOOD DROLD LYMECT06371184408R010
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{FirmName}, '', 'FirmName matches for Wildwood' ); is( $hash->{Address1}, '', 'Address1 matches for Wildwood' ); is( $hash->{Address2}, '8 WILDWOOD DR', 'Address2 matches for Wildwood' ); is( $hash->{City}, 'OLD LYME', 'City matches for Wildwood' ); is( $hash->{State}, 'CT', 'State matches for Wildwood' ); is( $hash->{Zip5}, '06371', 'Zip5 matches for Wildwood' ); is( $hash->{Zip4}, '1844', 'Zip4 matches for Wildwood' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good response #3 subtest good_response_3 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '4411 Romlon Street', City => 'Beltsville', State => 'MD', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E4411+Romlon+Street%3C%2FAddress2%3E%3CCity%3EBeltsville%3C%2FCity%3E%3CState%3EMD%3C%2FState%3E%3CZip5%3E%3C%2FZip5%3E%3CZip4%3E%3C%2FZip4%3E%3C%2FAddress%3E%3C%2FAddressValidateRequest%3E|, "URL for Romlan Street is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "Response is not an error" ); my $expected = <<"XML";
4411 ROMLON STBELTSVILLEMD20705242599Default address: The address you entered was found but more information is needed (such as an apartment, suite, or box number) to match to a specific address.C017
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{FirmName}, '', 'FirmName matches for Romlan' ); is( $hash->{Address1}, '', 'Address1 matches for Romlan' ); is( $hash->{Address2}, '4411 ROMLON ST', 'Address2 matches for Romlan' ); is( $hash->{City}, 'BELTSVILLE', 'City matches for Romlan' ); is( $hash->{State}, 'MD', 'State matches for Romlan' ); is( $hash->{Zip5}, '20705', 'Zip5 matches for Romlan' ); is( $hash->{Zip4}, '2425', 'Zip4 matches for Romlan' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good response #4 subtest good_response_4 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '3527 Sharonwood Road Apt. 3C', City => 'Laurel', State => 'MD', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E3527+Sharonwood+Road+Apt.+3C%3C%2FAddress2%3E%3CCity%3ELaurel%3C%2FCity%3E%3CState%3EMD%3C%2FState%3E%3CZip5%3E%3C%2FZip5%3E%3CZip4%3E%3C%2FZip4%3E%3C%2FAddress%3E%3C%2FAddressValidateRequest%3E|, "URL for Sharonwood Road is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "Response is not an error" ); my $expected = <<"XML";
3527 SHARONWOOD RD APT 3CLAURELMD20724592033R008
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{FirmName}, '', 'FirmName matches for Sharonwood' ); is( $hash->{Address1}, '', 'Address1 matches for Sharonwood' ); is( $hash->{Address2}, '3527 SHARONWOOD RD APT 3C', 'Address2 matches for Sharonwood' ); is( $hash->{City}, 'LAUREL', 'City matches for Sharonwood' ); is( $hash->{State}, 'MD', 'State matches for Sharonwood' ); is( $hash->{Zip5}, '20724', 'Zip5 matches for Sharonwood' ); is( $hash->{Zip4}, '5920', 'Zip4 matches for Sharonwood' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error Requests # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error response #1 subtest error_response_1 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '3527 Sharonwood Road Apt. 3C', City => 'Wilmington', State => 'DE', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E3527+Sharonwood+Road+Apt.+3C%3C%2FAddress2%3E%3CCity%3EWilmington%3C%2FCity%3E%3CState%3EDE%3C%2FState%3E%3CZip5%3E%3C%2FZip5%3E%3CZip4%3E%3C%2FZip4%3E%3C%2FAddress%3E%3C%2FAddressValidateRequest%3E|, "URL for Sharonwood Road Error is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( $verifier->is_error, "Error request gets an error response" ); my $expected = <<"XML";
-2147219401clsAMSAddress Not Found.
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); is( $verifier->{error}{number}, -2147219401, 'Error number matches for Sharonwood error' ); is( $verifier->{error}{source}, 'clsAMS', 'Error source matches for Sharonwood error' ); is( $verifier->{error}{description}, 'Address Not Found. ', 'Error description matches for Sharonwood error' ); is( $verifier->{error}{help_file}, undef, 'Error help file matches for Sharonwood error' ); is( $verifier->{error}{help_context}, undef, 'Error help context matches for Sharonwood error' ); my $hash = $verifier->_parse_response; is( $hash->{FirmName}, '', 'FirmName is empty for Sharonwood error' ); is( $hash->{Address1}, '', 'Address1 is empty for Sharonwood error' ); is( $hash->{Address2}, '', 'Address2 is empty for Sharonwood error' ); is( $hash->{City}, '', 'City is empty for Sharonwood error' ); is( $hash->{State}, '', 'State is empty for Sharonwood error' ); is( $hash->{Zip5}, '', 'Zip5 is empty for Sharonwood error' ); is( $hash->{Zip4}, '', 'Zip4 is empty for Sharonwood error' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error response #2 =pod # this works now { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '1600 Pennsylvania Avenue', City => 'Washington', State => 'DC', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E1600+Pennsylvania+Avenue%3C%2FAddress2%3E%3CCity%3EWashington%3C%2FCity%3E%3CState%3EDC%3C%2FState%3E%3CZip5%3E%3C%2FZip5%3E%3CZip4%3E%3C%2FZip4%3E%3C%2FAddress%3E%3C%2FAddressValidateRequest%3E|, "URL for Pennsylvania Avenue Error is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( $verifier->is_error, "Error request gets an error response" ); my $expected = <<"XML";
-2147219403SOLServerTest;SOLServerTest.CallAddressDllMultiple responses found. No default address.
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); is( $verifier->{error}{number}, -2147219403, 'Error number matches for Pennsylvania Avenue error' ); is( $verifier->{error}{source}, 'clsAMS', 'Error source matches for Pennsylvania Avenue error' ); is( $verifier->{error}{description}, 'Multiple responses found. No default address.', 'Error description matches for Pennsylvania Avenue error' ); is( $verifier->{error}{help_file}, undef, 'Error help file matches for Pennsylvania Avenue error' ); is( $verifier->{error}{help_context}, undef, 'Error help context matches for Pennsylvania Avenue error' ); my $hash = $verifier->_parse_response; # print STDERR "In _make_request:\n" . Dumper( $verifier ) . "\n"; is( $hash->{FirmName}, '', 'FirmName is empty for Pennsylvania Avenue error' ); is( $hash->{Address1}, '', 'Address1 is empty for Pennsylvania Avenue error' ); is( $hash->{Address2}, '', 'Address2 is empty for Pennsylvania Avenue error' ); is( $hash->{City}, '', 'City is empty for Pennsylvania Avenue error' ); is( $hash->{State}, '', 'State is empty for Pennsylvania Avenue error' ); is( $hash->{Zip5}, '', 'Zip5 is empty for Pennsylvania Avenue error' ); is( $hash->{Zip4}, '', 'Zip4 is empty for Pennsylvania Avenue error' ); }; =cut # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error response #3 subtest error_response_3 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '123 Main Street', City => 'Washington', State => 'ZZ', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E123+Main+Street%3C%2FAddress2%3E%3CCity%3EWashington%3C%2FCity%3E%3CState%3EZZ%3C%2FState%3E%3CZip5%3E%3C%2FZip5%3E%3CZip4%3E%3C%2FZip4%3E%3C%2FAddress%3E%3C%2FAddressValidateRequest%3E|, "URL for Main Street Error is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( $verifier->is_error, "Error request gets an error response" ); my $expected = <<"XML";
-2147219402clsAMSInvalid State Code.
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); is( $verifier->{error}{number}, -2147219402, 'Error number matches for Main Street error' ); is( $verifier->{error}{source}, 'clsAMS', 'Error source matches for Main Street error' ); is( $verifier->{error}{description}, 'Invalid State Code. ', 'Error description matches for Main Street error' ); is( $verifier->{error}{help_file}, undef, 'Error help file matches for Main Street error' ); is( $verifier->{error}{help_context}, undef, 'Error help context matches for Main Street error' ); my $hash = $verifier->_parse_response; # print STDERR "In _make_request:\n" . Dumper( $verifier ) . "\n"; is( $hash->{FirmName}, '', 'FirmName is empty for Main Street error' ); is( $hash->{Address1}, '', 'Address1 is empty for Main Street error' ); is( $hash->{Address2}, '', 'Address2 is empty for Main Street error' ); is( $hash->{City}, '', 'City is empty for Main Street error' ); is( $hash->{State}, '', 'State is empty for Main Street error' ); is( $hash->{Zip5}, '', 'Zip5 is empty for Main Street error' ); is( $hash->{Zip4}, '', 'Zip4 is empty for Main Street error' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error response #4 subtest error_response_4 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '123 Main Street', City => 'Trenton', State => 'NJ', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E123+Main+Street%3C%2FAddress2%3E%3CCity%3ETrenton%3C%2FCity%3E%3CState%3ENJ%3C%2FState%3E%3CZip5%3E%3C%2FZip5%3E%3CZip4%3E%3C%2FZip4%3E%3C%2FAddress%3E%3C%2FAddressValidateRequest%3E|, "URL for Trenton, NJ Error is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( $verifier->is_error, "Error request gets an error response" ); my $expected = <<"XML";
-2147219401clsAMSAddress Not Found.
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); is( $verifier->{error}{number}, -2147219401, 'Error number matches for Trenton, NJ error' ); is( $verifier->{error}{source}, 'clsAMS', 'Error source matches for Trenton, NJ error' ); is( $verifier->{error}{description}, 'Address Not Found. ', 'Error description matches for Trenton, NJ error' ); is( $verifier->{error}{help_file}, undef, 'Error help file matches for Trenton, NJ error' ); is( $verifier->{error}{help_context}, undef, 'Error help context matches for Trenton, NJ error' ); my $hash = $verifier->_parse_response; # print STDERR "In _make_request:\n" . Dumper( $verifier ) . "\n"; is( $hash->{FirmName}, '', 'FirmName is empty for Trenton, NJ error' ); is( $hash->{Address1}, '', 'Address1 is empty for Trenton, NJ error' ); is( $hash->{Address2}, '', 'Address2 is empty for Trenton, NJ error' ); is( $hash->{City}, '', 'City is empty for Trenton, NJ error' ); is( $hash->{State}, '', 'State is empty for Trenton, NJ error' ); is( $hash->{Zip5}, '', 'Zip5 is empty for Trenton, NJ error' ); is( $hash->{Zip4}, '', 'Zip4 is empty for Trenton, NJ error' ); }; done_testing(); Business-US-USPS-WebTools-1.125/t/test_manifest0000644000175000017500000000017713723267663021207 0ustar smsimmssmsimms#env.t load.t pod.t pod_coverage.t test_or_live.t address_verification.t zip_code_lookup.t city_state_lookup.t track_confirm.t Business-US-USPS-WebTools-1.125/t/test_or_live.t0000644000175000017500000000302514051275736021270 0ustar smsimmssmsimmsuse Test::More 0.98; my $class = "Business::US::USPS::WebTools"; use_ok( $class ); # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # subtest testing => sub { my $webtools = $class->new( { UserID => 'fake_user', Password => "this won't work", Testing => 1, } ); ok( $webtools->_testing, "I think I'm testing" ); is( ! $webtools->_live, 1, "I don't think I'm live!" ); is( $webtools->_api_host, "stg-production.shippingapis.com", "Testing host is right" ); is( $webtools->_api_path, "/ShippingAPI.dll", "Testing path is right" ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # subtest not_testing => sub { my $webtools = $class->new( { UserID => 'fake_user', Password => "this won't work", Testing => 0, } ); ok( $webtools->_live, "I think I'm live" ); is( ! $webtools->_testing, 1, "I don't think I'm testing!" ); is( $webtools->_api_host, "production.shippingapis.com", "Live host is right" ); is( $webtools->_api_path, "/ShippingAPI.dll", "Testing path is right" ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Passing empty hash subtest empty => sub { my $webtools = $class->new( { UserID => 'fake_user', Password => "this won't work", } ); ok( $webtools->_live, "I think I'm live" ); is( ! $webtools->_testing, 1, "I don't think I'm testing!" ); is( $webtools->_api_host, "production.shippingapis.com", "Live host is right" ); is( $webtools->_api_path, "/ShippingAPI.dll", "Testing path is right" ); }; done_testing(); Business-US-USPS-WebTools-1.125/t/load.t0000644000175000017500000000051013723267663017512 0ustar smsimmssmsimmsBEGIN { @classes = qw( Business::US::USPS::WebTools Business::US::USPS::WebTools::AddressStandardization Business::US::USPS::WebTools::ZipCodeLookup Business::US::USPS::WebTools::CityStateLookup ); } use Test::More tests => scalar @classes; foreach my $class ( @classes ) { BAIL_OUT() unless use_ok( $class ); } Business-US-USPS-WebTools-1.125/t/pod.t0000644000175000017500000000020113723267663017352 0ustar smsimmssmsimmsuse Test::More; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); Business-US-USPS-WebTools-1.125/t/zip_code_lookup.t0000644000175000017500000004606214051276540021761 0ustar smsimmssmsimms#!/usr/bin/perl # See http://www.usps.com/webtools/htm/Address-Information.htm for # the test requirements. The headings ( "Good response #1", etc ) # correspond to the USPS test specification # # the sample requests are now at https://www.usps.com/business/web-tools-apis/general-api-developer-guide.htm#_Toc423593927 # but I haven't updated this. Some requests no longer appear there but # they still work. use Test::More 0.98; my $class = "Business::US::USPS::WebTools::ZipCodeLookup"; my $method = 'lookup_zipcode'; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # unless( $ENV{USPS_WEBTOOLS_USERID} and $ENV{USPS_WEBTOOLS_PASSWORD} ) { plan skip_all => "You must set the USPS_WEBTOOLS_USERID and USPS_WEBTOOLS_PASSWORD " . "environment variables to run these tests\n"; } my $is_testing = uc($ENV{USPS_WEBTOOLS_ENVIRONMENT}) eq 'TESTING'; my $base = 'https://' . ($is_testing ? 'stg-' : '') . 'production.shippingapis.com/ShippingAPI.dll'; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # my $verifier; subtest setup => sub { use_ok( $class ); $verifier = $class->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, Testing => $is_testing, } ); isa_ok( $verifier, $class ); can_ok( $verifier, $method ); }; =pod 2021-05-19: This test is failing because the API is no longer returning the expected output; it now includes the following warning: Default address: The address you entered was found but more information is needed (such as an apartment, suite, or box number) to match to a specific address. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good Request #1 subtest good_request_1 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '6406 Ivy Lane', City => 'Greenbelt', State => 'MD', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base?API=ZipCodeLookup&XML=%3CZipCodeLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E6406+Ivy+Lane%3C%2FAddress2%3E%3CCity%3EGreenbelt%3C%2FCity%3E%3CState%3EMD%3C%2FState%3E%3C%2FAddress%3E%3C%2FZipCodeLookupRequest%3E|, "URL for Ivy Lane is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "Response is not an error" ); my $expected = <<"XML";
6406 IVY LNGREENBELTMD207701441
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{Address2}, '6406 IVY LN', 'Address2 matches for Ivy Lane' ); is( $hash->{City}, 'GREENBELT', 'City matches for Ivy Lane' ); is( $hash->{State}, 'MD', 'State matches for Ivy Lane' ); is( $hash->{Zip5}, '20770', 'Zip5 matches for Ivy Lane' ); is( $hash->{Zip4}, '1441', 'Zip4 matches for Ivy Lane' ); }; =cut # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good request 2 subtest good_request_2 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '8 Wildwood Drive', City => 'Old Lyme', State => 'CT', Zip5 => '06371', Zip4 => '', } ); is( $url, qq|$base?API=ZipCodeLookup&XML=%3CZipCodeLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E8+Wildwood+Drive%3C%2FAddress2%3E%3CCity%3EOld+Lyme%3C%2FCity%3E%3CState%3ECT%3C%2FState%3E%3C%2FAddress%3E%3C%2FZipCodeLookupRequest%3E|, "URL for Wildwood Drive is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "Response is not an error" ); my $expected = <<"XML";
8 WILDWOOD DROLD LYMECT063711844
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{FirmName}, '', 'FirmName matches for Wildwood' ); is( $hash->{Address1}, '', 'Address1 matches for Wildwood' ); is( $hash->{Address2}, '8 WILDWOOD DR', 'Address2 matches for Wildwood' ); is( $hash->{City}, 'OLD LYME', 'City matches for Wildwood' ); is( $hash->{State}, 'CT', 'State matches for Wildwood' ); is( $hash->{Zip5}, '06371', 'Zip5 matches for Wildwood' ); is( $hash->{Zip4}, '1844', 'Zip4 matches for Wildwood' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good request 3 subtest good_request_3 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '4411 Romlon Street', City => 'Beltsville', State => 'MD', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base?API=ZipCodeLookup&XML=%3CZipCodeLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E4411+Romlon+Street%3C%2FAddress2%3E%3CCity%3EBeltsville%3C%2FCity%3E%3CState%3EMD%3C%2FState%3E%3C%2FAddress%3E%3C%2FZipCodeLookupRequest%3E|, "URL for Romlan Street is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "Response is not an error" ); my $expected = <<"XML";
4411 ROMLON STBELTSVILLEMD207052425Default address: The address you entered was found but more information is needed (such as an apartment, suite, or box number) to match to a specific address.
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{FirmName}, '', 'FirmName matches for Romlan' ); is( $hash->{Address1}, '', 'Address1 matches for Romlan' ); is( $hash->{Address2}, '4411 ROMLON ST', 'Address2 matches for Romlan' ); is( $hash->{City}, 'BELTSVILLE', 'City matches for Romlan' ); is( $hash->{State}, 'MD', 'State matches for Romlan' ); is( $hash->{Zip5}, '20705', 'Zip5 matches for Romlan' ); is( $hash->{Zip4}, '2425', 'Zip4 matches for Romlan' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Good request 4 subtest good_request_4 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '3527 Sharonwood Road Apt. 3C', City => 'Laurel', State => 'MD', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base?API=ZipCodeLookup&XML=%3CZipCodeLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E3527+Sharonwood+Road+Apt.+3C%3C%2FAddress2%3E%3CCity%3ELaurel%3C%2FCity%3E%3CState%3EMD%3C%2FState%3E%3C%2FAddress%3E%3C%2FZipCodeLookupRequest%3E|, "URL for Sharonwood Road is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( ! $verifier->is_error, "Response is not an error" ); my $expected = <<"XML";
3527 SHARONWOOD RD APT 3CLAURELMD207245920
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); my $hash = $verifier->_parse_response; is( $hash->{FirmName}, '', 'FirmName matches for Sharonwood' ); is( $hash->{Address1}, '', 'Address1 matches for Sharonwood' ); is( $hash->{Address2}, '3527 SHARONWOOD RD APT 3C', 'Address2 matches for Sharonwood' ); is( $hash->{City}, 'LAUREL', 'City matches for Sharonwood' ); is( $hash->{State}, 'MD', 'State matches for Sharonwood' ); is( $hash->{Zip5}, '20724', 'Zip5 matches for Sharonwood' ); is( $hash->{Zip4}, '5920', 'Zip4 matches for Sharonwood' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error Requests # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error response #1 subtest error_response_1 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '3527 Sharonwood Road Apt. 3C', City => 'Wilmington', State => 'DE', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base?API=ZipCodeLookup&XML=%3CZipCodeLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E3527+Sharonwood+Road+Apt.+3C%3C%2FAddress2%3E%3CCity%3EWilmington%3C%2FCity%3E%3CState%3EDE%3C%2FState%3E%3C%2FAddress%3E%3C%2FZipCodeLookupRequest%3E|, "URL for Sharonwood Road Error is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( $verifier->is_error, "Error request gets an error response" ); my $expected = <<"XML";
-2147219401clsAMSAddress Not Found.
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); is( $verifier->{error}{number}, -2147219401, 'Error number matches for Sharonwood error' ); is( $verifier->{error}{source}, 'clsAMS', 'Error source matches for Sharonwood error' ); is( $verifier->{error}{description}, 'Address Not Found. ', 'Error description matches for Sharonwood error' ); is( $verifier->{error}{help_file}, undef, 'Error help file matches for Sharonwood error' ); is( $verifier->{error}{help_context}, undef, 'Error help context matches for Sharonwood error' ); my $hash = $verifier->_parse_response; is( $hash->{FirmName}, '', 'FirmName is empty for Sharonwood error' ); is( $hash->{Address1}, '', 'Address1 is empty for Sharonwood error' ); is( $hash->{Address2}, '', 'Address2 is empty for Sharonwood error' ); is( $hash->{City}, '', 'City is empty for Sharonwood error' ); is( $hash->{State}, '', 'State is empty for Sharonwood error' ); is( $hash->{Zip5}, '', 'Zip5 is empty for Sharonwood error' ); is( $hash->{Zip4}, '', 'Zip4 is empty for Sharonwood error' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error response #2 =pod # this one no longer returns an hour subtest error_response_2 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '1600 Pennsylvania Avenue', City => 'Washington', State => 'DC', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base?API=ZipCodeLookup&XML=%3CZipCodeLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E1600+Pennsylvania+Avenue%3C%2FAddress2%3E%3CCity%3EWashington%3C%2FCity%3E%3CState%3EDC%3C%2FState%3E%3C%2FAddress%3E%3C%2FZipCodeLookupRequest%3E|, "URL for Pennsylvania Avenue Error is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( $verifier->is_error, "Error request gets an error response" ); my $expected = <<"XML";
-2147219403SOLServerTest;SOLServerTest.CallAddressDllMultiple responses found. No default address.
XML is( $response, $expected ); is( $verifier->{error}{number}, -2147219403, 'Error number matches for Pennsylvania Avenue error' ); is( $verifier->{error}{source}, 'SOLServerTest;SOLServerTest.CallAddressDll', 'Error source matches for Pennsylvania Avenue error' ); is( $verifier->{error}{description}, 'Multiple responses found. No default address.', 'Error description matches for Pennsylvania Avenue error' ); is( $verifier->{error}{help_file}, '', 'Error help file matches for Pennsylvania Avenue error' ); is( $verifier->{error}{help_context}, '', 'Error help context matches for Pennsylvania Avenue error' ); my $hash = $verifier->_parse_response; # print STDERR "In _make_request:\n" . Dumper( $verifier ) . "\n"; is( $hash->{FirmName}, '', 'FirmName is empty for Pennsylvania Avenue error' ); is( $hash->{Address1}, '', 'Address1 is empty for Pennsylvania Avenue error' ); is( $hash->{Address2}, '', 'Address2 is empty for Pennsylvania Avenue error' ); is( $hash->{City}, '', 'City is empty for Pennsylvania Avenue error' ); is( $hash->{State}, '', 'State is empty for Pennsylvania Avenue error' ); is( $hash->{Zip5}, '', 'Zip5 is empty for Pennsylvania Avenue error' ); is( $hash->{Zip4}, '', 'Zip4 is empty for Pennsylvania Avenue error' ); }; =cut # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error response #3 subtest error_response_3 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '123 Main Street', City => 'Washington', State => 'ZZ', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base?API=ZipCodeLookup&XML=%3CZipCodeLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E123+Main+Street%3C%2FAddress2%3E%3CCity%3EWashington%3C%2FCity%3E%3CState%3EZZ%3C%2FState%3E%3C%2FAddress%3E%3C%2FZipCodeLookupRequest%3E|, "URL for Main Street Error is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( $verifier->is_error, "Error request gets an error response" ); my $expected = <<"XML";
-2147219402clsAMSInvalid State Code.
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); is( $verifier->{error}{number}, -2147219402, 'Error number matches for Main Street error' ); is( $verifier->{error}{source}, 'clsAMS', 'Error source matches for Main Street error' ); is( $verifier->{error}{description}, 'Invalid State Code. ', 'Error description matches for Main Street error' ); is( $verifier->{error}{help_file}, undef, 'Error help file matches for Main Street error' ); is( $verifier->{error}{help_context}, undef, 'Error help context matches for Main Street error' ); my $hash = $verifier->_parse_response; # print STDERR "In _make_request:\n" . Dumper( $verifier ) . "\n"; is( $hash->{FirmName}, '', 'FirmName is empty for Main Street error' ); is( $hash->{Address1}, '', 'Address1 is empty for Main Street error' ); is( $hash->{Address2}, '', 'Address2 is empty for Main Street error' ); is( $hash->{City}, '', 'City is empty for Main Street error' ); is( $hash->{State}, '', 'State is empty for Main Street error' ); is( $hash->{Zip5}, '', 'Zip5 is empty for Main Street error' ); is( $hash->{Zip4}, '', 'Zip4 is empty for Main Street error' ); }; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Error response #4 subtest error_response_3 => sub { my $url = $verifier->_make_url( { FirmName => '', Address1 => '', Address2 => '123 Main Street', City => 'Trenton', State => 'NJ', Zip5 => '', Zip4 => '', } ); is( $url, qq|$base?API=ZipCodeLookup&XML=%3CZipCodeLookupRequest+USERID%3D%22$ENV{USPS_WEBTOOLS_USERID}%22+PASSWORD%3D%22$ENV{USPS_WEBTOOLS_PASSWORD}%22%3E%3CAddress+ID%3D%220%22%3E%3CFirmName%3E%3C%2FFirmName%3E%3CAddress1%3E%3C%2FAddress1%3E%3CAddress2%3E123+Main+Street%3C%2FAddress2%3E%3CCity%3ETrenton%3C%2FCity%3E%3CState%3ENJ%3C%2FState%3E%3C%2FAddress%3E%3C%2FZipCodeLookupRequest%3E|, "URL for Trenton, NJ Error is correct", ); my $response = $verifier->_make_request; ok( defined $response ); ok( $verifier->is_error, "Error request gets an error response" ); my $expected = <<"XML";
-2147219401clsAMSAddress Not Found.
XML $response =~ s/\s+\z//; $expected =~ s/\s+\z//; is( $response, $expected ); is( $verifier->{error}{number}, -2147219401, 'Error number matches for Trenton, NJ error' ); is( $verifier->{error}{source}, 'clsAMS', 'Error source matches for Trenton, NJ error' ); is( $verifier->{error}{description}, 'Address Not Found. ', 'Error description matches for Trenton, NJ error' ); is( $verifier->{error}{help_file}, undef, 'Error help file matches for Trenton, NJ error' ); is( $verifier->{error}{help_context}, undef, 'Error help context matches for Trenton, NJ error' ); my $hash = $verifier->_parse_response; # print STDERR "In _make_request:\n" . Dumper( $verifier ) . "\n"; is( $hash->{FirmName}, '', 'FirmName is empty for Trenton, NJ error' ); is( $hash->{Address1}, '', 'Address1 is empty for Trenton, NJ error' ); is( $hash->{Address2}, '', 'Address2 is empty for Trenton, NJ error' ); is( $hash->{City}, '', 'City is empty for Trenton, NJ error' ); is( $hash->{State}, '', 'State is empty for Trenton, NJ error' ); is( $hash->{Zip5}, '', 'Zip5 is empty for Trenton, NJ error' ); is( $hash->{Zip4}, '', 'Zip4 is empty for Trenton, NJ error' ); }; done_testing(); Business-US-USPS-WebTools-1.125/t/pod_coverage.t0000644000175000017500000000026113723267663021233 0ustar smsimmssmsimms#!/usr/bin/perl use Test::More; eval "use Test::Pod::Coverage 1.00"; plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD coverage" if $@; all_pod_coverage_ok(); Business-US-USPS-WebTools-1.125/t/track_confirm.t0000644000175000017500000000563314051276201021406 0ustar smsimmssmsimms#!/usr/bin/perl use Test::More; my $class = "Business::US::USPS::WebTools::TrackConfirm"; my $method = 'track'; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # unless( $ENV{USPS_WEBTOOLS_USERID} and $ENV{USPS_WEBTOOLS_PASSWORD} ) { plan skip_all => "You must set the USPS_WEBTOOLS_USERID and USPS_WEBTOOLS_PASSWORD " . "environment variables to run these tests\n"; } my $is_testing = uc($ENV{USPS_WEBTOOLS_ENVIRONMENT}) eq 'TESTING'; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # subtest setup => sub { use_ok( $class ); can_ok( $class, $method ); }; my $tracker; subtest create_tracker => sub { $tracker = $class->new( { UserID => $ENV{USPS_WEBTOOLS_USERID}, Password => $ENV{USPS_WEBTOOLS_PASSWORD}, Testing => $is_testing, } ); isa_ok( $tracker, $class ); }; =pod These don't work even though they are documented. Simply requesting the URL provided in the docs returns an error. These tracking IDs are supposed to have hard-coded responses in the server and they do not. subtest test_request_1 => sub { my $array = $tracker->track( TrackID => 'EJ958083578US' ); diag $tracker->url; isa_ok( $array, ref [] ); is( scalar @$array, 3, 'There are three details' ); diag $tracker->response; # is( $array->[0], }; subtest test_request_2 => sub { my $array = $tracker->track( TrackID => 'EJ958088694US' ); diag $tracker->url; isa_ok( $array, ref [] ); is( scalar @$array, 3, 'There are three details' ); diag $tracker->response; }; =cut done_testing(); __END__ Test Request #1 This test shows a multi-entry return that is arranged in reverse chronological order. Note that a DOM parser may scramble the order of the XML which may cause programmatic confusion. http://production.shippingapis.com/ShippingAPITest.dll?API=TrackV2 &XML= Your item was delivered at 8:10 am on June 1 in Wilmington DE 19801. May 30 11:07 am NOTICE LEFT WILMINGTON DE 19801. May 30 10:08 am ARRIVAL AT UNIT WILMINGTON DE 19850. May 29 9:55 am ACCEPT OR PICKUP EDGEWATER NJ 07020. Test Request #2 http://production.shippingapis.com/ShippingAPITest.dll?API=TrackV2 &XML= Your item was delivered at 1:39 pm on June 1 in WOBURN MA 01815. May 30 7:44 am NOTICE LEFT WOBURN MA 01815. May 30 7:36 am ARRIVAL AT UNIT NORTH READING MA 01889. May 29 6:00 pm ACCEPT OR PICKUP PORTSMOUTH NH 03801. Business-US-USPS-WebTools-1.125/CONTRIBUTING.md0000644000175000017500000000513013731215757020373 0ustar smsimmssmsimms# Contributing to this project This is a general guide to working with this project through GitHub. If you'd like to take over this Perl module, I'm more than willing to give it up. Write to me at ssimms@cpan.org and we'll work it out. ## Pull requests Good pull requests - patches, improvements, new features - are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. **Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code, porting to a different language), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project. Please adhere to the coding conventions used throughout a project (indentation, accurate comments, etc.) and any other requirements (such as test coverage). Follow this process if you'd like your work considered for inclusion in the project: 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: ```bash # Clone your fork of the repo into the current directory git clone https://github.com// # Navigate to the newly cloned directory cd # Assign the original repo to a remote called "upstream" git remote add upstream https://github.com// ``` 2. If you cloned a while ago, get the latest changes from upstream: ```bash git checkout git pull upstream ``` 3. Create a new topic branch (off the main project development branch) to contain your feature, change, or fix: ```bash git checkout -b ``` 4. Commit your changes in logical chunks. Please make you git commit message detailed and specific or your code is unlikely be merged into the main project. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. 5. Locally merge (or rebase) the upstream development branch into your topic branch: ```bash git pull [--rebase] upstream ``` 6. Push your topic branch up to your fork: ```bash git push origin ``` 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description. **IMPORTANT**: By submitting a patch, you agree to allow the project owner to license your work under the same license as that used by the project.