File Coverage

blib/lib/Webservice/Shipment/Carrier/FedEx.pm
Criterion Covered Total %
statement 53 62 85.4
branch 10 18 55.5
condition n/a
subroutine 14 17 82.3
pod 6 6 100.0
total 83 103 80.5


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