Business-Shipping
view release on metacpan or search on metacpan
lib/Business/Shipping/USPS_Online/Tracking.pm view on Meta::CPAN
package Business::Shipping::USPS_Online::Tracking;
=head1 NAME
Business::Shipping::USPS_Online::Tracking - A USPS module for Tracking Packages
See Tracking.pm POD for usage information.
=head2 EXAMPLE
my $results = $tracker->results();
# The results hash will contain this type of information
{
# Summary will contain the latest activity entry, a copy of activity->[0]
summary => { },
# Activity of the package in transit, newest entries first.
activity => [
{
# Address information of the activity
address => {
city => '...',
state => '...',
zip => '...',
country => '...',
signedforbyname => '...',
},
# Description of activity
status_description => '...',
# Date of activity (YYYYMMDD)
date => '...',
# Time of activity (HHMMSS)
time => '...',
}
],
}
=cut
use Any::Moose;
use Business::Shipping::Logging;
use XML::Simple 2.05;
use XML::DOM;
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Response;
use Date::Parse;
use POSIX;
use version; our $VERSION = qv('400');
extends 'Business::Shipping::Tracking';
has 'prod_url' => (
is => 'rw',
default => 'http://production.shippingapis.com/ShippingAPI.dll'
);
has 'test_url' => (
is => 'rw',
default => 'http://testing.shippingapis.com/ShippingAPItest.dll'
);
# _gen_request_xml()
# Generate the XML document.
sub _gen_request_xml {
trace '()';
my $self = shift;
if (!grep { !$self->results_exists($_) } @{ $self->tracking_ids }) {
# All results were found in the cache
return;
}
my @results;
foreach my $id (@{ $self->tracking_ids() }) {
# Note: The XML::Simple hash-tree-based generation method wont work with USPS,
# because they enforce the order of their parameters (unlike UPS).
#
my $trackReqDoc = XML::DOM::Document->new();
my $trackReqEl = $trackReqDoc->createElement('TrackFieldRequest');
$trackReqEl->setAttribute('USERID', $self->user_id());
$trackReqEl->setAttribute('PASSWORD', $self->password());
$trackReqDoc->appendChild($trackReqEl);
# Could already have some responses cached so don't pull them from the server.
foreach my $tracking_id (grep { !$self->results_exists($_) }
@{ $self->tracking_ids })
{
my $trackIDEl = $trackReqDoc->createElement("TrackID");
$trackIDEl->setAttribute('ID', $tracking_id);
$trackReqEl->appendChild($trackIDEl);
}
my $request_xml = $trackReqDoc->toString();
# We only do this to provide a pretty, formatted XML doc for the debug.
my $request_xml_tree = XML::Simple::XMLin(
$request_xml,
KeepRoot => 1,
ForceArray => 1
);
trace(XML::Simple::XMLout($request_xml_tree, KeepRoot => 1))
if is_trace();
#
push @results, $request_xml;
}
return @results;
}
sub _gen_url {
trace '()';
my ($self) = shift;
return ($self->test_mode() ? $self->test_url() : $self->prod_url());
}
sub _gen_request {
my ($self) = shift;
trace('called');
my @reqs;
foreach my $request_xml ($self->_gen_request_xml()) {
my $request = HTTP::Request->new('POST', $self->_gen_url());
$request->header(
'content-type' => 'application/x-www-form-urlencoded');
$request->header('content-length' => length($request_xml));
# This is how USPS slightly varies from Business::Shipping
my $new_content = 'API=TrackV2' . '&XML=' . $request_xml;
$request->content($new_content);
$request->header('content-length' => length($request->content()));
trace('HTTP Request: ' . $request->as_string()) if is_trace();
push @reqs, $request;
}
return @reqs;
}
sub cleanup_xml_hash {
my $hash_ref = shift;
map { $hash_ref->{$_} = undef; } grep {
ref($hash_ref->{$_}) eq 'HASH'
&& scalar(keys %{ $hash_ref->{$_} })
== 0
} keys %$hash_ref;
}
sub _handle_response {
trace '()';
my $self = shift;
my $response_tree = XML::Simple::XMLin(
$self->response()->content(),
ForceArray => 0,
KeepRoot => 1,
);
# TODO: Handle multiple packages errors.
# (this doesn't seem to handle multiple packagess errors very well)
if ($response_tree->{Error}) {
my $error = $response_tree->{Error};
my $error_number = $error->{Number};
my $error_source = $error->{Source};
my $error_description = $error->{Description};
$self->user_error(
"$error_source: $error_description ($error_number)");
return (undef);
}
trace('response = ' . $self->response->content) if is_trace();
$response_tree = $response_tree->{TrackResponse};
my $results;
foreach my $trackInfo (
( (ref($response_tree->{TrackInfo}) eq 'ARRAY')
? (@{ $response_tree->{TrackInfo} })
: $response_tree->{TrackInfo}
)
( run in 1.004 second using v1.01-cache-2.11-cpan-5735350b133 )