File Coverage

lib/Net/API/Stripe/Generic.pm
Criterion Covered Total %
statement 44 291 15.1
branch 3 210 1.4
condition 1 81 1.2
subroutine 13 32 40.6
pod 4 4 100.0
total 65 618 10.5


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## Stripe API - ~/lib/Net/API/Stripe/Generic.pm
3             ## Version v0.101.0
4             ## Copyright(c) 2020 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest <jack@deguest.jp>
6             ## Created 2019/11/02
7             ## Modified 2020/12/02
8             ## All rights reserved
9             ##
10             ## This program is free software; you can redistribute it and/or modify it
11             ## under the same terms as Perl itself.
12             ##----------------------------------------------------------------------------
13             BEGIN
14             {
15             use strict;
16 137     137   59023 use warnings;
  137         384  
  137         4523  
17 137     137   697 use parent qw( Module::Generic );
  137         271  
  137         4038  
18 137     137   737 use Module::Generic::Exception;
  137         328  
  137         886  
19 137     137   71557 use vars qw( $VERSION );
  137         362395  
  137         1220  
20 137     137   48979 use Nice::Try;
  137         300  
  137         5684  
21 137     137   874 use Devel::Confess;
  137         335  
  137         1428  
22 137     137   95775427 use Want;
  137         933609  
  137         676  
23 137     137   10649 our( $VERSION ) = 'v0.101.0';
  137         326  
  137         10509  
24 137     137   2901 };
25              
26             use strict;
27 137     137   843 use warnings;
  137         281  
  137         2626  
28 137     137   665  
  137         291  
  137         223698  
