File Coverage

blib/lib/Net/Async/Webservice/UPS/Address.pm
Criterion Covered Total %
statement 18 58 31.0
branch 0 44 0.0
condition 0 36 0.0
subroutine 6 14 42.8
pod 7 8 87.5
total 31 160 19.3


line stmt bran cond sub pod time code
1             package Net::Async::Webservice::UPS::Address;
2             $Net::Async::Webservice::UPS::Address::VERSION = '1.1.3';
3             {
4             $Net::Async::Webservice::UPS::Address::DIST = 'Net-Async-Webservice-UPS';
5             }
6 3     3   2076 use Moo;
  3         5  
  3         19  
7 3     3   1032 use 5.010;
  3         18  
  3         123  
8 3     3   16 use Types::Standard qw(Str Int Bool StrictNum);
  3         4  
  3         46  
9 3     3   2838 use Net::Async::Webservice::UPS::Types ':types';
  3         7  
  3         32  
10 3     3   14734 use Net::Async::Webservice::UPS::Response::Utils ':all';
  3         1351  
  3         28  
11 3     3   2815 use namespace::autoclean;
  3         7  
  3         33  
12              
13             # ABSTRACT: an address for UPS
14              
15              
16             has city => (
17             is => 'ro',
18             isa => Str,
19             required => 0,
20             );
21              
22              
23             has postal_code => (
24             is => 'ro',
25             isa => Str,
26             required => 0,
27             );
28              
29              
30             has postal_code_extended => (
31             is => 'ro',
32             isa => Str,
33             required => 0,
34             );
35              
36              
37             has state => (
38             is => 'ro',
39             isa => Str,
40             required => 0,
41             );
42              
43              
44             has country_code => (
45             is => 'ro',
46             isa => Str,
47             required => 0,
48             default => 'US',
49             );
50              
51              
52             has name => (
53             is => 'ro',
54             isa => Str,
55             required => 0,
56             );
57              
58              
59             has building_name => (
60             is => 'ro',
61             isa => Str,
62             required => 0,
63             );
64              
65              
66             has address => (
67             is => 'ro',
68             isa => Str,
69             required => 0,
70             );
71              
72              
73             has address2 => (
74             is => 'ro',
75             isa => Str,
76             required => 0,
77             );
78              
79              
80             has address3 => (
81             is => 'ro',
82             isa => Str,
83             required => 0,
84             );
85              
86              
87             has is_residential => (
88             is => 'ro',
89             isa => Bool,
90             required => 0,
91             );
92              
93              
94             has quality => (
95             is => 'ro',
96             isa => StrictNum,
97             required => 0,
98             );
99              
100              
101             sub is_exact_match {
102 0     0 1   my $self = shift;
103 0 0         return unless $self->quality();
104 0           return ($self->quality == 1);
105             }
106              
107              
108             sub is_very_close_match {
109 0     0 1   my $self = shift;
110 0 0         return unless $self->quality();
111 0           return ($self->quality >= 0.95);
112             }
113              
114              
115             sub is_close_match {
116 0     0 1   my $self = shift;
117 0 0         return unless $self->quality();
118 0           return ($self->quality >= 0.90);
119             }
120              
121              
122             sub is_possible_match {
123 0     0 1   my $self = shift;
124 0 0         return unless $self->quality();
125 0           return ($self->quality >= 0.90);
126             }
127              
128              
129             sub is_poor_match {
130 0     0 1   my $self = shift;
131 0 0         return unless $self->quality();
132 0           return ($self->quality <= 0.69);
133             }
134              
135              
136             sub as_hash {
137 0     0 1   my ($self, $shape) = @_;
138 0   0       $shape //= 'AV';
139              
140 0           set_implied_argument($self);
141              
142 0 0         if ($shape eq 'AV') {
    0          
    0          
143             return {
144 0 0 0       Address => {
145             CountryCode => $self->country_code || "US",
146             PostalCode => $self->postal_code,
147             out_if(City=>'city'),
148             out_if(StateProvinceCode=>'state'),
149             ( $self->is_residential ? ( ResidentialAddressIndicator => undef ) : () ),
150             }
151             };
152             }
153             elsif ($shape eq 'XAV') {
154             return {
155 0 0 0       AddressKeyFormat => {
    0          
    0          
156             CountryCode => $self->country_code || "US",
157             PostcodePrimaryLow => $self->postal_code,
158             out_if(PostcodeExtendedLow=>'postal_code_extended'),
159             out_if(ConsigneeName=>'name'),
160             out_if(BuildingName=>'building_name'),
161             AddressLine => [
162             ( $self->address ? $self->address : () ),
163             ( $self->address2 ? $self->address2 : () ),
164             ( $self->address3 ? $self->address3 : () ),
165             ],
166             out_if(PoliticalDivision1=>'state'),
167             out_if(PoliticalDivision2=>'city'),
168             }
169             }
170             }
171             elsif ($shape eq 'Ship') {
172             return {
173 0   0       Address => {
174             CountryCode => $self->country_code || "US",
175             PostalCode => $self->postal_code,
176             out_if(AddressLine1=>'address'),
177             out_if(AddressLine2=>'address2'),
178             out_if(AddressLine3=>'address3'),
179             out_if(City=>'city'),
180             out_if(StateProvinceCode=>'state'),
181             }
182             }
183             }
184             else {
185 0           die "bad address as_hash shape $shape";
186             }
187             }
188              
189             sub BUILDARGS {
190 0     0 0   my ($class,@etc) = @_;
191 0           my $hashref = $class->next::method(@etc);
192              
193 0   0       my $data = $hashref->{Address} || $hashref->{AddressKeyFormat} || $hashref->{AddressArtifactFormat};
194              
195 0 0         if (not $data) {
196 0 0 0       if ($hashref->{postal_code}
      0        
197             and not defined $hashref->{postal_code_extended}
198             and $hashref->{postal_code} =~ m{\A(\d+)-(\d+)\z}) {
199 0           $hashref->{postal_code} = $1;
200 0           $hashref->{postal_code_extended} = $2;
201             }
202 0           my @undef_k = grep {not defined $hashref->{$_} } keys %$hashref;
  0            
203 0           delete @$hashref{@undef_k};
204 0           return $hashref;
205             }
206              
207 0           set_implied_argument($data);
208              
209             return {
210 0           country_code => 'US', # default,
211             pair_if(quality=>$hashref->{Quality}),
212             in_if(country_code=>'CountryCode'),
213             in_if(postal_code=>'PostalCode'),
214             in_if(postal_code=>'PostcodePrimaryLow'),
215             in_if(city=>'City'),
216             in_if(city=>'PoliticalDivision2'),
217             in_if(state=>'StateProvinceCode'),
218             in_if(state=>'PoliticalDivision1'),
219             in_if(postal_code_extended=>'PostcodeExtendedLow'),
220             in_if(name=>'ConsigneeName'),
221             in_if(building_name=>'BuildingName'),
222             in_if(address=>'AddressLine1'),
223             in_if(address2=>'AddressLine2'),
224             in_if(address3=>'AddressLine3'),
225              
226             ( exists $data->{ResidentialAddressIndicator} ? ( is_residential => 1 ) : () ),
227             ( exists $data->{AddressClassification} ? ( is_residential => $data->{AddressClassification}{Code} eq 2 ? 1 : 0 ) : () ),
228              
229             ( $data->{StreetName} || $data->{StreetNumberLow} || $data->{StreetType} ? (
230             address => join(
231 0           ' ',grep { defined }
232 0 0 0       @{$data}{qw(StreetNumberLow StreetName {StreetType)})
    0          
    0          
    0          
    0          
    0          
    0          
    0          
233             ) : () ),
234              
235             ( ref($data->{AddressLine}) eq 'ARRAY' ? (
236             ( $data->{AddressLine}[0] ? ( address => $data->{AddressLine}[0] ) : () ),
237             ( $data->{AddressLine}[1] ? ( address2 => $data->{AddressLine}[1] ) : () ),
238             ( $data->{AddressLine}[2] ? ( address3 => $data->{AddressLine}[2] ) : () ),
239             ) : () ),
240             };
241             }
242              
243              
244             sub cache_id {
245 0     0 1   my ($self) = @_;
246 0   0       return join ':',
      0        
      0        
      0        
      0        
      0        
      0        
      0        
247             $self->name||'',
248             $self->building_name||'',
249             $self->address||'',
250             $self->address2||'',
251             $self->address3||'',
252             $self->country_code,
253             $self->state||'',
254             $self->city||'',
255             $self->postal_code,
256             $self->postal_code_extended||'',
257             }
258              
259             1;
260              
261             __END__
262              
263             =pod
264              
265             =encoding UTF-8
266              
267             =head1 NAME
268              
269             Net::Async::Webservice::UPS::Address - an address for UPS
270              
271             =head1 VERSION
272              
273             version 1.1.3
274              
275             =head1 ATTRIBUTES
276              
277             =head2 C<city>
278              
279             String with the name of the city, optional.
280              
281             =head2 C<postal_code>
282              
283             String with the post code of the address, usually required.
284              
285             =head2 C<postal_code_extended>
286              
287             String with the extended post code of the address, optional. If a
288             postcode matching C<< \d+-\d+ >> is passed in to the constructor, the
289             first group of digits is assigned to L</postal_code> and the second
290             one to L</postal_code_extended>.
291              
292             =head2 C<state>
293              
294             String with the name of the state, optional.
295              
296             =head2 C<country_code>
297              
298             String with the 2 letter country code, optional (defaults to C<US>).
299              
300             =head2 C<name>
301              
302             String with the recipient name, optional.
303              
304             =head2 C<building_name>
305              
306             String with the building name, optional.
307              
308             =head2 C<address>
309              
310             String with the first line of the address, optional.
311              
312             =head2 C<address2>
313              
314             String with the second line of address, optional.
315              
316             =head2 C<address3>
317              
318             String with the third line of the address, optional.
319              
320             =head2 C<is_residential>
321              
322             Boolean, indicating whether this address is residential. Optional.
323              
324             =head2 C<quality>
325              
326             This should only be set in objects that are returned as part of a
327             L<Net::Async::Webservice::UPS::Response::Address>. It's a float
328             between 0 and 1 expressing how good a match this address is for the
329             one provided.
330              
331             =head1 METHODS
332              
333             =head2 C<is_exact_match>
334              
335             True if L</quality> is 1. This method exists for compatibility with
336             L<Net::UPS::Address>.
337              
338             =head2 C<is_very_close_match>
339              
340             True if L</quality> is >= 0.95. This method exists for compatibility
341             with L<Net::UPS::Address>.
342              
343             =head2 C<is_close_match>
344              
345             True if L</quality> is >=0.9. This method exists for compatibility
346             with L<Net::UPS::Address>.
347              
348             =head2 C<is_possible_match>
349              
350             True if L</quality> is >= 0.9 (yes, the same as
351             L</is_close_match>). This method exists for compatibility with
352             L<Net::UPS::Address>.
353              
354             =head2 C<is_poor_match>
355              
356             True if L</quality> is <= 0.69. This method exists for compatibility
357             with L<Net::UPS::Address>.
358              
359             =head2 C<as_hash>
360              
361             Returns a hashref that, when passed through L<XML::Simple>, will
362             produce the XML fragment needed in UPS requests to represent this
363             address. Takes one parameter, either C<'AV'> or C<'XAV'>, to select
364             which representation to use (C<'XAV'> is the "street level validation"
365             variant).
366              
367             =head2 C<cache_id>
368              
369             Returns a string identifying this address.
370              
371             =for Pod::Coverage BUILDARGS
372              
373             =head1 AUTHORS
374              
375             =over 4
376              
377             =item *
378              
379             Gianni Ceccarelli <gianni.ceccarelli@net-a-porter.com>
380              
381             =item *
382              
383             Sherzod B. Ruzmetov <sherzodr@cpan.org>
384              
385             =back
386              
387             =head1 COPYRIGHT AND LICENSE
388              
389             This software is copyright (c) 2015 by Gianni Ceccarelli <gianni.ceccarelli@net-a-porter.com>.
390              
391             This is free software; you can redistribute it and/or modify it under
392             the same terms as the Perl 5 programming language system itself.
393              
394             =cut