File Coverage

blib/lib/Webservice/Shipment/Carrier/FedEx.pm
Criterion Covered Total %
statement 50 59 84.7
branch 10 18 55.5
condition n/a
subroutine 13 16 81.2
pod 6 6 100.0
total 79 99 79.8


line stmt bran cond sub pod time code
1             package Webservice::Shipment::Carrier::FedEx;
2              
3 1     1   143665 use Mojo::Base 'Webservice::Shipment::Carrier';
  1         3  
  1         7  
4              
5 1     1   154 use constant DEBUG => $ENV{MOJO_SHIPMENT_DEBUG};
  1         11  
  1         47  
6              
7 1     1   6 use Mojo::IOLoop;
  1         2  
  1         3  
8 1     1   22 use Mojo::JSON;
  1         2  
  1         30  
9 1     1   5 use Mojo::URL;
  1         1  
  1         3  
10 1     1   319 use Time::Piece;
  1         4693  
  1         4  
11              
12             has api_url => sub { Mojo::URL->new('https://www.fedex.com/trackingCal/track') };
13             has carrier_description => sub { 'FedEx' };
14             has validation_regex => sub { qr/(\b96\d{20}\b)|(\b\d{15}\b)|(\b\d{12}\b)/ };
15              
16             sub human_url {
17 1     1 1 2 my ($self, $id, $doc) = @_;
18 1         6 return Mojo::URL->new('https://www.fedex.com/apps/fedextrack/')->query(
19             action => 'track',
20             locale => 'en_US',
21             cntry_code => 'us',
22             language => 'english',
23             tracknumbers => $id,
24             );
25             }
26              
27             sub extract_destination {
28 6     6 1 13 my ($self, $id, $doc, $target) = @_;
29              
30 6         16 my %targets = (
31             postal_code => 'destZip',
32             state => 'destStateCD',
33             city => 'destCity',
34             country => 'destCntryCD',
35             );
36              
37 6 100       18 my $t = $targets{$target} or return;
38 4 100       16 my $addr = $doc->{$t} or return;
39 3         10 return $addr;
40             }
41              
42             sub extract_service {
43 1     1 1 3 my ($self, $id, $doc) = @_;
44 1         2 my $class = $doc->{serviceDesc};
45 1 50       6 my $service = $class =~ /fedex/i ? $class : 'FedEx ' . $class;
46 1         4 return $service;
47             }
48              
49             sub extract_status {
50 1     1 1 3 my ($self, $id, $doc) = @_;
51              
52 1         3 my $summary = $doc->{scanEventList}[0];
53 1 50       4 return unless $summary;
54              
55 1 50       31 my $delivered = $doc->{isDelivered} ? 1 : 0;
56              
57 1         17 my $desc = $doc->{statusWithDetails};
58 1 50       5 unless ($summary->{date}) {
59 0         0 $desc = 'No information found for ' . $id . '';
60 0         0 return ($desc, undef, $delivered);
61             }
62              
63 1         5 my $timestamp = join(' ', $summary->{date}, $summary->{time});
64 1         2 eval{
65 1         11 $timestamp = Time::Piece->strptime($summary->{date} . ' T ' . $summary->{time}, '%Y-%m-%d T %H:%M:%S');
66             };
67              
68 1 50       92 $desc = $summary->{date} ? join(' ', $desc , $summary->{date}, $summary->{time}) : $desc;
69 1         4 return ($desc, $timestamp, $delivered);
70             }
71              
72 1     1 1 3 sub extract_weight { '' }
73              
74             sub request {
75 1     1 1 2 my ($self, $id, $cb) = @_;
76              
77 1         5 my $tx = $self->ua->build_tx(
78             POST => $self->api_url.
79             {Accept => 'application/json'},
80             form => {
81             action => 'trackpackages',
82             locale => 'en_US',
83             version => '1',
84             format => 'json',
85             data => Mojo::JSON::encode_json({
86             TrackPackagesRequest => {
87             appType => 'WTRK',
88             uniqueKey => '',
89             processingParameters => {},
90             trackingInfoList => [
91             {
92             trackNumberInfo => {
93             trackingNumber => $id,
94             trackingQualifier => '',
95             trackingCarrier => '',
96             }
97             }
98             ]
99             }
100             })
101             }
102             );
103              
104 1 50       2066 unless ($cb) {
105 1         4 $self->ua->start($tx);
106 1         2657 return _handle_response($tx);
107             }
108              
109             Mojo::IOLoop->delay(
110 0     0   0 sub { $self->ua->start($tx, shift->begin) },
111             sub {
112 0     0   0 my ($ua, $tx) = @_;
113 0 0       0 die $tx->error->{message} unless $tx->success;
114 0         0 my $json = _handle_response($tx);
115 0         0 $self->$cb(undef, $json);
116             },
117 0     0   0 )->catch(sub { $self->$cb(pop, undef) })->wait;
  0         0  
118             }
119              
120             sub _handle_response {
121 1     1   2 my $tx = shift;
122 1         4 my $json = $tx->res->json;
123 1         17407 warn "Response:\n" . $tx->res->body . "\n" if DEBUG;
124 1         10 return $json->{TrackPackagesResponse}{packageList}[0];
125             }
126              
127             1;
128              
129             =head1 NAME
130              
131             Webservice::Shipment::Carrier::FedEx - FedEx handling for Webservice::Shipment
132              
133             =head1 DESCRIPTION
134              
135             Implements FedEx handling for L.
136             It is a subclass of L which implements all the necessary methods.
137              
138             =head1 NOTES
139              
140             The service does not provide weight information, so C will always return an empty string.