29             {
30             my $self = shift( @_ );
31             # Get the init params always present and including keys like _parent and _field
32 136     136 1 395866018 my $init = @_ ? shift( @_ ) : {};
33             $self->{_parent} = $init->{_parent};
34 136 100       3168 $self->{_field} = $init->{_field};
35 136         10644 $self->{_error} = '';
36 136         1918 $self->{debug} = $init->{_debug};
37 136         2250 $self->{_dbh} = $init->{_dbh} if( exists( $init->{_dbh} ) && $init->{_dbh} );
38 136         1376 $self->{_init_strict_use_sub} = 1;
39 136 0 33     2287 # $self->SUPER::init( @_ ) || return;
40 136         1230 $self->SUPER::init( @_ ) || return( $self->pass_error );
41             return( $self );
42 136 50       3881 }
43 136         13253  
44              
45              
46 0     0 1   {
47             my $self = shift( @_ );
48 0     0 1   return( $self->can( 'as_string' ) ? $self->as_string : $self );
49             }
50              
51             # Used in Net::API::Stripe::Payment::Source and Net::API::Stripe::Connect::ExternalAccount::Card
52 0     0 1   {
53 0 0         my $self = shift( @_ );
54             my $addr = shift( @_ ) || return;
55             # No 'state' property
56             my $map =
57             {
58             line1 => 'line1',
59 0     0     line2 => 'line2',
60 0   0       city => 'city',
61             state => 'state',
62 0           postal_code => 'zip',
63             country => 'country',
64             };
65             if( $self->_is_hash( $addr ) )
66             {
67             foreach my $k ( keys( %$map ) )
68             {
69             next unless( exists( $addr->{ $k } ) && length( $addr->{ $k } ) );
70             my $sub = "address_" . $map->{ $k };
71 0 0 0       $self->$sub( $addr->{ $k } );
    0          
72             }
73 0           }
74             elsif( $self->_is_object( $addr ) && $addr->isa( 'Net::API::Stripe::Address' ) )
75 0 0 0       {
76 0           foreach my $k ( keys( %$map ) )
77 0           {
78             next unless( exists( $addr->{ $k } ) && length( $addr->{ $k } ) );
79             my $sub = "address_" . $map->{ $k };
80             $self->$sub( $addr->$k );
81             }
82 0           }
83             else
84 0 0 0       {
85 0           return( $self->error( "I do not know what to do with '$addr'. I was expecting either a Net::API::Strie::Address or an hash reference." ) );
86 0           }
87             }
88              
89             {
90             my $self = shift( @_ );
91 0           my $p = shift( @_ );
92             my $num = $p->{value};
93             return if( !length( $num ) );
94             return( $self->error( "No \"from\" parameter was provided to convert number \"$num\"." ) ) if( !length( $p->{from} ) );
95             my $inch_to_cm = 2.54;
96             my $cm_to_inch = 0.39370078740157;
97 0     0     my $ounce_to_gram = 28.34952;
98 0           my $gram_to_ounce = 0.03527396583787;
99 0           if( lc( $p->{from} ) eq 'inch' )
100 0 0         {
101 0 0         return( $num / $inch_to_cm );
102 0           }
103 0           elsif( lc( $p->{from} ) eq 'cm' || lc( $p->{from} ) eq 'centimetre' )
104 0           {
105 0           return( $num / $cm_to_inch );
106 0 0 0       }
    0          
    0          
    0          
107             elsif( lc( $p->{from} ) eq 'ounce' )
108 0           {
109             return( $num / $ounce_to_gram );
110             }
111             elsif( lc( $p->{from} ) eq 'gram' )
112 0           {
113             return( $num / $gram_to_ounce );
114             }
115             else
116 0           {
117             return( $self->error( "I do not know how to convert from \"$p->{from}\"" ) );
118             }
119             }
120 0            
121             {
122             my $self = shift( @_ );
123             my $class = shift( @_ );
124 0           my $base = __PACKAGE__;
125             $base =~ s/\:\:Generic$//;
126             my $pkg = ( $class =~ /^($base\:\:(?:[^\:]+)?)/ )[0];
127             }
128              
129             # Overriding Module::Generic
130 0     0     {
131 0           my $self = shift( @_ );
132 0           my $field = shift( @_ );
133 0           return( $self->{ $field } ) if( exists( $self->{ $field } ) && Scalar::Util::blessed( $self->{ $field } ) && !$self->_is_array( $self->{ $field } ) );
134 0           my $class = shift( @_ );
135             my $this;
136             my $h =
137             {
138             '_parent' => $self->{_parent},
139             '_field' => $field,
140 0     0     '_debug' => $self->{debug},
141 0           };
142 0 0 0       $h->{_dbh} = $self->{_dbh} if( $self->{_dbh} );
      0        
143 0           my $o;
144 0           try
145             {
146             # https://stackoverflow.com/questions/32608504/how-to-check-if-perl-module-is-available#comment53081298_32608860
147             # my $class_file = join( '/', split( /::/, $class ) ) . '.pm';
148             # if( CORE::exists( $INC{ $class_file } ) || defined( *{"${class}::"} ) )
149             # if( Class::Load::is_class_loaded( $class ) )
150 0           # if( defined( ${"${class}::VERSION"} ) || scalar( @{"$class::ISA"} ) )
151 0 0         # {
152 0           # }
153 0 0 0       # else
  0            
  0            
  0            
  0            
  0            
  0            
  0            
154 0     0     # {
155             # my $rc = eval( "require $class;" );
156             # }
157             my $rc = eval{ $self->_load_class( $class ); };
158             # print( STDERR __PACKAGE__, "::_instantiate_object(): Error while loading module $class? $@\n" );
159             return( $self->error( "Unable to load module $class: $@" ) ) if( $@ );
160             if( $class->isa( 'Module::Generic::Dynamic' ) )
161             {
162             $o = @_ ? $class->new( @_ ) : $class->new;
163             $o->{debug} = $self->{debug};
164             $o->{_parent} = $self->{_parent};
165             $o->{_field} = $field;
166 0           }
  0            
167             else
168 0 0         {
169 0 0         $o = @_ ? $class->new( $h, @_ ) : $class->new( $h );
170             }
171 0 0         return( $self->pass_error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) );
172 0           }
173 0           catch( $e )
174 0           {
175             return( $self->error({ code => 500, message => $e }) );
176             }
177             return( $o );
178 0 0         }
179              
180 0 0         {
181             my $self = shift( @_ );
182 0 0 0       my $type = shift( @_ ) || return( $self->error( "No object type was provided" ) );
  0 0 0        
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
183 0     0     require Net::API::Stripe;
184 0           my $ref = $Net::API::Stripe::TYPE2CLASS;
185 137 0 0 137   1171 return( $self->error( "No object type '$type' known to get its related class for field $self->{_field}" ) ) if( !exists( $ref->{ $type } ) );
  137 0 0     342  
  137 0 0     170098  
  0 0 0        
  0 0 0        
  0 0 0        
  0 0 0        
  0 0 0        
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
186 0           return( $ref->{ $type } );
187             }
188              
189             {
190             my $self = shift( @_ );
191 0     0     my $field = shift( @_ );
192 0   0       my $o;
193 0           if( @_ || !$self->{ $field } )
194 0           {
195 0 0         my $class = $field;
196 0           $class =~ tr/-/_/;
197             $class =~ s/\_{2,}/_/g;
198             $class = ref( $self ) . '::' . join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $class ) ) );
199             # require Devel::StackTrace;
200             # my $trace = Devel::StackTrace->new;
201 0     0     $o = $self->_set_get_hash_as_object( $field, $class, @_ );
202 0           $o->debug( $self->debug );
203 0           $self->{ $field } = $o;
204 0 0 0       }
205             $o = $self->{ $field };
206 0           if( want( 'OBJECT' ) )
207 0           {
208 0           return( $o );
209 0           }
210             my $hash = $o->{_data};
211             return( $hash );
212 0           }
213 0            
214 0           # Overiden
215             {
216 0           my $self = shift( @_ );
217 0 0         my $field = shift( @_ );
218             @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
219 0           if( @_ )
220             {
221 0           $self->{ $field } = Module::Generic::Number->new( shift( @_ ) );
222 0           }
223             return( $self->{ $field } );
224             }
225              
226             {
227             my $self = shift( @_ );
228 0     0     my $field = shift( @_ );
229 0           my $class = shift( @_ );
230 0 0 0       @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
231 0 0         if( @_ )
232             {
233 0           my $ref = shift( @_ );
234             return( $self->error( "I was expecting an array ref, but instead got '$ref'" ) ) if( !$self->_is_array( $ref ) );
235 0           my $arr = [];
236             for( my $i = 0; $i < scalar( @$ref ); $i++ )
237             {
238             my $o = defined( $ref->[$i] ) ? $self->_instantiate_object( $field, $class, $ref->[$i] ) : $self->_instantiate_object( $field, $class );
239             return( $self->error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) );
240 0     0     push( @$arr, $o );
241 0           }
242 0           $self->{ $field } = $arr;
243 0 0 0       }
244 0 0         return( $self->{ $field } );
245             }
246 0            
247 0 0         {
248 0           my $self = shift( @_ );
249 0           my $field = shift( @_ );
250             # The class precisely depends on what we find looking ahead
251 0 0         # my $class = shift( @_ );
252 0 0         if( @_ )
253 0           {
254             my $process = sub
255 0           {
256             my $ref = shift( @_ );
257 0           my $type = $ref->{object} || return( $self->error( "No object type could be found in hash: ", sub{ $self->_dumper( $ref ) } ) );
258             my $class = $self->_object_type_to_class( $type );
259             my $o = $self->_instantiate_object( $field, $class, $ref );
260             $self->{ $field } = $o;
261             # return( $class->new( %$ref ) );
262 0     0     # return( $self->_set_get_object( 'object', $class, $ref ) );
263 0           };
264            
265             if( ref( $_[0] ) eq 'HASH' )
266 0 0         {
267             my $o = $process->( @_ )
268             }
269             # AN array of objects hash
270 0     0     elsif( ref( $_[0] ) eq 'ARRAY' )
271 0   0       {
272 0           my $arr = shift( @_ );
273 0           my $res = [];
274 0           foreach my $data ( @$arr )
275             {
276             my $o = $process->( $data ) || return( $self->error( "Unable to create object: ", $self->error ) );
277 0           push( @$res, $o );
278             }
279 0 0         $self->{ $field } = $res;
    0          
280             }
281 0           }
282             return( $self->{ $field } );
283             }
284              
285             {
286 0           my $self = shift( @_ );
287 0           my $field = shift( @_ );
288 0           my $class = shift( @_ );
289             @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
290 0   0       if( @_ )
291 0           {
292             my $ref = shift( @_ );
293 0           return( $self->error( "I was expecting an array ref, but instead got '$ref'" ) ) if( !$self->_is_array( $ref ) );
294             my $arr = [];
295             for( my $i = 0; $i < scalar( @$ref ); $i++ )
296 0           {
297             # If this is an HASH reference, we make it an object
298             my $o;
299             if( ref( $ref->[$i] ) )
300             {
301 0     0     $o = $self->_instantiate_object( $field, $class, $ref->[$i] );
302 0           }
303 0           else
304 0 0 0       {
305 0 0         # push( @$arr, $ref->[$i] );
306             $o = defined( $ref->[$i] ) ? $self->_instantiate_object( $field, $class, { id => $ref->[$i] } ) : $self->_instantiate_object( $field, $class );
307 0           }
308 0 0         return( $self->error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) );
309 0           push( @$arr, $o );
310 0           }
311             $self->{ $field } = $arr;
312             }
313 0           return( $self->{ $field } );
314 0 0         }
315              
316 0           {
317             my $self = shift( @_ );
318             my $field = shift( @_ );
319             if( @_ )
320             {
321 0 0         if( ref( $_[0] ) eq 'HASH' || ref( $_[0] ) eq 'ARRAY' )
322             {
323 0 0         return( $self->_set_get_object_variant( $field, @_ ) );
324 0           }
325             else
326 0           {
327             return( $self->_set_get_scalar( $field, @_ ) );
328 0           }
329             }
330             if( !$self->{ $field } && want( 'OBJECT' ) )
331             {
332             my $null = Module::Generic::Null->new({ debug => $self->{debug}, has_error => 0 });
333 0     0     rreturn( $null );
334 0           }
335 0 0         return( $self->{ $field } );
336             }
337 0 0 0        
338             {
339 0           my $self = shift( @_ );
340             my $field = shift( @_ );
341             if( @_ )
342             {
343 0           my $str = $self->SUPER::_set_get_uri( $field, @_ );
344             if( defined( $str ) && Scalar::Util::blessed( $str ) )
345             {
346 0 0 0       $self->{ $field } = $str->abs( $self->_parent->api_uri );
347             }
348 0           }
349 0           return( $self->{ $field } );
350             }
351 0            
352              
353             1;
354              
355              
356 0     0     =encoding utf8
357 0            
358 0 0         =head1 NAME
359              
360 0           Net::API::Stripe::Generic - A Stripe Generic Module
361 0 0 0        
362             =head1 VERSION
363 0            
364             v0.101.0
365              
366 0           =head1 DESCRIPTION
367              
368             This is a module inherited by all other L<Net::API::Stripe> modules. Its purpose is to provide some shared methods and special object instantiation procedure with some key properties set such as I<_parent> and I<_field>.
369 0     0      
370             =head1 CONSTRUCTOR
371              
372             =head2 new( %ARG )
373              
374             Creates a new L<Net::API::Stripe::Fraud> object.
375             It may also take an hash like arguments, that also are method of the same name.
376              
377             Possible parameters are:
378              
379             =over 4
380              
381             =item I<_parent> The parent calling object
382              
383             =item I<_field> The field or property name this object is associated with
384              
385             =item I<_error>
386              
387             =item I<debug> Integer. A debug level.
388              
389             =item I<_dbh> A Database handler, if any
390              
391             =item I<_init_strict_use_sub> Boolean set for method B<init> in L<Module::Generic>. When set to true, only parameters that have a corresponding method will be accepted.
392              
393             =back
394              
395             =head1 METHODS
396              
397             =head2 field
398              
399             Set/get the field to which this object is associated
400              
401             =head2 parent
402              
403             Set/get the parent (caller) of this object.
404              
405             =head2 TO_JSON
406              
407             Returns a stringified version of this object if the method B<as_string> exists or is inherited, otherwise it just returns the object itself.
408              
409             =head2 _address_populate
410              
411             Provided with an L<Net::API::Stripe::Address> object, and this will set the fields line, line2, city, postal_code, state and country to address_line, address_line2, address_city, address_zip, address_state and address_country.
412              
413             This is used in L<Net::API::Stripe::Payment::Source> and L<Net::API::Stripe::Connect::ExternalAccount::Card>
414              
415             =head2 _get_base_class
416              
417             Get the base class of the object
418              
419             =head2 _instantiate_object( field, class )
420              
421             Provided with a field aka property name and a class name and this method creates an object.
422              
423             If the object is already instantiated, it returns it.
424              
425             Otherwise, it will attempt to load the given class using B<_load_class> from L<Module::Generic> or return undef and set an error if an error occurred.
426              
427             =head2 _object_type_to_class( type )
428              
429             Provided with a Stripe object type such as I<charge> or I<invoice> or I<customer>, this method will return the equivalent L<Net::API::Stripe> module package name.
430              
431             =head2 _set_get_hash( field, hash )
432              
433             Provided with a field (aka property) name and a hash reference, and this method will call method B<_set_get_hash_as_object> from L<Module::Generic> to create an hash whose properties can be accessed as methods of an object. So:
434              
435             $o->name
436              
437             instead of:
438              
439             $o->{name}
440              
441             =head2 _set_get_number( field, number )
442              
443             Provided with a field (aka property) and a number, this will create a new L<Module::Generic::Number> object for the associated field I<field>
444              
445             =head2 _set_get_object_array( field, class, array reference )
446              
447             Provided with a field (aka property) name, a class (package name) and an array reference, and this method will instantiate an object for each array entry.
448              
449             It returns an array reference for this field
450              
451             =head2 _set_get_object_variant( field, hash or array reference )
452              
453             Provided with a field (aka property) name and an hash or array reference and this method will instantiate an object if the data provided is an hash reference or it will instantiate an array of objects if the data provided is an array reference.
454              
455             =head2 _set_get_scalar_or_object_variant( field, scalar, hash or array reference )
456              
457             Provided with a scalar, an hash reference or an array reference and this will set the value for this field accordingly.
458              
459             If this is just a scalar, the scalar value will be set for the I<field>. If the data is an hash reference or an array reference, the same operation is done as in method B<_set_get_object_variant>
460              
461             =head2 _set_get_uri( field, uri )
462              
463             Provided with a field (aka a property) and an uri and this will create an L<URI> object for this I<field>
464              
465             =head2 _will
466              
467             Calls B<will> from the module L<Module::Generic>
468              
469             =head1 HISTORY
470              
471             =head2 v0.100.0
472              
473             Initial version
474              
475             =head1 AUTHOR
476              
477             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
478              
479             =head1 SEE ALSO
480              
481             L<Net::API::Stripe>, L<Module::Generic>, L<Module::Generic::Number>, L<JSON>, L<URI>
482              
483             =head1 COPYRIGHT & LICENSE
484              
485             Copyright (c) 2019-2020 DEGUEST Pte. Ltd.
486              
487             You can use, copy, modify and redistribute this package and associated
488             files under the same terms as Perl itself.
489              
490             =cut